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 "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 &&
155
	    ether->prom == 0){
156
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
157
			if(fromwire){
158
				freeb(bp);
159
				bp = 0;
160
			}
161
			return bp;
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) != nil && (f->type == type || f->type < 0) &&
176
		    (tome || multi || f->prom)){
177
			/* Don't want to hear bridged packets */
178
			if(f->bridge && !fromwire && !fromme)
179
				continue;
180
			if(!f->headersonly){
181
				if(fromwire && fx == 0)
182
					fx = f;
183
				else if(xbp = iallocb(len)){
184
					memmove(xbp->wp, pkt, len);
185
					xbp->wp += len;
186
					if(qpass(f->in, xbp) < 0)
187
						ether->soverflows++;
188
				}
189
				else
190
					ether->soverflows++;
191
			}
192
			else
193
				etherrtrace(f, pkt, len);
194
		}
195
	}
196
 
197
	if(fx){
198
		if(qpass(fx->in, bp) < 0)
199
			ether->soverflows++;
200
		return 0;
201
	}
202
	if(fromwire){
203
		freeb(bp);
204
		return 0;
205
	}
206
	return bp;
207
}
208
 
209
static int
210
etheroq(Ether* ether, Block* bp)
211
{
212
	int len, loopback, s;
213
	Etherpkt *pkt;
214
 
215
	ether->outpackets++;
216
 
217
	/*
218
	 * Check if the packet has to be placed back onto the input queue,
219
	 * i.e. if it's a loopback or broadcast packet or the interface is
220
	 * in promiscuous mode.
221
	 * If it's a loopback packet indicate to etheriq that the data isn't
222
	 * needed and return, etheriq will pass-on or free the block.
223
	 * To enable bridging to work, only packets that were originated
224
	 * by this interface are fed back.
225
	 */
226
	pkt = (Etherpkt*)bp->rp;
227
	len = BLEN(bp);
228
	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
229
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
230
		s = splhi();
231
		etheriq(ether, bp, 0);
232
		splx(s);
233
	}
234
 
235
	if(!loopback){
236
		qbwrite(ether->oq, bp);
237
		if(ether->transmit != nil)
238
			ether->transmit(ether);
239
	} else
240
		freeb(bp);
241
 
242
	return len;
243
}
244
 
245
static long
246
etherwrite(Chan* chan, void* buf, long n, vlong)
247
{
248
	Ether *ether;
249
	Block *bp;
250
	int nn, onoff;
251
	Cmdbuf *cb;
252
 
253
	ether = etherxx[chan->dev];
254
	if(NETTYPE(chan->qid.path) != Ndataqid) {
255
		nn = netifwrite(ether, chan, buf, n);
256
		if(nn >= 0)
257
			return nn;
258
		cb = parsecmd(buf, n);
259
		if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
260
			if(cb->nf <= 1)
261
				onoff = 1;
262
			else
263
				onoff = atoi(cb->f[1]);
264
			qnoblock(ether->oq, onoff);
265
			free(cb);
266
			return n;
267
		}
268
		free(cb);
269
		if(ether->ctl!=nil)
270
			return ether->ctl(ether,buf,n);
271
 
272
		error(Ebadctl);
273
	}
274
 
275
	if(n > ether->maxmtu)
276
		error(Etoobig);
277
	if(n < ether->minmtu)
278
		error(Etoosmall);
279
 
280
	bp = allocb(n);
281
	if(waserror()){
282
		freeb(bp);
283
		nexterror();
284
	}
285
	memmove(bp->rp, buf, n);
286
	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
287
	poperror();
288
	bp->wp += n;
289
 
290
	return etheroq(ether, bp);
291
}
292
 
293
static long
294
etherbwrite(Chan* chan, Block* bp, ulong)
295
{
296
	Ether *ether;
297
	long n;
298
 
299
	n = BLEN(bp);
300
	if(NETTYPE(chan->qid.path) != Ndataqid){
301
		if(waserror()) {
302
			freeb(bp);
303
			nexterror();
304
		}
305
		n = etherwrite(chan, bp->rp, n, 0);
306
		poperror();
307
		freeb(bp);
308
		return n;
309
	}
310
	ether = etherxx[chan->dev];
311
 
312
	if(n > ether->maxmtu){
313
		freeb(bp);
314
		error(Etoobig);
315
	}
316
	if(n < ether->minmtu){
317
		freeb(bp);
318
		error(Etoosmall);
319
	}
320
 
321
	return etheroq(ether, bp);
322
}
323
 
324
static struct {
325
	char*	type;
326
	int	(*reset)(Ether*);
327
} cards[MaxEther+1];
328
 
