xref: /dragonfly/sys/net/rtsock.c (revision 2441f4a6)
1 /*
2  * Copyright (c) 2004, 2005 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Jeffrey M. Hsu.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of The DragonFly Project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific, prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 2004, 2005 Jeffrey M. Hsu.  All rights reserved.
35  *
36  * License terms: all terms for the DragonFly license above plus the following:
37  *
38  * 4. All advertising materials mentioning features or use of this software
39  *    must display the following acknowledgement:
40  *
41  *	This product includes software developed by Jeffrey M. Hsu
42  *	for the DragonFly Project.
43  *
44  *    This requirement may be waived with permission from Jeffrey Hsu.
45  *    Permission will be granted to any DragonFly user for free.
46  *    This requirement will sunset and may be removed on Jan 31, 2006,
47  *    after which the standard DragonFly license (as shown above) will
48  *    apply.
49  */
50 
51 /*
52  * Copyright (c) 1988, 1991, 1993
53  *	The Regents of the University of California.  All rights reserved.
54  *
55  * Redistribution and use in source and binary forms, with or without
56  * modification, are permitted provided that the following conditions
57  * are met:
58  * 1. Redistributions of source code must retain the above copyright
59  *    notice, this list of conditions and the following disclaimer.
60  * 2. Redistributions in binary form must reproduce the above copyright
61  *    notice, this list of conditions and the following disclaimer in the
62  *    documentation and/or other materials provided with the distribution.
63  * 3. All advertising materials mentioning features or use of this software
64  *    must display the following acknowledgement:
65  *	This product includes software developed by the University of
66  *	California, Berkeley and its contributors.
67  * 4. Neither the name of the University nor the names of its contributors
68  *    may be used to endorse or promote products derived from this software
69  *    without specific prior written permission.
70  *
71  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
72  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
73  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
74  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
75  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
76  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
77  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
78  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
79  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
80  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
81  * SUCH DAMAGE.
82  *
83  *	@(#)rtsock.c	8.7 (Berkeley) 10/12/95
84  * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $
85  * $DragonFly: src/sys/net/rtsock.c,v 1.21 2005/01/26 23:09:57 hsu Exp $
86  */
87 
88 #include <sys/param.h>
89 #include <sys/systm.h>
90 #include <sys/kernel.h>
91 #include <sys/sysctl.h>
92 #include <sys/proc.h>
93 #include <sys/malloc.h>
94 #include <sys/mbuf.h>
95 #include <sys/protosw.h>
96 #include <sys/socket.h>
97 #include <sys/socketvar.h>
98 #include <sys/domain.h>
99 
100 #include <machine/stdarg.h>
101 
102 #include <net/if.h>
103 #include <net/route.h>
104 #include <net/raw_cb.h>
105 
106 MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
107 
108 static struct route_cb {
109 	int	ip_count;
110 	int	ip6_count;
111 	int	ipx_count;
112 	int	ns_count;
113 	int	any_count;
114 } route_cb;
115 
116 static const struct sockaddr route_src = { 2, PF_ROUTE, };
117 
118 struct walkarg {
119 	int	w_tmemsize;
120 	int	w_op, w_arg;
121 	char	*w_tmem;
122 	struct sysctl_req *w_req;
123 };
124 
125 static struct mbuf *
126 		rt_msg_mbuf (int, struct rt_addrinfo *);
127 static void	rt_msg_buffer (int, struct rt_addrinfo *, void *buf, int len);
128 static int	rt_msgsize (int type, struct rt_addrinfo *rtinfo);
129 static int	rt_xaddrs (char *, char *, struct rt_addrinfo *);
130 static int	sysctl_dumpentry (struct radix_node *rn, void *vw);
131 static int	sysctl_iflist (int af, struct walkarg *w);
132 static int	route_output(struct mbuf *, struct socket *, ...);
133 static void	rt_setmetrics (u_long, struct rt_metrics *,
134 			       struct rt_metrics *);
135 
136 /*
137  * It really doesn't make any sense at all for this code to share much
138  * with raw_usrreq.c, since its functionality is so restricted.  XXX
139  */
140 static int
141 rts_abort(struct socket *so)
142 {
143 	int s, error;
144 
145 	s = splnet();
146 	error = raw_usrreqs.pru_abort(so);
147 	splx(s);
148 	return error;
149 }
150 
151 /* pru_accept is EOPNOTSUPP */
152 
153 static int
154 rts_attach(struct socket *so, int proto, struct pru_attach_info *ai)
155 {
156 	struct rawcb *rp;
157 	int s, error;
158 
159 	if (sotorawcb(so) != NULL)
160 		return EISCONN;	/* XXX panic? */
161 
162 	rp = malloc(sizeof *rp, M_PCB, M_WAITOK | M_ZERO);
163 	if (rp == NULL)
164 		return ENOBUFS;
165 
166 	/*
167 	 * The splnet() is necessary to block protocols from sending
168 	 * error notifications (like RTM_REDIRECT or RTM_LOSING) while
169 	 * this PCB is extant but incompletely initialized.
170 	 * Probably we should try to do more of this work beforehand and
171 	 * eliminate the spl.
172 	 */
173 	s = splnet();
174 	so->so_pcb = rp;
175 	error = raw_attach(so, proto, ai->sb_rlimit);
176 	rp = sotorawcb(so);
177 	if (error) {
178 		splx(s);
179 		free(rp, M_PCB);
180 		return error;
181 	}
182 	switch(rp->rcb_proto.sp_protocol) {
183 	case AF_INET:
184 		route_cb.ip_count++;
185 		break;
186 	case AF_INET6:
187 		route_cb.ip6_count++;
188 		break;
189 	case AF_IPX:
190 		route_cb.ipx_count++;
191 		break;
192 	case AF_NS:
193 		route_cb.ns_count++;
194 		break;
195 	}
196 	rp->rcb_faddr = &route_src;
197 	route_cb.any_count++;
198 	soisconnected(so);
199 	so->so_options |= SO_USELOOPBACK;
200 	splx(s);
201 	return 0;
202 }
203 
204 static int
205 rts_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
206 {
207 	int s, error;
208 
209 	s = splnet();
210 	error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */
211 	splx(s);
212 	return error;
213 }
214 
215 static int
216 rts_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
217 {
218 	int s, error;
219 
220 	s = splnet();
221 	error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */
222 	splx(s);
223 	return error;
224 }
225 
226 /* pru_connect2 is EOPNOTSUPP */
227 /* pru_control is EOPNOTSUPP */
228 
229 static int
230 rts_detach(struct socket *so)
231 {
232 	struct rawcb *rp = sotorawcb(so);
233 	int s, error;
234 
235 	s = splnet();
236 	if (rp != NULL) {
237 		switch(rp->rcb_proto.sp_protocol) {
238 		case AF_INET:
239 			route_cb.ip_count--;
240 			break;
241 		case AF_INET6:
242 			route_cb.ip6_count--;
243 			break;
244 		case AF_IPX:
245 			route_cb.ipx_count--;
246 			break;
247 		case AF_NS:
248 			route_cb.ns_count--;
249 			break;
250 		}
251 		route_cb.any_count--;
252 	}
253 	error = raw_usrreqs.pru_detach(so);
254 	splx(s);
255 	return error;
256 }
257 
258 static int
259 rts_disconnect(struct socket *so)
260 {
261 	int s, error;
262 
263 	s = splnet();
264 	error = raw_usrreqs.pru_disconnect(so);
265 	splx(s);
266 	return error;
267 }
268 
269 /* pru_listen is EOPNOTSUPP */
270 
271 static int
272 rts_peeraddr(struct socket *so, struct sockaddr **nam)
273 {
274 	int s, error;
275 
276 	s = splnet();
277 	error = raw_usrreqs.pru_peeraddr(so, nam);
278 	splx(s);
279 	return error;
280 }
281 
282 /* pru_rcvd is EOPNOTSUPP */
283 /* pru_rcvoob is EOPNOTSUPP */
284 
285 static int
286 rts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
287 	 struct mbuf *control, struct thread *td)
288 {
289 	int s, error;
290 
291 	s = splnet();
292 	error = raw_usrreqs.pru_send(so, flags, m, nam, control, td);
293 	splx(s);
294 	return error;
295 }
296 
297 /* pru_sense is null */
298 
299 static int
300 rts_shutdown(struct socket *so)
301 {
302 	int s, error;
303 
304 	s = splnet();
305 	error = raw_usrreqs.pru_shutdown(so);
306 	splx(s);
307 	return error;
308 }
309 
310 static int
311 rts_sockaddr(struct socket *so, struct sockaddr **nam)
312 {
313 	int s, error;
314 
315 	s = splnet();
316 	error = raw_usrreqs.pru_sockaddr(so, nam);
317 	splx(s);
318 	return error;
319 }
320 
321 static struct pr_usrreqs route_usrreqs = {
322 	rts_abort, pru_accept_notsupp, rts_attach, rts_bind, rts_connect,
323 	pru_connect2_notsupp, pru_control_notsupp, rts_detach, rts_disconnect,
324 	pru_listen_notsupp, rts_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
325 	rts_send, pru_sense_null, rts_shutdown, rts_sockaddr,
326 	sosend, soreceive, sopoll
327 };
328 
329 static __inline sa_family_t
330 familyof(struct sockaddr *sa)
331 {
332 	return (sa != NULL ? sa->sa_family : 0);
333 }
334 
335 static void
336 rts_input(struct mbuf *m, sa_family_t family)
337 {
338 	static const struct sockaddr route_dst = { 2, PF_ROUTE, };
339 	struct sockproto route_proto = { PF_ROUTE, family };
340 
341 	raw_input(m, &route_proto, &route_src, &route_dst);
342 }
343 
344 static void *
345 reallocbuf(void *ptr, size_t len, size_t olen)
346 {
347 	void *newptr;
348 
349 	newptr = malloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
350 	if (newptr == NULL)
351 		return NULL;
352 	bcopy(ptr, newptr, olen);
353 	free(ptr, M_RTABLE);
354 	return (newptr);
355 }
356 
357 static int
358 fillrtmsg(struct rt_msghdr **prtm, struct rtentry *rt,
359 	  struct rt_addrinfo *rtinfo)
360 {
361 	int msglen;
362 	struct rt_msghdr *rtm = *prtm;
363 
364 	/* Fill in rt_addrinfo for call to rt_msg_buffer(). */
365 	rtinfo->rti_dst = rt_key(rt);
366 	rtinfo->rti_gateway = rt->rt_gateway;
367 	rtinfo->rti_netmask = rt_mask(rt);		/* might be NULL */
368 	rtinfo->rti_genmask = rt->rt_genmask;		/* might be NULL */
369 	if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
370 		if (rt->rt_ifp != NULL) {
371 			rtinfo->rti_ifpaddr =
372 			    TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr;
373 			rtinfo->rti_ifaaddr = rt->rt_ifa->ifa_addr;
374 			if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
375 				rtinfo->rti_bcastaddr = rt->rt_ifa->ifa_dstaddr;
376 			rtm->rtm_index = rt->rt_ifp->if_index;
377 		} else {
378 			rtinfo->rti_ifpaddr = NULL;
379 			rtinfo->rti_ifaaddr = NULL;
380 	    }
381 	}
382 
383 	msglen = rt_msgsize(rtm->rtm_type, rtinfo);
384 	if (rtm->rtm_msglen < msglen) {
385 		rtm = reallocbuf(rtm, msglen, rtm->rtm_msglen);
386 		if (rtm == NULL)
387 			return (ENOBUFS);
388 		*prtm = rtm;
389 	}
390 	rt_msg_buffer(rtm->rtm_type, rtinfo, rtm, msglen);
391 
392 	rtm->rtm_flags = rt->rt_flags;
393 	rtm->rtm_rmx = rt->rt_rmx;
394 	rtm->rtm_addrs = rtinfo->rti_addrs;
395 
396 	return (0);
397 }
398 
399 /*ARGSUSED*/
400 static int
401 route_output(struct mbuf *m, struct socket *so, ...)
402 {
403 	struct rt_msghdr *rtm = NULL;
404 	struct rtentry *rt = NULL;
405 	struct rtentry *saved_nrt = NULL;
406 	struct radix_node_head *rnh;
407 	struct ifaddr *ifa = NULL;
408 	struct rawcb *rp = NULL;
409 	struct pr_output_info *oi;
410 	struct rt_addrinfo rtinfo;
411 	int len, error = 0;
412 	__va_list ap;
413 
414 	__va_start(ap, so);
415 	oi = __va_arg(ap, struct pr_output_info *);
416 	__va_end(ap);
417 
418 #define gotoerr(e) { error = e; goto flush;}
419 
420 	if (m == NULL ||
421 	    (m->m_len < sizeof(long) &&
422 	     (m = m_pullup(m, sizeof(long))) == NULL))
423 		return (ENOBUFS);
424 	if (!(m->m_flags & M_PKTHDR))
425 		panic("route_output");
426 	len = m->m_pkthdr.len;
427 	if (len < sizeof(struct rt_msghdr) ||
428 	    len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
429 		rtinfo.rti_dst = NULL;
430 		gotoerr(EINVAL);
431 	}
432 	rtm = malloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
433 	if (rtm == NULL) {
434 		rtinfo.rti_dst = NULL;
435 		gotoerr(ENOBUFS);
436 	}
437 	m_copydata(m, 0, len, (caddr_t)rtm);
438 	if (rtm->rtm_version != RTM_VERSION) {
439 		rtinfo.rti_dst = NULL;
440 		gotoerr(EPROTONOSUPPORT);
441 	}
442 	rtm->rtm_pid = oi->p_pid;
443 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
444 	rtinfo.rti_addrs = rtm->rtm_addrs;
445 	if (rt_xaddrs((char *)(rtm + 1), (char *)rtm + len, &rtinfo) != 0) {
446 		rtinfo.rti_dst = NULL;
447 		gotoerr(EINVAL);
448 	}
449 	rtinfo.rti_flags = rtm->rtm_flags;
450 	if (rtinfo.rti_dst == NULL || rtinfo.rti_dst->sa_family >= AF_MAX ||
451 	    (rtinfo.rti_gateway && rtinfo.rti_gateway->sa_family >= AF_MAX))
452 		gotoerr(EINVAL);
453 
454 	if (rtinfo.rti_genmask != NULL) {
455 		struct radix_node *n;
456 
457 #define	clen(s)	(*(u_char *)(s))
458 		n = rn_addmask((char *)rtinfo.rti_genmask, TRUE, 1);
459 		if (n != NULL &&
460 		    rtinfo.rti_genmask->sa_len >= clen(n->rn_key) &&
461 		    bcmp((char *)rtinfo.rti_genmask + 1,
462 		         (char *)n->rn_key + 1, clen(n->rn_key) - 1) == 0)
463 			rtinfo.rti_genmask = (struct sockaddr *)n->rn_key;
464 		else
465 			gotoerr(ENOBUFS);
466 	}
467 
468 	/*
469 	 * Verify that the caller has the appropriate privilege; RTM_GET
470 	 * is the only operation the non-superuser is allowed.
471 	 */
472 	if (rtm->rtm_type != RTM_GET && suser_cred(so->so_cred, 0) != 0)
473 		gotoerr(EPERM);
474 
475 	switch (rtm->rtm_type) {
476 	case RTM_ADD:
477 		if (rtinfo.rti_gateway == NULL)
478 			gotoerr(EINVAL);
479 		error = rtrequest1(RTM_ADD, &rtinfo, &saved_nrt);
480 		if (error == 0 && saved_nrt != NULL) {
481 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
482 			    &saved_nrt->rt_rmx);
483 			saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
484 			saved_nrt->rt_rmx.rmx_locks |=
485 			    (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
486 			--saved_nrt->rt_refcnt;
487 			saved_nrt->rt_genmask = rtinfo.rti_genmask;
488 		}
489 		break;
490 	case RTM_DELETE:
491 		error = rtrequest1(RTM_DELETE, &rtinfo, &saved_nrt);
492 		if (error == 0) {
493 			if ((rt = saved_nrt))
494 				rt->rt_refcnt++;
495 			if (fillrtmsg(&rtm, rt, &rtinfo) != 0)
496 				gotoerr(ENOBUFS);
497 		}
498 		break;
499 	case RTM_GET:
500 	case RTM_CHANGE:
501 	case RTM_LOCK:
502 		if ((rnh = rt_tables[rtinfo.rti_dst->sa_family]) == NULL)
503 			gotoerr(EAFNOSUPPORT);
504 		rt = (struct rtentry *)
505 		    rnh->rnh_lookup((char *)rtinfo.rti_dst,
506 		    		    (char *)rtinfo.rti_netmask, rnh);
507 		if (rt == NULL)
508 			gotoerr(ESRCH);
509 		rt->rt_refcnt++;
510 
511 		switch(rtm->rtm_type) {
512 		case RTM_GET:
513 			if (fillrtmsg(&rtm, rt, &rtinfo) != 0)
514 				gotoerr(ENOBUFS);
515 			break;
516 		case RTM_CHANGE:
517 			/*
518 			 * new gateway could require new ifaddr, ifp;
519 			 * flags may also be different; ifp may be specified
520 			 * by ll sockaddr when protocol address is ambiguous
521 			 */
522 			if (((rt->rt_flags & RTF_GATEWAY) &&
523 			     rtinfo.rti_gateway != NULL) ||
524 			    rtinfo.rti_ifpaddr != NULL ||
525 			    (rtinfo.rti_ifaaddr != NULL &&
526 			     sa_equal(rtinfo.rti_ifaaddr,
527 			     	      rt->rt_ifa->ifa_addr))) {
528 				error = rt_getifa(&rtinfo);
529 				if (error != 0)
530 					gotoerr(error);
531 			}
532 			if (rtinfo.rti_gateway != NULL) {
533 				error = rt_setgate(rt, rt_key(rt),
534 						   rtinfo.rti_gateway);
535 				if (error != 0)
536 					gotoerr(error);
537 			}
538 			if ((ifa = rtinfo.rti_ifa) != NULL) {
539 				struct ifaddr *oifa = rt->rt_ifa;
540 
541 				if (oifa != ifa) {
542 					if (oifa && oifa->ifa_rtrequest)
543 						oifa->ifa_rtrequest(RTM_DELETE,
544 						    rt, &rtinfo);
545 					IFAFREE(rt->rt_ifa);
546 					IFAREF(ifa);
547 					rt->rt_ifa = ifa;
548 					rt->rt_ifp = rtinfo.rti_ifp;
549 				}
550 			}
551 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
552 				      &rt->rt_rmx);
553 			if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
554 			       rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &rtinfo);
555 			if (rtinfo.rti_genmask != NULL)
556 				rt->rt_genmask = rtinfo.rti_genmask;
557 			/*
558 			 * Fall into
559 			 */
560 		case RTM_LOCK:
561 			rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
562 			rt->rt_rmx.rmx_locks |=
563 				(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
564 			break;
565 		}
566 
567 		break;
568 	default:
569 		gotoerr(EOPNOTSUPP);
570 	}
571 
572 flush:
573 	if (rtm != NULL) {
574 		if (error != 0)
575 			rtm->rtm_errno = error;
576 		else
577 			rtm->rtm_flags |= RTF_DONE;
578 	}
579 	if (rt != NULL)
580 		rtfree(rt);
581 	/*
582 	 * Check to see if we don't want our own messages.
583 	 */
584 	if (!(so->so_options & SO_USELOOPBACK)) {
585 		if (route_cb.any_count <= 1) {
586 			if (rtm != NULL)
587 				free(rtm, M_RTABLE);
588 			m_freem(m);
589 			return (error);
590 		}
591 		/* There is another listener, so construct message */
592 		rp = sotorawcb(so);
593 	}
594 	if (rtm != NULL) {
595 		m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
596 		if (m->m_pkthdr.len < rtm->rtm_msglen) {
597 			m_freem(m);
598 			m = NULL;
599 		} else if (m->m_pkthdr.len > rtm->rtm_msglen)
600 			m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
601 		free(rtm, M_RTABLE);
602 	}
603 	if (rp != NULL)
604 		rp->rcb_proto.sp_family = 0; /* Avoid us */
605 	if (m != NULL)
606 		rts_input(m, familyof(rtinfo.rti_dst));
607 	if (rp != NULL)
608 		rp->rcb_proto.sp_family = PF_ROUTE;
609 	return (error);
610 }
611 
612 static void
613 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_metrics *out)
614 {
615 #define setmetric(flag, elt) if (which & (flag)) out->elt = in->elt;
616 	setmetric(RTV_RPIPE, rmx_recvpipe);
617 	setmetric(RTV_SPIPE, rmx_sendpipe);
618 	setmetric(RTV_SSTHRESH, rmx_ssthresh);
619 	setmetric(RTV_RTT, rmx_rtt);
620 	setmetric(RTV_RTTVAR, rmx_rttvar);
621 	setmetric(RTV_HOPCOUNT, rmx_hopcount);
622 	setmetric(RTV_MTU, rmx_mtu);
623 	setmetric(RTV_EXPIRE, rmx_expire);
624 #undef setmetric
625 }
626 
627 #define ROUNDUP(a) \
628 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
629 
630 /*
631  * Extract the addresses of the passed sockaddrs.
632  * Do a little sanity checking so as to avoid bad memory references.
633  * This data is derived straight from userland.
634  */
635 static int
636 rt_xaddrs(char *cp, char *cplim, struct rt_addrinfo *rtinfo)
637 {
638 	struct sockaddr *sa;
639 	int i;
640 
641 	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
642 		if ((rtinfo->rti_addrs & (1 << i)) == 0)
643 			continue;
644 		sa = (struct sockaddr *)cp;
645 		/*
646 		 * It won't fit.
647 		 */
648 		if ((cp + sa->sa_len) > cplim) {
649 			return (EINVAL);
650 		}
651 
652 		/*
653 		 * There are no more...  Quit now.
654 		 * If there are more bits, they are in error.
655 		 * I've seen this.  route(1) can evidently generate these.
656 		 * This causes kernel to core dump.
657 		 * For compatibility, if we see this, point to a safe address.
658 		 */
659 		if (sa->sa_len == 0) {
660 			static struct sockaddr sa_zero = {
661 				sizeof sa_zero, AF_INET,
662 			};
663 
664 			rtinfo->rti_info[i] = &sa_zero;
665 			return (0); /* should be EINVAL but for compat */
666 		}
667 
668 		/* Accept the sockaddr. */
669 		rtinfo->rti_info[i] = sa;
670 		cp += ROUNDUP(sa->sa_len);
671 	}
672 	return (0);
673 }
674 
675 static int
676 rt_msghdrsize(int type)
677 {
678 	switch (type) {
679 	case RTM_DELADDR:
680 	case RTM_NEWADDR:
681 		return sizeof(struct ifa_msghdr);
682 	case RTM_DELMADDR:
683 	case RTM_NEWMADDR:
684 		return sizeof(struct ifma_msghdr);
685 	case RTM_IFINFO:
686 		return sizeof(struct if_msghdr);
687 	case RTM_IFANNOUNCE:
688 		return sizeof(struct if_announcemsghdr);
689 	default:
690 		return sizeof(struct rt_msghdr);
691 	}
692 }
693 
694 static int
695 rt_msgsize(int type, struct rt_addrinfo *rtinfo)
696 {
697 	int len, i;
698 
699 	len = rt_msghdrsize(type);
700 	for (i = 0; i < RTAX_MAX; i++) {
701 		if (rtinfo->rti_info[i] != NULL)
702 			len += ROUNDUP(rtinfo->rti_info[i]->sa_len);
703 	}
704 	len = ALIGN(len);
705 	return len;
706 }
707 
708 /*
709  * Build a routing message in a buffer.
710  * Copy the addresses in the rtinfo->rti_info[] sockaddr array
711  * to the end of the buffer after the message header.
712  *
713  * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[].
714  * This side-effect can be avoided if we reorder the addrs bitmask field in all
715  * the route messages to line up so we can set it here instead of back in the
716  * calling routine.
717  */
718 static void
719 rt_msg_buffer(int type, struct rt_addrinfo *rtinfo, void *buf, int msglen)
720 {
721 	struct rt_msghdr *rtm;
722 	char *cp;
723 	int dlen, i;
724 
725 	rtm = (struct rt_msghdr *) buf;
726 	rtm->rtm_version = RTM_VERSION;
727 	rtm->rtm_type = type;
728 	rtm->rtm_msglen = msglen;
729 
730 	cp = (char *)buf + rt_msghdrsize(type);
731 	rtinfo->rti_addrs = 0;
732 	for (i = 0; i < RTAX_MAX; i++) {
733 		struct sockaddr *sa;
734 
735 		if ((sa = rtinfo->rti_info[i]) == NULL)
736 			continue;
737 		rtinfo->rti_addrs |= (1 << i);
738 		dlen = ROUNDUP(sa->sa_len);
739 		bcopy(sa, cp, dlen);
740 		cp += dlen;
741 	}
742 }
743 
744 /*
745  * Build a routing message in a mbuf chain.
746  * Copy the addresses in the rtinfo->rti_info[] sockaddr array
747  * to the end of the mbuf after the message header.
748  *
749  * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[].
750  * This side-effect can be avoided if we reorder the addrs bitmask field in all
751  * the route messages to line up so we can set it here instead of back in the
752  * calling routine.
753  */
754 static struct mbuf *
755 rt_msg_mbuf(int type, struct rt_addrinfo *rtinfo)
756 {
757 	struct mbuf *m;
758 	struct rt_msghdr *rtm;
759 	int hlen, len;
760 	int i;
761 
762 	hlen = rt_msghdrsize(type);
763 	KASSERT(hlen <= MCLBYTES, ("rt_msg_mbuf: hlen %d doesn't fit", hlen));
764 
765 	m = m_gethdr(MB_DONTWAIT, MT_DATA);
766 	if (m == NULL)
767 		return (NULL);
768 	if (hlen > MHLEN) {
769 		MCLGET(m, MB_DONTWAIT);
770 		if (!(m->m_flags & M_EXT)) {
771 			m_free(m);
772 			return (NULL);
773 		}
774 	}
775 	m->m_pkthdr.len = m->m_len = hlen;
776 	m->m_pkthdr.rcvif = NULL;
777 	rtinfo->rti_addrs = 0;
778 	len = hlen;
779 	for (i = 0; i < RTAX_MAX; i++) {
780 		struct sockaddr *sa;
781 		int dlen;
782 
783 		if ((sa = rtinfo->rti_info[i]) == NULL)
784 			continue;
785 		rtinfo->rti_addrs |= (1 << i);
786 		dlen = ROUNDUP(sa->sa_len);
787 		m_copyback(m, len, dlen, (caddr_t)sa); /* can grow mbuf chain */
788 		len += dlen;
789 	}
790 	if (m->m_pkthdr.len != len) { /* one of the m_copyback() calls failed */
791 		m_freem(m);
792 		return (NULL);
793 	}
794 	rtm = mtod(m, struct rt_msghdr *);
795 	bzero(rtm, hlen);
796 	rtm->rtm_msglen = len;
797 	rtm->rtm_version = RTM_VERSION;
798 	rtm->rtm_type = type;
799 	return (m);
800 }
801 
802 /*
803  * This routine is called to generate a message from the routing
804  * socket indicating that a redirect has occurred, a routing lookup
805  * has failed, or that a protocol has detected timeouts to a particular
806  * destination.
807  */
808 void
809 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
810 {
811 	struct sockaddr *dst = rtinfo->rti_info[RTAX_DST];
812 	struct rt_msghdr *rtm;
813 	struct mbuf *m;
814 
815 	if (route_cb.any_count == 0)
816 		return;
817 	m = rt_msg_mbuf(type, rtinfo);
818 	if (m == NULL)
819 		return;
820 	rtm = mtod(m, struct rt_msghdr *);
821 	rtm->rtm_flags = RTF_DONE | flags;
822 	rtm->rtm_errno = error;
823 	rtm->rtm_addrs = rtinfo->rti_addrs;
824 	rts_input(m, familyof(dst));
825 }
826 
827 void
828 rt_dstmsg(int type, struct sockaddr *dst, int error)
829 {
830 	struct rt_msghdr *rtm;
831 	struct rt_addrinfo addrs;
832 	struct mbuf *m;
833 
834 	if (route_cb.any_count == 0)
835 		return;
836 	bzero(&addrs, sizeof(struct rt_addrinfo));
837 	addrs.rti_info[RTAX_DST] = dst;
838 	m = rt_msg_mbuf(type, &addrs);
839 	if (m == NULL)
840 		return;
841 	rtm = mtod(m, struct rt_msghdr *);
842 	rtm->rtm_flags = RTF_DONE;
843 	rtm->rtm_errno = error;
844 	rtm->rtm_addrs = addrs.rti_addrs;
845 	rts_input(m, familyof(dst));
846 }
847 
848 /*
849  * This routine is called to generate a message from the routing
850  * socket indicating that the status of a network interface has changed.
851  */
852 void
853 rt_ifmsg(struct ifnet *ifp)
854 {
855 	struct if_msghdr *ifm;
856 	struct mbuf *m;
857 	struct rt_addrinfo rtinfo;
858 
859 	if (route_cb.any_count == 0)
860 		return;
861 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
862 	m = rt_msg_mbuf(RTM_IFINFO, &rtinfo);
863 	if (m == NULL)
864 		return;
865 	ifm = mtod(m, struct if_msghdr *);
866 	ifm->ifm_index = ifp->if_index;
867 	ifm->ifm_flags = (u_short)ifp->if_flags;
868 	ifm->ifm_data = ifp->if_data;
869 	ifm->ifm_addrs = 0;
870 	rts_input(m, 0);
871 }
872 
873 static void
874 rt_ifamsg(int cmd, struct ifaddr *ifa)
875 {
876 	struct ifa_msghdr *ifam;
877 	struct rt_addrinfo rtinfo;
878 	struct mbuf *m;
879 	struct ifnet *ifp = ifa->ifa_ifp;
880 
881 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
882 	rtinfo.rti_ifaaddr = ifa->ifa_addr;
883 	rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
884 	rtinfo.rti_netmask = ifa->ifa_netmask;
885 	rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
886 
887 	m = rt_msg_mbuf(cmd, &rtinfo);
888 	if (m == NULL)
889 		return;
890 
891 	ifam = mtod(m, struct ifa_msghdr *);
892 	ifam->ifam_index = ifp->if_index;
893 	ifam->ifam_metric = ifa->ifa_metric;
894 	ifam->ifam_flags = ifa->ifa_flags;
895 	ifam->ifam_addrs = rtinfo.rti_addrs;
896 
897 	rts_input(m, familyof(ifa->ifa_addr));
898 }
899 
900 void
901 rt_rtmsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int error)
902 {
903 	struct rt_msghdr *rtm;
904 	struct rt_addrinfo rtinfo;
905 	struct mbuf *m;
906 	struct sockaddr *dst;
907 
908 	if (rt == NULL)
909 		return;
910 
911 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
912 	rtinfo.rti_dst = dst = rt_key(rt);
913 	rtinfo.rti_gateway = rt->rt_gateway;
914 	rtinfo.rti_netmask = rt_mask(rt);
915 	if (ifp != NULL)
916 		rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
917 	rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
918 
919 	m = rt_msg_mbuf(cmd, &rtinfo);
920 	if (m == NULL)
921 		return;
922 
923 	rtm = mtod(m, struct rt_msghdr *);
924 	if (ifp != NULL)
925 		rtm->rtm_index = ifp->if_index;
926 	rtm->rtm_flags |= rt->rt_flags;
927 	rtm->rtm_errno = error;
928 	rtm->rtm_addrs = rtinfo.rti_addrs;
929 
930 	rts_input(m, familyof(dst));
931 }
932 
933 /*
934  * This is called to generate messages from the routing socket
935  * indicating a network interface has had addresses associated with it.
936  * if we ever reverse the logic and replace messages TO the routing
937  * socket indicate a request to configure interfaces, then it will
938  * be unnecessary as the routing socket will automatically generate
939  * copies of it.
940  */
941 void
942 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
943 {
944 	if (route_cb.any_count == 0)
945 		return;
946 
947 	if (cmd == RTM_ADD) {
948 		rt_ifamsg(RTM_NEWADDR, ifa);
949 		rt_rtmsg(RTM_ADD, rt, ifa->ifa_ifp, error);
950 	} else {
951 		KASSERT((cmd == RTM_DELETE), ("unknown cmd %d", cmd));
952 		rt_rtmsg(RTM_DELETE, rt, ifa->ifa_ifp, error);
953 		rt_ifamsg(RTM_DELADDR, ifa);
954 	}
955 }
956 
957 /*
958  * This is the analogue to the rt_newaddrmsg which performs the same
959  * function but for multicast group memberhips.  This is easier since
960  * there is no route state to worry about.
961  */
962 void
963 rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma)
964 {
965 	struct rt_addrinfo rtinfo;
966 	struct mbuf *m = NULL;
967 	struct ifnet *ifp = ifma->ifma_ifp;
968 	struct ifma_msghdr *ifmam;
969 
970 	if (route_cb.any_count == 0)
971 		return;
972 
973 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
974 	rtinfo.rti_ifaaddr = ifma->ifma_addr;
975 	if (ifp != NULL)
976 		rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
977 	else
978 		rtinfo.rti_ifpaddr = NULL;
979 	/*
980 	 * If a link-layer address is present, present it as a ``gateway''
981 	 * (similarly to how ARP entries, e.g., are presented).
982 	 */
983 	rtinfo.rti_gateway = ifma->ifma_lladdr;
984 
985 	m = rt_msg_mbuf(cmd, &rtinfo);
986 	if (m == NULL)
987 		return;
988 
989 	ifmam = mtod(m, struct ifma_msghdr *);
990 	ifmam->ifmam_index = ifp->if_index;
991 	ifmam->ifmam_addrs = rtinfo.rti_addrs;
992 
993 	rts_input(m, familyof(ifma->ifma_addr));
994 }
995 
996 /*
997  * This is called to generate routing socket messages indicating
998  * network interface arrival and departure.
999  */
1000 void
1001 rt_ifannouncemsg(struct ifnet *ifp, int what)
1002 {
1003 	struct rt_addrinfo addrinfo;
1004 	struct mbuf *m;
1005 	struct if_announcemsghdr *ifan;
1006 
1007 	if (route_cb.any_count == 0)
1008 		return;
1009 
1010 	bzero(&addrinfo, sizeof addrinfo);
1011 	m = rt_msg_mbuf(RTM_IFANNOUNCE, &addrinfo);
1012 	if (m == NULL)
1013 		return;
1014 
1015 	ifan = mtod(m, struct if_announcemsghdr *);
1016 	ifan->ifan_index = ifp->if_index;
1017 	strlcpy(ifan->ifan_name, ifp->if_xname, sizeof ifan->ifan_name);
1018 	ifan->ifan_what = what;
1019 
1020 	rts_input(m, 0);
1021 }
1022 
1023 static int
1024 resizewalkarg(struct walkarg *w, int len)
1025 {
1026 	void *newptr;
1027 
1028 	newptr = malloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
1029 	if (newptr == NULL)
1030 		return (ENOMEM);
1031 	if (w->w_tmem != NULL)
1032 		free(w->w_tmem, M_RTABLE);
1033 	w->w_tmem = newptr;
1034 	w->w_tmemsize = len;
1035 	return (0);
1036 }
1037 
1038 /*
1039  * This is used in dumping the kernel table via sysctl().
1040  */
1041 int
1042 sysctl_dumpentry(struct radix_node *rn, void *vw)
1043 {
1044 	struct walkarg *w = vw;
1045 	struct rtentry *rt = (struct rtentry *)rn;
1046 	struct rt_addrinfo rtinfo;
1047 	int error, msglen;
1048 
1049 	if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
1050 		return 0;
1051 
1052 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
1053 	rtinfo.rti_dst = rt_key(rt);
1054 	rtinfo.rti_gateway = rt->rt_gateway;
1055 	rtinfo.rti_netmask = rt_mask(rt);
1056 	rtinfo.rti_genmask = rt->rt_genmask;
1057 	if (rt->rt_ifp != NULL) {
1058 		rtinfo.rti_ifpaddr =
1059 		    TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr;
1060 		rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
1061 		if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
1062 			rtinfo.rti_bcastaddr = rt->rt_ifa->ifa_dstaddr;
1063 	}
1064 	msglen = rt_msgsize(RTM_GET, &rtinfo);
1065 	if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0)
1066 		return (ENOMEM);
1067 	rt_msg_buffer(RTM_GET, &rtinfo, w->w_tmem, msglen);
1068 	if (w->w_req != NULL) {
1069 		struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
1070 
1071 		rtm->rtm_flags = rt->rt_flags;
1072 		rtm->rtm_use = rt->rt_use;
1073 		rtm->rtm_rmx = rt->rt_rmx;
1074 		rtm->rtm_index = rt->rt_ifp->if_index;
1075 		rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
1076 		rtm->rtm_addrs = rtinfo.rti_addrs;
1077 		error = SYSCTL_OUT(w->w_req, rtm, msglen);
1078 		return (error);
1079 	}
1080 	return (0);
1081 }
1082 
1083 static int
1084 sysctl_iflist(int af, struct walkarg *w)
1085 {
1086 	struct ifnet *ifp;
1087 	struct ifaddr *ifa;
1088 	struct rt_addrinfo rtinfo;
1089 	int msglen, error;
1090 
1091 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
1092 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1093 		if (w->w_arg && w->w_arg != ifp->if_index)
1094 			continue;
1095 		ifa = TAILQ_FIRST(&ifp->if_addrhead);
1096 		rtinfo.rti_ifpaddr = ifa->ifa_addr;
1097 		msglen = rt_msgsize(RTM_IFINFO, &rtinfo);
1098 		if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0)
1099 			return (ENOMEM);
1100 		rt_msg_buffer(RTM_IFINFO, &rtinfo, w->w_tmem, msglen);
1101 		rtinfo.rti_ifpaddr = NULL;
1102 		if (w->w_req != NULL && w->w_tmem != NULL) {
1103 			struct if_msghdr *ifm;
1104 
1105 			ifm = (struct if_msghdr *)w->w_tmem;
1106 			ifm->ifm_index = ifp->if_index;
1107 			ifm->ifm_flags = (u_short)ifp->if_flags;
1108 			ifm->ifm_data = ifp->if_data;
1109 			ifm->ifm_addrs = rtinfo.rti_addrs;
1110 			error = SYSCTL_OUT(w->w_req, ifm, msglen);
1111 			if (error)
1112 				return (error);
1113 		}
1114 		while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != NULL) {
1115 			if (af && af != ifa->ifa_addr->sa_family)
1116 				continue;
1117 			if (curproc->p_ucred->cr_prison &&
1118 			    prison_if(curthread, ifa->ifa_addr))
1119 				continue;
1120 			rtinfo.rti_ifaaddr = ifa->ifa_addr;
1121 			rtinfo.rti_netmask = ifa->ifa_netmask;
1122 			rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
1123 			msglen = rt_msgsize(RTM_NEWADDR, &rtinfo);
1124 			if (w->w_tmemsize < msglen &&
1125 			    resizewalkarg(w, msglen) != 0)
1126 				return (ENOMEM);
1127 			rt_msg_buffer(RTM_NEWADDR, &rtinfo, w->w_tmem, msglen);
1128 			if (w->w_req != NULL) {
1129 				struct ifa_msghdr *ifam;
1130 
1131 				ifam = (struct ifa_msghdr *)w->w_tmem;
1132 				ifam->ifam_index = ifa->ifa_ifp->if_index;
1133 				ifam->ifam_flags = ifa->ifa_flags;
1134 				ifam->ifam_metric = ifa->ifa_metric;
1135 				ifam->ifam_addrs = rtinfo.rti_addrs;
1136 				error = SYSCTL_OUT(w->w_req, w->w_tmem, msglen);
1137 				if (error)
1138 					return (error);
1139 			}
1140 		}
1141 		rtinfo.rti_netmask = NULL;
1142 		rtinfo.rti_ifaaddr = NULL;
1143 		rtinfo.rti_bcastaddr = NULL;
1144 	}
1145 	return (0);
1146 }
1147 
1148 static int
1149 sysctl_rtsock(SYSCTL_HANDLER_ARGS)
1150 {
1151 	int	*name = (int *)arg1;
1152 	u_int	namelen = arg2;
1153 	struct radix_node_head *rnh;
1154 	int	i, s, error = EINVAL;
1155 	u_char  af;
1156 	struct	walkarg w;
1157 
1158 	name ++;
1159 	namelen--;
1160 	if (req->newptr)
1161 		return (EPERM);
1162 	if (namelen != 3)
1163 		return (EINVAL);
1164 	af = name[0];
1165 	bzero(&w, sizeof w);
1166 	w.w_op = name[1];
1167 	w.w_arg = name[2];
1168 	w.w_req = req;
1169 
1170 	s = splnet();
1171 	switch (w.w_op) {
1172 
1173 	case NET_RT_DUMP:
1174 	case NET_RT_FLAGS:
1175 		for (i = 1; i <= AF_MAX; i++)
1176 			if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
1177 			    (error = rnh->rnh_walktree(rnh,
1178 						       sysctl_dumpentry, &w)))
1179 				break;
1180 		break;
1181 
1182 	case NET_RT_IFLIST:
1183 		error = sysctl_iflist(af, &w);
1184 	}
1185 	splx(s);
1186 	if (w.w_tmem != NULL)
1187 		free(w.w_tmem, M_RTABLE);
1188 	return (error);
1189 }
1190 
1191 SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
1192 
1193 /*
1194  * Definitions of protocols supported in the ROUTE domain.
1195  */
1196 
1197 extern struct domain routedomain;		/* or at least forward */
1198 
1199 static struct protosw routesw[] = {
1200 { SOCK_RAW,	&routedomain,	0,		PR_ATOMIC|PR_ADDR,
1201   0,		route_output,	raw_ctlinput,	0,
1202   cpu0_soport,
1203   raw_init,	0,		0,		0,
1204   &route_usrreqs
1205 }
1206 };
1207 
1208 static struct domain routedomain =
1209     { PF_ROUTE, "route", 0, 0, 0,
1210       routesw, &routesw[(sizeof routesw)/(sizeof routesw[0])] };
1211 
1212 DOMAIN_SET(route);
1213