]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/net/rtsock.c
xnu-517.11.1.tar.gz
[apple/xnu.git] / bsd / net / rtsock.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1988, 1991, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)rtsock.c 8.5 (Berkeley) 11/2/94
55 */
56
57
58#include <sys/param.h>
59#include <sys/systm.h>
60#include <sys/kernel.h>
61#include <sys/sysctl.h>
62#include <sys/proc.h>
63#include <sys/malloc.h>
64#include <sys/mbuf.h>
65#include <sys/socket.h>
66#include <sys/socketvar.h>
67#include <sys/domain.h>
68#include <sys/protosw.h>
69#include <sys/syslog.h>
70
71#include <net/if.h>
72#include <net/route.h>
73#include <net/raw_cb.h>
74#include <netinet/in.h>
75
76MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
77
78static struct sockaddr route_dst = { 2, PF_ROUTE, };
79static struct sockaddr route_src = { 2, PF_ROUTE, };
80static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, };
81static struct sockproto route_proto = { PF_ROUTE, };
82
83struct walkarg {
84 int w_tmemsize;
85 int w_op, w_arg;
86 caddr_t w_tmem;
87 struct sysctl_req *w_req;
88};
89
90static struct mbuf *
91 rt_msg1 __P((int, struct rt_addrinfo *));
92static int rt_msg2 __P((int,
93 struct rt_addrinfo *, caddr_t, struct walkarg *));
94static int rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
95static int sysctl_dumpentry __P((struct radix_node *rn, void *vw));
96static int sysctl_iflist __P((int af, struct walkarg *w));
97static int route_output __P((struct mbuf *, struct socket *));
98static void rt_setmetrics __P((u_long, struct rt_metrics *, struct rt_metrics *));
99static void rt_setif __P((struct rtentry *, struct sockaddr *, struct sockaddr *,
100 struct sockaddr *));
101
102/* Sleazy use of local variables throughout file, warning!!!! */
103#define dst info.rti_info[RTAX_DST]
104#define gate info.rti_info[RTAX_GATEWAY]
105#define netmask info.rti_info[RTAX_NETMASK]
106#define genmask info.rti_info[RTAX_GENMASK]
107#define ifpaddr info.rti_info[RTAX_IFP]
108#define ifaaddr info.rti_info[RTAX_IFA]
109#define brdaddr info.rti_info[RTAX_BRD]
110
111/*
112 * It really doesn't make any sense at all for this code to share much
113 * with raw_usrreq.c, since its functionality is so restricted. XXX
114 */
115static int
116rts_abort(struct socket *so)
117{
118 int s, error;
119 s = splnet();
120 error = raw_usrreqs.pru_abort(so);
121 splx(s);
122 return error;
123}
124
125/* pru_accept is EOPNOTSUPP */
126
127static int
128rts_attach(struct socket *so, int proto, struct proc *p)
129{
130 struct rawcb *rp;
131 int s, error;
132
133 if (sotorawcb(so) != 0)
134 return EISCONN; /* XXX panic? */
135 MALLOC(rp, struct rawcb *, sizeof *rp, M_PCB, M_WAITOK); /* XXX */
136 if (rp == 0)
137 return ENOBUFS;
138 bzero(rp, sizeof *rp);
139
140 /*
141 * The splnet() is necessary to block protocols from sending
142 * error notifications (like RTM_REDIRECT or RTM_LOSING) while
143 * this PCB is extant but incompletely initialized.
144 * Probably we should try to do more of this work beforehand and
145 * eliminate the spl.
146 */
147 s = splnet();
148 so->so_pcb = (caddr_t)rp;
149 error = raw_attach(so, proto); /* don't use raw_usrreqs.pru_attach, it checks for SS_PRIV */
150 rp = sotorawcb(so);
151 if (error) {
152 splx(s);
153 FREE(rp, M_PCB);
154 so->so_pcb = 0;
155 return error;
156 }
157 switch(rp->rcb_proto.sp_protocol) {
158 case AF_INET:
159 route_cb.ip_count++;
160 break;
161 case AF_INET6:
162 route_cb.ip6_count++;
163 break;
164 case AF_IPX:
165 route_cb.ipx_count++;
166 break;
167 case AF_NS:
168 route_cb.ns_count++;
169 break;
170 }
171 rp->rcb_faddr = &route_src;
172 route_cb.any_count++;
173 soisconnected(so);
174 so->so_options |= SO_USELOOPBACK;
175 splx(s);
176 return 0;
177}
178
179static int
180rts_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
181{
182 int s, error;
183 s = splnet();
184 error = raw_usrreqs.pru_bind(so, nam, p); /* xxx just EINVAL */
185 splx(s);
186 return error;
187}
188
189static int
190rts_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
191{
192 int s, error;
193 s = splnet();
194 error = raw_usrreqs.pru_connect(so, nam, p); /* XXX just EINVAL */
195 splx(s);
196 return error;
197}
198
199/* pru_connect2 is EOPNOTSUPP */
200/* pru_control is EOPNOTSUPP */
201
202static int
203rts_detach(struct socket *so)
204{
205 struct rawcb *rp = sotorawcb(so);
206 int s, error;
207
208 s = splnet();
209 if (rp != 0) {
210 switch(rp->rcb_proto.sp_protocol) {
211 case AF_INET:
212 route_cb.ip_count--;
213 break;
214 case AF_INET6:
215 route_cb.ip6_count--;
216 break;
217 case AF_IPX:
218 route_cb.ipx_count--;
219 break;
220 case AF_NS:
221 route_cb.ns_count--;
222 break;
223 }
224 route_cb.any_count--;
225 }
226 error = raw_usrreqs.pru_detach(so);
227 splx(s);
228 return error;
229}
230
231static int
232rts_disconnect(struct socket *so)
233{
234 int s, error;
235 s = splnet();
236 error = raw_usrreqs.pru_disconnect(so);
237 splx(s);
238 return error;
239}
240
241/* pru_listen is EOPNOTSUPP */
242
243static int
244rts_peeraddr(struct socket *so, struct sockaddr **nam)
245{
246 int s, error;
247 s = splnet();
248 error = raw_usrreqs.pru_peeraddr(so, nam);
249 splx(s);
250 return error;
251}
252
253/* pru_rcvd is EOPNOTSUPP */
254/* pru_rcvoob is EOPNOTSUPP */
255
256static int
257rts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
258 struct mbuf *control, struct proc *p)
259{
260 int s, error;
261 s = splnet();
262 error = raw_usrreqs.pru_send(so, flags, m, nam, control, p);
263 splx(s);
264 return error;
265}
266
267/* pru_sense is null */
268
269static int
270rts_shutdown(struct socket *so)
271{
272 int s, error;
273 s = splnet();
274 error = raw_usrreqs.pru_shutdown(so);
275 splx(s);
276 return error;
277}
278
279static int
280rts_sockaddr(struct socket *so, struct sockaddr **nam)
281{
282 int s, error;
283 s = splnet();
284 error = raw_usrreqs.pru_sockaddr(so, nam);
285 splx(s);
286 return error;
287}
288
289static struct pr_usrreqs route_usrreqs = {
290 rts_abort, pru_accept_notsupp, rts_attach, rts_bind, rts_connect,
291 pru_connect2_notsupp, pru_control_notsupp, rts_detach, rts_disconnect,
292 pru_listen_notsupp, rts_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
293 rts_send, pru_sense_null, rts_shutdown, rts_sockaddr,
294 sosend, soreceive, sopoll
295};
296
297/*ARGSUSED*/
298static int
299route_output(m, so)
300 register struct mbuf *m;
301 struct socket *so;
302{
303 register struct rt_msghdr *rtm = 0;
304 register struct rtentry *rt = 0;
305 struct rtentry *saved_nrt = 0;
306 struct radix_node_head *rnh;
307 struct rt_addrinfo info;
308 int len, error = 0;
309 struct ifnet *ifp = 0;
310 struct ifaddr *ifa = 0;
311 struct proc *curproc = current_proc();
312 int sendonlytoself = 0;
313
314#define senderr(e) { error = e; goto flush;}
315 if (m == 0 || ((m->m_len < sizeof(long)) &&
316 (m = m_pullup(m, sizeof(long))) == 0))
317 return (ENOBUFS);
318 if ((m->m_flags & M_PKTHDR) == 0)
319 panic("route_output");
320 len = m->m_pkthdr.len;
321 if (len < sizeof(*rtm) ||
322 len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
323 dst = 0;
324 senderr(EINVAL);
325 }
326 R_Malloc(rtm, struct rt_msghdr *, len);
327 if (rtm == 0) {
328 dst = 0;
329 senderr(ENOBUFS);
330 }
331 m_copydata(m, 0, len, (caddr_t)rtm);
332 if (rtm->rtm_version != RTM_VERSION) {
333 dst = 0;
334 senderr(EPROTONOSUPPORT);
335 }
336
337 /*
338 * Silent version of RTM_GET for Reachabiltiy APIs. We may change
339 * all RTM_GETs to be silent in the future, so this is private for now.
340 */
341 if (rtm->rtm_type == RTM_GET_SILENT) {
342 if ((so->so_options & SO_USELOOPBACK) == 0)
343 senderr(EINVAL);
344 sendonlytoself = 1;
345 rtm->rtm_type = RTM_GET;
346 }
347
348 /*
349 * Perform permission checking, only privileged sockets
350 * may perform operations other than RTM_GET
351 */
352 if (rtm->rtm_type != RTM_GET && (so->so_state & SS_PRIV) == 0) {
353 dst = 0;
354 senderr(EPERM);
355 }
356 rtm->rtm_pid = curproc->p_pid;
357 info.rti_addrs = rtm->rtm_addrs;
358 if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) {
359 dst = 0;
360 senderr(EINVAL);
361 }
362 if (dst == 0 || (dst->sa_family >= AF_MAX)
363 || (gate != 0 && (gate->sa_family >= AF_MAX)))
364 senderr(EINVAL);
365 if (genmask) {
366 struct radix_node *t;
367 t = rn_addmask((caddr_t)genmask, 0, 1);
368 if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
369 genmask = (struct sockaddr *)(t->rn_key);
370 else
371 senderr(ENOBUFS);
372 }
373 switch (rtm->rtm_type) {
374
375 case RTM_ADD:
376 if (gate == 0)
377 senderr(EINVAL);
378
379#ifdef __APPLE__
380/* XXX LD11JUL02 Special case for AOL 5.1.2 connectivity issue to AirPort BS (Radar 2969954)
381 * AOL is adding a circular route ("10.0.1.1/32 10.0.1.1") when establishing its ppp tunnel
382 * to the AP BaseStation by removing the default gateway and replacing it with their tunnel entry point.
383 * There is no apparent reason to add this route as there is a valid 10.0.1.1/24 route to the BS.
384 * That circular route was ignored on previous version of MacOS X because of a routing bug
385 * corrected with the merge to FreeBSD4.4 (a route generated from an RTF_CLONING route had the RTF_WASCLONED
386 * flag set but did not have a reference to the parent route) and that entry was left in the RT. This workaround is
387 * made in order to provide binary compatibility with AOL.
388 * If we catch a process adding a circular route with a /32 from the routing socket, we error it out instead of
389 * confusing the routing table with a wrong route to the previous default gateway
390 */
391{
392 extern int check_routeselfref;
393#define satosinaddr(sa) (((struct sockaddr_in *)sa)->sin_addr.s_addr)
394
395 if (check_routeselfref && (dst && dst->sa_family == AF_INET) &&
396 (netmask && satosinaddr(netmask) == INADDR_BROADCAST) &&
397 (gate && satosinaddr(dst) == satosinaddr(gate))) {
398 log(LOG_WARNING, "route_output: circular route %ld.%ld.%ld.%ld/32 ignored\n",
399 (ntohl(satosinaddr(gate)>>24))&0xff,
400 (ntohl(satosinaddr(gate)>>16))&0xff,
401 (ntohl(satosinaddr(gate)>>8))&0xff,
402 (ntohl(satosinaddr(gate)))&0xff);
403
404 senderr(EINVAL);
405 }
406}
407#endif
408 error = rtrequest(RTM_ADD, dst, gate, netmask,
409 rtm->rtm_flags, &saved_nrt);
410 if (error == 0 && saved_nrt) {
411#ifdef __APPLE__
412 /*
413 * If the route request specified an interface with
414 * IFA and/or IFP, we set the requested interface on
415 * the route with rt_setif. It would be much better
416 * to do this inside rtrequest, but that would
417 * require passing the desired interface, in some
418 * form, to rtrequest. Since rtrequest is called in
419 * so many places (roughly 40 in our source), adding
420 * a parameter is to much for us to swallow; this is
421 * something for the FreeBSD developers to tackle.
422 * Instead, we let rtrequest compute whatever
423 * interface it wants, then come in behind it and
424 * stick in the interface that we really want. This
425 * works reasonably well except when rtrequest can't
426 * figure out what interface to use (with
427 * ifa_withroute) and returns ENETUNREACH. Ideally
428 * it shouldn't matter if rtrequest can't figure out
429 * the interface if we're going to explicitly set it
430 * ourselves anyway. But practically we can't
431 * recover here because rtrequest will not do any of
432 * the work necessary to add the route if it can't
433 * find an interface. As long as there is a default
434 * route that leads to some interface, rtrequest will
435 * find an interface, so this problem should be
436 * rarely encountered.
437 * dwiggins@bbn.com
438 */
439
440 rt_setif(saved_nrt, ifpaddr, ifaaddr, gate);
441#endif
442 rt_setmetrics(rtm->rtm_inits,
443 &rtm->rtm_rmx, &saved_nrt->rt_rmx);
444 saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
445 saved_nrt->rt_rmx.rmx_locks |=
446 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
447 rtunref(saved_nrt);
448 saved_nrt->rt_genmask = genmask;
449 }
450 break;
451
452 case RTM_DELETE:
453 error = rtrequest(RTM_DELETE, dst, gate, netmask,
454 rtm->rtm_flags, &saved_nrt);
455 if (error == 0) {
456 if ((rt = saved_nrt))
457 rtref(rt);
458 goto report;
459 }
460 break;
461
462 case RTM_GET:
463 case RTM_CHANGE:
464 case RTM_LOCK:
465 if ((rnh = rt_tables[dst->sa_family]) == 0) {
466 senderr(EAFNOSUPPORT);
467 } else if ((rt = (struct rtentry *)
468 rnh->rnh_lookup(dst, netmask, rnh)) != NULL)
469 rtref(rt);
470 else
471 senderr(ESRCH);
472 switch(rtm->rtm_type) {
473
474 case RTM_GET:
475 report:
476 dst = rt_key(rt);
477 gate = rt->rt_gateway;
478 netmask = rt_mask(rt);
479 genmask = rt->rt_genmask;
480 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
481 ifp = rt->rt_ifp;
482 if (ifp) {
483 ifpaddr = ifp->if_addrhead.tqh_first->ifa_addr;
484 ifaaddr = rt->rt_ifa->ifa_addr;
485 rtm->rtm_index = ifp->if_index;
486 } else {
487 ifpaddr = 0;
488 ifaaddr = 0;
489 }
490 }
491 len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0,
492 (struct walkarg *)0);
493 if (len > rtm->rtm_msglen) {
494 struct rt_msghdr *new_rtm;
495 R_Malloc(new_rtm, struct rt_msghdr *, len);
496 if (new_rtm == 0)
497 senderr(ENOBUFS);
498 Bcopy(rtm, new_rtm, rtm->rtm_msglen);
499 Free(rtm); rtm = new_rtm;
500 }
501 (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm,
502 (struct walkarg *)0);
503 rtm->rtm_flags = rt->rt_flags;
504 rtm->rtm_rmx = rt->rt_rmx;
505 rtm->rtm_addrs = info.rti_addrs;
506 break;
507
508 case RTM_CHANGE:
509 if (gate && (error = rt_setgate(rt, rt_key(rt), gate)))
510 senderr(error);
511
512 /*
513 * If they tried to change things but didn't specify
514 * the required gateway, then just use the old one.
515 * This can happen if the user tries to change the
516 * flags on the default route without changing the
517 * default gateway. Changing flags still doesn't work.
518 */
519 if ((rt->rt_flags & RTF_GATEWAY) && !gate)
520 gate = rt->rt_gateway;
521
522#ifdef __APPLE__
523 /*
524 * On Darwin, we call rt_setif which contains the
525 * equivalent to the code found at this very spot
526 * in BSD.
527 */
528 rt_setif(rt, ifpaddr, ifaaddr, gate);
529#endif
530
531 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
532 &rt->rt_rmx);
533#ifndef __APPLE__
534 /* rt_setif, called above does this for us on darwin */
535 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
536 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
537#endif
538 if (genmask)
539 rt->rt_genmask = genmask;
540 /*
541 * Fall into
542 */
543 case RTM_LOCK:
544 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
545 rt->rt_rmx.rmx_locks |=
546 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
547 break;
548 }
549 break;
550
551 default:
552 senderr(EOPNOTSUPP);
553 }
554
555flush:
556 if (rtm) {
557 if (error)
558 rtm->rtm_errno = error;
559 else
560 rtm->rtm_flags |= RTF_DONE;
561 }
562 if (rt)
563 rtfree(rt);
564 {
565 register struct rawcb *rp = 0;
566 /*
567 * Check to see if we don't want our own messages.
568 */
569 if ((so->so_options & SO_USELOOPBACK) == 0) {
570 if (route_cb.any_count <= 1) {
571 if (rtm)
572 Free(rtm);
573 m_freem(m);
574 return (error);
575 }
576 /* There is another listener, so construct message */
577 rp = sotorawcb(so);
578 }
579 if (rtm) {
580 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
581 if (m->m_pkthdr.len < rtm->rtm_msglen) {
582 m_freem(m);
583 m = NULL;
584 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
585 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
586 Free(rtm);
587 }
588 if (sendonlytoself && m) {
589 if (sbappendaddr(&so->so_rcv, &route_src, m, (struct mbuf*)0) == 0) {
590 m_freem(m);
591 error = ENOBUFS;
592 } else {
593 sorwakeup(so);
594 }
595 } else {
596 if (rp)
597 rp->rcb_proto.sp_family = 0; /* Avoid us */
598 if (dst)
599 route_proto.sp_protocol = dst->sa_family;
600 if (m)
601 raw_input(m, &route_proto, &route_src, &route_dst);
602 if (rp)
603 rp->rcb_proto.sp_family = PF_ROUTE;
604 }
605 }
606 return (error);
607}
608
609static void
610rt_setmetrics(which, in, out)
611 u_long which;
612 register struct rt_metrics *in, *out;
613{
614#define metric(f, e) if (which & (f)) out->e = in->e;
615 metric(RTV_RPIPE, rmx_recvpipe);
616 metric(RTV_SPIPE, rmx_sendpipe);
617 metric(RTV_SSTHRESH, rmx_ssthresh);
618 metric(RTV_RTT, rmx_rtt);
619 metric(RTV_RTTVAR, rmx_rttvar);
620 metric(RTV_HOPCOUNT, rmx_hopcount);
621 metric(RTV_MTU, rmx_mtu);
622 metric(RTV_EXPIRE, rmx_expire);
623#undef metric
624}
625
626/*
627 * Set route's interface given ifpaddr, ifaaddr, and gateway.
628 */
629static void
630rt_setif(rt, Ifpaddr, Ifaaddr, Gate)
631 struct rtentry *rt;
632 struct sockaddr *Ifpaddr, *Ifaaddr, *Gate;
633{
634 struct ifaddr *ifa = 0;
635 struct ifnet *ifp = 0;
636
637 /* new gateway could require new ifaddr, ifp;
638 flags may also be different; ifp may be specified
639 by ll sockaddr when protocol address is ambiguous */
640 if (Ifpaddr && (ifa = ifa_ifwithnet(Ifpaddr)) &&
641 (ifp = ifa->ifa_ifp) && (Ifaaddr || Gate))
642 ifa = ifaof_ifpforaddr(Ifaaddr ? Ifaaddr : Gate,
643 ifp);
644 else if (Ifpaddr && (ifp = if_withname(Ifpaddr)) ) {
645 ifa = Gate ? ifaof_ifpforaddr(Gate, ifp) :
646 TAILQ_FIRST(&ifp->if_addrhead);
647 }
648 else if ((Ifaaddr && (ifa = ifa_ifwithaddr(Ifaaddr))) ||
649 (Gate && (ifa = ifa_ifwithroute(rt->rt_flags,
650 rt_key(rt), Gate))))
651 ifp = ifa->ifa_ifp;
652 if (ifa) {
653 register struct ifaddr *oifa = rt->rt_ifa;
654 if (oifa != ifa) {
655 if (oifa && oifa->ifa_rtrequest)
656 oifa->ifa_rtrequest(RTM_DELETE,
657 rt, Gate);
658 rtsetifa(rt, ifa);
659 rt->rt_ifp = ifp;
660 rt->rt_rmx.rmx_mtu = ifp->if_mtu;
661 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
662 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, Gate);
663 } else
664 goto call_ifareq;
665 return;
666 }
667 call_ifareq:
668 /* XXX: to reset gateway to correct value, at RTM_CHANGE */
669 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
670 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, Gate);
671}
672
673
674#define ROUNDUP(a) \
675 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
676#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
677
678
679/*
680 * Extract the addresses of the passed sockaddrs.
681 * Do a little sanity checking so as to avoid bad memory references.
682 * This data is derived straight from userland.
683 */
684static int
685rt_xaddrs(cp, cplim, rtinfo)
686 register caddr_t cp, cplim;
687 register struct rt_addrinfo *rtinfo;
688{
689 register struct sockaddr *sa;
690 register int i;
691
692 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
693 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
694 if ((rtinfo->rti_addrs & (1 << i)) == 0)
695 continue;
696 sa = (struct sockaddr *)cp;
697 /*
698 * It won't fit.
699 */
700 if ( (cp + sa->sa_len) > cplim ) {
701 return (EINVAL);
702 }
703
704 /*
705 * there are no more.. quit now
706 * If there are more bits, they are in error.
707 * I've seen this. route(1) can evidently generate these.
708 * This causes kernel to core dump.
709 * for compatibility, If we see this, point to a safe address.
710 */
711 if (sa->sa_len == 0) {
712 rtinfo->rti_info[i] = &sa_zero;
713 return (0); /* should be EINVAL but for compat */
714 }
715
716 /* accept it */
717 rtinfo->rti_info[i] = sa;
718 ADVANCE(cp, sa);
719 }
720 return (0);
721}
722
723static struct mbuf *
724rt_msg1(type, rtinfo)
725 int type;
726 register struct rt_addrinfo *rtinfo;
727{
728 register struct rt_msghdr *rtm;
729 register struct mbuf *m;
730 register int i;
731 register struct sockaddr *sa;
732 int len, dlen;
733
734 switch (type) {
735
736 case RTM_DELADDR:
737 case RTM_NEWADDR:
738 len = sizeof(struct ifa_msghdr);
739 break;
740
741 case RTM_DELMADDR:
742 case RTM_NEWMADDR:
743 len = sizeof(struct ifma_msghdr);
744 break;
745
746 case RTM_IFINFO:
747 len = sizeof(struct if_msghdr);
748 break;
749
750 default:
751 len = sizeof(struct rt_msghdr);
752 }
753 if (len > MCLBYTES)
754 panic("rt_msg1");
755 m = m_gethdr(M_DONTWAIT, MT_DATA);
756 if (m && len > MHLEN) {
757 MCLGET(m, M_DONTWAIT);
758 if ((m->m_flags & M_EXT) == 0) {
759 m_free(m);
760 m = NULL;
761 }
762 }
763 if (m == 0)
764 return (m);
765 m->m_pkthdr.len = m->m_len = len;
766 m->m_pkthdr.rcvif = 0;
767 rtm = mtod(m, struct rt_msghdr *);
768 bzero((caddr_t)rtm, len);
769 for (i = 0; i < RTAX_MAX; i++) {
770 if ((sa = rtinfo->rti_info[i]) == NULL)
771 continue;
772 rtinfo->rti_addrs |= (1 << i);
773 dlen = ROUNDUP(sa->sa_len);
774 m_copyback(m, len, dlen, (caddr_t)sa);
775 len += dlen;
776 }
777 if (m->m_pkthdr.len != len) {
778 m_freem(m);
779 return (NULL);
780 }
781 rtm->rtm_msglen = len;
782 rtm->rtm_version = RTM_VERSION;
783 rtm->rtm_type = type;
784 return (m);
785}
786
787static int
788rt_msg2(type, rtinfo, cp, w)
789 int type;
790 register struct rt_addrinfo *rtinfo;
791 caddr_t cp;
792 struct walkarg *w;
793{
794 register int i;
795 int len, dlen, second_time = 0;
796 caddr_t cp0;
797
798 rtinfo->rti_addrs = 0;
799again:
800 switch (type) {
801
802 case RTM_DELADDR:
803 case RTM_NEWADDR:
804 len = sizeof(struct ifa_msghdr);
805 break;
806
807 case RTM_IFINFO:
808 len = sizeof(struct if_msghdr);
809 break;
810
811 default:
812 len = sizeof(struct rt_msghdr);
813 }
814 cp0 = cp;
815 if (cp0)
816 cp += len;
817 for (i = 0; i < RTAX_MAX; i++) {
818 register struct sockaddr *sa;
819
820 if ((sa = rtinfo->rti_info[i]) == 0)
821 continue;
822 rtinfo->rti_addrs |= (1 << i);
823 dlen = ROUNDUP(sa->sa_len);
824 if (cp) {
825 bcopy((caddr_t)sa, cp, (unsigned)dlen);
826 cp += dlen;
827 }
828 len += dlen;
829 }
830 if (cp == 0 && w != NULL && !second_time) {
831 register struct walkarg *rw = w;
832
833 if (rw->w_req) {
834 if (rw->w_tmemsize < len) {
835 if (rw->w_tmem)
836 FREE(rw->w_tmem, M_RTABLE);
837 rw->w_tmem = (caddr_t)
838 _MALLOC(len, M_RTABLE, M_WAITOK); /*###LD0412 was NOWAIT */
839 if (rw->w_tmem)
840 rw->w_tmemsize = len;
841 }
842 if (rw->w_tmem) {
843 cp = rw->w_tmem;
844 second_time = 1;
845 goto again;
846 }
847 }
848 }
849 if (cp) {
850 register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
851
852 rtm->rtm_version = RTM_VERSION;
853 rtm->rtm_type = type;
854 rtm->rtm_msglen = len;
855 }
856 return (len);
857}
858
859/*
860 * This routine is called to generate a message from the routing
861 * socket indicating that a redirect has occured, a routing lookup
862 * has failed, or that a protocol has detected timeouts to a particular
863 * destination.
864 */
865void
866rt_missmsg(type, rtinfo, flags, error)
867 int type, flags, error;
868 register struct rt_addrinfo *rtinfo;
869{
870 register struct rt_msghdr *rtm;
871 register struct mbuf *m;
872 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
873
874 if (route_cb.any_count == 0)
875 return;
876 m = rt_msg1(type, rtinfo);
877 if (m == 0)
878 return;
879 rtm = mtod(m, struct rt_msghdr *);
880 rtm->rtm_flags = RTF_DONE | flags;
881 rtm->rtm_errno = error;
882 rtm->rtm_addrs = rtinfo->rti_addrs;
883 route_proto.sp_protocol = sa ? sa->sa_family : 0;
884 raw_input(m, &route_proto, &route_src, &route_dst);
885}
886
887/*
888 * This routine is called to generate a message from the routing
889 * socket indicating that the status of a network interface has changed.
890 */
891void
892rt_ifmsg(ifp)
893 register struct ifnet *ifp;
894{
895 register struct if_msghdr *ifm;
896 struct mbuf *m;
897 struct rt_addrinfo info;
898
899 if (route_cb.any_count == 0)
900 return;
901 bzero((caddr_t)&info, sizeof(info));
902 m = rt_msg1(RTM_IFINFO, &info);
903 if (m == 0)
904 return;
905 ifm = mtod(m, struct if_msghdr *);
906 ifm->ifm_index = ifp->if_index;
907 ifm->ifm_flags = (u_short)ifp->if_flags;
908 ifm->ifm_data = ifp->if_data;
909 ifm->ifm_addrs = 0;
910 route_proto.sp_protocol = 0;
911 raw_input(m, &route_proto, &route_src, &route_dst);
912}
913
914/*
915 * This is called to generate messages from the routing socket
916 * indicating a network interface has had addresses associated with it.
917 * if we ever reverse the logic and replace messages TO the routing
918 * socket indicate a request to configure interfaces, then it will
919 * be unnecessary as the routing socket will automatically generate
920 * copies of it.
921 */
922void
923rt_newaddrmsg(cmd, ifa, error, rt)
924 int cmd, error;
925 register struct ifaddr *ifa;
926 register struct rtentry *rt;
927{
928 struct rt_addrinfo info;
929 struct sockaddr *sa = 0;
930 int pass;
931 struct mbuf *m = 0;
932 struct ifnet *ifp = ifa->ifa_ifp;
933
934 if (route_cb.any_count == 0)
935 return;
936 for (pass = 1; pass < 3; pass++) {
937 bzero((caddr_t)&info, sizeof(info));
938 if ((cmd == RTM_ADD && pass == 1) ||
939 (cmd == RTM_DELETE && pass == 2)) {
940 register struct ifa_msghdr *ifam;
941 int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
942
943 ifaaddr = sa = ifa->ifa_addr;
944 ifpaddr = ifp->if_addrhead.tqh_first->ifa_addr;
945 netmask = ifa->ifa_netmask;
946 brdaddr = ifa->ifa_dstaddr;
947 if ((m = rt_msg1(ncmd, &info)) == NULL)
948 continue;
949 ifam = mtod(m, struct ifa_msghdr *);
950 ifam->ifam_index = ifp->if_index;
951 ifam->ifam_metric = ifa->ifa_metric;
952 ifam->ifam_flags = ifa->ifa_flags;
953 ifam->ifam_addrs = info.rti_addrs;
954 }
955 if ((cmd == RTM_ADD && pass == 2) ||
956 (cmd == RTM_DELETE && pass == 1)) {
957 register struct rt_msghdr *rtm;
958
959 if (rt == 0)
960 continue;
961 netmask = rt_mask(rt);
962 dst = sa = rt_key(rt);
963 gate = rt->rt_gateway;
964 if ((m = rt_msg1(cmd, &info)) == NULL)
965 continue;
966 rtm = mtod(m, struct rt_msghdr *);
967 rtm->rtm_index = ifp->if_index;
968 rtm->rtm_flags |= rt->rt_flags;
969 rtm->rtm_errno = error;
970 rtm->rtm_addrs = info.rti_addrs;
971 }
972 route_proto.sp_protocol = sa ? sa->sa_family : 0;
973 raw_input(m, &route_proto, &route_src, &route_dst);
974 }
975}
976
977/*
978 * This is the analogue to the rt_newaddrmsg which performs the same
979 * function but for multicast group memberhips. This is easier since
980 * there is no route state to worry about.
981 */
982void
983rt_newmaddrmsg(cmd, ifma)
984 int cmd;
985 struct ifmultiaddr *ifma;
986{
987 struct rt_addrinfo info;
988 struct mbuf *m = 0;
989 struct ifnet *ifp = ifma->ifma_ifp;
990 struct ifma_msghdr *ifmam;
991
992 if (route_cb.any_count == 0)
993 return;
994
995 bzero((caddr_t)&info, sizeof(info));
996 ifaaddr = ifma->ifma_addr;
997 if (ifp && ifp->if_addrhead.tqh_first)
998 ifpaddr = ifp->if_addrhead.tqh_first->ifa_addr;
999 else
1000 ifpaddr = NULL;
1001 /*
1002 * If a link-layer address is present, present it as a ``gateway''
1003 * (similarly to how ARP entries, e.g., are presented).
1004 */
1005 gate = ifma->ifma_lladdr;
1006 if ((m = rt_msg1(cmd, &info)) == NULL)
1007 return;
1008 ifmam = mtod(m, struct ifma_msghdr *);
1009 ifmam->ifmam_index = ifp->if_index;
1010 ifmam->ifmam_addrs = info.rti_addrs;
1011 route_proto.sp_protocol = ifma->ifma_addr->sa_family;
1012 raw_input(m, &route_proto, &route_src, &route_dst);
1013}
1014
1015/*
1016 * This is used in dumping the kernel table via sysctl().
1017 */
1018int
1019sysctl_dumpentry(rn, vw)
1020 struct radix_node *rn;
1021 void *vw;
1022{
1023 register struct walkarg *w = vw;
1024 register struct rtentry *rt = (struct rtentry *)rn;
1025 int error = 0, size;
1026 struct rt_addrinfo info;
1027
1028 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
1029 return 0;
1030 bzero((caddr_t)&info, sizeof(info));
1031 dst = rt_key(rt);
1032 gate = rt->rt_gateway;
1033 netmask = rt_mask(rt);
1034 genmask = rt->rt_genmask;
1035 size = rt_msg2(RTM_GET, &info, 0, w);
1036 if (w->w_req && w->w_tmem) {
1037 register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
1038
1039 rtm->rtm_flags = rt->rt_flags;
1040 rtm->rtm_use = rt->rt_use;
1041 rtm->rtm_rmx = rt->rt_rmx;
1042 rtm->rtm_index = rt->rt_ifp->if_index;
1043 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
1044 rtm->rtm_addrs = info.rti_addrs;
1045 error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size);
1046 return (error);
1047 }
1048 return (error);
1049}
1050
1051int
1052sysctl_iflist(af, w)
1053 int af;
1054 register struct walkarg *w;
1055{
1056 register struct ifnet *ifp;
1057 register struct ifaddr *ifa;
1058 struct rt_addrinfo info;
1059 int len, error = 0;
1060
1061 bzero((caddr_t)&info, sizeof(info));
1062 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
1063 if (w->w_arg && w->w_arg != ifp->if_index)
1064 continue;
1065 ifa = ifp->if_addrhead.tqh_first;
1066 ifpaddr = ifa->ifa_addr;
1067 len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w);
1068 ifpaddr = 0;
1069 if (w->w_req && w->w_tmem) {
1070 register struct if_msghdr *ifm;
1071
1072 ifm = (struct if_msghdr *)w->w_tmem;
1073 ifm->ifm_index = ifp->if_index;
1074 ifm->ifm_flags = (u_short)ifp->if_flags;
1075 ifm->ifm_data = ifp->if_data;
1076 ifm->ifm_addrs = info.rti_addrs;
1077 error = SYSCTL_OUT(w->w_req,(caddr_t)ifm, len);
1078 if (error)
1079 return (error);
1080 }
1081 while ((ifa = ifa->ifa_link.tqe_next) != 0) {
1082 if (af && af != ifa->ifa_addr->sa_family)
1083 continue;
1084#ifndef __APPLE__
1085 if (curproc->p_prison && prison_if(curproc, ifa->ifa_addr))
1086 continue;
1087#endif
1088 ifaaddr = ifa->ifa_addr;
1089 netmask = ifa->ifa_netmask;
1090 brdaddr = ifa->ifa_dstaddr;
1091 len = rt_msg2(RTM_NEWADDR, &info, 0, w);
1092 if (w->w_req && w->w_tmem) {
1093 register struct ifa_msghdr *ifam;
1094
1095 ifam = (struct ifa_msghdr *)w->w_tmem;
1096 ifam->ifam_index = ifa->ifa_ifp->if_index;
1097 ifam->ifam_flags = ifa->ifa_flags;
1098 ifam->ifam_metric = ifa->ifa_metric;
1099 ifam->ifam_addrs = info.rti_addrs;
1100 error = SYSCTL_OUT(w->w_req, w->w_tmem, len);
1101 if (error)
1102 return (error);
1103 }
1104 }
1105 ifaaddr = netmask = brdaddr = 0;
1106 }
1107 return (0);
1108}
1109
1110static int
1111sysctl_rtsock SYSCTL_HANDLER_ARGS
1112{
1113 int *name = (int *)arg1;
1114 u_int namelen = arg2;
1115 register struct radix_node_head *rnh;
1116 int i, s, error = EINVAL;
1117 u_char af;
1118 struct walkarg w;
1119
1120 name ++;
1121 namelen--;
1122 if (req->newptr)
1123 return (EPERM);
1124 if (namelen != 3)
1125 return (EINVAL);
1126 af = name[0];
1127 Bzero(&w, sizeof(w));
1128 w.w_op = name[1];
1129 w.w_arg = name[2];
1130 w.w_req = req;
1131
1132 s = splnet();
1133 switch (w.w_op) {
1134
1135 case NET_RT_DUMP:
1136 case NET_RT_FLAGS:
1137 for (i = 1; i <= AF_MAX; i++)
1138 if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
1139 (error = rnh->rnh_walktree(rnh,
1140 sysctl_dumpentry, &w)))
1141 break;
1142 break;
1143
1144 case NET_RT_IFLIST:
1145 error = sysctl_iflist(af, &w);
1146 }
1147 splx(s);
1148 if (w.w_tmem)
1149 FREE(w.w_tmem, M_RTABLE);
1150 return (error);
1151}
1152
1153SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
1154
1155/*
1156 * Definitions of protocols supported in the ROUTE domain.
1157 */
1158
1159struct domain routedomain; /* or at least forward */
1160
1161static struct protosw routesw[] = {
1162{ SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR,
1163 0, route_output, raw_ctlinput, 0,
1164 0,
1165 raw_init, 0, 0, 0,
1166 0, &route_usrreqs, 0, 0
1167}
1168};
1169
1170struct domain routedomain =
1171 { PF_ROUTE, "route", route_init, 0, 0,
1172 routesw};
1173
1174DOMAIN_SET(route);
1175