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