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