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
#include	"../port/netif.h"
8
 
9
static int netown(Netfile*, char*, int);
10
static int openfile(Netif*, int);
11
static char* matchtoken(char*, char*);
12
static char* netmulti(Netif*, Netfile*, uchar*, int);
13
static int parseaddr(uchar*, char*, int);
14
 
15
/*
16
 *  set up a new network interface
17
 */
18
void
19
netifinit(Netif *nif, char *name, int nfile, ulong limit)
20
{
21
	strncpy(nif->name, name, KNAMELEN-1);
22
	nif->name[KNAMELEN-1] = 0;
23
	nif->nfile = nfile;
24
	nif->f = xalloc(nfile*sizeof(Netfile*));
25
	if (nif->f == nil)
26
		panic("netifinit: no memory");
27
	memset(nif->f, 0, nfile*sizeof(Netfile*));
28
	nif->limit = limit;
29
}
30
 
31
/*
32
 *  generate a 3 level directory
33
 */
34
static int
35
netifgen(Chan *c, char*, Dirtab *vp, int, int i, Dir *dp)
36
{
37
	Qid q;
38
	Netif *nif = (Netif*)vp;
39
	Netfile *f;
40
	int t;
41
	int perm;
42
	char *o;
43
 
44
	q.type = QTFILE;
45
	q.vers = 0;
46
 
47
	/* top level directory contains the name of the network */
48
	if(c->qid.path == 0){
49
		switch(i){
50
		case DEVDOTDOT:
51
			q.path = 0;
52
			q.type = QTDIR;
53
			devdir(c, q, ".", 0, eve, 0555, dp);
54
			break;
55
		case 0:
56
			q.path = N2ndqid;
57
			q.type = QTDIR;
58
			strcpy(up->genbuf, nif->name);
59
			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
60
			break;
61
		default:
62
			return -1;
63
		}
64
		return 1;
65
	}
66
 
67
	/* second level contains clone plus all the conversations */
68
	t = NETTYPE(c->qid.path);
69
	if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){
70
		switch(i) {
71
		case DEVDOTDOT:
72
			q.type = QTDIR;
73
			q.path = 0;
74
			devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
75
			break;
76
		case 0:
77
			q.path = Ncloneqid;
78
			devdir(c, q, "clone", 0, eve, 0666, dp);
79
			break;
80
		case 1:
81
			q.path = Naddrqid;
82
			devdir(c, q, "addr", 0, eve, 0666, dp);
83
			break;
84
		case 2:
85
			q.path = Nstatqid;
86
			devdir(c, q, "stats", 0, eve, 0444, dp);
87
			break;
88
		case 3:
89
			q.path = Nifstatqid;
90
			devdir(c, q, "ifstats", 0, eve, 0444, dp);
91
			break;
92
		default:
93
			i -= 4;
94
			if(i >= nif->nfile)
95
				return -1;
96
			if(nif->f[i] == 0)
97
				return 0;
98
			q.type = QTDIR;
99
			q.path = NETQID(i, N3rdqid);
100
			snprint(up->genbuf, sizeof up->genbuf, "%d", i);
101
			devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
102
			break;
103
		}
104
		return 1;
105
	}
106
 
107
	/* third level */
108
	f = nif->f[NETID(c->qid.path)];
109
	if(f == 0)
110
		return 0;
111
	if(*f->owner){
112
		o = f->owner;
113
		perm = f->mode;
114
	} else {
115
		o = eve;
116
		perm = 0666;
117
	}
118
	switch(i){
119
	case DEVDOTDOT:
120
		q.type = QTDIR;
121
		q.path = N2ndqid;
122
		strcpy(up->genbuf, nif->name);
123
		devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
124
		break;
125
	case 0:
126
		q.path = NETQID(NETID(c->qid.path), Ndataqid);
127
		devdir(c, q, "data", 0, o, perm, dp);
128
		break;
129
	case 1:
130
		q.path = NETQID(NETID(c->qid.path), Nctlqid);
131
		devdir(c, q, "ctl", 0, o, perm, dp);
132
		break;
133
	case 2:
134
		q.path = NETQID(NETID(c->qid.path), Nstatqid);
135
		devdir(c, q, "stats", 0, eve, 0444, dp);
136
		break;
137
	case 3:
138
		q.path = NETQID(NETID(c->qid.path), Ntypeqid);
139
		devdir(c, q, "type", 0, eve, 0444, dp);
140
		break;
141
	case 4:
142
		q.path = NETQID(NETID(c->qid.path), Nifstatqid);
143
		devdir(c, q, "ifstats", 0, eve, 0444, dp);
144
		break;
145
	default:
146
		return -1;
147
	}
