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