Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/cmd/ip/ipconfig/ipv6.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * ipconfig for IPv6
3
 *	RS means Router Solicitation
4
 *	RA means Router Advertisement
5
 */
6
 
7
#include <u.h>
8
#include <libc.h>
9
#include <bio.h>
10
#include <ip.h>
11
#include "ipconfig.h"
12
#include "../icmp.h"
13
 
14
#pragma varargck argpos ralog 1
15
 
16
#define RALOG "v6routeradv"
17
 
18
#define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1])
19
#define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \
20
		 ((uchar*)x)[2]<< 8 | ((uchar*)x)[3])
21
 
22
enum {
23
	ICMP6LEN=	4,
24
};
25
 
26
typedef struct Hdr Hdr;
27
struct Hdr			/* ICMP v4 & v6 header */
28
{
29
	uchar	type;
30
	uchar	code;
31
	uchar	cksum[2];	/* Checksum */
32
	uchar	data[];
33
};
34
 
35
char *icmpmsg6[Maxtype6+1] =
36
{
37
[EchoReply]		"EchoReply",
38
[UnreachableV6]		"UnreachableV6",
39
[PacketTooBigV6]	"PacketTooBigV6",
40
[TimeExceedV6]		"TimeExceedV6",
41
[Redirect]		"Redirect",
42
[EchoRequest]		"EchoRequest",
43
[TimeExceed]		"TimeExceed",
44
[InParmProblem]		"InParmProblem",
45
[Timestamp]		"Timestamp",
46
[TimestampReply]	"TimestampReply",
47
[InfoRequest]		"InfoRequest",
48
[InfoReply]		"InfoReply",
49
[AddrMaskRequest]	"AddrMaskRequest",
50
[AddrMaskReply]		"AddrMaskReply",
51
[EchoRequestV6]		"EchoRequestV6",
52
[EchoReplyV6]		"EchoReplyV6",
53
[RouterSolicit]		"RouterSolicit",
54
[RouterAdvert]		"RouterAdvert",
55
[NbrSolicit]		"NbrSolicit",
56
[NbrAdvert]		"NbrAdvert",
57
[RedirectV6]		"RedirectV6",
58
};
59
 
60
static char *icmp6opts[] =
61
{
62
[0]			"unknown option",
63
[V6nd_srclladdr]	"srcll_addr",
64
[V6nd_targlladdr]	"targll_addr",
65
[V6nd_pfxinfo]		"prefix",
66
[V6nd_redirhdr]		"redirect",
67
[V6nd_mtu]		"mtu",
68
[V6nd_home]		"home",
69
[V6nd_srcaddrs]		"src_addrs",
70
[V6nd_ip]		"ip",
71
[V6nd_rdns]		"rdns",
72
[V6nd_9fs]		"9fs",
73
[V6nd_9auth]		"9auth",
74
};
75
 
76
uchar v6allroutersL[IPaddrlen] = {
77
	0xff, 0x02, 0, 0,
78
	0, 0, 0, 0,
79
	0, 0, 0, 0,
80
	0, 0, 0, 0x02
81
};
82
 
83
uchar v6allnodesL[IPaddrlen] = {
84
	0xff, 0x02, 0, 0,
85
	0, 0, 0, 0,
86
	0, 0, 0, 0,
87
	0, 0, 0, 0x01
88
};
89
 
90
uchar v6Unspecified[IPaddrlen] = {
91
	0, 0, 0, 0,
92
	0, 0, 0, 0,
93
	0, 0, 0, 0,
94
	0, 0, 0, 0
95
};
96
 
97
uchar v6loopback[IPaddrlen] = {
98
	0, 0, 0, 0,
99
	0, 0, 0, 0,
100
	0, 0, 0, 0,
101
	0, 0, 0, 1
102
};
103
 
104
uchar v6glunicast[IPaddrlen] = {
105
	0x08, 0, 0, 0,
106
	0, 0, 0, 0,
107
	0, 0, 0, 0,
108
	0, 0, 0, 0
109
};
110
 
