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