Line data Source code
1 : /* $OpenBSD: rtsock.c,v 1.279 2018/07/10 20:28:34 claudio Exp $ */
2 : /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */
3 :
4 : /*
5 : * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the project nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
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.
45 : * 3. Neither the name of the University nor the names of its contributors
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.6 (Berkeley) 2/11/95
62 : */
63 :
64 : #include <sys/param.h>
65 : #include <sys/systm.h>
66 : #include <sys/proc.h>
67 : #include <sys/sysctl.h>
68 : #include <sys/mbuf.h>
69 : #include <sys/socket.h>
70 : #include <sys/socketvar.h>
71 : #include <sys/domain.h>
72 : #include <sys/protosw.h>
73 : #include <sys/srp.h>
74 :
75 : #include <net/if.h>
76 : #include <net/if_dl.h>
77 : #include <net/if_var.h>
78 : #include <net/route.h>
79 :
80 : #include <netinet/in.h>
81 :
82 : #ifdef MPLS
83 : #include <netmpls/mpls.h>
84 : #endif
85 : #ifdef IPSEC
86 : #include <netinet/ip_ipsp.h>
87 : #include <net/if_enc.h>
88 : #endif
89 : #ifdef BFD
90 : #include <net/bfd.h>
91 : #endif
92 :
93 : #include <sys/stdarg.h>
94 : #include <sys/kernel.h>
95 : #include <sys/timeout.h>
96 :
97 : #define ROUTESNDQ 8192
98 : #define ROUTERCVQ 8192
99 :
100 : const struct sockaddr route_src = { 2, PF_ROUTE, };
101 :
102 : struct walkarg {
103 : int w_op, w_arg, w_given, w_needed, w_tmemsize;
104 : caddr_t w_where, w_tmem;
105 : };
106 :
107 : void route_prinit(void);
108 : void rcb_ref(void *, void *);
109 : void rcb_unref(void *, void *);
110 : int route_output(struct mbuf *, struct socket *, struct sockaddr *,
111 : struct mbuf *);
112 : int route_ctloutput(int, struct socket *, int, int, struct mbuf *);
113 : int route_usrreq(struct socket *, int, struct mbuf *, struct mbuf *,
114 : struct mbuf *, struct proc *);
115 : void route_input(struct mbuf *m0, struct socket *, sa_family_t);
116 : int route_arp_conflict(struct rtentry *, struct rt_addrinfo *);
117 : int route_cleargateway(struct rtentry *, void *, unsigned int);
118 : void rtm_senddesync_timer(void *);
119 : void rtm_senddesync(struct socket *);
120 : int rtm_sendup(struct socket *, struct mbuf *, int);
121 :
122 : int rtm_getifa(struct rt_addrinfo *, unsigned int);
123 : int rtm_output(struct rt_msghdr *, struct rtentry **, struct rt_addrinfo *,
124 : uint8_t, unsigned int);
125 : struct rt_msghdr *rtm_report(struct rtentry *, u_char, int, int);
126 : struct mbuf *rtm_msg1(int, struct rt_addrinfo *);
127 : int rtm_msg2(int, int, struct rt_addrinfo *, caddr_t,
128 : struct walkarg *);
129 : void rtm_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
130 : int rtm_validate_proposal(struct rt_addrinfo *);
131 : void rtm_setmetrics(u_long, const struct rt_metrics *,
132 : struct rt_kmetrics *);
133 : void rtm_getmetrics(const struct rt_kmetrics *,
134 : struct rt_metrics *);
135 :
136 : int sysctl_iflist(int, struct walkarg *);
137 : int sysctl_ifnames(struct walkarg *);
138 : int sysctl_rtable_rtstat(void *, size_t *, void *);
139 :
140 : struct rtpcb {
141 : struct socket *rop_socket;
142 :
143 : SRPL_ENTRY(rtpcb) rop_list;
144 : struct refcnt rop_refcnt;
145 : struct timeout rop_timeout;
146 : unsigned int rop_msgfilter;
147 : unsigned int rop_flags;
148 : u_int rop_rtableid;
149 : unsigned short rop_proto;
150 : u_char rop_priority;
151 : };
152 : #define sotortpcb(so) ((struct rtpcb *)(so)->so_pcb)
153 :
154 : struct rtptable {
155 : SRPL_HEAD(, rtpcb) rtp_list;
156 : struct srpl_rc rtp_rc;
157 : struct rwlock rtp_lk;
158 : unsigned int rtp_count;
159 : };
160 :
161 : struct rtptable rtptable;
162 :
163 : /*
164 : * These flags and timeout are used for indicating to userland (via a
165 : * RTM_DESYNC msg) when the route socket has overflowed and messages
166 : * have been lost.
167 : */
168 : #define ROUTECB_FLAG_DESYNC 0x1 /* Route socket out of memory */
169 : #define ROUTECB_FLAG_FLUSH 0x2 /* Wait until socket is empty before
170 : queueing more packets */
171 :
172 : #define ROUTE_DESYNC_RESEND_TIMEOUT (hz / 5) /* In hz */
173 :
174 : void
175 0 : route_prinit(void)
176 : {
177 0 : srpl_rc_init(&rtptable.rtp_rc, rcb_ref, rcb_unref, NULL);
178 0 : rw_init(&rtptable.rtp_lk, "rtsock");
179 0 : SRPL_INIT(&rtptable.rtp_list);
180 0 : }
181 :
182 : void
183 0 : rcb_ref(void *null, void *v)
184 : {
185 0 : struct rtpcb *rop = v;
186 :
187 0 : refcnt_take(&rop->rop_refcnt);
188 0 : }
189 :
190 : void
191 0 : rcb_unref(void *null, void *v)
192 : {
193 0 : struct rtpcb *rop = v;
194 :
195 0 : refcnt_rele_wake(&rop->rop_refcnt);
196 0 : }
197 :
198 : int
199 0 : route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
200 : struct mbuf *control, struct proc *p)
201 : {
202 : struct rtpcb *rop;
203 : int error = 0;
204 :
205 0 : if (req == PRU_CONTROL)
206 0 : return (EOPNOTSUPP);
207 :
208 0 : soassertlocked(so);
209 :
210 0 : if (control && control->m_len) {
211 : error = EOPNOTSUPP;
212 0 : goto release;
213 : }
214 :
215 0 : rop = sotortpcb(so);
216 0 : if (rop == NULL) {
217 : error = EINVAL;
218 0 : goto release;
219 : }
220 :
221 0 : switch (req) {
222 : /* no connect, bind, accept. Socket is connected from the start */
223 : case PRU_CONNECT:
224 : case PRU_BIND:
225 : case PRU_CONNECT2:
226 : case PRU_LISTEN:
227 : case PRU_ACCEPT:
228 : error = EOPNOTSUPP;
229 0 : break;
230 :
231 : case PRU_DISCONNECT:
232 : case PRU_ABORT:
233 0 : soisdisconnected(so);
234 0 : break;
235 : case PRU_SHUTDOWN:
236 0 : socantsendmore(so);
237 0 : break;
238 : case PRU_SENSE:
239 : /* stat: don't bother with a blocksize. */
240 0 : return (0);
241 :
242 : /* minimal support, just implement a fake peer address */
243 : case PRU_SOCKADDR:
244 : error = EINVAL;
245 0 : break;
246 : case PRU_PEERADDR:
247 0 : bcopy(&route_src, mtod(nam, caddr_t), route_src.sa_len);
248 0 : nam->m_len = route_src.sa_len;
249 0 : break;
250 :
251 : case PRU_RCVOOB:
252 0 : return (EOPNOTSUPP);
253 : case PRU_RCVD:
254 : /*
255 : * If we are in a FLUSH state, check if the buffer is
256 : * empty so that we can clear the flag.
257 : */
258 0 : if (((rop->rop_flags & ROUTECB_FLAG_FLUSH) != 0) &&
259 0 : ((sbspace(rop->rop_socket, &rop->rop_socket->so_rcv) ==
260 0 : rop->rop_socket->so_rcv.sb_hiwat)))
261 0 : rop->rop_flags &= ~ROUTECB_FLAG_FLUSH;
262 0 : return (0);
263 :
264 : case PRU_SENDOOB:
265 : error = EOPNOTSUPP;
266 0 : break;
267 : case PRU_SEND:
268 0 : if (nam) {
269 : error = EISCONN;
270 0 : break;
271 : }
272 0 : error = (*so->so_proto->pr_output)(m, so, NULL, NULL);
273 : m = NULL;
274 0 : break;
275 : default:
276 0 : panic("route_usrreq");
277 : }
278 :
279 : release:
280 0 : m_freem(control);
281 0 : m_freem(m);
282 0 : return (error);
283 0 : }
284 :
285 : int
286 0 : route_attach(struct socket *so, int proto)
287 : {
288 : struct rtpcb *rop;
289 : int error;
290 :
291 : /*
292 : * use the rawcb but allocate a rtpcb, this
293 : * code does not care about the additional fields
294 : * and works directly on the raw socket.
295 : */
296 0 : rop = malloc(sizeof(struct rtpcb), M_PCB, M_WAITOK|M_ZERO);
297 0 : so->so_pcb = rop;
298 : /* Init the timeout structure */
299 0 : timeout_set(&rop->rop_timeout, rtm_senddesync_timer, so);
300 0 : refcnt_init(&rop->rop_refcnt);
301 :
302 0 : if (curproc == NULL)
303 0 : error = EACCES;
304 : else
305 0 : error = soreserve(so, ROUTESNDQ, ROUTERCVQ);
306 0 : if (error) {
307 0 : free(rop, M_PCB, sizeof(struct rtpcb));
308 0 : return (error);
309 : }
310 :
311 0 : rop->rop_socket = so;
312 0 : rop->rop_proto = proto;
313 :
314 0 : rop->rop_rtableid = curproc->p_p->ps_rtableid;
315 :
316 0 : soisconnected(so);
317 0 : so->so_options |= SO_USELOOPBACK;
318 :
319 0 : rw_enter(&rtptable.rtp_lk, RW_WRITE);
320 0 : SRPL_INSERT_HEAD_LOCKED(&rtptable.rtp_rc, &rtptable.rtp_list, rop, rop_list);
321 0 : rtptable.rtp_count++;
322 0 : rw_exit(&rtptable.rtp_lk);
323 :
324 0 : return (0);
325 0 : }
326 :
327 : int
328 0 : route_detach(struct socket *so)
329 : {
330 : struct rtpcb *rop;
331 :
332 0 : soassertlocked(so);
333 :
334 0 : rop = sotortpcb(so);
335 0 : if (rop == NULL)
336 0 : return (EINVAL);
337 :
338 0 : rw_enter(&rtptable.rtp_lk, RW_WRITE);
339 :
340 0 : timeout_del(&rop->rop_timeout);
341 0 : rtptable.rtp_count--;
342 :
343 0 : SRPL_REMOVE_LOCKED(&rtptable.rtp_rc, &rtptable.rtp_list, rop, rtpcb,
344 : rop_list);
345 0 : rw_exit(&rtptable.rtp_lk);
346 :
347 : /* wait for all references to drop */
348 0 : refcnt_finalize(&rop->rop_refcnt, "rtsockrefs");
349 :
350 0 : so->so_pcb = NULL;
351 0 : KASSERT((so->so_state & SS_NOFDREF) == 0);
352 0 : free(rop, M_PCB, sizeof(struct rtpcb));
353 :
354 0 : return (0);
355 0 : }
356 :
357 : int
358 0 : route_ctloutput(int op, struct socket *so, int level, int optname,
359 : struct mbuf *m)
360 : {
361 0 : struct rtpcb *rop = sotortpcb(so);
362 : int error = 0;
363 : unsigned int tid, prio;
364 :
365 0 : if (level != AF_ROUTE)
366 0 : return (EINVAL);
367 :
368 0 : switch (op) {
369 : case PRCO_SETOPT:
370 0 : switch (optname) {
371 : case ROUTE_MSGFILTER:
372 0 : if (m == NULL || m->m_len != sizeof(unsigned int))
373 0 : error = EINVAL;
374 : else
375 0 : rop->rop_msgfilter = *mtod(m, unsigned int *);
376 : break;
377 : case ROUTE_TABLEFILTER:
378 0 : if (m == NULL || m->m_len != sizeof(unsigned int)) {
379 : error = EINVAL;
380 0 : break;
381 : }
382 0 : tid = *mtod(m, unsigned int *);
383 0 : if (tid != RTABLE_ANY && !rtable_exists(tid))
384 0 : error = ENOENT;
385 : else
386 0 : rop->rop_rtableid = tid;
387 : break;
388 : case ROUTE_PRIOFILTER:
389 0 : if (m == NULL || m->m_len != sizeof(unsigned int)) {
390 : error = EINVAL;
391 0 : break;
392 : }
393 0 : prio = *mtod(m, unsigned int *);
394 0 : if (prio > RTP_MAX)
395 0 : error = EINVAL;
396 : else
397 0 : rop->rop_priority = prio;
398 : break;
399 : default:
400 : error = ENOPROTOOPT;
401 0 : break;
402 : }
403 : break;
404 : case PRCO_GETOPT:
405 0 : switch (optname) {
406 : case ROUTE_MSGFILTER:
407 0 : m->m_len = sizeof(unsigned int);
408 0 : *mtod(m, unsigned int *) = rop->rop_msgfilter;
409 0 : break;
410 : case ROUTE_TABLEFILTER:
411 0 : m->m_len = sizeof(unsigned int);
412 0 : *mtod(m, unsigned int *) = rop->rop_rtableid;
413 0 : break;
414 : case ROUTE_PRIOFILTER:
415 0 : m->m_len = sizeof(unsigned int);
416 0 : *mtod(m, unsigned int *) = rop->rop_priority;
417 0 : break;
418 : default:
419 : error = ENOPROTOOPT;
420 0 : break;
421 : }
422 : }
423 0 : return (error);
424 0 : }
425 :
426 : void
427 0 : rtm_senddesync_timer(void *xso)
428 : {
429 0 : struct socket *so = xso;
430 : int s;
431 :
432 0 : s = solock(so);
433 0 : rtm_senddesync(so);
434 0 : sounlock(so, s);
435 0 : }
436 :
437 : void
438 0 : rtm_senddesync(struct socket *so)
439 : {
440 0 : struct rtpcb *rop = sotortpcb(so);
441 : struct mbuf *desync_mbuf;
442 :
443 0 : soassertlocked(so);
444 :
445 : /* If we are in a DESYNC state, try to send a RTM_DESYNC packet */
446 0 : if ((rop->rop_flags & ROUTECB_FLAG_DESYNC) == 0)
447 0 : return;
448 :
449 : /*
450 : * If we fail to alloc memory or if sbappendaddr()
451 : * fails, re-add timeout and try again.
452 : */
453 0 : desync_mbuf = rtm_msg1(RTM_DESYNC, NULL);
454 0 : if (desync_mbuf != NULL) {
455 0 : if (sbappendaddr(so, &so->so_rcv, &route_src,
456 0 : desync_mbuf, NULL) != 0) {
457 0 : rop->rop_flags &= ~ROUTECB_FLAG_DESYNC;
458 0 : sorwakeup(rop->rop_socket);
459 0 : return;
460 : }
461 0 : m_freem(desync_mbuf);
462 0 : }
463 : /* Re-add timeout to try sending msg again */
464 0 : timeout_add(&rop->rop_timeout, ROUTE_DESYNC_RESEND_TIMEOUT);
465 0 : }
466 :
467 : void
468 0 : route_input(struct mbuf *m0, struct socket *so0, sa_family_t sa_family)
469 : {
470 : struct socket *so;
471 : struct rtpcb *rop;
472 : struct rt_msghdr *rtm;
473 : struct mbuf *m = m0;
474 : struct socket *last = NULL;
475 0 : struct srp_ref sr;
476 : int s;
477 :
478 : /* ensure that we can access the rtm_type via mtod() */
479 0 : if (m->m_len < offsetof(struct rt_msghdr, rtm_type) + 1) {
480 0 : m_freem(m);
481 0 : return;
482 : }
483 :
484 0 : SRPL_FOREACH(rop, &sr, &rtptable.rtp_list, rop_list) {
485 : /*
486 : * If route socket is bound to an address family only send
487 : * messages that match the address family. Address family
488 : * agnostic messages are always sent.
489 : */
490 0 : if (sa_family != AF_UNSPEC && rop->rop_proto != AF_UNSPEC &&
491 0 : rop->rop_proto != sa_family)
492 : continue;
493 :
494 :
495 0 : so = rop->rop_socket;
496 0 : s = solock(so);
497 :
498 : /*
499 : * Check to see if we don't want our own messages and
500 : * if we can receive anything.
501 : */
502 0 : if ((so0 == so && !(so0->so_options & SO_USELOOPBACK)) ||
503 0 : !(so->so_state & SS_ISCONNECTED) ||
504 0 : (so->so_state & SS_CANTRCVMORE)) {
505 : next:
506 0 : sounlock(so, s);
507 0 : continue;
508 : }
509 :
510 : /* filter messages that the process does not want */
511 0 : rtm = mtod(m, struct rt_msghdr *);
512 : /* but RTM_DESYNC can't be filtered */
513 0 : if (rtm->rtm_type != RTM_DESYNC && rop->rop_msgfilter != 0 &&
514 0 : !(rop->rop_msgfilter & (1 << rtm->rtm_type)))
515 : goto next;
516 0 : switch (rtm->rtm_type) {
517 : case RTM_IFANNOUNCE:
518 : case RTM_DESYNC:
519 : /* no tableid */
520 : break;
521 : case RTM_RESOLVE:
522 : case RTM_NEWADDR:
523 : case RTM_DELADDR:
524 : case RTM_IFINFO:
525 : case RTM_BFD:
526 : /* check against rdomain id */
527 0 : if (rop->rop_rtableid != RTABLE_ANY &&
528 0 : rtable_l2(rop->rop_rtableid) != rtm->rtm_tableid)
529 : goto next;
530 : break;
531 : default:
532 0 : if (rop->rop_priority != 0 &&
533 0 : rop->rop_priority < rtm->rtm_priority)
534 : goto next;
535 : /* check against rtable id */
536 0 : if (rop->rop_rtableid != RTABLE_ANY &&
537 0 : rop->rop_rtableid != rtm->rtm_tableid)
538 : goto next;
539 : break;
540 : }
541 :
542 : /*
543 : * Check to see if the flush flag is set. If so, don't queue
544 : * any more messages until the flag is cleared.
545 : */
546 0 : if ((rop->rop_flags & ROUTECB_FLAG_FLUSH) != 0)
547 : goto next;
548 0 : sounlock(so, s);
549 :
550 0 : if (last) {
551 0 : s = solock(last);
552 0 : rtm_sendup(last, m, 1);
553 0 : sounlock(last, s);
554 0 : refcnt_rele_wake(&sotortpcb(last)->rop_refcnt);
555 0 : }
556 : /* keep a reference for last */
557 0 : refcnt_take(&rop->rop_refcnt);
558 0 : last = rop->rop_socket;
559 0 : }
560 0 : SRPL_LEAVE(&sr);
561 :
562 0 : if (last) {
563 0 : s = solock(last);
564 0 : rtm_sendup(last, m, 0);
565 0 : sounlock(last, s);
566 0 : refcnt_rele_wake(&sotortpcb(last)->rop_refcnt);
567 0 : } else
568 0 : m_freem(m);
569 0 : }
570 :
571 : int
572 0 : rtm_sendup(struct socket *so, struct mbuf *m0, int more)
573 : {
574 0 : struct rtpcb *rop = sotortpcb(so);
575 : struct mbuf *m;
576 :
577 0 : soassertlocked(so);
578 :
579 0 : if (more) {
580 0 : m = m_copym(m0, 0, M_COPYALL, M_NOWAIT);
581 0 : if (m == NULL)
582 0 : return (ENOMEM);
583 : } else
584 : m = m0;
585 :
586 0 : if (sbspace(so, &so->so_rcv) < (2 * MSIZE) ||
587 0 : sbappendaddr(so, &so->so_rcv, &route_src, m, NULL) == 0) {
588 : /* Flag socket as desync'ed and flush required */
589 0 : rop->rop_flags |= ROUTECB_FLAG_DESYNC | ROUTECB_FLAG_FLUSH;
590 0 : rtm_senddesync(so);
591 0 : m_freem(m);
592 0 : return (ENOBUFS);
593 : }
594 :
595 0 : sorwakeup(so);
596 0 : return (0);
597 0 : }
598 :
599 : struct rt_msghdr *
600 0 : rtm_report(struct rtentry *rt, u_char type, int seq, int tableid)
601 : {
602 : struct rt_msghdr *rtm;
603 0 : struct rt_addrinfo info;
604 0 : struct sockaddr_rtlabel sa_rl;
605 0 : struct sockaddr_in6 sa_mask;
606 : #ifdef BFD
607 : struct sockaddr_bfd sa_bfd;
608 : #endif
609 : struct ifnet *ifp = NULL;
610 : int len;
611 :
612 0 : bzero(&info, sizeof(info));
613 0 : info.rti_info[RTAX_DST] = rt_key(rt);
614 0 : info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
615 0 : info.rti_info[RTAX_NETMASK] = rt_plen2mask(rt, &sa_mask);
616 0 : info.rti_info[RTAX_LABEL] = rtlabel_id2sa(rt->rt_labelid, &sa_rl);
617 : #ifdef BFD
618 : if (rt->rt_flags & RTF_BFD)
619 : info.rti_info[RTAX_BFD] = bfd2sa(rt, &sa_bfd);
620 : #endif
621 : #ifdef MPLS
622 0 : if (rt->rt_flags & RTF_MPLS) {
623 0 : struct sockaddr_mpls sa_mpls;
624 :
625 0 : bzero(&sa_mpls, sizeof(sa_mpls));
626 0 : sa_mpls.smpls_family = AF_MPLS;
627 0 : sa_mpls.smpls_len = sizeof(sa_mpls);
628 0 : sa_mpls.smpls_label = ((struct rt_mpls *)
629 0 : rt->rt_llinfo)->mpls_label;
630 0 : info.rti_info[RTAX_SRC] = (struct sockaddr *)&sa_mpls;
631 0 : info.rti_mpls = ((struct rt_mpls *)
632 0 : rt->rt_llinfo)->mpls_operation;
633 0 : }
634 : #endif
635 0 : ifp = if_get(rt->rt_ifidx);
636 0 : if (ifp != NULL) {
637 0 : info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl);
638 0 : info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
639 0 : if (ifp->if_flags & IFF_POINTOPOINT)
640 0 : info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr;
641 : }
642 0 : if_put(ifp);
643 : /* RTAX_GENMASK, RTAX_AUTHOR, RTAX_SRCMASK ignored */
644 :
645 : /* build new route message */
646 0 : len = rtm_msg2(type, RTM_VERSION, &info, NULL, NULL);
647 0 : rtm = malloc(len, M_RTABLE, M_WAITOK | M_ZERO);
648 :
649 0 : rtm_msg2(type, RTM_VERSION, &info, (caddr_t)rtm, NULL);
650 0 : rtm->rtm_type = type;
651 0 : rtm->rtm_index = rt->rt_ifidx;
652 0 : rtm->rtm_tableid = tableid;
653 0 : rtm->rtm_priority = rt->rt_priority & RTP_MASK;
654 0 : rtm->rtm_flags = rt->rt_flags;
655 0 : rtm->rtm_pid = curproc->p_p->ps_pid;
656 0 : rtm->rtm_seq = seq;
657 0 : rtm_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
658 0 : rtm->rtm_addrs = info.rti_addrs;
659 : #ifdef MPLS
660 0 : rtm->rtm_mpls = info.rti_mpls;
661 : #endif
662 0 : return rtm;
663 0 : }
664 :
665 : int
666 0 : route_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr,
667 : struct mbuf *control)
668 : {
669 : struct rt_msghdr *rtm = NULL;
670 0 : struct rtentry *rt = NULL;
671 0 : struct rt_addrinfo info;
672 : int len, seq, error = 0;
673 : u_int tableid;
674 : u_int8_t prio;
675 : u_char vers, type;
676 :
677 0 : if (m == NULL || ((m->m_len < sizeof(int32_t)) &&
678 0 : (m = m_pullup(m, sizeof(int32_t))) == 0))
679 0 : return (ENOBUFS);
680 0 : if ((m->m_flags & M_PKTHDR) == 0)
681 0 : panic("route_output");
682 0 : len = m->m_pkthdr.len;
683 0 : if (len < offsetof(struct rt_msghdr, rtm_type) + 1 ||
684 0 : len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
685 : error = EINVAL;
686 0 : goto fail;
687 : }
688 0 : vers = mtod(m, struct rt_msghdr *)->rtm_version;
689 0 : switch (vers) {
690 : case RTM_VERSION:
691 0 : if (len < sizeof(struct rt_msghdr)) {
692 : error = EINVAL;
693 0 : goto fail;
694 : }
695 0 : if (len > RTM_MAXSIZE) {
696 : error = EMSGSIZE;
697 0 : goto fail;
698 : }
699 0 : rtm = malloc(len, M_RTABLE, M_WAITOK);
700 0 : m_copydata(m, 0, len, (caddr_t)rtm);
701 : break;
702 : default:
703 : error = EPROTONOSUPPORT;
704 0 : goto fail;
705 : }
706 0 : rtm->rtm_pid = curproc->p_p->ps_pid;
707 0 : if (rtm->rtm_hdrlen == 0) /* old client */
708 0 : rtm->rtm_hdrlen = sizeof(struct rt_msghdr);
709 0 : if (len < rtm->rtm_hdrlen) {
710 : error = EINVAL;
711 0 : goto fail;
712 : }
713 :
714 : /* Verify that the caller is sending an appropriate message early */
715 0 : switch (rtm->rtm_type) {
716 : case RTM_ADD:
717 : case RTM_DELETE:
718 : case RTM_GET:
719 : case RTM_CHANGE:
720 : case RTM_PROPOSAL:
721 : break;
722 : default:
723 : error = EOPNOTSUPP;
724 0 : goto fail;
725 : }
726 :
727 : /*
728 : * Verify that the caller has the appropriate privilege; RTM_GET
729 : * is the only operation the non-superuser is allowed.
730 : */
731 0 : if (rtm->rtm_type != RTM_GET && suser(curproc) != 0) {
732 : error = EACCES;
733 0 : goto fail;
734 : }
735 0 : tableid = rtm->rtm_tableid;
736 0 : if (!rtable_exists(tableid)) {
737 0 : if (rtm->rtm_type == RTM_ADD) {
738 0 : if ((error = rtable_add(tableid)) != 0)
739 : goto fail;
740 : } else {
741 : error = EINVAL;
742 0 : goto fail;
743 : }
744 : }
745 :
746 :
747 : /* Do not let userland play with kernel-only flags. */
748 0 : if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0) {
749 : error = EINVAL;
750 0 : goto fail;
751 : }
752 :
753 : /* make sure that kernel-only bits are not set */
754 0 : rtm->rtm_priority &= RTP_MASK;
755 0 : rtm->rtm_flags &= ~(RTF_DONE|RTF_CLONED|RTF_CACHED);
756 0 : rtm->rtm_fmask &= RTF_FMASK;
757 :
758 0 : if (rtm->rtm_priority != 0) {
759 0 : if (rtm->rtm_priority > RTP_MAX ||
760 0 : rtm->rtm_priority == RTP_LOCAL) {
761 : error = EINVAL;
762 0 : goto fail;
763 : }
764 : prio = rtm->rtm_priority;
765 0 : } else if (rtm->rtm_type != RTM_ADD)
766 0 : prio = RTP_ANY;
767 0 : else if (rtm->rtm_flags & RTF_STATIC)
768 0 : prio = 0;
769 : else
770 : prio = RTP_DEFAULT;
771 :
772 0 : bzero(&info, sizeof(info));
773 0 : info.rti_addrs = rtm->rtm_addrs;
774 0 : rtm_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, len + (caddr_t)rtm, &info);
775 0 : info.rti_flags = rtm->rtm_flags;
776 0 : if (rtm->rtm_type != RTM_PROPOSAL &&
777 0 : (info.rti_info[RTAX_DST] == NULL ||
778 0 : info.rti_info[RTAX_DST]->sa_family >= AF_MAX ||
779 0 : (info.rti_info[RTAX_GATEWAY] != NULL &&
780 0 : info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX) ||
781 0 : info.rti_info[RTAX_GENMASK] != NULL)) {
782 : error = EINVAL;
783 0 : goto fail;
784 : }
785 : #ifdef MPLS
786 0 : info.rti_mpls = rtm->rtm_mpls;
787 : #endif
788 :
789 0 : if (info.rti_info[RTAX_GATEWAY] != NULL &&
790 0 : info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK &&
791 0 : (info.rti_flags & RTF_CLONING) == 0) {
792 0 : info.rti_flags |= RTF_LLINFO;
793 0 : }
794 :
795 : /*
796 : * Validate RTM_PROPOSAL and pass it along or error out.
797 : */
798 0 : if (rtm->rtm_type == RTM_PROPOSAL) {
799 0 : if (rtm_validate_proposal(&info) == -1) {
800 : error = EINVAL;
801 0 : goto fail;
802 : }
803 : } else {
804 0 : error = rtm_output(rtm, &rt, &info, prio, tableid);
805 0 : if (!error) {
806 0 : type = rtm->rtm_type;
807 0 : seq = rtm->rtm_seq;
808 0 : free(rtm, M_RTABLE, len);
809 0 : rtm = rtm_report(rt, type, seq, tableid);
810 0 : len = rtm->rtm_msglen;
811 0 : }
812 : }
813 :
814 0 : rtfree(rt);
815 0 : if (error) {
816 0 : rtm->rtm_errno = error;
817 0 : } else {
818 0 : rtm->rtm_flags |= RTF_DONE;
819 : }
820 :
821 : /*
822 : * Check to see if we don't want our own messages.
823 : */
824 0 : if (!(so->so_options & SO_USELOOPBACK)) {
825 0 : if (rtptable.rtp_count <= 1) {
826 : /* no other listener and no loopback of messages */
827 : fail:
828 0 : free(rtm, M_RTABLE, len);
829 0 : m_freem(m);
830 0 : return (error);
831 : }
832 : }
833 0 : if (rtm) {
834 0 : if (m_copyback(m, 0, len, rtm, M_NOWAIT)) {
835 0 : m_freem(m);
836 : m = NULL;
837 0 : } else if (m->m_pkthdr.len > len)
838 0 : m_adj(m, len - m->m_pkthdr.len);
839 0 : free(rtm, M_RTABLE, len);
840 0 : }
841 0 : if (m)
842 0 : route_input(m, so, info.rti_info[RTAX_DST] ?
843 0 : info.rti_info[RTAX_DST]->sa_family : AF_UNSPEC);
844 :
845 0 : return (error);
846 0 : }
847 :
848 : int
849 0 : rtm_output(struct rt_msghdr *rtm, struct rtentry **prt,
850 : struct rt_addrinfo *info, uint8_t prio, unsigned int tableid)
851 : {
852 0 : struct rtentry *rt = *prt;
853 : struct ifnet *ifp = NULL;
854 : int plen, newgate = 0, error = 0;
855 :
856 0 : switch (rtm->rtm_type) {
857 : case RTM_ADD:
858 0 : if (info->rti_info[RTAX_GATEWAY] == NULL) {
859 : error = EINVAL;
860 0 : break;
861 : }
862 :
863 0 : rt = rtable_match(tableid, info->rti_info[RTAX_DST], NULL);
864 0 : if ((error = route_arp_conflict(rt, info))) {
865 0 : rtfree(rt);
866 0 : rt = NULL;
867 0 : break;
868 : }
869 :
870 : /*
871 : * We cannot go through a delete/create/insert cycle for
872 : * cached route because this can lead to races in the
873 : * receive path. Instead we update the L2 cache.
874 : */
875 0 : if ((rt != NULL) && ISSET(rt->rt_flags, RTF_CACHED))
876 : goto change;
877 :
878 0 : rtfree(rt);
879 0 : rt = NULL;
880 :
881 0 : NET_LOCK();
882 0 : if ((error = rtm_getifa(info, tableid)) != 0) {
883 0 : NET_UNLOCK();
884 0 : break;
885 : }
886 0 : error = rtrequest(RTM_ADD, info, prio, &rt, tableid);
887 0 : NET_UNLOCK();
888 0 : if (error == 0)
889 0 : rtm_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
890 0 : &rt->rt_rmx);
891 : break;
892 : case RTM_DELETE:
893 0 : rt = rtable_lookup(tableid, info->rti_info[RTAX_DST],
894 0 : info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY],
895 : prio);
896 0 : if (rt == NULL) {
897 : error = ESRCH;
898 0 : break;
899 : }
900 :
901 : /*
902 : * If we got multipath routes, we require users to specify
903 : * a matching gateway.
904 : */
905 0 : if (ISSET(rt->rt_flags, RTF_MPATH) &&
906 0 : info->rti_info[RTAX_GATEWAY] == NULL) {
907 : error = ESRCH;
908 0 : break;
909 : }
910 :
911 : /* Detaching an interface requires the KERNEL_LOCK(). */
912 0 : ifp = if_get(rt->rt_ifidx);
913 0 : KASSERT(ifp != NULL);
914 :
915 : /*
916 : * Invalidate the cache of automagically created and
917 : * referenced L2 entries to make sure that ``rt_gwroute''
918 : * pointer stays valid for other CPUs.
919 : */
920 0 : if ((ISSET(rt->rt_flags, RTF_CACHED))) {
921 0 : NET_LOCK();
922 0 : ifp->if_rtrequest(ifp, RTM_INVALIDATE, rt);
923 : /* Reset the MTU of the gateway route. */
924 0 : rtable_walk(tableid, rt_key(rt)->sa_family,
925 0 : route_cleargateway, rt);
926 0 : NET_UNLOCK();
927 0 : if_put(ifp);
928 0 : break;
929 : }
930 :
931 : /*
932 : * Make sure that local routes are only modified by the
933 : * kernel.
934 : */
935 0 : if (ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST)) {
936 0 : if_put(ifp);
937 : error = EINVAL;
938 0 : break;
939 : }
940 :
941 0 : rtfree(rt);
942 0 : rt = NULL;
943 :
944 0 : NET_LOCK();
945 0 : error = rtrequest_delete(info, prio, ifp, &rt, tableid);
946 0 : NET_UNLOCK();
947 0 : if_put(ifp);
948 0 : break;
949 : case RTM_CHANGE:
950 0 : rt = rtable_lookup(tableid, info->rti_info[RTAX_DST],
951 0 : info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY],
952 : prio);
953 : /*
954 : * If we got multipath routes, we require users to specify
955 : * a matching gateway.
956 : */
957 0 : if ((rt != NULL) && ISSET(rt->rt_flags, RTF_MPATH) &&
958 0 : (info->rti_info[RTAX_GATEWAY] == NULL)) {
959 0 : rtfree(rt);
960 0 : rt = NULL;
961 0 : }
962 : /*
963 : * If RTAX_GATEWAY is the argument we're trying to
964 : * change, try to find a compatible route.
965 : */
966 0 : if ((rt == NULL) && (info->rti_info[RTAX_GATEWAY] != NULL) &&
967 0 : (rtm->rtm_type == RTM_CHANGE)) {
968 0 : rt = rtable_lookup(tableid, info->rti_info[RTAX_DST],
969 0 : info->rti_info[RTAX_NETMASK], NULL, prio);
970 : /* Ensure we don't pick a multipath one. */
971 0 : if ((rt != NULL) && ISSET(rt->rt_flags, RTF_MPATH)) {
972 0 : rtfree(rt);
973 0 : rt = NULL;
974 0 : }
975 : }
976 :
977 0 : if (rt == NULL) {
978 : error = ESRCH;
979 0 : break;
980 : }
981 :
982 : /*
983 : * Make sure that local routes are only modified by the
984 : * kernel.
985 : */
986 0 : if (ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST)) {
987 : error = EINVAL;
988 0 : break;
989 : }
990 :
991 : /*
992 : * RTM_CHANGE/LOCK need a perfect match.
993 : */
994 0 : plen = rtable_satoplen(info->rti_info[RTAX_DST]->sa_family,
995 0 : info->rti_info[RTAX_NETMASK]);
996 0 : if (rt_plen(rt) != plen) {
997 : error = ESRCH;
998 0 : break;
999 : }
1000 :
1001 0 : switch (rtm->rtm_type) {
1002 : case RTM_CHANGE:
1003 0 : if (info->rti_info[RTAX_GATEWAY] != NULL)
1004 0 : if (rt->rt_gateway == NULL ||
1005 0 : bcmp(rt->rt_gateway,
1006 0 : info->rti_info[RTAX_GATEWAY],
1007 0 : info->rti_info[RTAX_GATEWAY]->sa_len)) {
1008 : newgate = 1;
1009 0 : }
1010 : /*
1011 : * Check reachable gateway before changing the route.
1012 : * New gateway could require new ifaddr, ifp;
1013 : * flags may also be different; ifp may be specified
1014 : * by ll sockaddr when protocol address is ambiguous.
1015 : */
1016 0 : if (newgate || info->rti_info[RTAX_IFP] != NULL ||
1017 0 : info->rti_info[RTAX_IFA] != NULL) {
1018 : struct ifaddr *ifa = NULL;
1019 :
1020 0 : NET_LOCK();
1021 0 : if ((error = rtm_getifa(info, tableid)) != 0) {
1022 0 : NET_UNLOCK();
1023 0 : break;
1024 : }
1025 0 : ifa = info->rti_ifa;
1026 0 : if (rt->rt_ifa != ifa) {
1027 0 : ifp = if_get(rt->rt_ifidx);
1028 0 : KASSERT(ifp != NULL);
1029 0 : ifp->if_rtrequest(ifp, RTM_DELETE, rt);
1030 0 : ifafree(rt->rt_ifa);
1031 0 : if_put(ifp);
1032 :
1033 0 : ifa->ifa_refcnt++;
1034 0 : rt->rt_ifa = ifa;
1035 0 : rt->rt_ifidx = ifa->ifa_ifp->if_index;
1036 : /* recheck link state after ifp change*/
1037 0 : rt_if_linkstate_change(rt, ifa->ifa_ifp,
1038 : tableid);
1039 0 : }
1040 0 : NET_UNLOCK();
1041 0 : }
1042 : change:
1043 0 : if (info->rti_info[RTAX_GATEWAY] != NULL) {
1044 : /*
1045 : * When updating the gateway, make sure it's
1046 : * valid.
1047 : */
1048 0 : if (!newgate && rt->rt_gateway->sa_family !=
1049 0 : info->rti_info[RTAX_GATEWAY]->sa_family) {
1050 : error = EINVAL;
1051 0 : break;
1052 : }
1053 :
1054 0 : NET_LOCK();
1055 0 : error = rt_setgate(rt,
1056 0 : info->rti_info[RTAX_GATEWAY], tableid);
1057 0 : NET_UNLOCK();
1058 0 : if (error)
1059 : break;
1060 : }
1061 : #ifdef MPLS
1062 0 : if ((rtm->rtm_flags & RTF_MPLS) &&
1063 0 : info->rti_info[RTAX_SRC] != NULL) {
1064 0 : NET_LOCK();
1065 0 : error = rt_mpls_set(rt,
1066 0 : info->rti_info[RTAX_SRC], info->rti_mpls);
1067 0 : NET_UNLOCK();
1068 0 : if (error)
1069 : break;
1070 0 : } else if (newgate || ((rtm->rtm_fmask & RTF_MPLS) &&
1071 0 : !(rtm->rtm_flags & RTF_MPLS))) {
1072 0 : NET_LOCK();
1073 : /* if gateway changed remove MPLS information */
1074 0 : rt_mpls_clear(rt);
1075 0 : NET_UNLOCK();
1076 0 : }
1077 : #endif
1078 :
1079 : #ifdef BFD
1080 : if (ISSET(rtm->rtm_flags, RTF_BFD)) {
1081 : if ((error = bfdset(rt)))
1082 : break;
1083 : } else if (!ISSET(rtm->rtm_flags, RTF_BFD) &&
1084 : ISSET(rtm->rtm_fmask, RTF_BFD)) {
1085 : bfdclear(rt);
1086 : }
1087 : #endif
1088 :
1089 0 : NET_LOCK();
1090 : /* Hack to allow some flags to be toggled */
1091 0 : if (rtm->rtm_fmask)
1092 0 : rt->rt_flags =
1093 0 : (rt->rt_flags & ~rtm->rtm_fmask) |
1094 0 : (rtm->rtm_flags & rtm->rtm_fmask);
1095 :
1096 0 : rtm_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
1097 0 : &rt->rt_rmx);
1098 :
1099 0 : ifp = if_get(rt->rt_ifidx);
1100 0 : KASSERT(ifp != NULL);
1101 0 : ifp->if_rtrequest(ifp, RTM_ADD, rt);
1102 0 : if_put(ifp);
1103 :
1104 0 : if (info->rti_info[RTAX_LABEL] != NULL) {
1105 0 : char *rtlabel = ((struct sockaddr_rtlabel *)
1106 0 : info->rti_info[RTAX_LABEL])->sr_label;
1107 0 : rtlabel_unref(rt->rt_labelid);
1108 0 : rt->rt_labelid = rtlabel_name2id(rtlabel);
1109 0 : }
1110 0 : if_group_routechange(info->rti_info[RTAX_DST],
1111 0 : info->rti_info[RTAX_NETMASK]);
1112 0 : rt->rt_locks &= ~(rtm->rtm_inits);
1113 0 : rt->rt_locks |=
1114 0 : (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
1115 0 : NET_UNLOCK();
1116 0 : break;
1117 : }
1118 : break;
1119 : case RTM_GET:
1120 0 : rt = rtable_lookup(tableid, info->rti_info[RTAX_DST],
1121 0 : info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY],
1122 : prio);
1123 0 : if (rt == NULL)
1124 0 : error = ESRCH;
1125 : break;
1126 : }
1127 :
1128 0 : *prt = rt;
1129 0 : return (error);
1130 0 : }
1131 :
1132 : struct ifaddr *
1133 0 : ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway,
1134 : unsigned int rtableid)
1135 : {
1136 : struct ifaddr *ifa;
1137 :
1138 0 : if ((flags & RTF_GATEWAY) == 0) {
1139 : /*
1140 : * If we are adding a route to an interface,
1141 : * and the interface is a pt to pt link
1142 : * we should search for the destination
1143 : * as our clue to the interface. Otherwise
1144 : * we can use the local address.
1145 : */
1146 : ifa = NULL;
1147 0 : if (flags & RTF_HOST)
1148 0 : ifa = ifa_ifwithdstaddr(dst, rtableid);
1149 0 : if (ifa == NULL)
1150 0 : ifa = ifa_ifwithaddr(gateway, rtableid);
1151 : } else {
1152 : /*
1153 : * If we are adding a route to a remote net
1154 : * or host, the gateway may still be on the
1155 : * other end of a pt to pt link.
1156 : */
1157 0 : ifa = ifa_ifwithdstaddr(gateway, rtableid);
1158 : }
1159 0 : if (ifa == NULL) {
1160 0 : if (gateway->sa_family == AF_LINK) {
1161 0 : struct sockaddr_dl *sdl = satosdl(gateway);
1162 0 : struct ifnet *ifp = if_get(sdl->sdl_index);
1163 :
1164 0 : if (ifp != NULL)
1165 0 : ifa = ifaof_ifpforaddr(dst, ifp);
1166 0 : if_put(ifp);
1167 0 : } else {
1168 : struct rtentry *rt;
1169 :
1170 0 : rt = rtalloc(gateway, RT_RESOLVE, rtable_l2(rtableid));
1171 0 : if (rt != NULL)
1172 0 : ifa = rt->rt_ifa;
1173 0 : rtfree(rt);
1174 : }
1175 : }
1176 0 : if (ifa == NULL)
1177 0 : return (NULL);
1178 0 : if (ifa->ifa_addr->sa_family != dst->sa_family) {
1179 : struct ifaddr *oifa = ifa;
1180 0 : ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
1181 0 : if (ifa == NULL)
1182 0 : ifa = oifa;
1183 0 : }
1184 0 : return (ifa);
1185 0 : }
1186 :
1187 : int
1188 0 : rtm_getifa(struct rt_addrinfo *info, unsigned int rtid)
1189 : {
1190 : struct ifnet *ifp = NULL;
1191 :
1192 : /*
1193 : * The "returned" `ifa' is guaranteed to be alive only if
1194 : * the NET_LOCK() is held.
1195 : */
1196 0 : NET_ASSERT_LOCKED();
1197 :
1198 : /*
1199 : * ifp may be specified by sockaddr_dl when protocol address
1200 : * is ambiguous
1201 : */
1202 0 : if (info->rti_info[RTAX_IFP] != NULL) {
1203 : struct sockaddr_dl *sdl;
1204 :
1205 0 : sdl = satosdl(info->rti_info[RTAX_IFP]);
1206 0 : ifp = if_get(sdl->sdl_index);
1207 0 : }
1208 :
1209 : #ifdef IPSEC
1210 : /*
1211 : * If the destination is a PF_KEY address, we'll look
1212 : * for the existence of a encap interface number or address
1213 : * in the options list of the gateway. By default, we'll return
1214 : * enc0.
1215 : */
1216 0 : if (info->rti_info[RTAX_DST] &&
1217 0 : info->rti_info[RTAX_DST]->sa_family == PF_KEY)
1218 0 : info->rti_ifa = enc_getifa(rtid, 0);
1219 : #endif
1220 :
1221 0 : if (info->rti_ifa == NULL && info->rti_info[RTAX_IFA] != NULL)
1222 0 : info->rti_ifa = ifa_ifwithaddr(info->rti_info[RTAX_IFA], rtid);
1223 :
1224 0 : if (info->rti_ifa == NULL) {
1225 : struct sockaddr *sa;
1226 :
1227 0 : if ((sa = info->rti_info[RTAX_IFA]) == NULL)
1228 0 : if ((sa = info->rti_info[RTAX_GATEWAY]) == NULL)
1229 0 : sa = info->rti_info[RTAX_DST];
1230 :
1231 0 : if (sa != NULL && ifp != NULL)
1232 0 : info->rti_ifa = ifaof_ifpforaddr(sa, ifp);
1233 0 : else if (info->rti_info[RTAX_DST] != NULL &&
1234 0 : info->rti_info[RTAX_GATEWAY] != NULL)
1235 0 : info->rti_ifa = ifa_ifwithroute(info->rti_flags,
1236 : info->rti_info[RTAX_DST],
1237 : info->rti_info[RTAX_GATEWAY],
1238 : rtid);
1239 0 : else if (sa != NULL)
1240 0 : info->rti_ifa = ifa_ifwithroute(info->rti_flags,
1241 : sa, sa, rtid);
1242 0 : }
1243 :
1244 0 : if_put(ifp);
1245 :
1246 0 : if (info->rti_ifa == NULL)
1247 0 : return (ENETUNREACH);
1248 :
1249 0 : return (0);
1250 0 : }
1251 :
1252 : int
1253 0 : route_cleargateway(struct rtentry *rt, void *arg, unsigned int rtableid)
1254 : {
1255 0 : struct rtentry *nhrt = arg;
1256 :
1257 0 : if (ISSET(rt->rt_flags, RTF_GATEWAY) && rt->rt_gwroute == nhrt &&
1258 0 : !ISSET(rt->rt_locks, RTV_MTU))
1259 0 : rt->rt_mtu = 0;
1260 :
1261 0 : return (0);
1262 : }
1263 :
1264 : /*
1265 : * Check if the user request to insert an ARP entry does not conflict
1266 : * with existing ones.
1267 : *
1268 : * Only two entries are allowed for a given IP address: a private one
1269 : * (priv) and a public one (pub).
1270 : */
1271 : int
1272 0 : route_arp_conflict(struct rtentry *rt, struct rt_addrinfo *info)
1273 : {
1274 0 : int proxy = (info->rti_flags & RTF_ANNOUNCE);
1275 :
1276 0 : if ((info->rti_flags & RTF_LLINFO) == 0 ||
1277 0 : (info->rti_info[RTAX_DST]->sa_family != AF_INET))
1278 0 : return (0);
1279 :
1280 0 : if (rt == NULL || !ISSET(rt->rt_flags, RTF_LLINFO))
1281 0 : return (0);
1282 :
1283 : /* If the entry is cached, it can be updated. */
1284 0 : if (ISSET(rt->rt_flags, RTF_CACHED))
1285 0 : return (0);
1286 :
1287 : /*
1288 : * Same destination, not cached and both "priv" or "pub" conflict.
1289 : * If a second entry exists, it always conflict.
1290 : */
1291 0 : if ((ISSET(rt->rt_flags, RTF_ANNOUNCE) == proxy) ||
1292 0 : ISSET(rt->rt_flags, RTF_MPATH))
1293 0 : return (EEXIST);
1294 :
1295 : /* No conflict but an entry exist so we need to force mpath. */
1296 0 : info->rti_flags |= RTF_MPATH;
1297 0 : return (0);
1298 0 : }
1299 :
1300 : void
1301 0 : rtm_setmetrics(u_long which, const struct rt_metrics *in,
1302 : struct rt_kmetrics *out)
1303 : {
1304 : int64_t expire;
1305 :
1306 0 : if (which & RTV_MTU)
1307 0 : out->rmx_mtu = in->rmx_mtu;
1308 0 : if (which & RTV_EXPIRE) {
1309 0 : expire = in->rmx_expire;
1310 0 : if (expire != 0) {
1311 0 : expire -= time_second;
1312 0 : expire += time_uptime;
1313 0 : }
1314 :
1315 0 : out->rmx_expire = expire;
1316 0 : }
1317 0 : }
1318 :
1319 : void
1320 0 : rtm_getmetrics(const struct rt_kmetrics *in, struct rt_metrics *out)
1321 : {
1322 : int64_t expire;
1323 :
1324 0 : expire = in->rmx_expire;
1325 0 : if (expire != 0) {
1326 0 : expire -= time_uptime;
1327 0 : expire += time_second;
1328 0 : }
1329 :
1330 0 : bzero(out, sizeof(*out));
1331 0 : out->rmx_locks = in->rmx_locks;
1332 0 : out->rmx_mtu = in->rmx_mtu;
1333 0 : out->rmx_expire = expire;
1334 0 : out->rmx_pksent = in->rmx_pksent;
1335 0 : }
1336 :
1337 : #define ROUNDUP(a) \
1338 : ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1339 : #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
1340 :
1341 : void
1342 0 : rtm_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
1343 : {
1344 : struct sockaddr *sa;
1345 : int i;
1346 :
1347 0 : bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
1348 0 : for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
1349 0 : if ((rtinfo->rti_addrs & (1 << i)) == 0)
1350 : continue;
1351 0 : rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
1352 0 : ADVANCE(cp, sa);
1353 0 : }
1354 0 : }
1355 :
1356 : struct mbuf *
1357 0 : rtm_msg1(int type, struct rt_addrinfo *rtinfo)
1358 : {
1359 : struct rt_msghdr *rtm;
1360 : struct mbuf *m;
1361 : int i;
1362 : struct sockaddr *sa;
1363 : int len, dlen, hlen;
1364 :
1365 0 : switch (type) {
1366 : case RTM_DELADDR:
1367 : case RTM_NEWADDR:
1368 : len = sizeof(struct ifa_msghdr);
1369 0 : break;
1370 : case RTM_IFINFO:
1371 : len = sizeof(struct if_msghdr);
1372 0 : break;
1373 : case RTM_IFANNOUNCE:
1374 : len = sizeof(struct if_announcemsghdr);
1375 0 : break;
1376 : #ifdef BFD
1377 : case RTM_BFD:
1378 : len = sizeof(struct bfd_msghdr);
1379 : break;
1380 : #endif
1381 : default:
1382 : len = sizeof(struct rt_msghdr);
1383 0 : break;
1384 : }
1385 0 : if (len > MCLBYTES)
1386 0 : panic("rtm_msg1");
1387 0 : m = m_gethdr(M_DONTWAIT, MT_DATA);
1388 0 : if (m && len > MHLEN) {
1389 0 : MCLGET(m, M_DONTWAIT);
1390 0 : if ((m->m_flags & M_EXT) == 0) {
1391 0 : m_free(m);
1392 : m = NULL;
1393 0 : }
1394 : }
1395 0 : if (m == NULL)
1396 0 : return (m);
1397 0 : m->m_pkthdr.len = m->m_len = hlen = len;
1398 0 : m->m_pkthdr.ph_ifidx = 0;
1399 0 : rtm = mtod(m, struct rt_msghdr *);
1400 0 : bzero(rtm, len);
1401 0 : for (i = 0; i < RTAX_MAX; i++) {
1402 0 : if (rtinfo == NULL || (sa = rtinfo->rti_info[i]) == NULL)
1403 : continue;
1404 0 : rtinfo->rti_addrs |= (1 << i);
1405 0 : dlen = ROUNDUP(sa->sa_len);
1406 0 : if (m_copyback(m, len, dlen, sa, M_NOWAIT)) {
1407 0 : m_freem(m);
1408 0 : return (NULL);
1409 : }
1410 0 : len += dlen;
1411 0 : }
1412 0 : rtm->rtm_msglen = len;
1413 0 : rtm->rtm_hdrlen = hlen;
1414 0 : rtm->rtm_version = RTM_VERSION;
1415 0 : rtm->rtm_type = type;
1416 0 : return (m);
1417 0 : }
1418 :
1419 : int
1420 0 : rtm_msg2(int type, int vers, struct rt_addrinfo *rtinfo, caddr_t cp,
1421 : struct walkarg *w)
1422 : {
1423 : int i;
1424 : int len, dlen, hlen, second_time = 0;
1425 : caddr_t cp0;
1426 :
1427 0 : rtinfo->rti_addrs = 0;
1428 : again:
1429 0 : switch (type) {
1430 : case RTM_DELADDR:
1431 : case RTM_NEWADDR:
1432 : len = sizeof(struct ifa_msghdr);
1433 0 : break;
1434 : case RTM_IFINFO:
1435 : len = sizeof(struct if_msghdr);
1436 0 : break;
1437 : default:
1438 : len = sizeof(struct rt_msghdr);
1439 0 : break;
1440 : }
1441 : hlen = len;
1442 0 : if ((cp0 = cp) != NULL)
1443 0 : cp += len;
1444 0 : for (i = 0; i < RTAX_MAX; i++) {
1445 : struct sockaddr *sa;
1446 :
1447 0 : if ((sa = rtinfo->rti_info[i]) == NULL)
1448 0 : continue;
1449 0 : rtinfo->rti_addrs |= (1 << i);
1450 0 : dlen = ROUNDUP(sa->sa_len);
1451 0 : if (cp) {
1452 0 : bcopy(sa, cp, (size_t)dlen);
1453 0 : cp += dlen;
1454 0 : }
1455 0 : len += dlen;
1456 0 : }
1457 : /* align message length to the next natural boundary */
1458 0 : len = ALIGN(len);
1459 0 : if (cp == 0 && w != NULL && !second_time) {
1460 0 : w->w_needed += len;
1461 0 : if (w->w_needed <= 0 && w->w_where) {
1462 0 : if (w->w_tmemsize < len) {
1463 0 : free(w->w_tmem, M_RTABLE, w->w_tmemsize);
1464 0 : w->w_tmem = malloc(len, M_RTABLE, M_NOWAIT);
1465 0 : if (w->w_tmem)
1466 0 : w->w_tmemsize = len;
1467 : }
1468 0 : if (w->w_tmem) {
1469 : cp = w->w_tmem;
1470 : second_time = 1;
1471 0 : goto again;
1472 : } else
1473 0 : w->w_where = 0;
1474 0 : }
1475 : }
1476 0 : if (cp && w) /* clear the message header */
1477 0 : bzero(cp0, hlen);
1478 :
1479 0 : if (cp) {
1480 0 : struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
1481 :
1482 0 : rtm->rtm_version = RTM_VERSION;
1483 0 : rtm->rtm_type = type;
1484 0 : rtm->rtm_msglen = len;
1485 0 : rtm->rtm_hdrlen = hlen;
1486 0 : }
1487 0 : return (len);
1488 : }
1489 :
1490 : void
1491 0 : rtm_send(struct rtentry *rt, int cmd, int error, unsigned int rtableid)
1492 : {
1493 0 : struct rt_addrinfo info;
1494 : struct ifnet *ifp;
1495 0 : struct sockaddr_rtlabel sa_rl;
1496 0 : struct sockaddr_in6 sa_mask;
1497 :
1498 0 : memset(&info, 0, sizeof(info));
1499 0 : info.rti_info[RTAX_DST] = rt_key(rt);
1500 0 : info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
1501 0 : if (!ISSET(rt->rt_flags, RTF_HOST))
1502 0 : info.rti_info[RTAX_NETMASK] = rt_plen2mask(rt, &sa_mask);
1503 0 : info.rti_info[RTAX_LABEL] = rtlabel_id2sa(rt->rt_labelid, &sa_rl);
1504 0 : ifp = if_get(rt->rt_ifidx);
1505 0 : if (ifp != NULL) {
1506 0 : info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl);
1507 0 : info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
1508 0 : }
1509 :
1510 0 : rtm_miss(cmd, &info, rt->rt_flags, rt->rt_priority, rt->rt_ifidx, error,
1511 : rtableid);
1512 0 : if_put(ifp);
1513 0 : }
1514 :
1515 : /*
1516 : * This routine is called to generate a message from the routing
1517 : * socket indicating that a redirect has occurred, a routing lookup
1518 : * has failed, or that a protocol has detected timeouts to a particular
1519 : * destination.
1520 : */
1521 : void
1522 0 : rtm_miss(int type, struct rt_addrinfo *rtinfo, int flags, uint8_t prio,
1523 : u_int ifidx, int error, u_int tableid)
1524 : {
1525 : struct rt_msghdr *rtm;
1526 : struct mbuf *m;
1527 0 : struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
1528 :
1529 0 : if (rtptable.rtp_count == 0)
1530 0 : return;
1531 0 : m = rtm_msg1(type, rtinfo);
1532 0 : if (m == NULL)
1533 0 : return;
1534 0 : rtm = mtod(m, struct rt_msghdr *);
1535 0 : rtm->rtm_flags = RTF_DONE | flags;
1536 0 : rtm->rtm_priority = prio;
1537 0 : rtm->rtm_errno = error;
1538 0 : rtm->rtm_tableid = tableid;
1539 0 : rtm->rtm_addrs = rtinfo->rti_addrs;
1540 0 : rtm->rtm_index = ifidx;
1541 0 : route_input(m, NULL, sa ? sa->sa_family : AF_UNSPEC);
1542 0 : }
1543 :
1544 : /*
1545 : * This routine is called to generate a message from the routing
1546 : * socket indicating that the status of a network interface has changed.
1547 : */
1548 : void
1549 0 : rtm_ifchg(struct ifnet *ifp)
1550 : {
1551 : struct if_msghdr *ifm;
1552 : struct mbuf *m;
1553 :
1554 0 : if (rtptable.rtp_count == 0)
1555 0 : return;
1556 0 : m = rtm_msg1(RTM_IFINFO, NULL);
1557 0 : if (m == NULL)
1558 0 : return;
1559 0 : ifm = mtod(m, struct if_msghdr *);
1560 0 : ifm->ifm_index = ifp->if_index;
1561 0 : ifm->ifm_tableid = ifp->if_rdomain;
1562 0 : ifm->ifm_flags = ifp->if_flags;
1563 0 : ifm->ifm_xflags = ifp->if_xflags;
1564 0 : if_getdata(ifp, &ifm->ifm_data);
1565 0 : ifm->ifm_addrs = 0;
1566 0 : route_input(m, NULL, AF_UNSPEC);
1567 0 : }
1568 :
1569 : /*
1570 : * This is called to generate messages from the routing socket
1571 : * indicating a network interface has had addresses associated with it.
1572 : * if we ever reverse the logic and replace messages TO the routing
1573 : * socket indicate a request to configure interfaces, then it will
1574 : * be unnecessary as the routing socket will automatically generate
1575 : * copies of it.
1576 : */
1577 : void
1578 0 : rtm_addr(int cmd, struct ifaddr *ifa)
1579 : {
1580 0 : struct ifnet *ifp = ifa->ifa_ifp;
1581 : struct mbuf *m;
1582 0 : struct rt_addrinfo info;
1583 : struct ifa_msghdr *ifam;
1584 :
1585 0 : if (rtptable.rtp_count == 0)
1586 0 : return;
1587 :
1588 0 : memset(&info, 0, sizeof(info));
1589 0 : info.rti_info[RTAX_IFA] = ifa->ifa_addr;
1590 0 : info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl);
1591 0 : info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
1592 0 : info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
1593 0 : if ((m = rtm_msg1(cmd, &info)) == NULL)
1594 0 : return;
1595 0 : ifam = mtod(m, struct ifa_msghdr *);
1596 0 : ifam->ifam_index = ifp->if_index;
1597 0 : ifam->ifam_metric = ifa->ifa_metric;
1598 0 : ifam->ifam_flags = ifa->ifa_flags;
1599 0 : ifam->ifam_addrs = info.rti_addrs;
1600 0 : ifam->ifam_tableid = ifp->if_rdomain;
1601 :
1602 0 : route_input(m, NULL,
1603 0 : ifa->ifa_addr ? ifa->ifa_addr->sa_family : AF_UNSPEC);
1604 0 : }
1605 :
1606 : /*
1607 : * This is called to generate routing socket messages indicating
1608 : * network interface arrival and departure.
1609 : */
1610 : void
1611 0 : rtm_ifannounce(struct ifnet *ifp, int what)
1612 : {
1613 : struct if_announcemsghdr *ifan;
1614 : struct mbuf *m;
1615 :
1616 0 : if (rtptable.rtp_count == 0)
1617 0 : return;
1618 0 : m = rtm_msg1(RTM_IFANNOUNCE, NULL);
1619 0 : if (m == NULL)
1620 0 : return;
1621 0 : ifan = mtod(m, struct if_announcemsghdr *);
1622 0 : ifan->ifan_index = ifp->if_index;
1623 0 : strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
1624 0 : ifan->ifan_what = what;
1625 0 : route_input(m, NULL, AF_UNSPEC);
1626 0 : }
1627 :
1628 : #ifdef BFD
1629 : /*
1630 : * This is used to generate routing socket messages indicating
1631 : * the state of a BFD session.
1632 : */
1633 : void
1634 : rtm_bfd(struct bfd_config *bfd)
1635 : {
1636 : struct bfd_msghdr *bfdm;
1637 : struct sockaddr_bfd sa_bfd;
1638 : struct mbuf *m;
1639 : struct rt_addrinfo info;
1640 :
1641 : if (rtptable.rtp_count == 0)
1642 : return;
1643 : memset(&info, 0, sizeof(info));
1644 : info.rti_info[RTAX_DST] = rt_key(bfd->bc_rt);
1645 : info.rti_info[RTAX_IFA] = bfd->bc_rt->rt_ifa->ifa_addr;
1646 :
1647 : m = rtm_msg1(RTM_BFD, &info);
1648 : if (m == NULL)
1649 : return;
1650 : bfdm = mtod(m, struct bfd_msghdr *);
1651 : bfdm->bm_addrs = info.rti_addrs;
1652 :
1653 : bfd2sa(bfd->bc_rt, &sa_bfd);
1654 : memcpy(&bfdm->bm_sa, &sa_bfd, sizeof(sa_bfd));
1655 :
1656 : route_input(m, NULL, info.rti_info[RTAX_DST]->sa_family);
1657 : }
1658 : #endif /* BFD */
1659 :
1660 : /*
1661 : * This is used in dumping the kernel table via sysctl().
1662 : */
1663 : int
1664 0 : sysctl_dumpentry(struct rtentry *rt, void *v, unsigned int id)
1665 : {
1666 0 : struct walkarg *w = v;
1667 : int error = 0, size;
1668 0 : struct rt_addrinfo info;
1669 : struct ifnet *ifp;
1670 : #ifdef BFD
1671 : struct sockaddr_bfd sa_bfd;
1672 : #endif
1673 0 : struct sockaddr_rtlabel sa_rl;
1674 0 : struct sockaddr_in6 sa_mask;
1675 :
1676 0 : if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
1677 0 : return 0;
1678 0 : if (w->w_op == NET_RT_DUMP && w->w_arg) {
1679 0 : u_int8_t prio = w->w_arg & RTP_MASK;
1680 0 : if (w->w_arg < 0) {
1681 0 : prio = (-w->w_arg) & RTP_MASK;
1682 : /* Show all routes that are not this priority */
1683 0 : if (prio == (rt->rt_priority & RTP_MASK))
1684 0 : return 0;
1685 : } else {
1686 0 : if (prio != (rt->rt_priority & RTP_MASK) &&
1687 0 : prio != RTP_ANY)
1688 0 : return 0;
1689 : }
1690 0 : }
1691 0 : bzero(&info, sizeof(info));
1692 0 : info.rti_info[RTAX_DST] = rt_key(rt);
1693 0 : info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
1694 0 : info.rti_info[RTAX_NETMASK] = rt_plen2mask(rt, &sa_mask);
1695 0 : ifp = if_get(rt->rt_ifidx);
1696 0 : if (ifp != NULL) {
1697 0 : info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl);
1698 0 : info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
1699 0 : if (ifp->if_flags & IFF_POINTOPOINT)
1700 0 : info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr;
1701 : }
1702 0 : if_put(ifp);
1703 0 : info.rti_info[RTAX_LABEL] = rtlabel_id2sa(rt->rt_labelid, &sa_rl);
1704 : #ifdef BFD
1705 : if (rt->rt_flags & RTF_BFD)
1706 : info.rti_info[RTAX_BFD] = bfd2sa(rt, &sa_bfd);
1707 : #endif
1708 : #ifdef MPLS
1709 0 : if (rt->rt_flags & RTF_MPLS) {
1710 0 : struct sockaddr_mpls sa_mpls;
1711 :
1712 0 : bzero(&sa_mpls, sizeof(sa_mpls));
1713 0 : sa_mpls.smpls_family = AF_MPLS;
1714 0 : sa_mpls.smpls_len = sizeof(sa_mpls);
1715 0 : sa_mpls.smpls_label = ((struct rt_mpls *)
1716 0 : rt->rt_llinfo)->mpls_label;
1717 0 : info.rti_info[RTAX_SRC] = (struct sockaddr *)&sa_mpls;
1718 0 : info.rti_mpls = ((struct rt_mpls *)
1719 0 : rt->rt_llinfo)->mpls_operation;
1720 0 : }
1721 : #endif
1722 :
1723 0 : size = rtm_msg2(RTM_GET, RTM_VERSION, &info, NULL, w);
1724 0 : if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1725 0 : struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
1726 :
1727 0 : rtm->rtm_pid = curproc->p_p->ps_pid;
1728 0 : rtm->rtm_flags = rt->rt_flags;
1729 0 : rtm->rtm_priority = rt->rt_priority & RTP_MASK;
1730 0 : rtm_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
1731 : /* Do not account the routing table's reference. */
1732 0 : rtm->rtm_rmx.rmx_refcnt = rt->rt_refcnt - 1;
1733 0 : rtm->rtm_index = rt->rt_ifidx;
1734 0 : rtm->rtm_addrs = info.rti_addrs;
1735 0 : rtm->rtm_tableid = id;
1736 : #ifdef MPLS
1737 0 : rtm->rtm_mpls = info.rti_mpls;
1738 : #endif
1739 0 : if ((error = copyout(rtm, w->w_where, size)) != 0)
1740 0 : w->w_where = NULL;
1741 : else
1742 0 : w->w_where += size;
1743 0 : }
1744 0 : return (error);
1745 0 : }
1746 :
1747 : int
1748 0 : sysctl_iflist(int af, struct walkarg *w)
1749 : {
1750 : struct ifnet *ifp;
1751 : struct ifaddr *ifa;
1752 0 : struct rt_addrinfo info;
1753 : int len, error = 0;
1754 :
1755 0 : bzero(&info, sizeof(info));
1756 0 : TAILQ_FOREACH(ifp, &ifnet, if_list) {
1757 0 : if (w->w_arg && w->w_arg != ifp->if_index)
1758 : continue;
1759 : /* Copy the link-layer address first */
1760 0 : info.rti_info[RTAX_IFP] = sdltosa(ifp->if_sadl);
1761 0 : len = rtm_msg2(RTM_IFINFO, RTM_VERSION, &info, 0, w);
1762 0 : if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1763 : struct if_msghdr *ifm;
1764 :
1765 0 : ifm = (struct if_msghdr *)w->w_tmem;
1766 0 : ifm->ifm_index = ifp->if_index;
1767 0 : ifm->ifm_tableid = ifp->if_rdomain;
1768 0 : ifm->ifm_flags = ifp->if_flags;
1769 0 : if_getdata(ifp, &ifm->ifm_data);
1770 0 : ifm->ifm_addrs = info.rti_addrs;
1771 0 : error = copyout(ifm, w->w_where, len);
1772 0 : if (error)
1773 0 : return (error);
1774 0 : w->w_where += len;
1775 0 : }
1776 0 : info.rti_info[RTAX_IFP] = NULL;
1777 0 : TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1778 0 : KASSERT(ifa->ifa_addr->sa_family != AF_LINK);
1779 0 : if (af && af != ifa->ifa_addr->sa_family)
1780 : continue;
1781 0 : info.rti_info[RTAX_IFA] = ifa->ifa_addr;
1782 0 : info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
1783 0 : info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
1784 0 : len = rtm_msg2(RTM_NEWADDR, RTM_VERSION, &info, 0, w);
1785 0 : if (w->w_where && w->w_tmem && w->w_needed <= 0) {
1786 : struct ifa_msghdr *ifam;
1787 :
1788 0 : ifam = (struct ifa_msghdr *)w->w_tmem;
1789 0 : ifam->ifam_index = ifa->ifa_ifp->if_index;
1790 0 : ifam->ifam_flags = ifa->ifa_flags;
1791 0 : ifam->ifam_metric = ifa->ifa_metric;
1792 0 : ifam->ifam_addrs = info.rti_addrs;
1793 0 : error = copyout(w->w_tmem, w->w_where, len);
1794 0 : if (error)
1795 0 : return (error);
1796 0 : w->w_where += len;
1797 0 : }
1798 : }
1799 0 : info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] =
1800 0 : info.rti_info[RTAX_BRD] = NULL;
1801 0 : }
1802 0 : return (0);
1803 0 : }
1804 :
1805 : int
1806 0 : sysctl_ifnames(struct walkarg *w)
1807 : {
1808 0 : struct if_nameindex_msg ifn;
1809 : struct ifnet *ifp;
1810 : int error = 0;
1811 :
1812 : /* XXX ignore tableid for now */
1813 0 : TAILQ_FOREACH(ifp, &ifnet, if_list) {
1814 0 : if (w->w_arg && w->w_arg != ifp->if_index)
1815 : continue;
1816 0 : w->w_needed += sizeof(ifn);
1817 0 : if (w->w_where && w->w_needed <= 0) {
1818 :
1819 0 : memset(&ifn, 0, sizeof(ifn));
1820 0 : ifn.if_index = ifp->if_index;
1821 0 : strlcpy(ifn.if_name, ifp->if_xname,
1822 : sizeof(ifn.if_name));
1823 0 : error = copyout(&ifn, w->w_where, sizeof(ifn));
1824 0 : if (error)
1825 0 : return (error);
1826 0 : w->w_where += sizeof(ifn);
1827 0 : }
1828 : }
1829 :
1830 0 : return (0);
1831 0 : }
1832 :
1833 : int
1834 0 : sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new,
1835 : size_t newlen)
1836 : {
1837 : int i, error = EINVAL;
1838 : u_char af;
1839 0 : struct walkarg w;
1840 0 : struct rt_tableinfo tableinfo;
1841 : u_int tableid = 0;
1842 :
1843 0 : if (new)
1844 0 : return (EPERM);
1845 0 : if (namelen < 3 || namelen > 4)
1846 0 : return (EINVAL);
1847 0 : af = name[0];
1848 0 : bzero(&w, sizeof(w));
1849 0 : w.w_where = where;
1850 0 : w.w_given = *given;
1851 0 : w.w_needed = 0 - w.w_given;
1852 0 : w.w_op = name[1];
1853 0 : w.w_arg = name[2];
1854 :
1855 0 : if (namelen == 4) {
1856 0 : tableid = name[3];
1857 0 : if (!rtable_exists(tableid))
1858 0 : return (ENOENT);
1859 : } else
1860 0 : tableid = curproc->p_p->ps_rtableid;
1861 :
1862 0 : switch (w.w_op) {
1863 : case NET_RT_DUMP:
1864 : case NET_RT_FLAGS:
1865 0 : NET_LOCK();
1866 0 : for (i = 1; i <= AF_MAX; i++) {
1867 0 : if (af != 0 && af != i)
1868 : continue;
1869 :
1870 0 : error = rtable_walk(tableid, i, sysctl_dumpentry, &w);
1871 0 : if (error == EAFNOSUPPORT)
1872 : error = 0;
1873 0 : if (error)
1874 : break;
1875 : }
1876 0 : NET_UNLOCK();
1877 0 : break;
1878 :
1879 : case NET_RT_IFLIST:
1880 0 : NET_LOCK();
1881 0 : error = sysctl_iflist(af, &w);
1882 0 : NET_UNLOCK();
1883 0 : break;
1884 :
1885 : case NET_RT_STATS:
1886 0 : return (sysctl_rtable_rtstat(where, given, new));
1887 : case NET_RT_TABLE:
1888 0 : tableid = w.w_arg;
1889 0 : if (!rtable_exists(tableid))
1890 0 : return (ENOENT);
1891 0 : memset(&tableinfo, 0, sizeof tableinfo);
1892 0 : tableinfo.rti_tableid = tableid;
1893 0 : tableinfo.rti_domainid = rtable_l2(tableid);
1894 0 : error = sysctl_rdstruct(where, given, new,
1895 : &tableinfo, sizeof(tableinfo));
1896 0 : return (error);
1897 : case NET_RT_IFNAMES:
1898 0 : NET_LOCK();
1899 0 : error = sysctl_ifnames(&w);
1900 0 : NET_UNLOCK();
1901 0 : break;
1902 : }
1903 0 : free(w.w_tmem, M_RTABLE, w.w_tmemsize);
1904 0 : w.w_needed += w.w_given;
1905 0 : if (where) {
1906 0 : *given = w.w_where - (caddr_t)where;
1907 0 : if (*given < w.w_needed)
1908 0 : return (ENOMEM);
1909 : } else
1910 0 : *given = (11 * w.w_needed) / 10;
1911 :
1912 0 : return (error);
1913 0 : }
1914 :
1915 : int
1916 0 : sysctl_rtable_rtstat(void *oldp, size_t *oldlenp, void *newp)
1917 : {
1918 : extern struct cpumem *rtcounters;
1919 0 : uint64_t counters[rts_ncounters];
1920 0 : struct rtstat rtstat;
1921 0 : uint32_t *words = (uint32_t *)&rtstat;
1922 : int i;
1923 :
1924 : CTASSERT(sizeof(rtstat) == (nitems(counters) * sizeof(uint32_t)));
1925 0 : memset(&rtstat, 0, sizeof rtstat);
1926 0 : counters_read(rtcounters, counters, nitems(counters));
1927 :
1928 0 : for (i = 0; i < nitems(counters); i++)
1929 0 : words[i] = (uint32_t)counters[i];
1930 :
1931 0 : return (sysctl_rdstruct(oldp, oldlenp, newp, &rtstat, sizeof(rtstat)));
1932 0 : }
1933 :
1934 : int
1935 0 : rtm_validate_proposal(struct rt_addrinfo *info)
1936 : {
1937 0 : if (info->rti_addrs & ~(RTA_NETMASK | RTA_IFA | RTA_DNS | RTA_STATIC |
1938 : RTA_SEARCH)) {
1939 0 : return -1;
1940 : }
1941 :
1942 0 : if (ISSET(info->rti_addrs, RTA_NETMASK)) {
1943 0 : struct sockaddr *sa = info->rti_info[RTAX_NETMASK];
1944 0 : if (sa == NULL)
1945 0 : return -1;
1946 0 : switch (sa->sa_family) {
1947 : case AF_INET:
1948 0 : if (sa->sa_len != sizeof(struct sockaddr_in))
1949 0 : return -1;
1950 : break;
1951 : case AF_INET6:
1952 0 : if (sa->sa_len != sizeof(struct sockaddr_in6))
1953 0 : return -1;
1954 : break;
1955 : default:
1956 0 : return -1;
1957 : }
1958 0 : }
1959 :
1960 0 : if (ISSET(info->rti_addrs, RTA_IFA)) {
1961 0 : struct sockaddr *sa = info->rti_info[RTAX_IFA];
1962 0 : if (sa == NULL)
1963 0 : return -1;
1964 0 : switch (sa->sa_family) {
1965 : case AF_INET:
1966 0 : if (sa->sa_len != sizeof(struct sockaddr_in))
1967 0 : return -1;
1968 : break;
1969 : case AF_INET6:
1970 0 : if (sa->sa_len != sizeof(struct sockaddr_in6))
1971 0 : return -1;
1972 : break;
1973 : default:
1974 0 : return -1;
1975 : }
1976 0 : }
1977 :
1978 0 : if (ISSET(info->rti_addrs, RTA_DNS)) {
1979 : struct sockaddr_rtdns *rtdns =
1980 0 : (struct sockaddr_rtdns *)info->rti_info[RTAX_DNS];
1981 0 : if (rtdns == NULL)
1982 0 : return -1;
1983 0 : if (rtdns->sr_len > sizeof(*rtdns))
1984 0 : return -1;
1985 0 : if (rtdns->sr_len <=
1986 : offsetof(struct sockaddr_rtdns, sr_dns))
1987 0 : return -1;
1988 0 : }
1989 :
1990 0 : if (ISSET(info->rti_addrs, RTA_STATIC)) {
1991 : struct sockaddr_rtstatic *rtstatic =
1992 0 : (struct sockaddr_rtstatic *)info->rti_info[RTAX_STATIC];
1993 0 : if (rtstatic == NULL)
1994 0 : return -1;
1995 0 : if (rtstatic->sr_len > sizeof(*rtstatic))
1996 0 : return -1;
1997 0 : if (rtstatic->sr_len <=
1998 : offsetof(struct sockaddr_rtstatic, sr_static))
1999 0 : return -1;
2000 0 : }
2001 :
2002 0 : if (ISSET(info->rti_addrs, RTA_SEARCH)) {
2003 : struct sockaddr_rtsearch *rtsearch =
2004 0 : (struct sockaddr_rtsearch *)info->rti_info[RTAX_SEARCH];
2005 0 : if (rtsearch == NULL)
2006 0 : return -1;
2007 0 : if (rtsearch->sr_len > sizeof(*rtsearch))
2008 0 : return -1;
2009 0 : if (rtsearch->sr_len <=
2010 : offsetof(struct sockaddr_rtsearch, sr_search))
2011 0 : return -1;
2012 0 : }
2013 :
2014 0 : return 0;
2015 0 : }
2016 :
2017 : /*
2018 : * Definitions of protocols supported in the ROUTE domain.
2019 : */
2020 :
2021 : extern struct domain routedomain; /* or at least forward */
2022 :
2023 : struct protosw routesw[] = {
2024 : {
2025 : .pr_type = SOCK_RAW,
2026 : .pr_domain = &routedomain,
2027 : .pr_flags = PR_ATOMIC|PR_ADDR|PR_WANTRCVD,
2028 : .pr_output = route_output,
2029 : .pr_ctloutput = route_ctloutput,
2030 : .pr_usrreq = route_usrreq,
2031 : .pr_attach = route_attach,
2032 : .pr_detach = route_detach,
2033 : .pr_init = route_prinit,
2034 : .pr_sysctl = sysctl_rtable
2035 : }
2036 : };
2037 :
2038 : struct domain routedomain = {
2039 : .dom_family = PF_ROUTE,
2040 : .dom_name = "route",
2041 : .dom_init = route_init,
2042 : .dom_protosw = routesw,
2043 : .dom_protoswNPROTOSW = &routesw[nitems(routesw)]
2044 : };
|