Van's suggestion: add a means to let kernel set IP header ident #
[unix-history] / usr / src / sys / netinet / ip_input.c
index 02f3c56..1092270 100644 (file)
@@ -1,43 +1,33 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1988, 1993 Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)ip_input.c  7.15 (Berkeley) %G%
+ *     @(#)ip_input.c  7.26 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "malloc.h"
-#include "mbuf.h"
-#include "domain.h"
-#include "protosw.h"
-#include "socket.h"
-#include "errno.h"
-#include "time.h"
-#include "kernel.h"
-
-#include "../net/if.h"
-#include "../net/route.h"
-
-#include "in.h"
-#include "in_systm.h"
-#include "ip.h"
-#include "in_pcb.h"
-#include "in_var.h"
-#include "ip_var.h"
-#include "ip_icmp.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
 
 #ifndef        IPFORWARDING
 #ifdef GATEWAY
 
 #ifndef        IPFORWARDING
 #ifdef GATEWAY
@@ -66,13 +56,16 @@ int ipsendredirects = IPSENDREDIRECTS;
 #endif
 int    ipforwarding = IPFORWARDING;
 int    ipsendredirects = IPSENDREDIRECTS;
 #endif
 int    ipforwarding = IPFORWARDING;
 int    ipsendredirects = IPSENDREDIRECTS;
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
 int    ipprintfs = 0;
 #endif
 
 int    ipprintfs = 0;
 #endif
 
+extern struct domain inetdomain;
+extern struct protosw inetsw[];
 u_char ip_protox[IPPROTO_MAX];
 int    ipqmaxlen = IFQ_MAXLEN;
 struct in_ifaddr *in_ifaddr;                   /* first inet address */
 u_char ip_protox[IPPROTO_MAX];
 int    ipqmaxlen = IFQ_MAXLEN;
 struct in_ifaddr *in_ifaddr;                   /* first inet address */
+struct ifqueue ipintrq;
 
 /*
  * We need to save the IP options in case a protocol wants to respond
 
 /*
  * We need to save the IP options in case a protocol wants to respond
@@ -119,8 +112,8 @@ ip_init()
        ipintrq.ifq_maxlen = ipqmaxlen;
 #ifdef GATEWAY
        i = (if_index + 1) * (if_index + 1) * sizeof (u_long);
        ipintrq.ifq_maxlen = ipqmaxlen;
 #ifdef GATEWAY
        i = (if_index + 1) * (if_index + 1) * sizeof (u_long);
-       if ((ip_ifmatrix = (u_long *) malloc(i, M_RTABLE, M_WAITOK)) == 0)
-               panic("no memory for ip_ifmatrix");
+       ip_ifmatrix = (u_long *) malloc(i, M_RTABLE, M_WAITOK);
+       bzero((char *)ip_ifmatrix, i);
 #endif
 }
 
 #endif
 }
 
@@ -150,8 +143,10 @@ next:
        splx(s);
        if (m == 0)
                return;
        splx(s);
        if (m == 0)
                return;
-if ((m->m_flags & M_PKTHDR) == 0)
-panic("ipintr no HDR");
+#ifdef DIAGNOSTIC
+       if ((m->m_flags & M_PKTHDR) == 0)
+               panic("ipintr no HDR");
+#endif
        /*
         * If no IP addresses have been set yet but the interfaces
         * are receiving, can't do anything with incoming packets yet.
        /*
         * If no IP addresses have been set yet but the interfaces
         * are receiving, can't do anything with incoming packets yet.
@@ -165,6 +160,10 @@ panic("ipintr no HDR");
                goto next;
        }
        ip = mtod(m, struct ip *);
                goto next;
        }
        ip = mtod(m, struct ip *);
+       if (ip->ip_v != IPVERSION) {
+               ipstat.ips_badvers++;
+               goto bad;
+       }
        hlen = ip->ip_hl << 2;
        if (hlen < sizeof(struct ip)) { /* minimum header length */
                ipstat.ips_badhlen++;
        hlen = ip->ip_hl << 2;
        if (hlen < sizeof(struct ip)) { /* minimum header length */
                ipstat.ips_badhlen++;
@@ -252,6 +251,54 @@ panic("ipintr no HDR");
                                goto ours;
                }
        }
                                goto ours;
                }
        }