148
	return 1;
149
}
150
 
151
Walkqid*
152
netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
153
{
154
	return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen);
155
}
156
 
157
Chan*
158
netifopen(Netif *nif, Chan *c, int omode)
159
{
160
	int id;
161
	Netfile *f;
162
 
163
	id = 0;
164
	if(c->qid.type & QTDIR){
165
		if(omode != OREAD)
166
			error(Eperm);
167
	} else {
168
		switch(NETTYPE(c->qid.path)){
169
		case Ndataqid:
170
		case Nctlqid:
171
			id = NETID(c->qid.path);
172
			openfile(nif, id);
173
			break;
174
		case Ncloneqid:
175
			id = openfile(nif, -1);
176
			c->qid.path = NETQID(id, Nctlqid);
177
			break;
178
		default:
179
			if(omode != OREAD)
180
				error(Ebadarg);
181
		}
182
		switch(NETTYPE(c->qid.path)){
183
		case Ndataqid:
184
		case Nctlqid:
185
			f = nif->f[id];
186
			if(netown(f, up->user, omode&7) < 0)
187
				error(Eperm);
188
			break;
189
		}
190
	}
191
	c->mode = openmode(omode);
192
	c->flag |= COPEN;
193
	c->offset = 0;
194
	c->iounit = qiomaxatomic;
195
	return c;
196
}
197
 
198
long
199
netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
200
{
201
	int i, j;
202
	Netfile *f;
203
	char *p;
204
 
205
	if(c->qid.type&QTDIR)
206
		return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);
207
 
208
	switch(NETTYPE(c->qid.path)){
209
	case Ndataqid:
210
		f = nif->f[NETID(c->qid.path)];
211
		return qread(f->in, a, n);
212
	case Nctlqid:
213
		return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
214
	case Nstatqid:
215
		p = malloc(READSTR);
216
		if(p == nil)
217
			error(Enomem);
218
		j = snprint(p, READSTR, "in: %llud\n", nif->inpackets);
219
		j += snprint(p+j, READSTR-j, "link: %d\n", nif->link);
220
		j += snprint(p+j, READSTR-j, "out: %llud\n", nif->outpackets);
221
		j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs);
222
		j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows);
223
		j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows);
224
		j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames);
225
		j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs);
226
		j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs);
227
		j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom);
228
		j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
229
		j += snprint(p+j, READSTR-j, "addr: ");
230
		for(i = 0; i < nif->alen; i++)
231
			j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
232
		snprint(p+j, READSTR-j, "\n");
233
		n = readstr(offset, a, n, p);
234
		free(p);
235
		return n;
236
	case Naddrqid:
237
		p = malloc(READSTR);
238
		if(p == nil)
239
			error(Enomem);
240
		j = 0;
241
		for(i = 0; i < nif->alen; i++)
242
			j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
243
		n = readstr(offset, a, n, p);
244
		free(p);
245
		return n;
246
	case Ntypeqid:
247
		f = nif->f[NETID(c->qid.path)];
248
		return readnum(offset, a, n, f->type, NUMSIZE);
249
	case Nifstatqid:
250
		return 0;
251
	}
252
	error(Ebadarg);
253
	return -1;	/* not reached */
254
}
255
 
256
Block*
257
netifbread(Netif *nif, Chan *c, long n, ulong offset)
258
{
259
	if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
260
		return devbread(c, n, offset);
261
 
262
	return qbread(nif->f[NETID(c->qid.path)]->in, n);
263
}
264
 
265
/*
266
 *  make sure this type isn't already in use on this device
267
 */
268
static int
269
typeinuse(Netif *nif, int type)
270
{
271
	Netfile *f, **fp, **efp;
272
 
273
	if(type <= 0)
274
		return 0;
275
 
276
	efp = &nif->f[nif->nfile];
277
	for(fp = nif->f; fp < efp; fp++){
278
		f = *fp;
279
		if(f == 0)
280
			continue;
281
		if(f->type == type)
282
			return 1;
283
	}
284
	return 0;
285
}
286
 
