BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / net / rtsock.c
index fb61882..a64719b 100644 (file)
@@ -1,21 +1,45 @@
 /*
 /*
- * Copyright (c) 1988 Regents of the University of California.
+ * Copyright (c) 1988, 1991 Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
  *
- *     @(#)rtsock.c    7.14 (Berkeley) %G%
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)rtsock.c    7.18 (Berkeley) 6/27/91
  */
 
 #include "param.h"
 #include "mbuf.h"
  */
 
 #include "param.h"
 #include "mbuf.h"
-#include "user.h"
 #include "proc.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "domain.h"
 #include "protosw.h"
 #include "proc.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "domain.h"
 #include "protosw.h"
-#include "errno.h"
 
 #include "af.h"
 #include "if.h"
 
 #include "af.h"
 #include "if.h"
@@ -77,8 +101,9 @@ route_usrreq(so, req, m, nam, control)
        splx(s);
        return (error);
 }
        splx(s);
        return (error);
 }
-#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
-#define ADVANCE(x, n) (x += ((n) > 0 ? ROUNDUP(n) : sizeof(long)))
+#define ROUNDUP(a) \
+       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
 
 /*ARGSUSED*/
 route_output(m, so)
 
 /*ARGSUSED*/
 route_output(m, so)
@@ -89,12 +114,12 @@ route_output(m, so)
        register struct rtentry *rt = 0;
        struct rtentry *saved_nrt = 0;
        struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0;
        register struct rtentry *rt = 0;
        struct rtentry *saved_nrt = 0;
        struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0;
-       struct sockaddr *ifpaddr = 0;
+       struct sockaddr *ifpaddr = 0, *ifaaddr = 0;
        caddr_t cp, lim;
        int len, error = 0;
        struct ifnet *ifp = 0;
        caddr_t cp, lim;
        int len, error = 0;
        struct ifnet *ifp = 0;
-       struct  ifaddr *ifa;
-       extern struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute();
+       struct ifaddr *ifa = 0;
+       struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute();
 
 #define senderr(e) { error = e; goto flush;}
        if (m == 0 || m->m_len < sizeof(long))
 
 #define senderr(e) { error = e; goto flush;}
        if (m == 0 || m->m_len < sizeof(long))
@@ -113,26 +138,26 @@ route_output(m, so)
        m_copydata(m, 0, len, (caddr_t)rtm);
        if (rtm->rtm_version != RTM_VERSION)
                senderr(EPROTONOSUPPORT);
        m_copydata(m, 0, len, (caddr_t)rtm);
        if (rtm->rtm_version != RTM_VERSION)
                senderr(EPROTONOSUPPORT);
