Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | 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 "io.h"
7
#include "../port/error.h"
8
 
9
#include "../port/netif.h"
10
#include "etherif.h"
11
 
12
extern int archether(unsigned ctlno, Ether *ether);
13
 
14
static Ether *etherxx[MaxEther];
15
 
16
Chan*
17
etherattach(char* spec)
18
{
19
	int ctlrno;
20
	char *p;
21
	Chan *chan;
22
 
23
	ctlrno = 0;
24
	if(spec && *spec){
25
		ctlrno = strtoul(spec, &p, 0);
26
		if((ctlrno == 0 && p == spec) || *p != 0)
27
			error(Ebadarg);
28
		if(ctlrno < 0 || ctlrno >= MaxEther)
29
			error(Ebadarg);
30
	}
31
	if(etherxx[ctlrno] == 0)
32
		error(Enodev);
33
 
34
	chan = devattach('l', spec);
35
	if(waserror()){
36
		chanfree(chan);
37
		nexterror();
38
	}
39
	chan->dev = ctlrno;
40
	if(etherxx[ctlrno]->attach)
41
		etherxx[ctlrno]->attach(etherxx[ctlrno]);
42
	poperror();
43
	return chan;
44
}
45
 
46
static Walkqid*
47
etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
48
{
49
	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
50
}
51
 
52
static int
53
etherstat(Chan* chan, uchar* dp, int n)
54
{
55
	return netifstat(etherxx[chan->dev], chan, dp, n);
56
}
57
 
58
static Chan*
59
etheropen(Chan* chan, int omode)
60
{
61
	return netifopen(etherxx[chan->dev], chan, omode);
62
}
63
 
64
static void
65
ethercreate(Chan*, char*, int, ulong)
66
{
67
}
68
 
69
static void
70
etherclose(Chan* chan)
71
{
72
	netifclose(etherxx[chan->dev], chan);
73
}
74
 
75
static long
76
etherread(Chan* chan, void* buf, long n, vlong off)
77
{
78
	Ether *ether;
79
	ulong offset = off;
80
 
81
	ether = etherxx[chan->dev];
82
	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
83
		/*
84
		 * With some controllers it is necessary to reach
85
		 * into the chip to extract statistics.
86
		 */
87
		if(NETTYPE(chan->qid.path) == Nifstatqid)
88
			return ether->ifstat(ether, buf, n, offset);
89
		else if(NETTYPE(chan->qid.path) == Nstatqid)
90
			ether->ifstat(ether, buf, 0, offset);
91
	}
92
 
93
	return netifread(ether, chan, buf, n, offset);
94
}
95
 
96
static Block*
97
etherbread(Chan* chan, long n, ulong offset)
98
{
99
	return netifbread(etherxx[chan->dev], chan, n, offset);
100
}
101
 
102
static int
103
etherwstat(Chan* chan, uchar* dp, int n)
104
{
105
	return netifwstat(etherxx[chan->dev], chan, dp, n);
106
}
107
 
108
static void
109
etherrtrace(Netfile* f, Etherpkt* pkt, int len)
110
{
111
	int i, n;
112
	Block *bp;
113
 
114
	if(qwindow(f->in) <= 0)
115
		return;
116
	if(len > 58)
117
		n = 58;
118
	else
119
		n = len;
120
	bp = iallocb(64);
121
	if(bp == nil)
122
		return;
123
	memmove(bp->wp, pkt->d, n);
124
	i = TK2MS(MACHP(0)->ticks);
125
	bp->wp[58] = len>>8;
126
	bp->wp[59] = len;
127
	bp->wp[60] = i>>24;
128
	bp->wp[61] = i>>16;
129
	bp->wp[62] = i>>8;
130
	bp->wp[63] = i;
131
	bp->wp += 64;
132
	qpass(f->in, bp);
133
}
134
 