287
/*
288
 *  the devxxx.c that calls us handles writing data, it knows best
289
 */
290
long
291
netifwrite(Netif *nif, Chan *c, void *a, long n)
292
{
293
	Netfile *f;
294
	int type;
295
	char *p, buf[64];
296
	uchar binaddr[Nmaxaddr];
297
 
298
	if(NETTYPE(c->qid.path) != Nctlqid)
299
		error(Eperm);
300
 
301
	if(n >= sizeof(buf))
302
		n = sizeof(buf)-1;
303
	memmove(buf, a, n);
304
	buf[n] = 0;
305
 
306
	if(waserror()){
307
		qunlock(nif);
308
		nexterror();
309
	}
310
 
311
	qlock(nif);
312
	f = nif->f[NETID(c->qid.path)];
313
	if((p = matchtoken(buf, "connect")) != 0){
314
		type = atoi(p);
315
		if(typeinuse(nif, type))
316
			error(Einuse);
317
		f->type = type;
318
		if(f->type < 0)
319
			nif->all++;
320
	} else if(matchtoken(buf, "promiscuous")){
321
		if(f->prom == 0){
322
			if(nif->prom == 0 && nif->promiscuous != nil)
323
				nif->promiscuous(nif->arg, 1);
324
			f->prom = 1;
325
			nif->prom++;
326
		}
327
	} else if((p = matchtoken(buf, "scanbs")) != 0){
328
		/* scan for base stations */
329
		if(f->scan == 0){
330
			type = atoi(p);
331
			if(type < 5)
332
				type = 5;
333
			if(nif->scanbs != nil)
334
				nif->scanbs(nif->arg, type);
335
			f->scan = type;
336
			nif->scan++;
337
		}
338
	} else if(matchtoken(buf, "bridge")){
339
		f->bridge = 1;
340
	} else if(matchtoken(buf, "headersonly")){
341
		f->headersonly = 1;
342
	} else if((p = matchtoken(buf, "addmulti")) != 0){
343
		if(parseaddr(binaddr, p, nif->alen) < 0)
344
			error("bad address");
345
		p = netmulti(nif, f, binaddr, 1);
346
		if(p)
347
			error(p);
348
	} else if((p = matchtoken(buf, "remmulti")) != 0){
349
		if(parseaddr(binaddr, p, nif->alen) < 0)
350
			error("bad address");
351
		p = netmulti(nif, f, binaddr, 0);
352
		if(p)
353
			error(p);
354
	} else
355
		n = -1;
356
	qunlock(nif);
357
	poperror();
358
	return n;
359
}
360
 
361
int
362
netifwstat(Netif *nif, Chan *c, uchar *db, int n)
363
{
364
	Dir *dir;
365
	Netfile *f;
366
	int m;
367
 
368
	f = nif->f[NETID(c->qid.path)];
369
	if(f == 0)
370
		error(Enonexist);
371
 
372
	if(netown(f, up->user, OWRITE) < 0)
373
		error(Eperm);
374
 
375
	dir = smalloc(sizeof(Dir)+n);
376
	m = convM2D(db, n, &dir[0], (char*)&dir[1]);
377
	if(m == 0){
378
		free(dir);
379
		error(Eshortstat);
380
	}
381
	if(!emptystr(dir[0].uid))
382
		strncpy(f->owner, dir[0].uid, KNAMELEN);
383
	if(dir[0].mode != ~0UL)
384
		f->mode = dir[0].mode;
385
	free(dir);
386
	return m;
387
}
388
 
389
int
390
netifstat(Netif *nif, Chan *c, uchar *db, int n)
391
{
392
	return devstat(c, db, n, (Dirtab *)nif, 0, netifgen);
393
}
394
 
