1 /*	$OpenBSD: rtsock.c,v 1.48 2005/06/08 06:43:07 henning 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 #include <sys/stdarg.h>
81 
82 struct sockaddr		route_dst = { 2, PF_ROUTE, };
83 struct sockaddr		route_src = { 2, PF_ROUTE, };
84 struct sockproto	route_proto = { PF_ROUTE, };
85 
86 struct walkarg {
87 	int	w_op, w_arg, w_given, w_needed, w_tmemsize;
88 	caddr_t	w_where, w_tmem;
89 };
90 
91 static struct mbuf
92 		*rt_msg1(int, struct rt_addrinfo *);
93 static int	 rt_msg2(int, struct rt_addrinfo *, caddr_t, struct walkarg *);
94 static void	 rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
95 
96 /* Sleazy use of local variables throughout file, warning!!!! */
97 #define dst	info.rti_info[RTAX_DST]
98 #define gate	info.rti_info[RTAX_GATEWAY]
99 #define netmask	info.rti_info[RTAX_NETMASK]
100 #define genmask	info.rti_info[RTAX_GENMASK]
101 #define ifpaddr	info.rti_info[RTAX_IFP]
102 #define ifaaddr	info.rti_info[RTAX_IFA]
103 #define brdaddr	info.rti_info[RTAX_BRD]
104 
105 int
route_usrreq(struct socket * so,int req,struct mbuf * m,struct mbuf * nam,struct mbuf * control)106 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
107     struct mbuf *control)
108 {
109 	int		 error = 0;
110 	struct rawcb	*rp = sotorawcb(so);
111 	int		 s;
112 
113 	if (req == PRU_ATTACH) {
114 		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
115 		so->so_pcb = rp;
116 		bzero(so->so_pcb, sizeof(*rp));
117 	}
118 	if (req == PRU_DETACH && rp) {
119 		int af = rp->rcb_proto.sp_protocol;
120 		if (af == AF_INET)
121 			route_cb.ip_count--;
122 		else if (af == AF_INET6)
123 			route_cb.ip6_count--;
124 		route_cb.any_count--;
125 	}
126 	s = splsoftnet();
127 	/*
128 	 * Don't call raw_usrreq() in the attach case, because
129 	 * we want to allow non-privileged processes to listen on
130 	 * and send "safe" commands to the routing socket.
131 	 */
132 	if (req == PRU_ATTACH) {
133 		if (curproc == 0)
134 			error = EACCES;
135 		else
136 			error = raw_attach(so, (int)(long)nam);
137 	} else
138 		error = raw_usrreq(so, req, m, nam, control);
139 
140 	rp = sotorawcb(so);
141 	if (req == PRU_ATTACH && rp) {
142 		int af = rp->rcb_proto.sp_protocol;
143 		if (error) {
144 			free(rp, M_PCB);
145 			splx(s);
146 			return (error);
147 		}
148 		if (af == AF_INET)
149 			route_cb.ip_count++;
150 		else if (af == AF_INET6)
151 			route_cb.ip6_count++;
152 		rp->rcb_faddr = &route_src;
153 		route_cb.any_count++;
154 		soisconnected(so);
155 		so->so_options |= SO_USELOOPBACK;
156 	}
157 	splx(s);
158 	return (error);
159 }
160 
161 int
route_output(struct mbuf * m,...)162 route_output(struct mbuf *m, ...)
163 {
164 	struct rt_msghdr	*rtm = NULL;
165 	struct radix_node	*rn = NULL;
166 	struct rtentry		*rt = NULL;
167 	struct rtentry		*saved_nrt = NULL;
168 	struct radix_node_head	*rnh;
169 	struct rt_addrinfo	 info;
170 	int			 len, error = 0;
171 	struct ifnet		*ifp = NULL;
172 	struct ifaddr		*ifa = NULL;
173 	struct socket		*so;
174 	struct rawcb		*rp = NULL;
175 	struct sockaddr_rtlabel	 sa_rt;
176 	const char		*label;
177 	va_list			 ap;
178 
179 	va_start(ap, m);
180 	so = va_arg(ap, struct socket *);
181 	va_end(ap);
182 
183 	if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
184 	    (m = m_pullup(m, sizeof(int32_t))) == 0))
185 		return (ENOBUFS);
186 	if ((m->m_flags & M_PKTHDR) == 0)
187 		panic("route_output");
188 	len = m->m_pkthdr.len;
189 	if (len < sizeof(*rtm) ||
190 	    len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
191 		dst = 0;
192 		error = EINVAL;
193 		goto flush;
194 	}
195 	R_Malloc(rtm, struct rt_msghdr *, len);
196 	if (rtm == 0) {
197 		dst = 0;
198 		error = ENOBUFS;
199 		goto flush;
200 	}
201 	m_copydata(m, 0, len, (caddr_t)rtm);
202 	if (rtm->rtm_version != RTM_VERSION) {
203 		dst = 0;
204 		error = EPROTONOSUPPORT;
205 		goto flush;
206 	}
207 	rtm->rtm_pid = curproc->p_pid;
208 
209 	bzero(&info, sizeof(info));
210 	info.rti_addrs = rtm->rtm_addrs;
211 	rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);
212 	info.rti_flags = rtm->rtm_flags;
213 	if (dst == 0 || dst->sa_family >= AF_MAX ||
214 	    (gate != 0 && gate->sa_family >= AF_MAX)) {
215 		error = EINVAL;
216 		goto flush;
217 	}
218 	if (genmask) {
219 		struct radix_node	*t;
220 		t = rn_addmask(genmask, 0, 1);
221 		if (t && genmask->sa_len >=
222 		    ((struct sockaddr *)t->rn_key)->sa_len &&
223 		    Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1,
224 		    ((struct sockaddr *)t->rn_key)->sa_len) - 1)
225 			genmask = (struct sockaddr *)(t->rn_key);
226 		else {
227 			error = ENOBUFS;
228 			goto flush;
229 		}
230 	}
231 
232 	/*
233 	 * Verify that the caller has the appropriate privilege; RTM_GET
234 	 * is the only operation the non-superuser is allowed.
235 	 */
236 	if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) {
237 		error = EACCES;
238 		goto flush;
239 	}
240 
241 	switch (rtm->rtm_type) {
242 	case RTM_ADD:
243 		if (gate == 0) {
244 			error = EINVAL;
245 			goto flush;
246 		}
247 		error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);
248 		if (error == 0 && saved_nrt) {
249 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
250 			    &saved_nrt->rt_rmx);
251 			saved_nrt->rt_refcnt--;
252 			saved_nrt->rt_genmask = genmask;
253 		}
254 		break;
255 	case RTM_DELETE:
256 		error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);
257 		if (error == 0) {
258 			(rt = saved_nrt)->rt_refcnt++;
259 			goto report;
260 		}
261 		break;
262 	case RTM_GET:
263 	case RTM_CHANGE:
264 	case RTM_LOCK:
265 		if ((rnh = rt_tables[dst->sa_family]) == 0) {
266 			error = EAFNOSUPPORT;
267 			goto flush;
268 		}
269 		rn = rnh->rnh_lookup(dst, netmask, rnh);
270 		if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {
271 			error = ESRCH;
272 			goto flush;
273 		}
274 		rt = (struct rtentry *)rn;
275 #ifndef SMALL_KERNEL
276 		/*
277 		 * for RTM_CHANGE/LOCK, if we got multipath routes,
278 		 * we require users to specify a matching RTAX_GATEWAY.
279 		 *
280 		 * for RTM_GET, gate is optional even with multipath.
281 		 * if gate == NULL the first match is returned.
282 		 * (no need to call rt_mpath_matchgate if gate == NULL)
283 		 */
284 		if (rn_mpath_capable(rnh) &&
285 		    (rtm->rtm_type != RTM_GET || gate)) {
286 			rt = rt_mpath_matchgate(rt, gate);
287 			rn = (struct radix_node *)rt;
288 			if (!rt) {
289 				error = ESRCH;
290 				goto flush;
291 			}
292 		}
293 #endif
294 		rt->rt_refcnt++;
295 
296 		/*
297 		 * RTM_CHANGE/LOCK need a perfect match, rn_lookup()
298 		 * returns a perfect match in case a netmask is specified.
299 		 * For host routes only a longest prefix match is returned
300 		 * so it is necessary to compare the existence of the netmaks.
301 		 * If both have a netmask rn_lookup() did a perfect match and
302 		 * if non of them have a netmask both are host routes which is
303 		 * also a perfect match.
304 		 */
305 		if (rtm->rtm_type != RTM_GET && !rt_mask(rt) != !netmask) {
306 				error = ESRCH;
307 				goto flush;
308 		}
309 
310 		switch (rtm->rtm_type) {
311 		case RTM_GET:
312 report:
313 			dst = rt_key(rt);
314 			gate = rt->rt_gateway;
315 			netmask = rt_mask(rt);
316 			genmask = rt->rt_genmask;
317 
318 			if (rt->rt_labelid) {
319 				bzero(&sa_rt, sizeof(sa_rt));
320 				sa_rt.sr_len = sizeof(sa_rt);
321 				label = rtlabel_id2name(rt->rt_labelid);
322 				if (label != NULL)
323 					strlcpy(sa_rt.sr_label, label,
324 					    sizeof(sa_rt.sr_label));
325 				info.rti_info[RTAX_LABEL] =
326 				    (struct sockaddr *)&sa_rt;
327 			}
328 
329 			ifpaddr = 0;
330 			ifaaddr = 0;
331 			if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) &&
332 			    (ifp = rt->rt_ifp) != NULL) {
333 				ifpaddr =
334 				    TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
335 				ifaaddr = rt->rt_ifa->ifa_addr;
336 				if (ifp->if_flags & IFF_POINTOPOINT)
337 					brdaddr = rt->rt_ifa->ifa_dstaddr;
338 				else
339 					brdaddr = 0;
340 				rtm->rtm_index = ifp->if_index;
341 			}
342 			len = rt_msg2(rtm->rtm_type, &info, NULL, NULL);
343 			if (len > rtm->rtm_msglen) {
344 				struct rt_msghdr	*new_rtm;
345 				R_Malloc(new_rtm, struct rt_msghdr *, len);
346 				if (new_rtm == 0) {
347 					error = ENOBUFS;
348 					goto flush;
349 				}
350 				Bcopy(rtm, new_rtm, rtm->rtm_msglen);
351 				Free(rtm); rtm = new_rtm;
352 			}
353 			rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL);
354 			rtm->rtm_flags = rt->rt_flags;
355 			rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
356 			rtm->rtm_addrs = info.rti_addrs;
357 			break;
358 
359 		case RTM_CHANGE:
360 			/*
361 			 * new gateway could require new ifaddr, ifp;
362 			 * flags may also be different; ifp may be specified
363 			 * by ll sockaddr when protocol address is ambiguous
364 			 */
365 			if ((error = rt_getifa(&info)) != 0)
366 				goto flush;
367 			if (gate && rt_setgate(rt, rt_key(rt), gate)) {
368 				error = EDQUOT;
369 				goto flush;
370 			}
371 			if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
372 			    (ifp = ifa->ifa_ifp) && (ifaaddr || gate))
373 				ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
374 							ifp);
375 			else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
376 			    (gate && (ifa = ifa_ifwithroute(rt->rt_flags,
377 			    rt_key(rt), gate))))
378 				ifp = ifa->ifa_ifp;
379 			if (ifa) {
380 				struct ifaddr *oifa = rt->rt_ifa;
381 				if (oifa != ifa) {
382 				    if (oifa && oifa->ifa_rtrequest)
383 					oifa->ifa_rtrequest(RTM_DELETE, rt,
384 					    &info);
385 				    IFAFREE(rt->rt_ifa);
386 				    rt->rt_ifa = ifa;
387 				    ifa->ifa_refcnt++;
388 				    rt->rt_ifp = ifp;
389 				}
390 			}
391 
392 			/* XXX Hack to allow the jumbo flag to be toggled */
393 			if (rtm->rtm_use & RTF_JUMBO)
394 				rt->rt_flags = (rt->rt_flags &
395 				    ~rtm->rtm_fmask) |
396 				    (rtm->rtm_flags & rtm->rtm_fmask);
397 
398 			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
399 			    &rt->rt_rmx);
400 			if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
401 				rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
402 			if (genmask)
403 				rt->rt_genmask = genmask;
404 			if (info.rti_info[RTAX_LABEL] != NULL) {
405 				char *rtlabel = ((struct sockaddr_rtlabel *)
406 				    info.rti_info[RTAX_LABEL])->sr_label;
407 				rtlabel_unref(rt->rt_labelid);
408 				rt->rt_labelid =
409 				    rtlabel_name2id(rtlabel);
410 			}
411 			/* fallthrough */
412 		case RTM_LOCK:
413 			rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
414 			rt->rt_rmx.rmx_locks |=
415 			    (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
416 			break;
417 		}
418 		break;
419 
420 	default:
421 		error = EOPNOTSUPP;
422 		break;
423 	}
424 
425 flush:
426 	if (rtm) {
427 		if (error)
428 			rtm->rtm_errno = error;
429 		else
430 			rtm->rtm_flags |= RTF_DONE;
431 	}
432 	if (rt)
433 		rtfree(rt);
434 
435 	/*
436 	 * Check to see if we don't want our own messages.
437 	 */
438 	if (!(so->so_options & SO_USELOOPBACK)) {
439 		if (route_cb.any_count <= 1) {
440 			if (rtm)
441 				Free(rtm);
442 			m_freem(m);
443 			return (error);
444 		}
445 		/* There is another listener, so construct message */
446 		rp = sotorawcb(so);
447 	}
448 	if (rp)
449 		rp->rcb_proto.sp_family = 0; /* Avoid us */
450 	if (dst)
451 		route_proto.sp_protocol = dst->sa_family;
452 	if (rtm) {
453 		m_copyback(m, 0, rtm->rtm_msglen, rtm);
454 		if (m->m_pkthdr.len < rtm->rtm_msglen) {
455 			m_freem(m);
456 			m = NULL;
457 		} else if (m->m_pkthdr.len > rtm->rtm_msglen)
458 			m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
459 		Free(rtm);
460 	}
461 	if (m)
462 		raw_input(m, &route_proto, &route_src, &route_dst);
463 	if (rp)
464 		rp->rcb_proto.sp_family = PF_ROUTE;
465 
466 	return (error);
467 }
468 
469 void
rt_setmetrics(u_long which,struct rt_metrics * in,struct rt_kmetrics * out)470 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out)
471 {
472 	if (which & RTV_MTU)
473 		out->rmx_mtu = in->rmx_mtu;
474 	if (which & RTV_EXPIRE)
475 		out->rmx_expire = in->rmx_expire;
476 }
477 
478 void
rt_getmetrics(struct rt_kmetrics * in,struct rt_metrics * out)479 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out)
480 {
481 	bzero(out, sizeof(*out));
482 	out->rmx_locks = in->rmx_locks;
483 	out->rmx_mtu = in->rmx_mtu;
484 	out->rmx_expire = in->rmx_expire;
485 	out->rmx_pksent = in->rmx_pksent;
486 }
487 
488 #define ROUNDUP(a) \
489 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
490 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
491 
492 static void
rt_xaddrs(caddr_t cp,caddr_t cplim,struct rt_addrinfo * rtinfo)493 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
494 {
495 	struct sockaddr	*sa;
496 	int		 i;
497 
498 	bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
499 	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
500 		if ((rtinfo->rti_addrs & (1 << i)) == 0)
501 			continue;
502 		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
503 		ADVANCE(cp, sa);
504 	}
505 }
506 
507 static struct mbuf *
rt_msg1(int type,struct rt_addrinfo * rtinfo)508 rt_msg1(int type, struct rt_addrinfo *rtinfo)
509 {
510 	struct rt_msghdr	*rtm;
511 	struct mbuf		*m;
512 	int			 i;
513 	struct sockaddr		*sa;
514 	int			 len, dlen;
515 
516 	switch (type) {
517 	case RTM_DELADDR:
518 	case RTM_NEWADDR:
519 		len = sizeof(struct ifa_msghdr);
520 		break;
521 	case RTM_IFINFO:
522 		len = sizeof(struct if_msghdr);
523 		break;
524 	case RTM_IFANNOUNCE:
525 		len = sizeof(struct if_announcemsghdr);
526 		break;
527 	default:
528 		len = sizeof(struct rt_msghdr);
529 		break;
530 	}
531 	if (len > MCLBYTES)
532 		panic("rt_msg1");
533 	m = m_gethdr(M_DONTWAIT, MT_DATA);
534 	if (m && len > MHLEN) {
535 		MCLGET(m, M_DONTWAIT);
536 		if ((m->m_flags & M_EXT) == 0) {
537 			m_free(m);
538 			m = NULL;
539 		}
540 	}
541 	if (m == 0)
542 		return (m);
543 	m->m_pkthdr.len = m->m_len = len;
544 	m->m_pkthdr.rcvif = NULL;
545 	rtm = mtod(m, struct rt_msghdr *);
546 	bzero(rtm, len);
547 	for (i = 0; i < RTAX_MAX; i++) {
548 		if ((sa = rtinfo->rti_info[i]) == NULL)
549 			continue;
550 		rtinfo->rti_addrs |= (1 << i);
551 		dlen = ROUNDUP(sa->sa_len);
552 		m_copyback(m, len, dlen, sa);
553 		len += dlen;
554 	}
555 	if (m->m_pkthdr.len != len) {
556 		m_freem(m);
557 		return (NULL);
558 	}
559 	rtm->rtm_msglen = len;
560 	rtm->rtm_version = RTM_VERSION;
561 	rtm->rtm_type = type;
562 	return (m);
563 }
564 
565 static int
rt_msg2(int type,struct rt_addrinfo * rtinfo,caddr_t cp,struct walkarg * w)566 rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w)
567 {
568 	int		i;
569 	int		len, dlen, second_time = 0;
570 	caddr_t		cp0;
571 
572 	rtinfo->rti_addrs = 0;
573 again:
574 	switch (type) {
575 	case RTM_DELADDR:
576 	case RTM_NEWADDR:
577 		len = sizeof(struct ifa_msghdr);
578 		break;
579 	case RTM_IFINFO:
580 		len = sizeof(struct if_msghdr);
581 		break;
582 	default:
583 		len = sizeof(struct rt_msghdr);
584 		break;
585 	}
586 	if ((cp0 = cp) != NULL)
587 		cp += len;
588 	for (i = 0; i < RTAX_MAX; i++) {
589 		struct sockaddr *sa;
590 
591 		if ((sa = rtinfo->rti_info[i]) == 0)
592 			continue;
593 		rtinfo->rti_addrs |= (1 << i);
594 		dlen = ROUNDUP(sa->sa_len);
595 		if (cp) {
596 			bcopy(sa, cp, (size_t)dlen);
597 			cp += dlen;
598 		}
599 		len += dlen;
600 	}
601 	if (cp == 0 && w != NULL && !second_time) {
602 		struct walkarg *rw = w;
603 
604 		rw->w_needed += len;
605 		if (rw->w_needed <= 0 && rw->w_where) {
606 			if (rw->w_tmemsize < len) {
607 				if (rw->w_tmem)
608 					free(rw->w_tmem, M_RTABLE);
609 				rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT);
610 				if (rw->w_tmem)
611 					rw->w_tmemsize = len;
612 			}
613 			if (rw->w_tmem) {
614 				cp = rw->w_tmem;
615 				second_time = 1;
616 				goto again;
617 			} else
618 				rw->w_where = 0;
619 		}
620 	}
621 	if (cp) {
622 		struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
623 
624 		rtm->rtm_version = RTM_VERSION;
625 		rtm->rtm_type = type;
626 		rtm->rtm_msglen = len;
627 	}
628 	return (len);
629 }
630 
631 /*
632  * This routine is called to generate a message from the routing
633  * socket indicating that a redirect has occurred, a routing lookup
634  * has failed, or that a protocol has detected timeouts to a particular
635  * destination.
636  */
637 void
rt_missmsg(int type,struct rt_addrinfo * rtinfo,int flags,int error)638 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
639 {
640 	struct rt_msghdr	*rtm;
641 	struct mbuf		*m;
642 	struct sockaddr		*sa = rtinfo->rti_info[RTAX_DST];
643 
644 	if (route_cb.any_count == 0)
645 		return;
646 	m = rt_msg1(type, rtinfo);
647 	if (m == 0)
648 		return;
649 	rtm = mtod(m, struct rt_msghdr *);
650 	rtm->rtm_flags = RTF_DONE | flags;
651 	rtm->rtm_errno = error;
652 	rtm->rtm_addrs = rtinfo->rti_addrs;
653 	if (sa == NULL)
654 		route_proto.sp_protocol = 0;
655 	else
656 		route_proto.sp_protocol = sa->sa_family;
657 	raw_input(m, &route_proto, &route_src, &route_dst);
658 }
659 
660 /*
661  * This routine is called to generate a message from the routing
662  * socket indicating that the status of a network interface has changed.
663  */
664 void
rt_ifmsg(struct ifnet * ifp)665 rt_ifmsg(struct ifnet *ifp)
666 {
667 	struct if_msghdr	*ifm;
668 	struct mbuf		*m;
669 	struct rt_addrinfo	 info;
670 
671 	if (route_cb.any_count == 0)
672 		return;
673 	bzero(&info, sizeof(info));
674 	m = rt_msg1(RTM_IFINFO, &info);
675 	if (m == 0)
676 		return;
677 	ifm = mtod(m, struct if_msghdr *);
678 	ifm->ifm_index = ifp->if_index;
679 	ifm->ifm_flags = ifp->if_flags;
680 	ifm->ifm_data = ifp->if_data;
681 	ifm->ifm_addrs = 0;
682 	route_proto.sp_protocol = 0;
683 	raw_input(m, &route_proto, &route_src, &route_dst);
684 }
685 
686 /*
687  * This is called to generate messages from the routing socket
688  * indicating a network interface has had addresses associated with it.
689  * if we ever reverse the logic and replace messages TO the routing
690  * socket indicate a request to configure interfaces, then it will
691  * be unnecessary as the routing socket will automatically generate
692  * copies of it.
693  */
694 void
rt_newaddrmsg(int cmd,struct ifaddr * ifa,int error,struct rtentry * rt)695 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
696 {
697 	struct rt_addrinfo	 info;
698 	struct sockaddr		*sa = NULL;
699 	int			 pass;
700 	struct mbuf		*m = NULL;
701 	struct ifnet		*ifp = ifa->ifa_ifp;
702 
703 	if (route_cb.any_count == 0)
704 		return;
705 	for (pass = 1; pass < 3; pass++) {
706 		bzero(&info, sizeof(info));
707 		if ((cmd == RTM_ADD && pass == 1) ||
708 		    (cmd == RTM_DELETE && pass == 2)) {
709 			struct ifa_msghdr	*ifam;
710 			int			 ncmd;
711 
712 			if (cmd == RTM_ADD)
713 				ncmd = RTM_NEWADDR;
714 			else
715 				ncmd = RTM_DELADDR;
716 
717 			ifaaddr = sa = ifa->ifa_addr;
718 			ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
719 			netmask = ifa->ifa_netmask;
720 			brdaddr = ifa->ifa_dstaddr;
721 			if ((m = rt_msg1(ncmd, &info)) == NULL)
722 				continue;
723 			ifam = mtod(m, struct ifa_msghdr *);
724 			ifam->ifam_index = ifp->if_index;
725 			ifam->ifam_metric = ifa->ifa_metric;
726 			ifam->ifam_flags = ifa->ifa_flags;
727 			ifam->ifam_addrs = info.rti_addrs;
728 		}
729 		if ((cmd == RTM_ADD && pass == 2) ||
730 		    (cmd == RTM_DELETE && pass == 1)) {
731 			struct rt_msghdr *rtm;
732 
733 			if (rt == 0)
734 				continue;
735 			netmask = rt_mask(rt);
736 			dst = sa = rt_key(rt);
737 			gate = rt->rt_gateway;
738 			if ((m = rt_msg1(cmd, &info)) == NULL)
739 				continue;
740 			rtm = mtod(m, struct rt_msghdr *);
741 			rtm->rtm_index = ifp->if_index;
742 			rtm->rtm_flags |= rt->rt_flags;
743 			rtm->rtm_errno = error;
744 			rtm->rtm_addrs = info.rti_addrs;
745 		}
746 		if (sa == NULL)
747 			route_proto.sp_protocol = 0;
748 		else
749 			route_proto.sp_protocol = sa->sa_family;
750 		raw_input(m, &route_proto, &route_src, &route_dst);
751 	}
752 }
753 
754 /*
755  * This is called to generate routing socket messages indicating
756  * network interface arrival and departure.
757  */
758 void
rt_ifannouncemsg(struct ifnet * ifp,int what)759 rt_ifannouncemsg(struct ifnet *ifp, int what)
760 {
761 	struct if_announcemsghdr	*ifan;
762 	struct mbuf			*m;
763 	struct rt_addrinfo		 info;
764 
765 	if (route_cb.any_count == 0)
766 		return;
767 	bzero(&info, sizeof(info));
768 	m = rt_msg1(RTM_IFANNOUNCE, &info);
769 	if (m == 0)
770 		return;
771 	ifan = mtod(m, struct if_announcemsghdr *);
772 	ifan->ifan_index = ifp->if_index;
773 	strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
774 	ifan->ifan_what = what;
775 	route_proto.sp_protocol = 0;
776 	raw_input(m, &route_proto, &route_src, &route_dst);
777 }
778 
779 /*
780  * This is used in dumping the kernel table via sysctl().
781  */
782 int
sysctl_dumpentry(struct radix_node * rn,void * v)783 sysctl_dumpentry(struct radix_node *rn, void *v)
784 {
785 	struct walkarg		*w = v;
786 	struct rtentry		*rt = (struct rtentry *)rn;
787 	int			 error = 0, size;
788 	struct rt_addrinfo	 info;
789 
790 	if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
791 		return 0;
792 	bzero(&info, sizeof(info));
793 	dst = rt_key(rt);
794 	gate = rt->rt_gateway;
795 	netmask = rt_mask(rt);
796 	genmask = rt->rt_genmask;
797 	if (rt->rt_ifp) {
798 		ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
799 		ifaaddr = rt->rt_ifa->ifa_addr;
800 		if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
801 			brdaddr = rt->rt_ifa->ifa_dstaddr;
802 	}
803 	size = rt_msg2(RTM_GET, &info, NULL, w);
804 	if (w->w_where && w->w_tmem && w->w_needed <= 0) {
805 		struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
806 
807 		rtm->rtm_flags = rt->rt_flags;
808 		rtm->rtm_use = rt->rt_use;
809 		rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
810 		rtm->rtm_index = rt->rt_ifp->if_index;
811 		rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
812 		rtm->rtm_addrs = info.rti_addrs;
813 		if ((error = copyout(rtm, w->w_where, size)) != 0)
814 			w->w_where = NULL;
815 		else
816 			w->w_where += size;
817 	}
818 	return (error);
819 }
820 
821 int
sysctl_iflist(int af,struct walkarg * w)822 sysctl_iflist(int af, struct walkarg *w)
823 {
824 	struct ifnet		*ifp;
825 	struct ifaddr		*ifa;
826 	struct rt_addrinfo	 info;
827 	int			 len, error = 0;
828 
829 	bzero(&info, sizeof(info));
830 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
831 		if (w->w_arg && w->w_arg != ifp->if_index)
832 			continue;
833 		ifa = TAILQ_FIRST(&ifp->if_addrlist);
834 		if (!ifa)
835 			continue;
836 		ifpaddr = ifa->ifa_addr;
837 		len = rt_msg2(RTM_IFINFO, &info, 0, w);
838 		ifpaddr = 0;
839 		if (w->w_where && w->w_tmem && w->w_needed <= 0) {
840 			struct if_msghdr *ifm;
841 
842 			ifm = (struct if_msghdr *)w->w_tmem;
843 			ifm->ifm_index = ifp->if_index;
844 			ifm->ifm_flags = ifp->if_flags;
845 			ifm->ifm_data = ifp->if_data;
846 			ifm->ifm_addrs = info.rti_addrs;
847 			error = copyout(ifm, w->w_where, len);
848 			if (error)
849 				return (error);
850 			w->w_where += len;
851 		}
852 		while ((ifa = TAILQ_NEXT(ifa, ifa_list)) !=
853 		    TAILQ_END(&ifp->if_addrlist)) {
854 			if (af && af != ifa->ifa_addr->sa_family)
855 				continue;
856 			ifaaddr = ifa->ifa_addr;
857 			netmask = ifa->ifa_netmask;
858 			brdaddr = ifa->ifa_dstaddr;
859 			len = rt_msg2(RTM_NEWADDR, &info, 0, w);
860 			if (w->w_where && w->w_tmem && w->w_needed <= 0) {
861 				struct ifa_msghdr *ifam;
862 
863 				ifam = (struct ifa_msghdr *)w->w_tmem;
864 				ifam->ifam_index = ifa->ifa_ifp->if_index;
865 				ifam->ifam_flags = ifa->ifa_flags;
866 				ifam->ifam_metric = ifa->ifa_metric;
867 				ifam->ifam_addrs = info.rti_addrs;
868 				error = copyout(w->w_tmem, w->w_where, len);
869 				if (error)
870 					return (error);
871 				w->w_where += len;
872 			}
873 		}
874 		ifaaddr = netmask = brdaddr = 0;
875 	}
876 	return (0);
877 }
878 
879 int
sysctl_rtable(int * name,u_int namelen,void * where,size_t * given,void * new,size_t newlen)880 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new,
881     size_t newlen)
882 {
883 	struct radix_node_head	*rnh;
884 	int			 i, s, error = EINVAL;
885 	u_char  		 af;
886 	struct walkarg		 w;
887 
888 	if (new)
889 		return (EPERM);
890 	if (namelen != 3)
891 		return (EINVAL);
892 	af = name[0];
893 	bzero(&w, sizeof(w));
894 	w.w_where = where;
895 	w.w_given = *given;
896 	w.w_needed = 0 - w.w_given;
897 	w.w_op = name[1];
898 	w.w_arg = name[2];
899 
900 	s = splsoftnet();
901 	switch (w.w_op) {
902 
903 	case NET_RT_DUMP:
904 	case NET_RT_FLAGS:
905 		for (i = 1; i <= AF_MAX; i++)
906 			if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
907 			    (error = (*rnh->rnh_walktree)(rnh,
908 			    sysctl_dumpentry, &w)))
909 				break;
910 		break;
911 
912 	case NET_RT_IFLIST:
913 		error = sysctl_iflist(af, &w);
914 	}
915 	splx(s);
916 	if (w.w_tmem)
917 		free(w.w_tmem, M_RTABLE);
918 	w.w_needed += w.w_given;
919 	if (where) {
920 		*given = w.w_where - (caddr_t)where;
921 		if (*given < w.w_needed)
922 			return (ENOMEM);
923 	} else
924 		*given = (11 * w.w_needed) / 10;
925 
926 	return (error);
927 }
928 
929 /*
930  * Definitions of protocols supported in the ROUTE domain.
931  */
932 
933 extern	struct domain routedomain;		/* or at least forward */
934 
935 struct protosw routesw[] = {
936 { SOCK_RAW,	&routedomain,	0,		PR_ATOMIC|PR_ADDR,
937   raw_input,	route_output,	raw_ctlinput,	0,
938   route_usrreq,
939   raw_init,	0,		0,		0,
940   sysctl_rtable,
941 }
942 };
943 
944 struct domain routedomain =
945     { PF_ROUTE, "route", route_init, 0, 0,
946       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
947