135
Block*
136
etheriq(Ether* ether, Block* bp, int fromwire)
137
{
138
	Etherpkt *pkt;
139
	ushort type;
140
	int len, multi, tome, fromme;
141
	Netfile **ep, *f, **fp, *fx;
142
	Block *xbp;
143
 
144
	ether->inpackets++;
145
 
146
	pkt = (Etherpkt*)bp->rp;
147
	len = BLEN(bp);
148
	type = (pkt->type[0]<<8)|pkt->type[1];
149
	fx = 0;
150
	ep = &ether->f[Ntypes];
151
 
152
	multi = pkt->d[0] & 1;
153
	/* check for valid multicast addresses */
154
	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
155
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
156
			if(fromwire){
157
				freeb(bp);
158
				bp = 0;
159
			}
160
			return bp;
161
		}
162
	}
163
 
164
	/* is it for me? */
165
	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
166
	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
167
 
168
	/*
169
	 * Multiplex the packet to all the connections which want it.
170
	 * If the packet is not to be used subsequently (fromwire != 0),
171
	 * attempt to simply pass it into one of the connections, thereby
172
	 * saving a copy of the data (usual case hopefully).
173
	 */
174
	for(fp = ether->f; fp < ep; fp++){
175
		if(f = *fp)
176
		if(f->type == type || f->type < 0)
177
		if(tome || multi || f->prom){
178
			/* Don't want to hear bridged packets */
179
			if(f->bridge && !fromwire && !fromme)
180
				continue;
181
			if(!f->headersonly){
182
				if(fromwire && fx == 0)
183
					fx = f;
184
				else if(xbp = iallocb(len)){
185
					memmove(xbp->wp, pkt, len);
186
					xbp->wp += len;
187
					if(qpass(f->in, xbp) < 0)
188
						ether->soverflows++;
189
				}
190
				else
191
					ether->soverflows++;
192
			}
193
			else
194
				etherrtrace(f, pkt, len);
195
		}
196
	}
197
 
198
	if(fx){
199
		if(qpass(fx->in, bp) < 0)
200
			ether->soverflows++;
201
		return 0;
202
	}
203
	if(fromwire){
204
		freeb(bp);
205
		return 0;
206
	}
207
 
208
	return bp;
209
}
210
 
211
static int
212
etheroq(Ether* ether, Block* bp)
213
{
214
	int len, loopback, s;
215
	Etherpkt *pkt;
216
 
217
	ether->outpackets++;
218
 
219
	/*
220
	 * Check if the packet has to be placed back onto the input queue,
221
	 * i.e. if it's a loopback or broadcast packet or the interface is
222
	 * in promiscuous mode.
223
	 * If it's a loopback packet indicate to etheriq that the data isn't
224
	 * needed and return, etheriq will pass-on or free the block.
225
	 * To enable bridging to work, only packets that were originated
226
	 * by this interface are fed back.
227
	 */
228
	pkt = (Etherpkt*)bp->rp;
229
	len = BLEN(bp);
230
	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
231
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
232
		s = splhi();
233
		etheriq(ether, bp, 0);
234
		splx(s);
235
	}
236
 
237
	if(!loopback){
238
		qbwrite(ether->oq, bp);
239
		if(ether->transmit != nil)
240
			ether->transmit(ether);
241
	} else
242
		freeb(bp);
243
 
244
	return len;
245
}
246
 
247
static long
248
etherwrite(Chan* chan, void* buf, long n, vlong)
249
{
250
	Ether *ether;
251
	Block *bp;
252
	int nn, onoff;
253
	Cmdbuf *cb;
254
 
255
	ether = etherxx[chan->dev];
256
	if(NETTYPE(chan->qid.path) != Ndataqid) {
257
		nn = netifwrite(ether, chan, buf, n);
258
		if(nn >= 0)
259
			return nn;
260
		cb = parsecmd(buf, n);
261
		if(strcmp(cb->f[0], "nonblocking") == 0){
262
			if(cb->nf <= 1)
263
				onoff = 1;
264
			else
265
				onoff = atoi(cb->f[1]);
266
			qnoblock(ether->oq, onoff);
267
			free(cb);
268
			return n;
269
		}
270
		free(cb);
271
		if(ether->ctl!=nil)
272
			return ether->ctl(ether,buf,n);
273
 
274
		error(Ebadctl);
275
	}
276
 
277
	if(n > ether->maxmtu)
278
		error(Etoobig);
279
	if(n < ether->minmtu)
280
		error(Etoosmall);
281
 
282
	bp = allocb(n);
283
	if(waserror()){
284
		freeb(bp);
285
		nexterror();
286
	}
287
	memmove(bp->rp, buf, n);
288
	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
289
	poperror();
290
	bp->wp += n;
291
 
292
	return etheroq(ether, bp);
293
}
294
 