+       if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+               struct in_multi *inm;
+#ifdef MROUTING
+               extern struct socket *ip_mrouter;
+
+               if (ip_mrouter) {
+                       /*
+                        * If we are acting as a multicast router, all
+                        * incoming multicast packets are passed to the
+                        * kernel-level multicast forwarding function.
+                        * The packet is returned (relatively) intact; if
+                        * ip_mforward() returns a non-zero value, the packet
+                        * must be discarded, else it may be accepted below.
+                        *
+                        * (The IP ident field is put in the same byte order
+                        * as expected when ip_mforward() is called from
+                        * ip_output().)
+                        */
+                       ip->ip_id = htons(ip->ip_id);
+                       if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) {
+                               ipstat.ips_cantforward++;
+                               m_freem(m);
+                               goto next;
+                       }
+                       ip->ip_id = ntohs(ip->ip_id);
+
+                       /*
+                        * The process-level routing demon needs to receive
+                        * all multicast IGMP packets, whether or not this
+                        * host belongs to their destination groups.
+                        */
+                       if (ip->ip_p == IPPROTO_IGMP)
+                               goto ours;
+                       ipstat.ips_forward++;
+               }
+#endif
+               /*
+                * See if we belong to the destination multicast group on the
+                * arrival interface.
+                */
+               IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
+               if (inm == NULL) {
+                       ipstat.ips_cantforward++;
+                       m_freem(m);
+                       goto next;
+               }
+               goto ours;
+       }
        if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
                goto ours;
        if (ip->ip_dst.s_addr == INADDR_ANY)
        if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
                goto ours;
        if (ip->ip_dst.s_addr == INADDR_ANY)
@@ -302,9 +349,9 @@ found:
                 * convert offset of this to bytes.
                 */
                ip->ip_len -= hlen;
                 * convert offset of this to bytes.
                 */
                ip->ip_len -= hlen;
-               ((struct ipasfrag *)ip)->ipf_mff = 0;
+               ((struct ipasfrag *)ip)->ipf_mff &= ~1;
                if (ip->ip_off & IP_MF)
                if (ip->ip_off & IP_MF)
-                       ((struct ipasfrag *)ip)->ipf_mff = 1;
+                       ((struct ipasfrag *)ip)->ipf_mff |= 1;
                ip->ip_off <<= 3;
 
                /*
                ip->ip_off <<= 3;
 
                /*
@@ -312,13 +359,12 @@ found:
                 * or if this is not the first fragment,
                 * attempt reassembly; if it succeeds, proceed.
                 */
                 * or if this is not the first fragment,
                 * attempt reassembly; if it succeeds, proceed.
                 */
-               if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
+               if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
                        ipstat.ips_fragments++;
                        ip = ip_reass((struct ipasfrag *)ip, fp);
                        if (ip == 0)
                                goto next;
                        ipstat.ips_fragments++;
                        ip = ip_reass((struct ipasfrag *)ip, fp);
                        if (ip == 0)
                                goto next;
-                       else
-                               ipstat.ips_reassembled++;
+                       ipstat.ips_reassembled++;
                        m = dtom(ip);
                } else
                        if (fp)
                        m = dtom(ip);
                } else
                        if (fp)
@@ -431,7 +477,7 @@ insert:
                        return (0);
                next += q->ip_len;
        }
                        return (0);
                next += q->ip_len;
        }
