Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/9/pc/devether.c – Rev 2

Subversion Repositories planix.SVN

Rev

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