Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "../port/error.h"
7
 
8
#include "ip.h"
9
#include "ipv6.h"
10
 
11
#define DPRINT if(0)print
12
 
13
enum {
14
	Maxmedia	= 32,
15
	Nself		= Maxmedia*5,
16
	NHASH		= 1<<6,
17
	NCACHE		= 256,
18
	QMAX		= 192*1024-1,
19
	Maxv6repr	= (128/(4*4))*(4+1), /* limit of xxxx:xxxx:⋯ notation */
20
};
21
 
22
Medium *media[Maxmedia] = { 0 };
23
 
24
/*
25
 *  cache of local addresses (addresses we answer to)
26
 */
27
struct Ipself
28
{
29
	uchar	a[IPaddrlen];
30
	Ipself	*hnext;		/* next address in the hash table */
31
	Iplink	*link;		/* binding twixt Ipself and Ipifc */
32
	ulong	expire;
33
	uchar	type;		/* type of address */
34
	int	ref;
35
	Ipself	*next;		/* free list */
36
};
37
 
38
struct Ipselftab
39
{
40
	QLock;
41
	int	inited;
42
	int	acceptall;	/* true if an interface has the null address */
43
	Ipself	*hash[NHASH];	/* hash chains */
44
};
45
 
46
/*
47
 *  Multicast addresses are chained onto a Chan so that
48
 *  we can remove them when the Chan is closed.
49
 */
50
typedef struct Ipmcast Ipmcast;
51
struct Ipmcast
52
{
53
	Ipmcast	*next;
54
	uchar	ma[IPaddrlen];	/* multicast address */
55
	uchar	ia[IPaddrlen];	/* interface address */
56
};
57
 
58
/* quick hash for ip addresses */
59
#define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
60
 
61
static char tifc[] = "ifc ";
62
 
63
static void	addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
64
static void	remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
65
static char*	ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
66
static char*	ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
67
static void	ipifcregisterproxy(Fs*, Ipifc*, uchar*);
68
static char*	ipifcremlifc(Ipifc*, Iplifc*);
69
 
70
/*
71
 *  link in a new medium
72
 */
73
void
74
addipmedium(Medium *med)
75
{
76
	int i;
77
 
78
	for(i = 0; i < nelem(media)-1; i++)
79
		if(media[i] == nil){
80
			media[i] = med;
81
			break;
82
		}
83
}
84
 
85
/*
86
 *  find the medium with this name
87
 */
88
Medium*
89
ipfindmedium(char *name)
90
{
91
	Medium **mp;
92
 
93
	for(mp = media; *mp != nil; mp++)
94
		if(strcmp((*mp)->name, name) == 0)
95
			break;
96
	return *mp;
97
}
98
 
99
/*
100
 *  attach a device (or pkt driver) to the interface.
101
 *  called with c locked
102
 */
103
static char*
104
ipifcbind(Conv *c, char **argv, int argc)
105
{
106
	Ipifc *ifc;
107
	Medium *m;
108
 
109
	if(argc < 2)
110
		return Ebadarg;
111
 
112
	ifc = (Ipifc*)c->ptcl;
113
 
114
	/* bind the device to the interface */
115
	m = ipfindmedium(argv[1]);
116
	if(m == nil)
117
		return "unknown interface type";
118
 
119
	wlock(ifc);
120
	if(ifc->m != nil){
121
		wunlock(ifc);
122
		return "interface already bound";
123
	}
124
	if(waserror()){
125
		wunlock(ifc);
126
		nexterror();
127
	}
128
 
129
	/* do medium specific binding */
130
	(*m->bind)(ifc, argc, argv);
131
 
132
	/* set the bound device name */
133
	if(argc > 2)
134
		strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
135
	else
136
		snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
137
	ifc->dev[sizeof(ifc->dev)-1] = 0;
138
 
139
	/* set up parameters */
140
	ifc->m = m;
141
	ifc->mintu = ifc->m->mintu;
142
	ifc->maxtu = ifc->m->maxtu;
143
	if(ifc->m->unbindonclose == 0)
144
		ifc->conv->inuse++;
145
	ifc->rp.mflag = 0;		/* default not managed */
146
	ifc->rp.oflag = 0;
147
	ifc->rp.maxraint = 600000;	/* millisecs */
148
	ifc->rp.minraint = 200000;
149
	ifc->rp.linkmtu = 0;		/* no mtu sent */
150
	ifc->rp.reachtime = 0;
151
	ifc->rp.rxmitra = 0;
152
	ifc->rp.ttl = MAXTTL;
153
	ifc->rp.routerlt = 3 * ifc->rp.maxraint;
154
 
155
	/* any ancillary structures (like routes) no longer pertain */
156
	ifc->ifcid++;
157
 
158
	/* reopen all the queues closed by a previous unbind */
159
	qreopen(c->rq);
160
	qreopen(c->eq);
161
	qreopen(c->sq);
162
 
163
	wunlock(ifc);
164
	poperror();
165
 
166
	return nil;
167
}
168
 
169
/*
170
 *  detach a device from an interface, close the interface
171
 *  called with ifc->conv closed
172
 */
173
static char*
174
ipifcunbind(Ipifc *ifc)
175
{
176
	char *err;
177
 
178
	if(waserror()){
179
		wunlock(ifc);
180
		nexterror();
181
	}
182
	wlock(ifc);
183
 
184
	/* dissociate routes */
185
	if(ifc->m != nil && ifc->m->unbindonclose == 0)
186
		ifc->conv->inuse--;
187
	ifc->ifcid++;
188
 
189
	/* disassociate logical interfaces (before zeroing ifc->arg) */
190
	while(ifc->lifc){
191
		err = ipifcremlifc(ifc, ifc->lifc);
192
		/*
193
		 * note: err non-zero means lifc not found,
194
		 * which can't happen in this case.
195
		 */
196
		if(err)
197
			error(err);
198
	}
199
 
200
	/* disassociate device */
201
	if(ifc->m && ifc->m->unbind)
202
		(*ifc->m->unbind)(ifc);
203
	memset(ifc->dev, 0, sizeof(ifc->dev));
204
	ifc->arg = nil;
205
	ifc->reassemble = 0;
206
 
207
	/* close queues to stop queuing of packets */
208
	qclose(ifc->conv->rq);
209
	qclose(ifc->conv->wq);
210
	qclose(ifc->conv->sq);
211
 
212
	ifc->m = nil;
213
	wunlock(ifc);
214
	poperror();
215
	return nil;
216
}
217
 
