add crontab entry
[unix-history] / usr / src / sys / netinet / ip_input.c
index e971ccc..c0488df 100644 (file)
@@ -1,9 +1,20 @@
 /*
 /*
- * Copyright (c) 1982 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ip_input.c  6.17 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ip_input.c  7.10 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -224,43 +235,53 @@ next:
 
 ours:
        /*
 
 ours:
        /*
-        * Look for queue of fragments
-        * of this datagram.
+        * If offset or IP_MF are set, must reassemble.
+        * Otherwise, nothing need be done.
+        * (We could look in the reassembly queue to see
+        * if the packet was previously fragmented,
+        * but it's not worth the time; just let them time out.)
         */
         */
-       for (fp = ipq.next; fp != &ipq; fp = fp->next)
-               if (ip->ip_id == fp->ipq_id &&
-                   ip->ip_src.s_addr == fp->ipq_src.s_addr &&
-                   ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
-                   ip->ip_p == fp->ipq_p)
-                       goto found;
-       fp = 0;
+       if (ip->ip_off &~ IP_DF) {
+               /*
+                * Look for queue of fragments
+                * of this datagram.
+                */
+               for (fp = ipq.next; fp != &ipq; fp = fp->next)
+                       if (ip->ip_id == fp->ipq_id &&
+                           ip->ip_src.s_addr == fp->ipq_src.s_addr &&
+                           ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
+                           ip->ip_p == fp->ipq_p)
+                               goto found;
+               fp = 0;
 found:
 
 found:
 
-       /*
-        * Adjust ip_len to not reflect header,
-        * set ip_mff if more fragments are expected,
-        * convert offset of this to bytes.
-        */
-       ip->ip_len -= hlen;
-       ((struct ipasfrag *)ip)->ipf_mff = 0;
-       if (ip->ip_off & IP_MF)
-               ((struct ipasfrag *)ip)->ipf_mff = 1;
-       ip->ip_off <<= 3;
+               /*
+                * Adjust ip_len to not reflect header,
+                * set ip_mff if more fragments are expected,
+                * convert offset of this to bytes.
+                */
+               ip->ip_len -= hlen;
+               ((struct ipasfrag *)ip)->ipf_mff = 0;
+               if (ip->ip_off & IP_MF)
+                       ((struct ipasfrag *)ip)->ipf_mff = 1;
+               ip->ip_off <<= 3;
 
 
-       /*
-        * If datagram marked as having more fragments
-        * or if this is not the first fragment,
-        * attempt reassembly; if it succeeds, proceed.
-        */
-       if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
-               ipstat.ips_fragments++;
-               ip = ip_reass((struct ipasfrag *)ip, fp);
-               if (ip == 0)
-                       goto next;
-               m = dtom(ip);
+               /*
+                * If datagram marked as having more fragments
+                * or if this is not the first fragment,
+                * attempt reassembly; if it succeeds, proceed.
+                */
+               if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
+                       ipstat.ips_fragments++;
+                       ip = ip_reass((struct ipasfrag *)ip, fp);
+                       if (ip == 0)
+                               goto next;
+                       m = dtom(ip);
+               } else
+                       if (fp)
+                               ip_freef(fp);
        } else
        } else
-               if (fp)
-                       ip_freef(fp);
+               ip->ip_len -= hlen;
 
        /*
         * Switch out to protocol's input routine.
 
        /*
         * Switch out to protocol's input routine.
@@ -300,7 +321,7 @@ ip_reass(ip, fp)
         * If first fragment to arrive, create a reassembly queue.
         */
        if (fp == 0) {
         * If first fragment to arrive, create a reassembly queue.
         */
        if (fp == 0) {
-               if ((t = m_get(M_WAIT, MT_FTABLE)) == NULL)
+               if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
                        goto dropfrag;
                fp = mtod(t, struct ipq *);
                insque(fp, &ipq);
                        goto dropfrag;
                fp = mtod(t, struct ipq *);
                insque(fp, &ipq);
@@ -488,6 +509,7 @@ ip_drain()
        }
 }
 
        }
 }
 
