/*
- * Copyright (c) 1988 Regents of the University of California.
+ * Copyright (c) 1988, 1991 Regents of the University of California.
* 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.
+ * 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.8 (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 "user.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 "machine/mtpr.h"
-struct sockaddr route_dst = { 0, PF_ROUTE, };
-struct sockaddr route_src = { 0, PF_ROUTE, };
+struct sockaddr route_dst = { 2, PF_ROUTE, };
+struct sockaddr route_src = { 2, PF_ROUTE, };
struct sockproto route_proto = { PF_ROUTE, };
/*ARGSUSED*/
{
register int error = 0;
register struct rawcb *rp = sotorawcb(so);
+ int s;
if (req == PRU_ATTACH) {
MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
if (so->so_pcb = (caddr_t)rp)
route_cb.iso_count--;
route_cb.any_count--;
}
+ s = splnet();
error = raw_usrreq(so, req, m, nam, control);
rp = sotorawcb(so);
if (req == PRU_ATTACH && rp) {
int af = rp->rcb_proto.sp_protocol;
if (error) {
free((caddr_t)rp, M_PCB);
+ splx(s);
return (error);
}
if (af == AF_INET)
rp->rcb_faddr = &route_src;
route_cb.any_count++;
soisconnected(so);
+ so->so_options |= SO_USELOOPBACK;
}
+ splx(s);
return (error);
}
-#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
+#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)
register struct rtentry *rt = 0;
struct rtentry *saved_nrt = 0;
struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0;
+ struct sockaddr *ifpaddr = 0, *ifaaddr = 0;
caddr_t cp, lim;
int len, error = 0;
+ struct ifnet *ifp = 0;
+ 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))
if ((m->m_flags & M_PKTHDR) == 0)
panic("route_output");
len = m->m_pkthdr.len;
- rtm = mtod(m, struct rt_msghdr *);
- if (len < rtm->rtm_msglen)
+ if (len < sizeof(*rtm) ||
+ len != mtod(m, struct rt_msghdr *)->rtm_msglen)
senderr(EINVAL);
R_Malloc(rtm, struct rt_msghdr *, len);
if (rtm == 0)
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;
- cp += ROUNDUP(dst->sa_len);
+ ADVANCE(cp, dst);
} 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 (*cp)
- cp += ROUNDUP(netmask->sa_len);
- else
- cp += sizeof(long);
-
+ ADVANCE(cp, netmask);
}
if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim) {
+ struct radix_node *t, *rn_addmask();
genmask = (struct sockaddr *)cp;
+ 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);
+ else
+ senderr(ENOBUFS);
+ }
+ 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:
rt_setmetrics(rtm->rtm_inits,
&rtm->rtm_rmx, &saved_nrt->rt_rmx);
saved_nrt->rt_refcnt--;
+ saved_nrt->rt_genmask = genmask;
}
break;
rt = rtalloc1(dst, 0);
if (rt == 0)
senderr(ESRCH);
+ 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) {
- struct sockaddr *outmask;
case RTM_GET:
- netmask = rt_mask(rt);
- len = sizeof(*rtm) + ROUNDUP(rt_key(rt)->sa_len);
- rtm->rtm_addrs = RTA_DST;
- if (rt->rt_gateway) {
- len += ROUNDUP(rt->rt_gateway->sa_len);
+ dst = rt_key(rt); len = sizeof(*rtm);
+ ADVANCE(len, dst);
+ rtm->rtm_addrs |= RTA_DST;
+ if (gate = rt->rt_gateway) {
+ ADVANCE(len, gate);
rtm->rtm_addrs |= RTA_GATEWAY;
- }
- if (netmask) {
- len += netmask->sa_len;
+ } else
+ rtm->rtm_addrs &= ~RTA_GATEWAY;
+ if (netmask = rt_mask(rt)) {
+ ADVANCE(len, netmask);
rtm->rtm_addrs |= RTA_NETMASK;
+ } else
+ rtm->rtm_addrs &= ~RTA_NETMASK;
+ if (genmask = rt->rt_genmask) {
+ ADVANCE(len, 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;
senderr(ENOBUFS);
Bcopy(rtm, new_rtm, rtm->rtm_msglen);
Free(rtm); rtm = new_rtm;
- gate = (struct sockaddr *)
- (ROUNDUP(rt->rt_gateway->sa_len)
- + (char *)dst);
- Bcopy(&rt->rt_gateway, gate,
- rt->rt_gateway->sa_len);
- rtm->rtm_flags = rt->rt_flags;
- if (netmask) {
- outmask = (struct sockaddr *)
- (ROUNDUP(netmask->sa_len)+(char *)gate);
- Bcopy(netmask, outmask, netmask->sa_len);
- }
+ }
+ rtm->rtm_msglen = len;
+ rtm->rtm_flags = rt->rt_flags;
+ rtm->rtm_rmx = rt->rt_rmx;
+ cp = (caddr_t) (1 + rtm);
+ len = ROUNDUP(dst->sa_len);
+ Bcopy(dst, cp, len); cp += len;
+ if (gate) {
+ len = ROUNDUP(gate->sa_len);
+ Bcopy(gate, cp, len); cp += len;
+ }
+ if (netmask) {
+ len = ROUNDUP(netmask->sa_len);
+ Bcopy(netmask, cp, len); cp += 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;
case RTM_CHANGE:
- if (gate == 0)
- senderr(EINVAL);
- if (gate->sa_len > (len = rt->rt_gateway->sa_len))
+ if (gate &&
+ (gate->sa_len > (len = rt->rt_gateway->sa_len)))
senderr(EDQUOT);
+ /* 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(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) {
+ 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_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_CHANGE, rt, gate);
- Bcopy(gate, rt->rt_gateway, len);
- rt->rt_gateway->sa_len = len;
-
- rt_setmetrics(rtm->rtm_inits,
- &rtm->rtm_rmx, &rt->rt_rmx);
+ rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
+ if (genmask)
+ rt->rt_genmask = genmask;
/*
* Fall into
*/
cleanup:
if (rt)
rtfree(rt);
- if (cp = (caddr_t)rtm) {
- m_copyback(m, 0, len, cp);
+ {
+ register struct rawcb *rp = 0;
+ /*
+ * Check to see if we don't want our own messages.
+ */
+ if ((so->so_options & SO_USELOOPBACK) == 0) {
+ if (route_cb.any_count <= 1) {
+ if (rtm)
+ Free(rtm);
+ m_freem(m);
+ return (error);
+ }
+ /* There is another listener, so construct message */
+ rp = sotorawcb(so);
+ }
+ if (rtm) {
+ m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
Free(rtm);
}
- route_proto.sp_protocol = dst->sa_family;
+ if (rp)
+ rp->rcb_proto.sp_family = 0; /* Avoid us */
+ if (dst)
+ route_proto.sp_protocol = dst->sa_family;
raw_input(m, &route_proto, &route_src, &route_dst);
+ if (rp)
+ rp->rcb_proto.sp_family = PF_ROUTE;
+ }
return (error);
}
-static rt_setmetrics(which, in, out)
+rt_setmetrics(which, in, out)
u_long which;
register struct rt_metrics *in, *out;
{
metric(RTV_RTTVAR, rmx_rttvar);
metric(RTV_HOPCOUNT, rmx_hopcount);
metric(RTV_MTU, rmx_mtu);
+ metric(RTV_EXPIRE, rmx_expire);
#undef metric
}
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) {
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) {
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;
register struct sockaddr *sa;
int n, error;
- for (; rn && !(rn->rn_flags & RNF_ROOT); rn = rn->rn_dupedkey) {
+ for (; rn; rn = rn->rn_dupedkey) {
int count = 0, size = sizeof(w->w_rtm);
register struct rtentry *rt = (struct rtentry *)rn;
+ if (rn->rn_flags & RNF_ROOT)
+ continue;
if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg))
continue;
#define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); }
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_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_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));
}
* Definitions of protocols supported in the ROUTE domain.
*/
-int route_output();
int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput();
extern struct domain routedomain; /* or at least forward */
raw_input, route_output, raw_ctlinput, 0,
route_usrreq,
raw_init, 0, 0, 0,
-},
-{ 0, 0, 0, 0,
- raw_input, 0, raw_ctlinput, 0,
- raw_usrreq,
- raw_init, 0, 0, 0,
}
};