218
char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
219
" %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
220
" %d pktin %lud pktout %lud errin %lud errout %lud\n";
221
 
222
char slineformat[] = "	%-40I %-10M %-40I %-12lud %-12lud\n";
223
 
224
static int
225
ipifcstate(Conv *c, char *state, int n)
226
{
227
	Ipifc *ifc;
228
	Iplifc *lifc;
229
	int m;
230
 
231
	ifc = (Ipifc*)c->ptcl;
232
	m = snprint(state, n, sfixedformat,
233
		ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
234
		ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
235
		ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
236
		ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
237
		ifc->in, ifc->out, ifc->inerr, ifc->outerr);
238
 
239
	rlock(ifc);
240
	for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
241
		m += snprint(state+m, n - m, slineformat, lifc->local,
242
			lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
243
	if(ifc->lifc == nil)
244
		m += snprint(state+m, n - m, "\n");
245
	runlock(ifc);
246
	return m;
247
}
248
 
249
static int
250
ipifclocal(Conv *c, char *state, int n)
251
{
252
	Ipifc *ifc;
253
	Iplifc *lifc;
254
	Iplink *link;
255
	int m;
256
 
257
	ifc = (Ipifc*)c->ptcl;
258
	m = 0;
259
 
260
	rlock(ifc);
261
	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
262
		m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
263
		for(link = lifc->link; link; link = link->lifclink)
264
			m += snprint(state+m, n - m, " %-40.40I", link->self->a);
265
		m += snprint(state+m, n - m, "\n");
266
	}
267
	runlock(ifc);
268
	return m;
269
}
270
 
271
static int
272
ipifcinuse(Conv *c)
273
{
274
	Ipifc *ifc;
275
 
276
	ifc = (Ipifc*)c->ptcl;
277
	return ifc->m != nil;
278
}
279
 
280
/*
281
 *  called when a process writes to an interface's 'data'
282
 */
283
static void
284
ipifckick(void *x)
285
{
286
	Conv *c = x;
287
	Block *bp;
288
	Ipifc *ifc;
289
 
290
	bp = qget(c->wq);
291
	if(bp == nil)
292
		return;
293
 
294
	ifc = (Ipifc*)c->ptcl;
295
	if(!canrlock(ifc)){
296
		freeb(bp);
297
		return;
298
	}
299
	if(waserror()){
300
		runlock(ifc);
301
		nexterror();
302
	}
303
	if(ifc->m == nil || ifc->m->pktin == nil)
304
		freeb(bp);
305
	else
306
		(*ifc->m->pktin)(c->p->f, ifc, bp);
307
	runlock(ifc);
308
	poperror();
309
}
310
 
311
/*
312
 *  called when a new ipifc structure is created
313
 */
314
static void
315
ipifccreate(Conv *c)
316
{
317
	Ipifc *ifc;
318
 
319
	c->rq = qopen(QMAX, 0, 0, 0);
320
	c->sq = qopen(QMAX, 0, 0, 0);
321
	c->wq = qopen(QMAX, Qkick, ipifckick, c);
322
	ifc = (Ipifc*)c->ptcl;
323
	ifc->conv = c;
324
	ifc->unbinding = 0;
325
	ifc->m = nil;
326
	ifc->reassemble = 0;
327
}
328
 
329
/*
330
 *  called after last close of ipifc data or ctl
331
 *  called with c locked, we must unlock
332
 */
333
static void
334
ipifcclose(Conv *c)
335
{
336
	Ipifc *ifc;
337
	Medium *m;
338
 
339
	ifc = (Ipifc*)c->ptcl;
340
	m = ifc->m;
341
	if(m && m->unbindonclose)
342
		ipifcunbind(ifc);
343
}
344
 
345
/*
346
 *  change an interface's mtu
347
 */
348
char*
349
ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
350
{
351
	int mtu;
352
 
353
	if(argc < 2 || ifc->m == nil)
354
		return Ebadarg;
355
	mtu = strtoul(argv[1], 0, 0);
356
	if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
357
		return Ebadarg;
358
	ifc->maxtu = mtu;
359
	return nil;
360
}
361
 
362
/*
363
 *  add an address to an interface.
364
 */
365
char*
366
ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
367
{
368
	int i, type, mtu, sendnbrdisc = 0;
369
	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
370
	uchar bcast[IPaddrlen], net[IPaddrlen];
371
	Iplifc *lifc, **l;
372
	Fs *f;
373
 
374
	if(ifc->m == nil)
375
		return "ipifc not yet bound to device";
376
 
377
	f = ifc->conv->p->f;
378
 
379
	type = Rifc;
380
	memset(ip, 0, IPaddrlen);
381
	memset(mask, 0, IPaddrlen);
382
	memset(rem, 0, IPaddrlen);
383
	switch(argc){
384
	case 6:
385
		if(strcmp(argv[5], "proxy") == 0)
386
			type |= Rproxy;
387
		/* fall through */
388
	case 5:
389
		mtu = strtoul(argv[4], 0, 0);
390
		if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
391
			ifc->maxtu = mtu;
392
		/* fall through */
393
	case 4:
394
		if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
395
			return Ebadip;
396
		parseipmask(mask, argv[2]);
397
		maskip(rem, mask, net);
398
		break;
399
	case 3:
400
		if (parseip(ip, argv[1]) == -1)
401
			return Ebadip;
402
		parseipmask(mask, argv[2]);
403
		maskip(ip, mask, rem);
404
		maskip(rem, mask, net);
405
		break;
406
	case 2:
407
		if (parseip(ip, argv[1]) == -1)
408
			return Ebadip;
409
		memmove(mask, defmask(ip), IPaddrlen);
410
		maskip(ip, mask, rem);
411
		maskip(rem, mask, net);
412
		break;
413
	default:
414
		return Ebadarg;
415
	}
416
	if(isv4(ip))
417
		tentative = 0;
418
	wlock(ifc);
419
 
420
	/* ignore if this is already a local address for this ifc */
421
	for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
422
		if(ipcmp(lifc->local, ip) == 0) {
423
			if(lifc->tentative != tentative)
424
				lifc->tentative = tentative;
425
			if(lifcp) {
426
				lifc->onlink = lifcp->onlink;
427
				lifc->autoflag = lifcp->autoflag;
428
				lifc->validlt = lifcp->validlt;
429
				lifc->preflt = lifcp->preflt;
430
				lifc->origint = lifcp->origint;
431
			}
432
			goto out;
433
		}
434
	}
435
 
436
	/* add the address to the list of logical ifc's for this ifc */
437
	lifc = smalloc(sizeof(Iplifc));