295
static long
296
etherbwrite(Chan* chan, Block* bp, ulong)
297
{
298
	Ether *ether;
299
	long n;
300
 
301
	n = BLEN(bp);
302
	if(NETTYPE(chan->qid.path) != Ndataqid){
303
		if(waserror()) {
304
			freeb(bp);
305
			nexterror();
306
		}
307
		n = etherwrite(chan, bp->rp, n, 0);
308
		poperror();
309
		freeb(bp);
310
		return n;
311
	}
312
	ether = etherxx[chan->dev];
313
 
314
	if(n > ether->maxmtu){
315
		freeb(bp);
316
		error(Etoobig);
317
	}
318
	if(n < ether->minmtu){
319
		freeb(bp);
320
		error(Etoosmall);
321
	}
322
 
323
	return etheroq(ether, bp);
324
}
325
 
326
static struct {
327
	char*	type;
328
	int	(*reset)(Ether*);
329
} cards[MaxEther+1];
330
 
331
void
332
addethercard(char* t, int (*r)(Ether*))
333
{
334
	static int ncard;
335
 
336
	if(ncard == MaxEther)
337
		panic("too many ether cards");
338
	cards[ncard].type = t;
339
	cards[ncard].reset = r;
340
	ncard++;
341
}
342
 
343
int
344
parseether(uchar *to, char *from)
345
{
346
	char nip[4];
347
	char *p;
348
	int i;
349
 
350
	p = from;
351
	for(i = 0; i < Eaddrlen; i++){
352
		if(*p == 0)
353
			return -1;
354
		nip[0] = *p++;
355
		if(*p == 0)
356
			return -1;
357
		nip[1] = *p++;
358
		nip[2] = 0;
359
		to[i] = strtoul(nip, 0, 16);
360
		if(*p == ':')
361
			p++;
362
	}
363
	return 0;
364
}
365
 
