fix autoconf, move code to isa.c, remove debugging, drop redundant tlbflushes, macros...
[unix-history] / usr / src / sys / netinet / ip_output.c
index 5d03bc2..3177ef0 100644 (file)
@@ -1,20 +1,10 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1988, 1990 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_output.c 7.15 (Berkeley) %G%
+ *     @(#)ip_output.c 7.23 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #include "../net/route.h"
 
 #include "in.h"
 #include "../net/route.h"
 
 #include "in.h"
-#include "in_pcb.h"
 #include "in_systm.h"
 #include "in_systm.h"
-#include "in_var.h"
 #include "ip.h"
 #include "ip.h"
+#include "in_pcb.h"
+#include "in_var.h"
 #include "ip_var.h"
 
 #ifdef vax
 #include "ip_var.h"
 
 #ifdef vax
@@ -60,9 +50,12 @@ ip_output(m0, opt, ro, flags)
        int len, off, error = 0;
        struct route iproute;
        struct sockaddr_in *dst;
        int len, off, error = 0;
        struct route iproute;
        struct sockaddr_in *dst;
+       struct in_ifaddr *ia;
 
 
-if ((m->m_flags & M_PKTHDR) == 0)
-panic("ip_output no HDR");
+#ifdef DIAGNOSTIC
+       if ((m->m_flags & M_PKTHDR) == 0)
+               panic("ip_output no HDR");
+#endif
        if (opt) {
                m = ip_insertoptions(m, opt, &len);
                hlen = len;
        if (opt) {
                m = ip_insertoptions(m, opt, &len);
                hlen = len;
@@ -76,9 +69,10 @@ panic("ip_output no HDR");
                ip->ip_off &= IP_DF;
                ip->ip_id = htons(ip_id++);
                ip->ip_hl = hlen >> 2;
                ip->ip_off &= IP_DF;
                ip->ip_id = htons(ip_id++);
                ip->ip_hl = hlen >> 2;
-       } else
+       } else {
                hlen = ip->ip_hl << 2;
                hlen = ip->ip_hl << 2;
-
+               ipstat.ips_localout++;
+       }
        /*
         * Route packet.
         */
        /*
         * Route packet.
         */
@@ -107,7 +101,6 @@ panic("ip_output no HDR");
         * short circuit routing lookup.
         */
        if (flags & IP_ROUTETOIF) {
         * short circuit routing lookup.
         */
        if (flags & IP_ROUTETOIF) {
-               struct in_ifaddr *ia;
 
                ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
                if (ia == 0)
 
                ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
                if (ia == 0)
@@ -120,13 +113,12 @@ panic("ip_output no HDR");
        } else {
                if (ro->ro_rt == 0)
                        rtalloc(ro);
        } else {
                if (ro->ro_rt == 0)
                        rtalloc(ro);
-               if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
-                       if (in_localaddr(ip->ip_dst))
-                               error = EHOSTUNREACH;
-                       else
-                               error = ENETUNREACH;
+               if (ro->ro_rt == 0) {
+                       error = EHOSTUNREACH;
                        goto bad;
                }
                        goto bad;
                }
+               ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa;
+               ifp = ro->ro_rt->rt_ifp;
                ro->ro_rt->rt_use++;
                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
                ro->ro_rt->rt_use++;
                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
@@ -136,15 +128,8 @@ panic("ip_output no HDR");
         * If source address not specified yet, use address
         * of outgoing interface.
         */
         * If source address not specified yet, use address
         * of outgoing interface.
         */
-       if (ip->ip_src.s_addr == INADDR_ANY) {
-               register struct in_ifaddr *ia;
-
-               for (ia = in_ifaddr; ia; ia = ia->ia_next)
-                       if (ia->ia_ifp == ifp) {
-                               ip->ip_src = IA_SIN(ia)->sin_addr;
-                               break;
-                       }
-       }
+       if (ip->ip_src.s_addr == INADDR_ANY)
+               ip->ip_src = IA_SIN(ia)->sin_addr;
 #endif
        /*
         * Look for broadcast address and
 #endif
        /*
         * Look for broadcast address and
@@ -161,7 +146,7 @@ panic("ip_output no HDR");
                        goto bad;
                }
                /* don't allow broadcast messages to be fragmented */
                        goto bad;
                }
                /* don't allow broadcast messages to be fragmented */
-               if (ip->ip_len > ifp->if_mtu) {
+               if ((u_short)ip->ip_len > ifp->if_mtu) {
                        error = EMSGSIZE;
                        goto bad;
                }
                        error = EMSGSIZE;
                        goto bad;
                }
@@ -171,15 +156,16 @@ panic("ip_output no HDR");
        /*
         * If small enough for interface, can just send directly.
         */
        /*
         * If small enough for interface, can just send directly.
         */
-       if (ip->ip_len <= ifp->if_mtu) {
+       if ((u_short)ip->ip_len <= ifp->if_mtu) {
                ip->ip_len = htons((u_short)ip->ip_len);
                ip->ip_off = htons((u_short)ip->ip_off);
                ip->ip_sum = 0;
                ip->ip_sum = in_cksum(m, hlen);
                ip->ip_len = htons((u_short)ip->ip_len);
                ip->ip_off = htons((u_short)ip->ip_off);
                ip->ip_sum = 0;
                ip->ip_sum = in_cksum(m, hlen);
-               error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
+               error = (*ifp->if_output)(ifp, m,
+                               (struct sockaddr *)dst, ro->ro_rt);
                goto done;
        }
                goto done;
        }
-
+       ipstat.ips_fragmented++;
        /*
         * Too large for interface; fragment if possible.
         * Must be able to put at least 8 bytes per fragment.
        /*
         * Too large for interface; fragment if possible.
         * Must be able to put at least 8 bytes per fragment.
@@ -204,7 +190,7 @@ panic("ip_output no HDR");
         */
        m0 = m;
        mhlen = sizeof (struct ip);
         */
        m0 = m;
        mhlen = sizeof (struct ip);
-       for (off = hlen + len; off < ip->ip_len; off += len) {
+       for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
                MGETHDR(m, M_DONTWAIT, MT_HEADER);
                if (m == 0) {
                        error = ENOBUFS;
                MGETHDR(m, M_DONTWAIT, MT_HEADER);
                if (m == 0) {
                        error = ENOBUFS;
@@ -221,8 +207,8 @@ panic("ip_output no HDR");
                mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
                if (ip->ip_off & IP_MF)
                        mhip->ip_off |= IP_MF;
                mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
                if (ip->ip_off & IP_MF)
                        mhip->ip_off |= IP_MF;
-               if (off + len >= ip->ip_len)
-                       len = ip->ip_len - off;
+               if (off + len >= (u_short)ip->ip_len)
+                       len = (u_short)ip->ip_len - off;
                else
                        mhip->ip_off |= IP_MF;
                mhip->ip_len = htons((u_short)(len + mhlen));
                else
                        mhip->ip_off |= IP_MF;
                mhip->ip_len = htons((u_short)(len + mhlen));
@@ -238,24 +224,26 @@ panic("ip_output no HDR");
                mhip->ip_sum = in_cksum(m, mhlen);
                *mnext = m;
                mnext = &m->m_nextpkt;
                mhip->ip_sum = in_cksum(m, mhlen);
                *mnext = m;
                mnext = &m->m_nextpkt;
+               ipstat.ips_ofragments++;
        }
        /*
         * Update first fragment by trimming what's been copied out
         * and updating header, then send each fragment (in order).
         */
        }
        /*
         * Update first fragment by trimming what's been copied out
         * and updating header, then send each fragment (in order).
         */
-       m_adj(m0, hlen + firstlen - ip->ip_len);
+       m = m0;
+       m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
        m->m_pkthdr.len = hlen + firstlen;
        ip->ip_len = htons((u_short)m->m_pkthdr.len);
        ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
        ip->ip_sum = 0;
        m->m_pkthdr.len = hlen + firstlen;
        ip->ip_len = htons((u_short)m->m_pkthdr.len);
        ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
        ip->ip_sum = 0;
-       ip->ip_sum = in_cksum(m0, hlen);
+       ip->ip_sum = in_cksum(m, hlen);
 sendorfree:
        for (m = m0; m; m = m0) {
                m0 = m->m_nextpkt;
                m->m_nextpkt = 0;
                if (error == 0)
                        error = (*ifp->if_output)(ifp, m,
 sendorfree:
        for (m = m0; m; m = m0) {
                m0 = m->m_nextpkt;
                m->m_nextpkt = 0;
                if (error == 0)
                        error = (*ifp->if_output)(ifp, m,
-                           (struct sockaddr *)dst);
+                           (struct sockaddr *)dst, ro->ro_rt);
                else
                        m_freem(m);
        }
                else
                        m_freem(m);
        }
@@ -286,6 +274,8 @@ ip_insertoptions(m, opt, phlen)
        unsigned optlen;
 
        optlen = opt->m_len - sizeof(p->ipopt_dst);
        unsigned optlen;
 
        optlen = opt->m_len - sizeof(p->ipopt_dst);
+       if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
+               return (m);             /* XXX should fail */
        if (p->ipopt_dst.s_addr)
                ip->ip_dst = p->ipopt_dst;
        if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
        if (p->ipopt_dst.s_addr)
                ip->ip_dst = p->ipopt_dst;
        if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
@@ -350,14 +340,16 @@ ip_optcopy(ip, jp)
 /*
  * IP socket option processing.
  */
 /*
  * IP socket option processing.
  */
-ip_ctloutput(op, so, level, optname, m)
+ip_ctloutput(op, so, level, optname, mp)
        int op;
        struct socket *so;
        int level, optname;
        int op;
        struct socket *so;
        int level, optname;
-       struct mbuf **m;
+       struct mbuf **mp;
 {
 {
+       register struct inpcb *inp = sotoinpcb(so);
+       register struct mbuf *m = *mp;
+       register int optval;
        int error = 0;
        int error = 0;
-       struct inpcb *inp = sotoinpcb(so);
 
        if (level != IPPROTO_IP)
                error = EINVAL;
 
        if (level != IPPROTO_IP)
                error = EINVAL;
@@ -366,33 +358,114 @@ ip_ctloutput(op, so, level, optname, m)
        case PRCO_SETOPT:
                switch (optname) {
                case IP_OPTIONS:
        case PRCO_SETOPT:
                switch (optname) {
                case IP_OPTIONS:
-                       return (ip_pcbopts(&inp->inp_options, *m));
+#ifdef notyet
+               case IP_RETOPTS:
+                       return (ip_pcbopts(optname, &inp->inp_options, m));
+#else
+                       return (ip_pcbopts(&inp->inp_options, m));
+#endif
+
+               case IP_TOS:
+               case IP_TTL:
+               case IP_RECVOPTS:
+               case IP_RECVRETOPTS:
+               case IP_RECVDSTADDR:
+                       if (m->m_len != sizeof(int))
+                               error = EINVAL;
+                       else {
+                               optval = *mtod(m, int *);
+                               switch (optname) {
+
+                               case IP_TOS:
+                                       inp->inp_ip.ip_tos = optval;
+                                       break;
+
+                               case IP_TTL:
+                                       inp->inp_ip.ip_ttl = optval;
+                                       break;
+#define        OPTSET(bit) \
+       if (optval) \
+               inp->inp_flags |= bit; \
+       else \
+               inp->inp_flags &= ~bit;
+
+                               case IP_RECVOPTS:
+                                       OPTSET(INP_RECVOPTS);
+                                       break;
+
+                               case IP_RECVRETOPTS:
+                                       OPTSET(INP_RECVRETOPTS);
+                                       break;
+
+                               case IP_RECVDSTADDR:
+                                       OPTSET(INP_RECVDSTADDR);
+                                       break;
+                               }
+                       }
+                       break;
+#undef OPTSET
 
                default:
                        error = EINVAL;
                        break;
                }
 
                default:
                        error = EINVAL;
                        break;
                }
+               if (m)
+                       (void)m_free(m);
                break;
 
        case PRCO_GETOPT:
                switch (optname) {
                case IP_OPTIONS:
                break;
 
        case PRCO_GETOPT:
                switch (optname) {
                case IP_OPTIONS:
-                       *m = m_get(M_WAIT, MT_SOOPTS);
+               case IP_RETOPTS:
+                       *mp = m = m_get(M_WAIT, MT_SOOPTS);
                        if (inp->inp_options) {
                        if (inp->inp_options) {
-                               (*m)->m_len = inp->inp_options->m_len;
+                               m->m_len = inp->inp_options->m_len;
                                bcopy(mtod(inp->inp_options, caddr_t),
                                bcopy(mtod(inp->inp_options, caddr_t),
-                                   mtod(*m, caddr_t), (unsigned)(*m)->m_len);
+                                   mtod(m, caddr_t), (unsigned)m->m_len);
                        } else
                        } else
-                               (*m)->m_len = 0;
+                               m->m_len = 0;
+                       break;
+
+               case IP_TOS:
+               case IP_TTL:
+               case IP_RECVOPTS:
+               case IP_RECVRETOPTS:
+               case IP_RECVDSTADDR:
+                       *mp = m = m_get(M_WAIT, MT_SOOPTS);
+                       m->m_len = sizeof(int);
+                       switch (optname) {
+
+                       case IP_TOS:
+                               optval = inp->inp_ip.ip_tos;
+                               break;
+
+                       case IP_TTL:
+                               optval = inp->inp_ip.ip_ttl;
+                               break;
+
+#define        OPTBIT(bit)     (inp->inp_flags & bit ? 1 : 0)
+
+                       case IP_RECVOPTS:
+                               optval = OPTBIT(INP_RECVOPTS);
+                               break;
+
+                       case IP_RECVRETOPTS:
+                               optval = OPTBIT(INP_RECVRETOPTS);
+                               break;
+
+                       case IP_RECVDSTADDR:
+                               optval = OPTBIT(INP_RECVDSTADDR);
+                               break;
+                       }
+                       *mtod(m, int *) = optval;
                        break;
                        break;
+
                default:
                        error = EINVAL;
                        break;
                }
                break;
        }
                default:
                        error = EINVAL;
                        break;
                }
                break;
        }
-       if (op == PRCO_SETOPT && *m)
-               (void)m_free(*m);
        return (error);
 }
 
        return (error);
 }
 
@@ -401,7 +474,12 @@ ip_ctloutput(op, so, level, optname, m)
  * Store in mbuf with pointer in pcbopt, adding pseudo-option
  * with destination address if source routed.
  */
  * Store in mbuf with pointer in pcbopt, adding pseudo-option
  * with destination address if source routed.
  */
+#ifdef notyet
+ip_pcbopts(optname, pcbopt, m)
+       int optname;
+#else
 ip_pcbopts(pcbopt, m)
 ip_pcbopts(pcbopt, m)
+#endif
        struct mbuf **pcbopt;
        register struct mbuf *m;
 {
        struct mbuf **pcbopt;
        register struct mbuf *m;
 {