1 |
|
|
/* $NetBSD: vif.c,v 1.6 1995/12/10 10:07:19 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 |
|
|
#include <fcntl.h> |
15 |
|
|
|
16 |
|
|
/* |
17 |
|
|
* Exported variables. |
18 |
|
|
*/ |
19 |
|
|
struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */ |
20 |
|
|
vifi_t numvifs; /* number of vifs in use */ |
21 |
|
|
int vifs_down; /* 1=>some interfaces are down */ |
22 |
|
|
int phys_vif; /* An enabled vif */ |
23 |
|
|
int udp_socket; /* Since the honkin' kernel doesn't support */ |
24 |
|
|
/* ioctls on raw IP sockets, we need a UDP */ |
25 |
|
|
/* socket as well as our IGMP (raw) socket. */ |
26 |
|
|
/* How dumb. */ |
27 |
|
|
int vifs_with_neighbors; /* == 1 if I am a leaf */ |
28 |
|
|
|
29 |
|
|
typedef struct { |
30 |
|
|
vifi_t vifi; |
31 |
|
|
struct listaddr *g; |
32 |
|
|
int q_time; |
33 |
|
|
} cbk_t; |
34 |
|
|
|
35 |
|
|
/* |
36 |
|
|
* Forward declarations. |
37 |
|
|
*/ |
38 |
|
|
static void start_vif(vifi_t vifi); |
39 |
|
|
static void start_vif2(vifi_t vifi); |
40 |
|
|
static void stop_vif(vifi_t vifi); |
41 |
|
|
static void age_old_hosts(void); |
42 |
|
|
static void send_probe_on_vif(struct uvif *v); |
43 |
|
|
static int info_version(char *p, int); |
44 |
|
|
static void DelVif(void *arg); |
45 |
|
|
static int SetTimer(int vifi, struct listaddr *g); |
46 |
|
|
static int DeleteTimer(int id); |
47 |
|
|
static void SendQuery(void *arg); |
48 |
|
|
static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, |
49 |
|
|
int q_time); |
50 |
|
|
|
51 |
|
|
|
52 |
|
|
/* |
53 |
|
|
* Initialize the virtual interfaces, but do not install |
54 |
|
|
* them in the kernel. Start routing on all vifs that are |
55 |
|
|
* not down or disabled. |
56 |
|
|
*/ |
57 |
|
|
void |
58 |
|
|
init_vifs(void) |
59 |
|
|
{ |
60 |
|
|
vifi_t vifi; |
61 |
|
|
struct uvif *v; |
62 |
|
|
int enabled_vifs, enabled_phyints; |
63 |
|
|
extern char *configfilename; |
64 |
|
|
|
65 |
|
|
numvifs = 0; |
66 |
|
|
vifs_with_neighbors = 0; |
67 |
|
|
vifs_down = FALSE; |
68 |
|
|
|
69 |
|
|
/* |
70 |
|
|
* Configure the vifs based on the interface configuration of the |
71 |
|
|
* the kernel and the contents of the configuration file. |
72 |
|
|
* (Open a UDP socket for ioctl use in the config procedures.) |
73 |
|
|
*/ |
74 |
|
|
if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
75 |
|
|
logit(LOG_ERR, errno, "UDP socket"); |
76 |
|
|
logit(LOG_INFO,0,"Getting vifs from kernel interfaces"); |
77 |
|
|
config_vifs_from_kernel(); |
78 |
|
|
logit(LOG_INFO,0,"Getting vifs from %s",configfilename); |
79 |
|
|
config_vifs_from_file(); |
80 |
|
|
|
81 |
|
|
/* |
82 |
|
|
* Quit if there are fewer than two enabled vifs. |
83 |
|
|
*/ |
84 |
|
|
enabled_vifs = 0; |
85 |
|
|
enabled_phyints = 0; |
86 |
|
|
phys_vif = -1; |
87 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { |
88 |
|
|
if (!(v->uv_flags & VIFF_DISABLED)) { |
89 |
|
|
++enabled_vifs; |
90 |
|
|
if (!(v->uv_flags & VIFF_TUNNEL)) { |
91 |
|
|
if (phys_vif == -1) |
92 |
|
|
phys_vif = vifi; |
93 |
|
|
++enabled_phyints; |
94 |
|
|
} |
95 |
|
|
} |
96 |
|
|
} |
97 |
|
|
if (enabled_vifs < 2) |
98 |
|
|
logit(LOG_ERR, 0, "can't forward: %s", |
99 |
|
|
enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif"); |
100 |
|
|
|
101 |
|
|
if (enabled_phyints == 0) |
102 |
|
|
logit(LOG_WARNING, 0, |
103 |
|
|
"no enabled interfaces, forwarding via tunnels only"); |
104 |
|
|
|
105 |
|
|
logit(LOG_INFO, 0, "Installing vifs in mrouted..."); |
106 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { |
107 |
|
|
if (!(v->uv_flags & VIFF_DISABLED)) { |
108 |
|
|
if (!(v->uv_flags & VIFF_DOWN)) { |
109 |
|
|
if (v->uv_flags & VIFF_TUNNEL) |
110 |
|
|
logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi, |
111 |
|
|
inet_fmt(v->uv_lcl_addr, s1), |
112 |
|
|
inet_fmt(v->uv_rmt_addr, s2)); |
113 |
|
|
else |
114 |
|
|
logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi, |
115 |
|
|
inet_fmt(v->uv_lcl_addr, s1)); |
116 |
|
|
start_vif2(vifi); |
117 |
|
|
} else logit(LOG_INFO, 0, |
118 |
|
|
"%s is not yet up; vif #%u not in service", |
119 |
|
|
v->uv_name, vifi); |
120 |
|
|
} |
121 |
|
|
} |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
/* |
125 |
|
|
* Start routing on all virtual interfaces that are not down or |
126 |
|
|
* administratively disabled. |
127 |
|
|
*/ |
128 |
|
|
void |
129 |
|
|
init_installvifs(void) |
130 |
|
|
{ |
131 |
|
|
vifi_t vifi; |
132 |
|
|
struct uvif *v; |
133 |
|
|
|
134 |
|
|
logit(LOG_INFO, 0, "Installing vifs in kernel..."); |
135 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { |
136 |
|
|
if (!(v->uv_flags & VIFF_DISABLED)) { |
137 |
|
|
if (!(v->uv_flags & VIFF_DOWN)) { |
138 |
|
|
if (v->uv_flags & VIFF_TUNNEL) |
139 |
|
|
logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi, |
140 |
|
|
inet_fmt(v->uv_lcl_addr, s1), |
141 |
|
|
inet_fmt(v->uv_rmt_addr, s2)); |
142 |
|
|
else |
143 |
|
|
logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi, |
144 |
|
|
inet_fmt(v->uv_lcl_addr, s1)); |
145 |
|
|
k_add_vif(vifi, &uvifs[vifi]); |
146 |
|
|
} else logit(LOG_INFO, 0, |
147 |
|
|
"%s is not yet up; vif #%u not in service", |
148 |
|
|
v->uv_name, vifi); |
149 |
|
|
} |
150 |
|
|
} |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
/* |
154 |
|
|
* See if any interfaces have changed from up state to down, or vice versa, |
155 |
|
|
* including any non-multicast-capable interfaces that are in use as local |
156 |
|
|
* tunnel end-points. Ignore interfaces that have been administratively |
157 |
|
|
* disabled. |
158 |
|
|
*/ |
159 |
|
|
void |
160 |
|
|
check_vif_state(void) |
161 |
|
|
{ |
162 |
|
|
vifi_t vifi; |
163 |
|
|
struct uvif *v; |
164 |
|
|
struct ifreq ifr; |
165 |
|
|
|
166 |
|
|
vifs_down = FALSE; |
167 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { |
168 |
|
|
|
169 |
|
|
if (v->uv_flags & VIFF_DISABLED) continue; |
170 |
|
|
|
171 |
|
|
strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ); |
172 |
|
|
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0) |
173 |
|
|
logit(LOG_ERR, errno, |
174 |
|
|
"ioctl SIOCGIFFLAGS for %s", ifr.ifr_name); |
175 |
|
|
|
176 |
|
|
if (v->uv_flags & VIFF_DOWN) { |
177 |
|
|
if (ifr.ifr_flags & IFF_UP) { |
178 |
|
|
v->uv_flags &= ~VIFF_DOWN; |
179 |
|
|
start_vif(vifi); |
180 |
|
|
logit(LOG_INFO, 0, |
181 |
|
|
"%s has come up; vif #%u now in service", |
182 |
|
|
v->uv_name, vifi); |
183 |
|
|
} |
184 |
|
|
else vifs_down = TRUE; |
185 |
|
|
} |
186 |
|
|
else { |
187 |
|
|
if (!(ifr.ifr_flags & IFF_UP)) { |
188 |
|
|
stop_vif(vifi); |
189 |
|
|
v->uv_flags |= VIFF_DOWN; |
190 |
|
|
logit(LOG_INFO, 0, |
191 |
|
|
"%s has gone down; vif #%u taken out of service", |
192 |
|
|
v->uv_name, vifi); |
193 |
|
|
vifs_down = TRUE; |
194 |
|
|
} |
195 |
|
|
} |
196 |
|
|
} |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
/* |
200 |
|
|
* Send a probe message on vif v |
201 |
|
|
*/ |
202 |
|
|
static void |
203 |
|
|
send_probe_on_vif(struct uvif *v) |
204 |
|
|
{ |
205 |
|
|
char *p; |
206 |
|
|
int datalen = 0; |
207 |
|
|
struct listaddr *nbr; |
208 |
|
|
int i; |
209 |
|
|
|
210 |
|
|
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; |
211 |
|
|
|
212 |
|
|
for (i = 0; i < 4; i++) |
213 |
|
|
*p++ = ((char *)&(dvmrp_genid))[i]; |
214 |
|
|
datalen += 4; |
215 |
|
|
|
216 |
|
|
/* |
217 |
|
|
* add the neighbor list on the interface to the message |
218 |
|
|
*/ |
219 |
|
|
nbr = v->uv_neighbors; |
220 |
|
|
|
221 |
|
|
while (nbr) { |
222 |
|
|
for (i = 0; i < 4; i++) |
223 |
|
|
*p++ = ((char *)&nbr->al_addr)[i]; |
224 |
|
|
datalen +=4; |
225 |
|
|
nbr = nbr->al_next; |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
send_igmp(v->uv_lcl_addr, |
229 |
|
|
(v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr |
230 |
|
|
: dvmrp_group, |
231 |
|
|
IGMP_DVMRP, DVMRP_PROBE, |
232 |
|
|
htonl(MROUTED_LEVEL | |
233 |
|
|
((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS)), |
234 |
|
|
datalen); |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
/* |
238 |
|
|
* Add a vifi to the kernel and start routing on it. |
239 |
|
|
*/ |
240 |
|
|
static void |
241 |
|
|
start_vif(vifi_t vifi) |
242 |
|
|
{ |
243 |
|
|
/* |
244 |
|
|
* Install the interface in the kernel's vif structure. |
245 |
|
|
*/ |
246 |
|
|
k_add_vif(vifi, &uvifs[vifi]); |
247 |
|
|
|
248 |
|
|
start_vif2(vifi); |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
/* |
252 |
|
|
* Add a vifi to all the user-level data structures but don't add |
253 |
|
|
* it to the kernel yet. |
254 |
|
|
*/ |
255 |
|
|
static void |
256 |
|
|
start_vif2(vifi_t vifi) |
257 |
|
|
{ |
258 |
|
|
struct uvif *v; |
259 |
|
|
u_int32_t src; |
260 |
|
|
struct phaddr *p; |
261 |
|
|
|
262 |
|
|
v = &uvifs[vifi]; |
263 |
|
|
src = v->uv_lcl_addr; |
264 |
|
|
|
265 |
|
|
/* |
266 |
|
|
* Update the existing route entries to take into account the new vif. |
267 |
|
|
*/ |
268 |
|
|
add_vif_to_routes(vifi); |
269 |
|
|
|
270 |
|
|
if (!(v->uv_flags & VIFF_TUNNEL)) { |
271 |
|
|
/* |
272 |
|
|
* Join the DVMRP multicast group on the interface. |
273 |
|
|
* (This is not strictly necessary, since the kernel promiscuously |
274 |
|
|
* receives IGMP packets addressed to ANY IP multicast group while |
275 |
|
|
* multicast routing is enabled. However, joining the group allows |
276 |
|
|
* this host to receive non-IGMP packets as well, such as 'pings'.) |
277 |
|
|
*/ |
278 |
|
|
k_join(dvmrp_group, src); |
279 |
|
|
|
280 |
|
|
/* |
281 |
|
|
* Join the ALL-ROUTERS multicast group on the interface. |
282 |
|
|
* This allows mtrace requests to loop back if they are run |
283 |
|
|
* on the multicast router. |
284 |
|
|
*/ |
285 |
|
|
k_join(allrtrs_group, src); |
286 |
|
|
|
287 |
|
|
/* |
288 |
|
|
* Install an entry in the routing table for the subnet to which |
289 |
|
|
* the interface is connected. |
290 |
|
|
*/ |
291 |
|
|
start_route_updates(); |
292 |
|
|
update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi); |
293 |
|
|
for (p = v->uv_addrs; p; p = p->pa_next) { |
294 |
|
|
start_route_updates(); |
295 |
|
|
update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi); |
296 |
|
|
} |
297 |
|
|
|
298 |
|
|
/* |
299 |
|
|
* Until neighbors are discovered, assume responsibility for sending |
300 |
|
|
* periodic group membership queries to the subnet. Send the first |
301 |
|
|
* query. |
302 |
|
|
*/ |
303 |
|
|
v->uv_flags |= VIFF_QUERIER; |
304 |
|
|
send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY, |
305 |
|
|
(v->uv_flags & VIFF_IGMPV1) ? 0 : |
306 |
|
|
IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0); |
307 |
|
|
age_old_hosts(); |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; |
311 |
|
|
|
312 |
|
|
/* |
313 |
|
|
* Send a probe via the new vif to look for neighbors. |
314 |
|
|
*/ |
315 |
|
|
send_probe_on_vif(v); |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
/* |
319 |
|
|
* Stop routing on the specified virtual interface. |
320 |
|
|
*/ |
321 |
|
|
static void |
322 |
|
|
stop_vif(vifi_t vifi) |
323 |
|
|
{ |
324 |
|
|
struct uvif *v; |
325 |
|
|
struct listaddr *a; |
326 |
|
|
struct phaddr *p; |
327 |
|
|
|
328 |
|
|
v = &uvifs[vifi]; |
329 |
|
|
|
330 |
|
|
if (!(v->uv_flags & VIFF_TUNNEL)) { |
331 |
|
|
/* |
332 |
|
|
* Depart from the DVMRP multicast group on the interface. |
333 |
|
|
*/ |
334 |
|
|
k_leave(dvmrp_group, v->uv_lcl_addr); |
335 |
|
|
|
336 |
|
|
/* |
337 |
|
|
* Depart from the ALL-ROUTERS multicast group on the interface. |
338 |
|
|
*/ |
339 |
|
|
k_leave(allrtrs_group, v->uv_lcl_addr); |
340 |
|
|
|
341 |
|
|
/* |
342 |
|
|
* Update the entry in the routing table for the subnet to which |
343 |
|
|
* the interface is connected, to take into account the interface |
344 |
|
|
* failure. |
345 |
|
|
*/ |
346 |
|
|
start_route_updates(); |
347 |
|
|
update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi); |
348 |
|
|
for (p = v->uv_addrs; p; p = p->pa_next) { |
349 |
|
|
start_route_updates(); |
350 |
|
|
update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi); |
351 |
|
|
} |
352 |
|
|
|
353 |
|
|
/* |
354 |
|
|
* Discard all group addresses. (No need to tell kernel; |
355 |
|
|
* the k_del_vif() call, below, will clean up kernel state.) |
356 |
|
|
*/ |
357 |
|
|
while (v->uv_groups != NULL) { |
358 |
|
|
a = v->uv_groups; |
359 |
|
|
v->uv_groups = a->al_next; |
360 |
|
|
free((char *)a); |
361 |
|
|
} |
362 |
|
|
|
363 |
|
|
v->uv_flags &= ~VIFF_QUERIER; |
364 |
|
|
} |
365 |
|
|
|
366 |
|
|
/* |
367 |
|
|
* Update the existing route entries to take into account the vif failure. |
368 |
|
|
*/ |
369 |
|
|
delete_vif_from_routes(vifi); |
370 |
|
|
|
371 |
|
|
/* |
372 |
|
|
* Delete the interface from the kernel's vif structure. |
373 |
|
|
*/ |
374 |
|
|
k_del_vif(vifi); |
375 |
|
|
|
376 |
|
|
/* |
377 |
|
|
* Discard all neighbor addresses. |
378 |
|
|
*/ |
379 |
|
|
if (v->uv_neighbors) |
380 |
|
|
vifs_with_neighbors--; |
381 |
|
|
|
382 |
|
|
while (v->uv_neighbors != NULL) { |
383 |
|
|
a = v->uv_neighbors; |
384 |
|
|
v->uv_neighbors = a->al_next; |
385 |
|
|
free((char *)a); |
386 |
|
|
} |
387 |
|
|
} |
388 |
|
|
|
389 |
|
|
|
390 |
|
|
/* |
391 |
|
|
* stop routing on all vifs |
392 |
|
|
*/ |
393 |
|
|
void |
394 |
|
|
stop_all_vifs(void) |
395 |
|
|
{ |
396 |
|
|
vifi_t vifi; |
397 |
|
|
struct uvif *v; |
398 |
|
|
struct listaddr *a; |
399 |
|
|
struct vif_acl *acl; |
400 |
|
|
|
401 |
|
|
for (vifi = 0; vifi < numvifs; vifi++) { |
402 |
|
|
v = &uvifs[vifi]; |
403 |
|
|
while (v->uv_groups != NULL) { |
404 |
|
|
a = v->uv_groups; |
405 |
|
|
v->uv_groups = a->al_next; |
406 |
|
|
free((char *)a); |
407 |
|
|
} |
408 |
|
|
while (v->uv_neighbors != NULL) { |
409 |
|
|
a = v->uv_neighbors; |
410 |
|
|
v->uv_neighbors = a->al_next; |
411 |
|
|
free((char *)a); |
412 |
|
|
} |
413 |
|
|
while (v->uv_acl != NULL) { |
414 |
|
|
acl = v->uv_acl; |
415 |
|
|
v->uv_acl = acl->acl_next; |
416 |
|
|
free((char *)acl); |
417 |
|
|
} |
418 |
|
|
} |
419 |
|
|
} |
420 |
|
|
|
421 |
|
|
|
422 |
|
|
/* |
423 |
|
|
* Find the virtual interface from which an incoming packet arrived, |
424 |
|
|
* based on the packet's source and destination IP addresses. |
425 |
|
|
*/ |
426 |
|
|
vifi_t |
427 |
|
|
find_vif(u_int32_t src, u_int32_t dst) |
428 |
|
|
{ |
429 |
|
|
vifi_t vifi; |
430 |
|
|
struct uvif *v; |
431 |
|
|
struct phaddr *p; |
432 |
|
|
|
433 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { |
434 |
|
|
if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { |
435 |
|
|
if (v->uv_flags & VIFF_TUNNEL) { |
436 |
|
|
if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr) |
437 |
|
|
return(vifi); |
438 |
|
|
} |
439 |
|
|
else { |
440 |
|
|
if ((src & v->uv_subnetmask) == v->uv_subnet && |
441 |
|
|
((v->uv_subnetmask == 0xffffffff) || |
442 |
|
|
(src != v->uv_subnetbcast))) |
443 |
|
|
return(vifi); |
444 |
|
|
for (p=v->uv_addrs; p; p=p->pa_next) { |
445 |
|
|
if ((src & p->pa_subnetmask) == p->pa_subnet && |
446 |
|
|
((p->pa_subnetmask == 0xffffffff) || |
447 |
|
|
(src != p->pa_subnetbcast))) |
448 |
|
|
return(vifi); |
449 |
|
|
} |
450 |
|
|
} |
451 |
|
|
} |
452 |
|
|
} |
453 |
|
|
return (NO_VIF); |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
static void |
457 |
|
|
age_old_hosts(void) |
458 |
|
|
{ |
459 |
|
|
vifi_t vifi; |
460 |
|
|
struct uvif *v; |
461 |
|
|
struct listaddr *g; |
462 |
|
|
|
463 |
|
|
/* |
464 |
|
|
* Decrement the old-hosts-present timer for each |
465 |
|
|
* active group on each vif. |
466 |
|
|
*/ |
467 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) |
468 |
|
|
for (g = v->uv_groups; g != NULL; g = g->al_next) |
469 |
|
|
if (g->al_old) |
470 |
|
|
g->al_old--; |
471 |
|
|
} |
472 |
|
|
|
473 |
|
|
|
474 |
|
|
/* |
475 |
|
|
* Send group membership queries to all subnets for which I am querier. |
476 |
|
|
*/ |
477 |
|
|
void |
478 |
|
|
query_groups(void) |
479 |
|
|
{ |
480 |
|
|
vifi_t vifi; |
481 |
|
|
struct uvif *v; |
482 |
|
|
|
483 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { |
484 |
|
|
if (v->uv_flags & VIFF_QUERIER) { |
485 |
|
|
send_igmp(v->uv_lcl_addr, allhosts_group, |
486 |
|
|
IGMP_HOST_MEMBERSHIP_QUERY, |
487 |
|
|
(v->uv_flags & VIFF_IGMPV1) ? 0 : |
488 |
|
|
IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0); |
489 |
|
|
} |
490 |
|
|
} |
491 |
|
|
age_old_hosts(); |
492 |
|
|
} |
493 |
|
|
|
494 |
|
|
/* |
495 |
|
|
* Process an incoming host membership query |
496 |
|
|
*/ |
497 |
|
|
void |
498 |
|
|
accept_membership_query(u_int32_t src, u_int32_t dst, u_int32_t group, |
499 |
|
|
int tmo) |
500 |
|
|
{ |
501 |
|
|
vifi_t vifi; |
502 |
|
|
struct uvif *v; |
503 |
|
|
|
504 |
|
|
if ((vifi = find_vif(src, dst)) == NO_VIF || |
505 |
|
|
(uvifs[vifi].uv_flags & VIFF_TUNNEL)) { |
506 |
|
|
logit(LOG_INFO, 0, |
507 |
|
|
"ignoring group membership query from non-adjacent host %s", |
508 |
|
|
inet_fmt(src, s1)); |
509 |
|
|
return; |
510 |
|
|
} |
511 |
|
|
|
512 |
|
|
v = &uvifs[vifi]; |
513 |
|
|
|
514 |
|
|
/* |
515 |
|
|
* If we consider ourselves the querier for this vif, but hear a |
516 |
|
|
* query from a router with a lower IP address, yield to them. |
517 |
|
|
* |
518 |
|
|
* This is done here as well as in the neighbor discovery in case |
519 |
|
|
* there is a querier that doesn't speak DVMRP. |
520 |
|
|
* |
521 |
|
|
* XXX If this neighbor doesn't speak DVMRP, then we need to create |
522 |
|
|
* some neighbor state for him so that we can time him out! |
523 |
|
|
*/ |
524 |
|
|
if ((v->uv_flags & VIFF_QUERIER) && |
525 |
|
|
(ntohl(src) < ntohl(v->uv_lcl_addr))) { |
526 |
|
|
v->uv_flags &= ~VIFF_QUERIER; |
527 |
|
|
|
528 |
|
|
} |
529 |
|
|
} |
530 |
|
|
|
531 |
|
|
/* |
532 |
|
|
* Process an incoming group membership report. |
533 |
|
|
*/ |
534 |
|
|
void |
535 |
|
|
accept_group_report(u_int32_t src, u_int32_t dst, u_int32_t group, |
536 |
|
|
int r_type) |
537 |
|
|
{ |
538 |
|
|
vifi_t vifi; |
539 |
|
|
struct uvif *v; |
540 |
|
|
struct listaddr *g; |
541 |
|
|
|
542 |
|
|
if ((vifi = find_vif(src, dst)) == NO_VIF || |
543 |
|
|
(uvifs[vifi].uv_flags & VIFF_TUNNEL)) { |
544 |
|
|
logit(LOG_INFO, 0, |
545 |
|
|
"ignoring group membership report from non-adjacent host %s", |
546 |
|
|
inet_fmt(src, s1)); |
547 |
|
|
return; |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
v = &uvifs[vifi]; |
551 |
|
|
|
552 |
|
|
/* |
553 |
|
|
* Look for the group in our group list; if found, reset its timer. |
554 |
|
|
*/ |
555 |
|
|
for (g = v->uv_groups; g != NULL; g = g->al_next) { |
556 |
|
|
if (group == g->al_addr) { |
557 |
|
|
if (r_type == IGMP_v1_HOST_MEMBERSHIP_REPORT) |
558 |
|
|
g->al_old = OLD_AGE_THRESHOLD; |
559 |
|
|
|
560 |
|
|
/** delete old timers, set a timer for expiration **/ |
561 |
|
|
g->al_timer = GROUP_EXPIRE_TIME; |
562 |
|
|
if (g->al_query) |
563 |
|
|
g->al_query = DeleteTimer(g->al_query); |
564 |
|
|
if (g->al_timerid) |
565 |
|
|
g->al_timerid = DeleteTimer(g->al_timerid); |
566 |
|
|
g->al_timerid = SetTimer(vifi, g); |
567 |
|
|
break; |
568 |
|
|
} |
569 |
|
|
} |
570 |
|
|
|
571 |
|
|
/* |
572 |
|
|
* If not found, add it to the list and update kernel cache. |
573 |
|
|
*/ |
574 |
|
|
if (g == NULL) { |
575 |
|
|
g = malloc(sizeof(struct listaddr)); |
576 |
|
|
if (g == NULL) |
577 |
|
|
logit(LOG_ERR, 0, "ran out of memory"); /* fatal */ |
578 |
|
|
|
579 |
|
|
g->al_addr = group; |
580 |
|
|
if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT) |
581 |
|
|
g->al_old = 0; |
582 |
|
|
else |
583 |
|
|
g->al_old = OLD_AGE_THRESHOLD; |
584 |
|
|
|
585 |
|
|
/** set a timer for expiration **/ |
586 |
|
|
g->al_query = 0; |
587 |
|
|
g->al_timer = GROUP_EXPIRE_TIME; |
588 |
|
|
time(&g->al_ctime); |
589 |
|
|
g->al_timerid = SetTimer(vifi, g); |
590 |
|
|
g->al_next = v->uv_groups; |
591 |
|
|
v->uv_groups = g; |
592 |
|
|
|
593 |
|
|
update_lclgrp(vifi, group); |
594 |
|
|
} |
595 |
|
|
|
596 |
|
|
/* |
597 |
|
|
* Check if a graft is necessary for this group |
598 |
|
|
*/ |
599 |
|
|
chkgrp_graft(vifi, group); |
600 |
|
|
} |
601 |
|
|
|
602 |
|
|
|
603 |
|
|
void |
604 |
|
|
accept_leave_message(u_int32_t src, u_int32_t dst, u_int32_t group) |
605 |
|
|
{ |
606 |
|
|
vifi_t vifi; |
607 |
|
|
struct uvif *v; |
608 |
|
|
struct listaddr *g; |
609 |
|
|
|
610 |
|
|
if ((vifi = find_vif(src, dst)) == NO_VIF || |
611 |
|
|
(uvifs[vifi].uv_flags & VIFF_TUNNEL)) { |
612 |
|
|
logit(LOG_INFO, 0, |
613 |
|
|
"ignoring group leave report from non-adjacent host %s", |
614 |
|
|
inet_fmt(src, s1)); |
615 |
|
|
return; |
616 |
|
|
} |
617 |
|
|
|
618 |
|
|
v = &uvifs[vifi]; |
619 |
|
|
|
620 |
|
|
if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1)) |
621 |
|
|
return; |
622 |
|
|
|
623 |
|
|
/* |
624 |
|
|
* Look for the group in our group list in order to set up a short-timeout |
625 |
|
|
* query. |
626 |
|
|
*/ |
627 |
|
|
for (g = v->uv_groups; g != NULL; g = g->al_next) { |
628 |
|
|
if (group == g->al_addr) { |
629 |
|
|
logit(LOG_DEBUG, 0, |
630 |
|
|
"[vif.c, _accept_leave_message] %d %d \n", |
631 |
|
|
g->al_old, g->al_query); |
632 |
|
|
|
633 |
|
|
/* Ignore the leave message if there are old hosts present */ |
634 |
|
|
if (g->al_old) |
635 |
|
|
return; |
636 |
|
|
|
637 |
|
|
/* still waiting for a reply to a query, ignore the leave */ |
638 |
|
|
if (g->al_query) |
639 |
|
|
return; |
640 |
|
|
|
641 |
|
|
/** delete old timer set a timer for expiration **/ |
642 |
|
|
if (g->al_timerid) |
643 |
|
|
g->al_timerid = DeleteTimer(g->al_timerid); |
644 |
|
|
|
645 |
|
|
/** send a group specific querry **/ |
646 |
|
|
g->al_timer = LEAVE_EXPIRE_TIME; |
647 |
|
|
send_igmp(v->uv_lcl_addr, g->al_addr, |
648 |
|
|
IGMP_HOST_MEMBERSHIP_QUERY, |
649 |
|
|
LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE, |
650 |
|
|
g->al_addr, 0); |
651 |
|
|
g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3, |
652 |
|
|
LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE); |
653 |
|
|
g->al_timerid = SetTimer(vifi, g); |
654 |
|
|
break; |
655 |
|
|
} |
656 |
|
|
} |
657 |
|
|
} |
658 |
|
|
|
659 |
|
|
|
660 |
|
|
/* |
661 |
|
|
* Send a periodic probe on all vifs. |
662 |
|
|
* Useful to determine one-way interfaces. |
663 |
|
|
* Detect neighbor loss faster. |
664 |
|
|
*/ |
665 |
|
|
void |
666 |
|
|
probe_for_neighbors(void) |
667 |
|
|
{ |
668 |
|
|
vifi_t vifi; |
669 |
|
|
struct uvif *v; |
670 |
|
|
|
671 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { |
672 |
|
|
if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { |
673 |
|
|
send_probe_on_vif(v); |
674 |
|
|
} |
675 |
|
|
} |
676 |
|
|
} |
677 |
|
|
|
678 |
|
|
|
679 |
|
|
/* |
680 |
|
|
* Send a list of all of our neighbors to the requestor, `src'. |
681 |
|
|
*/ |
682 |
|
|
void |
683 |
|
|
accept_neighbor_request(u_int32_t src, u_int32_t dst) |
684 |
|
|
{ |
685 |
|
|
vifi_t vifi; |
686 |
|
|
struct uvif *v; |
687 |
|
|
u_char *p, *ncount; |
688 |
|
|
struct listaddr *la; |
689 |
|
|
int datalen; |
690 |
|
|
u_int32_t temp_addr, us, them = src; |
691 |
|
|
|
692 |
|
|
/* Determine which of our addresses to use as the source of our response |
693 |
|
|
* to this query. |
694 |
|
|
*/ |
695 |
|
|
if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */ |
696 |
|
|
int udp; /* find best interface to reply on */ |
697 |
|
|
struct sockaddr_in addr; |
698 |
|
|
int addrlen = sizeof(addr); |
699 |
|
|
|
700 |
|
|
memset(&addr, 0, sizeof addr); |
701 |
|
|
addr.sin_family = AF_INET; |
702 |
|
|
addr.sin_len = sizeof addr; |
703 |
|
|
addr.sin_addr.s_addr = dst; |
704 |
|
|
addr.sin_port = htons(2000); /* any port over 1024 will do... */ |
705 |
|
|
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 |
706 |
|
|
|| connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 |
707 |
|
|
|| getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { |
708 |
|
|
logit(LOG_WARNING, errno, "Determining local address"); |
709 |
|
|
close(udp); |
710 |
|
|
return; |
711 |
|
|
} |
712 |
|
|
close(udp); |
713 |
|
|
us = addr.sin_addr.s_addr; |
714 |
|
|
} else /* query sent to us alone */ |
715 |
|
|
us = dst; |
716 |
|
|
|
717 |
|
|
#define PUT_ADDR(a) temp_addr = ntohl(a); \ |
718 |
|
|
*p++ = temp_addr >> 24; \ |
719 |
|
|
*p++ = (temp_addr >> 16) & 0xFF; \ |
720 |
|
|
*p++ = (temp_addr >> 8) & 0xFF; \ |
721 |
|
|
*p++ = temp_addr & 0xFF; |
722 |
|
|
|
723 |
|
|
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); |
724 |
|
|
datalen = 0; |
725 |
|
|
|
726 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { |
727 |
|
|
if (v->uv_flags & VIFF_DISABLED) |
728 |
|
|
continue; |
729 |
|
|
|
730 |
|
|
ncount = 0; |
731 |
|
|
|
732 |
|
|
for (la = v->uv_neighbors; la; la = la->al_next) { |
733 |
|
|
|
734 |
|
|
/* Make sure that there's room for this neighbor... */ |
735 |
|
|
if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) { |
736 |
|
|
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, |
737 |
|
|
htonl(MROUTED_LEVEL), datalen); |
738 |
|
|
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); |
739 |
|
|
datalen = 0; |
740 |
|
|
ncount = 0; |
741 |
|
|
} |
742 |
|
|
|
743 |
|
|
/* Put out the header for this neighbor list... */ |
744 |
|
|
if (ncount == 0) { |
745 |
|
|
PUT_ADDR(v->uv_lcl_addr); |
746 |
|
|
*p++ = v->uv_metric; |
747 |
|
|
*p++ = v->uv_threshold; |
748 |
|
|
ncount = p; |
749 |
|
|
*p++ = 0; |
750 |
|
|
datalen += 4 + 3; |
751 |
|
|
} |
752 |
|
|
|
753 |
|
|
PUT_ADDR(la->al_addr); |
754 |
|
|
datalen += 4; |
755 |
|
|
(*ncount)++; |
756 |
|
|
} |
757 |
|
|
} |
758 |
|
|
|
759 |
|
|
if (datalen != 0) |
760 |
|
|
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL), |
761 |
|
|
datalen); |
762 |
|
|
} |
763 |
|
|
|
764 |
|
|
/* |
765 |
|
|
* Send a list of all of our neighbors to the requestor, `src'. |
766 |
|
|
*/ |
767 |
|
|
void |
768 |
|
|
accept_neighbor_request2(u_int32_t src, u_int32_t dst) |
769 |
|
|
{ |
770 |
|
|
vifi_t vifi; |
771 |
|
|
struct uvif *v; |
772 |
|
|
u_char *p, *ncount; |
773 |
|
|
struct listaddr *la; |
774 |
|
|
int datalen; |
775 |
|
|
u_int32_t us, them = src; |
776 |
|
|
|
777 |
|
|
/* Determine which of our addresses to use as the source of our response |
778 |
|
|
* to this query. |
779 |
|
|
*/ |
780 |
|
|
if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */ |
781 |
|
|
int udp; /* find best interface to reply on */ |
782 |
|
|
struct sockaddr_in addr; |
783 |
|
|
int addrlen = sizeof(addr); |
784 |
|
|
|
785 |
|
|
memset(&addr, 0, sizeof addr); |
786 |
|
|
addr.sin_family = AF_INET; |
787 |
|
|
addr.sin_len = sizeof addr; |
788 |
|
|
addr.sin_addr.s_addr = dst; |
789 |
|
|
addr.sin_port = htons(2000); /* any port over 1024 will do... */ |
790 |
|
|
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 |
791 |
|
|
|| connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0 |
792 |
|
|
|| getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) { |
793 |
|
|
logit(LOG_WARNING, errno, "Determining local address"); |
794 |
|
|
close(udp); |
795 |
|
|
return; |
796 |
|
|
} |
797 |
|
|
close(udp); |
798 |
|
|
us = addr.sin_addr.s_addr; |
799 |
|
|
} else /* query sent to us alone */ |
800 |
|
|
us = dst; |
801 |
|
|
|
802 |
|
|
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); |
803 |
|
|
datalen = 0; |
804 |
|
|
|
805 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { |
806 |
|
|
u_short vflags = v->uv_flags; |
807 |
|
|
u_char rflags = 0; |
808 |
|
|
if (vflags & VIFF_TUNNEL) |
809 |
|
|
rflags |= DVMRP_NF_TUNNEL; |
810 |
|
|
if (vflags & VIFF_SRCRT) |
811 |
|
|
rflags |= DVMRP_NF_SRCRT; |
812 |
|
|
if (vflags & VIFF_DOWN) |
813 |
|
|
rflags |= DVMRP_NF_DOWN; |
814 |
|
|
if (vflags & VIFF_DISABLED) |
815 |
|
|
rflags |= DVMRP_NF_DISABLED; |
816 |
|
|
if (vflags & VIFF_QUERIER) |
817 |
|
|
rflags |= DVMRP_NF_QUERIER; |
818 |
|
|
if (vflags & VIFF_LEAF) |
819 |
|
|
rflags |= DVMRP_NF_LEAF; |
820 |
|
|
ncount = 0; |
821 |
|
|
la = v->uv_neighbors; |
822 |
|
|
if (la == NULL) { |
823 |
|
|
/* |
824 |
|
|
* include down & disabled interfaces and interfaces on |
825 |
|
|
* leaf nets. |
826 |
|
|
*/ |
827 |
|
|
if (rflags & DVMRP_NF_TUNNEL) |
828 |
|
|
rflags |= DVMRP_NF_DOWN; |
829 |
|
|
if (datalen > MAX_DVMRP_DATA_LEN - 12) { |
830 |
|
|
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, |
831 |
|
|
htonl(MROUTED_LEVEL), datalen); |
832 |
|
|
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); |
833 |
|
|
datalen = 0; |
834 |
|
|
} |
835 |
|
|
*(u_int*)p = v->uv_lcl_addr; |
836 |
|
|
p += 4; |
837 |
|
|
*p++ = v->uv_metric; |
838 |
|
|
*p++ = v->uv_threshold; |
839 |
|
|
*p++ = rflags; |
840 |
|
|
*p++ = 1; |
841 |
|
|
*(u_int*)p = v->uv_rmt_addr; |
842 |
|
|
p += 4; |
843 |
|
|
datalen += 12; |
844 |
|
|
} else { |
845 |
|
|
for ( ; la; la = la->al_next) { |
846 |
|
|
/* Make sure that there's room for this neighbor... */ |
847 |
|
|
if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) { |
848 |
|
|
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, |
849 |
|
|
htonl(MROUTED_LEVEL), datalen); |
850 |
|
|
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); |
851 |
|
|
datalen = 0; |
852 |
|
|
ncount = 0; |
853 |
|
|
} |
854 |
|
|
/* Put out the header for this neighbor list... */ |
855 |
|
|
if (ncount == 0) { |
856 |
|
|
*(u_int*)p = v->uv_lcl_addr; |
857 |
|
|
p += 4; |
858 |
|
|
*p++ = v->uv_metric; |
859 |
|
|
*p++ = v->uv_threshold; |
860 |
|
|
*p++ = rflags; |
861 |
|
|
ncount = p; |
862 |
|
|
*p++ = 0; |
863 |
|
|
datalen += 4 + 4; |
864 |
|
|
} |
865 |
|
|
*(u_int*)p = la->al_addr; |
866 |
|
|
p += 4; |
867 |
|
|
datalen += 4; |
868 |
|
|
(*ncount)++; |
869 |
|
|
} |
870 |
|
|
} |
871 |
|
|
} |
872 |
|
|
if (datalen != 0) |
873 |
|
|
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL), |
874 |
|
|
datalen); |
875 |
|
|
} |
876 |
|
|
|
877 |
|
|
void |
878 |
|
|
accept_info_request(u_int32_t src, u_int32_t dst, u_char *p, int datalen) |
879 |
|
|
{ |
880 |
|
|
u_char *q; |
881 |
|
|
int len; |
882 |
|
|
int outlen = 0; |
883 |
|
|
|
884 |
|
|
q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN); |
885 |
|
|
|
886 |
|
|
/* To be general, this must deal properly with breaking up over-sized |
887 |
|
|
* packets. That implies passing a length to each function, and |
888 |
|
|
* allowing each function to request to be called again. Right now, |
889 |
|
|
* we're only implementing the one thing we are positive will fit into |
890 |
|
|
* a single packet, so we wimp out. |
891 |
|
|
*/ |
892 |
|
|
while (datalen > 0) { |
893 |
|
|
len = 0; |
894 |
|
|
switch (*p) { |
895 |
|
|
case DVMRP_INFO_VERSION: |
896 |
|
|
len = info_version(q, (u_char *)send_buf + RECV_BUF_SIZE - q); |
897 |
|
|
break; |
898 |
|
|
|
899 |
|
|
case DVMRP_INFO_NEIGHBORS: |
900 |
|
|
default: |
901 |
|
|
logit(LOG_INFO, 0, "ignoring unknown info type %d", *p); |
902 |
|
|
break; |
903 |
|
|
} |
904 |
|
|
*(q+1) = len++; |
905 |
|
|
outlen += len * 4; |
906 |
|
|
q += len * 4; |
907 |
|
|
len = (*(p+1) + 1) * 4; |
908 |
|
|
p += len; |
909 |
|
|
datalen -= len; |
910 |
|
|
} |
911 |
|
|
|
912 |
|
|
if (outlen != 0) |
913 |
|
|
send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY, |
914 |
|
|
htonl(MROUTED_LEVEL), outlen); |
915 |
|
|
} |
916 |
|
|
|
917 |
|
|
/* |
918 |
|
|
* Information response -- return version string |
919 |
|
|
*/ |
920 |
|
|
static int |
921 |
|
|
info_version(char *p, int len) |
922 |
|
|
{ |
923 |
|
|
extern char versionstring[]; |
924 |
|
|
|
925 |
|
|
if (len < 5) |
926 |
|
|
return (0); |
927 |
|
|
*p++ = DVMRP_INFO_VERSION; |
928 |
|
|
p++; /* skip over length */ |
929 |
|
|
*p++ = 0; /* zero out */ |
930 |
|
|
*p++ = 0; /* reserved fields */ |
931 |
|
|
strlcpy(p, versionstring, len - 4); |
932 |
|
|
|
933 |
|
|
len = strlen(p); |
934 |
|
|
return ((len + 3) / 4); |
935 |
|
|
} |
936 |
|
|
|
937 |
|
|
/* |
938 |
|
|
* Process an incoming neighbor-list message. |
939 |
|
|
*/ |
940 |
|
|
void |
941 |
|
|
accept_neighbors(u_int32_t src, u_int32_t dst, u_char *p, int datalen, |
942 |
|
|
u_int32_t level) |
943 |
|
|
{ |
944 |
|
|
logit(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s", |
945 |
|
|
inet_fmt(src, s1), inet_fmt(dst, s2)); |
946 |
|
|
} |
947 |
|
|
|
948 |
|
|
|
949 |
|
|
/* |
950 |
|
|
* Process an incoming neighbor-list message. |
951 |
|
|
*/ |
952 |
|
|
void |
953 |
|
|
accept_neighbors2(u_int32_t src, u_int32_t dst, u_char *p, int datalen, |
954 |
|
|
u_int32_t level) |
955 |
|
|
{ |
956 |
|
|
logit(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s", |
957 |
|
|
inet_fmt(src, s1), inet_fmt(dst, s2)); |
958 |
|
|
} |
959 |
|
|
|
960 |
|
|
/* |
961 |
|
|
* Process an incoming info reply message. |
962 |
|
|
*/ |
963 |
|
|
void |
964 |
|
|
accept_info_reply(u_int32_t src, u_int32_t dst, u_char *p, int datalen) |
965 |
|
|
{ |
966 |
|
|
logit(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s", |
967 |
|
|
inet_fmt(src, s1), inet_fmt(dst, s2)); |
968 |
|
|
} |
969 |
|
|
|
970 |
|
|
|
971 |
|
|
/* |
972 |
|
|
* Update the neighbor entry for neighbor 'addr' on vif 'vifi'. |
973 |
|
|
* 'msgtype' is the type of DVMRP message received from the neighbor. |
974 |
|
|
* Return TRUE if 'addr' is a valid neighbor, FALSE otherwise. |
975 |
|
|
*/ |
976 |
|
|
int |
977 |
|
|
update_neighbor(vifi_t vifi, u_int32_t addr, int msgtype, char *p, |
978 |
|
|
int datalen, u_int32_t level) |
979 |
|
|
{ |
980 |
|
|
struct uvif *v; |
981 |
|
|
struct listaddr *n; |
982 |
|
|
u_int32_t genid = 0; |
983 |
|
|
u_int32_t router; |
984 |
|
|
u_int32_t send_tables = 0; |
985 |
|
|
int do_reset = FALSE; |
986 |
|
|
int nflags; |
987 |
|
|
|
988 |
|
|
v = &uvifs[vifi]; |
989 |
|
|
nflags = (level >> 16) & 0xff; |
990 |
|
|
|
991 |
|
|
/* |
992 |
|
|
* Confirm that 'addr' is a valid neighbor address on vif 'vifi'. |
993 |
|
|
* IT IS ASSUMED that this was preceded by a call to find_vif(), which |
994 |
|
|
* checks that 'addr' is either a valid remote tunnel endpoint or a |
995 |
|
|
* non-broadcast address belonging to a directly-connected subnet. |
996 |
|
|
* Therefore, here we check only that 'addr' is not our own address |
997 |
|
|
* (due to an impostor or erroneous loopback) or an address of the form |
998 |
|
|
* {subnet,0} ("the unknown host"). These checks are not performed in |
999 |
|
|
* find_vif() because those types of address are acceptable for some |
1000 |
|
|
* types of IGMP message (such as group membership reports). |
1001 |
|
|
*/ |
1002 |
|
|
if (!(v->uv_flags & VIFF_TUNNEL) && |
1003 |
|
|
(addr == v->uv_lcl_addr || |
1004 |
|
|
addr == v->uv_subnet )) { |
1005 |
|
|
logit(LOG_WARNING, 0, |
1006 |
|
|
"received DVMRP message from 'the unknown host' or self: %s", |
1007 |
|
|
inet_fmt(addr, s1)); |
1008 |
|
|
return (FALSE); |
1009 |
|
|
} |
1010 |
|
|
|
1011 |
|
|
/* |
1012 |
|
|
* Look for addr in list of neighbors. |
1013 |
|
|
*/ |
1014 |
|
|
for (n = v->uv_neighbors; n != NULL; n = n->al_next) { |
1015 |
|
|
if (addr == n->al_addr) { |
1016 |
|
|
break; |
1017 |
|
|
} |
1018 |
|
|
} |
1019 |
|
|
|
1020 |
|
|
/* |
1021 |
|
|
* Found it. Reset its timer, and check for a version change |
1022 |
|
|
*/ |
1023 |
|
|
if (n) { |
1024 |
|
|
n->al_timer = 0; |
1025 |
|
|
|
1026 |
|
|
/* |
1027 |
|
|
* update the neighbors version and protocol number |
1028 |
|
|
* if changed => router went down and came up, |
1029 |
|
|
* so take action immediately. |
1030 |
|
|
*/ |
1031 |
|
|
if ((n->al_pv != (level & 0xff)) || |
1032 |
|
|
(n->al_mv != ((level >> 8) & 0xff))) { |
1033 |
|
|
|
1034 |
|
|
do_reset = TRUE; |
1035 |
|
|
logit(LOG_DEBUG, 0, |
1036 |
|
|
"version change neighbor %s [old:%d.%d, new:%d.%d]", |
1037 |
|
|
inet_fmt(addr, s1), |
1038 |
|
|
n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff); |
1039 |
|
|
|
1040 |
|
|
n->al_pv = level & 0xff; |
1041 |
|
|
n->al_mv = (level >> 8) & 0xff; |
1042 |
|
|
} |
1043 |
|
|
} else { |
1044 |
|
|
/* |
1045 |
|
|
* If not found, add it to the list. If the neighbor has a lower |
1046 |
|
|
* IP address than me, yield querier duties to it. |
1047 |
|
|
*/ |
1048 |
|
|
logit(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x", |
1049 |
|
|
inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff, |
1050 |
|
|
(level >> 16) & 0xff); |
1051 |
|
|
|
1052 |
|
|
n = malloc(sizeof(struct listaddr)); |
1053 |
|
|
if (n == NULL) |
1054 |
|
|
logit(LOG_ERR, 0, "ran out of memory"); /* fatal */ |
1055 |
|
|
|
1056 |
|
|
n->al_addr = addr; |
1057 |
|
|
n->al_pv = level & 0xff; |
1058 |
|
|
n->al_mv = (level >> 8) & 0xff; |
1059 |
|
|
n->al_genid = 0; |
1060 |
|
|
|
1061 |
|
|
time(&n->al_ctime); |
1062 |
|
|
n->al_timer = 0; |
1063 |
|
|
n->al_next = v->uv_neighbors; |
1064 |
|
|
|
1065 |
|
|
/* |
1066 |
|
|
* If we thought that we had no neighbors on this vif, send a route |
1067 |
|
|
* report to the vif. If this is just a new neighbor on the same |
1068 |
|
|
* vif, send the route report just to the new neighbor. |
1069 |
|
|
*/ |
1070 |
|
|
if (v->uv_neighbors == NULL) { |
1071 |
|
|
send_tables = (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group; |
1072 |
|
|
vifs_with_neighbors++; |
1073 |
|
|
} else { |
1074 |
|
|
send_tables = addr; |
1075 |
|
|
} |
1076 |
|
|
|
1077 |
|
|
v->uv_neighbors = n; |
1078 |
|
|
|
1079 |
|
|
if (!(v->uv_flags & VIFF_TUNNEL) && |
1080 |
|
|
ntohl(addr) < ntohl(v->uv_lcl_addr)) |
1081 |
|
|
v->uv_flags &= ~VIFF_QUERIER; |
1082 |
|
|
} |
1083 |
|
|
|
1084 |
|
|
/* |
1085 |
|
|
* Check if the router gen-ids are the same. |
1086 |
|
|
* Need to reset the prune state of the router if not. |
1087 |
|
|
* Also check for one-way interfaces by seeing if we are in our |
1088 |
|
|
* neighbor's list of known routers. |
1089 |
|
|
*/ |
1090 |
|
|
if (msgtype == DVMRP_PROBE) { |
1091 |
|
|
|
1092 |
|
|
/* Check genid neighbor flag. Also check version number; 3.3 and |
1093 |
|
|
* 3.4 didn't set this flag. */ |
1094 |
|
|
if ((((level >> 16) & 0xff) & NF_GENID) || |
1095 |
|
|
(((level & 0xff) == 3) && (((level >> 8) & 0xff) > 2))) { |
1096 |
|
|
|
1097 |
|
|
int i; |
1098 |
|
|
|
1099 |
|
|
if (datalen < 4) { |
1100 |
|
|
logit(LOG_WARNING, 0, |
1101 |
|
|
"received truncated probe message from %s (len %d)", |
1102 |
|
|
inet_fmt(addr, s1), datalen); |
1103 |
|
|
return (FALSE); |
1104 |
|
|
} |
1105 |
|
|
|
1106 |
|
|
for (i = 0; i < 4; i++) |
1107 |
|
|
((char *)&genid)[i] = *p++; |
1108 |
|
|
datalen -= 4; |
1109 |
|
|
|
1110 |
|
|
if (n->al_genid == 0) |
1111 |
|
|
n->al_genid = genid; |
1112 |
|
|
else if (n->al_genid != genid) { |
1113 |
|
|
logit(LOG_DEBUG, 0, |
1114 |
|
|
"new genid neigbor %s on vif %d [old:%x, new:%x]", |
1115 |
|
|
inet_fmt(addr, s1), vifi, n->al_genid, genid); |
1116 |
|
|
|
1117 |
|
|
n->al_genid = genid; |
1118 |
|
|
do_reset = TRUE; |
1119 |
|
|
} |
1120 |
|
|
|
1121 |
|
|
/* |
1122 |
|
|
* loop through router list and check for one-way ifs. |
1123 |
|
|
*/ |
1124 |
|
|
|
1125 |
|
|
v->uv_flags |= VIFF_ONEWAY; |
1126 |
|
|
|
1127 |
|
|
while (datalen > 0) { |
1128 |
|
|
if (datalen < 4) { |
1129 |
|
|
logit(LOG_WARNING, 0, |
1130 |
|
|
"received truncated probe message from %s (len %d)", |
1131 |
|
|
inet_fmt(addr, s1), datalen); |
1132 |
|
|
return (FALSE); |
1133 |
|
|
} |
1134 |
|
|
for (i = 0; i < 4; i++) |
1135 |
|
|
((char *)&router)[i] = *p++; |
1136 |
|
|
datalen -= 4; |
1137 |
|
|
if (router == v->uv_lcl_addr) { |
1138 |
|
|
v->uv_flags &= ~VIFF_ONEWAY; |
1139 |
|
|
break; |
1140 |
|
|
} |
1141 |
|
|
} |
1142 |
|
|
} |
1143 |
|
|
} |
1144 |
|
|
if (n->al_flags != nflags) { |
1145 |
|
|
n->al_flags = nflags; |
1146 |
|
|
|
1147 |
|
|
if (n->al_flags & NF_LEAF) { |
1148 |
|
|
/*XXX If we have non-leaf neighbors then we know we shouldn't |
1149 |
|
|
* mark this vif as a leaf. For now we just count on other |
1150 |
|
|
* probes and/or reports resetting the timer. */ |
1151 |
|
|
if (!v->uv_leaf_timer) |
1152 |
|
|
v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; |
1153 |
|
|
} else { |
1154 |
|
|
/* If we get a leaf to non-leaf transition, we *must* update |
1155 |
|
|
* the routing table. */ |
1156 |
|
|
if (v->uv_flags & VIFF_LEAF && send_tables == 0) |
1157 |
|
|
send_tables = addr; |
1158 |
|
|
v->uv_flags &= ~VIFF_LEAF; |
1159 |
|
|
v->uv_leaf_timer = 0; |
1160 |
|
|
} |
1161 |
|
|
} |
1162 |
|
|
if (do_reset) { |
1163 |
|
|
reset_neighbor_state(vifi, addr); |
1164 |
|
|
if (!send_tables) |
1165 |
|
|
send_tables = addr; |
1166 |
|
|
} |
1167 |
|
|
if (send_tables) |
1168 |
|
|
report(ALL_ROUTES, vifi, send_tables); |
1169 |
|
|
|
1170 |
|
|
return (TRUE); |
1171 |
|
|
} |
1172 |
|
|
|
1173 |
|
|
|
1174 |
|
|
/* |
1175 |
|
|
* On every timer interrupt, advance the timer in each neighbor and |
1176 |
|
|
* group entry on every vif. |
1177 |
|
|
*/ |
1178 |
|
|
void |
1179 |
|
|
age_vifs(void) |
1180 |
|
|
{ |
1181 |
|
|
vifi_t vifi; |
1182 |
|
|
struct uvif *v; |
1183 |
|
|
struct listaddr *a, *prev_a, *n; |
1184 |
|
|
u_int32_t addr; |
1185 |
|
|
|
1186 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) { |
1187 |
|
|
if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) { |
1188 |
|
|
v->uv_flags |= VIFF_LEAF; |
1189 |
|
|
} |
1190 |
|
|
|
1191 |
|
|
for (prev_a = (struct listaddr *)&(v->uv_neighbors), |
1192 |
|
|
a = v->uv_neighbors; |
1193 |
|
|
a != NULL; |
1194 |
|
|
prev_a = a, a = a->al_next) { |
1195 |
|
|
|
1196 |
|
|
if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME) |
1197 |
|
|
continue; |
1198 |
|
|
|
1199 |
|
|
/* |
1200 |
|
|
* Neighbor has expired; delete it from the neighbor list, |
1201 |
|
|
* delete it from the 'dominants' and 'subordinates arrays of |
1202 |
|
|
* any route entries and assume querier duties unless there is |
1203 |
|
|
* another neighbor with a lower IP address than mine. |
1204 |
|
|
*/ |
1205 |
|
|
addr = a->al_addr; |
1206 |
|
|
prev_a->al_next = a->al_next; |
1207 |
|
|
free((char *)a); |
1208 |
|
|
a = prev_a; |
1209 |
|
|
|
1210 |
|
|
delete_neighbor_from_routes(addr, vifi); |
1211 |
|
|
|
1212 |
|
|
if (v->uv_neighbors == NULL) |
1213 |
|
|
vifs_with_neighbors--; |
1214 |
|
|
|
1215 |
|
|
v->uv_leaf_timer = LEAF_CONFIRMATION_TIME; |
1216 |
|
|
|
1217 |
|
|
if (!(v->uv_flags & VIFF_TUNNEL)) { |
1218 |
|
|
v->uv_flags |= VIFF_QUERIER; |
1219 |
|
|
for (n = v->uv_neighbors; n != NULL; n = n->al_next) { |
1220 |
|
|
if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) { |
1221 |
|
|
v->uv_flags &= ~VIFF_QUERIER; |
1222 |
|
|
} |
1223 |
|
|
if (!(n->al_flags & NF_LEAF)) { |
1224 |
|
|
v->uv_leaf_timer = 0; |
1225 |
|
|
} |
1226 |
|
|
} |
1227 |
|
|
} |
1228 |
|
|
} |
1229 |
|
|
} |
1230 |
|
|
} |
1231 |
|
|
|
1232 |
|
|
/* |
1233 |
|
|
* Returns the neighbor info struct for a given neighbor |
1234 |
|
|
*/ |
1235 |
|
|
struct listaddr * |
1236 |
|
|
neighbor_info(vifi_t vifi, u_int32_t addr) |
1237 |
|
|
{ |
1238 |
|
|
struct listaddr *u; |
1239 |
|
|
|
1240 |
|
|
for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next) |
1241 |
|
|
if (u->al_addr == addr) |
1242 |
|
|
return u; |
1243 |
|
|
|
1244 |
|
|
return NULL; |
1245 |
|
|
} |
1246 |
|
|
|
1247 |
|
|
/* |
1248 |
|
|
* Print the contents of the uvifs array on file 'fp'. |
1249 |
|
|
*/ |
1250 |
|
|
void |
1251 |
|
|
dump_vifs(FILE *fp) |
1252 |
|
|
{ |
1253 |
|
|
vifi_t vifi; |
1254 |
|
|
struct uvif *v; |
1255 |
|
|
struct listaddr *a; |
1256 |
|
|
struct phaddr *p; |
1257 |
|
|
struct sioc_vif_req v_req; |
1258 |
|
|
|
1259 |
|
|
fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors); |
1260 |
|
|
|
1261 |
|
|
if (vifs_with_neighbors == 1) |
1262 |
|
|
fprintf(fp,"[This host is a leaf]\n\n"); |
1263 |
|
|
|
1264 |
|
|
fprintf(fp, |
1265 |
|
|
"\nVirtual Interface Table\n%s", |
1266 |
|
|
"Vif Name Local-Address "); |
1267 |
|
|
fprintf(fp, |
1268 |
|
|
"M Thr Rate Flags\n"); |
1269 |
|
|
|
1270 |
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) { |
1271 |
|
|
|
1272 |
|
|
fprintf(fp, "%2u %6s %-15s %6s: %-18s %2u %3u %5u ", |
1273 |
|
|
vifi, |
1274 |
|
|
v->uv_name, |
1275 |
|
|
inet_fmt(v->uv_lcl_addr, s1), |
1276 |
|
|
(v->uv_flags & VIFF_TUNNEL) ? |
1277 |
|
|
"tunnel": |
1278 |
|
|
"subnet", |
1279 |
|
|
(v->uv_flags & VIFF_TUNNEL) ? |
1280 |
|
|
inet_fmt(v->uv_rmt_addr, s2) : |
1281 |
|
|
inet_fmts(v->uv_subnet, v->uv_subnetmask, s3), |
1282 |
|
|
v->uv_metric, |
1283 |
|
|
v->uv_threshold, |
1284 |
|
|
v->uv_rate_limit); |
1285 |
|
|
|
1286 |
|
|
if (v->uv_flags & VIFF_ONEWAY) fprintf(fp, " one-way"); |
1287 |
|
|
if (v->uv_flags & VIFF_DOWN) fprintf(fp, " down"); |
1288 |
|
|
if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled"); |
1289 |
|
|
if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier"); |
1290 |
|
|
if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt"); |
1291 |
|
|
if (v->uv_flags & VIFF_LEAF) fprintf(fp, " leaf"); |
1292 |
|
|
if (v->uv_flags & VIFF_IGMPV1) fprintf(fp, " IGMPv1"); |
1293 |
|
|
fprintf(fp, "\n"); |
1294 |
|
|
|
1295 |
|
|
if (v->uv_addrs != NULL) { |
1296 |
|
|
fprintf(fp, " alternate subnets: %s\n", |
1297 |
|
|
inet_fmts(v->uv_addrs->pa_subnet, v->uv_addrs->pa_subnetmask, s1)); |
1298 |
|
|
for (p = v->uv_addrs->pa_next; p; p = p->pa_next) { |
1299 |
|
|
fprintf(fp, " %s\n", |
1300 |
|
|
inet_fmts(p->pa_subnet, p->pa_subnetmask, s1)); |
1301 |
|
|
} |
1302 |
|
|
} |
1303 |
|
|
|
1304 |
|
|
if (v->uv_neighbors != NULL) { |
1305 |
|
|
fprintf(fp, " peers: %s (%d.%d) (0x%x)\n", |
1306 |
|
|
inet_fmt(v->uv_neighbors->al_addr, s1), |
1307 |
|
|
v->uv_neighbors->al_pv, v->uv_neighbors->al_mv, |
1308 |
|
|
v->uv_neighbors->al_flags); |
1309 |
|
|
for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) { |
1310 |
|
|
fprintf(fp, " %s (%d.%d) (0x%x)\n", |
1311 |
|
|
inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, |
1312 |
|
|
a->al_flags); |
1313 |
|
|
} |
1314 |
|
|
} |
1315 |
|
|
|
1316 |
|
|
if (v->uv_groups != NULL) { |
1317 |
|
|
fprintf(fp, " groups: %-15s\n", |
1318 |
|
|
inet_fmt(v->uv_groups->al_addr, s1)); |
1319 |
|
|
for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) { |
1320 |
|
|
fprintf(fp, " %-15s\n", |
1321 |
|
|
inet_fmt(a->al_addr, s1)); |
1322 |
|
|
} |
1323 |
|
|
} |
1324 |
|
|
if (v->uv_acl != NULL) { |
1325 |
|
|
struct vif_acl *acl; |
1326 |
|
|
|
1327 |
|
|
fprintf(fp, " boundaries: %-18s\n", |
1328 |
|
|
inet_fmts(v->uv_acl->acl_addr, v->uv_acl->acl_mask, s1)); |
1329 |
|
|
for (acl = v->uv_acl->acl_next; acl != NULL; acl = acl->acl_next) { |
1330 |
|
|
fprintf(fp, " : %-18s\n", |
1331 |
|
|
inet_fmts(acl->acl_addr, acl->acl_mask, s1)); |
1332 |
|
|
} |
1333 |
|
|
} |
1334 |
|
|
v_req.vifi = vifi; |
1335 |
|
|
if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) { |
1336 |
|
|
logit(LOG_WARNING, 0, |
1337 |
|
|
"SIOCGETVIFCNT fails"); |
1338 |
|
|
} |
1339 |
|
|
else { |
1340 |
|
|
fprintf(fp, " pkts in : %ld\n", |
1341 |
|
|
v_req.icount); |
1342 |
|
|
fprintf(fp, " pkts out: %ld\n", |
1343 |
|
|
v_req.ocount); |
1344 |
|
|
} |
1345 |
|
|
fprintf(fp, "\n"); |
1346 |
|
|
} |
1347 |
|
|
fprintf(fp, "\n"); |
1348 |
|
|
} |
1349 |
|
|
|
1350 |
|
|
/* |
1351 |
|
|
* Time out record of a group membership on a vif |
1352 |
|
|
*/ |
1353 |
|
|
static void |
1354 |
|
|
DelVif(void *arg) |
1355 |
|
|
{ |
1356 |
|
|
cbk_t *cbk = (cbk_t *)arg; |
1357 |
|
|
vifi_t vifi = cbk->vifi; |
1358 |
|
|
struct uvif *v = &uvifs[vifi]; |
1359 |
|
|
struct listaddr *a, **anp, *g = cbk->g; |
1360 |
|
|
|
1361 |
|
|
/* |
1362 |
|
|
* Group has expired |
1363 |
|
|
* delete all kernel cache entries with this group |
1364 |
|
|
*/ |
1365 |
|
|
if (g->al_query) |
1366 |
|
|
DeleteTimer(g->al_query); |
1367 |
|
|
|
1368 |
|
|
delete_lclgrp(vifi, g->al_addr); |
1369 |
|
|
|
1370 |
|
|
anp = &(v->uv_groups); |
1371 |
|
|
while ((a = *anp) != NULL) { |
1372 |
|
|
if (a == g) { |
1373 |
|
|
*anp = a->al_next; |
1374 |
|
|
free((char *)a); |
1375 |
|
|
} else { |
1376 |
|
|
anp = &a->al_next; |
1377 |
|
|
} |
1378 |
|
|
} |
1379 |
|
|
|
1380 |
|
|
free(cbk); |
1381 |
|
|
} |
1382 |
|
|
|
1383 |
|
|
/* |
1384 |
|
|
* Set a timer to delete the record of a group membership on a vif. |
1385 |
|
|
*/ |
1386 |
|
|
static int |
1387 |
|
|
SetTimer(int vifi, struct listaddr *g) |
1388 |
|
|
{ |
1389 |
|
|
cbk_t *cbk; |
1390 |
|
|
|
1391 |
|
|
cbk = malloc(sizeof(cbk_t)); |
1392 |
|
|
cbk->g = g; |
1393 |
|
|
cbk->vifi = vifi; |
1394 |
|
|
return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk); |
1395 |
|
|
} |
1396 |
|
|
|
1397 |
|
|
/* |
1398 |
|
|
* Delete a timer that was set above. |
1399 |
|
|
*/ |
1400 |
|
|
static int |
1401 |
|
|
DeleteTimer(int id) |
1402 |
|
|
{ |
1403 |
|
|
timer_clearTimer(id); |
1404 |
|
|
return 0; |
1405 |
|
|
} |
1406 |
|
|
|
1407 |
|
|
/* |
1408 |
|
|
* Send a group-specific query. |
1409 |
|
|
*/ |
1410 |
|
|
static void |
1411 |
|
|
SendQuery(void *arg) |
1412 |
|
|
{ |
1413 |
|
|
cbk_t *cbk = (cbk_t *)arg; |
1414 |
|
|
struct uvif *v = &uvifs[cbk->vifi]; |
1415 |
|
|
|
1416 |
|
|
send_igmp(v->uv_lcl_addr, cbk->g->al_addr, |
1417 |
|
|
IGMP_HOST_MEMBERSHIP_QUERY, |
1418 |
|
|
cbk->q_time, cbk->g->al_addr, 0); |
1419 |
|
|
cbk->g->al_query = 0; |
1420 |
|
|
free(cbk); |
1421 |
|
|
} |
1422 |
|
|
|
1423 |
|
|
/* |
1424 |
|
|
* Set a timer to send a group-specific query. |
1425 |
|
|
*/ |
1426 |
|
|
static int |
1427 |
|
|
SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time) |
1428 |
|
|
{ |
1429 |
|
|
cbk_t *cbk; |
1430 |
|
|
|
1431 |
|
|
cbk = malloc(sizeof(cbk_t)); |
1432 |
|
|
cbk->g = g; |
1433 |
|
|
cbk->q_time = q_time; |
1434 |
|
|
cbk->vifi = vifi; |
1435 |
|
|
return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk); |
1436 |
|
|
} |