111
uchar v6linklocal[IPaddrlen] = {
112
	0xfe, 0x80, 0, 0,
113
	0, 0, 0, 0,
114
	0, 0, 0, 0,
115
	0, 0, 0, 0
116
};
117
 
118
uchar v6solpfx[IPaddrlen] = {
119
	0xff, 0x02, 0, 0,
120
	0, 0, 0, 0,
121
	0, 0, 0, 1,
122
	/* last 3 bytes filled with low-order bytes of addr being solicited */
123
	0xff, 0, 0, 0,
124
};
125
 
126
uchar v6defmask[IPaddrlen] = {
127
	0xff, 0xff, 0xff, 0xff,
128
	0xff, 0xff, 0xff, 0xff,
129
	0, 0, 0, 0,
130
	0, 0, 0, 0
131
};
132
 
133
enum
134
{
135
	Vadd,
136
	Vremove,
137
	Vunbind,
138
	Vaddpref6,
139
	Vra6,
140
};
141
 
142
static void
143
ralog(char *fmt, ...)
144
{
145
	char msg[512];
146
	va_list arg;
147
 
148
	va_start(arg, fmt);
149
	vseprint(msg, msg+sizeof msg, fmt, arg);
150
	va_end(arg);
151
	syslog(debug, RALOG, msg);
152
}
153
 
154
extern void
155
ea2lla(uchar *lla, uchar *ea)
156
{
157
	assert(IPaddrlen == 16);
158
	memset(lla, 0, IPaddrlen);
159
	lla[0]  = 0xFE;
160
	lla[1]  = 0x80;
161
	lla[8]  = ea[0] | 0x2;
162
	lla[9]  = ea[1];
163
	lla[10] = ea[2];
164
	lla[11] = 0xFF;
165
	lla[12] = 0xFE;
166
	lla[13] = ea[3];
167
	lla[14] = ea[4];
168
	lla[15] = ea[5];
169
}
170
 
171
extern void
172
ipv62smcast(uchar *smcast, uchar *a)
173
{
174
	assert(IPaddrlen == 16);
175
	memset(smcast, 0, IPaddrlen);
176
	smcast[0]  = 0xFF;
177
	smcast[1]  = 0x02;
178
	smcast[11] = 0x1;
179
	smcast[12] = 0xFF;
180
	smcast[13] = a[13];
181
	smcast[14] = a[14];
182
	smcast[15] = a[15];
183
}
184
 
185
void
186
v6paraminit(Conf *cf)
187
{
188
	cf->sendra = cf->recvra = 0;
189
	cf->mflag = 0;
190
	cf->oflag = 0;
191
	cf->maxraint = Maxv6initraintvl;
192
	cf->minraint = Maxv6initraintvl / 4;
193
	cf->linkmtu = 1500;
194
	cf->reachtime = V6reachabletime;
195
	cf->rxmitra = V6retranstimer;
196
	cf->ttl = MAXTTL;
197
 
198
	cf->routerlt = 0;
199
 
200
	cf->prefixlen = 64;
201
	cf->onlink = 0;
202
	cf->autoflag = 0;
203
	cf->validlt = cf->preflt = ~0L;
204
}
205
 
206
static char *
207
optname(unsigned opt)
208
{
209
	static char buf[32];
210
 
211
	if (opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) {
212
		snprint(buf, sizeof buf, "unknown option %d", opt);
213
		return buf;
214
	} else
215
		return icmp6opts[opt];
216
}
217
 
