Home | History | Annotate | Line # | Download | only in net
rtsock.c revision 1.1.1.1
      1 /*
      2  * Copyright (c) 1988, 1991 Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  *
     33  *	@(#)rtsock.c	7.18 (Berkeley) 6/27/91
     34  */
     35 
     36 #include "param.h"
     37 #include "mbuf.h"
     38 #include "proc.h"
     39 #include "socket.h"
     40 #include "socketvar.h"
     41 #include "domain.h"
     42 #include "protosw.h"
     43 
     44 #include "af.h"
     45 #include "if.h"
     46 #include "route.h"
     47 #include "raw_cb.h"
     48 
     49 #include "machine/mtpr.h"
     50 
     51 struct sockaddr route_dst = { 2, PF_ROUTE, };
     52 struct sockaddr route_src = { 2, PF_ROUTE, };
     53 struct sockproto route_proto = { PF_ROUTE, };
     54 
     55 /*ARGSUSED*/
     56 route_usrreq(so, req, m, nam, control)
     57 	register struct socket *so;
     58 	int req;
     59 	struct mbuf *m, *nam, *control;
     60 {
     61 	register int error = 0;
     62 	register struct rawcb *rp = sotorawcb(so);
     63 	int s;
     64 	if (req == PRU_ATTACH) {
     65 		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
     66 		if (so->so_pcb = (caddr_t)rp)
     67 			bzero(so->so_pcb, sizeof(*rp));
     68 
     69 	}
     70 	if (req == PRU_DETACH && rp) {
     71 		int af = rp->rcb_proto.sp_protocol;
     72 		if (af == AF_INET)
     73 			route_cb.ip_count--;
     74 		else if (af == AF_NS)
     75 			route_cb.ns_count--;
     76 		else if (af == AF_ISO)
     77 			route_cb.iso_count--;
     78 		route_cb.any_count--;
     79 	}
     80 	s = splnet();
     81 	error = raw_usrreq(so, req, m, nam, control);
     82 	rp = sotorawcb(so);
     83 	if (req == PRU_ATTACH && rp) {
     84 		int af = rp->rcb_proto.sp_protocol;
     85 		if (error) {
     86 			free((caddr_t)rp, M_PCB);
     87 			splx(s);
     88 			return (error);
     89 		}
     90 		if (af == AF_INET)
     91 			route_cb.ip_count++;
     92 		else if (af == AF_NS)
     93 			route_cb.ns_count++;
     94 		else if (af == AF_ISO)
     95 			route_cb.iso_count++;
     96 		rp->rcb_faddr = &route_src;
     97 		route_cb.any_count++;
     98 		soisconnected(so);
     99 		so->so_options |= SO_USELOOPBACK;
    100 	}
    101 	splx(s);
    102 	return (error);
    103 }
    104 #define ROUNDUP(a) \
    105 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
    106 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
    107 
    108 /*ARGSUSED*/
    109 route_output(m, so)
    110 	register struct mbuf *m;
    111 	struct socket *so;
    112 {
    113 	register struct rt_msghdr *rtm = 0;
    114 	register struct rtentry *rt = 0;
    115 	struct rtentry *saved_nrt = 0;
    116 	struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0;
    117 	struct sockaddr *ifpaddr = 0, *ifaaddr = 0;
    118 	caddr_t cp, lim;
    119 	int len, error = 0;
    120 	struct ifnet *ifp = 0;
    121 	struct ifaddr *ifa = 0;
    122 	struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute();
    123 
    124 #define senderr(e) { error = e; goto flush;}
    125 	if (m == 0 || m->m_len < sizeof(long))
    126 		return (ENOBUFS);
    127 	if ((m = m_pullup(m, sizeof(long))) == 0)
    128 		return (ENOBUFS);
    129 	if ((m->m_flags & M_PKTHDR) == 0)
    130 		panic("route_output");
    131 	len = m->m_pkthdr.len;
    132 	if (len < sizeof(*rtm) ||
    133 	    len != mtod(m, struct rt_msghdr *)->rtm_msglen)
    134 		senderr(EINVAL);
    135 	R_Malloc(rtm, struct rt_msghdr *, len);
    136 	if (rtm == 0)
    137 		senderr(ENOBUFS);
    138 	m_copydata(m, 0, len, (caddr_t)rtm);
    139 	if (rtm->rtm_version != RTM_VERSION)
    140 		senderr(EPROTONOSUPPORT);
    141 	rtm->rtm_pid = curproc->p_pid;
    142 	lim = len + (caddr_t) rtm;
    143 	cp = (caddr_t) (rtm + 1);
    144 	if (rtm->rtm_addrs & RTA_DST) {
    145 		dst = (struct sockaddr *)cp;
    146 		ADVANCE(cp, dst);
    147 	} else
    148 		senderr(EINVAL);
    149 	if ((rtm->rtm_addrs & RTA_GATEWAY) && cp < lim)  {
    150 		gate = (struct sockaddr *)cp;
    151 		ADVANCE(cp, gate);
    152 	}
    153 	if ((rtm->rtm_addrs & RTA_NETMASK) && cp < lim)  {
    154 		netmask = (struct sockaddr *)cp;
    155 		ADVANCE(cp, netmask);
    156 	}
    157 	if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim)  {
    158 		struct radix_node *t, *rn_addmask();
    159 		genmask = (struct sockaddr *)cp;
    160 		ADVANCE(cp, genmask);
    161 		t = rn_addmask(genmask, 1, 2);
    162 		if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
    163 			genmask = (struct sockaddr *)(t->rn_key);
    164 		else
    165 			senderr(ENOBUFS);
    166 	}
    167 	if ((rtm->rtm_addrs & RTA_IFP) && cp < lim)  {
    168 		ifpaddr = (struct sockaddr *)cp;
    169 		ADVANCE(cp, ifpaddr);
    170 	}
    171 	if ((rtm->rtm_addrs & RTA_IFA) && cp < lim)  {
    172 		ifaaddr = (struct sockaddr *)cp;
    173 	}
    174 	switch (rtm->rtm_type) {
    175 	case RTM_ADD:
    176 		if (gate == 0)
    177 			senderr(EINVAL);
    178 		error = rtrequest(RTM_ADD, dst, gate, netmask,
    179 					rtm->rtm_flags, &saved_nrt);
    180 		if (error == 0 && saved_nrt) {
    181 			rt_setmetrics(rtm->rtm_inits,
    182 				&rtm->rtm_rmx, &saved_nrt->rt_rmx);
    183 			saved_nrt->rt_refcnt--;
    184 			saved_nrt->rt_genmask = genmask;
    185 		}
    186 		break;
    187 
    188 	case RTM_DELETE:
    189 		error = rtrequest(RTM_DELETE, dst, gate, netmask,
    190 				rtm->rtm_flags, (struct rtentry **)0);
    191 		break;
    192 
    193 	case RTM_GET:
    194 	case RTM_CHANGE:
    195 	case RTM_LOCK:
    196 		rt = rtalloc1(dst, 0);
    197 		if (rt == 0)
    198 			senderr(ESRCH);
    199 		if (rtm->rtm_type != RTM_GET) {
    200 			if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0)
    201 				senderr(ESRCH);
    202 			if (rt->rt_nodes->rn_dupedkey &&
    203 			    (netmask == 0 ||
    204 			     Bcmp(netmask, rt_mask(rt), netmask->sa_len)))
    205 				senderr(ETOOMANYREFS);
    206 		}
    207 		switch(rtm->rtm_type) {
    208 
    209 		case RTM_GET:
    210 			dst = rt_key(rt); len = sizeof(*rtm);
    211 			ADVANCE(len, dst);
    212 			rtm->rtm_addrs |= RTA_DST;
    213 			if (gate = rt->rt_gateway) {
    214 				ADVANCE(len, gate);
    215 				rtm->rtm_addrs |= RTA_GATEWAY;
    216 			} else
    217 				rtm->rtm_addrs &= ~RTA_GATEWAY;
    218 			if (netmask = rt_mask(rt)) {
    219 				ADVANCE(len, netmask);
    220 				rtm->rtm_addrs |= RTA_NETMASK;
    221 			} else
    222 				rtm->rtm_addrs &= ~RTA_NETMASK;
    223 			if (genmask = rt->rt_genmask) {
    224 				ADVANCE(len, genmask);
    225 				rtm->rtm_addrs |= RTA_GENMASK;
    226 			} else
    227 				rtm->rtm_addrs &= ~RTA_GENMASK;
    228 			if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
    229 				if (rt->rt_ifp == 0)
    230 					goto badif;
    231 				for (ifa = rt->rt_ifp->if_addrlist;
    232 				    ifa && ifa->ifa_addr->sa_family != AF_LINK;
    233 				     ifa = ifa->ifa_next){}
    234 				if (ifa && rt->rt_ifa) {
    235 					ifpaddr = ifa->ifa_addr;
    236 					ADVANCE(len, ifpaddr);
    237 					ifaaddr = rt->rt_ifa->ifa_addr;
    238 					ADVANCE(len, ifaaddr);
    239 					rtm->rtm_addrs |= RTA_IFP | RTA_IFA;
    240 				} else {
    241 				badif:	ifpaddr = 0;
    242 					rtm->rtm_addrs &= ~(RTA_IFP | RTA_IFA);
    243 				}
    244 			}
    245 			if (len > rtm->rtm_msglen) {
    246 				struct rt_msghdr *new_rtm;
    247 				R_Malloc(new_rtm, struct rt_msghdr *, len);
    248 				if (new_rtm == 0)
    249 					senderr(ENOBUFS);
    250 				Bcopy(rtm, new_rtm, rtm->rtm_msglen);
    251 				Free(rtm); rtm = new_rtm;
    252 			}
    253 			rtm->rtm_msglen = len;
    254 			rtm->rtm_flags = rt->rt_flags;
    255 			rtm->rtm_rmx = rt->rt_rmx;
    256 			cp = (caddr_t) (1 + rtm);
    257 			len = ROUNDUP(dst->sa_len);
    258 			Bcopy(dst, cp, len); cp += len;
    259 			if (gate) {
    260 			    len = ROUNDUP(gate->sa_len);
    261 			    Bcopy(gate, cp, len); cp += len;
    262 			}
    263 			if (netmask) {
    264 			    len = ROUNDUP(netmask->sa_len);
    265 			    Bcopy(netmask, cp, len); cp += len;
    266 			}
    267 			if (genmask) {
    268 			    len = ROUNDUP(genmask->sa_len);
    269 			    Bcopy(genmask, cp, len); cp += len;
    270 			}
    271 			if (ifpaddr) {
    272 			    len = ROUNDUP(ifpaddr->sa_len);
    273 			    Bcopy(ifpaddr, cp, len); cp += len;
    274 			    len = ROUNDUP(ifaaddr->sa_len);
    275 			    Bcopy(ifaaddr, cp, len); cp += len;
    276 			}
    277 			break;
    278 
    279 		case RTM_CHANGE:
    280 			if (gate &&
    281 			    (gate->sa_len > (len = rt->rt_gateway->sa_len)))
    282 				senderr(EDQUOT);
    283 			/* new gateway could require new ifaddr, ifp;
    284 			   flags may also be different; ifp may be specified
    285 			   by ll sockaddr when protocol address is ambiguous */
    286 			if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
    287 			    (ifp = ifa->ifa_ifp))
    288 				ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
    289 							ifp);
    290 			else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
    291 				 (ifa = ifa_ifwithroute(rt->rt_flags,
    292 							rt_key(rt), gate)))
    293 				ifp = ifa->ifa_ifp;
    294 			if (ifa) {
    295 				register struct ifaddr *oifa = rt->rt_ifa;
    296 				if (oifa != ifa) {
    297 				    if (oifa && oifa->ifa_rtrequest)
    298 					oifa->ifa_rtrequest(RTM_DELETE,
    299 								rt, gate);
    300 				    rt->rt_ifa = ifa;
    301 				    rt->rt_ifp = ifp;
    302 				}
    303 			}
    304 			if (gate)
    305 				Bcopy(gate, rt->rt_gateway, len);
    306 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
    307 					&rt->rt_rmx);
    308 			if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
    309 			       rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
    310 			if (genmask)
    311 				rt->rt_genmask = genmask;
    312 			/*
    313 			 * Fall into
    314 			 */
    315 		case RTM_LOCK:
    316 			rt->rt_rmx.rmx_locks |=
    317 				(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
    318 			rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
    319 			break;
    320 		}
    321 		goto cleanup;
    322 
    323 	default:
    324 		senderr(EOPNOTSUPP);
    325 	}
    326 
    327 flush:
    328 	if (rtm) {
    329 		if (error)
    330 			rtm->rtm_errno = error;
    331 		else
    332 			rtm->rtm_flags |= RTF_DONE;
    333 	}
    334 cleanup:
    335 	if (rt)
    336 		rtfree(rt);
    337     {
    338 	register struct rawcb *rp = 0;
    339 	/*
    340 	 * Check to see if we don't want our own messages.
    341 	 */
    342 	if ((so->so_options & SO_USELOOPBACK) == 0) {
    343 		if (route_cb.any_count <= 1) {
    344 			if (rtm)
    345 				Free(rtm);
    346 			m_freem(m);
    347 			return (error);
    348 		}
    349 		/* There is another listener, so construct message */
    350 		rp = sotorawcb(so);
    351 	}
    352 	if (rtm) {
    353 		m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
    354 		Free(rtm);
    355 	}
    356 	if (rp)
    357 		rp->rcb_proto.sp_family = 0; /* Avoid us */
    358 	if (dst)
    359 		route_proto.sp_protocol = dst->sa_family;
    360 	raw_input(m, &route_proto, &route_src, &route_dst);
    361 	if (rp)
    362 		rp->rcb_proto.sp_family = PF_ROUTE;
    363     }
    364 	return (error);
    365 }
    366 
    367 rt_setmetrics(which, in, out)
    368 	u_long which;
    369 	register struct rt_metrics *in, *out;
    370 {
    371 #define metric(f, e) if (which & (f)) out->e = in->e;
    372 	metric(RTV_RPIPE, rmx_recvpipe);
    373 	metric(RTV_SPIPE, rmx_sendpipe);
    374 	metric(RTV_SSTHRESH, rmx_ssthresh);
    375 	metric(RTV_RTT, rmx_rtt);
    376 	metric(RTV_RTTVAR, rmx_rttvar);
    377 	metric(RTV_HOPCOUNT, rmx_hopcount);
    378 	metric(RTV_MTU, rmx_mtu);
    379 	metric(RTV_EXPIRE, rmx_expire);
    380 #undef metric
    381 }
    382 
    383 /*
    384  * Copy data from a buffer back into the indicated mbuf chain,
    385  * starting "off" bytes from the beginning, extending the mbuf
    386  * chain if necessary.
    387  */
    388 m_copyback(m0, off, len, cp)
    389 	struct	mbuf *m0;
    390 	register int off;
    391 	register int len;
    392 	caddr_t cp;
    393 
    394 {
    395 	register int mlen;
    396 	register struct mbuf *m = m0, *n;
    397 	int totlen = 0;
    398 
    399 	if (m0 == 0)
    400 		return;
    401 	while (off > (mlen = m->m_len)) {
    402 		off -= mlen;
    403 		totlen += mlen;
    404 		if (m->m_next == 0) {
    405 			n = m_getclr(M_DONTWAIT, m->m_type);
    406 			if (n == 0)
    407 				goto out;
    408 			n->m_len = min(MLEN, len + off);
    409 			m->m_next = n;
    410 		}
    411 		m = m->m_next;
    412 	}
    413 	while (len > 0) {
    414 		mlen = min (m->m_len - off, len);
    415 		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
    416 		cp += mlen;
    417 		len -= mlen;
    418 		mlen += off;
    419 		off = 0;
    420 		totlen += mlen;
    421 		if (len == 0)
    422 			break;
    423 		if (m->m_next == 0) {
    424 			n = m_get(M_DONTWAIT, m->m_type);
    425 			if (n == 0)
    426 				break;
    427 			n->m_len = min(MLEN, len);
    428 			m->m_next = n;
    429 		}
    430 		m = m->m_next;
    431 	}
    432 out:	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
    433 		m->m_pkthdr.len = totlen;
    434 }
    435 
    436 /*
    437  * The miss message and losing message are very similar.
    438  */
    439 
    440 rt_missmsg(type, dst, gate, mask, src, flags, error)
    441 register struct sockaddr *dst;
    442 struct sockaddr *gate, *mask, *src;
    443 {
    444 	register struct rt_msghdr *rtm;
    445 	register struct mbuf *m;
    446 	int dlen = ROUNDUP(dst->sa_len);
    447 	int len = dlen + sizeof(*rtm);
    448 
    449 	if (route_cb.any_count == 0)
    450 		return;
    451 	m = m_gethdr(M_DONTWAIT, MT_DATA);
    452 	if (m == 0)
    453 		return;
    454 	m->m_pkthdr.len = m->m_len = min(len, MHLEN);
    455 	m->m_pkthdr.rcvif = 0;
    456 	rtm = mtod(m, struct rt_msghdr *);
    457 	bzero((caddr_t)rtm, sizeof(*rtm)); /*XXX assumes sizeof(*rtm) < MHLEN*/
    458 	rtm->rtm_flags = RTF_DONE | flags;
    459 	rtm->rtm_msglen = len;
    460 	rtm->rtm_version = RTM_VERSION;
    461 	rtm->rtm_type = type;
    462 	rtm->rtm_addrs = RTA_DST;
    463 	if (type == RTM_OLDADD || type == RTM_OLDDEL) {
    464 		rtm->rtm_pid = curproc->p_pid;
    465 	}
    466 	m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst);
    467 	if (gate) {
    468 		dlen = ROUNDUP(gate->sa_len);
    469 		m_copyback(m, len ,  dlen, (caddr_t)gate);
    470 		len += dlen;
    471 		rtm->rtm_addrs |= RTA_GATEWAY;
    472 	}
    473 	if (mask) {
    474 		dlen = ROUNDUP(mask->sa_len);
    475 		m_copyback(m, len ,  dlen, (caddr_t)mask);
    476 		len += dlen;
    477 		rtm->rtm_addrs |= RTA_NETMASK;
    478 	}
    479 	if (src) {
    480 		dlen = ROUNDUP(src->sa_len);
    481 		m_copyback(m, len ,  dlen, (caddr_t)src);
    482 		len += dlen;
    483 		rtm->rtm_addrs |= RTA_AUTHOR;
    484 	}
    485 	if (m->m_pkthdr.len != len) {
    486 		m_freem(m);
    487 		return;
    488 	}
    489 	rtm->rtm_errno = error;
    490 	rtm->rtm_msglen = len;
    491 	route_proto.sp_protocol = dst->sa_family;
    492 	raw_input(m, &route_proto, &route_src, &route_dst);
    493 }
    494 
    495 #include "kinfo.h"
    496 struct walkarg {
    497 	int	w_op, w_arg;
    498 	int	w_given, w_needed;
    499 	caddr_t	w_where;
    500 	struct	{
    501 		struct rt_msghdr m_rtm;
    502 		char	m_sabuf[128];
    503 	} w_m;
    504 #define w_rtm w_m.m_rtm
    505 };
    506 /*
    507  * This is used in dumping the kernel table via getkinfo().
    508  */
    509 rt_dumpentry(rn, w)
    510 	struct radix_node *rn;
    511 	register struct walkarg *w;
    512 {
    513 	register struct sockaddr *sa;
    514 	int n, error;
    515 
    516     for (; rn; rn = rn->rn_dupedkey) {
    517 	int count = 0, size = sizeof(w->w_rtm);
    518 	register struct rtentry *rt = (struct rtentry *)rn;
    519 
    520 	if (rn->rn_flags & RNF_ROOT)
    521 		continue;
    522 	if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg))
    523 		continue;
    524 #define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); }
    525 	w->w_rtm.rtm_addrs = 0;
    526 	if (sa = rt_key(rt))
    527 		next(RTA_DST, ROUNDUP(sa->sa_len));
    528 	if (sa = rt->rt_gateway)
    529 		next(RTA_GATEWAY, ROUNDUP(sa->sa_len));
    530 	if (sa = rt_mask(rt))
    531 		next(RTA_NETMASK, ROUNDUP(sa->sa_len));
    532 	if (sa = rt->rt_genmask)
    533 		next(RTA_GENMASK, ROUNDUP(sa->sa_len));
    534 	w->w_needed += size;
    535 	if (w->w_where == NULL || w->w_needed > 0)
    536 		continue;
    537 	w->w_rtm.rtm_msglen = size;
    538 	w->w_rtm.rtm_flags = rt->rt_flags;
    539 	w->w_rtm.rtm_use = rt->rt_use;
    540 	w->w_rtm.rtm_rmx = rt->rt_rmx;
    541 	w->w_rtm.rtm_index = rt->rt_ifp->if_index;
    542 #undef next
    543 #define next(l) {n = (l); Bcopy(sa, cp, n); cp += n;}
    544 	if (size <= sizeof(w->w_m)) {
    545 		register caddr_t cp = (caddr_t)(w->w_m.m_sabuf);
    546 		if (sa = rt_key(rt))
    547 			next(ROUNDUP(sa->sa_len));
    548 		if (sa = rt->rt_gateway)
    549 			next(ROUNDUP(sa->sa_len));
    550 		if (sa = rt_mask(rt))
    551 			next(ROUNDUP(sa->sa_len));
    552 		if (sa = rt->rt_genmask)
    553 			next(ROUNDUP(sa->sa_len));
    554 #undef next
    555 #define next(s, l) {n = (l); \
    556     if (error = copyout((caddr_t)(s), w->w_where, n)) return (error); \
    557     w->w_where += n;}
    558 
    559 		next(&w->w_m, size); /* Copy rtmsg and sockaddrs back */
    560 		continue;
    561 	}
    562 	next(&w->w_rtm, sizeof(w->w_rtm));
    563 	if (sa = rt_key(rt))
    564 		next(sa, ROUNDUP(sa->sa_len));
    565 	if (sa = rt->rt_gateway)
    566 		next(sa, ROUNDUP(sa->sa_len));
    567 	if (sa = rt_mask(rt))
    568 		next(sa, ROUNDUP(sa->sa_len));
    569 	if (sa = rt->rt_genmask)
    570 		next(sa, ROUNDUP(sa->sa_len));
    571     }
    572 	return (0);
    573 #undef next
    574 }
    575 
    576 kinfo_rtable(op, where, given, arg, needed)
    577 	int	op, arg;
    578 	caddr_t	where;
    579 	int	*given, *needed;
    580 {
    581 	register struct radix_node_head *rnh;
    582 	int	s, error = 0;
    583 	u_char  af = ki_af(op);
    584 	struct	walkarg w;
    585 
    586 	op &= 0xffff;
    587 	if (op != KINFO_RT_DUMP && op != KINFO_RT_FLAGS)
    588 		return (EINVAL);
    589 
    590 	Bzero(&w, sizeof(w));
    591 	if ((w.w_where = where) && given)
    592 		w.w_given = *given;
    593 	w.w_needed = 0 - w.w_given;
    594 	w.w_arg = arg;
    595 	w.w_op = op;
    596 	w.w_rtm.rtm_version = RTM_VERSION;
    597 	w.w_rtm.rtm_type = RTM_GET;
    598 
    599 	s = splnet();
    600 	for (rnh = radix_node_head; rnh; rnh = rnh->rnh_next) {
    601 		if (rnh->rnh_af == 0)
    602 			continue;
    603 		if (af && af != rnh->rnh_af)
    604 			continue;
    605 		error = rt_walk(rnh->rnh_treetop, rt_dumpentry, &w);
    606 		if (error)
    607 			break;
    608 	}
    609 	w.w_needed += w.w_given;
    610 	if (where && given)
    611 		*given = w.w_where - where;
    612 	else
    613 		w.w_needed = (11 * w.w_needed) / 10;
    614 	*needed = w.w_needed;
    615 	splx(s);
    616 	return (error);
    617 }
    618 
    619 rt_walk(rn, f, w)
    620 	register struct radix_node *rn;
    621 	register int (*f)();
    622 	struct walkarg *w;
    623 {
    624 	int error;
    625 	for (;;) {
    626 		while (rn->rn_b >= 0)
    627 			rn = rn->rn_l;	/* First time through node, go left */
    628 		if (error = (*f)(rn, w))
    629 			return (error);	/* Process Leaf */
    630 		while (rn->rn_p->rn_r == rn) {	/* if coming back from right */
    631 			rn = rn->rn_p;		/* go back up */
    632 			if (rn->rn_flags & RNF_ROOT)
    633 				return 0;
    634 		}
    635 		rn = rn->rn_p->rn_r;		/* otherwise, go right*/
    636 	}
    637 }
    638 
    639 /*
    640  * Definitions of protocols supported in the ROUTE domain.
    641  */
    642 
    643 int	raw_init(),raw_usrreq(),raw_input(),raw_ctlinput();
    644 extern	struct domain routedomain;		/* or at least forward */
    645 
    646 struct protosw routesw[] = {
    647 { SOCK_RAW,	&routedomain,	0,		PR_ATOMIC|PR_ADDR,
    648   raw_input,	route_output,	raw_ctlinput,	0,
    649   route_usrreq,
    650   raw_init,	0,		0,		0,
    651 }
    652 };
    653 
    654 int	unp_externalize(), unp_dispose();
    655 
    656 struct domain routedomain =
    657     { PF_ROUTE, "route", 0, 0, 0,
    658       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
    659