dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / in.routed / rdisc.c
blobd7325b3393a77039e7987826f4c884d4c940a3f5
1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
5 * Copyright (c) 1995
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgment:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
36 * $FreeBSD: src/sbin/routed/rdisc.c,v 1.8 2000/08/11 08:24:38 sheldonh Exp $
39 #pragma ident "%Z%%M% %I% %E% SMI"
41 #include "defs.h"
42 #include <netinet/in_systm.h>
43 #include <netinet/ip.h>
44 #include <netinet/ip_icmp.h>
45 #include <fcntl.h>
46 #include <strings.h>
49 * The size of the control buffer passed to recvmsg() used to receive
50 * ancillary data.
52 #define CONTROL_BUFSIZE 1024
54 /* router advertisement ICMP packet */
55 struct icmp_ad {
56 uint8_t icmp_type; /* type of message */
57 uint8_t icmp_code; /* type sub code */
58 uint16_t icmp_cksum; /* ones complement cksum of struct */
59 uint8_t icmp_ad_num; /* # of following router addresses */
60 uint8_t icmp_ad_asize; /* 2--words in each advertisement */
61 uint16_t icmp_ad_life; /* seconds of validity */
62 struct icmp_ad_info {
63 in_addr_t icmp_ad_addr;
64 uint32_t icmp_ad_pref;
65 } icmp_ad_info[1];
68 /* router solicitation ICMP packet */
69 struct icmp_so {
70 uint8_t icmp_type; /* type of message */
71 uint8_t icmp_code; /* type sub code */
72 uint16_t icmp_cksum; /* ones complement cksum of struct */
73 uint32_t icmp_so_rsvd;
76 union ad_u {
77 struct icmp icmp;
78 struct icmp_ad ad;
79 struct icmp_so so;
83 int rdisc_sock = -1; /* router-discovery raw socket */
84 int rdisc_mib_sock = -1; /* AF_UNIX mib info socket */
85 static struct interface *rdisc_sock_interface; /* current rdisc interface */
87 struct timeval rdisc_timer;
88 boolean_t rdisc_ok; /* using solicited route */
90 #define MAX_ADS 16
91 int max_ads; /* at least one per interface */
92 /* accumulated advertisements */
93 static struct dr *cur_drp;
94 struct dr *drs;
97 * adjust unsigned preference by interface metric,
98 * without driving it to infinity
100 #define PREF(p, ifp) ((p) <= (uint32_t)(ifp)->int_metric ? ((p) != 0 ? 1 : 0) \
101 : (p) - ((ifp)->int_metric))
103 static void rdisc_sort(void);
105 typedef enum { unicast, bcast, mcast } dstaddr_t;
107 /* dump an ICMP Router Discovery Advertisement Message */
108 static void
109 trace_rdisc(const char *act,
110 uint32_t from,
111 uint32_t to,
112 struct interface *ifp,
113 union ad_u *p,
114 uint_t len)
116 int i;
117 n_long *wp, *lim;
120 if (!TRACEPACKETS || ftrace == 0)
121 return;
123 lastlog();
125 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) {
126 (void) fprintf(ftrace, "%s Router Ad"
127 " from %s to %s via %s life=%d\n",
128 act, naddr_ntoa(from), naddr_ntoa(to),
129 ifp ? ifp->int_name : "?",
130 ntohs(p->ad.icmp_ad_life));
131 if (!TRACECONTENTS)
132 return;
134 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr;
135 lim = &wp[(len - sizeof (p->ad)) / sizeof (*wp)];
136 for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) {
137 (void) fprintf(ftrace, "\t%s preference=%ld",
138 naddr_ntoa(wp[0]), (long)ntohl(wp[1]));
139 wp += p->ad.icmp_ad_asize;
141 (void) fputc('\n', ftrace);
143 } else {
144 trace_act("%s Router Solic. from %s to %s via %s rsvd=%#x",
145 act, naddr_ntoa(from), naddr_ntoa(to),
146 ifp ? ifp->int_name : "?",
147 ntohl(p->so.icmp_so_rsvd));
152 * Prepare Router Discovery socket.
154 static void
155 get_rdisc_sock(void)
157 int on = 1;
158 unsigned char ttl = 1;
159 struct sockaddr_un laddr;
160 int len;
162 if (rdisc_sock < 0) {
163 max_ads = MAX_ADS;
164 drs = rtmalloc(max_ads * sizeof (struct dr), "get_rdisc_sock");
165 (void) memset(drs, 0, max_ads * sizeof (struct dr));
166 rdisc_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
167 if (rdisc_sock < 0)
168 BADERR(_B_TRUE, "rdisc_sock = socket()");
169 fix_sock(rdisc_sock, "rdisc_sock");
171 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_RECVIF, &on,
172 sizeof (on)))
173 BADERR(_B_FALSE, "setsockopt(IP_RECVIF)");
175 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_TTL,
176 &ttl, sizeof (ttl)) < 0)
177 DBGERR(_B_TRUE,
178 "rdisc_sock setsockopt(IP_MULTICAST_TTL)");
181 * On Solaris also open an AF_UNIX socket to
182 * pass default router information to mib agent
185 rdisc_mib_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
186 if (rdisc_mib_sock < 0) {
187 BADERR(_B_TRUE, "rdisc_mib_sock = socket()");
190 bzero(&laddr, sizeof (laddr));
191 laddr.sun_family = AF_UNIX;
193 (void) strncpy(laddr.sun_path, RDISC_SNMP_SOCKET,
194 sizeof (laddr.sun_path));
195 len = sizeof (struct sockaddr_un);
197 (void) unlink(RDISC_SNMP_SOCKET);
199 if (bind(rdisc_mib_sock, (struct sockaddr *)&laddr, len) < 0) {
200 BADERR(_B_TRUE, "bind(rdisc_mib_sock)");
203 if (fcntl(rdisc_mib_sock, F_SETFL, O_NONBLOCK) < 0) {
204 BADERR(_B_TRUE, "rdisc_mib_sock fcntl O_NONBLOCK");
207 fix_select();
213 * Pick multicast group for router-discovery socket
215 void
216 set_rdisc_mg(struct interface *ifp,
217 int on) /* 0=turn it off */
219 struct ip_mreq m;
220 boolean_t dosupply;
222 if (rdisc_sock < 0) {
224 * Create the raw socket so that we can hear at least
225 * broadcast router discovery packets.
227 if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC ||
228 !on)
229 return;
230 get_rdisc_sock();
233 if (!(ifp->int_if_flags & IFF_MULTICAST)) {
234 /* Can't multicast, so no groups could have been joined. */
235 ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS);
236 return;
239 dosupply = should_supply(ifp);
241 (void) memset(&m, 0, sizeof (m));
242 m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) &&
243 (ifp->int_dstaddr != 0) ? ifp->int_dstaddr : ifp->int_addr);
244 if (dosupply || (ifp->int_state & IS_NO_ADV_IN) || !on) {
245 /* stop listening to advertisements */
246 if (ifp->int_state & IS_ALL_HOSTS) {
247 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
248 if (setsockopt(rdisc_sock, IPPROTO_IP,
249 IP_DROP_MEMBERSHIP, &m, sizeof (m)) < 0 &&
250 errno != EADDRNOTAVAIL && errno != ENOENT)
251 LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS");
252 ifp->int_state &= ~IS_ALL_HOSTS;
255 } else if (!(ifp->int_state & IS_ALL_HOSTS)) {
256 /* start listening to advertisements */
257 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
258 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
259 &m, sizeof (m)) < 0) {
260 LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS");
261 } else {
262 ifp->int_state |= IS_ALL_HOSTS;
266 if (!dosupply || (ifp->int_state & IS_NO_ADV_OUT) ||
267 !IS_IFF_ROUTING(ifp->int_if_flags) || !on) {
268 /* stop listening to solicitations */
269 if (ifp->int_state & IS_ALL_ROUTERS) {
270 m.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP);
271 if (setsockopt(rdisc_sock, IPPROTO_IP,
272 IP_DROP_MEMBERSHIP, &m, sizeof (m)) < 0 &&
273 errno != EADDRNOTAVAIL && errno != ENOENT)
274 LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS");
275 ifp->int_state &= ~IS_ALL_ROUTERS;
278 } else if (!(ifp->int_state & IS_ALL_ROUTERS)) {
279 /* start hearing solicitations */
280 m.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP);
281 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
282 &m, sizeof (m)) < 0) {
283 LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS");
284 } else {
285 ifp->int_state |= IS_ALL_ROUTERS;
292 * start or stop supplying routes to other systems.
294 void
295 set_supplier(void)
297 struct interface *ifp;
298 struct dr *drp;
299 static boolean_t supplystate = _B_FALSE;
301 if (supplystate == (fwd_interfaces > 1))
302 return;
303 supplystate = fwd_interfaces > 1;
305 trace_act("%d forwarding interfaces present; becoming %ssupplier",
306 fwd_interfaces, supplystate ? "" : "non-");
308 if (supplystate) {
309 /* Forget discovered routes. */
310 for (drp = drs; drp < &drs[max_ads]; drp++) {
311 drp->dr_recv_pref = DEF_PREFERENCELEVEL;
312 drp->dr_life = 0;
314 rdisc_age(0);
317 * Do not start advertising until we have heard some
318 * RIP routes.
320 LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME);
322 /* get rid of any redirects */
323 del_redirects(0, 0);
324 } else {
326 * Flush out all those advertisements we had sent by sending
327 * one with lifetime=0.
329 rdisc_adv(_B_TRUE);
333 * Switch router discovery multicast groups from soliciting
334 * to advertising or back.
336 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
337 if (ifp->int_state & IS_BROKE)
338 continue;
339 ifp->int_rdisc_cnt = 0;
340 ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec;
341 ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME;
342 set_rdisc_mg(ifp, 1);
348 * Age discovered routes and find the best one
350 void
351 rdisc_age(in_addr_t bad_gate)
353 time_t sec;
354 struct dr *drp;
355 struct rt_spare new;
356 struct rt_entry *rt;
359 * If we are being told about a bad router,
360 * then age the discovered default route, and if there is
361 * no alternative, solicit a replacement.
363 if (bad_gate != 0) {
365 * Look for the bad discovered default route.
366 * Age it and note its interface.
368 for (drp = drs; drp < &drs[max_ads]; drp++) {
369 if (drp->dr_ts == 0)
370 continue;
373 * When we find the bad router, age the route
374 * to at most SUPPLY_INTERVAL.
375 * This is contrary to RFC 1256, but defends against
376 * black holes.
378 if (drp->dr_gate == bad_gate) {
379 sec = (now.tv_sec - drp->dr_life +
380 SUPPLY_INTERVAL);
381 if (drp->dr_ts > sec) {
382 trace_act("age 0.0.0.0 --> %s via %s",
383 naddr_ntoa(drp->dr_gate),
384 drp->dr_ifp->int_name);
385 drp->dr_ts = sec;
387 break;
390 } else if (should_supply(NULL)) {
392 * If switching from client to server, get rid of old
393 * default routes.
395 if (cur_drp != NULL) {
396 rt = rtget(RIP_DEFAULT, 0);
398 * If there is a current default router, and the
399 * there is no rt_spare entry, create one
400 * for cur_drp to prevent segmentation fault
401 * at rdisc_sort.
403 if (rt == NULL) {
404 (void) memset(&new, 0, sizeof (new));
405 new.rts_ifp = cur_drp->dr_ifp;
406 new.rts_gate = cur_drp->dr_gate;
407 new.rts_router = cur_drp->dr_gate;
408 new.rts_metric = HOPCNT_INFINITY-1;
409 new.rts_time = now.tv_sec;
410 new.rts_origin = RO_RDISC;
411 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new);
414 rdisc_sort();
416 rdisc_adv(_B_FALSE);
419 rdisc_sol();
420 if (cur_drp != NULL) {
421 rt = rtget(RIP_DEFAULT, 0);
422 if (rt == NULL) {
423 (void) memset(&new, 0, sizeof (new));
424 new.rts_ifp = cur_drp->dr_ifp;
425 new.rts_gate = cur_drp->dr_gate;
426 new.rts_router = cur_drp->dr_gate;
427 new.rts_metric = HOPCNT_INFINITY-1;
428 new.rts_time = now.tv_sec;
429 new.rts_origin = RO_RDISC;
430 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new);
433 rdisc_sort();
436 * Delete old redirected routes to keep the kernel table small,
437 * and to prevent black holes. Check that the kernel table
438 * matches the daemon table (i.e. has the default route).
439 * But only if RIP is not running and we are not dealing with
440 * a bad gateway, since otherwise age() will be called.
442 if (rip_sock < 0 && bad_gate == 0)
443 age(0);
448 * Zap all routes discovered via an interface that has gone bad
449 * This should only be called when !(ifp->int_state & IS_DUP)
450 * This is called by if_del and if_bad, and the interface pointer
451 * might not be valid after this.
453 void
454 if_bad_rdisc(struct interface *ifp)
456 struct dr *drp;
458 for (drp = drs; drp < &drs[max_ads]; drp++) {
459 if (drp->dr_ifp != ifp)
460 continue;
461 (void) memset(drp, 0, sizeof (*drp));
464 /* make a note to re-solicit, turn RIP on or off, etc. */
465 rdisc_timer.tv_sec = 0;
469 * Rewire all routes discovered via an interface that has gone bad
470 * This is only called by if_del.
472 void
473 if_rewire_rdisc(struct interface *oldifp, struct interface *newifp)
475 struct dr *drp;
477 for (drp = drs; drp < &drs[max_ads]; drp++) {
478 if (drp->dr_ifp != oldifp)
479 continue;
480 drp->dr_ifp = newifp;
481 drp->dr_pref += (newifp->int_metric - oldifp->int_metric);
482 drp->dr_flags |= DR_CHANGED;
485 /* make a note to re-solicit, turn RIP on or off, etc. */
486 rdisc_timer.tv_sec = 0;
490 * Mark an interface ok for router discovering.
491 * This is called by if_ok and ifinit.
493 void
494 if_ok_rdisc(struct interface *ifp)
496 set_rdisc_mg(ifp, 1);
498 ifp->int_rdisc_cnt = 0;
499 ifp->int_rdisc_timer.tv_sec = now.tv_sec +
500 ((ifp->int_state & IS_NO_ADV_OUT) ?
501 MAX_SOLICITATION_DELAY : MIN_WAITTIME);
502 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, > /* cstyle */))
503 rdisc_timer = ifp->int_rdisc_timer;
507 * Get rid of a dead discovered router
509 static void
510 del_rdisc(struct dr *drp)
512 struct interface *ifp;
513 uint32_t gate;
514 int i;
515 struct rt_entry *rt;
516 struct rt_spare *rts = NULL;
518 del_redirects(gate = drp->dr_gate, 0);
519 drp->dr_ts = 0;
520 drp->dr_life = 0;
522 rt = rtget(RIP_DEFAULT, 0);
523 if (rt == NULL) {
524 trace_act("could not find default route in table");
525 } else {
526 for (i = 0; i < rt->rt_num_spares; i++) {
527 if ((rt->rt_spares[i].rts_gate == drp->dr_gate) &&
528 (rt->rt_spares[i].rts_origin == RO_RDISC)) {
529 rts = &rt->rt_spares[i];
530 break;
533 if (rts != NULL)
534 rts_delete(rt, rts);
535 else
536 trace_act("could not find default route "
537 "through %s in table", naddr_ntoa(drp->dr_gate));
540 /* Count the other discovered routers on the interface. */
541 i = 0;
542 ifp = drp->dr_ifp;
543 for (drp = drs; drp < &drs[max_ads]; drp++) {
544 if (drp->dr_ts != 0 && drp->dr_ifp == ifp)
545 i++;
549 * If that was the last good discovered router on the interface,
550 * then solicit a new one.
551 * This is contrary to RFC 1256, but defends against black holes.
553 if (i != 0) {
554 trace_act("discovered router %s via %s"
555 " is bad--have %d remaining",
556 naddr_ntoa(gate), ifp->int_name, i);
557 } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) {
558 trace_act("last discovered router %s via %s"
559 " is bad--re-solicit",
560 naddr_ntoa(gate), ifp->int_name);
561 ifp->int_rdisc_cnt = 0;
562 ifp->int_rdisc_timer.tv_sec = 0;
563 rdisc_sol();
564 } else {
565 trace_act("last discovered router %s via %s"
566 " is bad--wait to solicit",
567 naddr_ntoa(gate), ifp->int_name);
572 /* Find the best discovered route, and discard stale routers. */
573 static void
574 rdisc_sort(void)
576 struct dr *drp, *new_drp;
577 struct rt_entry *rt;
578 struct rt_spare new, *rts;
579 struct interface *ifp;
580 uint_t new_st = 0;
581 uint32_t new_pref = DEF_PREFERENCELEVEL;
582 int first_rdisc_slot = 0;
583 int j;
584 boolean_t spares_avail;
585 void *ptr;
586 size_t ptrsize;
588 rt = rtget(RIP_DEFAULT, 0);
591 * If all the rt_spare entries are taken up with with default routes
592 * learnt from RIP (ie rts_origin = RO_RIP), bail out.
593 * NOTE:
594 * We *always* prefer default routes learned via RIP
595 * (ie RO_RIP) over those learnt via RDISC (ie RO_RDISC).
596 * The rdisc machinery should not modify, replace or
597 * remove any existing default routes with RO_RIP set.
599 if (rt != NULL) {
600 spares_avail = _B_FALSE;
601 for (j = 0; j < rt->rt_num_spares; j++) {
602 rts = &rt->rt_spares[j];
603 if (rts->rts_gate == 0 || rts->rts_origin != RO_RIP ||
604 rts->rts_ifp == &dummy_ifp) {
605 spares_avail = _B_TRUE;
606 break;
609 if (!spares_avail) {
610 ptrsize = (rt->rt_num_spares + SPARE_INC) *
611 sizeof (struct rt_spare);
612 ptr = realloc(rt->rt_spares, ptrsize);
613 if (ptr != NULL) {
614 struct rt_spare *tmprts;
616 rt->rt_spares = ptr;
617 rts = &rt->rt_spares[rt->rt_num_spares];
618 (void) memset(rts, 0,
619 (SPARE_INC * sizeof (struct rt_spare)));
620 rt->rt_num_spares += SPARE_INC;
621 for (tmprts = rts, j = SPARE_INC;
622 j != 0; j--, tmprts++)
623 tmprts->rts_metric = HOPCNT_INFINITY;
624 spares_avail = _B_TRUE;
625 } else {
626 return;
630 /* Find the best RDISC advertiser */
631 rt = NULL;
632 new_drp = NULL;
633 for (drp = drs; drp < &drs[max_ads]; drp++) {
634 if (drp->dr_ts == 0)
635 continue;
636 ifp = drp->dr_ifp;
638 /* Get rid of expired discovered routers. */
639 if (drp->dr_ts + drp->dr_life <= now.tv_sec) {
640 del_rdisc(drp);
641 continue;
644 LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life);
647 * Update preference with possibly changed interface
648 * metric.
650 drp->dr_pref = PREF(drp->dr_recv_pref, ifp);
653 * Prefer the current route to prevent thrashing.
654 * Prefer shorter lifetimes to speed the detection of
655 * bad routers.
656 * Avoid sick interfaces.
658 if (new_drp == NULL ||
659 (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) &&
660 (new_pref < drp->dr_pref ||
661 (new_pref == drp->dr_pref && (drp == cur_drp ||
662 (new_drp != cur_drp &&
663 new_drp->dr_life > drp->dr_life))))) ||
664 ((new_st & IS_SICK) &&
665 !(drp->dr_ifp->int_state & IS_SICK))) {
666 new_drp = drp;
667 new_st = drp->dr_ifp->int_state;
668 new_pref = drp->dr_pref;
673 * switch to a better RDISC advertiser
675 if ((new_drp != cur_drp) || (rt == NULL)) {
676 rt = rtget(RIP_DEFAULT, 0);
679 * Purge the table of all the default routes that were
680 * learnt via RDISC, while keeping an eye the first available
681 * slot for the spare entry of new_drp
683 if (rt != NULL) {
684 int i;
685 for (i = 0; i < rt->rt_num_spares; i++) {
686 rts = &rt->rt_spares[i];
687 if ((rts->rts_gate == 0 ||
688 rts->rts_ifp == &dummy_ifp) &&
689 first_rdisc_slot == 0)
690 first_rdisc_slot = i;
691 if (rts->rts_origin == RO_RDISC) {
692 rts_delete(rt, rts);
693 if (first_rdisc_slot == 0) {
694 first_rdisc_slot = i;
700 /* Stop using RDISC routes if they are all bad */
701 if (new_drp == NULL) {
702 trace_act("turn off Router Discovery client");
703 rdisc_ok = _B_FALSE;
705 } else {
706 if (cur_drp == NULL) {
707 trace_act("turn on Router Discovery client"
708 " using %s via %s",
709 naddr_ntoa(new_drp->dr_gate),
710 new_drp->dr_ifp->int_name);
711 rdisc_ok = _B_TRUE;
714 /* Prepare a spare entry for the new_drp */
715 (void) memset(&new, 0, sizeof (new));
716 new.rts_ifp = new_drp->dr_ifp;
717 new.rts_gate = new_drp->dr_gate;
718 new.rts_router = new_drp->dr_gate;
719 new.rts_metric = HOPCNT_INFINITY-1;
720 new.rts_time = now.tv_sec;
721 new.rts_origin = RO_RDISC;
723 * If there is no existing default route, add it
724 * to rts_spare[0].
726 if (rt == NULL) {
727 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new);
728 } else {
731 * Add the spare entry for the new_drp in
732 * the first available slot
734 trace_act("Switching to "
735 "default router with better "
736 "preference %s via %s ",
737 naddr_ntoa(new_drp->dr_gate),
738 new_drp->dr_ifp->int_name);
739 rt->rt_spares[first_rdisc_slot] = new;
740 rt = NULL; /* redo rt_spares */
745 * Get ready to redo the entire table. The table should
746 * only include :
747 * a. empty rt_spare slots
748 * b. default routes learnt via RIP
749 * c. default route for the latest best RDISC advertiser
750 * d. default routes of other RDISC advertisers whose
751 * dr_pref == best RDISC advertiser->dr_pref
753 cur_drp = new_drp;
756 /* Redo the entire spare table (without touching RO_RIP entries) */
757 if (rdisc_ok && rt == NULL) {
758 int i;
760 * We've either just turned on router discovery,
761 * or switched to a router with better preference.
762 * Find all other default routers whose
763 * pref == cur_drp->dr_pref and add them as spares
766 rt = rtget(RIP_DEFAULT, 0);
768 for (drp = drs; drp < &drs[max_ads]; drp++) {
769 boolean_t dr_done = _B_FALSE;
770 int slot = -1;
772 if (drp->dr_ts == 0)
773 continue;
775 if (drp->dr_pref != cur_drp->dr_pref &&
776 ((drp->dr_flags & DR_CHANGED) == 0))
777 continue;
780 * Either pref matches cur_drp->dr_pref,
781 * or something has changed in this drp.
782 * In the former case, we may need to add
783 * this to rt_spares. In the latter case,
784 * if the pref has changed, need to take it
785 * out of rt_spares and the kernel.
787 * First, find an empty slot in rt_spares
788 * in case we have to add this drp to kernel.
789 * Also check if it is already there.
791 for (i = 0; i < rt->rt_num_spares; i++) {
792 if (rt->rt_spares[i].rts_gate == 0) {
793 if (slot < 0)
794 slot = i;
795 continue;
797 if ((rt->rt_spares[i].rts_gate ==
798 drp->dr_gate) &&
799 (rt->rt_spares[i].rts_origin ==
800 RO_RDISC)) {
802 * a spare entry for this RDISC
803 * advertiser already exists. We need
804 * to check if this entry still belongs
805 * in the table
807 dr_done = _B_TRUE;
808 break;
812 drp->dr_flags &= ~DR_CHANGED;
814 if (drp->dr_pref != cur_drp->dr_pref) {
815 if (dr_done) {
817 * The rt_spare of this RDISC advertiser
818 * needs to be removed as it no longer
819 * belongs in the table because its
820 * dr_pref is different than the latest
821 * RDISC advertiser's->dr_pref
823 rts_delete(rt, &rt->rt_spares[i]);
825 continue;
828 if (slot < 0 && !dr_done) {
829 ptrsize = (rt->rt_num_spares + SPARE_INC) *
830 sizeof (struct rt_spare);
831 ptr = realloc(rt->rt_spares, ptrsize);
832 if (ptr != NULL) {
833 struct rt_spare *tmprts;
835 rt->rt_spares = ptr;
836 slot = rt->rt_num_spares;
837 rts = &rt->rt_spares[rt->rt_num_spares];
838 (void) memset(rts, 0, (SPARE_INC *
839 sizeof (struct rt_spare)));
840 rt->rt_num_spares += SPARE_INC;
841 for (tmprts = rts, i = SPARE_INC;
842 i != 0; i--, tmprts++)
843 tmprts->rts_metric =
844 HOPCNT_INFINITY;
848 if (slot >= 0 && (dr_done != _B_TRUE)) {
849 (void) memset(&new, 0, sizeof (new));
850 new.rts_ifp = drp->dr_ifp;
851 new.rts_gate = drp->dr_gate;
852 new.rts_router = drp->dr_gate;
853 new.rts_metric = HOPCNT_INFINITY-1;
854 new.rts_time = now.tv_sec;
855 new.rts_origin = RO_RDISC;
856 rt->rt_spares[slot] = new;
857 trace_act("spare default %s via %s",
858 naddr_ntoa(drp->dr_gate),
859 drp->dr_ifp->int_name);
864 /* turn RIP on or off */
865 if (!rdisc_ok || rip_interfaces > 1) {
866 rip_on(0);
867 } else {
868 rip_off();
873 /* Handle a single address in an advertisement */
874 static void
875 parse_ad(uint32_t from,
876 in_addr_t gate,
877 uint32_t pref, /* signed and in network order */
878 ushort_t life, /* in host byte order */
879 struct interface *ifp)
881 static struct msg_limit bad_gate;
882 struct dr *drp, *new_drp;
883 void *ptr;
884 size_t ptrsize;
886 if (gate == RIP_DEFAULT || !check_dst(gate)) {
887 msglim(&bad_gate, from, "router %s advertising bad gateway %s",
888 naddr_ntoa(from), naddr_ntoa(gate));
889 return;
893 * ignore pointers to ourself and routes via unreachable networks
895 if (ifwithaddr(gate, _B_TRUE, _B_FALSE) != 0) {
896 trace_pkt(" discard Router Discovery Ad pointing at us");
897 return;
899 if (!on_net(gate, ifp->int_net, ifp->int_mask)) {
900 trace_pkt(" discard Router Discovery Ad"
901 " toward unreachable net");
902 return;
905 * Convert preference to an unsigned value
906 * and later bias it by the metric of the interface.
908 pref = UNSIGN_PREF(ntohl(pref));
910 if (pref == DEF_PREFERENCELEVEL || life < MIN_MAXADVERTISEINTERVAL) {
911 pref = DEF_PREFERENCELEVEL;
912 life = 0;
915 for (new_drp = NULL, drp = drs; drp < &drs[max_ads]; drp++) {
916 /* accept new info for a familiar entry */
917 if ((drp->dr_gate == gate) && (drp->dr_ifp == ifp)) {
918 new_drp = drp;
919 drp->dr_flags |= DR_CHANGED;
920 break;
923 if (life == 0)
924 continue; /* do not worry about dead ads */
926 if (drp->dr_ts == 0) {
927 new_drp = drp; /* use unused entry */
929 } else if (new_drp == NULL) {
930 /* look for an entry worse than the new one to reuse. */
931 if ((!(ifp->int_state & IS_SICK) &&
932 (drp->dr_ifp->int_state & IS_SICK)) ||
933 (pref > drp->dr_pref &&
934 !((ifp->int_state ^ drp->dr_ifp->int_state) &
935 IS_SICK)))
936 new_drp = drp;
938 } else if (new_drp->dr_ts != 0) {
939 /* look for the least valuable entry to reuse */
940 if ((!(new_drp->dr_ifp->int_state & IS_SICK) &&
941 (drp->dr_ifp->int_state & IS_SICK)) ||
942 (new_drp->dr_pref > drp->dr_pref &&
943 !((new_drp->dr_ifp->int_state ^
944 drp->dr_ifp->int_state) & IS_SICK)))
945 new_drp = drp;
949 /* if all of the current entries are better, add more drs[] */
950 if (new_drp == NULL) {
951 ptrsize = (max_ads + MAX_ADS) * sizeof (struct dr);
952 ptr = realloc(drs, ptrsize);
953 if (ptr == NULL)
954 return;
955 drs = ptr;
956 (void) memset(&drs[max_ads], 0, MAX_ADS * sizeof (struct dr));
957 new_drp = &drs[max_ads];
958 max_ads += MAX_ADS;
962 * Pointer copy is safe here because if_del
963 * calls if_bad_rdisc first, so a non-NULL df_ifp
964 * is always a valid pointer.
966 new_drp->dr_ifp = ifp;
967 new_drp->dr_gate = gate;
968 new_drp->dr_ts = now.tv_sec;
969 new_drp->dr_life = life;
970 new_drp->dr_recv_pref = pref;
971 /* bias functional preference by metric of the interface */
972 new_drp->dr_pref = PREF(pref, ifp);
974 /* after hearing a good advertisement, stop asking */
975 if (!(ifp->int_state & IS_SICK))
976 ifp->int_rdisc_cnt = MAX_SOLICITATIONS;
981 * Compute the IP checksum. This assumes the packet is less than 32K long.
983 static uint16_t
984 in_cksum(uint16_t *p, uint_t len)
986 uint32_t sum = 0;
987 int nwords = len >> 1;
989 while (nwords-- != 0)
990 sum += *p++;
992 if (len & 1)
993 sum += *(uchar_t *)p;
995 /* end-around-carry */
996 sum = (sum >> 16) + (sum & 0xffff);
997 sum += (sum >> 16);
998 return (~sum);
1002 /* Send a router discovery advertisement or solicitation ICMP packet. */
1003 static void
1004 send_rdisc(union ad_u *p,
1005 uint_t p_size,
1006 struct interface *ifp,
1007 in_addr_t dst, /* 0 or unicast destination */
1008 dstaddr_t type)
1010 struct sockaddr_in sin;
1011 int flags = 0;
1012 const char *msg;
1013 int ifindex = 0;
1014 struct in_addr addr;
1017 * Don't send Rdisc packets on duplicate interfaces, we
1018 * don't want to generate duplicate packets.
1020 if (ifp->int_state & IS_DUP)
1021 return;
1023 (void) memset(&sin, 0, sizeof (sin));
1024 sin.sin_addr.s_addr = dst;
1025 sin.sin_family = AF_INET;
1027 switch (type) {
1028 case unicast: /* unicast */
1029 default:
1030 flags = MSG_DONTROUTE;
1031 msg = "Send";
1032 break;
1034 case bcast: /* broadcast */
1035 if (ifp->int_if_flags & IFF_POINTOPOINT) {
1036 msg = "Send pt-to-pt";
1037 if (ifp->int_dstaddr == 0)
1038 sin.sin_addr.s_addr = htonl(INADDR_BROADCAST);
1039 else
1040 sin.sin_addr.s_addr = ifp->int_dstaddr;
1041 } else {
1042 msg = "Send broadcast";
1043 sin.sin_addr.s_addr = ifp->int_brdaddr;
1045 break;
1047 case mcast: /* multicast */
1048 msg = "Send multicast";
1049 break;
1052 if (rdisc_sock < 0)
1053 get_rdisc_sock();
1055 /* select the right interface. */
1056 ifindex = (type != mcast && ifp->int_phys != NULL) ?
1057 ifp->int_phys->phyi_index : 0;
1059 if (rdisc_sock_interface != ifp) {
1061 * For multicast, we have to choose the source
1062 * address. This is either the local address
1063 * (non-point-to-point) or the remote address.
1065 addr.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ?
1066 ifp->int_dstaddr : ifp->int_addr;
1067 if (type == mcast &&
1068 setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_IF, &addr,
1069 sizeof (addr)) == -1) {
1070 LOGERR("setsockopt(rdisc_sock, IP_MULTICAST_IF)");
1071 return;
1073 rdisc_sock_interface = ifp;
1076 trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, p, p_size);
1078 if (0 > sendtoif(rdisc_sock, p, p_size, flags, &sin, ifindex)) {
1079 if (!(ifp->int_state & IS_BROKE))
1080 writelog(LOG_WARNING, "sendto(%s%s%s): %s",
1081 ifp->int_name, ", ",
1082 inet_ntoa(sin.sin_addr),
1083 rip_strerror(errno));
1084 if (ifp != NULL)
1085 if_sick(ifp, _B_FALSE);
1090 /* Send an advertisement */
1091 static void
1092 send_adv(struct interface *ifp,
1093 in_addr_t dst,
1094 dstaddr_t type)
1096 union ad_u u;
1098 if ((ifp->int_state & (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC)) ==
1099 IS_SUPPRESS_RDISC)
1100 return;
1102 (void) memset(&u, 0, sizeof (u.ad));
1104 u.ad.icmp_type = ICMP_ROUTERADVERT;
1105 u.ad.icmp_code = ICMP_ROUTERADVERT_COMMON;
1106 u.ad.icmp_ad_num = 1;
1107 u.ad.icmp_ad_asize = sizeof (u.ad.icmp_ad_info[0])/4;
1109 u.ad.icmp_ad_life = (stopint || !should_supply(ifp) ||
1110 (ifp->int_state & IS_SUPPRESS_RDISC)) ? 0 :
1111 htons(ifp->int_rdisc_int*3);
1113 /* Send the configured preference as a network byte order value */
1114 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(ifp->int_rdisc_pref);
1116 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr;
1118 u.ad.icmp_cksum = in_cksum((uint16_t *)&u.ad, sizeof (u.ad));
1120 send_rdisc(&u, sizeof (u.ad), ifp, dst, type);
1122 if (ifp->int_state & IS_SUPPRESS_RDISC)
1123 ifp->int_state &= ~IS_FLUSH_RDISC;
1127 /* Advertise as a default router by way of router discovery. */
1128 void
1129 rdisc_adv(boolean_t forceadv)
1131 struct interface *ifp;
1133 if (!forceadv && !should_supply(NULL))
1134 return;
1136 rdisc_timer.tv_sec = now.tv_sec + NEVER;
1138 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
1139 if ((ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE)) ||
1140 (!forceadv && !IS_IFF_ROUTING(ifp->int_if_flags)))
1141 continue;
1143 /* skip interfaces we shouldn't use */
1144 if (IS_IFF_QUIET(ifp->int_if_flags))
1145 continue;
1147 if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */) ||
1148 stopint != 0 || forceadv) {
1149 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP),
1150 (ifp->int_state & IS_BCAST_RDISC) ? 1 : 2);
1151 ifp->int_rdisc_cnt++;
1153 intvl_random(&ifp->int_rdisc_timer,
1154 (ifp->int_rdisc_int*3)/4, ifp->int_rdisc_int);
1155 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS &&
1156 (ifp->int_rdisc_timer.tv_sec >
1157 MAX_INITIAL_ADVERT_INTERVAL)) {
1158 ifp->int_rdisc_timer.tv_sec =
1159 MAX_INITIAL_ADVERT_INTERVAL;
1161 timevaladd(&ifp->int_rdisc_timer, &now);
1163 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer,
1164 > /* cstyle */))
1165 rdisc_timer = ifp->int_rdisc_timer;
1170 /* Solicit for Router Discovery */
1171 void
1172 rdisc_sol(void)
1174 struct interface *ifp;
1175 union ad_u u;
1177 if (should_supply(NULL))
1178 return;
1180 rdisc_timer.tv_sec = now.tv_sec + NEVER;
1182 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
1183 if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) ||
1184 ifp->int_rdisc_cnt >= MAX_SOLICITATIONS)
1185 continue;
1187 /* skip interfaces we shouldn't use */
1188 if (IS_IFF_QUIET(ifp->int_if_flags))
1189 continue;
1191 if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */)) {
1192 (void) memset(&u, 0, sizeof (u.so));
1193 u.so.icmp_type = ICMP_ROUTERSOLICIT;
1194 u.so.icmp_cksum = in_cksum((uint16_t *)&u.so,
1195 sizeof (u.so));
1196 send_rdisc(&u, sizeof (u.so), ifp,
1197 htonl(INADDR_ALLRTRS_GROUP),
1198 ((ifp->int_state&IS_BCAST_RDISC) ? bcast : mcast));
1200 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS)
1201 continue;
1203 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL;
1204 ifp->int_rdisc_timer.tv_usec = 0;
1205 timevaladd(&ifp->int_rdisc_timer, &now);
1208 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer,
1209 > /* cstyle */))
1210 rdisc_timer = ifp->int_rdisc_timer;
1216 * check the IP header of a possible Router Discovery ICMP packet
1217 * Returns 0 if bad
1219 static struct interface *
1220 ck_icmp(const char *act,
1221 in_addr_t from,
1222 struct interface *ifp,
1223 in_addr_t to,
1224 union ad_u *p,
1225 uint_t len)
1227 const char *type;
1230 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) {
1231 type = "advertisement";
1232 if (p->icmp.icmp_code == ICMP_ROUTERADVERT_NOCOMMON)
1233 return (NULL); /* Mobile IP */
1234 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) {
1235 type = "solicitation";
1236 } else {
1237 return (NULL);
1240 if (p->icmp.icmp_code != ICMP_ROUTERADVERT_COMMON) {
1241 trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s",
1242 type, p->icmp.icmp_code, naddr_ntoa(from), naddr_ntoa(to));
1243 return (NULL);
1246 trace_rdisc(act, from, to, ifp, p, len);
1248 if (ifp == NULL)
1249 trace_pkt("unknown interface for router-discovery %s from %s "
1250 "to %s", type, naddr_ntoa(from), naddr_ntoa(to));
1252 return (ifp);
1256 /* Read packets from the router discovery socket */
1257 void
1258 read_d(void)
1260 #define PKTLEN 512
1261 static struct msg_limit bad_asize, bad_len;
1262 struct sockaddr_in from;
1263 int n, cc, hlen;
1264 struct {
1265 union {
1266 struct ip ip;
1267 uint16_t s[PKTLEN/sizeof (uint16_t)];
1268 uint8_t b[PKTLEN/sizeof (uint8_t)];
1269 } pkt;
1270 } buf;
1271 union ad_u *p;
1272 n_long *wp;
1273 struct interface *ifp;
1274 boolean_t needsort = _B_FALSE;
1275 struct msghdr msg;
1276 struct iovec iov;
1277 uint8_t ancillary_data[CONTROL_BUFSIZE];
1279 iov.iov_base = &buf;
1280 iov.iov_len = sizeof (buf);
1281 msg.msg_iov = &iov;
1282 msg.msg_iovlen = 1;
1283 msg.msg_name = &from;
1284 msg.msg_control = &ancillary_data;
1286 for (;;) {
1287 msg.msg_namelen = sizeof (from);
1288 msg.msg_controllen = sizeof (ancillary_data);
1289 cc = recvmsg(rdisc_sock, &msg, 0);
1290 if (cc <= 0) {
1291 if (cc < 0 && errno != EWOULDBLOCK)
1292 LOGERR("recvmsg(rdisc_sock)");
1293 break;
1296 hlen = buf.pkt.ip.ip_hl << 2;
1297 if (cc < hlen + ICMP_MINLEN)
1298 continue;
1299 /* LINTED [alignment will be lw aligned] */
1300 p = (union ad_u *)&buf.pkt.b[hlen];
1301 cc -= hlen;
1304 * If we could tell the interface on which a packet from
1305 * address 0 arrived, we could deal with such solicitations.
1307 ifp = receiving_interface(&msg, _B_FALSE);
1308 ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp,
1309 buf.pkt.ip.ip_dst.s_addr, p, cc);
1310 if (ifp == NULL)
1311 continue;
1313 if (IS_IFF_QUIET(ifp->int_if_flags)) {
1314 trace_misc("discard RDISC packet received over %s, %X",
1315 ifp->int_name, ifp->int_if_flags);
1316 continue;
1319 if (from.sin_addr.s_addr != 0 &&
1320 ifwithaddr(from.sin_addr.s_addr, _B_FALSE, _B_FALSE)) {
1321 trace_pkt(" "
1322 "discard our own Router Discovery message");
1323 continue;
1326 /* The remote address *must* be directly connected. */
1327 if (!remote_address_ok(ifp, from.sin_addr.s_addr)) {
1328 trace_misc("discard rdisc message; source %s not on "
1329 "interface %s", naddr_ntoa(from.sin_addr.s_addr),
1330 ifp->int_name);
1331 continue;
1334 switch (p->icmp.icmp_type) {
1335 case ICMP_ROUTERADVERT:
1336 if (ifp->int_state & IS_NO_ADV_IN)
1337 continue;
1339 if (p->ad.icmp_ad_asize*2*sizeof (wp[0]) <
1340 sizeof (p->ad.icmp_ad_info[0])) {
1341 msglim(&bad_asize, from.sin_addr.s_addr,
1342 "intolerable rdisc address size=%d",
1343 p->ad.icmp_ad_asize);
1344 continue;
1346 if (p->ad.icmp_ad_num == 0) {
1347 trace_pkt(" empty?");
1348 continue;
1350 if (cc < (sizeof (p->ad) -
1351 sizeof (p->ad.icmp_ad_info) +
1352 (p->ad.icmp_ad_num *
1353 sizeof (p->ad.icmp_ad_info[0])))) {
1354 msglim(&bad_len, from.sin_addr.s_addr,
1355 "rdisc length %d does not match ad_num"
1356 " %d", cc, p->ad.icmp_ad_num);
1357 continue;
1360 needsort = _B_TRUE;
1361 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr;
1362 for (n = 0; n < p->ad.icmp_ad_num; n++) {
1363 parse_ad(from.sin_addr.s_addr,
1364 wp[0], wp[1],
1365 ntohs(p->ad.icmp_ad_life), ifp);
1366 wp += p->ad.icmp_ad_asize;
1368 break;
1371 case ICMP_ROUTERSOLICIT:
1372 if (!should_supply(ifp))
1373 continue;
1374 if ((ifp->int_state & IS_NO_ADV_OUT) ||
1375 !IS_IFF_ROUTING(ifp->int_if_flags))
1376 continue;
1377 if (stopint != 0)
1378 continue;
1381 * We should handle messages from address 0,
1382 * but cannot due to kernel limitations.
1385 /* Respond with a point-to-point advertisement */
1386 send_adv(ifp, from.sin_addr.s_addr, 0);
1387 break;
1391 if (needsort)
1392 rdisc_sort();
1395 void
1396 rdisc_dump(void)
1398 struct dr *drp;
1400 for (drp = drs; drp < &drs[max_ads]; drp++)
1401 if (drp->dr_ts != 0)
1402 trace_dr(drp);
1405 void
1406 rdisc_suppress(struct interface *ifp)
1408 if (ifp->int_state & IS_ADV_OUT) {
1409 msglog("%s \"rdisc_adv\" specified, will not "
1410 "suppress rdisc adv", ifp->int_name);
1411 } else {
1412 if (ifp->int_state & IS_SUPPRESS_RDISC)
1413 return;
1414 ifp->int_state |= (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC);
1415 trace_misc("suppress rdisc adv on %s", ifp->int_name);
1416 rdisc_timer.tv_sec = 0;
1420 void
1421 rdisc_restore(struct interface *ifp)
1423 if ((ifp->int_state & IS_SUPPRESS_RDISC) == 0)
1424 return;
1425 ifp->int_state &= ~(IS_SUPPRESS_RDISC|IS_FLUSH_RDISC);
1426 trace_misc("restoring rdisc adv on %s", ifp->int_name);
1427 rdisc_timer.tv_sec = 0;
1430 void
1431 process_d_mib_sock(void)
1434 socklen_t fromlen;
1435 struct sockaddr_un from;
1436 ssize_t len;
1437 int command;
1438 struct dr *drp;
1439 rdisc_info_t rdisc_info;
1440 defr_t def_router;
1441 extern int max_ads;
1442 int num = 0;
1444 fromlen = (socklen_t)sizeof (from);
1445 len = recvfrom(rdisc_mib_sock, &command, sizeof (int), 0,
1446 (struct sockaddr *)&from, &fromlen);
1448 if (len < sizeof (int) || command != RDISC_SNMP_INFO_REQ) {
1449 trace_misc("Bad command on rdisc_mib_sock");
1450 return;
1454 * Count number of good routers
1456 for (drp = drs; drp < &drs[max_ads]; drp++) {
1457 if (drp->dr_ts != 0) {
1458 num++;
1462 rdisc_info.info_type = RDISC_SNMP_INFO_RESPONSE;
1463 rdisc_info.info_version = RDISC_SNMP_INFO_VER;
1464 rdisc_info.info_num_of_routers = num;
1466 (void) sendto(rdisc_mib_sock, &rdisc_info, sizeof (rdisc_info_t), 0,
1467 (struct sockaddr *)&from, fromlen);
1469 for (drp = drs; drp < &drs[max_ads]; drp++) {
1470 if (drp->dr_ts != 0) {
1471 def_router.defr_info_type = RDISC_DEF_ROUTER_INFO;
1472 def_router.defr_version = RDISC_DEF_ROUTER_VER;
1473 def_router.defr_index =
1474 drp->dr_ifp->int_phys->phyi_index;
1475 def_router.defr_life = drp->dr_life;
1476 def_router.defr_addr.s_addr = drp->dr_gate;
1477 def_router.defr_pref = drp->dr_pref;
1478 (void) sendto(rdisc_mib_sock, &def_router,
1479 sizeof (defr_t), 0, (struct sockaddr *)&from,
1480 fromlen);