218
static char*
219
opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
220
{
221
	int otype, osz, pktsz;
222
	uchar *a;
223
	char *p = sps, *e = spe;
224
 
225
	a = ps;
226
	for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) {
227
		otype = a[0];
228
		osz = a[1] * 8;
229
 
230
		switch (otype) {
231
		default:
232
			return seprint(p, e, " option=%s ", optname(otype));
233
		case V6nd_srclladdr:
234
		case V6nd_targlladdr:
235
			if (pktsz < osz || osz != 8)
236
				return seprint(p, e, " option=%s bad size=%d",
237
					optname(otype), osz);
238
			p = seprint(p, e, " option=%s maddr=%E", optname(otype),
239
				a+2);
240
			break;
241
		case V6nd_pfxinfo:
242
			if (pktsz < osz || osz != 32)
243
				return seprint(p, e, " option=%s: bad size=%d",
244
					optname(otype), osz);
245
 
246
			p = seprint(p, e, " option=%s pref=%I preflen=%3.3d"
247
				" lflag=%1.1d aflag=%1.1d unused1=%1.1d"
248
				" validlt=%ud preflt=%ud unused2=%1.1d",
249
				optname(otype), a+16, (int)(*(a+2)),
250
				(*(a+3) & (1 << 7)) != 0,
251
				(*(a+3) & (1 << 6)) != 0,
252
				(*(a+3) & 63) != 0,
253
				NetL(a+4), NetL(a+8), NetL(a+12)!=0);
254
			break;
255
		}
256
		a += osz;
257
	}
258
	return p;
259
}
260
 
261
static void
262
pkt2str(uchar *ps, uchar *pe, char *sps, char *spe)
263
{
264
	int pktlen;
265
	char *tn, *p, *e;
266
	uchar *a;
267
	Hdr *h;
268
 
269
	h = (Hdr*)ps;
270
	a = ps + 4;
271
	p = sps;
272
	e = spe;
273
 
274
	pktlen = pe - ps;
275
	if(pktlen < ICMP6LEN) {
276
		seprint(sps, spe, "short pkt");
277
		return;
278
	}
279
 
280
	tn = icmpmsg6[h->type];
281
	if(tn == nil)
282
		p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
283
			h->code, (ushort)NetS(h->cksum));
284
	else
285
		p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
286
			h->code, (ushort)NetS(h->cksum));
287
 
288
	switch(h->type){
289
	case RouterSolicit:
290
		ps += 8;
291
		p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
292
		opt_seprint(ps, pe, p, e);
293
		break;
294
	case RouterAdvert:
295
		ps += 16;
296
		p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d"
297
			" unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d",
298
			a[0],
299
			(*(a+1) & (1 << 7)) != 0,
300
			(*(a+1) & (1 << 6)) != 0,
301
			(*(a+1) & 63) != 0,
302
			NetS(a+2), NetL(a+4), NetL(a+8));
303
		opt_seprint(ps, pe, p, e);
304
		break;
305
	default:
306
		seprint(p, e, " unexpected icmp6 pkt type");
307
		break;
308
	}
309
}
310
 
311
static void
312
catch(void *a, char *msg)
313
{
314
	USED(a);
315
	if(strstr(msg, "alarm"))
316
		noted(NCONT);
317
	else
318
		noted(NDFLT);
319
}
320
 
321
/*
322
 * based on libthread's threadsetname, but drags in less library code.
323
 * actually just sets the arguments displayed.
324
 */
325
void
326
procsetname(char *fmt, ...)
327
{
328
	int fd;
329
	char *cmdname;
330
	char buf[128];
331
	va_list arg;
332
 
333
	va_start(arg, fmt);
334
	cmdname = vsmprint(fmt, arg);
335
	va_end(arg);
336
	if (cmdname == nil)
337
		return;
338
	snprint(buf, sizeof buf, "#p/%d/args", getpid());
339
	if((fd = open(buf, OWRITE)) >= 0){
340
		write(fd, cmdname, strlen(cmdname)+1);
341
		close(fd);
342
	}
343
	free(cmdname);
344
}
345
 
346
int
347
dialicmp(uchar *dst, int dport, int *ctlfd)
348
{
349
	int fd, cfd, n, m;
350
	char cmsg[100], name[128], connind[40];
351
	char hdrs[] = "headers";
352
 
353
	snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint);
354
	cfd = open(name, ORDWR);
355
	if(cfd < 0)
356
		sysfatal("dialicmp: can't open %s: %r", name);
357
 
358
	n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport);
359
	m = write(cfd, cmsg, n);
360
	if (m < n)
361
		sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name);
362
 
363
	seek(cfd, 0, 0);
364
	n = read(cfd, connind, sizeof connind);
365
	if (n < 0)
366
		connind[0] = 0;
367
	else if (n < sizeof connind)