438
	ipmove(lifc->local, ip);
439
	ipmove(lifc->mask, mask);
440
	ipmove(lifc->remote, rem);
441
	ipmove(lifc->net, net);
442
	lifc->tentative = tentative;
443
	if(lifcp) {
444
		lifc->onlink = lifcp->onlink;
445
		lifc->autoflag = lifcp->autoflag;
446
		lifc->validlt = lifcp->validlt;
447
		lifc->preflt = lifcp->preflt;
448
		lifc->origint = lifcp->origint;
449
	} else {		/* default values */
450
		lifc->onlink = lifc->autoflag = 1;
451
		lifc->validlt = lifc->preflt = ~0L;
452
		lifc->origint = NOW / 1000;
453
	}
454
	lifc->next = nil;
455
 
456
	for(l = &ifc->lifc; *l; l = &(*l)->next)
457
		;
458
	*l = lifc;
459
 
460
	/* check for point-to-point interface */
461
	if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
462
	if(ipcmp(mask, IPallbits) == 0)
463
		type |= Rptpt;
464
 
465
	/* add local routes */
466
	if(isv4(ip))
467
		v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
468
	else
469
		v6addroute(f, tifc, rem, mask, rem, type);
470
 
471
	addselfcache(f, ifc, lifc, ip, Runi);
472
 
473
	if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
474
		ipifcregisterproxy(f, ifc, rem);
475
		goto out;
476
	}
477
 
478
	if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
479
		/* add subnet directed broadcast address to the self cache */
480
		for(i = 0; i < IPaddrlen; i++)
481
			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
482
		addselfcache(f, ifc, lifc, bcast, Rbcast);
483
 
484
		/* add subnet directed network address to the self cache */
485
		for(i = 0; i < IPaddrlen; i++)
486
			bcast[i] = (ip[i] & mask[i]) & mask[i];
487
		addselfcache(f, ifc, lifc, bcast, Rbcast);
488
 
489
		/* add network directed broadcast address to the self cache */
490
		memmove(mask, defmask(ip), IPaddrlen);
491
		for(i = 0; i < IPaddrlen; i++)
492
			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
493
		addselfcache(f, ifc, lifc, bcast, Rbcast);
494
 
495
		/* add network directed network address to the self cache */
496
		memmove(mask, defmask(ip), IPaddrlen);
497
		for(i = 0; i < IPaddrlen; i++)
498
			bcast[i] = (ip[i] & mask[i]) & mask[i];
499
		addselfcache(f, ifc, lifc, bcast, Rbcast);
500
 
501
		addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
502
	}
503
	else {
504
		if(ipcmp(ip, v6loopback) == 0) {
505
			/* add node-local mcast address */
506
			addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
507
 
508
			/* add route for all node multicast */
509
			v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
510
				v6allnodesN, Rmulti);
511
		}
512
 
513
		/* add all nodes multicast address */
514
		addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
515
 
516
		/* add route for all nodes multicast */
517
		v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
518
			Rmulti);
519
 
520
		/* add solicited-node multicast address */
521
		ipv62smcast(bcast, ip);
522
		addselfcache(f, ifc, lifc, bcast, Rmulti);
523
 
524
		sendnbrdisc = 1;
525
	}
526
 
527
	/* register the address on this network for address resolution */
528
	if(isv4(ip) && ifc->m->areg != nil)
529
		(*ifc->m->areg)(ifc, ip);
530
 
531
out:
532
	wunlock(ifc);
533
	if(tentative && sendnbrdisc)
534
		icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
535
	return nil;
536
}
537
 
538
/*
539
 *  remove a logical interface from an ifc
540
 *  always called with ifc wlock'd
541
 */
542
static char*
543
ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
544
{
545
	Iplifc **l;
546
	Fs *f;
547
 
548
	f = ifc->conv->p->f;
549
 
550
	/*
551
	 *  find address on this interface and remove from chain.
552
	 *  for pt to pt we actually specify the remote address as the
553
	 *  addresss to remove.
554
	 */
555
	for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
556
		;
557
	if(*l == nil)
558
		return "address not on this interface";
559
	*l = lifc->next;
560
 
561
	/* disassociate any addresses */
562
	while(lifc->link)
563
		remselfcache(f, ifc, lifc, lifc->link->self->a);
564
 
565
	/* remove the route for this logical interface */
566
	if(isv4(lifc->local))
567
		v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
568
	else {
569
		v6delroute(f, lifc->remote, lifc->mask, 1);
570
		if(ipcmp(lifc->local, v6loopback) == 0)
571
			/* remove route for all node multicast */
572
			v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
573
		else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
574
			/* remove route for all link multicast */
575
			v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
576
	}
577
 
578
	free(lifc);
579
	return nil;
580
}
581
 
582
/*
583
 *  remove an address from an interface.
584
 *  called with c->car locked
585
 */
586
char*
587
ipifcrem(Ipifc *ifc, char **argv, int argc)
588
{
589
	char *rv;
590
	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
591
	Iplifc *lifc;
592
 
593
	if(argc < 3)
594
		return Ebadarg;
595
 
596
	if (parseip(ip, argv[1]) == -1)
597
		return Ebadip;
598
	parseipmask(mask, argv[2]);
599
	if(argc < 4)
600
		maskip(ip, mask, rem);
601
	else
602
		if (parseip(rem, argv[3]) == -1)
603
			return Ebadip;
604
 
605
	wlock(ifc);
606
 
607
	/*
608
	 *  find address on this interface and remove from chain.
609
	 *  for pt to pt we actually specify the remote address as the
610
	 *  addresss to remove.
611
	 */
612
	for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
613
		if (memcmp(ip, lifc->local, IPaddrlen) == 0
614
		&& memcmp(mask, lifc->mask, IPaddrlen) == 0
615
		&& memcmp(rem, lifc->remote, IPaddrlen) == 0)
616
			break;
617
	}
618
 
619
	rv = ipifcremlifc(ifc, lifc);
620
	wunlock(ifc);
621
	return rv;
622
}
623
 
624
/*
625
 * distribute routes to active interfaces like the
626
 * TRIP linecards
627
 */
628
void
629
ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
630
{
631
	Medium *m;
632
	Conv **cp, **e;
633
	Ipifc *ifc;
634
 
635
	e = &f->ipifc->conv[f->ipifc->nc];
636
	for(cp = f->ipifc->conv; cp < e; cp++){
637
		if(*cp != nil) {
638
			ifc = (Ipifc*)(*cp)->ptcl;
639
			m = ifc->m;
640
			if(m && m->addroute)
641
				m->addroute(ifc, vers, addr, mask, gate, type);
642
		}
643
	}
644
}
645
 