+extern struct in_ifaddr *ifptoia();
 struct in_ifaddr *ip_rtaddr();
 
 /*
 struct in_ifaddr *ip_rtaddr();
 
 /*
@@ -567,7 +589,7 @@ ip_dooptions(ip, ifp)
                        /*
                         * locate outgoing interface
                         */
                        /*
                         * locate outgoing interface
                         */
-                       bcopy(cp + off, (caddr_t)&ipaddr.sin_addr,
+                       bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
                            sizeof(ipaddr.sin_addr));
                        if ((opt == IPOPT_SSRR &&
                            in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) ||
                            sizeof(ipaddr.sin_addr));
                        if ((opt == IPOPT_SSRR &&
                            in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) ||
@@ -577,8 +599,8 @@ ip_dooptions(ip, ifp)
                                goto bad;
                        }
                        ip->ip_dst = ipaddr.sin_addr;
                                goto bad;
                        }
                        ip->ip_dst = ipaddr.sin_addr;
-                       bcopy(&(IA_SIN(ia)->sin_addr), cp + off,
-                               sizeof(struct in_addr));
+                       bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
+                           (caddr_t)(cp + off), sizeof(struct in_addr));
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        break;
 
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        break;
 
@@ -593,18 +615,18 @@ ip_dooptions(ip, ifp)
                        off--;                  /* 0 origin */
                        if (off > optlen - sizeof(struct in_addr))
                                break;
                        off--;                  /* 0 origin */
                        if (off > optlen - sizeof(struct in_addr))
                                break;
-                       bcopy(cp + off, (caddr_t)ipaddr.sin_addr,
+                       bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
                            sizeof(ipaddr.sin_addr));
                        /*
                         * locate outgoing interface
                         */
                        if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
                                type = ICMP_UNREACH;
                            sizeof(ipaddr.sin_addr));
                        /*
                         * locate outgoing interface
                         */
                        if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
                                type = ICMP_UNREACH;
-                               code = ICMP_UNREACH_SRCFAIL;
+                               code = ICMP_UNREACH_HOST;
                                goto bad;
                        }
                                goto bad;
                        }
-                       bcopy(&(IA_SIN(ia)->sin_addr), cp + off,
-                               sizeof(struct in_addr));
+                       bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
+                           (caddr_t)(cp + off), sizeof(struct in_addr));
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        break;
 
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        break;
 
@@ -618,7 +640,7 @@ ip_dooptions(ip, ifp)
                                        goto bad;
                                break;
                        }
                                        goto bad;
                                break;
                        }
-                       sin = (struct in_addr *)(cp+cp[IPOPT_OFFSET]-1);
+                       sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
                        switch (ipt->ipt_flg) {
 
                        case IPOPT_TS_TSONLY:
                        switch (ipt->ipt_flg) {
 
                        case IPOPT_TS_TSONLY:
@@ -628,21 +650,20 @@ ip_dooptions(ip, ifp)
                                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;
-                               if (in_ifaddr == 0)
-                                       goto bad;       /* ??? */
-                               bcopy((caddr_t)&IA_SIN(in_ifaddr)->sin_addr,
+                               ia = ifptoia(ifp);
+                               bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
                                    (caddr_t)sin, sizeof(struct in_addr));
                                    (caddr_t)sin, sizeof(struct in_addr));
-                               sin++;
+                               ipt->ipt_ptr += sizeof(struct in_addr);
                                break;
 
                        case IPOPT_TS_PRESPEC:
                                break;
 
                        case IPOPT_TS_PRESPEC:
+                               if (ipt->ipt_ptr + sizeof(n_time) +
+                                   sizeof(struct in_addr) > ipt->ipt_len)
+                                       goto bad;
                                bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
                                    sizeof(struct in_addr));
                                if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
                                        continue;
                                bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
                                    sizeof(struct in_addr));
                                if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
                                        continue;