368
		connind[n] = 0;
369
	else
370
		connind[sizeof connind - 1] = 0;
371
 
372
	snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind);
373
	fd = open(name, ORDWR);
374
	if(fd < 0)
375
		sysfatal("dialicmp: can't open %s: %r", name);
376
 
377
	n = sizeof hdrs - 1;
378
	if(write(cfd, hdrs, n) < n)
379
		sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name);
380
	*ctlfd = cfd;
381
	return fd;
382
}
383
 
384
/* add ipv6 addr to an interface */
385
int
386
ip6cfg(int autoconf)
387
{
388
	int dupfound = 0, n;
389
	char *p;
390
	char buf[256];
391
	uchar ethaddr[6];
392
	Biobuf *bp;
393
 
394
	if (autoconf) {			/* create link-local addr */
395
		if (myetheraddr(ethaddr, conf.dev) < 0)
396
			sysfatal("myetheraddr w/ %s failed: %r", conf.dev);
397
		ea2lla(conf.laddr, ethaddr);
398
	}
399
 
400
	if (dupl_disc)
401
		n = sprint(buf, "try");
402
	else
403
		n = sprint(buf, "add");
404
 
405
	n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
406
	if(!validip(conf.mask))
407
		ipmove(conf.mask, v6defmask);
408
	n += snprint(buf+n, sizeof buf-n, " %M", conf.mask);
409
	if(validip(conf.raddr)){
410
		n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
411
		if(conf.mtu != 0)
412
			n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
413
	}
414
 
415
	if(write(conf.cfd, buf, n) < 0){
416
		warning("write(%s): %r", buf);
417
		return -1;
418
	}
419
 
420
	if (!dupl_disc)
421
		return 0;
422
 
423
	sleep(3000);
424
 
425
	/* read arp table, look for addr duplication */
426
	snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
427
	bp = Bopen(buf, OREAD);
428
	if (bp == 0) {
429
		warning("couldn't open %s: %r", buf);
430
		return -1;
431
	}
432
 
433
	snprint(buf, sizeof buf, "%I", conf.laddr);
434
	while(p = Brdline(bp, '\n')){
435
		p[Blinelen(bp)-1] = 0;
436
		if(cistrstr(p, buf) != 0) {
437
			warning("found dup entry in arp cache");
438
			dupfound = 1;
439
			break;
440
		}
441
	}
442
	Bterm(bp);
443
 
444
	if (dupfound)
445
		doremove();
446
	else {
447
		n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
448
		if(validip(conf.raddr)){
449
			n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
450
			if(conf.mtu != 0)
451
				n += snprint(buf+n, sizeof buf-n, " %d",
452
					conf.mtu);
453
		}
454
		write(conf.cfd, buf, n);
455
	}
456
	return 0;
457
}
458
 
459
static int
460
recvra6on(char *net, int conn)
461
{
462
	Ipifc* ifc;
463
 
464
	ifc = readipifc(net, nil, conn);
465
	if (ifc == nil)
466
		return 0;
467
	else if (ifc->sendra6 > 0)
468
		return IsRouter;
469
	else if (ifc->recvra6 > 0)
470
		return IsHostRecv;
471
	else
472
		return IsHostNoRecv;
473
}
474
 
475
/* send icmpv6 router solicitation to multicast address for all routers */
476
static void
477
sendrs(int fd)
478
{
479
	Routersol *rs;
480
	uchar buff[sizeof *rs];
481
 
482
	memset(buff, 0, sizeof buff);
483
	rs = (Routersol *)buff;
484
	memmove(rs->dst, v6allroutersL, IPaddrlen);
485
	memmove(rs->src, v6Unspecified, IPaddrlen);
486
	rs->type = ICMP6_RS;
487
 
488
	if(write(fd, rs, sizeof buff) < sizeof buff)
489
		ralog("sendrs: write failed, pkt size %d", sizeof buff);
490
	else
491
		ralog("sendrs: sent solicitation to %I from %I on %s",
492
			rs->dst, rs->src, conf.dev);
493
}
494
 
