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