Bug Summary

File:netinet/ip_mroute.c
Warning:line 964, column 7
Although the value stored to 'v' is used in the enclosing expression, the value is never actually read from 'v'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ip_mroute.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -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 -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/lib/clang/13.0.0 -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/swsmu -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/powerplay -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/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 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 -D CONFIG_DRM_AMD_DC_DCN3_0 -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 -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 /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/netinet/ip_mroute.c
1/* $OpenBSD: ip_mroute.c,v 1.131 2021/12/15 17:21:08 deraadt Exp $ */
2/* $NetBSD: ip_mroute.c,v 1.85 2004/04/26 01:31:57 matt Exp $ */
3
4/*
5 * Copyright (c) 1989 Stephen Deering
6 * Copyright (c) 1992, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Stephen Deering of Stanford University.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
37 */
38
39/*
40 * IP multicast forwarding procedures
41 *
42 * Written by David Waitzman, BBN Labs, August 1988.
43 * Modified by Steve Deering, Stanford, February 1989.
44 * Modified by Mark J. Steiglitz, Stanford, May, 1991
45 * Modified by Van Jacobson, LBL, January 1993
46 * Modified by Ajit Thyagarajan, PARC, August 1993
47 * Modified by Bill Fenner, PARC, April 1994
48 * Modified by Charles M. Hannum, NetBSD, May 1995.
49 * Modified by Ahmed Helmy, SGI, June 1996
50 * Modified by George Edmond Eddy (Rusty), ISI, February 1998
51 * Modified by Pavlin Radoslavov, USC/ISI, May 1998, August 1999, October 2000
52 * Modified by Hitoshi Asaeda, WIDE, August 2000
53 * Modified by Pavlin Radoslavov, ICSI, October 2002
54 *
55 * MROUTING Revision: 1.2
56 * advanced API support, bandwidth metering and signaling
57 */
58
59#include <sys/param.h>
60#include <sys/systm.h>
61#include <sys/mbuf.h>
62#include <sys/socket.h>
63#include <sys/socketvar.h>
64#include <sys/protosw.h>
65#include <sys/ioctl.h>
66#include <sys/syslog.h>
67
68#include <net/if.h>
69#include <net/if_var.h>
70#include <net/route.h>
71
72#include <netinet/in.h>
73#include <netinet/ip.h>
74#include <netinet/ip_var.h>
75#include <netinet/in_pcb.h>
76#include <netinet/igmp.h>
77#include <netinet/ip_mroute.h>
78
79/* #define MCAST_DEBUG */
80
81#ifdef MCAST_DEBUG
82int mcast_debug = 1;
83#define DPRINTF(fmt, args...)do { } while (0) \
84 do { \
85 if (mcast_debug) \
86 printf("%s:%d " fmt "\n", \
87 __func__, __LINE__87, ## args); \
88 } while (0)
89#else
90#define DPRINTF(fmt, args...)do { } while (0) \
91 do { } while (0)
92#endif
93
94/*
95 * Globals. All but ip_mrouter and ip_mrtproto could be static,
96 * except for netstat or debugging purposes.
97 */
98struct socket *ip_mrouter[RT_TABLEID_MAX255 + 1];
99struct rttimer_queue *mrouterq[RT_TABLEID_MAX255 + 1];
100uint64_t mrt_count[RT_TABLEID_MAX255 + 1];
101int ip_mrtproto = IGMP_DVMRP0x13; /* for netstat only */
102
103struct mrtstat mrtstat;
104
105struct rtentry *mfc_find(struct ifnet *, struct in_addr *,
106 struct in_addr *, unsigned int);
107int get_sg_cnt(unsigned int, struct sioc_sg_req *);
108int get_vif_cnt(unsigned int, struct sioc_vif_req *);
109int mrt_rtwalk_mfcsysctl(struct rtentry *, void *, unsigned int);
110int ip_mrouter_init(struct socket *, struct mbuf *);
111int mrouter_rtwalk_delete(struct rtentry *, void *, unsigned int);
112int get_version(struct mbuf *);
113int add_vif(struct socket *, struct mbuf *);
114int del_vif(struct socket *, struct mbuf *);
115void update_mfc_params(struct mfcctl2 *, int, unsigned int);
116void mfc_expire_route(struct rtentry *, struct rttimer *);
117int mfc_add(struct mfcctl2 *, struct in_addr *, struct in_addr *,
118 int, unsigned int, int);
119int add_mfc(struct socket *, struct mbuf *);
120int del_mfc(struct socket *, struct mbuf *);
121int set_api_config(struct socket *, struct mbuf *); /* chose API capabilities */
122int get_api_support(struct mbuf *);
123int get_api_config(struct mbuf *);
124int socket_send(struct socket *, struct mbuf *,
125 struct sockaddr_in *);
126int ip_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
127struct ifnet *if_lookupbyvif(vifi_t, unsigned int);
128struct rtentry *rt_mcast_add(struct ifnet *, struct sockaddr *,
129 struct sockaddr *);
130void mrt_mcast_del(struct rtentry *, unsigned int);
131
132/*
133 * Kernel multicast routing API capabilities and setup.
134 * If more API capabilities are added to the kernel, they should be
135 * recorded in `mrt_api_support'.
136 */
137static const u_int32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF(1 << 0) |
138 MRT_MFC_RP(1 << 8));
139static u_int32_t mrt_api_config = 0;
140
141/*
142 * Find a route for a given origin IP address and Multicast group address
143 * Type of service parameter to be added in the future!!!
144 * Statistics are updated by the caller if needed
145 * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses)
146 */
147struct rtentry *
148mfc_find(struct ifnet *ifp, struct in_addr *origin, struct in_addr *group,
149 unsigned int rtableid)
150{
151 struct rtentry *rt;
152 struct sockaddr_in msin;
153
154 memset(&msin, 0, sizeof(msin))__builtin_memset((&msin), (0), (sizeof(msin)));
155 msin.sin_len = sizeof(msin);
156 msin.sin_family = AF_INET2;
157 msin.sin_addr = *group;
158
159 rt = rtalloc(sintosa(&msin), 0, rtableid);
160 do {
161 if (!rtisvalid(rt)) {
162 rtfree(rt);
163 return NULL((void *)0);
164 }
165 /* Don't consider non multicast routes. */
166 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
167 (RTF_HOST0x4 | RTF_MULTICAST0x200))
168 continue;
169 /* Return first occurrence if interface is not specified. */
170 if (ifp == NULL((void *)0))
171 return (rt);
172 if (rt->rt_ifidx == ifp->if_index)
173 return (rt);
174 } while ((rt = rtable_iterate(rt)) != NULL((void *)0));
175
176 return (NULL((void *)0));
177}
178
179/*
180 * Handle MRT setsockopt commands to modify the multicast routing tables.
181 */
182int
183ip_mrouter_set(struct socket *so, int optname, struct mbuf *m)
184{
185 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
186 int error;
187
188 if (optname != MRT_INIT100 &&
189 so != ip_mrouter[inp->inp_rtableid])
190 error = ENOPROTOOPT42;
191 else
192 switch (optname) {
193 case MRT_INIT100:
194 error = ip_mrouter_init(so, m);
195 break;
196 case MRT_DONE101:
197 error = ip_mrouter_done(so);
198 break;
199 case MRT_ADD_VIF102:
200 error = add_vif(so, m);
201 break;
202 case MRT_DEL_VIF103:
203 error = del_vif(so, m);
204 break;
205 case MRT_ADD_MFC104:
206 error = add_mfc(so, m);
207 break;
208 case MRT_DEL_MFC105:
209 error = del_mfc(so, m);
210 break;
211 case MRT_API_CONFIG110:
212 error = set_api_config(so, m);
213 break;
214 default:
215 error = ENOPROTOOPT42;
216 break;
217 }
218
219 return (error);
220}
221
222/*
223 * Handle MRT getsockopt commands
224 */
225int
226ip_mrouter_get(struct socket *so, int optname, struct mbuf *m)
227{
228 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
229 int error;
230
231 if (so != ip_mrouter[inp->inp_rtableid])
232 error = ENOPROTOOPT42;
233 else {
234 switch (optname) {
235 case MRT_VERSION106:
236 error = get_version(m);
237 break;
238 case MRT_API_SUPPORT109:
239 error = get_api_support(m);
240 break;
241 case MRT_API_CONFIG110:
242 error = get_api_config(m);
243 break;
244 default:
245 error = ENOPROTOOPT42;
246 break;
247 }
248 }
249
250 return (error);
251}
252
253/*
254 * Handle ioctl commands to obtain information from the cache
255 */
256int
257mrt_ioctl(struct socket *so, u_long cmd, caddr_t data)
258{
259 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
260 int error;
261
262 if (inp == NULL((void *)0))
263 return (ENOTCONN57);
264
265 if (so != ip_mrouter[inp->inp_rtableid])
266 error = EINVAL22;
267 else
268 switch (cmd) {
269 case SIOCGETVIFCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct sioc_vif_req) & 0x1fff) << 16) | ((('u')) <<
8) | ((51)))
:
270 NET_RLOCK_IN_IOCTL()do { rw_enter_read(&netlock); } while (0);
271 error = get_vif_cnt(inp->inp_rtableid,
272 (struct sioc_vif_req *)data);
273 NET_RUNLOCK_IN_IOCTL()do { rw_exit_read(&netlock); } while (0);
274 break;
275 case SIOCGETSGCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct sioc_sg_req) & 0x1fff) << 16) | ((('u')) <<
8) | ((52)))
:
276 NET_RLOCK_IN_IOCTL()do { rw_enter_read(&netlock); } while (0);
277 error = get_sg_cnt(inp->inp_rtableid,
278 (struct sioc_sg_req *)data);
279 NET_RUNLOCK_IN_IOCTL()do { rw_exit_read(&netlock); } while (0);
280 break;
281 default:
282 error = ENOTTY25;
283 break;
284 }
285
286 return (error);
287}
288
289/*
290 * returns the packet, byte, rpf-failure count for the source group provided
291 */
292int
293get_sg_cnt(unsigned int rtableid, struct sioc_sg_req *req)
294{
295 struct rtentry *rt;
296 struct mfc *mfc;
297
298 rt = mfc_find(NULL((void *)0), &req->src, &req->grp, rtableid);
299 if (rt == NULL((void *)0)) {
300 req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
301 return (EADDRNOTAVAIL49);
302 }
303
304 req->pktcnt = req->bytecnt = req->wrong_if = 0;
305 do {
306 /* Don't consider non multicast routes. */
307 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
308 (RTF_HOST0x4 | RTF_MULTICAST0x200))
309 continue;
310
311 mfc = (struct mfc *)rt->rt_llinfo;
312 if (mfc == NULL((void *)0))
313 continue;
314
315 req->pktcnt += mfc->mfc_pkt_cnt;
316 req->bytecnt += mfc->mfc_byte_cnt;
317 req->wrong_if += mfc->mfc_wrong_if;
318 } while ((rt = rtable_iterate(rt)) != NULL((void *)0));
319
320 return (0);
321}
322
323/*
324 * returns the input and output packet and byte counts on the vif provided
325 */
326int
327get_vif_cnt(unsigned int rtableid, struct sioc_vif_req *req)
328{
329 struct ifnet *ifp;
330 struct vif *v;
331 vifi_t vifi = req->vifi;
332
333 if ((ifp = if_lookupbyvif(vifi, rtableid)) == NULL((void *)0))
334 return (EINVAL22);
335
336 v = (struct vif *)ifp->if_mcast;
337 req->icount = v->v_pkt_in;
338 req->ocount = v->v_pkt_out;
339 req->ibytes = v->v_bytes_in;
340 req->obytes = v->v_bytes_out;
341
342 return (0);
343}
344
345int
346mrt_sysctl_vif(void *oldp, size_t *oldlenp)
347{
348 caddr_t where = oldp;
349 size_t needed, given;
350 struct ifnet *ifp;
351 struct vif *vifp;
352 struct vifinfo vinfo;
353
354 given = *oldlenp;
355 needed = 0;
356 memset(&vinfo, 0, sizeof vinfo)__builtin_memset((&vinfo), (0), (sizeof vinfo));
357 TAILQ_FOREACH(ifp, &ifnet, if_list)for((ifp) = ((&ifnet)->tqh_first); (ifp) != ((void *)0
); (ifp) = ((ifp)->if_list.tqe_next))
{
358 if ((vifp = (struct vif *)ifp->if_mcast) == NULL((void *)0))
359 continue;
360
361 vinfo.v_vifi = vifp->v_id;
362 vinfo.v_flags = vifp->v_flags;
363 vinfo.v_threshold = vifp->v_threshold;
364 vinfo.v_lcl_addr = vifp->v_lcl_addr;
365 vinfo.v_rmt_addr = vifp->v_rmt_addr;
366 vinfo.v_pkt_in = vifp->v_pkt_in;
367 vinfo.v_pkt_out = vifp->v_pkt_out;
368 vinfo.v_bytes_in = vifp->v_bytes_in;
369 vinfo.v_bytes_out = vifp->v_bytes_out;
370
371 needed += sizeof(vinfo);
372 if (where && needed <= given) {
373 int error;
374
375 error = copyout(&vinfo, where, sizeof(vinfo));
376 if (error)
377 return (error);
378 where += sizeof(vinfo);
379 }
380 }
381 if (where) {
382 *oldlenp = needed;
383 if (given < needed)
384 return (ENOMEM12);
385 } else
386 *oldlenp = (11 * needed) / 10;
387
388 return (0);
389}
390
391struct mfcsysctlarg {
392 struct mfcinfo *msa_minfos;
393 size_t msa_len;
394 size_t msa_needed;
395};
396
397int
398mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
399{
400 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
401 struct mfcsysctlarg *msa = (struct mfcsysctlarg *)arg;
402 struct ifnet *ifp;
403 struct vif *v;
404 struct mfcinfo *minfo;
405 int new = 0;
406
407 /* Skip entries being removed. */
408 if (mfc == NULL((void *)0))
409 return (0);
410
411 /* Skip non-multicast routes. */
412 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
413 (RTF_HOST0x4 | RTF_MULTICAST0x200))
414 return (0);
415
416 /* User just asked for the output size. */
417 if (msa->msa_minfos == NULL((void *)0)) {
418 msa->msa_needed += sizeof(*minfo);
419 return (0);
420 }
421
422 /* Skip route with invalid interfaces. */
423 if ((ifp = if_get(rt->rt_ifidx)) == NULL((void *)0))
424 return (0);
425 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0)) {
426 if_put(ifp);
427 return (0);
428 }
429
430 for (minfo = msa->msa_minfos;
431 (uint8_t *)minfo < ((uint8_t *)msa->msa_minfos + msa->msa_len);
432 minfo++) {
433 /* Find a new entry or update old entry. */
434 if (minfo->mfc_origin.s_addr !=
435 satosin(rt->rt_gateway)->sin_addr.s_addr ||
436 minfo->mfc_mcastgrp.s_addr !=
437 satosin(rt_key(rt)((rt)->rt_dest))->sin_addr.s_addr) {
438 if (minfo->mfc_origin.s_addr != 0 ||
439 minfo->mfc_mcastgrp.s_addr != 0)
440 continue;
441
442 new = 1;
443 }
444
445 minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
446 minfo->mfc_mcastgrp = satosin(rt_key(rt)((rt)->rt_dest))->sin_addr;
447 minfo->mfc_parent = mfc->mfc_parent;
448 minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
449 minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
450 minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
451 break;
452 }
453
454 if (new != 0)
455 msa->msa_needed += sizeof(*minfo);
456
457 if_put(ifp);
458
459 return (0);
460}
461
462int
463mrt_sysctl_mfc(void *oldp, size_t *oldlenp)
464{
465 unsigned int rtableid;
466 int error;
467 struct mfcsysctlarg msa;
468
469 if (oldp != NULL((void *)0) && *oldlenp > MAXPHYS(64 * 1024))
470 return (EINVAL22);
471
472 if (oldp != NULL((void *)0))
473 msa.msa_minfos = malloc(*oldlenp, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
474 else
475 msa.msa_minfos = NULL((void *)0);
476
477 msa.msa_len = *oldlenp;
478 msa.msa_needed = 0;
479
480 for (rtableid = 0; rtableid <= RT_TABLEID_MAX255; rtableid++) {
481 rtable_walk(rtableid, AF_INET2, NULL((void *)0), mrt_rtwalk_mfcsysctl,
482 &msa);
483 }
484
485 if (msa.msa_minfos != NULL((void *)0) && msa.msa_needed > 0 &&
486 (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) {
487 free(msa.msa_minfos, M_TEMP127, *oldlenp);
488 return (error);
489 }
490
491 free(msa.msa_minfos, M_TEMP127, *oldlenp);
492 *oldlenp = msa.msa_needed;
493
494 return (0);
495}
496
497/*
498 * Enable multicast routing
499 */
500int
501ip_mrouter_init(struct socket *so, struct mbuf *m)
502{
503 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
504 unsigned int rtableid = inp->inp_rtableid;
505 int *v;
506
507 if (so->so_type != SOCK_RAW3 ||
508 so->so_proto->pr_protocol != IPPROTO_IGMP2)
509 return (EOPNOTSUPP45);
510
511 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(int))
512 return (EINVAL22);
513
514 v = mtod(m, int *)((int *)((m)->m_hdr.mh_data));
515 if (*v != 1)
516 return (EINVAL22);
517
518 if (ip_mrouter[rtableid] != NULL((void *)0) ||
519 mrouterq[rtableid] != NULL((void *)0))
520 return (EADDRINUSE48);
521
522 ip_mrouter[rtableid] = so;
523 mrouterq[rtableid] = rt_timer_queue_create(MCAST_EXPIRE_FREQUENCY30);
524
525 return (0);
526}
527
528int
529mrouter_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
530{
531 /* Skip non-multicast routes. */
532 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
533 (RTF_HOST0x4 | RTF_MULTICAST0x200))
534 return (0);
535
536 return EEXIST17;
537}
538
539/*
540 * Disable multicast routing
541 */
542int
543ip_mrouter_done(struct socket *so)
544{
545 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
546 struct ifnet *ifp;
547 unsigned int rtableid = inp->inp_rtableid;
548 int error;
549
550 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
551
552 /* Delete all remaining installed multicast routes. */
553 do {
554 struct rtentry *rt = NULL((void *)0);
555
556 error = rtable_walk(rtableid, AF_INET2, &rt,
557 mrouter_rtwalk_delete, NULL((void *)0));
558 if (rt != NULL((void *)0) && error == EEXIST17) {
559 mrt_mcast_del(rt, rtableid);
560 error = EAGAIN35;
561 }
562 rtfree(rt);
563 } while (error == EAGAIN35);
564
565 /* Unregister all interfaces in the domain. */
566 TAILQ_FOREACH(ifp, &ifnet, if_list)for((ifp) = ((&ifnet)->tqh_first); (ifp) != ((void *)0
); (ifp) = ((ifp)->if_list.tqe_next))
{
567 if (ifp->if_rdomainif_data.ifi_rdomain != rtableid)
568 continue;
569
570 vif_delete(ifp);
571 }
572
573 mrt_api_config = 0;
574
575 rt_timer_queue_destroy(mrouterq[rtableid]);
576 mrouterq[rtableid] = NULL((void *)0);
577 ip_mrouter[rtableid] = NULL((void *)0);
578 mrt_count[rtableid] = 0;
579
580 return (0);
581}
582
583int
584get_version(struct mbuf *m)
585{
586 int *v = mtod(m, int *)((int *)((m)->m_hdr.mh_data));
587
588 *v = 0x0305; /* XXX !!!! */
589 m->m_lenm_hdr.mh_len = sizeof(int);
590 return (0);
591}
592
593/*
594 * Configure API capabilities
595 */
596int
597set_api_config(struct socket *so, struct mbuf *m)
598{
599 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
600 struct ifnet *ifp;
601 u_int32_t *apival;
602 unsigned int rtableid = inp->inp_rtableid;
603
604 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(u_int32_t))
605 return (EINVAL22);
606
607 apival = mtod(m, u_int32_t *)((u_int32_t *)((m)->m_hdr.mh_data));
608
609 /*
610 * We can set the API capabilities only if it is the first operation
611 * after MRT_INIT. I.e.:
612 * - there are no vifs installed
613 * - the MFC table is empty
614 */
615 TAILQ_FOREACH(ifp, &ifnet, if_list)for((ifp) = ((&ifnet)->tqh_first); (ifp) != ((void *)0
); (ifp) = ((ifp)->if_list.tqe_next))
{
616 if (ifp->if_rdomainif_data.ifi_rdomain != rtableid)
617 continue;
618 if (ifp->if_mcast == NULL((void *)0))
619 continue;
620
621 *apival = 0;
622 return (EPERM1);
623 }
624 if (mrt_count[rtableid] > 0) {
625 *apival = 0;
626 return (EPERM1);
627 }
628
629 mrt_api_config = *apival & mrt_api_support;
630 *apival = mrt_api_config;
631
632 return (0);
633}
634
635/*
636 * Get API capabilities
637 */
638int
639get_api_support(struct mbuf *m)
640{
641 u_int32_t *apival;
642
643 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(u_int32_t))
644 return (EINVAL22);
645
646 apival = mtod(m, u_int32_t *)((u_int32_t *)((m)->m_hdr.mh_data));
647
648 *apival = mrt_api_support;
649
650 return (0);
651}
652
653/*
654 * Get API configured capabilities
655 */
656int
657get_api_config(struct mbuf *m)
658{
659 u_int32_t *apival;
660
661 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(u_int32_t))
662 return (EINVAL22);
663
664 apival = mtod(m, u_int32_t *)((u_int32_t *)((m)->m_hdr.mh_data));
665
666 *apival = mrt_api_config;
667
668 return (0);
669}
670
671static struct sockaddr_in sin = { sizeof(sin), AF_INET2 };
672
673int
674add_vif(struct socket *so, struct mbuf *m)
675{
676 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
677 struct vifctl *vifcp;
678 struct vif *vifp;
679 struct ifaddr *ifa;
680 struct ifnet *ifp;
681 struct ifreq ifr;
682 int error;
683 unsigned int rtableid = inp->inp_rtableid;
684
685 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
686
687 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(struct vifctl))
688 return (EINVAL22);
689
690 vifcp = mtod(m, struct vifctl *)((struct vifctl *)((m)->m_hdr.mh_data));
691 if (vifcp->vifc_vifi >= MAXVIFS32)
692 return (EINVAL22);
693 if (in_nullhost(vifcp->vifc_lcl_addr)((vifcp->vifc_lcl_addr).s_addr == ((u_int32_t) (__uint32_t
)(__builtin_constant_p((u_int32_t)(0x00000000)) ? (__uint32_t
)(((__uint32_t)((u_int32_t)(0x00000000)) & 0xff) <<
24 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff00) <<
8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff0000) >>
8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff000000)
>> 24) : __swap32md((u_int32_t)(0x00000000)))))
)
694 return (EADDRNOTAVAIL49);
695 if (if_lookupbyvif(vifcp->vifc_vifi, rtableid) != NULL((void *)0))
696 return (EADDRINUSE48);
697
698 /* Tunnels are no longer supported use gif(4) instead. */
699 if (vifcp->vifc_flags & VIFF_TUNNEL0x1)
700 return (EOPNOTSUPP45);
701 {
702 sin.sin_addr = vifcp->vifc_lcl_addr;
703 ifa = ifa_ifwithaddr(sintosa(&sin), rtableid);
704 if (ifa == NULL((void *)0))
705 return (EADDRNOTAVAIL49);
706 }
707
708 /* Use the physical interface associated with the address. */
709 ifp = ifa->ifa_ifp;
710 if (ifp->if_mcast != NULL((void *)0))
711 return (EADDRINUSE48);
712
713 {
714 /* Make sure the interface supports multicast. */
715 if ((ifp->if_flags & IFF_MULTICAST0x8000) == 0)
716 return (EOPNOTSUPP45);
717
718 /* Enable promiscuous reception of all IP multicasts. */
719 memset(&ifr, 0, sizeof(ifr))__builtin_memset((&ifr), (0), (sizeof(ifr)));
720 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_len = sizeof(struct sockaddr_in);
721 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_family = AF_INET2;
722 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_addr = zeroin_addr;
723 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((49)))
, (caddr_t)&ifr);
724 if (error)
725 return (error);
726 }
727
728 vifp = malloc(sizeof(*vifp), M_MRTABLE56, M_WAITOK0x0001 | M_ZERO0x0008);
729 ifp->if_mcast = (caddr_t)vifp;
730
731 vifp->v_id = vifcp->vifc_vifi;
732 vifp->v_flags = vifcp->vifc_flags;
733 vifp->v_threshold = vifcp->vifc_threshold;
734 vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
735 vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
736
737 return (0);
738}
739
740int
741del_vif(struct socket *so, struct mbuf *m)
742{
743 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
744 struct ifnet *ifp;
745 vifi_t *vifip;
746 unsigned int rtableid = inp->inp_rtableid;
747
748 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
749
750 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(vifi_t))
751 return (EINVAL22);
752
753 vifip = mtod(m, vifi_t *)((vifi_t *)((m)->m_hdr.mh_data));
754 if ((ifp = if_lookupbyvif(*vifip, rtableid)) == NULL((void *)0))
755 return (EADDRNOTAVAIL49);
756
757 vif_delete(ifp);
758 return (0);
759}
760
761void
762vif_delete(struct ifnet *ifp)
763{
764 struct vif *v;
765 struct ifreq ifr;
766
767 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0))
768 return;
769
770 ifp->if_mcast = NULL((void *)0);
771
772 memset(&ifr, 0, sizeof(ifr))__builtin_memset((&ifr), (0), (sizeof(ifr)));
773 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_len = sizeof(struct sockaddr_in);
774 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_family = AF_INET2;
775 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_addr = zeroin_addr;
776 KERNEL_LOCK()_kernel_lock();
777 (*ifp->if_ioctl)(ifp, SIOCDELMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((50)))
, (caddr_t)&ifr);
778 KERNEL_UNLOCK()_kernel_unlock();
779
780 free(v, M_MRTABLE56, sizeof(*v));
781}
782
783void
784mfc_expire_route(struct rtentry *rt, struct rttimer *rtt)
785{
786 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
787 unsigned int rtableid = rtt->rtt_tableid;
788
789 /* Skip entry being deleted. */
790 if (mfc == NULL((void *)0))
791 return;
792
793 DPRINTF("Route domain %d origin %#08X group %#08x interface %d "do { } while (0)
794 "expire %s", rtt->rtt_tableid,do { } while (0)
795 satosin(rt->rt_gateway)->sin_addr.s_addr,do { } while (0)
796 satosin(rt_key(rt))->sin_addr.s_addr,do { } while (0)
797 rt->rt_ifidx, mfc->mfc_expire ? "yes" : "no")do { } while (0);
798
799 /* Not expired, add it back to the queue. */
800 if (mfc->mfc_expire == 0) {
801 mfc->mfc_expire = 1;
802 rt_timer_add(rt, mfc_expire_route, mrouterq[rtableid],
803 rtableid);
804 return;
805 }
806
807 mrt_mcast_del(rt, rtableid);
808}
809
810int
811mfc_add_route(struct ifnet *ifp, struct sockaddr *origin,
812 struct sockaddr *group, struct mfcctl2 *mfccp, int wait)
813{
814 struct vif *v = (struct vif *)ifp->if_mcast;
815 struct rtentry *rt;
816 struct mfc *mfc;
817 unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain;
818
819 rt = rt_mcast_add(ifp, origin, group);
820 if (rt == NULL((void *)0))
821 return (EHOSTUNREACH65);
822
823 mfc = malloc(sizeof(*mfc), M_MRTABLE56, wait | M_ZERO0x0008);
824 if (mfc == NULL((void *)0)) {
825 DPRINTF("origin %#08X group %#08X parent %d (%s) "do { } while (0)
826 "malloc failed",do { } while (0)
827 satosin(origin)->sin_addr.s_addr,do { } while (0)
828 satosin(group)->sin_addr.s_addr,do { } while (0)
829 mfccp->mfcc_parent, ifp->if_xname)do { } while (0);
830 mrt_mcast_del(rt, rtableid);
831 rtfree(rt);
832 return (ENOMEM12);
833 }
834
835 rt->rt_llinfo = (caddr_t)mfc;
836
837 rt_timer_add(rt, mfc_expire_route, mrouterq[rtableid],
838 rtableid);
839
840 mfc->mfc_parent = mfccp->mfcc_parent;
841 mfc->mfc_pkt_cnt = 0;
842 mfc->mfc_byte_cnt = 0;
843 mfc->mfc_wrong_if = 0;
844 mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
845 mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
846 MRT_MFC_FLAGS_ALL((1 << 0));
847 mfc->mfc_expire = 0;
848
849 /* set the RP address */
850 if (mrt_api_config & MRT_MFC_RP(1 << 8))
851 mfc->mfc_rp = mfccp->mfcc_rp;
852 else
853 mfc->mfc_rp = zeroin_addr;
854
855 rtfree(rt);
856
857 return (0);
858}
859
860void
861update_mfc_params(struct mfcctl2 *mfccp, int wait, unsigned int rtableid)
862{
863 struct rtentry *rt;
864 struct mfc *mfc;
865 struct ifnet *ifp;
866 int i;
867 struct sockaddr_in osin, msin;
868
869 memset(&osin, 0, sizeof(osin))__builtin_memset((&osin), (0), (sizeof(osin)));
870 osin.sin_len = sizeof(osin);
871 osin.sin_family = AF_INET2;
872 osin.sin_addr = mfccp->mfcc_origin;
873
874 memset(&msin, 0, sizeof(msin))__builtin_memset((&msin), (0), (sizeof(msin)));
875 msin.sin_len = sizeof(msin);
876 msin.sin_family = AF_INET2;
877 msin.sin_addr = mfccp->mfcc_mcastgrp;
878
879 for (i = 0; i < MAXVIFS32; i++) {
880 /* Don't add/del upstream routes here. */
881 if (i == mfccp->mfcc_parent)
882 continue;
883
884 /* Test for vif existence and then update the entry. */
885 if ((ifp = if_lookupbyvif(i, rtableid)) == NULL((void *)0))
886 continue;
887
888 rt = mfc_find(ifp, &mfccp->mfcc_origin,
889 &mfccp->mfcc_mcastgrp, rtableid);
890
891 /* vif not configured or removed. */
892 if (mfccp->mfcc_ttls[i] == 0) {
893 /* Route doesn't exist, nothing to do. */
894 if (rt == NULL((void *)0))
895 continue;
896
897 DPRINTF("del route (group %#08X) for vif %d (%s)",do { } while (0)
898 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname)do { } while (0);
899 mrt_mcast_del(rt, rtableid);
900 rtfree(rt);
901 continue;
902 }
903
904 /* Route exists, look for changes. */
905 if (rt != NULL((void *)0)) {
906 mfc = (struct mfc *)rt->rt_llinfo;
907 /* Skip route being deleted. */
908 if (mfc == NULL((void *)0)) {
909 rtfree(rt);
910 continue;
911 }
912
913 /* No new changes to apply. */
914 if (mfccp->mfcc_ttls[i] == mfc->mfc_ttl &&
915 mfccp->mfcc_parent == mfc->mfc_parent) {
916 rtfree(rt);
917 continue;
918 }
919
920 DPRINTF("update route (group %#08X) for vif %d (%s)",do { } while (0)
921 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname)do { } while (0);
922 mfc->mfc_ttl = mfccp->mfcc_ttls[i];
923 mfc->mfc_parent = mfccp->mfcc_parent;
924 rtfree(rt);
925 continue;
926 }
927
928 DPRINTF("add route (group %#08X) for vif %d (%s)",do { } while (0)
929 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname)do { } while (0);
930
931 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin),
932 mfccp, wait);
933 }
934
935 /* Create route for the parent interface. */
936 if ((ifp = if_lookupbyvif(mfccp->mfcc_parent, rtableid)) == NULL((void *)0)) {
937 DPRINTF("failed to find upstream interface %d",do { } while (0)
938 mfccp->mfcc_parent)do { } while (0);
939 return;
940 }
941
942 /* We already have a route, nothing to do here. */
943 if ((rt = mfc_find(ifp, &mfccp->mfcc_origin,
944 &mfccp->mfcc_mcastgrp, rtableid)) != NULL((void *)0)) {
945 rtfree(rt);
946 return;
947 }
948
949 DPRINTF("add upstream route (group %#08X) for if %s",do { } while (0)
950 mfccp->mfcc_mcastgrp.s_addr, ifp->if_xname)do { } while (0);
951 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin), mfccp, wait);
952}
953
954int
955mfc_add(struct mfcctl2 *mfcctl2, struct in_addr *origin,
956 struct in_addr *group, int vidx, unsigned int rtableid, int wait)
957{
958 struct ifnet *ifp;
959 struct vif *v;
960 struct mfcctl2 mfcctl;
961
962 ifp = if_lookupbyvif(vidx, rtableid);
963 if (ifp == NULL((void *)0) ||
964 (v = (struct vif *)ifp->if_mcast) == NULL((void *)0))
Although the value stored to 'v' is used in the enclosing expression, the value is never actually read from 'v'
965 return (EHOSTUNREACH65);
966
967 memset(&mfcctl, 0, sizeof(mfcctl))__builtin_memset((&mfcctl), (0), (sizeof(mfcctl)));
968 if (mfcctl2 == NULL((void *)0)) {
969 mfcctl.mfcc_origin = *origin;
970 mfcctl.mfcc_mcastgrp = *group;
971 mfcctl.mfcc_parent = vidx;
972 } else
973 memcpy(&mfcctl, mfcctl2, sizeof(mfcctl))__builtin_memcpy((&mfcctl), (mfcctl2), (sizeof(mfcctl)));
974
975 update_mfc_params(&mfcctl, wait, rtableid);
976
977 return (0);
978}
979
980int
981add_mfc(struct socket *so, struct mbuf *m)
982{
983 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
984 struct mfcctl2 mfcctl2;
985 int mfcctl_size = sizeof(struct mfcctl);
986 unsigned int rtableid = inp->inp_rtableid;
987
988 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
989
990 if (mrt_api_config & MRT_API_FLAGS_ALL(((1 << 0)) | (1 << 8) | (1 << 9)))
991 mfcctl_size = sizeof(struct mfcctl2);
992
993 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < mfcctl_size)
994 return (EINVAL22);
995
996 /*
997 * select data size depending on API version.
998 */
999 if (mrt_api_config & MRT_API_FLAGS_ALL(((1 << 0)) | (1 << 8) | (1 << 9))) {
1000 struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *)((struct mfcctl2 *)((m)->m_hdr.mh_data));
1001 memcpy((caddr_t)&mfcctl2, mp2, sizeof(*mp2))__builtin_memcpy(((caddr_t)&mfcctl2), (mp2), (sizeof(*mp2
)))
;
1002 } else {
1003 struct mfcctl *mp = mtod(m, struct mfcctl *)((struct mfcctl *)((m)->m_hdr.mh_data));
1004 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp))__builtin_memcpy(((caddr_t)&mfcctl2), (mp), (sizeof(*mp))
)
;
1005 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,__builtin_memset(((caddr_t)&mfcctl2 + sizeof(struct mfcctl
)), (0), (sizeof(mfcctl2) - sizeof(struct mfcctl)))
1006 sizeof(mfcctl2) - sizeof(struct mfcctl))__builtin_memset(((caddr_t)&mfcctl2 + sizeof(struct mfcctl
)), (0), (sizeof(mfcctl2) - sizeof(struct mfcctl)))
;
1007 }
1008
1009 if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
1010 mfcctl2.mfcc_parent, rtableid, M_WAITOK0x0001) == -1)
1011 return (EINVAL22);
1012
1013 return (0);
1014}
1015
1016int
1017del_mfc(struct socket *so, struct mbuf *m)
1018{
1019 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
1020 struct rtentry *rt;
1021 struct mfcctl2 mfcctl2;
1022 int mfcctl_size = sizeof(struct mfcctl);
1023 struct mfcctl *mp;
1024 unsigned int rtableid = inp->inp_rtableid;
1025
1026 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
1027
1028 /*
1029 * XXX: for deleting MFC entries the information in entries
1030 * of size "struct mfcctl" is sufficient.
1031 */
1032
1033 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < mfcctl_size)
1034 return (EINVAL22);
1035
1036 mp = mtod(m, struct mfcctl *)((struct mfcctl *)((m)->m_hdr.mh_data));
1037
1038 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp))__builtin_memcpy(((caddr_t)&mfcctl2), (mp), (sizeof(*mp))
)
;
1039 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,__builtin_memset(((caddr_t)&mfcctl2 + sizeof(struct mfcctl
)), (0), (sizeof(mfcctl2) - sizeof(struct mfcctl)))
1040 sizeof(mfcctl2) - sizeof(struct mfcctl))__builtin_memset(((caddr_t)&mfcctl2 + sizeof(struct mfcctl
)), (0), (sizeof(mfcctl2) - sizeof(struct mfcctl)))
;
1041
1042 DPRINTF("origin %#08X group %#08X rtableid %d",do { } while (0)
1043 mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid)do { } while (0);
1044
1045 while ((rt = mfc_find(NULL((void *)0), &mfcctl2.mfcc_origin,
1046 &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL((void *)0)) {
1047 mrt_mcast_del(rt, rtableid);
1048 rtfree(rt);
1049 }
1050
1051 return (0);
1052}
1053
1054int
1055socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in *src)
1056{
1057 if (s != NULL((void *)0)) {
1058 if (sbappendaddr(s, &s->so_rcv, sintosa(src), mm, NULL((void *)0)) != 0) {
1059 sorwakeup(s);
1060 return (0);
1061 }
1062 }
1063 m_freem(mm);
1064 return (-1);
1065}
1066
1067/*
1068 * IP multicast forwarding function. This function assumes that the packet
1069 * pointed to by "ip" has arrived on (or is about to be sent to) the interface
1070 * pointed to by "ifp", and the packet is to be relayed to other networks
1071 * that have members of the packet's destination IP multicast group.
1072 *
1073 * The packet is returned unscathed to the caller, unless it is
1074 * erroneous, in which case a non-zero return value tells the caller to
1075 * discard it.
1076 */
1077
1078#define IP_HDR_LEN20 20 /* # bytes of fixed IP header (excluding options) */
1079#define TUNNEL_LEN12 12 /* # bytes of IP option for tunnel encapsulation */
1080
1081int
1082ip_mforward(struct mbuf *m, struct ifnet *ifp)
1083{
1084 struct ip *ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
1085 struct vif *v;
1086 struct rtentry *rt;
1087 static int srctun = 0;
1088 struct mbuf *mm;
1089 unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain;
1090
1091 if (ip->ip_hl < (IP_HDR_LEN20 + TUNNEL_LEN12) >> 2 ||
1092 ((u_char *)(ip + 1))[1] != IPOPT_LSRR131) {
1093 /*
1094 * Packet arrived via a physical interface or
1095 * an encapsulated tunnel or a register_vif.
1096 */
1097 } else {
1098 /*
1099 * Packet arrived through a source-route tunnel.
1100 * Source-route tunnels are no longer supported.
1101 */
1102 if ((srctun++ % 1000) == 0)
1103 log(LOG_ERR3, "ip_mforward: received source-routed "
1104 "packet from %x\n", ntohl(ip->ip_src.s_addr)(__uint32_t)(__builtin_constant_p(ip->ip_src.s_addr) ? (__uint32_t
)(((__uint32_t)(ip->ip_src.s_addr) & 0xff) << 24
| ((__uint32_t)(ip->ip_src.s_addr) & 0xff00) <<
8 | ((__uint32_t)(ip->ip_src.s_addr) & 0xff0000) >>
8 | ((__uint32_t)(ip->ip_src.s_addr) & 0xff000000) >>
24) : __swap32md(ip->ip_src.s_addr))
);
1105 return (EOPNOTSUPP45);
1106 }
1107
1108 /*
1109 * Don't forward a packet with time-to-live of zero or one,
1110 * or a packet destined to a local-only group.
1111 */
1112 if (ip->ip_ttl <= 1 || IN_LOCAL_GROUP(ip->ip_dst.s_addr)(((u_int32_t)(ip->ip_dst.s_addr) & ((u_int32_t) (__uint32_t
)(__builtin_constant_p((u_int32_t)(0xffffff00)) ? (__uint32_t
)(((__uint32_t)((u_int32_t)(0xffffff00)) & 0xff) <<
24 | ((__uint32_t)((u_int32_t)(0xffffff00)) & 0xff00) <<
8 | ((__uint32_t)((u_int32_t)(0xffffff00)) & 0xff0000) >>
8 | ((__uint32_t)((u_int32_t)(0xffffff00)) & 0xff000000)
>> 24) : __swap32md((u_int32_t)(0xffffff00))))) == ((u_int32_t
) (__uint32_t)(__builtin_constant_p((u_int32_t)(0xe0000000)) ?
(__uint32_t)(((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff
) << 24 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff00
) << 8 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff0000
) >> 8 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff000000
) >> 24) : __swap32md((u_int32_t)(0xe0000000)))))
)
1113 return (0);
1114
1115 /*
1116 * Determine forwarding vifs from the forwarding cache table
1117 */
1118 ++mrtstat.mrts_mfc_lookups;
1119 rt = mfc_find(NULL((void *)0), &ip->ip_src, &ip->ip_dst, rtableid);
1120
1121 /* Entry exists, so forward if necessary */
1122 if (rt != NULL((void *)0)) {
1123 return (ip_mdq(m, ifp, rt));
1124 } else {
1125 /*
1126 * If we don't have a route for packet's origin,
1127 * Make a copy of the packet & send message to routing daemon
1128 */
1129 int hlen = ip->ip_hl << 2;
1130
1131 ++mrtstat.mrts_mfc_misses;
1132 mrtstat.mrts_no_route++;
1133
1134 {
1135 struct igmpmsg *im;
1136
1137 /*
1138 * Locate the vifi for the incoming interface for
1139 * this packet.
1140 * If none found, drop packet.
1141 */
1142 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0))
1143 return (EHOSTUNREACH65);
1144 /*
1145 * Make a copy of the header to send to the user level
1146 * process
1147 */
1148 mm = m_copym(m, 0, hlen, M_NOWAIT0x0002);
1149 if (mm == NULL((void *)0) ||
1150 (mm = m_pullup(mm, hlen)) == NULL((void *)0))
1151 return (ENOBUFS55);
1152
1153 /*
1154 * Send message to routing daemon to install
1155 * a route into the kernel table
1156 */
1157
1158 im = mtod(mm, struct igmpmsg *)((struct igmpmsg *)((mm)->m_hdr.mh_data));
1159 im->im_msgtype = IGMPMSG_NOCACHE1;
1160 im->im_mbz = 0;
1161 im->im_vif = v->v_id;
1162
1163 mrtstat.mrts_upcalls++;
1164
1165 sin.sin_addr = ip->ip_src;
1166 if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) {
1167 log(LOG_WARNING4, "ip_mforward: ip_mrouter "
1168 "socket queue full\n");
1169 ++mrtstat.mrts_upq_sockfull;
1170 return (ENOBUFS55);
1171 }
1172
1173 mfc_add(NULL((void *)0), &ip->ip_src, &ip->ip_dst, v->v_id,
1174 rtableid, M_NOWAIT0x0002);
1175 }
1176
1177 return (0);
1178 }
1179}
1180
1181/*
1182 * Packet forwarding routine once entry in the cache is made
1183 */
1184int
1185ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt)
1186{
1187 struct ip *ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
1188 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
1189 struct vif *v = (struct vif *)ifp0->if_mcast;
1190 struct ifnet *ifp;
1191 struct mbuf *mc;
1192 struct ip_moptions imo;
1193
1194 /* Sanity check: we have all promised pointers. */
1195 if (v == NULL((void *)0) || mfc == NULL((void *)0)) {
1196 rtfree(rt);
1197 return (EHOSTUNREACH65);
1198 }
1199
1200 /*
1201 * Don't forward if it didn't arrive from the parent vif for its origin.
1202 */
1203 if (mfc->mfc_parent != v->v_id) {
1204 /* came in the wrong interface */
1205 ++mrtstat.mrts_wrong_if;
1206 mfc->mfc_wrong_if++;
1207 rtfree(rt);
1208 return (0);
1209 }
1210
1211 /* If I sourced this packet, it counts as output, else it was input. */
1212 if (in_hosteq(ip->ip_src, v->v_lcl_addr)((ip->ip_src).s_addr == (v->v_lcl_addr).s_addr)) {
1213 v->v_pkt_out++;
1214 v->v_bytes_out += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1215 } else {
1216 v->v_pkt_in++;
1217 v->v_bytes_in += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1218 }
1219
1220 /*
1221 * For each vif, decide if a copy of the packet should be forwarded.
1222 * Forward if:
1223 * - the ttl exceeds the vif's threshold
1224 * - there are group members downstream on interface
1225 */
1226 do {
1227 /* Don't consider non multicast routes. */
1228 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
1229 (RTF_HOST0x4 | RTF_MULTICAST0x200))
1230 continue;
1231
1232 mfc = (struct mfc *)rt->rt_llinfo;
1233 if (mfc == NULL((void *)0))
1234 continue;
1235
1236 mfc->mfc_pkt_cnt++;
1237 mfc->mfc_byte_cnt += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1238
1239 /* Don't let this route expire. */
1240 mfc->mfc_expire = 0;
1241
1242 if (ip->ip_ttl <= mfc->mfc_ttl)
1243 continue;
1244 if ((ifp = if_get(rt->rt_ifidx)) == NULL((void *)0))
1245 continue;
1246
1247 /* Sanity check: did we configure this? */
1248 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0)) {
1249 if_put(ifp);
1250 continue;
1251 }
1252
1253 /* Don't send in the upstream interface. */
1254 if (mfc->mfc_parent == v->v_id) {
1255 if_put(ifp);
1256 continue;
1257 }
1258
1259 v->v_pkt_out++;
1260 v->v_bytes_out += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1261
1262 /*
1263 * Make a new reference to the packet; make sure
1264 * that the IP header is actually copied, not
1265 * just referenced, so that ip_output() only
1266 * scribbles on the copy.
1267 */
1268 mc = m_dup_pkt(m, max_linkhdr, M_NOWAIT0x0002);
1269 if (mc == NULL((void *)0)) {
1270 if_put(ifp);
1271 rtfree(rt);
1272 return (ENOBUFS55);
1273 }
1274
1275 /*
1276 * if physical interface option, extract the options
1277 * and then send
1278 */
1279 imo.imo_ifidx = rt->rt_ifidx;
1280 imo.imo_ttl = ip->ip_ttl - IPTTLDEC1;
1281 imo.imo_loop = 1;
1282
1283 ip_output(mc, NULL((void *)0), NULL((void *)0), IP_FORWARDING0x1, &imo, NULL((void *)0), 0);
1284 if_put(ifp);
1285 } while ((rt = rtable_iterate(rt)) != NULL((void *)0));
1286
1287 return (0);
1288}
1289
1290struct ifnet *
1291if_lookupbyvif(vifi_t vifi, unsigned int rtableid)
1292{
1293 struct vif *v;
1294 struct ifnet *ifp;
1295
1296 TAILQ_FOREACH(ifp, &ifnet, if_list)for((ifp) = ((&ifnet)->tqh_first); (ifp) != ((void *)0
); (ifp) = ((ifp)->if_list.tqe_next))
{
1297 if (ifp->if_rdomainif_data.ifi_rdomain != rtableid)
1298 continue;
1299 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0))
1300 continue;
1301 if (v->v_id != vifi)
1302 continue;
1303
1304 return (ifp);
1305 }
1306
1307 return (NULL((void *)0));
1308}
1309
1310struct rtentry *
1311rt_mcast_add(struct ifnet *ifp, struct sockaddr *origin, struct sockaddr *group)
1312{
1313 struct ifaddr *ifa;
1314 int rv;
1315 unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain;
1316
1317 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)for((ifa) = ((&ifp->if_addrlist)->tqh_first); (ifa)
!= ((void *)0); (ifa) = ((ifa)->ifa_list.tqe_next))
{
1318 if (ifa->ifa_addr->sa_family == AF_INET2)
1319 break;
1320 }
1321 if (ifa == NULL((void *)0)) {
1322 DPRINTF("ifa == NULL")do { } while (0);
1323 return (NULL((void *)0));
1324 }
1325
1326 rv = rt_ifa_add(ifa, RTF_HOST0x4 | RTF_MULTICAST0x200 | RTF_MPATH0x40000,
1327 group, ifp->if_rdomainif_data.ifi_rdomain);
1328 if (rv != 0) {
1329 DPRINTF("rt_ifa_add failed (%d)", rv)do { } while (0);
1330 return (NULL((void *)0));
1331 }
1332
1333 mrt_count[rtableid]++;
1334
1335 return (mfc_find(ifp, NULL((void *)0), &satosin(group)->sin_addr, rtableid));
1336}
1337
1338void
1339mrt_mcast_del(struct rtentry *rt, unsigned int rtableid)
1340{
1341 struct ifnet *ifp;
1342 int error;
1343
1344 /* Remove all timers related to this route. */
1345 rt_timer_remove_all(rt);
1346
1347 free(rt->rt_llinfo, M_MRTABLE56, sizeof(struct mfc));
1348 rt->rt_llinfo = NULL((void *)0);
1349
1350 ifp = if_get(rt->rt_ifidx);
1351 if (ifp == NULL((void *)0))
1352 return;
1353 error = rtdeletemsg(rt, ifp, rtableid);
1354 if_put(ifp);
1355
1356 if (error)
1357 DPRINTF("delete route error %d\n", error)do { } while (0);
1358
1359 mrt_count[rtableid]--;
1360}