495
/*
496
 * a router receiving a router adv from another
497
 * router calls this; it is basically supposed to
498
 * log the information in the ra and raise a flag
499
 * if any parameter value is different from its configured values.
500
 *
501
 * doing nothing for now since I don't know where to log this yet.
502
 */
503
static void
504
recvrarouter(uchar buf[], int pktlen)
505
{
506
	USED(buf, pktlen);
507
	ralog("i am a router and got a router advert");
508
}
509
 
510
/* host receiving a router advertisement calls this */
511
 
512
static void
513
ewrite(int fd, char *str)
514
{
515
	int n;
516
 
517
	n = strlen(str);
518
	if (write(fd, str, n) != n)
519
		ralog("write(%s) failed: %r", str);
520
}
521
 
522
static void
523
issuebasera6(Conf *cf)
524
{
525
	char *cfg;
526
 
527
	cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d "
528
		"ttl %d routerlt %d",
529
		cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra,
530
		cf->ttl, cf->routerlt);
531
	ewrite(cf->cfd, cfg);
532
	free(cfg);
533
}
534
 
535
static void
536
issuerara6(Conf *cf)
537
{
538
	char *cfg;
539
 
540
	cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d "
541
		"linkmtu %d",
542
		cf->sendra, cf->recvra, cf->maxraint, cf->minraint,
543
		cf->linkmtu);
544
	ewrite(cf->cfd, cfg);
545
	free(cfg);
546
}
547
 
548
static void
549
issueadd6(Conf *cf)
550
{
551
	char *cfg;
552
 
553
	cfg = smprint("add6 %I %d %d %d %lud %lud", cf->v6pref, cf->prefixlen,
554
		cf->onlink, cf->autoflag, cf->validlt, cf->preflt);
555
	ewrite(cf->cfd, cfg);
556
	free(cfg);
557
}
558
 
559
static void
560
recvrahost(uchar buf[], int pktlen)
561
{
562
	int arpfd, m, n;
563
	char abuf[100];
564
	uchar optype;
565
	Lladdropt *llao;
566
	Mtuopt *mtuo;
567
	Prefixopt *prfo;
568
	Routeradv *ra;
569
	static int first = 1;
570
 
571
	ra = (Routeradv*)buf;
572
//	memmove(conf.v6gaddr, ra->src, IPaddrlen);
573
	conf.ttl = ra->cttl;
574
	conf.mflag = (MFMASK & ra->mor);
575
	conf.oflag = (OCMASK & ra->mor);
576
	conf.routerlt =  nhgets(ra->routerlt);
577
	conf.reachtime = nhgetl(ra->rchbltime);
578
	conf.rxmitra =   nhgetl(ra->rxmtimer);
579
 
580
//	issueadd6(&conf);		/* for conf.v6gaddr? */
581
	if (fprint(conf.cfd, "ra6 recvra 1") < 0)
582
		ralog("write(ra6 recvra 1) failed: %r");
583
	issuebasera6(&conf);
584
 
585
	m = sizeof *ra;
586
	while (pktlen - m > 0) {
587
		optype = buf[m];
588
		switch (optype) {
589
		case V6nd_srclladdr:
590
			llao = (Lladdropt *)&buf[m];
591
			m += 8 * buf[m+1];
592
			if (llao->len != 1) {
593
				ralog("recvrahost: illegal len (%d) for source "
594
					"link layer address option", llao->len);
595
				return;
596
			}
597
			if (!ISIPV6LINKLOCAL(ra->src)) {
598
				ralog("recvrahost: non-link-local src addr for "
599
					"router adv %I", ra->src);
600
				return;
601
			}
602
 
603
			snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
604
			arpfd = open(abuf, OWRITE);
605
			if (arpfd < 0) {
606
				ralog("recvrahost: couldn't open %s to write: %r",
607
					abuf);
608
				return;
609
			}
610
 
611
			n = snprint(abuf, sizeof abuf, "add ether %I %E",
612
				ra->src, llao->lladdr);
613
			if (write(arpfd, abuf, n) < n)
614
				ralog("recvrahost: couldn't write to %s/arp",
615
					conf.mpoint);
616
			close(arpfd);
617
			break;
618
		case V6nd_targlladdr:
619
		case V6nd_redirhdr:
620
			m += 8 * buf[m+1];
621
			ralog("ignoring unexpected option type `%s' in Routeradv",
622
				optname(optype));
623
			break;
624
		case V6nd_mtu:
625
			mtuo = (Mtuopt*)&buf[m];
626
			m += 8 * mtuo->len;
627
			conf.linkmtu = nhgetl(mtuo->mtu);
628
			break;
629
		case V6nd_pfxinfo:
630
			prfo = (Prefixopt*)&buf[m];
631
			m += 8 * prfo->len;
632
			if (prfo->len != 4) {
633
				ralog("illegal len (%d) for prefix option",
634
					prfo->len);
635
				return;
636
			}
637
			memmove(conf.v6pref, prfo->pref, IPaddrlen);
638
			conf.prefixlen = prfo->plen;
639
			conf.onlink =   ((prfo->lar & OLMASK) != 0);
640
			conf.autoflag = ((prfo->lar & AFMASK) != 0);
641
			conf.validlt = nhgetl(prfo->validlt);
642
			conf.preflt =  nhgetl(prfo->preflt);
643
			issueadd6(&conf);
644
			if (first) {
645
				first = 0;
646
				ralog("got initial RA from %I on %s; pfx %I",
647
					ra->src, conf.dev, prfo->pref);
648
			}
649
			break;
650
		default:
651
			if (debug)
652
				ralog("ignoring optype %d in Routeradv from %I",
653
					optype, ra->src);
654
			/* fall through */
655
		case V6nd_srcaddrs:
656
			/* netsbd sends this, so quietly ignore it for now */
657
			m += 8 * buf[m+1];
658
			break;
659
		}
660
	}
661
}
662
 
