Fix whitespace.
[dragonfly.git] / sys / net / rtsock.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1988, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)rtsock.c 8.7 (Berkeley) 10/12/95
34 * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $
ef87f48d 35 * $DragonFly: src/sys/net/rtsock.c,v 1.16 2004/12/15 00:11:04 hsu Exp $
984263bc
MD
36 */
37
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/sysctl.h>
43#include <sys/proc.h>
44#include <sys/malloc.h>
45#include <sys/mbuf.h>
47e78ae8 46#include <sys/protosw.h>
984263bc
MD
47#include <sys/socket.h>
48#include <sys/socketvar.h>
49#include <sys/domain.h>
984263bc 50
deffea2e
JS
51#include <machine/stdarg.h>
52
984263bc
MD
53#include <net/if.h>
54#include <net/route.h>
55#include <net/raw_cb.h>
56
57MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
58
59static struct sockaddr route_dst = { 2, PF_ROUTE, };
60static struct sockaddr route_src = { 2, PF_ROUTE, };
61static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, };
62static struct sockproto route_proto = { PF_ROUTE, };
63
64struct walkarg {
65 int w_tmemsize;
66 int w_op, w_arg;
67 caddr_t w_tmem;
68 struct sysctl_req *w_req;
69};
70
71static struct mbuf *
158abb01 72 rt_msg1 (int, struct rt_addrinfo *);
47e78ae8 73static int rt_msg2 (int, struct rt_addrinfo *, caddr_t, struct walkarg *);
ef87f48d 74static int rt_xaddrs (char *, char *, struct rt_addrinfo *);
158abb01
RG
75static int sysctl_dumpentry (struct radix_node *rn, void *vw);
76static int sysctl_iflist (int af, struct walkarg *w);
deffea2e 77static int route_output(struct mbuf *, struct socket *, ...);
47e78ae8
JH
78static void rt_setmetrics (u_long, struct rt_metrics *,
79 struct rt_metrics *);
984263bc 80
984263bc
MD
81/*
82 * It really doesn't make any sense at all for this code to share much
83 * with raw_usrreq.c, since its functionality is so restricted. XXX
84 */
85static int
86rts_abort(struct socket *so)
87{
88 int s, error;
89 s = splnet();
90 error = raw_usrreqs.pru_abort(so);
91 splx(s);
92 return error;
93}
94
95/* pru_accept is EOPNOTSUPP */
96
97static int
e4700d00 98rts_attach(struct socket *so, int proto, struct pru_attach_info *ai)
984263bc
MD
99{
100 struct rawcb *rp;
101 int s, error;
102
ef87f48d 103 if (sotorawcb(so) != NULL)
984263bc
MD
104 return EISCONN; /* XXX panic? */
105 MALLOC(rp, struct rawcb *, sizeof *rp, M_PCB, M_WAITOK|M_ZERO);
ef87f48d 106 if (rp == NULL)
984263bc
MD
107 return ENOBUFS;
108
109 /*
110 * The splnet() is necessary to block protocols from sending
111 * error notifications (like RTM_REDIRECT or RTM_LOSING) while
112 * this PCB is extant but incompletely initialized.
113 * Probably we should try to do more of this work beforehand and
114 * eliminate the spl.
115 */
116 s = splnet();
ef87f48d 117 so->so_pcb = rp;
e4700d00 118 error = raw_attach(so, proto, ai->sb_rlimit);
984263bc
MD
119 rp = sotorawcb(so);
120 if (error) {
121 splx(s);
122 free(rp, M_PCB);
123 return error;
124 }
125 switch(rp->rcb_proto.sp_protocol) {
126 case AF_INET:
127 route_cb.ip_count++;
128 break;
129 case AF_INET6:
130 route_cb.ip6_count++;
131 break;
132 case AF_IPX:
133 route_cb.ipx_count++;
134 break;
135 case AF_NS:
136 route_cb.ns_count++;
137 break;
138 }
139 rp->rcb_faddr = &route_src;
140 route_cb.any_count++;
141 soisconnected(so);
142 so->so_options |= SO_USELOOPBACK;
143 splx(s);
144 return 0;
145}
146
147static int
dadab5e9 148rts_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
984263bc
MD
149{
150 int s, error;
151 s = splnet();
dadab5e9 152 error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */
984263bc
MD
153 splx(s);
154 return error;
155}
156
157static int
dadab5e9 158rts_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
984263bc
MD
159{
160 int s, error;
161 s = splnet();
dadab5e9 162 error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */
984263bc
MD
163 splx(s);
164 return error;
165}
166
167/* pru_connect2 is EOPNOTSUPP */
168/* pru_control is EOPNOTSUPP */
169
170static int
171rts_detach(struct socket *so)
172{
173 struct rawcb *rp = sotorawcb(so);
174 int s, error;
175
176 s = splnet();
ef87f48d 177 if (rp != NULL) {
984263bc
MD
178 switch(rp->rcb_proto.sp_protocol) {
179 case AF_INET:
180 route_cb.ip_count--;
181 break;
182 case AF_INET6:
183 route_cb.ip6_count--;
184 break;
185 case AF_IPX:
186 route_cb.ipx_count--;
187 break;
188 case AF_NS:
189 route_cb.ns_count--;
190 break;
191 }
192 route_cb.any_count--;
193 }
194 error = raw_usrreqs.pru_detach(so);
195 splx(s);
196 return error;
197}
198
199static int
200rts_disconnect(struct socket *so)
201{
202 int s, error;
203 s = splnet();
204 error = raw_usrreqs.pru_disconnect(so);
205 splx(s);
206 return error;
207}
208
209/* pru_listen is EOPNOTSUPP */
210
211static int
212rts_peeraddr(struct socket *so, struct sockaddr **nam)
213{
214 int s, error;
215 s = splnet();
216 error = raw_usrreqs.pru_peeraddr(so, nam);
217 splx(s);
218 return error;
219}
220
221/* pru_rcvd is EOPNOTSUPP */
222/* pru_rcvoob is EOPNOTSUPP */
223
224static int
225rts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
dadab5e9 226 struct mbuf *control, struct thread *td)
984263bc
MD
227{
228 int s, error;
229 s = splnet();
dadab5e9 230 error = raw_usrreqs.pru_send(so, flags, m, nam, control, td);
984263bc
MD
231 splx(s);
232 return error;
233}
234
235/* pru_sense is null */
236
237static int
238rts_shutdown(struct socket *so)
239{
240 int s, error;
241 s = splnet();
242 error = raw_usrreqs.pru_shutdown(so);
243 splx(s);
244 return error;
245}
246
247static int
248rts_sockaddr(struct socket *so, struct sockaddr **nam)
249{
250 int s, error;
251 s = splnet();
252 error = raw_usrreqs.pru_sockaddr(so, nam);
253 splx(s);
254 return error;
255}
256
257static struct pr_usrreqs route_usrreqs = {
258 rts_abort, pru_accept_notsupp, rts_attach, rts_bind, rts_connect,
259 pru_connect2_notsupp, pru_control_notsupp, rts_detach, rts_disconnect,
260 pru_listen_notsupp, rts_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
261 rts_send, pru_sense_null, rts_shutdown, rts_sockaddr,
262 sosend, soreceive, sopoll
263};
264
265/*ARGSUSED*/
266static int
deffea2e 267route_output(struct mbuf *m, struct socket *so, ...)
984263bc 268{
2e9572df
JH
269 struct rt_msghdr *rtm = NULL;
270 struct rtentry *rt = NULL;
271 struct rtentry *saved_nrt = NULL;
984263bc 272 struct radix_node_head *rnh;
2e9572df
JH
273 struct ifnet *ifp = NULL;
274 struct ifaddr *ifa = NULL;
deffea2e 275 struct pr_output_info *oi;
ef87f48d
JH
276 struct rt_addrinfo info;
277 int len, error = 0;
deffea2e
JS
278 __va_list ap;
279
280 __va_start(ap, so);
281 oi = __va_arg(ap, struct pr_output_info *);
282 __va_end(ap);
984263bc 283
ef87f48d 284#define gotoerr(e) { error = e; goto flush;}
2e9572df
JH
285 if (m == NULL || ((m->m_len < sizeof(long)) &&
286 (m = m_pullup(m, sizeof(long))) == NULL))
984263bc 287 return (ENOBUFS);
ef87f48d 288 if (!(m->m_flags & M_PKTHDR))
984263bc
MD
289 panic("route_output");
290 len = m->m_pkthdr.len;
291 if (len < sizeof(*rtm) ||
292 len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
ef87f48d
JH
293 info.sa_dst = NULL;
294 gotoerr(EINVAL);
984263bc
MD
295 }
296 R_Malloc(rtm, struct rt_msghdr *, len);
ef87f48d
JH
297 if (rtm == NULL) {
298 info.sa_dst = NULL;
299 gotoerr(ENOBUFS);
984263bc
MD
300 }
301 m_copydata(m, 0, len, (caddr_t)rtm);
302 if (rtm->rtm_version != RTM_VERSION) {
ef87f48d
JH
303 info.sa_dst = NULL;
304 gotoerr(EPROTONOSUPPORT);
984263bc 305 }
47e78ae8 306 rtm->rtm_pid = oi->p_pid;
984263bc
MD
307 bzero(&info, sizeof(info));
308 info.rti_addrs = rtm->rtm_addrs;
ef87f48d
JH
309 if (rt_xaddrs((char *)(rtm + 1), len + (char *)rtm, &info)) {
310 info.sa_dst = NULL;
311 gotoerr(EINVAL);
984263bc
MD
312 }
313 info.rti_flags = rtm->rtm_flags;
ef87f48d
JH
314 if (info.sa_dst == NULL || info.sa_dst->sa_family >= AF_MAX ||
315 (info.sa_gateway != NULL && (info.sa_gateway->sa_family >= AF_MAX)))
316 gotoerr(EINVAL);
317
318 if (info.sa_genmask != NULL) {
984263bc 319 struct radix_node *t;
ef87f48d
JH
320 int klen;
321
322 t = rn_addmask((char *)info.sa_genmask, TRUE, 1);
323 if (t != NULL &&
324 info.sa_genmask->sa_len >= (klen = *(u_char *)t->rn_key) &&
325 bcmp((char *)info.sa_genmask + 1, (char *)t->rn_key + 1,
326 klen - 1) == 0)
327 info.sa_genmask = (struct sockaddr *)(t->rn_key);
984263bc 328 else
ef87f48d 329 gotoerr(ENOBUFS);
984263bc
MD
330 }
331
332 /*
333 * Verify that the caller has the appropriate privilege; RTM_GET
334 * is the only operation the non-superuser is allowed.
335 */
dadab5e9 336 if (rtm->rtm_type != RTM_GET && suser_cred(so->so_cred, 0) != 0)
ef87f48d 337 gotoerr(EPERM);
984263bc
MD
338
339 switch (rtm->rtm_type) {
340
341 case RTM_ADD:
ef87f48d
JH
342 if (info.sa_gateway == NULL)
343 gotoerr(EINVAL);
984263bc 344 error = rtrequest1(RTM_ADD, &info, &saved_nrt);
ef87f48d 345 if (error == 0 && saved_nrt != NULL) {
984263bc
MD
346 rt_setmetrics(rtm->rtm_inits,
347 &rtm->rtm_rmx, &saved_nrt->rt_rmx);
348 saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
349 saved_nrt->rt_rmx.rmx_locks |=
350 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
351 saved_nrt->rt_refcnt--;
ef87f48d 352 saved_nrt->rt_genmask = info.sa_genmask;
984263bc
MD
353 }
354 break;
355
356 case RTM_DELETE:
357 error = rtrequest1(RTM_DELETE, &info, &saved_nrt);
358 if (error == 0) {
359 if ((rt = saved_nrt))
360 rt->rt_refcnt++;
361 goto report;
362 }
363 break;
364
365 case RTM_GET:
366 case RTM_CHANGE:
367 case RTM_LOCK:
ef87f48d
JH
368 if ((rnh = rt_tables[info.sa_dst->sa_family]) == NULL) {
369 gotoerr(EAFNOSUPPORT);
2e9572df 370 } else if ((rt = (struct rtentry *) rnh->rnh_lookup(
ef87f48d 371 (char *)info.sa_dst, (char *)info.sa_netmask, rnh)) != NULL)
984263bc
MD
372 rt->rt_refcnt++;
373 else
ef87f48d 374 gotoerr(ESRCH);
984263bc
MD
375 switch(rtm->rtm_type) {
376
377 case RTM_GET:
378 report:
ef87f48d
JH
379 info.sa_dst = rt_key(rt);
380 info.sa_gateway = rt->rt_gateway;
381 info.sa_netmask = rt_mask(rt);
382 info.sa_genmask = rt->rt_genmask;
984263bc
MD
383 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
384 ifp = rt->rt_ifp;
385 if (ifp) {
ef87f48d
JH
386 info.sa_ifpaddr =
387 TAILQ_FIRST(&ifp->if_addrhead)->
388 ifa_addr;
389 info.sa_ifaaddr = rt->rt_ifa->ifa_addr;
984263bc 390 if (ifp->if_flags & IFF_POINTOPOINT)
ef87f48d
JH
391 info.sa_bcastaddr =
392 rt->rt_ifa->ifa_dstaddr;
984263bc
MD
393 rtm->rtm_index = ifp->if_index;
394 } else {
ef87f48d
JH
395 info.sa_ifpaddr = NULL;
396 info.sa_ifaaddr = NULL;
984263bc
MD
397 }
398 }
ef87f48d 399 len = rt_msg2(rtm->rtm_type, &info, NULL, NULL);
984263bc
MD
400 if (len > rtm->rtm_msglen) {
401 struct rt_msghdr *new_rtm;
402 R_Malloc(new_rtm, struct rt_msghdr *, len);
ef87f48d
JH
403 if (new_rtm == NULL)
404 gotoerr(ENOBUFS);
2e9572df 405 bcopy(rtm, new_rtm, rtm->rtm_msglen);
984263bc
MD
406 Free(rtm); rtm = new_rtm;
407 }
ef87f48d 408 (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL);
984263bc
MD
409 rtm->rtm_flags = rt->rt_flags;
410 rtm->rtm_rmx = rt->rt_rmx;
411 rtm->rtm_addrs = info.rti_addrs;
412 break;
413
414 case RTM_CHANGE:
ef87f48d
JH
415 /*
416 * new gateway could require new ifaddr, ifp;
417 * flags may also be different; ifp may be specified
418 * by ll sockaddr when protocol address is ambiguous
419 */
420 if (((rt->rt_flags & RTF_GATEWAY) &&
421 info.sa_gateway != NULL) ||
422 info.sa_ifpaddr != NULL ||
423 (info.sa_ifaaddr != NULL &&
424 bcmp(info.sa_ifaaddr, rt->rt_ifa->ifa_addr,
425 info.sa_ifaaddr->sa_len) == 0)) {
984263bc 426 if ((error = rt_getifa(&info)) != 0)
ef87f48d 427 gotoerr(error);
984263bc 428 }
ef87f48d
JH
429 if (info.sa_gateway != NULL &&
430 (error = rt_setgate(rt, rt_key(rt),
431 info.sa_gateway)) != 0)
432 gotoerr(error);
984263bc 433 if ((ifa = info.rti_ifa) != NULL) {
82ed7fc2 434 struct ifaddr *oifa = rt->rt_ifa;
ef87f48d 435
984263bc
MD
436 if (oifa != ifa) {
437 if (oifa && oifa->ifa_rtrequest)
438 oifa->ifa_rtrequest(RTM_DELETE, rt,
439 &info);
440 IFAFREE(rt->rt_ifa);
441 rt->rt_ifa = ifa;
442 ifa->ifa_refcnt++;
443 rt->rt_ifp = info.rti_ifp;
444 }
445 }
446 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
447 &rt->rt_rmx);
448 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
449 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
ef87f48d
JH
450 if (info.sa_genmask != NULL)
451 rt->rt_genmask = info.sa_genmask;
984263bc
MD
452 /*
453 * Fall into
454 */
455 case RTM_LOCK:
456 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
457 rt->rt_rmx.rmx_locks |=
458 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
459 break;
460 }
461 break;
462
463 default:
ef87f48d 464 gotoerr(EOPNOTSUPP);
984263bc
MD
465 }
466
467flush:
468 if (rtm) {
469 if (error)
470 rtm->rtm_errno = error;
471 else
472 rtm->rtm_flags |= RTF_DONE;
473 }
474 if (rt)
475 rtfree(rt);
476 {
ef87f48d 477 struct rawcb *rp = NULL;
984263bc
MD
478 /*
479 * Check to see if we don't want our own messages.
480 */
ef87f48d 481 if (!(so->so_options & SO_USELOOPBACK)) {
984263bc
MD
482 if (route_cb.any_count <= 1) {
483 if (rtm)
484 Free(rtm);
485 m_freem(m);
486 return (error);
487 }
488 /* There is another listener, so construct message */
489 rp = sotorawcb(so);
490 }
491 if (rtm) {
492 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
493 if (m->m_pkthdr.len < rtm->rtm_msglen) {
494 m_freem(m);
495 m = NULL;
496 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
497 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
498 Free(rtm);
499 }
ef87f48d 500 if (rp != NULL)
984263bc 501 rp->rcb_proto.sp_family = 0; /* Avoid us */
ef87f48d
JH
502 if (info.sa_dst != NULL)
503 route_proto.sp_protocol = info.sa_dst->sa_family;
504 if (m != NULL)
984263bc 505 raw_input(m, &route_proto, &route_src, &route_dst);
ef87f48d 506 if (rp != NULL)
984263bc
MD
507 rp->rcb_proto.sp_family = PF_ROUTE;
508 }
509 return (error);
510}
511
512static void
ef87f48d 513rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_metrics *out)
984263bc 514{
2e9572df
JH
515#define setmetric(flag, elt) if (which & (flag)) out->elt = in->elt;
516 setmetric(RTV_RPIPE, rmx_recvpipe);
517 setmetric(RTV_SPIPE, rmx_sendpipe);
518 setmetric(RTV_SSTHRESH, rmx_ssthresh);
519 setmetric(RTV_RTT, rmx_rtt);
520 setmetric(RTV_RTTVAR, rmx_rttvar);
521 setmetric(RTV_HOPCOUNT, rmx_hopcount);
522 setmetric(RTV_MTU, rmx_mtu);
523 setmetric(RTV_EXPIRE, rmx_expire);
524#undef setmetric
984263bc
MD
525}
526
527#define ROUNDUP(a) \
528 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
529#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
530
984263bc
MD
531/*
532 * Extract the addresses of the passed sockaddrs.
533 * Do a little sanity checking so as to avoid bad memory references.
534 * This data is derived straight from userland.
535 */
536static int
ef87f48d 537rt_xaddrs(char *cp, char *cplim, struct rt_addrinfo *rtinfo)
984263bc 538{
82ed7fc2
RG
539 struct sockaddr *sa;
540 int i;
984263bc
MD
541
542 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
543 if ((rtinfo->rti_addrs & (1 << i)) == 0)
544 continue;
545 sa = (struct sockaddr *)cp;
546 /*
547 * It won't fit.
548 */
549 if ( (cp + sa->sa_len) > cplim ) {
550 return (EINVAL);
551 }
552
553 /*
ef87f48d 554 * There are no more... Quit now.
984263bc 555 * If there are more bits, they are in error.
ef87f48d 556 * I've seen this. route(1) can evidently generate these.
984263bc 557 * This causes kernel to core dump.
ef87f48d 558 * For compatibility, if we see this, point to a safe address.
984263bc
MD
559 */
560 if (sa->sa_len == 0) {
561 rtinfo->rti_info[i] = &sa_zero;
562 return (0); /* should be EINVAL but for compat */
563 }
564
ef87f48d 565 /* Accept the sockaddr. */
984263bc
MD
566 rtinfo->rti_info[i] = sa;
567 ADVANCE(cp, sa);
568 }
569 return (0);
570}
571
572static struct mbuf *
573rt_msg1(type, rtinfo)
574 int type;
82ed7fc2 575 struct rt_addrinfo *rtinfo;
984263bc 576{
82ed7fc2
RG
577 struct rt_msghdr *rtm;
578 struct mbuf *m;
579 int i;
580 struct sockaddr *sa;
984263bc
MD
581 int len, dlen;
582
583 switch (type) {
584
585 case RTM_DELADDR:
586 case RTM_NEWADDR:
587 len = sizeof(struct ifa_msghdr);
588 break;
589
590 case RTM_DELMADDR:
591 case RTM_NEWMADDR:
592 len = sizeof(struct ifma_msghdr);
593 break;
594
595 case RTM_IFINFO:
596 len = sizeof(struct if_msghdr);
597 break;
598
599 case RTM_IFANNOUNCE:
600 len = sizeof(struct if_announcemsghdr);
601 break;
602
603 default:
604 len = sizeof(struct rt_msghdr);
605 }
606 if (len > MCLBYTES)
607 panic("rt_msg1");
74f1caca 608 m = m_gethdr(MB_DONTWAIT, MT_DATA);
984263bc 609 if (m && len > MHLEN) {
74f1caca 610 MCLGET(m, MB_DONTWAIT);
ef87f48d 611 if (!(m->m_flags & M_EXT)) {
984263bc
MD
612 m_free(m);
613 m = NULL;
614 }
615 }
ef87f48d 616 if (m == NULL)
984263bc
MD
617 return (m);
618 m->m_pkthdr.len = m->m_len = len;
ef87f48d 619 m->m_pkthdr.rcvif = NULL;
984263bc 620 rtm = mtod(m, struct rt_msghdr *);
ef87f48d 621 bzero(rtm, len);
984263bc
MD
622 for (i = 0; i < RTAX_MAX; i++) {
623 if ((sa = rtinfo->rti_info[i]) == NULL)
624 continue;
625 rtinfo->rti_addrs |= (1 << i);
626 dlen = ROUNDUP(sa->sa_len);
627 m_copyback(m, len, dlen, (caddr_t)sa);
628 len += dlen;
629 }
630 if (m->m_pkthdr.len != len) {
631 m_freem(m);
632 return (NULL);
633 }
634 rtm->rtm_msglen = len;
635 rtm->rtm_version = RTM_VERSION;
636 rtm->rtm_type = type;
637 return (m);
638}
639
640static int
ef87f48d 641rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w)
984263bc 642{
82ed7fc2 643 int i;
ef87f48d
JH
644 int len, dlen;
645 boolean_t second_time = FALSE;
984263bc
MD
646 caddr_t cp0;
647
ef87f48d 648 rtinfo->rti_addrs = NULL;
984263bc
MD
649again:
650 switch (type) {
651
652 case RTM_DELADDR:
653 case RTM_NEWADDR:
654 len = sizeof(struct ifa_msghdr);
655 break;
656
657 case RTM_IFINFO:
658 len = sizeof(struct if_msghdr);
659 break;
660
661 default:
662 len = sizeof(struct rt_msghdr);
663 }
664 cp0 = cp;
ef87f48d 665 if (cp != NULL)
984263bc 666 cp += len;
ef87f48d 667
984263bc 668 for (i = 0; i < RTAX_MAX; i++) {
82ed7fc2 669 struct sockaddr *sa;
984263bc 670
ef87f48d 671 if ((sa = rtinfo->rti_info[i]) == NULL)
984263bc
MD
672 continue;
673 rtinfo->rti_addrs |= (1 << i);
674 dlen = ROUNDUP(sa->sa_len);
ef87f48d
JH
675 if (cp != NULL) {
676 bcopy(sa, cp, dlen);
984263bc
MD
677 cp += dlen;
678 }
679 len += dlen;
680 }
681 len = ALIGN(len);
ef87f48d 682 if (cp == NULL && w != NULL && !second_time) {
82ed7fc2 683 struct walkarg *rw = w;
984263bc 684
ef87f48d 685 if (rw->w_req != NULL) {
984263bc
MD
686 if (rw->w_tmemsize < len) {
687 if (rw->w_tmem)
688 free(rw->w_tmem, M_RTABLE);
ef87f48d
JH
689 rw->w_tmem = malloc(len, M_RTABLE,
690 M_INTWAIT | M_NULLOK);
984263bc
MD
691 if (rw->w_tmem)
692 rw->w_tmemsize = len;
693 }
ef87f48d 694 if (rw->w_tmem != NULL) {
984263bc 695 cp = rw->w_tmem;
ef87f48d 696 second_time = TRUE;
984263bc
MD
697 goto again;
698 }
699 }
700 }
ef87f48d 701 if (cp != NULL) {
82ed7fc2 702 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
984263bc
MD
703
704 rtm->rtm_version = RTM_VERSION;
705 rtm->rtm_type = type;
706 rtm->rtm_msglen = len;
707 }
708 return (len);
709}
710
711/*
712 * This routine is called to generate a message from the routing
713 * socket indicating that a redirect has occured, a routing lookup
714 * has failed, or that a protocol has detected timeouts to a particular
715 * destination.
716 */
717void
718rt_missmsg(type, rtinfo, flags, error)
719 int type, flags, error;
82ed7fc2 720 struct rt_addrinfo *rtinfo;
984263bc 721{
82ed7fc2
RG
722 struct rt_msghdr *rtm;
723 struct mbuf *m;
ef87f48d 724 struct sockaddr *sa = rtinfo->sa_dst;
984263bc
MD
725
726 if (route_cb.any_count == 0)
727 return;
728 m = rt_msg1(type, rtinfo);
ef87f48d 729 if (m == NULL)
984263bc
MD
730 return;
731 rtm = mtod(m, struct rt_msghdr *);
732 rtm->rtm_flags = RTF_DONE | flags;
733 rtm->rtm_errno = error;
734 rtm->rtm_addrs = rtinfo->rti_addrs;
735 route_proto.sp_protocol = sa ? sa->sa_family : 0;
736 raw_input(m, &route_proto, &route_src, &route_dst);
737}
738
739/*
740 * This routine is called to generate a message from the routing
741 * socket indicating that the status of a network interface has changed.
742 */
743void
744rt_ifmsg(ifp)
82ed7fc2 745 struct ifnet *ifp;
984263bc 746{
82ed7fc2 747 struct if_msghdr *ifm;
984263bc
MD
748 struct mbuf *m;
749 struct rt_addrinfo info;
750
751 if (route_cb.any_count == 0)
752 return;
ef87f48d 753 bzero(&info, sizeof(info));
984263bc 754 m = rt_msg1(RTM_IFINFO, &info);
ef87f48d 755 if (m == NULL)
984263bc
MD
756 return;
757 ifm = mtod(m, struct if_msghdr *);
758 ifm->ifm_index = ifp->if_index;
759 ifm->ifm_flags = (u_short)ifp->if_flags;
760 ifm->ifm_data = ifp->if_data;
ef87f48d 761 ifm->ifm_addrs = NULL;
984263bc
MD
762 route_proto.sp_protocol = 0;
763 raw_input(m, &route_proto, &route_src, &route_dst);
764}
765
372316d9
JH
766static void
767rt_ifamsg(int cmd, struct ifaddr *ifa)
768{
769 struct ifa_msghdr *ifam;
770 struct rt_addrinfo info;
771 struct mbuf *m;
772 struct sockaddr *sa;
773 struct ifnet *ifp = ifa->ifa_ifp;
774
775 bzero(&info, sizeof(info));
ef87f48d
JH
776 info.sa_ifaaddr = sa = ifa->ifa_addr;
777 info.sa_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
778 info.sa_netmask = ifa->ifa_netmask;
779 info.sa_bcastaddr = ifa->ifa_dstaddr;
372316d9
JH
780 if ((m = rt_msg1(cmd, &info)) == NULL)
781 return;
782 ifam = mtod(m, struct ifa_msghdr *);
783 ifam->ifam_index = ifp->if_index;
784 ifam->ifam_metric = ifa->ifa_metric;
785 ifam->ifam_flags = ifa->ifa_flags;
786 ifam->ifam_addrs = info.rti_addrs;
787
788 route_proto.sp_protocol = sa ? sa->sa_family : 0;
789 raw_input(m, &route_proto, &route_src, &route_dst);
790}
791
792static void
793rt_rtmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
794{
795 struct rt_msghdr *rtm;
796 struct rt_addrinfo info;
797 struct mbuf *m;
798 struct sockaddr *sa;
799 struct ifnet *ifp = ifa->ifa_ifp;
800
801 if (rt == NULL)
802 return;
803 bzero(&info, sizeof(info));
ef87f48d
JH
804 info.sa_netmask = rt_mask(rt);
805 info.sa_dst = sa = rt_key(rt);
806 info.sa_gateway = rt->rt_gateway;
372316d9
JH
807 if ((m = rt_msg1(cmd, &info)) == NULL)
808 return;
809 rtm = mtod(m, struct rt_msghdr *);
810 rtm->rtm_index = ifp->if_index;
811 rtm->rtm_flags |= rt->rt_flags;
812 rtm->rtm_errno = error;
813 rtm->rtm_addrs = info.rti_addrs;
814
815 route_proto.sp_protocol = sa ? sa->sa_family : 0;
816 raw_input(m, &route_proto, &route_src, &route_dst);
817}
818
984263bc
MD
819/*
820 * This is called to generate messages from the routing socket
821 * indicating a network interface has had addresses associated with it.
822 * if we ever reverse the logic and replace messages TO the routing
823 * socket indicate a request to configure interfaces, then it will
824 * be unnecessary as the routing socket will automatically generate
825 * copies of it.
826 */
827void
828rt_newaddrmsg(cmd, ifa, error, rt)
829 int cmd, error;
82ed7fc2
RG
830 struct ifaddr *ifa;
831 struct rtentry *rt;
984263bc 832{
984263bc
MD
833 if (route_cb.any_count == 0)
834 return;
984263bc 835
372316d9
JH
836 if (cmd == RTM_ADD) {
837 rt_ifamsg(RTM_NEWADDR, ifa);
838 rt_rtmsg(RTM_ADD, ifa, error, rt);
839 } else {
840 KASSERT((cmd == RTM_DELETE), ("unknown cmd %d", cmd));
841 rt_rtmsg(RTM_DELETE, ifa, error, rt);
842 rt_ifamsg(RTM_DELADDR, ifa);
984263bc
MD
843 }
844}
845
846/*
847 * This is the analogue to the rt_newaddrmsg which performs the same
848 * function but for multicast group memberhips. This is easier since
849 * there is no route state to worry about.
850 */
851void
852rt_newmaddrmsg(cmd, ifma)
853 int cmd;
854 struct ifmultiaddr *ifma;
855{
856 struct rt_addrinfo info;
ef87f48d 857 struct mbuf *m = NULL;
984263bc
MD
858 struct ifnet *ifp = ifma->ifma_ifp;
859 struct ifma_msghdr *ifmam;
860
861 if (route_cb.any_count == 0)
862 return;
863
ef87f48d
JH
864 bzero(&info, sizeof(info));
865 info.sa_ifaaddr = ifma->ifma_addr;
866 if (ifp != NULL && TAILQ_FIRST(&ifp->if_addrhead) != NULL)
867 info.sa_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
984263bc 868 else
ef87f48d 869 info.sa_ifpaddr = NULL;
984263bc
MD
870 /*
871 * If a link-layer address is present, present it as a ``gateway''
872 * (similarly to how ARP entries, e.g., are presented).
873 */
ef87f48d 874 info.sa_gateway = ifma->ifma_lladdr;
984263bc
MD
875 if ((m = rt_msg1(cmd, &info)) == NULL)
876 return;
877 ifmam = mtod(m, struct ifma_msghdr *);
878 ifmam->ifmam_index = ifp->if_index;
879 ifmam->ifmam_addrs = info.rti_addrs;
880 route_proto.sp_protocol = ifma->ifma_addr->sa_family;
881 raw_input(m, &route_proto, &route_src, &route_dst);
882}
883
884/*
885 * This is called to generate routing socket messages indicating
886 * network interface arrival and departure.
887 */
888void
889rt_ifannouncemsg(ifp, what)
890 struct ifnet *ifp;
891 int what;
892{
893 struct if_announcemsghdr *ifan;
894 struct mbuf *m;
895 struct rt_addrinfo info;
896
897 if (route_cb.any_count == 0)
898 return;
ef87f48d 899 bzero(&info, sizeof(info));
984263bc
MD
900 m = rt_msg1(RTM_IFANNOUNCE, &info);
901 if (m == NULL)
902 return;
903 ifan = mtod(m, struct if_announcemsghdr *);
904 ifan->ifan_index = ifp->if_index;
3e4a09e7 905 strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
984263bc
MD
906 ifan->ifan_what = what;
907 route_proto.sp_protocol = 0;
908 raw_input(m, &route_proto, &route_src, &route_dst);
909 }
910
911/*
912 * This is used in dumping the kernel table via sysctl().
913 */
914int
915sysctl_dumpentry(rn, vw)
916 struct radix_node *rn;
917 void *vw;
918{
82ed7fc2
RG
919 struct walkarg *w = vw;
920 struct rtentry *rt = (struct rtentry *)rn;
984263bc
MD
921 int error = 0, size;
922 struct rt_addrinfo info;
923
924 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
925 return 0;
ef87f48d
JH
926 bzero(&info, sizeof(info));
927 info.sa_dst = rt_key(rt);
928 info.sa_gateway = rt->rt_gateway;
929 info.sa_netmask = rt_mask(rt);
930 info.sa_genmask = rt->rt_genmask;
931 if (rt->rt_ifp != NULL) {
932 info.sa_ifpaddr =
933 TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr;
934 info.sa_ifaaddr = rt->rt_ifa->ifa_addr;
984263bc 935 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
ef87f48d 936 info.sa_bcastaddr = rt->rt_ifa->ifa_dstaddr;
984263bc 937 }
ef87f48d
JH
938 size = rt_msg2(RTM_GET, &info, NULL, w);
939 if (w->w_req != NULL && w->w_tmem != NULL) {
82ed7fc2 940 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
984263bc
MD
941
942 rtm->rtm_flags = rt->rt_flags;
943 rtm->rtm_use = rt->rt_use;
944 rtm->rtm_rmx = rt->rt_rmx;
945 rtm->rtm_index = rt->rt_ifp->if_index;
946 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
947 rtm->rtm_addrs = info.rti_addrs;
948 error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size);
949 return (error);
950 }
951 return (error);
952}
953
954int
955sysctl_iflist(af, w)
956 int af;
82ed7fc2 957 struct walkarg *w;
984263bc 958{
82ed7fc2
RG
959 struct ifnet *ifp;
960 struct ifaddr *ifa;
984263bc
MD
961 struct rt_addrinfo info;
962 int len, error = 0;
963
ef87f48d 964 bzero(&info, sizeof(info));
984263bc
MD
965 TAILQ_FOREACH(ifp, &ifnet, if_link) {
966 if (w->w_arg && w->w_arg != ifp->if_index)
967 continue;
968 ifa = TAILQ_FIRST(&ifp->if_addrhead);
ef87f48d
JH
969 info.sa_ifpaddr = ifa->ifa_addr;
970 len = rt_msg2(RTM_IFINFO, &info, NULL, w);
971 info.sa_ifpaddr = NULL;
972 if (w->w_req != NULL && w->w_tmem != NULL) {
82ed7fc2 973 struct if_msghdr *ifm;
984263bc
MD
974
975 ifm = (struct if_msghdr *)w->w_tmem;
976 ifm->ifm_index = ifp->if_index;
977 ifm->ifm_flags = (u_short)ifp->if_flags;
978 ifm->ifm_data = ifp->if_data;
979 ifm->ifm_addrs = info.rti_addrs;
980 error = SYSCTL_OUT(w->w_req,(caddr_t)ifm, len);
981 if (error)
982 return (error);
983 }
ef87f48d 984 while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != NULL) {
984263bc
MD
985 if (af && af != ifa->ifa_addr->sa_family)
986 continue;
dadab5e9 987 if (curproc->p_ucred->cr_prison && prison_if(curthread, ifa->ifa_addr))
984263bc 988 continue;
ef87f48d
JH
989 info.sa_ifaaddr = ifa->ifa_addr;
990 info.sa_netmask = ifa->ifa_netmask;
991 info.sa_bcastaddr = ifa->ifa_dstaddr;
992 len = rt_msg2(RTM_NEWADDR, &info, NULL, w);
984263bc 993 if (w->w_req && w->w_tmem) {
82ed7fc2 994 struct ifa_msghdr *ifam;
984263bc
MD
995
996 ifam = (struct ifa_msghdr *)w->w_tmem;
997 ifam->ifam_index = ifa->ifa_ifp->if_index;
998 ifam->ifam_flags = ifa->ifa_flags;
999 ifam->ifam_metric = ifa->ifa_metric;
1000 ifam->ifam_addrs = info.rti_addrs;
1001 error = SYSCTL_OUT(w->w_req, w->w_tmem, len);
1002 if (error)
1003 return (error);
1004 }
1005 }
ef87f48d 1006 info.sa_netmask = info.sa_ifaaddr = info.sa_bcastaddr = NULL;
984263bc
MD
1007 }
1008 return (0);
1009}
1010
1011static int
1012sysctl_rtsock(SYSCTL_HANDLER_ARGS)
1013{
1014 int *name = (int *)arg1;
1015 u_int namelen = arg2;
82ed7fc2 1016 struct radix_node_head *rnh;
984263bc
MD
1017 int i, s, error = EINVAL;
1018 u_char af;
1019 struct walkarg w;
1020
1021 name ++;
1022 namelen--;
1023 if (req->newptr)
1024 return (EPERM);
1025 if (namelen != 3)
1026 return (EINVAL);
1027 af = name[0];
2e9572df 1028 bzero(&w, sizeof(w));
984263bc
MD
1029 w.w_op = name[1];
1030 w.w_arg = name[2];
1031 w.w_req = req;
1032
1033 s = splnet();
1034 switch (w.w_op) {
1035
1036 case NET_RT_DUMP:
1037 case NET_RT_FLAGS:
1038 for (i = 1; i <= AF_MAX; i++)
1039 if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
1040 (error = rnh->rnh_walktree(rnh,
1041 sysctl_dumpentry, &w)))
1042 break;
1043 break;
1044
1045 case NET_RT_IFLIST:
1046 error = sysctl_iflist(af, &w);
1047 }
1048 splx(s);
1049 if (w.w_tmem)
1050 free(w.w_tmem, M_RTABLE);
1051 return (error);
1052}
1053
1054SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
1055
1056/*
1057 * Definitions of protocols supported in the ROUTE domain.
1058 */
1059
1060extern struct domain routedomain; /* or at least forward */
1061
1062static struct protosw routesw[] = {
1063{ SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR,
1064 0, route_output, raw_ctlinput, 0,
9eeaa8a9 1065 cpu0_soport,
984263bc
MD
1066 raw_init, 0, 0, 0,
1067 &route_usrreqs
1068}
1069};
1070
1071static struct domain routedomain =
1072 { PF_ROUTE, "route", 0, 0, 0,
1073 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
1074
1075DOMAIN_SET(route);