1 /* $NetBSD: mapper.c,v 1.24 2007/02/22 01:25:13 hubertf Exp $ */
3 /* Mapper for connections between MRouteD multicast routers.
4 * Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
8 * Copyright (c) 1992, 2001 Xerox Corporation. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
13 * Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
20 * Neither name of the Xerox, PARC, nor the names of its contributors may be used
21 * to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
26 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
34 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <sys/cdefs.h>
44 #include <arpa/inet.h>
47 #define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
48 #define DEFAULT_RETRIES 1 /* How many times to ask each router */
51 /* All IP addresses are stored in the data structure in NET order. */
53 typedef struct neighbor
{
54 struct neighbor
*next
;
55 u_int32_t addr
; /* IP address in NET order */
56 u_char metric
; /* TTL cost of forwarding */
57 u_char threshold
; /* TTL threshold to forward */
58 u_short flags
; /* flags on connection */
59 #define NF_PRESENT 0x8000 /* True if flags are meaningful */
62 typedef struct interface
{
63 struct interface
*next
;
64 u_int32_t addr
; /* IP address of the interface in NET order */
65 Neighbor
*neighbors
; /* List of neighbors' IP addresses */
69 u_int32_t addr
; /* IP address of this entry in NET order */
70 u_int32_t version
; /* which mrouted version is running */
71 int tries
; /* How many requests sent? -1 for aliases */
73 struct node
*alias
; /* If alias, to what? */
74 struct interface
*interfaces
; /* Else, neighbor data */
76 struct node
*left
, *right
;
81 u_int32_t our_addr
, target_addr
= 0; /* in NET order */
83 int retries
= DEFAULT_RETRIES
;
84 int timeout
= DEFAULT_TIMEOUT
;
85 int show_names
= TRUE
;
86 vifi_t numvifs
; /* to keep loader happy */
87 /* (see COPY_TABLES macro called in kern.c) */
89 Node
* find_node(u_int32_t addr
, Node
**ptr
);
90 Interface
* find_interface(u_int32_t addr
, Node
*node
);
91 Neighbor
* find_neighbor(u_int32_t addr
, Node
*node
);
92 int main(int argc
, char *argv
[]);
93 void ask(u_int32_t dst
);
94 void ask2(u_int32_t dst
);
95 int retry_requests(Node
*node
);
96 char * inet_name(u_int32_t addr
);
97 void print_map(Node
*node
);
98 char * graph_name(u_int32_t addr
, char *buf
, size_t);
99 void graph_edges(Node
*node
);
100 void elide_aliases(Node
*node
);
101 void graph_map(void);
102 int get_number(int *var
, int deflt
, char ***pargv
,
104 u_int32_t
host_addr(char *name
);
106 void logit(int severity
, int syserr
, const char *format
, ...)
107 __attribute__((__format__(__printf__
, 3, 4)));
109 Node
*find_node(u_int32_t addr
, Node
**ptr
)
114 *ptr
= n
= (Node
*) malloc(sizeof(Node
));
119 n
->left
= n
->right
= 0;
121 } else if (addr
== n
->addr
)
123 else if (addr
< n
->addr
)
124 return find_node(addr
, &(n
->left
));
126 return find_node(addr
, &(n
->right
));
130 Interface
*find_interface(u_int32_t addr
, Node
*node
)
134 for (ifc
= node
->u
.interfaces
; ifc
; ifc
= ifc
->next
)
135 if (ifc
->addr
== addr
)
138 ifc
= (Interface
*) malloc(sizeof(Interface
));
140 ifc
->next
= node
->u
.interfaces
;
141 node
->u
.interfaces
= ifc
;
148 Neighbor
*find_neighbor(u_int32_t addr
, Node
*node
)
152 for (ifc
= node
->u
.interfaces
; ifc
; ifc
= ifc
->next
) {
155 for (nb
= ifc
->neighbors
; nb
; nb
= nb
->next
)
156 if (nb
->addr
== addr
)
165 * Log errors and other messages to stderr, according to the severity of the
166 * message and the current debug level. For errors of severity LOG_ERR or
167 * worse, terminate the program.
170 logit(int severity
, int syserr
, const char *format
, ...)
176 case 0: if (severity
> LOG_WARNING
) return;
177 case 1: if (severity
> LOG_NOTICE
) return;
178 case 2: if (severity
> LOG_INFO
) return;
181 if (severity
== LOG_WARNING
)
182 strlcat(fmt
, "warning - ", sizeof(fmt
));
183 strlcat(fmt
, format
, sizeof(fmt
));
185 va_start(ap
, format
);
186 vfprintf(stderr
, format
, ap
);
189 fprintf(stderr
, "\n");
191 fprintf(stderr
, ": %s\n", strerror(syserr
));
194 if (severity
<= LOG_ERR
)
200 * Send a neighbors-list request.
202 void ask(u_int32_t dst
)
204 send_igmp(our_addr
, dst
, IGMP_DVMRP
, DVMRP_ASK_NEIGHBORS
,
205 htonl(MROUTED_LEVEL
), 0);
208 void ask2(u_int32_t dst
)
210 send_igmp(our_addr
, dst
, IGMP_DVMRP
, DVMRP_ASK_NEIGHBORS2
,
211 htonl(MROUTED_LEVEL
), 0);
216 * Process an incoming group membership report.
218 void accept_group_report(u_int32_t src
, u_int32_t dst
, u_int32_t group
, int r_type
)
220 logit(LOG_INFO
, 0, "ignoring IGMP group membership report from %s to %s",
221 inet_fmt(src
), inet_fmt(dst
));
226 * Process an incoming neighbor probe message.
228 void accept_probe(u_int32_t src
, u_int32_t dst
, char *p
, int datalen
,
231 logit(LOG_INFO
, 0, "ignoring DVMRP probe from %s to %s",
232 inet_fmt(src
), inet_fmt(dst
));
237 * Process an incoming route report message.
239 void accept_report(u_int32_t src
, u_int32_t dst
, char *p
, int datalen
,
242 logit(LOG_INFO
, 0, "ignoring DVMRP routing report from %s to %s",
243 inet_fmt(src
), inet_fmt(dst
));
248 * Process an incoming neighbor-list request message.
250 void accept_neighbor_request(u_int32_t src
, u_int32_t dst
)
254 "ignoring spurious DVMRP neighbor request from %s to %s",
255 inet_fmt(src
), inet_fmt(dst
));
258 void accept_neighbor_request2(u_int32_t src
, u_int32_t dst
)
262 "ignoring spurious DVMRP neighbor request2 from %s to %s",
263 inet_fmt(src
), inet_fmt(dst
));
268 * Process an incoming neighbor-list message.
270 void accept_neighbors(u_int32_t src
, u_int32_t dst
, u_char
*p
, int datalen
,
273 Node
*node
= find_node(src
, &routers
);
275 if (node
->tries
== 0) /* Never heard of 'em; must have hit them at */
276 node
->tries
= 1; /* least once, though...*/
277 else if (node
->tries
== -1) /* follow alias link */
278 node
= node
->u
.alias
;
280 #define GET_ADDR(a) (a = ((u_int32_t)*p++ << 24), a += ((u_int32_t)*p++ << 16),\
281 a += ((u_int32_t)*p++ << 8), a += *p++)
283 /* if node is running a recent mrouted, ask for additional info */
285 node
->version
= level
;
294 fprintf(stderr
, " datalen = %d\n", datalen
);
295 for (i
= 0; i
< datalen
; i
++) {
297 fprintf(stderr
, " ");
298 fprintf(stderr
, " %02x", p
[i
]);
299 if ((i
& 0xF) == 0xF)
300 fprintf(stderr
, "\n");
302 if ((datalen
& 0xF) != 0xF)
303 fprintf(stderr
, "\n");
306 while (datalen
> 0) { /* loop through interfaces */
308 u_char metric
, threshold
, ncount
;
311 Neighbor
*old_neighbors
;
313 if (datalen
< 4 + 3) {
314 logit(LOG_WARNING
, 0, "received truncated interface record from %s",
320 ifc_addr
= htonl(ifc_addr
);
326 /* Fix up any alias information */
327 ifc_node
= find_node(ifc_addr
, &routers
);
328 if (ifc_node
->tries
== 0) { /* new node */
329 ifc_node
->tries
= -1;
330 ifc_node
->u
.alias
= node
;
331 } else if (ifc_node
!= node
332 && (ifc_node
->tries
> 0 || ifc_node
->u
.alias
!= node
)) {
333 /* must merge two hosts' nodes */
334 Interface
*ifc_i
, *next_ifc_i
;
336 if (ifc_node
->tries
== -1) {
337 Node
*tmp
= ifc_node
->u
.alias
;
339 ifc_node
->u
.alias
= node
;
343 /* Merge ifc_node (foo_i) into node (foo_n) */
345 if (ifc_node
->tries
> node
->tries
)
346 node
->tries
= ifc_node
->tries
;
348 for (ifc_i
= ifc_node
->u
.interfaces
; ifc_i
; ifc_i
= next_ifc_i
) {
349 Neighbor
*nb_i
, *next_nb_i
, *nb_n
;
350 Interface
*ifc_n
= find_interface(ifc_i
->addr
, node
);
352 old_neighbors
= ifc_n
->neighbors
;
353 for (nb_i
= ifc_i
->neighbors
; nb_i
; nb_i
= next_nb_i
) {
354 next_nb_i
= nb_i
->next
;
355 for (nb_n
= old_neighbors
; nb_n
; nb_n
= nb_n
->next
)
356 if (nb_i
->addr
== nb_n
->addr
) {
357 if (nb_i
->metric
!= nb_n
->metric
358 || nb_i
->threshold
!= nb_n
->threshold
)
359 logit(LOG_WARNING
, 0,
360 "inconsistent %s for neighbor %s of %s",
362 inet_fmt(nb_i
->addr
),
363 inet_fmt(node
->addr
));
367 if (!nb_n
) { /* no match for this neighbor yet */
368 nb_i
->next
= ifc_n
->neighbors
;
369 ifc_n
->neighbors
= nb_i
;
373 next_ifc_i
= ifc_i
->next
;
377 ifc_node
->tries
= -1;
378 ifc_node
->u
.alias
= node
;
381 ifc
= find_interface(ifc_addr
, node
);
382 old_neighbors
= ifc
->neighbors
;
384 /* Add the neighbors for this interface */
391 logit(LOG_WARNING
, 0, "received truncated neighbor list from %s",
397 neighbor
= htonl(neighbor
);
400 for (nb
= old_neighbors
; nb
; nb
= nb
->next
)
401 if (nb
->addr
== neighbor
) {
402 if (metric
!= nb
->metric
|| threshold
!= nb
->threshold
)
403 logit(LOG_WARNING
, 0,
404 "inconsistent %s for neighbor %s of %s",
406 inet_fmt(nb
->addr
), inet_fmt(node
->addr
));
410 nb
= (Neighbor
*) malloc(sizeof(Neighbor
));
411 nb
->next
= ifc
->neighbors
;
415 nb
->threshold
= threshold
;
418 n_node
= find_node(neighbor
, &routers
);
419 if (n_node
->tries
== 0 && !target_addr
) { /* it's a new router */
429 void accept_neighbors2(u_int32_t src
, u_int32_t dst
, u_char
*p
, int datalen
,
432 Node
*node
= find_node(src
, &routers
);
433 u_int broken_cisco
= ((level
& 0xffff) == 0x020a); /* 10.2 */
434 /* well, only possibly_broken_cisco, but that's too long to type. */
436 if (node
->tries
== 0) /* Never heard of 'em; must have hit them at */
437 node
->tries
= 1; /* least once, though...*/
438 else if (node
->tries
== -1) /* follow alias link */
439 node
= node
->u
.alias
;
441 while (datalen
> 0) { /* loop through interfaces */
443 u_char metric
, threshold
, ncount
, flags
;
446 Neighbor
*old_neighbors
;
448 if (datalen
< 4 + 4) {
449 logit(LOG_WARNING
, 0, "received truncated interface record from %s",
454 ifc_addr
= *(u_int32_t
*)p
;
462 if (broken_cisco
&& ncount
== 0) /* dumb Ciscos */
464 if (broken_cisco
&& ncount
> 15) /* dumb Ciscos */
465 ncount
= ncount
& 0xf;
467 /* Fix up any alias information */
468 ifc_node
= find_node(ifc_addr
, &routers
);
469 if (ifc_node
->tries
== 0) { /* new node */
470 ifc_node
->tries
= -1;
471 ifc_node
->u
.alias
= node
;
472 } else if (ifc_node
!= node
473 && (ifc_node
->tries
> 0 || ifc_node
->u
.alias
!= node
)) {
474 /* must merge two hosts' nodes */
475 Interface
*ifc_i
, *next_ifc_i
;
477 if (ifc_node
->tries
== -1) {
478 Node
*tmp
= ifc_node
->u
.alias
;
480 ifc_node
->u
.alias
= node
;
484 /* Merge ifc_node (foo_i) into node (foo_n) */
486 if (ifc_node
->tries
> node
->tries
)
487 node
->tries
= ifc_node
->tries
;
489 for (ifc_i
= ifc_node
->u
.interfaces
; ifc_i
; ifc_i
= next_ifc_i
) {
490 Neighbor
*nb_i
, *next_nb_i
, *nb_n
;
491 Interface
*ifc_n
= find_interface(ifc_i
->addr
, node
);
493 old_neighbors
= ifc_n
->neighbors
;
494 for (nb_i
= ifc_i
->neighbors
; nb_i
; nb_i
= next_nb_i
) {
495 next_nb_i
= nb_i
->next
;
496 for (nb_n
= old_neighbors
; nb_n
; nb_n
= nb_n
->next
)
497 if (nb_i
->addr
== nb_n
->addr
) {
498 if (nb_i
->metric
!= nb_n
->metric
499 || nb_i
->threshold
!= nb_i
->threshold
)
500 logit(LOG_WARNING
, 0,
501 "inconsistent %s for neighbor %s of %s",
503 inet_fmt(nb_i
->addr
),
504 inet_fmt(node
->addr
));
508 if (!nb_n
) { /* no match for this neighbor yet */
509 nb_i
->next
= ifc_n
->neighbors
;
510 ifc_n
->neighbors
= nb_i
;
514 next_ifc_i
= ifc_i
->next
;
518 ifc_node
->tries
= -1;
519 ifc_node
->u
.alias
= node
;
522 ifc
= find_interface(ifc_addr
, node
);
523 old_neighbors
= ifc
->neighbors
;
525 /* Add the neighbors for this interface */
526 while (ncount
-- && datalen
> 0) {
532 logit(LOG_WARNING
, 0, "received truncated neighbor list from %s",
537 neighbor
= *(u_int32_t
*)p
;
541 /* make leaf nets point to themselves */
544 for (nb
= old_neighbors
; nb
; nb
= nb
->next
)
545 if (nb
->addr
== neighbor
) {
546 if (metric
!= nb
->metric
|| threshold
!= nb
->threshold
)
547 logit(LOG_WARNING
, 0,
548 "inconsistent %s for neighbor %s of %s",
550 inet_fmt(nb
->addr
), inet_fmt(node
->addr
));
554 nb
= (Neighbor
*) malloc(sizeof(Neighbor
));
555 nb
->next
= ifc
->neighbors
;
559 nb
->threshold
= threshold
;
560 nb
->flags
= flags
| NF_PRESENT
;
562 n_node
= find_node(neighbor
, &routers
);
563 if (n_node
->tries
== 0 && !target_addr
) { /* it's a new router */
574 void check_vif_state(void)
576 logit(LOG_NOTICE
, 0, "network marked down...");
580 int retry_requests(Node
*node
)
585 result
= retry_requests(node
->left
);
586 if (node
->tries
> 0 && node
->tries
< retries
) {
594 return retry_requests(node
->right
) || result
;
600 char *inet_name(u_int32_t addr
)
604 e
= gethostbyaddr((char *)&addr
, sizeof(addr
), AF_INET
);
606 return e
? e
->h_name
: 0;
610 void print_map(Node
*node
)
615 print_map(node
->left
);
617 addr
= inet_fmt(node
->addr
);
619 || (node
->tries
>= 0 && node
->u
.interfaces
)
620 || (node
->tries
== -1
621 && node
->u
.alias
->tries
>= 0
622 && node
->u
.alias
->u
.interfaces
)) {
623 if (show_names
&& (name
= inet_name(node
->addr
)))
624 printf("%s (%s):", addr
, name
);
628 printf(" alias for %s\n\n", inet_fmt(node
->u
.alias
->addr
));
629 else if (!node
->u
.interfaces
)
630 printf(" no response to query\n\n");
635 printf(" <v%d.%d>", node
->version
& 0xff,
636 (node
->version
>> 8) & 0xff);
638 for (ifc
= node
->u
.interfaces
; ifc
; ifc
= ifc
->next
) {
640 char *ifc_name
= inet_fmt(ifc
->addr
);
641 int ifc_len
= strlen(ifc_name
);
644 printf(" %s:", ifc_name
);
645 for (nb
= ifc
->neighbors
; nb
; nb
= nb
->next
) {
647 printf("%*s", ifc_len
+ 5, "");
648 printf(" %s", inet_fmt(nb
->addr
));
649 if (show_names
&& (name
= inet_name(nb
->addr
)))
650 printf(" (%s)", name
);
651 printf(" [%d/%d", nb
->metric
, nb
->threshold
);
653 u_short flags
= nb
->flags
;
654 if (flags
& DVMRP_NF_TUNNEL
)
656 if (flags
& DVMRP_NF_SRCRT
)
658 if (flags
& DVMRP_NF_QUERIER
)
660 if (flags
& DVMRP_NF_DISABLED
)
662 if (flags
& DVMRP_NF_DOWN
)
672 print_map(node
->right
);
677 char *graph_name(u_int32_t addr
, char *buf
, size_t l
)
681 if (show_names
&& (name
= inet_name(addr
)))
682 strlcpy(buf
, name
, l
);
690 void graph_edges(Node
*node
)
697 graph_edges(node
->left
);
698 if (node
->tries
>= 0) {
699 printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n",
701 node
->addr
& 0xFF, (node
->addr
>> 8) & 0xFF,
702 graph_name(node
->addr
, name
, sizeof(name
)),
703 node
->u
.interfaces
? "" : "*");
704 for (ifc
= node
->u
.interfaces
; ifc
; ifc
= ifc
->next
)
705 for (nb
= ifc
->neighbors
; nb
; nb
= nb
->next
) {
706 Node
*nb_node
= find_node(nb
->addr
, &routers
);
709 if (nb_node
->tries
< 0)
710 nb_node
= nb_node
->u
.alias
;
712 if (node
!= nb_node
&&
713 (!(nb2
= find_neighbor(node
->addr
, nb_node
))
714 || node
->addr
< nb_node
->addr
)) {
715 printf(" %d \"%d/%d",
716 nb_node
->addr
, nb
->metric
, nb
->threshold
);
717 if (nb2
&& (nb2
->metric
!= nb
->metric
718 || nb2
->threshold
!= nb
->threshold
))
719 printf(",%d/%d", nb2
->metric
, nb2
->threshold
);
720 if (nb
->flags
& NF_PRESENT
)
722 nb
->flags
& DVMRP_NF_SRCRT
? "" :
723 nb
->flags
& DVMRP_NF_TUNNEL
? "E" : "P",
724 nb
->flags
& DVMRP_NF_DOWN
? "D" : "");
730 graph_edges(node
->right
);
734 void elide_aliases(Node
*node
)
737 elide_aliases(node
->left
);
738 if (node
->tries
>= 0) {
741 for (ifc
= node
->u
.interfaces
; ifc
; ifc
= ifc
->next
) {
744 for (nb
= ifc
->neighbors
; nb
; nb
= nb
->next
) {
745 Node
*nb_node
= find_node(nb
->addr
, &routers
);
747 if (nb_node
->tries
< 0)
748 nb
->addr
= nb_node
->u
.alias
->addr
;
752 elide_aliases(node
->right
);
758 time_t now
= time(0);
759 char *nowstr
= ctime(&now
);
761 nowstr
[24] = '\0'; /* Kill the newline at the end */
762 elide_aliases(routers
);
763 printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n",
765 graph_edges(routers
);
770 int get_number(int *var
, int deflt
, char ***pargv
, int *pargc
)
772 if ((*pargv
)[0][2] == '\0') { /* Get the value from the next argument */
773 if (*pargc
> 1 && isdigit((unsigned char)(*pargv
)[1][0])) {
774 (*pargv
)++, (*pargc
)--;
775 *var
= atoi((*pargv
)[0]);
777 } else if (deflt
>= 0) {
782 } else { /* Get value from the rest of this argument */
783 if (isdigit((unsigned char)(*pargv
)[0][2])) {
784 *var
= atoi((*pargv
)[0] + 2);
793 u_int32_t
host_addr(char *name
)
795 struct hostent
*e
= gethostbyname(name
);
799 memcpy(&addr
, e
->h_addr_list
[0], e
->h_length
);
801 addr
= inet_addr(name
);
810 int main(int argc
, char **argv
)
812 int flood
= FALSE
, graph
= FALSE
;
813 struct pollfd set
[1];
817 if (geteuid() != 0) {
818 fprintf(stderr
, "must be root\n");
823 while (argc
> 0 && argv
[0][0] == '-') {
824 switch (argv
[0][1]) {
826 if (!get_number(&debug
, DEFAULT_DEBUG
, &argv
, &argc
))
839 if (!get_number(&retries
, -1, &argv
, &argc
))
843 if (!get_number(&timeout
, -1, &argv
, &argc
))
855 "usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n",
856 "[-r retries] [-d [debug-level]] [router]");
857 fprintf(stderr
, "\t-f Flood the routing graph with queries\n");
858 fprintf(stderr
, "\t (True by default unless `router' is given)\n");
859 fprintf(stderr
, "\t-g Generate output in GraphEd format\n");
860 fprintf(stderr
, "\t-n Don't look up DNS names for routers\n");
862 } else if (argc
== 1 && !(target_addr
= host_addr(argv
[0]))) {
863 fprintf(stderr
, "Unknown host: %s\n", argv
[0]);
868 fprintf(stderr
, "Debug level %u\n", debug
);
872 { /* Find a good local address for us. */
874 struct sockaddr_in addr
;
875 socklen_t addrlen
= sizeof(addr
);
877 memset(&addr
, 0, sizeof(addr
));
878 addr
.sin_family
= AF_INET
;
879 #if (defined(BSD) && (BSD >= 199103))
880 addr
.sin_len
= sizeof addr
;
882 addr
.sin_addr
.s_addr
= dvmrp_group
;
883 addr
.sin_port
= htons(2000); /* any port over 1024 will do... */
884 if ((udp
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0
885 || connect(udp
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0
886 || getsockname(udp
, (struct sockaddr
*) &addr
, &addrlen
) < 0) {
887 perror("Determining local address");
891 our_addr
= addr
.sin_addr
.s_addr
;
894 /* Send initial seed message to all local routers */
895 ask(target_addr
? target_addr
: allhosts_group
);
898 Node
*n
= find_node(target_addr
, &routers
);
906 /* Main receive loop */
907 set
[0].fd
= igmp_socket
;
908 set
[0].events
= POLLIN
;
913 count
= poll(set
, 1, timeout
* 1000);
919 } else if (count
== 0) {
920 logit(LOG_DEBUG
, 0, "Timed out receiving neighbor lists");
921 if (retry_requests(routers
))
927 recvlen
= recvfrom(igmp_socket
, recv_buf
, RECV_BUF_SIZE
,
930 accept_igmp(recvlen
);
931 else if (errno
!= EINTR
)
941 printf("Multicast Router Connectivity:\n\n");
949 void accept_prune(u_int32_t src
, u_int32_t dst
, char *p
, int datalen
)
952 void accept_graft(u_int32_t src
, u_int32_t dst
, char *p
, int datalen
)
955 void accept_g_ack(u_int32_t src
, u_int32_t dst
, char *p
, int datalen
)
958 void add_table_entry(u_int32_t origin
, u_int32_t mcastgrp
)
961 void accept_leave_message(u_int32_t src
, u_int32_t dst
, u_int32_t group
)
964 void accept_mtrace(u_int32_t src
, u_int32_t dst
, u_int32_t group
, char *data
,
965 u_int no
, int datalen
)
968 void accept_membership_query(u_int32_t src
, u_int32_t dst
, u_int32_t group
,
972 void accept_info_request(u_int32_t src
, u_int32_t dst
, u_char
*p
, int datalen
)
975 void accept_info_reply(u_int32_t src
, u_int32_t dst
, u_char
*p
, int datalen
)