663
/*
664
 * daemon to receive router advertisements from routers
665
 */
666
void
667
recvra6(void)
668
{
669
	int fd, cfd, n, sendrscnt, sleepfor;
670
	uchar buf[4096];
671
 
672
	/* TODO: why not v6allroutersL? */
673
	fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
674
	if (fd < 0)
675
		sysfatal("can't open icmp_ra connection: %r");
676
 
677
	notify(catch);
678
	sendrscnt = Maxv6rss;
679
 
680
	switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
681
	case -1:
682
		sysfatal("can't fork: %r");
683
	default:
684
		return;
685
	case 0:
686
		break;
687
	}
688
 
689
	procsetname("recvra6 on %s", conf.dev);
690
	ralog("recvra6 on %s", conf.dev);
691
	sleepfor = jitter();
692
	for (;;) {
693
		/*
694
		 * We only get 3 (Maxv6rss) tries, so make sure we
695
		 * wait long enough to be certain that at least one RA
696
		 * will be transmitted.
697
		 */
698
		if (sleepfor < 7000)
699
			sleepfor = 7000;
700
		alarm(sleepfor);
701
		n = read(fd, buf, sizeof buf);
702
		alarm(0);
703
		if (n <= 0) {
704
			if (sendrscnt > 0) {
705
				sendrscnt--;
706
				if (recvra6on(conf.mpoint, myifc) == IsHostRecv)
707
					sendrs(fd);
708
				sleepfor = V6rsintvl + nrand(100);
709
			}
710
			if (sendrscnt == 0) {
711
				sendrscnt--;
712
				sleepfor = 0;
713
				ralog("recvra6: no router advs after %d sols on %s",
714
					Maxv6rss, conf.dev);
715
			}
716
			continue;
717
		}
718
 
719
		sleepfor = 0;
720
		sendrscnt = -1;		/* got at least initial ra; no whining */
721
		switch (recvra6on(conf.mpoint, myifc)) {
722
		case IsRouter:
723
			recvrarouter(buf, n);
724
			break;
725
		case IsHostRecv:
726
			recvrahost(buf, n);
727
			break;
728
		case IsHostNoRecv:
729
			ralog("recvra6: recvra off, quitting on %s", conf.dev);
730
			close(fd);
731
			exits(0);
732
		default:
733
			ralog("recvra6: unable to read router status on %s",
734
				conf.dev);
735
			break;
736
		}
737
	}
