xref: /plan9/sys/src/cmd/ip/rip.c (revision f27a9a5a0b699d2f44893d9491ecc2336a1fbc19)
1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier #include <ip.h>
5219b2ee8SDavid du Colombier 
6219b2ee8SDavid du Colombier enum
7219b2ee8SDavid du Colombier {
8219b2ee8SDavid du Colombier 	Version=	1,
9219b2ee8SDavid du Colombier 	Pasize=		4,
10219b2ee8SDavid du Colombier 
11219b2ee8SDavid du Colombier 	/*
12219b2ee8SDavid du Colombier 	 *  definitions that are innately tied to BSD
13219b2ee8SDavid du Colombier 	 */
14219b2ee8SDavid du Colombier 	AF_INET=	2,
15219b2ee8SDavid du Colombier 	AF_UNSPEC=	0,
16219b2ee8SDavid du Colombier 
17219b2ee8SDavid du Colombier 	/*
18219b2ee8SDavid du Colombier 	 *  Packet types.
19219b2ee8SDavid du Colombier 	 */
20219b2ee8SDavid du Colombier 	Request=	1,
21219b2ee8SDavid du Colombier 	Response=	2,
22219b2ee8SDavid du Colombier 	Traceon=	3,
23219b2ee8SDavid du Colombier 	Traceoff=	4,
24219b2ee8SDavid du Colombier 
25219b2ee8SDavid du Colombier 	Infinity=	16,	/* infinite hop count */
26219b2ee8SDavid du Colombier 	Maxpacket=	488,	/* largest packet body */
27219b2ee8SDavid du Colombier };
28219b2ee8SDavid du Colombier 
29219b2ee8SDavid du Colombier 
30219b2ee8SDavid du Colombier /*
31219b2ee8SDavid du Colombier  *  network info
32219b2ee8SDavid du Colombier  */
33219b2ee8SDavid du Colombier typedef struct Rip	Rip;
34219b2ee8SDavid du Colombier struct Rip
35219b2ee8SDavid du Colombier {
36219b2ee8SDavid du Colombier 	uchar	family[2];
37219b2ee8SDavid du Colombier 	uchar	port[2];
38219b2ee8SDavid du Colombier 	uchar	addr[Pasize];
39219b2ee8SDavid du Colombier 	uchar	pad[8];
40219b2ee8SDavid du Colombier 	uchar	metric[4];
41219b2ee8SDavid du Colombier };
42219b2ee8SDavid du Colombier typedef struct Ripmsg	Ripmsg;
43219b2ee8SDavid du Colombier struct Ripmsg
44219b2ee8SDavid du Colombier {
45219b2ee8SDavid du Colombier 	uchar	type;
46219b2ee8SDavid du Colombier 	uchar	vers;
47219b2ee8SDavid du Colombier 	uchar	pad[2];
48219b2ee8SDavid du Colombier 	Rip	rip[1];		/* the rest of the packet consists of routes */
49219b2ee8SDavid du Colombier };
50219b2ee8SDavid du Colombier 
51219b2ee8SDavid du Colombier enum
52219b2ee8SDavid du Colombier {
53219b2ee8SDavid du Colombier 	Maxroutes=	(Maxpacket-4)/sizeof(Ripmsg),
54219b2ee8SDavid du Colombier };
55219b2ee8SDavid du Colombier 
56219b2ee8SDavid du Colombier /*
57219b2ee8SDavid du Colombier  *  internal route info
58219b2ee8SDavid du Colombier  */
59219b2ee8SDavid du Colombier enum
60219b2ee8SDavid du Colombier {
617dd7cddfSDavid du Colombier 	Nroute=	2048,		/* this has to be smaller than what /ip has */
62219b2ee8SDavid du Colombier 	Nhash=	256,		/* routing hash buckets */
63219b2ee8SDavid du Colombier 	Nifc=	16,
64219b2ee8SDavid du Colombier };
65219b2ee8SDavid du Colombier 
66219b2ee8SDavid du Colombier typedef struct Route	Route;
67219b2ee8SDavid du Colombier struct Route
68219b2ee8SDavid du Colombier {
69219b2ee8SDavid du Colombier 	Route	*next;
70219b2ee8SDavid du Colombier 
71219b2ee8SDavid du Colombier 	uchar	dest[Pasize];
72219b2ee8SDavid du Colombier 	uchar	mask[Pasize];
73219b2ee8SDavid du Colombier 	uchar	gate[Pasize];
74219b2ee8SDavid du Colombier 	int	metric;
75219b2ee8SDavid du Colombier 	int	inuse;
76219b2ee8SDavid du Colombier 	long	time;
77219b2ee8SDavid du Colombier };
78219b2ee8SDavid du Colombier struct {
79219b2ee8SDavid du Colombier 	Route	route[Nroute];
80219b2ee8SDavid du Colombier 	Route	*hash[Nhash];
81219b2ee8SDavid du Colombier 	int	nroute;
82219b2ee8SDavid du Colombier 	Route	def;	/* default route (immutable by us) */
83219b2ee8SDavid du Colombier } ralloc;
84219b2ee8SDavid du Colombier 
85219b2ee8SDavid du Colombier typedef struct Ifc	Ifc;
86219b2ee8SDavid du Colombier struct Ifc
87219b2ee8SDavid du Colombier {
88219b2ee8SDavid du Colombier 	int	bcast;
89219b2ee8SDavid du Colombier 	uchar	addr[Pasize];	/* my address */
90219b2ee8SDavid du Colombier 	uchar	mask[Pasize];	/* subnet mask */
91219b2ee8SDavid du Colombier 	uchar	net[Pasize];	/* subnet */
92219b2ee8SDavid du Colombier 	uchar	*cmask;		/* class mask */
93219b2ee8SDavid du Colombier 	uchar	cnet[Pasize];	/* class net */
94219b2ee8SDavid du Colombier };
95219b2ee8SDavid du Colombier struct {
96219b2ee8SDavid du Colombier 	Ifc	ifc[Nifc];
97219b2ee8SDavid du Colombier 	int	nifc;
98219b2ee8SDavid du Colombier } ialloc;
99219b2ee8SDavid du Colombier 
100219b2ee8SDavid du Colombier /*
101219b2ee8SDavid du Colombier  *  specific networks to broadcast on
102219b2ee8SDavid du Colombier  */
103219b2ee8SDavid du Colombier typedef struct Bnet Bnet;
104219b2ee8SDavid du Colombier struct Bnet
105219b2ee8SDavid du Colombier {
106219b2ee8SDavid du Colombier 	Bnet	*next;
107219b2ee8SDavid du Colombier 	uchar	addr[Pasize];
108219b2ee8SDavid du Colombier };
109219b2ee8SDavid du Colombier Bnet	*bnets;
110219b2ee8SDavid du Colombier 
111219b2ee8SDavid du Colombier int	ripfd;
112219b2ee8SDavid du Colombier long	now;
113219b2ee8SDavid du Colombier int	debug;
1147dd7cddfSDavid du Colombier int	readonly;
1157dd7cddfSDavid du Colombier char	routefile[256];
1167dd7cddfSDavid du Colombier char	netdir[256];
117219b2ee8SDavid du Colombier 
118219b2ee8SDavid du Colombier int	openport(void);
119219b2ee8SDavid du Colombier void	readroutes(void);
120219b2ee8SDavid du Colombier void	readifcs(void);
121219b2ee8SDavid du Colombier void	considerroute(Route*);
122219b2ee8SDavid du Colombier void	installroute(Route*);
123219b2ee8SDavid du Colombier void	removeroute(Route*);
124219b2ee8SDavid du Colombier uchar	*getmask(uchar*);
125219b2ee8SDavid du Colombier void	broadcast(void);
1267dd7cddfSDavid du Colombier void	timeoutroutes(void);
127219b2ee8SDavid du Colombier 
128219b2ee8SDavid du Colombier void
fatal(int syserr,char * fmt,...)129219b2ee8SDavid du Colombier fatal(int syserr, char *fmt, ...)
130219b2ee8SDavid du Colombier {
1319a747e4fSDavid du Colombier 	char buf[ERRMAX], sysbuf[ERRMAX];
1327dd7cddfSDavid du Colombier 	va_list arg;
133219b2ee8SDavid du Colombier 
1347dd7cddfSDavid du Colombier 	va_start(arg, fmt);
1359a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, arg);
1367dd7cddfSDavid du Colombier 	va_end(arg);
137219b2ee8SDavid du Colombier 	if(syserr) {
1389a747e4fSDavid du Colombier 		errstr(sysbuf, sizeof sysbuf);
1397dd7cddfSDavid du Colombier 		fprint(2, "routed: %s: %s\n", buf, sysbuf);
140219b2ee8SDavid du Colombier 	}
141219b2ee8SDavid du Colombier 	else
1427dd7cddfSDavid du Colombier 		fprint(2, "routed: %s\n", buf);
143219b2ee8SDavid du Colombier 	exits(buf);
144219b2ee8SDavid du Colombier }
145219b2ee8SDavid du Colombier 
1467dd7cddfSDavid du Colombier ulong
v4parseipmask(uchar * ip,char * p)1477dd7cddfSDavid du Colombier v4parseipmask(uchar *ip, char *p)
1487dd7cddfSDavid du Colombier {
1497dd7cddfSDavid du Colombier 	ulong x;
1507dd7cddfSDavid du Colombier 	uchar v6ip[IPaddrlen];
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 	x = parseipmask(v6ip, p);
1537dd7cddfSDavid du Colombier 	memmove(ip, v6ip+IPv4off, 4);
1547dd7cddfSDavid du Colombier 	return x;
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier uchar*
v4defmask(uchar * ip)1587dd7cddfSDavid du Colombier v4defmask(uchar *ip)
1597dd7cddfSDavid du Colombier {
1607dd7cddfSDavid du Colombier 	uchar v6ip[IPaddrlen];
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier 	v4tov6(v6ip, ip);
1637dd7cddfSDavid du Colombier 	ip = defmask(v6ip);
1647dd7cddfSDavid du Colombier 	return ip+IPv4off;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier void
v4maskip(uchar * from,uchar * mask,uchar * to)1687dd7cddfSDavid du Colombier v4maskip(uchar *from, uchar *mask, uchar *to)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier 	int i;
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	for(i = 0; i < Pasize; i++)
1737dd7cddfSDavid du Colombier 		*to++ = *from++ & *mask++;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier void
v6tov4mask(uchar * v4,uchar * v6)1777dd7cddfSDavid du Colombier v6tov4mask(uchar *v4, uchar *v6)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier 	memmove(v4, v6+IPv4off, 4);
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier #define equivip(a, b) (memcmp((a), (b), Pasize) == 0)
1837dd7cddfSDavid du Colombier 
184219b2ee8SDavid du Colombier void
ding(void * u,char * msg)185219b2ee8SDavid du Colombier ding(void *u, char *msg)
186219b2ee8SDavid du Colombier {
187219b2ee8SDavid du Colombier 	USED(u);
188219b2ee8SDavid du Colombier 
189219b2ee8SDavid du Colombier 	if(strstr(msg, "alarm"))
190219b2ee8SDavid du Colombier 		noted(NCONT);
191219b2ee8SDavid du Colombier 	noted(NDFLT);
192219b2ee8SDavid du Colombier }
193219b2ee8SDavid du Colombier 
194219b2ee8SDavid du Colombier void
usage(void)1957dd7cddfSDavid du Colombier usage(void)
1967dd7cddfSDavid du Colombier {
1977dd7cddfSDavid du Colombier 	fprint(2, "usage: %s [-bnd] [-x netmtpt]\n", argv0);
1987dd7cddfSDavid du Colombier 	exits("usage");
1997dd7cddfSDavid du Colombier }
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier void
main(int argc,char * argv[])202219b2ee8SDavid du Colombier main(int argc, char *argv[])
203219b2ee8SDavid du Colombier {
204*f27a9a5aSDavid du Colombier 	int dobroadcast, i, n;
2057dd7cddfSDavid du Colombier 	long diff;
2067dd7cddfSDavid du Colombier 	char *p;
207*f27a9a5aSDavid du Colombier 	char buf[2*1024];
2081e8349ebSDavid du Colombier 	uchar raddr[Pasize];
209*f27a9a5aSDavid du Colombier 	Bnet *bn, **l;
210*f27a9a5aSDavid du Colombier 	Udphdr *up;
211*f27a9a5aSDavid du Colombier 	Rip *r;
212*f27a9a5aSDavid du Colombier 	Ripmsg *m;
213*f27a9a5aSDavid du Colombier 	Route route;
214*f27a9a5aSDavid du Colombier 	static long btime;
2157dd7cddfSDavid du Colombier 
2167dd7cddfSDavid du Colombier 	setnetmtpt(netdir, sizeof(netdir), nil);
217219b2ee8SDavid du Colombier 	dobroadcast = 0;
218219b2ee8SDavid du Colombier 	ARGBEGIN{
219219b2ee8SDavid du Colombier 	case 'b':
220219b2ee8SDavid du Colombier 		dobroadcast++;
221219b2ee8SDavid du Colombier 		break;
222219b2ee8SDavid du Colombier 	case 'd':
223219b2ee8SDavid du Colombier 		debug++;
224219b2ee8SDavid du Colombier 		break;
2257dd7cddfSDavid du Colombier 	case 'n':
2267dd7cddfSDavid du Colombier 		readonly++;
2277dd7cddfSDavid du Colombier 		break;
2287dd7cddfSDavid du Colombier 	case 'x':
2297dd7cddfSDavid du Colombier 		p = ARGF();
2307dd7cddfSDavid du Colombier 		if(p == nil)
2317dd7cddfSDavid du Colombier 			usage();
2327dd7cddfSDavid du Colombier 		setnetmtpt(netdir, sizeof(netdir), p);
2337dd7cddfSDavid du Colombier 		break;
234219b2ee8SDavid du Colombier 	default:
2357dd7cddfSDavid du Colombier 		usage();
236219b2ee8SDavid du Colombier 	}ARGEND
237219b2ee8SDavid du Colombier 
238219b2ee8SDavid du Colombier 	/* specific broadcast nets */
239219b2ee8SDavid du Colombier 	l = &bnets;
240219b2ee8SDavid du Colombier 	while(argc > 0){
241219b2ee8SDavid du Colombier 		bn = (Bnet*)malloc(sizeof(Bnet));
242219b2ee8SDavid du Colombier 		if(bn == 0)
243219b2ee8SDavid du Colombier 			fatal(1, "out of mem");
2447dd7cddfSDavid du Colombier 		v4parseip(bn->addr, *argv);
245219b2ee8SDavid du Colombier 		*l = bn;
246219b2ee8SDavid du Colombier 		l = &bn->next;
247219b2ee8SDavid du Colombier 		argc--;
248219b2ee8SDavid du Colombier 		argv++;
249219b2ee8SDavid du Colombier 		dobroadcast++;
250219b2ee8SDavid du Colombier 	}
251219b2ee8SDavid du Colombier 
252219b2ee8SDavid du Colombier 	/* command returns */
2537dd7cddfSDavid du Colombier 	if(!debug)
254219b2ee8SDavid du Colombier 		switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNOWAIT)) {
255219b2ee8SDavid du Colombier 		case -1:
256219b2ee8SDavid du Colombier 			fatal(1, "fork");
257219b2ee8SDavid du Colombier 		case 0:
258219b2ee8SDavid du Colombier 			break;
259219b2ee8SDavid du Colombier 		default:
260219b2ee8SDavid du Colombier 			exits(0);
261219b2ee8SDavid du Colombier 		}
262219b2ee8SDavid du Colombier 
263219b2ee8SDavid du Colombier 
2649a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2659a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
266219b2ee8SDavid du Colombier 
2677dd7cddfSDavid du Colombier 	snprint(routefile, sizeof(routefile), "%s/iproute", netdir);
2687dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s/iproute", netdir);
269219b2ee8SDavid du Colombier 
2707dd7cddfSDavid du Colombier 	now = time(0);
271219b2ee8SDavid du Colombier 	readifcs();
272219b2ee8SDavid du Colombier 	readroutes();
273219b2ee8SDavid du Colombier 
274219b2ee8SDavid du Colombier 	notify(ding);
275219b2ee8SDavid du Colombier 
276219b2ee8SDavid du Colombier 	ripfd = openport();
277219b2ee8SDavid du Colombier 	for(;;) {
278219b2ee8SDavid du Colombier 		diff = btime - time(0);
279219b2ee8SDavid du Colombier 		if(diff <= 0){
2807dd7cddfSDavid du Colombier 			if(dobroadcast)
281219b2ee8SDavid du Colombier 				broadcast();
2827dd7cddfSDavid du Colombier 			timeoutroutes();
2837dd7cddfSDavid du Colombier 
284219b2ee8SDavid du Colombier 			btime = time(0) + 2*60;
285219b2ee8SDavid du Colombier 			diff = 2*60;
286219b2ee8SDavid du Colombier 		}
287219b2ee8SDavid du Colombier 		alarm(diff*1000);
288219b2ee8SDavid du Colombier 		n = read(ripfd, buf, sizeof(buf));
289219b2ee8SDavid du Colombier 		alarm(0);
290219b2ee8SDavid du Colombier 		if(n <= 0)
291219b2ee8SDavid du Colombier 			continue;
292219b2ee8SDavid du Colombier 
293*f27a9a5aSDavid du Colombier 		n = (n - Udphdrsize - 4) / sizeof(Rip);
294219b2ee8SDavid du Colombier 		if(n <= 0)
295219b2ee8SDavid du Colombier 			continue;
296219b2ee8SDavid du Colombier 
297*f27a9a5aSDavid du Colombier 		up = (Udphdr*)buf;
298*f27a9a5aSDavid du Colombier 		m = (Ripmsg*)(buf+Udphdrsize);
299219b2ee8SDavid du Colombier 		if(m->type != Response || m->vers != Version)
300219b2ee8SDavid du Colombier 			continue;
3011e8349ebSDavid du Colombier 		v6tov4(raddr, up->raddr);
302219b2ee8SDavid du Colombier 
303219b2ee8SDavid du Colombier 		/* ignore our own messages */
304219b2ee8SDavid du Colombier 		for(i = 0; i < ialloc.nifc; i++)
3051e8349ebSDavid du Colombier 			if(equivip(ialloc.ifc[i].addr, raddr))
306219b2ee8SDavid du Colombier 				continue;
307219b2ee8SDavid du Colombier 
308219b2ee8SDavid du Colombier 		now = time(0);
309219b2ee8SDavid du Colombier 		for(r = m->rip; r < &m->rip[n]; r++){
3101e8349ebSDavid du Colombier 			memmove(route.gate, raddr, Pasize);
311219b2ee8SDavid du Colombier 			memmove(route.mask, getmask(r->addr), Pasize);
3127dd7cddfSDavid du Colombier 			v4maskip(r->addr, route.mask, route.dest);
313219b2ee8SDavid du Colombier 			route.metric = nhgetl(r->metric) + 1;
314219b2ee8SDavid du Colombier 			if(route.metric < 1)
315219b2ee8SDavid du Colombier 				continue;
316219b2ee8SDavid du Colombier 			considerroute(&route);
317219b2ee8SDavid du Colombier 		}
318219b2ee8SDavid du Colombier 	}
319b85a8364SDavid du Colombier 	/* not reached */
320219b2ee8SDavid du Colombier }
321219b2ee8SDavid du Colombier 
322219b2ee8SDavid du Colombier int
openport(void)323219b2ee8SDavid du Colombier openport(void)
324219b2ee8SDavid du Colombier {
325219b2ee8SDavid du Colombier 	int ripctl, rip;
326*f27a9a5aSDavid du Colombier 	char data[128], devdir[40];
327219b2ee8SDavid du Colombier 
3287dd7cddfSDavid du Colombier 	snprint(data, sizeof(data), "%s/udp!*!rip", netdir);
3297dd7cddfSDavid du Colombier 	ripctl = announce(data, devdir);
330219b2ee8SDavid du Colombier 	if(ripctl < 0)
331219b2ee8SDavid du Colombier 		fatal(1, "can't announce");
3321e8349ebSDavid du Colombier 	if(fprint(ripctl, "headers") < 0)
333219b2ee8SDavid du Colombier 		fatal(1, "can't set header mode");
334219b2ee8SDavid du Colombier 
335219b2ee8SDavid du Colombier 	sprint(data, "%s/data", devdir);
336219b2ee8SDavid du Colombier 	rip = open(data, ORDWR);
337219b2ee8SDavid du Colombier 	if(rip < 0)
338219b2ee8SDavid du Colombier 		fatal(1, "open udp data");
339219b2ee8SDavid du Colombier 	return rip;
340219b2ee8SDavid du Colombier }
341219b2ee8SDavid du Colombier 
3429a747e4fSDavid du Colombier Ipifc *ifcs;
3437dd7cddfSDavid du Colombier 
344219b2ee8SDavid du Colombier void
readifcs(void)345219b2ee8SDavid du Colombier readifcs(void)
346219b2ee8SDavid du Colombier {
3479a747e4fSDavid du Colombier 	Ipifc *ifc;
3489a747e4fSDavid du Colombier 	Iplifc *lifc;
349219b2ee8SDavid du Colombier 	Ifc *ip;
350219b2ee8SDavid du Colombier 	Bnet *bn;
351219b2ee8SDavid du Colombier 	Route route;
3527dd7cddfSDavid du Colombier 	int i;
353219b2ee8SDavid du Colombier 
3549a747e4fSDavid du Colombier 	ifcs = readipifc(netdir, ifcs, -1);
355219b2ee8SDavid du Colombier 	i = 0;
3569a747e4fSDavid du Colombier 	for(ifc = ifcs; ifc != nil; ifc = ifc->next){
3579a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil && i < Nifc; lifc = lifc->next){
3587dd7cddfSDavid du Colombier 			// ignore any interfaces that aren't v4
3599a747e4fSDavid du Colombier 			if(memcmp(lifc->ip, v4prefix, IPaddrlen-IPv4addrlen) != 0)
360219b2ee8SDavid du Colombier 				continue;
361219b2ee8SDavid du Colombier 			ip = &ialloc.ifc[i++];
3629a747e4fSDavid du Colombier 			v6tov4(ip->addr, lifc->ip);
3639a747e4fSDavid du Colombier 			v6tov4mask(ip->mask, lifc->mask);
3649a747e4fSDavid du Colombier 			v6tov4(ip->net, lifc->net);
3657dd7cddfSDavid du Colombier 			ip->cmask = v4defmask(ip->net);
3667dd7cddfSDavid du Colombier 			v4maskip(ip->net, ip->cmask, ip->cnet);
367219b2ee8SDavid du Colombier 			ip->bcast = 0;
368219b2ee8SDavid du Colombier 
369219b2ee8SDavid du Colombier 			/* add as a route */
370219b2ee8SDavid du Colombier 			memmove(route.mask, ip->mask, Pasize);
371219b2ee8SDavid du Colombier 			memmove(route.dest, ip->net, Pasize);
372219b2ee8SDavid du Colombier 			memset(route.gate, 0, Pasize);
373219b2ee8SDavid du Colombier 			route.metric = 0;
374219b2ee8SDavid du Colombier 			considerroute(&route);
375219b2ee8SDavid du Colombier 
376219b2ee8SDavid du Colombier 			/* mark as broadcast */
377219b2ee8SDavid du Colombier 			if(bnets == 0)
378219b2ee8SDavid du Colombier 				ip->bcast = 1;
379219b2ee8SDavid du Colombier 			else for(bn = bnets; bn; bn = bn->next)
380219b2ee8SDavid du Colombier 				if(memcmp(bn->addr, ip->net, Pasize) == 0){
381219b2ee8SDavid du Colombier 					ip->bcast = 1;
382219b2ee8SDavid du Colombier 					break;
383219b2ee8SDavid du Colombier 				}
384219b2ee8SDavid du Colombier 		}
3859a747e4fSDavid du Colombier 	}
386219b2ee8SDavid du Colombier 	ialloc.nifc = i;
387219b2ee8SDavid du Colombier }
388219b2ee8SDavid du Colombier 
389219b2ee8SDavid du Colombier void
readroutes(void)390219b2ee8SDavid du Colombier readroutes(void)
391219b2ee8SDavid du Colombier {
392219b2ee8SDavid du Colombier 	int n;
393219b2ee8SDavid du Colombier 	char *p;
394219b2ee8SDavid du Colombier 	Biobuf *b;
395219b2ee8SDavid du Colombier 	char *f[6];
396219b2ee8SDavid du Colombier 	Route route;
397219b2ee8SDavid du Colombier 
3987dd7cddfSDavid du Colombier 	b = Bopen(routefile, OREAD);
399219b2ee8SDavid du Colombier 	if(b == 0)
400219b2ee8SDavid du Colombier 		return;
401219b2ee8SDavid du Colombier 	while(p = Brdline(b, '\n')){
402219b2ee8SDavid du Colombier 		p[Blinelen(b)-1] = 0;
4037dd7cddfSDavid du Colombier 		n = getfields(p, f, 6, 1, " \t");
404219b2ee8SDavid du Colombier 		if(n < 5)
405219b2ee8SDavid du Colombier 			continue;
4067dd7cddfSDavid du Colombier 		v4parseip(route.dest, f[0]);
4077dd7cddfSDavid du Colombier 		v4parseipmask(route.mask, f[1]);
4087dd7cddfSDavid du Colombier 		v4parseip(route.gate, f[2]);
409219b2ee8SDavid du Colombier 		route.metric = Infinity;
410219b2ee8SDavid du Colombier 		if(equivip(route.dest, ralloc.def.dest)
411219b2ee8SDavid du Colombier 		&& equivip(route.mask, ralloc.def.mask))
412219b2ee8SDavid du Colombier 			memmove(ralloc.def.gate, route.gate, Pasize);
4137dd7cddfSDavid du Colombier 		else if(!equivip(route.dest, route.gate) && strchr(f[3], 'i') == 0)
414219b2ee8SDavid du Colombier 			considerroute(&route);
415219b2ee8SDavid du Colombier 	}
416219b2ee8SDavid du Colombier 	Bterm(b);
417219b2ee8SDavid du Colombier }
418219b2ee8SDavid du Colombier 
419219b2ee8SDavid du Colombier /*
420219b2ee8SDavid du Colombier  *  route's hashed by net, not subnet
421219b2ee8SDavid du Colombier  */
422219b2ee8SDavid du Colombier ulong
rhash(uchar * d)423219b2ee8SDavid du Colombier rhash(uchar *d)
424219b2ee8SDavid du Colombier {
425219b2ee8SDavid du Colombier 	ulong h;
426219b2ee8SDavid du Colombier 	uchar net[Pasize];
427219b2ee8SDavid du Colombier 
4287dd7cddfSDavid du Colombier 	v4maskip(d, v4defmask(d), net);
429219b2ee8SDavid du Colombier 	h = net[0] + net[1] + net[2];
430219b2ee8SDavid du Colombier 	return h % Nhash;
431219b2ee8SDavid du Colombier }
432219b2ee8SDavid du Colombier 
433219b2ee8SDavid du Colombier /*
434219b2ee8SDavid du Colombier  *  consider installing a route.  Do so only if it is better than what
435219b2ee8SDavid du Colombier  *  we have.
436219b2ee8SDavid du Colombier  */
437219b2ee8SDavid du Colombier void
considerroute(Route * r)438219b2ee8SDavid du Colombier considerroute(Route *r)
439219b2ee8SDavid du Colombier {
4407dd7cddfSDavid du Colombier 	ulong h;
4417dd7cddfSDavid du Colombier 	Route *hp;
442219b2ee8SDavid du Colombier 
443219b2ee8SDavid du Colombier 	if(debug)
4447dd7cddfSDavid du Colombier 		fprint(2, "consider %16V & %16V -> %16V %d\n", r->dest, r->mask, r->gate, r->metric);
445219b2ee8SDavid du Colombier 
446219b2ee8SDavid du Colombier 	r->next = 0;
447219b2ee8SDavid du Colombier 	r->time = now;
448219b2ee8SDavid du Colombier 	r->inuse = 1;
449219b2ee8SDavid du Colombier 
450219b2ee8SDavid du Colombier 	/* don't allow our default route to be highjacked */
451219b2ee8SDavid du Colombier 	if(equivip(r->dest, ralloc.def.dest) || equivip(r->mask, ralloc.def.mask))
452219b2ee8SDavid du Colombier 		return;
453219b2ee8SDavid du Colombier 
454219b2ee8SDavid du Colombier 	h = rhash(r->dest);
455219b2ee8SDavid du Colombier 	for(hp = ralloc.hash[h]; hp; hp = hp->next){
456219b2ee8SDavid du Colombier 		if(equivip(hp->dest, r->dest)){
457219b2ee8SDavid du Colombier 			/*
458219b2ee8SDavid du Colombier 			 *  found a match, replace if better (or much newer)
459219b2ee8SDavid du Colombier 			 */
460219b2ee8SDavid du Colombier 			if(r->metric < hp->metric || now-hp->time > 5*60){
461219b2ee8SDavid du Colombier 				removeroute(hp);
462219b2ee8SDavid du Colombier 				memmove(hp->mask, r->mask, Pasize);
463219b2ee8SDavid du Colombier 				memmove(hp->gate, r->gate, Pasize);
464219b2ee8SDavid du Colombier 				hp->metric = r->metric;
465219b2ee8SDavid du Colombier 				installroute(hp);
466219b2ee8SDavid du Colombier 			}
467219b2ee8SDavid du Colombier 			if(equivip(hp->gate, r->gate))
468219b2ee8SDavid du Colombier 				hp->time = now;
469219b2ee8SDavid du Colombier 			return;
470219b2ee8SDavid du Colombier 		}
471219b2ee8SDavid du Colombier 	}
472219b2ee8SDavid du Colombier 
473219b2ee8SDavid du Colombier 	/*
474219b2ee8SDavid du Colombier 	 *  no match, look for space
475219b2ee8SDavid du Colombier 	 */
476219b2ee8SDavid du Colombier 	for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++)
477219b2ee8SDavid du Colombier 		if(hp->inuse == 0)
478219b2ee8SDavid du Colombier 			break;
479219b2ee8SDavid du Colombier 
480219b2ee8SDavid du Colombier 	if(hp == 0)
481219b2ee8SDavid du Colombier 		fatal(0, "no more routes");
482219b2ee8SDavid du Colombier 
483219b2ee8SDavid du Colombier 	memmove(hp, r, sizeof(Route));
484219b2ee8SDavid du Colombier 	hp->next = ralloc.hash[h];
485219b2ee8SDavid du Colombier 	ralloc.hash[h] = hp;
486219b2ee8SDavid du Colombier 	installroute(hp);
487219b2ee8SDavid du Colombier }
488219b2ee8SDavid du Colombier 
489219b2ee8SDavid du Colombier void
removeroute(Route * r)490219b2ee8SDavid du Colombier removeroute(Route *r)
491219b2ee8SDavid du Colombier {
492219b2ee8SDavid du Colombier 	int fd;
493219b2ee8SDavid du Colombier 
4947dd7cddfSDavid du Colombier 	fd = open(routefile, ORDWR);
495219b2ee8SDavid du Colombier 	if(fd < 0){
4967dd7cddfSDavid du Colombier 		fprint(2, "can't open oproute\n");
497219b2ee8SDavid du Colombier 		return;
498219b2ee8SDavid du Colombier 	}
4997dd7cddfSDavid du Colombier 	if(!readonly)
5007dd7cddfSDavid du Colombier 		fprint(fd, "delete %V", r->dest);
501219b2ee8SDavid du Colombier 	if(debug)
5027dd7cddfSDavid du Colombier 		fprint(2, "removeroute %V\n", r->dest);
503219b2ee8SDavid du Colombier 	close(fd);
504219b2ee8SDavid du Colombier }
505219b2ee8SDavid du Colombier 
506219b2ee8SDavid du Colombier /*
507219b2ee8SDavid du Colombier  *  pass a route to the kernel or /ip.  Don't bother if it is just the default
508219b2ee8SDavid du Colombier  *  gateway.
509219b2ee8SDavid du Colombier  */
510219b2ee8SDavid du Colombier void
installroute(Route * r)511219b2ee8SDavid du Colombier installroute(Route *r)
512219b2ee8SDavid du Colombier {
513219b2ee8SDavid du Colombier 	int fd;
514219b2ee8SDavid du Colombier 	ulong h;
515219b2ee8SDavid du Colombier 	Route *hp;
516219b2ee8SDavid du Colombier 	uchar net[Pasize];
517219b2ee8SDavid du Colombier 
5187dd7cddfSDavid du Colombier 	/*
5197dd7cddfSDavid du Colombier 	 *  don't install routes whose gateway is 00000000
5207dd7cddfSDavid du Colombier 	 */
521219b2ee8SDavid du Colombier 	if(equivip(r->gate, ralloc.def.dest))
522219b2ee8SDavid du Colombier 		return;
523219b2ee8SDavid du Colombier 
5247dd7cddfSDavid du Colombier 	fd = open(routefile, ORDWR);
525219b2ee8SDavid du Colombier 	if(fd < 0){
5267dd7cddfSDavid du Colombier 		fprint(2, "can't open oproute\n");
527219b2ee8SDavid du Colombier 		return;
528219b2ee8SDavid du Colombier 	}
529219b2ee8SDavid du Colombier 	h = rhash(r->dest);
5307dd7cddfSDavid du Colombier 
5317dd7cddfSDavid du Colombier 	/*
5327dd7cddfSDavid du Colombier 	 *  if the gateway is the same as the default gateway
5337dd7cddfSDavid du Colombier 	 *  we may be able to avoid a entry in the kernel
5347dd7cddfSDavid du Colombier 	 */
535219b2ee8SDavid du Colombier 	if(equivip(r->gate, ralloc.def.gate)){
5367dd7cddfSDavid du Colombier 		/*
5377dd7cddfSDavid du Colombier 		 *  look for a less specific match
5387dd7cddfSDavid du Colombier 		 */
539219b2ee8SDavid du Colombier 		for(hp = ralloc.hash[h]; hp; hp = hp->next){
5407dd7cddfSDavid du Colombier 			v4maskip(hp->mask, r->dest, net);
541219b2ee8SDavid du Colombier 			if(equivip(net, hp->dest) && !equivip(hp->gate, ralloc.def.gate))
542219b2ee8SDavid du Colombier 				break;
543219b2ee8SDavid du Colombier 		}
5447dd7cddfSDavid du Colombier 		/*
5457dd7cddfSDavid du Colombier 		 *  if no less specific match, just use the default
5467dd7cddfSDavid du Colombier 		 */
547219b2ee8SDavid du Colombier 		if(hp == 0){
5487dd7cddfSDavid du Colombier 			if(!readonly)
5497dd7cddfSDavid du Colombier 				fprint(fd, "delete %V", r->dest);
550219b2ee8SDavid du Colombier 			if(debug)
5517dd7cddfSDavid du Colombier 				fprint(2, "delete %V\n", r->dest);
552219b2ee8SDavid du Colombier 			close(fd);
553219b2ee8SDavid du Colombier 			return;
554219b2ee8SDavid du Colombier 		}
555219b2ee8SDavid du Colombier 	}
5567dd7cddfSDavid du Colombier 	if(!readonly)
5577dd7cddfSDavid du Colombier 		fprint(fd, "add %V %V %V", r->dest, r->mask, r->gate);
558219b2ee8SDavid du Colombier 	if(debug)
5597dd7cddfSDavid du Colombier 		fprint(2, "add %V & %V -> %V\n", r->dest, r->mask, r->gate);
560219b2ee8SDavid du Colombier 	close(fd);
561219b2ee8SDavid du Colombier }
562219b2ee8SDavid du Colombier 
563219b2ee8SDavid du Colombier /*
564219b2ee8SDavid du Colombier  *  return true of dest is on net
565219b2ee8SDavid du Colombier  */
566219b2ee8SDavid du Colombier int
onnet(uchar * dest,uchar * net,uchar * netmask)567219b2ee8SDavid du Colombier onnet(uchar *dest, uchar *net, uchar *netmask)
568219b2ee8SDavid du Colombier {
569219b2ee8SDavid du Colombier 	uchar dnet[Pasize];
570219b2ee8SDavid du Colombier 
5717dd7cddfSDavid du Colombier 	v4maskip(dest, netmask, dnet);
572219b2ee8SDavid du Colombier 	return equivip(dnet, net);
573219b2ee8SDavid du Colombier }
574219b2ee8SDavid du Colombier 
575219b2ee8SDavid du Colombier /*
576219b2ee8SDavid du Colombier  *  figure out what mask to use, if we have a direct connected network
577219b2ee8SDavid du Colombier  *  with the same class net use its subnet mask.
578219b2ee8SDavid du Colombier  */
579219b2ee8SDavid du Colombier uchar*
getmask(uchar * dest)580219b2ee8SDavid du Colombier getmask(uchar *dest)
581219b2ee8SDavid du Colombier {
582219b2ee8SDavid du Colombier 	int i;
583219b2ee8SDavid du Colombier 	Ifc *ip;
584219b2ee8SDavid du Colombier 	ulong mask, nmask;
585219b2ee8SDavid du Colombier 	uchar *m;
586219b2ee8SDavid du Colombier 
587219b2ee8SDavid du Colombier 	m = 0;
588219b2ee8SDavid du Colombier 	mask = 0xffffffff;
589219b2ee8SDavid du Colombier 	for(i = 0; i < ialloc.nifc; i++){
590219b2ee8SDavid du Colombier 		ip = &ialloc.ifc[i];
591219b2ee8SDavid du Colombier 		if(onnet(dest, ip->cnet, ip->cmask)){
592219b2ee8SDavid du Colombier 			nmask = nhgetl(ip->mask);
593219b2ee8SDavid du Colombier 			if(nmask < mask){
594219b2ee8SDavid du Colombier 				mask = nmask;
595219b2ee8SDavid du Colombier 				m = ip->mask;
596219b2ee8SDavid du Colombier 			}
597219b2ee8SDavid du Colombier 		}
598219b2ee8SDavid du Colombier 	}
599219b2ee8SDavid du Colombier 
600219b2ee8SDavid du Colombier 	if(m == 0)
6017dd7cddfSDavid du Colombier 		m = v4defmask(dest);
602219b2ee8SDavid du Colombier 	return m;
603219b2ee8SDavid du Colombier }
604219b2ee8SDavid du Colombier 
605219b2ee8SDavid du Colombier /*
606219b2ee8SDavid du Colombier  *  broadcast routes onto all networks
607219b2ee8SDavid du Colombier  */
608219b2ee8SDavid du Colombier void
sendto(Ifc * ip)609219b2ee8SDavid du Colombier sendto(Ifc *ip)
610219b2ee8SDavid du Colombier {
611219b2ee8SDavid du Colombier 	int h, n;
612*f27a9a5aSDavid du Colombier 	uchar raddr[Pasize], mbuf[Udphdrsize+512];
613219b2ee8SDavid du Colombier 	Ripmsg *m;
614*f27a9a5aSDavid du Colombier 	Route *r;
615*f27a9a5aSDavid du Colombier 	Udphdr *u;
616219b2ee8SDavid du Colombier 
617*f27a9a5aSDavid du Colombier 	u = (Udphdr*)mbuf;
618219b2ee8SDavid du Colombier 	for(n = 0; n < Pasize; n++)
6191e8349ebSDavid du Colombier 		raddr[n] = ip->net[n] | ~(ip->mask[n]);
6201e8349ebSDavid du Colombier 	v4tov6(u->raddr, raddr);
6217dd7cddfSDavid du Colombier 	hnputs(u->rport, 520);
622*f27a9a5aSDavid du Colombier 	m = (Ripmsg*)(mbuf+Udphdrsize);
623219b2ee8SDavid du Colombier 	m->type = Response;
624219b2ee8SDavid du Colombier 	m->vers = Version;
625219b2ee8SDavid du Colombier 	if(debug)
6267dd7cddfSDavid du Colombier 		fprint(2, "to %V\n", u->raddr);
627219b2ee8SDavid du Colombier 
628219b2ee8SDavid du Colombier 	n = 0;
629219b2ee8SDavid du Colombier 	for(h = 0; h < Nhash; h++){
630219b2ee8SDavid du Colombier 		for(r = ralloc.hash[h]; r; r = r->next){
631219b2ee8SDavid du Colombier 			/*
632219b2ee8SDavid du Colombier 			 *  don't send any route back to the net
633219b2ee8SDavid du Colombier 			 *  it came from
634219b2ee8SDavid du Colombier 			 */
635219b2ee8SDavid du Colombier 			if(onnet(r->gate, ip->net, ip->mask))
636219b2ee8SDavid du Colombier 				continue;
637219b2ee8SDavid du Colombier 
638219b2ee8SDavid du Colombier 			/*
639219b2ee8SDavid du Colombier 			 *  don't tell a network about itself
640219b2ee8SDavid du Colombier 			 */
641219b2ee8SDavid du Colombier 			if(equivip(r->dest, ip->net))
642219b2ee8SDavid du Colombier 				continue;
643219b2ee8SDavid du Colombier 
644219b2ee8SDavid du Colombier 			/*
645219b2ee8SDavid du Colombier 			 *  don't tell nets about other net's subnets
646219b2ee8SDavid du Colombier 			 */
6477dd7cddfSDavid du Colombier 			if(!equivip(r->mask, v4defmask(r->dest))
6487dd7cddfSDavid du Colombier 			&& !equivip(ip->cmask, v4defmask(r->dest)))
649219b2ee8SDavid du Colombier 				continue;
650219b2ee8SDavid du Colombier 
651219b2ee8SDavid du Colombier 			memset(&m->rip[n], 0, sizeof(m->rip[n]));
652219b2ee8SDavid du Colombier 			memmove(m->rip[n].addr, r->dest, Pasize);
653219b2ee8SDavid du Colombier 			if(r->metric < 1)
654219b2ee8SDavid du Colombier 				hnputl(m->rip[n].metric, 1);
655219b2ee8SDavid du Colombier 			else
656219b2ee8SDavid du Colombier 				hnputl(m->rip[n].metric, r->metric);
657219b2ee8SDavid du Colombier 			hnputs(m->rip[n].family, AF_INET);
658219b2ee8SDavid du Colombier 
659219b2ee8SDavid du Colombier 			if(debug)
660*f27a9a5aSDavid du Colombier 				fprint(2, " %16V & %16V -> %16V %2d\n",
661*f27a9a5aSDavid du Colombier 					r->dest, r->mask, r->gate, r->metric);
662219b2ee8SDavid du Colombier 
6637dd7cddfSDavid du Colombier 			if(++n == Maxroutes && !readonly){
664*f27a9a5aSDavid du Colombier 				write(ripfd, mbuf, Udphdrsize + 4 + n*20);
665219b2ee8SDavid du Colombier 				n = 0;
666219b2ee8SDavid du Colombier 			}
667219b2ee8SDavid du Colombier 		}
668219b2ee8SDavid du Colombier 	}
669219b2ee8SDavid du Colombier 
6707dd7cddfSDavid du Colombier 	if(n && !readonly)
671*f27a9a5aSDavid du Colombier 		write(ripfd, mbuf, Udphdrsize+4+n*20);
672219b2ee8SDavid du Colombier }
673219b2ee8SDavid du Colombier void
broadcast(void)674219b2ee8SDavid du Colombier broadcast(void)
675219b2ee8SDavid du Colombier {
676219b2ee8SDavid du Colombier 	int i;
677219b2ee8SDavid du Colombier 
678219b2ee8SDavid du Colombier 	readifcs();
679219b2ee8SDavid du Colombier 	for(i = 0; i < ialloc.nifc; i++){
680219b2ee8SDavid du Colombier 		if(ialloc.ifc[i].bcast)
681219b2ee8SDavid du Colombier 			sendto(&ialloc.ifc[i]);
682219b2ee8SDavid du Colombier 	}
683219b2ee8SDavid du Colombier }
684219b2ee8SDavid du Colombier 
6857dd7cddfSDavid du Colombier /*
6867dd7cddfSDavid du Colombier  *  timeout any routes that haven't been refreshed and aren't wired
6877dd7cddfSDavid du Colombier  */
688219b2ee8SDavid du Colombier void
timeoutroutes(void)6897dd7cddfSDavid du Colombier timeoutroutes(void)
690219b2ee8SDavid du Colombier {
6917dd7cddfSDavid du Colombier 	int h;
6927dd7cddfSDavid du Colombier 	long now;
6937dd7cddfSDavid du Colombier 	Route *r, **l;
694219b2ee8SDavid du Colombier 
6957dd7cddfSDavid du Colombier 	now = time(0);
6967dd7cddfSDavid du Colombier 
6977dd7cddfSDavid du Colombier 	for(h = 0; h < Nhash; h++){
6987dd7cddfSDavid du Colombier 		l = &ralloc.hash[h];
6997dd7cddfSDavid du Colombier 		for(r = *l; r; r = *l){
7007dd7cddfSDavid du Colombier 			if(r->metric < Infinity && now - r->time > 10*60){
7017dd7cddfSDavid du Colombier 				removeroute(r);
7027dd7cddfSDavid du Colombier 				r->inuse = 0;
7037dd7cddfSDavid du Colombier 				*l = r->next;
7047dd7cddfSDavid du Colombier 				continue;
7057dd7cddfSDavid du Colombier 			}
7067dd7cddfSDavid du Colombier 			l = &r->next;
7077dd7cddfSDavid du Colombier 		}
7087dd7cddfSDavid du Colombier 	}
709219b2ee8SDavid du Colombier }
710