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