vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

devether.c (10561B)


      1 #include "u.h"
      2 #include "lib.h"
      3 #include "mem.h"
      4 #include "dat.h"
      5 #include "fns.h"
      6 #include "io.h"
      7 #include "ureg.h"
      8 #include "error.h"
      9 #include "netif.h"
     10 
     11 #include "etherif.h"
     12 
     13 extern int memsize;
     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]->ni, chan, nchan, name, nname);
     48 }
     49 
     50 static int
     51 etherstat(Chan* chan, uchar* dp, int n)
     52 {
     53 	return netifstat(&etherxx[chan->dev]->ni, chan, dp, n);
     54 }
     55 
     56 static Chan*
     57 etheropen(Chan* chan, int omode)
     58 {
     59 	return netifopen(&etherxx[chan->dev]->ni, chan, omode);
     60 }
     61 
     62 static void
     63 ethercreate(Chan* ch, char* c, int i, ulong ul)
     64 {
     65 }
     66 
     67 static void
     68 etherclose(Chan* chan)
     69 {
     70 	netifclose(&etherxx[chan->dev]->ni, 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->ni, chan, buf, n, offset);
     92 }
     93 
     94 static Block*
     95 etherbread(Chan* chan, long n, ulong offset)
     96 {
     97 	return netifbread(&etherxx[chan->dev]->ni, chan, n, offset);
     98 }
     99 
    100 static int
    101 etherwstat(Chan* chan, uchar* dp, int n)
    102 {
    103 	return netifwstat(&etherxx[chan->dev]->ni, 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)->tscticks);
    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->ni.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->ni.f[Ntypes];
    149 
    150 	multi = pkt->d[0] & 1;
    151 	/* check for valid multicast addresses */
    152 	if(multi && memcmp(pkt->d, ether->ni.bcast, sizeof(pkt->d)) != 0 && ether->ni.prom == 0){
    153 		if(!activemulti(&ether->ni, 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->ni.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->ni.soverflows++;
    188 					}
    189 				}
    190 				else {
    191 					print("soverflow iallocb\n");
    192 					ether->ni.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->ni.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->ni.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->ni.bcast, sizeof(pkt->d)) == 0 || ether->ni.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 v)
    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->ni, 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->maxmtu)
    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 u)
    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->maxmtu){
    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 	memset(ether, 0, sizeof(Ether));
    382 	ether->ctlrno = ctlrno;
    383 	ether->tbdf = BUSUNKNOWN;
    384 	ether->ni.mbps = 10;
    385 	ether->minmtu = ETHERMINTU;
    386 	ether->maxmtu = ETHERMAXTU;
    387 
    388 	if(cardno < 0){
    389 		for(cardno = 0; cards[cardno].type; cardno++){
    390 			for(i = 0; i < ether->isac.nopt; i++){
    391 				if(strncmp(ether->isac.opt[i], "ea=", 3))
    392 					continue;
    393 				if(parseether(ether->ea, &ether->isac.opt[i][3]))
    394 					memset(ether->ea, 0, Eaddrlen);
    395 			}
    396 			break;
    397 		}
    398 	}
    399 
    400 	if(cardno >= MaxEther || cards[cardno].type == nil){
    401 		free(ether);
    402 		return nil;
    403 	}
    404 	if(cards[cardno].reset(ether) < 0){
    405 		free(ether);
    406 		return nil;
    407 	}
    408 
    409 	/*
    410 	 * IRQ2 doesn't really exist, it's used to gang the interrupt
    411 	 * controllers together. A device set to IRQ2 will appear on
    412 	 * the second interrupt controller as IRQ9.
    413 	 */
    414 	if(ether->isac.irq == 2)
    415 		ether->isac.irq = 9;
    416 	snprint(name, sizeof(name), "ether%d", ctlrno);
    417 
    418 	i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
    419 		ctlrno, cards[cardno].type, ether->ni.mbps, ether->isac.port, ether->isac.irq);
    420 	if(ether->isac.mem)
    421 		i += sprint(buf+i, " addr 0x%luX", ether->isac.mem);
    422 	if(ether->isac.size)
    423 		i += sprint(buf+i, " size 0x%luX", ether->isac.size);
    424 	i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
    425 		ether->ea[0], ether->ea[1], ether->ea[2],
    426 		ether->ea[3], ether->ea[4], ether->ea[5]);
    427 	sprint(buf+i, "\n");
    428 	print(buf);
    429 
    430 	/* compute log10(ether->ni.mbps) into lg */
    431 	for(lg = 0, mb = ether->ni.mbps; mb >= 10; lg++)
    432 		mb /= 10;
    433 	if (lg > 0)
    434 		lg--;
    435 	if (lg > 14)			/* 2^(14+17) = 2⁳ⁱ */
    436 		lg = 14;
    437 	/* allocate larger output queues for higher-speed interfaces */
    438 	bsz = 1UL << (lg + 17);		/* 2ⁱ⁷ = 128K, bsz = 2ⁿ × 128K */
    439 	while (bsz > memsize && bsz > 128*1024)
    440 		bsz /= 2;
    441 
    442 	netifinit(&ether->ni, name, Ntypes, bsz);
    443 	if(ether->oq == nil) {
    444 		ether->oq = qopen(bsz, Qmsg, 0, 0);
    445 		ether->ni.limit = bsz;
    446 	}
    447 	if(ether->oq == nil)
    448 		panic("etherreset %s: can't allocate output queue of %ld bytes",
    449 			name, bsz);
    450 	ether->ni.alen = Eaddrlen;
    451 	memmove(ether->ni.addr, ether->ea, Eaddrlen);
    452 	memset(ether->ni.bcast, 0xFF, Eaddrlen);
    453 
    454 	return ether;
    455 }
    456 
    457 static void
    458 etherreset(void)
    459 {
    460 	Ether *ether;
    461 	int cardno, ctlrno;
    462 
    463 	for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
    464 		if((ether = etherprobe(-1, ctlrno)) == nil)
    465 			continue;
    466 		etherxx[ctlrno] = ether;
    467 	}
    468 
    469 	cardno = ctlrno = 0;
    470 	while(cards[cardno].type != nil && ctlrno < MaxEther){
    471 		if(etherxx[ctlrno] != nil){
    472 			ctlrno++;
    473 			continue;
    474 		}
    475 		if((ether = etherprobe(cardno, ctlrno)) == nil){
    476 			cardno++;
    477 			continue;
    478 		}
    479 		etherxx[ctlrno] = ether;
    480 		ctlrno++;
    481 	}
    482 }
    483 
    484 static void
    485 ethershutdown(void)
    486 {
    487 	Ether *ether;
    488 	int i;
    489 
    490 	for(i = 0; i < MaxEther; i++){
    491 		ether = etherxx[i];
    492 		if(ether == nil)
    493 			continue;
    494 		if(ether->shutdown == nil) {
    495 			print("#l%d: no shutdown fuction\n", i);
    496 			continue;
    497 		}
    498 		(*ether->shutdown)(ether);
    499 	}
    500 }
    501 
    502 
    503 #define POLY 0xedb88320
    504 
    505 /* really slow 32 bit crc for ethers */
    506 ulong
    507 ethercrc(uchar *p, int len)
    508 {
    509 	int i, j;
    510 	ulong crc, b;
    511 
    512 	crc = 0xffffffff;
    513 	for(i = 0; i < len; i++){
    514 		b = *p++;
    515 		for(j = 0; j < 8; j++){
    516 			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
    517 			b >>= 1;
    518 		}
    519 	}
    520 	return crc;
    521 }
    522 
    523 Dev etherdevtab = {
    524 	'l',
    525 	"ether",
    526 
    527 	etherreset,
    528 	devinit,
    529 	ethershutdown,
    530 	etherattach,
    531 	etherwalk,
    532 	etherstat,
    533 	etheropen,
    534 	ethercreate,
    535 	etherclose,
    536 	etherread,
    537 	etherbread,
    538 	etherwrite,
    539 	etherbwrite,
    540 	devremove,
    541 	etherwstat,
    542 };