xref: /openbsd/sys/net/rtsock.c (revision 404b540a)
1 /*	$OpenBSD: rtsock.c,v 1.94 2009/09/17 13:27:24 claudio Exp $	*/
2 /*	$NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1988, 1991, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  *
61  *	@(#)rtsock.c	8.6 (Berkeley) 2/11/95
62  */
63 
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/proc.h>
67 #include <sys/mbuf.h>
68 #include <sys/socket.h>
69 #include <sys/socketvar.h>
70 #include <sys/domain.h>
71 #include <sys/protosw.h>
72 
73 #include <uvm/uvm_extern.h>
74 #include <sys/sysctl.h>
75 
76 #include <net/if.h>
77 #include <net/route.h>
78 #include <net/raw_cb.h>
79 
80 #ifdef MPLS
81 #include <netmpls/mpls.h>
82 #endif /* MPLS */
83 
84 #include <sys/stdarg.h>
85 
86 struct sockaddr		route_dst = { 2, PF_ROUTE, };
87 struct sockaddr		route_src = { 2, PF_ROUTE, };
88 struct sockproto	route_proto = { PF_ROUTE, };
89 
90 struct walkarg {
91 	int	w_op, w_arg, w_given, w_needed, w_tmemsize;
92 	caddr_t	w_where, w_tmem;
93 };
94 
95 int	route_ctloutput(int, struct socket *, int, int, struct mbuf **);
96 void	route_input(struct mbuf *m0, ...);
97 
98 struct mbuf	*rt_msg1(int, struct rt_addrinfo *);
99 int		 rt_msg2(int, int, struct rt_addrinfo *, caddr_t,
100 		     struct walkarg *);
101 void		 rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
102 
103 /* Sleazy use of local variables throughout file, warning!!!! */
104 #define dst	info.rti_info[RTAX_DST]
105 #define gate	info.rti_info[RTAX_GATEWAY]
106 #define netmask	info.rti_info[RTAX_NETMASK]
107 #define genmask	info.rti_info[RTAX_GENMASK]
108 #define ifpaddr	info.rti_info[RTAX_IFP]
109 #define ifaaddr	info.rti_info[RTAX_IFA]
110 #define brdaddr	info.rti_info[RTAX_BRD]
111 
112 struct routecb {
113 	struct rawcb	rcb;
114 	unsigned int	msgfilter;
115 };
116 #define	sotoroutecb(so)	((struct routecb *)(so)->so_pcb)
117 
118 
119 int
120 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
121     struct mbuf *control, struct proc *p)
122 {
123 	struct rawcb	*rp;
124 	int		 s, af;
125 	int		 error = 0;
126 
127 	s = splsoftnet();
128 	rp = sotorawcb(so);
129 
130 	switch (req) {
131 	case PRU_ATTACH:
132 		/*
133 		 * use the rawcb but allocate a routecb, this
134 		 * code does not care about the additional fields
135 		 * and works directly on the raw socket.
136 		 */
137 		rp = malloc(sizeof(struct routecb), M_PCB, M_WAITOK|M_ZERO);
138 		so->so_pcb = rp;
139 		/*
140 		 * Don't call raw_usrreq() in the attach case, because
141 		 * we want to allow non-privileged processes to listen
142 		 * on and send "safe" commands to the routing socket.
143 		 */
144 		if (curproc == 0)
145 			error = EACCES;
146 		else
147 			error = raw_attach(so, (int)(long)nam);
148 		if (error) {
149 			free(rp, M_PCB);
150 			splx(s);
151 			return (error);
152 		}
153 		af = rp->rcb_proto.sp_protocol;
154 		if (af == AF_INET)
155 			route_cb.ip_count++;
156 		else if (af == AF_INET6)
157 			route_cb.ip6_count++;
158 #ifdef MPLS
159 		else if (af == AF_MPLS)
160 			route_cb.mpls_count++;
161 #endif /* MPLS */
162 		rp->rcb_faddr = &route_src;
163 		route_cb.any_count++;
164 		soisconnected(so);
165 		so->so_options |= SO_USELOOPBACK;
166 		break;
167 
168 	case PRU_DETACH:
169 		if (rp) {
170 			af = rp->rcb_proto.sp_protocol;
171 			if (af == AF_INET)
172 				route_cb.ip_count--;
173 			else if (af == AF_INET6)
174 				route_cb.ip6_count--;
175 #ifdef MPLS
176 			else if (af == AF_MPLS)
177 				route_cb.mpls_count--;
178 #endif /* MPLS */
179 			route_cb.any_count--;
180 		}
181 		/* FALLTHROUGH */
182 	default:
183 		error = raw_usrreq(so, req, m, nam, control, p);
184 	}
185 
186 	splx(s);
187 	return (error);
188 }
189 
190 int
191 route_ctloutput(int op, struct socket *so, int level, int optname,
192     struct mbuf **mp)
193 {
194 	struct routecb *rop = sotoroutecb(so);
195 	struct mbuf *m = *mp;
196 	int error = 0;
197 
198 	if (level != AF_ROUTE) {
199 		error = EINVAL;
200 		if (op == PRCO_SETOPT && *mp)
201 			m_free(*mp);
202 		return (error);
203 	}
204 
205 	switch (op) {
206 	case PRCO_SETOPT:
207 		switch (optname) {
208 		case ROUTE_MSGFILTER:
209 			if (m == NULL || m->m_len != sizeof(unsigned int))
210 				error = EINVAL;
211 			else
212 				rop->msgfilter = *mtod(m, unsigned int *);
213 			break;
214 		default:
215 			error = ENOPROTOOPT;
216 			break;
217 		}
218 		if (m)
219 			m_free(m);
220 		break;
221 	case PRCO_GETOPT:
222 		switch (optname) {
223 		case ROUTE_MSGFILTER:
224 			*mp = m = m_get(M_WAIT, MT_SOOPTS);
225 			m->m_len = sizeof(int);
226 			*mtod(m, unsigned int *) = rop->msgfilter;
227 			break;
228 		default:
229 			error = ENOPROTOOPT;
230 			break;
231 		}
232 	}
233 	return (error);
234 }
235 
236 void
237 route_input(struct mbuf *m0, ...)
238 {
239 	struct rawcb *rp;
240 	struct routecb *rop;
241 	struct mbuf *m = m0;
242 	int sockets = 0;
243 	struct socket *last;
244 	va_list ap;
245 	struct sockproto *proto;
246 	struct sockaddr *sosrc, *sodst;
247 
248 	va_start(ap, m0);
249 	proto = va_arg(ap, struct sockproto *);
250 	sosrc = va_arg(ap, struct sockaddr *);
251 	sodst = va_arg(ap, struct sockaddr *);
252 	va_end(ap);
253 
254 	/* ensure that we can access the rtm_type via mtod() */
255 	if (m->m_len < offsetof(struct rt_msghdr, rtm_type) + 1) {
256 		m_freem(m);
257 		return;
258 	}
259 
260 	last = 0;
261 	LIST_FOREACH(rp, &rawcb, rcb_list) {
262 		if (rp->rcb_proto.sp_family != proto->sp_family)
263 			continue;
264 		if (rp->rcb_proto.sp_protocol  &&
265 		    rp->rcb_proto.sp_protocol != proto->sp_protocol)
266 			continue;
267 		/*
268 		 * We assume the lower level routines have
269 		 * placed the address in a canonical format
270 		 * suitable for a structure comparison.
271 		 *
272 		 * Note that if the lengths are not the same
273 		 * the comparison will fail at the first byte.
274 		 */
275 #define	equal(a1, a2) \
276   (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0)
277 		if (rp->rcb_laddr && !equal(rp->rcb_laddr, sodst))
278 			continue;
279 		if (rp->rcb_faddr && !equal(rp->rcb_faddr, sosrc))
280 			continue;
281 
282 		/* filter messages that the process does not want */
283 		rop = (struct routecb *)rp;
284 		if (rop->msgfilter != 0 && !(rop->msgfilter & (1 <<
285 		    mtod(m, struct rt_msghdr *)->rtm_type)))
286 			continue;
287 
288 		if (last) {
289 			struct mbuf *n;
290 			if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
291 				if (sbappendaddr(&last->so_rcv, sosrc,
292 				    n, (struct mbuf *)0) == 0)
293 					/* should notify about lost packet */
294 					m_freem(n);
295 				else {
296 					sorwakeup(last);
297 					sockets++;
298 				}
299 			}
300 		}
301 		last = rp->rcb_socket;
302 	}
303 	if (last) {
304 		if (sbappendaddr(&last->so_rcv, sosrc,
305 		    m, (struct mbuf *)0) == 0)
306 			m_freem(m);
307 		else {
308 			sorwakeup(last);
309 			sockets++;
310 		}
311 	} else
312 		m_freem(m);
313 }
314 
315 int
316 route_output(struct mbuf *m, ...)
317 {
318 	struct rt_msghdr	*rtm = NULL;
319 	struct radix_node	*rn = NULL;
320 	struct rtentry		*rt = NULL;
321 	struct rtentry		*saved_nrt = NULL;
322 	struct radix_node_head	*rnh;
323 	struct rt_addrinfo	 info;
324 	int			 len, error = 0;
325 	struct ifnet		*ifp = NULL;
326 	struct ifaddr		*ifa = NULL;
327 	struct socket		*so;
328 	struct rawcb		*rp = NULL;
329 	struct sockaddr_rtlabel	 sa_rt;
330 #ifdef MPLS
331 	struct sockaddr_mpls	 sa_mpls, *psa_mpls;
332 #endif
333 	const char		*label;
334 	va_list			 ap;
335 	u_int			 tableid;
336 	u_int8_t		 prio;
337 
338 	va_start(ap, m);
339 	so = va_arg(ap, struct socket *);
340 	va_end(ap);
341 
342 	dst = NULL;	/* for error handling (goto flush) */
343 	if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
344 	    (m = m_pullup(m, sizeof(int32_t))) == 0))
345 		return (ENOBUFS);
346 	if ((m->m_flags & M_PKTHDR) == 0)
347 		panic("route_output");
348 	len = m->m_pkthdr.len;
349 	if (len < offsetof(struct rt_msghdr, rtm_type) + 1 ||
350 	    len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
351 		error = EINVAL;
352 		goto flush;
353 	}
354 	switch (mtod(m, struct rt_msghdr *)->rtm_version) {
355 	case RTM_VERSION:
356 		if (len < sizeof(struct rt_msghdr)) {
357 			error = EINVAL;
358 			goto flush;
359 		}
360 		R_Malloc(rtm, struct rt_msghdr *, len);
361 		if (rtm == 0) {
362 			error = ENOBUFS;
363 			goto flush;
364 		}
365 		m_copydata(m, 0, len, (caddr_t)rtm);
366 		break;
367 	default:
368 		error = EPROTONOSUPPORT;
369 		goto flush;
370 	}
371 	rtm->rtm_pid = curproc->p_pid;
372 	if (rtm->rtm_hdrlen == 0)	/* old client */
373 		rtm->rtm_hdrlen = sizeof(struct rt_msghdr);
374 	if (len < rtm->rtm_hdrlen) {
375 		error = EINVAL;
376 		goto flush;
377 	}
378 
379 	tableid = rtm->rtm_tableid;
380 	if (!rtable_exists(tableid)) {
381 		if (rtm->rtm_type == RTM_ADD) {
382 			if (rtable_add(tableid)) {
383 				error = EINVAL;
384 				goto flush;
385 			}
386 		} else {
387 			error = EINVAL;
388 			goto flush;
389 		}
390 	}
391 
392 	/* make sure that kernel-only bits are not set */
393 	rtm->rtm_priority &= RTP_MASK;
394 
395 	if (rtm->rtm_priority != 0) {
396 		if (rtm->rtm_priority > RTP_MAX) {
397 			error = EINVAL;
398 			goto flush;
399 		}
400 		prio = rtm->rtm_priority;
401 	} else if (rtm->rtm_type != RTM_ADD)
402 		prio = RTP_ANY;
403 	else if (rtm->rtm_flags & RTF_STATIC)
404 		prio = 0;
405 	else
406 		prio = RTP_DEFAULT;
407 
408 	bzero(&info, sizeof(info));
409 	info.rti_addrs = rtm->rtm_addrs;
410 	rt_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, len + (caddr_t)rtm, &info);
411 	info.rti_flags = rtm->rtm_flags;
412 	if (dst == 0 || dst->sa_family >= AF_MAX ||
413 	    (gate != 0 && gate->sa_family >= AF_MAX)) {
414 		error = EINVAL;
415 		goto flush;
416 	}
417 	if (genmask) {
418 		struct radix_node	*t;
419 		t = rn_addmask(genmask, 0, 1);
420 		if (t && genmask->sa_len >=
421 		    ((struct sockaddr *)t->rn_key)->sa_len &&
422 		    Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1,
423 		    ((struct sockaddr *)t->rn_key)->sa_len) - 1)
424 			genmask = (struct sockaddr *)(t->rn_key);
425 		else {
426 			error = ENOBUFS;
427 			goto flush;
428 		}
429 	}
430 #ifdef MPLS
431 	info.rti_mpls = rtm->rtm_mpls;
432 #endif
433 
434 	/*
435 	 * Verify that the caller has the appropriate privilege; RTM_GET
436 	 * is the only operation the non-superuser is allowed.
437 	 */
438 	if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) {
439 		error = EACCES;
440 		goto flush;
441 	}
442 
443 	switch (rtm->rtm_type) {
444 	case RTM_ADD:
445 		if (gate == 0) {
446 			error = EINVAL;
447 			goto flush;
448 		}
449 		error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt,
450 		    tableid);
451 		if (error == 0 && saved_nrt) {
452 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
453 			    &saved_nrt->rt_rmx);
454 			saved_nrt->rt_refcnt--;
455 			saved_nrt->rt_genmask = genmask;
456 			/* write back the priority the kernel used */
457 			rtm->rtm_index = saved_nrt->rt_ifp->if_index;
458 			rtm->rtm_priority = saved_nrt->rt_priority & RTP_MASK;
459 		}
460 		break;
461 	case RTM_DELETE:
462 		error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt,
463 		    tableid);
464 		if (error == 0) {
465 			(rt = saved_nrt)->rt_refcnt++;
466 			goto report;
467 		}
468 		break;
469 	case RTM_GET:
470 	case RTM_CHANGE:
471 	case RTM_LOCK:
472 		if ((rnh = rt_gettable(dst->sa_family, tableid)) == NULL) {
473 			error = EAFNOSUPPORT;
474 			goto flush;
475 		}
476 		rn = rt_lookup(dst, netmask, tableid);
477 		if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {
478 			error = ESRCH;
479 			goto flush;
480 		}
481 		rt = (struct rtentry *)rn;
482 #ifndef SMALL_KERNEL
483 		/*
484 		 * for RTM_CHANGE/LOCK, if we got multipath routes,
485 		 * we require users to specify a matching RTAX_GATEWAY.
486 		 *
487 		 * for RTM_GET, gate is optional even with multipath.
488 		 * if gate == NULL the first match is returned.
489 		 * (no need to call rt_mpath_matchgate if gate == NULL)
490 		 */
491 		if (rn_mpath_capable(rnh)) {
492 			/* first find correct priority bucket */
493 			rn = rn_mpath_prio(rn, prio);
494 			rt = (struct rtentry *)rn;
495 			if (prio != RTP_ANY &&
496 			    (rt->rt_priority & RTP_MASK) != prio) {
497 				error = ESRCH;
498 				rt->rt_refcnt++;
499 				goto flush;
500 			}
501 
502 			/* if multipath routes */
503 			if (rn_mpath_next(rn, 0)) {
504 				if (gate)
505 					rt = rt_mpath_matchgate(rt, gate, prio);
506 				else if (rtm->rtm_type != RTM_GET)
507 					/*
508 					 * only RTM_GET may use an empty gate
509 					 * on multipath ...
510 					 */
511 					rt = NULL;
512 			} else if (gate && (rtm->rtm_type == RTM_GET ||
513 			    rtm->rtm_type == RTM_LOCK))
514 				/*
515 				 * ... but if a gate is specified RTM_GET
516 				 * and RTM_LOCK must match the gate no matter
517 				 * what.
518 				 */
519 				rt = rt_mpath_matchgate(rt, gate, prio);
520 
521 			if (!rt) {
522 				error = ESRCH;
523 				goto flush;
524 			}
525 			rn = (struct radix_node *)rt;
526 		}
527 #endif
528 		rt->rt_refcnt++;
529 
530 		/*
531 		 * RTM_CHANGE/LOCK need a perfect match, rn_lookup()
532 		 * returns a perfect match in case a netmask is specified.
533 		 * For host routes only a longest prefix match is returned
534 		 * so it is necessary to compare the existence of the netmaks.
535 		 * If both have a netmask rn_lookup() did a perfect match and
536 		 * if none of them have a netmask both are host routes which is
537 		 * also a perfect match.
538 		 */
539 		if (rtm->rtm_type != RTM_GET && !rt_mask(rt) != !netmask) {
540 				error = ESRCH;
541 				goto flush;
542 		}
543 
544 		switch (rtm->rtm_type) {
545 		case RTM_GET:
546 report:
547 			dst = rt_key(rt);
548 			gate = rt->rt_gateway;
549 			netmask = rt_mask(rt);
550 			genmask = rt->rt_genmask;
551 
552 			if (rt->rt_labelid) {
553 				bzero(&sa_rt, sizeof(sa_rt));
554 				sa_rt.sr_len = sizeof(sa_rt);
555 				label = rtlabel_id2name(rt->rt_labelid);
556 				if (label != NULL)
557 					strlcpy(sa_rt.sr_label, label,
558 					    sizeof(sa_rt.sr_label));
559 				info.rti_info[RTAX_LABEL] =
560 				    (struct sockaddr *)&sa_rt;
561 			}
562 #ifdef MPLS
563 			if (rt->rt_flags & RTF_MPLS) {
564 				bzero(&sa_mpls, sizeof(sa_mpls));
565 				sa_mpls.smpls_family = AF_MPLS;
566 				sa_mpls.smpls_len = sizeof(sa_mpls);
567 				sa_mpls.smpls_label = ((struct rt_mpls *)
568 				    rt->rt_llinfo)->mpls_label;
569 				info.rti_info[RTAX_SRC] =
570 				    (struct sockaddr *)&sa_mpls;
571 				info.rti_mpls = ((struct rt_mpls *)
572 				    rt->rt_llinfo)->mpls_operation;
573 			}
574 #endif
575 			ifpaddr = 0;
576 			ifaaddr = 0;
577 			if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) &&
578 			    (ifp = rt->rt_ifp) != NULL) {
579 				ifpaddr =
580 				    TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
581 				ifaaddr = rt->rt_ifa->ifa_addr;
582 				if (ifp->if_flags & IFF_POINTOPOINT)
583 					brdaddr = rt->rt_ifa->ifa_dstaddr;
584 				else
585 					brdaddr = 0;
586 				rtm->rtm_index = ifp->if_index;
587 			}
588 			len = rt_msg2(rtm->rtm_type, RTM_VERSION, &info, NULL,
589 			    NULL);
590 			if (len > rtm->rtm_msglen) {
591 				struct rt_msghdr	*new_rtm;
592 				R_Malloc(new_rtm, struct rt_msghdr *, len);
593 				if (new_rtm == 0) {
594 					error = ENOBUFS;
595 					goto flush;
596 				}
597 				Bcopy(rtm, new_rtm, rtm->rtm_msglen);
598 				Free(rtm); rtm = new_rtm;
599 			}
600 			rt_msg2(rtm->rtm_type, RTM_VERSION, &info, (caddr_t)rtm,
601 			    NULL);
602 			rtm->rtm_flags = rt->rt_flags;
603 			rtm->rtm_use = 0;
604 			rtm->rtm_priority = rt->rt_priority & RTP_MASK;
605 			rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
606 			rtm->rtm_addrs = info.rti_addrs;
607 			break;
608 
609 		case RTM_CHANGE:
610 			/*
611 			 * new gateway could require new ifaddr, ifp;
612 			 * flags may also be different; ifp may be specified
613 			 * by ll sockaddr when protocol address is ambiguous
614 			 */
615 			if ((error = rt_getifa(&info,
616 			    /* XXX wrong, only rdomain */ tableid)) != 0)
617 				goto flush;
618 			if (gate && rt_setgate(rt, rt_key(rt), gate, tableid)) {
619 				error = EDQUOT;
620 				goto flush;
621 			}
622 			if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr,
623 			    /* XXX again rtable vs. rdomain */ tableid)) &&
624 			    (ifp = ifa->ifa_ifp) && (ifaaddr || gate))
625 				ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
626 				    ifp);
627 			else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr,
628 			    /* XXX one more time */ tableid))) ||
629 			    (gate && (ifa = ifa_ifwithroute(rt->rt_flags,
630 			    rt_key(rt), gate, /* XXX again */ tableid))))
631 				ifp = ifa->ifa_ifp;
632 			if (ifa) {
633 				struct ifaddr *oifa = rt->rt_ifa;
634 				if (oifa != ifa) {
635 				    if (oifa && oifa->ifa_rtrequest)
636 					oifa->ifa_rtrequest(RTM_DELETE, rt,
637 					    &info);
638 				    IFAFREE(rt->rt_ifa);
639 				    rt->rt_ifa = ifa;
640 				    ifa->ifa_refcnt++;
641 				    rt->rt_ifp = ifp;
642 				}
643 			}
644 
645 			/* XXX Hack to allow some flags to be toggled */
646 			if (rtm->rtm_fmask & RTF_FMASK)
647 				rt->rt_flags = (rt->rt_flags &
648 				    ~rtm->rtm_fmask) |
649 				    (rtm->rtm_flags & rtm->rtm_fmask);
650 
651 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
652 			    &rt->rt_rmx);
653 			rtm->rtm_index = rt->rt_ifp->if_index;
654 			rtm->rtm_priority = rt->rt_priority & RTP_MASK;
655 			if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
656 				rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
657 			if (genmask)
658 				rt->rt_genmask = genmask;
659 			if (info.rti_info[RTAX_LABEL] != NULL) {
660 				char *rtlabel = ((struct sockaddr_rtlabel *)
661 				    info.rti_info[RTAX_LABEL])->sr_label;
662 				rtlabel_unref(rt->rt_labelid);
663 				rt->rt_labelid =
664 				    rtlabel_name2id(rtlabel);
665 			}
666 #ifdef MPLS
667 			if (info.rti_info[RTAX_SRC] != NULL) {
668 				struct rt_mpls *rt_mpls;
669 
670 				psa_mpls = (struct sockaddr_mpls *)
671 				    info.rti_info[RTAX_SRC];
672 
673 				if (rt->rt_llinfo == NULL) {
674 					rt->rt_llinfo = (caddr_t)
675 					    malloc(sizeof(struct rt_mpls),
676 					    M_TEMP, M_NOWAIT|M_ZERO);
677 				}
678 				if (rt->rt_llinfo == NULL) {
679 					error = ENOMEM;
680 					goto flush;
681 				}
682 
683 				rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
684 
685 				if (psa_mpls != NULL) {
686 					rt_mpls->mpls_label =
687 					    psa_mpls->smpls_label;
688 				}
689 
690 				rt_mpls->mpls_operation = info.rti_mpls;
691 
692 				/* XXX: set experimental bits */
693 
694 				rt->rt_flags |= RTF_MPLS;
695 			} else {
696 				if (rt->rt_llinfo != NULL &&
697 				    rt->rt_flags & RTF_MPLS) {
698 					free(rt->rt_llinfo, M_TEMP);
699 					rt->rt_llinfo = NULL;
700 
701 					rt->rt_flags &= (~RTF_MPLS);
702 				}
703 			}
704 #endif
705 			if_group_routechange(dst, netmask);
706 			/* FALLTHROUGH */
707 		case RTM_LOCK:
708 			rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
709 			rt->rt_rmx.rmx_locks |=
710 			    (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
711 			rtm->rtm_priority = rt->rt_priority & RTP_MASK;
712 			break;
713 		}
714 		break;
715 
716 	default:
717 		error = EOPNOTSUPP;
718 		break;
719 	}
720 
721 flush:
722 	if (rtm) {
723 		if (error)
724 			rtm->rtm_errno = error;
725 		else {
726 #ifdef MPLS
727 			if (rt && rt->rt_flags & RTF_MPLS)
728 				rtm->rtm_flags |= RTF_MPLS;
729 #endif
730 			rtm->rtm_flags |= RTF_DONE;
731 		}
732 	}
733 	if (rt)
734 		rtfree(rt);
735 
736 	/*
737 	 * Check to see if we don't want our own messages.
738 	 */
739 	if (!(so->so_options & SO_USELOOPBACK)) {
740 		if (route_cb.any_count <= 1) {
741 			if (rtm)
742 				Free(rtm);
743 			m_freem(m);
744 			return (error);
745 		}
746 		/* There is another listener, so construct message */
747 		rp = sotorawcb(so);
748 	}
749 	if (rp)
750 		rp->rcb_proto.sp_family = 0; /* Avoid us */
751 	if (dst)
752 		route_proto.sp_protocol = dst->sa_family;
753 	if (rtm) {
754 		m_copyback(m, 0, rtm->rtm_msglen, rtm);
755 		if (m->m_pkthdr.len < rtm->rtm_msglen) {
756 			m_freem(m);
757 			m = NULL;
758 		} else if (m->m_pkthdr.len > rtm->rtm_msglen)
759 			m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
760 		Free(rtm);
761 	}
762 	if (m)
763 		route_input(m, &route_proto, &route_src, &route_dst);
764 	if (rp)
765 		rp->rcb_proto.sp_family = PF_ROUTE;
766 
767 	return (error);
768 }
769 
770 void
771 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out)
772 {
773 	if (which & RTV_MTU)
774 		out->rmx_mtu = in->rmx_mtu;
775 	if (which & RTV_EXPIRE)
776 		out->rmx_expire = in->rmx_expire;
777 	/* RTV_PRIORITY handled befor */
778 }
779 
780 void
781 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out)
782 {
783 	bzero(out, sizeof(*out));
784 	out->rmx_locks = in->rmx_locks;
785 	out->rmx_mtu = in->rmx_mtu;
786 	out->rmx_expire = in->rmx_expire;
787 	out->rmx_pksent = in->rmx_pksent;
788 }
789 
790 #define ROUNDUP(a) \
791 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
792 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
793 
794 void
795 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
796 {
797 	struct sockaddr	*sa;
798 	int		 i;
799 
800 	bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
801 	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
802 		if ((rtinfo->rti_addrs & (1 << i)) == 0)
803 			continue;
804 		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
805 		ADVANCE(cp, sa);
806 	}
807 }
808 
809 struct mbuf *
810 rt_msg1(int type, struct rt_addrinfo *rtinfo)
811 {
812 	struct rt_msghdr	*rtm;
813 	struct mbuf		*m;
814 	int			 i;
815 	struct sockaddr		*sa;
816 	int			 len, dlen, hlen;
817 
818 	switch (type) {
819 	case RTM_DELADDR:
820 	case RTM_NEWADDR:
821 		len = sizeof(struct ifa_msghdr);
822 		break;
823 	case RTM_IFINFO:
824 		len = sizeof(struct if_msghdr);
825 		break;
826 	case RTM_IFANNOUNCE:
827 		len = sizeof(struct if_announcemsghdr);
828 		break;
829 	default:
830 		len = sizeof(struct rt_msghdr);
831 		break;
832 	}
833 	if (len > MCLBYTES)
834 		panic("rt_msg1");
835 	m = m_gethdr(M_DONTWAIT, MT_DATA);
836 	if (m && len > MHLEN) {
837 		MCLGET(m, M_DONTWAIT);
838 		if ((m->m_flags & M_EXT) == 0) {
839 			m_free(m);
840 			m = NULL;
841 		}
842 	}
843 	if (m == 0)
844 		return (m);
845 	m->m_pkthdr.len = m->m_len = hlen = len;
846 	m->m_pkthdr.rcvif = NULL;
847 	rtm = mtod(m, struct rt_msghdr *);
848 	bzero(rtm, len);
849 	for (i = 0; i < RTAX_MAX; i++) {
850 		if (rtinfo == NULL || (sa = rtinfo->rti_info[i]) == NULL)
851 			continue;
852 		rtinfo->rti_addrs |= (1 << i);
853 		dlen = ROUNDUP(sa->sa_len);
854 		m_copyback(m, len, dlen, sa);
855 		len += dlen;
856 	}
857 	if (m->m_pkthdr.len != len) {
858 		m_freem(m);
859 		return (NULL);
860 	}
861 	rtm->rtm_msglen = len;
862 	rtm->rtm_hdrlen = hlen;
863 	rtm->rtm_version = RTM_VERSION;
864 	rtm->rtm_type = type;
865 	return (m);
866 }
867 
868 int
869 rt_msg2(int type, int vers, struct rt_addrinfo *rtinfo, caddr_t cp,
870     struct walkarg *w)
871 {
872 	int		i;
873 	int		len, dlen, hlen, second_time = 0;
874 	caddr_t		cp0;
875 
876 	rtinfo->rti_addrs = 0;
877 again:
878 	switch (type) {
879 	case RTM_DELADDR:
880 	case RTM_NEWADDR:
881 		len = sizeof(struct ifa_msghdr);
882 		break;
883 	case RTM_IFINFO:
884 		len = sizeof(struct if_msghdr);
885 		break;
886 	default:
887 		len = sizeof(struct rt_msghdr);
888 		break;
889 	}
890 	hlen = len;
891 	if ((cp0 = cp) != NULL)
892 		cp += len;
893 	for (i = 0; i < RTAX_MAX; i++) {
894 		struct sockaddr *sa;
895 
896 		if ((sa = rtinfo->rti_info[i]) == 0)
897 			continue;
898 		rtinfo->rti_addrs |= (1 << i);
899 		dlen = ROUNDUP(sa->sa_len);
900 		if (cp) {
901 			bcopy(sa, cp, (size_t)dlen);
902 			cp += dlen;
903 		}
904 		len += dlen;
905 	}
906 	/* align message length to the next natural boundary */
907 	len = ALIGN(len);
908 	if (cp == 0 && w != NULL && !second_time) {
909 		struct walkarg *rw = w;
910 
911 		rw->w_needed += len;
912 		if (rw->w_needed <= 0 && rw->w_where) {
913 			if (rw->w_tmemsize < len) {
914 				if (rw->w_tmem)
915 					free(rw->w_tmem, M_RTABLE);
916 				rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT);
917 				if (rw->w_tmem)
918 					rw->w_tmemsize = len;
919 			}
920 			if (rw->w_tmem) {
921 				cp = rw->w_tmem;
922 				second_time = 1;
923 				goto again;
924 			} else
925 				rw->w_where = 0;
926 		}
927 	}
928 	if (cp && w)		/* clear the message header */
929 		bzero(cp0, hlen);
930 
931 	if (cp) {
932 		struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
933 
934 		rtm->rtm_version = RTM_VERSION;
935 		rtm->rtm_type = type;
936 		rtm->rtm_msglen = len;
937 		rtm->rtm_hdrlen = hlen;
938 	}
939 	return (len);
940 }
941 
942 /*
943  * This routine is called to generate a message from the routing
944  * socket indicating that a redirect has occurred, a routing lookup
945  * has failed, or that a protocol has detected timeouts to a particular
946  * destination.
947  */
948 void
949 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags,
950     struct ifnet *ifp, int error, u_int tableid)
951 {
952 	struct rt_msghdr	*rtm;
953 	struct mbuf		*m;
954 	struct sockaddr		*sa = rtinfo->rti_info[RTAX_DST];
955 
956 	if (route_cb.any_count == 0)
957 		return;
958 	m = rt_msg1(type, rtinfo);
959 	if (m == 0)
960 		return;
961 	rtm = mtod(m, struct rt_msghdr *);
962 	rtm->rtm_flags = RTF_DONE | flags;
963 	rtm->rtm_errno = error;
964 	rtm->rtm_tableid = tableid;
965 	rtm->rtm_addrs = rtinfo->rti_addrs;
966 	if (ifp != NULL)
967 		rtm->rtm_index = ifp->if_index;
968 	if (sa == NULL)
969 		route_proto.sp_protocol = 0;
970 	else
971 		route_proto.sp_protocol = sa->sa_family;
972 	route_input(m, &route_proto, &route_src, &route_dst);
973 }
974 
975 /*
976  * This routine is called to generate a message from the routing
977  * socket indicating that the status of a network interface has changed.
978  */
979 void
980 rt_ifmsg(struct ifnet *ifp)
981 {
982 	struct if_msghdr	*ifm;
983 	struct mbuf		*m;
984 
985 	if (route_cb.any_count == 0)
986 		return;
987 	m = rt_msg1(RTM_IFINFO, NULL);
988 	if (m == 0)
989 		return;
990 	ifm = mtod(m, struct if_msghdr *);
991 	ifm->ifm_index = ifp->if_index;
992 	ifm->ifm_flags = ifp->if_flags;
993 	ifm->ifm_xflags = ifp->if_xflags;
994 	ifm->ifm_data = ifp->if_data;
995 	ifm->ifm_addrs = 0;
996 	route_proto.sp_protocol = 0;
997 	route_input(m, &route_proto, &route_src, &route_dst);
998 }
999 
1000 /*
1001  * This is called to generate messages from the routing socket
1002  * indicating a network interface has had addresses associated with it.
1003  * if we ever reverse the logic and replace messages TO the routing
1004  * socket indicate a request to configure interfaces, then it will
1005  * be unnecessary as the routing socket will automatically generate
1006  * copies of it.
1007  */
1008 void
1009 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
1010 {
1011 	struct rt_addrinfo	 info;
1012 	struct sockaddr		*sa = NULL;
1013 	int			 pass;
1014 	struct mbuf		*m = NULL;
1015 	struct ifnet		*ifp = ifa->ifa_ifp;
1016 
1017 	if (route_cb.any_count == 0)
1018 		return;
1019 	for (pass = 1; pass < 3; pass++) {
1020 		bzero(&info, sizeof(info));
1021 		if ((cmd == RTM_ADD && pass == 1) ||
1022 		    (cmd == RTM_DELETE && pass == 2)) {
1023 			struct ifa_msghdr	*ifam;
1024 			int			 ncmd;
1025 
1026 			if (cmd == RTM_ADD)
1027 				ncmd = RTM_NEWADDR;
1028 			else
1029 				ncmd = RTM_DELADDR;
1030 
1031 			ifaaddr = sa = ifa->ifa_addr;
1032 			ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
1033 			netmask = ifa->ifa_netmask;
1034 			brdaddr = ifa->ifa_dstaddr;
1035 			if ((m = rt_msg1(ncmd, &info)) == NULL)
1036 				continue;
1037 			ifam = mtod(m, struct ifa_msghdr *);
1038 			ifam->ifam_index = ifp->if_index;
1039 			ifam->ifam_metric = ifa->ifa_metric;
1040 			ifam->ifam_flags = ifa->ifa_flags;
1041 			ifam->ifam_addrs = info.rti_addrs;
1042 			ifam->ifam_tableid = ifp->if_rdomain;
1043 		}
1044 		if ((cmd == RTM_ADD && pass == 2) ||
1045 		    (cmd == RTM_DELETE && pass == 1)) {
1046 			struct rt_msghdr *rtm;
1047 
1048 			if (rt == 0)
1049 				continue;
1050 			netmask = rt_mask(rt);
1051 			dst = sa = rt_key(rt);
1052 			gate = rt->rt_gateway;
1053 			if ((m = rt_msg1(cmd, &info)) == NULL)
1054 				continue;
1055 			rtm = mtod(m, struct rt_msghdr *);
1056 			rtm->rtm_index = ifp->if_index;
1057 			rtm->rtm_flags |= rt->rt_flags;
1058 			rtm->rtm_errno = error;
1059 			rtm->rtm_addrs = info.rti_addrs;
1060 			rtm->rtm_tableid = ifp->if_rdomain;
1061 		}
1062 		if (sa == NULL)
1063 			route_proto.sp_protocol = 0;
1064 		else
1065 			route_proto.sp_protocol = sa->sa_family;
1066 		route_input(m, &route_proto, &route_src, &route_dst);
1067 	}
1068 }
1069 
1070 /*
1071  * This is called to generate routing socket messages indicating
1072  * network interface arrival and departure.
1073  */
1074 void
1075 rt_ifannouncemsg(struct ifnet *ifp, int what)
1076 {
1077 	struct if_announcemsghdr	*ifan;
1078 	struct mbuf			*m;
1079 
1080 	if (route_cb.any_count == 0)
1081 		return;
1082 	m = rt_msg1(RTM_IFANNOUNCE, NULL);
1083 	if (m == 0)
1084 		return;
1085 	ifan = mtod(m, struct if_announcemsghdr *);
1086 	ifan->ifan_index = ifp->if_index;
1087 	strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
1088 	ifan->ifan_what = what;
1089 	route_proto.sp_protocol = 0;
1090 	route_input(m, &route_proto, &route_src, &route_dst);
1091 }
1092 
1093 /*
1094  * This is used in dumping the kernel table via sysctl().
1095  */
1096 int
1097 sysctl_dumpentry(struct radix_node *rn, void *v)
1098 {
1099 	struct walkarg		*w = v;
1100 	struct rtentry		*rt = (struct rtentry *)rn;
1101 	int			 error = 0, size;
1102 	struct rt_addrinfo	 info;
1103 #ifdef MPLS
1104 	struct sockaddr_mpls	 sa_mpls;
1105 #endif
1106 	struct sockaddr_rtlabel	 sa_rt;
1107 	const char		*label;
1108 
1109 	if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
1110 		return 0;
1111 	bzero(&info, sizeof(info));
1112 	dst = rt_key(rt);
1113 	gate = rt->rt_gateway;
1114 	netmask = rt_mask(rt);
1115 	genmask = rt->rt_genmask;
1116 	if (rt->rt_ifp) {
1117 		ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
1118 		ifaaddr = rt->rt_ifa->ifa_addr;
1119 		if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
1120 			brdaddr = rt->rt_ifa->ifa_dstaddr;
1121 	}
1122 	if (rt->rt_labelid) {
1123 		bzero(&sa_rt, sizeof(sa_rt));
1124 		sa_rt.sr_len = sizeof(sa_rt);
1125 		label = rtlabel_id2name(rt->rt_labelid);
1126 		if (label != NULL) {
1127 			strlcpy(sa_rt.sr_label, label,
1128 			    sizeof(sa_rt.sr_label));
1129 			info.rti_info[RTAX_LABEL] =
1130 			    (struct sockaddr *)&sa_rt;
1131 		}
1132 	}
1133 #ifdef MPLS
1134 	if (rt->rt_flags & RTF_MPLS) {
1135 		bzero(&sa_mpls, sizeof(sa_mpls));
1136 		sa_mpls.smpls_family = AF_MPLS;
1137 		sa_mpls.smpls_len = sizeof(sa_mpls);
1138 		sa_mpls.smpls_label = ((struct rt_mpls *)
1139 		    rt->rt_llinfo)->mpls_label;
1140 		info.rti_info[RTAX_SRC] = (struct sockaddr *)&sa_mpls;
1141 		info.rti_mpls = ((struct rt_mpls *)
1142 		    rt->rt_llinfo)->mpls_operation;
1143 	}
1144 #endif
1145 
1146 	size = rt_msg2(RTM_GET, RTM_VERSION, &info, NULL, w);
1147 	if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1148 		struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
1149 
1150 		rtm->rtm_flags = rt->rt_flags;
1151 		rtm->rtm_priority = rt->rt_priority & RTP_MASK;
1152 		rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
1153 		rtm->rtm_rmx.rmx_refcnt = rt->rt_refcnt;
1154 		rtm->rtm_index = rt->rt_ifp->if_index;
1155 		rtm->rtm_addrs = info.rti_addrs;
1156 #ifdef MPLS
1157 		rtm->rtm_mpls = info.rti_mpls;
1158 #endif
1159 		if ((error = copyout(rtm, w->w_where, size)) != 0)
1160 			w->w_where = NULL;
1161 		else
1162 			w->w_where += size;
1163 	}
1164 	return (error);
1165 }
1166 
1167 int
1168 sysctl_iflist(int af, struct walkarg *w)
1169 {
1170 	struct ifnet		*ifp;
1171 	struct ifaddr		*ifa;
1172 	struct rt_addrinfo	 info;
1173 	int			 len, error = 0;
1174 
1175 	bzero(&info, sizeof(info));
1176 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
1177 		if (w->w_arg && w->w_arg != ifp->if_index)
1178 			continue;
1179 		ifa = TAILQ_FIRST(&ifp->if_addrlist);
1180 		if (!ifa)
1181 			continue;
1182 		ifpaddr = ifa->ifa_addr;
1183 		len = rt_msg2(RTM_IFINFO, RTM_VERSION, &info, 0, w);
1184 		if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1185 			struct if_msghdr *ifm;
1186 
1187 			ifm = (struct if_msghdr *)w->w_tmem;
1188 			ifm->ifm_index = ifp->if_index;
1189 			ifm->ifm_flags = ifp->if_flags;
1190 			ifm->ifm_data = ifp->if_data;
1191 			ifm->ifm_addrs = info.rti_addrs;
1192 			error = copyout(ifm, w->w_where, len);
1193 			if (error)
1194 				return (error);
1195 			w->w_where += len;
1196 		}
1197 		ifpaddr = 0;
1198 		while ((ifa = TAILQ_NEXT(ifa, ifa_list)) !=
1199 		    TAILQ_END(&ifp->if_addrlist)) {
1200 			if (af && af != ifa->ifa_addr->sa_family)
1201 				continue;
1202 			ifaaddr = ifa->ifa_addr;
1203 			netmask = ifa->ifa_netmask;
1204 			brdaddr = ifa->ifa_dstaddr;
1205 			len = rt_msg2(RTM_NEWADDR, RTM_VERSION, &info, 0, w);
1206 			if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1207 				struct ifa_msghdr *ifam;
1208 
1209 				ifam = (struct ifa_msghdr *)w->w_tmem;
1210 				ifam->ifam_index = ifa->ifa_ifp->if_index;
1211 				ifam->ifam_flags = ifa->ifa_flags;
1212 				ifam->ifam_metric = ifa->ifa_metric;
1213 				ifam->ifam_addrs = info.rti_addrs;
1214 				error = copyout(w->w_tmem, w->w_where, len);
1215 				if (error)
1216 					return (error);
1217 				w->w_where += len;
1218 			}
1219 		}
1220 		ifaaddr = netmask = brdaddr = 0;
1221 	}
1222 	return (0);
1223 }
1224 
1225 int
1226 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new,
1227     size_t newlen)
1228 {
1229 	struct radix_node_head	*rnh;
1230 	int			 i, s, error = EINVAL;
1231 	u_char  		 af;
1232 	struct walkarg		 w;
1233 	u_int			 tableid = 0;
1234 
1235 	if (new)
1236 		return (EPERM);
1237 	if (namelen < 3 || namelen > 4)
1238 		return (EINVAL);
1239 	af = name[0];
1240 	bzero(&w, sizeof(w));
1241 	w.w_where = where;
1242 	w.w_given = *given;
1243 	w.w_needed = 0 - w.w_given;
1244 	w.w_op = name[1];
1245 	w.w_arg = name[2];
1246 
1247 	if (namelen == 4) {
1248 		tableid = name[3];
1249 		if (!rtable_exists(tableid))
1250 			return (EINVAL);
1251 	}
1252 
1253 	s = splsoftnet();
1254 	switch (w.w_op) {
1255 
1256 	case NET_RT_DUMP:
1257 	case NET_RT_FLAGS:
1258 		for (i = 1; i <= AF_MAX; i++)
1259 			if ((rnh = rt_gettable(i, tableid)) != NULL &&
1260 			    (af == 0 || af == i) &&
1261 			    (error = (*rnh->rnh_walktree)(rnh,
1262 			    sysctl_dumpentry, &w)))
1263 				break;
1264 		break;
1265 
1266 	case NET_RT_IFLIST:
1267 		error = sysctl_iflist(af, &w);
1268 		break;
1269 
1270 	case NET_RT_STATS:
1271 		error = sysctl_rdstruct(where, given, new,
1272 		    &rtstat, sizeof(rtstat));
1273 		splx(s);
1274 		return (error);
1275 	}
1276 	splx(s);
1277 	if (w.w_tmem)
1278 		free(w.w_tmem, M_RTABLE);
1279 	w.w_needed += w.w_given;
1280 	if (where) {
1281 		*given = w.w_where - (caddr_t)where;
1282 		if (*given < w.w_needed)
1283 			return (ENOMEM);
1284 	} else
1285 		*given = (11 * w.w_needed) / 10;
1286 
1287 	return (error);
1288 }
1289 
1290 /*
1291  * Definitions of protocols supported in the ROUTE domain.
1292  */
1293 
1294 extern	struct domain routedomain;		/* or at least forward */
1295 
1296 struct protosw routesw[] = {
1297 { SOCK_RAW,	&routedomain,	0,		PR_ATOMIC|PR_ADDR,
1298   route_input,	route_output,	raw_ctlinput,	route_ctloutput,
1299   route_usrreq,
1300   raw_init,	0,		0,		0,
1301   sysctl_rtable,
1302 }
1303 };
1304 
1305 struct domain routedomain =
1306     { PF_ROUTE, "route", route_init, 0, 0,
1307       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
1308