Bug Summary

File:src/usr.sbin/mrouted/prune.c
Warning:line 490, column 16
Access to field 'st_origin' results in a dereference of a null pointer (loaded from variable 'st')

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 prune.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 pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/mrouted/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/mrouted -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/mrouted/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 -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/mrouted/prune.c
1/* $NetBSD: prune.c,v 1.3 1995/12/10 10:07:09 mycroft Exp $ */
2
3/*
4 * The mrouted program is covered by the license in the accompanying file
5 * named "LICENSE". Use of the mrouted program represents acceptance of
6 * the terms and conditions listed in that file.
7 *
8 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
9 * Leland Stanford Junior University.
10 */
11
12
13#include "defs.h"
14
15extern int cache_lifetime;
16extern int max_prune_lifetime;
17extern struct rtentry *routing_table;
18
19extern int phys_vif;
20
21/*
22 * dither cache lifetime to obtain a value between x and 2*x
23 */
24#define CACHE_LIFETIME(x)((x) + (arc4random_uniform(x))) ((x) + (arc4random_uniform(x)))
25
26struct gtable *kernel_table; /* ptr to list of kernel grp entries*/
27static struct gtable *kernel_no_route; /* list of grp entries w/o routes */
28struct gtable *gtp; /* pointer for kernel rt entries */
29unsigned int kroutes; /* current number of cache entries */
30
31/****************************************************************************
32 Functions that are local to prune.c
33****************************************************************************/
34static void prun_add_ttls(struct gtable *gt);
35static int pruning_neighbor(vifi_t vifi, u_int32_t addr);
36static int can_mtrace(vifi_t vifi, u_int32_t addr);
37static struct ptable * find_prune_entry(u_int32_t vr, struct ptable *pt);
38static void expire_prune(vifi_t vifi, struct gtable *gt);
39static void send_prune(struct gtable *gt);
40static void send_graft(struct gtable *gt);
41static void send_graft_ack(u_int32_t src, u_int32_t dst,
42 u_int32_t origin, u_int32_t grp);
43static void update_kernel(struct gtable *g);
44static char * scaletime(time_t t);
45
46/*
47 * Updates the ttl values for each vif.
48 */
49static void
50prun_add_ttls(struct gtable *gt)
51{
52 struct uvif *v;
53 vifi_t vifi;
54
55 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
56 if (VIFM_ISSET(vifi, gt->gt_grpmems)((gt->gt_grpmems) & (1 << (vifi))))
57 gt->gt_ttls[vifi] = v->uv_threshold;
58 else
59 gt->gt_ttls[vifi] = 0;
60 }
61}
62
63/*
64 * checks for scoped multicast addresses
65 */
66#define GET_SCOPE(gt){ vifi_t _i; if (((__uint32_t)(__builtin_constant_p((gt)->
gt_mcastgrp) ? (__uint32_t)(((__uint32_t)((gt)->gt_mcastgrp
) & 0xff) << 24 | ((__uint32_t)((gt)->gt_mcastgrp
) & 0xff00) << 8 | ((__uint32_t)((gt)->gt_mcastgrp
) & 0xff0000) >> 8 | ((__uint32_t)((gt)->gt_mcastgrp
) & 0xff000000) >> 24) : __swap32md((gt)->gt_mcastgrp
)) & 0xff000000) == 0xef000000) for (_i = 0; _i < numvifs
; _i++) if (scoped_addr(_i, (gt)->gt_mcastgrp)) (((gt)->
gt_scope) |= (1 << (_i))); }
{ \
67 vifi_t _i; \
68 if ((ntohl((gt)->gt_mcastgrp)(__uint32_t)(__builtin_constant_p((gt)->gt_mcastgrp) ? (__uint32_t
)(((__uint32_t)((gt)->gt_mcastgrp) & 0xff) << 24
| ((__uint32_t)((gt)->gt_mcastgrp) & 0xff00) <<
8 | ((__uint32_t)((gt)->gt_mcastgrp) & 0xff0000) >>
8 | ((__uint32_t)((gt)->gt_mcastgrp) & 0xff000000) >>
24) : __swap32md((gt)->gt_mcastgrp))
& 0xff000000) == 0xef000000) \
69 for (_i = 0; _i < numvifs; _i++) \
70 if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
71 VIFM_SET(_i, (gt)->gt_scope)(((gt)->gt_scope) |= (1 << (_i))); \
72 }
73
74int
75scoped_addr(vifi_t vifi, u_int32_t addr)
76{
77 struct vif_acl *acl;
78
79 for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next)
80 if ((addr & acl->acl_mask) == acl->acl_addr)
81 return 1;
82
83 return 0;
84}
85
86/*
87 * Determine if mcastgrp has a listener on vifi
88 */
89int
90grplst_mem(vifi_t vifi, u_int32_t mcastgrp)
91{
92 struct listaddr *g;
93 struct uvif *v;
94
95 v = &uvifs[vifi];
96
97 for (g = v->uv_groups; g != NULL((void *)0); g = g->al_next)
98 if (mcastgrp == g->al_addr)
99 return 1;
100
101 return 0;
102}
103
104/*
105 * Finds the group entry with the specified source and netmask.
106 * If netmask is 0, it uses the route's netmask.
107 *
108 * Returns TRUE if found a match, and the global variable gtp is left
109 * pointing to entry before the found entry.
110 * Returns FALSE if no exact match found, gtp is left pointing to before
111 * the entry in question belongs, or is NULL if the it belongs at the
112 * head of the list.
113 */
114int
115find_src_grp(u_int32_t src, u_int32_t mask, u_int32_t grp)
116{
117 struct gtable *gt;
118
119 gtp = NULL((void *)0);
120 gt = kernel_table;
121 while (gt != NULL((void *)0)) {
122 if (grp == gt->gt_mcastgrp &&
123 (mask ? (gt->gt_route->rt_origin == src &&
124 gt->gt_route->rt_originmask == mask) :
125 ((src & gt->gt_route->rt_originmask) ==
126 gt->gt_route->rt_origin)))
127 return TRUE1;
128 if (ntohl(grp)(__uint32_t)(__builtin_constant_p(grp) ? (__uint32_t)(((__uint32_t
)(grp) & 0xff) << 24 | ((__uint32_t)(grp) & 0xff00
) << 8 | ((__uint32_t)(grp) & 0xff0000) >> 8 |
((__uint32_t)(grp) & 0xff000000) >> 24) : __swap32md
(grp))
> ntohl(gt->gt_mcastgrp)(__uint32_t)(__builtin_constant_p(gt->gt_mcastgrp) ? (__uint32_t
)(((__uint32_t)(gt->gt_mcastgrp) & 0xff) << 24 |
((__uint32_t)(gt->gt_mcastgrp) & 0xff00) << 8 |
((__uint32_t)(gt->gt_mcastgrp) & 0xff0000) >> 8
| ((__uint32_t)(gt->gt_mcastgrp) & 0xff000000) >>
24) : __swap32md(gt->gt_mcastgrp))
||
129 (grp == gt->gt_mcastgrp &&
130 (ntohl(mask)(__uint32_t)(__builtin_constant_p(mask) ? (__uint32_t)(((__uint32_t
)(mask) & 0xff) << 24 | ((__uint32_t)(mask) & 0xff00
) << 8 | ((__uint32_t)(mask) & 0xff0000) >> 8
| ((__uint32_t)(mask) & 0xff000000) >> 24) : __swap32md
(mask))
< ntohl(gt->gt_route->rt_originmask)(__uint32_t)(__builtin_constant_p(gt->gt_route->rt_originmask
) ? (__uint32_t)(((__uint32_t)(gt->gt_route->rt_originmask
) & 0xff) << 24 | ((__uint32_t)(gt->gt_route->
rt_originmask) & 0xff00) << 8 | ((__uint32_t)(gt->
gt_route->rt_originmask) & 0xff0000) >> 8 | ((__uint32_t
)(gt->gt_route->rt_originmask) & 0xff000000) >>
24) : __swap32md(gt->gt_route->rt_originmask))
||
131 (mask == gt->gt_route->rt_originmask &&
132 (ntohl(src)(__uint32_t)(__builtin_constant_p(src) ? (__uint32_t)(((__uint32_t
)(src) & 0xff) << 24 | ((__uint32_t)(src) & 0xff00
) << 8 | ((__uint32_t)(src) & 0xff0000) >> 8 |
((__uint32_t)(src) & 0xff000000) >> 24) : __swap32md
(src))
> ntohl(gt->gt_route->rt_origin)(__uint32_t)(__builtin_constant_p(gt->gt_route->rt_origin
) ? (__uint32_t)(((__uint32_t)(gt->gt_route->rt_origin)
& 0xff) << 24 | ((__uint32_t)(gt->gt_route->
rt_origin) & 0xff00) << 8 | ((__uint32_t)(gt->gt_route
->rt_origin) & 0xff0000) >> 8 | ((__uint32_t)(gt
->gt_route->rt_origin) & 0xff000000) >> 24) :
__swap32md(gt->gt_route->rt_origin))
))))) {
133 gtp = gt;
134 gt = gt->gt_gnext;
135 }
136 else break;
137 }
138 return FALSE0;
139}
140
141/*
142 * Check if the neighbor supports pruning
143 */
144static int
145pruning_neighbor(vifi_t vifi, u_int32_t addr)
146{
147 struct listaddr *n = neighbor_info(vifi, addr);
148 int vers;
149
150 if (n == NULL((void *)0))
151 return 0;
152
153 if (n->al_flags & NF_PRUNE0x02)
154 return 1;
155
156 /*
157 * Versions from 3.0 to 3.4 relied on the version number to identify
158 * that they could handle pruning.
159 */
160 vers = NBR_VERS(n)(((n)->al_pv << 8) + (n)->al_mv);
161 return (vers >= 0x0300 && vers <= 0x0304);
162}
163
164/*
165 * Can the neighbor in question handle multicast traceroute?
166 */
167static int
168can_mtrace(vifi_t vifi, u_int32_t addr)
169{
170 struct listaddr *n = neighbor_info(vifi, addr);
171 int vers;
172
173 if (n == NULL((void *)0))
174 return 0;
175
176 if (n->al_flags & NF_MTRACE0x08)
177 return 1;
178
179 /*
180 * Versions 3.3 and 3.4 relied on the version number to identify
181 * that they could handle traceroute.
182 */
183 vers = NBR_VERS(n)(((n)->al_pv << 8) + (n)->al_mv);
184 return (vers >= 0x0303 && vers <= 0x0304);
185}
186
187/*
188 * Returns the prune entry of the router, or NULL if none exists
189 */
190static struct ptable *
191find_prune_entry(u_int32_t vr, struct ptable *pt)
192{
193 while (pt) {
194 if (pt->pt_router == vr)
195 return pt;
196 pt = pt->pt_next;
197 }
198
199 return NULL((void *)0);
200}
201
202/*
203 * Send a prune message to the dominant router for
204 * this source.
205 *
206 * Record an entry that a prune was sent for this group
207 */
208static void
209send_prune(struct gtable *gt)
210{
211 struct ptable *pt;
212 char *p;
213 int i;
214 int datalen;
215 u_int32_t src;
216 u_int32_t dst;
217 u_int32_t tmp;
218
219 /* Don't process any prunes if router is not pruning */
220 if (pruning == 0)
221 return;
222
223 /* Can't process a prune if we don't have an associated route */
224 if (gt->gt_route == NULL((void *)0))
225 return;
226
227 /* Don't send a prune to a non-pruning router */
228 if (!pruning_neighbor(gt->gt_route->rt_parent, gt->gt_route->rt_gateway))
229 return;
230
231 /*
232 * sends a prune message to the router upstream.
233 */
234 src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
235 dst = gt->gt_route->rt_gateway;
236
237 p = send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8;
238 datalen = 0;
239
240 /*
241 * determine prune lifetime
242 */
243 gt->gt_prsent_timer = gt->gt_timer;
244 for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next)
245 if (pt->pt_timer < gt->gt_prsent_timer)
246 gt->gt_prsent_timer = pt->pt_timer;
247
248 /*
249 * If we have a graft pending, cancel graft retransmission
250 */
251 gt->gt_grftsnt = 0;
252
253 for (i = 0; i < 4; i++)
254 *p++ = ((char *)&(gt->gt_route->rt_origin))[i];
255 for (i = 0; i < 4; i++)
256 *p++ = ((char *)&(gt->gt_mcastgrp))[i];
257 tmp = htonl(gt->gt_prsent_timer)(__uint32_t)(__builtin_constant_p(gt->gt_prsent_timer) ? (
__uint32_t)(((__uint32_t)(gt->gt_prsent_timer) & 0xff)
<< 24 | ((__uint32_t)(gt->gt_prsent_timer) & 0xff00
) << 8 | ((__uint32_t)(gt->gt_prsent_timer) & 0xff0000
) >> 8 | ((__uint32_t)(gt->gt_prsent_timer) & 0xff000000
) >> 24) : __swap32md(gt->gt_prsent_timer))
;
258 for (i = 0; i < 4; i++)
259 *p++ = ((char *)&(tmp))[i];
260 datalen += 12;
261
262 send_igmp(src, dst, IGMP_DVMRP0x13, DVMRP_PRUNE7,
263 htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02
| 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t
)(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) <<
16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t
)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (
1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8
<< 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 <<
24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 <<
8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24
))) & 0xff000000) >> 24) : __swap32md(((8 << 8
) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))
))
, datalen);
264
265 logit(LOG_DEBUG7, 0, "sent prune for (%s %s)/%d on vif %d to %s",
266 inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask, s1),
267 inet_fmt(gt->gt_mcastgrp, s2),
268 gt->gt_prsent_timer, gt->gt_route->rt_parent,
269 inet_fmt(gt->gt_route->rt_gateway, s3));
270}
271
272/*
273 * a prune was sent upstream
274 * so, a graft has to be sent to annul the prune
275 * set up a graft timer so that if an ack is not
276 * heard within that time, another graft request
277 * is sent out.
278 */
279static void
280send_graft(struct gtable *gt)
281{
282 char *p;
283 int i;
284 int datalen;
285 u_int32_t src;
286 u_int32_t dst;
287
288 /* Can't send a graft without an associated route */
289 if (gt->gt_route == NULL((void *)0))
290 return;
291
292 src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
293 dst = gt->gt_route->rt_gateway;
294
295 p = send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8;
296 datalen = 0;
297
298 for (i = 0; i < 4; i++)
299 *p++ = ((char *)&(gt->gt_route->rt_origin))[i];
300 for (i = 0; i < 4; i++)
301 *p++ = ((char *)&(gt->gt_mcastgrp))[i];
302 datalen += 8;
303
304 if (datalen != 0) {
305 send_igmp(src, dst, IGMP_DVMRP0x13, DVMRP_GRAFT8,
306 htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02
| 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t
)(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) <<
16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t
)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (
1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8
<< 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 <<
24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 <<
8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24
))) & 0xff000000) >> 24) : __swap32md(((8 << 8
) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))
))
, datalen);
307 }
308 logit(LOG_DEBUG7, 0, "sent graft for (%s %s) to %s on vif %d",
309 inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask, s1),
310 inet_fmt(gt->gt_mcastgrp, s2),
311 inet_fmt(gt->gt_route->rt_gateway, s3), gt->gt_route->rt_parent);
312}
313
314/*
315 * Send an ack that a graft was received
316 */
317static void
318send_graft_ack(u_int32_t src, u_int32_t dst, u_int32_t origin, u_int32_t grp)
319{
320 char *p;
321 int i;
322 int datalen;
323
324 p = send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8;
325 datalen = 0;
326
327 for (i = 0; i < 4; i++)
328 *p++ = ((char *)&(origin))[i];
329 for (i = 0; i < 4; i++)
330 *p++ = ((char *)&(grp))[i];
331 datalen += 8;
332
333 send_igmp(src, dst, IGMP_DVMRP0x13, DVMRP_GRAFT_ACK9,
334 htonl(MROUTED_LEVEL)(__uint32_t)(__builtin_constant_p(((8 << 8) | 3 | ((0x02
| 0x04 | 0x08) << 16) | (1 << 24))) ? (__uint32_t
)(((__uint32_t)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) <<
16) | (1 << 24))) & 0xff) << 24 | ((__uint32_t
)(((8 << 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (
1 << 24))) & 0xff00) << 8 | ((__uint32_t)(((8
<< 8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 <<
24))) & 0xff0000) >> 8 | ((__uint32_t)(((8 <<
8) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24
))) & 0xff000000) >> 24) : __swap32md(((8 << 8
) | 3 | ((0x02 | 0x04 | 0x08) << 16) | (1 << 24))
))
, datalen);
335
336 logit(LOG_DEBUG7, 0, "sent graft ack for (%s, %s) to %s",
337 inet_fmt(origin, s1), inet_fmt(grp, s2), inet_fmt(dst, s3));
338}
339
340/*
341 * Update the kernel cache with all the routes hanging off the group entry
342 */
343static void
344update_kernel(struct gtable *g)
345{
346 struct stable *st;
347
348 for (st = g->gt_srctbl; st; st = st->st_next)
349 k_add_rg(st->st_origin, g);
350}
351
352/****************************************************************************
353 Functions that are used externally
354****************************************************************************/
355
356/*
357 * Initialize the kernel table structure
358 */
359void
360init_ktable(void)
361{
362 kernel_table = NULL((void *)0);
363 kernel_no_route = NULL((void *)0);
364 kroutes = 0;
365}
366
367/*
368 * Add a new table entry for (origin, mcastgrp)
369 */
370void
371add_table_entry(u_int32_t origin, u_int32_t mcastgrp)
372{
373 struct rtentry *r;
374 struct gtable *gt,**gtnp,*prev_gt;
375 struct stable *st,**stnp;
376 vifi_t i;
377
378#ifdef DEBUG_MFC
379 md_logit(MD_MISS, origin, mcastgrp);
380#endif
381
382 r = determine_route(origin);
383 prev_gt = NULL((void *)0);
384 if (r == NULL((void *)0)) {
1
Assuming 'r' is not equal to NULL
2
Taking false branch
385 /*
386 * Look for it on the no_route table; if it is found then
387 * it will be detected as a duplicate below.
388 */
389 for (gt = kernel_no_route; gt; gt = gt->gt_next)
390 if (mcastgrp == gt->gt_mcastgrp &&
391 gt->gt_srctbl && gt->gt_srctbl->st_origin == origin)
392 break;
393 gtnp = &kernel_no_route;
394 } else {
395 gtnp = &r->rt_groups;
396 while ((gt = *gtnp) != NULL((void *)0)) {
3
Assuming the condition is true
4
Loop condition is true. Entering loop body
397 if (gt->gt_mcastgrp >= mcastgrp)
5
Assuming 'mcastgrp' is <= field 'gt_mcastgrp'
6
Taking true branch
398 break;
7
Execution continues on line 404
399 gtnp = &gt->gt_next;
400 prev_gt = gt;
401 }
402 }
403
404 if (gt
7.1
'gt' is not equal to NULL
== NULL((void *)0) || gt->gt_mcastgrp != mcastgrp) {
8
Assuming 'mcastgrp' is equal to field 'gt_mcastgrp'
9
Taking false branch
405 gt = malloc(sizeof(struct gtable));
406 if (gt == NULL((void *)0))
407 logit(LOG_ERR3, 0, "ran out of memory");
408
409 gt->gt_mcastgrp = mcastgrp;
410 gt->gt_timer = CACHE_LIFETIME(cache_lifetime)((cache_lifetime) + (arc4random_uniform(cache_lifetime)));
411 time(&gt->gt_ctime);
412 gt->gt_grpmems = 0;
413 gt->gt_scope = 0;
414 gt->gt_prsent_timer = 0;
415 gt->gt_grftsnt = 0;
416 gt->gt_srctbl = NULL((void *)0);
417 gt->gt_pruntbl = NULL((void *)0);
418 gt->gt_route = r;
419#ifdef RSRR
420 gt->gt_rsrr_cache = NULL((void *)0);
421#endif
422
423 if (r != NULL((void *)0)) {
424 /* obtain the multicast group membership list */
425 for (i = 0; i < numvifs; i++) {
426 if (VIFM_ISSET(i, r->rt_children)((r->rt_children) & (1 << (i))) &&
427 !(VIFM_ISSET(i, r->rt_leaves)((r->rt_leaves) & (1 << (i)))))
428 VIFM_SET(i, gt->gt_grpmems)((gt->gt_grpmems) |= (1 << (i)));
429
430 if (VIFM_ISSET(i, r->rt_leaves)((r->rt_leaves) & (1 << (i))) && grplst_mem(i, mcastgrp))
431 VIFM_SET(i, gt->gt_grpmems)((gt->gt_grpmems) |= (1 << (i)));
432 }
433 GET_SCOPE(gt){ vifi_t _i; if (((__uint32_t)(__builtin_constant_p((gt)->
gt_mcastgrp) ? (__uint32_t)(((__uint32_t)((gt)->gt_mcastgrp
) & 0xff) << 24 | ((__uint32_t)((gt)->gt_mcastgrp
) & 0xff00) << 8 | ((__uint32_t)((gt)->gt_mcastgrp
) & 0xff0000) >> 8 | ((__uint32_t)((gt)->gt_mcastgrp
) & 0xff000000) >> 24) : __swap32md((gt)->gt_mcastgrp
)) & 0xff000000) == 0xef000000) for (_i = 0; _i < numvifs
; _i++) if (scoped_addr(_i, (gt)->gt_mcastgrp)) (((gt)->
gt_scope) |= (1 << (_i))); }
;
434 if (VIFM_ISSET(r->rt_parent, gt->gt_scope)((gt->gt_scope) & (1 << (r->rt_parent))))
435 gt->gt_scope = -1;
436 gt->gt_grpmems &= ~gt->gt_scope;
437 } else {
438 gt->gt_scope = -1;
439 gt->gt_grpmems = 0;
440 }
441
442 /* update ttls */
443 prun_add_ttls(gt);
444
445 gt->gt_next = *gtnp;
446 *gtnp = gt;
447 if (gt->gt_next)
448 gt->gt_next->gt_prev = gt;
449 gt->gt_prev = prev_gt;
450
451 if (r) {
452 if (find_src_grp(r->rt_origin, r->rt_originmask, gt->gt_mcastgrp)) {
453 struct gtable *g;
454
455 g = gtp ? gtp->gt_gnext : kernel_table;
456 logit(LOG_WARNING4, 0, "Entry for (%s %s) (rt:%x) exists (rt:%x)",
457 inet_fmts(r->rt_origin, r->rt_originmask, s1),
458 inet_fmt(g->gt_mcastgrp, s2),
459 r, g->gt_route);
460 } else {
461 if (gtp) {
462 gt->gt_gnext = gtp->gt_gnext;
463 gt->gt_gprev = gtp;
464 gtp->gt_gnext = gt;
465 } else {
466 gt->gt_gnext = kernel_table;
467 gt->gt_gprev = NULL((void *)0);
468 kernel_table = gt;
469 }
470 if (gt->gt_gnext)
471 gt->gt_gnext->gt_gprev = gt;
472 }
473 } else {
474 gt->gt_gnext = gt->gt_gprev = NULL((void *)0);
475 }
476 }
477
478 stnp = &gt->gt_srctbl;
479 while ((st = *stnp) != NULL((void *)0)) {
10
Assuming the condition is false
11
Loop condition is false. Execution continues on line 485
480 if (ntohl(st->st_origin)(__uint32_t)(__builtin_constant_p(st->st_origin) ? (__uint32_t
)(((__uint32_t)(st->st_origin) & 0xff) << 24 | (
(__uint32_t)(st->st_origin) & 0xff00) << 8 | ((__uint32_t
)(st->st_origin) & 0xff0000) >> 8 | ((__uint32_t
)(st->st_origin) & 0xff000000) >> 24) : __swap32md
(st->st_origin))
>= ntohl(origin)(__uint32_t)(__builtin_constant_p(origin) ? (__uint32_t)(((__uint32_t
)(origin) & 0xff) << 24 | ((__uint32_t)(origin) &
0xff00) << 8 | ((__uint32_t)(origin) & 0xff0000) >>
8 | ((__uint32_t)(origin) & 0xff000000) >> 24) : __swap32md
(origin))
)
481 break;
482 stnp = &st->st_next;
483 }
484
485 if (st
11.1
'st' is equal to NULL
== NULL((void *)0) || st->st_origin != origin) {
486 st = malloc(sizeof(struct stable));
12
Value assigned to 'st'
487 if (st == NULL((void *)0))
13
Assuming 'st' is equal to NULL
14
Taking true branch
488 logit(LOG_ERR3, 0, "ran out of memory");
489
490 st->st_origin = origin;
15
Access to field 'st_origin' results in a dereference of a null pointer (loaded from variable 'st')
491 st->st_pktcnt = 0;
492 st->st_next = *stnp;
493 *stnp = st;
494 } else {
495#ifdef DEBUG_MFC
496 md_logit(MD_DUPE, origin, mcastgrp);
497#endif
498 logit(LOG_WARNING4, 0, "kernel entry already exists for (%s %s)",
499 inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
500 /* XXX Doing this should cause no harm, and may ensure
501 * kernel<>mrouted synchronization */
502 k_add_rg(origin, gt);
503 return;
504 }
505
506 kroutes++;
507 k_add_rg(origin, gt);
508
509 logit(LOG_DEBUG7, 0, "add cache entry (%s %s) gm:%x, parent-vif:%d",
510 inet_fmt(origin, s1),
511 inet_fmt(mcastgrp, s2),
512 gt->gt_grpmems, r ? r->rt_parent : -1);
513
514 /* If there are no leaf vifs
515 * which have this group, then
516 * mark this src-grp as a prune candidate.
517 */
518 if (!gt->gt_prsent_timer && !gt->gt_grpmems && r && r->rt_gateway)
519 send_prune(gt);
520}
521
522/*
523 * An mrouter has gone down and come up on an interface
524 * Forward on that interface immediately
525 */
526void
527reset_neighbor_state(vifi_t vifi, u_int32_t addr)
528{
529 struct rtentry *r;
530 struct gtable *g;
531 struct ptable *pt, **ptnp;
532 struct stable *st;
533
534 for (g = kernel_table; g; g = g->gt_gnext) {
535 r = g->gt_route;
536
537 /*
538 * If neighbor was the parent, remove the prune sent state
539 * and all of the source cache info so that prunes get
540 * regenerated.
541 */
542 if (vifi == r->rt_parent) {
543 if (addr == r->rt_gateway) {
544 logit(LOG_DEBUG7, 0, "reset_neighbor_state parent reset (%s %s)",
545 inet_fmts(r->rt_origin, r->rt_originmask, s1),
546 inet_fmt(g->gt_mcastgrp, s2));
547
548 g->gt_prsent_timer = 0;
549 g->gt_grftsnt = 0;
550 while ((st = g->gt_srctbl)) {
551 g->gt_srctbl = st->st_next;
552 k_del_rg(st->st_origin, g);
553 kroutes--;
554 free(st);
555 }
556 }
557 } else {
558 /*
559 * Neighbor was not the parent, send grafts to join the groups
560 */
561 if (g->gt_prsent_timer) {
562 g->gt_grftsnt = 1;
563 send_graft(g);
564 g->gt_prsent_timer = 0;
565 }
566
567 /*
568 * Remove any prunes that this router has sent us.
569 */
570 ptnp = &g->gt_pruntbl;
571 while ((pt = *ptnp) != NULL((void *)0)) {
572 if (pt->pt_vifi == vifi && pt->pt_router == addr) {
573 *ptnp = pt->pt_next;
574 free(pt);
575 } else
576 ptnp = &pt->pt_next;
577 }
578
579 /*
580 * And see if we want to forward again.
581 */
582 if (!VIFM_ISSET(vifi, g->gt_grpmems)((g->gt_grpmems) & (1 << (vifi)))) {
583 if (VIFM_ISSET(vifi, r->rt_children)((r->rt_children) & (1 << (vifi))) &&
584 !(VIFM_ISSET(vifi, r->rt_leaves)((r->rt_leaves) & (1 << (vifi)))))
585 VIFM_SET(vifi, g->gt_grpmems)((g->gt_grpmems) |= (1 << (vifi)));
586
587 if (VIFM_ISSET(vifi, r->rt_leaves)((r->rt_leaves) & (1 << (vifi))) &&
588 grplst_mem(vifi, g->gt_mcastgrp))
589 VIFM_SET(vifi, g->gt_grpmems)((g->gt_grpmems) |= (1 << (vifi)));
590
591 g->gt_grpmems &= ~g->gt_scope;
592 prun_add_ttls(g);
593
594 /* Update kernel state */
595 update_kernel(g);
596#ifdef RSRR
597 /* Send route change notification to reservation protocol. */
598 rsrr_cache_send(g,1);
599#endif /* RSRR */
600
601 logit(LOG_DEBUG7, 0, "reset member state (%s %s) gm:%x",
602 inet_fmts(r->rt_origin, r->rt_originmask, s1),
603 inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
604 }
605 }
606 }
607}
608
609/*
610 * Delete table entry from the kernel
611 * del_flag determines how many entries to delete
612 */
613void
614del_table_entry(struct rtentry *r, u_int32_t mcastgrp, u_int del_flag)
615{
616 struct gtable *g, *prev_g;
617 struct stable *st, *prev_st;
618 struct ptable *pt, *prev_pt;
619
620 if (del_flag == DEL_ALL_ROUTES1) {
621 g = r->rt_groups;
622 while (g) {
623 logit(LOG_DEBUG7, 0, "del_table_entry deleting (%s %s)",
624 inet_fmts(r->rt_origin, r->rt_originmask, s1),
625 inet_fmt(g->gt_mcastgrp, s2));
626 st = g->gt_srctbl;
627 while (st) {
628 if (k_del_rg(st->st_origin, g) < 0) {
629 logit(LOG_WARNING4, errno(*__errno()),
630 "del_table_entry trying to delete (%s, %s)",
631 inet_fmt(st->st_origin, s1),
632 inet_fmt(g->gt_mcastgrp, s2));
633 }
634 kroutes--;
635 prev_st = st;
636 st = st->st_next;
637 free(prev_st);
638 }
639 g->gt_srctbl = NULL((void *)0);
640
641 pt = g->gt_pruntbl;
642 while (pt) {
643 prev_pt = pt;
644 pt = pt->pt_next;
645 free(prev_pt);
646 }
647 g->gt_pruntbl = NULL((void *)0);
648
649 if (g->gt_gnext)
650 g->gt_gnext->gt_gprev = g->gt_gprev;
651 if (g->gt_gprev)
652 g->gt_gprev->gt_gnext = g->gt_gnext;
653 else
654 kernel_table = g->gt_gnext;
655
656#ifdef RSRR
657 /* Send route change notification to reservation protocol. */
658 rsrr_cache_send(g,0);
659 rsrr_cache_clean(g);
660#endif /* RSRR */
661 prev_g = g;
662 g = g->gt_next;
663 free(prev_g);
664 }
665 r->rt_groups = NULL((void *)0);
666 }
667
668 /*
669 * Dummy routine - someday this may be needed, so it is just there
670 */
671 if (del_flag == DEL_RTE_GROUP0) {
672 prev_g = (struct gtable *)&r->rt_groups;
673 for (g = r->rt_groups; g; g = g->gt_next) {
674 if (g->gt_mcastgrp == mcastgrp) {
675 logit(LOG_DEBUG7, 0, "del_table_entry deleting (%s %s)",
676 inet_fmts(r->rt_origin, r->rt_originmask, s1),
677 inet_fmt(g->gt_mcastgrp, s2));
678 st = g->gt_srctbl;
679 while (st) {
680 if (k_del_rg(st->st_origin, g) < 0) {
681 logit(LOG_WARNING4, errno(*__errno()),
682 "del_table_entry trying to delete (%s, %s)",
683 inet_fmt(st->st_origin, s1),
684 inet_fmt(g->gt_mcastgrp, s2));
685 }
686 kroutes--;
687 prev_st = st;
688 st = st->st_next;
689 free(prev_st);
690 }
691 g->gt_srctbl = NULL((void *)0);
692
693 pt = g->gt_pruntbl;
694 while (pt) {
695 prev_pt = pt;
696 pt = pt->pt_next;
697 free(prev_pt);
698 }
699 g->gt_pruntbl = NULL((void *)0);
700
701 if (g->gt_gnext)
702 g->gt_gnext->gt_gprev = g->gt_gprev;
703 if (g->gt_gprev)
704 g->gt_gprev->gt_gnext = g->gt_gnext;
705 else
706 kernel_table = g->gt_gnext;
707
708 if (prev_g != (struct gtable *)&r->rt_groups)
709 g->gt_next->gt_prev = prev_g;
710 else
711 g->gt_next->gt_prev = NULL((void *)0);
712 prev_g->gt_next = g->gt_next;
713
714#ifdef RSRR
715 /* Send route change notification to reservation protocol. */
716 rsrr_cache_send(g,0);
717 rsrr_cache_clean(g);
718#endif /* RSRR */
719 free(g);
720 g = prev_g;
721 } else {
722 prev_g = g;
723 }
724 }
725 }
726}
727
728/*
729 * update kernel table entry when a route entry changes
730 */
731void
732update_table_entry(struct rtentry *r)
733{
734 struct gtable *g;
735 struct ptable *pt, *prev_pt;
736 vifi_t i;
737
738 for (g = r->rt_groups; g; g = g->gt_next) {
739 pt = g->gt_pruntbl;
740 while (pt) {
741 prev_pt = pt->pt_next;
742 free(pt);
743 pt = prev_pt;
744 }
745 g->gt_pruntbl = NULL((void *)0);
746
747 g->gt_grpmems = 0;
748
749 /* obtain the multicast group membership list */
750 for (i = 0; i < numvifs; i++) {
751 if (VIFM_ISSET(i, r->rt_children)((r->rt_children) & (1 << (i))) &&
752 !(VIFM_ISSET(i, r->rt_leaves)((r->rt_leaves) & (1 << (i)))))
753 VIFM_SET(i, g->gt_grpmems)((g->gt_grpmems) |= (1 << (i)));
754
755 if (VIFM_ISSET(i, r->rt_leaves)((r->rt_leaves) & (1 << (i))) && grplst_mem(i, g->gt_mcastgrp))
756 VIFM_SET(i, g->gt_grpmems)((g->gt_grpmems) |= (1 << (i)));
757 }
758 if (VIFM_ISSET(r->rt_parent, g->gt_scope)((g->gt_scope) & (1 << (r->rt_parent))))
759 g->gt_scope = -1;
760 g->gt_grpmems &= ~g->gt_scope;
761
762 logit(LOG_DEBUG7, 0, "updating cache entries (%s %s) gm:%x",
763 inet_fmts(r->rt_origin, r->rt_originmask, s1),
764 inet_fmt(g->gt_mcastgrp, s2),
765 g->gt_grpmems);
766
767 if (g->gt_grpmems && g->gt_prsent_timer) {
768 g->gt_grftsnt = 1;
769 send_graft(g);
770 g->gt_prsent_timer = 0;
771 }
772
773 /* update ttls and add entry into kernel */
774 prun_add_ttls(g);
775 update_kernel(g);
776#ifdef RSRR
777 /* Send route change notification to reservation protocol. */
778 rsrr_cache_send(g,1);
779#endif /* RSRR */
780
781 /* Check if we want to prune this group */
782 if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
783 g->gt_timer = CACHE_LIFETIME(cache_lifetime)((cache_lifetime) + (arc4random_uniform(cache_lifetime)));
784 send_prune(g);
785 }
786 }
787}
788
789/*
790 * set the forwarding flag for all mcastgrps on this vifi
791 */
792void
793update_lclgrp(vifi_t vifi, u_int32_t mcastgrp)
794{
795 struct rtentry *r;
796 struct gtable *g;
797
798 logit(LOG_DEBUG7, 0, "group %s joined on vif %d",
799 inet_fmt(mcastgrp, s1), vifi);
800
801 for (g = kernel_table; g; g = g->gt_gnext) {
802 if (ntohl(mcastgrp)(__uint32_t)(__builtin_constant_p(mcastgrp) ? (__uint32_t)(((
__uint32_t)(mcastgrp) & 0xff) << 24 | ((__uint32_t)
(mcastgrp) & 0xff00) << 8 | ((__uint32_t)(mcastgrp)
& 0xff0000) >> 8 | ((__uint32_t)(mcastgrp) & 0xff000000
) >> 24) : __swap32md(mcastgrp))
< ntohl(g->gt_mcastgrp)(__uint32_t)(__builtin_constant_p(g->gt_mcastgrp) ? (__uint32_t
)(((__uint32_t)(g->gt_mcastgrp) & 0xff) << 24 | (
(__uint32_t)(g->gt_mcastgrp) & 0xff00) << 8 | ((
__uint32_t)(g->gt_mcastgrp) & 0xff0000) >> 8 | (
(__uint32_t)(g->gt_mcastgrp) & 0xff000000) >> 24
) : __swap32md(g->gt_mcastgrp))
)
803 break;
804
805 r = g->gt_route;
806 if (g->gt_mcastgrp == mcastgrp &&
807 VIFM_ISSET(vifi, r->rt_children)((r->rt_children) & (1 << (vifi)))) {
808
809 VIFM_SET(vifi, g->gt_grpmems)((g->gt_grpmems) |= (1 << (vifi)));
810 g->gt_grpmems &= ~g->gt_scope;
811 if (g->gt_grpmems == 0)
812 continue;
813
814 prun_add_ttls(g);
815 logit(LOG_DEBUG7, 0, "update lclgrp (%s %s) gm:%x",
816 inet_fmts(r->rt_origin, r->rt_originmask, s1),
817 inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
818
819 update_kernel(g);
820#ifdef RSRR
821 /* Send route change notification to reservation protocol. */
822 rsrr_cache_send(g,1);
823#endif /* RSRR */
824 }
825 }
826}
827
828/*
829 * reset forwarding flag for all mcastgrps on this vifi
830 */
831void
832delete_lclgrp(vifi_t vifi, u_int32_t mcastgrp)
833{
834 struct rtentry *r;
835 struct gtable *g;
836
837 logit(LOG_DEBUG7, 0, "group %s left on vif %d",
838 inet_fmt(mcastgrp, s1), vifi);
839
840 for (g = kernel_table; g; g = g->gt_gnext) {
841 if (ntohl(mcastgrp)(__uint32_t)(__builtin_constant_p(mcastgrp) ? (__uint32_t)(((
__uint32_t)(mcastgrp) & 0xff) << 24 | ((__uint32_t)
(mcastgrp) & 0xff00) << 8 | ((__uint32_t)(mcastgrp)
& 0xff0000) >> 8 | ((__uint32_t)(mcastgrp) & 0xff000000
) >> 24) : __swap32md(mcastgrp))
< ntohl(g->gt_mcastgrp)(__uint32_t)(__builtin_constant_p(g->gt_mcastgrp) ? (__uint32_t
)(((__uint32_t)(g->gt_mcastgrp) & 0xff) << 24 | (
(__uint32_t)(g->gt_mcastgrp) & 0xff00) << 8 | ((
__uint32_t)(g->gt_mcastgrp) & 0xff0000) >> 8 | (
(__uint32_t)(g->gt_mcastgrp) & 0xff000000) >> 24
) : __swap32md(g->gt_mcastgrp))
)
842 break;
843
844 if (g->gt_mcastgrp == mcastgrp) {
845 int stop_sending = 1;
846
847 r = g->gt_route;
848 /*
849 * If this is not a leaf, then we have router neighbors on this
850 * vif. Only turn off forwarding if they have all pruned.
851 */
852 if (!VIFM_ISSET(vifi, r->rt_leaves)((r->rt_leaves) & (1 << (vifi)))) {
853 struct listaddr *vr;
854
855 for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
856 if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL((void *)0)) {
857 stop_sending = 0;
858 break;
859 }
860 }
861
862 if (stop_sending) {
863 VIFM_CLR(vifi, g->gt_grpmems)((g->gt_grpmems) &= ~(1 << (vifi)));
864 logit(LOG_DEBUG7, 0, "delete lclgrp (%s %s) gm:%x",
865 inet_fmts(r->rt_origin, r->rt_originmask, s1),
866 inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
867
868 prun_add_ttls(g);
869 update_kernel(g);
870#ifdef RSRR
871 /* Send route change notification to reservation protocol. */
872 rsrr_cache_send(g,1);
873#endif /* RSRR */
874
875 /*
876 * If there are no more members of this particular group,
877 * send prune upstream
878 */
879 if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway)
880 send_prune(g);
881 }
882 }
883 }
884}
885
886/*
887 * Takes the prune message received and then strips it to
888 * determine the (src, grp) pair to be pruned.
889 *
890 * Adds the router to the (src, grp) entry then.
891 *
892 * Determines if further packets have to be sent down that vif
893 *
894 * Determines if a corresponding prune message has to be generated
895 */
896void
897accept_prune(u_int32_t src, u_int32_t dst, char *p, int datalen)
898{
899 u_int32_t prun_src;
900 u_int32_t prun_grp;
901 u_int32_t prun_tmr;
902 vifi_t vifi;
903 int i;
904 int stop_sending;
905 struct rtentry *r;
906 struct gtable *g;
907 struct ptable *pt;
908 struct listaddr *vr;
909
910 /* Don't process any prunes if router is not pruning */
911 if (pruning == 0)
912 return;
913
914 if ((vifi = find_vif(src, dst)) == NO_VIF((vifi_t)32)) {
915 logit(LOG_INFO6, 0,
916 "ignoring prune report from non-neighbor %s",
917 inet_fmt(src, s1));
918 return;
919 }
920
921 /* Check if enough data is present */
922 if (datalen < 12)
923 {
924 logit(LOG_WARNING4, 0,
925 "non-decipherable prune from %s",
926 inet_fmt(src, s1));
927 return;
928 }
929
930 for (i = 0; i< 4; i++)
931 ((char *)&prun_src)[i] = *p++;
932 for (i = 0; i< 4; i++)
933 ((char *)&prun_grp)[i] = *p++;
934 for (i = 0; i< 4; i++)
935 ((char *)&prun_tmr)[i] = *p++;
936 prun_tmr = ntohl(prun_tmr)(__uint32_t)(__builtin_constant_p(prun_tmr) ? (__uint32_t)(((
__uint32_t)(prun_tmr) & 0xff) << 24 | ((__uint32_t)
(prun_tmr) & 0xff00) << 8 | ((__uint32_t)(prun_tmr)
& 0xff0000) >> 8 | ((__uint32_t)(prun_tmr) & 0xff000000
) >> 24) : __swap32md(prun_tmr))
;
937
938 logit(LOG_DEBUG7, 0, "%s on vif %d prunes (%s %s)/%d",
939 inet_fmt(src, s1), vifi,
940 inet_fmt(prun_src, s2), inet_fmt(prun_grp, s3), prun_tmr);
941
942 /*
943 * Find the subnet for the prune
944 */
945 if (find_src_grp(prun_src, 0, prun_grp)) {
946 g = gtp ? gtp->gt_gnext : kernel_table;
947 r = g->gt_route;
948
949 if (!VIFM_ISSET(vifi, r->rt_children)((r->rt_children) & (1 << (vifi)))) {
950 logit(LOG_WARNING4, 0, "prune received from non-child %s for (%s %s)",
951 inet_fmt(src, s1), inet_fmt(prun_src, s2),
952 inet_fmt(prun_grp, s3));
953 return;
954 }
955 if (VIFM_ISSET(vifi, g->gt_scope)((g->gt_scope) & (1 << (vifi)))) {
956 logit(LOG_WARNING4, 0, "prune received from %s on scoped grp (%s %s)",
957 inet_fmt(src, s1), inet_fmt(prun_src, s2),
958 inet_fmt(prun_grp, s3));
959 return;
960 }
961 if ((pt = find_prune_entry(src, g->gt_pruntbl)) != NULL((void *)0)) {
962 /*
963 * If it's about to expire, then it's only still around because
964 * of timer granularity, so don't warn about it.
965 */
966 if (pt->pt_timer > 10) {
967 logit(LOG_WARNING4, 0, "%s %d from %s for (%s %s)/%d %s %d %s %x",
968 "duplicate prune received on vif",
969 vifi, inet_fmt(src, s1), inet_fmt(prun_src, s2),
970 inet_fmt(prun_grp, s3), prun_tmr,
971 "old timer:", pt->pt_timer, "cur gm:", g->gt_grpmems);
972 }
973 pt->pt_timer = prun_tmr;
974 } else {
975 /* allocate space for the prune structure */
976 pt = malloc(sizeof(struct ptable));
977 if (pt == NULL((void *)0))
978 logit(LOG_ERR3, 0, "pt: ran out of memory");
979
980 pt->pt_vifi = vifi;
981 pt->pt_router = src;
982 pt->pt_timer = prun_tmr;
983
984 pt->pt_next = g->gt_pruntbl;
985 g->gt_pruntbl = pt;
986 }
987
988 /* Refresh the group's lifetime */
989 g->gt_timer = CACHE_LIFETIME(cache_lifetime)((cache_lifetime) + (arc4random_uniform(cache_lifetime)));
990 if (g->gt_timer < prun_tmr)
991 g->gt_timer = prun_tmr;
992
993 /*
994 * check if any more packets need to be sent on the
995 * vif which sent this message
996 */
997 stop_sending = 1;
998 for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
999 if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL((void *)0)) {
1000 stop_sending = 0;
1001 break;
1002 }
1003
1004 if (stop_sending && !grplst_mem(vifi, prun_grp)) {
1005 VIFM_CLR(vifi, g->gt_grpmems)((g->gt_grpmems) &= ~(1 << (vifi)));
1006 logit(LOG_DEBUG7, 0, "prune (%s %s), stop sending on vif %d, gm:%x",
1007 inet_fmts(r->rt_origin, r->rt_originmask, s1),
1008 inet_fmt(g->gt_mcastgrp, s2), vifi, g->gt_grpmems);
1009
1010 prun_add_ttls(g);
1011 update_kernel(g);
1012#ifdef RSRR
1013 /* Send route change notification to reservation protocol. */
1014 rsrr_cache_send(g,1);
1015#endif /* RSRR */
1016 }
1017
1018 /*
1019 * check if all the child routers have expressed no interest
1020 * in this group and if this group does not exist in the
1021 * interface
1022 * Send a prune message then upstream
1023 */
1024 if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
1025 send_prune(g);
1026 }
1027 } else {
1028 /*
1029 * There is no kernel entry for this group. Therefore, we can
1030 * simply ignore the prune, as we are not forwarding this traffic
1031 * downstream.
1032 */
1033 logit(LOG_DEBUG7, 0, "%s (%s %s)/%d from %s",
1034 "prune message received with no kernel entry for",
1035 inet_fmt(prun_src, s1), inet_fmt(prun_grp, s2),
1036 prun_tmr, inet_fmt(src, s3));
1037 return;
1038 }
1039}
1040
1041/*
1042 * Checks if this mcastgrp is present in the kernel table
1043 * If so and if a prune was sent, it sends a graft upwards
1044 */
1045void
1046chkgrp_graft(vifi_t vifi, u_int32_t mcastgrp)
1047{
1048 struct rtentry *r;
1049 struct gtable *g;
1050
1051 for (g = kernel_table; g; g = g->gt_gnext) {
1052 if (ntohl(mcastgrp)(__uint32_t)(__builtin_constant_p(mcastgrp) ? (__uint32_t)(((
__uint32_t)(mcastgrp) & 0xff) << 24 | ((__uint32_t)
(mcastgrp) & 0xff00) << 8 | ((__uint32_t)(mcastgrp)
& 0xff0000) >> 8 | ((__uint32_t)(mcastgrp) & 0xff000000
) >> 24) : __swap32md(mcastgrp))
< ntohl(g->gt_mcastgrp)(__uint32_t)(__builtin_constant_p(g->gt_mcastgrp) ? (__uint32_t
)(((__uint32_t)(g->gt_mcastgrp) & 0xff) << 24 | (
(__uint32_t)(g->gt_mcastgrp) & 0xff00) << 8 | ((
__uint32_t)(g->gt_mcastgrp) & 0xff0000) >> 8 | (
(__uint32_t)(g->gt_mcastgrp) & 0xff000000) >> 24
) : __swap32md(g->gt_mcastgrp))
)
1053 break;
1054
1055 r = g->gt_route;
1056 if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, r->rt_children)((r->rt_children) & (1 << (vifi))))
1057 if (g->gt_prsent_timer) {
1058 VIFM_SET(vifi, g->gt_grpmems)((g->gt_grpmems) |= (1 << (vifi)));
1059
1060 /*
1061 * If the vif that was joined was a scoped vif,
1062 * ignore it ; don't graft back
1063 */
1064 g->gt_grpmems &= ~g->gt_scope;
1065 if (g->gt_grpmems == 0)
1066 continue;
1067
1068 /* set the flag for graft retransmission */
1069 g->gt_grftsnt = 1;
1070
1071 /* send graft upwards */
1072 send_graft(g);
1073
1074 /* reset the prune timer and update cache timer*/
1075 g->gt_prsent_timer = 0;
1076 g->gt_timer = max_prune_lifetime;
1077
1078 logit(LOG_DEBUG7, 0, "chkgrp graft (%s %s) gm:%x",
1079 inet_fmts(r->rt_origin, r->rt_originmask, s1),
1080 inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
1081
1082 prun_add_ttls(g);
1083 update_kernel(g);
1084#ifdef RSRR
1085 /* Send route change notification to reservation protocol. */
1086 rsrr_cache_send(g,1);
1087#endif /* RSRR */
1088 }
1089 }
1090}
1091
1092/* determine the multicast group and src
1093 *
1094 * if it does, then determine if a prune was sent
1095 * upstream.
1096 * if prune sent upstream, send graft upstream and send
1097 * ack downstream.
1098 *
1099 * if no prune sent upstream, change the forwarding bit
1100 * for this interface and send ack downstream.
1101 *
1102 * if no entry exists for this group send ack downstream.
1103 */
1104void
1105accept_graft(u_int32_t src, u_int32_t dst, char *p, int datalen)
1106{
1107 vifi_t vifi;
1108 u_int32_t graft_src;
1109 u_int32_t graft_grp;
1110 int i;
1111 struct rtentry *r;
1112 struct gtable *g;
1113 struct ptable *pt, **ptnp;
1114
1115 if ((vifi = find_vif(src, dst)) == NO_VIF((vifi_t)32)) {
1116 logit(LOG_INFO6, 0,
1117 "ignoring graft from non-neighbor %s",
1118 inet_fmt(src, s1));
1119 return;
1120 }
1121
1122 if (datalen < 8) {
1123 logit(LOG_WARNING4, 0,
1124 "received non-decipherable graft from %s",
1125 inet_fmt(src, s1));
1126 return;
1127 }
1128
1129 for (i = 0; i< 4; i++)
1130 ((char *)&graft_src)[i] = *p++;
1131 for (i = 0; i< 4; i++)
1132 ((char *)&graft_grp)[i] = *p++;
1133
1134 logit(LOG_DEBUG7, 0, "%s on vif %d grafts (%s %s)",
1135 inet_fmt(src, s1), vifi,
1136 inet_fmt(graft_src, s2), inet_fmt(graft_grp, s3));
1137
1138 /*
1139 * Find the subnet for the graft
1140 */
1141 if (find_src_grp(graft_src, 0, graft_grp)) {
1142 g = gtp ? gtp->gt_gnext : kernel_table;
1143 r = g->gt_route;
1144
1145 if (VIFM_ISSET(vifi, g->gt_scope)((g->gt_scope) & (1 << (vifi)))) {
1146 logit(LOG_WARNING4, 0, "graft received from %s on scoped grp (%s %s)",
1147 inet_fmt(src, s1), inet_fmt(graft_src, s2),
1148 inet_fmt(graft_grp, s3));
1149 return;
1150 }
1151
1152 ptnp = &g->gt_pruntbl;
1153 while ((pt = *ptnp) != NULL((void *)0)) {
1154 if ((pt->pt_vifi == vifi) && (pt->pt_router == src)) {
1155 *ptnp = pt->pt_next;
1156 free(pt);
1157
1158 VIFM_SET(vifi, g->gt_grpmems)((g->gt_grpmems) |= (1 << (vifi)));
1159 logit(LOG_DEBUG7, 0, "accept graft (%s %s) gm:%x",
1160 inet_fmts(r->rt_origin, r->rt_originmask, s1),
1161 inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
1162
1163 prun_add_ttls(g);
1164 update_kernel(g);
1165#ifdef RSRR
1166 /* Send route change notification to reservation protocol. */
1167 rsrr_cache_send(g,1);
1168#endif /* RSRR */
1169 break;
1170 } else {
1171 ptnp = &pt->pt_next;
1172 }
1173 }
1174
1175 /* send ack downstream */
1176 send_graft_ack(dst, src, graft_src, graft_grp);
1177 g->gt_timer = max_prune_lifetime;
1178
1179 if (g->gt_prsent_timer) {
1180 /* set the flag for graft retransmission */
1181 g->gt_grftsnt = 1;
1182
1183 /* send graft upwards */
1184 send_graft(g);
1185
1186 /* reset the prune sent timer */
1187 g->gt_prsent_timer = 0;
1188 }
1189 } else {
1190 /*
1191 * We have no state for the source and group in question.
1192 * We can simply acknowledge the graft, since we know
1193 * that we have no prune state, and grafts are requests
1194 * to remove prune state.
1195 */
1196 send_graft_ack(dst, src, graft_src, graft_grp);
1197 logit(LOG_DEBUG7, 0, "%s (%s %s) from %s",
1198 "graft received with no kernel entry for",
1199 inet_fmt(graft_src, s1), inet_fmt(graft_grp, s2),
1200 inet_fmt(src, s3));
1201 return;
1202 }
1203}
1204
1205/*
1206 * find out which group is involved first of all
1207 * then determine if a graft was sent.
1208 * if no graft sent, ignore the message
1209 * if graft was sent and the ack is from the right
1210 * source, remove the graft timer so that we don't
1211 * have send a graft again
1212 */
1213void
1214accept_g_ack(u_int32_t src, u_int32_t dst, char *p, int datalen)
1215{
1216 struct gtable *g;
1217 vifi_t vifi;
1218 u_int32_t grft_src;
1219 u_int32_t grft_grp;
1220 int i;
1221
1222 if ((vifi = find_vif(src, dst)) == NO_VIF((vifi_t)32)) {
1223 logit(LOG_INFO6, 0,
1224 "ignoring graft ack from non-neighbor %s",
1225 inet_fmt(src, s1));
1226 return;
1227 }
1228
1229 if (datalen < 0 || datalen > 8) {
1230 logit(LOG_WARNING4, 0,
1231 "received non-decipherable graft ack from %s",
1232 inet_fmt(src, s1));
1233 return;
1234 }
1235
1236 for (i = 0; i< 4; i++)
1237 ((char *)&grft_src)[i] = *p++;
1238 for (i = 0; i< 4; i++)
1239 ((char *)&grft_grp)[i] = *p++;
1240
1241 logit(LOG_DEBUG7, 0, "%s on vif %d acks graft (%s, %s)",
1242 inet_fmt(src, s1), vifi,
1243 inet_fmt(grft_src, s2), inet_fmt(grft_grp, s3));
1244
1245 /*
1246 * Find the subnet for the graft ack
1247 */
1248 if (find_src_grp(grft_src, 0, grft_grp)) {
1249 g = gtp ? gtp->gt_gnext : kernel_table;
1250 g->gt_grftsnt = 0;
1251 } else {
1252 logit(LOG_WARNING4, 0, "%s (%s, %s) from %s",
1253 "rcvd graft ack with no kernel entry for",
1254 inet_fmt(grft_src, s1), inet_fmt(grft_grp, s2),
1255 inet_fmt(src, s3));
1256 return;
1257 }
1258}
1259
1260
1261/*
1262 * free all prune entries and kernel routes
1263 * normally, this should inform the kernel that all of its routes
1264 * are going away, but this is only called by restart(), which is
1265 * about to call MRT_DONE which does that anyway.
1266 */
1267void
1268free_all_prunes(void)
1269{
1270 struct rtentry *r;
1271 struct gtable *g, *prev_g;
1272 struct stable *s, *prev_s;
1273 struct ptable *p, *prev_p;
1274
1275 for (r = routing_table; r; r = r->rt_next) {
1276 g = r->rt_groups;
1277 while (g) {
1278 s = g->gt_srctbl;
1279 while (s) {
1280 prev_s = s;
1281 s = s->st_next;
1282 free(prev_s);
1283 }
1284
1285 p = g->gt_pruntbl;
1286 while (p) {
1287 prev_p = p;
1288 p = p->pt_next;
1289 free(prev_p);
1290 }
1291
1292 prev_g = g;
1293 g = g->gt_next;
1294 free(prev_g);
1295 }
1296 r->rt_groups = NULL((void *)0);
1297 }
1298 kernel_table = NULL((void *)0);
1299
1300 g = kernel_no_route;
1301 while (g) {
1302 free(g->gt_srctbl);
1303
1304 prev_g = g;
1305 g = g->gt_next;
1306 free(prev_g);
1307 }
1308 kernel_no_route = NULL((void *)0);
1309}
1310
1311/*
1312 * When a new route is created, search
1313 * a) The less-specific part of the routing table
1314 * b) The route-less kernel table
1315 * for sources that the new route might want to handle.
1316 *
1317 * "Inheriting" these sources might be cleanest, but simply deleting
1318 * them is easier, and letting the kernel re-request them.
1319 */
1320void
1321steal_sources(struct rtentry *rt)
1322{
1323 struct rtentry *rp;
1324 struct gtable *gt, **gtnp;
1325 struct stable *st, **stnp;
1326
1327 for (rp = rt->rt_next; rp; rp = rp->rt_next) {
1328 if ((rt->rt_origin & rp->rt_originmask) == rp->rt_origin) {
1329 logit(LOG_DEBUG7, 0, "Route for %s stealing sources from %s",
1330 inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
1331 inet_fmts(rp->rt_origin, rp->rt_originmask, s2));
1332 for (gt = rp->rt_groups; gt; gt = gt->gt_next) {
1333 stnp = &gt->gt_srctbl;
1334 while ((st = *stnp) != NULL((void *)0)) {
1335 if ((st->st_origin & rt->rt_originmask) == rt->rt_origin) {
1336 logit(LOG_DEBUG7, 0, "%s stealing (%s %s) from %s",
1337 inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
1338 inet_fmt(st->st_origin, s3),
1339 inet_fmt(gt->gt_mcastgrp, s4),
1340 inet_fmts(rp->rt_origin, rp->rt_originmask, s2));
1341 if (k_del_rg(st->st_origin, gt) < 0) {
1342 logit(LOG_WARNING4, errno(*__errno()), "%s (%s, %s)",
1343 "steal_sources trying to delete",
1344 inet_fmt(st->st_origin, s1),
1345 inet_fmt(gt->gt_mcastgrp, s2));
1346 }
1347 *stnp = st->st_next;
1348 kroutes--;
1349 free(st);
1350 } else {
1351 stnp = &st->st_next;
1352 }
1353 }
1354 }
1355 }
1356 }
1357
1358 gtnp = &kernel_no_route;
1359 while ((gt = *gtnp) != NULL((void *)0)) {
1360 if (gt->gt_srctbl && ((gt->gt_srctbl->st_origin & rt->rt_originmask)
1361 == rt->rt_origin)) {
1362 logit(LOG_DEBUG7, 0, "%s stealing (%s %s) from %s",
1363 inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
1364 inet_fmt(gt->gt_srctbl->st_origin, s3),
1365 inet_fmt(gt->gt_mcastgrp, s4),
1366 "no_route table");
1367 if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
1368 logit(LOG_WARNING4, errno(*__errno()), "%s (%s %s)",
1369 "steal_sources trying to delete",
1370 inet_fmt(gt->gt_srctbl->st_origin, s1),
1371 inet_fmt(gt->gt_mcastgrp, s2));
1372 }
1373 kroutes--;
1374 free(gt->gt_srctbl);
1375 *gtnp = gt->gt_next;
1376 if (gt->gt_next)
1377 gt->gt_next->gt_prev = gt->gt_prev;
1378 free(gt);
1379 } else {
1380 gtnp = &gt->gt_next;
1381 }
1382 }
1383}
1384
1385/*
1386 * Advance the timers on all the cache entries.
1387 * If there are any entries whose timers have expired,
1388 * remove these entries from the kernel cache.
1389 */
1390void
1391age_table_entry(void)
1392{
1393 struct rtentry *r;
1394 struct gtable *gt, **gtnptr;
1395 struct stable *st, **stnp;
1396 struct ptable *pt, **ptnp;
1397 struct sioc_sg_req sg_req;
1398
1399 logit(LOG_DEBUG7, 0, "ageing entries");
1400
1401 gtnptr = &kernel_table;
1402 while ((gt = *gtnptr) != NULL((void *)0)) {
1403 r = gt->gt_route;
1404
1405 /* advance the timer for the kernel entry */
1406 gt->gt_timer -= ROUTE_MAX_REPORT_DELAY5;
1407
1408 /* decrement prune timer if need be */
1409 if (gt->gt_prsent_timer > 0) {
1410 gt->gt_prsent_timer -= ROUTE_MAX_REPORT_DELAY5;
1411 if (gt->gt_prsent_timer <= 0) {
1412 logit(LOG_DEBUG7, 0, "upstream prune tmo (%s %s)",
1413 inet_fmts(r->rt_origin, r->rt_originmask, s1),
1414 inet_fmt(gt->gt_mcastgrp, s2));
1415 gt->gt_prsent_timer = -1;
1416 }
1417 }
1418
1419 /* retransmit graft if graft sent flag is still set */
1420 if (gt->gt_grftsnt) {
1421 switch(gt->gt_grftsnt++) {
1422 case 2:
1423 case 4:
1424 case 8:
1425 case 16:
1426 case 32:
1427 case 64:
1428 case 128:
1429 send_graft(gt);
1430 break;
1431 default:
1432 break;
1433 }
1434 }
1435
1436 /*
1437 * Age prunes
1438 *
1439 * If a prune expires, forward again on that vif.
1440 */
1441 ptnp = &gt->gt_pruntbl;
1442 while ((pt = *ptnp) != NULL((void *)0)) {
1443 if ((pt->pt_timer -= ROUTE_MAX_REPORT_DELAY5) <= 0) {
1444 logit(LOG_DEBUG7, 0, "expire prune (%s %s) from %s on vif %d",
1445 inet_fmts(r->rt_origin, r->rt_originmask, s1),
1446 inet_fmt(gt->gt_mcastgrp, s2),
1447 inet_fmt(pt->pt_router, s3),
1448 pt->pt_vifi);
1449
1450 expire_prune(pt->pt_vifi, gt);
1451
1452 /* remove the router's prune entry and await new one */
1453 *ptnp = pt->pt_next;
1454 free(pt);
1455 } else {
1456 ptnp = &pt->pt_next;
1457 }
1458 }
1459
1460 /*
1461 * If the cache entry has expired, delete source table entries for
1462 * silent sources. If there are no source entries left, and there
1463 * are no downstream prunes, then the entry is deleted.
1464 * Otherwise, the cache entry's timer is refreshed.
1465 */
1466 if (gt->gt_timer <= 0) {
1467 /* Check for traffic before deleting source entries */
1468 sg_req.grp.s_addr = gt->gt_mcastgrp;
1469 stnp = &gt->gt_srctbl;
1470 while ((st = *stnp) != NULL((void *)0)) {
1471 sg_req.src.s_addr = st->st_origin;
1472 if (ioctl(udp_socket, SIOCGETSGCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct sioc_sg_req) & 0x1fff) << 16) | ((('u')) <<
8) | ((52)))
, (char *)&sg_req) == -1) {
1473 logit(LOG_WARNING4, errno(*__errno()), "%s (%s %s)",
1474 "age_table_entry: SIOCGETSGCNT failing for",
1475 inet_fmt(st->st_origin, s1),
1476 inet_fmt(gt->gt_mcastgrp, s2));
1477 /* Make sure it gets deleted below */
1478 sg_req.pktcnt = st->st_pktcnt;
1479 }
1480 if (sg_req.pktcnt == st->st_pktcnt) {
1481 *stnp = st->st_next;
1482 logit(LOG_DEBUG7, 0, "age_table_entry deleting (%s %s)",
1483 inet_fmt(st->st_origin, s1),
1484 inet_fmt(gt->gt_mcastgrp, s2));
1485 if (k_del_rg(st->st_origin, gt) < 0) {
1486 logit(LOG_WARNING4, errno(*__errno()),
1487 "age_table_entry trying to delete (%s %s)",
1488 inet_fmt(st->st_origin, s1),
1489 inet_fmt(gt->gt_mcastgrp, s2));
1490 }
1491 kroutes--;
1492 free(st);
1493 } else {
1494 st->st_pktcnt = sg_req.pktcnt;
1495 stnp = &st->st_next;
1496 }
1497 }
1498
1499 /*
1500 * Retain the group entry if we have downstream prunes or if
1501 * there is at least one source in the list that still has
1502 * traffic, or if our upstream prune timer is running.
1503 */
1504 if (gt->gt_pruntbl != NULL((void *)0) || gt->gt_srctbl != NULL((void *)0) ||
1505 gt->gt_prsent_timer > 0) {
1506 gt->gt_timer = CACHE_LIFETIME(cache_lifetime)((cache_lifetime) + (arc4random_uniform(cache_lifetime)));
1507 if (gt->gt_prsent_timer == -1) {
1508 if (gt->gt_grpmems == 0)
1509 send_prune(gt);
1510 else
1511 gt->gt_prsent_timer = 0;
1512 }
1513 gtnptr = &gt->gt_gnext;
1514 continue;
1515 }
1516
1517 logit(LOG_DEBUG7, 0, "timeout cache entry (%s, %s)",
1518 inet_fmts(r->rt_origin, r->rt_originmask, s1),
1519 inet_fmt(gt->gt_mcastgrp, s2));
1520
1521 if (gt->gt_prev)
1522 gt->gt_prev->gt_next = gt->gt_next;
1523 else
1524 gt->gt_route->rt_groups = gt->gt_next;
1525 if (gt->gt_next)
1526 gt->gt_next->gt_prev = gt->gt_prev;
1527
1528 if (gt->gt_gprev) {
1529 gt->gt_gprev->gt_gnext = gt->gt_gnext;
1530 gtnptr = &gt->gt_gprev->gt_gnext;
1531 } else {
1532 kernel_table = gt->gt_gnext;
1533 gtnptr = &kernel_table;
1534 }
1535 if (gt->gt_gnext)
1536 gt->gt_gnext->gt_gprev = gt->gt_gprev;
1537
1538#ifdef RSRR
1539 /* Send route change notification to reservation protocol. */
1540 rsrr_cache_send(gt,0);
1541 rsrr_cache_clean(gt);
1542#endif /* RSRR */
1543 free((char *)gt);
1544 } else {
1545 if (gt->gt_prsent_timer == -1) {
1546 if (gt->gt_grpmems == 0)
1547 send_prune(gt);
1548 else
1549 gt->gt_prsent_timer = 0;
1550 }
1551 gtnptr = &gt->gt_gnext;
1552 }
1553 }
1554
1555 /*
1556 * When traversing the no_route table, the decision is much easier.
1557 * Just delete it if it has timed out.
1558 */
1559 gtnptr = &kernel_no_route;
1560 while ((gt = *gtnptr) != NULL((void *)0)) {
1561 /* advance the timer for the kernel entry */
1562 gt->gt_timer -= ROUTE_MAX_REPORT_DELAY5;
1563
1564 if (gt->gt_timer < 0) {
1565 if (gt->gt_srctbl) {
1566 if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
1567 logit(LOG_WARNING4, errno(*__errno()), "%s (%s %s)",
1568 "age_table_entry trying to delete no-route",
1569 inet_fmt(gt->gt_srctbl->st_origin, s1),
1570 inet_fmt(gt->gt_mcastgrp, s2));
1571 }
1572 free(gt->gt_srctbl);
1573 }
1574 *gtnptr = gt->gt_next;
1575 if (gt->gt_next)
1576 gt->gt_next->gt_prev = gt->gt_prev;
1577
1578 free((char *)gt);
1579 } else {
1580 gtnptr = &gt->gt_next;
1581 }
1582 }
1583}
1584
1585/*
1586 * Modify the kernel to forward packets when one or multiple prunes that
1587 * were received on the vif given by vifi, for the group given by gt,
1588 * have expired.
1589 */
1590static void
1591expire_prune(vifi_t vifi, struct gtable *gt)
1592{
1593 /*
1594 * No need to send a graft, any prunes that we sent
1595 * will expire before any prunes that we have received.
1596 */
1597 if (gt->gt_prsent_timer > 0) {
1598 logit(LOG_DEBUG7, 0, "prune expired with %d left on %s",
1599 gt->gt_prsent_timer, "prsent_timer");
1600 gt->gt_prsent_timer = 0;
1601 }
1602
1603 /* modify the kernel entry to forward packets */
1604 if (!VIFM_ISSET(vifi, gt->gt_grpmems)((gt->gt_grpmems) & (1 << (vifi)))) {
1605 struct rtentry *rt = gt->gt_route;
1606 VIFM_SET(vifi, gt->gt_grpmems)((gt->gt_grpmems) |= (1 << (vifi)));
1607 logit(LOG_DEBUG7, 0, "forw again (%s %s) gm:%x vif:%d",
1608 inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
1609 inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems, vifi);
1610
1611 prun_add_ttls(gt);
1612 update_kernel(gt);
1613#ifdef RSRR
1614 /* Send route change notification to reservation protocol. */
1615 rsrr_cache_send(gt,1);
1616#endif /* RSRR */
1617 }
1618}
1619
1620
1621static char *
1622scaletime(time_t t)
1623{
1624 static char buf1[5];
1625 static char buf2[5];
1626 static char *buf=buf1;
1627 char s;
1628 char *p;
1629
1630 p = buf;
1631 if (buf == buf1)
1632 buf = buf2;
1633 else
1634 buf = buf1;
1635
1636 if (t < 120) {
1637 s = 's';
1638 } else if (t < 3600) {
1639 t /= 60;
1640 s = 'm';
1641 } else if (t < 86400) {
1642 t /= 3600;
1643 s = 'h';
1644 } else if (t < 864000) {
1645 t /= 86400;
1646 s = 'd';
1647 } else {
1648 t /= 604800;
1649 s = 'w';
1650 }
1651 if (t > 999)
1652 return "*** ";
1653
1654 snprintf(p, 5, "%3d%c", (int)t, s);
1655
1656 return p;
1657}
1658
1659/*
1660 * Print the contents of the cache table on file 'fp2'.
1661 */
1662void
1663dump_cache(FILE *fp2)
1664{
1665 struct rtentry *r;
1666 struct gtable *gt;
1667 struct stable *st;
1668 vifi_t i;
1669 time_t thyme = time(NULL((void *)0));
1670
1671 fprintf(fp2,
1672 "Multicast Routing Cache Table (%d entries)\n%s", kroutes,
1673 " Origin Mcast-group CTmr Age Ptmr IVif Forwvifs\n");
1674
1675 for (gt = kernel_no_route; gt; gt = gt->gt_next) {
1676 if (gt->gt_srctbl) {
1677 fprintf(fp2, " %-18s %-15s %-4s %-4s - -1\n",
1678 inet_fmts(gt->gt_srctbl->st_origin, 0xffffffff, s1),
1679 inet_fmt(gt->gt_mcastgrp, s2), scaletime(gt->gt_timer),
1680 scaletime(thyme - gt->gt_ctime));
1681 fprintf(fp2, ">%s\n", inet_fmt(gt->gt_srctbl->st_origin, s1));
1682 }
1683 }
1684
1685 for (gt = kernel_table; gt; gt = gt->gt_gnext) {
1686 r = gt->gt_route;
1687 fprintf(fp2, " %-18s %-15s",
1688 inet_fmts(r->rt_origin, r->rt_originmask, s1),
1689 inet_fmt(gt->gt_mcastgrp, s2));
1690
1691 fprintf(fp2, " %-4s", scaletime(gt->gt_timer));
1692
1693 fprintf(fp2, " %-4s %-4s ", scaletime(thyme - gt->gt_ctime),
1694 gt->gt_prsent_timer ? scaletime(gt->gt_prsent_timer) :
1695 " -");
1696
1697 fprintf(fp2, "%2u%c%c ", r->rt_parent,
1698 gt->gt_prsent_timer ? 'P' : ' ',
1699 VIFM_ISSET(r->rt_parent, gt->gt_scope)((gt->gt_scope) & (1 << (r->rt_parent))) ? 'B' : ' ');
1700
1701 for (i = 0; i < numvifs; ++i) {
1702 if (VIFM_ISSET(i, gt->gt_grpmems)((gt->gt_grpmems) & (1 << (i))))
1703 fprintf(fp2, " %u ", i);
1704 else if (VIFM_ISSET(i, r->rt_children)((r->rt_children) & (1 << (i))) &&
1705 !VIFM_ISSET(i, r->rt_leaves)((r->rt_leaves) & (1 << (i))))
1706 fprintf(fp2, " %u%c", i,
1707 VIFM_ISSET(i, gt->gt_scope)((gt->gt_scope) & (1 << (i))) ? 'b' : 'p');
1708 }
1709 fprintf(fp2, "\n");
1710 for (st = gt->gt_srctbl; st; st = st->st_next) {
1711 fprintf(fp2, ">%s\n", inet_fmt(st->st_origin, s1));
1712 }
1713#ifdef DEBUG_PRUNES
1714 for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) {
1715 fprintf(fp2, "<r:%s v:%d t:%d\n", inet_fmt(pt->pt_router, s1),
1716 pt->pt_vifi, pt->pt_timer);
1717 }
1718#endif
1719 }
1720}
1721
1722/*
1723 * Traceroute function which returns traceroute replies to the requesting
1724 * router. Also forwards the request to downstream routers.
1725 * NOTE: u_int no is narrowed to u_char
1726 */
1727void
1728accept_mtrace(u_int32_t src, u_int32_t dst, u_int32_t group,
1729 char *data, u_int no, int datalen)
1730{
1731 u_char type;
1732 struct rtentry *rt;
1733 struct gtable *gt;
1734 struct tr_query *qry;
1735 struct tr_resp *resp;
1736 int vifi;
1737 char *p;
1738 int rcount;
1739 int errcode = TR_NO_ERR0;
1740 int resptype;
1741 struct timeval tp;
1742 struct sioc_vif_req v_req;
1743 struct sioc_sg_req sg_req;
1744
1745 /* Remember qid across invocations */
1746 static u_int32_t oqid = 0;
1747
1748 /* timestamp the request/response */
1749 gettimeofday(&tp, 0);
1750
1751 /*
1752 * Check if it is a query or a response
1753 */
1754 if (datalen == QLENsizeof(struct tr_query)) {
1755 type = QUERY1;
1756 logit(LOG_DEBUG7, 0, "Initial traceroute query rcvd from %s to %s",
1757 inet_fmt(src, s1), inet_fmt(dst, s2));
1758 }
1759 else if ((datalen - QLENsizeof(struct tr_query)) % RLENsizeof(struct tr_resp) == 0) {
1760 type = RESP2;
1761 logit(LOG_DEBUG7, 0, "In-transit traceroute query rcvd from %s to %s",
1762 inet_fmt(src, s1), inet_fmt(dst, s2));
1763 if (IN_MULTICAST(ntohl(dst))(((u_int32_t)((__uint32_t)(__builtin_constant_p(dst) ? (__uint32_t
)(((__uint32_t)(dst) & 0xff) << 24 | ((__uint32_t)(
dst) & 0xff00) << 8 | ((__uint32_t)(dst) & 0xff0000
) >> 8 | ((__uint32_t)(dst) & 0xff000000) >> 24
) : __swap32md(dst))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t
)(0xe0000000)))
) {
1764 logit(LOG_DEBUG7, 0, "Dropping multicast response");
1765 return;
1766 }
1767 }
1768 else {
1769 logit(LOG_WARNING4, 0, "%s from %s to %s",
1770 "Non decipherable traceroute request received",
1771 inet_fmt(src, s1), inet_fmt(dst, s2));
1772 return;
1773 }
1774
1775 qry = (struct tr_query *)data;
1776
1777 /*
1778 * if it is a packet with all reports filled, drop it
1779 */
1780 if ((rcount = (datalen - QLENsizeof(struct tr_query))/RLENsizeof(struct tr_resp)) == no) {
1781 logit(LOG_DEBUG7, 0, "packet with all reports filled in");
1782 return;
1783 }
1784
1785 logit(LOG_DEBUG7, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1),
1786 inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3));
1787 logit(LOG_DEBUG7, 0, "rttl: %d rd: %s", qry->tr_rttlq.ttl,
1788 inet_fmt(qry->tr_raddr, s1));
1789 logit(LOG_DEBUG7, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qidq.qid);
1790
1791 /* determine the routing table entry for this traceroute */
1792 rt = determine_route(qry->tr_src);
1793 if (rt) {
1794 logit(LOG_DEBUG7, 0, "rt parent vif: %d rtr: %s metric: %d",
1795 rt->rt_parent, inet_fmt(rt->rt_gateway, s1), rt->rt_metric);
1796 logit(LOG_DEBUG7, 0, "rt origin %s",
1797 inet_fmts(rt->rt_origin, rt->rt_originmask, s1));
1798 } else
1799 logit(LOG_DEBUG7, 0, "...no route");
1800
1801 /*
1802 * Query type packet - check if rte exists
1803 * Check if the query destination is a vif connected to me.
1804 * and if so, whether I should start response back
1805 */
1806 if (type == QUERY1) {
1807 if (oqid == qry->tr_qidq.qid) {
1808 /*
1809 * If the multicast router is a member of the group being
1810 * queried, and the query is multicasted, then the router can
1811 * receive multiple copies of the same query. If we have already
1812 * replied to this traceroute, just ignore it this time.
1813 *
1814 * This is not a total solution, but since if this fails you
1815 * only get N copies, N <= the number of interfaces on the router,
1816 * it is not fatal.
1817 */
1818 logit(LOG_DEBUG7, 0, "ignoring duplicate traceroute packet");
1819 return;
1820 }
1821
1822 if (rt == NULL((void *)0)) {
1823 logit(LOG_DEBUG7, 0, "Mcast traceroute: no route entry %s",
1824 inet_fmt(qry->tr_src, s1));
1825 if (IN_MULTICAST(ntohl(dst))(((u_int32_t)((__uint32_t)(__builtin_constant_p(dst) ? (__uint32_t
)(((__uint32_t)(dst) & 0xff) << 24 | ((__uint32_t)(
dst) & 0xff00) << 8 | ((__uint32_t)(dst) & 0xff0000
) >> 8 | ((__uint32_t)(dst) & 0xff000000) >> 24
) : __swap32md(dst))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t
)(0xe0000000)))
)
1826 return;
1827 }
1828 vifi = find_vif(qry->tr_dst, 0);
1829
1830 if (vifi == NO_VIF((vifi_t)32)) {
1831 /* The traceroute destination is not on one of my subnet vifs. */
1832 logit(LOG_DEBUG7, 0, "Destination %s not an interface",
1833 inet_fmt(qry->tr_dst, s1));
1834 if (IN_MULTICAST(ntohl(dst))(((u_int32_t)((__uint32_t)(__builtin_constant_p(dst) ? (__uint32_t
)(((__uint32_t)(dst) & 0xff) << 24 | ((__uint32_t)(
dst) & 0xff00) << 8 | ((__uint32_t)(dst) & 0xff0000
) >> 8 | ((__uint32_t)(dst) & 0xff000000) >> 24
) : __swap32md(dst))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t
)(0xe0000000)))
)
1835 return;
1836 errcode = TR_WRONG_IF1;
1837 } else if (rt != NULL((void *)0) && !VIFM_ISSET(vifi, rt->rt_children)((rt->rt_children) & (1 << (vifi)))) {
1838 logit(LOG_DEBUG7, 0, "Destination %s not on forwarding tree for src %s",
1839 inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
1840 if (IN_MULTICAST(ntohl(dst))(((u_int32_t)((__uint32_t)(__builtin_constant_p(dst) ? (__uint32_t
)(((__uint32_t)(dst) & 0xff) << 24 | ((__uint32_t)(
dst) & 0xff00) << 8 | ((__uint32_t)(dst) & 0xff0000
) >> 8 | ((__uint32_t)(dst) & 0xff000000) >> 24
) : __swap32md(dst))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t
)(0xe0000000)))
)
1841 return;
1842 errcode = TR_WRONG_IF1;
1843 }
1844 }
1845 else {
1846 /*
1847 * determine which interface the packet came in on
1848 * RESP packets travel hop-by-hop so this either traversed
1849 * a tunnel or came from a directly attached mrouter.
1850 */
1851 if ((vifi = find_vif(src, dst)) == NO_VIF((vifi_t)32)) {
1852 logit(LOG_DEBUG7, 0, "Wrong interface for packet");
1853 errcode = TR_WRONG_IF1;
1854 }
1855 }
1856
1857 /* Now that we've decided to send a response, save the qid */
1858 oqid = qry->tr_qidq.qid;
1859
1860 logit(LOG_DEBUG7, 0, "Sending traceroute response");
1861
1862 /* copy the packet to the sending buffer */
1863 p = send_buf + MIN_IP_HEADER_LEN20 + IGMP_MINLEN8;
1864
1865 bcopy(data, p, datalen);
1866
1867 p += datalen;
1868
1869 /*
1870 * If there is no room to insert our reply, coopt the previous hop
1871 * error indication to relay this fact.
1872 */
1873 if (p + sizeof(struct tr_resp) > send_buf + RECV_BUF_SIZE8192) {
1874 resp = (struct tr_resp *)p - 1;
1875 resp->tr_rflags = TR_NO_SPACE0x81;
1876 rt = NULL((void *)0);
1877 goto sendit;
1878 }
1879
1880 /*
1881 * fill in initial response fields
1882 */
1883 resp = (struct tr_resp *)p;
1884 bzero(resp, sizeof(struct tr_resp));
1885 datalen += RLENsizeof(struct tr_resp);
1886
1887 resp->tr_qarr = htonl((tp.tv_sec + JAN_1970) << 16)(__uint32_t)(__builtin_constant_p((tp.tv_sec + 2208988800UL) <<
16) ? (__uint32_t)(((__uint32_t)((tp.tv_sec + 2208988800UL) <<
16) & 0xff) << 24 | ((__uint32_t)((tp.tv_sec + 2208988800UL
) << 16) & 0xff00) << 8 | ((__uint32_t)((tp.tv_sec
+ 2208988800UL) << 16) & 0xff0000) >> 8 | ((
__uint32_t)((tp.tv_sec + 2208988800UL) << 16) & 0xff000000
) >> 24) : __swap32md((tp.tv_sec + 2208988800UL) <<
16))
+
1888 ((tp.tv_usec >> 4) & 0xffff);
1889
1890 resp->tr_rproto = PROTO_DVMRP1;
1891 if (errcode != TR_NO_ERR0) {
1892 resp->tr_rflags = errcode;
1893 rt = NULL((void *)0); /* hack to enforce send straight to requestor */
1894 goto sendit;
1895 }
1896 resp->tr_outaddr = uvifs[vifi].uv_lcl_addr;
1897 resp->tr_fttl = uvifs[vifi].uv_threshold;
1898 resp->tr_rflags = TR_NO_ERR0;
1899
1900 /*
1901 * obtain # of packets out on interface
1902 */
1903 v_req.vifi = vifi;
1904 if (ioctl(udp_socket, SIOCGETVIFCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct sioc_vif_req) & 0x1fff) << 16) | ((('u')) <<
8) | ((51)))
, (char *)&v_req) == 0)
1905 resp->tr_vifout = htonl(v_req.ocount)(__uint32_t)(__builtin_constant_p(v_req.ocount) ? (__uint32_t
)(((__uint32_t)(v_req.ocount) & 0xff) << 24 | ((__uint32_t
)(v_req.ocount) & 0xff00) << 8 | ((__uint32_t)(v_req
.ocount) & 0xff0000) >> 8 | ((__uint32_t)(v_req.ocount
) & 0xff000000) >> 24) : __swap32md(v_req.ocount))
;
1906
1907 /*
1908 * fill in scoping & pruning information
1909 */
1910 if (rt)
1911 for (gt = rt->rt_groups; gt; gt = gt->gt_next) {
1912 if (gt->gt_mcastgrp >= group)
1913 break;
1914 }
1915 else
1916 gt = NULL((void *)0);
1917
1918 if (gt && gt->gt_mcastgrp == group) {
1919 sg_req.src.s_addr = qry->tr_src;
1920 sg_req.grp.s_addr = group;
1921 if (ioctl(udp_socket, SIOCGETSGCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct sioc_sg_req) & 0x1fff) << 16) | ((('u')) <<
8) | ((52)))
, (char *)&sg_req) == 0)
1922 resp->tr_pktcnt = htonl(sg_req.pktcnt)(__uint32_t)(__builtin_constant_p(sg_req.pktcnt) ? (__uint32_t
)(((__uint32_t)(sg_req.pktcnt) & 0xff) << 24 | ((__uint32_t
)(sg_req.pktcnt) & 0xff00) << 8 | ((__uint32_t)(sg_req
.pktcnt) & 0xff0000) >> 8 | ((__uint32_t)(sg_req.pktcnt
) & 0xff000000) >> 24) : __swap32md(sg_req.pktcnt))
;
1923
1924 if (VIFM_ISSET(vifi, gt->gt_scope)((gt->gt_scope) & (1 << (vifi))))
1925 resp->tr_rflags = TR_SCOPED4;
1926 else if (gt->gt_prsent_timer)
1927 resp->tr_rflags = TR_PRUNED2;
1928 else if (!VIFM_ISSET(vifi, gt->gt_grpmems)((gt->gt_grpmems) & (1 << (vifi)))) {
1929 if (VIFM_ISSET(vifi, rt->rt_children)((rt->rt_children) & (1 << (vifi))) &&
1930 !VIFM_ISSET(vifi, rt->rt_leaves)((rt->rt_leaves) & (1 << (vifi))))
1931 resp->tr_rflags = TR_OPRUNED3;
1932 else
1933 resp->tr_rflags = TR_NO_FWD7;
1934 }
1935 } else {
1936 if (scoped_addr(vifi, group))
1937 resp->tr_rflags = TR_SCOPED4;
1938 else if (rt && !VIFM_ISSET(vifi, rt->rt_children)((rt->rt_children) & (1 << (vifi))))
1939 resp->tr_rflags = TR_NO_FWD7;
1940 }
1941
1942 /*
1943 * if no rte exists, set NO_RTE error
1944 */
1945 if (rt == NULL((void *)0)) {
1946 src = dst; /* the dst address of resp. pkt */
1947 resp->tr_inaddr = 0;
1948 resp->tr_rflags = TR_NO_RTE5;
1949 resp->tr_rmtaddr = 0;
1950 } else {
1951 /* get # of packets in on interface */
1952 v_req.vifi = rt->rt_parent;
1953 if (ioctl(udp_socket, SIOCGETVIFCNT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct sioc_vif_req) & 0x1fff) << 16) | ((('u')) <<
8) | ((51)))
, (char *)&v_req) == 0)
1954 resp->tr_vifin = htonl(v_req.icount)(__uint32_t)(__builtin_constant_p(v_req.icount) ? (__uint32_t
)(((__uint32_t)(v_req.icount) & 0xff) << 24 | ((__uint32_t
)(v_req.icount) & 0xff00) << 8 | ((__uint32_t)(v_req
.icount) & 0xff0000) >> 8 | ((__uint32_t)(v_req.icount
) & 0xff000000) >> 24) : __swap32md(v_req.icount))
;
1955
1956 MASK_TO_VAL(rt->rt_originmask, resp->tr_smask){ u_int32_t _x = (__uint32_t)(__builtin_constant_p(rt->rt_originmask
) ? (__uint32_t)(((__uint32_t)(rt->rt_originmask) & 0xff
) << 24 | ((__uint32_t)(rt->rt_originmask) & 0xff00
) << 8 | ((__uint32_t)(rt->rt_originmask) & 0xff0000
) >> 8 | ((__uint32_t)(rt->rt_originmask) & 0xff000000
) >> 24) : __swap32md(rt->rt_originmask)); (resp->
tr_smask) = 1; while ((_x) <<= 1) (resp->tr_smask)++
; };
;
1957 src = uvifs[rt->rt_parent].uv_lcl_addr;
1958 resp->tr_inaddr = src;
1959 resp->tr_rmtaddr = rt->rt_gateway;
1960 if (!VIFM_ISSET(vifi, rt->rt_children)((rt->rt_children) & (1 << (vifi)))) {
1961 logit(LOG_DEBUG7, 0, "Destination %s not on forwarding tree for src %s",
1962 inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
1963 resp->tr_rflags = TR_WRONG_IF1;
1964 }
1965 if (rt->rt_metric >= UNREACHABLE32) {
1966 resp->tr_rflags = TR_NO_RTE5;
1967 /* Hack to send reply directly */
1968 rt = NULL((void *)0);
1969 }
1970 }
1971
1972sendit:
1973 /*
1974 * if metric is 1 or no. of reports is 1, send response to requestor
1975 * else send to upstream router. If the upstream router can't handle
1976 * mtrace, set an error code and send to requestor anyway.
1977 */
1978 logit(LOG_DEBUG7, 0, "rcount:%d, no:%d", rcount, no);
1979
1980 if ((rcount + 1 == no) || (rt == NULL((void *)0)) || (rt->rt_metric == 1)) {
1981 resptype = IGMP_MTRACE_REPLY0x1e;
1982 dst = qry->tr_raddr;
1983 } else
1984 if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
1985 dst = qry->tr_raddr;
1986 resp->tr_rflags = TR_OLD_ROUTER0x82;
1987 resptype = IGMP_MTRACE_REPLY0x1e;
1988 } else {
1989 dst = rt->rt_gateway;
1990 resptype = IGMP_MTRACE_QUERY0x1f;
1991 }
1992
1993 if (IN_MULTICAST(ntohl(dst))(((u_int32_t)((__uint32_t)(__builtin_constant_p(dst) ? (__uint32_t
)(((__uint32_t)(dst) & 0xff) << 24 | ((__uint32_t)(
dst) & 0xff00) << 8 | ((__uint32_t)(dst) & 0xff0000
) >> 8 | ((__uint32_t)(dst) & 0xff000000) >> 24
) : __swap32md(dst))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t
)(0xe0000000)))
) {
1994 /*
1995 * Send the reply on a known multicast capable vif.
1996 * If we don't have one, we can't source any multicasts anyway.
1997 */
1998 if (phys_vif != -1) {
1999 logit(LOG_DEBUG7, 0, "Sending reply to %s from %s",
2000 inet_fmt(dst, s1), inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2));
2001 k_set_ttl(qry->tr_rttlq.ttl);
2002 send_igmp(uvifs[phys_vif].uv_lcl_addr, dst,
2003 resptype, no, group,
2004 datalen);
2005 k_set_ttl(1);
2006 } else
2007 logit(LOG_INFO6, 0, "No enabled phyints -- %s",
2008 "dropping traceroute reply");
2009 } else {
2010 logit(LOG_DEBUG7, 0, "Sending %s to %s from %s",
2011 resptype == IGMP_MTRACE_REPLY0x1e ? "reply" : "request on",
2012 inet_fmt(dst, s1), inet_fmt(src, s2));
2013
2014 send_igmp(src, dst,
2015 resptype, no, group,
2016 datalen);
2017 }
2018 return;
2019}