-       if (q->ipf_prev->ipf_mff)
+       if (q->ipf_prev->ipf_mff & 1)
                return (0);
 
        /*
                return (0);
 
        /*
@@ -457,6 +503,7 @@ insert:
         */
        ip = fp->ipq_next;
        ip->ip_len = next;
         */
        ip = fp->ipq_next;
        ip->ip_len = next;
+       ip->ipf_mff &= ~1;
        ((struct ip *)ip)->ip_src = fp->ipq_src;
        ((struct ip *)ip)->ip_dst = fp->ipq_dst;
        remque(fp);
        ((struct ip *)ip)->ip_src = fp->ipq_src;
        ((struct ip *)ip)->ip_dst = fp->ipq_dst;
        remque(fp);
@@ -464,6 +511,13 @@ insert:
        m = dtom(ip);
        m->m_len += (ip->ip_hl << 2);
        m->m_data -= (ip->ip_hl << 2);
        m = dtom(ip);
        m->m_len += (ip->ip_hl << 2);
        m->m_data -= (ip->ip_hl << 2);
+       /* some debugging cruft by sklower, below, will go away soon */
+       if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
+               register int plen = 0;
+               for (t = m; m; m = m->m_next)
+                       plen += m->m_len;
+               t->m_pkthdr.len = plen;
+       }
        return ((struct ip *)ip);
 
 dropfrag:
        return ((struct ip *)ip);
 
 dropfrag:
@@ -553,7 +607,6 @@ ip_drain()
        }
 }
 
        }
 }
 
-extern struct in_ifaddr *ifptoia();
 struct in_ifaddr *ip_rtaddr();
 
 /*
 struct in_ifaddr *ip_rtaddr();
 
 /*
@@ -573,9 +626,10 @@ ip_dooptions(m)
        register struct in_ifaddr *ia;
        int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
        int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
        register struct in_ifaddr *ia;
        int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
        int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
-       struct in_addr *sin;
+       struct in_addr *sin, dst;
        n_time ntime;
 
        n_time ntime;
 
+       dst = ip->ip_dst;
        cp = (u_char *)(ip + 1);
        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
        for (; cnt > 0; cnt -= optlen, cp += optlen) {
        cp = (u_char *)(ip + 1);
        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
        for (; cnt > 0; cnt -= optlen, cp += optlen) {
@@ -643,7 +697,7 @@ ip_dooptions(m)
 #define        INA     struct in_ifaddr *
 #define        SA      struct sockaddr *
                            if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
 #define        INA     struct in_ifaddr *
 #define        SA      struct sockaddr *
                            if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
-                               ia = in_iaonnetof(in_netof(ipaddr.sin_addr));
+                               ia = (INA)ifa_ifwithnet((SA)&ipaddr);
                        } else
                                ia = ip_rtaddr(ipaddr.sin_addr);
                        if (ia == 0) {
                        } else
                                ia = ip_rtaddr(ipaddr.sin_addr);
                        if (ia == 0) {
@@ -656,7 +710,10 @@ ip_dooptions(m)
                            (caddr_t)(cp + off), sizeof(struct in_addr));
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        forward = 1;
                            (caddr_t)(cp + off), sizeof(struct in_addr));
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        forward = 1;
-                       forward = 1;
+                       /*
+                        * Let ip_intr's mcast routing check handle mcast pkts
+                        */
+                       forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
                        break;
 
                case IPOPT_RR:
                        break;
 
                case IPOPT_RR:
@@ -707,7 +764,11 @@ ip_dooptions(m)
                                if (ipt->ipt_ptr + sizeof(n_time) +
                                    sizeof(struct in_addr) > ipt->ipt_len)
                                        goto bad;
                                if (ipt->ipt_ptr + sizeof(n_time) +
                                    sizeof(struct in_addr) > ipt->ipt_len)
                                        goto bad;