-                               if (ipt->ipt_ptr + sizeof(n_time) +
-                                   sizeof(struct in_addr) > ipt->ipt_len)
-                                       goto bad;
                                ipt->ipt_ptr += sizeof(struct in_addr);
                                break;
 
                                ipt->ipt_ptr += sizeof(struct in_addr);
                                break;
 
@@ -650,7 +671,8 @@ ip_dooptions(ip, ifp)
                                goto bad;
                        }
                        ntime = iptime();
                                goto bad;
                        }
                        ntime = iptime();
-                       bcopy((caddr_t)&ntime, (caddr_t)sin, sizeof(n_time));
+                       bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
+                           sizeof(n_time));
                        ipt->ipt_ptr += sizeof(n_time);
                }
        }
                        ipt->ipt_ptr += sizeof(n_time);
                }
        }
@@ -699,10 +721,10 @@ ip_rtaddr(dst)
  * to be picked up later by ip_srcroute if the receiver is interested.
  */
 save_rte(option, dst)
  * to be picked up later by ip_srcroute if the receiver is interested.
  */
 save_rte(option, dst)
-       caddr_t option;
+       u_char *option;
        struct in_addr dst;
 {
        struct in_addr dst;
 {
-       int olen;
+       unsigned olen;
        extern ipprintfs;
 
        olen = option[IPOPT_OLEN];
        extern ipprintfs;
 
        olen = option[IPOPT_OLEN];
@@ -711,7 +733,7 @@ save_rte(option, dst)
                        printf("save_rte: olen %d\n", olen);
                return;
        }
                        printf("save_rte: olen %d\n", olen);
                return;
        }
-       bcopy(option, (caddr_t)ip_srcrt.srcopt, olen);
+       bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen);
        ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
        ip_srcrt.route[ip_nhops++] = dst;
 }
        ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
        ip_srcrt.route[ip_nhops++] = dst;
 }
@@ -729,7 +751,9 @@ ip_srcroute()
 
        if (ip_nhops == 0)
                return ((struct mbuf *)0);
 
        if (ip_nhops == 0)
                return ((struct mbuf *)0);
-       m = m_get(M_WAIT, MT_SOOPTS);
+       m = m_get(M_DONTWAIT, MT_SOOPTS);
+       if (m == 0)
+               return ((struct mbuf *)0);
        m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1;
 
        /*
        m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1;
 
        /*
@@ -809,6 +833,11 @@ int        ipsendredirects = IPSENDREDIRECTS;
  * an icmp packet.  Note we can't always generate a meaningful
  * icmp message because icmp doesn't have a large enough repertoire
  * of codes and types.
  * an icmp packet.  Note we can't always generate a meaningful
  * icmp message because icmp doesn't have a large enough repertoire
  * of codes and types.
+ *
+ * If not forwarding (possibly because we have only a single external
+ * network), just drop the packet.  This could be confusing if ipforwarding
+ * was zero but some routing protocol was advancing us as a gateway
+ * to somewhere.  However, we must let the routing protocol deal with that.
  */
 ip_forward(ip, ifp)
        register struct ip *ip;
  */
 ip_forward(ip, ifp)
        register struct ip *ip;
@@ -819,19 +848,22 @@ ip_forward(ip, ifp)
        struct mbuf *mcopy;
        struct in_addr dest;
 
        struct mbuf *mcopy;
        struct in_addr dest;
 
-#ifdef lint
        dest.s_addr = 0;
        dest.s_addr = 0;
-#endif
        if (ipprintfs)
                printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
                        ip->ip_dst, ip->ip_ttl);
        ip->ip_id = htons(ip->ip_id);
        if (ipforwarding == 0 || in_interfaces <= 1) {
        if (ipprintfs)
                printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
                        ip->ip_dst, ip->ip_ttl);
        ip->ip_id = htons(ip->ip_id);
        if (ipforwarding == 0 || in_interfaces <= 1) {
-               /* can't tell difference between net and host */
+               ipstat.ips_cantforward++;
+#ifdef GATEWAY
                type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
                goto sendicmp;
                type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
                goto sendicmp;
+#else
+               m_freem(dtom(ip));
+               return;
+#endif
        }
        }
