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