Bug Summary

File:netinet/ip_mroute.c
Warning:line 960, 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.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ip_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/netinet/ip_mroute.c
1/* $OpenBSD: ip_mroute.c,v 1.140 2023/12/06 09:27:17 bluhm 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 ip_mrouterq;
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);
116int mfc_add(struct mfcctl2 *, struct in_addr *, struct in_addr *,
117 int, unsigned int, int);
118int add_mfc(struct socket *, struct mbuf *);
119int del_mfc(struct socket *, struct mbuf *);
120int set_api_config(struct socket *, struct mbuf *); /* chose API capabilities */
121int get_api_support(struct mbuf *);
122int get_api_config(struct mbuf *);
123int socket_send(struct socket *, struct mbuf *,
124 struct sockaddr_in *);
125int ip_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
126struct ifnet *if_lookupbyvif(vifi_t, unsigned int);
127struct rtentry *rt_mcast_add(struct ifnet *, struct sockaddr *,
128 struct sockaddr *);
129void mrt_mcast_del(struct rtentry *, unsigned int);
130
131/*
132 * Kernel multicast routing API capabilities and setup.
133 * If more API capabilities are added to the kernel, they should be
134 * recorded in `mrt_api_support'.
135 */
136static const u_int32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF(1 << 0) |
137 MRT_MFC_RP(1 << 8));
138static u_int32_t mrt_api_config = 0;
139
140/*
141 * Find a route for a given origin IP address and Multicast group address
142 * Type of service parameter to be added in the future!!!
143 * Statistics are updated by the caller if needed
144 * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses)
145 */
146struct rtentry *
147mfc_find(struct ifnet *ifp, struct in_addr *origin, struct in_addr *group,
148 unsigned int rtableid)
149{
150 struct rtentry *rt;
151 struct sockaddr_in msin;
152
153 memset(&msin, 0, sizeof(msin))__builtin_memset((&msin), (0), (sizeof(msin)));
154 msin.sin_len = sizeof(msin);
155 msin.sin_family = AF_INET2;
156 msin.sin_addr = *group;
157
158 rt = rtalloc(sintosa(&msin), 0, rtableid);
159 do {
160 if (!rtisvalid(rt)) {
161 rtfree(rt);
162 return NULL((void *)0);
163 }
164 /* Don't consider non multicast routes. */
165 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
166 (RTF_HOST0x4 | RTF_MULTICAST0x200))
167 continue;
168 /* Return first occurrence if interface is not specified. */
169 if (ifp == NULL((void *)0))
170 return (rt);
171 if (rt->rt_ifidx == ifp->if_index)
172 return (rt);
173 } while ((rt = rtable_iterate(rt)) != NULL((void *)0));
174
175 return (NULL((void *)0));
176}
177
178/*
179 * Handle MRT setsockopt commands to modify the multicast routing tables.
180 */
181int
182ip_mrouter_set(struct socket *so, int optname, struct mbuf *m)
183{
184 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
185 int error;
186
187 if (optname != MRT_INIT100 &&
188 so != ip_mrouter[inp->inp_rtableid])
189 error = ENOPROTOOPT42;
190 else
191 switch (optname) {
192 case MRT_INIT100:
193 error = ip_mrouter_init(so, m);
194 break;
195 case MRT_DONE101:
196 error = ip_mrouter_done(so);
197 break;
198 case MRT_ADD_VIF102:
199 error = add_vif(so, m);
200 break;
201 case MRT_DEL_VIF103:
202 error = del_vif(so, m);
203 break;
204 case MRT_ADD_MFC104:
205 error = add_mfc(so, m);
206 break;
207 case MRT_DEL_MFC105:
208 error = del_mfc(so, m);
209 break;
210 case MRT_API_CONFIG110:
211 error = set_api_config(so, m);
212 break;
213 default:
214 error = ENOPROTOOPT42;
215 break;
216 }
217
218 return (error);
219}
220
221/*
222 * Handle MRT getsockopt commands
223 */
224int
225ip_mrouter_get(struct socket *so, int optname, struct mbuf *m)
226{
227 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
228 int error;
229
230 if (so != ip_mrouter[inp->inp_rtableid])
231 error = ENOPROTOOPT42;
232 else {
233 switch (optname) {
234 case MRT_VERSION106:
235 error = get_version(m);
236 break;
237 case MRT_API_SUPPORT109:
238 error = get_api_support(m);
239 break;
240 case MRT_API_CONFIG110:
241 error = get_api_config(m);
242 break;
243 default:
244 error = ENOPROTOOPT42;
245 break;
246 }
247 }
248
249 return (error);
250}
251
252/*
253 * Handle ioctl commands to obtain information from the cache
254 */
255int
256mrt_ioctl(struct socket *so, u_long cmd, caddr_t data)
257{
258 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
259 int error;
260
261 if (inp == NULL((void *)0))
262 return (ENOTCONN57);
263
264 KERNEL_LOCK()_kernel_lock();
265
266 if (so != ip_mrouter[inp->inp_rtableid])
267 error = EINVAL22;
268 else
269 switch (cmd) {
270 case SIOCGETVIFCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct sioc_vif_req) & 0x1fff) << 16) | ((('u')) <<
8) | ((51)))
:
271 NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0);
272 error = get_vif_cnt(inp->inp_rtableid,
273 (struct sioc_vif_req *)data);
274 NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0);
275 break;
276 case SIOCGETSGCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct sioc_sg_req) & 0x1fff) << 16) | ((('u')) <<
8) | ((52)))
:
277 NET_LOCK_SHARED()do { rw_enter_read(&netlock); } while (0);
278 error = get_sg_cnt(inp->inp_rtableid,
279 (struct sioc_sg_req *)data);
280 NET_UNLOCK_SHARED()do { rw_exit_read(&netlock); } while (0);
281 break;
282 default:
283 error = ENOTTY25;
284 break;
285 }
286
287 KERNEL_UNLOCK()_kernel_unlock();
288 return (error);
289}
290
291/*
292 * returns the packet, byte, rpf-failure count for the source group provided
293 */
294int
295get_sg_cnt(unsigned int rtableid, struct sioc_sg_req *req)
296{
297 struct rtentry *rt;
298 struct mfc *mfc;
299
300 rt = mfc_find(NULL((void *)0), &req->src, &req->grp, rtableid);
301 if (rt == NULL((void *)0)) {
302 req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
303 return (EADDRNOTAVAIL49);
304 }
305
306 req->pktcnt = req->bytecnt = req->wrong_if = 0;
307 do {
308 /* Don't consider non multicast routes. */
309 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
310 (RTF_HOST0x4 | RTF_MULTICAST0x200))
311 continue;
312
313 mfc = (struct mfc *)rt->rt_llinfo;
314 if (mfc == NULL((void *)0))
315 continue;
316
317 req->pktcnt += mfc->mfc_pkt_cnt;
318 req->bytecnt += mfc->mfc_byte_cnt;
319 req->wrong_if += mfc->mfc_wrong_if;
320 } while ((rt = rtable_iterate(rt)) != NULL((void *)0));
321
322 return (0);
323}
324
325/*
326 * returns the input and output packet and byte counts on the vif provided
327 */
328int
329get_vif_cnt(unsigned int rtableid, struct sioc_vif_req *req)
330{
331 struct ifnet *ifp;
332 struct vif *v;
333 vifi_t vifi = req->vifi;
334
335 if ((ifp = if_lookupbyvif(vifi, rtableid)) == NULL((void *)0))
336 return (EINVAL22);
337
338 v = (struct vif *)ifp->if_mcast;
339 req->icount = v->v_pkt_in;
340 req->ocount = v->v_pkt_out;
341 req->ibytes = v->v_bytes_in;
342 req->obytes = v->v_bytes_out;
343
344 return (0);
345}
346
347int
348mrt_sysctl_vif(void *oldp, size_t *oldlenp)
349{
350 caddr_t where = oldp;
351 size_t needed, given;
352 struct ifnet *ifp;
353 struct vif *vifp;
354 struct vifinfo vinfo;
355
356 given = *oldlenp;
357 needed = 0;
358 memset(&vinfo, 0, sizeof vinfo)__builtin_memset((&vinfo), (0), (sizeof vinfo));
359 TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void
*)0); (ifp) = ((ifp)->if_list.tqe_next))
{
360 if ((vifp = (struct vif *)ifp->if_mcast) == NULL((void *)0))
361 continue;
362
363 vinfo.v_vifi = vifp->v_id;
364 vinfo.v_flags = vifp->v_flags;
365 vinfo.v_threshold = vifp->v_threshold;
366 vinfo.v_lcl_addr = vifp->v_lcl_addr;
367 vinfo.v_rmt_addr = vifp->v_rmt_addr;
368 vinfo.v_pkt_in = vifp->v_pkt_in;
369 vinfo.v_pkt_out = vifp->v_pkt_out;
370 vinfo.v_bytes_in = vifp->v_bytes_in;
371 vinfo.v_bytes_out = vifp->v_bytes_out;
372
373 needed += sizeof(vinfo);
374 if (where && needed <= given) {
375 int error;
376
377 error = copyout(&vinfo, where, sizeof(vinfo));
378 if (error)
379 return (error);
380 where += sizeof(vinfo);
381 }
382 }
383 if (where) {
384 *oldlenp = needed;
385 if (given < needed)
386 return (ENOMEM12);
387 } else
388 *oldlenp = (11 * needed) / 10;
389
390 return (0);
391}
392
393struct mfcsysctlarg {
394 struct mfcinfo *msa_minfos;
395 size_t msa_len;
396 size_t msa_needed;
397};
398
399int
400mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
401{
402 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
403 struct mfcsysctlarg *msa = (struct mfcsysctlarg *)arg;
404 struct ifnet *ifp;
405 struct vif *v;
406 struct mfcinfo *minfo;
407 int new = 0;
408
409 /* Skip entries being removed. */
410 if (mfc == NULL((void *)0))
411 return (0);
412
413 /* Skip non-multicast routes. */
414 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
415 (RTF_HOST0x4 | RTF_MULTICAST0x200))
416 return (0);
417
418 /* User just asked for the output size. */
419 if (msa->msa_minfos == NULL((void *)0)) {
420 msa->msa_needed += sizeof(*minfo);
421 return (0);
422 }
423
424 /* Skip route with invalid interfaces. */
425 if ((ifp = if_get(rt->rt_ifidx)) == NULL((void *)0))
426 return (0);
427 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0)) {
428 if_put(ifp);
429 return (0);
430 }
431
432 for (minfo = msa->msa_minfos;
433 (uint8_t *)minfo < ((uint8_t *)msa->msa_minfos + msa->msa_len);
434 minfo++) {
435 /* Find a new entry or update old entry. */
436 if (minfo->mfc_origin.s_addr !=
437 satosin(rt->rt_gateway)->sin_addr.s_addr ||
438 minfo->mfc_mcastgrp.s_addr !=
439 satosin(rt_key(rt)((rt)->rt_dest))->sin_addr.s_addr) {
440 if (minfo->mfc_origin.s_addr != 0 ||
441 minfo->mfc_mcastgrp.s_addr != 0)
442 continue;
443
444 new = 1;
445 }
446
447 minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
448 minfo->mfc_mcastgrp = satosin(rt_key(rt)((rt)->rt_dest))->sin_addr;
449 minfo->mfc_parent = mfc->mfc_parent;
450 minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
451 minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
452 minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
453 break;
454 }
455
456 if (new != 0)
457 msa->msa_needed += sizeof(*minfo);
458
459 if_put(ifp);
460
461 return (0);
462}
463
464int
465mrt_sysctl_mfc(void *oldp, size_t *oldlenp)
466{
467 unsigned int rtableid;
468 int error;
469 struct mfcsysctlarg msa;
470
471 if (oldp != NULL((void *)0) && *oldlenp > MAXPHYS(64 * 1024))
472 return (EINVAL22);
473
474 if (oldp != NULL((void *)0))
475 msa.msa_minfos = malloc(*oldlenp, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
476 else
477 msa.msa_minfos = NULL((void *)0);
478
479 msa.msa_len = *oldlenp;
480 msa.msa_needed = 0;
481
482 for (rtableid = 0; rtableid <= RT_TABLEID_MAX255; rtableid++) {
483 rtable_walk(rtableid, AF_INET2, NULL((void *)0), mrt_rtwalk_mfcsysctl,
484 &msa);
485 }
486
487 if (msa.msa_minfos != NULL((void *)0) && msa.msa_needed > 0 &&
488 (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) {
489 free(msa.msa_minfos, M_TEMP127, *oldlenp);
490 return (error);
491 }
492
493 free(msa.msa_minfos, M_TEMP127, *oldlenp);
494 *oldlenp = msa.msa_needed;
495
496 return (0);
497}
498
499/*
500 * Enable multicast routing
501 */
502int
503ip_mrouter_init(struct socket *so, struct mbuf *m)
504{
505 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
506 unsigned int rtableid = inp->inp_rtableid;
507 int *v;
508
509 if (so->so_type != SOCK_RAW3 ||
510 so->so_proto->pr_protocol != IPPROTO_IGMP2)
511 return (EOPNOTSUPP45);
512
513 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(int))
514 return (EINVAL22);
515
516 v = mtod(m, int *)((int *)((m)->m_hdr.mh_data));
517 if (*v != 1)
518 return (EINVAL22);
519
520 if (ip_mrouter[rtableid] != NULL((void *)0))
521 return (EADDRINUSE48);
522
523 ip_mrouter[rtableid] = so;
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, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->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 ip_mrouter[rtableid] = NULL((void *)0);
576 mrt_count[rtableid] = 0;
577
578 return (0);
579}
580
581int
582get_version(struct mbuf *m)
583{
584 int *v = mtod(m, int *)((int *)((m)->m_hdr.mh_data));
585
586 *v = 0x0305; /* XXX !!!! */
587 m->m_lenm_hdr.mh_len = sizeof(int);
588 return (0);
589}
590
591/*
592 * Configure API capabilities
593 */
594int
595set_api_config(struct socket *so, struct mbuf *m)
596{
597 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
598 struct ifnet *ifp;
599 u_int32_t *apival;
600 unsigned int rtableid = inp->inp_rtableid;
601
602 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(u_int32_t))
603 return (EINVAL22);
604
605 apival = mtod(m, u_int32_t *)((u_int32_t *)((m)->m_hdr.mh_data));
606
607 /*
608 * We can set the API capabilities only if it is the first operation
609 * after MRT_INIT. I.e.:
610 * - there are no vifs installed
611 * - the MFC table is empty
612 */
613 TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void
*)0); (ifp) = ((ifp)->if_list.tqe_next))
{
614 if (ifp->if_rdomainif_data.ifi_rdomain != rtableid)
615 continue;
616 if (ifp->if_mcast == NULL((void *)0))
617 continue;
618
619 *apival = 0;
620 return (EPERM1);
621 }
622 if (mrt_count[rtableid] > 0) {
623 *apival = 0;
624 return (EPERM1);
625 }
626
627 mrt_api_config = *apival & mrt_api_support;
628 *apival = mrt_api_config;
629
630 return (0);
631}
632
633/*
634 * Get API capabilities
635 */
636int
637get_api_support(struct mbuf *m)
638{
639 u_int32_t *apival;
640
641 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(u_int32_t))
642 return (EINVAL22);
643
644 apival = mtod(m, u_int32_t *)((u_int32_t *)((m)->m_hdr.mh_data));
645
646 *apival = mrt_api_support;
647
648 return (0);
649}
650
651/*
652 * Get API configured capabilities
653 */
654int
655get_api_config(struct mbuf *m)
656{
657 u_int32_t *apival;
658
659 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(u_int32_t))
660 return (EINVAL22);
661
662 apival = mtod(m, u_int32_t *)((u_int32_t *)((m)->m_hdr.mh_data));
663
664 *apival = mrt_api_config;
665
666 return (0);
667}
668
669static struct sockaddr_in sin = { sizeof(sin), AF_INET2 };
670
671int
672add_vif(struct socket *so, struct mbuf *m)
673{
674 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
675 struct vifctl *vifcp;
676 struct vif *vifp;
677 struct ifaddr *ifa;
678 struct ifnet *ifp;
679 struct ifreq ifr;
680 int error;
681 unsigned int rtableid = inp->inp_rtableid;
682
683 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
684
685 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < sizeof(struct vifctl))
686 return (EINVAL22);
687
688 vifcp = mtod(m, struct vifctl *)((struct vifctl *)((m)->m_hdr.mh_data));
689 if (vifcp->vifc_vifi >= MAXVIFS32)
690 return (EINVAL22);
691 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)))))
)
692 return (EADDRNOTAVAIL49);
693 if (if_lookupbyvif(vifcp->vifc_vifi, rtableid) != NULL((void *)0))
694 return (EADDRINUSE48);
695
696 /* Tunnels are no longer supported use gif(4) instead. */
697 if (vifcp->vifc_flags & VIFF_TUNNEL0x1)
698 return (EOPNOTSUPP45);
699 {
700 sin.sin_addr = vifcp->vifc_lcl_addr;
701 ifa = ifa_ifwithaddr(sintosa(&sin), rtableid);
702 if (ifa == NULL((void *)0))
703 return (EADDRNOTAVAIL49);
704 }
705
706 /* Use the physical interface associated with the address. */
707 ifp = ifa->ifa_ifp;
708 if (ifp->if_mcast != NULL((void *)0))
709 return (EADDRINUSE48);
710
711 {
712 /* Make sure the interface supports multicast. */
713 if ((ifp->if_flags & IFF_MULTICAST0x8000) == 0)
714 return (EOPNOTSUPP45);
715
716 /* Enable promiscuous reception of all IP multicasts. */
717 memset(&ifr, 0, sizeof(ifr))__builtin_memset((&ifr), (0), (sizeof(ifr)));
718 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_len = sizeof(struct sockaddr_in);
719 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_family = AF_INET2;
720 satosin(&ifr.ifr_addrifr_ifru.ifru_addr)->sin_addr = zeroin_addr;
721 KERNEL_LOCK()_kernel_lock();
722 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((49)))
, (caddr_t)&ifr);
723 KERNEL_UNLOCK()_kernel_unlock();
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, u_int rtableid)
785{
786 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
787
788 /* Skip entry being deleted. */
789 if (mfc == NULL((void *)0))
790 return;
791
792 DPRINTF("Route domain %d origin %#08X group %#08x interface %d "do { } while (0)
793 "expire %s", rtableid, satosin(rt->rt_gateway)->sin_addr.s_addr,do { } while (0)
794 satosin(rt_key(rt))->sin_addr.s_addr,do { } while (0)
795 rt->rt_ifidx, mfc->mfc_expire ? "yes" : "no")do { } while (0);
796
797 /* Not expired, add it back to the queue. */
798 if (mfc->mfc_expire == 0) {
799 mfc->mfc_expire = 1;
800 rt_timer_add(rt, &ip_mrouterq, rtableid);
801 return;
802 }
803
804 mrt_mcast_del(rt, rtableid);
805}
806
807int
808mfc_add_route(struct ifnet *ifp, struct sockaddr *origin,
809 struct sockaddr *group, struct mfcctl2 *mfccp, int wait)
810{
811 struct vif *v = (struct vif *)ifp->if_mcast;
812 struct rtentry *rt;
813 struct mfc *mfc;
814 unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain;
815
816 rt = rt_mcast_add(ifp, origin, group);
817 if (rt == NULL((void *)0))
818 return (EHOSTUNREACH65);
819
820 mfc = malloc(sizeof(*mfc), M_MRTABLE56, wait | M_ZERO0x0008);
821 if (mfc == NULL((void *)0)) {
822 DPRINTF("origin %#08X group %#08X parent %d (%s) "do { } while (0)
823 "malloc failed",do { } while (0)
824 satosin(origin)->sin_addr.s_addr,do { } while (0)
825 satosin(group)->sin_addr.s_addr,do { } while (0)
826 mfccp->mfcc_parent, ifp->if_xname)do { } while (0);
827 mrt_mcast_del(rt, rtableid);
828 rtfree(rt);
829 return (ENOMEM12);
830 }
831
832 rt->rt_llinfo = (caddr_t)mfc;
833
834 rt_timer_add(rt, &ip_mrouterq, rtableid);
835
836 mfc->mfc_parent = mfccp->mfcc_parent;
837 mfc->mfc_pkt_cnt = 0;
838 mfc->mfc_byte_cnt = 0;
839 mfc->mfc_wrong_if = 0;
840 mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
841 mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
842 MRT_MFC_FLAGS_ALL((1 << 0));
843 mfc->mfc_expire = 0;
844
845 /* set the RP address */
846 if (mrt_api_config & MRT_MFC_RP(1 << 8))
847 mfc->mfc_rp = mfccp->mfcc_rp;
848 else
849 mfc->mfc_rp = zeroin_addr;
850
851 rtfree(rt);
852
853 return (0);
854}
855
856void
857update_mfc_params(struct mfcctl2 *mfccp, int wait, unsigned int rtableid)
858{
859 struct rtentry *rt;
860 struct mfc *mfc;
861 struct ifnet *ifp;
862 int i;
863 struct sockaddr_in osin, msin;
864
865 memset(&osin, 0, sizeof(osin))__builtin_memset((&osin), (0), (sizeof(osin)));
866 osin.sin_len = sizeof(osin);
867 osin.sin_family = AF_INET2;
868 osin.sin_addr = mfccp->mfcc_origin;
869
870 memset(&msin, 0, sizeof(msin))__builtin_memset((&msin), (0), (sizeof(msin)));
871 msin.sin_len = sizeof(msin);
872 msin.sin_family = AF_INET2;
873 msin.sin_addr = mfccp->mfcc_mcastgrp;
874
875 for (i = 0; i < MAXVIFS32; i++) {
876 /* Don't add/del upstream routes here. */
877 if (i == mfccp->mfcc_parent)
878 continue;
879
880 /* Test for vif existence and then update the entry. */
881 if ((ifp = if_lookupbyvif(i, rtableid)) == NULL((void *)0))
882 continue;
883
884 rt = mfc_find(ifp, &mfccp->mfcc_origin,
885 &mfccp->mfcc_mcastgrp, rtableid);
886
887 /* vif not configured or removed. */
888 if (mfccp->mfcc_ttls[i] == 0) {
889 /* Route doesn't exist, nothing to do. */
890 if (rt == NULL((void *)0))
891 continue;
892
893 DPRINTF("del route (group %#08X) for vif %d (%s)",do { } while (0)
894 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname)do { } while (0);
895 mrt_mcast_del(rt, rtableid);
896 rtfree(rt);
897 continue;
898 }
899
900 /* Route exists, look for changes. */
901 if (rt != NULL((void *)0)) {
902 mfc = (struct mfc *)rt->rt_llinfo;
903 /* Skip route being deleted. */
904 if (mfc == NULL((void *)0)) {
905 rtfree(rt);
906 continue;
907 }
908
909 /* No new changes to apply. */
910 if (mfccp->mfcc_ttls[i] == mfc->mfc_ttl &&
911 mfccp->mfcc_parent == mfc->mfc_parent) {
912 rtfree(rt);
913 continue;
914 }
915
916 DPRINTF("update route (group %#08X) for vif %d (%s)",do { } while (0)
917 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname)do { } while (0);
918 mfc->mfc_ttl = mfccp->mfcc_ttls[i];
919 mfc->mfc_parent = mfccp->mfcc_parent;
920 rtfree(rt);
921 continue;
922 }
923
924 DPRINTF("add route (group %#08X) for vif %d (%s)",do { } while (0)
925 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname)do { } while (0);
926
927 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin),
928 mfccp, wait);
929 }
930
931 /* Create route for the parent interface. */
932 if ((ifp = if_lookupbyvif(mfccp->mfcc_parent, rtableid)) == NULL((void *)0)) {
933 DPRINTF("failed to find upstream interface %d",do { } while (0)
934 mfccp->mfcc_parent)do { } while (0);
935 return;
936 }
937
938 /* We already have a route, nothing to do here. */
939 if ((rt = mfc_find(ifp, &mfccp->mfcc_origin,
940 &mfccp->mfcc_mcastgrp, rtableid)) != NULL((void *)0)) {
941 rtfree(rt);
942 return;
943 }
944
945 DPRINTF("add upstream route (group %#08X) for if %s",do { } while (0)
946 mfccp->mfcc_mcastgrp.s_addr, ifp->if_xname)do { } while (0);
947 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin), mfccp, wait);
948}
949
950int
951mfc_add(struct mfcctl2 *mfcctl2, struct in_addr *origin,
952 struct in_addr *group, int vidx, unsigned int rtableid, int wait)
953{
954 struct ifnet *ifp;
955 struct vif *v;
956 struct mfcctl2 mfcctl;
957
958 ifp = if_lookupbyvif(vidx, rtableid);
959 if (ifp == NULL((void *)0) ||
960 (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'
961 return (EHOSTUNREACH65);
962
963 memset(&mfcctl, 0, sizeof(mfcctl))__builtin_memset((&mfcctl), (0), (sizeof(mfcctl)));
964 if (mfcctl2 == NULL((void *)0)) {
965 mfcctl.mfcc_origin = *origin;
966 mfcctl.mfcc_mcastgrp = *group;
967 mfcctl.mfcc_parent = vidx;
968 } else
969 memcpy(&mfcctl, mfcctl2, sizeof(mfcctl))__builtin_memcpy((&mfcctl), (mfcctl2), (sizeof(mfcctl)));
970
971 update_mfc_params(&mfcctl, wait, rtableid);
972
973 return (0);
974}
975
976int
977add_mfc(struct socket *so, struct mbuf *m)
978{
979 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
980 struct mfcctl2 mfcctl2;
981 int mfcctl_size = sizeof(struct mfcctl);
982 unsigned int rtableid = inp->inp_rtableid;
983
984 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
985
986 if (mrt_api_config & MRT_API_FLAGS_ALL(((1 << 0)) | (1 << 8) | (1 << 9)))
987 mfcctl_size = sizeof(struct mfcctl2);
988
989 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < mfcctl_size)
990 return (EINVAL22);
991
992 /*
993 * select data size depending on API version.
994 */
995 if (mrt_api_config & MRT_API_FLAGS_ALL(((1 << 0)) | (1 << 8) | (1 << 9))) {
996 struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *)((struct mfcctl2 *)((m)->m_hdr.mh_data));
997 memcpy((caddr_t)&mfcctl2, mp2, sizeof(*mp2))__builtin_memcpy(((caddr_t)&mfcctl2), (mp2), (sizeof(*mp2
)))
;
998 } else {
999 struct mfcctl *mp = mtod(m, struct mfcctl *)((struct mfcctl *)((m)->m_hdr.mh_data));
1000 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp))__builtin_memcpy(((caddr_t)&mfcctl2), (mp), (sizeof(*mp))
)
;
1001 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,__builtin_memset(((caddr_t)&mfcctl2 + sizeof(struct mfcctl
)), (0), (sizeof(mfcctl2) - sizeof(struct mfcctl)))
1002 sizeof(mfcctl2) - sizeof(struct mfcctl))__builtin_memset(((caddr_t)&mfcctl2 + sizeof(struct mfcctl
)), (0), (sizeof(mfcctl2) - sizeof(struct mfcctl)))
;
1003 }
1004
1005 if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
1006 mfcctl2.mfcc_parent, rtableid, M_WAITOK0x0001) == -1)
1007 return (EINVAL22);
1008
1009 return (0);
1010}
1011
1012int
1013del_mfc(struct socket *so, struct mbuf *m)
1014{
1015 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
1016 struct rtentry *rt;
1017 struct mfcctl2 mfcctl2;
1018 int mfcctl_size = sizeof(struct mfcctl);
1019 struct mfcctl *mp;
1020 unsigned int rtableid = inp->inp_rtableid;
1021
1022 NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl >
0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail
(0x0002UL, _s, __func__); } while (0)
;
1023
1024 /*
1025 * XXX: for deleting MFC entries the information in entries
1026 * of size "struct mfcctl" is sufficient.
1027 */
1028
1029 if (m == NULL((void *)0) || m->m_lenm_hdr.mh_len < mfcctl_size)
1030 return (EINVAL22);
1031
1032 mp = mtod(m, struct mfcctl *)((struct mfcctl *)((m)->m_hdr.mh_data));
1033
1034 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp))__builtin_memcpy(((caddr_t)&mfcctl2), (mp), (sizeof(*mp))
)
;
1035 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,__builtin_memset(((caddr_t)&mfcctl2 + sizeof(struct mfcctl
)), (0), (sizeof(mfcctl2) - sizeof(struct mfcctl)))
1036 sizeof(mfcctl2) - sizeof(struct mfcctl))__builtin_memset(((caddr_t)&mfcctl2 + sizeof(struct mfcctl
)), (0), (sizeof(mfcctl2) - sizeof(struct mfcctl)))
;
1037
1038 DPRINTF("origin %#08X group %#08X rtableid %d",do { } while (0)
1039 mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid)do { } while (0);
1040
1041 while ((rt = mfc_find(NULL((void *)0), &mfcctl2.mfcc_origin,
1042 &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL((void *)0)) {
1043 mrt_mcast_del(rt, rtableid);
1044 rtfree(rt);
1045 }
1046
1047 return (0);
1048}
1049
1050int
1051socket_send(struct socket *so, struct mbuf *mm, struct sockaddr_in *src)
1052{
1053 if (so != NULL((void *)0)) {
1054 struct inpcb *inp = sotoinpcb(so)((struct inpcb *)(so)->so_pcb);
1055 int ret;
1056
1057 mtx_enter(&inp->inp_mtx);
1058 ret = sbappendaddr(so, &so->so_rcv, sintosa(src), mm, NULL((void *)0));
1059 mtx_leave(&inp->inp_mtx);
1060
1061 if (ret != 0) {
1062 sorwakeup(so);
1063 return (0);
1064 }
1065 }
1066 m_freem(mm);
1067 return (-1);
1068}
1069
1070/*
1071 * IP multicast forwarding function. This function assumes that the packet
1072 * pointed to by "ip" has arrived on (or is about to be sent to) the interface
1073 * pointed to by "ifp", and the packet is to be relayed to other networks
1074 * that have members of the packet's destination IP multicast group.
1075 *
1076 * The packet is returned unscathed to the caller, unless it is
1077 * erroneous, in which case a non-zero return value tells the caller to
1078 * discard it.
1079 */
1080
1081#define IP_HDR_LEN20 20 /* # bytes of fixed IP header (excluding options) */
1082#define TUNNEL_LEN12 12 /* # bytes of IP option for tunnel encapsulation */
1083
1084int
1085ip_mforward(struct mbuf *m, struct ifnet *ifp)
1086{
1087 struct ip *ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
1088 struct vif *v;
1089 struct rtentry *rt;
1090 static int srctun = 0;
1091 struct mbuf *mm;
1092 unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain;
1093
1094 if (ip->ip_hl < (IP_HDR_LEN20 + TUNNEL_LEN12) >> 2 ||
1095 ((u_char *)(ip + 1))[1] != IPOPT_LSRR131) {
1096 /*
1097 * Packet arrived via a physical interface or
1098 * an encapsulated tunnel or a register_vif.
1099 */
1100 } else {
1101 /*
1102 * Packet arrived through a source-route tunnel.
1103 * Source-route tunnels are no longer supported.
1104 */
1105 if ((srctun++ % 1000) == 0)
1106 log(LOG_ERR3, "ip_mforward: received source-routed "
1107 "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))
);
1108 return (EOPNOTSUPP45);
1109 }
1110
1111 /*
1112 * Don't forward a packet with time-to-live of zero or one,
1113 * or a packet destined to a local-only group.
1114 */
1115 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)))))
)
1116 return (0);
1117
1118 /*
1119 * Determine forwarding vifs from the forwarding cache table
1120 */
1121 ++mrtstat.mrts_mfc_lookups;
1122 rt = mfc_find(NULL((void *)0), &ip->ip_src, &ip->ip_dst, rtableid);
1123
1124 /* Entry exists, so forward if necessary */
1125 if (rt != NULL((void *)0)) {
1126 return (ip_mdq(m, ifp, rt));
1127 } else {
1128 /*
1129 * If we don't have a route for packet's origin,
1130 * Make a copy of the packet & send message to routing daemon
1131 */
1132 int hlen = ip->ip_hl << 2;
1133
1134 ++mrtstat.mrts_mfc_misses;
1135 mrtstat.mrts_no_route++;
1136
1137 {
1138 struct igmpmsg *im;
1139
1140 /*
1141 * Locate the vifi for the incoming interface for
1142 * this packet.
1143 * If none found, drop packet.
1144 */
1145 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0))
1146 return (EHOSTUNREACH65);
1147 /*
1148 * Make a copy of the header to send to the user level
1149 * process
1150 */
1151 mm = m_copym(m, 0, hlen, M_NOWAIT0x0002);
1152 if (mm == NULL((void *)0) ||
1153 (mm = m_pullup(mm, hlen)) == NULL((void *)0))
1154 return (ENOBUFS55);
1155
1156 /*
1157 * Send message to routing daemon to install
1158 * a route into the kernel table
1159 */
1160
1161 im = mtod(mm, struct igmpmsg *)((struct igmpmsg *)((mm)->m_hdr.mh_data));
1162 im->im_msgtype = IGMPMSG_NOCACHE1;
1163 im->im_mbz = 0;
1164 im->im_vif = v->v_id;
1165
1166 mrtstat.mrts_upcalls++;
1167
1168 sin.sin_addr = ip->ip_src;
1169 if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) {
1170 log(LOG_WARNING4, "ip_mforward: ip_mrouter "
1171 "socket queue full\n");
1172 ++mrtstat.mrts_upq_sockfull;
1173 return (ENOBUFS55);
1174 }
1175
1176 mfc_add(NULL((void *)0), &ip->ip_src, &ip->ip_dst, v->v_id,
1177 rtableid, M_NOWAIT0x0002);
1178 }
1179
1180 return (0);
1181 }
1182}
1183
1184/*
1185 * Packet forwarding routine once entry in the cache is made
1186 */
1187int
1188ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt)
1189{
1190 struct ip *ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data));
1191 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
1192 struct vif *v = (struct vif *)ifp0->if_mcast;
1193 struct ifnet *ifp;
1194 struct mbuf *mc;
1195 struct ip_moptions imo;
1196
1197 /* Sanity check: we have all promised pointers. */
1198 if (v == NULL((void *)0) || mfc == NULL((void *)0)) {
1199 rtfree(rt);
1200 return (EHOSTUNREACH65);
1201 }
1202
1203 /*
1204 * Don't forward if it didn't arrive from the parent vif for its origin.
1205 */
1206 if (mfc->mfc_parent != v->v_id) {
1207 /* came in the wrong interface */
1208 ++mrtstat.mrts_wrong_if;
1209 mfc->mfc_wrong_if++;
1210 rtfree(rt);
1211 return (0);
1212 }
1213
1214 /* If I sourced this packet, it counts as output, else it was input. */
1215 if (in_hosteq(ip->ip_src, v->v_lcl_addr)((ip->ip_src).s_addr == (v->v_lcl_addr).s_addr)) {
1216 v->v_pkt_out++;
1217 v->v_bytes_out += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1218 } else {
1219 v->v_pkt_in++;
1220 v->v_bytes_in += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1221 }
1222
1223 /*
1224 * For each vif, decide if a copy of the packet should be forwarded.
1225 * Forward if:
1226 * - the ttl exceeds the vif's threshold
1227 * - there are group members downstream on interface
1228 */
1229 do {
1230 /* Don't consider non multicast routes. */
1231 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST)((rt->rt_flags) & (0x4 | 0x200)) !=
1232 (RTF_HOST0x4 | RTF_MULTICAST0x200))
1233 continue;
1234
1235 mfc = (struct mfc *)rt->rt_llinfo;
1236 if (mfc == NULL((void *)0))
1237 continue;
1238
1239 mfc->mfc_pkt_cnt++;
1240 mfc->mfc_byte_cnt += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1241
1242 /* Don't let this route expire. */
1243 mfc->mfc_expire = 0;
1244
1245 if (ip->ip_ttl <= mfc->mfc_ttl)
1246 continue;
1247 if ((ifp = if_get(rt->rt_ifidx)) == NULL((void *)0))
1248 continue;
1249
1250 /* Sanity check: did we configure this? */
1251 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0)) {
1252 if_put(ifp);
1253 continue;
1254 }
1255
1256 /* Don't send in the upstream interface. */
1257 if (mfc->mfc_parent == v->v_id) {
1258 if_put(ifp);
1259 continue;
1260 }
1261
1262 v->v_pkt_out++;
1263 v->v_bytes_out += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1264
1265 /*
1266 * Make a new reference to the packet; make sure
1267 * that the IP header is actually copied, not
1268 * just referenced, so that ip_output() only
1269 * scribbles on the copy.
1270 */
1271 mc = m_dup_pkt(m, max_linkhdr, M_NOWAIT0x0002);
1272 if (mc == NULL((void *)0)) {
1273 if_put(ifp);
1274 rtfree(rt);
1275 return (ENOBUFS55);
1276 }
1277
1278 /*
1279 * if physical interface option, extract the options
1280 * and then send
1281 */
1282 imo.imo_ifidx = rt->rt_ifidx;
1283 imo.imo_ttl = ip->ip_ttl - IPTTLDEC1;
1284 imo.imo_loop = 1;
1285
1286 ip_output(mc, NULL((void *)0), NULL((void *)0), IP_FORWARDING0x1, &imo, NULL((void *)0), 0);
1287 if_put(ifp);
1288 } while ((rt = rtable_iterate(rt)) != NULL((void *)0));
1289
1290 return (0);
1291}
1292
1293struct ifnet *
1294if_lookupbyvif(vifi_t vifi, unsigned int rtableid)
1295{
1296 struct vif *v;
1297 struct ifnet *ifp;
1298
1299 TAILQ_FOREACH(ifp, &ifnetlist, if_list)for((ifp) = ((&ifnetlist)->tqh_first); (ifp) != ((void
*)0); (ifp) = ((ifp)->if_list.tqe_next))
{
1300 if (ifp->if_rdomainif_data.ifi_rdomain != rtableid)
1301 continue;
1302 if ((v = (struct vif *)ifp->if_mcast) == NULL((void *)0))
1303 continue;
1304 if (v->v_id != vifi)
1305 continue;
1306
1307 return (ifp);
1308 }
1309
1310 return (NULL((void *)0));
1311}
1312
1313struct rtentry *
1314rt_mcast_add(struct ifnet *ifp, struct sockaddr *origin, struct sockaddr *group)
1315{
1316 struct ifaddr *ifa;
1317 int rv;
1318 unsigned int rtableid = ifp->if_rdomainif_data.ifi_rdomain;
1319
1320 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)for((ifa) = ((&ifp->if_addrlist)->tqh_first); (ifa)
!= ((void *)0); (ifa) = ((ifa)->ifa_list.tqe_next))
{
1321 if (ifa->ifa_addr->sa_family == AF_INET2)
1322 break;
1323 }
1324 if (ifa == NULL((void *)0)) {
1325 DPRINTF("ifa == NULL")do { } while (0);
1326 return (NULL((void *)0));
1327 }
1328
1329 rv = rt_ifa_add(ifa, RTF_HOST0x4 | RTF_MULTICAST0x200 | RTF_MPATH0x40000,
1330 group, ifp->if_rdomainif_data.ifi_rdomain);
1331 if (rv != 0) {
1332 DPRINTF("rt_ifa_add failed (%d)", rv)do { } while (0);
1333 return (NULL((void *)0));
1334 }
1335
1336 mrt_count[rtableid]++;
1337
1338 return (mfc_find(ifp, NULL((void *)0), &satosin(group)->sin_addr, rtableid));
1339}
1340
1341void
1342mrt_mcast_del(struct rtentry *rt, unsigned int rtableid)
1343{
1344 struct ifnet *ifp;
1345 int error;
1346
1347 /* Remove all timers related to this route. */
1348 rt_timer_remove_all(rt);
1349
1350 free(rt->rt_llinfo, M_MRTABLE56, sizeof(struct mfc));
1351 rt->rt_llinfo = NULL((void *)0);
1352
1353 ifp = if_get(rt->rt_ifidx);
1354 if (ifp == NULL((void *)0))
1355 return;
1356 error = rtdeletemsg(rt, ifp, rtableid);
1357 if_put(ifp);
1358
1359 if (error)
1360 DPRINTF("delete route error %d\n", error)do { } while (0);
1361
1362 mrt_count[rtableid]--;
1363}