-       rtm->rtm_pid = u.u_procp->p_pid;
+       rtm->rtm_pid = curproc->p_pid;
        lim = len + (caddr_t) rtm;
        cp = (caddr_t) (rtm + 1);
        if (rtm->rtm_addrs & RTA_DST) {
                dst = (struct sockaddr *)cp;
        lim = len + (caddr_t) rtm;
        cp = (caddr_t) (rtm + 1);
        if (rtm->rtm_addrs & RTA_DST) {
                dst = (struct sockaddr *)cp;
-               ADVANCE(cp, dst->sa_len);
+               ADVANCE(cp, dst);
        } else
                senderr(EINVAL);
        if ((rtm->rtm_addrs & RTA_GATEWAY) && cp < lim)  {
                gate = (struct sockaddr *)cp;
        } else
                senderr(EINVAL);
        if ((rtm->rtm_addrs & RTA_GATEWAY) && cp < lim)  {
                gate = (struct sockaddr *)cp;
-               cp += ROUNDUP(gate->sa_len);
+               ADVANCE(cp, gate);
        }
        if ((rtm->rtm_addrs & RTA_NETMASK) && cp < lim)  {
                netmask = (struct sockaddr *)cp;
        }
        if ((rtm->rtm_addrs & RTA_NETMASK) && cp < lim)  {
                netmask = (struct sockaddr *)cp;
-               ADVANCE(cp, netmask->sa_len);
+               ADVANCE(cp, netmask);
        }
        if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim)  {
                struct radix_node *t, *rn_addmask();
                genmask = (struct sockaddr *)cp;
        }
        if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim)  {
                struct radix_node *t, *rn_addmask();
                genmask = (struct sockaddr *)cp;
-               ADVANCE(cp, genmask->sa_len);
+               ADVANCE(cp, genmask);
                t = rn_addmask(genmask, 1, 2);
                if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
                        genmask = (struct sockaddr *)(t->rn_key);
                t = rn_addmask(genmask, 1, 2);
                if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
                        genmask = (struct sockaddr *)(t->rn_key);
@@ -141,6 +166,10 @@ route_output(m, so)
        }
        if ((rtm->rtm_addrs & RTA_IFP) && cp < lim)  {
                ifpaddr = (struct sockaddr *)cp;
        }
        if ((rtm->rtm_addrs & RTA_IFP) && cp < lim)  {
                ifpaddr = (struct sockaddr *)cp;
+               ADVANCE(cp, ifpaddr);
+       }
+       if ((rtm->rtm_addrs & RTA_IFA) && cp < lim)  {
+               ifaaddr = (struct sockaddr *)cp;
        }
        switch (rtm->rtm_type) {
        case RTM_ADD:
        }
        switch (rtm->rtm_type) {
        case RTM_ADD:
@@ -167,32 +196,52 @@ route_output(m, so)
                rt = rtalloc1(dst, 0);
                if (rt == 0)
                        senderr(ESRCH);
                rt = rtalloc1(dst, 0);
                if (rt == 0)
                        senderr(ESRCH);
-               if (((struct radix_node *)rt)->rn_dupedkey) {
-                       if (netmask == 0 && rtm->rtm_type != RTM_GET)
+               if (rtm->rtm_type != RTM_GET) {
+                       if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0)
+                               senderr(ESRCH);
+                       if (rt->rt_nodes->rn_dupedkey &&
+                           (netmask == 0 ||
+                            Bcmp(netmask, rt_mask(rt), netmask->sa_len)))
                                senderr(ETOOMANYREFS);
                }
                switch(rtm->rtm_type) {
 
                case RTM_GET:
                                senderr(ETOOMANYREFS);
                }
                switch(rtm->rtm_type) {
 
                case RTM_GET:
-                       dst = rt_key(rt);
-                       len = sizeof(*rtm) + (dst->sa_len > 0 ?
-                               ROUNDUP(dst->sa_len) : sizeof(long));
+                       dst = rt_key(rt); len = sizeof(*rtm);
+                       ADVANCE(len, dst);
                        rtm->rtm_addrs |= RTA_DST;
                        if (gate = rt->rt_gateway) {
                        rtm->rtm_addrs |= RTA_DST;
                        if (gate = rt->rt_gateway) {
-                               len += ROUNDUP(rt->rt_gateway->sa_len);
+                               ADVANCE(len, gate);
                                rtm->rtm_addrs |= RTA_GATEWAY;
                        } else
                                rtm->rtm_addrs &= ~RTA_GATEWAY;
                        if (netmask = rt_mask(rt)) {
                                rtm->rtm_addrs |= RTA_GATEWAY;
                        } else
                                rtm->rtm_addrs &= ~RTA_GATEWAY;
                        if (netmask = rt_mask(rt)) {
-                               len += netmask->sa_len;
+                               ADVANCE(len, netmask);
                                rtm->rtm_addrs |= RTA_NETMASK;
                        } else
                                rtm->rtm_addrs &= ~RTA_NETMASK;
                                rtm->rtm_addrs |= RTA_NETMASK;
                        } else
                                rtm->rtm_addrs &= ~RTA_NETMASK;
-                       if (rt->rt_genmask) {
-                               len += ROUNDUP(rt->rt_genmask->sa_len);
+                       if (genmask = rt->rt_genmask) {
+                               ADVANCE(len, genmask);
                                rtm->rtm_addrs |= RTA_GENMASK;
                        } else
                                rtm->rtm_addrs &= ~RTA_GENMASK;
                                rtm->rtm_addrs |= RTA_GENMASK;
                        } else
                                rtm->rtm_addrs &= ~RTA_GENMASK;
+                       if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
+                               if (rt->rt_ifp == 0)
+                                       goto badif;
+                               for (ifa = rt->rt_ifp->if_addrlist;
+                                   ifa && ifa->ifa_addr->sa_family != AF_LINK;
+                                    ifa = ifa->ifa_next){}
+                               if (ifa && rt->rt_ifa) {
+                                       ifpaddr = ifa->ifa_addr;
+                                       ADVANCE(len, ifpaddr);
+                                       ifaaddr = rt->rt_ifa->ifa_addr;
+                                       ADVANCE(len, ifaaddr);
+                                       rtm->rtm_addrs |= RTA_IFP | RTA_IFA;
+                               } else {
+                               badif:  ifpaddr = 0;
+                                       rtm->rtm_addrs &= ~(RTA_IFP | RTA_IFA);
+                               }
+                       }
                        if (len > rtm->rtm_msglen) {
                                struct rt_msghdr *new_rtm;
                                R_Malloc(new_rtm, struct rt_msghdr *, len);
                        if (len > rtm->rtm_msglen) {
                                struct rt_msghdr *new_rtm;
                                R_Malloc(new_rtm, struct rt_msghdr *, len);
@@ -205,19 +254,25 @@ route_output(m, so)
                        rtm->rtm_flags = rt->rt_flags;
                        rtm->rtm_rmx = rt->rt_rmx;
                        cp = (caddr_t) (1 + rtm);
                        rtm->rtm_flags = rt->rt_flags;
                        rtm->rtm_rmx = rt->rt_rmx;
                        cp = (caddr_t) (1 + rtm);
-                       Bcopy(dst, cp, dst->sa_len);
-                       ADVANCE(cp, dst->sa_len);
+                       len = ROUNDUP(dst->sa_len); 
+                       Bcopy(dst, cp, len); cp += len;
                        if (gate) {
                        if (gate) {
-                           Bcopy(gate, cp, gate->sa_len);
-                           ADVANCE(cp, gate->sa_len);
+                           len = ROUNDUP(gate->sa_len);
+                           Bcopy(gate, cp, len); cp += len;
                        }
                        if (netmask) {
                        }
                        if (netmask) {
-                           Bcopy(netmask, cp, netmask->sa_len);
-                           ADVANCE(cp, netmask->sa_len);
+                           len = ROUNDUP(netmask->sa_len);
+                           Bcopy(netmask, cp, len); cp += len;
                        }
                        }
-                       if (rt->rt_genmask) {
-                           Bcopy(rt->rt_genmask, cp, rt->rt_genmask->sa_len);
-                           ADVANCE(cp, rt->rt_genmask->sa_len);
+                       if (genmask) {
+                           len = ROUNDUP(genmask->sa_len);
+                           Bcopy(genmask, cp, len); cp += len;
+                       }
+                       if (ifpaddr) {
+                           len = ROUNDUP(ifpaddr->sa_len);
+                           Bcopy(ifpaddr, cp, len); cp += len;
+                           len = ROUNDUP(ifaaddr->sa_len);
+                           Bcopy(ifaaddr, cp, len); cp += len;
                        }
                        break;
 
                        }
                        break;
 
@@ -225,32 +280,31 @@ route_output(m, so)
                        if (gate &&
                            (gate->sa_len > (len = rt->rt_gateway->sa_len)))
                                senderr(EDQUOT);
                        if (gate &&
                            (gate->sa_len > (len = rt->rt_gateway->sa_len)))
                                senderr(EDQUOT);
-                       if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
-                               rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, gate);
                        /* new gateway could require new ifaddr, ifp;
                           flags may also be different; ifp may be specified
                           by ll sockaddr when protocol address is ambiguous */
                        /* new gateway could require new ifaddr, ifp;
                           flags may also be different; ifp may be specified
                           by ll sockaddr when protocol address is ambiguous */
-                       if (ifpaddr &&
-                           (ifa = ifa_ifwithnet(ifpaddr)) &&
-                           (ifp = ifa->ifa_ifp) &&
-                           (ifa = ifaof_ifpforaddr(gate, ifp))) {
-                                    /* We got it */
-                       } else {
-                           ifa = 0; ifp = 0;
-                       }
-                       if (gate)
-                               Bcopy(gate, rt->rt_gateway, len);
-                       rt_setmetrics(rtm->rtm_inits,
-                               &rtm->rtm_rmx, &rt->rt_rmx);
-                       if (ifa == 0)
-                           ifa = ifa_ifwithroute(rt->rt_flags, rt_key(rt),
-                                               gate);
+                       if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
+                           (ifp = ifa->ifa_ifp))
+                               ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
+                                                       ifp);
+                       else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
+                                (ifa = ifa_ifwithroute(rt->rt_flags,
+                                                       rt_key(rt), gate)))
+                               ifp = ifa->ifa_ifp;
                        if (ifa) {
                        if (ifa) {
-                               if (rt->rt_ifa != ifa) {
+                               register struct ifaddr *oifa = rt->rt_ifa;
+                               if (oifa != ifa) {
+                                   if (oifa && oifa->ifa_rtrequest)
+                                       oifa->ifa_rtrequest(RTM_DELETE,
+                                                               rt, gate);
                                    rt->rt_ifa = ifa;
                                    rt->rt_ifa = ifa;
-                                   rt->rt_ifp = ifa->ifa_ifp;
+                                   rt->rt_ifp = ifp;
                                }
                        }
                                }
                        }
