xref: /freebsd/sys/net/rtsock.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
1 /*
2  * Copyright (c) 1988, 1991, 1993
3  *	The Regents of the University of California.  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	8.3 (Berkeley) 1/4/94
34  * $Id: rtsock.c,v 1.7 1994/10/11 23:16:29 wollman Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/proc.h>
40 #include <sys/mbuf.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/domain.h>
44 #include <sys/protosw.h>
45 
46 #include <net/if.h>
47 #include <net/route.h>
48 #include <net/raw_cb.h>
49 
50 struct	sockaddr route_dst = { 2, PF_ROUTE, };
51 struct	sockaddr route_src = { 2, PF_ROUTE, };
52 struct	sockproto route_proto = { PF_ROUTE, };
53 
54 struct walkarg {
55 	int	w_op, w_arg, w_given, w_needed, w_tmemsize;
56 	caddr_t	w_where, w_tmem;
57 };
58 
59 static struct mbuf *
60 		rt_msg1 __P((int, struct rt_addrinfo *));
61 static int	rt_msg2 __P((int,
62 		    struct rt_addrinfo *, caddr_t, struct walkarg *));
63 static void	rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
64 
65 /* Sleazy use of local variables throughout file, warning!!!! */
66 #define dst	info.rti_info[RTAX_DST]
67 #define gate	info.rti_info[RTAX_GATEWAY]
68 #define netmask	info.rti_info[RTAX_NETMASK]
69 #define genmask	info.rti_info[RTAX_GENMASK]
70 #define ifpaddr	info.rti_info[RTAX_IFP]
71 #define ifaaddr	info.rti_info[RTAX_IFA]
72 #define brdaddr	info.rti_info[RTAX_BRD]
73 
74 /*ARGSUSED*/
75 int
76 route_usrreq(so, req, m, nam, control)
77 	register struct socket *so;
78 	int req;
79 	struct mbuf *m, *nam, *control;
80 {
81 	register int error = 0;
82 	register struct rawcb *rp = sotorawcb(so);
83 	int s;
84 
85 	if (req == PRU_ATTACH) {
86 		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
87 		so->so_pcb = (caddr_t)rp;
88 		if (so->so_pcb)
89 			bzero(so->so_pcb, sizeof(*rp));
90 
91 	}
92 	if (req == PRU_DETACH && rp) {
93 		int af = rp->rcb_proto.sp_protocol;
94 		if (af == AF_INET)
95 			route_cb.ip_count--;
96 		else if (af == AF_NS)
97 			route_cb.ns_count--;
98 		else if (af == AF_ISO)
99 			route_cb.iso_count--;
100 		route_cb.any_count--;
101 	}
102 	s = splnet();
103 	error = raw_usrreq(so, req, m, nam, control);
104 	rp = sotorawcb(so);
105 	if (req == PRU_ATTACH && rp) {
106 		int af = rp->rcb_proto.sp_protocol;
107 		if (error) {
108 			free((caddr_t)rp, M_PCB);
109 			splx(s);
110 			return (error);
111 		}
112 		if (af == AF_INET)
113 			route_cb.ip_count++;
114 		else if (af == AF_NS)
115 			route_cb.ns_count++;
116 		else if (af == AF_ISO)
117 			route_cb.iso_count++;
118 		rp->rcb_faddr = &route_src;
119 		route_cb.any_count++;
120 		soisconnected(so);
121 		so->so_options |= SO_USELOOPBACK;
122 	}
123 	splx(s);
124 	return (error);
125 }
126 
127 /*ARGSUSED*/
128 int
129 route_output(m, so)
130 	register struct mbuf *m;
131 	struct socket *so;
132 {
133 	register struct rt_msghdr *rtm = 0;
134 	register struct rtentry *rt = 0;
135 	struct rtentry *saved_nrt = 0;
136 	struct rt_addrinfo info;
137 	int len, error = 0;
138 	struct ifnet *ifp = 0;
139 	struct ifaddr *ifa = 0;
140 
141 #define senderr(e) { error = e; goto flush;}
142 	if (m == 0 || ((m->m_len < sizeof(long)) &&
143 		       (m = m_pullup(m, sizeof(long))) == 0))
144 		return (ENOBUFS);
145 	if ((m->m_flags & M_PKTHDR) == 0)
146 		panic("route_output");
147 	len = m->m_pkthdr.len;
148 	if (len < sizeof(*rtm) ||
149 	    len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
150 		dst = 0;
151 		senderr(EINVAL);
152 	}
153 	R_Malloc(rtm, struct rt_msghdr *, len);
154 	if (rtm == 0) {
155 		dst = 0;
156 		senderr(ENOBUFS);
157 	}
158 	m_copydata(m, 0, len, (caddr_t)rtm);
159 	if (rtm->rtm_version != RTM_VERSION) {
160 		dst = 0;
161 		senderr(EPROTONOSUPPORT);
162 	}
163 	rtm->rtm_pid = curproc->p_pid;
164 	info.rti_addrs = rtm->rtm_addrs;
165 	rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);
166 	if (dst == 0)
167 		senderr(EINVAL);
168 	if (genmask) {
169 		struct radix_node *t;
170 		t = rn_addmask((caddr_t)genmask, 1, 2);
171 		if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
172 			genmask = (struct sockaddr *)(t->rn_key);
173 		else
174 			senderr(ENOBUFS);
175 	}
176 	switch (rtm->rtm_type) {
177 
178 	case RTM_ADD:
179 		if (gate == 0)
180 			senderr(EINVAL);
181 		error = rtrequest(RTM_ADD, dst, gate, netmask,
182 					rtm->rtm_flags, &saved_nrt);
183 		if (error == 0 && saved_nrt) {
184 			rt_setmetrics(rtm->rtm_inits,
185 				&rtm->rtm_rmx, &saved_nrt->rt_rmx);
186 			saved_nrt->rt_refcnt--;
187 			saved_nrt->rt_genmask = genmask;
188 		}
189 		break;
190 
191 	case RTM_DELETE:
192 		error = rtrequest(RTM_DELETE, dst, gate, netmask,
193 				rtm->rtm_flags, (struct rtentry **)0);
194 		break;
195 
196 	case RTM_GET:
197 	case RTM_CHANGE:
198 	case RTM_LOCK:
199 		rt = rtalloc1(dst, 0, 0UL);
200 		if (rt == 0)
201 			senderr(ESRCH);
202 		if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */
203 			struct radix_node *rn;
204 			extern struct radix_node_head *mask_rnhead;
205 
206 			if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0)
207 				senderr(ESRCH);
208 			if (netmask && (rn = rn_search(netmask,
209 					    mask_rnhead->rnh_treetop)))
210 				netmask = (struct sockaddr *)rn->rn_key;
211 			for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey)
212 				if (netmask == (struct sockaddr *)rn->rn_mask)
213 					break;
214 			if (rn == 0)
215 				senderr(ETOOMANYREFS);
216 			rt = (struct rtentry *)rn;
217 		}
218 		switch(rtm->rtm_type) {
219 
220 		case RTM_GET:
221 			dst = rt_key(rt);
222 			gate = rt->rt_gateway;
223 			netmask = rt_mask(rt);
224 			genmask = rt->rt_genmask;
225 			if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
226 				ifp = rt->rt_ifp;
227 				if (ifp) {
228 					ifpaddr = ifp->if_addrlist->ifa_addr;
229 					ifaaddr = rt->rt_ifa->ifa_addr;
230 					rtm->rtm_index = ifp->if_index;
231 				} else {
232 					ifpaddr = 0;
233 					ifaaddr = 0;
234 			    }
235 			}
236 			len = rt_msg2(RTM_GET, &info, (caddr_t)0,
237 				(struct walkarg *)0);
238 			if (len > rtm->rtm_msglen) {
239 				struct rt_msghdr *new_rtm;
240 				R_Malloc(new_rtm, struct rt_msghdr *, len);
241 				if (new_rtm == 0)
242 					senderr(ENOBUFS);
243 				Bcopy(rtm, new_rtm, rtm->rtm_msglen);
244 				Free(rtm); rtm = new_rtm;
245 			}
246 			(void)rt_msg2(RTM_GET, &info, (caddr_t)rtm,
247 				(struct walkarg *)0);
248 			rtm->rtm_flags = rt->rt_flags;
249 			rtm->rtm_rmx = rt->rt_rmx;
250 			rtm->rtm_addrs = info.rti_addrs;
251 			break;
252 
253 		case RTM_CHANGE:
254 			if (gate && rt_setgate(rt, rt_key(rt), gate))
255 				senderr(EDQUOT);
256 
257 			/*
258 			 * If they tried to change things but didn't specify
259 			 * the required gateway, then just use the old one.
260 			 * This can happen if the user tries to change the
261 			 * flags on the default route without changing the
262 			 * default gateway.  Changing flags still doesn't work.
263 			 */
264 			if ((rt->rt_flags & RTF_GATEWAY) && !gate)
265 				gate = rt->rt_gateway;
266 
267 			/* new gateway could require new ifaddr, ifp;
268 			   flags may also be different; ifp may be specified
269 			   by ll sockaddr when protocol address is ambiguous */
270 			if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
271 			    (ifp = ifa->ifa_ifp))
272 				ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
273 							ifp);
274 			else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
275 				 (ifa = ifa_ifwithroute(rt->rt_flags,
276 							rt_key(rt), gate)))
277 				ifp = ifa->ifa_ifp;
278 			if (ifa) {
279 				register struct ifaddr *oifa = rt->rt_ifa;
280 				if (oifa != ifa) {
281 				    if (oifa && oifa->ifa_rtrequest)
282 					oifa->ifa_rtrequest(RTM_DELETE,
283 								rt, gate);
284 				    IFAFREE(rt->rt_ifa);
285 				    rt->rt_ifa = ifa;
286 				    ifa->ifa_refcnt++;
287 				    rt->rt_ifp = ifp;
288 				}
289 			}
290 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
291 					&rt->rt_rmx);
292 			if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
293 			       rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
294 			if (genmask)
295 				rt->rt_genmask = genmask;
296 			/*
297 			 * Fall into
298 			 */
299 		case RTM_LOCK:
300 			rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
301 			rt->rt_rmx.rmx_locks |=
302 				(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
303 			break;
304 		}
305 		break;
306 
307 	default:
308 		senderr(EOPNOTSUPP);
309 	}
310 
311 flush:
312 	if (rtm) {
313 		if (error)
314 			rtm->rtm_errno = error;
315 		else
316 			rtm->rtm_flags |= RTF_DONE;
317 	}
318 	if (rt)
319 		rtfree(rt);
320     {
321 	register struct rawcb *rp = 0;
322 	/*
323 	 * Check to see if we don't want our own messages.
324 	 */
325 	if ((so->so_options & SO_USELOOPBACK) == 0) {
326 		if (route_cb.any_count <= 1) {
327 			if (rtm)
328 				Free(rtm);
329 			m_freem(m);
330 			return (error);
331 		}
332 		/* There is another listener, so construct message */
333 		rp = sotorawcb(so);
334 	}
335 	if (rtm) {
336 		m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
337 		Free(rtm);
338 	}
339 	if (rp)
340 		rp->rcb_proto.sp_family = 0; /* Avoid us */
341 	if (dst)
342 		route_proto.sp_protocol = dst->sa_family;
343 	raw_input(m, &route_proto, &route_src, &route_dst);
344 	if (rp)
345 		rp->rcb_proto.sp_family = PF_ROUTE;
346     }
347 	return (error);
348 }
349 
350 void
351 rt_setmetrics(which, in, out)
352 	u_long which;
353 	register struct rt_metrics *in, *out;
354 {
355 #define metric(f, e) if (which & (f)) out->e = in->e;
356 	metric(RTV_RPIPE, rmx_recvpipe);
357 	metric(RTV_SPIPE, rmx_sendpipe);
358 	metric(RTV_SSTHRESH, rmx_ssthresh);
359 	metric(RTV_RTT, rmx_rtt);
360 	metric(RTV_RTTVAR, rmx_rttvar);
361 	metric(RTV_HOPCOUNT, rmx_hopcount);
362 	metric(RTV_MTU, rmx_mtu);
363 	metric(RTV_EXPIRE, rmx_expire);
364 #undef metric
365 }
366 
367 #define ROUNDUP(a) \
368 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
369 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
370 
371 static void
372 rt_xaddrs(cp, cplim, rtinfo)
373 	register caddr_t cp, cplim;
374 	register struct rt_addrinfo *rtinfo;
375 {
376 	register struct sockaddr *sa;
377 	register int i;
378 
379 	bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
380 	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
381 		if ((rtinfo->rti_addrs & (1 << i)) == 0)
382 			continue;
383 		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
384 		ADVANCE(cp, sa);
385 	}
386 }
387 
388 static struct mbuf *
389 rt_msg1(type, rtinfo)
390 	int type;
391 	register struct rt_addrinfo *rtinfo;
392 {
393 	register struct rt_msghdr *rtm;
394 	register struct mbuf *m;
395 	register int i;
396 	register struct sockaddr *sa;
397 	int len, dlen;
398 
399 	m = m_gethdr(M_DONTWAIT, MT_DATA);
400 	if (m == 0)
401 		return (m);
402 	switch (type) {
403 
404 	case RTM_DELADDR:
405 	case RTM_NEWADDR:
406 		len = sizeof(struct ifa_msghdr);
407 		break;
408 
409 	case RTM_IFINFO:
410 		len = sizeof(struct if_msghdr);
411 		break;
412 
413 	default:
414 		len = sizeof(struct rt_msghdr);
415 	}
416 	if (len > MHLEN)
417 		panic("rt_msg1");
418 	m->m_pkthdr.len = m->m_len = len;
419 	m->m_pkthdr.rcvif = 0;
420 	rtm = mtod(m, struct rt_msghdr *);
421 	bzero((caddr_t)rtm, len);
422 	for (i = 0; i < RTAX_MAX; i++) {
423 		if ((sa = rtinfo->rti_info[i]) == NULL)
424 			continue;
425 		rtinfo->rti_addrs |= (1 << i);
426 		dlen = ROUNDUP(sa->sa_len);
427 		m_copyback(m, len, dlen, (caddr_t)sa);
428 		len += dlen;
429 	}
430 	if (m->m_pkthdr.len != len) {
431 		m_freem(m);
432 		return (NULL);
433 	}
434 	rtm->rtm_msglen = len;
435 	rtm->rtm_version = RTM_VERSION;
436 	rtm->rtm_type = type;
437 	return (m);
438 }
439 
440 static int
441 rt_msg2(type, rtinfo, cp, w)
442 	int type;
443 	register struct rt_addrinfo *rtinfo;
444 	caddr_t cp;
445 	struct walkarg *w;
446 {
447 	register int i;
448 	int len, dlen, second_time = 0;
449 	caddr_t cp0;
450 
451 	rtinfo->rti_addrs = 0;
452 again:
453 	switch (type) {
454 
455 	case RTM_DELADDR:
456 	case RTM_NEWADDR:
457 		len = sizeof(struct ifa_msghdr);
458 		break;
459 
460 	case RTM_IFINFO:
461 		len = sizeof(struct if_msghdr);
462 		break;
463 
464 	default:
465 		len = sizeof(struct rt_msghdr);
466 	}
467 	cp0 = cp;
468 	if (cp0)
469 		cp += len;
470 	for (i = 0; i < RTAX_MAX; i++) {
471 		register struct sockaddr *sa;
472 
473 		if ((sa = rtinfo->rti_info[i]) == 0)
474 			continue;
475 		rtinfo->rti_addrs |= (1 << i);
476 		dlen = ROUNDUP(sa->sa_len);
477 		if (cp) {
478 			bcopy((caddr_t)sa, cp, (unsigned)dlen);
479 			cp += dlen;
480 		}
481 		len += dlen;
482 	}
483 	if (cp == 0 && w != NULL && !second_time) {
484 		register struct walkarg *rw = w;
485 
486 		rw->w_needed += len;
487 		if (rw->w_needed <= 0 && rw->w_where) {
488 			if (rw->w_tmemsize < len) {
489 				if (rw->w_tmem)
490 					free(rw->w_tmem, M_RTABLE);
491 				rw->w_tmem = (caddr_t)
492 					malloc(len, M_RTABLE, M_NOWAIT);
493 				if (rw->w_tmem)
494 					rw->w_tmemsize = len;
495 			}
496 			if (rw->w_tmem) {
497 				cp = rw->w_tmem;
498 				second_time = 1;
499 				goto again;
500 			} else
501 				rw->w_where = 0;
502 		}
503 	}
504 	if (cp) {
505 		register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
506 
507 		rtm->rtm_version = RTM_VERSION;
508 		rtm->rtm_type = type;
509 		rtm->rtm_msglen = len;
510 	}
511 	return (len);
512 }
513 
514 /*
515  * This routine is called to generate a message from the routing
516  * socket indicating that a redirect has occured, a routing lookup
517  * has failed, or that a protocol has detected timeouts to a particular
518  * destination.
519  */
520 void
521 rt_missmsg(type, rtinfo, flags, error)
522 	int type, flags, error;
523 	register struct rt_addrinfo *rtinfo;
524 {
525 	register struct rt_msghdr *rtm;
526 	register struct mbuf *m;
527 	struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
528 
529 	if (route_cb.any_count == 0)
530 		return;
531 	m = rt_msg1(type, rtinfo);
532 	if (m == 0)
533 		return;
534 	rtm = mtod(m, struct rt_msghdr *);
535 	rtm->rtm_flags = RTF_DONE | flags;
536 	rtm->rtm_errno = error;
537 	rtm->rtm_addrs = rtinfo->rti_addrs;
538 	route_proto.sp_protocol = sa ? sa->sa_family : 0;
539 	raw_input(m, &route_proto, &route_src, &route_dst);
540 }
541 
542 /*
543  * This routine is called to generate a message from the routing
544  * socket indicating that the status of a network interface has changed.
545  */
546 void
547 rt_ifmsg(ifp)
548 	register struct ifnet *ifp;
549 {
550 	register struct if_msghdr *ifm;
551 	struct mbuf *m;
552 	struct rt_addrinfo info;
553 
554 	if (route_cb.any_count == 0)
555 		return;
556 	bzero((caddr_t)&info, sizeof(info));
557 	m = rt_msg1(RTM_IFINFO, &info);
558 	if (m == 0)
559 		return;
560 	ifm = mtod(m, struct if_msghdr *);
561 	ifm->ifm_index = ifp->if_index;
562 	ifm->ifm_flags = (u_short)ifp->if_flags;
563 	ifm->ifm_data = ifp->if_data;
564 	ifm->ifm_addrs = 0;
565 	route_proto.sp_protocol = 0;
566 	raw_input(m, &route_proto, &route_src, &route_dst);
567 }
568 
569 /*
570  * This is called to generate messages from the routing socket
571  * indicating a network interface has had addresses associated with it.
572  * if we ever reverse the logic and replace messages TO the routing
573  * socket indicate a request to configure interfaces, then it will
574  * be unnecessary as the routing socket will automatically generate
575  * copies of it.
576  */
577 void
578 rt_newaddrmsg(cmd, ifa, error, rt)
579 	int cmd, error;
580 	register struct ifaddr *ifa;
581 	register struct rtentry *rt;
582 {
583 	struct rt_addrinfo info;
584 	struct sockaddr *sa = 0;
585 	int pass;
586 	struct mbuf *m = 0;
587 	struct ifnet *ifp = ifa->ifa_ifp;
588 
589 	if (route_cb.any_count == 0)
590 		return;
591 	for (pass = 1; pass < 3; pass++) {
592 		bzero((caddr_t)&info, sizeof(info));
593 		if ((cmd == RTM_ADD && pass == 1) ||
594 		    (cmd == RTM_DELETE && pass == 2)) {
595 			register struct ifa_msghdr *ifam;
596 			int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
597 
598 			ifaaddr = sa = ifa->ifa_addr;
599 			ifpaddr = ifp->if_addrlist->ifa_addr;
600 			netmask = ifa->ifa_netmask;
601 			brdaddr = ifa->ifa_dstaddr;
602 			if ((m = rt_msg1(ncmd, &info)) == NULL)
603 				continue;
604 			ifam = mtod(m, struct ifa_msghdr *);
605 			ifam->ifam_index = ifp->if_index;
606 			ifam->ifam_metric = ifa->ifa_metric;
607 			ifam->ifam_flags = ifa->ifa_flags;
608 			ifam->ifam_addrs = info.rti_addrs;
609 		}
610 		if ((cmd == RTM_ADD && pass == 2) ||
611 		    (cmd == RTM_DELETE && pass == 1)) {
612 			register struct rt_msghdr *rtm;
613 
614 			if (rt == 0)
615 				continue;
616 			netmask = rt_mask(rt);
617 			dst = sa = rt_key(rt);
618 			gate = rt->rt_gateway;
619 			if ((m = rt_msg1(cmd, &info)) == NULL)
620 				continue;
621 			rtm = mtod(m, struct rt_msghdr *);
622 			rtm->rtm_index = ifp->if_index;
623 			rtm->rtm_flags |= rt->rt_flags;
624 			rtm->rtm_errno = error;
625 			rtm->rtm_addrs = info.rti_addrs;
626 		}
627 		route_proto.sp_protocol = sa ? sa->sa_family : 0;
628 		raw_input(m, &route_proto, &route_src, &route_dst);
629 	}
630 }
631 
632 /*
633  * This is used in dumping the kernel table via sysctl().
634  */
635 int
636 sysctl_dumpentry(rn, w)
637 	struct radix_node *rn;
638 	register struct walkarg *w;
639 {
640 	register struct rtentry *rt = (struct rtentry *)rn;
641 	int error = 0, size;
642 	struct rt_addrinfo info;
643 
644 	if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
645 		return 0;
646 	bzero((caddr_t)&info, sizeof(info));
647 	dst = rt_key(rt);
648 	gate = rt->rt_gateway;
649 	netmask = rt_mask(rt);
650 	genmask = rt->rt_genmask;
651 	size = rt_msg2(RTM_GET, &info, 0, w);
652 	if (w->w_where && w->w_tmem) {
653 		register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
654 
655 		rtm->rtm_flags = rt->rt_flags;
656 		rtm->rtm_use = rt->rt_use;
657 		rtm->rtm_rmx = rt->rt_rmx;
658 		rtm->rtm_index = rt->rt_ifp->if_index;
659 		rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
660 		rtm->rtm_addrs = info.rti_addrs;
661 		error = copyout((caddr_t)rtm, w->w_where, size);
662 		if (error)
663 			w->w_where = NULL;
664 		else
665 			w->w_where += size;
666 	}
667 	return (error);
668 }
669 
670 int
671 sysctl_iflist(af, w)
672 	int	af;
673 	register struct	walkarg *w;
674 {
675 	register struct ifnet *ifp;
676 	register struct ifaddr *ifa;
677 	struct	rt_addrinfo info;
678 	int	len, error = 0;
679 
680 	bzero((caddr_t)&info, sizeof(info));
681 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
682 		if (w->w_arg && w->w_arg != ifp->if_index)
683 			continue;
684 		ifa = ifp->if_addrlist;
685 		ifpaddr = ifa->ifa_addr;
686 		len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w);
687 		ifpaddr = 0;
688 		if (w->w_where && w->w_tmem) {
689 			register struct if_msghdr *ifm;
690 
691 			ifm = (struct if_msghdr *)w->w_tmem;
692 			ifm->ifm_index = ifp->if_index;
693 			ifm->ifm_flags = (u_short)ifp->if_flags;
694 			ifm->ifm_data = ifp->if_data;
695 			ifm->ifm_addrs = info.rti_addrs;
696 			error = copyout((caddr_t)ifm, w->w_where, len);
697 			if (error)
698 				return (error);
699 			w->w_where += len;
700 		}
701 		while ((ifa = ifa->ifa_next) != 0) {
702 			if (af && af != ifa->ifa_addr->sa_family)
703 				continue;
704 			ifaaddr = ifa->ifa_addr;
705 			netmask = ifa->ifa_netmask;
706 			brdaddr = ifa->ifa_dstaddr;
707 			len = rt_msg2(RTM_NEWADDR, &info, 0, w);
708 			if (w->w_where && w->w_tmem) {
709 				register struct ifa_msghdr *ifam;
710 
711 				ifam = (struct ifa_msghdr *)w->w_tmem;
712 				ifam->ifam_index = ifa->ifa_ifp->if_index;
713 				ifam->ifam_flags = ifa->ifa_flags;
714 				ifam->ifam_metric = ifa->ifa_metric;
715 				ifam->ifam_addrs = info.rti_addrs;
716 				error = copyout(w->w_tmem, w->w_where, len);
717 				if (error)
718 					return (error);
719 				w->w_where += len;
720 			}
721 		}
722 		ifaaddr = netmask = brdaddr = 0;
723 	}
724 	return (0);
725 }
726 
727 int
728 sysctl_rtable(name, namelen, where, given, new, newlen)
729 	int	*name;
730 	int	namelen;
731 	caddr_t	where;
732 	size_t	*given;
733 	caddr_t	*new;
734 	size_t	newlen;
735 {
736 	register struct radix_node_head *rnh;
737 	int	i, s, error = EINVAL;
738 	u_char  af;
739 	struct	walkarg w;
740 
741 	if (new)
742 		return (EPERM);
743 	if (namelen != 3)
744 		return (EINVAL);
745 	af = name[0];
746 	Bzero(&w, sizeof(w));
747 	w.w_where = where;
748 	w.w_given = *given;
749 	w.w_needed = 0 - w.w_given;
750 	w.w_op = name[1];
751 	w.w_arg = name[2];
752 
753 	s = splnet();
754 	switch (w.w_op) {
755 
756 	case NET_RT_DUMP:
757 	case NET_RT_FLAGS:
758 		for (i = 1; i <= AF_MAX; i++)
759 			if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
760 			    (error = rnh->rnh_walktree(rnh,
761 							sysctl_dumpentry, &w)))
762 				break;
763 		break;
764 
765 	case NET_RT_IFLIST:
766 		error = sysctl_iflist(af, &w);
767 	}
768 	splx(s);
769 	if (w.w_tmem)
770 		free(w.w_tmem, M_RTABLE);
771 	w.w_needed += w.w_given;
772 	if (where) {
773 		*given = w.w_where - where;
774 		if (*given < w.w_needed)
775 			return (ENOMEM);
776 	} else {
777 		*given = (11 * w.w_needed) / 10;
778 	}
779 	return (error);
780 }
781 
782 /*
783  * Definitions of protocols supported in the ROUTE domain.
784  */
785 
786 extern	struct domain routedomain;		/* or at least forward */
787 
788 struct protosw routesw[] = {
789 { SOCK_RAW,	&routedomain,	0,		PR_ATOMIC|PR_ADDR,
790   raw_input,	route_output,	raw_ctlinput,	0,
791   route_usrreq,
792   raw_init,	0,		0,		0,
793   sysctl_rtable,
794 }
795 };
796 
797 struct domain routedomain =
798     { PF_ROUTE, "route", route_init, 0, 0,
799       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
800