329
void
330
addethercard(char* t, int (*r)(Ether*))
331
{
332
	static int ncard;
333
 
334
	if(ncard == MaxEther)
335
		panic("too many ether cards");
336
	cards[ncard].type = t;
337
	cards[ncard].reset = r;
338
	ncard++;
339
}
340
 
341
int
342
parseether(uchar *to, char *from)
343
{
344
	char nip[4];
345
	char *p;
346
	int i;
347
 
348
	p = from;
349
	for(i = 0; i < Eaddrlen; i++){
350
		if(*p == 0)
351
			return -1;
352
		nip[0] = *p++;
353
		if(*p == 0)
354
			return -1;
355
		nip[1] = *p++;
356
		nip[2] = 0;
357
		to[i] = strtoul(nip, 0, 16);
358
		if(*p == ':')
359
			p++;
360
	}
361
	return 0;
362
}
363
 
364
static void
365
etherreset(void)
366
{
367
	Ether *ether;
368
	int i, n, ctlrno;
369
	char name[KNAMELEN], buf[128];
370
 
371
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
372
		if(ether == 0)
373
			ether = malloc(sizeof(Ether));
374
		memset(ether, 0, sizeof(Ether));
375
		ether->ctlrno = ctlrno;
376
		ether->mbps = 10;
377
		ether->minmtu = ETHERMINTU;
378
		ether->maxmtu = ETHERMAXTU;
379
 
380
		if(archether(ctlrno, ether) <= 0)
381
			continue;
382
 
383
		if(isaconfig("ether", ctlrno, ether) == 0){
384
//			free(ether);
385
//			return nil;
386
			continue;
387
		}
388
		for(n = 0; cards[n].type; n++){
389
			if(cistrcmp(cards[n].type, ether->type))
390
				continue;
391
			for(i = 0; i < ether->nopt; i++)
392
				if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
393
					if(parseether(ether->ea,
394
					    &ether->opt[i][3]) == -1)
395
						memset(ether->ea, 0, Eaddrlen);
396
				} else if(cistrcmp(ether->opt[i],
397
				    "100BASE-TXFD") == 0)
398
					ether->mbps = 100;
399
			if(cards[n].reset(ether))
400
				break;
401
			snprint(name, sizeof(name), "ether%d", ctlrno);
402
 
403
			if(ether->interrupt != nil && ether->irq >= 0)
404
				intrenable(ether->irq, ether->interrupt,
405
					ether, 0, name);
406
 
407
			i = snprint(buf, sizeof buf,
408
				"#l%d: %s: %dMbps port %#lux irq %d",
409
				ctlrno, ether->type, ether->mbps, ether->port,
410
				ether->irq);
411
			if(ether->mem)
412
				i += snprint(buf+i, sizeof buf - i,
413
					" addr %#lux", PADDR(ether->mem));
414
			if(ether->size)
415
				i += snprint(buf+i, sizeof buf - i,
416
					" size %#luX", ether->size);
417
			i += snprint(buf+i, sizeof buf - i,
418
				": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
419
				ether->ea[0], ether->ea[1], ether->ea[2],
420
				ether->ea[3], ether->ea[4], ether->ea[5]);
421
			snprint(buf+i, sizeof buf - i, "\n");
422
			iprint("%s", buf);  /* it may be too early for print */
423
 
424
			if(ether->mbps >= 1000)
425
				netifinit(ether, name, Ntypes, 4*1024*1024);
426
			else if(ether->mbps >= 100)
427
				netifinit(ether, name, Ntypes, 1024*1024);
428
			else
429
				netifinit(ether, name, Ntypes, 65*1024);
430
			if(ether->oq == 0)
431
				ether->oq = qopen(ether->limit, Qmsg, 0, 0);
432
			if(ether->oq == 0)
433
				panic("etherreset %s", name);
434
			ether->alen = Eaddrlen;
435
			memmove(ether->addr, ether->ea, Eaddrlen);
436
			memset(ether->bcast, 0xFF, Eaddrlen);
437
 
438
			etherxx[ctlrno] = ether;
439
			ether = 0;
440
			break;
441
		}
442
	}
443
	if(ether)
444
		free(ether);
445
}
446
 
447
static void
448
ethershutdown(void)
449
{
450
	Ether *ether;
451
	int i;
452
 
453
	for(i = 0; i < MaxEther; i++){
454
		ether = etherxx[i];
455
		if(ether == nil)
456
			continue;
457
		if(ether->shutdown == nil) {
458
			print("#l%d: no shutdown function\n", i);
459
			continue;
460
		}
461
		(*ether->shutdown)(ether);
462
	}
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
};