646
void
647
ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
648
{
649
	Medium *m;
650
	Conv **cp, **e;
651
	Ipifc *ifc;
652
 
653
	e = &f->ipifc->conv[f->ipifc->nc];
654
	for(cp = f->ipifc->conv; cp < e; cp++){
655
		if(*cp != nil) {
656
			ifc = (Ipifc*)(*cp)->ptcl;
657
			m = ifc->m;
658
			if(m && m->remroute)
659
				m->remroute(ifc, vers, addr, mask);
660
		}
661
	}
662
}
663
 
664
/*
665
 *  associate an address with the interface.  This wipes out any previous
666
 *  addresses.  This is a macro that means, remove all the old interfaces
667
 *  and add a new one.
668
 */
669
static char*
670
ipifcconnect(Conv* c, char **argv, int argc)
671
{
672
	char *err;
673
	Ipifc *ifc;
674
 
675
	ifc = (Ipifc*)c->ptcl;
676
 
677
	if(ifc->m == nil)
678
		 return "ipifc not yet bound to device";
679
 
680
	if(waserror()){
681
		wunlock(ifc);
682
		nexterror();
683
	}
684
	wlock(ifc);
685
	while(ifc->lifc){
686
		err = ipifcremlifc(ifc, ifc->lifc);
687
		if(err)
688
			error(err);
689
	}
690
	wunlock(ifc);
691
	poperror();
692
 
693
	err = ipifcadd(ifc, argv, argc, 0, nil);
694
	if(err)
695
		return err;
696
 
697
	Fsconnected(c, nil);
698
	return nil;
699
}
700
 
701
char*
702
ipifcra6(Ipifc *ifc, char **argv, int argc)
703
{
704
	int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
705
 
706
	argsleft = argc - 1;
707
	i = 1;
708
 
709
	if(argsleft % 2 != 0)
710
		return Ebadarg;
711
 
712
	while (argsleft > 1) {
713
		if(strcmp(argv[i], "recvra") == 0)
714
			ifc->recvra6 = (atoi(argv[i+1]) != 0);
715
		else if(strcmp(argv[i], "sendra") == 0)
716
			ifc->sendra6 = (atoi(argv[i+1]) != 0);
717
		else if(strcmp(argv[i], "mflag") == 0)
718
			ifc->rp.mflag = (atoi(argv[i+1]) != 0);
719
		else if(strcmp(argv[i], "oflag") == 0)
720
			ifc->rp.oflag = (atoi(argv[i+1]) != 0);
721
		else if(strcmp(argv[i], "maxraint") == 0)
722
			ifc->rp.maxraint = atoi(argv[i+1]);
723
		else if(strcmp(argv[i], "minraint") == 0)
724
			ifc->rp.minraint = atoi(argv[i+1]);
725
		else if(strcmp(argv[i], "linkmtu") == 0)
726
			ifc->rp.linkmtu = atoi(argv[i+1]);
727
		else if(strcmp(argv[i], "reachtime") == 0)
728
			ifc->rp.reachtime = atoi(argv[i+1]);
729
		else if(strcmp(argv[i], "rxmitra") == 0)
730
			ifc->rp.rxmitra = atoi(argv[i+1]);
731
		else if(strcmp(argv[i], "ttl") == 0)
732
			ifc->rp.ttl = atoi(argv[i+1]);
733
		else if(strcmp(argv[i], "routerlt") == 0)
734
			ifc->rp.routerlt = atoi(argv[i+1]);
735
		else
736
			return Ebadarg;
737
 
738
		argsleft -= 2;
739
		i += 2;
740
	}
741
 
742
	/* consistency check */
743
	if(ifc->rp.maxraint < ifc->rp.minraint) {
744
		ifc->rp.maxraint = vmax;
745
		ifc->rp.minraint = vmin;
746
		return Ebadarg;
747
	}
748
	return nil;
749
}
750
 
751
/*
752
 *  non-standard control messages.
753
 *  called with c->car locked.
754
 */
755
static char*
756
ipifcctl(Conv* c, char**argv, int argc)
757
{
758
	Ipifc *ifc;
759
	int i;
760
 
761
	ifc = (Ipifc*)c->ptcl;
762
	if(strcmp(argv[0], "add") == 0)
763
		return ipifcadd(ifc, argv, argc, 0, nil);
764
	else if(strcmp(argv[0], "try") == 0)
765
		return ipifcadd(ifc, argv, argc, 1, nil);
766
	else if(strcmp(argv[0], "remove") == 0)
767
		return ipifcrem(ifc, argv, argc);
768
	else if(strcmp(argv[0], "unbind") == 0)
769
		return ipifcunbind(ifc);
770
	else if(strcmp(argv[0], "joinmulti") == 0)
771
		return ipifcjoinmulti(ifc, argv, argc);
772
	else if(strcmp(argv[0], "leavemulti") == 0)
773
		return ipifcleavemulti(ifc, argv, argc);
774
	else if(strcmp(argv[0], "mtu") == 0)
775
		return ipifcsetmtu(ifc, argv, argc);
776
	else if(strcmp(argv[0], "reassemble") == 0){
777
		ifc->reassemble = 1;
778
		return nil;
779
	}
780
	else if(strcmp(argv[0], "iprouting") == 0){
781
		i = 1;
782
		if(argc > 1)
783
			i = atoi(argv[1]);
784
		iprouting(c->p->f, i);
785
		return nil;
786
	}
787
	else if(strcmp(argv[0], "add6") == 0)
788
		return ipifcadd6(ifc, argv, argc);
789
	else if(strcmp(argv[0], "ra6") == 0)
790
		return ipifcra6(ifc, argv, argc);
791
	return "unsupported ctl";
792
}
793
 
794
int
795
ipifcstats(Proto *ipifc, char *buf, int len)
796
{
797
	return ipstats(ipifc->f, buf, len);
798
}
799
 
800
void
801
ipifcinit(Fs *f)
802
{
803
	Proto *ipifc;
804
 
805
	ipifc = smalloc(sizeof(Proto));
806
	ipifc->name = "ipifc";
807
	ipifc->connect = ipifcconnect;
808
	ipifc->announce = nil;
809
	ipifc->bind = ipifcbind;
810
	ipifc->state = ipifcstate;
811
	ipifc->create = ipifccreate;
812
	ipifc->close = ipifcclose;
813
	ipifc->rcv = nil;
814
	ipifc->ctl = ipifcctl;
815
	ipifc->advise = nil;
816
	ipifc->stats = ipifcstats;
817
	ipifc->inuse = ipifcinuse;
818
	ipifc->local = ipifclocal;
819
	ipifc->ipproto = -1;
820
	ipifc->nc = Maxmedia;
821
	ipifc->ptclsize = sizeof(Ipifc);
822
 
823
	f->ipifc = ipifc;	/* hack for ipifcremroute, findipifc, ... */
824
	f->self = smalloc(sizeof(Ipselftab));	/* hack for ipforme */
825
 
826
	Fsproto(f, ipifc);
827
}
828
 
