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