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