829
/*
830
 *  add to self routing cache
831
 *	called with c->car locked
832
 */
833
static void
834
addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
835
{
836
	Ipself *p;
837
	Iplink *lp;
838
	int h;
839
 
840
	qlock(f->self);
841
 
842
	/* see if the address already exists */
843
	h = hashipa(a);
844
	for(p = f->self->hash[h]; p; p = p->next)
845
		if(memcmp(a, p->a, IPaddrlen) == 0)
846
			break;
847
 
848
	/* allocate a local address and add to hash chain */
849
	if(p == nil){
850
		p = smalloc(sizeof(*p));
851
		ipmove(p->a, a);
852
		p->type = type;
853
		p->next = f->self->hash[h];
854
		f->self->hash[h] = p;
855
 
856
		/* if the null address, accept all packets */
857
		if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
858
			f->self->acceptall = 1;
859
	}
860
 
861
	/* look for a link for this lifc */
862
	for(lp = p->link; lp; lp = lp->selflink)
863
		if(lp->lifc == lifc)
864
			break;
865
 
866
	/* allocate a lifc-to-local link and link to both */
867
	if(lp == nil){
868
		lp = smalloc(sizeof(*lp));
869
		lp->ref = 1;
870
		lp->lifc = lifc;
871
		lp->self = p;
872
		lp->selflink = p->link;
873
		p->link = lp;
874
		lp->lifclink = lifc->link;
875
		lifc->link = lp;
876
 
877
		/* add to routing table */
878
		if(isv4(a))
879
			v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
880
				a+IPv4off, type);
881
		else
882
			v6addroute(f, tifc, a, IPallbits, a, type);
883
 
884
		if((type & Rmulti) && ifc->m->addmulti != nil)
885
			(*ifc->m->addmulti)(ifc, a, lifc->local);
886
	} else
887
		lp->ref++;
888
 
889
	qunlock(f->self);
890
}
891
 
892
/*
893
 *  These structures are unlinked from their chains while
894
 *  other threads may be using them.  To avoid excessive locking,
895
 *  just put them aside for a while before freeing them.
896
 *	called with f->self locked
897
 */
898
static Iplink *freeiplink;
899
static Ipself *freeipself;
900
 
901
static void
902
iplinkfree(Iplink *p)
903
{
904
	Iplink **l, *np;
905
	ulong now = NOW;
906
 
907
	l = &freeiplink;
908
	for(np = *l; np; np = *l){
909
		if(np->expire > now){
910
			*l = np->next;
911
			free(np);
912
			continue;
913
		}
914
		l = &np->next;
915
	}
916
	p->expire = now + 5000;	/* give other threads 5 secs to get out */
917
	p->next = nil;
918
	*l = p;
919
}
920
 
921
static void
922
ipselffree(Ipself *p)
923
{
924
	Ipself **l, *np;
925
	ulong now = NOW;
926
 
927
	l = &freeipself;
928
	for(np = *l; np; np = *l){
929
		if(np->expire > now){
930
			*l = np->next;
931
			free(np);
932
			continue;
933
		}
934
		l = &np->next;
935
	}
936
	p->expire = now + 5000;	/* give other threads 5 secs to get out */
937
	p->next = nil;
938
	*l = p;
939
}
940
 
941
/*
942
 *  Decrement reference for this address on this link.
943
 *  Unlink from selftab if this is the last ref.
944
 *	called with c->car locked
945
 */
946
static void
947
remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
948
{
949
	Ipself *p, **l;
950
	Iplink *link, **l_self, **l_lifc;
951
 
952
	qlock(f->self);
953
 
954
	/* find the unique selftab entry */
955
	l = &f->self->hash[hashipa(a)];
956
	for(p = *l; p; p = *l){
957
		if(ipcmp(p->a, a) == 0)
958
			break;
959
		l = &p->next;
960
	}
961
 
962
	if(p == nil)
963
		goto out;
964
 
965
	/*
966
	 *  walk down links from an ifc looking for one
967
	 *  that matches the selftab entry
968
	 */
969
	l_lifc = &lifc->link;
970
	for(link = *l_lifc; link; link = *l_lifc){
971
		if(link->self == p)
972
			break;
973
		l_lifc = &link->lifclink;
974
	}
975
 
976
	if(link == nil)
977
		goto out;
978
 
979
	/*
980
	 *  walk down the links from the selftab looking for
981
	 *  the one we just found
982
	 */
983
	l_self = &p->link;
984
	for(link = *l_self; link; link = *l_self){
985
		if(link == *l_lifc)
986
			break;
987
		l_self = &link->selflink;
988
	}
989
 
990
	if(link == nil)
991
		panic("remselfcache");
992
 
993
	if(--(link->ref) != 0)
994
		goto out;
995
 
996
	if((p->type & Rmulti) && ifc->m->remmulti != nil)
997
		(*ifc->m->remmulti)(ifc, a, lifc->local);
998
 
999
	/* ref == 0, remove from both chains and free the link */
1000
	*l_lifc = link->lifclink;
1001
	*l_self = link->selflink;
1002
	iplinkfree(link);
1003
 
1004
	if(p->link != nil)
1005
		goto out;
1006
 
1007
	/* remove from routing table */
1008
	if(isv4(a))
1009
		v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
1010
	else
1011
		v6delroute(f, a, IPallbits, 1);
1012
 
1013
	/* no more links, remove from hash and free */
1014
	*l = p->next;
1015
	ipselffree(p);
1016
 
1017
	/* if IPnoaddr, forget */
1018
	if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1019
		f->self->acceptall = 0;
1020
 
1021
out:
1022
	qunlock(f->self);
1023
}
1024
 
1025
static char *stformat = "%-44.44I %2.2d %4.4s\n";
1026
enum
1027
{
1028
	Nstformat= 41,
1029
};
1030
 
