File: | netinet6/ip6_mroute.c |
Warning: | line 1184, column 3 Value stored to 'error' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ip6_mroute.c,v 1.138 2023/12/06 09:27:17 bluhm Exp $ */ |
2 | /* $NetBSD: ip6_mroute.c,v 1.59 2003/12/10 09:28:38 itojun Exp $ */ |
3 | /* $KAME: ip6_mroute.c,v 1.45 2001/03/25 08:38:51 itojun Exp $ */ |
4 | |
5 | /* |
6 | * Copyright (C) 1998 WIDE Project. |
7 | * All rights reserved. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. Neither the name of the project nor the names of its contributors |
18 | * may be used to endorse or promote products derived from this software |
19 | * without specific prior written permission. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | * SUCH DAMAGE. |
32 | */ |
33 | |
34 | /* BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp */ |
35 | |
36 | /* |
37 | * Copyright (c) 1989 Stephen Deering |
38 | * Copyright (c) 1992, 1993 |
39 | * The Regents of the University of California. All rights reserved. |
40 | * |
41 | * This code is derived from software contributed to Berkeley by |
42 | * Stephen Deering of Stanford University. |
43 | * |
44 | * Redistribution and use in source and binary forms, with or without |
45 | * modification, are permitted provided that the following conditions |
46 | * are met: |
47 | * 1. Redistributions of source code must retain the above copyright |
48 | * notice, this list of conditions and the following disclaimer. |
49 | * 2. Redistributions in binary form must reproduce the above copyright |
50 | * notice, this list of conditions and the following disclaimer in the |
51 | * documentation and/or other materials provided with the distribution. |
52 | * 3. Neither the name of the University nor the names of its contributors |
53 | * may be used to endorse or promote products derived from this software |
54 | * without specific prior written permission. |
55 | * |
56 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
57 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
58 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
59 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
60 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
61 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
62 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
63 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
64 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
65 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
66 | * SUCH DAMAGE. |
67 | * |
68 | * @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93 |
69 | */ |
70 | |
71 | /* |
72 | * IP multicast forwarding procedures |
73 | * |
74 | * Written by David Waitzman, BBN Labs, August 1988. |
75 | * Modified by Steve Deering, Stanford, February 1989. |
76 | * Modified by Mark J. Steiglitz, Stanford, May, 1991 |
77 | * Modified by Van Jacobson, LBL, January 1993 |
78 | * Modified by Ajit Thyagarajan, PARC, August 1993 |
79 | * Modified by Bill Fenner, PARC, April 1994 |
80 | * |
81 | * MROUTING Revision: 3.5.1.2 |
82 | */ |
83 | |
84 | #include <sys/param.h> |
85 | #include <sys/malloc.h> |
86 | #include <sys/systm.h> |
87 | #include <sys/timeout.h> |
88 | #include <sys/mbuf.h> |
89 | #include <sys/socket.h> |
90 | #include <sys/socketvar.h> |
91 | #include <sys/protosw.h> |
92 | #include <sys/kernel.h> |
93 | #include <sys/ioctl.h> |
94 | #include <sys/syslog.h> |
95 | #include <sys/sysctl.h> |
96 | |
97 | #include <net/if.h> |
98 | #include <net/if_var.h> |
99 | #include <net/route.h> |
100 | |
101 | #include <netinet/in.h> |
102 | #include <netinet6/in6_var.h> |
103 | #include <netinet/ip.h> |
104 | #include <netinet/ip6.h> |
105 | #include <netinet/icmp6.h> |
106 | #include <netinet6/ip6_var.h> |
107 | #include <netinet6/ip6_mroute.h> |
108 | #include <netinet/in_pcb.h> |
109 | |
110 | /* #define MCAST_DEBUG */ |
111 | |
112 | #ifdef MCAST_DEBUG |
113 | int mcast6_debug = 1; |
114 | #define DPRINTF(fmt, args...)do { } while (0) \ |
115 | do { \ |
116 | if (mcast6_debug) \ |
117 | printf("%s:%d " fmt "\n", \ |
118 | __func__, __LINE__118, ## args); \ |
119 | } while (0) |
120 | #else |
121 | #define DPRINTF(fmt, args...)do { } while (0) \ |
122 | do { } while (0) |
123 | #endif |
124 | |
125 | int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *); |
126 | void phyint_send6(struct ifnet *, struct ip6_hdr *, struct mbuf *); |
127 | |
128 | /* |
129 | * Globals. All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static, |
130 | * except for netstat or debugging purposes. |
131 | */ |
132 | struct socket *ip6_mrouter[RT_TABLEID_MAX255 + 1]; |
133 | struct rttimer_queue ip6_mrouterq; |
134 | int ip6_mrouter_ver = 0; |
135 | int ip6_mrtproto; /* for netstat only */ |
136 | struct mrt6stat mrt6stat; |
137 | |
138 | #define NO_RTE_FOUND0x1 0x1 |
139 | #define RTE_FOUND0x2 0x2 |
140 | |
141 | /* |
142 | * Macros to compute elapsed time efficiently |
143 | * Borrowed from Van Jacobson's scheduling code |
144 | */ |
145 | #define TV_DELTA(a, b, delta)do { int xxs; delta = (a).tv_usec - (b).tv_usec; if ((xxs = ( a).tv_sec - (b).tv_sec)) { switch (xxs) { case 2: delta += 1000000 ; case 1: delta += 1000000; break; default: delta += (1000000 * xxs); } } } while (0) do { \ |
146 | int xxs; \ |
147 | \ |
148 | delta = (a).tv_usec - (b).tv_usec; \ |
149 | if ((xxs = (a).tv_sec - (b).tv_sec)) { \ |
150 | switch (xxs) { \ |
151 | case 2: \ |
152 | delta += 1000000; \ |
153 | /* FALLTHROUGH */ \ |
154 | case 1: \ |
155 | delta += 1000000; \ |
156 | break; \ |
157 | default: \ |
158 | delta += (1000000 * xxs); \ |
159 | } \ |
160 | } \ |
161 | } while (0) |
162 | |
163 | #define TV_LT(a, b)(((a).tv_usec < (b).tv_usec && (a).tv_sec <= (b ).tv_sec) || (a).tv_sec < (b).tv_sec) (((a).tv_usec < (b).tv_usec && \ |
164 | (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) |
165 | |
166 | int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int); |
167 | int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int); |
168 | int ip6_mrouter_init(struct socket *, int, int); |
169 | int add_m6if(struct socket *, struct mif6ctl *); |
170 | int del_m6if(struct socket *, mifi_t *); |
171 | int add_m6fc(struct socket *, struct mf6cctl *); |
172 | int del_m6fc(struct socket *, struct mf6cctl *); |
173 | struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int); |
174 | struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *, |
175 | struct in6_addr *, unsigned int); |
176 | struct rtentry *mrt6_mcast_add(struct ifnet *, struct sockaddr *, |
177 | struct sockaddr *); |
178 | void mrt6_mcast_del(struct rtentry *, unsigned int); |
179 | |
180 | /* |
181 | * Handle MRT setsockopt commands to modify the multicast routing tables. |
182 | */ |
183 | int |
184 | ip6_mrouter_set(int cmd, struct socket *so, struct mbuf *m) |
185 | { |
186 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
187 | |
188 | if (cmd != MRT6_INIT108 && so != ip6_mrouter[inp->inp_rtableid]) |
189 | return (EPERM1); |
190 | |
191 | switch (cmd) { |
192 | case MRT6_INIT108: |
193 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(int)) |
194 | return (EINVAL22); |
195 | return (ip6_mrouter_init(so, *mtod(m, int *)((int *)((m)->m_hdr.mh_data)), cmd)); |
196 | case MRT6_DONE101: |
197 | return (ip6_mrouter_done(so)); |
198 | case MRT6_ADD_MIF102: |
199 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(struct mif6ctl)) |
200 | return (EINVAL22); |
201 | return (add_m6if(so, mtod(m, struct mif6ctl *)((struct mif6ctl *)((m)->m_hdr.mh_data)))); |
202 | case MRT6_DEL_MIF103: |
203 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(mifi_t)) |
204 | return (EINVAL22); |
205 | return (del_m6if(so, mtod(m, mifi_t *)((mifi_t *)((m)->m_hdr.mh_data)))); |
206 | case MRT6_ADD_MFC104: |
207 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(struct mf6cctl)) |
208 | return (EINVAL22); |
209 | return (add_m6fc(so, mtod(m, struct mf6cctl *)((struct mf6cctl *)((m)->m_hdr.mh_data)))); |
210 | case MRT6_DEL_MFC105: |
211 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(struct mf6cctl)) |
212 | return (EINVAL22); |
213 | return (del_m6fc(so, mtod(m, struct mf6cctl *)((struct mf6cctl *)((m)->m_hdr.mh_data)))); |
214 | default: |
215 | return (EOPNOTSUPP45); |
216 | } |
217 | } |
218 | |
219 | /* |
220 | * Handle MRT getsockopt commands |
221 | */ |
222 | int |
223 | ip6_mrouter_get(int cmd, struct socket *so, struct mbuf *m) |
224 | { |
225 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
226 | |
227 | if (so != ip6_mrouter[inp->inp_rtableid]) |
228 | return (EPERM1); |
229 | |
230 | switch (cmd) { |
231 | default: |
232 | return EOPNOTSUPP45; |
233 | } |
234 | } |
235 | |
236 | /* |
237 | * Handle ioctl commands to obtain information from the cache |
238 | */ |
239 | int |
240 | mrt6_ioctl(struct socket *so, u_long cmd, caddr_t data) |
241 | { |
242 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
243 | int error; |
244 | |
245 | if (inp == NULL((void *)0)) |
246 | return (ENOTCONN57); |
247 | |
248 | KERNEL_LOCK()_kernel_lock(); |
249 | |
250 | switch (cmd) { |
251 | case SIOCGETSGCNT_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct sioc_sg_req6) & 0x1fff) << 16) | ((('u')) << 8) | ((106))): |
252 | NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0); |
253 | error = get_sg6_cnt((struct sioc_sg_req6 *)data, |
254 | inp->inp_rtableid); |
255 | NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0); |
256 | break; |
257 | case SIOCGETMIFCNT_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct sioc_mif_req6) & 0x1fff) << 16) | ((('u')) << 8) | ((107))): |
258 | NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0); |
259 | error = get_mif6_cnt((struct sioc_mif_req6 *)data, |
260 | inp->inp_rtableid); |
261 | NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0); |
262 | break; |
263 | default: |
264 | error = ENOTTY25; |
265 | break; |
266 | } |
267 | |
268 | KERNEL_UNLOCK()_kernel_unlock(); |
269 | return error; |
270 | } |
271 | |
272 | /* |
273 | * returns the packet, byte, rpf-failure count for the source group provided |
274 | */ |
275 | int |
276 | get_sg6_cnt(struct sioc_sg_req6 *req, unsigned int rtableid) |
277 | { |
278 | struct rtentry *rt; |
279 | struct mf6c *mf6c; |
280 | |
281 | rt = mf6c_find(NULL((void *)0), &req->src.sin6_addr, &req->grp.sin6_addr, |
282 | rtableid); |
283 | if (rt == NULL((void *)0)) { |
284 | req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; |
285 | return EADDRNOTAVAIL49; |
286 | } |
287 | |
288 | req->pktcnt = req->bytecnt = req->wrong_if = 0; |
289 | do { |
290 | mf6c = (struct mf6c *)rt->rt_llinfo; |
291 | if (mf6c == NULL((void *)0)) |
292 | continue; |
293 | |
294 | req->pktcnt += mf6c->mf6c_pkt_cnt; |
295 | req->bytecnt += mf6c->mf6c_byte_cnt; |
296 | req->wrong_if += mf6c->mf6c_wrong_if; |
297 | } while ((rt = rtable_iterate(rt)) != NULL((void *)0)); |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | /* |
303 | * returns the input and output packet and byte counts on the mif provided |
304 | */ |
305 | int |
306 | get_mif6_cnt(struct sioc_mif_req6 *req, unsigned int rtableid) |
307 | { |
308 | struct ifnet *ifp; |
309 | struct mif6 *m6; |
310 | |
311 | if ((ifp = mrt6_iflookupbymif(req->mifi, rtableid)) == NULL((void *)0)) |
312 | return EINVAL22; |
313 | |
314 | m6 = (struct mif6 *)ifp->if_mcast6; |
315 | req->icount = m6->m6_pkt_in; |
316 | req->ocount = m6->m6_pkt_out; |
317 | req->ibytes = m6->m6_bytes_in; |
318 | req->obytes = m6->m6_bytes_out; |
319 | |
320 | return 0; |
321 | } |
322 | |
323 | int |
324 | mrt6_sysctl_mif(void *oldp, size_t *oldlenp) |
325 | { |
326 | struct ifnet *ifp; |
327 | caddr_t where = oldp; |
328 | size_t needed, given; |
329 | struct mif6 *mifp; |
330 | struct mif6info minfo; |
331 | |
332 | given = *oldlenp; |
333 | needed = 0; |
334 | memset(&minfo, 0, sizeof minfo)__builtin_memset((&minfo), (0), (sizeof minfo)); |
335 | TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void *)0); (ifp) = ((ifp)->if_list.tqe_next)) { |
336 | if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) |
337 | continue; |
338 | |
339 | minfo.m6_mifi = mifp->m6_mifi; |
340 | minfo.m6_flags = mifp->m6_flags; |
341 | minfo.m6_lcl_addr = mifp->m6_lcl_addr; |
342 | minfo.m6_ifindex = ifp->if_index; |
343 | minfo.m6_pkt_in = mifp->m6_pkt_in; |
344 | minfo.m6_pkt_out = mifp->m6_pkt_out; |
345 | minfo.m6_bytes_in = mifp->m6_bytes_in; |
346 | minfo.m6_bytes_out = mifp->m6_bytes_out; |
347 | minfo.m6_rate_limit = mifp->m6_rate_limit; |
348 | |
349 | needed += sizeof(minfo); |
350 | if (where && needed <= given) { |
351 | int error; |
352 | |
353 | error = copyout(&minfo, where, sizeof(minfo)); |
354 | if (error) |
355 | return (error); |
356 | where += sizeof(minfo); |
357 | } |
358 | } |
359 | if (where) { |
360 | *oldlenp = needed; |
361 | if (given < needed) |
362 | return (ENOMEM12); |
363 | } else |
364 | *oldlenp = (11 * needed) / 10; |
365 | |
366 | return (0); |
367 | } |
368 | |
369 | struct mf6csysctlarg { |
370 | struct mf6cinfo *ms6a_minfos; |
371 | size_t ms6a_len; |
372 | size_t ms6a_needed; |
373 | }; |
374 | |
375 | int |
376 | mrt6_rtwalk_mf6csysctl(struct rtentry *rt, void *arg, unsigned int rtableid) |
377 | { |
378 | struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; |
379 | struct mf6csysctlarg *msa = arg; |
380 | struct ifnet *ifp; |
381 | struct mif6 *m6; |
382 | struct mf6cinfo *minfo; |
383 | int new = 0; |
384 | |
385 | /* Skip entries being removed. */ |
386 | if (mf6c == NULL((void *)0)) |
387 | return 0; |
388 | |
389 | /* Skip non-multicast routes. */ |
390 | if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) != |
391 | (RTF_HOST0x4 | RTF_MULTICAST0x200)) |
392 | return 0; |
393 | |
394 | /* User just asked for the output size. */ |
395 | if (msa->ms6a_minfos == NULL((void *)0)) { |
396 | msa->ms6a_needed += sizeof(*minfo); |
397 | return 0; |
398 | } |
399 | |
400 | /* Skip route with invalid interfaces. */ |
401 | if ((ifp = if_get(rt->rt_ifidx)) == NULL((void *)0)) |
402 | return 0; |
403 | if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) { |
404 | if_put(ifp); |
405 | return 0; |
406 | } |
407 | |
408 | for (minfo = msa->ms6a_minfos; |
409 | (uint8_t *)minfo < ((uint8_t *)msa->ms6a_minfos + msa->ms6a_len); |
410 | minfo++) { |
411 | /* Find a new entry or update old entry. */ |
412 | if (!IN6_ARE_ADDR_EQUAL(&minfo->mf6c_origin.sin6_addr,(__builtin_memcmp((&(&minfo->mf6c_origin.sin6_addr )->__u6_addr.__u6_addr8[0]), (&(&satosin6(rt->rt_gateway )->sin6_addr)->__u6_addr.__u6_addr8[0]), (sizeof(struct in6_addr))) == 0) |
413 | &satosin6(rt->rt_gateway)->sin6_addr)(__builtin_memcmp((&(&minfo->mf6c_origin.sin6_addr )->__u6_addr.__u6_addr8[0]), (&(&satosin6(rt->rt_gateway )->sin6_addr)->__u6_addr.__u6_addr8[0]), (sizeof(struct in6_addr))) == 0) || |
414 | !IN6_ARE_ADDR_EQUAL(&minfo->mf6c_mcastgrp.sin6_addr,(__builtin_memcmp((&(&minfo->mf6c_mcastgrp.sin6_addr )->__u6_addr.__u6_addr8[0]), (&(&satosin6(((rt)-> rt_dest))->sin6_addr)->__u6_addr.__u6_addr8[0]), (sizeof (struct in6_addr))) == 0) |
415 | &satosin6(rt_key(rt))->sin6_addr)(__builtin_memcmp((&(&minfo->mf6c_mcastgrp.sin6_addr )->__u6_addr.__u6_addr8[0]), (&(&satosin6(((rt)-> rt_dest))->sin6_addr)->__u6_addr.__u6_addr8[0]), (sizeof (struct in6_addr))) == 0)) { |
416 | if (!IN6_IS_ADDR_UNSPECIFIED(((*(const u_int32_t *)(const void *)(&(&minfo->mf6c_origin .sin6_addr)->__u6_addr.__u6_addr8[0]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_origin .sin6_addr)->__u6_addr.__u6_addr8[4]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_origin .sin6_addr)->__u6_addr.__u6_addr8[8]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_origin .sin6_addr)->__u6_addr.__u6_addr8[12]) == 0)) |
417 | &minfo->mf6c_origin.sin6_addr)((*(const u_int32_t *)(const void *)(&(&minfo->mf6c_origin .sin6_addr)->__u6_addr.__u6_addr8[0]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_origin .sin6_addr)->__u6_addr.__u6_addr8[4]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_origin .sin6_addr)->__u6_addr.__u6_addr8[8]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_origin .sin6_addr)->__u6_addr.__u6_addr8[12]) == 0)) || |
418 | !IN6_IS_ADDR_UNSPECIFIED(((*(const u_int32_t *)(const void *)(&(&minfo->mf6c_mcastgrp .sin6_addr)->__u6_addr.__u6_addr8[0]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_mcastgrp .sin6_addr)->__u6_addr.__u6_addr8[4]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_mcastgrp .sin6_addr)->__u6_addr.__u6_addr8[8]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_mcastgrp .sin6_addr)->__u6_addr.__u6_addr8[12]) == 0)) |
419 | &minfo->mf6c_mcastgrp.sin6_addr)((*(const u_int32_t *)(const void *)(&(&minfo->mf6c_mcastgrp .sin6_addr)->__u6_addr.__u6_addr8[0]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_mcastgrp .sin6_addr)->__u6_addr.__u6_addr8[4]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_mcastgrp .sin6_addr)->__u6_addr.__u6_addr8[8]) == 0) && (*( const u_int32_t *)(const void *)(&(&minfo->mf6c_mcastgrp .sin6_addr)->__u6_addr.__u6_addr8[12]) == 0))) |
420 | continue; |
421 | |
422 | new = 1; |
423 | } |
424 | |
425 | minfo->mf6c_origin = *satosin6(rt->rt_gateway); |
426 | minfo->mf6c_mcastgrp = *satosin6(rt_key(rt)((rt)->rt_dest)); |
427 | minfo->mf6c_parent = mf6c->mf6c_parent; |
428 | minfo->mf6c_pkt_cnt += mf6c->mf6c_pkt_cnt; |
429 | minfo->mf6c_byte_cnt += mf6c->mf6c_byte_cnt; |
430 | IF_SET(m6->m6_mifi, &minfo->mf6c_ifset)((&minfo->mf6c_ifset)->ifs_bits[(m6->m6_mifi)/(sizeof (uint32_t) * 8)] |= (1U << ((m6->m6_mifi) % (sizeof( uint32_t) * 8)))); |
431 | break; |
432 | } |
433 | |
434 | if (new != 0) |
435 | msa->ms6a_needed += sizeof(*minfo); |
436 | |
437 | if_put(ifp); |
438 | |
439 | return 0; |
440 | } |
441 | |
442 | int |
443 | mrt6_sysctl_mfc(void *oldp, size_t *oldlenp) |
444 | { |
445 | unsigned int rtableid; |
446 | int error; |
447 | struct mf6csysctlarg msa; |
448 | |
449 | if (oldp != NULL((void *)0) && *oldlenp > MAXPHYS(64 * 1024)) |
450 | return EINVAL22; |
451 | |
452 | if (oldp != NULL((void *)0)) |
453 | msa.ms6a_minfos = malloc(*oldlenp, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008); |
454 | else |
455 | msa.ms6a_minfos = NULL((void *)0); |
456 | |
457 | msa.ms6a_len = *oldlenp; |
458 | msa.ms6a_needed = 0; |
459 | |
460 | for (rtableid = 0; rtableid <= RT_TABLEID_MAX255; rtableid++) { |
461 | rtable_walk(rtableid, AF_INET624, NULL((void *)0), mrt6_rtwalk_mf6csysctl, |
462 | &msa); |
463 | } |
464 | |
465 | if (msa.ms6a_minfos != NULL((void *)0) && msa.ms6a_needed > 0 && |
466 | (error = copyout(msa.ms6a_minfos, oldp, msa.ms6a_needed)) != 0) { |
467 | free(msa.ms6a_minfos, M_TEMP127, *oldlenp); |
468 | return error; |
469 | } |
470 | |
471 | free(msa.ms6a_minfos, M_TEMP127, *oldlenp); |
472 | *oldlenp = msa.ms6a_needed; |
473 | |
474 | return 0; |
475 | } |
476 | |
477 | /* |
478 | * Enable multicast routing |
479 | */ |
480 | int |
481 | ip6_mrouter_init(struct socket *so, int v, int cmd) |
482 | { |
483 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
484 | unsigned int rtableid = inp->inp_rtableid; |
485 | |
486 | if (so->so_type != SOCK_RAW3 || |
487 | so->so_proto->pr_protocol != IPPROTO_ICMPV658) |
488 | return (EOPNOTSUPP45); |
489 | |
490 | if (v != 1) |
491 | return (ENOPROTOOPT42); |
492 | |
493 | if (ip6_mrouter[rtableid] != NULL((void *)0)) |
494 | return (EADDRINUSE48); |
495 | |
496 | ip6_mrouter[rtableid] = so; |
497 | ip6_mrouter_ver = cmd; |
498 | |
499 | return (0); |
500 | } |
501 | |
502 | int |
503 | mrouter6_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid) |
504 | { |
505 | /* Skip non-multicast routes. */ |
506 | if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) != |
507 | (RTF_HOST0x4 | RTF_MULTICAST0x200)) |
508 | return 0; |
509 | |
510 | return EEXIST17; |
511 | } |
512 | |
513 | /* |
514 | * Disable multicast routing |
515 | */ |
516 | int |
517 | ip6_mrouter_done(struct socket *so) |
518 | { |
519 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
520 | struct ifnet *ifp; |
521 | unsigned int rtableid = inp->inp_rtableid; |
522 | int error; |
523 | |
524 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
525 | |
526 | /* Delete all remaining installed multicast routes. */ |
527 | do { |
528 | struct rtentry *rt = NULL((void *)0); |
529 | |
530 | error = rtable_walk(rtableid, AF_INET624, &rt, |
531 | mrouter6_rtwalk_delete, NULL((void *)0)); |
532 | if (rt != NULL((void *)0) && error == EEXIST17) { |
533 | mrt6_mcast_del(rt, rtableid); |
534 | error = EAGAIN35; |
535 | } |
536 | rtfree(rt); |
537 | } while (error == EAGAIN35); |
538 | |
539 | /* Unregister all interfaces in the domain. */ |
540 | TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void *)0); (ifp) = ((ifp)->if_list.tqe_next)) { |
541 | if (ifp->if_rdomainif_data.ifi_rdomain != rtableid) |
542 | continue; |
543 | |
544 | ip6_mrouter_detach(ifp); |
545 | } |
546 | |
547 | ip6_mrouter[inp->inp_rtableid] = NULL((void *)0); |
548 | ip6_mrouter_ver = 0; |
549 | |
550 | return 0; |
551 | } |
552 | |
553 | void |
554 | ip6_mrouter_detach(struct ifnet *ifp) |
555 | { |
556 | struct mif6 *m6 = (struct mif6 *)ifp->if_mcast6; |
557 | struct in6_ifreq ifr; |
558 | |
559 | if (m6 == NULL((void *)0)) |
560 | return; |
561 | |
562 | ifp->if_mcast6 = NULL((void *)0); |
563 | |
564 | memset(&ifr, 0, sizeof(ifr))__builtin_memset((&ifr), (0), (sizeof(ifr))); |
565 | ifr.ifr_addrifr_ifru.ifru_addr.sin6_family = AF_INET624; |
566 | ifr.ifr_addrifr_ifru.ifru_addr.sin6_addr = in6addr_any; |
567 | KERNEL_LOCK()_kernel_lock(); |
568 | (*ifp->if_ioctl)(ifp, SIOCDELMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((50))), (caddr_t)&ifr); |
569 | KERNEL_UNLOCK()_kernel_unlock(); |
570 | |
571 | free(m6, M_MRTABLE56, sizeof(*m6)); |
572 | } |
573 | |
574 | /* |
575 | * Add a mif to the mif table |
576 | */ |
577 | int |
578 | add_m6if(struct socket *so, struct mif6ctl *mifcp) |
579 | { |
580 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
581 | struct mif6 *mifp; |
582 | struct ifnet *ifp; |
583 | struct in6_ifreq ifr; |
584 | int error; |
585 | unsigned int rtableid = inp->inp_rtableid; |
586 | |
587 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
588 | |
589 | if (mifcp->mif6c_mifi >= MAXMIFS64) |
590 | return EINVAL22; |
591 | |
592 | if (mrt6_iflookupbymif(mifcp->mif6c_mifi, rtableid) != NULL((void *)0)) |
593 | return EADDRINUSE48; /* XXX: is it appropriate? */ |
594 | |
595 | { |
596 | ifp = if_get(mifcp->mif6c_pifi); |
597 | if (ifp == NULL((void *)0)) |
598 | return ENXIO6; |
599 | |
600 | /* Make sure the interface supports multicast */ |
601 | if ((ifp->if_flags & IFF_MULTICAST0x8000) == 0) { |
602 | if_put(ifp); |
603 | return EOPNOTSUPP45; |
604 | } |
605 | |
606 | /* |
607 | * Enable promiscuous reception of all IPv6 multicasts |
608 | * from the interface. |
609 | */ |
610 | memset(&ifr, 0, sizeof(ifr))__builtin_memset((&ifr), (0), (sizeof(ifr))); |
611 | ifr.ifr_addrifr_ifru.ifru_addr.sin6_family = AF_INET624; |
612 | ifr.ifr_addrifr_ifru.ifru_addr.sin6_addr = in6addr_any; |
613 | KERNEL_LOCK()_kernel_lock(); |
614 | error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((49))), (caddr_t)&ifr); |
615 | KERNEL_UNLOCK()_kernel_unlock(); |
616 | |
617 | if (error) { |
618 | if_put(ifp); |
619 | return error; |
620 | } |
621 | } |
622 | |
623 | mifp = malloc(sizeof(*mifp), M_MRTABLE56, M_WAITOK0x0001 | M_ZERO0x0008); |
624 | ifp->if_mcast6 = (caddr_t)mifp; |
625 | mifp->m6_mifi = mifcp->mif6c_mifi; |
626 | mifp->m6_flags = mifcp->mif6c_flags; |
627 | #ifdef notyet |
628 | /* scaling up here allows division by 1024 in critical code */ |
629 | mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000; |
630 | #endif |
631 | |
632 | if_put(ifp); |
633 | |
634 | return 0; |
635 | } |
636 | |
637 | /* |
638 | * Delete a mif from the mif table |
639 | */ |
640 | int |
641 | del_m6if(struct socket *so, mifi_t *mifip) |
642 | { |
643 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
644 | struct ifnet *ifp; |
645 | |
646 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
647 | |
648 | if (*mifip >= MAXMIFS64) |
649 | return EINVAL22; |
650 | if ((ifp = mrt6_iflookupbymif(*mifip, inp->inp_rtableid)) == NULL((void *)0)) |
651 | return EINVAL22; |
652 | |
653 | ip6_mrouter_detach(ifp); |
654 | |
655 | return 0; |
656 | } |
657 | |
658 | int |
659 | mf6c_add_route(struct ifnet *ifp, struct sockaddr *origin, |
660 | struct sockaddr *group, struct mf6cctl *mf6cc, int wait) |
661 | { |
662 | struct rtentry *rt; |
663 | struct mf6c *mf6c; |
664 | unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain; |
665 | #ifdef MCAST_DEBUG |
666 | char bsrc[INET6_ADDRSTRLEN46], bdst[INET6_ADDRSTRLEN46]; |
667 | #endif /* MCAST_DEBUG */ |
668 | |
669 | rt = mrt6_mcast_add(ifp, origin, group); |
670 | if (rt == NULL((void *)0)) |
671 | return ENOENT2; |
672 | |
673 | mf6c = malloc(sizeof(*mf6c), M_MRTABLE56, wait | M_ZERO0x0008); |
674 | if (mf6c == NULL((void *)0)) { |
675 | DPRINTF("origin %s group %s parent %d (%s) malloc failed",do { } while (0) |
676 | inet_ntop(AF_INET6, origin, bsrc, sizeof(bsrc)),do { } while (0) |
677 | inet_ntop(AF_INET6, group, bdst, sizeof(bdst)),do { } while (0) |
678 | mf6cc->mf6cc_parent, ifp->if_xname)do { } while (0); |
679 | mrt6_mcast_del(rt, rtableid); |
680 | rtfree(rt); |
681 | return ENOMEM12; |
682 | } |
683 | |
684 | rt->rt_llinfo = (caddr_t)mf6c; |
685 | rt_timer_add(rt, &ip6_mrouterq, rtableid); |
686 | mf6c->mf6c_parent = mf6cc->mf6cc_parent; |
687 | rtfree(rt); |
688 | |
689 | return 0; |
690 | } |
691 | |
692 | void |
693 | mf6c_update(struct mf6cctl *mf6cc, int wait, unsigned int rtableid) |
694 | { |
695 | struct rtentry *rt; |
696 | struct mf6c *mf6c; |
697 | struct ifnet *ifp; |
698 | struct sockaddr_in6 osin6, gsin6; |
699 | mifi_t mifi; |
700 | #ifdef MCAST_DEBUG |
701 | char bdst[INET6_ADDRSTRLEN46]; |
702 | #endif /* MCAST_DEBUG */ |
703 | |
704 | memset(&osin6, 0, sizeof(osin6))__builtin_memset((&osin6), (0), (sizeof(osin6))); |
705 | osin6.sin6_family = AF_INET624; |
706 | osin6.sin6_len = sizeof(osin6); |
707 | osin6.sin6_addr = mf6cc->mf6cc_origin.sin6_addr; |
708 | |
709 | memset(&gsin6, 0, sizeof(gsin6))__builtin_memset((&gsin6), (0), (sizeof(gsin6))); |
710 | gsin6.sin6_family = AF_INET624; |
711 | gsin6.sin6_len = sizeof(gsin6); |
712 | gsin6.sin6_addr = mf6cc->mf6cc_mcastgrp.sin6_addr; |
713 | |
714 | for (mifi = 0; mifi < MAXMIFS64; mifi++) { |
715 | if (mifi == mf6cc->mf6cc_parent) |
716 | continue; |
717 | |
718 | /* Test for mif existence and then update the entry. */ |
719 | if ((ifp = mrt6_iflookupbymif(mifi, rtableid)) == NULL((void *)0)) |
720 | continue; |
721 | |
722 | rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr, |
723 | &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid); |
724 | |
725 | /* mif not configured or removed. */ |
726 | if (!IF_ISSET(mifi, &mf6cc->mf6cc_ifset)((&mf6cc->mf6cc_ifset)->ifs_bits[(mifi)/(sizeof(uint32_t ) * 8)] & (1U << ((mifi) % (sizeof(uint32_t) * 8))) )) { |
727 | /* Route doesn't exist, nothing to do. */ |
728 | if (rt == NULL((void *)0)) |
729 | continue; |
730 | |
731 | DPRINTF("del route (group %s) for mif %d (%s)",do { } while (0) |
732 | inet_ntop(AF_INET6,do { } while (0) |
733 | &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,do { } while (0) |
734 | sizeof(bdst)), mifi, ifp->if_xname)do { } while (0); |
735 | mrt6_mcast_del(rt, rtableid); |
736 | rtfree(rt); |
737 | continue; |
738 | } |
739 | |
740 | /* Route exists, look for changes. */ |
741 | if (rt != NULL((void *)0)) { |
742 | mf6c = (struct mf6c *)rt->rt_llinfo; |
743 | /* Skip route being deleted. */ |
744 | if (mf6c == NULL((void *)0)) { |
745 | rtfree(rt); |
746 | continue; |
747 | } |
748 | |
749 | /* No new changes to apply. */ |
750 | if (mf6cc->mf6cc_parent == mf6c->mf6c_parent) { |
751 | rtfree(rt); |
752 | continue; |
753 | } |
754 | |
755 | DPRINTF("update route (group %s) for mif %d (%s)",do { } while (0) |
756 | inet_ntop(AF_INET6,do { } while (0) |
757 | &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,do { } while (0) |
758 | sizeof(bdst)), mifi, ifp->if_xname)do { } while (0); |
759 | |
760 | mf6c->mf6c_parent = mf6cc->mf6cc_parent; |
761 | rtfree(rt); |
762 | continue; |
763 | } |
764 | |
765 | DPRINTF("add route (group %s) for mif %d (%s)",do { } while (0) |
766 | inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,do { } while (0) |
767 | bdst, sizeof(bdst)), mifi, ifp->if_xname)do { } while (0); |
768 | |
769 | mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6), |
770 | mf6cc, wait); |
771 | } |
772 | |
773 | /* Create route for the parent interface. */ |
774 | if ((ifp = mrt6_iflookupbymif(mf6cc->mf6cc_parent, |
775 | rtableid)) == NULL((void *)0)) { |
776 | DPRINTF("failed to find upstream interface %d",do { } while (0) |
777 | mf6cc->mf6cc_parent)do { } while (0); |
778 | return; |
779 | } |
780 | |
781 | /* We already have a route, nothing to do here. */ |
782 | if ((rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr, |
783 | &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL((void *)0)) { |
784 | rtfree(rt); |
785 | return; |
786 | } |
787 | |
788 | DPRINTF("add upstream route (group %s) for if %s",do { } while (0) |
789 | inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,do { } while (0) |
790 | bdst, sizeof(bdst)), ifp->if_xname)do { } while (0); |
791 | mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6), mf6cc, wait); |
792 | } |
793 | |
794 | int |
795 | mf6c_add(struct mf6cctl *mfccp, struct in6_addr *origin, |
796 | struct in6_addr *group, int vidx, unsigned int rtableid, int wait) |
797 | { |
798 | struct ifnet *ifp; |
799 | struct mif6 *m6; |
800 | struct mf6cctl mf6cc; |
801 | |
802 | ifp = mrt6_iflookupbymif(vidx, rtableid); |
803 | if (ifp == NULL((void *)0) || |
804 | (m6 = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) |
805 | return ENOENT2; |
806 | |
807 | memset(&mf6cc, 0, sizeof(mf6cc))__builtin_memset((&mf6cc), (0), (sizeof(mf6cc))); |
808 | if (mfccp == NULL((void *)0)) { |
809 | mf6cc.mf6cc_origin.sin6_family = AF_INET624; |
810 | mf6cc.mf6cc_origin.sin6_len = sizeof(mf6cc.mf6cc_origin); |
811 | mf6cc.mf6cc_origin.sin6_addr = *origin; |
812 | mf6cc.mf6cc_mcastgrp.sin6_family = AF_INET624; |
813 | mf6cc.mf6cc_mcastgrp.sin6_len = sizeof(mf6cc.mf6cc_mcastgrp); |
814 | mf6cc.mf6cc_mcastgrp.sin6_addr = *group; |
815 | mf6cc.mf6cc_parent = vidx; |
816 | } else |
817 | memcpy(&mf6cc, mfccp, sizeof(mf6cc))__builtin_memcpy((&mf6cc), (mfccp), (sizeof(mf6cc))); |
818 | |
819 | mf6c_update(&mf6cc, wait, rtableid); |
820 | |
821 | return 0; |
822 | } |
823 | |
824 | int |
825 | add_m6fc(struct socket *so, struct mf6cctl *mfccp) |
826 | { |
827 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
828 | unsigned int rtableid = inp->inp_rtableid; |
829 | |
830 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
831 | |
832 | return mf6c_add(mfccp, &mfccp->mf6cc_origin.sin6_addr, |
833 | &mfccp->mf6cc_mcastgrp.sin6_addr, mfccp->mf6cc_parent, |
834 | rtableid, M_WAITOK0x0001); |
835 | } |
836 | |
837 | int |
838 | del_m6fc(struct socket *so, struct mf6cctl *mfccp) |
839 | { |
840 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
841 | struct rtentry *rt; |
842 | unsigned int rtableid = inp->inp_rtableid; |
843 | |
844 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
845 | |
846 | while ((rt = mf6c_find(NULL((void *)0), &mfccp->mf6cc_origin.sin6_addr, |
847 | &mfccp->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL((void *)0)) { |
848 | mrt6_mcast_del(rt, rtableid); |
849 | rtfree(rt); |
850 | } |
851 | |
852 | return 0; |
853 | } |
854 | |
855 | int |
856 | socket6_send(struct socket *so, struct mbuf *mm, struct sockaddr_in6 *src) |
857 | { |
858 | if (so != NULL((void *)0)) { |
859 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
860 | int ret; |
861 | |
862 | mtx_enter(&inp->inp_mtx); |
863 | ret = sbappendaddr(so, &so->so_rcv, sin6tosa(src), mm, NULL((void *)0)); |
864 | mtx_leave(&inp->inp_mtx); |
865 | |
866 | if (ret != 0) { |
867 | sorwakeup(so); |
868 | return 0; |
869 | } |
870 | } |
871 | m_freem(mm); |
872 | return -1; |
873 | } |
874 | |
875 | /* |
876 | * IPv6 multicast forwarding function. This function assumes that the packet |
877 | * pointed to by "ip6" has arrived on (or is about to be sent to) the interface |
878 | * pointed to by "ifp", and the packet is to be relayed to other networks |
879 | * that have members of the packet's destination IPv6 multicast group. |
880 | * |
881 | * The packet is returned unscathed to the caller, unless it is |
882 | * erroneous, in which case a non-zero return value tells the caller to |
883 | * discard it. |
884 | */ |
885 | int |
886 | ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m) |
887 | { |
888 | struct rtentry *rt; |
889 | struct mif6 *mifp; |
890 | struct mbuf *mm; |
891 | struct sockaddr_in6 sin6; |
892 | unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain; |
893 | |
894 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
895 | |
896 | /* |
897 | * Don't forward a packet with Hop limit of zero or one, |
898 | * or a packet destined to a local-only group. |
899 | */ |
900 | if (ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)(((&ip6->ip6_dst)->__u6_addr.__u6_addr8[0] == 0xff) && (((&ip6->ip6_dst)->__u6_addr.__u6_addr8 [1] & 0x0f) == 0x01)) || |
901 | IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)(((&ip6->ip6_dst)->__u6_addr.__u6_addr8[0] == 0xff) && (((&ip6->ip6_dst)->__u6_addr.__u6_addr8 [1] & 0x0f) == 0x02))) |
902 | return 0; |
903 | ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim--; |
904 | |
905 | /* |
906 | * Source address check: do not forward packets with unspecified |
907 | * source. It was discussed in July 2000, on ipngwg mailing list. |
908 | * This is rather more serious than unicast cases, because some |
909 | * MLD packets can be sent with the unspecified source address |
910 | * (although such packets must normally set 1 to the hop limit field). |
911 | */ |
912 | if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)((*(const u_int32_t *)(const void *)(&(&ip6->ip6_src )->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t *)(const void *)(&(&ip6->ip6_src)->__u6_addr.__u6_addr8 [4]) == 0) && (*(const u_int32_t *)(const void *)(& (&ip6->ip6_src)->__u6_addr.__u6_addr8[8]) == 0) && (*(const u_int32_t *)(const void *)(&(&ip6->ip6_src )->__u6_addr.__u6_addr8[12]) == 0))) { |
913 | ip6stat_inc(ip6s_cantforward); |
914 | if (ip6_log_time + ip6_log_interval < getuptime()) { |
915 | char src[INET6_ADDRSTRLEN46], dst[INET6_ADDRSTRLEN46]; |
916 | |
917 | ip6_log_time = getuptime(); |
918 | |
919 | inet_ntop(AF_INET624, &ip6->ip6_src, src, sizeof(src)); |
920 | inet_ntop(AF_INET624, &ip6->ip6_dst, dst, sizeof(dst)); |
921 | log(LOG_DEBUG7, "cannot forward " |
922 | "from %s to %s nxt %d received on interface %u\n", |
923 | src, dst, ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt, m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx); |
924 | } |
925 | return 0; |
926 | } |
927 | |
928 | /* |
929 | * Determine forwarding mifs from the forwarding cache table |
930 | */ |
931 | rt = mf6c_find(NULL((void *)0), &ip6->ip6_src, &ip6->ip6_dst, rtableid); |
932 | |
933 | /* Entry exists, so forward if necessary */ |
934 | if (rt) { |
935 | return (ip6_mdq(m, ifp, rt)); |
936 | } else { |
937 | /* |
938 | * If we don't have a route for packet's origin, |
939 | * Make a copy of the packet & |
940 | * send message to routing daemon |
941 | */ |
942 | |
943 | mrt6stat.mrt6s_no_route++; |
944 | |
945 | { |
946 | struct mrt6msg *im; |
947 | |
948 | if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) |
949 | return EHOSTUNREACH65; |
950 | |
951 | /* |
952 | * Make a copy of the header to send to the user |
953 | * level process |
954 | */ |
955 | mm = m_copym(m, 0, sizeof(struct ip6_hdr), M_NOWAIT0x0002); |
956 | if (mm == NULL((void *)0)) |
957 | return ENOBUFS55; |
958 | |
959 | /* |
960 | * Send message to routing daemon |
961 | */ |
962 | (void)memset(&sin6, 0, sizeof(sin6))__builtin_memset((&sin6), (0), (sizeof(sin6))); |
963 | sin6.sin6_len = sizeof(sin6); |
964 | sin6.sin6_family = AF_INET624; |
965 | sin6.sin6_addr = ip6->ip6_src; |
966 | |
967 | im = NULL((void *)0); |
968 | switch (ip6_mrouter_ver) { |
969 | case MRT6_INIT108: |
970 | im = mtod(mm, struct mrt6msg *)((struct mrt6msg *)((mm)->m_hdr.mh_data)); |
971 | im->im6_msgtype = MRT6MSG_NOCACHE1; |
972 | im->im6_mbz = 0; |
973 | im->im6_mif = mifp->m6_mifi; |
974 | break; |
975 | default: |
976 | m_freem(mm); |
977 | return EINVAL22; |
978 | } |
979 | |
980 | if (socket6_send(ip6_mrouter[rtableid], mm, |
981 | &sin6) < 0) { |
982 | log(LOG_WARNING4, "ip6_mforward: ip6_mrouter " |
983 | "socket queue full\n"); |
984 | mrt6stat.mrt6s_upq_sockfull++; |
985 | return ENOBUFS55; |
986 | } |
987 | |
988 | mrt6stat.mrt6s_upcalls++; |
989 | |
990 | mf6c_add(NULL((void *)0), &ip6->ip6_src, &ip6->ip6_dst, |
991 | mifp->m6_mifi, rtableid, M_NOWAIT0x0002); |
992 | } |
993 | |
994 | return 0; |
995 | } |
996 | } |
997 | |
998 | void |
999 | mf6c_expire_route(struct rtentry *rt, u_int rtableid) |
1000 | { |
1001 | struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; |
1002 | #ifdef MCAST_DEBUG |
1003 | char bsrc[INET6_ADDRSTRLEN46], bdst[INET6_ADDRSTRLEN46]; |
1004 | #endif /* MCAST_DEBUG */ |
1005 | |
1006 | /* Skip entry being deleted. */ |
1007 | if (mf6c == NULL((void *)0)) |
1008 | return; |
1009 | |
1010 | DPRINTF("origin %s group %s interface %d expire %s",do { } while (0) |
1011 | inet_ntop(AF_INET6, &satosin6(rt->rt_gateway)->sin6_addr,do { } while (0) |
1012 | bsrc, sizeof(bsrc)),do { } while (0) |
1013 | inet_ntop(AF_INET6, &satosin6(rt_key(rt))->sin6_addr,do { } while (0) |
1014 | bdst, sizeof(bdst)), rt->rt_ifidx,do { } while (0) |
1015 | mf6c->mf6c_expire ? "yes" : "no")do { } while (0); |
1016 | |
1017 | if (mf6c->mf6c_expire == 0) { |
1018 | mf6c->mf6c_expire = 1; |
1019 | rt_timer_add(rt, &ip6_mrouterq, rtableid); |
1020 | return; |
1021 | } |
1022 | |
1023 | mrt6_mcast_del(rt, rtableid); |
1024 | } |
1025 | |
1026 | /* |
1027 | * Packet forwarding routine once entry in the cache is made |
1028 | */ |
1029 | int |
1030 | ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt) |
1031 | { |
1032 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data)); |
1033 | struct mif6 *m6, *mifp = (struct mif6 *)ifp->if_mcast6; |
1034 | struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; |
1035 | struct ifnet *ifn; |
1036 | int plen = m->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1037 | |
1038 | if (mifp == NULL((void *)0) || mf6c == NULL((void *)0)) { |
1039 | rtfree(rt); |
1040 | return EHOSTUNREACH65; |
1041 | } |
1042 | |
1043 | /* |
1044 | * Don't forward if it didn't arrive from the parent mif |
1045 | * for its origin. |
1046 | */ |
1047 | if (mifp->m6_mifi != mf6c->mf6c_parent) { |
1048 | /* came in the wrong interface */ |
1049 | mrt6stat.mrt6s_wrong_if++; |
1050 | mf6c->mf6c_wrong_if++; |
1051 | rtfree(rt); |
1052 | return 0; |
1053 | } /* if wrong iif */ |
1054 | |
1055 | /* If I sourced this packet, it counts as output, else it was input. */ |
1056 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx == 0) { |
1057 | /* XXX: is ph_ifidx really 0 when output?? */ |
1058 | mifp->m6_pkt_out++; |
1059 | mifp->m6_bytes_out += plen; |
1060 | } else { |
1061 | mifp->m6_pkt_in++; |
1062 | mifp->m6_bytes_in += plen; |
1063 | } |
1064 | |
1065 | /* |
1066 | * For each mif, forward a copy of the packet if there are group |
1067 | * members downstream on the interface. |
1068 | */ |
1069 | do { |
1070 | /* Don't consider non multicast routes. */ |
1071 | if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) != |
1072 | (RTF_HOST0x4 | RTF_MULTICAST0x200)) |
1073 | continue; |
1074 | |
1075 | mf6c = (struct mf6c *)rt->rt_llinfo; |
1076 | if (mf6c == NULL((void *)0)) |
1077 | continue; |
1078 | |
1079 | mf6c->mf6c_pkt_cnt++; |
1080 | mf6c->mf6c_byte_cnt += m->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1081 | |
1082 | /* Don't let this route expire. */ |
1083 | mf6c->mf6c_expire = 0; |
1084 | |
1085 | if ((ifn = if_get(rt->rt_ifidx)) == NULL((void *)0)) |
1086 | continue; |
1087 | |
1088 | /* Sanity check: did we configure this? */ |
1089 | if ((m6 = (struct mif6 *)ifn->if_mcast6) == NULL((void *)0)) { |
1090 | if_put(ifn); |
1091 | continue; |
1092 | } |
1093 | |
1094 | /* Don't send in the upstream interface. */ |
1095 | if (mf6c->mf6c_parent == m6->m6_mifi) { |
1096 | if_put(ifn); |
1097 | continue; |
1098 | } |
1099 | |
1100 | /* |
1101 | * check if the outgoing packet is going to break |
1102 | * a scope boundary. |
1103 | */ |
1104 | if ((mifp->m6_flags & MIFF_REGISTER0x1) == 0 && |
1105 | (m6->m6_flags & MIFF_REGISTER0x1) == 0 && |
1106 | (in6_addr2scopeid(ifp->if_index, &ip6->ip6_dst) != |
1107 | in6_addr2scopeid(ifn->if_index, &ip6->ip6_dst) || |
1108 | in6_addr2scopeid(ifp->if_index, &ip6->ip6_src) != |
1109 | in6_addr2scopeid(ifn->if_index, &ip6->ip6_src))) { |
1110 | if_put(ifn); |
1111 | ip6stat_inc(ip6s_badscope); |
1112 | continue; |
1113 | } |
1114 | |
1115 | m6->m6_pkt_out++; |
1116 | m6->m6_bytes_out += plen; |
1117 | |
1118 | phyint_send6(ifn, ip6, m); |
1119 | if_put(ifn); |
1120 | } while ((rt = rtable_iterate(rt)) != NULL((void *)0)); |
1121 | |
1122 | return 0; |
1123 | } |
1124 | |
1125 | void |
1126 | phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m) |
1127 | { |
1128 | struct mbuf *mb_copy; |
1129 | struct sockaddr_in6 *dst6, sin6; |
1130 | int error = 0; |
1131 | |
1132 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
1133 | |
1134 | /* |
1135 | * Make a new reference to the packet; make sure that |
1136 | * the IPv6 header is actually copied, not just referenced, |
1137 | * so that ip6_output() only scribbles on the copy. |
1138 | */ |
1139 | mb_copy = m_dup_pkt(m, max_linkhdr, M_NOWAIT0x0002); |
1140 | if (mb_copy == NULL((void *)0)) |
1141 | return; |
1142 | /* set MCAST flag to the outgoing packet */ |
1143 | mb_copy->m_flagsm_hdr.mh_flags |= M_MCAST0x0200; |
1144 | |
1145 | /* |
1146 | * If we sourced the packet, call ip6_output since we may divide |
1147 | * the packet into fragments when the packet is too big for the |
1148 | * outgoing interface. |
1149 | * Otherwise, we can simply send the packet to the interface |
1150 | * sending queue. |
1151 | */ |
1152 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx == 0) { |
1153 | struct ip6_moptions im6o; |
1154 | |
1155 | im6o.im6o_ifidx = ifp->if_index; |
1156 | /* XXX: ip6_output will override ip6->ip6_hlim */ |
1157 | im6o.im6o_hlim = ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim; |
1158 | im6o.im6o_loop = 1; |
1159 | error = ip6_output(mb_copy, NULL((void *)0), NULL((void *)0), IPV6_FORWARDING0x02, &im6o, |
1160 | NULL((void *)0)); |
1161 | return; |
1162 | } |
1163 | |
1164 | /* |
1165 | * If we belong to the destination multicast group |
1166 | * on the outgoing interface, loop back a copy. |
1167 | */ |
1168 | dst6 = &sin6; |
1169 | memset(&sin6, 0, sizeof(sin6))__builtin_memset((&sin6), (0), (sizeof(sin6))); |
1170 | if (in6_hasmulti(&ip6->ip6_dst, ifp)) { |
1171 | dst6->sin6_len = sizeof(struct sockaddr_in6); |
1172 | dst6->sin6_family = AF_INET624; |
1173 | dst6->sin6_addr = ip6->ip6_dst; |
1174 | ip6_mloopback(ifp, m, dst6); |
1175 | } |
1176 | /* |
1177 | * Put the packet into the sending queue of the outgoing interface |
1178 | * if it would fit in the MTU of the interface. |
1179 | */ |
1180 | if (mb_copy->m_pkthdrM_dat.MH.MH_pkthdr.len <= ifp->if_mtuif_data.ifi_mtu || ifp->if_mtuif_data.ifi_mtu < IPV6_MMTU1280) { |
1181 | dst6->sin6_len = sizeof(struct sockaddr_in6); |
1182 | dst6->sin6_family = AF_INET624; |
1183 | dst6->sin6_addr = ip6->ip6_dst; |
1184 | error = ifp->if_output(ifp, mb_copy, sin6tosa(dst6), NULL((void *)0)); |
Value stored to 'error' is never read | |
1185 | } else { |
1186 | if (ip6_mcast_pmtu) |
1187 | icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG2, 0, |
1188 | ifp->if_mtuif_data.ifi_mtu); |
1189 | else { |
1190 | m_freem(mb_copy); /* simply discard the packet */ |
1191 | } |
1192 | } |
1193 | } |
1194 | |
1195 | struct ifnet * |
1196 | mrt6_iflookupbymif(mifi_t mifi, unsigned int rtableid) |
1197 | { |
1198 | struct mif6 *m6; |
1199 | struct ifnet *ifp; |
1200 | |
1201 | TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void *)0); (ifp) = ((ifp)->if_list.tqe_next)) { |
1202 | if (ifp->if_rdomainif_data.ifi_rdomain != rtableid) |
1203 | continue; |
1204 | if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) |
1205 | continue; |
1206 | if (m6->m6_mifi != mifi) |
1207 | continue; |
1208 | |
1209 | return ifp; |
1210 | } |
1211 | |
1212 | return NULL((void *)0); |
1213 | } |
1214 | |
1215 | struct rtentry * |
1216 | mf6c_find(struct ifnet *ifp, struct in6_addr *origin, struct in6_addr *group, |
1217 | unsigned int rtableid) |
1218 | { |
1219 | struct rtentry *rt; |
1220 | struct sockaddr_in6 msin6; |
1221 | |
1222 | memset(&msin6, 0, sizeof(msin6))__builtin_memset((&msin6), (0), (sizeof(msin6))); |
1223 | msin6.sin6_family = AF_INET624; |
1224 | msin6.sin6_len = sizeof(msin6); |
1225 | msin6.sin6_addr = *group; |
1226 | |
1227 | rt = rtalloc(sin6tosa(&msin6), 0, rtableid); |
1228 | do { |
1229 | if (!rtisvalid(rt)) { |
1230 | rtfree(rt); |
1231 | return NULL((void *)0); |
1232 | } |
1233 | if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) != |
1234 | (RTF_HOST0x4 | RTF_MULTICAST0x200)) |
1235 | continue; |
1236 | /* Return first occurrence if interface is not specified. */ |
1237 | if (ifp == NULL((void *)0)) |
1238 | return rt; |
1239 | if (rt->rt_ifidx == ifp->if_index) |
1240 | return rt; |
1241 | } while ((rt = rtable_iterate(rt)) != NULL((void *)0)); |
1242 | |
1243 | return NULL((void *)0); |
1244 | } |
1245 | |
1246 | struct rtentry * |
1247 | mrt6_mcast_add(struct ifnet *ifp, struct sockaddr *origin, |
1248 | struct sockaddr *group) |
1249 | { |
1250 | struct ifaddr *ifa; |
1251 | int rv; |
1252 | unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain; |
1253 | |
1254 | TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)for((ifa) = ((&ifp->if_addrlist)->tqh_first); (ifa) != ((void *)0); (ifa) = ((ifa)->ifa_list.tqe_next)) { |
1255 | if (ifa->ifa_addr->sa_family == AF_INET624) |
1256 | break; |
1257 | } |
1258 | if (ifa == NULL((void *)0)) { |
1259 | DPRINTF("ifa == NULL")do { } while (0); |
1260 | return NULL((void *)0); |
1261 | } |
1262 | |
1263 | rv = rt_ifa_add(ifa, RTF_HOST0x4 | RTF_MULTICAST0x200 | RTF_MPATH0x40000, group, |
1264 | ifp->if_rdomainif_data.ifi_rdomain); |
1265 | if (rv != 0) { |
1266 | DPRINTF("rt_ifa_add failed %d", rv)do { } while (0); |
1267 | return NULL((void *)0); |
1268 | } |
1269 | |
1270 | return mf6c_find(ifp, NULL((void *)0), &satosin6(group)->sin6_addr, rtableid); |
1271 | } |
1272 | |
1273 | void |
1274 | mrt6_mcast_del(struct rtentry *rt, unsigned int rtableid) |
1275 | { |
1276 | struct ifnet *ifp; |
1277 | int error; |
1278 | |
1279 | /* Remove all timers related to this route. */ |
1280 | rt_timer_remove_all(rt); |
1281 | |
1282 | free(rt->rt_llinfo, M_MRTABLE56, sizeof(struct mf6c)); |
1283 | rt->rt_llinfo = NULL((void *)0); |
1284 | |
1285 | ifp = if_get(rt->rt_ifidx); |
1286 | if (ifp == NULL((void *)0)) |
1287 | return; |
1288 | error = rtdeletemsg(rt, ifp, rtableid); |
1289 | if_put(ifp); |
1290 | |
1291 | if (error) |
1292 | DPRINTF("delete route error %d\n", error)do { } while (0); |
1293 | } |