2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1987 Regents of the University of California.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by the University of California, Berkeley. The name of the
16 * University may not be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/socket.h>
36 #include <sys/ioctl.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip_icmp.h>
44 #include <arpa/inet.h>
52 #define ALIGN(ptr) (ptr)
55 #define signal(s, f) sigset(s, (void (*)(int))f)
56 #define random() rand()
59 #define ALL_HOSTS_ADDRESS "224.0.0.1"
60 #define ALL_ROUTERS_ADDRESS "224.0.0.2"
64 /* For router advertisement */
66 uchar_t icmp_type
; /* type of message, see below */
67 uchar_t icmp_code
; /* type sub code */
68 ushort_t icmp_cksum
; /* ones complement cksum of struct */
69 uchar_t icmp_num_addrs
;
70 uchar_t icmp_wpa
; /* Words per address */
79 /* Router constants */
80 #define MAX_INITIAL_ADVERT_INTERVAL 16
81 #define MAX_INITIAL_ADVERTISEMENTS 3
82 #define MAX_RESPONSE_DELAY 2 /* Not used */
85 #define MAX_SOLICITATIONS 3
86 #define SOLICITATION_INTERVAL 3
87 #define MAX_SOLICITATION_DELAY 1 /* Not used */
89 #define IGNORE_PREFERENCE 0x80000000 /* Maximum negative */
91 #define MAX_ADV_INT 600
95 * A doubly linked list of all physical interfaces that each contain a
96 * doubly linked list of logical interfaces aka IP addresses.
99 char pi_name
[IFNAMSIZ
]; /* Used to identify it */
100 int pi_state
; /* See below */
101 struct logint
*pi_logical_first
;
102 struct logint
*pi_logical_last
;
103 struct phyint
*pi_next
;
104 struct phyint
*pi_prev
;
108 char li_name
[IFNAMSIZ
]; /* Used to identify it */
109 int li_state
; /* See below */
110 struct in_addr li_address
; /* Used to identify the interface */
111 struct in_addr li_localaddr
; /* Actual address of the interface */
113 int li_index
; /* interface index (SIOCGLIFINDEX) */
115 struct in_addr li_bcastaddr
;
116 struct in_addr li_remoteaddr
;
117 struct in_addr li_netmask
;
118 struct logint
*li_next
; /* Next logical for this physical */
119 struct logint
*li_prev
; /* Prev logical for this physical */
120 struct phyint
*li_physical
; /* Back pointer */
123 struct phyint
*phyint
;
124 int num_usable_interfaces
; /* Num used for sending/receiving */
129 #define ST_MARKED 0x01 /* To determine removed interfaces */
130 #define ST_JOINED 0x02 /* Joined multicast group */
131 #define ST_DELETED 0x04 /* Interface should be ignored */
133 /* Function prototypes */
134 static void solicitor(struct sockaddr_in
*sin
);
135 static void advertise(struct sockaddr_in
*sin
);
137 static void age_table(int time
);
138 static void flush_unreachable_routers(void);
139 static void record_router(struct in_addr router
, long preference
, int ttl
);
141 static void add_route(struct in_addr addr
);
142 static void del_route(struct in_addr addr
);
143 static void rtioctl(struct in_addr addr
, int op
);
145 static int support_multicast(void);
146 static int sendbcast(int s
, char *packet
, int packetlen
);
147 static int sendbcastif(int s
, char *packet
, int packetlen
,
149 static int sendmcast(int s
, char *packet
, int packetlen
,
150 struct sockaddr_in
*sin
);
151 static int sendmcastif(int s
, char *packet
, int packetlen
,
152 struct sockaddr_in
*sin
, struct logint
*li
);
154 static int ismulticast(struct sockaddr_in
*sin
);
155 static int isbroadcast(struct sockaddr_in
*sin
);
156 int in_cksum(ushort_t
*addr
, int len
);
157 static struct logint
*find_directly_connected_logint(struct in_addr in
,
159 static void force_preference(int preference
);
161 static void timer(void);
162 static void finish(void);
163 static void report(void);
164 static void report_interfaces(void);
165 static void report_routes(void);
166 static void reinitifs(void);
168 static struct phyint
*find_phyint(char *name
);
169 static struct phyint
*add_phyint(char *name
);
170 static void free_phyint(struct phyint
*pi
);
171 static struct logint
*find_logint(struct phyint
*pi
, char *name
);
172 static struct logint
*add_logint(struct phyint
*pi
, char *name
);
173 static void free_logint(struct logint
*li
);
175 static void deleted_phyint(struct phyint
*pi
, int s
,
176 struct sockaddr_in
*joinaddr
);
177 static void added_logint(struct logint
*li
, int s
,
178 struct sockaddr_in
*joinaddr
);
179 static void deleted_logint(struct logint
*li
, struct logint
*newli
, int s
,
180 struct sockaddr_in
*joinaddr
);
182 static int initifs(int s
, struct sockaddr_in
*joinaddr
, int preference
);
183 static boolean_t
getconfig(int sock
, uint64_t if_flags
, struct sockaddr
*addr
,
184 struct ifreq
*ifr
, struct logint
*li
);
186 static void pr_pack(char *buf
, int cc
, struct sockaddr_in
*from
);
187 char *pr_name(struct in_addr addr
);
188 char *pr_type(int t
);
190 static void initlog(void);
191 void logerr(), logtrace(), logdebug(), logperror();
193 /* Local variables */
195 #define MAXPACKET 4096 /* max packet size */
196 uchar_t packet
[MAXPACKET
];
199 "Usage: rdisc [-s] [-v] [-f] [-a] [send_address] [receive_address]\n"
200 " rdisc -r [-v] [-p <preference>] [-T <secs>] \n"
201 " [send_address] [receive_address]\n";
204 int s
; /* Socket file descriptor */
205 struct sockaddr_in whereto
; /* Address to send to */
206 struct sockaddr_in g_joinaddr
; /* Address to receive on */
207 char *sendaddress
, *recvaddress
; /* For logging purposes only */
209 /* Common variables */
213 int start_solicit
= 0; /* -s parameter set */
214 int solicit
= 0; /* Are we currently sending solicitations? */
216 int ntransmitted
= 0;
218 int forever
= 0; /* Never give up on host. If 0 defer fork until */
219 /* first response. */
221 /* Router variables */
222 int max_adv_int
= MAX_ADV_INT
;
225 int initial_advert_interval
= MAX_INITIAL_ADVERT_INTERVAL
;
226 int initial_advertisements
= MAX_INITIAL_ADVERTISEMENTS
;
227 ulong_t g_preference
= 0; /* Setable with -p option */
230 int max_solicitations
= MAX_SOLICITATIONS
;
231 unsigned int solicitation_interval
= SOLICITATION_INTERVAL
;
232 int best_preference
= 1; /* Set to record only the router(s) with the */
233 /* best preference in the kernel. Not set */
234 /* puts all routes in the kernel. */
240 (void) fprintf(stderr
, usage
);
244 static int sock
= -1;
256 for (t
= 0; t
< 20; t
++)
260 (void) open("/", O_RDONLY
);
264 t
= open("/dev/tty", O_RDWR
);
266 (void) ioctl(t
, TIOCNOTTY
, (char *)0);
279 main(int argc
, char *argv
[])
284 struct sockaddr_in from
;
286 struct sockaddr_in
*to
= &whereto
;
289 min_adv_int
= (max_adv_int
* 3 / 4);
290 lifetime
= (3*max_adv_int
);
293 while (argc
> 0 && *av
[0] == '-') {
306 start_solicit
= solicit
= 1;
323 val
= strtol(av
[0], (char **)NULL
, 0);
324 if (val
< 4 || val
> 1800) {
325 (void) fprintf(stderr
,
326 "Bad Max Advertisement Interval\n");
330 min_adv_int
= (max_adv_int
* 3 / 4);
331 lifetime
= (3*max_adv_int
);
340 val
= strtoul(av
[0], (char **)NULL
, 0);
355 if (support_multicast()) {
357 sendaddress
= ALL_HOSTS_ADDRESS
;
359 sendaddress
= ALL_ROUTERS_ADDRESS
;
361 sendaddress
= "255.255.255.255";
367 if (support_multicast()) {
369 recvaddress
= ALL_ROUTERS_ADDRESS
;
371 recvaddress
= ALL_HOSTS_ADDRESS
;
373 recvaddress
= "255.255.255.255";
379 (void) fprintf(stderr
, "Extra paramaters\n");
384 if (solicit
&& responder
) {
389 if (!(solicit
&& !forever
)) {
393 bzero((char *)&whereto
, sizeof (struct sockaddr_in
));
394 to
->sin_family
= AF_INET
;
395 to
->sin_addr
.s_addr
= inet_addr(sendaddress
);
396 if (to
->sin_addr
.s_addr
== (unsigned long)-1) {
397 logerr("in.rdisc: bad address %s\n", sendaddress
);
401 bzero((char *)&g_joinaddr
, sizeof (struct sockaddr_in
));
402 g_joinaddr
.sin_family
= AF_INET
;
403 g_joinaddr
.sin_addr
.s_addr
= inet_addr(recvaddress
);
404 if (g_joinaddr
.sin_addr
.s_addr
== (unsigned long)-1) {
405 logerr("in.rdisc: bad address %s\n", recvaddress
);
411 srand((int)gethostid());
413 srandom((int)gethostid());
417 if ((s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
)) < 0) {
423 setvbuf(stdout
, NULL
, _IOLBF
, 0);
428 (void) signal(SIGINT
, finish
);
429 (void) signal(SIGTERM
, finish
);
430 (void) signal(SIGHUP
, reinitifs
);
431 (void) signal(SIGUSR1
, report
);
433 if (initifs(s
, &g_joinaddr
, g_preference
) < 0) {
434 logerr("Failed initializing interfaces\n");
439 * If there are no usable interfaces and we are soliciting
440 * waiting for to return an exit code (i.e. forever isn't set)
441 * give up immediately.
443 if (num_usable_interfaces
== 0 && solicit
&& !forever
) {
444 logerr("in.rdisc: No interfaces up\n");
449 (void) signal(SIGALRM
, timer
);
452 * Make sure that this signal actually interrupts (rather than
453 * restarts) the recvfrom call below.
455 sv
.sv_handler
= timer
;
457 sv
.sv_flags
= SV_INTERRUPT
;
458 (void) sigvec(SIGALRM
, &sv
, NULL
);
460 timer(); /* start things going */
463 int len
= sizeof (packet
);
464 socklen_t fromlen
= (socklen_t
)sizeof (from
);
466 sigset_t newmask
, oldmask
;
468 if ((cc
= recvfrom(s
, (char *)packet
, len
, 0,
469 (struct sockaddr
*)&from
,
473 logperror("recvfrom");
476 /* Block all signals while processing */
477 (void) sigfillset(&newmask
);
478 (void) sigprocmask(SIG_SETMASK
, &newmask
, &oldmask
);
479 pr_pack((char *)packet
, cc
, &from
);
480 (void) sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
492 #define TIMER_INTERVAL 6
493 #define GETIFCONF_TIMER 30
495 static int left_until_advertise
;
497 /* Called every TIMER_INTERVAL */
502 static int left_until_getifconf
;
503 static int left_until_solicit
;
505 time
+= TIMER_INTERVAL
;
507 left_until_getifconf
-= TIMER_INTERVAL
;
508 left_until_advertise
-= TIMER_INTERVAL
;
509 left_until_solicit
-= TIMER_INTERVAL
;
511 if (left_until_getifconf
< 0) {
512 (void) initifs(s
, &g_joinaddr
, g_preference
);
513 left_until_getifconf
= GETIFCONF_TIMER
;
515 if (responder
&& left_until_advertise
<= 0) {
518 if (ntransmitted
< initial_advertisements
)
519 left_until_advertise
= initial_advert_interval
;
521 left_until_advertise
= min_adv_int
+
522 ((max_adv_int
- min_adv_int
) *
523 (random() % 1000)/1000);
524 } else if (solicit
&& left_until_solicit
<= 0) {
525 if (ntransmitted
< max_solicitations
) {
528 left_until_solicit
= solicitation_interval
;
531 if (!forever
&& nreceived
== 0)
535 age_table(TIMER_INTERVAL
);
536 (void) alarm(TIMER_INTERVAL
);
542 * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.
543 * The IP packet will be added on by the kernel.
546 solicitor(struct sockaddr_in
*sin
)
548 static uchar_t outpack
[MAXPACKET
];
549 register struct icmp
*icp
= (struct icmp
*)ALIGN(outpack
);
553 logtrace("Sending solicitation to %s\n",
554 pr_name(sin
->sin_addr
));
556 icp
->icmp_type
= ICMP_ROUTERSOLICIT
;
559 icp
->icmp_void
= 0; /* Reserved */
562 /* Compute ICMP checksum here */
563 icp
->icmp_cksum
= in_cksum((ushort_t
*)icp
, packetlen
);
565 if (isbroadcast(sin
))
566 i
= sendbcast(s
, (char *)outpack
, packetlen
);
567 else if (ismulticast(sin
))
568 i
= sendmcast(s
, (char *)outpack
, packetlen
, sin
);
572 li
= find_directly_connected_logint(sin
->sin_addr
, NULL
);
573 if (li
!= NULL
&& (li
->li_flags
& IFF_NORTEXCH
)) {
575 logtrace("Suppressing sending %s on %s "
576 "(no route exchange on interface)\n",
577 pr_type((int)icp
->icmp_type
), li
->li_name
);
581 i
= sendto(s
, (char *)outpack
, packetlen
, 0,
582 (struct sockaddr
*)sin
, sizeof (struct sockaddr
));
586 if (i
< 0 || i
!= packetlen
) {
590 logerr("wrote %s %d chars, ret=%d\n",
591 sendaddress
, packetlen
, i
);
598 * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.
599 * The IP packet will be added on by the kernel.
602 advertise(struct sockaddr_in
*sin
)
605 struct logint
*li
, *li_tmp
;
606 static uchar_t outpack
[MAXPACKET
];
607 register struct icmp_ra
*rap
= (struct icmp_ra
*)ALIGN(outpack
);
608 struct icmp_ra_addr
*ap
;
612 logtrace("Sending advertisement to %s\n",
613 pr_name(sin
->sin_addr
));
616 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
617 rap
->icmp_type
= ICMP_ROUTERADVERT
;
620 rap
->icmp_num_addrs
= 0;
622 rap
->icmp_lifetime
= htons(lifetime
);
623 packetlen
= ICMP_MINLEN
;
625 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
626 if (li
->li_state
& ST_DELETED
)
630 * XXX Just truncate the list of addresses.
631 * Should probably send multiple packets.
633 if (packetlen
+ rap
->icmp_wpa
* 4 > sizeof (outpack
)) {
635 logdebug("full packet: %d addresses\n",
636 rap
->icmp_num_addrs
);
639 ap
= (struct icmp_ra_addr
*)ALIGN(outpack
+ packetlen
);
640 ap
->addr
= li
->li_localaddr
.s_addr
;
641 ap
->preference
= htonl(li
->li_preference
);
642 packetlen
+= rap
->icmp_wpa
* 4;
643 rap
->icmp_num_addrs
++;
646 if (rap
->icmp_num_addrs
== 0)
649 /* Compute ICMP checksum here */
650 rap
->icmp_cksum
= in_cksum((ushort_t
*)rap
, packetlen
);
652 if (isbroadcast(sin
))
653 cc
= sendbcastif(s
, (char *)outpack
, packetlen
,
654 pi
->pi_logical_first
);
655 else if (ismulticast(sin
))
656 cc
= sendmcastif(s
, (char *)outpack
, packetlen
, sin
,
657 pi
->pi_logical_first
);
660 * Verify that the physical interface matches the
661 * destination address.
663 li_tmp
= find_directly_connected_logint(sin
->sin_addr
,
667 if (li_tmp
->li_flags
& IFF_NORTEXCH
) {
669 logtrace("Suppressing sending %s on %s "
670 "(no route exchange on "
672 pr_type((int)rap
->icmp_type
),
678 logdebug("Unicast to %s ",
679 pr_name(sin
->sin_addr
));
680 logdebug("on interface %s\n", pi
->pi_name
);
682 cc
= sendto(s
, (char *)outpack
, packetlen
, 0,
683 (struct sockaddr
*)sin
, sizeof (struct sockaddr
));
685 if (cc
< 0 || cc
!= packetlen
) {
689 logerr("wrote %s %d chars, ret=%d\n",
690 sendaddress
, packetlen
, cc
);
699 * Convert an ICMP "type" field to a printable string.
704 static char *ttab
[] = {
715 "Router Solicitation",
727 return ("OUT-OF-RANGE");
735 * Return a string name for the given IP address.
738 pr_name(struct in_addr addr
)
741 static char buf
[256];
743 phe
= gethostbyaddr((char *)&addr
.s_addr
, 4, AF_INET
);
745 return (inet_ntoa(addr
));
746 (void) sprintf(buf
, "%s (%s)", phe
->h_name
, inet_ntoa(addr
));
753 * Print out the packet, if it came from us. This logic is necessary
754 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
755 * which arrive ('tis only fair). This permits multiple copies of this
756 * program to be run without having intermingled output (or statistics!).
759 pr_pack(char *buf
, int cc
, struct sockaddr_in
*from
)
762 register struct icmp
*icp
;
767 ip
= (struct ip
*)ALIGN(buf
);
768 hlen
= ip
->ip_hl
<< 2;
769 if (cc
< hlen
+ ICMP_MINLEN
) {
771 logtrace("packet too short (%d bytes) from %s\n", cc
,
772 pr_name(from
->sin_addr
));
777 icp
= (struct icmp
*)ALIGN(buf
+ hlen
);
780 * Let's check if IFF_NORTEXCH flag is set on the interface which
781 * recevied this packet.
782 * TODO: this code can be re-written using one socket per interface
783 * to determine which interface the packet is recevied.
785 li
= find_directly_connected_logint(ip
->ip_src
, NULL
);
786 if (li
!= NULL
&& (li
->li_flags
& IFF_NORTEXCH
)) {
788 logtrace("Ignoring received %s on %s "
789 "(no route exchange on interface)",
790 pr_type((int)icp
->icmp_type
), li
->li_name
);
797 * Assume that we are running on a pre-4.3BSD system
798 * such as SunOS before 4.0
800 icp
= (struct icmp
*)ALIGN(buf
);
802 switch (icp
->icmp_type
) {
803 case ICMP_ROUTERADVERT
: {
804 struct icmp_ra
*rap
= (struct icmp_ra
*)ALIGN(icp
);
805 struct icmp_ra_addr
*ap
;
810 /* TBD verify that the link is multicast or broadcast */
811 /* XXX Find out the link it came in over? */
814 logdebug("ROUTER_ADVERTISEMENT: \n");
815 pr_hex(buf
+hlen
, cc
);
818 if (in_cksum((ushort_t
*)ALIGN(buf
+hlen
), cc
)) {
820 logtrace("ICMP %s from %s: Bad checksum\n",
821 pr_type((int)rap
->icmp_type
),
822 pr_name(from
->sin_addr
));
825 if (rap
->icmp_code
!= 0) {
827 logtrace("ICMP %s from %s: Code = %d\n",
828 pr_type((int)rap
->icmp_type
),
829 pr_name(from
->sin_addr
),
833 if (rap
->icmp_num_addrs
< 1) {
835 logtrace("ICMP %s from %s: No addresses\n",
836 pr_type((int)rap
->icmp_type
),
837 pr_name(from
->sin_addr
));
840 if (rap
->icmp_wpa
< 2) {
842 logtrace("ICMP %s from %s: Words/addr = %d\n",
843 pr_type((int)rap
->icmp_type
),
844 pr_name(from
->sin_addr
),
849 ICMP_MINLEN
+ rap
->icmp_num_addrs
* rap
->icmp_wpa
* 4) {
851 logtrace("ICMP %s from %s: Too short %d, %d\n",
852 pr_type((int)rap
->icmp_type
),
853 pr_name(from
->sin_addr
),
856 rap
->icmp_num_addrs
*
860 rap
->icmp_lifetime
= ntohs(rap
->icmp_lifetime
);
861 if ((rap
->icmp_lifetime
< 4 && rap
->icmp_lifetime
!= 0) ||
862 rap
->icmp_lifetime
> 9000) {
864 logtrace("ICMP %s from %s: Invalid lifetime %d\n",
865 pr_type((int)rap
->icmp_type
),
866 pr_name(from
->sin_addr
),
871 logtrace("ICMP %s from %s, lifetime %d\n",
872 pr_type((int)rap
->icmp_type
),
873 pr_name(from
->sin_addr
),
877 * Check that at least one router address is a neighbor
878 * on the arriving link.
880 for (i
= 0; (unsigned)i
< rap
->icmp_num_addrs
; i
++) {
882 ap
= (struct icmp_ra_addr
*)
883 ALIGN(buf
+ hlen
+ ICMP_MINLEN
+
884 i
* rap
->icmp_wpa
* 4);
885 ap
->preference
= ntohl(ap
->preference
);
886 ina
.s_addr
= ap
->addr
;
888 logtrace("\taddress %s, preference 0x%x\n",
892 if (find_directly_connected_logint(ina
, NULL
) !=
895 (long)ap
->preference
,
905 (void) alarm(TIMER_INTERVAL
);
910 case ICMP_ROUTERSOLICIT
: {
911 struct sockaddr_in sin
;
916 /* TBD verify that the link is multicast or broadcast */
917 /* XXX Find out the link it came in over? */
920 logdebug("ROUTER_SOLICITATION: \n");
921 pr_hex(buf
+hlen
, cc
);
924 if (in_cksum((ushort_t
*)ALIGN(buf
+hlen
), cc
)) {
926 logtrace("ICMP %s from %s: Bad checksum\n",
927 pr_type((int)icp
->icmp_type
),
928 pr_name(from
->sin_addr
));
931 if (icp
->icmp_code
!= 0) {
933 logtrace("ICMP %s from %s: Code = %d\n",
934 pr_type((int)icp
->icmp_type
),
935 pr_name(from
->sin_addr
),
940 if (cc
< ICMP_MINLEN
) {
942 logtrace("ICMP %s from %s: Too short %d, %d\n",
943 pr_type((int)icp
->icmp_type
),
944 pr_name(from
->sin_addr
),
951 logtrace("ICMP %s from %s\n",
952 pr_type((int)icp
->icmp_type
),
953 pr_name(from
->sin_addr
));
959 * Check that ip_src is either a neighbor
960 * on the arriving link or 0.
962 sin
.sin_family
= AF_INET
;
963 if (ip
->ip_src
.s_addr
== 0) {
965 * If it was sent to the broadcast address we respond
966 * to the broadcast address.
968 if (IN_CLASSD(ntohl(ip
->ip_dst
.s_addr
))) {
969 sin
.sin_addr
.s_addr
=
970 htonl(INADDR_ALLHOSTS_GROUP
);
972 sin
.sin_addr
.s_addr
= htonl(INADDR_BROADCAST
);
973 /* Restart the timer when we broadcast */
974 left_until_advertise
= min_adv_int
+
975 ((max_adv_int
- min_adv_int
)
976 * (random() % 1000)/1000);
980 logtrace("ICMP %s from %s: %s\n",
981 pr_type((int)icp
->icmp_type
),
982 pr_name(from
->sin_addr
),
983 "source not directly connected");
986 sin
.sin_addr
.s_addr
= ip
->ip_src
.s_addr
;
1000 * Checksum routine for Internet Protocol family headers (C Version)
1004 in_cksum(ushort_t
*addr
, int len
)
1006 register int nleft
= len
;
1007 register ushort_t
*w
= addr
;
1008 register ushort_t answer
;
1009 ushort_t odd_byte
= 0;
1010 register int sum
= 0;
1013 * Our algorithm is simple, using a 32 bit accumulator (sum),
1014 * we add sequential 16 bit words to it, and at the end, fold
1015 * back all the carry bits from the top 16 bits into the lower
1023 /* mop up an odd byte, if necessary */
1025 *(uchar_t
*)(&odd_byte
) = *(uchar_t
*)w
;
1030 * add back carry outs from top 16 bits to low 16 bits
1032 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
1033 sum
+= (sum
>> 16); /* add carry */
1034 answer
= ~sum
; /* truncate to 16 bits */
1041 * Print out statistics, and give up.
1042 * Heavily buffered stdio is used here, so that all the statistics
1043 * will be written with 1 sys-write call. This is nice when more
1044 * than one copy of the program is running on a terminal; it prevents
1045 * the statistics output from becoming intermingled.
1052 * Send out a packet with a preference so that all
1053 * hosts will know that we are dead.
1055 logerr("terminated\n");
1056 force_preference(IGNORE_PREFERENCE
);
1058 advertise(&whereto
);
1061 logtrace("\n----%s rdisc Statistics----\n", sendaddress
);
1062 logtrace("%d packets transmitted, ", ntransmitted
);
1063 logtrace("%d packets received, ", nreceived
);
1066 (void) fflush(stdout
);
1074 pr_hex(unsigned char *data
, int len
)
1082 char charstring
[17];
1084 (void) strcpy(charstring
, " "); /* 16 spaces */
1085 for (i
= 0; i
< 16; i
++) {
1087 * output the bytes one at a time,
1088 * not going past "len" bytes
1091 char ch
= *data
& 0x7f; /* strip parity */
1092 if (!isprint((uchar_t
)ch
))
1093 ch
= ' '; /* ensure printable */
1095 (void) fprintf(out
, "%02x ", *data
++);
1098 (void) fprintf(out
, " ");
1100 (void) fprintf(out
, " ");
1103 (void) fprintf(out
, " *%s*\n", charstring
);
1109 isbroadcast(struct sockaddr_in
*sin
)
1111 return (sin
->sin_addr
.s_addr
== htonl(INADDR_BROADCAST
));
1115 ismulticast(struct sockaddr_in
*sin
)
1117 return (IN_CLASSD(ntohl(sin
->sin_addr
.s_addr
)));
1120 /* From libc/rpc/pmap_rmt.c */
1123 /* Only send once per physical interface */
1125 sendbcast(int s
, char *packet
, int packetlen
)
1132 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
1134 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1135 if (li
->li_state
& ST_DELETED
)
1138 if (li
->li_flags
& IFF_BROADCAST
) {
1145 cc
= sendbcastif(s
, packet
, packetlen
, li
);
1146 if (cc
!= packetlen
) {
1154 sendbcastif(int s
, char *packet
, int packetlen
, struct logint
*li
)
1157 struct sockaddr_in baddr
;
1158 struct icmp
*icp
= (struct icmp
*)ALIGN(packet
);
1160 baddr
.sin_family
= AF_INET
;
1162 if ((li
->li_flags
& IFF_BROADCAST
) == 0) {
1164 logtrace("Suppressing sending %s on %s "
1165 "(interface is not broadcast capable)\n",
1166 pr_type((int)icp
->icmp_type
), li
->li_name
);
1170 if (li
->li_flags
& IFF_NORTEXCH
) {
1172 logtrace("Suppressing sending %s on %s "
1173 "(no route exchange on interface)\n",
1174 pr_type((int)icp
->icmp_type
), li
->li_name
);
1179 baddr
.sin_addr
= li
->li_bcastaddr
;
1181 logdebug("Broadcast to %s\n",
1182 pr_name(baddr
.sin_addr
));
1183 cc
= sendto(s
, packet
, packetlen
, 0,
1184 (struct sockaddr
*)&baddr
, sizeof (struct sockaddr
));
1185 if (cc
!= packetlen
) {
1186 logperror("sendbcast: sendto");
1187 logerr("Cannot send broadcast packet to %s\n",
1188 pr_name(baddr
.sin_addr
));
1194 sendmcast(int s
, char *packet
, int packetlen
, struct sockaddr_in
*sin
)
1201 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
1203 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1204 if (li
->li_state
& ST_DELETED
)
1207 if (li
->li_flags
& IFF_MULTICAST
) {
1214 cc
= sendmcastif(s
, packet
, packetlen
, sin
, li
);
1215 if (cc
!= packetlen
) {
1223 sendmcastif(int s
, char *packet
, int packetlen
, struct sockaddr_in
*sin
,
1227 struct sockaddr_in ifaddr
;
1228 struct icmp
*icp
= (struct icmp
*)ALIGN(packet
);
1230 ifaddr
.sin_family
= AF_INET
;
1232 if ((li
->li_flags
& IFF_MULTICAST
) == 0) {
1234 logtrace("Suppressing sending %s on %s "
1235 "(interface is not multicast capable)\n",
1236 pr_type((int)icp
->icmp_type
), li
->li_name
);
1240 if (li
->li_flags
& IFF_NORTEXCH
) {
1242 logtrace("Suppressing sending %s on %s "
1243 "(no route exchange on interface)\n",
1244 pr_type((int)icp
->icmp_type
), li
->li_name
);
1249 ifaddr
.sin_addr
= li
->li_address
;
1251 logdebug("Multicast to interface %s\n",
1252 pr_name(ifaddr
.sin_addr
));
1253 if (setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
,
1254 (char *)&ifaddr
.sin_addr
,
1255 sizeof (ifaddr
.sin_addr
)) < 0) {
1256 logperror("setsockopt (IP_MULTICAST_IF)");
1257 logerr("Cannot send multicast packet over interface %s\n",
1258 pr_name(ifaddr
.sin_addr
));
1261 cc
= sendto(s
, packet
, packetlen
, 0,
1262 (struct sockaddr
*)sin
, sizeof (struct sockaddr
));
1263 if (cc
!= packetlen
) {
1264 logperror("sendmcast: sendto");
1265 logerr("Cannot send multicast packet over interface %s\n",
1266 pr_name(ifaddr
.sin_addr
));
1274 (void) initifs(s
, &g_joinaddr
, g_preference
);
1278 force_preference(int preference
)
1283 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
1284 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1285 if (li
->li_state
& ST_DELETED
)
1288 li
->li_preference
= preference
;
1294 * Returns -1 on failure.
1297 initifs(int s
, struct sockaddr_in
*joinaddr
, int preference
)
1300 struct ifreq ifreq
, *ifr
;
1301 struct lifreq lifreq
;
1309 char phyintname
[IFNAMSIZ
];
1311 int old_num_usable_interfaces
= num_usable_interfaces
;
1314 * Mark all interfaces so that we can determine which ones
1317 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
1318 pi
->pi_state
|= ST_MARKED
;
1319 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1320 li
->li_state
|= ST_MARKED
;
1325 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1327 logperror("initifs: socket");
1332 if (ioctl(sock
, SIOCGIFNUM
, (char *)&numifs
) < 0) {
1333 logperror("initifs: SIOCGIFNUM");
1339 bufsize
= numifs
* sizeof (struct ifreq
);
1340 buf
= (char *)malloc(bufsize
);
1342 logerr("out of memory\n");
1347 ifc
.ifc_len
= bufsize
;
1349 if (ioctl(sock
, SIOCGIFCONF
, (char *)&ifc
) < 0) {
1350 logperror("initifs: ioctl (get interface configuration)");
1357 for (n
= ifc
.ifc_len
/sizeof (struct ifreq
); n
> 0; n
--, ifr
++) {
1360 * We need to use new interface ioctls to get 64-bit flags.
1362 (void) strncpy(lifreq
.lifr_name
, ifr
->ifr_name
,
1363 sizeof (ifr
->ifr_name
));
1364 if (ioctl(sock
, SIOCGLIFFLAGS
, (char *)&lifreq
) < 0) {
1365 logperror("initifs: ioctl (get interface flags)");
1368 if (ifr
->ifr_addr
.sa_family
!= AF_INET
)
1370 if ((lifreq
.lifr_flags
& IFF_UP
) == 0)
1372 if (lifreq
.lifr_flags
& IFF_LOOPBACK
)
1374 if ((lifreq
.lifr_flags
& (IFF_MULTICAST
| IFF_BROADCAST
)) == 0)
1377 /* Create the physical name by truncating at the ':' */
1378 strncpy(phyintname
, ifreq
.ifr_name
, sizeof (phyintname
));
1379 if ((cp
= strchr(phyintname
, ':')) != NULL
)
1382 pi
= find_phyint(phyintname
);
1384 pi
= add_phyint(phyintname
);
1386 logerr("out of memory\n");
1393 pi
->pi_state
&= ~ST_MARKED
;
1395 li
= find_logint(pi
, ifreq
.ifr_name
);
1398 * Detect significant changes.
1399 * We treat netmask changes as insignificant but all
1400 * other changes cause a delete plus add of the
1401 * logical interface.
1402 * Note: if the flags and localaddr are unchanged
1403 * then nothing but the netmask and the broadcast
1404 * address could have changed since the other addresses
1405 * are derived from the flags and the localaddr.
1407 struct logint newli
;
1409 if (!getconfig(sock
, lifreq
.lifr_flags
, &ifr
->ifr_addr
,
1415 if (newli
.li_flags
!= li
->li_flags
||
1416 newli
.li_localaddr
.s_addr
!=
1417 li
->li_localaddr
.s_addr
|| newli
.li_index
!=
1419 /* Treat as an interface deletion + addition */
1420 li
->li_state
|= ST_DELETED
;
1421 deleted_logint(li
, &newli
, s
, joinaddr
);
1423 li
= NULL
; /* li recreated below */
1426 * No significant changes.
1427 * Just update the netmask, and broadcast.
1429 li
->li_netmask
= newli
.li_netmask
;
1430 li
->li_bcastaddr
= newli
.li_bcastaddr
;
1434 li
= add_logint(pi
, ifreq
.ifr_name
);
1436 logerr("out of memory\n");
1444 if (!getconfig(sock
, lifreq
.lifr_flags
, &ifr
->ifr_addr
,
1449 li
->li_preference
= preference
;
1450 added_logint(li
, s
, joinaddr
);
1452 li
->li_state
&= ~ST_MARKED
;
1457 * Determine which interfaces have gone away.
1458 * The deletion is done in three phases:
1459 * 1. Mark ST_DELETED
1460 * 2. Inform using the deleted_* function.
1461 * 3. Unlink and free the actual memory.
1462 * Note that for #3 the physical interface must be deleted after
1464 * Also count the number of physical interfaces.
1466 num_usable_interfaces
= 0;
1468 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
1469 if (pi
->pi_state
& ST_MARKED
) {
1471 pi
->pi_state
|= ST_DELETED
;
1473 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1474 if (li
->li_state
& ST_MARKED
) {
1476 li
->li_state
|= ST_DELETED
;
1479 if (!(pi
->pi_state
& ST_DELETED
))
1480 num_usable_interfaces
++;
1482 if (num_deletions
!= 0) {
1483 struct phyint
*nextpi
;
1484 struct logint
*nextli
;
1486 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
1487 if (pi
->pi_state
& ST_DELETED
) {
1489 * By deleting the physical interface pi, all of
1490 * the corresponding logical interfaces will
1491 * also be deleted so there is no need to delete
1492 * them individually.
1494 deleted_phyint(pi
, s
, joinaddr
);
1496 for (li
= pi
->pi_logical_first
; li
!= NULL
;
1498 if (li
->li_state
& ST_DELETED
) {
1499 deleted_logint(li
, NULL
, s
,
1505 /* Do the actual linked list update + free */
1506 for (pi
= phyint
; pi
!= NULL
; pi
= nextpi
) {
1507 nextpi
= pi
->pi_next
;
1508 for (li
= pi
->pi_logical_first
; li
!= NULL
;
1510 nextli
= li
->li_next
;
1511 if (li
->li_state
& ST_DELETED
)
1514 if (pi
->pi_state
& ST_DELETED
)
1519 * When the set of available interfaces goes from zero to
1520 * non-zero we restart solicitations if '-s' was specified.
1522 if (old_num_usable_interfaces
== 0 && num_usable_interfaces
> 0 &&
1523 start_solicit
&& !solicit
) {
1525 logdebug("switching to solicitations: num if %d\n",
1526 num_usable_interfaces
);
1527 solicit
= start_solicit
;
1530 solicitor(&whereto
);
1536 getconfig(int sock
, uint64_t if_flags
, struct sockaddr
*addr
,
1537 struct ifreq
*ifr
, struct logint
*li
)
1540 struct sockaddr_in
*sin
;
1541 struct lifreq lifreq
;
1543 ifreq
= *ifr
; /* Copy name etc */
1545 li
->li_flags
= if_flags
;
1546 sin
= (struct sockaddr_in
*)ALIGN(addr
);
1547 li
->li_localaddr
= sin
->sin_addr
;
1549 (void) strlcpy(lifreq
.lifr_name
, ifr
->ifr_name
,
1550 sizeof (lifreq
.lifr_name
));
1551 if (ioctl(sock
, SIOCGLIFINDEX
, &lifreq
) < 0) {
1552 logperror("initifs: ioctl (get if index)");
1553 /* Continue with 0; a safe value never used for interfaces */
1556 li
->li_index
= lifreq
.lifr_index
;
1559 if (if_flags
& IFF_POINTOPOINT
) {
1560 li
->li_netmask
.s_addr
= (unsigned long)0xffffffff;
1561 if (ioctl(sock
, SIOCGIFDSTADDR
, (char *)&ifreq
) < 0) {
1562 logperror("initifs: ioctl (get dest addr)");
1565 /* A pt-pt link is identified by the remote address */
1566 sin
= (struct sockaddr_in
*)ALIGN(&ifreq
.ifr_addr
);
1567 li
->li_address
= sin
->sin_addr
;
1568 li
->li_remoteaddr
= sin
->sin_addr
;
1569 /* Simulate broadcast for pt-pt */
1570 li
->li_bcastaddr
= sin
->sin_addr
;
1571 li
->li_flags
|= IFF_BROADCAST
;
1574 * Non pt-pt links are identified by the local
1577 li
->li_address
= li
->li_localaddr
;
1578 li
->li_remoteaddr
= li
->li_address
;
1579 if (ioctl(sock
, SIOCGIFNETMASK
, (char *)&ifreq
) < 0) {
1580 logperror("initifs: ioctl (get netmask)");
1583 sin
= (struct sockaddr_in
*)ALIGN(&ifreq
.ifr_addr
);
1584 li
->li_netmask
= sin
->sin_addr
;
1585 if (if_flags
& IFF_BROADCAST
) {
1586 if (ioctl(sock
, SIOCGIFBRDADDR
, (char *)&ifreq
) < 0) {
1588 "initifs: ioctl (get broadcast address)");
1591 sin
= (struct sockaddr_in
*)ALIGN(&ifreq
.ifr_addr
);
1592 li
->li_bcastaddr
= sin
->sin_addr
;
1600 support_multicast(void)
1605 sock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1607 logperror("support_multicast: socket");
1611 if (setsockopt(sock
, IPPROTO_IP
, IP_MULTICAST_TTL
,
1612 (char *)&ttl
, sizeof (ttl
)) < 0) {
1621 * For a given destination address, find the logical interface to use.
1622 * If opi is NULL check all interfaces. Otherwise just match against
1623 * the specified physical interface.
1624 * Return logical interface if there's a match, NULL otherwise.
1626 static struct logint
*
1627 find_directly_connected_logint(struct in_addr in
, struct phyint
*opi
)
1637 for (; pi
!= NULL
; pi
= pi
->pi_next
) {
1638 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1639 if (li
->li_state
& ST_DELETED
)
1642 /* Check that the subnetwork numbers match */
1643 if ((in
.s_addr
& li
->li_netmask
.s_addr
) ==
1644 (li
->li_remoteaddr
.s_addr
&
1645 li
->li_netmask
.s_addr
))
1655 * INTERFACES - physical and logical identified by name
1660 report_interfaces(void)
1665 logdebug("\nInterfaces:\n\n");
1666 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
1667 logdebug("Phyint %s state 0x%x\n",
1668 pi
->pi_name
, pi
->pi_state
);
1669 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1670 logdebug("IF %s state 0x%x, flags 0x%x, addr %s\n",
1671 li
->li_name
, li
->li_state
, li
->li_flags
,
1672 pr_name(li
->li_address
));
1673 logdebug("\tlocal %s pref 0x%x ",
1674 pr_name(li
->li_localaddr
), li
->li_preference
);
1675 logdebug("bcast %s\n",
1676 pr_name(li
->li_bcastaddr
));
1677 logdebug("\tremote %s ",
1678 pr_name(li
->li_remoteaddr
));
1679 logdebug("netmask %s\n",
1680 pr_name(li
->li_netmask
));
1685 static struct phyint
*
1686 find_phyint(char *name
)
1690 for (pi
= phyint
; pi
!= NULL
; pi
= pi
->pi_next
) {
1691 if (strcmp(pi
->pi_name
, name
) == 0)
1697 /* Assumes that the entry does not exist - caller must use find_* */
1698 static struct phyint
*
1699 add_phyint(char *name
)
1703 pi
= malloc(sizeof (*pi
));
1706 bzero((char *)pi
, sizeof (*pi
));
1708 strncpy(pi
->pi_name
, name
, sizeof (pi
->pi_name
));
1709 /* Link into list */
1710 pi
->pi_next
= phyint
;
1713 phyint
->pi_prev
= pi
;
1719 free_phyint(struct phyint
*pi
)
1721 assert(pi
->pi_logical_first
== NULL
);
1722 assert(pi
->pi_logical_last
== NULL
);
1724 if (pi
->pi_prev
== NULL
) {
1726 assert(phyint
== pi
);
1727 phyint
= pi
->pi_next
;
1729 assert(pi
->pi_prev
->pi_next
== pi
);
1730 pi
->pi_prev
->pi_next
= pi
->pi_next
;
1732 if (pi
->pi_next
!= NULL
) {
1733 assert(pi
->pi_next
->pi_prev
== pi
);
1734 pi
->pi_next
->pi_prev
= pi
->pi_prev
;
1739 static struct logint
*
1740 find_logint(struct phyint
*pi
, char *name
)
1744 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1745 if (strcmp(li
->li_name
, name
) == 0)
1752 * Assumes that the entry does not exist - caller must use find_*
1755 static struct logint
*
1756 add_logint(struct phyint
*pi
, char *name
)
1760 li
= malloc(sizeof (*li
));
1763 bzero((char *)li
, sizeof (*li
));
1765 strncpy(li
->li_name
, name
, sizeof (li
->li_name
));
1766 /* Link into list */
1767 li
->li_prev
= pi
->pi_logical_last
;
1768 if (pi
->pi_logical_last
== NULL
) {
1770 assert(pi
->pi_logical_first
== NULL
);
1771 pi
->pi_logical_first
= li
;
1773 pi
->pi_logical_last
->li_next
= li
;
1776 li
->li_physical
= pi
;
1777 pi
->pi_logical_last
= li
;
1783 free_logint(struct logint
*li
)
1787 pi
= li
->li_physical
;
1788 if (li
->li_prev
== NULL
) {
1790 assert(pi
->pi_logical_first
== li
);
1791 pi
->pi_logical_first
= li
->li_next
;
1793 assert(li
->li_prev
->li_next
== li
);
1794 li
->li_prev
->li_next
= li
->li_next
;
1796 if (li
->li_next
== NULL
) {
1798 assert(pi
->pi_logical_last
== li
);
1799 pi
->pi_logical_last
= li
->li_prev
;
1801 assert(li
->li_next
->li_prev
== li
);
1802 li
->li_next
->li_prev
= li
->li_prev
;
1808 /* Tell all the logical interfaces that they are going away */
1810 deleted_phyint(struct phyint
*pi
, int s
,
1811 struct sockaddr_in
*joinaddr
)
1816 logdebug("Deleting physical interface %s\n", pi
->pi_name
);
1818 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1819 li
->li_state
|= ST_DELETED
;
1821 for (li
= pi
->pi_logical_first
; li
!= NULL
; li
= li
->li_next
) {
1822 deleted_logint(li
, NULL
, s
, joinaddr
);
1827 * Join the multicast address if no other logical interface has done
1828 * so for this physical interface.
1831 added_logint(struct logint
*li
, int s
,
1832 struct sockaddr_in
*joinaddr
)
1835 logdebug("Adding logical interface %s\n", li
->li_name
);
1837 if ((!(li
->li_physical
->pi_state
& ST_JOINED
)) &&
1838 (!isbroadcast(joinaddr
))) {
1839 struct ip_mreq mreq
;
1841 mreq
.imr_multiaddr
= joinaddr
->sin_addr
;
1842 mreq
.imr_interface
= li
->li_address
;
1845 logdebug("Joining MC on interface %s\n", li
->li_name
);
1847 if (setsockopt(s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
1848 (char *)&mreq
, sizeof (mreq
)) < 0) {
1849 logperror("setsockopt (IP_ADD_MEMBERSHIP)");
1851 li
->li_physical
->pi_state
|= ST_JOINED
;
1852 li
->li_state
|= ST_JOINED
;
1858 * Leave the multicast address if this logical interface joined it.
1859 * Look for a replacement logical interface for the same physical interface.
1860 * Remove any routes which are no longer reachable.
1862 * If newli is non-NULL, then it is likely that the address of a logical
1863 * interface has changed. In this case, the membership should be dropped using
1864 * the new address of the interface in question.
1866 * XXX When a physical interface is being deleted by deleted_phyint(), this
1867 * routine will be called for each logical interface associated with the
1868 * physical one. This should be made more efficient as there is no point in
1869 * searching for an alternate logical interface to add group membership to as
1870 * they all are marked ST_DELETED.
1873 deleted_logint(struct logint
*li
, struct logint
*newli
, int s
,
1874 struct sockaddr_in
*joinaddr
)
1880 logdebug("Deleting logical interface %s\n", li
->li_name
);
1882 assert(li
->li_state
& ST_DELETED
);
1884 if (li
->li_state
& ST_JOINED
) {
1885 struct ip_mreq mreq
;
1887 pi
= li
->li_physical
;
1888 assert(pi
->pi_state
& ST_JOINED
);
1889 assert(!isbroadcast(joinaddr
));
1891 mreq
.imr_multiaddr
= joinaddr
->sin_addr
;
1893 mreq
.imr_interface
= newli
->li_address
;
1895 mreq
.imr_interface
= li
->li_address
;
1898 logdebug("Leaving MC on interface %s\n", li
->li_name
);
1900 if (setsockopt(s
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
,
1901 (char *)&mreq
, sizeof (mreq
)) < 0) {
1903 * EADDRNOTAVAIL will be returned if the interface has
1904 * been unplumbed or if the interface no longer has
1905 * IFF_MULTICAST set. The former is the common case
1906 * while the latter is rare so don't log the error
1907 * unless some other error was returned or if debug is
1910 if (errno
!= EADDRNOTAVAIL
) {
1911 logperror("setsockopt (IP_DROP_MEMBERSHIP)");
1913 logdebug("%s: %s\n",
1914 "setsockopt (IP_DROP_MEMBERSHIP)",
1918 li
->li_physical
->pi_state
&= ~ST_JOINED
;
1919 li
->li_state
&= ~ST_JOINED
;
1921 /* Is there another interface that can join? */
1922 for (oli
= pi
->pi_logical_first
; oli
!= NULL
;
1923 oli
= oli
->li_next
) {
1924 if (oli
->li_state
& ST_DELETED
)
1927 mreq
.imr_multiaddr
= joinaddr
->sin_addr
;
1928 mreq
.imr_interface
= oli
->li_address
;
1931 logdebug("Joining MC on interface %s\n",
1934 if (setsockopt(s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
1935 (char *)&mreq
, sizeof (mreq
)) < 0) {
1936 logperror("setsockopt (IP_ADD_MEMBERSHIP)");
1938 pi
->pi_state
|= ST_JOINED
;
1939 oli
->li_state
|= ST_JOINED
;
1945 flush_unreachable_routers();
1954 struct in_addr router
;
1961 struct table
*table
;
1968 logdebug("\nRoutes:\n\n");
1971 logdebug("Router %s, pref 0x%x, time %d, %s kernel\n",
1972 pr_name(tp
->router
), tp
->preference
,
1974 (tp
->in_kernel
? "in" : "not in"));
1979 static struct table
*
1980 find_router(struct in_addr addr
)
1986 if (tp
->router
.s_addr
== addr
.s_addr
)
1994 max_preference(void)
1997 int max
= (int)IGNORE_PREFERENCE
;
2001 if (tp
->preference
> max
)
2002 max
= tp
->preference
;
2009 /* Note: this might leave the kernel with no default route for a short time. */
2013 struct table
**tpp
, *tp
;
2014 int recalculate_max
= 0;
2015 int max
= max_preference();
2018 while (*tpp
!= NULL
) {
2020 tp
->remaining_time
-= time
;
2021 if (tp
->remaining_time
<= 0) {
2024 logdebug("Timed out router %s\n",
2025 pr_name(tp
->router
));
2028 del_route(tp
->router
);
2029 if (best_preference
&&
2030 tp
->preference
== max
)
2037 if (recalculate_max
) {
2038 int max
= max_preference();
2040 if (max
!= IGNORE_PREFERENCE
) {
2043 if (tp
->preference
== max
&& !tp
->in_kernel
) {
2044 add_route(tp
->router
);
2054 * Remove any routes which are no longer directly connected.
2057 flush_unreachable_routers(void)
2059 struct table
**tpp
, *tp
;
2060 int recalculate_max
= 0;
2061 int max
= max_preference();
2064 while (*tpp
!= NULL
) {
2066 if (find_directly_connected_logint(tp
->router
, NULL
) == NULL
) {
2069 logdebug("Unreachable router %s\n",
2070 pr_name(tp
->router
));
2073 del_route(tp
->router
);
2074 if (best_preference
&&
2075 tp
->preference
== max
)
2082 if (recalculate_max
) {
2083 int max
= max_preference();
2085 if (max
!= IGNORE_PREFERENCE
) {
2088 if (tp
->preference
== max
&& !tp
->in_kernel
) {
2089 add_route(tp
->router
);
2099 record_router(struct in_addr router
, long preference
, int ttl
)
2102 int old_max
= max_preference();
2103 int changed_up
= 0; /* max preference could have increased */
2104 int changed_down
= 0; /* max preference could have decreased */
2107 logdebug("Recording %s, preference 0x%x\n",
2110 tp
= find_router(router
);
2112 if (tp
->preference
> preference
&&
2113 tp
->preference
== old_max
)
2115 else if (preference
> tp
->preference
)
2117 tp
->preference
= preference
;
2118 tp
->remaining_time
= ttl
;
2120 if (preference
> old_max
)
2122 tp
= (struct table
*)ALIGN(malloc(sizeof (struct table
)));
2124 logerr("Out of memory\n");
2127 tp
->router
= router
;
2128 tp
->preference
= preference
;
2129 tp
->remaining_time
= ttl
;
2134 if (!tp
->in_kernel
&&
2135 (!best_preference
|| tp
->preference
== max_preference()) &&
2136 tp
->preference
!= IGNORE_PREFERENCE
) {
2137 add_route(tp
->router
);
2140 if (tp
->preference
== IGNORE_PREFERENCE
&& tp
->in_kernel
) {
2141 del_route(tp
->router
);
2144 if (best_preference
&& changed_down
) {
2145 /* Check if we should add routes */
2146 int new_max
= max_preference();
2147 if (new_max
!= IGNORE_PREFERENCE
) {
2150 if (tp
->preference
== new_max
&&
2152 add_route(tp
->router
);
2159 if (best_preference
&& (changed_up
|| changed_down
)) {
2160 /* Check if we should remove routes already in the kernel */
2161 int new_max
= max_preference();
2164 if (tp
->preference
< new_max
&& tp
->in_kernel
) {
2165 del_route(tp
->router
);
2174 #include <net/route.h>
2177 add_route(struct in_addr addr
)
2180 logdebug("Add default route to %s\n", pr_name(addr
));
2181 rtioctl(addr
, SIOCADDRT
);
2185 del_route(struct in_addr addr
)
2188 logdebug("Delete default route to %s\n", pr_name(addr
));
2189 rtioctl(addr
, SIOCDELRT
);
2193 rtioctl(struct in_addr addr
, int op
)
2197 struct sockaddr_in
*sin
;
2198 bzero((char *)&rt
, sizeof (struct rtentry
));
2199 rt
.rt_dst
.sa_family
= AF_INET
;
2200 rt
.rt_gateway
.sa_family
= AF_INET
;
2201 sin
= (struct sockaddr_in
*)ALIGN(&rt
.rt_gateway
);
2202 sin
->sin_addr
= addr
;
2203 rt
.rt_flags
= RTF_UP
| RTF_GATEWAY
;
2205 sock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2207 logperror("rtioctl: socket");
2210 if (ioctl(sock
, op
, (char *)&rt
) < 0) {
2211 if (!(op
== SIOCADDRT
&& errno
== EEXIST
))
2212 logperror("ioctl (add/delete route)");
2225 static int logging
= 0;
2231 openlog("in.rdisc", LOG_PID
| LOG_CONS
, LOG_DAEMON
);
2236 logerr(fmt
, a
, b
, c
, d
, e
, f
, g
, h
)
2240 syslog(LOG_ERR
, fmt
, a
, b
, c
, d
, e
, f
, g
, h
);
2242 (void) fprintf(stderr
, fmt
, a
, b
, c
, d
, e
, f
, g
, h
);
2247 logtrace(fmt
, a
, b
, c
, d
, e
, f
, g
, h
)
2251 syslog(LOG_INFO
, fmt
, a
, b
, c
, d
, e
, f
, g
, h
);
2253 (void) fprintf(stdout
, fmt
, a
, b
, c
, d
, e
, f
, g
, h
);
2258 logdebug(fmt
, a
, b
, c
, d
, e
, f
, g
, h
)
2262 syslog(LOG_DEBUG
, fmt
, a
, b
, c
, d
, e
, f
, g
, h
);
2264 (void) fprintf(stdout
, fmt
, a
, b
, c
, d
, e
, f
, g
, h
);
2272 syslog(LOG_ERR
, "%s: %s\n", str
, strerror(errno
));
2274 (void) fprintf(stderr
, "%s: %s\n", str
, strerror(errno
));