xref: /dflybsd-src/sys/net/rtsock.c (revision 23c32883e759b0ea42fdaff39e661bd1a12e3b9f)
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.24 2005/03/04 03:37:43 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 	void	*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 /*
358  * Internal helper routine for route_output().
359  */
360 static int
361 fillrtmsg(struct rt_msghdr **prtm, struct rtentry *rt,
362 	  struct rt_addrinfo *rtinfo)
363 {
364 	int msglen;
365 	struct rt_msghdr *rtm = *prtm;
366 
367 	/* Fill in rt_addrinfo for call to rt_msg_buffer(). */
368 	rtinfo->rti_dst = rt_key(rt);
369 	rtinfo->rti_gateway = rt->rt_gateway;
370 	rtinfo->rti_netmask = rt_mask(rt);		/* might be NULL */
371 	rtinfo->rti_genmask = rt->rt_genmask;		/* might be NULL */
372 	if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
373 		if (rt->rt_ifp != NULL) {
374 			rtinfo->rti_ifpaddr =
375 			    TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr;
376 			rtinfo->rti_ifaaddr = rt->rt_ifa->ifa_addr;
377 			if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
378 				rtinfo->rti_bcastaddr = rt->rt_ifa->ifa_dstaddr;
379 			rtm->rtm_index = rt->rt_ifp->if_index;
380 		} else {
381 			rtinfo->rti_ifpaddr = NULL;
382 			rtinfo->rti_ifaaddr = NULL;
383 	    }
384 	}
385 
386 	msglen = rt_msgsize(rtm->rtm_type, rtinfo);
387 	if (rtm->rtm_msglen < msglen) {
388 		rtm = reallocbuf(rtm, msglen, rtm->rtm_msglen);
389 		if (rtm == NULL)
390 			return (ENOBUFS);
391 		*prtm = rtm;
392 	}
393 	rt_msg_buffer(rtm->rtm_type, rtinfo, rtm, msglen);
394 
395 	rtm->rtm_flags = rt->rt_flags;
396 	rtm->rtm_rmx = rt->rt_rmx;
397 	rtm->rtm_addrs = rtinfo->rti_addrs;
398 
399 	return (0);
400 }
401 
402 /*ARGSUSED*/
403 static int
404 route_output(struct mbuf *m, struct socket *so, ...)
405 {
406 	struct rt_msghdr *rtm = NULL;
407 	struct rtentry *rt = NULL;
408 	struct rtentry *saved_nrt = NULL;
409 	struct radix_node_head *rnh;
410 	struct ifaddr *ifa = NULL;
411 	struct rawcb *rp = NULL;
412 	struct pr_output_info *oi;
413 	struct rt_addrinfo rtinfo;
414 	int len, error = 0;
415 	__va_list ap;
416 
417 	__va_start(ap, so);
418 	oi = __va_arg(ap, struct pr_output_info *);
419 	__va_end(ap);
420 
421 #define gotoerr(e) { error = e; goto flush;}
422 
423 	if (m == NULL ||
424 	    (m->m_len < sizeof(long) &&
425 	     (m = m_pullup(m, sizeof(long))) == NULL))
426 		return (ENOBUFS);
427 	if (!(m->m_flags & M_PKTHDR))
428 		panic("route_output");
429 	len = m->m_pkthdr.len;
430 	if (len < sizeof(struct rt_msghdr) ||
431 	    len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
432 		rtinfo.rti_dst = NULL;
433 		gotoerr(EINVAL);
434 	}
435 	rtm = malloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
436 	if (rtm == NULL) {
437 		rtinfo.rti_dst = NULL;
438 		gotoerr(ENOBUFS);
439 	}
440 	m_copydata(m, 0, len, (caddr_t)rtm);
441 	if (rtm->rtm_version != RTM_VERSION) {
442 		rtinfo.rti_dst = NULL;
443 		gotoerr(EPROTONOSUPPORT);
444 	}
445 	rtm->rtm_pid = oi->p_pid;
446 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
447 	rtinfo.rti_addrs = rtm->rtm_addrs;
448 	if (rt_xaddrs((char *)(rtm + 1), (char *)rtm + len, &rtinfo) != 0) {
449 		rtinfo.rti_dst = NULL;
450 		gotoerr(EINVAL);
451 	}
452 	rtinfo.rti_flags = rtm->rtm_flags;
453 	if (rtinfo.rti_dst == NULL || rtinfo.rti_dst->sa_family >= AF_MAX ||
454 	    (rtinfo.rti_gateway && rtinfo.rti_gateway->sa_family >= AF_MAX))
455 		gotoerr(EINVAL);
456 
457 	if (rtinfo.rti_genmask != NULL) {
458 		struct radix_node *n;
459 
460 #define	clen(s)	(*(u_char *)(s))
461 		n = rn_addmask((char *)rtinfo.rti_genmask, TRUE, 1);
462 		if (n != NULL &&
463 		    rtinfo.rti_genmask->sa_len >= clen(n->rn_key) &&
464 		    bcmp((char *)rtinfo.rti_genmask + 1,
465 		         (char *)n->rn_key + 1, clen(n->rn_key) - 1) == 0)
466 			rtinfo.rti_genmask = (struct sockaddr *)n->rn_key;
467 		else
468 			gotoerr(ENOBUFS);
469 	}
470 
471 	/*
472 	 * Verify that the caller has the appropriate privilege; RTM_GET
473 	 * is the only operation the non-superuser is allowed.
474 	 */
475 	if (rtm->rtm_type != RTM_GET && suser_cred(so->so_cred, 0) != 0)
476 		gotoerr(EPERM);
477 
478 	switch (rtm->rtm_type) {
479 	case RTM_ADD:
480 		if (rtinfo.rti_gateway == NULL)
481 			gotoerr(EINVAL);
482 		error = rtrequest1(RTM_ADD, &rtinfo, &saved_nrt);
483 		if (error == 0 && saved_nrt != NULL) {
484 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
485 			    &saved_nrt->rt_rmx);
486 			saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
487 			saved_nrt->rt_rmx.rmx_locks |=
488 			    (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
489 			--saved_nrt->rt_refcnt;
490 			saved_nrt->rt_genmask = rtinfo.rti_genmask;
491 		}
492 		break;
493 	case RTM_DELETE:
494 		error = rtrequest1(RTM_DELETE, &rtinfo, &saved_nrt);
495 		if (error == 0) {
496 			if ((rt = saved_nrt))
497 				rt->rt_refcnt++;
498 			if (fillrtmsg(&rtm, rt, &rtinfo) != 0)
499 				gotoerr(ENOBUFS);
500 		}
501 		break;
502 	case RTM_GET:
503 	case RTM_CHANGE:
504 	case RTM_LOCK:
505 		if ((rnh = rt_tables[rtinfo.rti_dst->sa_family]) == NULL)
506 			gotoerr(EAFNOSUPPORT);
507 		rt = (struct rtentry *)
508 		    rnh->rnh_lookup((char *)rtinfo.rti_dst,
509 		    		    (char *)rtinfo.rti_netmask, rnh);
510 		if (rt == NULL)
511 			gotoerr(ESRCH);
512 		rt->rt_refcnt++;
513 
514 		switch(rtm->rtm_type) {
515 		case RTM_GET:
516 			if (fillrtmsg(&rtm, rt, &rtinfo) != 0)
517 				gotoerr(ENOBUFS);
518 			break;
519 		case RTM_CHANGE:
520 			/*
521 			 * new gateway could require new ifaddr, ifp;
522 			 * flags may also be different; ifp may be specified
523 			 * by ll sockaddr when protocol address is ambiguous
524 			 */
525 			if (((rt->rt_flags & RTF_GATEWAY) &&
526 			     rtinfo.rti_gateway != NULL) ||
527 			    rtinfo.rti_ifpaddr != NULL ||
528 			    (rtinfo.rti_ifaaddr != NULL &&
529 			     sa_equal(rtinfo.rti_ifaaddr,
530 			     	      rt->rt_ifa->ifa_addr))) {
531 				error = rt_getifa(&rtinfo);
532 				if (error != 0)
533 					gotoerr(error);
534 			}
535 			if (rtinfo.rti_gateway != NULL) {
536 				error = rt_setgate(rt, rt_key(rt),
537 						   rtinfo.rti_gateway);
538 				if (error != 0)
539 					gotoerr(error);
540 			}
541 			if ((ifa = rtinfo.rti_ifa) != NULL) {
542 				struct ifaddr *oifa = rt->rt_ifa;
543 
544 				if (oifa != ifa) {
545 					if (oifa && oifa->ifa_rtrequest)
546 						oifa->ifa_rtrequest(RTM_DELETE,
547 						    rt, &rtinfo);
548 					IFAFREE(rt->rt_ifa);
549 					IFAREF(ifa);
550 					rt->rt_ifa = ifa;
551 					rt->rt_ifp = rtinfo.rti_ifp;
552 				}
553 			}
554 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
555 				      &rt->rt_rmx);
556 			if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
557 			       rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &rtinfo);
558 			if (rtinfo.rti_genmask != NULL)
559 				rt->rt_genmask = rtinfo.rti_genmask;
560 			/*
561 			 * Fall into
562 			 */
563 		case RTM_LOCK:
564 			rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
565 			rt->rt_rmx.rmx_locks |=
566 				(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
567 			break;
568 		}
569 
570 		break;
571 	default:
572 		gotoerr(EOPNOTSUPP);
573 	}
574 
575 flush:
576 	if (rtm != NULL) {
577 		if (error != 0)
578 			rtm->rtm_errno = error;
579 		else
580 			rtm->rtm_flags |= RTF_DONE;
581 	}
582 	if (rt != NULL)
583 		rtfree(rt);
584 	/*
585 	 * Check to see if we don't want our own messages.
586 	 */
587 	if (!(so->so_options & SO_USELOOPBACK)) {
588 		if (route_cb.any_count <= 1) {
589 			if (rtm != NULL)
590 				free(rtm, M_RTABLE);
591 			m_freem(m);
592 			return (error);
593 		}
594 		/* There is another listener, so construct message */
595 		rp = sotorawcb(so);
596 	}
597 	if (rtm != NULL) {
598 		m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
599 		if (m->m_pkthdr.len < rtm->rtm_msglen) {
600 			m_freem(m);
601 			m = NULL;
602 		} else if (m->m_pkthdr.len > rtm->rtm_msglen)
603 			m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
604 		free(rtm, M_RTABLE);
605 	}
606 	if (rp != NULL)
607 		rp->rcb_proto.sp_family = 0; /* Avoid us */
608 	if (m != NULL)
609 		rts_input(m, familyof(rtinfo.rti_dst));
610 	if (rp != NULL)
611 		rp->rcb_proto.sp_family = PF_ROUTE;
612 	return (error);
613 }
614 
615 static void
616 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_metrics *out)
617 {
618 #define setmetric(flag, elt) if (which & (flag)) out->elt = in->elt;
619 	setmetric(RTV_RPIPE, rmx_recvpipe);
620 	setmetric(RTV_SPIPE, rmx_sendpipe);
621 	setmetric(RTV_SSTHRESH, rmx_ssthresh);
622 	setmetric(RTV_RTT, rmx_rtt);
623 	setmetric(RTV_RTTVAR, rmx_rttvar);
624 	setmetric(RTV_HOPCOUNT, rmx_hopcount);
625 	setmetric(RTV_MTU, rmx_mtu);
626 	setmetric(RTV_EXPIRE, rmx_expire);
627 #undef setmetric
628 }
629 
630 #define ROUNDUP(a) \
631 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
632 
633 /*
634  * Extract the addresses of the passed sockaddrs.
635  * Do a little sanity checking so as to avoid bad memory references.
636  * This data is derived straight from userland.
637  */
638 static int
639 rt_xaddrs(char *cp, char *cplim, struct rt_addrinfo *rtinfo)
640 {
641 	struct sockaddr *sa;
642 	int i;
643 
644 	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
645 		if ((rtinfo->rti_addrs & (1 << i)) == 0)
646 			continue;
647 		sa = (struct sockaddr *)cp;
648 		/*
649 		 * It won't fit.
650 		 */
651 		if ((cp + sa->sa_len) > cplim) {
652 			return (EINVAL);
653 		}
654 
655 		/*
656 		 * There are no more...  Quit now.
657 		 * If there are more bits, they are in error.
658 		 * I've seen this.  route(1) can evidently generate these.
659 		 * This causes kernel to core dump.
660 		 * For compatibility, if we see this, point to a safe address.
661 		 */
662 		if (sa->sa_len == 0) {
663 			static struct sockaddr sa_zero = {
664 				sizeof sa_zero, AF_INET,
665 			};
666 
667 			rtinfo->rti_info[i] = &sa_zero;
668 			return (0); /* should be EINVAL but for compat */
669 		}
670 
671 		/* Accept the sockaddr. */
672 		rtinfo->rti_info[i] = sa;
673 		cp += ROUNDUP(sa->sa_len);
674 	}
675 	return (0);
676 }
677 
678 static int
679 rt_msghdrsize(int type)
680 {
681 	switch (type) {
682 	case RTM_DELADDR:
683 	case RTM_NEWADDR:
684 		return sizeof(struct ifa_msghdr);
685 	case RTM_DELMADDR:
686 	case RTM_NEWMADDR:
687 		return sizeof(struct ifma_msghdr);
688 	case RTM_IFINFO:
689 		return sizeof(struct if_msghdr);
690 	case RTM_IFANNOUNCE:
691 		return sizeof(struct if_announcemsghdr);
692 	default:
693 		return sizeof(struct rt_msghdr);
694 	}
695 }
696 
697 static int
698 rt_msgsize(int type, struct rt_addrinfo *rtinfo)
699 {
700 	int len, i;
701 
702 	len = rt_msghdrsize(type);
703 	for (i = 0; i < RTAX_MAX; i++) {
704 		if (rtinfo->rti_info[i] != NULL)
705 			len += ROUNDUP(rtinfo->rti_info[i]->sa_len);
706 	}
707 	len = ALIGN(len);
708 	return len;
709 }
710 
711 /*
712  * Build a routing message in a buffer.
713  * Copy the addresses in the rtinfo->rti_info[] sockaddr array
714  * to the end of the buffer after the message header.
715  *
716  * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[].
717  * This side-effect can be avoided if we reorder the addrs bitmask field in all
718  * the route messages to line up so we can set it here instead of back in the
719  * calling routine.
720  */
721 static void
722 rt_msg_buffer(int type, struct rt_addrinfo *rtinfo, void *buf, int msglen)
723 {
724 	struct rt_msghdr *rtm;
725 	char *cp;
726 	int dlen, i;
727 
728 	rtm = (struct rt_msghdr *) buf;
729 	rtm->rtm_version = RTM_VERSION;
730 	rtm->rtm_type = type;
731 	rtm->rtm_msglen = msglen;
732 
733 	cp = (char *)buf + rt_msghdrsize(type);
734 	rtinfo->rti_addrs = 0;
735 	for (i = 0; i < RTAX_MAX; i++) {
736 		struct sockaddr *sa;
737 
738 		if ((sa = rtinfo->rti_info[i]) == NULL)
739 			continue;
740 		rtinfo->rti_addrs |= (1 << i);
741 		dlen = ROUNDUP(sa->sa_len);
742 		bcopy(sa, cp, dlen);
743 		cp += dlen;
744 	}
745 }
746 
747 /*
748  * Build a routing message in a mbuf chain.
749  * Copy the addresses in the rtinfo->rti_info[] sockaddr array
750  * to the end of the mbuf after the message header.
751  *
752  * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[].
753  * This side-effect can be avoided if we reorder the addrs bitmask field in all
754  * the route messages to line up so we can set it here instead of back in the
755  * calling routine.
756  */
757 static struct mbuf *
758 rt_msg_mbuf(int type, struct rt_addrinfo *rtinfo)
759 {
760 	struct mbuf *m;
761 	struct rt_msghdr *rtm;
762 	int hlen, len;
763 	int i;
764 
765 	hlen = rt_msghdrsize(type);
766 	KASSERT(hlen <= MCLBYTES, ("rt_msg_mbuf: hlen %d doesn't fit", hlen));
767 
768 	m = m_gethdr(MB_DONTWAIT, MT_DATA);
769 	if (m == NULL)
770 		return (NULL);
771 	if (hlen > MHLEN) {
772 		MCLGET(m, MB_DONTWAIT);
773 		if (!(m->m_flags & M_EXT)) {
774 			m_free(m);
775 			return (NULL);
776 		}
777 	}
778 	m->m_pkthdr.len = m->m_len = hlen;
779 	m->m_pkthdr.rcvif = NULL;
780 	rtinfo->rti_addrs = 0;
781 	len = hlen;
782 	for (i = 0; i < RTAX_MAX; i++) {
783 		struct sockaddr *sa;
784 		int dlen;
785 
786 		if ((sa = rtinfo->rti_info[i]) == NULL)
787 			continue;
788 		rtinfo->rti_addrs |= (1 << i);
789 		dlen = ROUNDUP(sa->sa_len);
790 		m_copyback(m, len, dlen, (caddr_t)sa); /* can grow mbuf chain */
791 		len += dlen;
792 	}
793 	if (m->m_pkthdr.len != len) { /* one of the m_copyback() calls failed */
794 		m_freem(m);
795 		return (NULL);
796 	}
797 	rtm = mtod(m, struct rt_msghdr *);
798 	bzero(rtm, hlen);
799 	rtm->rtm_msglen = len;
800 	rtm->rtm_version = RTM_VERSION;
801 	rtm->rtm_type = type;
802 	return (m);
803 }
804 
805 /*
806  * This routine is called to generate a message from the routing
807  * socket indicating that a redirect has occurred, a routing lookup
808  * has failed, or that a protocol has detected timeouts to a particular
809  * destination.
810  */
811 void
812 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
813 {
814 	struct sockaddr *dst = rtinfo->rti_info[RTAX_DST];
815 	struct rt_msghdr *rtm;
816 	struct mbuf *m;
817 
818 	if (route_cb.any_count == 0)
819 		return;
820 	m = rt_msg_mbuf(type, rtinfo);
821 	if (m == NULL)
822 		return;
823 	rtm = mtod(m, struct rt_msghdr *);
824 	rtm->rtm_flags = RTF_DONE | flags;
825 	rtm->rtm_errno = error;
826 	rtm->rtm_addrs = rtinfo->rti_addrs;
827 	rts_input(m, familyof(dst));
828 }
829 
830 void
831 rt_dstmsg(int type, struct sockaddr *dst, int error)
832 {
833 	struct rt_msghdr *rtm;
834 	struct rt_addrinfo addrs;
835 	struct mbuf *m;
836 
837 	if (route_cb.any_count == 0)
838 		return;
839 	bzero(&addrs, sizeof(struct rt_addrinfo));
840 	addrs.rti_info[RTAX_DST] = dst;
841 	m = rt_msg_mbuf(type, &addrs);
842 	if (m == NULL)
843 		return;
844 	rtm = mtod(m, struct rt_msghdr *);
845 	rtm->rtm_flags = RTF_DONE;
846 	rtm->rtm_errno = error;
847 	rtm->rtm_addrs = addrs.rti_addrs;
848 	rts_input(m, familyof(dst));
849 }
850 
851 /*
852  * This routine is called to generate a message from the routing
853  * socket indicating that the status of a network interface has changed.
854  */
855 void
856 rt_ifmsg(struct ifnet *ifp)
857 {
858 	struct if_msghdr *ifm;
859 	struct mbuf *m;
860 	struct rt_addrinfo rtinfo;
861 
862 	if (route_cb.any_count == 0)
863 		return;
864 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
865 	m = rt_msg_mbuf(RTM_IFINFO, &rtinfo);
866 	if (m == NULL)
867 		return;
868 	ifm = mtod(m, struct if_msghdr *);
869 	ifm->ifm_index = ifp->if_index;
870 	ifm->ifm_flags = (u_short)ifp->if_flags;
871 	ifm->ifm_data = ifp->if_data;
872 	ifm->ifm_addrs = 0;
873 	rts_input(m, 0);
874 }
875 
876 static void
877 rt_ifamsg(int cmd, struct ifaddr *ifa)
878 {
879 	struct ifa_msghdr *ifam;
880 	struct rt_addrinfo rtinfo;
881 	struct mbuf *m;
882 	struct ifnet *ifp = ifa->ifa_ifp;
883 
884 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
885 	rtinfo.rti_ifaaddr = ifa->ifa_addr;
886 	rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
887 	rtinfo.rti_netmask = ifa->ifa_netmask;
888 	rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
889 
890 	m = rt_msg_mbuf(cmd, &rtinfo);
891 	if (m == NULL)
892 		return;
893 
894 	ifam = mtod(m, struct ifa_msghdr *);
895 	ifam->ifam_index = ifp->if_index;
896 	ifam->ifam_metric = ifa->ifa_metric;
897 	ifam->ifam_flags = ifa->ifa_flags;
898 	ifam->ifam_addrs = rtinfo.rti_addrs;
899 
900 	rts_input(m, familyof(ifa->ifa_addr));
901 }
902 
903 void
904 rt_rtmsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int error)
905 {
906 	struct rt_msghdr *rtm;
907 	struct rt_addrinfo rtinfo;
908 	struct mbuf *m;
909 	struct sockaddr *dst;
910 
911 	if (rt == NULL)
912 		return;
913 
914 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
915 	rtinfo.rti_dst = dst = rt_key(rt);
916 	rtinfo.rti_gateway = rt->rt_gateway;
917 	rtinfo.rti_netmask = rt_mask(rt);
918 	if (ifp != NULL)
919 		rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
920 	rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
921 
922 	m = rt_msg_mbuf(cmd, &rtinfo);
923 	if (m == NULL)
924 		return;
925 
926 	rtm = mtod(m, struct rt_msghdr *);
927 	if (ifp != NULL)
928 		rtm->rtm_index = ifp->if_index;
929 	rtm->rtm_flags |= rt->rt_flags;
930 	rtm->rtm_errno = error;
931 	rtm->rtm_addrs = rtinfo.rti_addrs;
932 
933 	rts_input(m, familyof(dst));
934 }
935 
936 /*
937  * This is called to generate messages from the routing socket
938  * indicating a network interface has had addresses associated with it.
939  * if we ever reverse the logic and replace messages TO the routing
940  * socket indicate a request to configure interfaces, then it will
941  * be unnecessary as the routing socket will automatically generate
942  * copies of it.
943  */
944 void
945 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
946 {
947 	if (route_cb.any_count == 0)
948 		return;
949 
950 	if (cmd == RTM_ADD) {
951 		rt_ifamsg(RTM_NEWADDR, ifa);
952 		rt_rtmsg(RTM_ADD, rt, ifa->ifa_ifp, error);
953 	} else {
954 		KASSERT((cmd == RTM_DELETE), ("unknown cmd %d", cmd));
955 		rt_rtmsg(RTM_DELETE, rt, ifa->ifa_ifp, error);
956 		rt_ifamsg(RTM_DELADDR, ifa);
957 	}
958 }
959 
960 /*
961  * This is the analogue to the rt_newaddrmsg which performs the same
962  * function but for multicast group memberhips.  This is easier since
963  * there is no route state to worry about.
964  */
965 void
966 rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma)
967 {
968 	struct rt_addrinfo rtinfo;
969 	struct mbuf *m = NULL;
970 	struct ifnet *ifp = ifma->ifma_ifp;
971 	struct ifma_msghdr *ifmam;
972 
973 	if (route_cb.any_count == 0)
974 		return;
975 
976 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
977 	rtinfo.rti_ifaaddr = ifma->ifma_addr;
978 	if (ifp != NULL && TAILQ_FIRST(&ifp->if_addrhead) != NULL)
979 		rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
980 	else
981 		rtinfo.rti_ifpaddr = NULL;
982 	/*
983 	 * If a link-layer address is present, present it as a ``gateway''
984 	 * (similarly to how ARP entries, e.g., are presented).
985 	 */
986 	rtinfo.rti_gateway = ifma->ifma_lladdr;
987 
988 	m = rt_msg_mbuf(cmd, &rtinfo);
989 	if (m == NULL)
990 		return;
991 
992 	ifmam = mtod(m, struct ifma_msghdr *);
993 	ifmam->ifmam_index = ifp->if_index;
994 	ifmam->ifmam_addrs = rtinfo.rti_addrs;
995 
996 	rts_input(m, familyof(ifma->ifma_addr));
997 }
998 
999 /*
1000  * This is called to generate routing socket messages indicating
1001  * network interface arrival and departure.
1002  */
1003 void
1004 rt_ifannouncemsg(struct ifnet *ifp, int what)
1005 {
1006 	struct rt_addrinfo addrinfo;
1007 	struct mbuf *m;
1008 	struct if_announcemsghdr *ifan;
1009 
1010 	if (route_cb.any_count == 0)
1011 		return;
1012 
1013 	bzero(&addrinfo, sizeof addrinfo);
1014 	m = rt_msg_mbuf(RTM_IFANNOUNCE, &addrinfo);
1015 	if (m == NULL)
1016 		return;
1017 
1018 	ifan = mtod(m, struct if_announcemsghdr *);
1019 	ifan->ifan_index = ifp->if_index;
1020 	strlcpy(ifan->ifan_name, ifp->if_xname, sizeof ifan->ifan_name);
1021 	ifan->ifan_what = what;
1022 
1023 	rts_input(m, 0);
1024 }
1025 
1026 static int
1027 resizewalkarg(struct walkarg *w, int len)
1028 {
1029 	void *newptr;
1030 
1031 	newptr = malloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
1032 	if (newptr == NULL)
1033 		return (ENOMEM);
1034 	if (w->w_tmem != NULL)
1035 		free(w->w_tmem, M_RTABLE);
1036 	w->w_tmem = newptr;
1037 	w->w_tmemsize = len;
1038 	return (0);
1039 }
1040 
1041 /*
1042  * This is used in dumping the kernel table via sysctl().
1043  */
1044 int
1045 sysctl_dumpentry(struct radix_node *rn, void *vw)
1046 {
1047 	struct walkarg *w = vw;
1048 	struct rtentry *rt = (struct rtentry *)rn;
1049 	struct rt_addrinfo rtinfo;
1050 	int error, msglen;
1051 
1052 	if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
1053 		return 0;
1054 
1055 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
1056 	rtinfo.rti_dst = rt_key(rt);
1057 	rtinfo.rti_gateway = rt->rt_gateway;
1058 	rtinfo.rti_netmask = rt_mask(rt);
1059 	rtinfo.rti_genmask = rt->rt_genmask;
1060 	if (rt->rt_ifp != NULL) {
1061 		rtinfo.rti_ifpaddr =
1062 		    TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr;
1063 		rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
1064 		if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
1065 			rtinfo.rti_bcastaddr = rt->rt_ifa->ifa_dstaddr;
1066 	}
1067 	msglen = rt_msgsize(RTM_GET, &rtinfo);
1068 	if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0)
1069 		return (ENOMEM);
1070 	rt_msg_buffer(RTM_GET, &rtinfo, w->w_tmem, msglen);
1071 	if (w->w_req != NULL) {
1072 		struct rt_msghdr *rtm = w->w_tmem;
1073 
1074 		rtm->rtm_flags = rt->rt_flags;
1075 		rtm->rtm_use = rt->rt_use;
1076 		rtm->rtm_rmx = rt->rt_rmx;
1077 		rtm->rtm_index = rt->rt_ifp->if_index;
1078 		rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
1079 		rtm->rtm_addrs = rtinfo.rti_addrs;
1080 		error = SYSCTL_OUT(w->w_req, rtm, msglen);
1081 		return (error);
1082 	}
1083 	return (0);
1084 }
1085 
1086 static int
1087 sysctl_iflist(int af, struct walkarg *w)
1088 {
1089 	struct ifnet *ifp;
1090 	struct ifaddr *ifa;
1091 	struct rt_addrinfo rtinfo;
1092 	int msglen, error;
1093 
1094 	bzero(&rtinfo, sizeof(struct rt_addrinfo));
1095 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1096 		if (w->w_arg && w->w_arg != ifp->if_index)
1097 			continue;
1098 		ifa = TAILQ_FIRST(&ifp->if_addrhead);
1099 		rtinfo.rti_ifpaddr = ifa->ifa_addr;
1100 		msglen = rt_msgsize(RTM_IFINFO, &rtinfo);
1101 		if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0)
1102 			return (ENOMEM);
1103 		rt_msg_buffer(RTM_IFINFO, &rtinfo, w->w_tmem, msglen);
1104 		rtinfo.rti_ifpaddr = NULL;
1105 		if (w->w_req != NULL && w->w_tmem != NULL) {
1106 			struct if_msghdr *ifm = w->w_tmem;
1107 
1108 			ifm->ifm_index = ifp->if_index;
1109 			ifm->ifm_flags = (u_short)ifp->if_flags;
1110 			ifm->ifm_data = ifp->if_data;
1111 			ifm->ifm_addrs = rtinfo.rti_addrs;
1112 			error = SYSCTL_OUT(w->w_req, ifm, msglen);
1113 			if (error)
1114 				return (error);
1115 		}
1116 		while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != NULL) {
1117 			if (af && af != ifa->ifa_addr->sa_family)
1118 				continue;
1119 			if (curproc->p_ucred->cr_prison &&
1120 			    prison_if(curthread, ifa->ifa_addr))
1121 				continue;
1122 			rtinfo.rti_ifaaddr = ifa->ifa_addr;
1123 			rtinfo.rti_netmask = ifa->ifa_netmask;
1124 			rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
1125 			msglen = rt_msgsize(RTM_NEWADDR, &rtinfo);
1126 			if (w->w_tmemsize < msglen &&
1127 			    resizewalkarg(w, msglen) != 0)
1128 				return (ENOMEM);
1129 			rt_msg_buffer(RTM_NEWADDR, &rtinfo, w->w_tmem, msglen);
1130 			if (w->w_req != NULL) {
1131 				struct ifa_msghdr *ifam = w->w_tmem;
1132 
1133 				ifam->ifam_index = ifa->ifa_ifp->if_index;
1134 				ifam->ifam_flags = ifa->ifa_flags;
1135 				ifam->ifam_metric = ifa->ifa_metric;
1136 				ifam->ifam_addrs = rtinfo.rti_addrs;
1137 				error = SYSCTL_OUT(w->w_req, w->w_tmem, msglen);
1138 				if (error)
1139 					return (error);
1140 			}
1141 		}
1142 		rtinfo.rti_netmask = NULL;
1143 		rtinfo.rti_ifaaddr = NULL;
1144 		rtinfo.rti_bcastaddr = NULL;
1145 	}
1146 	return (0);
1147 }
1148 
1149 static int
1150 sysctl_rtsock(SYSCTL_HANDLER_ARGS)
1151 {
1152 	int	*name = (int *)arg1;
1153 	u_int	namelen = arg2;
1154 	struct radix_node_head *rnh;
1155 	int	i, s, error = EINVAL;
1156 	u_char  af;
1157 	struct	walkarg w;
1158 
1159 	name ++;
1160 	namelen--;
1161 	if (req->newptr)
1162 		return (EPERM);
1163 	if (namelen != 3)
1164 		return (EINVAL);
1165 	af = name[0];
1166 	bzero(&w, sizeof w);
1167 	w.w_op = name[1];
1168 	w.w_arg = name[2];
1169 	w.w_req = req;
1170 
1171 	s = splnet();
1172 	switch (w.w_op) {
1173 
1174 	case NET_RT_DUMP:
1175 	case NET_RT_FLAGS:
1176 		for (i = 1; i <= AF_MAX; i++)
1177 			if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
1178 			    (error = rnh->rnh_walktree(rnh,
1179 						       sysctl_dumpentry, &w)))
1180 				break;
1181 		break;
1182 
1183 	case NET_RT_IFLIST:
1184 		error = sysctl_iflist(af, &w);
1185 	}
1186 	splx(s);
1187 	if (w.w_tmem != NULL)
1188 		free(w.w_tmem, M_RTABLE);
1189 	return (error);
1190 }
1191 
1192 SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
1193 
1194 /*
1195  * Definitions of protocols supported in the ROUTE domain.
1196  */
1197 
1198 extern struct domain routedomain;		/* or at least forward */
1199 
1200 static struct protosw routesw[] = {
1201 { SOCK_RAW,	&routedomain,	0,		PR_ATOMIC|PR_ADDR,
1202   0,		route_output,	raw_ctlinput,	0,
1203   cpu0_soport,
1204   raw_init,	0,		0,		0,
1205   &route_usrreqs
1206 }
1207 };
1208 
1209 static struct domain routedomain = {
1210 	PF_ROUTE, "route", NULL, NULL, NULL,
1211 	routesw, &routesw[(sizeof routesw)/(sizeof routesw[0])],
1212 };
1213 
1214 DOMAIN_SET(route);
1215