1 /*
2 * PIM for Quagga
3 * Copyright (C) 2008 Everton da Silva Marques
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21
22 #include "memory.h"
23 #include "prefix.h"
24 #include "if.h"
25 #include "hash.h"
26 #include "jhash.h"
27 #include "lib_errors.h"
28
29 #include "pimd.h"
30 #include "pim_igmp.h"
31 #include "pim_igmpv2.h"
32 #include "pim_igmpv3.h"
33 #include "pim_igmp_mtrace.h"
34 #include "pim_iface.h"
35 #include "pim_sock.h"
36 #include "pim_mroute.h"
37 #include "pim_str.h"
38 #include "pim_util.h"
39 #include "pim_time.h"
40 #include "pim_zebra.h"
41
42 static void group_timer_off(struct igmp_group *group);
43 static int pim_igmp_general_query(struct thread *t);
44
45 /* This socket is used for TXing IGMP packets only, IGMP RX happens
46 * in pim_mroute_msg()
47 */
igmp_sock_open(struct in_addr ifaddr,struct interface * ifp,uint32_t pim_options)48 static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp,
49 uint32_t pim_options)
50 {
51 int fd;
52 int join = 0;
53 struct in_addr group;
54
55 fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, ifp, 1);
56
57 if (fd < 0)
58 return -1;
59
60 if (PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(pim_options)) {
61 if (inet_aton(PIM_ALL_ROUTERS, &group)) {
62 if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex))
63 ++join;
64 } else {
65 zlog_warn(
66 "%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
67 __FILE__, __func__, fd, inet_ntoa(ifaddr),
68 PIM_ALL_ROUTERS, errno, safe_strerror(errno));
69 }
70 }
71
72 /*
73 IGMP routers periodically send IGMP general queries to
74 AllSystems=224.0.0.1
75 IGMP routers must receive general queries for querier election.
76 */
77 if (inet_aton(PIM_ALL_SYSTEMS, &group)) {
78 if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex))
79 ++join;
80 } else {
81 zlog_warn(
82 "%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
83 __FILE__, __func__, fd, inet_ntoa(ifaddr),
84 PIM_ALL_SYSTEMS, errno, safe_strerror(errno));
85 }
86
87 if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) {
88 if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex)) {
89 ++join;
90 }
91 } else {
92 zlog_warn(
93 "%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
94 __FILE__, __func__, fd, inet_ntoa(ifaddr),
95 PIM_ALL_IGMP_ROUTERS, errno, safe_strerror(errno));
96 }
97
98 if (!join) {
99 flog_err_sys(
100 EC_LIB_SOCKET,
101 "IGMP socket fd=%d could not join any group on interface address %s",
102 fd, inet_ntoa(ifaddr));
103 close(fd);
104 fd = -1;
105 }
106
107 return fd;
108 }
109
110 #undef IGMP_SOCK_DUMP
111
112 #ifdef IGMP_SOCK_DUMP
igmp_sock_dump(array_t * igmp_sock_array)113 static void igmp_sock_dump(array_t *igmp_sock_array)
114 {
115 int size = array_size(igmp_sock_array);
116 for (int i = 0; i < size; ++i) {
117
118 struct igmp_sock *igmp = array_get(igmp_sock_array, i);
119
120 zlog_debug("%s %s: [%d/%d] igmp_addr=%s fd=%d", __FILE__,
121 __func__, i, size, inet_ntoa(igmp->ifaddr),
122 igmp->fd);
123 }
124 }
125 #endif
126
pim_igmp_sock_lookup_ifaddr(struct list * igmp_sock_list,struct in_addr ifaddr)127 struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list,
128 struct in_addr ifaddr)
129 {
130 struct listnode *sock_node;
131 struct igmp_sock *igmp;
132
133 #ifdef IGMP_SOCK_DUMP
134 igmp_sock_dump(igmp_sock_list);
135 #endif
136
137 for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp))
138 if (ifaddr.s_addr == igmp->ifaddr.s_addr)
139 return igmp;
140
141 return NULL;
142 }
143
igmp_sock_lookup_by_fd(struct list * igmp_sock_list,int fd)144 struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd)
145 {
146 struct listnode *sock_node;
147 struct igmp_sock *igmp;
148
149 for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp))
150 if (fd == igmp->fd)
151 return igmp;
152
153 return NULL;
154 }
155
pim_igmp_other_querier_expire(struct thread * t)156 static int pim_igmp_other_querier_expire(struct thread *t)
157 {
158 struct igmp_sock *igmp;
159
160 igmp = THREAD_ARG(t);
161
162 zassert(!igmp->t_igmp_query_timer);
163
164 if (PIM_DEBUG_IGMP_TRACE) {
165 char ifaddr_str[INET_ADDRSTRLEN];
166 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
167 sizeof(ifaddr_str));
168 zlog_debug("%s: Querier %s resuming", __func__, ifaddr_str);
169 }
170
171 /*
172 We are the current querier, then
173 re-start sending general queries.
174 RFC 2236 - sec 7 Other Querier
175 present timer expired (Send General
176 Query, Set Gen. Query. timer)
177 */
178 pim_igmp_general_query(t);
179
180 return 0;
181 }
182
pim_igmp_other_querier_timer_on(struct igmp_sock * igmp)183 void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp)
184 {
185 long other_querier_present_interval_msec;
186 struct pim_interface *pim_ifp;
187
188 zassert(igmp);
189 zassert(igmp->interface);
190 zassert(igmp->interface->info);
191
192 pim_ifp = igmp->interface->info;
193
194 if (igmp->t_other_querier_timer) {
195 /*
196 There is other querier present already,
197 then reset the other-querier-present timer.
198 */
199
200 if (PIM_DEBUG_IGMP_TRACE) {
201 char ifaddr_str[INET_ADDRSTRLEN];
202 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
203 sizeof(ifaddr_str));
204 zlog_debug(
205 "Querier %s resetting TIMER event for Other-Querier-Present",
206 ifaddr_str);
207 }
208 THREAD_OFF(igmp->t_other_querier_timer);
209 } else {
210 /*
211 We are the current querier, then stop sending general queries:
212 igmp->t_igmp_query_timer = NULL;
213 */
214 pim_igmp_general_query_off(igmp);
215 }
216
217 /*
218 Since this socket is starting the other-querier-present timer,
219 there should not be periodic query timer for this socket.
220 */
221 zassert(!igmp->t_igmp_query_timer);
222
223 /*
224 RFC 3376: 8.5. Other Querier Present Interval
225
226 The Other Querier Present Interval is the length of time that must
227 pass before a multicast router decides that there is no longer
228 another multicast router which should be the querier. This value
229 MUST be ((the Robustness Variable) times (the Query Interval)) plus
230 (one half of one Query Response Interval).
231
232 other_querier_present_interval_msec = \
233 igmp->querier_robustness_variable * \
234 1000 * igmp->querier_query_interval + \
235 100 * (pim_ifp->query_max_response_time_dsec >> 1);
236 */
237 other_querier_present_interval_msec = PIM_IGMP_OQPI_MSEC(
238 igmp->querier_robustness_variable, igmp->querier_query_interval,
239 pim_ifp->igmp_query_max_response_time_dsec);
240
241 if (PIM_DEBUG_IGMP_TRACE) {
242 char ifaddr_str[INET_ADDRSTRLEN];
243 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
244 sizeof(ifaddr_str));
245 zlog_debug(
246 "Querier %s scheduling %ld.%03ld sec TIMER event for Other-Querier-Present",
247 ifaddr_str, other_querier_present_interval_msec / 1000,
248 other_querier_present_interval_msec % 1000);
249 }
250
251 thread_add_timer_msec(router->master, pim_igmp_other_querier_expire,
252 igmp, other_querier_present_interval_msec,
253 &igmp->t_other_querier_timer);
254 }
255
pim_igmp_other_querier_timer_off(struct igmp_sock * igmp)256 void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp)
257 {
258 zassert(igmp);
259
260 if (PIM_DEBUG_IGMP_TRACE) {
261 if (igmp->t_other_querier_timer) {
262 char ifaddr_str[INET_ADDRSTRLEN];
263 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
264 sizeof(ifaddr_str));
265 zlog_debug(
266 "IGMP querier %s fd=%d cancelling other-querier-present TIMER event on %s",
267 ifaddr_str, igmp->fd, igmp->interface->name);
268 }
269 }
270 THREAD_OFF(igmp->t_other_querier_timer);
271 }
272
igmp_recv_query(struct igmp_sock * igmp,int query_version,int max_resp_code,struct in_addr from,const char * from_str,char * igmp_msg,int igmp_msg_len)273 static int igmp_recv_query(struct igmp_sock *igmp, int query_version,
274 int max_resp_code, struct in_addr from,
275 const char *from_str, char *igmp_msg,
276 int igmp_msg_len)
277 {
278 struct interface *ifp;
279 struct pim_interface *pim_ifp;
280 struct in_addr group_addr;
281 uint16_t recv_checksum;
282 uint16_t checksum;
283
284 if (igmp->mtrace_only)
285 return 0;
286
287 memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
288
289 ifp = igmp->interface;
290 pim_ifp = ifp->info;
291
292 recv_checksum = *(uint16_t *)(igmp_msg + IGMP_CHECKSUM_OFFSET);
293
294 /* for computing checksum */
295 *(uint16_t *)(igmp_msg + IGMP_CHECKSUM_OFFSET) = 0;
296
297 checksum = in_cksum(igmp_msg, igmp_msg_len);
298 if (checksum != recv_checksum) {
299 zlog_warn(
300 "Recv IGMP query v%d from %s on %s: checksum mismatch: received=%x computed=%x",
301 query_version, from_str, ifp->name, recv_checksum,
302 checksum);
303 return -1;
304 }
305
306 if (!pim_if_connected_to_source(ifp, from)) {
307 if (PIM_DEBUG_IGMP_PACKETS)
308 zlog_debug("Recv IGMP query on interface: %s from a non-connected source: %s",
309 ifp->name, from_str);
310 return 0;
311 }
312
313 if (if_lookup_exact_address(&from, AF_INET, ifp->vrf_id)) {
314 if (PIM_DEBUG_IGMP_PACKETS)
315 zlog_debug("Recv IGMP query on interface: %s from ourself %s",
316 ifp->name, from_str);
317 return 0;
318 }
319
320 /* Collecting IGMP Rx stats */
321 switch (query_version) {
322 case 1:
323 igmp->rx_stats.query_v1++;
324 break;
325 case 2:
326 igmp->rx_stats.query_v2++;
327 break;
328 case 3:
329 igmp->rx_stats.query_v3++;
330 break;
331 default:
332 igmp->rx_stats.unsupported++;
333 }
334
335 /*
336 * RFC 3376 defines some guidelines on operating in backwards
337 * compatibility with older versions of IGMP but there are some gaps in
338 * the logic:
339 *
340 * - once we drop from say version 3 to version 2 we will never go back
341 * to version 3 even if the node that TXed an IGMP v2 query upgrades
342 * to v3
343 *
344 * - The node with the lowest IP is the querier so we will only know to
345 * drop from v3 to v2 if the node that is the querier is also the one
346 * that is running igmp v2. If a non-querier only supports igmp v2
347 * we will have no way of knowing.
348 *
349 * For now we will simplify things and inform the user that they need to
350 * configure all PIM routers to use the same version of IGMP.
351 */
352 if (query_version != pim_ifp->igmp_version) {
353 zlog_warn(
354 "Recv IGMP query v%d from %s on %s but we are using v%d, please configure all PIM routers on this subnet to use the same IGMP version",
355 query_version, from_str, ifp->name,
356 pim_ifp->igmp_version);
357 return 0;
358 }
359
360 if (PIM_DEBUG_IGMP_PACKETS) {
361 char group_str[INET_ADDRSTRLEN];
362 pim_inet4_dump("<group?>", group_addr, group_str,
363 sizeof(group_str));
364 zlog_debug("Recv IGMP query v%d from %s on %s for group %s",
365 query_version, from_str, ifp->name, group_str);
366 }
367
368 /*
369 RFC 3376: 6.6.2. Querier Election
370
371 When a router receives a query with a lower IP address, it sets
372 the Other-Querier-Present timer to Other Querier Present Interval
373 and ceases to send queries on the network if it was the previously
374 elected querier.
375 */
376 if (ntohl(from.s_addr) < ntohl(igmp->ifaddr.s_addr)) {
377
378 if (PIM_DEBUG_IGMP_TRACE) {
379 char ifaddr_str[INET_ADDRSTRLEN];
380 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
381 sizeof(ifaddr_str));
382 zlog_debug(
383 "%s: local address %s (%u) lost querier election to %s (%u)",
384 ifp->name, ifaddr_str,
385 ntohl(igmp->ifaddr.s_addr), from_str,
386 ntohl(from.s_addr));
387 }
388
389 pim_igmp_other_querier_timer_on(igmp);
390 }
391
392 /* IGMP version 3 is the only one where we process the RXed query */
393 if (query_version == 3) {
394 igmp_v3_recv_query(igmp, from_str, igmp_msg);
395 }
396
397 return 0;
398 }
399
on_trace(const char * label,struct interface * ifp,struct in_addr from)400 static void on_trace(const char *label, struct interface *ifp,
401 struct in_addr from)
402 {
403 if (PIM_DEBUG_IGMP_TRACE) {
404 char from_str[INET_ADDRSTRLEN];
405 pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
406 zlog_debug("%s: from %s on %s", label, from_str, ifp->name);
407 }
408 }
409
igmp_v1_recv_report(struct igmp_sock * igmp,struct in_addr from,const char * from_str,char * igmp_msg,int igmp_msg_len)410 static int igmp_v1_recv_report(struct igmp_sock *igmp, struct in_addr from,
411 const char *from_str, char *igmp_msg,
412 int igmp_msg_len)
413 {
414 struct interface *ifp = igmp->interface;
415 struct igmp_group *group;
416 struct in_addr group_addr;
417
418 on_trace(__func__, igmp->interface, from);
419
420 if (igmp->mtrace_only)
421 return 0;
422
423 if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
424 zlog_warn(
425 "Recv IGMP report v1 from %s on %s: size=%d other than correct=%d",
426 from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
427 return -1;
428 }
429
430 /* Collecting IGMP Rx stats */
431 igmp->rx_stats.report_v1++;
432
433 if (PIM_DEBUG_IGMP_TRACE) {
434 zlog_warn("%s %s: FIXME WRITEME", __FILE__, __func__);
435 }
436
437 memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
438
439 if (pim_is_group_filtered(ifp->info, &group_addr))
440 return -1;
441
442 /* non-existant group is created as INCLUDE {empty} */
443 group = igmp_add_group_by_addr(igmp, group_addr);
444 if (!group) {
445 return -1;
446 }
447
448 group->last_igmp_v1_report_dsec = pim_time_monotonic_dsec();
449
450 return 0;
451 }
452
pim_igmp_packet(struct igmp_sock * igmp,char * buf,size_t len)453 int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len)
454 {
455 struct ip *ip_hdr;
456 size_t ip_hlen; /* ip header length in bytes */
457 char *igmp_msg;
458 int igmp_msg_len;
459 int msg_type;
460 char from_str[INET_ADDRSTRLEN];
461 char to_str[INET_ADDRSTRLEN];
462
463 if (len < sizeof(*ip_hdr)) {
464 zlog_warn("IGMP packet size=%zu shorter than minimum=%zu", len,
465 sizeof(*ip_hdr));
466 return -1;
467 }
468
469 ip_hdr = (struct ip *)buf;
470
471 pim_inet4_dump("<src?>", ip_hdr->ip_src, from_str, sizeof(from_str));
472 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, to_str, sizeof(to_str));
473
474 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
475
476 if (ip_hlen > len) {
477 zlog_warn(
478 "IGMP packet header claims size %zu, but we only have %zu bytes",
479 ip_hlen, len);
480 return -1;
481 }
482
483 igmp_msg = buf + ip_hlen;
484 igmp_msg_len = len - ip_hlen;
485
486 if (igmp_msg_len < PIM_IGMP_MIN_LEN) {
487 zlog_warn("IGMP message size=%d shorter than minimum=%d",
488 igmp_msg_len, PIM_IGMP_MIN_LEN);
489 return -1;
490 }
491
492 msg_type = *igmp_msg;
493
494 if (PIM_DEBUG_IGMP_PACKETS) {
495 zlog_debug(
496 "Recv IGMP packet from %s to %s on %s: size=%zu ttl=%d msg_type=%d msg_size=%d",
497 from_str, to_str, igmp->interface->name, len, ip_hdr->ip_ttl,
498 msg_type, igmp_msg_len);
499 }
500
501 switch (msg_type) {
502 case PIM_IGMP_MEMBERSHIP_QUERY: {
503 int max_resp_code = igmp_msg[1];
504 int query_version;
505
506 /*
507 RFC 3376: 7.1. Query Version Distinctions
508 IGMPv1 Query: length = 8 octets AND Max Resp Code field is
509 zero
510 IGMPv2 Query: length = 8 octets AND Max Resp Code field is
511 non-zero
512 IGMPv3 Query: length >= 12 octets
513 */
514
515 if (igmp_msg_len == 8) {
516 query_version = max_resp_code ? 2 : 1;
517 } else if (igmp_msg_len >= 12) {
518 query_version = 3;
519 } else {
520 zlog_warn("Unknown IGMP query version");
521 return -1;
522 }
523
524 return igmp_recv_query(igmp, query_version, max_resp_code,
525 ip_hdr->ip_src, from_str, igmp_msg,
526 igmp_msg_len);
527 }
528
529 case PIM_IGMP_V3_MEMBERSHIP_REPORT:
530 return igmp_v3_recv_report(igmp, ip_hdr->ip_src, from_str,
531 igmp_msg, igmp_msg_len);
532
533 case PIM_IGMP_V2_MEMBERSHIP_REPORT:
534 return igmp_v2_recv_report(igmp, ip_hdr->ip_src, from_str,
535 igmp_msg, igmp_msg_len);
536
537 case PIM_IGMP_V1_MEMBERSHIP_REPORT:
538 return igmp_v1_recv_report(igmp, ip_hdr->ip_src, from_str,
539 igmp_msg, igmp_msg_len);
540
541 case PIM_IGMP_V2_LEAVE_GROUP:
542 return igmp_v2_recv_leave(igmp, ip_hdr->ip_src, from_str,
543 igmp_msg, igmp_msg_len);
544
545 case PIM_IGMP_MTRACE_RESPONSE:
546 return igmp_mtrace_recv_response(igmp, ip_hdr, ip_hdr->ip_src,
547 from_str, igmp_msg,
548 igmp_msg_len);
549 case PIM_IGMP_MTRACE_QUERY_REQUEST:
550 return igmp_mtrace_recv_qry_req(igmp, ip_hdr, ip_hdr->ip_src,
551 from_str, igmp_msg,
552 igmp_msg_len);
553 }
554
555 zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type);
556
557 /* Collecting IGMP Rx stats */
558 igmp->rx_stats.unsupported++;
559
560 return -1;
561 }
562
pim_igmp_general_query_on(struct igmp_sock * igmp)563 void pim_igmp_general_query_on(struct igmp_sock *igmp)
564 {
565 struct pim_interface *pim_ifp;
566 int startup_mode;
567 int query_interval;
568
569 /*
570 Since this socket is starting as querier,
571 there should not exist a timer for other-querier-present.
572 */
573 zassert(!igmp->t_other_querier_timer);
574 pim_ifp = igmp->interface->info;
575 zassert(pim_ifp);
576
577 /*
578 RFC 3376: 8.6. Startup Query Interval
579
580 The Startup Query Interval is the interval between General Queries
581 sent by a Querier on startup. Default: 1/4 the Query Interval.
582 The first one should be sent out immediately instead of 125/4
583 seconds from now.
584 */
585 startup_mode = igmp->startup_query_count > 0;
586 if (startup_mode) {
587 /*
588 * If this is the first time we are sending a query on a
589 * newly configured igmp interface send it out in 1 second
590 * just to give the entire world a tiny bit of time to settle
591 * else the query interval is:
592 * query_interval = pim_ifp->igmp_default_query_interval >> 2;
593 */
594 if (igmp->startup_query_count
595 == igmp->querier_robustness_variable)
596 query_interval = 1;
597 else
598 query_interval = PIM_IGMP_SQI(
599 pim_ifp->igmp_default_query_interval);
600
601 --igmp->startup_query_count;
602 } else {
603 query_interval = igmp->querier_query_interval;
604 }
605
606 if (PIM_DEBUG_IGMP_TRACE) {
607 char ifaddr_str[INET_ADDRSTRLEN];
608 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
609 sizeof(ifaddr_str));
610 zlog_debug(
611 "Querier %s scheduling %d-second (%s) TIMER event for IGMP query on fd=%d",
612 ifaddr_str, query_interval,
613 startup_mode ? "startup" : "non-startup", igmp->fd);
614 }
615 igmp->t_igmp_query_timer = NULL;
616 thread_add_timer(router->master, pim_igmp_general_query, igmp,
617 query_interval, &igmp->t_igmp_query_timer);
618 }
619
pim_igmp_general_query_off(struct igmp_sock * igmp)620 void pim_igmp_general_query_off(struct igmp_sock *igmp)
621 {
622 zassert(igmp);
623
624 if (PIM_DEBUG_IGMP_TRACE) {
625 if (igmp->t_igmp_query_timer) {
626 char ifaddr_str[INET_ADDRSTRLEN];
627 pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
628 sizeof(ifaddr_str));
629 zlog_debug(
630 "IGMP querier %s fd=%d cancelling query TIMER event on %s",
631 ifaddr_str, igmp->fd, igmp->interface->name);
632 }
633 }
634 THREAD_OFF(igmp->t_igmp_query_timer);
635 }
636
637 /* Issue IGMP general query */
pim_igmp_general_query(struct thread * t)638 static int pim_igmp_general_query(struct thread *t)
639 {
640 struct igmp_sock *igmp;
641 struct in_addr dst_addr;
642 struct in_addr group_addr;
643 struct pim_interface *pim_ifp;
644 int query_buf_size;
645
646 igmp = THREAD_ARG(t);
647
648 zassert(igmp->interface);
649 zassert(igmp->interface->info);
650
651 pim_ifp = igmp->interface->info;
652
653 if (pim_ifp->igmp_version == 3) {
654 query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
655 } else {
656 query_buf_size = IGMP_V12_MSG_SIZE;
657 }
658
659 char query_buf[query_buf_size];
660
661 /*
662 RFC3376: 4.1.12. IP Destination Addresses for Queries
663
664 In IGMPv3, General Queries are sent with an IP destination address
665 of 224.0.0.1, the all-systems multicast address. Group-Specific
666 and Group-and-Source-Specific Queries are sent with an IP
667 destination address equal to the multicast address of interest.
668 */
669
670 dst_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
671 group_addr.s_addr = PIM_NET_INADDR_ANY;
672
673 if (PIM_DEBUG_IGMP_TRACE) {
674 char querier_str[INET_ADDRSTRLEN];
675 char dst_str[INET_ADDRSTRLEN];
676 pim_inet4_dump("<querier?>", igmp->ifaddr, querier_str,
677 sizeof(querier_str));
678 pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
679 zlog_debug("Querier %s issuing IGMP general query to %s on %s",
680 querier_str, dst_str, igmp->interface->name);
681 }
682
683 igmp_send_query(pim_ifp->igmp_version, 0 /* igmp_group */, igmp->fd,
684 igmp->interface->name, query_buf, sizeof(query_buf),
685 0 /* num_sources */, dst_addr, group_addr,
686 pim_ifp->igmp_query_max_response_time_dsec,
687 1 /* s_flag: always set for general queries */,
688 igmp->querier_robustness_variable,
689 igmp->querier_query_interval);
690
691 pim_igmp_general_query_on(igmp);
692
693 return 0;
694 }
695
sock_close(struct igmp_sock * igmp)696 static void sock_close(struct igmp_sock *igmp)
697 {
698 pim_igmp_other_querier_timer_off(igmp);
699 pim_igmp_general_query_off(igmp);
700
701 if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
702 if (igmp->t_igmp_read) {
703 zlog_debug(
704 "Cancelling READ event on IGMP socket %s fd=%d on interface %s",
705 inet_ntoa(igmp->ifaddr), igmp->fd,
706 igmp->interface->name);
707 }
708 }
709 THREAD_OFF(igmp->t_igmp_read);
710
711 if (close(igmp->fd)) {
712 flog_err(
713 EC_LIB_SOCKET,
714 "Failure closing IGMP socket %s fd=%d on interface %s: errno=%d: %s",
715 inet_ntoa(igmp->ifaddr), igmp->fd,
716 igmp->interface->name, errno, safe_strerror(errno));
717 }
718
719 if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
720 zlog_debug("Deleted IGMP socket %s fd=%d on interface %s",
721 inet_ntoa(igmp->ifaddr), igmp->fd,
722 igmp->interface->name);
723 }
724 }
725
igmp_startup_mode_on(struct igmp_sock * igmp)726 void igmp_startup_mode_on(struct igmp_sock *igmp)
727 {
728 struct pim_interface *pim_ifp;
729
730 pim_ifp = igmp->interface->info;
731
732 /*
733 RFC 3376: 8.7. Startup Query Count
734
735 The Startup Query Count is the number of Queries sent out on
736 startup, separated by the Startup Query Interval. Default: the
737 Robustness Variable.
738 */
739 igmp->startup_query_count = igmp->querier_robustness_variable;
740
741 /*
742 Since we're (re)starting, reset QQI to default Query Interval
743 */
744 igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
745 }
746
igmp_group_free(struct igmp_group * group)747 static void igmp_group_free(struct igmp_group *group)
748 {
749 list_delete(&group->group_source_list);
750
751 XFREE(MTYPE_PIM_IGMP_GROUP, group);
752 }
753
igmp_group_count_incr(struct igmp_sock * igmp)754 static void igmp_group_count_incr(struct igmp_sock *igmp)
755 {
756 struct pim_interface *pim_ifp = igmp->interface->info;
757
758 if (!pim_ifp)
759 return;
760
761 ++pim_ifp->pim->igmp_group_count;
762 if (pim_ifp->pim->igmp_group_count
763 == pim_ifp->pim->igmp_watermark_limit) {
764 zlog_warn(
765 "IGMP group count reached watermark limit: %u(vrf: %s)",
766 pim_ifp->pim->igmp_group_count,
767 VRF_LOGNAME(pim_ifp->pim->vrf));
768 }
769 }
770
igmp_group_count_decr(struct igmp_sock * igmp)771 static void igmp_group_count_decr(struct igmp_sock *igmp)
772 {
773 struct pim_interface *pim_ifp = igmp->interface->info;
774
775 if (!pim_ifp)
776 return;
777
778 if (pim_ifp->pim->igmp_group_count == 0) {
779 zlog_warn("Cannot decrement igmp group count below 0(vrf: %s)",
780 VRF_LOGNAME(pim_ifp->pim->vrf));
781 return;
782 }
783
784 --pim_ifp->pim->igmp_group_count;
785 }
786
igmp_group_delete(struct igmp_group * group)787 void igmp_group_delete(struct igmp_group *group)
788 {
789 struct listnode *src_node;
790 struct listnode *src_nextnode;
791 struct igmp_source *src;
792
793 if (PIM_DEBUG_IGMP_TRACE) {
794 char group_str[INET_ADDRSTRLEN];
795 pim_inet4_dump("<group?>", group->group_addr, group_str,
796 sizeof(group_str));
797 zlog_debug("Deleting IGMP group %s from socket %d interface %s",
798 group_str, group->group_igmp_sock->fd,
799 group->group_igmp_sock->interface->name);
800 }
801
802 for (ALL_LIST_ELEMENTS(group->group_source_list, src_node, src_nextnode,
803 src)) {
804 igmp_source_delete(src);
805 }
806
807 if (group->t_group_query_retransmit_timer) {
808 THREAD_OFF(group->t_group_query_retransmit_timer);
809 }
810
811 group_timer_off(group);
812 igmp_group_count_decr(group->group_igmp_sock);
813 listnode_delete(group->group_igmp_sock->igmp_group_list, group);
814 hash_release(group->group_igmp_sock->igmp_group_hash, group);
815
816 igmp_group_free(group);
817 }
818
igmp_group_delete_empty_include(struct igmp_group * group)819 void igmp_group_delete_empty_include(struct igmp_group *group)
820 {
821 zassert(!group->group_filtermode_isexcl);
822 zassert(!listcount(group->group_source_list));
823
824 igmp_group_delete(group);
825 }
826
igmp_sock_free(struct igmp_sock * igmp)827 void igmp_sock_free(struct igmp_sock *igmp)
828 {
829 zassert(!igmp->t_igmp_read);
830 zassert(!igmp->t_igmp_query_timer);
831 zassert(!igmp->t_other_querier_timer);
832 zassert(igmp->igmp_group_list);
833 zassert(!listcount(igmp->igmp_group_list));
834
835 list_delete(&igmp->igmp_group_list);
836 hash_free(igmp->igmp_group_hash);
837
838 XFREE(MTYPE_PIM_IGMP_SOCKET, igmp);
839 }
840
igmp_sock_delete(struct igmp_sock * igmp)841 void igmp_sock_delete(struct igmp_sock *igmp)
842 {
843 struct pim_interface *pim_ifp;
844 struct listnode *grp_node;
845 struct listnode *grp_nextnode;
846 struct igmp_group *grp;
847
848 for (ALL_LIST_ELEMENTS(igmp->igmp_group_list, grp_node, grp_nextnode,
849 grp)) {
850 igmp_group_delete(grp);
851 }
852
853 sock_close(igmp);
854
855 pim_ifp = igmp->interface->info;
856
857 listnode_delete(pim_ifp->igmp_socket_list, igmp);
858
859 igmp_sock_free(igmp);
860 }
861
igmp_sock_delete_all(struct interface * ifp)862 void igmp_sock_delete_all(struct interface *ifp)
863 {
864 struct pim_interface *pim_ifp;
865 struct listnode *igmp_node, *igmp_nextnode;
866 struct igmp_sock *igmp;
867
868 pim_ifp = ifp->info;
869
870 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_socket_list, igmp_node,
871 igmp_nextnode, igmp)) {
872 igmp_sock_delete(igmp);
873 }
874 }
875
igmp_group_hash_key(const void * arg)876 static unsigned int igmp_group_hash_key(const void *arg)
877 {
878 const struct igmp_group *group = arg;
879
880 return jhash_1word(group->group_addr.s_addr, 0);
881 }
882
igmp_group_hash_equal(const void * arg1,const void * arg2)883 static bool igmp_group_hash_equal(const void *arg1, const void *arg2)
884 {
885 const struct igmp_group *g1 = (const struct igmp_group *)arg1;
886 const struct igmp_group *g2 = (const struct igmp_group *)arg2;
887
888 if (g1->group_addr.s_addr == g2->group_addr.s_addr)
889 return true;
890
891 return false;
892 }
893
igmp_sock_new(int fd,struct in_addr ifaddr,struct interface * ifp,int mtrace_only)894 static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr,
895 struct interface *ifp, int mtrace_only)
896 {
897 struct pim_interface *pim_ifp;
898 struct igmp_sock *igmp;
899 char hash_name[64];
900
901 pim_ifp = ifp->info;
902
903 if (PIM_DEBUG_IGMP_TRACE) {
904 zlog_debug(
905 "Creating IGMP socket fd=%d for address %s on interface %s",
906 fd, inet_ntoa(ifaddr), ifp->name);
907 }
908
909 igmp = XCALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp));
910
911 igmp->igmp_group_list = list_new();
912 igmp->igmp_group_list->del = (void (*)(void *))igmp_group_free;
913
914 snprintf(hash_name, sizeof(hash_name), "IGMP %s hash", ifp->name);
915 igmp->igmp_group_hash = hash_create(igmp_group_hash_key,
916 igmp_group_hash_equal, hash_name);
917
918 igmp->fd = fd;
919 igmp->interface = ifp;
920 igmp->ifaddr = ifaddr;
921 igmp->t_igmp_read = NULL;
922 igmp->t_igmp_query_timer = NULL;
923 igmp->t_other_querier_timer = NULL; /* no other querier present */
924 igmp->querier_robustness_variable =
925 pim_ifp->igmp_default_robustness_variable;
926 igmp->sock_creation = pim_time_monotonic_sec();
927
928 igmp_stats_init(&igmp->rx_stats);
929
930 if (mtrace_only) {
931 igmp->mtrace_only = mtrace_only;
932 return igmp;
933 }
934
935 igmp->mtrace_only = false;
936
937 /*
938 igmp_startup_mode_on() will reset QQI:
939
940 igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
941 */
942 igmp_startup_mode_on(igmp);
943 pim_igmp_general_query_on(igmp);
944
945 return igmp;
946 }
947
948 static void igmp_read_on(struct igmp_sock *igmp);
949
pim_igmp_read(struct thread * t)950 static int pim_igmp_read(struct thread *t)
951 {
952 uint8_t buf[10000];
953 struct igmp_sock *igmp = (struct igmp_sock *)THREAD_ARG(t);
954 struct sockaddr_in from;
955 struct sockaddr_in to;
956 socklen_t fromlen = sizeof(from);
957 socklen_t tolen = sizeof(to);
958 ifindex_t ifindex = -1;
959 int len;
960
961 while (1) {
962 len = pim_socket_recvfromto(igmp->fd, buf, sizeof(buf), &from,
963 &fromlen, &to, &tolen, &ifindex);
964 if (len < 0) {
965 if (errno == EINTR)
966 continue;
967 if (errno == EWOULDBLOCK || errno == EAGAIN)
968 break;
969
970 goto done;
971 }
972 }
973
974 done:
975 igmp_read_on(igmp);
976 return 0;
977 }
978
igmp_read_on(struct igmp_sock * igmp)979 static void igmp_read_on(struct igmp_sock *igmp)
980 {
981
982 if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
983 zlog_debug("Scheduling READ event on IGMP socket fd=%d",
984 igmp->fd);
985 }
986 igmp->t_igmp_read = NULL;
987 thread_add_read(router->master, pim_igmp_read, igmp, igmp->fd,
988 &igmp->t_igmp_read);
989 }
990
pim_igmp_sock_add(struct list * igmp_sock_list,struct in_addr ifaddr,struct interface * ifp,bool mtrace_only)991 struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
992 struct in_addr ifaddr,
993 struct interface *ifp,
994 bool mtrace_only)
995 {
996 struct pim_interface *pim_ifp;
997 struct igmp_sock *igmp;
998 struct sockaddr_in sin;
999 int fd;
1000
1001 pim_ifp = ifp->info;
1002
1003 fd = igmp_sock_open(ifaddr, ifp, pim_ifp->options);
1004 if (fd < 0) {
1005 zlog_warn("Could not open IGMP socket for %s on %s",
1006 inet_ntoa(ifaddr), ifp->name);
1007 return NULL;
1008 }
1009
1010 sin.sin_family = AF_INET;
1011 sin.sin_addr = ifaddr;
1012 sin.sin_port = 0;
1013 if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
1014 zlog_warn("Could not bind IGMP socket for %s on %s",
1015 inet_ntoa(ifaddr), ifp->name);
1016 close(fd);
1017
1018 return NULL;
1019 }
1020
1021 igmp = igmp_sock_new(fd, ifaddr, ifp, mtrace_only);
1022
1023 igmp_read_on(igmp);
1024
1025 listnode_add(igmp_sock_list, igmp);
1026
1027 #ifdef IGMP_SOCK_DUMP
1028 igmp_sock_dump(igmp_sock_array);
1029 #endif
1030
1031 return igmp;
1032 }
1033
1034 /*
1035 RFC 3376: 6.5. Switching Router Filter-Modes
1036
1037 When a router's filter-mode for a group is EXCLUDE and the group
1038 timer expires, the router filter-mode for the group transitions to
1039 INCLUDE.
1040
1041 A router uses source records with running source timers as its state
1042 for the switch to a filter-mode of INCLUDE. If there are any source
1043 records with source timers greater than zero (i.e., requested to be
1044 forwarded), a router switches to filter-mode of INCLUDE using those
1045 source records. Source records whose timers are zero (from the
1046 previous EXCLUDE mode) are deleted.
1047 */
igmp_group_timer(struct thread * t)1048 static int igmp_group_timer(struct thread *t)
1049 {
1050 struct igmp_group *group;
1051
1052 group = THREAD_ARG(t);
1053
1054 if (PIM_DEBUG_IGMP_TRACE) {
1055 char group_str[INET_ADDRSTRLEN];
1056 pim_inet4_dump("<group?>", group->group_addr, group_str,
1057 sizeof(group_str));
1058 zlog_debug("%s: Timer for group %s on interface %s", __func__,
1059 group_str, group->group_igmp_sock->interface->name);
1060 }
1061
1062 zassert(group->group_filtermode_isexcl);
1063
1064 group->group_filtermode_isexcl = 0;
1065
1066 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
1067 igmp_anysource_forward_stop(group);
1068
1069 igmp_source_delete_expired(group->group_source_list);
1070
1071 zassert(!group->group_filtermode_isexcl);
1072
1073 /*
1074 RFC 3376: 6.2.2. Definition of Group Timers
1075
1076 If there are no more source records for the group, delete group
1077 record.
1078 */
1079 if (listcount(group->group_source_list) < 1) {
1080 igmp_group_delete_empty_include(group);
1081 }
1082
1083 return 0;
1084 }
1085
group_timer_off(struct igmp_group * group)1086 static void group_timer_off(struct igmp_group *group)
1087 {
1088 if (!group->t_group_timer)
1089 return;
1090
1091 if (PIM_DEBUG_IGMP_TRACE) {
1092 char group_str[INET_ADDRSTRLEN];
1093 pim_inet4_dump("<group?>", group->group_addr, group_str,
1094 sizeof(group_str));
1095 zlog_debug("Cancelling TIMER event for group %s on %s",
1096 group_str, group->group_igmp_sock->interface->name);
1097 }
1098 THREAD_OFF(group->t_group_timer);
1099 }
1100
igmp_group_timer_on(struct igmp_group * group,long interval_msec,const char * ifname)1101 void igmp_group_timer_on(struct igmp_group *group, long interval_msec,
1102 const char *ifname)
1103 {
1104 group_timer_off(group);
1105
1106 if (PIM_DEBUG_IGMP_EVENTS) {
1107 char group_str[INET_ADDRSTRLEN];
1108 pim_inet4_dump("<group?>", group->group_addr, group_str,
1109 sizeof(group_str));
1110 zlog_debug(
1111 "Scheduling %ld.%03ld sec TIMER event for group %s on %s",
1112 interval_msec / 1000, interval_msec % 1000, group_str,
1113 ifname);
1114 }
1115
1116 /*
1117 RFC 3376: 6.2.2. Definition of Group Timers
1118
1119 The group timer is only used when a group is in EXCLUDE mode and
1120 it represents the time for the *filter-mode* of the group to
1121 expire and switch to INCLUDE mode.
1122 */
1123 zassert(group->group_filtermode_isexcl);
1124
1125 thread_add_timer_msec(router->master, igmp_group_timer, group,
1126 interval_msec, &group->t_group_timer);
1127 }
1128
find_group_by_addr(struct igmp_sock * igmp,struct in_addr group_addr)1129 struct igmp_group *find_group_by_addr(struct igmp_sock *igmp,
1130 struct in_addr group_addr)
1131 {
1132 struct igmp_group lookup;
1133
1134 lookup.group_addr.s_addr = group_addr.s_addr;
1135
1136 return hash_lookup(igmp->igmp_group_hash, &lookup);
1137 }
1138
igmp_add_group_by_addr(struct igmp_sock * igmp,struct in_addr group_addr)1139 struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
1140 struct in_addr group_addr)
1141 {
1142 struct igmp_group *group;
1143
1144 group = find_group_by_addr(igmp, group_addr);
1145 if (group) {
1146 return group;
1147 }
1148
1149 if (!pim_is_group_224_4(group_addr)) {
1150 zlog_warn("%s: Group Specified is not part of 224.0.0.0/4",
1151 __func__);
1152 return NULL;
1153 }
1154
1155 if (pim_is_group_224_0_0_0_24(group_addr)) {
1156 if (PIM_DEBUG_IGMP_TRACE)
1157 zlog_debug(
1158 "%s: Group specified %s is part of 224.0.0.0/24",
1159 __func__, inet_ntoa(group_addr));
1160 return NULL;
1161 }
1162 /*
1163 Non-existant group is created as INCLUDE {empty}:
1164
1165 RFC 3376 - 5.1. Action on Change of Interface State
1166
1167 If no interface state existed for that multicast address before
1168 the change (i.e., the change consisted of creating a new
1169 per-interface record), or if no state exists after the change
1170 (i.e., the change consisted of deleting a per-interface record),
1171 then the "non-existent" state is considered to have a filter mode
1172 of INCLUDE and an empty source list.
1173 */
1174
1175 group = XCALLOC(MTYPE_PIM_IGMP_GROUP, sizeof(*group));
1176
1177 group->group_source_list = list_new();
1178 group->group_source_list->del = (void (*)(void *))igmp_source_free;
1179
1180 group->t_group_timer = NULL;
1181 group->t_group_query_retransmit_timer = NULL;
1182 group->group_specific_query_retransmit_count = 0;
1183 group->group_addr = group_addr;
1184 group->group_igmp_sock = igmp;
1185 group->last_igmp_v1_report_dsec = -1;
1186 group->last_igmp_v2_report_dsec = -1;
1187 group->group_creation = pim_time_monotonic_sec();
1188 group->igmp_version = IGMP_DEFAULT_VERSION;
1189
1190 /* initialize new group as INCLUDE {empty} */
1191 group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */
1192
1193 listnode_add(igmp->igmp_group_list, group);
1194 group = hash_get(igmp->igmp_group_hash, group, hash_alloc_intern);
1195
1196 if (PIM_DEBUG_IGMP_TRACE) {
1197 char group_str[INET_ADDRSTRLEN];
1198 pim_inet4_dump("<group?>", group->group_addr, group_str,
1199 sizeof(group_str));
1200 zlog_debug(
1201 "Creating new IGMP group %s on socket %d interface %s",
1202 group_str, igmp->fd, igmp->interface->name);
1203 }
1204
1205 igmp_group_count_incr(igmp);
1206
1207 /*
1208 RFC 3376: 6.2.2. Definition of Group Timers
1209
1210 The group timer is only used when a group is in EXCLUDE mode and
1211 it represents the time for the *filter-mode* of the group to
1212 expire and switch to INCLUDE mode.
1213 */
1214 zassert(!group->group_filtermode_isexcl); /* INCLUDE mode */
1215 zassert(!group->t_group_timer); /* group timer == 0 */
1216
1217 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
1218 igmp_anysource_forward_stop(group);
1219
1220 return group;
1221 }
1222
igmp_send_query(int igmp_version,struct igmp_group * group,int fd,const char * ifname,char * query_buf,int query_buf_size,int num_sources,struct in_addr dst_addr,struct in_addr group_addr,int query_max_response_time_dsec,uint8_t s_flag,uint8_t querier_robustness_variable,uint16_t querier_query_interval)1223 void igmp_send_query(int igmp_version, struct igmp_group *group, int fd,
1224 const char *ifname, char *query_buf, int query_buf_size,
1225 int num_sources, struct in_addr dst_addr,
1226 struct in_addr group_addr,
1227 int query_max_response_time_dsec, uint8_t s_flag,
1228 uint8_t querier_robustness_variable,
1229 uint16_t querier_query_interval)
1230 {
1231 if (igmp_version == 3) {
1232 igmp_v3_send_query(group, fd, ifname, query_buf, query_buf_size,
1233 num_sources, dst_addr, group_addr,
1234 query_max_response_time_dsec, s_flag,
1235 querier_robustness_variable,
1236 querier_query_interval);
1237 } else if (igmp_version == 2) {
1238 igmp_v2_send_query(group, fd, ifname, query_buf, dst_addr,
1239 group_addr, query_max_response_time_dsec);
1240 }
1241 }
1242
igmp_send_query_on_intf(struct interface * ifp,int igmp_ver)1243 void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver)
1244 {
1245 struct pim_interface *pim_ifp = ifp->info;
1246 struct listnode *sock_node = NULL;
1247 struct igmp_sock *igmp = NULL;
1248 struct in_addr dst_addr;
1249 struct in_addr group_addr;
1250 int query_buf_size;
1251
1252 if (!igmp_ver)
1253 igmp_ver = 2;
1254
1255 if (igmp_ver == 3)
1256 query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
1257 else
1258 query_buf_size = IGMP_V12_MSG_SIZE;
1259
1260 dst_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
1261 group_addr.s_addr = PIM_NET_INADDR_ANY;
1262
1263 if (PIM_DEBUG_IGMP_TRACE)
1264 zlog_debug("Issuing general query on request on %s",
1265 ifp->name);
1266
1267 for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
1268
1269 char query_buf[query_buf_size];
1270
1271 igmp_send_query(igmp_ver, 0 /* igmp_group */, igmp->fd,
1272 igmp->interface->name, query_buf,
1273 sizeof(query_buf), 0 /* num_sources */,
1274 dst_addr, group_addr,
1275 pim_ifp->igmp_query_max_response_time_dsec,
1276 1 /* s_flag: always set for general queries */,
1277 igmp->querier_robustness_variable,
1278 igmp->querier_query_interval);
1279 }
1280 }
1281