395
void
396
netifclose(Netif *nif, Chan *c)
397
{
398
	Netfile *f;
399
	int t;
400
	Netaddr *ap;
401
 
402
	if((c->flag & COPEN) == 0)
403
		return;
404
 
405
	t = NETTYPE(c->qid.path);
406
	if(t != Ndataqid && t != Nctlqid)
407
		return;
408
 
409
	f = nif->f[NETID(c->qid.path)];
410
	qlock(f);
411
	if(--(f->inuse) == 0){
412
		if(f->prom){
413
			qlock(nif);
414
			if(--(nif->prom) == 0 && nif->promiscuous != nil)
415
				nif->promiscuous(nif->arg, 0);
416
			qunlock(nif);
417
			f->prom = 0;
418
		}
419
		if(f->scan){
420
			qlock(nif);
421
			if(--(nif->scan) == 0 && nif->scanbs != nil)
422
				nif->scanbs(nif->arg, 0);
423
			qunlock(nif);
424
			f->prom = 0;
425
			f->scan = 0;
426
		}
427
		if(f->nmaddr){
428
			qlock(nif);
429
			t = 0;
430
			for(ap = nif->maddr; ap; ap = ap->next){
431
				if(f->maddr[t/8] & (1<<(t%8)))
432
					netmulti(nif, f, ap->addr, 0);
433
			}
434
			qunlock(nif);
435
			f->nmaddr = 0;
436
		}
437
		if(f->type < 0){
438
			qlock(nif);
439
			--(nif->all);
440
			qunlock(nif);
441
		}
442
		f->owner[0] = 0;
443
		f->type = 0;
444
		f->bridge = 0;
445
		f->headersonly = 0;
446
		qclose(f->in);
447
	}
448
	qunlock(f);
449
}
450
 
451
Lock netlock;
452
 
453
static int
454
netown(Netfile *p, char *o, int omode)
455
{
456
	static int access[] = { 0400, 0200, 0600, 0100 };
457
	int mode;
458
	int t;
459
 
460
	lock(&netlock);
461
	if(*p->owner){
462
		if(strncmp(o, p->owner, KNAMELEN) == 0)	/* User */
463
			mode = p->mode;
464
		else if(strncmp(o, eve, KNAMELEN) == 0)	/* Bootes is group */
465
			mode = p->mode<<3;
466
		else
467
			mode = p->mode<<6;		/* Other */
468
 
469
		t = access[omode&3];
470
		if((t & mode) == t){
471
			unlock(&netlock);
472
			return 0;
473
		} else {
474
			unlock(&netlock);
475
			return -1;
476
		}
477
	}
478
	strncpy(p->owner, o, KNAMELEN);
479
	p->mode = 0660;
480
	unlock(&netlock);
481
	return 0;
482
}
483
 
484
/*
485
 *  Increment the reference count of a network device.
486
 *  If id < 0, return an unused ether device.
487
 */
488
static int
489
openfile(Netif *nif, int id)
490
{
491
	Netfile *f, **fp, **efp;
492
 
493
	if(id >= 0){
494
		f = nif->f[id];
495
		if(f == 0)
496
			error(Enodev);
497
		qlock(f);
498
		qreopen(f->in);
499
		f->inuse++;
500
		qunlock(f);
501
		return id;
502
	}
503
 
504
	qlock(nif);
505
	if(waserror()){
506
		qunlock(nif);
507
		nexterror();
508
	}
509
	efp = &nif->f[nif->nfile];
510
	for(fp = nif->f; fp < efp; fp++){
511
		f = *fp;
512
		if(f == 0){
513
			f = malloc(sizeof(Netfile));
514
			if(f == 0)
515
				exhausted("memory");
516
			f->in = qopen(nif->limit, Qmsg, 0, 0);
517
			if(f->in == nil){
518
				free(f);
519
				exhausted("memory");
520
			}
521
			*fp = f;
522
			qlock(f);
523
		} else {
524
			qlock(f);
525
			if(f->inuse){
526
				qunlock(f);
527
				continue;
528
			}
529
		}
530
		f->inuse = 1;
531
		qreopen(f->in);
532
		netown(f, up->user, 0);
533
		qunlock(f);
534
		qunlock(nif);
535
		poperror();
536
		return fp - nif->f;
537
	}
538
	error(Enodev);
539
	return -1;	/* not reached */
540
}
541
 
542
/*
543
 *  look for a token starting a string,
544
 *  return a pointer to first non-space char after it
545
 */
546
static char*
547
matchtoken(char *p, char *token)
548
{
549
	int n;
550
 
551
	n = strlen(token);
552
	if(strncmp(p, token, n))
553
		return 0;
554
	p += n;
555
	if(*p == 0)
556
		return p;
557
	if(*p != ' ' && *p != '\t' && *p != '\n')
558
		return 0;
559
	while(*p == ' ' || *p == '\t' || *p == '\n')
560
		p++;
561
	return p;
562
}
563
 
