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