-                               ia = ifptoia(m->m_pkthdr.rcvif);
+                               ipaddr.sin_addr = dst;
+                               ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
+                                                           m->m_pkthdr.rcvif);
+                               if (ia == 0)
+                                       continue;
                                bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
                                    (caddr_t)sin, sizeof(struct in_addr));
                                ipt->ipt_ptr += sizeof(struct in_addr);
                                bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
                                    (caddr_t)sin, sizeof(struct in_addr));
                                ipt->ipt_ptr += sizeof(struct in_addr);
@@ -736,10 +797,12 @@ ip_dooptions(m)
        if (forward) {
                ip_forward(m, 1);
                return (1);
        if (forward) {
                ip_forward(m, 1);
                return (1);
-       } else
-               return (0);
+       }
+       return (0);
 bad:
 bad:
-       icmp_error(m, type, code);
+       ip->ip_len -= ip->ip_hl << 2;   /* XXX icmp_error adds in hdr length */
+       icmp_error(m, type, code, 0, 0);
+       ipstat.ips_badoptions++;
        return (1);
 }
 
        return (1);
 }
 
@@ -782,7 +845,7 @@ save_rte(option, dst)
        unsigned olen;
 
        olen = option[IPOPT_OLEN];
        unsigned olen;
 
        olen = option[IPOPT_OLEN];
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if (ipprintfs)
                printf("save_rte: olen %d\n", olen);
 #endif
        if (ipprintfs)
                printf("save_rte: olen %d\n", olen);
 #endif
@@ -823,7 +886,7 @@ ip_srcroute()
        /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
        m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
            OPTSIZ;
        /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
        m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
            OPTSIZ;
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if (ipprintfs)
                printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
 #endif
        if (ipprintfs)
                printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
 #endif
@@ -833,11 +896,11 @@ ip_srcroute()
         */
        p = &ip_srcrt.route[ip_nhops - 1];
        *(mtod(m, struct in_addr *)) = *p--;
         */
        p = &ip_srcrt.route[ip_nhops - 1];
        *(mtod(m, struct in_addr *)) = *p--;
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if (ipprintfs)
                printf(" hops %X", ntohl(*mtod(m, struct in_addr *)));
        if (ipprintfs)
        if (ipprintfs)
                printf(" hops %X", ntohl(*mtod(m, struct in_addr *)));
        if (ipprintfs)
-               printf(" hops %X", ntohl(*mtod(m, struct in_addr *)));
+               printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr));
 #endif
 
        /*
 #endif
 
        /*
@@ -855,9 +918,9 @@ ip_srcroute()
         * reversing the path (pointers are now aligned).
         */
        while (p >= ip_srcrt.route) {
         * reversing the path (pointers are now aligned).
         */
        while (p >= ip_srcrt.route) {
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
                if (ipprintfs)
                if (ipprintfs)
-                       printf(" %X", ntohl(*q));
+                       printf(" %lx", ntohl(q->s_addr));
 #endif
                *q++ = *p--;
        }
 #endif
                *q++ = *p--;
        }
@@ -872,9 +935,9 @@ ip_srcroute()
         * Last hop goes to final destination.
         */
        *q = ip_srcrt.dst;
         * Last hop goes to final destination.
         */
        *q = ip_srcrt.dst;
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if (ipprintfs)
        if (ipprintfs)
-               printf(" %X\n", ntohl(*q));
+               printf(" %lx\n", ntohl(q->s_addr));
 #endif
        return (m);
 }
 #endif
        return (m);
 }
@@ -942,9 +1005,10 @@ ip_forward(m, srcrt)
        int error, type = 0, code;
        struct mbuf *mcopy;
        struct in_addr dest;
        int error, type = 0, code;
        struct mbuf *mcopy;
        struct in_addr dest;
+       struct ifnet *destifp;
 
        dest.s_addr = 0;
 
        dest.s_addr = 0;
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if (ipprintfs)
                printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
                        ip->ip_dst, ip->ip_ttl);
        if (ipprintfs)
                printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
                        ip->ip_dst, ip->ip_ttl);
