Van's suggestion: add a means to let kernel set IP header ident #
[unix-history] / usr / src / sys / netinet / ip_input.c
index 973da9b..1092270 100644 (file)
@@ -1,33 +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.
  *
  * %sccs.include.redist.c%
  *
  * All rights reserved.
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_input.c  7.21 (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
@@ -65,6 +65,7 @@ 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
@@ -159,6 +160,10 @@ next:
                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++;
@@ -246,6 +251,54 @@ next:
                                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)
@@ -296,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;
 
                /*
@@ -306,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)
@@ -425,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);
 
        /*
@@ -451,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);
@@ -554,7 +607,6 @@ ip_drain()
        }
 }
 
        }
 }
 
-extern struct in_ifaddr *ifptoia();
 struct in_ifaddr *ip_rtaddr();
 
 /*
 struct in_ifaddr *ip_rtaddr();
 
 /*
@@ -574,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) {
@@ -644,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) {
@@ -657,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:
@@ -708,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);
@@ -737,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);
 }
 
@@ -943,6 +1005,7 @@ 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;
 #ifdef DIAGNOSTIC
 
        dest.s_addr = 0;
 #ifdef DIAGNOSTIC
@@ -1014,21 +1077,9 @@ ip_forward(m, srcrt)
                        dest = satosin(rt->rt_gateway)->sin_addr;
                    else
                        dest = ip->ip_dst;
                        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.)
-                    */
+                   /* 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;
+                   code = ICMP_REDIRECT_HOST;
 #ifdef DIAGNOSTIC
                    if (ipprintfs)
                        printf("redirect (%d) to %x\n", code, dest.s_addr);
 #ifdef DIAGNOSTIC
                    if (ipprintfs)
                        printf("redirect (%d) to %x\n", code, dest.s_addr);
@@ -1036,7 +1087,11 @@ ip_forward(m, srcrt)
                }
        }
 
                }
        }
 
-       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);
 }
 }