<sys/types.h>: Add some *_T_DECLARED guards for upcoming work.
[dragonfly.git] / sys / net / rtsock.c
CommitLineData
f3ed2586
JH
1/*
2 * Copyright (c) 2004, 2005 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Jeffrey M. Hsu.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of The DragonFly Project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific, prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
984263bc
MD
33/*
34 * Copyright (c) 1988, 1991, 1993
35 * The Regents of the University of California. All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
dc71b7ab 45 * 3. Neither the name of the University nor the names of its contributors
984263bc
MD
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)rtsock.c 8.7 (Berkeley) 10/12/95
62 * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $
63 */
64
984263bc
MD
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/kernel.h>
68#include <sys/sysctl.h>
69#include <sys/proc.h>
895c1f85 70#include <sys/priv.h>
984263bc
MD
71#include <sys/malloc.h>
72#include <sys/mbuf.h>
47e78ae8 73#include <sys/protosw.h>
984263bc
MD
74#include <sys/socket.h>
75#include <sys/socketvar.h>
76#include <sys/domain.h>
e1c6b0c1 77#include <sys/jail.h>
6cef7136 78
a49aa710 79#include <sys/thread2.h>
6cef7136 80#include <sys/socketvar2.h>
deffea2e 81
984263bc 82#include <net/if.h>
bff82488 83#include <net/if_var.h>
984263bc
MD
84#include <net/route.h>
85#include <net/raw_cb.h>
47db7f9b 86#include <net/netmsg2.h>
5337421c 87#include <net/netisr2.h>
984263bc
MD
88
89MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
90
f23061d4
JH
91static struct route_cb {
92 int ip_count;
93 int ip6_count;
f23061d4
JH
94 int ns_count;
95 int any_count;
96} route_cb;
97
590b8cd4 98static const struct sockaddr route_src = { 2, PF_ROUTE, };
984263bc
MD
99
100struct walkarg {
101 int w_tmemsize;
102 int w_op, w_arg;
8e63efec 103 void *w_tmem;
984263bc
MD
104 struct sysctl_req *w_req;
105};
106
291dd55b
SZ
107#ifndef RTTABLE_DUMP_MSGCNT_MAX
108/* Should be large enough for dupkeys */
109#define RTTABLE_DUMP_MSGCNT_MAX 64
110#endif
111
112struct rttable_walkarg {
113 int w_op;
114 int w_arg;
115 int w_bufsz;
116 void *w_buf;
117
118 int w_buflen;
119
120 const char *w_key;
121 const char *w_mask;
122
123 struct sockaddr_storage w_key0;
124 struct sockaddr_storage w_mask0;
125};
126
127struct netmsg_rttable_walk {
128 struct netmsg_base base;
129 int af;
130 struct rttable_walkarg *w;
131};
132
8aeffa9f
RM
133struct routecb {
134 struct rawcb rocb_rcb;
135 unsigned int rocb_msgfilter;
136};
137#define sotoroutecb(so) ((struct routecb *)(so)->so_pcb)
138
984263bc 139static struct mbuf *
590b8cd4
JH
140 rt_msg_mbuf (int, struct rt_addrinfo *);
141static void rt_msg_buffer (int, struct rt_addrinfo *, void *buf, int len);
c3b2a749 142static int rt_msgsize(int type, const struct rt_addrinfo *rtinfo);
ef87f48d 143static int rt_xaddrs (char *, char *, struct rt_addrinfo *);
085b1d2a 144static int sysctl_rttable(int af, struct sysctl_req *req, int op, int arg);
43a37315 145static int if_addrflags(const struct ifaddr *ifa);
158abb01 146static int sysctl_iflist (int af, struct walkarg *w);
deffea2e 147static int route_output(struct mbuf *, struct socket *, ...);
47e78ae8 148static void rt_setmetrics (u_long, struct rt_metrics *,
f23061d4 149 struct rt_metrics *);
984263bc 150
984263bc
MD
151/*
152 * It really doesn't make any sense at all for this code to share much
153 * with raw_usrreq.c, since its functionality is so restricted. XXX
154 */
002c1265
MD
155static void
156rts_abort(netmsg_t msg)
984263bc 157{
a49aa710 158 crit_enter();
002c1265
MD
159 raw_usrreqs.pru_abort(msg);
160 /* msg invalid now */
a49aa710 161 crit_exit();
984263bc
MD
162}
163
8aeffa9f
RM
164static int
165rts_filter(struct mbuf *m, const struct sockproto *proto,
166 const struct rawcb *rp)
167{
168 const struct routecb *rop = (const struct routecb *)rp;
169 const struct rt_msghdr *rtm;
170
171 KKASSERT(m != NULL);
172 KKASSERT(proto != NULL);
173 KKASSERT(rp != NULL);
174
175 /* Wrong family for this socket. */
176 if (proto->sp_family != PF_ROUTE)
177 return ENOPROTOOPT;
178
179 /* If no filter set, just return. */
180 if (rop->rocb_msgfilter == 0)
181 return 0;
182
183 /* Ensure we can access rtm_type */
184 if (m->m_len <
185 offsetof(struct rt_msghdr, rtm_type) + sizeof(rtm->rtm_type))
186 return EINVAL;
187
188 rtm = mtod(m, const struct rt_msghdr *);
189 /* If the rtm type is filtered out, return a positive. */
190 if (!(rop->rocb_msgfilter & ROUTE_FILTER(rtm->rtm_type)))
191 return EEXIST;
192
193 /* Passed the filter. */
194 return 0;
195}
196
197
984263bc
MD
198/* pru_accept is EOPNOTSUPP */
199
002c1265
MD
200static void
201rts_attach(netmsg_t msg)
984263bc 202{
002c1265
MD
203 struct socket *so = msg->base.nm_so;
204 struct pru_attach_info *ai = msg->attach.nm_ai;
984263bc 205 struct rawcb *rp;
8aeffa9f 206 struct routecb *rop;
002c1265 207 int proto = msg->attach.nm_proto;
a49aa710 208 int error;
984263bc 209
002c1265
MD
210 crit_enter();
211 if (sotorawcb(so) != NULL) {
212 error = EISCONN;
213 goto done;
214 }
f23061d4 215
8aeffa9f
RM
216 rop = kmalloc(sizeof *rop, M_PCB, M_WAITOK | M_ZERO);
217 rp = &rop->rocb_rcb;
984263bc
MD
218
219 /*
a49aa710 220 * The critical section is necessary to block protocols from sending
984263bc
MD
221 * error notifications (like RTM_REDIRECT or RTM_LOSING) while
222 * this PCB is extant but incompletely initialized.
223 * Probably we should try to do more of this work beforehand and
a49aa710 224 * eliminate the critical section.
984263bc 225 */
ef87f48d 226 so->so_pcb = rp;
6cef7136 227 soreference(so); /* so_pcb assignment */
e4700d00 228 error = raw_attach(so, proto, ai->sb_rlimit);
984263bc
MD
229 rp = sotorawcb(so);
230 if (error) {
8aeffa9f 231 kfree(rop, M_PCB);
002c1265 232 goto done;
984263bc
MD
233 }
234 switch(rp->rcb_proto.sp_protocol) {
235 case AF_INET:
236 route_cb.ip_count++;
237 break;
238 case AF_INET6:
239 route_cb.ip6_count++;
240 break;
984263bc
MD
241 }
242 rp->rcb_faddr = &route_src;
8aeffa9f 243 rp->rcb_filter = rts_filter;
984263bc
MD
244 route_cb.any_count++;
245 soisconnected(so);
246 so->so_options |= SO_USELOOPBACK;
002c1265
MD
247 error = 0;
248done:
a49aa710 249 crit_exit();
002c1265 250 lwkt_replymsg(&msg->lmsg, error);
984263bc
MD
251}
252
002c1265
MD
253static void
254rts_bind(netmsg_t msg)
984263bc 255{
a49aa710 256 crit_enter();
002c1265
MD
257 raw_usrreqs.pru_bind(msg); /* xxx just EINVAL */
258 /* msg invalid now */
a49aa710 259 crit_exit();
984263bc
MD
260}
261
002c1265
MD
262static void
263rts_connect(netmsg_t msg)
984263bc 264{
a49aa710 265 crit_enter();
002c1265
MD
266 raw_usrreqs.pru_connect(msg); /* XXX just EINVAL */
267 /* msg invalid now */
a49aa710 268 crit_exit();
984263bc
MD
269}
270
271/* pru_connect2 is EOPNOTSUPP */
272/* pru_control is EOPNOTSUPP */
273
002c1265
MD
274static void
275rts_detach(netmsg_t msg)
984263bc 276{
002c1265 277 struct socket *so = msg->base.nm_so;
984263bc 278 struct rawcb *rp = sotorawcb(so);
984263bc 279
a49aa710 280 crit_enter();
ef87f48d 281 if (rp != NULL) {
984263bc
MD
282 switch(rp->rcb_proto.sp_protocol) {
283 case AF_INET:
284 route_cb.ip_count--;
285 break;
286 case AF_INET6:
287 route_cb.ip6_count--;
288 break;
984263bc
MD
289 }
290 route_cb.any_count--;
291 }
002c1265
MD
292 raw_usrreqs.pru_detach(msg);
293 /* msg invalid now */
a49aa710 294 crit_exit();
984263bc
MD
295}
296
002c1265
MD
297static void
298rts_disconnect(netmsg_t msg)
984263bc 299{
a49aa710 300 crit_enter();
002c1265
MD
301 raw_usrreqs.pru_disconnect(msg);
302 /* msg invalid now */
a49aa710 303 crit_exit();
984263bc
MD
304}
305
306/* pru_listen is EOPNOTSUPP */
307
002c1265
MD
308static void
309rts_peeraddr(netmsg_t msg)
984263bc 310{
a49aa710 311 crit_enter();
002c1265
MD
312 raw_usrreqs.pru_peeraddr(msg);
313 /* msg invalid now */
a49aa710 314 crit_exit();
984263bc
MD
315}
316
317/* pru_rcvd is EOPNOTSUPP */
318/* pru_rcvoob is EOPNOTSUPP */
319
002c1265
MD
320static void
321rts_send(netmsg_t msg)
984263bc 322{
a49aa710 323 crit_enter();
002c1265
MD
324 raw_usrreqs.pru_send(msg);
325 /* msg invalid now */
a49aa710 326 crit_exit();
984263bc
MD
327}
328
329/* pru_sense is null */
330
002c1265
MD
331static void
332rts_shutdown(netmsg_t msg)
984263bc 333{
a49aa710 334 crit_enter();
002c1265
MD
335 raw_usrreqs.pru_shutdown(msg);
336 /* msg invalid now */
a49aa710 337 crit_exit();
984263bc
MD
338}
339
002c1265
MD
340static void
341rts_sockaddr(netmsg_t msg)
984263bc 342{
a49aa710 343 crit_enter();
002c1265
MD
344 raw_usrreqs.pru_sockaddr(msg);
345 /* msg invalid now */
a49aa710 346 crit_exit();
984263bc
MD
347}
348
349static struct pr_usrreqs route_usrreqs = {
fa5e758c 350 .pru_abort = rts_abort,
002c1265 351 .pru_accept = pr_generic_notsupp,
fa5e758c
MD
352 .pru_attach = rts_attach,
353 .pru_bind = rts_bind,
354 .pru_connect = rts_connect,
002c1265
MD
355 .pru_connect2 = pr_generic_notsupp,
356 .pru_control = pr_generic_notsupp,
fa5e758c
MD
357 .pru_detach = rts_detach,
358 .pru_disconnect = rts_disconnect,
002c1265 359 .pru_listen = pr_generic_notsupp,
fa5e758c 360 .pru_peeraddr = rts_peeraddr,
002c1265
MD
361 .pru_rcvd = pr_generic_notsupp,
362 .pru_rcvoob = pr_generic_notsupp,
fa5e758c
MD
363 .pru_send = rts_send,
364 .pru_sense = pru_sense_null,
365 .pru_shutdown = rts_shutdown,
366 .pru_sockaddr = rts_sockaddr,
367 .pru_sosend = sosend,
8b5c39bb 368 .pru_soreceive = soreceive
984263bc
MD
369};
370
590b8cd4
JH
371static __inline sa_family_t
372familyof(struct sockaddr *sa)
373{
374 return (sa != NULL ? sa->sa_family : 0);
375}
376
47db7f9b
MD
377/*
378 * Routing socket input function. The packet must be serialized onto cpu 0.
379 * We use the cpu0_soport() netisr processing loop to handle it.
380 *
381 * This looks messy but it means that anyone, including interrupt code,
382 * can send a message to the routing socket.
383 */
590b8cd4 384static void
002c1265 385rts_input_handler(netmsg_t msg)
590b8cd4
JH
386{
387 static const struct sockaddr route_dst = { 2, PF_ROUTE, };
47db7f9b 388 struct sockproto route_proto;
002c1265 389 struct netmsg_packet *pmsg = &msg->packet;
47db7f9b
MD
390 struct mbuf *m;
391 sa_family_t family;
d16fa201 392 struct rawcb *skip;
47db7f9b 393
002c1265 394 family = pmsg->base.lmsg.u.ms_result;
47db7f9b
MD
395 route_proto.sp_family = PF_ROUTE;
396 route_proto.sp_protocol = family;
590b8cd4 397
d16fa201
SZ
398 m = pmsg->nm_packet;
399 M_ASSERTPKTHDR(m);
400
401 skip = m->m_pkthdr.header;
402 m->m_pkthdr.header = NULL;
403
404 raw_input(m, &route_proto, &route_src, &route_dst, skip);
590b8cd4
JH
405}
406
47db7f9b 407static void
d16fa201 408rts_input_skip(struct mbuf *m, sa_family_t family, struct rawcb *skip)
47db7f9b
MD
409{
410 struct netmsg_packet *pmsg;
411 lwkt_port_t port;
412
d16fa201
SZ
413 M_ASSERTPKTHDR(m);
414
ec7f7fc8 415 port = netisr_cpuport(0); /* XXX same as for routing socket */
47db7f9b 416 pmsg = &m->m_hdr.mh_netmsg;
002c1265 417 netmsg_init(&pmsg->base, NULL, &netisr_apanic_rport,
47db7f9b
MD
418 0, rts_input_handler);
419 pmsg->nm_packet = m;
002c1265 420 pmsg->base.lmsg.u.ms_result = family;
d16fa201 421 m->m_pkthdr.header = skip; /* XXX steal field in pkthdr */
002c1265 422 lwkt_sendmsg(port, &pmsg->base.lmsg);
47db7f9b
MD
423}
424
d16fa201
SZ
425static __inline void
426rts_input(struct mbuf *m, sa_family_t family)
427{
428 rts_input_skip(m, family, NULL);
429}
430
8aeffa9f
RM
431static void
432route_ctloutput(netmsg_t msg)
433{
434 struct socket *so = msg->ctloutput.base.nm_so;
435 struct sockopt *sopt = msg->ctloutput.nm_sopt;
436 struct routecb *rop = sotoroutecb(so);
437 int error;
438 unsigned int msgfilter;
439
440 if (sopt->sopt_level != AF_ROUTE) {
441 error = EINVAL;
442 goto out;
443 }
444
445 error = 0;
446
447 switch (sopt->sopt_dir) {
448 case SOPT_SET:
449 switch (sopt->sopt_name) {
450 case ROUTE_MSGFILTER:
451 error = soopt_to_kbuf(sopt, &msgfilter,
452 sizeof(msgfilter), sizeof(msgfilter));
453 if (error == 0)
454 rop->rocb_msgfilter = msgfilter;
455 break;
456 default:
457 error = ENOPROTOOPT;
458 break;
459 }
460 break;
461 case SOPT_GET:
462 switch (sopt->sopt_name) {
463 case ROUTE_MSGFILTER:
464 msgfilter = rop->rocb_msgfilter;
465 soopt_from_kbuf(sopt, &msgfilter, sizeof(msgfilter));
466 break;
467 default:
468 error = ENOPROTOOPT;
469 break;
470 }
471 }
472out:
473 lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
474}
475
476
477
590b8cd4 478static void *
6e6b3e50 479reallocbuf_nofree(void *ptr, size_t len, size_t olen)
590b8cd4
JH
480{
481 void *newptr;
482
efda3bd0 483 newptr = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
590b8cd4
JH
484 if (newptr == NULL)
485 return NULL;
486 bcopy(ptr, newptr, olen);
590b8cd4
JH
487 return (newptr);
488}
489
8e63efec
JH
490/*
491 * Internal helper routine for route_output().
492 */
590b8cd4 493static int
6e6b3e50
SZ
494_fillrtmsg(struct rt_msghdr **prtm, struct rtentry *rt,
495 struct rt_addrinfo *rtinfo)
590b8cd4
JH
496{
497 int msglen;
498 struct rt_msghdr *rtm = *prtm;
499
500 /* Fill in rt_addrinfo for call to rt_msg_buffer(). */
501 rtinfo->rti_dst = rt_key(rt);
502 rtinfo->rti_gateway = rt->rt_gateway;
503 rtinfo->rti_netmask = rt_mask(rt); /* might be NULL */
504 rtinfo->rti_genmask = rt->rt_genmask; /* might be NULL */
505 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
506 if (rt->rt_ifp != NULL) {
507 rtinfo->rti_ifpaddr =
b2632176
SZ
508 TAILQ_FIRST(&rt->rt_ifp->if_addrheads[mycpuid])
509 ->ifa->ifa_addr;
590b8cd4
JH
510 rtinfo->rti_ifaaddr = rt->rt_ifa->ifa_addr;
511 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
512 rtinfo->rti_bcastaddr = rt->rt_ifa->ifa_dstaddr;
513 rtm->rtm_index = rt->rt_ifp->if_index;
514 } else {
515 rtinfo->rti_ifpaddr = NULL;
516 rtinfo->rti_ifaaddr = NULL;
1730f0e1 517 }
9d1f1679
SZ
518 } else if (rt->rt_ifp != NULL) {
519 rtm->rtm_index = rt->rt_ifp->if_index;
590b8cd4
JH
520 }
521
522 msglen = rt_msgsize(rtm->rtm_type, rtinfo);
523 if (rtm->rtm_msglen < msglen) {
6e6b3e50
SZ
524 /* NOTE: Caller will free the old rtm accordingly */
525 rtm = reallocbuf_nofree(rtm, msglen, rtm->rtm_msglen);
590b8cd4
JH
526 if (rtm == NULL)
527 return (ENOBUFS);
528 *prtm = rtm;
529 }
530 rt_msg_buffer(rtm->rtm_type, rtinfo, rtm, msglen);
531
532 rtm->rtm_flags = rt->rt_flags;
533 rtm->rtm_rmx = rt->rt_rmx;
534 rtm->rtm_addrs = rtinfo->rti_addrs;
535
536 return (0);
537}
538
6e6b3e50
SZ
539struct rtm_arg {
540 struct rt_msghdr *bak_rtm;
541 struct rt_msghdr *new_rtm;
542};
543
544static int
545fillrtmsg(struct rtm_arg *arg, struct rtentry *rt,
546 struct rt_addrinfo *rtinfo)
547{
548 struct rt_msghdr *rtm = arg->new_rtm;
549 int error;
550
551 error = _fillrtmsg(&rtm, rt, rtinfo);
552 if (!error) {
553 if (arg->new_rtm != rtm) {
554 /*
555 * _fillrtmsg() just allocated a new rtm;
556 * if the previously allocated rtm is not
557 * the backing rtm, it should be freed.
558 */
559 if (arg->new_rtm != arg->bak_rtm)
560 kfree(arg->new_rtm, M_RTABLE);
561 arg->new_rtm = rtm;
562 }
563 }
564 return error;
565}
566
ecdefdda
MD
567static void route_output_add_callback(int, int, struct rt_addrinfo *,
568 struct rtentry *, void *);
569static void route_output_delete_callback(int, int, struct rt_addrinfo *,
570 struct rtentry *, void *);
00104f14 571static int route_output_get_callback(int, struct rt_addrinfo *,
b5e01dd3 572 struct rtentry *, void *, int);
2c62ae3b 573static int route_output_change_callback(int, struct rt_addrinfo *,
b5e01dd3 574 struct rtentry *, void *, int);
ae2a5ccd 575static int route_output_lock_callback(int, struct rt_addrinfo *,
b5e01dd3 576 struct rtentry *, void *, int);
ecdefdda 577
984263bc
MD
578/*ARGSUSED*/
579static int
deffea2e 580route_output(struct mbuf *m, struct socket *so, ...)
984263bc 581{
6e6b3e50 582 struct rtm_arg arg;
2e9572df 583 struct rt_msghdr *rtm = NULL;
f23061d4 584 struct rawcb *rp = NULL;
deffea2e 585 struct pr_output_info *oi;
590b8cd4 586 struct rt_addrinfo rtinfo;
a8c218b2 587 sa_family_t family;
ef87f48d 588 int len, error = 0;
deffea2e
JS
589 __va_list ap;
590
1cfcc9b6
SZ
591 M_ASSERTPKTHDR(m);
592
deffea2e
JS
593 __va_start(ap, so);
594 oi = __va_arg(ap, struct pr_output_info *);
595 __va_end(ap);
984263bc 596
a8c218b2
SZ
597 family = familyof(NULL);
598
ef87f48d 599#define gotoerr(e) { error = e; goto flush;}
590b8cd4
JH
600
601 if (m == NULL ||
602 (m->m_len < sizeof(long) &&
603 (m = m_pullup(m, sizeof(long))) == NULL))
984263bc 604 return (ENOBUFS);
984263bc 605 len = m->m_pkthdr.len;
590b8cd4 606 if (len < sizeof(struct rt_msghdr) ||
a8c218b2 607 len != mtod(m, struct rt_msghdr *)->rtm_msglen)
ef87f48d 608 gotoerr(EINVAL);
a8c218b2 609
efda3bd0 610 rtm = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
a8c218b2 611 if (rtm == NULL)
ef87f48d 612 gotoerr(ENOBUFS);
a8c218b2 613
984263bc 614 m_copydata(m, 0, len, (caddr_t)rtm);
a8c218b2 615 if (rtm->rtm_version != RTM_VERSION)
ef87f48d 616 gotoerr(EPROTONOSUPPORT);
a8c218b2 617
47e78ae8 618 rtm->rtm_pid = oi->p_pid;
590b8cd4
JH
619 bzero(&rtinfo, sizeof(struct rt_addrinfo));
620 rtinfo.rti_addrs = rtm->rtm_addrs;
a8c218b2 621 if (rt_xaddrs((char *)(rtm + 1), (char *)rtm + len, &rtinfo) != 0)
ef87f48d 622 gotoerr(EINVAL);
a8c218b2 623
590b8cd4
JH
624 rtinfo.rti_flags = rtm->rtm_flags;
625 if (rtinfo.rti_dst == NULL || rtinfo.rti_dst->sa_family >= AF_MAX ||
626 (rtinfo.rti_gateway && rtinfo.rti_gateway->sa_family >= AF_MAX))
ef87f48d
JH
627 gotoerr(EINVAL);
628
a8c218b2
SZ
629 family = familyof(rtinfo.rti_dst);
630
984263bc
MD
631 /*
632 * Verify that the caller has the appropriate privilege; RTM_GET
633 * is the only operation the non-superuser is allowed.
634 */
02650706
SZ
635 if (rtm->rtm_type != RTM_GET &&
636 priv_check_cred(so->so_cred, PRIV_ROOT, 0) != 0)
ef87f48d 637 gotoerr(EPERM);
984263bc 638
7c09365b 639 if (rtinfo.rti_genmask != NULL) {
04221313
SZ
640 error = rtmask_add_global(rtinfo.rti_genmask,
641 rtm->rtm_type != RTM_GET ?
642 RTREQ_PRIO_HIGH : RTREQ_PRIO_NORM);
7c09365b
SZ
643 if (error)
644 goto flush;
645 }
646
984263bc 647 switch (rtm->rtm_type) {
984263bc 648 case RTM_ADD:
ecdefdda
MD
649 if (rtinfo.rti_gateway == NULL) {
650 error = EINVAL;
651 } else {
04221313
SZ
652 error = rtrequest1_global(RTM_ADD, &rtinfo,
653 route_output_add_callback, rtm, RTREQ_PRIO_HIGH);
984263bc
MD
654 }
655 break;
984263bc 656 case RTM_DELETE:
ecdefdda 657 /*
6e6b3e50
SZ
658 * Backing rtm (bak_rtm) could _not_ be freed during
659 * rtrequest1_global or rtsearch_global, even if the
660 * callback reallocates the rtm due to its size changes,
661 * since rtinfo points to the backing rtm's memory area.
662 * After rtrequest1_global or rtsearch_global returns,
663 * it is safe to free the backing rtm, since rtinfo will
664 * not be used anymore.
665 *
666 * new_rtm will be used to save the new rtm allocated
667 * by rtrequest1_global or rtsearch_global.
ecdefdda 668 */
6e6b3e50
SZ
669 arg.bak_rtm = rtm;
670 arg.new_rtm = rtm;
ecdefdda 671 error = rtrequest1_global(RTM_DELETE, &rtinfo,
04221313 672 route_output_delete_callback, &arg, RTREQ_PRIO_HIGH);
6e6b3e50
SZ
673 rtm = arg.new_rtm;
674 if (rtm != arg.bak_rtm)
675 kfree(arg.bak_rtm, M_RTABLE);
984263bc 676 break;
984263bc 677 case RTM_GET:
6e6b3e50
SZ
678 /* See the comment in RTM_DELETE */
679 arg.bak_rtm = rtm;
680 arg.new_rtm = rtm;
00104f14 681 error = rtsearch_global(RTM_GET, &rtinfo,
04221313
SZ
682 route_output_get_callback, &arg, RTS_NOEXACTMATCH,
683 RTREQ_PRIO_NORM);
6e6b3e50
SZ
684 rtm = arg.new_rtm;
685 if (rtm != arg.bak_rtm)
686 kfree(arg.bak_rtm, M_RTABLE);
ecdefdda
MD
687 break;
688 case RTM_CHANGE:
2c62ae3b 689 error = rtsearch_global(RTM_CHANGE, &rtinfo,
04221313
SZ
690 route_output_change_callback, rtm, RTS_EXACTMATCH,
691 RTREQ_PRIO_HIGH);
ecdefdda
MD
692 break;
693 case RTM_LOCK:
ae2a5ccd 694 error = rtsearch_global(RTM_LOCK, &rtinfo,
04221313
SZ
695 route_output_lock_callback, rtm, RTS_EXACTMATCH,
696 RTREQ_PRIO_HIGH);
590b8cd4 697 break;
984263bc 698 default:
ecdefdda
MD
699 error = EOPNOTSUPP;
700 break;
984263bc 701 }
984263bc 702flush:
590b8cd4
JH
703 if (rtm != NULL) {
704 if (error != 0)
984263bc
MD
705 rtm->rtm_errno = error;
706 else
707 rtm->rtm_flags |= RTF_DONE;
708 }
ecdefdda 709
984263bc
MD
710 /*
711 * Check to see if we don't want our own messages.
712 */
ef87f48d 713 if (!(so->so_options & SO_USELOOPBACK)) {
984263bc 714 if (route_cb.any_count <= 1) {
590b8cd4 715 if (rtm != NULL)
efda3bd0 716 kfree(rtm, M_RTABLE);
984263bc
MD
717 m_freem(m);
718 return (error);
719 }
720 /* There is another listener, so construct message */
721 rp = sotorawcb(so);
722 }
590b8cd4 723 if (rtm != NULL) {
984263bc
MD
724 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
725 if (m->m_pkthdr.len < rtm->rtm_msglen) {
726 m_freem(m);
727 m = NULL;
728 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
729 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
efda3bd0 730 kfree(rtm, M_RTABLE);
984263bc 731 }
ef87f48d 732 if (m != NULL)
a8c218b2 733 rts_input_skip(m, family, rp);
984263bc
MD
734 return (error);
735}
736
ecdefdda
MD
737static void
738route_output_add_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
739 struct rtentry *rt, void *arg)
740{
741 struct rt_msghdr *rtm = arg;
742
743 if (error == 0 && rt != NULL) {
744 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
745 &rt->rt_rmx);
746 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
747 rt->rt_rmx.rmx_locks |=
748 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
ac0f13c5
SZ
749 if (rtinfo->rti_genmask != NULL) {
750 rt->rt_genmask = rtmask_purelookup(rtinfo->rti_genmask);
751 if (rt->rt_genmask == NULL) {
752 /*
753 * This should not happen, since we
754 * have already installed genmask
755 * on each CPU before we reach here.
756 */
757 panic("genmask is gone!?");
758 }
759 } else {
760 rt->rt_genmask = NULL;
761 }
31f89d97 762 rtm->rtm_index = rt->rt_ifp->if_index;
ecdefdda
MD
763 }
764}
765
766static void
767route_output_delete_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
768 struct rtentry *rt, void *arg)
769{
ecdefdda
MD
770 if (error == 0 && rt) {
771 ++rt->rt_refcnt;
6e6b3e50 772 if (fillrtmsg(arg, rt, rtinfo) != 0) {
ecdefdda
MD
773 error = ENOBUFS;
774 /* XXX no way to return the error */
775 }
776 --rt->rt_refcnt;
777 }
6e6b3e50
SZ
778 if (rt && rt->rt_refcnt == 0) {
779 ++rt->rt_refcnt;
780 rtfree(rt);
781 }
ecdefdda
MD
782}
783
00104f14
SZ
784static int
785route_output_get_callback(int cmd, struct rt_addrinfo *rtinfo,
b5e01dd3 786 struct rtentry *rt, void *arg, int found_cnt)
00104f14 787{
00104f14
SZ
788 int error, found = 0;
789
790 if (((rtinfo->rti_flags ^ rt->rt_flags) & RTF_HOST) == 0)
791 found = 1;
792
6e6b3e50 793 error = fillrtmsg(arg, rt, rtinfo);
00104f14
SZ
794 if (!error && found) {
795 /* Got the exact match, we could return now! */
796 error = EJUSTRETURN;
797 }
798 return error;
799}
800
2c62ae3b
SZ
801static int
802route_output_change_callback(int cmd, struct rt_addrinfo *rtinfo,
b5e01dd3 803 struct rtentry *rt, void *arg, int found_cnt)
ecdefdda
MD
804{
805 struct rt_msghdr *rtm = arg;
806 struct ifaddr *ifa;
2c62ae3b 807 int error = 0;
ecdefdda
MD
808
809 /*
810 * new gateway could require new ifaddr, ifp;
811 * flags may also be different; ifp may be specified
812 * by ll sockaddr when protocol address is ambiguous
813 */
814 if (((rt->rt_flags & RTF_GATEWAY) && rtinfo->rti_gateway != NULL) ||
fb41af81
SZ
815 rtinfo->rti_ifpaddr != NULL ||
816 (rtinfo->rti_ifaaddr != NULL &&
817 !sa_equal(rtinfo->rti_ifaaddr, rt->rt_ifa->ifa_addr))) {
ecdefdda
MD
818 error = rt_getifa(rtinfo);
819 if (error != 0)
820 goto done;
821 }
822 if (rtinfo->rti_gateway != NULL) {
b5e01dd3
SZ
823 /*
824 * We only need to generate rtmsg upon the
825 * first route to be changed.
826 */
5772e17c 827 error = rt_setgate(rt, rt_key(rt), rtinfo->rti_gateway);
ecdefdda
MD
828 if (error != 0)
829 goto done;
830 }
831 if ((ifa = rtinfo->rti_ifa) != NULL) {
832 struct ifaddr *oifa = rt->rt_ifa;
833
834 if (oifa != ifa) {
835 if (oifa && oifa->ifa_rtrequest)
3ffea39d 836 oifa->ifa_rtrequest(RTM_DELETE, rt);
ecdefdda
MD
837 IFAFREE(rt->rt_ifa);
838 IFAREF(ifa);
839 rt->rt_ifa = ifa;
840 rt->rt_ifp = rtinfo->rti_ifp;
841 }
842 }
843 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx);
844 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
3ffea39d 845 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt);
ac0f13c5
SZ
846 if (rtinfo->rti_genmask != NULL) {
847 rt->rt_genmask = rtmask_purelookup(rtinfo->rti_genmask);
848 if (rt->rt_genmask == NULL) {
849 /*
850 * This should not happen, since we
851 * have already installed genmask
852 * on each CPU before we reach here.
853 */
ed20d0e3 854 panic("genmask is gone!?");
ac0f13c5
SZ
855 }
856 }
31f89d97 857 rtm->rtm_index = rt->rt_ifp->if_index;
5772e17c
RM
858 if (found_cnt == 1)
859 rt_rtmsg(RTM_CHANGE, rt, rt->rt_ifp, 0);
ecdefdda 860done:
2c62ae3b 861 return error;
ecdefdda
MD
862}
863
ae2a5ccd
SZ
864static int
865route_output_lock_callback(int cmd, struct rt_addrinfo *rtinfo,
b5e01dd3
SZ
866 struct rtentry *rt, void *arg,
867 int found_cnt __unused)
ecdefdda
MD
868{
869 struct rt_msghdr *rtm = arg;
870
871 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
872 rt->rt_rmx.rmx_locks |=
873 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
ae2a5ccd 874 return 0;
ecdefdda
MD
875}
876
984263bc 877static void
ef87f48d 878rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_metrics *out)
984263bc 879{
2e9572df
JH
880#define setmetric(flag, elt) if (which & (flag)) out->elt = in->elt;
881 setmetric(RTV_RPIPE, rmx_recvpipe);
882 setmetric(RTV_SPIPE, rmx_sendpipe);
883 setmetric(RTV_SSTHRESH, rmx_ssthresh);
884 setmetric(RTV_RTT, rmx_rtt);
885 setmetric(RTV_RTTVAR, rmx_rttvar);
886 setmetric(RTV_HOPCOUNT, rmx_hopcount);
887 setmetric(RTV_MTU, rmx_mtu);
888 setmetric(RTV_EXPIRE, rmx_expire);
8ec89e60 889 setmetric(RTV_MSL, rmx_msl);
bf522a91
SZ
890 setmetric(RTV_IWMAXSEGS, rmx_iwmaxsegs);
891 setmetric(RTV_IWCAPSEGS, rmx_iwcapsegs);
2e9572df 892#undef setmetric
984263bc
MD
893}
894
984263bc
MD
895/*
896 * Extract the addresses of the passed sockaddrs.
897 * Do a little sanity checking so as to avoid bad memory references.
898 * This data is derived straight from userland.
899 */
900static int
ef87f48d 901rt_xaddrs(char *cp, char *cplim, struct rt_addrinfo *rtinfo)
984263bc 902{
82ed7fc2
RG
903 struct sockaddr *sa;
904 int i;
984263bc
MD
905
906 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
907 if ((rtinfo->rti_addrs & (1 << i)) == 0)
908 continue;
909 sa = (struct sockaddr *)cp;
910 /*
911 * It won't fit.
912 */
0c3c561c 913 if ((cp + sa->sa_len) > cplim) {
984263bc
MD
914 return (EINVAL);
915 }
916
917 /*
ef87f48d 918 * There are no more... Quit now.
984263bc 919 * If there are more bits, they are in error.
ef87f48d 920 * I've seen this. route(1) can evidently generate these.
984263bc 921 * This causes kernel to core dump.
ef87f48d 922 * For compatibility, if we see this, point to a safe address.
984263bc
MD
923 */
924 if (sa->sa_len == 0) {
590b8cd4
JH
925 static struct sockaddr sa_zero = {
926 sizeof sa_zero, AF_INET,
927 };
928
984263bc 929 rtinfo->rti_info[i] = &sa_zero;
9b42cabe 930 kprintf("rtsock: received more addr bits than sockaddrs.\n");
984263bc
MD
931 return (0); /* should be EINVAL but for compat */
932 }
933
ef87f48d 934 /* Accept the sockaddr. */
984263bc 935 rtinfo->rti_info[i] = sa;
4ff4d99f 936 cp += RT_ROUNDUP(sa->sa_len);
984263bc
MD
937 }
938 return (0);
939}
940
590b8cd4
JH
941static int
942rt_msghdrsize(int type)
984263bc 943{
984263bc 944 switch (type) {
984263bc
MD
945 case RTM_DELADDR:
946 case RTM_NEWADDR:
590b8cd4 947 return sizeof(struct ifa_msghdr);
984263bc
MD
948 case RTM_DELMADDR:
949 case RTM_NEWMADDR:
590b8cd4 950 return sizeof(struct ifma_msghdr);
984263bc 951 case RTM_IFINFO:
590b8cd4 952 return sizeof(struct if_msghdr);
984263bc 953 case RTM_IFANNOUNCE:
841ab66c 954 case RTM_IEEE80211:
590b8cd4 955 return sizeof(struct if_announcemsghdr);
984263bc 956 default:
590b8cd4 957 return sizeof(struct rt_msghdr);
984263bc 958 }
590b8cd4
JH
959}
960
961static int
c3b2a749 962rt_msgsize(int type, const struct rt_addrinfo *rtinfo)
590b8cd4
JH
963{
964 int len, i;
965
966 len = rt_msghdrsize(type);
967 for (i = 0; i < RTAX_MAX; i++) {
968 if (rtinfo->rti_info[i] != NULL)
4ff4d99f 969 len += RT_ROUNDUP(rtinfo->rti_info[i]->sa_len);
984263bc 970 }
590b8cd4
JH
971 len = ALIGN(len);
972 return len;
973}
974
975/*
976 * Build a routing message in a buffer.
977 * Copy the addresses in the rtinfo->rti_info[] sockaddr array
978 * to the end of the buffer after the message header.
979 *
980 * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[].
981 * This side-effect can be avoided if we reorder the addrs bitmask field in all
982 * the route messages to line up so we can set it here instead of back in the
983 * calling routine.
984 */
985static void
986rt_msg_buffer(int type, struct rt_addrinfo *rtinfo, void *buf, int msglen)
987{
988 struct rt_msghdr *rtm;
989 char *cp;
990 int dlen, i;
991
992 rtm = (struct rt_msghdr *) buf;
993 rtm->rtm_version = RTM_VERSION;
994 rtm->rtm_type = type;
995 rtm->rtm_msglen = msglen;
996
997 cp = (char *)buf + rt_msghdrsize(type);
998 rtinfo->rti_addrs = 0;
984263bc 999 for (i = 0; i < RTAX_MAX; i++) {
590b8cd4
JH
1000 struct sockaddr *sa;
1001
984263bc
MD
1002 if ((sa = rtinfo->rti_info[i]) == NULL)
1003 continue;
1004 rtinfo->rti_addrs |= (1 << i);
4ff4d99f 1005 dlen = RT_ROUNDUP(sa->sa_len);
590b8cd4
JH
1006 bcopy(sa, cp, dlen);
1007 cp += dlen;
984263bc 1008 }
984263bc
MD
1009}
1010
590b8cd4
JH
1011/*
1012 * Build a routing message in a mbuf chain.
1013 * Copy the addresses in the rtinfo->rti_info[] sockaddr array
1014 * to the end of the mbuf after the message header.
1015 *
1016 * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[].
1017 * This side-effect can be avoided if we reorder the addrs bitmask field in all
1018 * the route messages to line up so we can set it here instead of back in the
1019 * calling routine.
1020 */
1021static struct mbuf *
1022rt_msg_mbuf(int type, struct rt_addrinfo *rtinfo)
984263bc 1023{
590b8cd4
JH
1024 struct mbuf *m;
1025 struct rt_msghdr *rtm;
1026 int hlen, len;
82ed7fc2 1027 int i;
984263bc 1028
590b8cd4
JH
1029 hlen = rt_msghdrsize(type);
1030 KASSERT(hlen <= MCLBYTES, ("rt_msg_mbuf: hlen %d doesn't fit", hlen));
984263bc 1031
b5523eac 1032 m = m_getl(hlen, M_NOWAIT, MT_DATA, M_PKTHDR, NULL);
590b8cd4
JH
1033 if (m == NULL)
1034 return (NULL);
e9fa4b60 1035 mbuftrackid(m, 32);
590b8cd4
JH
1036 m->m_pkthdr.len = m->m_len = hlen;
1037 m->m_pkthdr.rcvif = NULL;
1038 rtinfo->rti_addrs = 0;
1039 len = hlen;
984263bc 1040 for (i = 0; i < RTAX_MAX; i++) {
82ed7fc2 1041 struct sockaddr *sa;
590b8cd4 1042 int dlen;
984263bc 1043
ef87f48d 1044 if ((sa = rtinfo->rti_info[i]) == NULL)
984263bc
MD
1045 continue;
1046 rtinfo->rti_addrs |= (1 << i);
4ff4d99f 1047 dlen = RT_ROUNDUP(sa->sa_len);
590b8cd4 1048 m_copyback(m, len, dlen, (caddr_t)sa); /* can grow mbuf chain */
984263bc
MD
1049 len += dlen;
1050 }
590b8cd4
JH
1051 if (m->m_pkthdr.len != len) { /* one of the m_copyback() calls failed */
1052 m_freem(m);
1053 return (NULL);
984263bc 1054 }
590b8cd4
JH
1055 rtm = mtod(m, struct rt_msghdr *);
1056 bzero(rtm, hlen);
1057 rtm->rtm_msglen = len;
1058 rtm->rtm_version = RTM_VERSION;
1059 rtm->rtm_type = type;
1060 return (m);
984263bc
MD
1061}
1062
1063/*
1064 * This routine is called to generate a message from the routing
f23061d4 1065 * socket indicating that a redirect has occurred, a routing lookup
984263bc
MD
1066 * has failed, or that a protocol has detected timeouts to a particular
1067 * destination.
1068 */
1069void
f23061d4 1070rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
984263bc 1071{
0c3c561c 1072 struct sockaddr *dst = rtinfo->rti_info[RTAX_DST];
82ed7fc2
RG
1073 struct rt_msghdr *rtm;
1074 struct mbuf *m;
984263bc
MD
1075
1076 if (route_cb.any_count == 0)
1077 return;
590b8cd4 1078 m = rt_msg_mbuf(type, rtinfo);
ef87f48d 1079 if (m == NULL)
984263bc
MD
1080 return;
1081 rtm = mtod(m, struct rt_msghdr *);
1082 rtm->rtm_flags = RTF_DONE | flags;
1083 rtm->rtm_errno = error;
1084 rtm->rtm_addrs = rtinfo->rti_addrs;
590b8cd4 1085 rts_input(m, familyof(dst));
984263bc
MD
1086}
1087
f3ed2586
JH
1088void
1089rt_dstmsg(int type, struct sockaddr *dst, int error)
1090{
1091 struct rt_msghdr *rtm;
1092 struct rt_addrinfo addrs;
1093 struct mbuf *m;
1094
1095 if (route_cb.any_count == 0)
1096 return;
1097 bzero(&addrs, sizeof(struct rt_addrinfo));
1098 addrs.rti_info[RTAX_DST] = dst;
590b8cd4 1099 m = rt_msg_mbuf(type, &addrs);
f3ed2586
JH
1100 if (m == NULL)
1101 return;
1102 rtm = mtod(m, struct rt_msghdr *);
1103 rtm->rtm_flags = RTF_DONE;
1104 rtm->rtm_errno = error;
1105 rtm->rtm_addrs = addrs.rti_addrs;
590b8cd4 1106 rts_input(m, familyof(dst));
f3ed2586
JH
1107}
1108
984263bc
MD
1109/*
1110 * This routine is called to generate a message from the routing
1111 * socket indicating that the status of a network interface has changed.
1112 */
1113void
0c3c561c 1114rt_ifmsg(struct ifnet *ifp)
984263bc 1115{
82ed7fc2 1116 struct if_msghdr *ifm;
984263bc 1117 struct mbuf *m;
590b8cd4 1118 struct rt_addrinfo rtinfo;
984263bc
MD
1119
1120 if (route_cb.any_count == 0)
1121 return;
590b8cd4
JH
1122 bzero(&rtinfo, sizeof(struct rt_addrinfo));
1123 m = rt_msg_mbuf(RTM_IFINFO, &rtinfo);
ef87f48d 1124 if (m == NULL)
984263bc
MD
1125 return;
1126 ifm = mtod(m, struct if_msghdr *);
1127 ifm->ifm_index = ifp->if_index;
9c095379 1128 ifm->ifm_flags = ifp->if_flags;
984263bc 1129 ifm->ifm_data = ifp->if_data;
590b8cd4
JH
1130 ifm->ifm_addrs = 0;
1131 rts_input(m, 0);
984263bc
MD
1132}
1133
372316d9
JH
1134static void
1135rt_ifamsg(int cmd, struct ifaddr *ifa)
1136{
1137 struct ifa_msghdr *ifam;
590b8cd4 1138 struct rt_addrinfo rtinfo;
372316d9 1139 struct mbuf *m;
372316d9
JH
1140 struct ifnet *ifp = ifa->ifa_ifp;
1141
590b8cd4
JH
1142 bzero(&rtinfo, sizeof(struct rt_addrinfo));
1143 rtinfo.rti_ifaaddr = ifa->ifa_addr;
b2632176
SZ
1144 rtinfo.rti_ifpaddr =
1145 TAILQ_FIRST(&ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
590b8cd4
JH
1146 rtinfo.rti_netmask = ifa->ifa_netmask;
1147 rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
f23061d4 1148
590b8cd4 1149 m = rt_msg_mbuf(cmd, &rtinfo);
f23061d4 1150 if (m == NULL)
372316d9 1151 return;
f23061d4 1152
372316d9
JH
1153 ifam = mtod(m, struct ifa_msghdr *);
1154 ifam->ifam_index = ifp->if_index;
372316d9 1155 ifam->ifam_flags = ifa->ifa_flags;
590b8cd4 1156 ifam->ifam_addrs = rtinfo.rti_addrs;
43a37315
RM
1157 ifam->ifam_addrflags = if_addrflags(ifa);
1158 ifam->ifam_metric = ifa->ifa_metric;
f23061d4 1159
590b8cd4 1160 rts_input(m, familyof(ifa->ifa_addr));
372316d9
JH
1161}
1162
f3ed2586
JH
1163void
1164rt_rtmsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int error)
372316d9
JH
1165{
1166 struct rt_msghdr *rtm;
590b8cd4 1167 struct rt_addrinfo rtinfo;
372316d9 1168 struct mbuf *m;
f3ed2586 1169 struct sockaddr *dst;
372316d9
JH
1170
1171 if (rt == NULL)
1172 return;
f23061d4 1173
590b8cd4
JH
1174 bzero(&rtinfo, sizeof(struct rt_addrinfo));
1175 rtinfo.rti_dst = dst = rt_key(rt);
1176 rtinfo.rti_gateway = rt->rt_gateway;
1177 rtinfo.rti_netmask = rt_mask(rt);
b2632176
SZ
1178 if (ifp != NULL) {
1179 rtinfo.rti_ifpaddr =
1180 TAILQ_FIRST(&ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
1181 }
5772e17c
RM
1182 if (rt->rt_ifa != NULL)
1183 rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
f23061d4 1184
590b8cd4 1185 m = rt_msg_mbuf(cmd, &rtinfo);
f23061d4 1186 if (m == NULL)
372316d9 1187 return;
f23061d4 1188
372316d9 1189 rtm = mtod(m, struct rt_msghdr *);
f3ed2586
JH
1190 if (ifp != NULL)
1191 rtm->rtm_index = ifp->if_index;
372316d9
JH
1192 rtm->rtm_flags |= rt->rt_flags;
1193 rtm->rtm_errno = error;
590b8cd4 1194 rtm->rtm_addrs = rtinfo.rti_addrs;
f23061d4 1195
590b8cd4 1196 rts_input(m, familyof(dst));
372316d9
JH
1197}
1198
984263bc
MD
1199/*
1200 * This is called to generate messages from the routing socket
1201 * indicating a network interface has had addresses associated with it.
1202 * if we ever reverse the logic and replace messages TO the routing
1203 * socket indicate a request to configure interfaces, then it will
1204 * be unnecessary as the routing socket will automatically generate
1205 * copies of it.
1206 */
1207void
0c3c561c 1208rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
984263bc 1209{
984263bc
MD
1210 if (route_cb.any_count == 0)
1211 return;
984263bc 1212
372316d9
JH
1213 if (cmd == RTM_ADD) {
1214 rt_ifamsg(RTM_NEWADDR, ifa);
f3ed2586 1215 rt_rtmsg(RTM_ADD, rt, ifa->ifa_ifp, error);
372316d9
JH
1216 } else {
1217 KASSERT((cmd == RTM_DELETE), ("unknown cmd %d", cmd));
f3ed2586 1218 rt_rtmsg(RTM_DELETE, rt, ifa->ifa_ifp, error);
372316d9 1219 rt_ifamsg(RTM_DELADDR, ifa);
984263bc
MD
1220 }
1221}
1222
1223/*
1224 * This is the analogue to the rt_newaddrmsg which performs the same
1225 * function but for multicast group memberhips. This is easier since
1226 * there is no route state to worry about.
1227 */
1228void
0c3c561c 1229rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma)
984263bc 1230{
590b8cd4 1231 struct rt_addrinfo rtinfo;
ef87f48d 1232 struct mbuf *m = NULL;
984263bc
MD
1233 struct ifnet *ifp = ifma->ifma_ifp;
1234 struct ifma_msghdr *ifmam;
1235
1236 if (route_cb.any_count == 0)
1237 return;
1238
590b8cd4
JH
1239 bzero(&rtinfo, sizeof(struct rt_addrinfo));
1240 rtinfo.rti_ifaaddr = ifma->ifma_addr;
b2632176
SZ
1241 if (ifp != NULL && !TAILQ_EMPTY(&ifp->if_addrheads[mycpuid])) {
1242 rtinfo.rti_ifpaddr =
1243 TAILQ_FIRST(&ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
1244 }
984263bc
MD
1245 /*
1246 * If a link-layer address is present, present it as a ``gateway''
1247 * (similarly to how ARP entries, e.g., are presented).
1248 */
590b8cd4 1249 rtinfo.rti_gateway = ifma->ifma_lladdr;
f23061d4 1250
590b8cd4 1251 m = rt_msg_mbuf(cmd, &rtinfo);
f23061d4 1252 if (m == NULL)
984263bc 1253 return;
f23061d4 1254
984263bc
MD
1255 ifmam = mtod(m, struct ifma_msghdr *);
1256 ifmam->ifmam_index = ifp->if_index;
590b8cd4 1257 ifmam->ifmam_addrs = rtinfo.rti_addrs;
f23061d4 1258
590b8cd4 1259 rts_input(m, familyof(ifma->ifma_addr));
984263bc
MD
1260}
1261
841ab66c
SZ
1262static struct mbuf *
1263rt_makeifannouncemsg(struct ifnet *ifp, int type, int what,
1264 struct rt_addrinfo *info)
984263bc 1265{
590b8cd4 1266 struct if_announcemsghdr *ifan;
841ab66c 1267 struct mbuf *m;
984263bc
MD
1268
1269 if (route_cb.any_count == 0)
841ab66c 1270 return NULL;
f23061d4 1271
841ab66c
SZ
1272 bzero(info, sizeof(*info));
1273 m = rt_msg_mbuf(type, info);
984263bc 1274 if (m == NULL)
841ab66c 1275 return NULL;
f23061d4 1276
984263bc
MD
1277 ifan = mtod(m, struct if_announcemsghdr *);
1278 ifan->ifan_index = ifp->if_index;
5fe66e68 1279 strlcpy(ifan->ifan_name, ifp->if_xname, sizeof ifan->ifan_name);
984263bc 1280 ifan->ifan_what = what;
841ab66c
SZ
1281 return m;
1282}
1283
1284/*
1285 * This is called to generate routing socket messages indicating
1286 * IEEE80211 wireless events.
1287 * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way.
1288 */
1289void
1290rt_ieee80211msg(struct ifnet *ifp, int what, void *data, size_t data_len)
1291{
1292 struct rt_addrinfo info;
1293 struct mbuf *m;
f23061d4 1294
841ab66c
SZ
1295 m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info);
1296 if (m == NULL)
1297 return;
1298
1299 /*
1300 * Append the ieee80211 data. Try to stick it in the
1301 * mbuf containing the ifannounce msg; otherwise allocate
1302 * a new mbuf and append.
1303 *
1304 * NB: we assume m is a single mbuf.
1305 */
1306 if (data_len > M_TRAILINGSPACE(m)) {
b5523eac
SW
1307 /* XXX use m_getb(data_len, M_NOWAIT, MT_DATA, 0); */
1308 struct mbuf *n = m_get(M_NOWAIT, MT_DATA);
841ab66c
SZ
1309 if (n == NULL) {
1310 m_freem(m);
1311 return;
1312 }
e28d8186 1313 KKASSERT(data_len <= M_TRAILINGSPACE(n));
841ab66c
SZ
1314 bcopy(data, mtod(n, void *), data_len);
1315 n->m_len = data_len;
1316 m->m_next = n;
1317 } else if (data_len > 0) {
1318 bcopy(data, mtod(m, u_int8_t *) + m->m_len, data_len);
1319 m->m_len += data_len;
1320 }
e9fa4b60 1321 mbuftrackid(m, 33);
841ab66c
SZ
1322 if (m->m_flags & M_PKTHDR)
1323 m->m_pkthdr.len += data_len;
1324 mtod(m, struct if_announcemsghdr *)->ifan_msglen += data_len;
590b8cd4 1325 rts_input(m, 0);
841ab66c
SZ
1326}
1327
1328/*
1329 * This is called to generate routing socket messages indicating
1330 * network interface arrival and departure.
1331 */
1332void
1333rt_ifannouncemsg(struct ifnet *ifp, int what)
1334{
1335 struct rt_addrinfo addrinfo;
1336 struct mbuf *m;
1337
1338 m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &addrinfo);
1339 if (m != NULL)
1340 rts_input(m, 0);
590b8cd4 1341}
f23061d4 1342
590b8cd4
JH
1343static int
1344resizewalkarg(struct walkarg *w, int len)
1345{
1346 void *newptr;
1347
efda3bd0 1348 newptr = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
590b8cd4
JH
1349 if (newptr == NULL)
1350 return (ENOMEM);
1351 if (w->w_tmem != NULL)
efda3bd0 1352 kfree(w->w_tmem, M_RTABLE);
590b8cd4
JH
1353 w->w_tmem = newptr;
1354 w->w_tmemsize = len;
1355 return (0);
1356}
984263bc 1357
06cd98a8
AHJ
1358static void
1359ifnet_compute_stats(struct ifnet *ifp)
1360{
1361 IFNET_STAT_GET(ifp, ipackets, ifp->if_ipackets);
1362 IFNET_STAT_GET(ifp, ierrors, ifp->if_ierrors);
1363 IFNET_STAT_GET(ifp, opackets, ifp->if_opackets);
1364 IFNET_STAT_GET(ifp, collisions, ifp->if_collisions);
1365 IFNET_STAT_GET(ifp, ibytes, ifp->if_ibytes);
1366 IFNET_STAT_GET(ifp, obytes, ifp->if_obytes);
1367 IFNET_STAT_GET(ifp, imcasts, ifp->if_imcasts);
1368 IFNET_STAT_GET(ifp, omcasts, ifp->if_omcasts);
1369 IFNET_STAT_GET(ifp, iqdrops, ifp->if_iqdrops);
1370 IFNET_STAT_GET(ifp, noproto, ifp->if_noproto);
6de344ba 1371 IFNET_STAT_GET(ifp, oqdrops, ifp->if_oqdrops);
06cd98a8
AHJ
1372}
1373
43a37315
RM
1374static int
1375if_addrflags(const struct ifaddr *ifa)
1376{
1377 switch (ifa->ifa_addr->sa_family) {
1378#ifdef INET6
1379 case AF_INET6:
1380 return ((const struct in6_ifaddr *)ifa)->ia6_flags;
1381#endif
1382 default:
1383 return 0;
1384 }
1385}
1386
590b8cd4
JH
1387static int
1388sysctl_iflist(int af, struct walkarg *w)
984263bc 1389{
82ed7fc2 1390 struct ifnet *ifp;
590b8cd4
JH
1391 struct rt_addrinfo rtinfo;
1392 int msglen, error;
984263bc 1393
590b8cd4 1394 bzero(&rtinfo, sizeof(struct rt_addrinfo));
b4051e25
SZ
1395
1396 ifnet_lock();
1397 TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
9a74b592
SZ
1398 struct ifaddr_container *ifac, *ifac_mark;
1399 struct ifaddr_marker mark;
1400 struct ifaddrhead *head;
b2632176
SZ
1401 struct ifaddr *ifa;
1402
984263bc
MD
1403 if (w->w_arg && w->w_arg != ifp->if_index)
1404 continue;
9a74b592
SZ
1405 head = &ifp->if_addrheads[mycpuid];
1406 /*
1407 * There is no need to reference the first ifaddr
1408 * even if the following resizewalkarg() blocks,
1409 * since the first ifaddr will not be destroyed
1410 * when the ifnet lock is held.
1411 */
1412 ifac = TAILQ_FIRST(head);
b2632176 1413 ifa = ifac->ifa;
590b8cd4
JH
1414 rtinfo.rti_ifpaddr = ifa->ifa_addr;
1415 msglen = rt_msgsize(RTM_IFINFO, &rtinfo);
b4051e25
SZ
1416 if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0) {
1417 ifnet_unlock();
590b8cd4 1418 return (ENOMEM);
b4051e25 1419 }
590b8cd4
JH
1420 rt_msg_buffer(RTM_IFINFO, &rtinfo, w->w_tmem, msglen);
1421 rtinfo.rti_ifpaddr = NULL;
ef87f48d 1422 if (w->w_req != NULL && w->w_tmem != NULL) {
8e63efec 1423 struct if_msghdr *ifm = w->w_tmem;
984263bc 1424
984263bc 1425 ifm->ifm_index = ifp->if_index;
9c095379 1426 ifm->ifm_flags = ifp->if_flags;
06cd98a8 1427 ifnet_compute_stats(ifp);
984263bc 1428 ifm->ifm_data = ifp->if_data;
590b8cd4
JH
1429 ifm->ifm_addrs = rtinfo.rti_addrs;
1430 error = SYSCTL_OUT(w->w_req, ifm, msglen);
b4051e25
SZ
1431 if (error) {
1432 ifnet_unlock();
984263bc 1433 return (error);
b4051e25 1434 }
984263bc 1435 }
9a74b592
SZ
1436 /*
1437 * Add a marker, since SYSCTL_OUT() could block and during
1438 * that period the list could be changed.
1439 */
1440 ifa_marker_init(&mark, ifp);
1441 ifac_mark = &mark.ifac;
1442 TAILQ_INSERT_AFTER(head, ifac, ifac_mark, ifa_link);
1443 while ((ifac = TAILQ_NEXT(ifac_mark, ifa_link)) != NULL) {
1444 TAILQ_REMOVE(head, ifac_mark, ifa_link);
1445 TAILQ_INSERT_AFTER(head, ifac, ifac_mark, ifa_link);
1446
b2632176
SZ
1447 ifa = ifac->ifa;
1448
9a74b592
SZ
1449 /* Ignore marker */
1450 if (ifa->ifa_addr->sa_family == AF_UNSPEC)
1451 continue;
1452
984263bc
MD
1453 if (af && af != ifa->ifa_addr->sa_family)
1454 continue;
590b8cd4 1455 if (curproc->p_ucred->cr_prison &&
87de5057 1456 prison_if(curproc->p_ucred, ifa->ifa_addr))
984263bc 1457 continue;
590b8cd4
JH
1458 rtinfo.rti_ifaaddr = ifa->ifa_addr;
1459 rtinfo.rti_netmask = ifa->ifa_netmask;
1460 rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
1461 msglen = rt_msgsize(RTM_NEWADDR, &rtinfo);
9a74b592
SZ
1462 /*
1463 * Keep a reference on this ifaddr, so that it will
1464 * not be destroyed if the following resizewalkarg()
1465 * blocks.
1466 */
1467 IFAREF(ifa);
590b8cd4 1468 if (w->w_tmemsize < msglen &&
b4051e25 1469 resizewalkarg(w, msglen) != 0) {
9a74b592
SZ
1470 IFAFREE(ifa);
1471 TAILQ_REMOVE(head, ifac_mark, ifa_link);
b4051e25 1472 ifnet_unlock();
590b8cd4 1473 return (ENOMEM);
b4051e25 1474 }
590b8cd4
JH
1475 rt_msg_buffer(RTM_NEWADDR, &rtinfo, w->w_tmem, msglen);
1476 if (w->w_req != NULL) {
8e63efec 1477 struct ifa_msghdr *ifam = w->w_tmem;
984263bc 1478
984263bc
MD
1479 ifam->ifam_index = ifa->ifa_ifp->if_index;
1480 ifam->ifam_flags = ifa->ifa_flags;
590b8cd4 1481 ifam->ifam_addrs = rtinfo.rti_addrs;
43a37315
RM
1482 ifam->ifam_addrflags = if_addrflags(ifa);
1483 ifam->ifam_metric = ifa->ifa_metric;
590b8cd4 1484 error = SYSCTL_OUT(w->w_req, w->w_tmem, msglen);
b4051e25 1485 if (error) {
9a74b592
SZ
1486 IFAFREE(ifa);
1487 TAILQ_REMOVE(head, ifac_mark, ifa_link);
b4051e25 1488 ifnet_unlock();
984263bc 1489 return (error);
b4051e25 1490 }
984263bc 1491 }
9a74b592 1492 IFAFREE(ifa);
984263bc 1493 }
9a74b592 1494 TAILQ_REMOVE(head, ifac_mark, ifa_link);
590b8cd4
JH
1495 rtinfo.rti_netmask = NULL;
1496 rtinfo.rti_ifaaddr = NULL;
1497 rtinfo.rti_bcastaddr = NULL;
984263bc 1498 }
b4051e25 1499 ifnet_unlock();
984263bc
MD
1500 return (0);
1501}
1502
085b1d2a 1503static int
291dd55b 1504rttable_walkarg_create(struct rttable_walkarg *w, int op, int arg)
085b1d2a 1505{
291dd55b
SZ
1506 struct rt_addrinfo rtinfo;
1507 struct sockaddr_storage ss;
1508 int i, msglen;
085b1d2a 1509
291dd55b
SZ
1510 memset(w, 0, sizeof(*w));
1511 w->w_op = op;
1512 w->w_arg = arg;
085b1d2a 1513
291dd55b
SZ
1514 memset(&ss, 0, sizeof(ss));
1515 ss.ss_len = sizeof(ss);
085b1d2a 1516
291dd55b
SZ
1517 memset(&rtinfo, 0, sizeof(rtinfo));
1518 for (i = 0; i < RTAX_MAX; ++i)
1519 rtinfo.rti_info[i] = (struct sockaddr *)&ss;
1520 msglen = rt_msgsize(RTM_GET, &rtinfo);
1521
1522 w->w_bufsz = msglen * RTTABLE_DUMP_MSGCNT_MAX;
1523 w->w_buf = kmalloc(w->w_bufsz, M_TEMP, M_WAITOK | M_NULLOK);
1524 if (w->w_buf == NULL)
1525 return ENOMEM;
1526 return 0;
1527}
1528
1529static void
1530rttable_walkarg_destroy(struct rttable_walkarg *w)
1531{
1532 kfree(w->w_buf, M_TEMP);
1533}
1534
1535static void
1536rttable_entry_rtinfo(struct rt_addrinfo *rtinfo, struct radix_node *rn)
1537{
1538 struct rtentry *rt = (struct rtentry *)rn;
1539
1540 bzero(rtinfo, sizeof(*rtinfo));
1541 rtinfo->rti_dst = rt_key(rt);
1542 rtinfo->rti_gateway = rt->rt_gateway;
1543 rtinfo->rti_netmask = rt_mask(rt);
1544 rtinfo->rti_genmask = rt->rt_genmask;
1545 if (rt->rt_ifp != NULL) {
1546 rtinfo->rti_ifpaddr =
1547 TAILQ_FIRST(&rt->rt_ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
1548 rtinfo->rti_ifaaddr = rt->rt_ifa->ifa_addr;
1549 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
1550 rtinfo->rti_bcastaddr = rt->rt_ifa->ifa_dstaddr;
1551 }
1552}
1553
1554static int
1555rttable_walk_entry(struct radix_node *rn, void *xw)
1556{
1557 struct rttable_walkarg *w = xw;
1558 struct rtentry *rt = (struct rtentry *)rn;
1559 struct rt_addrinfo rtinfo;
1560 struct rt_msghdr *rtm;
1561 boolean_t save = FALSE;
1562 int msglen, w_bufleft;
1563 void *ptr;
1564
1565 rttable_entry_rtinfo(&rtinfo, rn);
1566 msglen = rt_msgsize(RTM_GET, &rtinfo);
1567
1568 w_bufleft = w->w_bufsz - w->w_buflen;
1569
1570 if (rn->rn_dupedkey != NULL) {
1571 struct radix_node *rn1 = rn;
1572 int total_msglen = msglen;
1573
1574 /*
1575 * Make sure that we have enough space left for all
1576 * dupedkeys, since rn_walktree_at always starts
1577 * from the first dupedkey.
1578 */
1579 while ((rn1 = rn1->rn_dupedkey) != NULL) {
1580 struct rt_addrinfo rtinfo1;
1581 int msglen1;
1582
1583 if (rn1->rn_flags & RNF_ROOT)
1584 continue;
1585
1586 rttable_entry_rtinfo(&rtinfo1, rn1);
1587 msglen1 = rt_msgsize(RTM_GET, &rtinfo1);
1588 total_msglen += msglen1;
1589 }
1590
1591 if (total_msglen > w_bufleft) {
1592 if (total_msglen > w->w_bufsz) {
1593 static int logged = 0;
1594
1595 if (!logged) {
1596 kprintf("buffer is too small for "
1597 "all dupedkeys, increase "
1598 "RTTABLE_DUMP_MSGCNT_MAX\n");
1599 logged = 1;
1600 }
1601 return ENOMEM;
1602 }
1603 save = TRUE;
1604 }
1605 } else if (msglen > w_bufleft) {
1606 save = TRUE;
085b1d2a
SZ
1607 }
1608
291dd55b
SZ
1609 if (save) {
1610 /*
1611 * Not enough buffer left; remember the position
1612 * to start from upon next round.
1613 */
1614 KASSERT(msglen <= w->w_bufsz, ("msg too long %d", msglen));
1615
1616 KASSERT(rtinfo.rti_dst->sa_len <= sizeof(w->w_key0),
1617 ("key too long %d", rtinfo.rti_dst->sa_len));
1618 memset(&w->w_key0, 0, sizeof(w->w_key0));
1619 memcpy(&w->w_key0, rtinfo.rti_dst, rtinfo.rti_dst->sa_len);
1620 w->w_key = (const char *)&w->w_key0;
1621
1622 if (rtinfo.rti_netmask != NULL) {
1623 KASSERT(
1624 rtinfo.rti_netmask->sa_len <= sizeof(w->w_mask0),
1625 ("mask too long %d", rtinfo.rti_netmask->sa_len));
1626 memset(&w->w_mask0, 0, sizeof(w->w_mask0));
1627 memcpy(&w->w_mask0, rtinfo.rti_netmask,
1628 rtinfo.rti_netmask->sa_len);
1629 w->w_mask = (const char *)&w->w_mask0;
1630 } else {
1631 w->w_mask = NULL;
1632 }
1633 return EJUSTRETURN;
1634 }
085b1d2a 1635
03d7fd4f
SZ
1636 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
1637 return 0;
1638
291dd55b
SZ
1639 ptr = ((uint8_t *)w->w_buf) + w->w_buflen;
1640 rt_msg_buffer(RTM_GET, &rtinfo, ptr, msglen);
1641
1642 rtm = (struct rt_msghdr *)ptr;
1643 rtm->rtm_flags = rt->rt_flags;
1644 rtm->rtm_use = rt->rt_use;
1645 rtm->rtm_rmx = rt->rt_rmx;
1646 rtm->rtm_index = rt->rt_ifp->if_index;
1647 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
1648 rtm->rtm_addrs = rtinfo.rti_addrs;
1649
1650 w->w_buflen += msglen;
1651
1652 return 0;
1653}
1654
1655static void
1656rttable_walk_dispatch(netmsg_t msg)
1657{
1658 struct netmsg_rttable_walk *nmsg = (struct netmsg_rttable_walk *)msg;
1659 struct radix_node_head *rnh = rt_tables[mycpuid][nmsg->af];
1660 struct rttable_walkarg *w = nmsg->w;
1661 int error;
1662
1663 error = rnh->rnh_walktree_at(rnh, w->w_key, w->w_mask,
1664 rttable_walk_entry, w);
1665 lwkt_replymsg(&nmsg->base.lmsg, error);
1666}
1667
1668static int
1669sysctl_rttable(int af, struct sysctl_req *req, int op, int arg)
1670{
1671 struct rttable_walkarg w;
1672 int error, i;
1673
1674 error = rttable_walkarg_create(&w, op, arg);
1675 if (error)
1676 return error;
1677
1678 error = EINVAL;
1679 for (i = 1; i <= AF_MAX; i++) {
1680 if (rt_tables[mycpuid][i] != NULL && (af == 0 || af == i)) {
1681 w.w_key = NULL;
1682 w.w_mask = NULL;
1683 for (;;) {
1684 struct netmsg_rttable_walk nmsg;
1685
1686 netmsg_init(&nmsg.base, NULL,
1687 &curthread->td_msgport, 0,
1688 rttable_walk_dispatch);
1689 nmsg.af = i;
1690 nmsg.w = &w;
1691
1692 w.w_buflen = 0;
1693
1694 error = lwkt_domsg(netisr_cpuport(mycpuid),
1695 &nmsg.base.lmsg, 0);
1696 if (error && error != EJUSTRETURN)
1697 goto done;
1698
1699 if (req != NULL && w.w_buflen > 0) {
1700 int error1;
1701
1702 error1 = SYSCTL_OUT(req, w.w_buf,
1703 w.w_buflen);
1704 if (error1) {
1705 error = error1;
1706 goto done;
1707 }
1708 }
1709 if (error == 0) /* done */
1710 break;
1711 }
1712 }
1713 }
1714done:
1715 rttable_walkarg_destroy(&w);
085b1d2a
SZ
1716 return error;
1717}
1718
984263bc
MD
1719static int
1720sysctl_rtsock(SYSCTL_HANDLER_ARGS)
1721{
1722 int *name = (int *)arg1;
1723 u_int namelen = arg2;
085b1d2a 1724 int error = EINVAL;
0c14b383 1725 int origcpu, cpu;
984263bc
MD
1726 u_char af;
1727 struct walkarg w;
1728
1729 name ++;
1730 namelen--;
1731 if (req->newptr)
1732 return (EPERM);
ecdefdda 1733 if (namelen != 3 && namelen != 4)
984263bc
MD
1734 return (EINVAL);
1735 af = name[0];
5fe66e68 1736 bzero(&w, sizeof w);
984263bc
MD
1737 w.w_op = name[1];
1738 w.w_arg = name[2];
1739 w.w_req = req;
1740
ecdefdda
MD
1741 /*
1742 * Optional third argument specifies cpu, used primarily for
1743 * debugging the route table.
1744 */
1745 if (namelen == 4) {
43dbcc2a 1746 if (name[3] < 0 || name[3] >= netisr_ncpus)
ecdefdda 1747 return (EINVAL);
0c14b383 1748 cpu = name[3];
ecdefdda 1749 } else {
0c14b383
SZ
1750 /*
1751 * Target cpu is not specified, use cpu0 then, so that
1752 * the result set will be relatively stable.
1753 */
1754 cpu = 0;
ecdefdda 1755 }
0c14b383
SZ
1756 origcpu = mycpuid;
1757 lwkt_migratecpu(cpu);
085b1d2a 1758
984263bc 1759 switch (w.w_op) {
984263bc
MD
1760 case NET_RT_DUMP:
1761 case NET_RT_FLAGS:
085b1d2a 1762 error = sysctl_rttable(af, w.w_req, w.w_op, w.w_arg);
984263bc
MD
1763 break;
1764
1765 case NET_RT_IFLIST:
1766 error = sysctl_iflist(af, &w);
085b1d2a 1767 break;
984263bc 1768 }
590b8cd4 1769 if (w.w_tmem != NULL)
efda3bd0 1770 kfree(w.w_tmem, M_RTABLE);
085b1d2a 1771
0c14b383 1772 lwkt_migratecpu(origcpu);
984263bc
MD
1773 return (error);
1774}
1775
1776SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
1777
1778/*
1779 * Definitions of protocols supported in the ROUTE domain.
1780 */
1781
ba4257b8 1782static struct domain routedomain; /* or at least forward */
984263bc
MD
1783
1784static struct protosw routesw[] = {
002c1265
MD
1785 {
1786 .pr_type = SOCK_RAW,
1787 .pr_domain = &routedomain,
1788 .pr_protocol = 0,
1789 .pr_flags = PR_ATOMIC|PR_ADDR,
1790 .pr_input = NULL,
1791 .pr_output = route_output,
1792 .pr_ctlinput = raw_ctlinput,
8aeffa9f 1793 .pr_ctloutput = route_ctloutput,
002c1265
MD
1794 .pr_ctlport = cpu0_ctlport,
1795
1796 .pr_init = raw_init,
1797 .pr_usrreqs = &route_usrreqs
1798 }
984263bc
MD
1799};
1800
ba4257b8 1801static struct domain routedomain = {
51e5cc05
SZ
1802 .dom_family = AF_ROUTE,
1803 .dom_name = "route",
1804 .dom_init = NULL,
1805 .dom_externalize = NULL,
1806 .dom_dispose = NULL,
1807 .dom_protosw = routesw,
1808 .dom_protoswNPROTOSW = &routesw[(sizeof routesw)/(sizeof routesw[0])],
1809 .dom_next = SLIST_ENTRY_INITIALIZER,
1810 .dom_rtattach = NULL,
1811 .dom_rtoffset = 0,
1812 .dom_maxrtkey = 0,
1813 .dom_ifattach = NULL,
1814 .dom_ifdetach = NULL
9c70fe43 1815};
984263bc
MD
1816
1817DOMAIN_SET(route);
47db7f9b 1818