+                       if (gate)
+                               Bcopy(gate, rt->rt_gateway, len);
+                       rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
+                                       &rt->rt_rmx);
                        if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
                               rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
                        if (genmask)
                        if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
                               rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
                        if (genmask)
@@ -295,8 +349,8 @@ cleanup:
                /* There is another listener, so construct message */
                rp = sotorawcb(so);
        }
                /* There is another listener, so construct message */
                rp = sotorawcb(so);
        }
-       if (cp = (caddr_t)rtm) {
-               m_copyback(m, 0, len, cp);
+       if (rtm) {
+               m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
                Free(rtm);
        }
        if (rp)
                Free(rtm);
        }
        if (rp)
@@ -322,6 +376,7 @@ rt_setmetrics(which, in, out)
        metric(RTV_RTTVAR, rmx_rttvar);
        metric(RTV_HOPCOUNT, rmx_hopcount);
        metric(RTV_MTU, rmx_mtu);
        metric(RTV_RTTVAR, rmx_rttvar);
        metric(RTV_HOPCOUNT, rmx_hopcount);
        metric(RTV_MTU, rmx_mtu);
+       metric(RTV_EXPIRE, rmx_expire);
 #undef metric
 }
 
 #undef metric
 }
 
@@ -343,7 +398,7 @@ m_copyback(m0, off, len, cp)
 
        if (m0 == 0)
                return;
 
        if (m0 == 0)
                return;