366
static void
367
etherreset(void)
368
{
369
	Ether *ether;
370
	int i, n, ctlrno;
371
	char name[KNAMELEN], buf[128];
372
 
373
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
374
		if(ether == 0)
375
			ether = malloc(sizeof(Ether));
376
		if(ether == 0)
377
			panic("etherreset: no memory");
378
		memset(ether, 0, sizeof(Ether));
379
		ether->ctlrno = ctlrno;
380
		ether->mbps = 10;
381
		ether->minmtu = ETHERMINTU;
382
		ether->maxmtu = ETHERMAXTU;
383
 
384
		if(archether(ctlrno, ether) <= 0)
385
			continue;
386
 
387
		for(n = 0; cards[n].type; n++){
388
			if(cistrcmp(cards[n].type, ether->type))
389
				continue;
390
			for(i = 0; i < ether->nopt; i++){
391
				if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
392
					if(parseether(ether->ea, &ether->opt[i][3]) == -1)
393
						memset(ether->ea, 0, Eaddrlen);
394
				}else if(cistrcmp(ether->opt[i], "fullduplex") == 0 ||
395
					cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
396
					ether->fullduplex = 1;
397
				else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
398
					ether->mbps = 100;
399
			}
400
			if(cards[n].reset(ether))
401
				break;
402
			snprint(name, sizeof(name), "ether%d", ctlrno);
403
 
404
			if(ether->interrupt != nil)
405
				intrenable(Irqlo, ether->irq, ether->interrupt,
406
					ether, name);
407
 
408
			i = snprint(buf, sizeof buf,
409
				"#l%d: %s: %dMbps port %#lux irq %d",
410
				ctlrno, ether->type, ether->mbps, ether->port,
411
				ether->irq);
412
			if(ether->mem)
413
				i += snprint(buf+i, sizeof buf - i,
414
					" addr %#lux", PADDR(ether->mem));
415
			if(ether->size)
416
				i += snprint(buf+i, sizeof buf - i,
417
					" size %#luX", ether->size);
418
			i += snprint(buf+i, sizeof buf - i,
419
				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
420
				ether->ea[0], ether->ea[1], ether->ea[2],
421
				ether->ea[3], ether->ea[4], ether->ea[5]);
422
			snprint(buf+i, sizeof buf - i, "\n");
423
			print("%s", buf);
424
 
425
			if(ether->mbps >= 1000)
426
				netifinit(ether, name, Ntypes, 4*1024*1024);
427
			else if(ether->mbps >= 100)
428
				netifinit(ether, name, Ntypes, 1024*1024);
429
			else
430
				netifinit(ether, name, Ntypes, 65*1024);
431
			if(ether->oq == 0)
432
				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
433
			if(ether->oq == 0)
434
				panic("etherreset %s", name);
435
			ether->alen = Eaddrlen;
436
			memmove(ether->addr, ether->ea, Eaddrlen);
437
			memset(ether->bcast, 0xFF, Eaddrlen);
438
 
439
			etherxx[ctlrno] = ether;
440
			ether = 0;
441
			break;
442
		}
443
	}
444
	if(ether)
445
		free(ether);
446
}
447
 
448
static void
449
ethershutdown(void)
450
{
451
	Ether *ether;
452
	int i;
453
 
454
	for(i = 0; i < MaxEther; i++){
455
		ether = etherxx[i];
456
		if(ether == nil)
457
			continue;
458
		if(ether->shutdown == nil) {
459
			print("#l%d: no shutdown function\n", i);
460
			continue;
461
		}
462
		(*ether->shutdown)(ether);
463
	}
464
}
465
 
466
#define POLY 0xedb88320
467
 
468
/* really slow 32 bit crc for ethers */
469
ulong
470
ethercrc(uchar *p, int len)
471
{
472
	int i, j;
473
	ulong crc, b;
474
 
475
	crc = 0xffffffff;
476
	for(i = 0; i < len; i++){
477
		b = *p++;
478
		for(j = 0; j < 8; j++){
479
			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
480
			b >>= 1;
481
		}
482
	}
483
	return crc;
484
}
485
 
486
void
487
dumpoq(Queue *oq)
488
{
489
	if (oq == nil)
490
		print("no outq! ");
491
	else if (qisclosed(oq))
492
		print("outq closed ");
493
	else if (qfull(oq))
494
		print("outq full ");
495
	else
496
		print("outq %d ", qlen(oq));
497
}
498
 
499
void
500
dumpnetif(Netif *netif)
501
{
502
	print("netif %s ", netif->name);
503
	print("limit %d mbps %d link %d ",
504
		netif->limit, netif->mbps, netif->link);
505
	print("inpkts %lld outpkts %lld errs %d\n",
506
		netif->inpackets, netif->outpackets,
507
		netif->crcs + netif->oerrs + netif->frames + netif->overflows +
508
		netif->buffs + netif->soverflows);
509
}
510
 
511
Dev etherdevtab = {
512
	'l',
513
	"ether",
514
 
515
	etherreset,
516
	devinit,
517
	ethershutdown,
518
	etherattach,
519
	etherwalk,
520
	etherstat,
521
	etheropen,
522
	ethercreate,
523
	etherclose,
524
	etherread,
525
	etherbread,
526
	etherwrite,
527
	etherbwrite,
528
	devremove,
529
	etherwstat,
530
};