1031
long
1032
ipselftabread(Fs *f, char *cp, ulong offset, int n)
1033
{
1034
	int i, m, nifc, off;
1035
	Ipself *p;
1036
	Iplink *link;
1037
	char state[8];
1038
 
1039
	m = 0;
1040
	off = offset;
1041
	qlock(f->self);
1042
	for(i = 0; i < NHASH && m < n; i++){
1043
		for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1044
			nifc = 0;
1045
			for(link = p->link; link; link = link->selflink)
1046
				nifc++;
1047
			routetype(p->type, state);
1048
			m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
1049
			if(off > 0){
1050
				off -= m;
1051
				m = 0;
1052
			}
1053
		}
1054
	}
1055
	qunlock(f->self);
1056
	return m;
1057
}
1058
 
1059
int
1060
iptentative(Fs *f, uchar *addr)
1061
{
1062
 	Ipself *p;
1063
 
1064
	p = f->self->hash[hashipa(addr)];
1065
	for(; p; p = p->next){
1066
		if(ipcmp(addr, p->a) == 0)
1067
			return p->link->lifc->tentative;
1068
	}
1069
	return 0;
1070
}
1071
 
1072
/*
1073
 *  returns
1074
 *	0		- no match
1075
 *	Runi
1076
 *	Rbcast
1077
 *	Rmcast
1078
 */
1079
int
1080
ipforme(Fs *f, uchar *addr)
1081
{
1082
	Ipself *p;
1083
 
1084
	p = f->self->hash[hashipa(addr)];
1085
	for(; p; p = p->next){
1086
		if(ipcmp(addr, p->a) == 0)
1087
			return p->type;
1088
	}
1089
 
1090
	/* hack to say accept anything */
1091
	if(f->self->acceptall)
1092
		return Runi;
1093
	return 0;
1094
}
1095
 
1096
/*
1097
 *  find the ifc on same net as the remote system.  If none,
1098
 *  return nil.
1099
 */
1100
Ipifc*
1101
findipifc(Fs *f, uchar *remote, int type)
1102
{
1103
	Ipifc *ifc, *x;
1104
	Iplifc *lifc;
1105
	Conv **cp, **e;
1106
	uchar gnet[IPaddrlen], xmask[IPaddrlen];
1107
 
1108
	x = nil;
1109
	memset(xmask, 0, IPaddrlen);
1110
 
1111
	/* find most specific match */
1112
	e = &f->ipifc->conv[f->ipifc->nc];
1113
	for(cp = f->ipifc->conv; cp < e; cp++){
1114
		if(*cp == 0)
1115
			continue;
1116
		ifc = (Ipifc*)(*cp)->ptcl;
1117
		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1118
			maskip(remote, lifc->mask, gnet);
1119
			if(ipcmp(gnet, lifc->net) == 0){
1120
				if(x == nil || ipcmp(lifc->mask, xmask) > 0){
1121
					x = ifc;
1122
					ipmove(xmask, lifc->mask);
1123
				}
1124
			}
1125
		}
1126
	}
1127
	if(x != nil)
1128
		return x;
1129
 
1130
	/* for now for broadcast and multicast, just use first interface */
1131
	if(type & (Rbcast|Rmulti)){
1132
		for(cp = f->ipifc->conv; cp < e; cp++){
1133
			if(*cp == 0)
1134
				continue;
1135
			ifc = (Ipifc*)(*cp)->ptcl;
1136
			if(ifc->lifc != nil)
1137
				return ifc;
1138
		}
1139
	}
1140
	return nil;
1141
}
1142
 
1143
enum {
1144
	unknownv6,		/* UGH */
1145
//	multicastv6,
1146
	unspecifiedv6,
1147
	linklocalv6,
1148
	globalv6,
1149
};
1150
 
1151
int
1152
v6addrtype(uchar *addr)
1153
{
1154
	if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
1155
		return unknownv6;
1156
	else if(islinklocal(addr) ||
1157
	    isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
1158
		return linklocalv6;
1159
	else
1160
		return globalv6;
1161
}
1162
 
1163
#define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
1164
			(lifc)->origint + (lifc)->preflt >= NOW/1000)
1165
 
1166
static void
1167
findprimaryipv6(Fs *f, uchar *local)
1168
{
1169
	int atype, atypel;
1170
	Conv **cp, **e;
1171
	Ipifc *ifc;
1172
	Iplifc *lifc;
1173
 
1174
	ipmove(local, v6Unspecified);
1175
	atype = unspecifiedv6;
1176
 
1177
	/*
1178
	 * find "best" (global > link local > unspecified)
1179
	 * local address; address must be current.
1180
	 */
1181
	e = &f->ipifc->conv[f->ipifc->nc];
1182
	for(cp = f->ipifc->conv; cp < e; cp++){
1183
		if(*cp == 0)
1184
			continue;
1185
		ifc = (Ipifc*)(*cp)->ptcl;
1186
		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1187
			atypel = v6addrtype(lifc->local);
1188
			if(atypel > atype && v6addrcurr(lifc)) {
1189
				ipmove(local, lifc->local);
1190
				atype = atypel;
1191
				if(atype == globalv6)
1192
					return;
1193
			}
1194
		}
1195
	}
1196
}
1197
 
1198
/*
1199
 *  returns first ip address configured
1200
 */
1201
static void
1202
findprimaryipv4(Fs *f, uchar *local)
1203
{
1204
	Conv **cp, **e;
1205
	Ipifc *ifc;
1206
	Iplifc *lifc;
1207
 
1208
	/* find first ifc local address */
1209
	e = &f->ipifc->conv[f->ipifc->nc];
1210
	for(cp = f->ipifc->conv; cp < e; cp++){
1211
		if(*cp == 0)
1212
			continue;
1213
		ifc = (Ipifc*)(*cp)->ptcl;
1214
		if((lifc = ifc->lifc) != nil){
1215
			ipmove(local, lifc->local);
1216
			return;
1217
		}
1218
	}
1219
}
1220
 
1221
/*
1222
 *  find the local address 'closest' to the remote system, copy it to
1223
 *  local and return the ifc for that address
1224
 */
1225
void
1226
findlocalip(Fs *f, uchar *local, uchar *remote)
1227
{
1228
	int version, atype = unspecifiedv6, atypel = unknownv6;
1229
	int atyper, deprecated;
1230
	uchar gate[IPaddrlen], gnet[IPaddrlen];
1231
	Ipifc *ifc;
1232
	Iplifc *lifc;
1233
	Route *r;
1234
 
1235
	USED(atype);
1236
	USED(atypel);
1237
	qlock(f->ipifc);
1238
	r = v6lookup(f, remote, nil);
1239
 	version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
1240
 
1241
	if(r != nil){
1242
		ifc = r->ifc;
1243
		if(r->type & Rv4)
1244
			v4tov6(gate, r->v4.gate);
1245
		else {
1246
			ipmove(gate, r->v6.gate);
1247
			ipmove(local, v6Unspecified);
1248
		}
1249
 
1250
		switch(version) {
1251
		case V4:
1252
			/* find ifc address closest to the gateway to use */
1253
			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1254
				maskip(gate, lifc->mask, gnet);
1255
				if(ipcmp(gnet, lifc->net) == 0){
1256
					ipmove(local, lifc->local);
1257
					goto out;
1258
				}
1259
			}
1260
			break;
1261
		case V6:
1262
			/* find ifc address with scope matching the destination */
1263
			atyper = v6addrtype(remote);
1264
			deprecated = 0;
1265
			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1266
				atypel = v6addrtype(lifc->local);
1267
				/* prefer appropriate scope */
1268
				if(atypel > atype && atype < atyper ||
1269
				   atypel < atype && atype > atyper){
1270
					ipmove(local, lifc->local);
1271
					deprecated = !v6addrcurr(lifc);
1272
					atype = atypel;
1273
				} else if(atypel == atype){
1274
					/* avoid deprecated addresses */
1275
					if(deprecated && v6addrcurr(lifc)){
1276
						ipmove(local, lifc->local);
1277
						atype = atypel;
1278
						deprecated = 0;
1279
					}
1280
				}
1281
				if(atype == atyper && !deprecated)
1282
					goto out;
1283
			}
1284
			if(atype >= atyper)
1285
				goto out;
1286
			break;
1287
		default:
1288
			panic("findlocalip: version %d", version);
1289
		}
1290
	}
1291
 
1292
	switch(version){
1293
	case V4:
1294
		findprimaryipv4(f, local);
1295
		break;
1296
	case V6:
1297
		findprimaryipv6(f, local);
1298
		break;
1299
	default:
1300
		panic("findlocalip2: version %d", version);
1301
	}
1302
 
1303
out:
1304
	qunlock(f->ipifc);
1305
}
1306
 
1307
/*
1308
 *  return first v4 address associated with an interface
1309
 */
1310
int
1311
ipv4local(Ipifc *ifc, uchar *addr)
1312
{
1313
	Iplifc *lifc;
1314
 
1315
	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1316
		if(isv4(lifc->local)){
1317
			memmove(addr, lifc->local+IPv4off, IPv4addrlen);
1318
			return 1;
1319
		}
1320
	}
1321
	return 0;
1322
}
1323
 
1324
/*
1325
 *  return first v6 address associated with an interface
1326
 */
1327
int
1328
ipv6local(Ipifc *ifc, uchar *addr)
1329
{
1330
	Iplifc *lifc;
1331
 
1332
	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1333
		if(!isv4(lifc->local) && !(lifc->tentative)){
1334
			ipmove(addr, lifc->local);
1335
			return 1;
1336
		}
1337
	}
1338
	return 0;
1339
}
1340
 
1341
int
1342
ipv6anylocal(Ipifc *ifc, uchar *addr)
1343
{
1344
	Iplifc *lifc;
1345
 
1346
	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1347
		if(!isv4(lifc->local)){
1348
			ipmove(addr, lifc->local);
1349
			return SRC_UNI;
1350
		}
1351
	}
1352
	return SRC_UNSPEC;
1353
}
1354
 
1355
/*
1356
 *  see if this address is bound to the interface
1357
 */
1358
Iplifc*
1359
iplocalonifc(Ipifc *ifc, uchar *ip)
1360
{
1361
	Iplifc *lifc;
1362
 
1363
	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1364
		if(ipcmp(ip, lifc->local) == 0)
1365
			return lifc;
1366
	return nil;
1367
}
1368
 
1369
 
1370
/*
1371
 *  See if we're proxying for this address on this interface
1372
 */
1373
int
1374
ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1375
{
1376
	Route *r;
1377
	uchar net[IPaddrlen];
1378
	Iplifc *lifc;
1379
 
1380
	/* see if this is a direct connected pt to pt address */
1381
	r = v6lookup(f, ip, nil);
1382
	if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1383
		return 0;
1384
 
1385
	/* see if this is on the right interface */
1386
	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1387
		maskip(ip, lifc->mask, net);
1388
		if(ipcmp(net, lifc->remote) == 0)
1389
			return 1;
1390
	}
1391
	return 0;
1392
}
1393
 
1394
/*
1395
 *  return multicast version if any
1396
 */
1397
int
1398
ipismulticast(uchar *ip)
1399
{
1400
	if(isv4(ip)){
1401
		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1402
			return V4;
1403
	}
1404
	else if(ip[0] == 0xff)
1405
		return V6;
1406
	return 0;
1407
}
1408
int
1409
ipisbm(uchar *ip)
1410
{
1411
	if(isv4(ip)){
1412
		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1413
			return V4;
1414
		else if(ipcmp(ip, IPv4bcast) == 0)
1415
			return V4;
1416
	}
1417
	else if(ip[0] == 0xff)
1418
		return V6;
1419
	return 0;
1420
}
1421
 
1422
 
1423
/*
1424
 *  add a multicast address to an interface, called with c->car locked
1425
 */
1426
void
1427
ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1428
{
1429
	Ipifc *ifc;
1430
	Iplifc *lifc;
1431
	Conv **p;
1432
	Ipmulti *multi, **l;
1433
	Fs *f;
1434
 
1435
	f = c->p->f;
1436
 
1437
	for(l = &c->multi; *l; l = &(*l)->next)
1438
		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1439
			return;		/* it's already there */
1440
 
1441
	multi = *l = smalloc(sizeof(*multi));
1442
	ipmove(multi->ma, ma);
1443
	ipmove(multi->ia, ia);
1444
	multi->next = nil;
1445
 
1446
	for(p = f->ipifc->conv; *p; p++){
1447
		if((*p)->inuse == 0)
1448
			continue;
1449
		ifc = (Ipifc*)(*p)->ptcl;
1450
		if(waserror()){
1451
			wunlock(ifc);
1452
			nexterror();
1453
		}
1454
		wlock(ifc);
1455
		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1456
			if(ipcmp(ia, lifc->local) == 0)
1457
				addselfcache(f, ifc, lifc, ma, Rmulti);
1458
		wunlock(ifc);
1459
		poperror();
1460
	}
1461
}
1462
 
1463
 
1464
/*
1465
 *  remove a multicast address from an interface, called with c->car locked
1466
 */
1467
void
1468
ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1469
{
1470
	Ipmulti *multi, **l;
1471
	Iplifc *lifc;
1472
	Conv **p;
1473
	Ipifc *ifc;
1474
	Fs *f;
1475
 
1476
	f = c->p->f;
1477
 
1478
	for(l = &c->multi; *l; l = &(*l)->next)
1479
		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1480
			break;
1481
 
1482
	multi = *l;
1483
	if(multi == nil)
1484
		return; 	/* we don't have it open */
1485
 
1486
	*l = multi->next;
1487
 
1488
	for(p = f->ipifc->conv; *p; p++){
1489
		if((*p)->inuse == 0)
1490
			continue;
1491
 
1492
		ifc = (Ipifc*)(*p)->ptcl;
1493
		if(waserror()){
1494
			wunlock(ifc);
1495
			nexterror();
1496
		}
1497
		wlock(ifc);
1498
		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1499
			if(ipcmp(ia, lifc->local) == 0)
1500
				remselfcache(f, ifc, lifc, ma);
1501
		wunlock(ifc);
1502
		poperror();
1503
	}
1504
 
1505
	free(multi);
1506
}
1507
 
1508
/*
1509
 *  make lifc's join and leave multicast groups
1510
 */
1511
static char*
1512
ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
1513
{
1514
	USED(ifc, argv, argc);
1515
	return nil;
1516
}
1517
 
1518
static char*
1519
ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
1520
{
1521
	USED(ifc, argv, argc);
1522
	return nil;
1523
}
1524
 
1525
static void
1526
ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
1527
{
1528
	Conv **cp, **e;
1529
	Ipifc *nifc;
1530
	Iplifc *lifc;
1531
	Medium *m;
1532
	uchar net[IPaddrlen];
1533
 
1534
	/* register the address on any network that will proxy for us */
1535
	e = &f->ipifc->conv[f->ipifc->nc];
1536
 
1537
	if(!isv4(ip)) {				/* V6 */
1538
		for(cp = f->ipifc->conv; cp < e; cp++){
1539
			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1540
				continue;
1541
			rlock(nifc);
1542
			m = nifc->m;
1543
			if(m == nil || m->addmulti == nil) {
1544
				runlock(nifc);
1545
				continue;
1546
			}
1547
			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1548
				maskip(ip, lifc->mask, net);
1549
				if(ipcmp(net, lifc->remote) == 0) {
1550
					/* add solicited-node multicast addr */
1551
					ipv62smcast(net, ip);
1552
					addselfcache(f, nifc, lifc, net, Rmulti);
1553
					arpenter(f, V6, ip, nifc->mac, 6, 0);
1554
					// (*m->addmulti)(nifc, net, ip);
1555
					break;
1556
				}
1557
			}
1558
			runlock(nifc);
1559
		}
1560
	}
1561
	else {					/* V4 */
1562
		for(cp = f->ipifc->conv; cp < e; cp++){
1563
			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1564
				continue;
1565
			rlock(nifc);
1566
			m = nifc->m;
1567
			if(m == nil || m->areg == nil){
1568
				runlock(nifc);
1569
				continue;
1570
			}
1571
			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1572
				maskip(ip, lifc->mask, net);
1573
				if(ipcmp(net, lifc->remote) == 0){
1574
					(*m->areg)(nifc, ip);
1575
					break;
1576
				}
1577
			}
1578
			runlock(nifc);
1579
		}
1580
	}
1581
}
1582
 
1583
 
1584
/* added for new v6 mesg types */
1585
static void
1586
adddefroute6(Fs *f, uchar *gate, int force)
1587
{
1588
	Route *r;
1589
 
1590
	r = v6lookup(f, v6Unspecified, nil);
1591
	/*
1592
	 * route entries generated by all other means take precedence
1593
	 * over router announcements.
1594
	 */
1595
	if (r && !force && strcmp(r->tag, "ra") != 0)
1596
		return;
1597
 
1598
	v6delroute(f, v6Unspecified, v6Unspecified, 1);
1599
	v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1600
}
1601
 
1602
enum {
1603
	Ngates = 3,
1604
};
1605
 
1606
char*
1607
ipifcadd6(Ipifc *ifc, char**argv, int argc)
1608
{
1609
	int plen = 64;
1610
	long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
1611
	char addr[Maxv6repr], preflen[6];
1612
	char *params[3];
1613
	uchar autoflag = 1, onlink = 1;
1614
	uchar prefix[IPaddrlen];
1615
	Iplifc *lifc;
1616
 
1617
	switch(argc) {
1618
	case 7:
1619
		preflt = atoi(argv[6]);
1620
		/* fall through */
1621
	case 6:
1622
		validlt = atoi(argv[5]);
1623
		/* fall through */
1624
	case 5:
1625
		autoflag = atoi(argv[4]);
1626
		/* fall through */
1627
	case 4:
1628
		onlink = atoi(argv[3]);
1629
		/* fall through */
1630
	case 3:
1631
		plen = atoi(argv[2]);
1632
		/* fall through */
1633
	case 2:
1634
		break;
1635
	default:
1636
		return Ebadarg;
1637
	}
1638
 
1639
	if (parseip(prefix, argv[1]) != 6)
1640
		return "bad ipv6 address";
1641
	if (validlt < preflt)
1642
		return "valid ipv6 lifetime less than preferred lifetime";
1643
	if (plen < 0)
1644
		return "negative ipv6 prefix length";
1645
	/* i think that this length limit is bogus - geoff */
1646
//	if (plen > 64)
1647
//		return "ipv6 prefix length greater than 64;
1648
	if (islinklocal(prefix))
1649
		return "ipv6 prefix is link-local";
1650
 
1651
	lifc = smalloc(sizeof(Iplifc));
1652
	lifc->onlink = (onlink != 0);
1653
	lifc->autoflag = (autoflag != 0);
1654
	lifc->validlt = validlt;
1655
	lifc->preflt = preflt;
1656
	lifc->origint = origint;
1657
 
1658
	/* issue "add" ctl msg for v6 link-local addr and prefix len */
1659
	if(!ifc->m->pref2addr)
1660
		return "no pref2addr on interface";
1661
	ifc->m->pref2addr(prefix, ifc->mac);	/* mac → v6 link-local addr */
1662
	snprint(addr, sizeof addr, "%I", prefix);
1663
	snprint(preflen, sizeof preflen, "/%d", plen);
1664
	params[0] = "add";
1665
	params[1] = addr;
1666
	params[2] = preflen;
1667
 
1668
	return ipifcadd(ifc, params, 3, 0, lifc);
1669
}