-       while (off >= (mlen = m->m_len)) {
+       while (off > (mlen = m->m_len)) {
                off -= mlen;
                totlen += mlen;
                if (m->m_next == 0) {
                off -= mlen;
                totlen += mlen;
                if (m->m_next == 0) {
@@ -406,7 +461,7 @@ struct sockaddr *gate, *mask, *src;
        rtm->rtm_type = type;
        rtm->rtm_addrs = RTA_DST;
        if (type == RTM_OLDADD || type == RTM_OLDDEL) {
        rtm->rtm_type = type;
        rtm->rtm_addrs = RTA_DST;
        if (type == RTM_OLDADD || type == RTM_OLDDEL) {
-               rtm->rtm_pid = u.u_procp->p_pid;
+               rtm->rtm_pid = curproc->p_pid;
        }
        m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst);
        if (gate) {
        }
        m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst);
        if (gate) {
@@ -416,10 +471,7 @@ struct sockaddr *gate, *mask, *src;
                rtm->rtm_addrs |= RTA_GATEWAY;
        }
        if (mask) {
                rtm->rtm_addrs |= RTA_GATEWAY;
        }
        if (mask) {
-               if (mask->sa_len)
-                       dlen = ROUNDUP(mask->sa_len);
-               else
-                       dlen = sizeof(long);
+               dlen = ROUNDUP(mask->sa_len);
                m_copyback(m, len ,  dlen, (caddr_t)mask);
                len += dlen;
                rtm->rtm_addrs |= RTA_NETMASK;
                m_copyback(m, len ,  dlen, (caddr_t)mask);
                len += dlen;
                rtm->rtm_addrs |= RTA_NETMASK;
@@ -476,8 +528,7 @@ rt_dumpentry(rn, w)
        if (sa = rt->rt_gateway)
                next(RTA_GATEWAY, ROUNDUP(sa->sa_len));
        if (sa = rt_mask(rt))
        if (sa = rt->rt_gateway)
                next(RTA_GATEWAY, ROUNDUP(sa->sa_len));
        if (sa = rt_mask(rt))
-               next(RTA_NETMASK,
-                       sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long));
+               next(RTA_NETMASK, ROUNDUP(sa->sa_len));
        if (sa = rt->rt_genmask)
                next(RTA_GENMASK, ROUNDUP(sa->sa_len));
        w->w_needed += size;
        if (sa = rt->rt_genmask)
                next(RTA_GENMASK, ROUNDUP(sa->sa_len));
        w->w_needed += size;
@@ -497,7 +548,7 @@ rt_dumpentry(rn, w)
                if (sa = rt->rt_gateway)
                        next(ROUNDUP(sa->sa_len));
                if (sa = rt_mask(rt))
                if (sa = rt->rt_gateway)
                        next(ROUNDUP(sa->sa_len));
                if (sa = rt_mask(rt))
-                       next(sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long));
+                       next(ROUNDUP(sa->sa_len));
                if (sa = rt->rt_genmask)
                        next(ROUNDUP(sa->sa_len));
 #undef next
                if (sa = rt->rt_genmask)
                        next(ROUNDUP(sa->sa_len));
 #undef next
@@ -514,7 +565,7 @@ rt_dumpentry(rn, w)
        if (sa = rt->rt_gateway)
                next(sa, ROUNDUP(sa->sa_len));
        if (sa = rt_mask(rt))
        if (sa = rt->rt_gateway)
                next(sa, ROUNDUP(sa->sa_len));
        if (sa = rt_mask(rt))
-               next(sa, sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long));
+               next(sa, ROUNDUP(sa->sa_len));
        if (sa = rt->rt_genmask)
                next(sa, ROUNDUP(sa->sa_len));
     }
        if (sa = rt->rt_genmask)
                next(sa, ROUNDUP(sa->sa_len));
     }