564
void
565
hnputv(void *p, uvlong v)
566
{
567
	uchar *a;
568
 
569
	a = p;
570
	hnputl(a, v>>32);
571
	hnputl(a+4, v);
572
}
573
 
574
void
575
hnputl(void *p, uint v)
576
{
577
	uchar *a;
578
 
579
	a = p;
580
	a[0] = v>>24;
581
	a[1] = v>>16;
582
	a[2] = v>>8;
583
	a[3] = v;
584
}
585
 
586
void
587
hnputs(void *p, ushort v)
588
{
589
	uchar *a;
590
 
591
	a = p;
592
	a[0] = v>>8;
593
	a[1] = v;
594
}
595
 
596
uvlong
597
nhgetv(void *p)
598
{
599
	uchar *a;
600
 
601
	a = p;
602
	return ((vlong)nhgetl(a) << 32) | nhgetl(a+4);
603
}
604
 
605
uint
606
nhgetl(void *p)
607
{
608
	uchar *a;
609
 
610
	a = p;
611
	return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
612
}
613
 
614
ushort
615
nhgets(void *p)
616
{
617
	uchar *a;
618
 
619
	a = p;
620
	return (a[0]<<8)|(a[1]<<0);
621
}
622
 
623
static ulong
624
hash(uchar *a, int len)
625
{
626
	ulong sum = 0;
627
 
628
	while(len-- > 0)
629
		sum = (sum << 1) + *a++;
630
	return sum%Nmhash;
631
}
632
 
633
int
634
activemulti(Netif *nif, uchar *addr, int alen)
635
{
636
	Netaddr *hp;
637
 
638
	for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
639
		if(memcmp(addr, hp->addr, alen) == 0){
640
			if(hp->ref)
641
				return 1;
642
			else
643
				break;
644
		}
645
	return 0;
646
}
647
 
648
static int
649
parseaddr(uchar *to, char *from, int alen)
650
{
651
	char nip[4];
652
	char *p;
653
	int i;
654
 
655
	p = from;
656
	for(i = 0; i < alen; i++){
657
		if(*p == 0)
658
			return -1;
659
		nip[0] = *p++;
660
		if(*p == 0)
661
			return -1;
662
		nip[1] = *p++;
663
		nip[2] = 0;
664
		to[i] = strtoul(nip, 0, 16);
665
		if(*p == ':')
666
			p++;
667
	}
668
	return 0;
669
}
670
 
671
/*
672
 *  keep track of multicast addresses
673
 */
674
static char*
675
netmulti(Netif *nif, Netfile *f, uchar *addr, int add)
676
{
677
	Netaddr **l, *ap;
678
	int i;
679
	ulong h;
680
 
681
	if(nif->multicast == nil)
682
		return "interface does not support multicast";
683
 
684
	l = &nif->maddr;
685
	i = 0;
686
	for(ap = *l; ap; ap = *l){
687
		if(memcmp(addr, ap->addr, nif->alen) == 0)
688
			break;
689
		i++;
690
		l = &ap->next;
691
	}
692
 
693
	if(add){
694
		if(ap == 0){
695
			*l = ap = smalloc(sizeof(*ap));
696
			memmove(ap->addr, addr, nif->alen);
697
			ap->next = 0;
698
			ap->ref = 1;
699
			h = hash(addr, nif->alen);
700
			ap->hnext = nif->mhash[h];
701
			nif->mhash[h] = ap;
702
		} else {
703
			ap->ref++;
704
		}
705
		if(ap->ref == 1){
706
			nif->nmaddr++;
707
			nif->multicast(nif->arg, addr, 1);
708
		}
709
		if(i < 8*sizeof(f->maddr)){
710
			if((f->maddr[i/8] & (1<<(i%8))) == 0)
711
				f->nmaddr++;
712
			f->maddr[i/8] |= 1<<(i%8);
713
		}
714
	} else {
715
		if(ap == 0 || ap->ref == 0)
716
			return 0;
717
		ap->ref--;
718
		if(ap->ref == 0){
719
			nif->nmaddr--;
720
			nif->multicast(nif->arg, addr, 0);
721
		}
722
		if(i < 8*sizeof(f->maddr)){
723
			if((f->maddr[i/8] & (1<<(i%8))) != 0)
724
				f->nmaddr--;
725
			f->maddr[i/8] &= ~(1<<(i%8));
726
		}
727
	}
728
	return 0;
729
}