-       if (ip->ip_ttl < IPTTLDEC) {
+       if (ip->ip_ttl <= IPTTLDEC) {
                type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
                goto sendicmp;
        }
                type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
                goto sendicmp;
        }
@@ -841,7 +873,7 @@ ip_forward(ip, ifp)
         * Save at most 64 bytes of the packet in case
         * we need to generate an ICMP message to the src.
         */
         * Save at most 64 bytes of the packet in case
         * we need to generate an ICMP message to the src.
         */
-       mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64));
+       mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64));
 
        sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
        if (ipforward_rt.ro_rt == 0 ||
 
        sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
        if (ipforward_rt.ro_rt == 0 ||
@@ -860,11 +892,15 @@ ip_forward(ip, ifp)
         * perhaps should send a redirect to sender to shortcut a hop.
         * Only send redirect if source is sending directly to us,
         * and if packet was not source routed (or has any options).
         * perhaps should send a redirect to sender to shortcut a hop.
         * Only send redirect if source is sending directly to us,
         * and if packet was not source routed (or has any options).
+        * Also, don't send redirect if forwarding using a default route
+        * or a route modfied by a redirect.
         */
         */
+#define        satosin(sa)     ((struct sockaddr_in *)(sa))
        if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp &&
        if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp &&
+           (ipforward_rt.ro_rt->rt_flags & RTF_DYNAMIC) == 0 &&
+           satosin(&ipforward_rt.ro_rt->rt_dst)->sin_addr.s_addr != 0 &&
            ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) {
                struct in_ifaddr *ia;
            ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) {
                struct in_ifaddr *ia;
-               extern struct in_ifaddr *ifptoia();
                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);
 
@@ -876,9 +912,8 @@ ip_forward(ip, ifp)
                        dest = ip->ip_dst;
                    /*
                     * If the destination is reached by a route to host,
                        dest = ip->ip_dst;
                    /*
                     * If the destination is reached by a route to host,
-                    * is directly on the attached net (!),
-                    * or if the destination is on a subnet of a local net
-                    * not known to the source net, use host redirect.
+                    * 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.)
                     */
                    type = ICMP_REDIRECT;
                     * (We may be the correct first hop for other subnets.)
                     */
                    type = ICMP_REDIRECT;
@@ -888,8 +923,8 @@ ip_forward(ip, ifp)
                        code = ICMP_REDIRECT_HOST;
                    else for (ia = in_ifaddr; ia = ia->ia_next; )
                        if ((dst & ia->ia_netmask) == ia->ia_net) {
                        code = ICMP_REDIRECT_HOST;
                    else for (ia = in_ifaddr; ia = ia->ia_next; )
                        if ((dst & ia->ia_netmask) == ia->ia_net) {
-                           if ((src & ia->ia_netmask) != ia->ia_net)
-                               code = ICMP_REDIRECT_HOST;
+                           if (ia->ia_subnetmask != ia->ia_netmask)
+                                   code = ICMP_REDIRECT_HOST;
                            break;
                        }
                    if (ipprintfs)
                            break;
                        }
                    if (ipprintfs)
@@ -922,7 +957,10 @@ ip_forward(ip, ifp)
 
        case ENETUNREACH:
        case ENETDOWN:
 
        case ENETUNREACH:
        case ENETDOWN:
-               code = ICMP_UNREACH_NET;
+               if (in_localaddr(ip->ip_dst))
+                       code = ICMP_UNREACH_HOST;
+               else
+                       code = ICMP_UNREACH_NET;
                break;
 
        case EMSGSIZE:
                break;
 
        case EMSGSIZE: