rdisc.c revision 146838
1/*
2 * Copyright (c) 1995
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sbin/routed/rdisc.c 146838 2005-05-31 20:28:49Z stefanf $
30 */
31
32#include "defs.h"
33#include <netinet/in_systm.h>
34#include <netinet/ip.h>
35#include <netinet/ip_icmp.h>
36
37#ifdef __NetBSD__
38__RCSID("$NetBSD$");
39#elif defined(__FreeBSD__)
40__RCSID("$FreeBSD: head/sbin/routed/rdisc.c 146838 2005-05-31 20:28:49Z stefanf $");
41#else
42__RCSID("$Revision: 2.27 $");
43#ident "$Revision: 2.27 $"
44#endif
45
46/* router advertisement ICMP packet */
47struct icmp_ad {
48	u_int8_t    icmp_type;		/* type of message */
49	u_int8_t    icmp_code;		/* type sub code */
50	u_int16_t   icmp_cksum;		/* ones complement cksum of struct */
51	u_int8_t    icmp_ad_num;	/* # of following router addresses */
52	u_int8_t    icmp_ad_asize;	/* 2--words in each advertisement */
53	u_int16_t   icmp_ad_life;	/* seconds of validity */
54	struct icmp_ad_info {
55	    n_long  icmp_ad_addr;
56	    n_long  icmp_ad_pref;
57	} icmp_ad_info[1];
58};
59
60/* router solicitation ICMP packet */
61struct icmp_so {
62	u_int8_t    icmp_type;		/* type of message */
63	u_int8_t    icmp_code;		/* type sub code */
64	u_int16_t   icmp_cksum;		/* ones complement cksum of struct */
65	n_long	    icmp_so_rsvd;
66};
67
68union ad_u {
69	struct icmp icmp;
70	struct icmp_ad ad;
71	struct icmp_so so;
72};
73
74
75int	rdisc_sock = -1;		/* router-discovery raw socket */
76struct interface *rdisc_sock_mcast;	/* current multicast interface */
77
78struct timeval rdisc_timer;
79int rdisc_ok;				/* using solicited route */
80
81
82#define MAX_ADS 16			/* at least one per interface */
83struct dr {				/* accumulated advertisements */
84    struct interface *dr_ifp;
85    naddr   dr_gate;			/* gateway */
86    time_t  dr_ts;			/* when received */
87    time_t  dr_life;			/* lifetime in host byte order */
88    n_long  dr_recv_pref;		/* received but biased preference */
89    n_long  dr_pref;			/* preference adjusted by metric */
90} *cur_drp, drs[MAX_ADS];
91
92/* convert between signed, balanced around zero,
93 * and unsigned zero-based preferences */
94#define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel)
95#define UNSIGN_PREF(p) SIGN_PREF(p)
96/* adjust unsigned preference by interface metric,
97 * without driving it to infinity */
98#define PREF(p, ifp) ((int)(p) <= ((ifp)->int_metric+(ifp)->int_adj_outmetric)\
99		      ? ((p) != 0 ? 1 : 0)				    \
100		      : (p) - ((ifp)->int_metric+(ifp)->int_adj_outmetric))
101
102static void rdisc_sort(void);
103
104
105/* dump an ICMP Router Discovery Advertisement Message
106 */
107static void
108trace_rdisc(const char	*act,
109	    naddr	from,
110	    naddr	to,
111	    struct interface *ifp,
112	    union ad_u	*p,
113	    u_int	len)
114{
115	int i;
116	n_long *wp, *lim;
117
118
119	if (!TRACEPACKETS || ftrace == 0)
120		return;
121
122	lastlog();
123
124	if (p->icmp.icmp_type == ICMP_ROUTERADVERT) {
125		(void)fprintf(ftrace, "%s Router Ad"
126			      " from %s to %s via %s life=%d\n",
127			      act, naddr_ntoa(from), naddr_ntoa(to),
128			      ifp ? ifp->int_name : "?",
129			      ntohs(p->ad.icmp_ad_life));
130		if (!TRACECONTENTS)
131			return;
132
133		wp = &p->ad.icmp_ad_info[0].icmp_ad_addr;
134		lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)];
135		for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) {
136			(void)fprintf(ftrace, "\t%s preference=%d",
137				      naddr_ntoa(wp[0]), (int)ntohl(wp[1]));
138			wp += p->ad.icmp_ad_asize;
139		}
140		(void)fputc('\n',ftrace);
141
142	} else {
143		trace_act("%s Router Solic. from %s to %s via %s value=%#x",
144			  act, naddr_ntoa(from), naddr_ntoa(to),
145			  ifp ? ifp->int_name : "?",
146			  (int)ntohl(p->so.icmp_so_rsvd));
147	}
148}
149
150/* prepare Router Discovery socket.
151 */
152static void
153get_rdisc_sock(void)
154{
155	if (rdisc_sock < 0) {
156		rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
157		if (rdisc_sock < 0)
158			BADERR(1,"rdisc_sock = socket()");
159		fix_sock(rdisc_sock,"rdisc_sock");
160		fix_select();
161	}
162}
163
164
165/* Pick multicast group for router-discovery socket
166 */
167void
168set_rdisc_mg(struct interface *ifp,
169	     int on)			/* 0=turn it off */
170{
171	struct ip_mreq m;
172
173	if (rdisc_sock < 0) {
174		/* Create the raw socket so that we can hear at least
175		 * broadcast router discovery packets.
176		 */
177		if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC
178		    || !on)
179			return;
180		get_rdisc_sock();
181	}
182
183	if (!(ifp->int_if_flags & IFF_MULTICAST)) {
184		ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS);
185		return;
186	}
187
188#ifdef MCAST_PPP_BUG
189	if (ifp->int_if_flags & IFF_POINTOPOINT)
190		return;
191#endif
192	memset(&m, 0, sizeof(m));
193#ifdef MCAST_IFINDEX
194	m.imr_interface.s_addr = htonl(ifp->int_index);
195#else
196	m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
197				  ? ifp->int_dstaddr
198				  : ifp->int_addr);
199#endif
200	if (supplier
201	    || (ifp->int_state & IS_NO_ADV_IN)
202	    || !on) {
203		/* stop listening to advertisements
204		 */
205		if (ifp->int_state & IS_ALL_HOSTS) {
206			m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
207			if (setsockopt(rdisc_sock, IPPROTO_IP,
208				       IP_DROP_MEMBERSHIP,
209				       &m, sizeof(m)) < 0)
210				LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS");
211			ifp->int_state &= ~IS_ALL_HOSTS;
212		}
213
214	} else if (!(ifp->int_state & IS_ALL_HOSTS)) {
215		/* start listening to advertisements
216		 */
217		m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
218		if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
219			       &m, sizeof(m)) < 0) {
220			LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS");
221		} else {
222			ifp->int_state |= IS_ALL_HOSTS;
223		}
224	}
225
226	if (!supplier
227	    || (ifp->int_state & IS_NO_ADV_OUT)
228	    || !on) {
229		/* stop listening to solicitations
230		 */
231		if (ifp->int_state & IS_ALL_ROUTERS) {
232			m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP);
233			if (setsockopt(rdisc_sock, IPPROTO_IP,
234				       IP_DROP_MEMBERSHIP,
235				       &m, sizeof(m)) < 0)
236				LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS");
237			ifp->int_state &= ~IS_ALL_ROUTERS;
238		}
239
240	} else if (!(ifp->int_state & IS_ALL_ROUTERS)) {
241		/* start hearing solicitations
242		 */
243		m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP);
244		if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
245			       &m, sizeof(m)) < 0) {
246			LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS");
247		} else {
248			ifp->int_state |= IS_ALL_ROUTERS;
249		}
250	}
251}
252
253
254/* start supplying routes
255 */
256void
257set_supplier(void)
258{
259	struct interface *ifp;
260	struct dr *drp;
261
262	if (supplier_set)
263		return;
264
265	trace_act("start supplying routes");
266
267	/* Forget discovered routes.
268	 */
269	for (drp = drs; drp < &drs[MAX_ADS]; drp++) {
270		drp->dr_recv_pref = 0;
271		drp->dr_life = 0;
272	}
273	rdisc_age(0);
274
275	supplier_set = 1;
276	supplier = 1;
277
278	/* Do not start advertising until we have heard some RIP routes */
279	LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME);
280
281	/* Switch router discovery multicast groups from soliciting
282	 * to advertising.
283	 */
284	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
285		if (ifp->int_state & IS_BROKE)
286			continue;
287		ifp->int_rdisc_cnt = 0;
288		ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec;
289		ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME;
290		set_rdisc_mg(ifp, 1);
291	}
292
293	/* get rid of any redirects */
294	del_redirects(0,0);
295}
296
297
298/* age discovered routes and find the best one
299 */
300void
301rdisc_age(naddr bad_gate)
302{
303	time_t sec;
304	struct dr *drp;
305
306
307	/* If only advertising, then do only that. */
308	if (supplier) {
309		/* If switching from client to server, get rid of old
310		 * default routes.
311		 */
312		if (cur_drp != 0)
313			rdisc_sort();
314		rdisc_adv();
315		return;
316	}
317
318	/* If we are being told about a bad router,
319	 * then age the discovered default route, and if there is
320	 * no alternative, solicit a replacement.
321	 */
322	if (bad_gate != 0) {
323		/* Look for the bad discovered default route.
324		 * Age it and note its interface.
325		 */
326		for (drp = drs; drp < &drs[MAX_ADS]; drp++) {
327			if (drp->dr_ts == 0)
328				continue;
329
330			/* When we find the bad router, then age the route
331			 * to at most SUPPLY_INTERVAL.
332			 * This is contrary to RFC 1256, but defends against
333			 * black holes.
334			 */
335			if (drp->dr_gate == bad_gate) {
336				sec = (now.tv_sec - drp->dr_life
337				       + SUPPLY_INTERVAL);
338				if (drp->dr_ts > sec) {
339					trace_act("age 0.0.0.0 --> %s via %s",
340						  naddr_ntoa(drp->dr_gate),
341						  drp->dr_ifp->int_name);
342					drp->dr_ts = sec;
343				}
344				break;
345			}
346		}
347	}
348
349	rdisc_sol();
350	rdisc_sort();
351
352	/* Delete old redirected routes to keep the kernel table small,
353	 * and to prevent black holes.  Check that the kernel table
354	 * matches the daemon table (i.e. has the default route).
355	 * But only if RIP is not running and we are not dealing with
356	 * a bad gateway, since otherwise age() will be called.
357	 */
358	if (rip_sock < 0 && bad_gate == 0)
359		age(0);
360}
361
362
363/* Zap all routes discovered via an interface that has gone bad
364 *	This should only be called when !(ifp->int_state & IS_ALIAS)
365 */
366void
367if_bad_rdisc(struct interface *ifp)
368{
369	struct dr *drp;
370
371	for (drp = drs; drp < &drs[MAX_ADS]; drp++) {
372		if (drp->dr_ifp != ifp)
373			continue;
374		drp->dr_recv_pref = 0;
375		drp->dr_ts = 0;
376		drp->dr_life = 0;
377	}
378
379	/* make a note to re-solicit, turn RIP on or off, etc. */
380	rdisc_timer.tv_sec = 0;
381}
382
383
384/* mark an interface ok for router discovering.
385 */
386void
387if_ok_rdisc(struct interface *ifp)
388{
389	set_rdisc_mg(ifp, 1);
390
391	ifp->int_rdisc_cnt = 0;
392	ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier
393						    ? MIN_WAITTIME
394						    : MAX_SOLICITATION_DELAY);
395	if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >))
396		rdisc_timer = ifp->int_rdisc_timer;
397}
398
399
400/* get rid of a dead discovered router
401 */
402static void
403del_rdisc(struct dr *drp)
404{
405	struct interface *ifp;
406	naddr gate;
407	int i;
408
409
410	del_redirects(gate = drp->dr_gate, 0);
411	drp->dr_ts = 0;
412	drp->dr_life = 0;
413
414
415	/* Count the other discovered routes on the interface.
416	 */
417	i = 0;
418	ifp = drp->dr_ifp;
419	for (drp = drs; drp < &drs[MAX_ADS]; drp++) {
420		if (drp->dr_ts != 0
421		    && drp->dr_ifp == ifp)
422			i++;
423	}
424
425	/* If that was the last good discovered router on the interface,
426	 * then solicit a new one.
427	 * This is contrary to RFC 1256, but defends against black holes.
428	 */
429	if (i != 0) {
430		trace_act("discovered router %s via %s"
431			  " is bad--have %d remaining",
432			  naddr_ntoa(gate), ifp->int_name, i);
433	} else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) {
434		trace_act("last discovered router %s via %s"
435			  " is bad--re-solicit",
436			  naddr_ntoa(gate), ifp->int_name);
437		ifp->int_rdisc_cnt = 0;
438		ifp->int_rdisc_timer.tv_sec = 0;
439		rdisc_sol();
440	} else {
441		trace_act("last discovered router %s via %s"
442			  " is bad--wait to solicit",
443			  naddr_ntoa(gate), ifp->int_name);
444	}
445}
446
447
448/* Find the best discovered route,
449 * and discard stale routers.
450 */
451static void
452rdisc_sort(void)
453{
454	struct dr *drp, *new_drp;
455	struct rt_entry *rt;
456	struct rt_spare new;
457	struct interface *ifp;
458	u_int new_st = 0;
459	n_long new_pref = 0;
460
461
462	/* Find the best discovered route.
463	 */
464	new_drp = 0;
465	for (drp = drs; drp < &drs[MAX_ADS]; drp++) {
466		if (drp->dr_ts == 0)
467			continue;
468		ifp = drp->dr_ifp;
469
470		/* Get rid of expired discovered routers.
471		 */
472		if (drp->dr_ts + drp->dr_life <= now.tv_sec) {
473			del_rdisc(drp);
474			continue;
475		}
476
477		LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1);
478
479		/* Update preference with possibly changed interface
480		 * metric.
481		 */
482		drp->dr_pref = PREF(drp->dr_recv_pref, ifp);
483
484		/* Prefer the current route to prevent thrashing.
485		 * Prefer shorter lifetimes to speed the detection of
486		 * bad routers.
487		 * Avoid sick interfaces.
488		 */
489		if (new_drp == 0
490		    || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK)
491			&& (new_pref < drp->dr_pref
492			    || (new_pref == drp->dr_pref
493				&& (drp == cur_drp
494				    || (new_drp != cur_drp
495					&& new_drp->dr_life > drp->dr_life)))))
496		    || ((new_st & IS_SICK)
497			&& !(drp->dr_ifp->int_state & IS_SICK))) {
498			    new_drp = drp;
499			    new_st = drp->dr_ifp->int_state;
500			    new_pref = drp->dr_pref;
501		}
502	}
503
504	/* switch to a better default route
505	 */
506	if (new_drp != cur_drp) {
507		rt = rtget(RIP_DEFAULT, 0);
508
509		/* Stop using discovered routes if they are all bad
510		 */
511		if (new_drp == 0) {
512			trace_act("turn off Router Discovery client");
513			rdisc_ok = 0;
514
515			if (rt != 0
516			    && (rt->rt_state & RS_RDISC)) {
517				new = rt->rt_spares[0];
518				new.rts_metric = HOPCNT_INFINITY;
519				new.rts_time = now.tv_sec - GARBAGE_TIME;
520				rtchange(rt, rt->rt_state & ~RS_RDISC,
521					 &new, 0);
522				rtswitch(rt, 0);
523			}
524
525		} else {
526			if (cur_drp == 0) {
527				trace_act("turn on Router Discovery client"
528					  " using %s via %s",
529					  naddr_ntoa(new_drp->dr_gate),
530					  new_drp->dr_ifp->int_name);
531				rdisc_ok = 1;
532
533			} else {
534				trace_act("switch Router Discovery from"
535					  " %s via %s to %s via %s",
536					  naddr_ntoa(cur_drp->dr_gate),
537					  cur_drp->dr_ifp->int_name,
538					  naddr_ntoa(new_drp->dr_gate),
539					  new_drp->dr_ifp->int_name);
540			}
541
542			memset(&new, 0, sizeof(new));
543			new.rts_ifp = new_drp->dr_ifp;
544			new.rts_gate = new_drp->dr_gate;
545			new.rts_router = new_drp->dr_gate;
546			new.rts_metric = HOPCNT_INFINITY-1;
547			new.rts_time = now.tv_sec;
548			if (rt != 0) {
549				rtchange(rt, rt->rt_state | RS_RDISC, &new, 0);
550			} else {
551				rtadd(RIP_DEFAULT, 0, RS_RDISC, &new);
552			}
553		}
554
555		cur_drp = new_drp;
556	}
557
558	/* turn RIP on or off */
559	if (!rdisc_ok || rip_interfaces > 1) {
560		rip_on(0);
561	} else {
562		rip_off();
563	}
564}
565
566
567/* handle a single address in an advertisement
568 */
569static void
570parse_ad(naddr from,
571	 naddr gate,
572	 n_long pref,			/* signed and in network order */
573	 u_short life,			/* in host byte order */
574	 struct interface *ifp)
575{
576	static struct msg_limit bad_gate;
577	struct dr *drp, *new_drp;
578
579
580	if (gate == RIP_DEFAULT
581	    || !check_dst(gate)) {
582		msglim(&bad_gate, from,"router %s advertising bad gateway %s",
583		       naddr_ntoa(from),
584		       naddr_ntoa(gate));
585		return;
586	}
587
588	/* ignore pointers to ourself and routes via unreachable networks
589	 */
590	if (ifwithaddr(gate, 1, 0) != 0) {
591		trace_pkt("    discard Router Discovery Ad pointing at us");
592		return;
593	}
594	if (!on_net(gate, ifp->int_net, ifp->int_mask)) {
595		trace_pkt("    discard Router Discovery Ad"
596			  " toward unreachable net");
597		return;
598	}
599
600	/* Convert preference to an unsigned value
601	 * and later bias it by the metric of the interface.
602	 */
603	pref = UNSIGN_PREF(ntohl(pref));
604
605	if (pref == 0 || life < MinMaxAdvertiseInterval) {
606		pref = 0;
607		life = 0;
608	}
609
610	for (new_drp = 0, drp = drs; drp < &drs[MAX_ADS]; drp++) {
611		/* accept new info for a familiar entry
612		 */
613		if (drp->dr_gate == gate) {
614			new_drp = drp;
615			break;
616		}
617
618		if (life == 0)
619			continue;	/* do not worry about dead ads */
620
621		if (drp->dr_ts == 0) {
622			new_drp = drp;	/* use unused entry */
623
624		} else if (new_drp == 0) {
625			/* look for an entry worse than the new one to
626			 * reuse.
627			 */
628			if ((!(ifp->int_state & IS_SICK)
629			     && (drp->dr_ifp->int_state & IS_SICK))
630			    || (pref > drp->dr_pref
631				&& !((ifp->int_state ^ drp->dr_ifp->int_state)
632				     & IS_SICK)))
633				new_drp = drp;
634
635		} else if (new_drp->dr_ts != 0) {
636			/* look for the least valuable entry to reuse
637			 */
638			if ((!(new_drp->dr_ifp->int_state & IS_SICK)
639			     && (drp->dr_ifp->int_state & IS_SICK))
640			    || (new_drp->dr_pref > drp->dr_pref
641				&& !((new_drp->dr_ifp->int_state
642				      ^ drp->dr_ifp->int_state)
643				     & IS_SICK)))
644				new_drp = drp;
645		}
646	}
647
648	/* forget it if all of the current entries are better */
649	if (new_drp == 0)
650		return;
651
652	new_drp->dr_ifp = ifp;
653	new_drp->dr_gate = gate;
654	new_drp->dr_ts = now.tv_sec;
655	new_drp->dr_life = life;
656	new_drp->dr_recv_pref = pref;
657	/* bias functional preference by metric of the interface */
658	new_drp->dr_pref = PREF(pref,ifp);
659
660	/* after hearing a good advertisement, stop asking
661	 */
662	if (!(ifp->int_state & IS_SICK))
663		ifp->int_rdisc_cnt = MAX_SOLICITATIONS;
664}
665
666
667/* Compute the IP checksum
668 *	This assumes the packet is less than 32K long.
669 */
670static u_short
671in_cksum(u_short *p,
672	 u_int len)
673{
674	u_int sum = 0;
675	int nwords = len >> 1;
676
677	while (nwords-- != 0)
678		sum += *p++;
679
680	if (len & 1)
681		sum += *(u_char *)p;
682
683	/* end-around-carry */
684	sum = (sum >> 16) + (sum & 0xffff);
685	sum += (sum >> 16);
686	return (~sum);
687}
688
689
690/* Send a router discovery advertisement or solicitation ICMP packet.
691 */
692static void
693send_rdisc(union ad_u *p,
694	   int p_size,
695	   struct interface *ifp,
696	   naddr dst,			/* 0 or unicast destination */
697	   int	type)			/* 0=unicast, 1=bcast, 2=mcast */
698{
699	struct sockaddr_in rsin;
700	int flags;
701	const char *msg;
702	naddr tgt_mcast;
703
704
705	memset(&rsin, 0, sizeof(rsin));
706	rsin.sin_addr.s_addr = dst;
707	rsin.sin_family = AF_INET;
708#ifdef _HAVE_SIN_LEN
709	rsin.sin_len = sizeof(rsin);
710#endif
711	flags = MSG_DONTROUTE;
712
713	switch (type) {
714	case 0:				/* unicast */
715	default:
716		msg = "Send";
717		break;
718
719	case 1:				/* broadcast */
720		if (ifp->int_if_flags & IFF_POINTOPOINT) {
721			msg = "Send pt-to-pt";
722			rsin.sin_addr.s_addr = ifp->int_dstaddr;
723		} else {
724			msg = "Send broadcast";
725			rsin.sin_addr.s_addr = ifp->int_brdaddr;
726		}
727		break;
728
729	case 2:				/* multicast */
730		msg = "Send multicast";
731		if (ifp->int_state & IS_DUP) {
732			trace_act("abort multicast output via %s"
733				  " with duplicate address",
734				  ifp->int_name);
735			return;
736		}
737		if (rdisc_sock_mcast != ifp) {
738			/* select the right interface. */
739#ifdef MCAST_IFINDEX
740			/* specify ifindex */
741			tgt_mcast = htonl(ifp->int_index);
742#else
743#ifdef MCAST_PPP_BUG
744			/* Do not specify the primary interface explicitly
745			 * if we have the multicast point-to-point kernel
746			 * bug, since the kernel will do the wrong thing
747			 * if the local address of a point-to-point link
748			 * is the same as the address of an ordinary
749			 * interface.
750			 */
751			if (ifp->int_addr == myaddr) {
752				tgt_mcast = 0;
753			} else
754#endif
755			tgt_mcast = ifp->int_addr;
756#endif
757			if (0 > setsockopt(rdisc_sock,
758					   IPPROTO_IP, IP_MULTICAST_IF,
759					   &tgt_mcast, sizeof(tgt_mcast))) {
760				LOGERR("setsockopt(rdisc_sock,"
761				       "IP_MULTICAST_IF)");
762				rdisc_sock_mcast = 0;
763				return;
764			}
765			rdisc_sock_mcast = ifp;
766		}
767		flags = 0;
768		break;
769	}
770
771	if (rdisc_sock < 0)
772		get_rdisc_sock();
773
774	trace_rdisc(msg, ifp->int_addr, rsin.sin_addr.s_addr, ifp,
775		    p, p_size);
776
777	if (0 > sendto(rdisc_sock, p, p_size, flags,
778		       (struct sockaddr *)&rsin, sizeof(rsin))) {
779		if (ifp == 0 || !(ifp->int_state & IS_BROKE))
780			msglog("sendto(%s%s%s): %s",
781			       ifp != 0 ? ifp->int_name : "",
782			       ifp != 0 ? ", " : "",
783			       inet_ntoa(rsin.sin_addr),
784			       strerror(errno));
785		if (ifp != 0)
786			if_sick(ifp);
787	}
788}
789
790
791/* Send an advertisement
792 */
793static void
794send_adv(struct interface *ifp,
795	 naddr	dst,			/* 0 or unicast destination */
796	 int	type)			/* 0=unicast, 1=bcast, 2=mcast */
797{
798	union ad_u u;
799	n_long pref;
800
801
802	memset(&u, 0, sizeof(u.ad));
803
804	u.ad.icmp_type = ICMP_ROUTERADVERT;
805	u.ad.icmp_ad_num = 1;
806	u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4;
807
808	u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3);
809
810	/* Convert the configured preference to an unsigned value,
811	 * bias it by the interface metric, and then send it as a
812	 * signed, network byte order value.
813	 */
814	pref = UNSIGN_PREF(ifp->int_rdisc_pref);
815	u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp)));
816
817	u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr;
818
819	u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad));
820
821	send_rdisc(&u, sizeof(u.ad), ifp, dst, type);
822}
823
824
825/* Advertise for Router Discovery
826 */
827void
828rdisc_adv(void)
829{
830	struct interface *ifp;
831
832	if (!supplier)
833		return;
834
835	rdisc_timer.tv_sec = now.tv_sec + NEVER;
836
837	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
838		if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE)))
839			continue;
840
841		if (!timercmp(&ifp->int_rdisc_timer, &now, >)
842		    || stopint) {
843			send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP),
844				 (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2);
845			ifp->int_rdisc_cnt++;
846
847			intvl_random(&ifp->int_rdisc_timer,
848				     (ifp->int_rdisc_int*3)/4,
849				     ifp->int_rdisc_int);
850			if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS
851			    && (ifp->int_rdisc_timer.tv_sec
852				> MAX_INITIAL_ADVERT_INTERVAL)) {
853				ifp->int_rdisc_timer.tv_sec
854				= MAX_INITIAL_ADVERT_INTERVAL;
855			}
856			timevaladd(&ifp->int_rdisc_timer, &now);
857		}
858
859		if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >))
860			rdisc_timer = ifp->int_rdisc_timer;
861	}
862}
863
864
865/* Solicit for Router Discovery
866 */
867void
868rdisc_sol(void)
869{
870	struct interface *ifp;
871	union ad_u u;
872
873
874	if (supplier)
875		return;
876
877	rdisc_timer.tv_sec = now.tv_sec + NEVER;
878
879	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
880		if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE))
881		    || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS)
882			continue;
883
884		if (!timercmp(&ifp->int_rdisc_timer, &now, >)) {
885			memset(&u, 0, sizeof(u.so));
886			u.so.icmp_type = ICMP_ROUTERSOLICIT;
887			u.so.icmp_cksum = in_cksum((u_short*)&u.so,
888						   sizeof(u.so));
889			send_rdisc(&u, sizeof(u.so), ifp,
890				   htonl(INADDR_ALLROUTERS_GROUP),
891				   ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2));
892
893			if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS)
894				continue;
895
896			ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL;
897			ifp->int_rdisc_timer.tv_usec = 0;
898			timevaladd(&ifp->int_rdisc_timer, &now);
899		}
900
901		if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >))
902			rdisc_timer = ifp->int_rdisc_timer;
903	}
904}
905
906
907/* check the IP header of a possible Router Discovery ICMP packet */
908static struct interface *		/* 0 if bad */
909ck_icmp(const char *act,
910	naddr	from,
911	struct interface *ifp,
912	naddr	to,
913	union ad_u *p,
914	u_int	len)
915{
916	const char *type;
917
918
919	if (p->icmp.icmp_type == ICMP_ROUTERADVERT) {
920		type = "advertisement";
921	} else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) {
922		type = "solicitation";
923	} else {
924		return 0;
925	}
926
927	if (p->icmp.icmp_code != 0) {
928		trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s",
929			  type, p->icmp.icmp_code,
930			  naddr_ntoa(from), naddr_ntoa(to));
931		return 0;
932	}
933
934	trace_rdisc(act, from, to, ifp, p, len);
935
936	if (ifp == 0)
937		trace_pkt("unknown interface for router-discovery %s"
938			  " from %s to %s",
939			  type, naddr_ntoa(from), naddr_ntoa(to));
940
941	return ifp;
942}
943
944
945/* read packets from the router discovery socket
946 */
947void
948read_d(void)
949{
950	static struct msg_limit bad_asize, bad_len;
951#ifdef USE_PASSIFNAME
952	static struct msg_limit  bad_name;
953#endif
954	struct sockaddr_in from;
955	int n, fromlen, cc, hlen;
956	struct {
957#ifdef USE_PASSIFNAME
958		char	ifname[IFNAMSIZ];
959#endif
960		union {
961			struct ip ip;
962			u_short s[512/2];
963			u_char	b[512];
964		} pkt;
965	} buf;
966	union ad_u *p;
967	n_long *wp;
968	struct interface *ifp;
969
970
971	for (;;) {
972		fromlen = sizeof(from);
973		cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0,
974			      (struct sockaddr*)&from,
975			      &fromlen);
976		if (cc <= 0) {
977			if (cc < 0 && errno != EWOULDBLOCK)
978				LOGERR("recvfrom(rdisc_sock)");
979			break;
980		}
981		if (fromlen != sizeof(struct sockaddr_in))
982			logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d",
983			       fromlen);
984#ifdef USE_PASSIFNAME
985		if ((cc -= sizeof(buf.ifname)) < 0)
986			logbad(0,"missing USE_PASSIFNAME; only %d bytes",
987			       cc+sizeof(buf.ifname));
988#endif
989
990		hlen = buf.pkt.ip.ip_hl << 2;
991		if (cc < hlen + ICMP_MINLEN)
992			continue;
993		p = (union ad_u *)&buf.pkt.b[hlen];
994		cc -= hlen;
995
996#ifdef USE_PASSIFNAME
997		ifp = ifwithname(buf.ifname, 0);
998		if (ifp == 0)
999			msglim(&bad_name, from.sin_addr.s_addr,
1000			       "impossible rdisc if_ name %.*s",
1001			       IFNAMSIZ, buf.ifname);
1002#else
1003		/* If we could tell the interface on which a packet from
1004		 * address 0 arrived, we could deal with such solicitations.
1005		 */
1006		ifp = ((from.sin_addr.s_addr == 0)
1007		       ? 0 : iflookup(from.sin_addr.s_addr));
1008#endif
1009		ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp,
1010			      buf.pkt.ip.ip_dst.s_addr, p, cc);
1011		if (ifp == 0)
1012			continue;
1013		if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) {
1014			trace_pkt("    "
1015				  "discard our own Router Discovery message");
1016			continue;
1017		}
1018
1019		switch (p->icmp.icmp_type) {
1020		case ICMP_ROUTERADVERT:
1021			if (p->ad.icmp_ad_asize*4
1022			    < (int)sizeof(p->ad.icmp_ad_info[0])) {
1023				msglim(&bad_asize, from.sin_addr.s_addr,
1024				       "intolerable rdisc address size=%d",
1025				       p->ad.icmp_ad_asize);
1026				continue;
1027			}
1028			if (p->ad.icmp_ad_num == 0) {
1029				trace_pkt("    empty?");
1030				continue;
1031			}
1032			if (cc != (int)(sizeof(p->ad)
1033					- sizeof(p->ad.icmp_ad_info)
1034					+ (p->ad.icmp_ad_num
1035					   * sizeof(p->ad.icmp_ad_info[0])))) {
1036				msglim(&bad_len, from.sin_addr.s_addr,
1037				       "rdisc length %d does not match ad_num"
1038				       " %d", cc, p->ad.icmp_ad_num);
1039				continue;
1040			}
1041			if (supplier)
1042				continue;
1043			if (ifp->int_state & IS_NO_ADV_IN)
1044				continue;
1045
1046			wp = &p->ad.icmp_ad_info[0].icmp_ad_addr;
1047			for (n = 0; n < p->ad.icmp_ad_num; n++) {
1048				parse_ad(from.sin_addr.s_addr,
1049					 wp[0], wp[1],
1050					 ntohs(p->ad.icmp_ad_life),
1051					 ifp);
1052				wp += p->ad.icmp_ad_asize;
1053			}
1054			break;
1055
1056
1057		case ICMP_ROUTERSOLICIT:
1058			if (!supplier)
1059				continue;
1060			if (ifp->int_state & IS_NO_ADV_OUT)
1061				continue;
1062			if (stopint)
1063				continue;
1064
1065			/* XXX
1066			 * We should handle messages from address 0.
1067			 */
1068
1069			/* Respond with a point-to-point advertisement */
1070			send_adv(ifp, from.sin_addr.s_addr, 0);
1071			break;
1072		}
1073	}
1074
1075	rdisc_sort();
1076}
1077