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