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