xref: /openbsd-src/sys/net/rtsock.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: rtsock.c,v 1.76 2008/08/07 21:32:08 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 struct mbuf	*rt_msg1(int, struct rt_addrinfo *);
96 int		 rt_msg2(int, int, struct rt_addrinfo *, caddr_t,
97 		     struct walkarg *);
98 void		 rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
99 #ifndef SMALL_KERNEL
100 struct rt_msghdr *rtmsg_3to4(struct mbuf *, int *);
101 #endif
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 int
113 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
114     struct mbuf *control, struct proc *p)
115 {
116 	int		 error = 0;
117 	struct rawcb	*rp = sotorawcb(so);
118 	int		 s;
119 
120 	if (req == PRU_ATTACH) {
121 		rp = malloc(sizeof(*rp), M_PCB, M_WAITOK|M_ZERO);
122 		so->so_pcb = rp;
123 	}
124 	if (req == PRU_DETACH && rp) {
125 		int af = rp->rcb_proto.sp_protocol;
126 		if (af == AF_INET)
127 			route_cb.ip_count--;
128 		else if (af == AF_INET6)
129 			route_cb.ip6_count--;
130 		route_cb.any_count--;
131 	}
132 	s = splsoftnet();
133 	/*
134 	 * Don't call raw_usrreq() in the attach case, because
135 	 * we want to allow non-privileged processes to listen on
136 	 * and send "safe" commands to the routing socket.
137 	 */
138 	if (req == PRU_ATTACH) {
139 		if (curproc == 0)
140 			error = EACCES;
141 		else
142 			error = raw_attach(so, (int)(long)nam);
143 	} else
144 		error = raw_usrreq(so, req, m, nam, control, p);
145 
146 	rp = sotorawcb(so);
147 	if (req == PRU_ATTACH && rp) {
148 		int af = rp->rcb_proto.sp_protocol;
149 		if (error) {
150 			free(rp, M_PCB);
151 			splx(s);
152 			return (error);
153 		}
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 	}
167 	splx(s);
168 	return (error);
169 }
170 
171 int
172 route_output(struct mbuf *m, ...)
173 {
174 	struct rt_msghdr	*rtm = NULL;
175 	struct radix_node	*rn = NULL;
176 	struct rtentry		*rt = NULL;
177 	struct rtentry		*saved_nrt = NULL;
178 	struct radix_node_head	*rnh;
179 	struct rt_addrinfo	 info;
180 	int			 len, error = 0;
181 	struct ifnet		*ifp = NULL;
182 	struct ifaddr		*ifa = NULL;
183 	struct socket		*so;
184 	struct rawcb		*rp = NULL;
185 	struct sockaddr_rtlabel	 sa_rt;
186 	const char		*label;
187 	va_list			 ap;
188 	u_int			 tableid;
189 	u_int8_t		 prio;
190 
191 	va_start(ap, m);
192 	so = va_arg(ap, struct socket *);
193 	va_end(ap);
194 
195 	dst = NULL;	/* for error handling (goto flush) */
196 	if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
197 	    (m = m_pullup(m, sizeof(int32_t))) == 0))
198 		return (ENOBUFS);
199 	if ((m->m_flags & M_PKTHDR) == 0)
200 		panic("route_output");
201 	len = m->m_pkthdr.len;
202 	if (len < offsetof(struct rt_msghdr, rtm_type) + 1 ||
203 	    len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
204 		error = EINVAL;
205 		goto flush;
206 	}
207 	switch (mtod(m, struct rt_msghdr *)->rtm_version) {
208 	case RTM_VERSION:
209 		if (len < sizeof(struct rt_msghdr)) {
210 			error = EINVAL;
211 			goto flush;
212 		}
213 		R_Malloc(rtm, struct rt_msghdr *, len);
214 		if (rtm == 0) {
215 			error = ENOBUFS;
216 			goto flush;
217 		}
218 		m_copydata(m, 0, len, (caddr_t)rtm);
219 		break;
220 #ifndef SMALL_KERNEL
221 	case RTM_OVERSION:
222 		if (len < sizeof(struct rt_omsghdr)) {
223 			error = EINVAL;
224 			goto flush;
225 		}
226 		rtm = rtmsg_3to4(m, &len);
227 		if (rtm == 0) {
228 			error = ENOBUFS;
229 			goto flush;
230 		}
231 		break;
232 #endif
233 	default:
234 		error = EPROTONOSUPPORT;
235 		goto flush;
236 	}
237 	rtm->rtm_pid = curproc->p_pid;
238 	if (rtm->rtm_hdrlen == 0)	/* old client */
239 		rtm->rtm_hdrlen = sizeof(struct rt_msghdr);
240 	if (len < rtm->rtm_hdrlen) {
241 		error = EINVAL;
242 		goto flush;
243 	}
244 
245 	tableid = rtm->rtm_tableid;
246 	if (!rtable_exists(tableid)) {
247 		if (rtm->rtm_type == RTM_ADD) {
248 			if (rtable_add(tableid)) {
249 				error = EINVAL;
250 				goto flush;
251 			}
252 		} else {
253 			error = EINVAL;
254 			goto flush;
255 		}
256 	}
257 
258 	if (rtm->rtm_priority != 0) {
259 		if (rtm->rtm_priority > RTP_MAX) {
260 			error = EINVAL;
261 			goto flush;
262 		}
263 		prio = rtm->rtm_priority;
264 	} else if (rtm->rtm_type != RTM_ADD)
265 		prio = RTP_ANY;
266 	else if (rtm->rtm_flags & RTF_STATIC)
267 		prio = RTP_STATIC;
268 	else
269 		prio = RTP_DEFAULT;
270 
271 	bzero(&info, sizeof(info));
272 	info.rti_addrs = rtm->rtm_addrs;
273 	rt_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, len + (caddr_t)rtm, &info);
274 	info.rti_flags = rtm->rtm_flags;
275 	if (dst == 0 || dst->sa_family >= AF_MAX ||
276 	    (gate != 0 && gate->sa_family >= AF_MAX)) {
277 		error = EINVAL;
278 		goto flush;
279 	}
280 	if (genmask) {
281 		struct radix_node	*t;
282 		t = rn_addmask(genmask, 0, 1);
283 		if (t && genmask->sa_len >=
284 		    ((struct sockaddr *)t->rn_key)->sa_len &&
285 		    Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1,
286 		    ((struct sockaddr *)t->rn_key)->sa_len) - 1)
287 			genmask = (struct sockaddr *)(t->rn_key);
288 		else {
289 			error = ENOBUFS;
290 			goto flush;
291 		}
292 	}
293 
294 	/*
295 	 * Verify that the caller has the appropriate privilege; RTM_GET
296 	 * is the only operation the non-superuser is allowed.
297 	 */
298 	if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) {
299 		error = EACCES;
300 		goto flush;
301 	}
302 
303 	switch (rtm->rtm_type) {
304 	case RTM_ADD:
305 		if (gate == 0) {
306 			error = EINVAL;
307 			goto flush;
308 		}
309 		error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt,
310 		    tableid);
311 		if (error == 0 && saved_nrt) {
312 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
313 			    &saved_nrt->rt_rmx);
314 			saved_nrt->rt_refcnt--;
315 			saved_nrt->rt_genmask = genmask;
316 			rtm->rtm_index = saved_nrt->rt_ifp->if_index;
317 		}
318 		break;
319 	case RTM_DELETE:
320 		error = rtrequest1(rtm->rtm_type, &info, prio, &saved_nrt,
321 		    tableid);
322 		if (error == 0) {
323 			(rt = saved_nrt)->rt_refcnt++;
324 			goto report;
325 		}
326 		break;
327 	case RTM_GET:
328 	case RTM_CHANGE:
329 	case RTM_LOCK:
330 		if ((rnh = rt_gettable(dst->sa_family, tableid)) == NULL) {
331 			error = EAFNOSUPPORT;
332 			goto flush;
333 		}
334 		rn = rt_lookup(dst, netmask, tableid);
335 		if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {
336 			error = ESRCH;
337 			goto flush;
338 		}
339 		rt = (struct rtentry *)rn;
340 #ifndef SMALL_KERNEL
341 		/*
342 		 * for RTM_CHANGE/LOCK, if we got multipath routes,
343 		 * we require users to specify a matching RTAX_GATEWAY.
344 		 *
345 		 * for RTM_GET, gate is optional even with multipath.
346 		 * if gate == NULL the first match is returned.
347 		 * (no need to call rt_mpath_matchgate if gate == NULL)
348 		 */
349 		if (rn_mpath_capable(rnh)) {
350 			/* first find correct priority bucket */
351 			rn = rn_mpath_prio(rn, prio);
352 			rt = (struct rtentry *)rn;
353 			if (prio != RTP_ANY && rt->rt_priority != prio) {
354 				error = ESRCH;
355 				goto flush;
356 			}
357 
358 			/* if multipath routes */
359 			if (rn_mpath_next(rn)) {
360 				if (gate)
361 					rt = rt_mpath_matchgate(rt, gate, prio);
362 				else if (rtm->rtm_type != RTM_GET)
363 					/*
364 					 * only RTM_GET may use an empty gate
365 					 * on multipath ...
366 					 */
367 					rt = NULL;
368 			} else if (gate && (rtm->rtm_type == RTM_GET ||
369 			    rtm->rtm_type == RTM_LOCK))
370 				/*
371 				 * ... but if a gate is specified RTM_GET
372 				 * and RTM_LOCK must match the gate no matter
373 				 * what.
374 				 */
375 				rt = rt_mpath_matchgate(rt, gate, prio);
376 
377 			if (!rt) {
378 				error = ESRCH;
379 				goto flush;
380 			}
381 			rn = (struct radix_node *)rt;
382 		}
383 #endif
384 		rt->rt_refcnt++;
385 
386 		/*
387 		 * RTM_CHANGE/LOCK need a perfect match, rn_lookup()
388 		 * returns a perfect match in case a netmask is specified.
389 		 * For host routes only a longest prefix match is returned
390 		 * so it is necessary to compare the existence of the netmaks.
391 		 * If both have a netmask rn_lookup() did a perfect match and
392 		 * if none of them have a netmask both are host routes which is
393 		 * also a perfect match.
394 		 */
395 		if (rtm->rtm_type != RTM_GET && !rt_mask(rt) != !netmask) {
396 				error = ESRCH;
397 				goto flush;
398 		}
399 
400 		switch (rtm->rtm_type) {
401 		case RTM_GET:
402 report:
403 			dst = rt_key(rt);
404 			gate = rt->rt_gateway;
405 			netmask = rt_mask(rt);
406 			genmask = rt->rt_genmask;
407 
408 			if (rt->rt_labelid) {
409 				bzero(&sa_rt, sizeof(sa_rt));
410 				sa_rt.sr_len = sizeof(sa_rt);
411 				label = rtlabel_id2name(rt->rt_labelid);
412 				if (label != NULL)
413 					strlcpy(sa_rt.sr_label, label,
414 					    sizeof(sa_rt.sr_label));
415 				info.rti_info[RTAX_LABEL] =
416 				    (struct sockaddr *)&sa_rt;
417 			}
418 
419 			ifpaddr = 0;
420 			ifaaddr = 0;
421 			if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) &&
422 			    (ifp = rt->rt_ifp) != NULL) {
423 				ifpaddr =
424 				    TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
425 				ifaaddr = rt->rt_ifa->ifa_addr;
426 				if (ifp->if_flags & IFF_POINTOPOINT)
427 					brdaddr = rt->rt_ifa->ifa_dstaddr;
428 				else
429 					brdaddr = 0;
430 				rtm->rtm_index = ifp->if_index;
431 			}
432 			len = rt_msg2(rtm->rtm_type, RTM_VERSION, &info, NULL,
433 			    NULL);
434 			if (len > rtm->rtm_msglen) {
435 				struct rt_msghdr	*new_rtm;
436 				R_Malloc(new_rtm, struct rt_msghdr *, len);
437 				if (new_rtm == 0) {
438 					error = ENOBUFS;
439 					goto flush;
440 				}
441 				Bcopy(rtm, new_rtm, rtm->rtm_msglen);
442 				Free(rtm); rtm = new_rtm;
443 			}
444 			rt_msg2(rtm->rtm_type, RTM_VERSION, &info, (caddr_t)rtm,
445 			    NULL);
446 			rtm->rtm_flags = rt->rt_flags;
447 			rtm->rtm_use = 0;
448 			rtm->rtm_priority = rt->rt_priority;
449 			rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
450 			rtm->rtm_addrs = info.rti_addrs;
451 			break;
452 
453 		case RTM_CHANGE:
454 			/*
455 			 * new gateway could require new ifaddr, ifp;
456 			 * flags may also be different; ifp may be specified
457 			 * by ll sockaddr when protocol address is ambiguous
458 			 */
459 			if ((error = rt_getifa(&info)) != 0)
460 				goto flush;
461 			if (gate && rt_setgate(rt, rt_key(rt), gate, tableid)) {
462 				error = EDQUOT;
463 				goto flush;
464 			}
465 			if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
466 			    (ifp = ifa->ifa_ifp) && (ifaaddr || gate))
467 				ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
468 							ifp);
469 			else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
470 			    (gate && (ifa = ifa_ifwithroute(rt->rt_flags,
471 			    rt_key(rt), gate))))
472 				ifp = ifa->ifa_ifp;
473 			if (ifa) {
474 				struct ifaddr *oifa = rt->rt_ifa;
475 				if (oifa != ifa) {
476 				    if (oifa && oifa->ifa_rtrequest)
477 					oifa->ifa_rtrequest(RTM_DELETE, rt,
478 					    &info);
479 				    IFAFREE(rt->rt_ifa);
480 				    rt->rt_ifa = ifa;
481 				    ifa->ifa_refcnt++;
482 				    rt->rt_ifp = ifp;
483 				}
484 			}
485 
486 			/* XXX Hack to allow some flags to be toggled */
487 			if (rtm->rtm_fmask & RTF_FMASK)
488 				rt->rt_flags = (rt->rt_flags &
489 				    ~rtm->rtm_fmask) |
490 				    (rtm->rtm_flags & rtm->rtm_fmask);
491 
492 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
493 			    &rt->rt_rmx);
494 			rtm->rtm_index = rt->rt_ifp->if_index;
495 			if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
496 				rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
497 			if (genmask)
498 				rt->rt_genmask = genmask;
499 			if (info.rti_info[RTAX_LABEL] != NULL) {
500 				char *rtlabel = ((struct sockaddr_rtlabel *)
501 				    info.rti_info[RTAX_LABEL])->sr_label;
502 				rtlabel_unref(rt->rt_labelid);
503 				rt->rt_labelid =
504 				    rtlabel_name2id(rtlabel);
505 			}
506 			if_group_routechange(dst, netmask);
507 			/* FALLTHROUGH */
508 		case RTM_LOCK:
509 			rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
510 			rt->rt_rmx.rmx_locks |=
511 			    (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
512 			break;
513 		}
514 		break;
515 
516 	default:
517 		error = EOPNOTSUPP;
518 		break;
519 	}
520 
521 flush:
522 	if (rtm) {
523 		if (error)
524 			rtm->rtm_errno = error;
525 		else
526 			rtm->rtm_flags |= RTF_DONE;
527 	}
528 	if (rt)
529 		rtfree(rt);
530 
531 	/*
532 	 * Check to see if we don't want our own messages.
533 	 */
534 	if (!(so->so_options & SO_USELOOPBACK)) {
535 		if (route_cb.any_count <= 1) {
536 			if (rtm)
537 				Free(rtm);
538 			m_freem(m);
539 			return (error);
540 		}
541 		/* There is another listener, so construct message */
542 		rp = sotorawcb(so);
543 	}
544 	if (rp)
545 		rp->rcb_proto.sp_family = 0; /* Avoid us */
546 	if (dst)
547 		route_proto.sp_protocol = dst->sa_family;
548 	if (rtm) {
549 		m_copyback(m, 0, rtm->rtm_msglen, rtm);
550 		if (m->m_pkthdr.len < rtm->rtm_msglen) {
551 			m_freem(m);
552 			m = NULL;
553 		} else if (m->m_pkthdr.len > rtm->rtm_msglen)
554 			m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
555 		Free(rtm);
556 	}
557 	if (m)
558 		raw_input(m, &route_proto, &route_src, &route_dst);
559 	if (rp)
560 		rp->rcb_proto.sp_family = PF_ROUTE;
561 
562 	return (error);
563 }
564 
565 void
566 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out)
567 {
568 	if (which & RTV_MTU)
569 		out->rmx_mtu = in->rmx_mtu;
570 	if (which & RTV_EXPIRE)
571 		out->rmx_expire = in->rmx_expire;
572 	/* RTV_PRIORITY handled befor */
573 }
574 
575 void
576 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out)
577 {
578 	bzero(out, sizeof(*out));
579 	out->rmx_locks = in->rmx_locks;
580 	out->rmx_mtu = in->rmx_mtu;
581 	out->rmx_expire = in->rmx_expire;
582 	out->rmx_pksent = in->rmx_pksent;
583 }
584 
585 #define ROUNDUP(a) \
586 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
587 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
588 
589 void
590 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
591 {
592 	struct sockaddr	*sa;
593 	int		 i;
594 
595 	bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
596 	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
597 		if ((rtinfo->rti_addrs & (1 << i)) == 0)
598 			continue;
599 		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
600 		ADVANCE(cp, sa);
601 	}
602 }
603 
604 struct mbuf *
605 rt_msg1(int type, struct rt_addrinfo *rtinfo)
606 {
607 	struct rt_msghdr	*rtm;
608 	struct mbuf		*m;
609 	int			 i;
610 	struct sockaddr		*sa;
611 	int			 len, dlen, hlen;
612 
613 	switch (type) {
614 	case RTM_DELADDR:
615 	case RTM_NEWADDR:
616 		len = sizeof(struct ifa_msghdr);
617 		break;
618 	case RTM_IFINFO:
619 		len = sizeof(struct if_msghdr);
620 		break;
621 	case RTM_IFANNOUNCE:
622 		len = sizeof(struct if_announcemsghdr);
623 		break;
624 	default:
625 		len = sizeof(struct rt_msghdr);
626 		break;
627 	}
628 	if (len > MCLBYTES)
629 		panic("rt_msg1");
630 	m = m_gethdr(M_DONTWAIT, MT_DATA);
631 	if (m && len > MHLEN) {
632 		MCLGET(m, M_DONTWAIT);
633 		if ((m->m_flags & M_EXT) == 0) {
634 			m_free(m);
635 			m = NULL;
636 		}
637 	}
638 	if (m == 0)
639 		return (m);
640 	m->m_pkthdr.len = m->m_len = hlen = len;
641 	m->m_pkthdr.rcvif = NULL;
642 	rtm = mtod(m, struct rt_msghdr *);
643 	bzero(rtm, len);
644 	for (i = 0; i < RTAX_MAX; i++) {
645 		if ((sa = rtinfo->rti_info[i]) == NULL)
646 			continue;
647 		rtinfo->rti_addrs |= (1 << i);
648 		dlen = ROUNDUP(sa->sa_len);
649 		m_copyback(m, len, dlen, sa);
650 		len += dlen;
651 	}
652 	if (m->m_pkthdr.len != len) {
653 		m_freem(m);
654 		return (NULL);
655 	}
656 	rtm->rtm_msglen = len;
657 	rtm->rtm_hdrlen = hlen;
658 	rtm->rtm_version = RTM_VERSION;
659 	rtm->rtm_type = type;
660 	return (m);
661 }
662 
663 int
664 rt_msg2(int type, int vers, struct rt_addrinfo *rtinfo, caddr_t cp,
665     struct walkarg *w)
666 {
667 	int		i;
668 	int		len, dlen, hlen, second_time = 0;
669 	caddr_t		cp0;
670 
671 	rtinfo->rti_addrs = 0;
672 again:
673 	switch (type) {
674 	case RTM_DELADDR:
675 	case RTM_NEWADDR:
676 #ifndef SMALL_KERNEL
677 		if (vers == RTM_OVERSION)
678 			len = sizeof(struct ifa_omsghdr);
679 		else
680 #endif
681 			len = sizeof(struct ifa_msghdr);
682 		break;
683 	case RTM_IFINFO:
684 #ifndef SMALL_KERNEL
685 		if (vers == RTM_OVERSION)
686 			len = sizeof(struct if_omsghdr);
687 		else
688 #endif
689 			len = sizeof(struct if_msghdr);
690 		break;
691 	default:
692 #ifndef SMALL_KERNEL
693 		if (vers == RTM_OVERSION)
694 			len = sizeof(struct rt_omsghdr);
695 		else
696 #endif
697 			len = sizeof(struct rt_msghdr);
698 		break;
699 	}
700 	hlen = len;
701 	if ((cp0 = cp) != NULL)
702 		cp += len;
703 	for (i = 0; i < RTAX_MAX; i++) {
704 		struct sockaddr *sa;
705 
706 		if ((sa = rtinfo->rti_info[i]) == 0)
707 			continue;
708 		rtinfo->rti_addrs |= (1 << i);
709 		dlen = ROUNDUP(sa->sa_len);
710 		if (cp) {
711 			bcopy(sa, cp, (size_t)dlen);
712 			cp += dlen;
713 		}
714 		len += dlen;
715 	}
716 	/* align message length to the next natural boundary */
717 	len = ALIGN(len);
718 	if (cp == 0 && w != NULL && !second_time) {
719 		struct walkarg *rw = w;
720 
721 		rw->w_needed += len;
722 		if (rw->w_needed <= 0 && rw->w_where) {
723 			if (rw->w_tmemsize < len) {
724 				if (rw->w_tmem)
725 					free(rw->w_tmem, M_RTABLE);
726 				rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT);
727 				if (rw->w_tmem)
728 					rw->w_tmemsize = len;
729 			}
730 			if (rw->w_tmem) {
731 				cp = rw->w_tmem;
732 				second_time = 1;
733 				goto again;
734 			} else
735 				rw->w_where = 0;
736 		}
737 	}
738 	if (cp && w)		/* clear the message header */
739 		bzero(cp0, hlen);
740 
741 	if (cp && vers != RTM_OVERSION) {
742 		struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
743 
744 		rtm->rtm_version = RTM_VERSION;
745 		rtm->rtm_type = type;
746 		rtm->rtm_msglen = len;
747 		rtm->rtm_hdrlen = hlen;
748 	}
749 #ifndef SMALL_KERNEL
750 	if (cp && vers == RTM_OVERSION) {
751 		struct rt_omsghdr *rtm = (struct rt_omsghdr *)cp0;
752 
753 		rtm->rtm_version = RTM_OVERSION;
754 		rtm->rtm_type = type;
755 		rtm->rtm_msglen = len;
756 	}
757 #endif
758 	return (len);
759 }
760 
761 /*
762  * This routine is called to generate a message from the routing
763  * socket indicating that a redirect has occurred, a routing lookup
764  * has failed, or that a protocol has detected timeouts to a particular
765  * destination.
766  */
767 void
768 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags,
769     struct ifnet *ifp, int error, u_int tableid)
770 {
771 	struct rt_msghdr	*rtm;
772 	struct mbuf		*m;
773 	struct sockaddr		*sa = rtinfo->rti_info[RTAX_DST];
774 
775 	if (route_cb.any_count == 0)
776 		return;
777 	m = rt_msg1(type, rtinfo);
778 	if (m == 0)
779 		return;
780 	rtm = mtod(m, struct rt_msghdr *);
781 	rtm->rtm_flags = RTF_DONE | flags;
782 	rtm->rtm_errno = error;
783 	rtm->rtm_tableid = tableid;
784 	rtm->rtm_addrs = rtinfo->rti_addrs;
785 	if (ifp != NULL)
786 		rtm->rtm_index = ifp->if_index;
787 	if (sa == NULL)
788 		route_proto.sp_protocol = 0;
789 	else
790 		route_proto.sp_protocol = sa->sa_family;
791 	raw_input(m, &route_proto, &route_src, &route_dst);
792 }
793 
794 /*
795  * This routine is called to generate a message from the routing
796  * socket indicating that the status of a network interface has changed.
797  */
798 void
799 rt_ifmsg(struct ifnet *ifp)
800 {
801 	struct if_msghdr	*ifm;
802 	struct mbuf		*m;
803 	struct rt_addrinfo	 info;
804 
805 	if (route_cb.any_count == 0)
806 		return;
807 	bzero(&info, sizeof(info));
808 	m = rt_msg1(RTM_IFINFO, &info);
809 	if (m == 0)
810 		return;
811 	ifm = mtod(m, struct if_msghdr *);
812 	ifm->ifm_index = ifp->if_index;
813 	ifm->ifm_flags = ifp->if_flags;
814 	ifm->ifm_data = ifp->if_data;
815 	ifm->ifm_addrs = 0;
816 	route_proto.sp_protocol = 0;
817 	raw_input(m, &route_proto, &route_src, &route_dst);
818 }
819 
820 /*
821  * This is called to generate messages from the routing socket
822  * indicating a network interface has had addresses associated with it.
823  * if we ever reverse the logic and replace messages TO the routing
824  * socket indicate a request to configure interfaces, then it will
825  * be unnecessary as the routing socket will automatically generate
826  * copies of it.
827  */
828 void
829 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
830 {
831 	struct rt_addrinfo	 info;
832 	struct sockaddr		*sa = NULL;
833 	int			 pass;
834 	struct mbuf		*m = NULL;
835 	struct ifnet		*ifp = ifa->ifa_ifp;
836 
837 	if (route_cb.any_count == 0)
838 		return;
839 	for (pass = 1; pass < 3; pass++) {
840 		bzero(&info, sizeof(info));
841 		if ((cmd == RTM_ADD && pass == 1) ||
842 		    (cmd == RTM_DELETE && pass == 2)) {
843 			struct ifa_msghdr	*ifam;
844 			int			 ncmd;
845 
846 			if (cmd == RTM_ADD)
847 				ncmd = RTM_NEWADDR;
848 			else
849 				ncmd = RTM_DELADDR;
850 
851 			ifaaddr = sa = ifa->ifa_addr;
852 			ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
853 			netmask = ifa->ifa_netmask;
854 			brdaddr = ifa->ifa_dstaddr;
855 			if ((m = rt_msg1(ncmd, &info)) == NULL)
856 				continue;
857 			ifam = mtod(m, struct ifa_msghdr *);
858 			ifam->ifam_index = ifp->if_index;
859 			ifam->ifam_metric = ifa->ifa_metric;
860 			ifam->ifam_flags = ifa->ifa_flags;
861 			ifam->ifam_addrs = info.rti_addrs;
862 		}
863 		if ((cmd == RTM_ADD && pass == 2) ||
864 		    (cmd == RTM_DELETE && pass == 1)) {
865 			struct rt_msghdr *rtm;
866 
867 			if (rt == 0)
868 				continue;
869 			netmask = rt_mask(rt);
870 			dst = sa = rt_key(rt);
871 			gate = rt->rt_gateway;
872 			if ((m = rt_msg1(cmd, &info)) == NULL)
873 				continue;
874 			rtm = mtod(m, struct rt_msghdr *);
875 			rtm->rtm_index = ifp->if_index;
876 			rtm->rtm_flags |= rt->rt_flags;
877 			rtm->rtm_errno = error;
878 			rtm->rtm_addrs = info.rti_addrs;
879 		}
880 		if (sa == NULL)
881 			route_proto.sp_protocol = 0;
882 		else
883 			route_proto.sp_protocol = sa->sa_family;
884 		raw_input(m, &route_proto, &route_src, &route_dst);
885 	}
886 }
887 
888 /*
889  * This is called to generate routing socket messages indicating
890  * network interface arrival and departure.
891  */
892 void
893 rt_ifannouncemsg(struct ifnet *ifp, int what)
894 {
895 	struct if_announcemsghdr	*ifan;
896 	struct mbuf			*m;
897 	struct rt_addrinfo		 info;
898 
899 	if (route_cb.any_count == 0)
900 		return;
901 	bzero(&info, sizeof(info));
902 	m = rt_msg1(RTM_IFANNOUNCE, &info);
903 	if (m == 0)
904 		return;
905 	ifan = mtod(m, struct if_announcemsghdr *);
906 	ifan->ifan_index = ifp->if_index;
907 	strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
908 	ifan->ifan_what = what;
909 	route_proto.sp_protocol = 0;
910 	raw_input(m, &route_proto, &route_src, &route_dst);
911 }
912 
913 /*
914  * This is used in dumping the kernel table via sysctl().
915  */
916 int
917 sysctl_dumpentry(struct radix_node *rn, void *v)
918 {
919 	struct walkarg		*w = v;
920 	struct rtentry		*rt = (struct rtentry *)rn;
921 	int			 error = 0, size;
922 	struct rt_addrinfo	 info;
923 	struct sockaddr_rtlabel	 sa_rt;
924 	const char		*label;
925 
926 	if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
927 		return 0;
928 	bzero(&info, sizeof(info));
929 	dst = rt_key(rt);
930 	gate = rt->rt_gateway;
931 	netmask = rt_mask(rt);
932 	genmask = rt->rt_genmask;
933 	if (rt->rt_ifp) {
934 		ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
935 		ifaaddr = rt->rt_ifa->ifa_addr;
936 		if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
937 			brdaddr = rt->rt_ifa->ifa_dstaddr;
938 	}
939 	if (rt->rt_labelid) {
940 		bzero(&sa_rt, sizeof(sa_rt));
941 		sa_rt.sr_len = sizeof(sa_rt);
942 		label = rtlabel_id2name(rt->rt_labelid);
943 		if (label != NULL) {
944 			strlcpy(sa_rt.sr_label, label,
945 			    sizeof(sa_rt.sr_label));
946 			info.rti_info[RTAX_LABEL] =
947 			    (struct sockaddr *)&sa_rt;
948 		}
949 	}
950 
951 	size = rt_msg2(RTM_GET, RTM_VERSION, &info, NULL, w);
952 	if (w->w_where && w->w_tmem && w->w_needed <= 0) {
953 		struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
954 
955 		rtm->rtm_flags = rt->rt_flags;
956 		rtm->rtm_priority = rt->rt_priority;
957 		rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
958 		rtm->rtm_rmx.rmx_refcnt = rt->rt_refcnt;
959 		rtm->rtm_index = rt->rt_ifp->if_index;
960 		rtm->rtm_addrs = info.rti_addrs;
961 		if ((error = copyout(rtm, w->w_where, size)) != 0)
962 			w->w_where = NULL;
963 		else
964 			w->w_where += size;
965 	}
966 #ifndef SMALL_KERNEL
967 	size = rt_msg2(RTM_GET, RTM_OVERSION, &info, NULL, w);
968 	if (w->w_where && w->w_tmem && w->w_needed <= 0) {
969 		struct rt_omsghdr *rtm = (struct rt_omsghdr *)w->w_tmem;
970 
971 		rtm->rtm_flags = rt->rt_flags;
972 		rtm->rtm_rmx.rmx_locks = rt->rt_rmx.rmx_locks;
973 		rtm->rtm_rmx.rmx_mtu = rt->rt_rmx.rmx_mtu;
974 		rtm->rtm_index = rt->rt_ifp->if_index;
975 		rtm->rtm_addrs = info.rti_addrs;
976 		if ((error = copyout(rtm, w->w_where, size)) != 0)
977 			w->w_where = NULL;
978 		else
979 			w->w_where += size;
980 	}
981 #endif
982 	return (error);
983 }
984 
985 int
986 sysctl_iflist(int af, struct walkarg *w)
987 {
988 	struct ifnet		*ifp;
989 	struct ifaddr		*ifa;
990 	struct rt_addrinfo	 info;
991 	int			 len, error = 0;
992 
993 	bzero(&info, sizeof(info));
994 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
995 		if (w->w_arg && w->w_arg != ifp->if_index)
996 			continue;
997 		ifa = TAILQ_FIRST(&ifp->if_addrlist);
998 		if (!ifa)
999 			continue;
1000 		ifpaddr = ifa->ifa_addr;
1001 		len = rt_msg2(RTM_IFINFO, RTM_VERSION, &info, 0, w);
1002 		if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1003 			struct if_msghdr *ifm;
1004 
1005 			ifm = (struct if_msghdr *)w->w_tmem;
1006 			ifm->ifm_index = ifp->if_index;
1007 			ifm->ifm_flags = ifp->if_flags;
1008 			ifm->ifm_data = ifp->if_data;
1009 			ifm->ifm_addrs = info.rti_addrs;
1010 			error = copyout(ifm, w->w_where, len);
1011 			if (error)
1012 				return (error);
1013 			w->w_where += len;
1014 		}
1015 #ifndef SMALL_KERNEL
1016 		len = rt_msg2(RTM_IFINFO, RTM_OVERSION, &info, 0, w);
1017 		if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1018 			struct if_omsghdr *ifm;
1019 
1020 			ifm = (struct if_omsghdr *)w->w_tmem;
1021 			ifm->ifm_index = ifp->if_index;
1022 			ifm->ifm_flags = ifp->if_flags;
1023 			/* just init the most important types of if_data */
1024 			ifm->ifm_data.ifi_type = ifp->if_data.ifi_type;
1025 			ifm->ifm_data.ifi_addrlen = ifp->if_data.ifi_addrlen;
1026 			ifm->ifm_data.ifi_hdrlen = ifp->if_data.ifi_hdrlen;
1027 			ifm->ifm_data.ifi_link_state =
1028 			    ifp->if_data.ifi_link_state;
1029 			ifm->ifm_data.ifi_mtu = ifp->if_data.ifi_mtu;
1030 			ifm->ifm_data.ifi_metric = ifp->if_data.ifi_metric;
1031 			if (ifp->if_data.ifi_baudrate > ULONG_MAX)
1032 				ifm->ifm_data.ifi_baudrate = ULONG_MAX;
1033 			else
1034 				ifm->ifm_data.ifi_baudrate =
1035 				    ifp->if_data.ifi_baudrate;
1036 
1037 			ifm->ifm_addrs = info.rti_addrs;
1038 			error = copyout(ifm, w->w_where, len);
1039 			if (error)
1040 				return (error);
1041 			w->w_where += len;
1042 		}
1043 #endif
1044 		ifpaddr = 0;
1045 		while ((ifa = TAILQ_NEXT(ifa, ifa_list)) !=
1046 		    TAILQ_END(&ifp->if_addrlist)) {
1047 			if (af && af != ifa->ifa_addr->sa_family)
1048 				continue;
1049 			ifaaddr = ifa->ifa_addr;
1050 			netmask = ifa->ifa_netmask;
1051 			brdaddr = ifa->ifa_dstaddr;
1052 			len = rt_msg2(RTM_NEWADDR, RTM_VERSION, &info, 0, w);
1053 			if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1054 				struct ifa_msghdr *ifam;
1055 
1056 				ifam = (struct ifa_msghdr *)w->w_tmem;
1057 				ifam->ifam_index = ifa->ifa_ifp->if_index;
1058 				ifam->ifam_flags = ifa->ifa_flags;
1059 				ifam->ifam_metric = ifa->ifa_metric;
1060 				ifam->ifam_addrs = info.rti_addrs;
1061 				error = copyout(w->w_tmem, w->w_where, len);
1062 				if (error)
1063 					return (error);
1064 				w->w_where += len;
1065 			}
1066 #ifndef SMALL_KERNEL
1067 			len = rt_msg2(RTM_NEWADDR, RTM_OVERSION, &info, 0, w);
1068 			if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1069 				struct ifa_omsghdr *ifam;
1070 
1071 				ifam = (struct ifa_omsghdr *)w->w_tmem;
1072 				ifam->ifam_index = ifa->ifa_ifp->if_index;
1073 				ifam->ifam_flags = ifa->ifa_flags;
1074 				ifam->ifam_metric = ifa->ifa_metric;
1075 				ifam->ifam_addrs = info.rti_addrs;
1076 				error = copyout(w->w_tmem, w->w_where, len);
1077 				if (error)
1078 					return (error);
1079 				w->w_where += len;
1080 			}
1081 #endif
1082 		}
1083 		ifaaddr = netmask = brdaddr = 0;
1084 	}
1085 	return (0);
1086 }
1087 
1088 int
1089 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new,
1090     size_t newlen)
1091 {
1092 	struct radix_node_head	*rnh;
1093 	int			 i, s, error = EINVAL;
1094 	u_char  		 af;
1095 	struct walkarg		 w;
1096 	u_int			 tableid = 0;
1097 
1098 	if (new)
1099 		return (EPERM);
1100 	if (namelen < 3 || namelen > 4)
1101 		return (EINVAL);
1102 	af = name[0];
1103 	bzero(&w, sizeof(w));
1104 	w.w_where = where;
1105 	w.w_given = *given;
1106 	w.w_needed = 0 - w.w_given;
1107 	w.w_op = name[1];
1108 	w.w_arg = name[2];
1109 
1110 	if (namelen == 4) {
1111 		tableid = name[3];
1112 		if (!rtable_exists(tableid))
1113 			return (EINVAL);
1114 	}
1115 
1116 	s = splsoftnet();
1117 	switch (w.w_op) {
1118 
1119 	case NET_RT_DUMP:
1120 	case NET_RT_FLAGS:
1121 		for (i = 1; i <= AF_MAX; i++)
1122 			if ((rnh = rt_gettable(i, tableid)) != NULL &&
1123 			    (af == 0 || af == i) &&
1124 			    (error = (*rnh->rnh_walktree)(rnh,
1125 			    sysctl_dumpentry, &w)))
1126 				break;
1127 		break;
1128 
1129 	case NET_RT_IFLIST:
1130 		error = sysctl_iflist(af, &w);
1131 		break;
1132 
1133 	case NET_RT_STATS:
1134 		error = sysctl_rdstruct(where, given, new,
1135 		    &rtstat, sizeof(rtstat));
1136 		splx(s);
1137 		return (error);
1138 	}
1139 	splx(s);
1140 	if (w.w_tmem)
1141 		free(w.w_tmem, M_RTABLE);
1142 	w.w_needed += w.w_given;
1143 	if (where) {
1144 		*given = w.w_where - (caddr_t)where;
1145 		if (*given < w.w_needed)
1146 			return (ENOMEM);
1147 	} else
1148 		*given = (11 * w.w_needed) / 10;
1149 
1150 	return (error);
1151 }
1152 
1153 #ifndef SMALL_KERNEL
1154 struct rt_msghdr *
1155 rtmsg_3to4(struct mbuf *m, int *len)
1156 {
1157 	struct rt_msghdr *rtm;
1158 	struct rt_omsghdr *ortm;
1159 	int slen;
1160 
1161 	slen = *len - sizeof(struct rt_omsghdr);
1162 	*len = sizeof(struct rt_msghdr) + slen;
1163 	R_Malloc(rtm, struct rt_msghdr *, *len);
1164 	if (rtm == 0)
1165 		return (NULL);
1166 	bzero(rtm, sizeof(struct rt_msghdr));
1167 	ortm = mtod(m, struct rt_omsghdr *);
1168 	rtm->rtm_msglen = sizeof(struct rt_msghdr) + slen;
1169 	rtm->rtm_version = RTM_VERSION;
1170 	rtm->rtm_type = ortm->rtm_type;
1171 	rtm->rtm_hdrlen = sizeof(struct rt_msghdr);
1172 	rtm->rtm_index = ortm->rtm_index;
1173 	rtm->rtm_tableid = 0; /* XXX we only care about the main table */
1174 	rtm->rtm_flags = ortm->rtm_flags;
1175 	rtm->rtm_addrs = ortm->rtm_addrs;
1176 	rtm->rtm_seq = ortm->rtm_seq;
1177 	rtm->rtm_fmask = ortm->rtm_fmask;
1178 	rtm->rtm_inits = ortm->rtm_inits;
1179 	/* copy just the interesting stuff ignore the rest */
1180 	rtm->rtm_rmx.rmx_locks = ortm->rtm_rmx.rmx_locks;
1181 	rtm->rtm_rmx.rmx_mtu = ortm->rtm_rmx.rmx_mtu;
1182 
1183 	m_copydata(m, sizeof(struct rt_omsghdr), slen,
1184 	    ((caddr_t)rtm + sizeof(struct rt_msghdr)));
1185 
1186 	return (rtm);
1187 }
1188 #endif
1189 
1190 /*
1191  * Definitions of protocols supported in the ROUTE domain.
1192  */
1193 
1194 extern	struct domain routedomain;		/* or at least forward */
1195 
1196 struct protosw routesw[] = {
1197 { SOCK_RAW,	&routedomain,	0,		PR_ATOMIC|PR_ADDR,
1198   raw_input,	route_output,	raw_ctlinput,	0,
1199   route_usrreq,
1200   raw_init,	0,		0,		0,
1201   sysctl_rtable,
1202 }
1203 };
1204 
1205 struct domain routedomain =
1206     { PF_ROUTE, "route", route_init, 0, 0,
1207       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
1208