File: | netinet6/ip6_mroute.c |
Warning: | line 1154, column 3 Value stored to 'error' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ip6_mroute.c,v 1.127 2021/12/15 17:21:08 deraadt 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 *mrouter6q[RT_TABLEID_MAX255 + 1]; |
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 | #define MCAST_EXPIRE_TIMEOUT30 30 /* seconds */ |
142 | |
143 | /* |
144 | * Macros to compute elapsed time efficiently |
145 | * Borrowed from Van Jacobson's scheduling code |
146 | */ |
147 | #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 { \ |
148 | int xxs; \ |
149 | \ |
150 | delta = (a).tv_usec - (b).tv_usec; \ |
151 | if ((xxs = (a).tv_sec - (b).tv_sec)) { \ |
152 | switch (xxs) { \ |
153 | case 2: \ |
154 | delta += 1000000; \ |
155 | /* FALLTHROUGH */ \ |
156 | case 1: \ |
157 | delta += 1000000; \ |
158 | break; \ |
159 | default: \ |
160 | delta += (1000000 * xxs); \ |
161 | } \ |
162 | } \ |
163 | } while (0) |
164 | |
165 | #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 && \ |
166 | (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) |
167 | |
168 | int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int); |
169 | int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int); |
170 | int ip6_mrouter_init(struct socket *, int, int); |
171 | int add_m6if(struct socket *, struct mif6ctl *); |
172 | int del_m6if(struct socket *, mifi_t *); |
173 | int add_m6fc(struct socket *, struct mf6cctl *); |
174 | int del_m6fc(struct socket *, struct mf6cctl *); |
175 | struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int); |
176 | struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *, |
177 | struct in6_addr *, unsigned int); |
178 | struct rtentry *mrt6_mcast_add(struct ifnet *, struct sockaddr *, |
179 | struct sockaddr *); |
180 | void mrt6_mcast_del(struct rtentry *, unsigned int); |
181 | void mf6c_expire_route(struct rtentry *, struct rttimer *); |
182 | |
183 | /* |
184 | * Handle MRT setsockopt commands to modify the multicast routing tables. |
185 | */ |
186 | int |
187 | ip6_mrouter_set(int cmd, struct socket *so, struct mbuf *m) |
188 | { |
189 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
190 | |
191 | if (cmd != MRT6_INIT108 && so != ip6_mrouter[inp->inp_rtableid]) |
192 | return (EPERM1); |
193 | |
194 | switch (cmd) { |
195 | case MRT6_INIT108: |
196 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(int)) |
197 | return (EINVAL22); |
198 | return (ip6_mrouter_init(so, *mtod(m, int *)((int *)((m)->m_hdr.mh_data)), cmd)); |
199 | case MRT6_DONE101: |
200 | return (ip6_mrouter_done(so)); |
201 | case MRT6_ADD_MIF102: |
202 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(struct mif6ctl)) |
203 | return (EINVAL22); |
204 | return (add_m6if(so, mtod(m, struct mif6ctl *)((struct mif6ctl *)((m)->m_hdr.mh_data)))); |
205 | case MRT6_DEL_MIF103: |
206 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(mifi_t)) |
207 | return (EINVAL22); |
208 | return (del_m6if(so, mtod(m, mifi_t *)((mifi_t *)((m)->m_hdr.mh_data)))); |
209 | case MRT6_ADD_MFC104: |
210 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(struct mf6cctl)) |
211 | return (EINVAL22); |
212 | return (add_m6fc(so, mtod(m, struct mf6cctl *)((struct mf6cctl *)((m)->m_hdr.mh_data)))); |
213 | case MRT6_DEL_MFC105: |
214 | if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(struct mf6cctl)) |
215 | return (EINVAL22); |
216 | return (del_m6fc(so, mtod(m, struct mf6cctl *)((struct mf6cctl *)((m)->m_hdr.mh_data)))); |
217 | default: |
218 | return (EOPNOTSUPP45); |
219 | } |
220 | } |
221 | |
222 | /* |
223 | * Handle MRT getsockopt commands |
224 | */ |
225 | int |
226 | ip6_mrouter_get(int cmd, struct socket *so, struct mbuf *m) |
227 | { |
228 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
229 | |
230 | if (so != ip6_mrouter[inp->inp_rtableid]) |
231 | return (EPERM1); |
232 | |
233 | switch (cmd) { |
234 | default: |
235 | return EOPNOTSUPP45; |
236 | } |
237 | } |
238 | |
239 | /* |
240 | * Handle ioctl commands to obtain information from the cache |
241 | */ |
242 | int |
243 | mrt6_ioctl(struct socket *so, u_long cmd, caddr_t data) |
244 | { |
245 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
246 | int error; |
247 | |
248 | if (inp == NULL((void *)0)) |
249 | return (ENOTCONN57); |
250 | |
251 | switch (cmd) { |
252 | case SIOCGETSGCNT_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct sioc_sg_req6) & 0x1fff) << 16) | ((('u')) << 8) | ((106))): |
253 | NET_RLOCK_IN_IOCTL()do { rw_enter_read(&netlock); } while (0); |
254 | error = get_sg6_cnt((struct sioc_sg_req6 *)data, |
255 | inp->inp_rtableid); |
256 | NET_RUNLOCK_IN_IOCTL()do { rw_exit_read(&netlock); } while (0); |
257 | break; |
258 | case SIOCGETMIFCNT_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct sioc_mif_req6) & 0x1fff) << 16) | ((('u')) << 8) | ((107))): |
259 | NET_RLOCK_IN_IOCTL()do { rw_enter_read(&netlock); } while (0); |
260 | error = get_mif6_cnt((struct sioc_mif_req6 *)data, |
261 | inp->inp_rtableid); |
262 | NET_RUNLOCK_IN_IOCTL()do { rw_exit_read(&netlock); } while (0); |
263 | break; |
264 | default: |
265 | error = ENOTTY25; |
266 | break; |
267 | } |
268 | return error; |
269 | } |
270 | |
271 | /* |
272 | * returns the packet, byte, rpf-failure count for the source group provided |
273 | */ |
274 | int |
275 | get_sg6_cnt(struct sioc_sg_req6 *req, unsigned int rtableid) |
276 | { |
277 | struct rtentry *rt; |
278 | struct mf6c *mf6c; |
279 | |
280 | rt = mf6c_find(NULL((void *)0), &req->src.sin6_addr, &req->grp.sin6_addr, |
281 | rtableid); |
282 | if (rt == NULL((void *)0)) { |
283 | req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; |
284 | return EADDRNOTAVAIL49; |
285 | } |
286 | |
287 | req->pktcnt = req->bytecnt = req->wrong_if = 0; |
288 | do { |
289 | mf6c = (struct mf6c *)rt->rt_llinfo; |
290 | if (mf6c == NULL((void *)0)) |
291 | continue; |
292 | |
293 | req->pktcnt += mf6c->mf6c_pkt_cnt; |
294 | req->bytecnt += mf6c->mf6c_byte_cnt; |
295 | req->wrong_if += mf6c->mf6c_wrong_if; |
296 | } while ((rt = rtable_iterate(rt)) != NULL((void *)0)); |
297 | |
298 | return 0; |
299 | } |
300 | |
301 | /* |
302 | * returns the input and output packet and byte counts on the mif provided |
303 | */ |
304 | int |
305 | get_mif6_cnt(struct sioc_mif_req6 *req, unsigned int rtableid) |
306 | { |
307 | struct ifnet *ifp; |
308 | struct mif6 *m6; |
309 | |
310 | if ((ifp = mrt6_iflookupbymif(req->mifi, rtableid)) == NULL((void *)0)) |
311 | return EINVAL22; |
312 | |
313 | m6 = (struct mif6 *)ifp->if_mcast6; |
314 | req->icount = m6->m6_pkt_in; |
315 | req->ocount = m6->m6_pkt_out; |
316 | req->ibytes = m6->m6_bytes_in; |
317 | req->obytes = m6->m6_bytes_out; |
318 | |
319 | return 0; |
320 | } |
321 | |
322 | int |
323 | mrt6_sysctl_mif(void *oldp, size_t *oldlenp) |
324 | { |
325 | struct ifnet *ifp; |
326 | caddr_t where = oldp; |
327 | size_t needed, given; |
328 | struct mif6 *mifp; |
329 | struct mif6info minfo; |
330 | |
331 | given = *oldlenp; |
332 | needed = 0; |
333 | memset(&minfo, 0, sizeof minfo)__builtin_memset((&minfo), (0), (sizeof minfo)); |
334 | TAILQ_FOREACH(ifp, &ifnet, if_list)for((ifp) = ((&ifnet)->tqh_first); (ifp) != ((void *)0 ); (ifp) = ((ifp)->if_list.tqe_next)) { |
335 | if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) |
336 | continue; |
337 | |
338 | minfo.m6_mifi = mifp->m6_mifi; |
339 | minfo.m6_flags = mifp->m6_flags; |
340 | minfo.m6_lcl_addr = mifp->m6_lcl_addr; |
341 | minfo.m6_ifindex = ifp->if_index; |
342 | minfo.m6_pkt_in = mifp->m6_pkt_in; |
343 | minfo.m6_pkt_out = mifp->m6_pkt_out; |
344 | minfo.m6_bytes_in = mifp->m6_bytes_in; |
345 | minfo.m6_bytes_out = mifp->m6_bytes_out; |
346 | minfo.m6_rate_limit = mifp->m6_rate_limit; |
347 | |
348 | needed += sizeof(minfo); |
349 | if (where && needed <= given) { |
350 | int error; |
351 | |
352 | error = copyout(&minfo, where, sizeof(minfo)); |
353 | if (error) |
354 | return (error); |
355 | where += sizeof(minfo); |
356 | } |
357 | } |
358 | if (where) { |
359 | *oldlenp = needed; |
360 | if (given < needed) |
361 | return (ENOMEM12); |
362 | } else |
363 | *oldlenp = (11 * needed) / 10; |
364 | |
365 | return (0); |
366 | } |
367 | |
368 | struct mf6csysctlarg { |
369 | struct mf6cinfo *ms6a_minfos; |
370 | size_t ms6a_len; |
371 | size_t ms6a_needed; |
372 | }; |
373 | |
374 | int |
375 | mrt6_rtwalk_mf6csysctl(struct rtentry *rt, void *arg, unsigned int rtableid) |
376 | { |
377 | struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; |
378 | struct mf6csysctlarg *msa = arg; |
379 | struct ifnet *ifp; |
380 | struct mif6 *m6; |
381 | struct mf6cinfo *minfo; |
382 | int new = 0; |
383 | |
384 | /* Skip entries being removed. */ |
385 | if (mf6c == NULL((void *)0)) |
386 | return 0; |
387 | |
388 | /* Skip non-multicast routes. */ |
389 | if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) != |
390 | (RTF_HOST0x4 | RTF_MULTICAST0x200)) |
391 | return 0; |
392 | |
393 | /* User just asked for the output size. */ |
394 | if (msa->ms6a_minfos == NULL((void *)0)) { |
395 | msa->ms6a_needed += sizeof(*minfo); |
396 | return 0; |
397 | } |
398 | |
399 | /* Skip route with invalid interfaces. */ |
400 | if ((ifp = if_get(rt->rt_ifidx)) == NULL((void *)0)) |
401 | return 0; |
402 | if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) { |
403 | if_put(ifp); |
404 | return 0; |
405 | } |
406 | |
407 | for (minfo = msa->ms6a_minfos; |
408 | (uint8_t *)minfo < ((uint8_t *)msa->ms6a_minfos + msa->ms6a_len); |
409 | minfo++) { |
410 | /* Find a new entry or update old entry. */ |
411 | 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) |
412 | &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) || |
413 | !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) |
414 | &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)) { |
415 | 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)) |
416 | &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)) || |
417 | !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)) |
418 | &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))) |
419 | continue; |
420 | |
421 | new = 1; |
422 | } |
423 | |
424 | minfo->mf6c_origin = *satosin6(rt->rt_gateway); |
425 | minfo->mf6c_mcastgrp = *satosin6(rt_key(rt)((rt)->rt_dest)); |
426 | minfo->mf6c_parent = mf6c->mf6c_parent; |
427 | minfo->mf6c_pkt_cnt += mf6c->mf6c_pkt_cnt; |
428 | minfo->mf6c_byte_cnt += mf6c->mf6c_byte_cnt; |
429 | 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)))); |
430 | break; |
431 | } |
432 | |
433 | if (new != 0) |
434 | msa->ms6a_needed += sizeof(*minfo); |
435 | |
436 | if_put(ifp); |
437 | |
438 | return 0; |
439 | } |
440 | |
441 | int |
442 | mrt6_sysctl_mfc(void *oldp, size_t *oldlenp) |
443 | { |
444 | unsigned int rtableid; |
445 | int error; |
446 | struct mf6csysctlarg msa; |
447 | |
448 | if (oldp != NULL((void *)0) && *oldlenp > MAXPHYS(64 * 1024)) |
449 | return EINVAL22; |
450 | |
451 | if (oldp != NULL((void *)0)) |
452 | msa.ms6a_minfos = malloc(*oldlenp, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008); |
453 | else |
454 | msa.ms6a_minfos = NULL((void *)0); |
455 | |
456 | msa.ms6a_len = *oldlenp; |
457 | msa.ms6a_needed = 0; |
458 | |
459 | for (rtableid = 0; rtableid <= RT_TABLEID_MAX255; rtableid++) { |
460 | rtable_walk(rtableid, AF_INET624, NULL((void *)0), mrt6_rtwalk_mf6csysctl, |
461 | &msa); |
462 | } |
463 | |
464 | if (msa.ms6a_minfos != NULL((void *)0) && msa.ms6a_needed > 0 && |
465 | (error = copyout(msa.ms6a_minfos, oldp, msa.ms6a_needed)) != 0) { |
466 | free(msa.ms6a_minfos, M_TEMP127, *oldlenp); |
467 | return error; |
468 | } |
469 | |
470 | free(msa.ms6a_minfos, M_TEMP127, *oldlenp); |
471 | *oldlenp = msa.ms6a_needed; |
472 | |
473 | return 0; |
474 | } |
475 | |
476 | /* |
477 | * Enable multicast routing |
478 | */ |
479 | int |
480 | ip6_mrouter_init(struct socket *so, int v, int cmd) |
481 | { |
482 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
483 | unsigned int rtableid = inp->inp_rtableid; |
484 | |
485 | if (so->so_type != SOCK_RAW3 || |
486 | so->so_proto->pr_protocol != IPPROTO_ICMPV658) |
487 | return (EOPNOTSUPP45); |
488 | |
489 | if (v != 1) |
490 | return (ENOPROTOOPT42); |
491 | |
492 | if (ip6_mrouter[rtableid] != NULL((void *)0)) |
493 | return (EADDRINUSE48); |
494 | |
495 | ip6_mrouter[rtableid] = so; |
496 | ip6_mrouter_ver = cmd; |
497 | mrouter6q[rtableid] = rt_timer_queue_create(MCAST_EXPIRE_TIMEOUT30); |
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, &ifnet, if_list)for((ifp) = ((&ifnet)->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 | rt_timer_queue_destroy(mrouter6q[rtableid]); |
548 | ip6_mrouter[inp->inp_rtableid] = NULL((void *)0); |
549 | ip6_mrouter_ver = 0; |
550 | mrouter6q[rtableid] = NULL((void *)0); |
551 | |
552 | return 0; |
553 | } |
554 | |
555 | void |
556 | ip6_mrouter_detach(struct ifnet *ifp) |
557 | { |
558 | struct mif6 *m6 = (struct mif6 *)ifp->if_mcast6; |
559 | struct in6_ifreq ifr; |
560 | |
561 | if (m6 == NULL((void *)0)) |
562 | return; |
563 | |
564 | ifp->if_mcast6 = NULL((void *)0); |
565 | |
566 | memset(&ifr, 0, sizeof(ifr))__builtin_memset((&ifr), (0), (sizeof(ifr))); |
567 | ifr.ifr_addrifr_ifru.ifru_addr.sin6_family = AF_INET624; |
568 | ifr.ifr_addrifr_ifru.ifru_addr.sin6_addr = in6addr_any; |
569 | KERNEL_LOCK()_kernel_lock(); |
570 | (*ifp->if_ioctl)(ifp, SIOCDELMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((50))), (caddr_t)&ifr); |
571 | KERNEL_UNLOCK()_kernel_unlock(); |
572 | |
573 | free(m6, M_MRTABLE56, sizeof(*m6)); |
574 | } |
575 | |
576 | /* |
577 | * Add a mif to the mif table |
578 | */ |
579 | int |
580 | add_m6if(struct socket *so, struct mif6ctl *mifcp) |
581 | { |
582 | struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb); |
583 | struct mif6 *mifp; |
584 | struct ifnet *ifp; |
585 | struct in6_ifreq ifr; |
586 | int error; |
587 | unsigned int rtableid = inp->inp_rtableid; |
588 | |
589 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
590 | |
591 | if (mifcp->mif6c_mifi >= MAXMIFS64) |
592 | return EINVAL22; |
593 | |
594 | if (mrt6_iflookupbymif(mifcp->mif6c_mifi, rtableid) != NULL((void *)0)) |
595 | return EADDRINUSE48; /* XXX: is it appropriate? */ |
596 | |
597 | { |
598 | ifp = if_get(mifcp->mif6c_pifi); |
599 | if (ifp == NULL((void *)0)) |
600 | return ENXIO6; |
601 | |
602 | /* Make sure the interface supports multicast */ |
603 | if ((ifp->if_flags & IFF_MULTICAST0x8000) == 0) { |
604 | if_put(ifp); |
605 | return EOPNOTSUPP45; |
606 | } |
607 | |
608 | /* |
609 | * Enable promiscuous reception of all IPv6 multicasts |
610 | * from the interface. |
611 | */ |
612 | memset(&ifr, 0, sizeof(ifr))__builtin_memset((&ifr), (0), (sizeof(ifr))); |
613 | ifr.ifr_addrifr_ifru.ifru_addr.sin6_family = AF_INET624; |
614 | ifr.ifr_addrifr_ifru.ifru_addr.sin6_addr = in6addr_any; |
615 | error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((49))), (caddr_t)&ifr); |
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, mf6c_expire_route, mrouter6q[rtableid], 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 *s, struct mbuf *mm, struct sockaddr_in6 *src) |
857 | { |
858 | if (s) { |
859 | if (sbappendaddr(s, &s->so_rcv, sin6tosa(src), mm, NULL((void *)0)) != 0) { |
860 | sorwakeup(s); |
861 | return 0; |
862 | } |
863 | } |
864 | m_freem(mm); |
865 | return -1; |
866 | } |
867 | |
868 | /* |
869 | * IPv6 multicast forwarding function. This function assumes that the packet |
870 | * pointed to by "ip6" has arrived on (or is about to be sent to) the interface |
871 | * pointed to by "ifp", and the packet is to be relayed to other networks |
872 | * that have members of the packet's destination IPv6 multicast group. |
873 | * |
874 | * The packet is returned unscathed to the caller, unless it is |
875 | * erroneous, in which case a non-zero return value tells the caller to |
876 | * discard it. |
877 | */ |
878 | int |
879 | ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m) |
880 | { |
881 | struct rtentry *rt; |
882 | struct mif6 *mifp; |
883 | struct mbuf *mm; |
884 | struct sockaddr_in6 sin6; |
885 | unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain; |
886 | |
887 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
888 | |
889 | /* |
890 | * Don't forward a packet with Hop limit of zero or one, |
891 | * or a packet destined to a local-only group. |
892 | */ |
893 | 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)) || |
894 | 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))) |
895 | return 0; |
896 | ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim--; |
897 | |
898 | /* |
899 | * Source address check: do not forward packets with unspecified |
900 | * source. It was discussed in July 2000, on ipngwg mailing list. |
901 | * This is rather more serious than unicast cases, because some |
902 | * MLD packets can be sent with the unspecified source address |
903 | * (although such packets must normally set 1 to the hop limit field). |
904 | */ |
905 | 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))) { |
906 | ip6stat_inc(ip6s_cantforward); |
907 | if (ip6_log_time + ip6_log_interval < getuptime()) { |
908 | char src[INET6_ADDRSTRLEN46], dst[INET6_ADDRSTRLEN46]; |
909 | |
910 | ip6_log_time = getuptime(); |
911 | |
912 | inet_ntop(AF_INET624, &ip6->ip6_src, src, sizeof(src)); |
913 | inet_ntop(AF_INET624, &ip6->ip6_dst, dst, sizeof(dst)); |
914 | log(LOG_DEBUG7, "cannot forward " |
915 | "from %s to %s nxt %d received on interface %u\n", |
916 | src, dst, ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt, m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx); |
917 | } |
918 | return 0; |
919 | } |
920 | |
921 | /* |
922 | * Determine forwarding mifs from the forwarding cache table |
923 | */ |
924 | rt = mf6c_find(NULL((void *)0), &ip6->ip6_src, &ip6->ip6_dst, rtableid); |
925 | |
926 | /* Entry exists, so forward if necessary */ |
927 | if (rt) { |
928 | return (ip6_mdq(m, ifp, rt)); |
929 | } else { |
930 | /* |
931 | * If we don't have a route for packet's origin, |
932 | * Make a copy of the packet & |
933 | * send message to routing daemon |
934 | */ |
935 | |
936 | mrt6stat.mrt6s_no_route++; |
937 | |
938 | { |
939 | struct mrt6msg *im; |
940 | |
941 | if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) |
942 | return EHOSTUNREACH65; |
943 | |
944 | /* |
945 | * Make a copy of the header to send to the user |
946 | * level process |
947 | */ |
948 | mm = m_copym(m, 0, sizeof(struct ip6_hdr), M_NOWAIT0x0002); |
949 | if (mm == NULL((void *)0)) |
950 | return ENOBUFS55; |
951 | |
952 | /* |
953 | * Send message to routing daemon |
954 | */ |
955 | (void)memset(&sin6, 0, sizeof(sin6))__builtin_memset((&sin6), (0), (sizeof(sin6))); |
956 | sin6.sin6_len = sizeof(sin6); |
957 | sin6.sin6_family = AF_INET624; |
958 | sin6.sin6_addr = ip6->ip6_src; |
959 | |
960 | im = NULL((void *)0); |
961 | switch (ip6_mrouter_ver) { |
962 | case MRT6_INIT108: |
963 | im = mtod(mm, struct mrt6msg *)((struct mrt6msg *)((mm)->m_hdr.mh_data)); |
964 | im->im6_msgtype = MRT6MSG_NOCACHE1; |
965 | im->im6_mbz = 0; |
966 | im->im6_mif = mifp->m6_mifi; |
967 | break; |
968 | default: |
969 | m_freem(mm); |
970 | return EINVAL22; |
971 | } |
972 | |
973 | if (socket6_send(ip6_mrouter[rtableid], mm, |
974 | &sin6) < 0) { |
975 | log(LOG_WARNING4, "ip6_mforward: ip6_mrouter " |
976 | "socket queue full\n"); |
977 | mrt6stat.mrt6s_upq_sockfull++; |
978 | return ENOBUFS55; |
979 | } |
980 | |
981 | mrt6stat.mrt6s_upcalls++; |
982 | |
983 | mf6c_add(NULL((void *)0), &ip6->ip6_src, &ip6->ip6_dst, |
984 | mifp->m6_mifi, rtableid, M_NOWAIT0x0002); |
985 | } |
986 | |
987 | return 0; |
988 | } |
989 | } |
990 | |
991 | void |
992 | mf6c_expire_route(struct rtentry *rt, struct rttimer *rtt) |
993 | { |
994 | struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; |
995 | unsigned int rtableid = rtt->rtt_tableid; |
996 | #ifdef MCAST_DEBUG |
997 | char bsrc[INET6_ADDRSTRLEN46], bdst[INET6_ADDRSTRLEN46]; |
998 | #endif /* MCAST_DEBUG */ |
999 | |
1000 | /* Skip entry being deleted. */ |
1001 | if (mf6c == NULL((void *)0)) |
1002 | return; |
1003 | |
1004 | DPRINTF("origin %s group %s interface %d expire %s",do { } while (0) |
1005 | inet_ntop(AF_INET6, &satosin6(rt->rt_gateway)->sin6_addr,do { } while (0) |
1006 | bsrc, sizeof(bsrc)),do { } while (0) |
1007 | inet_ntop(AF_INET6, &satosin6(rt_key(rt))->sin6_addr,do { } while (0) |
1008 | bdst, sizeof(bdst)), rt->rt_ifidx,do { } while (0) |
1009 | mf6c->mf6c_expire ? "yes" : "no")do { } while (0); |
1010 | |
1011 | if (mf6c->mf6c_expire == 0) { |
1012 | mf6c->mf6c_expire = 1; |
1013 | rt_timer_add(rt, mf6c_expire_route, mrouter6q[rtableid], |
1014 | rtableid); |
1015 | return; |
1016 | } |
1017 | |
1018 | mrt6_mcast_del(rt, rtableid); |
1019 | } |
1020 | |
1021 | /* |
1022 | * Packet forwarding routine once entry in the cache is made |
1023 | */ |
1024 | int |
1025 | ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt) |
1026 | { |
1027 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data)); |
1028 | struct mif6 *m6, *mifp = (struct mif6 *)ifp->if_mcast6; |
1029 | struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; |
1030 | struct ifnet *ifn; |
1031 | int plen = m->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1032 | |
1033 | if (mifp == NULL((void *)0) || mf6c == NULL((void *)0)) { |
1034 | rtfree(rt); |
1035 | return EHOSTUNREACH65; |
1036 | } |
1037 | |
1038 | /* |
1039 | * Don't forward if it didn't arrive from the parent mif |
1040 | * for its origin. |
1041 | */ |
1042 | if (mifp->m6_mifi != mf6c->mf6c_parent) { |
1043 | /* came in the wrong interface */ |
1044 | mrt6stat.mrt6s_wrong_if++; |
1045 | mf6c->mf6c_wrong_if++; |
1046 | rtfree(rt); |
1047 | return 0; |
1048 | } /* if wrong iif */ |
1049 | |
1050 | /* If I sourced this packet, it counts as output, else it was input. */ |
1051 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx == 0) { |
1052 | /* XXX: is ph_ifidx really 0 when output?? */ |
1053 | mifp->m6_pkt_out++; |
1054 | mifp->m6_bytes_out += plen; |
1055 | } else { |
1056 | mifp->m6_pkt_in++; |
1057 | mifp->m6_bytes_in += plen; |
1058 | } |
1059 | |
1060 | /* |
1061 | * For each mif, forward a copy of the packet if there are group |
1062 | * members downstream on the interface. |
1063 | */ |
1064 | do { |
1065 | /* Don't consider non multicast routes. */ |
1066 | if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) != |
1067 | (RTF_HOST0x4 | RTF_MULTICAST0x200)) |
1068 | continue; |
1069 | |
1070 | mf6c = (struct mf6c *)rt->rt_llinfo; |
1071 | if (mf6c == NULL((void *)0)) |
1072 | continue; |
1073 | |
1074 | mf6c->mf6c_pkt_cnt++; |
1075 | mf6c->mf6c_byte_cnt += m->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1076 | |
1077 | /* Don't let this route expire. */ |
1078 | mf6c->mf6c_expire = 0; |
1079 | |
1080 | if ((ifn = if_get(rt->rt_ifidx)) == NULL((void *)0)) |
1081 | continue; |
1082 | |
1083 | /* Sanity check: did we configure this? */ |
1084 | if ((m6 = (struct mif6 *)ifn->if_mcast6) == NULL((void *)0)) { |
1085 | if_put(ifn); |
1086 | continue; |
1087 | } |
1088 | |
1089 | /* Don't send in the upstream interface. */ |
1090 | if (mf6c->mf6c_parent == m6->m6_mifi) { |
1091 | if_put(ifn); |
1092 | continue; |
1093 | } |
1094 | |
1095 | /* |
1096 | * check if the outgoing packet is going to break |
1097 | * a scope boundary. |
1098 | */ |
1099 | if ((mifp->m6_flags & MIFF_REGISTER0x1) == 0 && |
1100 | (m6->m6_flags & MIFF_REGISTER0x1) == 0 && |
1101 | (in6_addr2scopeid(ifp->if_index, &ip6->ip6_dst) != |
1102 | in6_addr2scopeid(ifn->if_index, &ip6->ip6_dst) || |
1103 | in6_addr2scopeid(ifp->if_index, &ip6->ip6_src) != |
1104 | in6_addr2scopeid(ifn->if_index, &ip6->ip6_src))) { |
1105 | if_put(ifn); |
1106 | ip6stat_inc(ip6s_badscope); |
1107 | continue; |
1108 | } |
1109 | |
1110 | m6->m6_pkt_out++; |
1111 | m6->m6_bytes_out += plen; |
1112 | |
1113 | phyint_send6(ifn, ip6, m); |
1114 | if_put(ifn); |
1115 | } while ((rt = rtable_iterate(rt)) != NULL((void *)0)); |
1116 | |
1117 | return 0; |
1118 | } |
1119 | |
1120 | void |
1121 | phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m) |
1122 | { |
1123 | struct mbuf *mb_copy; |
1124 | struct sockaddr_in6 *dst6, sin6; |
1125 | int error = 0; |
1126 | |
1127 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
1128 | |
1129 | /* |
1130 | * Make a new reference to the packet; make sure that |
1131 | * the IPv6 header is actually copied, not just referenced, |
1132 | * so that ip6_output() only scribbles on the copy. |
1133 | */ |
1134 | mb_copy = m_dup_pkt(m, max_linkhdr, M_NOWAIT0x0002); |
1135 | if (mb_copy == NULL((void *)0)) |
1136 | return; |
1137 | /* set MCAST flag to the outgoing packet */ |
1138 | mb_copy->m_flagsm_hdr.mh_flags |= M_MCAST0x0200; |
1139 | |
1140 | /* |
1141 | * If we sourced the packet, call ip6_output since we may divide |
1142 | * the packet into fragments when the packet is too big for the |
1143 | * outgoing interface. |
1144 | * Otherwise, we can simply send the packet to the interface |
1145 | * sending queue. |
1146 | */ |
1147 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx == 0) { |
1148 | struct ip6_moptions im6o; |
1149 | |
1150 | im6o.im6o_ifidx = ifp->if_index; |
1151 | /* XXX: ip6_output will override ip6->ip6_hlim */ |
1152 | im6o.im6o_hlim = ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim; |
1153 | im6o.im6o_loop = 1; |
1154 | error = ip6_output(mb_copy, NULL((void *)0), NULL((void *)0), IPV6_FORWARDING0x02, &im6o, |
Value stored to 'error' is never read | |
1155 | NULL((void *)0)); |
1156 | return; |
1157 | } |
1158 | |
1159 | /* |
1160 | * If we belong to the destination multicast group |
1161 | * on the outgoing interface, loop back a copy. |
1162 | */ |
1163 | dst6 = &sin6; |
1164 | memset(&sin6, 0, sizeof(sin6))__builtin_memset((&sin6), (0), (sizeof(sin6))); |
1165 | if (in6_hasmulti(&ip6->ip6_dst, ifp)) { |
1166 | dst6->sin6_len = sizeof(struct sockaddr_in6); |
1167 | dst6->sin6_family = AF_INET624; |
1168 | dst6->sin6_addr = ip6->ip6_dst; |
1169 | ip6_mloopback(ifp, m, dst6); |
1170 | } |
1171 | /* |
1172 | * Put the packet into the sending queue of the outgoing interface |
1173 | * if it would fit in the MTU of the interface. |
1174 | */ |
1175 | if (mb_copy->m_pkthdrM_dat.MH.MH_pkthdr.len <= ifp->if_mtuif_data.ifi_mtu || ifp->if_mtuif_data.ifi_mtu < IPV6_MMTU1280) { |
1176 | dst6->sin6_len = sizeof(struct sockaddr_in6); |
1177 | dst6->sin6_family = AF_INET624; |
1178 | dst6->sin6_addr = ip6->ip6_dst; |
1179 | error = ifp->if_output(ifp, mb_copy, sin6tosa(dst6), NULL((void *)0)); |
1180 | } else { |
1181 | if (ip6_mcast_pmtu) |
1182 | icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG2, 0, |
1183 | ifp->if_mtuif_data.ifi_mtu); |
1184 | else { |
1185 | m_freem(mb_copy); /* simply discard the packet */ |
1186 | } |
1187 | } |
1188 | } |
1189 | |
1190 | struct ifnet * |
1191 | mrt6_iflookupbymif(mifi_t mifi, unsigned int rtableid) |
1192 | { |
1193 | struct mif6 *m6; |
1194 | struct ifnet *ifp; |
1195 | |
1196 | TAILQ_FOREACH(ifp, &ifnet, if_list)for((ifp) = ((&ifnet)->tqh_first); (ifp) != ((void *)0 ); (ifp) = ((ifp)->if_list.tqe_next)) { |
1197 | if (ifp->if_rdomainif_data.ifi_rdomain != rtableid) |
1198 | continue; |
1199 | if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL((void *)0)) |
1200 | continue; |
1201 | if (m6->m6_mifi != mifi) |
1202 | continue; |
1203 | |
1204 | return ifp; |
1205 | } |
1206 | |
1207 | return NULL((void *)0); |
1208 | } |
1209 | |
1210 | struct rtentry * |
1211 | mf6c_find(struct ifnet *ifp, struct in6_addr *origin, struct in6_addr *group, |
1212 | unsigned int rtableid) |
1213 | { |
1214 | struct rtentry *rt; |
1215 | struct sockaddr_in6 msin6; |
1216 | |
1217 | memset(&msin6, 0, sizeof(msin6))__builtin_memset((&msin6), (0), (sizeof(msin6))); |
1218 | msin6.sin6_family = AF_INET624; |
1219 | msin6.sin6_len = sizeof(msin6); |
1220 | msin6.sin6_addr = *group; |
1221 | |
1222 | rt = rtalloc(sin6tosa(&msin6), 0, rtableid); |
1223 | do { |
1224 | if (!rtisvalid(rt)) { |
1225 | rtfree(rt); |
1226 | return NULL((void *)0); |
1227 | } |
1228 | if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) != |
1229 | (RTF_HOST0x4 | RTF_MULTICAST0x200)) |
1230 | continue; |
1231 | /* Return first occurrence if interface is not specified. */ |
1232 | if (ifp == NULL((void *)0)) |
1233 | return rt; |
1234 | if (rt->rt_ifidx == ifp->if_index) |
1235 | return rt; |
1236 | } while ((rt = rtable_iterate(rt)) != NULL((void *)0)); |
1237 | |
1238 | return NULL((void *)0); |
1239 | } |
1240 | |
1241 | struct rtentry * |
1242 | mrt6_mcast_add(struct ifnet *ifp, struct sockaddr *origin, |
1243 | struct sockaddr *group) |
1244 | { |
1245 | struct ifaddr *ifa; |
1246 | int rv; |
1247 | unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain; |
1248 | |
1249 | TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)for((ifa) = ((&ifp->if_addrlist)->tqh_first); (ifa) != ((void *)0); (ifa) = ((ifa)->ifa_list.tqe_next)) { |
1250 | if (ifa->ifa_addr->sa_family == AF_INET624) |
1251 | break; |
1252 | } |
1253 | if (ifa == NULL((void *)0)) { |
1254 | DPRINTF("ifa == NULL")do { } while (0); |
1255 | return NULL((void *)0); |
1256 | } |
1257 | |
1258 | rv = rt_ifa_add(ifa, RTF_HOST0x4 | RTF_MULTICAST0x200 | RTF_MPATH0x40000, group, |
1259 | ifp->if_rdomainif_data.ifi_rdomain); |
1260 | if (rv != 0) { |
1261 | DPRINTF("rt_ifa_add failed %d", rv)do { } while (0); |
1262 | return NULL((void *)0); |
1263 | } |
1264 | |
1265 | return mf6c_find(ifp, NULL((void *)0), &satosin6(group)->sin6_addr, rtableid); |
1266 | } |
1267 | |
1268 | void |
1269 | mrt6_mcast_del(struct rtentry *rt, unsigned int rtableid) |
1270 | { |
1271 | struct ifnet *ifp; |
1272 | int error; |
1273 | |
1274 | /* Remove all timers related to this route. */ |
1275 | rt_timer_remove_all(rt); |
1276 | |
1277 | free(rt->rt_llinfo, M_MRTABLE56, sizeof(struct mf6c)); |
1278 | rt->rt_llinfo = NULL((void *)0); |
1279 | |
1280 | ifp = if_get(rt->rt_ifidx); |
1281 | if (ifp == NULL((void *)0)) |
1282 | return; |
1283 | error = rtdeletemsg(rt, ifp, rtableid); |
1284 | if_put(ifp); |
1285 | |
1286 | if (error) |
1287 | DPRINTF("delete route error %d\n", error)do { } while (0); |
1288 | } |