@@ -1003,40 +1067,31 @@ ip_forward(m, srcrt)
            (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
            satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
            ipsendredirects && !srcrt) {
            (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
            satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
            ipsendredirects && !srcrt) {
-               struct in_ifaddr *ia;
+#define        RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
                u_long src = ntohl(ip->ip_src.s_addr);
                u_long dst = ntohl(ip->ip_dst.s_addr);
 
                u_long src = ntohl(ip->ip_src.s_addr);
                u_long dst = ntohl(ip->ip_dst.s_addr);
 
-               if ((ia = ifptoia(m->m_pkthdr.rcvif)) &&
-                  (src & ia->ia_subnetmask) == ia->ia_subnet) {
+               if (RTA(rt) &&
+                   (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
                    if (rt->rt_flags & RTF_GATEWAY)
                        dest = satosin(rt->rt_gateway)->sin_addr;
                    else
                        dest = ip->ip_dst;
                    if (rt->rt_flags & RTF_GATEWAY)
                        dest = satosin(rt->rt_gateway)->sin_addr;
                    else
                        dest = ip->ip_dst;
-                   /*
-                    * If the destination is reached by a route to host,
-                    * is on a subnet of a local net, or is directly
-                    * on the attached net (!), use host redirect.
-                    * (We may be the correct first hop for other subnets.)
-                    */
-#define        RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
+                   /* Router requirements says to only send host redirects */
                    type = ICMP_REDIRECT;
                    type = ICMP_REDIRECT;
-                   if ((rt->rt_flags & RTF_HOST) ||
-                       (rt->rt_flags & RTF_GATEWAY) == 0)
-                           code = ICMP_REDIRECT_HOST;
-                   else if (RTA(rt)->ia_subnetmask != RTA(rt)->ia_netmask &&
-                       (dst & RTA(rt)->ia_netmask) ==  RTA(rt)->ia_net)
-                           code = ICMP_REDIRECT_HOST;
-                   else
-                           code = ICMP_REDIRECT_NET;
-#ifdef DEBUG
+                   code = ICMP_REDIRECT_HOST;
+#ifdef DIAGNOSTIC
                    if (ipprintfs)
                        printf("redirect (%d) to %x\n", code, dest.s_addr);
 #endif
                }
        }
 
                    if (ipprintfs)
                        printf("redirect (%d) to %x\n", code, dest.s_addr);
 #endif
                }
        }
 
-       error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING);
+       error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING
+#ifdef DIRECTED_BROADCAST
+                           | IP_ALLOWBROADCAST
+#endif
+                                               , 0);
        if (error)
                ipstat.ips_cantforward++;
        else {
        if (error)
                ipstat.ips_cantforward++;
        else {
@@ -1051,6 +1106,8 @@ ip_forward(m, srcrt)
        }
        if (mcopy == NULL)
                return;
        }
        if (mcopy == NULL)
                return;
+       destifp = NULL;
+
        switch (error) {
 
        case 0:                         /* forwarded, but need redirect */
        switch (error) {
 
        case 0:                         /* forwarded, but need redirect */
@@ -1069,6 +1126,8 @@ ip_forward(m, srcrt)
        case EMSGSIZE:
                type = ICMP_UNREACH;
                code = ICMP_UNREACH_NEEDFRAG;
        case EMSGSIZE:
                type = ICMP_UNREACH;
                code = ICMP_UNREACH_NEEDFRAG;
+               if (ipforward_rt.ro_rt)
+                       destifp = ipforward_rt.ro_rt->rt_ifp;
                ipstat.ips_cantfrag++;
                break;
 
                ipstat.ips_cantfrag++;
                break;
 
@@ -1077,5 +1136,5 @@ ip_forward(m, srcrt)
                code = 0;
                break;
        }
                code = 0;
                break;
        }
-       icmp_error(mcopy, type, code, dest);
+       icmp_error(mcopy, type, code, dest, destifp);
 }
 }