738
}
739
 
740
/*
741
 * return -1 -- error, reading/writing some file,
742
 *         0 -- no arp table updates
743
 *         1 -- successful arp table update
744
 */
745
int
746
recvrs(uchar *buf, int pktlen, uchar *sol)
747
{
748
	int n, optsz, arpfd;
749
	char abuf[256];
750
	Routersol *rs;
751
	Lladdropt *llao;
752
 
753
	rs = (Routersol *)buf;
754
	n = sizeof *rs;
755
	optsz = pktlen - n;
756
	pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
757
 
758
	if (optsz != sizeof *llao)
759
		return 0;
760
	if (buf[n] != V6nd_srclladdr || 8*buf[n+1] != sizeof *llao) {
761
		ralog("rs opt err %s", abuf);
762
		return -1;
763
	}
764
 
765
	ralog("rs recv %s", abuf);
766
 
767
	if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
768
		return 0;
769
 
770
	snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
771
	arpfd = open(abuf, OWRITE);
772
	if (arpfd < 0) {
773
		ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
774
		return -1;
775
	}
776
 
777
	llao = (Lladdropt *)buf[n];
778
	n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
779
	if (write(arpfd, abuf, n) < n) {
780
		ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
781
		close(arpfd);
782
		return -1;
783
	}
784
 
785
	memmove(sol, rs->src, IPaddrlen);
786
	close(arpfd);
787
	return 1;
788
}
789
 
790
void
791
sendra(int fd, uchar *dst, int rlt)
792
{
793
	int pktsz, preflen;
794
	char abuf[1024], tmp[40];
795
	uchar buf[1024], macaddr[6], src[IPaddrlen];
796
	Ipifc *ifc = nil;
797
	Iplifc *lifc, *nlifc;
798
	Lladdropt *llao;
799
	Prefixopt *prfo;
800
	Routeradv *ra;
801
 
802
	memset(buf, 0, sizeof buf);
803
	ra = (Routeradv *)buf;
804
 
805
	myetheraddr(macaddr, conf.dev);
806
	ea2lla(src, macaddr);
807
	memmove(ra->src, src, IPaddrlen);
808
	memmove(ra->dst, dst, IPaddrlen);
809
	ra->type = ICMP6_RA;
810
	ra->cttl = conf.ttl;
811
 
812
	if (conf.mflag > 0)
813
		ra->mor |= MFMASK;
814
	if (conf.oflag > 0)
815
		ra->mor |= OCMASK;
816
	if (rlt > 0)
817
		hnputs(ra->routerlt, conf.routerlt);
818
	else
819
		hnputs(ra->routerlt, 0);
820
	hnputl(ra->rchbltime, conf.reachtime);
821
	hnputl(ra->rxmtimer, conf.rxmitra);
822
 
823
	pktsz = sizeof *ra;
824
 
825
	/* include all global unicast prefixes on interface in prefix options */
826
	ifc = readipifc(conf.mpoint, ifc, myifc);
827
	for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
828
		nlifc = lifc->next;
829
		prfo = (Prefixopt *)(buf + pktsz);
830
		/* global unicast address? */
831
		if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) &&
832
		    memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 &&
833
		    memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 &&
834
		    !isv4(lifc->ip)) {
835
			memmove(prfo->pref, lifc->net, IPaddrlen);
836
 
837
			/* hack to find prefix length */
838
			snprint(tmp, sizeof tmp, "%M", lifc->mask);
839
			preflen = atoi(&tmp[1]);
840
			prfo->plen = preflen & 0xff;
841
			if (prfo->plen == 0)
842
				continue;
843
 
844
			prfo->type = V6nd_pfxinfo;
845
			prfo->len = 4;
846
			prfo->lar = AFMASK;
847
			hnputl(prfo->validlt, lifc->validlt);
848
			hnputl(prfo->preflt, lifc->preflt);
849
			pktsz += sizeof *prfo;
850
		}
851
	}
