add crontab entry
[unix-history] / usr / src / sys / netinet / ip_input.c
index 53f47f8..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.23 (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();
 
 /*
@@ -593,14 +615,14 @@ 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((caddr_t)(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;
                        }
                        bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
                                goto bad;
                        }
                        bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
@@ -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);
                }
        }
@@ -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;
 
        /*
@@ -839,7 +863,7 @@ ip_forward(ip, ifp)
                return;
 #endif
        }
                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;
        }
@@ -868,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);
 
@@ -929,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: