Bug Summary

File:netinet6/ip6_mroute.c
Warning:line 1184, column 3
Value stored to 'error' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ip6_mroute.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/netinet6/ip6_mroute.c
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
113int 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
125int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
126void 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 */
132struct socket *ip6_mrouter[RT_TABLEID_MAX255 + 1];
133struct rttimer_queue ip6_mrouterq;
134int ip6_mrouter_ver = 0;
135int ip6_mrtproto; /* for netstat only */
136struct 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
166int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int);
167int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int);
168int ip6_mrouter_init(struct socket *, int, int);
169int add_m6if(struct socket *, struct mif6ctl *);
170int del_m6if(struct socket *, mifi_t *);
171int add_m6fc(struct socket *, struct mf6cctl *);
172int del_m6fc(struct socket *, struct mf6cctl *);
173struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int);
174struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *,
175 struct in6_addr *, unsigned int);
176struct rtentry *mrt6_mcast_add(struct ifnet *, struct sockaddr *,
177 struct sockaddr *);
178void mrt6_mcast_del(struct rtentry *, unsigned int);
179
180/*
181 * Handle MRT setsockopt commands to modify the multicast routing tables.
182 */
183int
184ip6_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 */
222int
223ip6_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 */
239int
240mrt6_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 */
275int
276get_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 */
305int
306get_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
323int
324mrt6_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
369struct mf6csysctlarg {
370 struct mf6cinfo *ms6a_minfos;
371 size_t ms6a_len;
372 size_t ms6a_needed;
373};
374
375int
376mrt6_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
442int
443mrt6_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 */
480int
481ip6_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
502int
503mrouter6_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 */
516int
517ip6_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
553void
554ip6_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 */
577int
578add_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 */
640int
641del_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
658int
659mf6c_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
692void
693mf6c_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
794int
795mf6c_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
824int
825add_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
837int
838del_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
855int
856socket6_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 */
885int
886ip6_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
998void
999mf6c_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 */
1029int
1030ip6_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
1125void
1126phyint_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
1195struct ifnet *
1196mrt6_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
1215struct rtentry *
1216mf6c_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
1246struct rtentry *
1247mrt6_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
1273void
1274mrt6_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}