852
	/*
853
	 * include link layer address (mac address for now) in
854
	 * link layer address option
855
	 */
856
	llao = (Lladdropt *)(buf + pktsz);
857
	llao->type = V6nd_srclladdr;
858
	llao->len = 1;
859
	memmove(llao->lladdr, macaddr, sizeof macaddr);
860
	pktsz += sizeof *llao;
861
 
862
	pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
863
	if(write(fd, buf, pktsz) < pktsz)
864
		ralog("sendra fail %s: %r", abuf);
865
	else if (debug)
866
		ralog("sendra succ %s", abuf);
867
}
868
 
869
/*
870
 * daemon to send router advertisements to hosts
871
 */
872
void
873
sendra6(void)
874
{
875
	int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
876
	long lastra, now;
877
	uchar buf[4096], dst[IPaddrlen];
878
	Ipifc *ifc = nil;
879
 
880
	fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
881
	if (fd < 0)
882
		sysfatal("can't open icmp_rs connection: %r");
883
 
884
	notify(catch);
885
	sendracnt = Maxv6initras;
886
	nquitmsgs = Maxv6finalras;
887
 
888
	switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
889
	case -1:
890
		sysfatal("can't fork: %r");
891
	default:
892
		return;
893
	case 0:
894
		break;
895
	}
896
 
897
	procsetname("sendra6 on %s", conf.dev);
898
	ralog("sendra6 on %s", conf.dev);
899
	sleepfor = jitter();
900
	for (;;) {
901
		lastra = time(0);
902
		if (sleepfor < 0)
903
			sleepfor = 0;
904
		alarm(sleepfor);
905
		n = read(fd, buf, sizeof buf);
906
		alarm(0);
907
 
908
		ifc = readipifc(conf.mpoint, ifc, myifc);
909
		if (ifc == nil) {
910
			ralog("sendra6: can't read router params on %s",
911
				conf.mpoint);
912
			continue;
913
		}
914
 
915
		if (ifc->sendra6 <= 0)
916
			if (nquitmsgs > 0) {
917
				sendra(fd, v6allnodesL, 0);
918
				nquitmsgs--;
919
				sleepfor = Minv6interradelay + jitter();
920
				continue;
921
			} else {
922
				ralog("sendra6: sendra off, quitting on %s",
923
					conf.dev);
924
				exits(0);
925
			}
926
 
927
		nquitmsgs = Maxv6finalras;
928
 
929
		if (n <= 0) {			/* no RS */
930
			if (sendracnt > 0)
931
				sendracnt--;
932
		} else {			/* respond to RS */
933
			dstknown = recvrs(buf, n, dst);
934
			now = time(0);
935
 
936
			if (now - lastra < Minv6interradelay) {
937
				/* too close, skip */
938
				sleepfor = lastra + Minv6interradelay +
939
					jitter() - now;
940
				continue;
941
			}
942
			sleep(jitter());
943
		}
944
		sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
945
		if (dstknown > 0)
946
			sendra(fd, dst, 1);
947
		else
948
			sendra(fd, v6allnodesL, 1);
949
	}
950
}
951
 
952
void
953
startra6(void)
954
{
955
	static char routeon[] = "iprouting 1";
956
 
957
	if (conf.recvra > 0)
958
		recvra6();
959
 
960
	if (conf.sendra > 0) {
961
		if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
962
			warning("write (iprouting 1) failed: %r");
963
			return;
964
		}
965
		sendra6();
966
		if (conf.recvra <= 0)
967
			recvra6();
968
	}
969
}
970
 
971
void
972
doipv6(int what)
973
{
974
	nip = nipifcs(conf.mpoint);
975
	if(!noconfig){
976
		lookforip(conf.mpoint);
977
		controldevice();
978
		binddevice();
979
	}
980
 
981
	switch (what) {
982
	default:
983
		sysfatal("unknown IPv6 verb");
984
	case Vaddpref6:
985
		issueadd6(&conf);
986
		break;
987
	case Vra6:
988
		issuebasera6(&conf);
989
		issuerara6(&conf);
990
		dolog = 1;
991
		startra6();
992
		break;
993
	}
994
}