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