1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 *
5 * Copyright (c) 1995
6 * The Regents of the University of California. All rights reserved.
7 *
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.
23 *
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.
35 *
36 * $FreeBSD: src/sbin/routed/rdisc.c,v 1.8 2000/08/11 08:24:38 sheldonh Exp $
37 */
38
39 #include "defs.h"
40 #include <netinet/in_systm.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip_icmp.h>
43 #include <fcntl.h>
44 #include <strings.h>
45
46 /*
47 * The size of the control buffer passed to recvmsg() used to receive
48 * ancillary data.
49 */
50 #define CONTROL_BUFSIZE 1024
51
52 /* router advertisement ICMP packet */
53 struct icmp_ad {
54 uint8_t icmp_type; /* type of message */
55 uint8_t icmp_code; /* type sub code */
56 uint16_t icmp_cksum; /* ones complement cksum of struct */
57 uint8_t icmp_ad_num; /* # of following router addresses */
58 uint8_t icmp_ad_asize; /* 2--words in each advertisement */
59 uint16_t icmp_ad_life; /* seconds of validity */
60 struct icmp_ad_info {
61 in_addr_t icmp_ad_addr;
62 uint32_t icmp_ad_pref;
63 } icmp_ad_info[1];
64 };
65
66 /* router solicitation ICMP packet */
67 struct icmp_so {
68 uint8_t icmp_type; /* type of message */
69 uint8_t icmp_code; /* type sub code */
70 uint16_t icmp_cksum; /* ones complement cksum of struct */
71 uint32_t icmp_so_rsvd;
72 };
73
74 union ad_u {
75 struct icmp icmp;
76 struct icmp_ad ad;
77 struct icmp_so so;
78 };
79
80
81 int rdisc_sock = -1; /* router-discovery raw socket */
82 int rdisc_mib_sock = -1; /* AF_UNIX mib info socket */
83 static struct interface *rdisc_sock_interface; /* current rdisc interface */
84
85 struct timeval rdisc_timer;
86 boolean_t rdisc_ok; /* using solicited route */
87
88 #define MAX_ADS 16
89 int max_ads; /* at least one per interface */
90 /* accumulated advertisements */
91 static struct dr *cur_drp;
92 struct dr *drs;
93
94 /*
95 * adjust unsigned preference by interface metric,
96 * without driving it to infinity
97 */
98 #define PREF(p, ifp) ((p) <= (uint32_t)(ifp)->int_metric ? ((p) != 0 ? 1 : 0) \
99 : (p) - ((ifp)->int_metric))
100
101 static void rdisc_sort(void);
102
103 typedef enum { unicast, bcast, mcast } dstaddr_t;
104
105 /* dump an ICMP Router Discovery Advertisement Message */
106 static void
trace_rdisc(const char * act,uint32_t from,uint32_t to,struct interface * ifp,union ad_u * p,uint_t len)107 trace_rdisc(const char *act,
108 uint32_t from,
109 uint32_t to,
110 struct interface *ifp,
111 union ad_u *p,
112 uint_t len)
113 {
114 int i;
115 n_long *wp, *lim;
116
117
118 if (!TRACEPACKETS || ftrace == 0)
119 return;
120
121 lastlog();
122
123 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) {
124 (void) fprintf(ftrace, "%s Router Ad"
125 " from %s to %s via %s life=%d\n",
126 act, naddr_ntoa(from), naddr_ntoa(to),
127 ifp ? ifp->int_name : "?",
128 ntohs(p->ad.icmp_ad_life));
129 if (!TRACECONTENTS)
130 return;
131
132 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr;
133 lim = &wp[(len - sizeof (p->ad)) / sizeof (*wp)];
134 for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) {
135 (void) fprintf(ftrace, "\t%s preference=%ld",
136 naddr_ntoa(wp[0]), (long)ntohl(wp[1]));
137 wp += p->ad.icmp_ad_asize;
138 }
139 (void) fputc('\n', ftrace);
140
141 } else {
142 trace_act("%s Router Solic. from %s to %s via %s rsvd=%#x",
143 act, naddr_ntoa(from), naddr_ntoa(to),
144 ifp ? ifp->int_name : "?",
145 ntohl(p->so.icmp_so_rsvd));
146 }
147 }
148
149 /*
150 * Prepare Router Discovery socket.
151 */
152 static void
get_rdisc_sock(void)153 get_rdisc_sock(void)
154 {
155 int on = 1;
156 unsigned char ttl = 1;
157 struct sockaddr_un laddr;
158 int len;
159
160 if (rdisc_sock < 0) {
161 max_ads = MAX_ADS;
162 drs = rtmalloc(max_ads * sizeof (struct dr), "get_rdisc_sock");
163 (void) memset(drs, 0, max_ads * sizeof (struct dr));
164 rdisc_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
165 if (rdisc_sock < 0)
166 BADERR(_B_TRUE, "rdisc_sock = socket()");
167 fix_sock(rdisc_sock, "rdisc_sock");
168
169 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_RECVIF, &on,
170 sizeof (on)))
171 BADERR(_B_FALSE, "setsockopt(IP_RECVIF)");
172
173 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_TTL,
174 &ttl, sizeof (ttl)) < 0)
175 DBGERR(_B_TRUE,
176 "rdisc_sock setsockopt(IP_MULTICAST_TTL)");
177
178 /*
179 * On Solaris also open an AF_UNIX socket to
180 * pass default router information to mib agent
181 */
182
183 rdisc_mib_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
184 if (rdisc_mib_sock < 0) {
185 BADERR(_B_TRUE, "rdisc_mib_sock = socket()");
186 }
187
188 bzero(&laddr, sizeof (laddr));
189 laddr.sun_family = AF_UNIX;
190
191 (void) strncpy(laddr.sun_path, RDISC_SNMP_SOCKET,
192 sizeof (laddr.sun_path));
193 len = sizeof (struct sockaddr_un);
194
195 (void) unlink(RDISC_SNMP_SOCKET);
196
197 if (bind(rdisc_mib_sock, (struct sockaddr *)&laddr, len) < 0) {
198 BADERR(_B_TRUE, "bind(rdisc_mib_sock)");
199 }
200
201 if (fcntl(rdisc_mib_sock, F_SETFL, O_NONBLOCK) < 0) {
202 BADERR(_B_TRUE, "rdisc_mib_sock fcntl O_NONBLOCK");
203 }
204
205 fix_select();
206 }
207 }
208
209
210 /*
211 * Pick multicast group for router-discovery socket
212 */
213 void
set_rdisc_mg(struct interface * ifp,int on)214 set_rdisc_mg(struct interface *ifp,
215 int on) /* 0=turn it off */
216 {
217 struct ip_mreq m;
218 boolean_t dosupply;
219
220 if (rdisc_sock < 0) {
221 /*
222 * Create the raw socket so that we can hear at least
223 * broadcast router discovery packets.
224 */
225 if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC ||
226 !on)
227 return;
228 get_rdisc_sock();
229 }
230
231 if (!(ifp->int_if_flags & IFF_MULTICAST)) {
232 /* Can't multicast, so no groups could have been joined. */
233 ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS);
234 return;
235 }
236
237 dosupply = should_supply(ifp);
238
239 (void) memset(&m, 0, sizeof (m));
240 m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) &&
241 (ifp->int_dstaddr != 0) ? ifp->int_dstaddr : ifp->int_addr);
242 if (dosupply || (ifp->int_state & IS_NO_ADV_IN) || !on) {
243 /* stop listening to advertisements */
244 if (ifp->int_state & IS_ALL_HOSTS) {
245 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
246 if (setsockopt(rdisc_sock, IPPROTO_IP,
247 IP_DROP_MEMBERSHIP, &m, sizeof (m)) < 0 &&
248 errno != EADDRNOTAVAIL && errno != ENOENT)
249 LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS");
250 ifp->int_state &= ~IS_ALL_HOSTS;
251 }
252
253 } else if (!(ifp->int_state & IS_ALL_HOSTS)) {
254 /* start listening to advertisements */
255 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
256 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
257 &m, sizeof (m)) < 0) {
258 LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS");
259 } else {
260 ifp->int_state |= IS_ALL_HOSTS;
261 }
262 }
263
264 if (!dosupply || (ifp->int_state & IS_NO_ADV_OUT) ||
265 !IS_IFF_ROUTING(ifp->int_if_flags) || !on) {
266 /* stop listening to solicitations */
267 if (ifp->int_state & IS_ALL_ROUTERS) {
268 m.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP);
269 if (setsockopt(rdisc_sock, IPPROTO_IP,
270 IP_DROP_MEMBERSHIP, &m, sizeof (m)) < 0 &&
271 errno != EADDRNOTAVAIL && errno != ENOENT)
272 LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS");
273 ifp->int_state &= ~IS_ALL_ROUTERS;
274 }
275
276 } else if (!(ifp->int_state & IS_ALL_ROUTERS)) {
277 /* start hearing solicitations */
278 m.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP);
279 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
280 &m, sizeof (m)) < 0) {
281 LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS");
282 } else {
283 ifp->int_state |= IS_ALL_ROUTERS;
284 }
285 }
286 }
287
288
289 /*
290 * start or stop supplying routes to other systems.
291 */
292 void
set_supplier(void)293 set_supplier(void)
294 {
295 struct interface *ifp;
296 struct dr *drp;
297 static boolean_t supplystate = _B_FALSE;
298
299 if (supplystate == (fwd_interfaces > 1))
300 return;
301 supplystate = fwd_interfaces > 1;
302
303 trace_act("%d forwarding interfaces present; becoming %ssupplier",
304 fwd_interfaces, supplystate ? "" : "non-");
305
306 if (supplystate) {
307 /* Forget discovered routes. */
308 for (drp = drs; drp < &drs[max_ads]; drp++) {
309 drp->dr_recv_pref = DEF_PREFERENCELEVEL;
310 drp->dr_life = 0;
311 }
312 rdisc_age(0);
313
314 /*
315 * Do not start advertising until we have heard some
316 * RIP routes.
317 */
318 LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME);
319
320 /* get rid of any redirects */
321 del_redirects(0, 0);
322 } else {
323 /*
324 * Flush out all those advertisements we had sent by sending
325 * one with lifetime=0.
326 */
327 rdisc_adv(_B_TRUE);
328 }
329
330 /*
331 * Switch router discovery multicast groups from soliciting
332 * to advertising or back.
333 */
334 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
335 if (ifp->int_state & IS_BROKE)
336 continue;
337 ifp->int_rdisc_cnt = 0;
338 ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec;
339 ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME;
340 set_rdisc_mg(ifp, 1);
341 }
342 }
343
344
345 /*
346 * Age discovered routes and find the best one
347 */
348 void
rdisc_age(in_addr_t bad_gate)349 rdisc_age(in_addr_t bad_gate)
350 {
351 time_t sec;
352 struct dr *drp;
353 struct rt_spare new;
354 struct rt_entry *rt;
355
356 /*
357 * If we are being told about a bad router,
358 * then age the discovered default route, and if there is
359 * no alternative, solicit a replacement.
360 */
361 if (bad_gate != 0) {
362 /*
363 * Look for the bad discovered default route.
364 * Age it and note its interface.
365 */
366 for (drp = drs; drp < &drs[max_ads]; drp++) {
367 if (drp->dr_ts == 0)
368 continue;
369
370 /*
371 * When we find the bad router, age the route
372 * to at most SUPPLY_INTERVAL.
373 * This is contrary to RFC 1256, but defends against
374 * black holes.
375 */
376 if (drp->dr_gate == bad_gate) {
377 sec = (now.tv_sec - drp->dr_life +
378 SUPPLY_INTERVAL);
379 if (drp->dr_ts > sec) {
380 trace_act("age 0.0.0.0 --> %s via %s",
381 naddr_ntoa(drp->dr_gate),
382 drp->dr_ifp->int_name);
383 drp->dr_ts = sec;
384 }
385 break;
386 }
387 }
388 } else if (should_supply(NULL)) {
389 /*
390 * If switching from client to server, get rid of old
391 * default routes.
392 */
393 if (cur_drp != NULL) {
394 rt = rtget(RIP_DEFAULT, 0);
395 /*
396 * If there is a current default router, and the
397 * there is no rt_spare entry, create one
398 * for cur_drp to prevent segmentation fault
399 * at rdisc_sort.
400 */
401 if (rt == NULL) {
402 (void) memset(&new, 0, sizeof (new));
403 new.rts_ifp = cur_drp->dr_ifp;
404 new.rts_gate = cur_drp->dr_gate;
405 new.rts_router = cur_drp->dr_gate;
406 new.rts_metric = HOPCNT_INFINITY-1;
407 new.rts_time = now.tv_sec;
408 new.rts_origin = RO_RDISC;
409 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new);
410 }
411
412 rdisc_sort();
413 }
414 rdisc_adv(_B_FALSE);
415 }
416
417 rdisc_sol();
418 if (cur_drp != NULL) {
419 rt = rtget(RIP_DEFAULT, 0);
420 if (rt == NULL) {
421 (void) memset(&new, 0, sizeof (new));
422 new.rts_ifp = cur_drp->dr_ifp;
423 new.rts_gate = cur_drp->dr_gate;
424 new.rts_router = cur_drp->dr_gate;
425 new.rts_metric = HOPCNT_INFINITY-1;
426 new.rts_time = now.tv_sec;
427 new.rts_origin = RO_RDISC;
428 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new);
429 }
430 }
431 rdisc_sort();
432
433 /*
434 * Delete old redirected routes to keep the kernel table small,
435 * and to prevent black holes. Check that the kernel table
436 * matches the daemon table (i.e. has the default route).
437 * But only if RIP is not running and we are not dealing with
438 * a bad gateway, since otherwise age() will be called.
439 */
440 if (rip_sock < 0 && bad_gate == 0)
441 age(0);
442 }
443
444
445 /*
446 * Zap all routes discovered via an interface that has gone bad
447 * This should only be called when !(ifp->int_state & IS_DUP)
448 * This is called by if_del and if_bad, and the interface pointer
449 * might not be valid after this.
450 */
451 void
if_bad_rdisc(struct interface * ifp)452 if_bad_rdisc(struct interface *ifp)
453 {
454 struct dr *drp;
455
456 for (drp = drs; drp < &drs[max_ads]; drp++) {
457 if (drp->dr_ifp != ifp)
458 continue;
459 (void) memset(drp, 0, sizeof (*drp));
460 }
461
462 /* make a note to re-solicit, turn RIP on or off, etc. */
463 rdisc_timer.tv_sec = 0;
464 }
465
466 /*
467 * Rewire all routes discovered via an interface that has gone bad
468 * This is only called by if_del.
469 */
470 void
if_rewire_rdisc(struct interface * oldifp,struct interface * newifp)471 if_rewire_rdisc(struct interface *oldifp, struct interface *newifp)
472 {
473 struct dr *drp;
474
475 for (drp = drs; drp < &drs[max_ads]; drp++) {
476 if (drp->dr_ifp != oldifp)
477 continue;
478 drp->dr_ifp = newifp;
479 drp->dr_pref += (newifp->int_metric - oldifp->int_metric);
480 drp->dr_flags |= DR_CHANGED;
481 }
482
483 /* make a note to re-solicit, turn RIP on or off, etc. */
484 rdisc_timer.tv_sec = 0;
485 }
486
487 /*
488 * Mark an interface ok for router discovering.
489 * This is called by if_ok and ifinit.
490 */
491 void
if_ok_rdisc(struct interface * ifp)492 if_ok_rdisc(struct interface *ifp)
493 {
494 set_rdisc_mg(ifp, 1);
495
496 ifp->int_rdisc_cnt = 0;
497 ifp->int_rdisc_timer.tv_sec = now.tv_sec +
498 ((ifp->int_state & IS_NO_ADV_OUT) ?
499 MAX_SOLICITATION_DELAY : MIN_WAITTIME);
500 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, > /* cstyle */))
501 rdisc_timer = ifp->int_rdisc_timer;
502 }
503
504 /*
505 * Get rid of a dead discovered router
506 */
507 static void
del_rdisc(struct dr * drp)508 del_rdisc(struct dr *drp)
509 {
510 struct interface *ifp;
511 uint32_t gate;
512 int i;
513 struct rt_entry *rt;
514 struct rt_spare *rts = NULL;
515
516 del_redirects(gate = drp->dr_gate, 0);
517 drp->dr_ts = 0;
518 drp->dr_life = 0;
519
520 rt = rtget(RIP_DEFAULT, 0);
521 if (rt == NULL) {
522 trace_act("could not find default route in table");
523 } else {
524 for (i = 0; i < rt->rt_num_spares; i++) {
525 if ((rt->rt_spares[i].rts_gate == drp->dr_gate) &&
526 (rt->rt_spares[i].rts_origin == RO_RDISC)) {
527 rts = &rt->rt_spares[i];
528 break;
529 }
530 }
531 if (rts != NULL)
532 rts_delete(rt, rts);
533 else
534 trace_act("could not find default route "
535 "through %s in table", naddr_ntoa(drp->dr_gate));
536 }
537
538 /* Count the other discovered routers on the interface. */
539 i = 0;
540 ifp = drp->dr_ifp;
541 for (drp = drs; drp < &drs[max_ads]; drp++) {
542 if (drp->dr_ts != 0 && drp->dr_ifp == ifp)
543 i++;
544 }
545
546 /*
547 * If that was the last good discovered router on the interface,
548 * then solicit a new one.
549 * This is contrary to RFC 1256, but defends against black holes.
550 */
551 if (i != 0) {
552 trace_act("discovered router %s via %s"
553 " is bad--have %d remaining",
554 naddr_ntoa(gate), ifp->int_name, i);
555 } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) {
556 trace_act("last discovered router %s via %s"
557 " is bad--re-solicit",
558 naddr_ntoa(gate), ifp->int_name);
559 ifp->int_rdisc_cnt = 0;
560 ifp->int_rdisc_timer.tv_sec = 0;
561 rdisc_sol();
562 } else {
563 trace_act("last discovered router %s via %s"
564 " is bad--wait to solicit",
565 naddr_ntoa(gate), ifp->int_name);
566 }
567 }
568
569
570 /* Find the best discovered route, and discard stale routers. */
571 static void
rdisc_sort(void)572 rdisc_sort(void)
573 {
574 struct dr *drp, *new_drp;
575 struct rt_entry *rt;
576 struct rt_spare new, *rts;
577 struct interface *ifp;
578 uint_t new_st = 0;
579 uint32_t new_pref = DEF_PREFERENCELEVEL;
580 int first_rdisc_slot = 0;
581 int j;
582 boolean_t spares_avail;
583 void *ptr;
584 size_t ptrsize;
585
586 rt = rtget(RIP_DEFAULT, 0);
587
588 /*
589 * If all the rt_spare entries are taken up with with default routes
590 * learnt from RIP (ie rts_origin = RO_RIP), bail out.
591 * NOTE:
592 * We *always* prefer default routes learned via RIP
593 * (ie RO_RIP) over those learnt via RDISC (ie RO_RDISC).
594 * The rdisc machinery should not modify, replace or
595 * remove any existing default routes with RO_RIP set.
596 */
597 if (rt != NULL) {
598 spares_avail = _B_FALSE;
599 for (j = 0; j < rt->rt_num_spares; j++) {
600 rts = &rt->rt_spares[j];
601 if (rts->rts_gate == 0 || rts->rts_origin != RO_RIP ||
602 rts->rts_ifp == &dummy_ifp) {
603 spares_avail = _B_TRUE;
604 break;
605 }
606 }
607 if (!spares_avail) {
608 ptrsize = (rt->rt_num_spares + SPARE_INC) *
609 sizeof (struct rt_spare);
610 ptr = realloc(rt->rt_spares, ptrsize);
611 if (ptr != NULL) {
612 struct rt_spare *tmprts;
613
614 rt->rt_spares = ptr;
615 rts = &rt->rt_spares[rt->rt_num_spares];
616 (void) memset(rts, 0,
617 (SPARE_INC * sizeof (struct rt_spare)));
618 rt->rt_num_spares += SPARE_INC;
619 for (tmprts = rts, j = SPARE_INC;
620 j != 0; j--, tmprts++)
621 tmprts->rts_metric = HOPCNT_INFINITY;
622 spares_avail = _B_TRUE;
623 } else {
624 return;
625 }
626 }
627 }
628 /* Find the best RDISC advertiser */
629 rt = NULL;
630 new_drp = NULL;
631 for (drp = drs; drp < &drs[max_ads]; drp++) {
632 if (drp->dr_ts == 0)
633 continue;
634 ifp = drp->dr_ifp;
635
636 /* Get rid of expired discovered routers. */
637 if (drp->dr_ts + drp->dr_life <= now.tv_sec) {
638 del_rdisc(drp);
639 continue;
640 }
641
642 LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life);
643
644 /*
645 * Update preference with possibly changed interface
646 * metric.
647 */
648 drp->dr_pref = PREF(drp->dr_recv_pref, ifp);
649
650 /*
651 * Prefer the current route to prevent thrashing.
652 * Prefer shorter lifetimes to speed the detection of
653 * bad routers.
654 * Avoid sick interfaces.
655 */
656 if (new_drp == NULL ||
657 (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) &&
658 (new_pref < drp->dr_pref ||
659 (new_pref == drp->dr_pref && (drp == cur_drp ||
660 (new_drp != cur_drp &&
661 new_drp->dr_life > drp->dr_life))))) ||
662 ((new_st & IS_SICK) &&
663 !(drp->dr_ifp->int_state & IS_SICK))) {
664 new_drp = drp;
665 new_st = drp->dr_ifp->int_state;
666 new_pref = drp->dr_pref;
667 }
668 }
669
670 /*
671 * switch to a better RDISC advertiser
672 */
673 if ((new_drp != cur_drp) || (rt == NULL)) {
674 rt = rtget(RIP_DEFAULT, 0);
675
676 /*
677 * Purge the table of all the default routes that were
678 * learnt via RDISC, while keeping an eye the first available
679 * slot for the spare entry of new_drp
680 */
681 if (rt != NULL) {
682 int i;
683 for (i = 0; i < rt->rt_num_spares; i++) {
684 rts = &rt->rt_spares[i];
685 if ((rts->rts_gate == 0 ||
686 rts->rts_ifp == &dummy_ifp) &&
687 first_rdisc_slot == 0)
688 first_rdisc_slot = i;
689 if (rts->rts_origin == RO_RDISC) {
690 rts_delete(rt, rts);
691 if (first_rdisc_slot == 0) {
692 first_rdisc_slot = i;
693 }
694 }
695 }
696 }
697
698 /* Stop using RDISC routes if they are all bad */
699 if (new_drp == NULL) {
700 trace_act("turn off Router Discovery client");
701 rdisc_ok = _B_FALSE;
702
703 } else {
704 if (cur_drp == NULL) {
705 trace_act("turn on Router Discovery client"
706 " using %s via %s",
707 naddr_ntoa(new_drp->dr_gate),
708 new_drp->dr_ifp->int_name);
709 rdisc_ok = _B_TRUE;
710 }
711
712 /* Prepare a spare entry for the new_drp */
713 (void) memset(&new, 0, sizeof (new));
714 new.rts_ifp = new_drp->dr_ifp;
715 new.rts_gate = new_drp->dr_gate;
716 new.rts_router = new_drp->dr_gate;
717 new.rts_metric = HOPCNT_INFINITY-1;
718 new.rts_time = now.tv_sec;
719 new.rts_origin = RO_RDISC;
720 /*
721 * If there is no existing default route, add it
722 * to rts_spare[0].
723 */
724 if (rt == NULL) {
725 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new);
726 } else {
727
728 /*
729 * Add the spare entry for the new_drp in
730 * the first available slot
731 */
732 trace_act("Switching to "
733 "default router with better "
734 "preference %s via %s ",
735 naddr_ntoa(new_drp->dr_gate),
736 new_drp->dr_ifp->int_name);
737 rt->rt_spares[first_rdisc_slot] = new;
738 rt = NULL; /* redo rt_spares */
739 }
740 }
741
742 /*
743 * Get ready to redo the entire table. The table should
744 * only include :
745 * a. empty rt_spare slots
746 * b. default routes learnt via RIP
747 * c. default route for the latest best RDISC advertiser
748 * d. default routes of other RDISC advertisers whose
749 * dr_pref == best RDISC advertiser->dr_pref
750 */
751 cur_drp = new_drp;
752 }
753
754 /* Redo the entire spare table (without touching RO_RIP entries) */
755 if (rdisc_ok && rt == NULL) {
756 int i;
757 /*
758 * We've either just turned on router discovery,
759 * or switched to a router with better preference.
760 * Find all other default routers whose
761 * pref == cur_drp->dr_pref and add them as spares
762 */
763
764 rt = rtget(RIP_DEFAULT, 0);
765
766 for (drp = drs; drp < &drs[max_ads]; drp++) {
767 boolean_t dr_done = _B_FALSE;
768 int slot = -1;
769
770 if (drp->dr_ts == 0)
771 continue;
772
773 if (drp->dr_pref != cur_drp->dr_pref &&
774 ((drp->dr_flags & DR_CHANGED) == 0))
775 continue;
776
777 /*
778 * Either pref matches cur_drp->dr_pref,
779 * or something has changed in this drp.
780 * In the former case, we may need to add
781 * this to rt_spares. In the latter case,
782 * if the pref has changed, need to take it
783 * out of rt_spares and the kernel.
784 *
785 * First, find an empty slot in rt_spares
786 * in case we have to add this drp to kernel.
787 * Also check if it is already there.
788 */
789 for (i = 0; i < rt->rt_num_spares; i++) {
790 if (rt->rt_spares[i].rts_gate == 0) {
791 if (slot < 0)
792 slot = i;
793 continue;
794 }
795 if ((rt->rt_spares[i].rts_gate ==
796 drp->dr_gate) &&
797 (rt->rt_spares[i].rts_origin ==
798 RO_RDISC)) {
799 /*
800 * a spare entry for this RDISC
801 * advertiser already exists. We need
802 * to check if this entry still belongs
803 * in the table
804 */
805 dr_done = _B_TRUE;
806 break;
807 }
808 }
809
810 drp->dr_flags &= ~DR_CHANGED;
811
812 if (drp->dr_pref != cur_drp->dr_pref) {
813 if (dr_done) {
814 /*
815 * The rt_spare of this RDISC advertiser
816 * needs to be removed as it no longer
817 * belongs in the table because its
818 * dr_pref is different than the latest
819 * RDISC advertiser's->dr_pref
820 */
821 rts_delete(rt, &rt->rt_spares[i]);
822 }
823 continue;
824 }
825
826 if (slot < 0 && !dr_done) {
827 ptrsize = (rt->rt_num_spares + SPARE_INC) *
828 sizeof (struct rt_spare);
829 ptr = realloc(rt->rt_spares, ptrsize);
830 if (ptr != NULL) {
831 struct rt_spare *tmprts;
832
833 rt->rt_spares = ptr;
834 slot = rt->rt_num_spares;
835 rts = &rt->rt_spares[rt->rt_num_spares];
836 (void) memset(rts, 0, (SPARE_INC *
837 sizeof (struct rt_spare)));
838 rt->rt_num_spares += SPARE_INC;
839 for (tmprts = rts, i = SPARE_INC;
840 i != 0; i--, tmprts++)
841 tmprts->rts_metric =
842 HOPCNT_INFINITY;
843 }
844 }
845
846 if (slot >= 0 && (dr_done != _B_TRUE)) {
847 (void) memset(&new, 0, sizeof (new));
848 new.rts_ifp = drp->dr_ifp;
849 new.rts_gate = drp->dr_gate;
850 new.rts_router = drp->dr_gate;
851 new.rts_metric = HOPCNT_INFINITY-1;
852 new.rts_time = now.tv_sec;
853 new.rts_origin = RO_RDISC;
854 rt->rt_spares[slot] = new;
855 trace_act("spare default %s via %s",
856 naddr_ntoa(drp->dr_gate),
857 drp->dr_ifp->int_name);
858 }
859 }
860 }
861
862 /* turn RIP on or off */
863 if (!rdisc_ok || rip_interfaces > 1) {
864 rip_on(0);
865 } else {
866 rip_off();
867 }
868 }
869
870
871 /* Handle a single address in an advertisement */
872 static void
parse_ad(uint32_t from,in_addr_t gate,uint32_t pref,ushort_t life,struct interface * ifp)873 parse_ad(uint32_t from,
874 in_addr_t gate,
875 uint32_t pref, /* signed and in network order */
876 ushort_t life, /* in host byte order */
877 struct interface *ifp)
878 {
879 static struct msg_limit bad_gate;
880 struct dr *drp, *new_drp;
881 void *ptr;
882 size_t ptrsize;
883
884 if (gate == RIP_DEFAULT || !check_dst(gate)) {
885 msglim(&bad_gate, from, "router %s advertising bad gateway %s",
886 naddr_ntoa(from), naddr_ntoa(gate));
887 return;
888 }
889
890 /*
891 * ignore pointers to ourself and routes via unreachable networks
892 */
893 if (ifwithaddr(gate, _B_TRUE, _B_FALSE) != 0) {
894 trace_pkt(" discard Router Discovery Ad pointing at us");
895 return;
896 }
897 if (!on_net(gate, ifp->int_net, ifp->int_mask)) {
898 trace_pkt(" discard Router Discovery Ad"
899 " toward unreachable net");
900 return;
901 }
902 /*
903 * Convert preference to an unsigned value
904 * and later bias it by the metric of the interface.
905 */
906 pref = UNSIGN_PREF(ntohl(pref));
907
908 if (pref == DEF_PREFERENCELEVEL || life < MIN_MAXADVERTISEINTERVAL) {
909 pref = DEF_PREFERENCELEVEL;
910 life = 0;
911 }
912
913 for (new_drp = NULL, drp = drs; drp < &drs[max_ads]; drp++) {
914 /* accept new info for a familiar entry */
915 if ((drp->dr_gate == gate) && (drp->dr_ifp == ifp)) {
916 new_drp = drp;
917 drp->dr_flags |= DR_CHANGED;
918 break;
919 }
920
921 if (life == 0)
922 continue; /* do not worry about dead ads */
923
924 if (drp->dr_ts == 0) {
925 new_drp = drp; /* use unused entry */
926
927 } else if (new_drp == NULL) {
928 /* look for an entry worse than the new one to reuse. */
929 if ((!(ifp->int_state & IS_SICK) &&
930 (drp->dr_ifp->int_state & IS_SICK)) ||
931 (pref > drp->dr_pref &&
932 !((ifp->int_state ^ drp->dr_ifp->int_state) &
933 IS_SICK)))
934 new_drp = drp;
935
936 } else if (new_drp->dr_ts != 0) {
937 /* look for the least valuable entry to reuse */
938 if ((!(new_drp->dr_ifp->int_state & IS_SICK) &&
939 (drp->dr_ifp->int_state & IS_SICK)) ||
940 (new_drp->dr_pref > drp->dr_pref &&
941 !((new_drp->dr_ifp->int_state ^
942 drp->dr_ifp->int_state) & IS_SICK)))
943 new_drp = drp;
944 }
945 }
946
947 /* if all of the current entries are better, add more drs[] */
948 if (new_drp == NULL) {
949 ptrsize = (max_ads + MAX_ADS) * sizeof (struct dr);
950 ptr = realloc(drs, ptrsize);
951 if (ptr == NULL)
952 return;
953 drs = ptr;
954 (void) memset(&drs[max_ads], 0, MAX_ADS * sizeof (struct dr));
955 new_drp = &drs[max_ads];
956 max_ads += MAX_ADS;
957 }
958
959 /*
960 * Pointer copy is safe here because if_del
961 * calls if_bad_rdisc first, so a non-NULL df_ifp
962 * is always a valid pointer.
963 */
964 new_drp->dr_ifp = ifp;
965 new_drp->dr_gate = gate;
966 new_drp->dr_ts = now.tv_sec;
967 new_drp->dr_life = life;
968 new_drp->dr_recv_pref = pref;
969 /* bias functional preference by metric of the interface */
970 new_drp->dr_pref = PREF(pref, ifp);
971
972 /* after hearing a good advertisement, stop asking */
973 if (!(ifp->int_state & IS_SICK))
974 ifp->int_rdisc_cnt = MAX_SOLICITATIONS;
975 }
976
977
978 /*
979 * Compute the IP checksum. This assumes the packet is less than 32K long.
980 */
981 static uint16_t
in_cksum(uint16_t * p,uint_t len)982 in_cksum(uint16_t *p, uint_t len)
983 {
984 uint32_t sum = 0;
985 int nwords = len >> 1;
986
987 while (nwords-- != 0)
988 sum += *p++;
989
990 if (len & 1)
991 sum += *(uchar_t *)p;
992
993 /* end-around-carry */
994 sum = (sum >> 16) + (sum & 0xffff);
995 sum += (sum >> 16);
996 return (~sum);
997 }
998
999
1000 /* Send a router discovery advertisement or solicitation ICMP packet. */
1001 static void
send_rdisc(union ad_u * p,uint_t p_size,struct interface * ifp,in_addr_t dst,dstaddr_t type)1002 send_rdisc(union ad_u *p,
1003 uint_t p_size,
1004 struct interface *ifp,
1005 in_addr_t dst, /* 0 or unicast destination */
1006 dstaddr_t type)
1007 {
1008 struct sockaddr_in sin;
1009 int flags = 0;
1010 const char *msg;
1011 int ifindex = 0;
1012 struct in_addr addr;
1013
1014 /*
1015 * Don't send Rdisc packets on duplicate interfaces, we
1016 * don't want to generate duplicate packets.
1017 */
1018 if (ifp->int_state & IS_DUP)
1019 return;
1020
1021 (void) memset(&sin, 0, sizeof (sin));
1022 sin.sin_addr.s_addr = dst;
1023 sin.sin_family = AF_INET;
1024
1025 switch (type) {
1026 case unicast: /* unicast */
1027 default:
1028 flags = MSG_DONTROUTE;
1029 msg = "Send";
1030 break;
1031
1032 case bcast: /* broadcast */
1033 if (ifp->int_if_flags & IFF_POINTOPOINT) {
1034 msg = "Send pt-to-pt";
1035 if (ifp->int_dstaddr == 0)
1036 sin.sin_addr.s_addr = htonl(INADDR_BROADCAST);
1037 else
1038 sin.sin_addr.s_addr = ifp->int_dstaddr;
1039 } else {
1040 msg = "Send broadcast";
1041 sin.sin_addr.s_addr = ifp->int_brdaddr;
1042 }
1043 break;
1044
1045 case mcast: /* multicast */
1046 msg = "Send multicast";
1047 break;
1048 }
1049
1050 if (rdisc_sock < 0)
1051 get_rdisc_sock();
1052
1053 /* select the right interface. */
1054 ifindex = (type != mcast && ifp->int_phys != NULL) ?
1055 ifp->int_phys->phyi_index : 0;
1056
1057 if (rdisc_sock_interface != ifp) {
1058 /*
1059 * For multicast, we have to choose the source
1060 * address. This is either the local address
1061 * (non-point-to-point) or the remote address.
1062 */
1063 addr.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ?
1064 ifp->int_dstaddr : ifp->int_addr;
1065 if (type == mcast &&
1066 setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_IF, &addr,
1067 sizeof (addr)) == -1) {
1068 LOGERR("setsockopt(rdisc_sock, IP_MULTICAST_IF)");
1069 return;
1070 }
1071 rdisc_sock_interface = ifp;
1072 }
1073
1074 trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, p, p_size);
1075
1076 if (0 > sendtoif(rdisc_sock, p, p_size, flags, &sin, ifindex)) {
1077 if (!(ifp->int_state & IS_BROKE))
1078 writelog(LOG_WARNING, "sendto(%s%s%s): %s",
1079 ifp->int_name, ", ",
1080 inet_ntoa(sin.sin_addr),
1081 rip_strerror(errno));
1082 if (ifp != NULL)
1083 if_sick(ifp, _B_FALSE);
1084 }
1085 }
1086
1087
1088 /* Send an advertisement */
1089 static void
send_adv(struct interface * ifp,in_addr_t dst,dstaddr_t type)1090 send_adv(struct interface *ifp,
1091 in_addr_t dst,
1092 dstaddr_t type)
1093 {
1094 union ad_u u;
1095
1096 if ((ifp->int_state & (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC)) ==
1097 IS_SUPPRESS_RDISC)
1098 return;
1099
1100 (void) memset(&u, 0, sizeof (u.ad));
1101
1102 u.ad.icmp_type = ICMP_ROUTERADVERT;
1103 u.ad.icmp_code = ICMP_ROUTERADVERT_COMMON;
1104 u.ad.icmp_ad_num = 1;
1105 u.ad.icmp_ad_asize = sizeof (u.ad.icmp_ad_info[0])/4;
1106
1107 u.ad.icmp_ad_life = (stopint || !should_supply(ifp) ||
1108 (ifp->int_state & IS_SUPPRESS_RDISC)) ? 0 :
1109 htons(ifp->int_rdisc_int*3);
1110
1111 /* Send the configured preference as a network byte order value */
1112 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(ifp->int_rdisc_pref);
1113
1114 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr;
1115
1116 u.ad.icmp_cksum = in_cksum((uint16_t *)&u.ad, sizeof (u.ad));
1117
1118 send_rdisc(&u, sizeof (u.ad), ifp, dst, type);
1119
1120 if (ifp->int_state & IS_SUPPRESS_RDISC)
1121 ifp->int_state &= ~IS_FLUSH_RDISC;
1122 }
1123
1124
1125 /* Advertise as a default router by way of router discovery. */
1126 void
rdisc_adv(boolean_t forceadv)1127 rdisc_adv(boolean_t forceadv)
1128 {
1129 struct interface *ifp;
1130
1131 if (!forceadv && !should_supply(NULL))
1132 return;
1133
1134 rdisc_timer.tv_sec = now.tv_sec + NEVER;
1135
1136 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
1137 if ((ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE)) ||
1138 (!forceadv && !IS_IFF_ROUTING(ifp->int_if_flags)))
1139 continue;
1140
1141 /* skip interfaces we shouldn't use */
1142 if (IS_IFF_QUIET(ifp->int_if_flags))
1143 continue;
1144
1145 if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */) ||
1146 stopint != 0 || forceadv) {
1147 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP),
1148 (ifp->int_state & IS_BCAST_RDISC) ? 1 : 2);
1149 ifp->int_rdisc_cnt++;
1150
1151 intvl_random(&ifp->int_rdisc_timer,
1152 (ifp->int_rdisc_int*3)/4, ifp->int_rdisc_int);
1153 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS &&
1154 (ifp->int_rdisc_timer.tv_sec >
1155 MAX_INITIAL_ADVERT_INTERVAL)) {
1156 ifp->int_rdisc_timer.tv_sec =
1157 MAX_INITIAL_ADVERT_INTERVAL;
1158 }
1159 timevaladd(&ifp->int_rdisc_timer, &now);
1160 }
1161 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer,
1162 > /* cstyle */))
1163 rdisc_timer = ifp->int_rdisc_timer;
1164 }
1165 }
1166
1167
1168 /* Solicit for Router Discovery */
1169 void
rdisc_sol(void)1170 rdisc_sol(void)
1171 {
1172 struct interface *ifp;
1173 union ad_u u;
1174
1175 if (should_supply(NULL))
1176 return;
1177
1178 rdisc_timer.tv_sec = now.tv_sec + NEVER;
1179
1180 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
1181 if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) ||
1182 ifp->int_rdisc_cnt >= MAX_SOLICITATIONS)
1183 continue;
1184
1185 /* skip interfaces we shouldn't use */
1186 if (IS_IFF_QUIET(ifp->int_if_flags))
1187 continue;
1188
1189 if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */)) {
1190 (void) memset(&u, 0, sizeof (u.so));
1191 u.so.icmp_type = ICMP_ROUTERSOLICIT;
1192 u.so.icmp_cksum = in_cksum((uint16_t *)&u.so,
1193 sizeof (u.so));
1194 send_rdisc(&u, sizeof (u.so), ifp,
1195 htonl(INADDR_ALLRTRS_GROUP),
1196 ((ifp->int_state&IS_BCAST_RDISC) ? bcast : mcast));
1197
1198 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS)
1199 continue;
1200
1201 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL;
1202 ifp->int_rdisc_timer.tv_usec = 0;
1203 timevaladd(&ifp->int_rdisc_timer, &now);
1204 }
1205
1206 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer,
1207 > /* cstyle */))
1208 rdisc_timer = ifp->int_rdisc_timer;
1209 }
1210 }
1211
1212
1213 /*
1214 * check the IP header of a possible Router Discovery ICMP packet
1215 * Returns 0 if bad
1216 */
1217 static struct interface *
ck_icmp(const char * act,in_addr_t from,struct interface * ifp,in_addr_t to,union ad_u * p,uint_t len)1218 ck_icmp(const char *act,
1219 in_addr_t from,
1220 struct interface *ifp,
1221 in_addr_t to,
1222 union ad_u *p,
1223 uint_t len)
1224 {
1225 const char *type;
1226
1227
1228 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) {
1229 type = "advertisement";
1230 if (p->icmp.icmp_code == ICMP_ROUTERADVERT_NOCOMMON)
1231 return (NULL); /* Mobile IP */
1232 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) {
1233 type = "solicitation";
1234 } else {
1235 return (NULL);
1236 }
1237
1238 if (p->icmp.icmp_code != ICMP_ROUTERADVERT_COMMON) {
1239 trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s",
1240 type, p->icmp.icmp_code, naddr_ntoa(from), naddr_ntoa(to));
1241 return (NULL);
1242 }
1243
1244 trace_rdisc(act, from, to, ifp, p, len);
1245
1246 if (ifp == NULL)
1247 trace_pkt("unknown interface for router-discovery %s from %s "
1248 "to %s", type, naddr_ntoa(from), naddr_ntoa(to));
1249
1250 return (ifp);
1251 }
1252
1253
1254 /* Read packets from the router discovery socket */
1255 void
read_d(void)1256 read_d(void)
1257 {
1258 #define PKTLEN 512
1259 static struct msg_limit bad_asize, bad_len;
1260 struct sockaddr_in from;
1261 int n, cc, hlen;
1262 struct {
1263 union {
1264 struct ip ip;
1265 uint16_t s[PKTLEN/sizeof (uint16_t)];
1266 uint8_t b[PKTLEN/sizeof (uint8_t)];
1267 } pkt;
1268 } buf;
1269 union ad_u *p;
1270 n_long *wp;
1271 struct interface *ifp;
1272 boolean_t needsort = _B_FALSE;
1273 struct msghdr msg;
1274 struct iovec iov;
1275 uint8_t ancillary_data[CONTROL_BUFSIZE];
1276
1277 iov.iov_base = &buf;
1278 iov.iov_len = sizeof (buf);
1279 msg.msg_iov = &iov;
1280 msg.msg_iovlen = 1;
1281 msg.msg_name = &from;
1282 msg.msg_control = &ancillary_data;
1283
1284 for (;;) {
1285 msg.msg_namelen = sizeof (from);
1286 msg.msg_controllen = sizeof (ancillary_data);
1287 cc = recvmsg(rdisc_sock, &msg, 0);
1288 if (cc <= 0) {
1289 if (cc < 0 && errno != EWOULDBLOCK)
1290 LOGERR("recvmsg(rdisc_sock)");
1291 break;
1292 }
1293
1294 hlen = buf.pkt.ip.ip_hl << 2;
1295 if (cc < hlen + ICMP_MINLEN)
1296 continue;
1297 /* LINTED [alignment will be lw aligned] */
1298 p = (union ad_u *)&buf.pkt.b[hlen];
1299 cc -= hlen;
1300
1301 /*
1302 * If we could tell the interface on which a packet from
1303 * address 0 arrived, we could deal with such solicitations.
1304 */
1305 ifp = receiving_interface(&msg, _B_FALSE);
1306 ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp,
1307 buf.pkt.ip.ip_dst.s_addr, p, cc);
1308 if (ifp == NULL)
1309 continue;
1310
1311 if (IS_IFF_QUIET(ifp->int_if_flags)) {
1312 trace_misc("discard RDISC packet received over %s, %X",
1313 ifp->int_name, ifp->int_if_flags);
1314 continue;
1315 }
1316
1317 if (from.sin_addr.s_addr != 0 &&
1318 ifwithaddr(from.sin_addr.s_addr, _B_FALSE, _B_FALSE)) {
1319 trace_pkt(" "
1320 "discard our own Router Discovery message");
1321 continue;
1322 }
1323
1324 /* The remote address *must* be directly connected. */
1325 if (!remote_address_ok(ifp, from.sin_addr.s_addr)) {
1326 trace_misc("discard rdisc message; source %s not on "
1327 "interface %s", naddr_ntoa(from.sin_addr.s_addr),
1328 ifp->int_name);
1329 continue;
1330 }
1331
1332 switch (p->icmp.icmp_type) {
1333 case ICMP_ROUTERADVERT:
1334 if (ifp->int_state & IS_NO_ADV_IN)
1335 continue;
1336
1337 if (p->ad.icmp_ad_asize*2*sizeof (wp[0]) <
1338 sizeof (p->ad.icmp_ad_info[0])) {
1339 msglim(&bad_asize, from.sin_addr.s_addr,
1340 "intolerable rdisc address size=%d",
1341 p->ad.icmp_ad_asize);
1342 continue;
1343 }
1344 if (p->ad.icmp_ad_num == 0) {
1345 trace_pkt(" empty?");
1346 continue;
1347 }
1348 if (cc < (sizeof (p->ad) -
1349 sizeof (p->ad.icmp_ad_info) +
1350 (p->ad.icmp_ad_num *
1351 sizeof (p->ad.icmp_ad_info[0])))) {
1352 msglim(&bad_len, from.sin_addr.s_addr,
1353 "rdisc length %d does not match ad_num"
1354 " %d", cc, p->ad.icmp_ad_num);
1355 continue;
1356 }
1357
1358 needsort = _B_TRUE;
1359 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr;
1360 for (n = 0; n < p->ad.icmp_ad_num; n++) {
1361 parse_ad(from.sin_addr.s_addr,
1362 wp[0], wp[1],
1363 ntohs(p->ad.icmp_ad_life), ifp);
1364 wp += p->ad.icmp_ad_asize;
1365 }
1366 break;
1367
1368
1369 case ICMP_ROUTERSOLICIT:
1370 if (!should_supply(ifp))
1371 continue;
1372 if ((ifp->int_state & IS_NO_ADV_OUT) ||
1373 !IS_IFF_ROUTING(ifp->int_if_flags))
1374 continue;
1375 if (stopint != 0)
1376 continue;
1377
1378 /*
1379 * We should handle messages from address 0,
1380 * but cannot due to kernel limitations.
1381 */
1382
1383 /* Respond with a point-to-point advertisement */
1384 send_adv(ifp, from.sin_addr.s_addr, 0);
1385 break;
1386 }
1387 }
1388
1389 if (needsort)
1390 rdisc_sort();
1391 }
1392
1393 void
rdisc_dump(void)1394 rdisc_dump(void)
1395 {
1396 struct dr *drp;
1397
1398 for (drp = drs; drp < &drs[max_ads]; drp++)
1399 if (drp->dr_ts != 0)
1400 trace_dr(drp);
1401 }
1402
1403 void
rdisc_suppress(struct interface * ifp)1404 rdisc_suppress(struct interface *ifp)
1405 {
1406 if (ifp->int_state & IS_ADV_OUT) {
1407 msglog("%s \"rdisc_adv\" specified, will not "
1408 "suppress rdisc adv", ifp->int_name);
1409 } else {
1410 if (ifp->int_state & IS_SUPPRESS_RDISC)
1411 return;
1412 ifp->int_state |= (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC);
1413 trace_misc("suppress rdisc adv on %s", ifp->int_name);
1414 rdisc_timer.tv_sec = 0;
1415 }
1416 }
1417
1418 void
rdisc_restore(struct interface * ifp)1419 rdisc_restore(struct interface *ifp)
1420 {
1421 if ((ifp->int_state & IS_SUPPRESS_RDISC) == 0)
1422 return;
1423 ifp->int_state &= ~(IS_SUPPRESS_RDISC|IS_FLUSH_RDISC);
1424 trace_misc("restoring rdisc adv on %s", ifp->int_name);
1425 rdisc_timer.tv_sec = 0;
1426 }
1427
1428 void
process_d_mib_sock(void)1429 process_d_mib_sock(void)
1430 {
1431
1432 socklen_t fromlen;
1433 struct sockaddr_un from;
1434 ssize_t len;
1435 int command;
1436 struct dr *drp;
1437 rdisc_info_t rdisc_info;
1438 defr_t def_router;
1439 extern int max_ads;
1440 int num = 0;
1441
1442 fromlen = (socklen_t)sizeof (from);
1443 len = recvfrom(rdisc_mib_sock, &command, sizeof (int), 0,
1444 (struct sockaddr *)&from, &fromlen);
1445
1446 if (len < sizeof (int) || command != RDISC_SNMP_INFO_REQ) {
1447 trace_misc("Bad command on rdisc_mib_sock");
1448 return;
1449 }
1450
1451 /*
1452 * Count number of good routers
1453 */
1454 for (drp = drs; drp < &drs[max_ads]; drp++) {
1455 if (drp->dr_ts != 0) {
1456 num++;
1457 }
1458 }
1459
1460 rdisc_info.info_type = RDISC_SNMP_INFO_RESPONSE;
1461 rdisc_info.info_version = RDISC_SNMP_INFO_VER;
1462 rdisc_info.info_num_of_routers = num;
1463
1464 (void) sendto(rdisc_mib_sock, &rdisc_info, sizeof (rdisc_info_t), 0,
1465 (struct sockaddr *)&from, fromlen);
1466
1467 for (drp = drs; drp < &drs[max_ads]; drp++) {
1468 if (drp->dr_ts != 0) {
1469 def_router.defr_info_type = RDISC_DEF_ROUTER_INFO;
1470 def_router.defr_version = RDISC_DEF_ROUTER_VER;
1471 def_router.defr_index =
1472 drp->dr_ifp->int_phys->phyi_index;
1473 def_router.defr_life = drp->dr_life;
1474 def_router.defr_addr.s_addr = drp->dr_gate;
1475 def_router.defr_pref = drp->dr_pref;
1476 (void) sendto(rdisc_mib_sock, &def_router,
1477 sizeof (defr_t), 0, (struct sockaddr *)&from,
1478 fromlen);
1479 }
1480 }
1481 }
1482