File: | net/rtsock.c |
Warning: | line 526, column 23 Access to field 'so_options' results in a dereference of a null pointer (loaded from variable 'so0') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: rtsock.c,v 1.373 2023/12/03 10:51:17 mvs 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/pool.h> | |||
73 | #include <sys/protosw.h> | |||
74 | #include <sys/srp.h> | |||
75 | ||||
76 | #include <net/if.h> | |||
77 | #include <net/if_dl.h> | |||
78 | #include <net/if_var.h> | |||
79 | #include <net/route.h> | |||
80 | ||||
81 | #include <netinet/in.h> | |||
82 | ||||
83 | #ifdef MPLS1 | |||
84 | #include <netmpls/mpls.h> | |||
85 | #endif | |||
86 | #ifdef IPSEC1 | |||
87 | #include <netinet/ip_ipsp.h> | |||
88 | #include <net/if_enc.h> | |||
89 | #endif | |||
90 | #ifdef BFD | |||
91 | #include <net/bfd.h> | |||
92 | #endif | |||
93 | ||||
94 | #include <sys/stdarg.h> | |||
95 | #include <sys/kernel.h> | |||
96 | #include <sys/timeout.h> | |||
97 | ||||
98 | #define ROUTESNDQ8192 8192 | |||
99 | #define ROUTERCVQ8192 8192 | |||
100 | ||||
101 | const struct sockaddr route_src = { 2, PF_ROUTE17, }; | |||
102 | ||||
103 | struct walkarg { | |||
104 | int w_op, w_arg, w_tmemsize; | |||
105 | size_t w_given, w_needed; | |||
106 | caddr_t w_where, w_tmem; | |||
107 | }; | |||
108 | ||||
109 | void route_prinit(void); | |||
110 | void rcb_ref(void *, void *); | |||
111 | void rcb_unref(void *, void *); | |||
112 | int route_output(struct mbuf *, struct socket *); | |||
113 | int route_ctloutput(int, struct socket *, int, int, struct mbuf *); | |||
114 | int route_attach(struct socket *, int, int); | |||
115 | int route_detach(struct socket *); | |||
116 | int route_disconnect(struct socket *); | |||
117 | int route_shutdown(struct socket *); | |||
118 | void route_rcvd(struct socket *); | |||
119 | int route_send(struct socket *, struct mbuf *, struct mbuf *, | |||
120 | struct mbuf *); | |||
121 | int route_sockaddr(struct socket *, struct mbuf *); | |||
122 | int route_peeraddr(struct socket *, struct mbuf *); | |||
123 | void route_input(struct mbuf *m0, struct socket *, sa_family_t); | |||
124 | int route_arp_conflict(struct rtentry *, struct rt_addrinfo *); | |||
125 | int route_cleargateway(struct rtentry *, void *, unsigned int); | |||
126 | void rtm_senddesync_timer(void *); | |||
127 | void rtm_senddesync(struct socket *); | |||
128 | int rtm_sendup(struct socket *, struct mbuf *); | |||
129 | ||||
130 | int rtm_getifa(struct rt_addrinfo *, unsigned int); | |||
131 | int rtm_output(struct rt_msghdr *, struct rtentry **, struct rt_addrinfo *, | |||
132 | uint8_t, unsigned int); | |||
133 | struct rt_msghdr *rtm_report(struct rtentry *, u_char, int, int); | |||
134 | struct mbuf *rtm_msg1(int, struct rt_addrinfo *); | |||
135 | int rtm_msg2(int, int, struct rt_addrinfo *, caddr_t, | |||
136 | struct walkarg *); | |||
137 | int rtm_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); | |||
138 | int rtm_validate_proposal(struct rt_addrinfo *); | |||
139 | void rtm_setmetrics(u_long, const struct rt_metrics *, | |||
140 | struct rt_kmetrics *); | |||
141 | void rtm_getmetrics(const struct rtentry *, | |||
142 | struct rt_metrics *); | |||
143 | ||||
144 | int sysctl_iflist(int, struct walkarg *); | |||
145 | int sysctl_ifnames(struct walkarg *); | |||
146 | int sysctl_rtable_rtstat(void *, size_t *, void *); | |||
147 | ||||
148 | int rt_setsource(unsigned int, const struct sockaddr *); | |||
149 | ||||
150 | /* | |||
151 | * Locks used to protect struct members | |||
152 | * I immutable after creation | |||
153 | * s solock | |||
154 | */ | |||
155 | struct rtpcb { | |||
156 | struct socket *rop_socket; /* [I] */ | |||
157 | ||||
158 | SRPL_ENTRY(rtpcb)struct { struct srp se_next; } rop_list; | |||
159 | struct refcnt rop_refcnt; | |||
160 | struct timeout rop_timeout; | |||
161 | unsigned int rop_msgfilter; /* [s] */ | |||
162 | unsigned int rop_flagfilter; /* [s] */ | |||
163 | unsigned int rop_flags; /* [s] */ | |||
164 | u_int rop_rtableid; /* [s] */ | |||
165 | unsigned short rop_proto; /* [I] */ | |||
166 | u_char rop_priority; /* [s] */ | |||
167 | }; | |||
168 | #define sotortpcb(so)((struct rtpcb *)(so)->so_pcb) ((struct rtpcb *)(so)->so_pcb) | |||
169 | ||||
170 | struct rtptable { | |||
171 | SRPL_HEAD(, rtpcb)struct srpl rtp_list; | |||
172 | struct srpl_rc rtp_rc; | |||
173 | struct rwlock rtp_lk; | |||
174 | unsigned int rtp_count; | |||
175 | }; | |||
176 | ||||
177 | struct pool rtpcb_pool; | |||
178 | struct rtptable rtptable; | |||
179 | ||||
180 | /* | |||
181 | * These flags and timeout are used for indicating to userland (via a | |||
182 | * RTM_DESYNC msg) when the route socket has overflowed and messages | |||
183 | * have been lost. | |||
184 | */ | |||
185 | #define ROUTECB_FLAG_DESYNC0x1 0x1 /* Route socket out of memory */ | |||
186 | #define ROUTECB_FLAG_FLUSH0x2 0x2 /* Wait until socket is empty before | |||
187 | queueing more packets */ | |||
188 | ||||
189 | #define ROUTE_DESYNC_RESEND_TIMEOUT200 200 /* In ms */ | |||
190 | ||||
191 | void | |||
192 | route_prinit(void) | |||
193 | { | |||
194 | srpl_rc_init(&rtptable.rtp_rc, rcb_ref, rcb_unref, NULL((void *)0)); | |||
195 | rw_init(&rtptable.rtp_lk, "rtsock")_rw_init_flags(&rtptable.rtp_lk, "rtsock", 0, ((void *)0) ); | |||
196 | SRPL_INIT(&rtptable.rtp_list)srp_init(&(&rtptable.rtp_list)->sl_head); | |||
197 | pool_init(&rtpcb_pool, sizeof(struct rtpcb), 0, | |||
198 | IPL_SOFTNET0x2, PR_WAITOK0x0001, "rtpcb", NULL((void *)0)); | |||
199 | } | |||
200 | ||||
201 | void | |||
202 | rcb_ref(void *null, void *v) | |||
203 | { | |||
204 | struct rtpcb *rop = v; | |||
205 | ||||
206 | refcnt_take(&rop->rop_refcnt); | |||
207 | } | |||
208 | ||||
209 | void | |||
210 | rcb_unref(void *null, void *v) | |||
211 | { | |||
212 | struct rtpcb *rop = v; | |||
213 | ||||
214 | refcnt_rele_wake(&rop->rop_refcnt); | |||
215 | } | |||
216 | ||||
217 | int | |||
218 | route_attach(struct socket *so, int proto, int wait) | |||
219 | { | |||
220 | struct rtpcb *rop; | |||
221 | int error; | |||
222 | ||||
223 | error = soreserve(so, ROUTESNDQ8192, ROUTERCVQ8192); | |||
224 | if (error) | |||
225 | return (error); | |||
226 | /* | |||
227 | * use the rawcb but allocate a rtpcb, this | |||
228 | * code does not care about the additional fields | |||
229 | * and works directly on the raw socket. | |||
230 | */ | |||
231 | rop = pool_get(&rtpcb_pool, (wait == M_WAIT0x0001 ? PR_WAITOK0x0001 : PR_NOWAIT0x0002) | | |||
232 | PR_ZERO0x0008); | |||
233 | if (rop == NULL((void *)0)) | |||
234 | return (ENOBUFS55); | |||
235 | so->so_pcb = rop; | |||
236 | /* Init the timeout structure */ | |||
237 | timeout_set_flags(&rop->rop_timeout, rtm_senddesync_timer, so, | |||
238 | KCLOCK_NONE(-1), TIMEOUT_PROC0x01 | TIMEOUT_MPSAFE0x10); | |||
239 | refcnt_init(&rop->rop_refcnt); | |||
240 | ||||
241 | rop->rop_socket = so; | |||
242 | rop->rop_proto = proto; | |||
243 | ||||
244 | rop->rop_rtableid = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_rtableid; | |||
245 | ||||
246 | soisconnected(so); | |||
247 | so->so_options |= SO_USELOOPBACK0x0040; | |||
248 | ||||
249 | rw_enter(&rtptable.rtp_lk, RW_WRITE0x0001UL); | |||
250 | SRPL_INSERT_HEAD_LOCKED(&rtptable.rtp_rc, &rtptable.rtp_list, rop,do { void *head; srp_init(&(rop)->rop_list.se_next); head = srp_get_locked(&(&rtptable.rtp_list)->sl_head); if (head != ((void *)0)) { (&rtptable.rtp_rc)->srpl_ref (&(&rtptable.rtp_rc)->srpl_gc.srp_gc_cookie, head) ; srp_update_locked(&(&rtptable.rtp_rc)->srpl_gc, & (rop)->rop_list.se_next, head); } (&rtptable.rtp_rc)-> srpl_ref(&(&rtptable.rtp_rc)->srpl_gc.srp_gc_cookie , rop); srp_update_locked(&(&rtptable.rtp_rc)->srpl_gc , &(&rtptable.rtp_list)->sl_head, (rop)); } while ( 0) | |||
251 | rop_list)do { void *head; srp_init(&(rop)->rop_list.se_next); head = srp_get_locked(&(&rtptable.rtp_list)->sl_head); if (head != ((void *)0)) { (&rtptable.rtp_rc)->srpl_ref (&(&rtptable.rtp_rc)->srpl_gc.srp_gc_cookie, head) ; srp_update_locked(&(&rtptable.rtp_rc)->srpl_gc, & (rop)->rop_list.se_next, head); } (&rtptable.rtp_rc)-> srpl_ref(&(&rtptable.rtp_rc)->srpl_gc.srp_gc_cookie , rop); srp_update_locked(&(&rtptable.rtp_rc)->srpl_gc , &(&rtptable.rtp_list)->sl_head, (rop)); } while ( 0); | |||
252 | rtptable.rtp_count++; | |||
253 | rw_exit(&rtptable.rtp_lk); | |||
254 | ||||
255 | return (0); | |||
256 | } | |||
257 | ||||
258 | int | |||
259 | route_detach(struct socket *so) | |||
260 | { | |||
261 | struct rtpcb *rop; | |||
262 | ||||
263 | soassertlocked(so); | |||
264 | ||||
265 | rop = sotortpcb(so)((struct rtpcb *)(so)->so_pcb); | |||
266 | if (rop == NULL((void *)0)) | |||
267 | return (EINVAL22); | |||
268 | ||||
269 | rw_enter(&rtptable.rtp_lk, RW_WRITE0x0001UL); | |||
270 | ||||
271 | rtptable.rtp_count--; | |||
272 | SRPL_REMOVE_LOCKED(&rtptable.rtp_rc, &rtptable.rtp_list, rop, rtpcb,do { struct srp *ref; struct rtpcb *c, *n; ref = &(&rtptable .rtp_list)->sl_head; while ((c = srp_get_locked(ref)) != ( rop)) ref = &c->rop_list.se_next; n = srp_get_locked(& (c)->rop_list.se_next); if (n != ((void *)0)) (&rtptable .rtp_rc)->srpl_ref(&(&rtptable.rtp_rc)->srpl_gc .srp_gc_cookie, n); srp_update_locked(&(&rtptable.rtp_rc )->srpl_gc, ref, n); srp_update_locked(&(&rtptable .rtp_rc)->srpl_gc, &c->rop_list.se_next, ((void *)0 )); } while (0) | |||
273 | rop_list)do { struct srp *ref; struct rtpcb *c, *n; ref = &(&rtptable .rtp_list)->sl_head; while ((c = srp_get_locked(ref)) != ( rop)) ref = &c->rop_list.se_next; n = srp_get_locked(& (c)->rop_list.se_next); if (n != ((void *)0)) (&rtptable .rtp_rc)->srpl_ref(&(&rtptable.rtp_rc)->srpl_gc .srp_gc_cookie, n); srp_update_locked(&(&rtptable.rtp_rc )->srpl_gc, ref, n); srp_update_locked(&(&rtptable .rtp_rc)->srpl_gc, &c->rop_list.se_next, ((void *)0 )); } while (0); | |||
274 | rw_exit(&rtptable.rtp_lk); | |||
275 | ||||
276 | sounlock(so); | |||
277 | ||||
278 | /* wait for all references to drop */ | |||
279 | refcnt_finalize(&rop->rop_refcnt, "rtsockrefs"); | |||
280 | timeout_del_barrier(&rop->rop_timeout); | |||
281 | ||||
282 | solock(so); | |||
283 | ||||
284 | so->so_pcb = NULL((void *)0); | |||
285 | KASSERT((so->so_state & SS_NOFDREF) == 0)(((so->so_state & 0x001) == 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/rtsock.c", 285, "(so->so_state & SS_NOFDREF) == 0" )); | |||
286 | pool_put(&rtpcb_pool, rop); | |||
287 | ||||
288 | return (0); | |||
289 | } | |||
290 | ||||
291 | int | |||
292 | route_disconnect(struct socket *so) | |||
293 | { | |||
294 | soisdisconnected(so); | |||
295 | return (0); | |||
296 | } | |||
297 | ||||
298 | int | |||
299 | route_shutdown(struct socket *so) | |||
300 | { | |||
301 | socantsendmore(so); | |||
302 | return (0); | |||
303 | } | |||
304 | ||||
305 | void | |||
306 | route_rcvd(struct socket *so) | |||
307 | { | |||
308 | struct rtpcb *rop = sotortpcb(so)((struct rtpcb *)(so)->so_pcb); | |||
309 | ||||
310 | soassertlocked(so); | |||
311 | ||||
312 | /* | |||
313 | * If we are in a FLUSH state, check if the buffer is | |||
314 | * empty so that we can clear the flag. | |||
315 | */ | |||
316 | if (((rop->rop_flags & ROUTECB_FLAG_FLUSH0x2) != 0) && | |||
317 | ((sbspace(rop->rop_socket, &rop->rop_socket->so_rcv) == | |||
318 | rop->rop_socket->so_rcv.sb_hiwat))) | |||
319 | rop->rop_flags &= ~ROUTECB_FLAG_FLUSH0x2; | |||
320 | } | |||
321 | ||||
322 | int | |||
323 | route_send(struct socket *so, struct mbuf *m, struct mbuf *nam, | |||
324 | struct mbuf *control) | |||
325 | { | |||
326 | int error; | |||
327 | ||||
328 | soassertlocked(so); | |||
329 | ||||
330 | if (control && control->m_lenm_hdr.mh_len) { | |||
331 | error = EOPNOTSUPP45; | |||
332 | goto out; | |||
333 | } | |||
334 | ||||
335 | if (nam) { | |||
336 | error = EISCONN56; | |||
337 | goto out; | |||
338 | } | |||
339 | ||||
340 | error = route_output(m, so); | |||
341 | m = NULL((void *)0); | |||
342 | ||||
343 | out: | |||
344 | m_freem(control); | |||
345 | m_freem(m); | |||
346 | ||||
347 | return (error); | |||
348 | } | |||
349 | ||||
350 | int | |||
351 | route_sockaddr(struct socket *so, struct mbuf *nam) | |||
352 | { | |||
353 | return (EINVAL22); | |||
354 | } | |||
355 | ||||
356 | int | |||
357 | route_peeraddr(struct socket *so, struct mbuf *nam) | |||
358 | { | |||
359 | /* minimal support, just implement a fake peer address */ | |||
360 | bcopy(&route_src, mtod(nam, caddr_t)((caddr_t)((nam)->m_hdr.mh_data)), route_src.sa_len); | |||
361 | nam->m_lenm_hdr.mh_len = route_src.sa_len; | |||
362 | return (0); | |||
363 | } | |||
364 | ||||
365 | int | |||
366 | route_ctloutput(int op, struct socket *so, int level, int optname, | |||
367 | struct mbuf *m) | |||
368 | { | |||
369 | struct rtpcb *rop = sotortpcb(so)((struct rtpcb *)(so)->so_pcb); | |||
370 | int error = 0; | |||
371 | unsigned int tid, prio; | |||
372 | ||||
373 | if (level != AF_ROUTE17) | |||
374 | return (EINVAL22); | |||
375 | ||||
376 | switch (op) { | |||
377 | case PRCO_SETOPT1: | |||
378 | switch (optname) { | |||
379 | case ROUTE_MSGFILTER1: | |||
380 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len != sizeof(unsigned int)) | |||
381 | error = EINVAL22; | |||
382 | else | |||
383 | rop->rop_msgfilter = *mtod(m, unsigned int *)((unsigned int *)((m)->m_hdr.mh_data)); | |||
384 | break; | |||
385 | case ROUTE_TABLEFILTER2: | |||
386 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len != sizeof(unsigned int)) { | |||
387 | error = EINVAL22; | |||
388 | break; | |||
389 | } | |||
390 | tid = *mtod(m, unsigned int *)((unsigned int *)((m)->m_hdr.mh_data)); | |||
391 | if (tid != RTABLE_ANY0xffffffff && !rtable_exists(tid)) | |||
392 | error = ENOENT2; | |||
393 | else | |||
394 | rop->rop_rtableid = tid; | |||
395 | break; | |||
396 | case ROUTE_PRIOFILTER3: | |||
397 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len != sizeof(unsigned int)) { | |||
398 | error = EINVAL22; | |||
399 | break; | |||
400 | } | |||
401 | prio = *mtod(m, unsigned int *)((unsigned int *)((m)->m_hdr.mh_data)); | |||
402 | if (prio > RTP_MAX63) | |||
403 | error = EINVAL22; | |||
404 | else | |||
405 | rop->rop_priority = prio; | |||
406 | break; | |||
407 | case ROUTE_FLAGFILTER4: | |||
408 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len != sizeof(unsigned int)) | |||
409 | error = EINVAL22; | |||
410 | else | |||
411 | rop->rop_flagfilter = *mtod(m, unsigned int *)((unsigned int *)((m)->m_hdr.mh_data)); | |||
412 | break; | |||
413 | default: | |||
414 | error = ENOPROTOOPT42; | |||
415 | break; | |||
416 | } | |||
417 | break; | |||
418 | case PRCO_GETOPT0: | |||
419 | switch (optname) { | |||
420 | case ROUTE_MSGFILTER1: | |||
421 | m->m_lenm_hdr.mh_len = sizeof(unsigned int); | |||
422 | *mtod(m, unsigned int *)((unsigned int *)((m)->m_hdr.mh_data)) = rop->rop_msgfilter; | |||
423 | break; | |||
424 | case ROUTE_TABLEFILTER2: | |||
425 | m->m_lenm_hdr.mh_len = sizeof(unsigned int); | |||
426 | *mtod(m, unsigned int *)((unsigned int *)((m)->m_hdr.mh_data)) = rop->rop_rtableid; | |||
427 | break; | |||
428 | case ROUTE_PRIOFILTER3: | |||
429 | m->m_lenm_hdr.mh_len = sizeof(unsigned int); | |||
430 | *mtod(m, unsigned int *)((unsigned int *)((m)->m_hdr.mh_data)) = rop->rop_priority; | |||
431 | break; | |||
432 | case ROUTE_FLAGFILTER4: | |||
433 | m->m_lenm_hdr.mh_len = sizeof(unsigned int); | |||
434 | *mtod(m, unsigned int *)((unsigned int *)((m)->m_hdr.mh_data)) = rop->rop_flagfilter; | |||
435 | break; | |||
436 | default: | |||
437 | error = ENOPROTOOPT42; | |||
438 | break; | |||
439 | } | |||
440 | } | |||
441 | return (error); | |||
442 | } | |||
443 | ||||
444 | void | |||
445 | rtm_senddesync_timer(void *xso) | |||
446 | { | |||
447 | struct socket *so = xso; | |||
448 | ||||
449 | solock(so); | |||
450 | rtm_senddesync(so); | |||
451 | sounlock(so); | |||
452 | } | |||
453 | ||||
454 | void | |||
455 | rtm_senddesync(struct socket *so) | |||
456 | { | |||
457 | struct rtpcb *rop = sotortpcb(so)((struct rtpcb *)(so)->so_pcb); | |||
458 | struct mbuf *desync_mbuf; | |||
459 | ||||
460 | soassertlocked(so); | |||
461 | ||||
462 | /* | |||
463 | * Dying socket is disconnected by upper layer and there is | |||
464 | * no reason to send packet. Also we shouldn't reschedule | |||
465 | * timeout(9), otherwise timeout_del_barrier(9) can't help us. | |||
466 | */ | |||
467 | if ((so->so_state & SS_ISCONNECTED0x002) == 0 || | |||
468 | (so->so_rcv.sb_state & SS_CANTRCVMORE0x020)) | |||
469 | return; | |||
470 | ||||
471 | /* If we are in a DESYNC state, try to send a RTM_DESYNC packet */ | |||
472 | if ((rop->rop_flags & ROUTECB_FLAG_DESYNC0x1) == 0) | |||
473 | return; | |||
474 | ||||
475 | /* | |||
476 | * If we fail to alloc memory or if sbappendaddr() | |||
477 | * fails, re-add timeout and try again. | |||
478 | */ | |||
479 | desync_mbuf = rtm_msg1(RTM_DESYNC0x10, NULL((void *)0)); | |||
480 | if (desync_mbuf != NULL((void *)0)) { | |||
481 | if (sbappendaddr(so, &so->so_rcv, &route_src, | |||
482 | desync_mbuf, NULL((void *)0)) != 0) { | |||
483 | rop->rop_flags &= ~ROUTECB_FLAG_DESYNC0x1; | |||
484 | sorwakeup(rop->rop_socket); | |||
485 | return; | |||
486 | } | |||
487 | m_freem(desync_mbuf); | |||
488 | } | |||
489 | /* Re-add timeout to try sending msg again */ | |||
490 | timeout_add_msec(&rop->rop_timeout, ROUTE_DESYNC_RESEND_TIMEOUT200); | |||
491 | } | |||
492 | ||||
493 | void | |||
494 | route_input(struct mbuf *m0, struct socket *so0, sa_family_t sa_family) | |||
495 | { | |||
496 | struct socket *so; | |||
497 | struct rtpcb *rop; | |||
498 | struct rt_msghdr *rtm; | |||
499 | struct mbuf *m = m0; | |||
500 | struct srp_ref sr; | |||
501 | ||||
502 | /* ensure that we can access the rtm_type via mtod() */ | |||
503 | if (m->m_lenm_hdr.mh_len < offsetof(struct rt_msghdr, rtm_type)__builtin_offsetof(struct rt_msghdr, rtm_type) + 1) { | |||
504 | m_freem(m); | |||
505 | return; | |||
506 | } | |||
507 | ||||
508 | SRPL_FOREACH(rop, &sr, &rtptable.rtp_list, rop_list)for ((rop) = srp_enter((&sr), &(&rtptable.rtp_list )->sl_head); (rop) != ((void *)0); (rop) = srp_follow((& sr), &(rop)->rop_list.se_next)) { | |||
509 | /* | |||
510 | * If route socket is bound to an address family only send | |||
511 | * messages that match the address family. Address family | |||
512 | * agnostic messages are always sent. | |||
513 | */ | |||
514 | if (sa_family != AF_UNSPEC0 && rop->rop_proto != AF_UNSPEC0 && | |||
515 | rop->rop_proto != sa_family) | |||
516 | continue; | |||
517 | ||||
518 | ||||
519 | so = rop->rop_socket; | |||
520 | solock(so); | |||
521 | ||||
522 | /* | |||
523 | * Check to see if we don't want our own messages and | |||
524 | * if we can receive anything. | |||
525 | */ | |||
526 | if ((so0 == so && !(so0->so_options & SO_USELOOPBACK0x0040)) || | |||
| ||||
527 | !(so->so_state & SS_ISCONNECTED0x002) || | |||
528 | (so->so_rcv.sb_state & SS_CANTRCVMORE0x020)) | |||
529 | goto next; | |||
530 | ||||
531 | /* filter messages that the process does not want */ | |||
532 | rtm = mtod(m, struct rt_msghdr *)((struct rt_msghdr *)((m)->m_hdr.mh_data)); | |||
533 | /* but RTM_DESYNC can't be filtered */ | |||
534 | if (rtm->rtm_type != RTM_DESYNC0x10) { | |||
535 | if (rop->rop_msgfilter != 0 && | |||
536 | !(rop->rop_msgfilter & (1U << rtm->rtm_type))) | |||
537 | goto next; | |||
538 | if (ISSET(rop->rop_flagfilter, rtm->rtm_flags)((rop->rop_flagfilter) & (rtm->rtm_flags))) | |||
539 | goto next; | |||
540 | } | |||
541 | switch (rtm->rtm_type) { | |||
542 | case RTM_IFANNOUNCE0xf: | |||
543 | case RTM_DESYNC0x10: | |||
544 | /* no tableid */ | |||
545 | break; | |||
546 | case RTM_RESOLVE0xb: | |||
547 | case RTM_NEWADDR0xc: | |||
548 | case RTM_DELADDR0xd: | |||
549 | case RTM_IFINFO0xe: | |||
550 | case RTM_80211INFO0x15: | |||
551 | case RTM_BFD0x12: | |||
552 | /* check against rdomain id */ | |||
553 | if (rop->rop_rtableid != RTABLE_ANY0xffffffff && | |||
554 | rtable_l2(rop->rop_rtableid) != rtm->rtm_tableid) | |||
555 | goto next; | |||
556 | break; | |||
557 | default: | |||
558 | if (rop->rop_priority != 0 && | |||
559 | rop->rop_priority < rtm->rtm_priority) | |||
560 | goto next; | |||
561 | /* check against rtable id */ | |||
562 | if (rop->rop_rtableid != RTABLE_ANY0xffffffff && | |||
563 | rop->rop_rtableid != rtm->rtm_tableid) | |||
564 | goto next; | |||
565 | break; | |||
566 | } | |||
567 | ||||
568 | /* | |||
569 | * Check to see if the flush flag is set. If so, don't queue | |||
570 | * any more messages until the flag is cleared. | |||
571 | */ | |||
572 | if ((rop->rop_flags & ROUTECB_FLAG_FLUSH0x2) != 0) | |||
573 | goto next; | |||
574 | ||||
575 | rtm_sendup(so, m); | |||
576 | next: | |||
577 | sounlock(so); | |||
578 | } | |||
579 | SRPL_LEAVE(&sr)srp_leave((&sr)); | |||
580 | ||||
581 | m_freem(m); | |||
582 | } | |||
583 | ||||
584 | int | |||
585 | rtm_sendup(struct socket *so, struct mbuf *m0) | |||
586 | { | |||
587 | struct rtpcb *rop = sotortpcb(so)((struct rtpcb *)(so)->so_pcb); | |||
588 | struct mbuf *m; | |||
589 | ||||
590 | soassertlocked(so); | |||
591 | ||||
592 | m = m_copym(m0, 0, M_COPYALL1000000000, M_NOWAIT0x0002); | |||
593 | if (m == NULL((void *)0)) | |||
594 | return (ENOMEM12); | |||
595 | ||||
596 | if (sbspace(so, &so->so_rcv) < (2 * MSIZE256) || | |||
597 | sbappendaddr(so, &so->so_rcv, &route_src, m, NULL((void *)0)) == 0) { | |||
598 | /* Flag socket as desync'ed and flush required */ | |||
599 | rop->rop_flags |= ROUTECB_FLAG_DESYNC0x1 | ROUTECB_FLAG_FLUSH0x2; | |||
600 | rtm_senddesync(so); | |||
601 | m_freem(m); | |||
602 | return (ENOBUFS55); | |||
603 | } | |||
604 | ||||
605 | sorwakeup(so); | |||
606 | return (0); | |||
607 | } | |||
608 | ||||
609 | struct rt_msghdr * | |||
610 | rtm_report(struct rtentry *rt, u_char type, int seq, int tableid) | |||
611 | { | |||
612 | struct rt_msghdr *rtm; | |||
613 | struct rt_addrinfo info; | |||
614 | struct sockaddr_rtlabel sa_rl; | |||
615 | struct sockaddr_in6 sa_mask; | |||
616 | #ifdef BFD | |||
617 | struct sockaddr_bfd sa_bfd; | |||
618 | #endif | |||
619 | struct ifnet *ifp = NULL((void *)0); | |||
620 | int len; | |||
621 | ||||
622 | bzero(&info, sizeof(info))__builtin_bzero((&info), (sizeof(info))); | |||
623 | info.rti_info[RTAX_DST0] = rt_key(rt)((rt)->rt_dest); | |||
624 | info.rti_info[RTAX_GATEWAY1] = rt->rt_gateway; | |||
625 | info.rti_info[RTAX_NETMASK2] = rt_plen2mask(rt, &sa_mask); | |||
626 | info.rti_info[RTAX_LABEL10] = rtlabel_id2sa(rt->rt_labelid, &sa_rl); | |||
627 | #ifdef BFD | |||
628 | if (rt->rt_flags & RTF_BFD0x1000000) { | |||
629 | KERNEL_LOCK()_kernel_lock(); | |||
630 | info.rti_info[RTAX_BFD11] = bfd2sa(rt, &sa_bfd); | |||
631 | KERNEL_UNLOCK()_kernel_unlock(); | |||
632 | } | |||
633 | #endif | |||
634 | #ifdef MPLS1 | |||
635 | if (rt->rt_flags & RTF_MPLS0x100000) { | |||
636 | struct sockaddr_mpls sa_mpls; | |||
637 | ||||
638 | bzero(&sa_mpls, sizeof(sa_mpls))__builtin_bzero((&sa_mpls), (sizeof(sa_mpls))); | |||
639 | sa_mpls.smpls_family = AF_MPLS33; | |||
640 | sa_mpls.smpls_len = sizeof(sa_mpls); | |||
641 | sa_mpls.smpls_label = ((struct rt_mpls *) | |||
642 | rt->rt_llinfo)->mpls_label; | |||
643 | info.rti_info[RTAX_SRC8] = (struct sockaddr *)&sa_mpls; | |||
644 | info.rti_mpls = ((struct rt_mpls *) | |||
645 | rt->rt_llinfo)->mpls_operation; | |||
646 | } | |||
647 | #endif | |||
648 | ifp = if_get(rt->rt_ifidx); | |||
649 | if (ifp != NULL((void *)0)) { | |||
650 | info.rti_info[RTAX_IFP4] = sdltosa(ifp->if_sadl); | |||
651 | info.rti_info[RTAX_IFA5] = rtable_getsource(tableid, | |||
652 | info.rti_info[RTAX_DST0]->sa_family); | |||
653 | if (info.rti_info[RTAX_IFA5] == NULL((void *)0)) | |||
654 | info.rti_info[RTAX_IFA5] = rt->rt_ifa->ifa_addr; | |||
655 | if (ifp->if_flags & IFF_POINTOPOINT0x10) | |||
656 | info.rti_info[RTAX_BRD7] = rt->rt_ifa->ifa_dstaddr; | |||
657 | } | |||
658 | if_put(ifp); | |||
659 | /* RTAX_GENMASK, RTAX_AUTHOR, RTAX_SRCMASK ignored */ | |||
660 | ||||
661 | /* build new route message */ | |||
662 | len = rtm_msg2(type, RTM_VERSION5, &info, NULL((void *)0), NULL((void *)0)); | |||
663 | rtm = malloc(len, M_RTABLE5, M_WAITOK0x0001 | M_ZERO0x0008); | |||
664 | ||||
665 | rtm_msg2(type, RTM_VERSION5, &info, (caddr_t)rtm, NULL((void *)0)); | |||
666 | rtm->rtm_type = type; | |||
667 | rtm->rtm_index = rt->rt_ifidx; | |||
668 | rtm->rtm_tableid = tableid; | |||
669 | rtm->rtm_priority = rt->rt_priority & RTP_MASK0x7f; | |||
670 | rtm->rtm_flags = rt->rt_flags; | |||
671 | rtm->rtm_pid = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid; | |||
672 | rtm->rtm_seq = seq; | |||
673 | rtm_getmetrics(rt, &rtm->rtm_rmx); | |||
674 | rtm->rtm_addrs = info.rti_addrs; | |||
675 | #ifdef MPLS1 | |||
676 | rtm->rtm_mpls = info.rti_mpls; | |||
677 | #endif | |||
678 | return rtm; | |||
679 | } | |||
680 | ||||
681 | int | |||
682 | route_output(struct mbuf *m, struct socket *so) | |||
683 | { | |||
684 | struct rt_msghdr *rtm = NULL((void *)0); | |||
685 | struct rtentry *rt = NULL((void *)0); | |||
686 | struct rt_addrinfo info; | |||
687 | struct ifnet *ifp; | |||
688 | int len, seq, useloopback, error = 0; | |||
689 | u_int tableid; | |||
690 | u_int8_t prio; | |||
691 | u_char vers, type; | |||
692 | ||||
693 | if (m == NULL((void *)0) || ((m->m_lenm_hdr.mh_len < sizeof(int32_t)) && | |||
694 | (m = m_pullup(m, sizeof(int32_t))) == NULL((void *)0))) | |||
695 | return (ENOBUFS55); | |||
696 | if ((m->m_flagsm_hdr.mh_flags & M_PKTHDR0x0002) == 0) | |||
697 | panic("route_output"); | |||
698 | ||||
699 | useloopback = so->so_options & SO_USELOOPBACK0x0040; | |||
700 | ||||
701 | /* | |||
702 | * The socket can't be closed concurrently because the file | |||
703 | * descriptor reference is still held. | |||
704 | */ | |||
705 | ||||
706 | sounlock(so); | |||
707 | ||||
708 | len = m->m_pkthdrM_dat.MH.MH_pkthdr.len; | |||
709 | if (len < offsetof(struct rt_msghdr, rtm_hdrlen)__builtin_offsetof(struct rt_msghdr, rtm_hdrlen) + | |||
710 | sizeof(rtm->rtm_hdrlen) || | |||
711 | len != mtod(m, struct rt_msghdr *)((struct rt_msghdr *)((m)->m_hdr.mh_data))->rtm_msglen) { | |||
712 | error = EINVAL22; | |||
713 | goto fail; | |||
714 | } | |||
715 | vers = mtod(m, struct rt_msghdr *)((struct rt_msghdr *)((m)->m_hdr.mh_data))->rtm_version; | |||
716 | switch (vers) { | |||
717 | case RTM_VERSION5: | |||
718 | if (len < sizeof(struct rt_msghdr)) { | |||
719 | error = EINVAL22; | |||
720 | goto fail; | |||
721 | } | |||
722 | if (len > RTM_MAXSIZE2048) { | |||
723 | error = EMSGSIZE40; | |||
724 | goto fail; | |||
725 | } | |||
726 | rtm = malloc(len, M_RTABLE5, M_WAITOK0x0001); | |||
727 | m_copydata(m, 0, len, rtm); | |||
728 | break; | |||
729 | default: | |||
730 | error = EPROTONOSUPPORT43; | |||
731 | goto fail; | |||
732 | } | |||
733 | ||||
734 | /* Verify that the caller is sending an appropriate message early */ | |||
735 | switch (rtm->rtm_type) { | |||
736 | case RTM_ADD0x1: | |||
737 | case RTM_DELETE0x2: | |||
738 | case RTM_GET0x4: | |||
739 | case RTM_CHANGE0x3: | |||
740 | case RTM_PROPOSAL0x13: | |||
741 | case RTM_SOURCE0x16: | |||
742 | break; | |||
743 | default: | |||
744 | error = EOPNOTSUPP45; | |||
745 | goto fail; | |||
746 | } | |||
747 | /* | |||
748 | * Verify that the header length is valid. | |||
749 | * All messages from userland start with a struct rt_msghdr. | |||
750 | */ | |||
751 | if (rtm->rtm_hdrlen == 0) /* old client */ | |||
752 | rtm->rtm_hdrlen = sizeof(struct rt_msghdr); | |||
753 | if (rtm->rtm_hdrlen < sizeof(struct rt_msghdr) || | |||
754 | len < rtm->rtm_hdrlen) { | |||
755 | error = EINVAL22; | |||
756 | goto fail; | |||
757 | } | |||
758 | ||||
759 | rtm->rtm_pid = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid; | |||
760 | ||||
761 | /* | |||
762 | * Verify that the caller has the appropriate privilege; RTM_GET | |||
763 | * is the only operation the non-superuser is allowed. | |||
764 | */ | |||
765 | if (rtm->rtm_type != RTM_GET0x4 && suser(curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc) != 0) { | |||
766 | error = EACCES13; | |||
767 | goto fail; | |||
768 | } | |||
769 | tableid = rtm->rtm_tableid; | |||
770 | if (!rtable_exists(tableid)) { | |||
771 | if (rtm->rtm_type == RTM_ADD0x1) { | |||
772 | if ((error = rtable_add(tableid)) != 0) | |||
773 | goto fail; | |||
774 | } else { | |||
775 | error = EINVAL22; | |||
776 | goto fail; | |||
777 | } | |||
778 | } | |||
779 | ||||
780 | /* Do not let userland play with kernel-only flags. */ | |||
781 | if ((rtm->rtm_flags & (RTF_LOCAL0x200000|RTF_BROADCAST0x400000)) != 0) { | |||
782 | error = EINVAL22; | |||
783 | goto fail; | |||
784 | } | |||
785 | ||||
786 | /* make sure that kernel-only bits are not set */ | |||
787 | rtm->rtm_priority &= RTP_MASK0x7f; | |||
788 | rtm->rtm_flags &= ~(RTF_DONE0x40|RTF_CLONED0x10000|RTF_CACHED0x20000); | |||
789 | rtm->rtm_fmask &= RTF_FMASK(0x400 | 0x8000 | 0x4000 | 0x2000 | 0x1000 | 0x8 | 0x800 | 0x100000 | 0x1000000); | |||
790 | ||||
791 | if (rtm->rtm_priority != 0) { | |||
792 | if (rtm->rtm_priority > RTP_MAX63 || | |||
793 | rtm->rtm_priority == RTP_LOCAL1) { | |||
794 | error = EINVAL22; | |||
795 | goto fail; | |||
796 | } | |||
797 | prio = rtm->rtm_priority; | |||
798 | } else if (rtm->rtm_type != RTM_ADD0x1) | |||
799 | prio = RTP_ANY64; | |||
800 | else if (rtm->rtm_flags & RTF_STATIC0x800) | |||
801 | prio = 0; | |||
802 | else | |||
803 | prio = RTP_DEFAULT56; | |||
804 | ||||
805 | bzero(&info, sizeof(info))__builtin_bzero((&info), (sizeof(info))); | |||
806 | info.rti_addrs = rtm->rtm_addrs; | |||
807 | if ((error = rtm_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, | |||
808 | len + (caddr_t)rtm, &info)) != 0) | |||
809 | goto fail; | |||
810 | ||||
811 | info.rti_flags = rtm->rtm_flags; | |||
812 | ||||
813 | if (rtm->rtm_type != RTM_SOURCE0x16 && | |||
814 | rtm->rtm_type != RTM_PROPOSAL0x13 && | |||
815 | (info.rti_info[RTAX_DST0] == NULL((void *)0) || | |||
816 | info.rti_info[RTAX_DST0]->sa_family >= AF_MAX36 || | |||
817 | (info.rti_info[RTAX_GATEWAY1] != NULL((void *)0) && | |||
818 | info.rti_info[RTAX_GATEWAY1]->sa_family >= AF_MAX36) || | |||
819 | info.rti_info[RTAX_GENMASK3] != NULL((void *)0))) { | |||
820 | error = EINVAL22; | |||
821 | goto fail; | |||
822 | } | |||
823 | #ifdef MPLS1 | |||
824 | info.rti_mpls = rtm->rtm_mpls; | |||
825 | #endif | |||
826 | ||||
827 | if (info.rti_info[RTAX_GATEWAY1] != NULL((void *)0) && | |||
828 | info.rti_info[RTAX_GATEWAY1]->sa_family == AF_LINK18 && | |||
829 | (info.rti_flags & RTF_CLONING0x100) == 0) { | |||
830 | info.rti_flags |= RTF_LLINFO0x400; | |||
831 | } | |||
832 | ||||
833 | /* | |||
834 | * Validate RTM_PROPOSAL and pass it along or error out. | |||
835 | */ | |||
836 | if (rtm->rtm_type == RTM_PROPOSAL0x13) { | |||
837 | if (rtm_validate_proposal(&info) == -1) { | |||
838 | error = EINVAL22; | |||
839 | goto fail; | |||
840 | } | |||
841 | /* | |||
842 | * If this is a solicitation proposal forward request to | |||
843 | * all interfaces. Most handlers will ignore it but at least | |||
844 | * umb(4) will send a response to this event. | |||
845 | */ | |||
846 | if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT62) { | |||
847 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
848 | TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void *)0); (ifp) = ((ifp)->if_list.tqe_next)) { | |||
849 | ifp->if_rtrequest(ifp, RTM_PROPOSAL0x13, NULL((void *)0)); | |||
850 | } | |||
851 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
852 | } | |||
853 | } else if (rtm->rtm_type == RTM_SOURCE0x16) { | |||
854 | if (info.rti_info[RTAX_IFA5] == NULL((void *)0)) { | |||
855 | error = EINVAL22; | |||
856 | goto fail; | |||
857 | } | |||
858 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
859 | error = rt_setsource(tableid, info.rti_info[RTAX_IFA5]); | |||
860 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
861 | if (error) | |||
862 | goto fail; | |||
863 | } else { | |||
864 | error = rtm_output(rtm, &rt, &info, prio, tableid); | |||
865 | if (!error) { | |||
866 | type = rtm->rtm_type; | |||
867 | seq = rtm->rtm_seq; | |||
868 | free(rtm, M_RTABLE5, len); | |||
869 | NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0); | |||
870 | rtm = rtm_report(rt, type, seq, tableid); | |||
871 | NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0); | |||
872 | len = rtm->rtm_msglen; | |||
873 | } | |||
874 | } | |||
875 | ||||
876 | rtfree(rt); | |||
877 | if (error) { | |||
878 | rtm->rtm_errno = error; | |||
879 | } else { | |||
880 | rtm->rtm_flags |= RTF_DONE0x40; | |||
881 | } | |||
882 | ||||
883 | /* | |||
884 | * Check to see if we don't want our own messages. | |||
885 | */ | |||
886 | if (!useloopback) { | |||
887 | if (rtptable.rtp_count == 0) { | |||
888 | /* no other listener and no loopback of messages */ | |||
889 | goto fail; | |||
890 | } | |||
891 | } | |||
892 | if (m_copyback(m, 0, len, rtm, M_NOWAIT0x0002)) { | |||
893 | m_freem(m); | |||
894 | m = NULL((void *)0); | |||
895 | } else if (m->m_pkthdrM_dat.MH.MH_pkthdr.len > len) | |||
896 | m_adj(m, len - m->m_pkthdrM_dat.MH.MH_pkthdr.len); | |||
897 | free(rtm, M_RTABLE5, len); | |||
898 | if (m) | |||
899 | route_input(m, so, info.rti_info[RTAX_DST0] ? | |||
900 | info.rti_info[RTAX_DST0]->sa_family : AF_UNSPEC0); | |||
901 | solock(so); | |||
902 | ||||
903 | return (error); | |||
904 | fail: | |||
905 | free(rtm, M_RTABLE5, len); | |||
906 | m_freem(m); | |||
907 | solock(so); | |||
908 | ||||
909 | return (error); | |||
910 | } | |||
911 | ||||
912 | int | |||
913 | rtm_output(struct rt_msghdr *rtm, struct rtentry **prt, | |||
914 | struct rt_addrinfo *info, uint8_t prio, unsigned int tableid) | |||
915 | { | |||
916 | struct rtentry *rt = *prt; | |||
917 | struct ifnet *ifp = NULL((void *)0); | |||
918 | int plen, newgate = 0, error = 0; | |||
919 | ||||
920 | switch (rtm->rtm_type) { | |||
921 | case RTM_ADD0x1: | |||
922 | if (info->rti_info[RTAX_GATEWAY1] == NULL((void *)0)) { | |||
923 | error = EINVAL22; | |||
924 | break; | |||
925 | } | |||
926 | ||||
927 | rt = rtable_match(tableid, info->rti_info[RTAX_DST0], NULL((void *)0)); | |||
928 | if ((error = route_arp_conflict(rt, info))) { | |||
929 | rtfree(rt); | |||
930 | rt = NULL((void *)0); | |||
931 | break; | |||
932 | } | |||
933 | ||||
934 | /* | |||
935 | * We cannot go through a delete/create/insert cycle for | |||
936 | * cached route because this can lead to races in the | |||
937 | * receive path. Instead we update the L2 cache. | |||
938 | */ | |||
939 | if ((rt != NULL((void *)0)) && ISSET(rt->rt_flags, RTF_CACHED)((rt->rt_flags) & (0x20000))) { | |||
940 | ifp = if_get(rt->rt_ifidx); | |||
941 | if (ifp == NULL((void *)0)) { | |||
942 | rtfree(rt); | |||
943 | rt = NULL((void *)0); | |||
944 | error = ESRCH3; | |||
945 | break; | |||
946 | } | |||
947 | ||||
948 | goto change; | |||
949 | } | |||
950 | ||||
951 | rtfree(rt); | |||
952 | rt = NULL((void *)0); | |||
953 | ||||
954 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
955 | if ((error = rtm_getifa(info, tableid)) != 0) { | |||
956 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
957 | break; | |||
958 | } | |||
959 | error = rtrequest(RTM_ADD0x1, info, prio, &rt, tableid); | |||
960 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
961 | if (error == 0) | |||
962 | rtm_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, | |||
963 | &rt->rt_rmx); | |||
964 | break; | |||
965 | case RTM_DELETE0x2: | |||
966 | rt = rtable_lookup(tableid, info->rti_info[RTAX_DST0], | |||
967 | info->rti_info[RTAX_NETMASK2], info->rti_info[RTAX_GATEWAY1], | |||
968 | prio); | |||
969 | if (rt == NULL((void *)0)) { | |||
970 | error = ESRCH3; | |||
971 | break; | |||
972 | } | |||
973 | ||||
974 | /* | |||
975 | * If we got multipath routes, we require users to specify | |||
976 | * a matching gateway. | |||
977 | */ | |||
978 | if (ISSET(rt->rt_flags, RTF_MPATH)((rt->rt_flags) & (0x40000)) && | |||
979 | info->rti_info[RTAX_GATEWAY1] == NULL((void *)0)) { | |||
980 | error = ESRCH3; | |||
981 | break; | |||
982 | } | |||
983 | ||||
984 | ifp = if_get(rt->rt_ifidx); | |||
985 | if (ifp == NULL((void *)0)) { | |||
986 | rtfree(rt); | |||
987 | rt = NULL((void *)0); | |||
988 | error = ESRCH3; | |||
989 | break; | |||
990 | } | |||
991 | ||||
992 | /* | |||
993 | * Invalidate the cache of automagically created and | |||
994 | * referenced L2 entries to make sure that ``rt_gwroute'' | |||
995 | * pointer stays valid for other CPUs. | |||
996 | */ | |||
997 | if ((ISSET(rt->rt_flags, RTF_CACHED)((rt->rt_flags) & (0x20000)))) { | |||
998 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
999 | ifp->if_rtrequest(ifp, RTM_INVALIDATE0x11, rt); | |||
1000 | /* Reset the MTU of the gateway route. */ | |||
1001 | rtable_walk(tableid, rt_key(rt)((rt)->rt_dest)->sa_family, NULL((void *)0), | |||
1002 | route_cleargateway, rt); | |||
1003 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
1004 | break; | |||
1005 | } | |||
1006 | ||||
1007 | /* | |||
1008 | * Make sure that local routes are only modified by the | |||
1009 | * kernel. | |||
1010 | */ | |||
1011 | if (ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST)((rt->rt_flags) & (0x200000|0x400000))) { | |||
1012 | error = EINVAL22; | |||
1013 | break; | |||
1014 | } | |||
1015 | ||||
1016 | rtfree(rt); | |||
1017 | rt = NULL((void *)0); | |||
1018 | ||||
1019 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
1020 | error = rtrequest_delete(info, prio, ifp, &rt, tableid); | |||
1021 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
1022 | break; | |||
1023 | case RTM_CHANGE0x3: | |||
1024 | rt = rtable_lookup(tableid, info->rti_info[RTAX_DST0], | |||
1025 | info->rti_info[RTAX_NETMASK2], info->rti_info[RTAX_GATEWAY1], | |||
1026 | prio); | |||
1027 | /* | |||
1028 | * If we got multipath routes, we require users to specify | |||
1029 | * a matching gateway. | |||
1030 | */ | |||
1031 | if ((rt != NULL((void *)0)) && ISSET(rt->rt_flags, RTF_MPATH)((rt->rt_flags) & (0x40000)) && | |||
1032 | (info->rti_info[RTAX_GATEWAY1] == NULL((void *)0))) { | |||
1033 | rtfree(rt); | |||
1034 | rt = NULL((void *)0); | |||
1035 | } | |||
1036 | ||||
1037 | /* | |||
1038 | * If RTAX_GATEWAY is the argument we're trying to | |||
1039 | * change, try to find a compatible route. | |||
1040 | */ | |||
1041 | if ((rt == NULL((void *)0)) && (info->rti_info[RTAX_GATEWAY1] != NULL((void *)0))) { | |||
1042 | rt = rtable_lookup(tableid, info->rti_info[RTAX_DST0], | |||
1043 | info->rti_info[RTAX_NETMASK2], NULL((void *)0), prio); | |||
1044 | /* Ensure we don't pick a multipath one. */ | |||
1045 | if ((rt != NULL((void *)0)) && ISSET(rt->rt_flags, RTF_MPATH)((rt->rt_flags) & (0x40000))) { | |||
1046 | rtfree(rt); | |||
1047 | rt = NULL((void *)0); | |||
1048 | } | |||
1049 | } | |||
1050 | ||||
1051 | if (rt == NULL((void *)0)) { | |||
1052 | error = ESRCH3; | |||
1053 | break; | |||
1054 | } | |||
1055 | ||||
1056 | /* | |||
1057 | * Make sure that local routes are only modified by the | |||
1058 | * kernel. | |||
1059 | */ | |||
1060 | if (ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST)((rt->rt_flags) & (0x200000|0x400000))) { | |||
1061 | error = EINVAL22; | |||
1062 | break; | |||
1063 | } | |||
1064 | ||||
1065 | ifp = if_get(rt->rt_ifidx); | |||
1066 | if (ifp == NULL((void *)0)) { | |||
1067 | rtfree(rt); | |||
1068 | rt = NULL((void *)0); | |||
1069 | error = ESRCH3; | |||
1070 | break; | |||
1071 | } | |||
1072 | ||||
1073 | /* | |||
1074 | * RTM_CHANGE needs a perfect match. | |||
1075 | */ | |||
1076 | plen = rtable_satoplen(info->rti_info[RTAX_DST0]->sa_family, | |||
1077 | info->rti_info[RTAX_NETMASK2]); | |||
1078 | if (rt_plen(rt)((rt)->rt_plen) != plen) { | |||
1079 | error = ESRCH3; | |||
1080 | break; | |||
1081 | } | |||
1082 | ||||
1083 | if (info->rti_info[RTAX_GATEWAY1] != NULL((void *)0)) | |||
1084 | if (rt->rt_gateway == NULL((void *)0) || | |||
1085 | bcmp(rt->rt_gateway, | |||
1086 | info->rti_info[RTAX_GATEWAY1], | |||
1087 | info->rti_info[RTAX_GATEWAY1]->sa_len)) { | |||
1088 | newgate = 1; | |||
1089 | } | |||
1090 | /* | |||
1091 | * Check reachable gateway before changing the route. | |||
1092 | * New gateway could require new ifaddr, ifp; | |||
1093 | * flags may also be different; ifp may be specified | |||
1094 | * by ll sockaddr when protocol address is ambiguous. | |||
1095 | */ | |||
1096 | if (newgate || info->rti_info[RTAX_IFP4] != NULL((void *)0) || | |||
1097 | info->rti_info[RTAX_IFA5] != NULL((void *)0)) { | |||
1098 | struct ifaddr *ifa = NULL((void *)0); | |||
1099 | ||||
1100 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
1101 | if ((error = rtm_getifa(info, tableid)) != 0) { | |||
1102 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
1103 | break; | |||
1104 | } | |||
1105 | ifa = info->rti_ifa; | |||
1106 | if (rt->rt_ifa != ifa) { | |||
1107 | ifp->if_rtrequest(ifp, RTM_DELETE0x2, rt); | |||
1108 | ifafree(rt->rt_ifa); | |||
1109 | ||||
1110 | rt->rt_ifa = ifaref(ifa); | |||
1111 | rt->rt_ifidx = ifa->ifa_ifp->if_index; | |||
1112 | /* recheck link state after ifp change */ | |||
1113 | rt_if_linkstate_change(rt, ifa->ifa_ifp, | |||
1114 | tableid); | |||
1115 | } | |||
1116 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
1117 | } | |||
1118 | change: | |||
1119 | if (info->rti_info[RTAX_GATEWAY1] != NULL((void *)0)) { | |||
1120 | /* When updating the gateway, make sure it is valid. */ | |||
1121 | if (!newgate && rt->rt_gateway->sa_family != | |||
1122 | info->rti_info[RTAX_GATEWAY1]->sa_family) { | |||
1123 | error = EINVAL22; | |||
1124 | break; | |||
1125 | } | |||
1126 | ||||
1127 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
1128 | error = rt_setgate(rt, | |||
1129 | info->rti_info[RTAX_GATEWAY1], tableid); | |||
1130 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
1131 | if (error) | |||
1132 | break; | |||
1133 | } | |||
1134 | #ifdef MPLS1 | |||
1135 | if (rtm->rtm_flags & RTF_MPLS0x100000) { | |||
1136 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
1137 | error = rt_mpls_set(rt, | |||
1138 | info->rti_info[RTAX_SRC8], info->rti_mpls); | |||
1139 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
1140 | if (error) | |||
1141 | break; | |||
1142 | } else if (newgate || (rtm->rtm_fmask & RTF_MPLS0x100000)) { | |||
1143 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
1144 | /* if gateway changed remove MPLS information */ | |||
1145 | rt_mpls_clear(rt); | |||
1146 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
1147 | } | |||
1148 | #endif | |||
1149 | ||||
1150 | #ifdef BFD | |||
1151 | if (ISSET(rtm->rtm_flags, RTF_BFD)((rtm->rtm_flags) & (0x1000000))) { | |||
1152 | KERNEL_LOCK()_kernel_lock(); | |||
1153 | error = bfdset(rt); | |||
1154 | KERNEL_UNLOCK()_kernel_unlock(); | |||
1155 | if (error) | |||
1156 | break; | |||
1157 | } else if (!ISSET(rtm->rtm_flags, RTF_BFD)((rtm->rtm_flags) & (0x1000000)) && | |||
1158 | ISSET(rtm->rtm_fmask, RTF_BFD)((rtm->rtm_fmask) & (0x1000000))) { | |||
1159 | KERNEL_LOCK()_kernel_lock(); | |||
1160 | bfdclear(rt); | |||
1161 | KERNEL_UNLOCK()_kernel_unlock(); | |||
1162 | } | |||
1163 | #endif | |||
1164 | ||||
1165 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | |||
1166 | /* Hack to allow some flags to be toggled */ | |||
1167 | if (rtm->rtm_fmask) { | |||
1168 | /* MPLS flag it is set by rt_mpls_set() */ | |||
1169 | rtm->rtm_fmask &= ~RTF_MPLS0x100000; | |||
1170 | rtm->rtm_flags &= ~RTF_MPLS0x100000; | |||
1171 | rt->rt_flags = | |||
1172 | (rt->rt_flags & ~rtm->rtm_fmask) | | |||
1173 | (rtm->rtm_flags & rtm->rtm_fmask); | |||
1174 | } | |||
1175 | rtm_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx); | |||
1176 | ||||
1177 | ifp->if_rtrequest(ifp, RTM_ADD0x1, rt); | |||
1178 | ||||
1179 | if (info->rti_info[RTAX_LABEL10] != NULL((void *)0)) { | |||
1180 | const char *rtlabel = ((const struct sockaddr_rtlabel *) | |||
1181 | info->rti_info[RTAX_LABEL10])->sr_label; | |||
1182 | rtlabel_unref(rt->rt_labelid); | |||
1183 | rt->rt_labelid = rtlabel_name2id(rtlabel); | |||
1184 | } | |||
1185 | if_group_routechange(info->rti_info[RTAX_DST0], | |||
1186 | info->rti_info[RTAX_NETMASK2]); | |||
1187 | rt->rt_locksrt_rmx.rmx_locks &= ~(rtm->rtm_inits); | |||
1188 | rt->rt_locksrt_rmx.rmx_locks |= (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); | |||
1189 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | |||
1190 | break; | |||
1191 | case RTM_GET0x4: | |||
1192 | rt = rtable_lookup(tableid, info->rti_info[RTAX_DST0], | |||
1193 | info->rti_info[RTAX_NETMASK2], info->rti_info[RTAX_GATEWAY1], | |||
1194 | prio); | |||
1195 | if (rt == NULL((void *)0)) | |||
1196 | error = ESRCH3; | |||
1197 | break; | |||
1198 | } | |||
1199 | ||||
1200 | if_put(ifp); | |||
1201 | *prt = rt; | |||
1202 | return (error); | |||
1203 | } | |||
1204 | ||||
1205 | struct ifaddr * | |||
1206 | ifa_ifwithroute(int flags, const struct sockaddr *dst, | |||
1207 | const struct sockaddr *gateway, unsigned int rtableid) | |||
1208 | { | |||
1209 | struct ifaddr *ifa; | |||
1210 | ||||
1211 | if ((flags & RTF_GATEWAY0x2) == 0) { | |||
1212 | /* | |||
1213 | * If we are adding a route to an interface, | |||
1214 | * and the interface is a pt to pt link | |||
1215 | * we should search for the destination | |||
1216 | * as our clue to the interface. Otherwise | |||
1217 | * we can use the local address. | |||
1218 | */ | |||
1219 | ifa = NULL((void *)0); | |||
1220 | if (flags & RTF_HOST0x4) | |||
1221 | ifa = ifa_ifwithdstaddr(dst, rtableid); | |||
1222 | if (ifa == NULL((void *)0)) | |||
1223 | ifa = ifa_ifwithaddr(gateway, rtableid); | |||
1224 | } else { | |||
1225 | /* | |||
1226 | * If we are adding a route to a remote net | |||
1227 | * or host, the gateway may still be on the | |||
1228 | * other end of a pt to pt link. | |||
1229 | */ | |||
1230 | ifa = ifa_ifwithdstaddr(gateway, rtableid); | |||
1231 | } | |||
1232 | if (ifa == NULL((void *)0)) { | |||
1233 | if (gateway->sa_family == AF_LINK18) { | |||
1234 | const struct sockaddr_dl *sdl; | |||
1235 | struct ifnet *ifp; | |||
1236 | ||||
1237 | sdl = satosdl_const(gateway); | |||
1238 | ifp = if_get(sdl->sdl_index); | |||
1239 | if (ifp != NULL((void *)0)) | |||
1240 | ifa = ifaof_ifpforaddr(dst, ifp); | |||
1241 | if_put(ifp); | |||
1242 | } else { | |||
1243 | struct rtentry *rt; | |||
1244 | ||||
1245 | rt = rtalloc(gateway, RT_RESOLVE1, rtable_l2(rtableid)); | |||
1246 | if (rt != NULL((void *)0)) | |||
1247 | ifa = rt->rt_ifa; | |||
1248 | rtfree(rt); | |||
1249 | } | |||
1250 | } | |||
1251 | if (ifa == NULL((void *)0)) | |||
1252 | return (NULL((void *)0)); | |||
1253 | if (ifa->ifa_addr->sa_family != dst->sa_family) { | |||
1254 | struct ifaddr *oifa = ifa; | |||
1255 | ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); | |||
1256 | if (ifa == NULL((void *)0)) | |||
1257 | ifa = oifa; | |||
1258 | } | |||
1259 | return (ifa); | |||
1260 | } | |||
1261 | ||||
1262 | int | |||
1263 | rtm_getifa(struct rt_addrinfo *info, unsigned int rtid) | |||
1264 | { | |||
1265 | struct ifnet *ifp = NULL((void *)0); | |||
1266 | ||||
1267 | /* | |||
1268 | * The "returned" `ifa' is guaranteed to be alive only if | |||
1269 | * the NET_LOCK() is held. | |||
1270 | */ | |||
1271 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); | |||
1272 | ||||
1273 | /* | |||
1274 | * ifp may be specified by sockaddr_dl when protocol address | |||
1275 | * is ambiguous | |||
1276 | */ | |||
1277 | if (info->rti_info[RTAX_IFP4] != NULL((void *)0)) { | |||
1278 | const struct sockaddr_dl *sdl; | |||
1279 | ||||
1280 | sdl = satosdl_const(info->rti_info[RTAX_IFP4]); | |||
1281 | ifp = if_get(sdl->sdl_index); | |||
1282 | } | |||
1283 | ||||
1284 | #ifdef IPSEC1 | |||
1285 | /* | |||
1286 | * If the destination is a PF_KEY address, we'll look | |||
1287 | * for the existence of a encap interface number or address | |||
1288 | * in the options list of the gateway. By default, we'll return | |||
1289 | * enc0. | |||
1290 | */ | |||
1291 | if (info->rti_info[RTAX_DST0] && | |||
1292 | info->rti_info[RTAX_DST0]->sa_family == PF_KEY30) | |||
1293 | info->rti_ifa = enc_getifa(rtid, 0); | |||
1294 | #endif | |||
1295 | ||||
1296 | if (info->rti_ifa == NULL((void *)0) && info->rti_info[RTAX_IFA5] != NULL((void *)0)) | |||
1297 | info->rti_ifa = ifa_ifwithaddr(info->rti_info[RTAX_IFA5], rtid); | |||
1298 | ||||
1299 | if (info->rti_ifa == NULL((void *)0)) { | |||
1300 | const struct sockaddr *sa; | |||
1301 | ||||
1302 | if ((sa = info->rti_info[RTAX_IFA5]) == NULL((void *)0)) | |||
1303 | if ((sa = info->rti_info[RTAX_GATEWAY1]) == NULL((void *)0)) | |||
1304 | sa = info->rti_info[RTAX_DST0]; | |||
1305 | ||||
1306 | if (sa != NULL((void *)0) && ifp != NULL((void *)0)) | |||
1307 | info->rti_ifa = ifaof_ifpforaddr(sa, ifp); | |||
1308 | else if (info->rti_info[RTAX_DST0] != NULL((void *)0) && | |||
1309 | info->rti_info[RTAX_GATEWAY1] != NULL((void *)0)) | |||
1310 | info->rti_ifa = ifa_ifwithroute(info->rti_flags, | |||
1311 | info->rti_info[RTAX_DST0], | |||
1312 | info->rti_info[RTAX_GATEWAY1], | |||
1313 | rtid); | |||
1314 | else if (sa != NULL((void *)0)) | |||
1315 | info->rti_ifa = ifa_ifwithroute(info->rti_flags, | |||
1316 | sa, sa, rtid); | |||
1317 | } | |||
1318 | ||||
1319 | if_put(ifp); | |||
1320 | ||||
1321 | if (info->rti_ifa == NULL((void *)0)) | |||
1322 | return (ENETUNREACH51); | |||
1323 | ||||
1324 | return (0); | |||
1325 | } | |||
1326 | ||||
1327 | int | |||
1328 | route_cleargateway(struct rtentry *rt, void *arg, unsigned int rtableid) | |||
1329 | { | |||
1330 | struct rtentry *nhrt = arg; | |||
1331 | ||||
1332 | if (ISSET(rt->rt_flags, RTF_GATEWAY)((rt->rt_flags) & (0x2)) && rt->rt_gwrouteRT_gw._nh == nhrt && | |||
1333 | !ISSET(rt->rt_locks, RTV_MTU)((rt->rt_rmx.rmx_locks) & (0x1))) | |||
1334 | rt->rt_mturt_rmx.rmx_mtu = 0; | |||
1335 | ||||
1336 | return (0); | |||
1337 | } | |||
1338 | ||||
1339 | /* | |||
1340 | * Check if the user request to insert an ARP entry does not conflict | |||
1341 | * with existing ones. | |||
1342 | * | |||
1343 | * Only two entries are allowed for a given IP address: a private one | |||
1344 | * (priv) and a public one (pub). | |||
1345 | */ | |||
1346 | int | |||
1347 | route_arp_conflict(struct rtentry *rt, struct rt_addrinfo *info) | |||
1348 | { | |||
1349 | int proxy = (info->rti_flags & RTF_ANNOUNCE0x4000); | |||
1350 | ||||
1351 | if ((info->rti_flags & RTF_LLINFO0x400) == 0 || | |||
1352 | (info->rti_info[RTAX_DST0]->sa_family != AF_INET2)) | |||
1353 | return (0); | |||
1354 | ||||
1355 | if (rt == NULL((void *)0) || !ISSET(rt->rt_flags, RTF_LLINFO)((rt->rt_flags) & (0x400))) | |||
1356 | return (0); | |||
1357 | ||||
1358 | /* If the entry is cached, it can be updated. */ | |||
1359 | if (ISSET(rt->rt_flags, RTF_CACHED)((rt->rt_flags) & (0x20000))) | |||
1360 | return (0); | |||
1361 | ||||
1362 | /* | |||
1363 | * Same destination, not cached and both "priv" or "pub" conflict. | |||
1364 | * If a second entry exists, it always conflict. | |||
1365 | */ | |||
1366 | if ((ISSET(rt->rt_flags, RTF_ANNOUNCE)((rt->rt_flags) & (0x4000)) == proxy) || | |||
1367 | ISSET(rt->rt_flags, RTF_MPATH)((rt->rt_flags) & (0x40000))) | |||
1368 | return (EEXIST17); | |||
1369 | ||||
1370 | /* No conflict but an entry exist so we need to force mpath. */ | |||
1371 | info->rti_flags |= RTF_MPATH0x40000; | |||
1372 | return (0); | |||
1373 | } | |||
1374 | ||||
1375 | void | |||
1376 | rtm_setmetrics(u_long which, const struct rt_metrics *in, | |||
1377 | struct rt_kmetrics *out) | |||
1378 | { | |||
1379 | int64_t expire; | |||
1380 | ||||
1381 | if (which & RTV_MTU0x1) | |||
1382 | out->rmx_mtu = in->rmx_mtu; | |||
1383 | if (which & RTV_EXPIRE0x4) { | |||
1384 | expire = in->rmx_expire; | |||
1385 | if (expire != 0) { | |||
1386 | expire -= gettime(); | |||
1387 | expire += getuptime(); | |||
1388 | } | |||
1389 | ||||
1390 | out->rmx_expire = expire; | |||
1391 | } | |||
1392 | } | |||
1393 | ||||
1394 | void | |||
1395 | rtm_getmetrics(const struct rtentry *rt, struct rt_metrics *out) | |||
1396 | { | |||
1397 | const struct rt_kmetrics *in = &rt->rt_rmx; | |||
1398 | int64_t expire; | |||
1399 | ||||
1400 | expire = in->rmx_expire; | |||
1401 | if (expire == 0) | |||
1402 | expire = rt_timer_get_expire(rt); | |||
1403 | if (expire != 0) { | |||
1404 | expire -= getuptime(); | |||
1405 | expire += gettime(); | |||
1406 | } | |||
1407 | ||||
1408 | bzero(out, sizeof(*out))__builtin_bzero((out), (sizeof(*out))); | |||
1409 | out->rmx_locks = in->rmx_locks; | |||
1410 | out->rmx_mtu = in->rmx_mtu; | |||
1411 | out->rmx_expire = expire; | |||
1412 | out->rmx_pksent = in->rmx_pksent; | |||
1413 | } | |||
1414 | ||||
1415 | #define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof (long)) \ | |||
1416 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |||
1417 | #define ADVANCE(x, n)(x += (((n)->sa_len) > 0 ? (1 + ((((n)->sa_len) - 1) | (sizeof(long) - 1))) : sizeof(long))) (x += ROUNDUP((n)->sa_len)(((n)->sa_len) > 0 ? (1 + ((((n)->sa_len) - 1) | (sizeof (long) - 1))) : sizeof(long))) | |||
1418 | ||||
1419 | int | |||
1420 | rtm_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) | |||
1421 | { | |||
1422 | int i; | |||
1423 | ||||
1424 | /* | |||
1425 | * Parse address bits, split address storage in chunks, and | |||
1426 | * set info pointers. Use sa_len for traversing the memory | |||
1427 | * and check that we stay within in the limit. | |||
1428 | */ | |||
1429 | bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info))__builtin_bzero((rtinfo->rti_info), (sizeof(rtinfo->rti_info ))); | |||
1430 | for (i = 0; i < sizeof(rtinfo->rti_addrs) * 8; i++) { | |||
1431 | struct sockaddr *sa; | |||
1432 | ||||
1433 | if ((rtinfo->rti_addrs & (1U << i)) == 0) | |||
1434 | continue; | |||
1435 | if (i >= RTAX_MAX15 || cp + sizeof(socklen_t) > cplim) | |||
1436 | return (EINVAL22); | |||
1437 | sa = (struct sockaddr *)cp; | |||
1438 | if (cp + sa->sa_len > cplim) | |||
1439 | return (EINVAL22); | |||
1440 | rtinfo->rti_info[i] = sa; | |||
1441 | ADVANCE(cp, sa)(cp += (((sa)->sa_len) > 0 ? (1 + ((((sa)->sa_len) - 1) | (sizeof(long) - 1))) : sizeof(long))); | |||
1442 | } | |||
1443 | /* | |||
1444 | * Check that the address family is suitable for the route address | |||
1445 | * type. Check that each address has a size that fits its family | |||
1446 | * and its length is within the size. Strings within addresses must | |||
1447 | * be NUL terminated. | |||
1448 | */ | |||
1449 | for (i = 0; i < RTAX_MAX15; i++) { | |||
1450 | const struct sockaddr *sa; | |||
1451 | size_t len, maxlen, size; | |||
1452 | ||||
1453 | sa = rtinfo->rti_info[i]; | |||
1454 | if (sa == NULL((void *)0)) | |||
1455 | continue; | |||
1456 | maxlen = size = 0; | |||
1457 | switch (i) { | |||
1458 | case RTAX_DST0: | |||
1459 | case RTAX_GATEWAY1: | |||
1460 | case RTAX_SRC8: | |||
1461 | switch (sa->sa_family) { | |||
1462 | case AF_INET2: | |||
1463 | size = sizeof(struct sockaddr_in); | |||
1464 | break; | |||
1465 | case AF_LINK18: | |||
1466 | size = sizeof(struct sockaddr_dl); | |||
1467 | break; | |||
1468 | #ifdef INET61 | |||
1469 | case AF_INET624: | |||
1470 | size = sizeof(struct sockaddr_in6); | |||
1471 | break; | |||
1472 | #endif | |||
1473 | #ifdef MPLS1 | |||
1474 | case AF_MPLS33: | |||
1475 | size = sizeof(struct sockaddr_mpls); | |||
1476 | break; | |||
1477 | #endif | |||
1478 | } | |||
1479 | break; | |||
1480 | case RTAX_IFP4: | |||
1481 | if (sa->sa_family != AF_LINK18) | |||
1482 | return (EAFNOSUPPORT47); | |||
1483 | /* | |||
1484 | * XXX Should be sizeof(struct sockaddr_dl), but | |||
1485 | * route(8) has a bug and provides less memory. | |||
1486 | * arp(8) has another bug and uses sizeof pointer. | |||
1487 | */ | |||
1488 | size = 4; | |||
1489 | break; | |||
1490 | case RTAX_IFA5: | |||
1491 | switch (sa->sa_family) { | |||
1492 | case AF_INET2: | |||
1493 | size = sizeof(struct sockaddr_in); | |||
1494 | break; | |||
1495 | #ifdef INET61 | |||
1496 | case AF_INET624: | |||
1497 | size = sizeof(struct sockaddr_in6); | |||
1498 | break; | |||
1499 | #endif | |||
1500 | default: | |||
1501 | return (EAFNOSUPPORT47); | |||
1502 | } | |||
1503 | break; | |||
1504 | case RTAX_LABEL10: | |||
1505 | if (sa->sa_family != AF_UNSPEC0) | |||
1506 | return (EAFNOSUPPORT47); | |||
1507 | maxlen = RTLABEL_LEN32; | |||
1508 | size = sizeof(struct sockaddr_rtlabel); | |||
1509 | break; | |||
1510 | #ifdef BFD | |||
1511 | case RTAX_BFD11: | |||
1512 | if (sa->sa_family != AF_UNSPEC0) | |||
1513 | return (EAFNOSUPPORT47); | |||
1514 | size = sizeof(struct sockaddr_bfd); | |||
1515 | break; | |||
1516 | #endif | |||
1517 | case RTAX_DNS12: | |||
1518 | /* more validation in rtm_validate_proposal */ | |||
1519 | if (sa->sa_len > sizeof(struct sockaddr_rtdns)) | |||
1520 | return (EINVAL22); | |||
1521 | if (sa->sa_len < offsetof(struct sockaddr_rtdns,__builtin_offsetof(struct sockaddr_rtdns, sr_dns) | |||
1522 | sr_dns)__builtin_offsetof(struct sockaddr_rtdns, sr_dns)) | |||
1523 | return (EINVAL22); | |||
1524 | switch (sa->sa_family) { | |||
1525 | case AF_INET2: | |||
1526 | #ifdef INET61 | |||
1527 | case AF_INET624: | |||
1528 | #endif | |||
1529 | break; | |||
1530 | default: | |||
1531 | return (EAFNOSUPPORT47); | |||
1532 | } | |||
1533 | break; | |||
1534 | case RTAX_STATIC13: | |||
1535 | switch (sa->sa_family) { | |||
1536 | case AF_INET2: | |||
1537 | #ifdef INET61 | |||
1538 | case AF_INET624: | |||
1539 | #endif | |||
1540 | break; | |||
1541 | default: | |||
1542 | return (EAFNOSUPPORT47); | |||
1543 | } | |||
1544 | maxlen = RTSTATIC_LEN128; | |||
1545 | size = sizeof(struct sockaddr_rtstatic); | |||
1546 | break; | |||
1547 | case RTAX_SEARCH14: | |||
1548 | if (sa->sa_family != AF_UNSPEC0) | |||
1549 | return (EAFNOSUPPORT47); | |||
1550 | maxlen = RTSEARCH_LEN128; | |||
1551 | size = sizeof(struct sockaddr_rtsearch); | |||
1552 | break; | |||
1553 | } | |||
1554 | if (size) { | |||
1555 | /* memory for the full struct must be provided */ | |||
1556 | if (sa->sa_len < size) | |||
1557 | return (EINVAL22); | |||
1558 | } | |||
1559 | if (maxlen) { | |||
1560 | /* this should not happen */ | |||
1561 | if (2 + maxlen > size) | |||
1562 | return (EINVAL22); | |||
1563 | /* strings must be NUL terminated within the struct */ | |||
1564 | len = strnlen(sa->sa_data, maxlen); | |||
1565 | if (len >= maxlen || 2 + len >= sa->sa_len) | |||
1566 | return (EINVAL22); | |||
1567 | break; | |||
1568 | } | |||
1569 | } | |||
1570 | return (0); | |||
1571 | } | |||
1572 | ||||
1573 | struct mbuf * | |||
1574 | rtm_msg1(int type, struct rt_addrinfo *rtinfo) | |||
1575 | { | |||
1576 | struct rt_msghdr *rtm; | |||
1577 | struct mbuf *m; | |||
1578 | int i; | |||
1579 | const struct sockaddr *sa; | |||
1580 | int len, dlen, hlen; | |||
1581 | ||||
1582 | switch (type) { | |||
1583 | case RTM_DELADDR0xd: | |||
1584 | case RTM_NEWADDR0xc: | |||
1585 | hlen = sizeof(struct ifa_msghdr); | |||
1586 | break; | |||
1587 | case RTM_IFINFO0xe: | |||
1588 | hlen = sizeof(struct if_msghdr); | |||
1589 | break; | |||
1590 | case RTM_IFANNOUNCE0xf: | |||
1591 | hlen = sizeof(struct if_announcemsghdr); | |||
1592 | break; | |||
1593 | #ifdef BFD | |||
1594 | case RTM_BFD0x12: | |||
1595 | hlen = sizeof(struct bfd_msghdr); | |||
1596 | break; | |||
1597 | #endif | |||
1598 | case RTM_80211INFO0x15: | |||
1599 | hlen = sizeof(struct if_ieee80211_msghdr); | |||
1600 | break; | |||
1601 | default: | |||
1602 | hlen = sizeof(struct rt_msghdr); | |||
1603 | break; | |||
1604 | } | |||
1605 | len = hlen; | |||
1606 | for (i = 0; i < RTAX_MAX15; i++) { | |||
1607 | if (rtinfo == NULL((void *)0) || (sa = rtinfo->rti_info[i]) == NULL((void *)0)) | |||
1608 | continue; | |||
1609 | len += ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof (long) - 1))) : sizeof(long)); | |||
1610 | } | |||
1611 | if (len > MCLBYTES(1 << 11)) | |||
1612 | panic("rtm_msg1"); | |||
1613 | m = m_gethdr(M_DONTWAIT0x0002, MT_DATA1); | |||
1614 | if (m && len > MHLEN((256 - sizeof(struct m_hdr)) - sizeof(struct pkthdr))) { | |||
1615 | MCLGET(m, M_DONTWAIT)(void) m_clget((m), (0x0002), (1 << 11)); | |||
1616 | if ((m->m_flagsm_hdr.mh_flags & M_EXT0x0001) == 0) { | |||
1617 | m_free(m); | |||
1618 | m = NULL((void *)0); | |||
1619 | } | |||
1620 | } | |||
1621 | if (m == NULL((void *)0)) | |||
1622 | return (m); | |||
1623 | m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = len; | |||
1624 | m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = 0; | |||
1625 | rtm = mtod(m, struct rt_msghdr *)((struct rt_msghdr *)((m)->m_hdr.mh_data)); | |||
1626 | bzero(rtm, len)__builtin_bzero((rtm), (len)); | |||
1627 | len = hlen; | |||
1628 | for (i = 0; i < RTAX_MAX15; i++) { | |||
1629 | if (rtinfo == NULL((void *)0) || (sa = rtinfo->rti_info[i]) == NULL((void *)0)) | |||
1630 | continue; | |||
1631 | rtinfo->rti_addrs |= (1U << i); | |||
1632 | dlen = ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof (long) - 1))) : sizeof(long)); | |||
1633 | if (m_copyback(m, len, sa->sa_len, sa, M_NOWAIT0x0002)) { | |||
1634 | m_freem(m); | |||
1635 | return (NULL((void *)0)); | |||
1636 | } | |||
1637 | len += dlen; | |||
1638 | } | |||
1639 | rtm->rtm_msglen = len; | |||
1640 | rtm->rtm_hdrlen = hlen; | |||
1641 | rtm->rtm_version = RTM_VERSION5; | |||
1642 | rtm->rtm_type = type; | |||
1643 | return (m); | |||
1644 | } | |||
1645 | ||||
1646 | int | |||
1647 | rtm_msg2(int type, int vers, struct rt_addrinfo *rtinfo, caddr_t cp, | |||
1648 | struct walkarg *w) | |||
1649 | { | |||
1650 | int i; | |||
1651 | int len, dlen, hlen, second_time = 0; | |||
1652 | caddr_t cp0; | |||
1653 | ||||
1654 | rtinfo->rti_addrs = 0; | |||
1655 | again: | |||
1656 | switch (type) { | |||
1657 | case RTM_DELADDR0xd: | |||
1658 | case RTM_NEWADDR0xc: | |||
1659 | len = sizeof(struct ifa_msghdr); | |||
1660 | break; | |||
1661 | case RTM_IFINFO0xe: | |||
1662 | len = sizeof(struct if_msghdr); | |||
1663 | break; | |||
1664 | default: | |||
1665 | len = sizeof(struct rt_msghdr); | |||
1666 | break; | |||
1667 | } | |||
1668 | hlen = len; | |||
1669 | if ((cp0 = cp) != NULL((void *)0)) | |||
1670 | cp += len; | |||
1671 | for (i = 0; i < RTAX_MAX15; i++) { | |||
1672 | const struct sockaddr *sa; | |||
1673 | ||||
1674 | if ((sa = rtinfo->rti_info[i]) == NULL((void *)0)) | |||
1675 | continue; | |||
1676 | rtinfo->rti_addrs |= (1U << i); | |||
1677 | dlen = ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof (long) - 1))) : sizeof(long)); | |||
1678 | if (cp) { | |||
1679 | bcopy(sa, cp, sa->sa_len); | |||
1680 | bzero(cp + sa->sa_len, dlen - sa->sa_len)__builtin_bzero((cp + sa->sa_len), (dlen - sa->sa_len)); | |||
1681 | cp += dlen; | |||
1682 | } | |||
1683 | len += dlen; | |||
1684 | } | |||
1685 | /* align message length to the next natural boundary */ | |||
1686 | len = ALIGN(len)(((unsigned long)(len) + (sizeof(long) - 1)) &~(sizeof(long ) - 1)); | |||
1687 | if (cp == 0 && w != NULL((void *)0) && !second_time) { | |||
1688 | w->w_needed += len; | |||
1689 | if (w->w_needed <= w->w_given && w->w_where) { | |||
1690 | if (w->w_tmemsize < len) { | |||
1691 | free(w->w_tmem, M_RTABLE5, w->w_tmemsize); | |||
1692 | w->w_tmem = malloc(len, M_RTABLE5, | |||
1693 | M_NOWAIT0x0002 | M_ZERO0x0008); | |||
1694 | if (w->w_tmem) | |||
1695 | w->w_tmemsize = len; | |||
1696 | } | |||
1697 | if (w->w_tmem) { | |||
1698 | cp = w->w_tmem; | |||
1699 | second_time = 1; | |||
1700 | goto again; | |||
1701 | } else | |||
1702 | w->w_where = 0; | |||
1703 | } | |||
1704 | } | |||
1705 | if (cp && w) /* clear the message header */ | |||
1706 | bzero(cp0, hlen)__builtin_bzero((cp0), (hlen)); | |||
1707 | ||||
1708 | if (cp) { | |||
1709 | struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; | |||
1710 | ||||
1711 | rtm->rtm_version = RTM_VERSION5; | |||
1712 | rtm->rtm_type = type; | |||
1713 | rtm->rtm_msglen = len; | |||
1714 | rtm->rtm_hdrlen = hlen; | |||
1715 | } | |||
1716 | return (len); | |||
1717 | } | |||
1718 | ||||
1719 | void | |||
1720 | rtm_send(struct rtentry *rt, int cmd, int error, unsigned int rtableid) | |||
1721 | { | |||
1722 | struct rt_addrinfo info; | |||
1723 | struct ifnet *ifp; | |||
1724 | struct sockaddr_rtlabel sa_rl; | |||
1725 | struct sockaddr_in6 sa_mask; | |||
1726 | ||||
1727 | memset(&info, 0, sizeof(info))__builtin_memset((&info), (0), (sizeof(info))); | |||
1728 | info.rti_info[RTAX_DST0] = rt_key(rt)((rt)->rt_dest); | |||
1729 | info.rti_info[RTAX_GATEWAY1] = rt->rt_gateway; | |||
1730 | if (!ISSET(rt->rt_flags, RTF_HOST)((rt->rt_flags) & (0x4))) | |||
1731 | info.rti_info[RTAX_NETMASK2] = rt_plen2mask(rt, &sa_mask); | |||
1732 | info.rti_info[RTAX_LABEL10] = rtlabel_id2sa(rt->rt_labelid, &sa_rl); | |||
1733 | ifp = if_get(rt->rt_ifidx); | |||
1734 | if (ifp != NULL((void *)0)) { | |||
1735 | info.rti_info[RTAX_IFP4] = sdltosa(ifp->if_sadl); | |||
1736 | info.rti_info[RTAX_IFA5] = rtable_getsource(rtableid, | |||
1737 | info.rti_info[RTAX_DST0]->sa_family); | |||
1738 | if (info.rti_info[RTAX_IFA5] == NULL((void *)0)) | |||
1739 | info.rti_info[RTAX_IFA5] = rt->rt_ifa->ifa_addr; | |||
1740 | } | |||
1741 | ||||
1742 | rtm_miss(cmd, &info, rt->rt_flags, rt->rt_priority, rt->rt_ifidx, error, | |||
1743 | rtableid); | |||
1744 | if_put(ifp); | |||
1745 | } | |||
1746 | ||||
1747 | /* | |||
1748 | * This routine is called to generate a message from the routing | |||
1749 | * socket indicating that a redirect has occurred, a routing lookup | |||
1750 | * has failed, or that a protocol has detected timeouts to a particular | |||
1751 | * destination. | |||
1752 | */ | |||
1753 | void | |||
1754 | rtm_miss(int type, struct rt_addrinfo *rtinfo, int flags, uint8_t prio, | |||
1755 | u_int ifidx, int error, u_int tableid) | |||
1756 | { | |||
1757 | struct rt_msghdr *rtm; | |||
1758 | struct mbuf *m; | |||
1759 | const struct sockaddr *sa = rtinfo->rti_info[RTAX_DST0]; | |||
1760 | ||||
1761 | if (rtptable.rtp_count == 0) | |||
1762 | return; | |||
1763 | m = rtm_msg1(type, rtinfo); | |||
1764 | if (m == NULL((void *)0)) | |||
1765 | return; | |||
1766 | rtm = mtod(m, struct rt_msghdr *)((struct rt_msghdr *)((m)->m_hdr.mh_data)); | |||
1767 | rtm->rtm_flags = RTF_DONE0x40 | flags; | |||
1768 | rtm->rtm_priority = prio; | |||
1769 | rtm->rtm_errno = error; | |||
1770 | rtm->rtm_tableid = tableid; | |||
1771 | rtm->rtm_addrs = rtinfo->rti_addrs; | |||
1772 | rtm->rtm_index = ifidx; | |||
1773 | route_input(m, NULL((void *)0), sa ? sa->sa_family : AF_UNSPEC0); | |||
1774 | } | |||
1775 | ||||
1776 | /* | |||
1777 | * This routine is called to generate a message from the routing | |||
1778 | * socket indicating that the status of a network interface has changed. | |||
1779 | */ | |||
1780 | void | |||
1781 | rtm_ifchg(struct ifnet *ifp) | |||
1782 | { | |||
1783 | struct rt_addrinfo info; | |||
1784 | struct if_msghdr *ifm; | |||
1785 | struct mbuf *m; | |||
1786 | ||||
1787 | if (rtptable.rtp_count == 0) | |||
1788 | return; | |||
1789 | memset(&info, 0, sizeof(info))__builtin_memset((&info), (0), (sizeof(info))); | |||
1790 | info.rti_info[RTAX_IFP4] = sdltosa(ifp->if_sadl); | |||
1791 | m = rtm_msg1(RTM_IFINFO0xe, &info); | |||
1792 | if (m == NULL((void *)0)) | |||
1793 | return; | |||
1794 | ifm = mtod(m, struct if_msghdr *)((struct if_msghdr *)((m)->m_hdr.mh_data)); | |||
1795 | ifm->ifm_index = ifp->if_index; | |||
1796 | ifm->ifm_tableid = ifp->if_rdomainif_data.ifi_rdomain; | |||
1797 | ifm->ifm_flags = ifp->if_flags; | |||
1798 | ifm->ifm_xflags = ifp->if_xflags; | |||
1799 | if_getdata(ifp, &ifm->ifm_data); | |||
1800 | ifm->ifm_addrs = info.rti_addrs; | |||
1801 | route_input(m, NULL((void *)0), AF_UNSPEC0); | |||
1802 | } | |||
1803 | ||||
1804 | /* | |||
1805 | * This is called to generate messages from the routing socket | |||
1806 | * indicating a network interface has had addresses associated with it. | |||
1807 | * if we ever reverse the logic and replace messages TO the routing | |||
1808 | * socket indicate a request to configure interfaces, then it will | |||
1809 | * be unnecessary as the routing socket will automatically generate | |||
1810 | * copies of it. | |||
1811 | */ | |||
1812 | void | |||
1813 | rtm_addr(int cmd, struct ifaddr *ifa) | |||
1814 | { | |||
1815 | struct ifnet *ifp = ifa->ifa_ifp; | |||
1816 | struct mbuf *m; | |||
1817 | struct rt_addrinfo info; | |||
1818 | struct ifa_msghdr *ifam; | |||
1819 | ||||
1820 | if (rtptable.rtp_count == 0) | |||
1821 | return; | |||
1822 | ||||
1823 | memset(&info, 0, sizeof(info))__builtin_memset((&info), (0), (sizeof(info))); | |||
1824 | info.rti_info[RTAX_IFA5] = ifa->ifa_addr; | |||
1825 | info.rti_info[RTAX_IFP4] = sdltosa(ifp->if_sadl); | |||
1826 | info.rti_info[RTAX_NETMASK2] = ifa->ifa_netmask; | |||
1827 | info.rti_info[RTAX_BRD7] = ifa->ifa_dstaddr; | |||
1828 | if ((m = rtm_msg1(cmd, &info)) == NULL((void *)0)) | |||
1829 | return; | |||
1830 | ifam = mtod(m, struct ifa_msghdr *)((struct ifa_msghdr *)((m)->m_hdr.mh_data)); | |||
1831 | ifam->ifam_index = ifp->if_index; | |||
1832 | ifam->ifam_metric = ifa->ifa_metric; | |||
1833 | ifam->ifam_flags = ifa->ifa_flags; | |||
1834 | ifam->ifam_addrs = info.rti_addrs; | |||
1835 | ifam->ifam_tableid = ifp->if_rdomainif_data.ifi_rdomain; | |||
1836 | ||||
1837 | route_input(m, NULL((void *)0), | |||
1838 | ifa->ifa_addr ? ifa->ifa_addr->sa_family : AF_UNSPEC0); | |||
1839 | } | |||
1840 | ||||
1841 | /* | |||
1842 | * This is called to generate routing socket messages indicating | |||
1843 | * network interface arrival and departure. | |||
1844 | */ | |||
1845 | void | |||
1846 | rtm_ifannounce(struct ifnet *ifp, int what) | |||
1847 | { | |||
1848 | struct if_announcemsghdr *ifan; | |||
1849 | struct mbuf *m; | |||
1850 | ||||
1851 | if (rtptable.rtp_count == 0) | |||
1852 | return; | |||
1853 | m = rtm_msg1(RTM_IFANNOUNCE0xf, NULL((void *)0)); | |||
1854 | if (m == NULL((void *)0)) | |||
1855 | return; | |||
1856 | ifan = mtod(m, struct if_announcemsghdr *)((struct if_announcemsghdr *)((m)->m_hdr.mh_data)); | |||
1857 | ifan->ifan_index = ifp->if_index; | |||
1858 | strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name)); | |||
1859 | ifan->ifan_what = what; | |||
1860 | route_input(m, NULL((void *)0), AF_UNSPEC0); | |||
1861 | } | |||
1862 | ||||
1863 | #ifdef BFD | |||
1864 | /* | |||
1865 | * This is used to generate routing socket messages indicating | |||
1866 | * the state of a BFD session. | |||
1867 | */ | |||
1868 | void | |||
1869 | rtm_bfd(struct bfd_config *bfd) | |||
1870 | { | |||
1871 | struct bfd_msghdr *bfdm; | |||
1872 | struct sockaddr_bfd sa_bfd; | |||
1873 | struct mbuf *m; | |||
1874 | struct rt_addrinfo info; | |||
1875 | ||||
1876 | if (rtptable.rtp_count == 0) | |||
1877 | return; | |||
1878 | memset(&info, 0, sizeof(info))__builtin_memset((&info), (0), (sizeof(info))); | |||
1879 | info.rti_info[RTAX_DST0] = rt_key(bfd->bc_rt)((bfd->bc_rt)->rt_dest); | |||
1880 | info.rti_info[RTAX_IFA5] = bfd->bc_rt->rt_ifa->ifa_addr; | |||
1881 | ||||
1882 | m = rtm_msg1(RTM_BFD0x12, &info); | |||
1883 | if (m == NULL((void *)0)) | |||
1884 | return; | |||
1885 | bfdm = mtod(m, struct bfd_msghdr *)((struct bfd_msghdr *)((m)->m_hdr.mh_data)); | |||
1886 | bfdm->bm_addrs = info.rti_addrs; | |||
1887 | ||||
1888 | KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/rtsock.c" , 1888, "_kernel_lock_held()")); | |||
1889 | bfd2sa(bfd->bc_rt, &sa_bfd); | |||
1890 | memcpy(&bfdm->bm_sa, &sa_bfd, sizeof(sa_bfd))__builtin_memcpy((&bfdm->bm_sa), (&sa_bfd), (sizeof (sa_bfd))); | |||
1891 | ||||
1892 | route_input(m, NULL((void *)0), info.rti_info[RTAX_DST0]->sa_family); | |||
1893 | } | |||
1894 | #endif /* BFD */ | |||
1895 | ||||
1896 | /* | |||
1897 | * This is used to generate routing socket messages indicating | |||
1898 | * the state of an ieee80211 interface. | |||
1899 | */ | |||
1900 | void | |||
1901 | rtm_80211info(struct ifnet *ifp, struct if_ieee80211_data *ifie) | |||
1902 | { | |||
1903 | struct if_ieee80211_msghdr *ifim; | |||
1904 | struct mbuf *m; | |||
1905 | ||||
1906 | if (rtptable.rtp_count == 0) | |||
1907 | return; | |||
1908 | m = rtm_msg1(RTM_80211INFO0x15, NULL((void *)0)); | |||
1909 | if (m == NULL((void *)0)) | |||
1910 | return; | |||
1911 | ifim = mtod(m, struct if_ieee80211_msghdr *)((struct if_ieee80211_msghdr *)((m)->m_hdr.mh_data)); | |||
1912 | ifim->ifim_index = ifp->if_index; | |||
1913 | ifim->ifim_tableid = ifp->if_rdomainif_data.ifi_rdomain; | |||
1914 | ||||
1915 | memcpy(&ifim->ifim_ifie, ifie, sizeof(ifim->ifim_ifie))__builtin_memcpy((&ifim->ifim_ifie), (ifie), (sizeof(ifim ->ifim_ifie))); | |||
1916 | route_input(m, NULL((void *)0), AF_UNSPEC0); | |||
1917 | } | |||
1918 | ||||
1919 | /* | |||
1920 | * This is used to generate routing socket messages indicating | |||
1921 | * the address selection proposal from an interface. | |||
1922 | */ | |||
1923 | void | |||
1924 | rtm_proposal(struct ifnet *ifp, struct rt_addrinfo *rtinfo, int flags, | |||
1925 | uint8_t prio) | |||
1926 | { | |||
1927 | struct rt_msghdr *rtm; | |||
1928 | struct mbuf *m; | |||
1929 | ||||
1930 | m = rtm_msg1(RTM_PROPOSAL0x13, rtinfo); | |||
1931 | if (m == NULL((void *)0)) | |||
| ||||
1932 | return; | |||
1933 | rtm = mtod(m, struct rt_msghdr *)((struct rt_msghdr *)((m)->m_hdr.mh_data)); | |||
1934 | rtm->rtm_flags = RTF_DONE0x40 | flags; | |||
1935 | rtm->rtm_priority = prio; | |||
1936 | rtm->rtm_tableid = ifp->if_rdomainif_data.ifi_rdomain; | |||
1937 | rtm->rtm_index = ifp->if_index; | |||
1938 | rtm->rtm_addrs = rtinfo->rti_addrs; | |||
1939 | ||||
1940 | route_input(m, NULL((void *)0), rtinfo->rti_info[RTAX_DNS12]->sa_family); | |||
1941 | } | |||
1942 | ||||
1943 | /* | |||
1944 | * This is used in dumping the kernel table via sysctl(). | |||
1945 | */ | |||
1946 | int | |||
1947 | sysctl_dumpentry(struct rtentry *rt, void *v, unsigned int id) | |||
1948 | { | |||
1949 | struct walkarg *w = v; | |||
1950 | int error = 0, size; | |||
1951 | struct rt_addrinfo info; | |||
1952 | struct ifnet *ifp; | |||
1953 | #ifdef BFD | |||
1954 | struct sockaddr_bfd sa_bfd; | |||
1955 | #endif | |||
1956 | struct sockaddr_rtlabel sa_rl; | |||
1957 | struct sockaddr_in6 sa_mask; | |||
1958 | ||||
1959 | if (w->w_op == NET_RT_FLAGS2 && !(rt->rt_flags & w->w_arg)) | |||
1960 | return 0; | |||
1961 | if (w->w_op == NET_RT_DUMP1 && w->w_arg) { | |||
1962 | u_int8_t prio = w->w_arg & RTP_MASK0x7f; | |||
1963 | if (w->w_arg < 0) { | |||
1964 | prio = (-w->w_arg) & RTP_MASK0x7f; | |||
1965 | /* Show all routes that are not this priority */ | |||
1966 | if (prio == (rt->rt_priority & RTP_MASK0x7f)) | |||
1967 | return 0; | |||
1968 | } else { | |||
1969 | if (prio != (rt->rt_priority & RTP_MASK0x7f) && | |||
1970 | prio != RTP_ANY64) | |||
1971 | return 0; | |||
1972 | } | |||
1973 | } | |||
1974 | bzero(&info, sizeof(info))__builtin_bzero((&info), (sizeof(info))); | |||
1975 | info.rti_info[RTAX_DST0] = rt_key(rt)((rt)->rt_dest); | |||
1976 | info.rti_info[RTAX_GATEWAY1] = rt->rt_gateway; | |||
1977 | info.rti_info[RTAX_NETMASK2] = rt_plen2mask(rt, &sa_mask); | |||
1978 | ifp = if_get(rt->rt_ifidx); | |||
1979 | if (ifp != NULL((void *)0)) { | |||
1980 | info.rti_info[RTAX_IFP4] = sdltosa(ifp->if_sadl); | |||
1981 | info.rti_info[RTAX_IFA5] = | |||
1982 | rtable_getsource(id, info.rti_info[RTAX_DST0]->sa_family); | |||
1983 | if (info.rti_info[RTAX_IFA5] == NULL((void *)0)) | |||
1984 | info.rti_info[RTAX_IFA5] = rt->rt_ifa->ifa_addr; | |||
1985 | if (ifp->if_flags & IFF_POINTOPOINT0x10) | |||
1986 | info.rti_info[RTAX_BRD7] = rt->rt_ifa->ifa_dstaddr; | |||
1987 | } | |||
1988 | if_put(ifp); | |||
1989 | info.rti_info[RTAX_LABEL10] = rtlabel_id2sa(rt->rt_labelid, &sa_rl); | |||
1990 | #ifdef BFD | |||
1991 | if (rt->rt_flags & RTF_BFD0x1000000) { | |||
1992 | KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/rtsock.c" , 1992, "_kernel_lock_held()")); | |||
1993 | info.rti_info[RTAX_BFD11] = bfd2sa(rt, &sa_bfd); | |||
1994 | } | |||
1995 | #endif | |||
1996 | #ifdef MPLS1 | |||
1997 | if (rt->rt_flags & RTF_MPLS0x100000) { | |||
1998 | struct sockaddr_mpls sa_mpls; | |||
1999 | ||||
2000 | bzero(&sa_mpls, sizeof(sa_mpls))__builtin_bzero((&sa_mpls), (sizeof(sa_mpls))); | |||
2001 | sa_mpls.smpls_family = AF_MPLS33; | |||
2002 | sa_mpls.smpls_len = sizeof(sa_mpls); | |||
2003 | sa_mpls.smpls_label = ((struct rt_mpls *) | |||
2004 | rt->rt_llinfo)->mpls_label; | |||
2005 | info.rti_info[RTAX_SRC8] = (struct sockaddr *)&sa_mpls; | |||
2006 | info.rti_mpls = ((struct rt_mpls *) | |||
2007 | rt->rt_llinfo)->mpls_operation; | |||
2008 | } | |||
2009 | #endif | |||
2010 | ||||
2011 | size = rtm_msg2(RTM_GET0x4, RTM_VERSION5, &info, NULL((void *)0), w); | |||
2012 | if (w->w_where && w->w_tmem && w->w_needed <= w->w_given) { | |||
2013 | struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; | |||
2014 | ||||
2015 | rtm->rtm_pid = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid; | |||
2016 | rtm->rtm_flags = RTF_DONE0x40 | rt->rt_flags; | |||
2017 | rtm->rtm_priority = rt->rt_priority & RTP_MASK0x7f; | |||
2018 | rtm_getmetrics(rt, &rtm->rtm_rmx); | |||
2019 | /* Do not account the routing table's reference. */ | |||
2020 | rtm->rtm_rmx.rmx_refcnt = refcnt_read(&rt->rt_refcnt) - 1; | |||
2021 | rtm->rtm_index = rt->rt_ifidx; | |||
2022 | rtm->rtm_addrs = info.rti_addrs; | |||
2023 | rtm->rtm_tableid = id; | |||
2024 | #ifdef MPLS1 | |||
2025 | rtm->rtm_mpls = info.rti_mpls; | |||
2026 | #endif | |||
2027 | if ((error = copyout(rtm, w->w_where, size)) != 0) | |||
2028 | w->w_where = NULL((void *)0); | |||
2029 | else | |||
2030 | w->w_where += size; | |||
2031 | } | |||
2032 | return (error); | |||
2033 | } | |||
2034 | ||||
2035 | int | |||
2036 | sysctl_iflist(int af, struct walkarg *w) | |||
2037 | { | |||
2038 | struct ifnet *ifp; | |||
2039 | struct ifaddr *ifa; | |||
2040 | struct rt_addrinfo info; | |||
2041 | int len, error = 0; | |||
2042 | ||||
2043 | bzero(&info, sizeof(info))__builtin_bzero((&info), (sizeof(info))); | |||
2044 | TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void *)0); (ifp) = ((ifp)->if_list.tqe_next)) { | |||
2045 | if (w->w_arg && w->w_arg != ifp->if_index) | |||
2046 | continue; | |||
2047 | /* Copy the link-layer address first */ | |||
2048 | info.rti_info[RTAX_IFP4] = sdltosa(ifp->if_sadl); | |||
2049 | len = rtm_msg2(RTM_IFINFO0xe, RTM_VERSION5, &info, 0, w); | |||
2050 | if (w->w_where && w->w_tmem && w->w_needed <= w->w_given) { | |||
2051 | struct if_msghdr *ifm; | |||
2052 | ||||
2053 | ifm = (struct if_msghdr *)w->w_tmem; | |||
2054 | ifm->ifm_index = ifp->if_index; | |||
2055 | ifm->ifm_tableid = ifp->if_rdomainif_data.ifi_rdomain; | |||
2056 | ifm->ifm_flags = ifp->if_flags; | |||
2057 | if_getdata(ifp, &ifm->ifm_data); | |||
2058 | ifm->ifm_addrs = info.rti_addrs; | |||
2059 | error = copyout(ifm, w->w_where, len); | |||
2060 | if (error) | |||
2061 | return (error); | |||
2062 | w->w_where += len; | |||
2063 | } | |||
2064 | info.rti_info[RTAX_IFP4] = NULL((void *)0); | |||
2065 | TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)for((ifa) = ((&ifp->if_addrlist)->tqh_first); (ifa) != ((void *)0); (ifa) = ((ifa)->ifa_list.tqe_next)) { | |||
2066 | KASSERT(ifa->ifa_addr->sa_family != AF_LINK)((ifa->ifa_addr->sa_family != 18) ? (void)0 : __assert( "diagnostic ", "/usr/src/sys/net/rtsock.c", 2066, "ifa->ifa_addr->sa_family != AF_LINK" )); | |||
2067 | if (af && af != ifa->ifa_addr->sa_family) | |||
2068 | continue; | |||
2069 | info.rti_info[RTAX_IFA5] = ifa->ifa_addr; | |||
2070 | info.rti_info[RTAX_NETMASK2] = ifa->ifa_netmask; | |||
2071 | info.rti_info[RTAX_BRD7] = ifa->ifa_dstaddr; | |||
2072 | len = rtm_msg2(RTM_NEWADDR0xc, RTM_VERSION5, &info, 0, w); | |||
2073 | if (w->w_where && w->w_tmem && | |||
2074 | w->w_needed <= w->w_given) { | |||
2075 | struct ifa_msghdr *ifam; | |||
2076 | ||||
2077 | ifam = (struct ifa_msghdr *)w->w_tmem; | |||
2078 | ifam->ifam_index = ifa->ifa_ifp->if_index; | |||
2079 | ifam->ifam_flags = ifa->ifa_flags; | |||
2080 | ifam->ifam_metric = ifa->ifa_metric; | |||
2081 | ifam->ifam_addrs = info.rti_addrs; | |||
2082 | error = copyout(w->w_tmem, w->w_where, len); | |||
2083 | if (error) | |||
2084 | return (error); | |||
2085 | w->w_where += len; | |||
2086 | } | |||
2087 | } | |||
2088 | info.rti_info[RTAX_IFA5] = info.rti_info[RTAX_NETMASK2] = | |||
2089 | info.rti_info[RTAX_BRD7] = NULL((void *)0); | |||
2090 | } | |||
2091 | return (0); | |||
2092 | } | |||
2093 | ||||
2094 | int | |||
2095 | sysctl_ifnames(struct walkarg *w) | |||
2096 | { | |||
2097 | struct if_nameindex_msg ifn; | |||
2098 | struct ifnet *ifp; | |||
2099 | int error = 0; | |||
2100 | ||||
2101 | /* XXX ignore tableid for now */ | |||
2102 | TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void *)0); (ifp) = ((ifp)->if_list.tqe_next)) { | |||
2103 | if (w->w_arg && w->w_arg != ifp->if_index) | |||
2104 | continue; | |||
2105 | w->w_needed += sizeof(ifn); | |||
2106 | if (w->w_where && w->w_needed <= w->w_given) { | |||
2107 | ||||
2108 | memset(&ifn, 0, sizeof(ifn))__builtin_memset((&ifn), (0), (sizeof(ifn))); | |||
2109 | ifn.if_index = ifp->if_index; | |||
2110 | strlcpy(ifn.if_name, ifp->if_xname, | |||
2111 | sizeof(ifn.if_name)); | |||
2112 | error = copyout(&ifn, w->w_where, sizeof(ifn)); | |||
2113 | if (error) | |||
2114 | return (error); | |||
2115 | w->w_where += sizeof(ifn); | |||
2116 | } | |||
2117 | } | |||
2118 | ||||
2119 | return (0); | |||
2120 | } | |||
2121 | ||||
2122 | int | |||
2123 | sysctl_source(int af, u_int tableid, struct walkarg *w) | |||
2124 | { | |||
2125 | struct sockaddr *sa; | |||
2126 | int size, error = 0; | |||
2127 | ||||
2128 | sa = rtable_getsource(tableid, af); | |||
2129 | if (sa) { | |||
2130 | switch (sa->sa_family) { | |||
2131 | case AF_INET2: | |||
2132 | size = sizeof(struct sockaddr_in); | |||
2133 | break; | |||
2134 | #ifdef INET61 | |||
2135 | case AF_INET624: | |||
2136 | size = sizeof(struct sockaddr_in6); | |||
2137 | break; | |||
2138 | #endif | |||
2139 | default: | |||
2140 | return (0); | |||
2141 | } | |||
2142 | w->w_needed += size; | |||
2143 | if (w->w_where && w->w_needed <= w->w_given) { | |||
2144 | if ((error = copyout(sa, w->w_where, size))) | |||
2145 | return (error); | |||
2146 | w->w_where += size; | |||
2147 | } | |||
2148 | } | |||
2149 | return (0); | |||
2150 | } | |||
2151 | ||||
2152 | int | |||
2153 | sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new, | |||
2154 | size_t newlen) | |||
2155 | { | |||
2156 | int i, error = EINVAL22; | |||
2157 | u_char af; | |||
2158 | struct walkarg w; | |||
2159 | struct rt_tableinfo tableinfo; | |||
2160 | u_int tableid = 0; | |||
2161 | ||||
2162 | if (new) | |||
2163 | return (EPERM1); | |||
2164 | if (namelen < 3 || namelen > 4) | |||
2165 | return (EINVAL22); | |||
2166 | af = name[0]; | |||
2167 | bzero(&w, sizeof(w))__builtin_bzero((&w), (sizeof(w))); | |||
2168 | w.w_where = where; | |||
2169 | w.w_given = *given; | |||
2170 | w.w_op = name[1]; | |||
2171 | w.w_arg = name[2]; | |||
2172 | ||||
2173 | if (namelen == 4) { | |||
2174 | tableid = name[3]; | |||
2175 | if (!rtable_exists(tableid)) | |||
2176 | return (ENOENT2); | |||
2177 | } else | |||
2178 | tableid = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_rtableid; | |||
2179 | ||||
2180 | switch (w.w_op) { | |||
2181 | case NET_RT_DUMP1: | |||
2182 | case NET_RT_FLAGS2: | |||
2183 | NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0); | |||
2184 | for (i = 1; i <= AF_MAX36; i++) { | |||
2185 | if (af != 0 && af != i) | |||
2186 | continue; | |||
2187 | ||||
2188 | error = rtable_walk(tableid, i, NULL((void *)0), sysctl_dumpentry, | |||
2189 | &w); | |||
2190 | if (error == EAFNOSUPPORT47) | |||
2191 | error = 0; | |||
2192 | if (error) | |||
2193 | break; | |||
2194 | } | |||
2195 | NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0); | |||
2196 | break; | |||
2197 | ||||
2198 | case NET_RT_IFLIST3: | |||
2199 | NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0); | |||
2200 | error = sysctl_iflist(af, &w); | |||
2201 | NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0); | |||
2202 | break; | |||
2203 | ||||
2204 | case NET_RT_STATS4: | |||
2205 | return (sysctl_rtable_rtstat(where, given, new)); | |||
2206 | case NET_RT_TABLE5: | |||
2207 | tableid = w.w_arg; | |||
2208 | if (!rtable_exists(tableid)) | |||
2209 | return (ENOENT2); | |||
2210 | memset(&tableinfo, 0, sizeof tableinfo)__builtin_memset((&tableinfo), (0), (sizeof tableinfo)); | |||
2211 | tableinfo.rti_tableid = tableid; | |||
2212 | tableinfo.rti_domainid = rtable_l2(tableid); | |||
2213 | error = sysctl_rdstruct(where, given, new, | |||
2214 | &tableinfo, sizeof(tableinfo)); | |||
2215 | return (error); | |||
2216 | case NET_RT_IFNAMES6: | |||
2217 | NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0); | |||
2218 | error = sysctl_ifnames(&w); | |||
2219 | NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0); | |||
2220 | break; | |||
2221 | case NET_RT_SOURCE7: | |||
2222 | tableid = w.w_arg; | |||
2223 | if (!rtable_exists(tableid)) | |||
2224 | return (ENOENT2); | |||
2225 | NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0); | |||
2226 | for (i = 1; i <= AF_MAX36; i++) { | |||
2227 | if (af != 0 && af != i) | |||
2228 | continue; | |||
2229 | ||||
2230 | error = sysctl_source(i, tableid, &w); | |||
2231 | if (error == EAFNOSUPPORT47) | |||
2232 | error = 0; | |||
2233 | if (error) | |||
2234 | break; | |||
2235 | } | |||
2236 | NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0); | |||
2237 | break; | |||
2238 | } | |||
2239 | free(w.w_tmem, M_RTABLE5, w.w_tmemsize); | |||
2240 | if (where) { | |||
2241 | *given = w.w_where - (caddr_t)where; | |||
2242 | if (w.w_needed > w.w_given) | |||
2243 | return (ENOMEM12); | |||
2244 | } else if (w.w_needed == 0) { | |||
2245 | *given = 0; | |||
2246 | } else { | |||
2247 | *given = roundup(w.w_needed + MAX(w.w_needed / 10, 1024),((((w.w_needed + (((w.w_needed / 10)>(1024))?(w.w_needed / 10):(1024)))+(((1 << 12))-1))/((1 << 12)))*((1 << 12))) | |||
2248 | PAGE_SIZE)((((w.w_needed + (((w.w_needed / 10)>(1024))?(w.w_needed / 10):(1024)))+(((1 << 12))-1))/((1 << 12)))*((1 << 12))); | |||
2249 | } | |||
2250 | return (error); | |||
2251 | } | |||
2252 | ||||
2253 | int | |||
2254 | sysctl_rtable_rtstat(void *oldp, size_t *oldlenp, void *newp) | |||
2255 | { | |||
2256 | extern struct cpumem *rtcounters; | |||
2257 | uint64_t counters[rts_ncounters]; | |||
2258 | struct rtstat rtstat; | |||
2259 | uint32_t *words = (uint32_t *)&rtstat; | |||
2260 | int i; | |||
2261 | ||||
2262 | CTASSERT(sizeof(rtstat) == (nitems(counters) * sizeof(uint32_t)))extern char _ctassert[(sizeof(rtstat) == ((sizeof((counters)) / sizeof((counters)[0])) * sizeof(uint32_t))) ? 1 : -1 ] __attribute__ ((__unused__)); | |||
2263 | memset(&rtstat, 0, sizeof rtstat)__builtin_memset((&rtstat), (0), (sizeof rtstat)); | |||
2264 | counters_read(rtcounters, counters, nitems(counters)(sizeof((counters)) / sizeof((counters)[0])), NULL((void *)0)); | |||
2265 | ||||
2266 | for (i = 0; i < nitems(counters)(sizeof((counters)) / sizeof((counters)[0])); i++) | |||
2267 | words[i] = (uint32_t)counters[i]; | |||
2268 | ||||
2269 | return (sysctl_rdstruct(oldp, oldlenp, newp, &rtstat, sizeof(rtstat))); | |||
2270 | } | |||
2271 | ||||
2272 | int | |||
2273 | rtm_validate_proposal(struct rt_addrinfo *info) | |||
2274 | { | |||
2275 | if (info->rti_addrs & ~(RTA_NETMASK0x4 | RTA_IFA0x20 | RTA_DNS0x1000 | RTA_STATIC0x2000 | | |||
2276 | RTA_SEARCH0x4000)) { | |||
2277 | return -1; | |||
2278 | } | |||
2279 | ||||
2280 | if (ISSET(info->rti_addrs, RTA_NETMASK)((info->rti_addrs) & (0x4))) { | |||
2281 | const struct sockaddr *sa = info->rti_info[RTAX_NETMASK2]; | |||
2282 | if (sa == NULL((void *)0)) | |||
2283 | return -1; | |||
2284 | switch (sa->sa_family) { | |||
2285 | case AF_INET2: | |||
2286 | if (sa->sa_len != sizeof(struct sockaddr_in)) | |||
2287 | return -1; | |||
2288 | break; | |||
2289 | case AF_INET624: | |||
2290 | if (sa->sa_len != sizeof(struct sockaddr_in6)) | |||
2291 | return -1; | |||
2292 | break; | |||
2293 | default: | |||
2294 | return -1; | |||
2295 | } | |||
2296 | } | |||
2297 | ||||
2298 | if (ISSET(info->rti_addrs, RTA_IFA)((info->rti_addrs) & (0x20))) { | |||
2299 | const struct sockaddr *sa = info->rti_info[RTAX_IFA5]; | |||
2300 | if (sa == NULL((void *)0)) | |||
2301 | return -1; | |||
2302 | switch (sa->sa_family) { | |||
2303 | case AF_INET2: | |||
2304 | if (sa->sa_len != sizeof(struct sockaddr_in)) | |||
2305 | return -1; | |||
2306 | break; | |||
2307 | case AF_INET624: | |||
2308 | if (sa->sa_len != sizeof(struct sockaddr_in6)) | |||
2309 | return -1; | |||
2310 | break; | |||
2311 | default: | |||
2312 | return -1; | |||
2313 | } | |||
2314 | } | |||
2315 | ||||
2316 | if (ISSET(info->rti_addrs, RTA_DNS)((info->rti_addrs) & (0x1000))) { | |||
2317 | const struct sockaddr_rtdns *rtdns = | |||
2318 | (const struct sockaddr_rtdns *)info->rti_info[RTAX_DNS12]; | |||
2319 | if (rtdns == NULL((void *)0)) | |||
2320 | return -1; | |||
2321 | if (rtdns->sr_len > sizeof(*rtdns)) | |||
2322 | return -1; | |||
2323 | if (rtdns->sr_len < offsetof(struct sockaddr_rtdns, sr_dns)__builtin_offsetof(struct sockaddr_rtdns, sr_dns)) | |||
2324 | return -1; | |||
2325 | switch (rtdns->sr_family) { | |||
2326 | case AF_INET2: | |||
2327 | if ((rtdns->sr_len - offsetof(struct sockaddr_rtdns,__builtin_offsetof(struct sockaddr_rtdns, sr_dns) | |||
2328 | sr_dns)__builtin_offsetof(struct sockaddr_rtdns, sr_dns)) % sizeof(struct in_addr) != 0) | |||
2329 | return -1; | |||
2330 | break; | |||
2331 | #ifdef INET61 | |||
2332 | case AF_INET624: | |||
2333 | if ((rtdns->sr_len - offsetof(struct sockaddr_rtdns,__builtin_offsetof(struct sockaddr_rtdns, sr_dns) | |||
2334 | sr_dns)__builtin_offsetof(struct sockaddr_rtdns, sr_dns)) % sizeof(struct in6_addr) != 0) | |||
2335 | return -1; | |||
2336 | break; | |||
2337 | #endif | |||
2338 | default: | |||
2339 | return -1; | |||
2340 | } | |||
2341 | } | |||
2342 | ||||
2343 | if (ISSET(info->rti_addrs, RTA_STATIC)((info->rti_addrs) & (0x2000))) { | |||
2344 | const struct sockaddr_rtstatic *rtstatic = (const struct | |||
2345 | sockaddr_rtstatic *)info->rti_info[RTAX_STATIC13]; | |||
2346 | if (rtstatic == NULL((void *)0)) | |||
2347 | return -1; | |||
2348 | if (rtstatic->sr_len > sizeof(*rtstatic)) | |||
2349 | return -1; | |||
2350 | if (rtstatic->sr_len <= | |||
2351 | offsetof(struct sockaddr_rtstatic, sr_static)__builtin_offsetof(struct sockaddr_rtstatic, sr_static)) | |||
2352 | return -1; | |||
2353 | } | |||
2354 | ||||
2355 | if (ISSET(info->rti_addrs, RTA_SEARCH)((info->rti_addrs) & (0x4000))) { | |||
2356 | const struct sockaddr_rtsearch *rtsearch = (const struct | |||
2357 | sockaddr_rtsearch *)info->rti_info[RTAX_SEARCH14]; | |||
2358 | if (rtsearch == NULL((void *)0)) | |||
2359 | return -1; | |||
2360 | if (rtsearch->sr_len > sizeof(*rtsearch)) | |||
2361 | return -1; | |||
2362 | if (rtsearch->sr_len <= | |||
2363 | offsetof(struct sockaddr_rtsearch, sr_search)__builtin_offsetof(struct sockaddr_rtsearch, sr_search)) | |||
2364 | return -1; | |||
2365 | } | |||
2366 | ||||
2367 | return 0; | |||
2368 | } | |||
2369 | ||||
2370 | int | |||
2371 | rt_setsource(unsigned int rtableid, const struct sockaddr *src) | |||
2372 | { | |||
2373 | struct ifaddr *ifa; | |||
2374 | /* | |||
2375 | * If source address is 0.0.0.0 or :: | |||
2376 | * use automatic source selection | |||
2377 | */ | |||
2378 | switch(src->sa_family) { | |||
2379 | case AF_INET2: | |||
2380 | if(satosin_const(src)->sin_addr.s_addr == INADDR_ANY((u_int32_t) (__uint32_t)(__builtin_constant_p((u_int32_t)(0x00000000 )) ? (__uint32_t)(((__uint32_t)((u_int32_t)(0x00000000)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0x00000000) ) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0x00000000 ))))) { | |||
2381 | rtable_setsource(rtableid, AF_INET2, NULL((void *)0)); | |||
2382 | return (0); | |||
2383 | } | |||
2384 | break; | |||
2385 | #ifdef INET61 | |||
2386 | case AF_INET624: | |||
2387 | if (IN6_IS_ADDR_UNSPECIFIED(&satosin6_const(src)->sin6_addr)((*(const u_int32_t *)(const void *)(&(&satosin6_const (src)->sin6_addr)->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t *)(const void *)(&(&satosin6_const (src)->sin6_addr)->__u6_addr.__u6_addr8[4]) == 0) && (*(const u_int32_t *)(const void *)(&(&satosin6_const (src)->sin6_addr)->__u6_addr.__u6_addr8[8]) == 0) && (*(const u_int32_t *)(const void *)(&(&satosin6_const (src)->sin6_addr)->__u6_addr.__u6_addr8[12]) == 0))) { | |||
2388 | rtable_setsource(rtableid, AF_INET624, NULL((void *)0)); | |||
2389 | return (0); | |||
2390 | } | |||
2391 | break; | |||
2392 | #endif | |||
2393 | default: | |||
2394 | return (EAFNOSUPPORT47); | |||
2395 | } | |||
2396 | ||||
2397 | /* | |||
2398 | * Check if source address is assigned to an interface in the | |||
2399 | * same rdomain | |||
2400 | */ | |||
2401 | if ((ifa = ifa_ifwithaddr(src, rtableid)) == NULL((void *)0)) | |||
2402 | return (EINVAL22); | |||
2403 | ||||
2404 | return rtable_setsource(rtableid, src->sa_family, ifa->ifa_addr); | |||
2405 | } | |||
2406 | ||||
2407 | /* | |||
2408 | * Definitions of protocols supported in the ROUTE domain. | |||
2409 | */ | |||
2410 | ||||
2411 | const struct pr_usrreqs route_usrreqs = { | |||
2412 | .pru_attach = route_attach, | |||
2413 | .pru_detach = route_detach, | |||
2414 | .pru_disconnect = route_disconnect, | |||
2415 | .pru_shutdown = route_shutdown, | |||
2416 | .pru_rcvd = route_rcvd, | |||
2417 | .pru_send = route_send, | |||
2418 | .pru_sockaddr = route_sockaddr, | |||
2419 | .pru_peeraddr = route_peeraddr, | |||
2420 | }; | |||
2421 | ||||
2422 | const struct protosw routesw[] = { | |||
2423 | { | |||
2424 | .pr_type = SOCK_RAW3, | |||
2425 | .pr_domain = &routedomain, | |||
2426 | .pr_flags = PR_ATOMIC0x0001|PR_ADDR0x0002|PR_WANTRCVD0x0008, | |||
2427 | .pr_ctloutput = route_ctloutput, | |||
2428 | .pr_usrreqs = &route_usrreqs, | |||
2429 | .pr_init = route_prinit, | |||
2430 | .pr_sysctl = sysctl_rtable | |||
2431 | } | |||
2432 | }; | |||
2433 | ||||
2434 | const struct domain routedomain = { | |||
2435 | .dom_family = PF_ROUTE17, | |||
2436 | .dom_name = "route", | |||
2437 | .dom_init = route_init, | |||
2438 | .dom_protosw = routesw, | |||
2439 | .dom_protoswNPROTOSW = &routesw[nitems(routesw)(sizeof((routesw)) / sizeof((routesw)[0]))] | |||
2440 | }; |