1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 #include "../port/netif.h" 8 9 static int netown(Netfile*, char*, int); 10 static int openfile(Netif*, int); 11 static char* matchtoken(char*, char*); 12 static char* netmulti(Netif*, Netfile*, uchar*, int); 13 static int parseaddr(uchar*, char*, int); 14 15 /* 16 * set up a new network interface 17 */ 18 void 19 netifinit(Netif *nif, char *name, int nfile, ulong limit) 20 { 21 strncpy(nif->name, name, KNAMELEN-1); 22 nif->name[KNAMELEN-1] = 0; 23 nif->nfile = nfile; 24 nif->f = xalloc(nfile*sizeof(Netfile*)); 25 if (nif->f == nil) 26 panic("netifinit: no memory"); 27 memset(nif->f, 0, nfile*sizeof(Netfile*)); 28 nif->limit = limit; 29 } 30 31 /* 32 * generate a 3 level directory 33 */ 34 static int 35 netifgen(Chan *c, char*, Dirtab *vp, int, int i, Dir *dp) 36 { 37 Qid q; 38 Netif *nif = (Netif*)vp; 39 Netfile *f; 40 int t; 41 int perm; 42 char *o; 43 44 q.type = QTFILE; 45 q.vers = 0; 46 47 /* top level directory contains the name of the network */ 48 if(c->qid.path == 0){ 49 switch(i){ 50 case DEVDOTDOT: 51 q.path = 0; 52 q.type = QTDIR; 53 devdir(c, q, ".", 0, eve, 0555, dp); 54 break; 55 case 0: 56 q.path = N2ndqid; 57 q.type = QTDIR; 58 strcpy(up->genbuf, nif->name); 59 devdir(c, q, up->genbuf, 0, eve, 0555, dp); 60 break; 61 default: 62 return -1; 63 } 64 return 1; 65 } 66 67 /* second level contains clone plus all the conversations */ 68 t = NETTYPE(c->qid.path); 69 if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){ 70 switch(i) { 71 case DEVDOTDOT: 72 q.type = QTDIR; 73 q.path = 0; 74 devdir(c, q, ".", 0, eve, DMDIR|0555, dp); 75 break; 76 case 0: 77 q.path = Ncloneqid; 78 devdir(c, q, "clone", 0, eve, 0666, dp); 79 break; 80 case 1: 81 q.path = Naddrqid; 82 devdir(c, q, "addr", 0, eve, 0666, dp); 83 break; 84 case 2: 85 q.path = Nstatqid; 86 devdir(c, q, "stats", 0, eve, 0444, dp); 87 break; 88 case 3: 89 q.path = Nifstatqid; 90 devdir(c, q, "ifstats", 0, eve, 0444, dp); 91 break; 92 default: 93 i -= 4; 94 if(i >= nif->nfile) 95 return -1; 96 if(nif->f[i] == 0) 97 return 0; 98 q.type = QTDIR; 99 q.path = NETQID(i, N3rdqid); 100 snprint(up->genbuf, sizeof up->genbuf, "%d", i); 101 devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp); 102 break; 103 } 104 return 1; 105 } 106 107 /* third level */ 108 f = nif->f[NETID(c->qid.path)]; 109 if(f == 0) 110 return 0; 111 if(*f->owner){ 112 o = f->owner; 113 perm = f->mode; 114 } else { 115 o = eve; 116 perm = 0666; 117 } 118 switch(i){ 119 case DEVDOTDOT: 120 q.type = QTDIR; 121 q.path = N2ndqid; 122 strcpy(up->genbuf, nif->name); 123 devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp); 124 break; 125 case 0: 126 q.path = NETQID(NETID(c->qid.path), Ndataqid); 127 devdir(c, q, "data", 0, o, perm, dp); 128 break; 129 case 1: 130 q.path = NETQID(NETID(c->qid.path), Nctlqid); 131 devdir(c, q, "ctl", 0, o, perm, dp); 132 break; 133 case 2: 134 q.path = NETQID(NETID(c->qid.path), Nstatqid); 135 devdir(c, q, "stats", 0, eve, 0444, dp); 136 break; 137 case 3: 138 q.path = NETQID(NETID(c->qid.path), Ntypeqid); 139 devdir(c, q, "type", 0, eve, 0444, dp); 140 break; 141 case 4: 142 q.path = NETQID(NETID(c->qid.path), Nifstatqid); 143 devdir(c, q, "ifstats", 0, eve, 0444, dp); 144 break; 145 default: 146 return -1; 147 } 148 return 1; 149 } 150 151 Walkqid* 152 netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname) 153 { 154 return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen); 155 } 156 157 Chan* 158 netifopen(Netif *nif, Chan *c, int omode) 159 { 160 int id; 161 Netfile *f; 162 163 id = 0; 164 if(c->qid.type & QTDIR){ 165 if(omode != OREAD) 166 error(Eperm); 167 } else { 168 switch(NETTYPE(c->qid.path)){ 169 case Ndataqid: 170 case Nctlqid: 171 id = NETID(c->qid.path); 172 openfile(nif, id); 173 break; 174 case Ncloneqid: 175 id = openfile(nif, -1); 176 c->qid.path = NETQID(id, Nctlqid); 177 break; 178 default: 179 if(omode != OREAD) 180 error(Ebadarg); 181 } 182 switch(NETTYPE(c->qid.path)){ 183 case Ndataqid: 184 case Nctlqid: 185 f = nif->f[id]; 186 if(netown(f, up->user, omode&7) < 0) 187 error(Eperm); 188 break; 189 } 190 } 191 c->mode = openmode(omode); 192 c->flag |= COPEN; 193 c->offset = 0; 194 c->iounit = qiomaxatomic; 195 return c; 196 } 197 198 long 199 netifread(Netif *nif, Chan *c, void *a, long n, ulong offset) 200 { 201 int i, j; 202 Netfile *f; 203 char *p; 204 205 if(c->qid.type&QTDIR) 206 return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen); 207 208 switch(NETTYPE(c->qid.path)){ 209 case Ndataqid: 210 f = nif->f[NETID(c->qid.path)]; 211 return qread(f->in, a, n); 212 case Nctlqid: 213 return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE); 214 case Nstatqid: 215 p = malloc(READSTR); 216 if(p == nil) 217 error(Enomem); 218 j = snprint(p, READSTR, "in: %llud\n", nif->inpackets); 219 j += snprint(p+j, READSTR-j, "link: %d\n", nif->link); 220 j += snprint(p+j, READSTR-j, "out: %llud\n", nif->outpackets); 221 j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs); 222 j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows); 223 j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows); 224 j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames); 225 j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs); 226 j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs); 227 j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom); 228 j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps); 229 j += snprint(p+j, READSTR-j, "addr: "); 230 for(i = 0; i < nif->alen; i++) 231 j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]); 232 snprint(p+j, READSTR-j, "\n"); 233 n = readstr(offset, a, n, p); 234 free(p); 235 return n; 236 case Naddrqid: 237 p = malloc(READSTR); 238 if(p == nil) 239 error(Enomem); 240 j = 0; 241 for(i = 0; i < nif->alen; i++) 242 j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]); 243 n = readstr(offset, a, n, p); 244 free(p); 245 return n; 246 case Ntypeqid: 247 f = nif->f[NETID(c->qid.path)]; 248 return readnum(offset, a, n, f->type, NUMSIZE); 249 case Nifstatqid: 250 return 0; 251 } 252 error(Ebadarg); 253 return -1; /* not reached */ 254 } 255 256 Block* 257 netifbread(Netif *nif, Chan *c, long n, ulong offset) 258 { 259 if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid) 260 return devbread(c, n, offset); 261 262 return qbread(nif->f[NETID(c->qid.path)]->in, n); 263 } 264 265 /* 266 * make sure this type isn't already in use on this device 267 */ 268 static int 269 typeinuse(Netif *nif, int type) 270 { 271 Netfile *f, **fp, **efp; 272 273 if(type <= 0) 274 return 0; 275 276 efp = &nif->f[nif->nfile]; 277 for(fp = nif->f; fp < efp; fp++){ 278 f = *fp; 279 if(f == 0) 280 continue; 281 if(f->type == type) 282 return 1; 283 } 284 return 0; 285 } 286 287 /* 288 * the devxxx.c that calls us handles writing data, it knows best 289 */ 290 long 291 netifwrite(Netif *nif, Chan *c, void *a, long n) 292 { 293 Netfile *f; 294 int type; 295 char *p, buf[64]; 296 uchar binaddr[Nmaxaddr]; 297 298 if(NETTYPE(c->qid.path) != Nctlqid) 299 error(Eperm); 300 301 if(n >= sizeof(buf)) 302 n = sizeof(buf)-1; 303 memmove(buf, a, n); 304 buf[n] = 0; 305 306 if(waserror()){ 307 qunlock(nif); 308 nexterror(); 309 } 310 311 qlock(nif); 312 f = nif->f[NETID(c->qid.path)]; 313 if((p = matchtoken(buf, "connect")) != 0){ 314 type = atoi(p); 315 if(typeinuse(nif, type)) 316 error(Einuse); 317 f->type = type; 318 if(f->type < 0) 319 nif->all++; 320 } else if(matchtoken(buf, "promiscuous")){ 321 if(f->prom == 0){ 322 if(nif->prom == 0 && nif->promiscuous != nil) 323 nif->promiscuous(nif->arg, 1); 324 f->prom = 1; 325 nif->prom++; 326 } 327 } else if((p = matchtoken(buf, "scanbs")) != 0){ 328 /* scan for base stations */ 329 if(f->scan == 0){ 330 type = atoi(p); 331 if(type < 5) 332 type = 5; 333 if(nif->scanbs != nil) 334 nif->scanbs(nif->arg, type); 335 f->scan = type; 336 nif->scan++; 337 } 338 } else if(matchtoken(buf, "bridge")){ 339 f->bridge = 1; 340 } else if(matchtoken(buf, "headersonly")){ 341 f->headersonly = 1; 342 } else if((p = matchtoken(buf, "addmulti")) != 0){ 343 if(parseaddr(binaddr, p, nif->alen) < 0) 344 error("bad address"); 345 p = netmulti(nif, f, binaddr, 1); 346 if(p) 347 error(p); 348 } else if((p = matchtoken(buf, "remmulti")) != 0){ 349 if(parseaddr(binaddr, p, nif->alen) < 0) 350 error("bad address"); 351 p = netmulti(nif, f, binaddr, 0); 352 if(p) 353 error(p); 354 } else 355 n = -1; 356 qunlock(nif); 357 poperror(); 358 return n; 359 } 360 361 int 362 netifwstat(Netif *nif, Chan *c, uchar *db, int n) 363 { 364 Dir *dir; 365 Netfile *f; 366 int m; 367 368 f = nif->f[NETID(c->qid.path)]; 369 if(f == 0) 370 error(Enonexist); 371 372 if(netown(f, up->user, OWRITE) < 0) 373 error(Eperm); 374 375 dir = smalloc(sizeof(Dir)+n); 376 m = convM2D(db, n, &dir[0], (char*)&dir[1]); 377 if(m == 0){ 378 free(dir); 379 error(Eshortstat); 380 } 381 if(!emptystr(dir[0].uid)) 382 strncpy(f->owner, dir[0].uid, KNAMELEN); 383 if(dir[0].mode != ~0UL) 384 f->mode = dir[0].mode; 385 free(dir); 386 return m; 387 } 388 389 int 390 netifstat(Netif *nif, Chan *c, uchar *db, int n) 391 { 392 return devstat(c, db, n, (Dirtab *)nif, 0, netifgen); 393 } 394 395 void 396 netifclose(Netif *nif, Chan *c) 397 { 398 Netfile *f; 399 int t; 400 Netaddr *ap; 401 402 if((c->flag & COPEN) == 0) 403 return; 404 405 t = NETTYPE(c->qid.path); 406 if(t != Ndataqid && t != Nctlqid) 407 return; 408 409 f = nif->f[NETID(c->qid.path)]; 410 qlock(f); 411 if(--(f->inuse) == 0){ 412 if(f->prom){ 413 qlock(nif); 414 if(--(nif->prom) == 0 && nif->promiscuous != nil) 415 nif->promiscuous(nif->arg, 0); 416 qunlock(nif); 417 f->prom = 0; 418 } 419 if(f->scan){ 420 qlock(nif); 421 if(--(nif->scan) == 0 && nif->scanbs != nil) 422 nif->scanbs(nif->arg, 0); 423 qunlock(nif); 424 f->prom = 0; 425 f->scan = 0; 426 } 427 if(f->nmaddr){ 428 qlock(nif); 429 t = 0; 430 for(ap = nif->maddr; ap; ap = ap->next){ 431 if(f->maddr[t/8] & (1<<(t%8))) 432 netmulti(nif, f, ap->addr, 0); 433 } 434 qunlock(nif); 435 f->nmaddr = 0; 436 } 437 if(f->type < 0){ 438 qlock(nif); 439 --(nif->all); 440 qunlock(nif); 441 } 442 f->owner[0] = 0; 443 f->type = 0; 444 f->bridge = 0; 445 f->headersonly = 0; 446 qclose(f->in); 447 } 448 qunlock(f); 449 } 450 451 Lock netlock; 452 453 static int 454 netown(Netfile *p, char *o, int omode) 455 { 456 static int access[] = { 0400, 0200, 0600, 0100 }; 457 int mode; 458 int t; 459 460 lock(&netlock); 461 if(*p->owner){ 462 if(strncmp(o, p->owner, KNAMELEN) == 0) /* User */ 463 mode = p->mode; 464 else if(strncmp(o, eve, KNAMELEN) == 0) /* Bootes is group */ 465 mode = p->mode<<3; 466 else 467 mode = p->mode<<6; /* Other */ 468 469 t = access[omode&3]; 470 if((t & mode) == t){ 471 unlock(&netlock); 472 return 0; 473 } else { 474 unlock(&netlock); 475 return -1; 476 } 477 } 478 strncpy(p->owner, o, KNAMELEN); 479 p->mode = 0660; 480 unlock(&netlock); 481 return 0; 482 } 483 484 /* 485 * Increment the reference count of a network device. 486 * If id < 0, return an unused ether device. 487 */ 488 static int 489 openfile(Netif *nif, int id) 490 { 491 Netfile *f, **fp, **efp; 492 493 if(id >= 0){ 494 f = nif->f[id]; 495 if(f == 0) 496 error(Enodev); 497 qlock(f); 498 qreopen(f->in); 499 f->inuse++; 500 qunlock(f); 501 return id; 502 } 503 504 qlock(nif); 505 if(waserror()){ 506 qunlock(nif); 507 nexterror(); 508 } 509 efp = &nif->f[nif->nfile]; 510 for(fp = nif->f; fp < efp; fp++){ 511 f = *fp; 512 if(f == 0){ 513 f = malloc(sizeof(Netfile)); 514 if(f == 0) 515 exhausted("memory"); 516 f->in = qopen(nif->limit, Qmsg, 0, 0); 517 if(f->in == nil){ 518 free(f); 519 exhausted("memory"); 520 } 521 *fp = f; 522 qlock(f); 523 } else { 524 qlock(f); 525 if(f->inuse){ 526 qunlock(f); 527 continue; 528 } 529 } 530 f->inuse = 1; 531 qreopen(f->in); 532 netown(f, up->user, 0); 533 qunlock(f); 534 qunlock(nif); 535 poperror(); 536 return fp - nif->f; 537 } 538 error(Enodev); 539 return -1; /* not reached */ 540 } 541 542 /* 543 * look for a token starting a string, 544 * return a pointer to first non-space char after it 545 */ 546 static char* 547 matchtoken(char *p, char *token) 548 { 549 int n; 550 551 n = strlen(token); 552 if(strncmp(p, token, n)) 553 return 0; 554 p += n; 555 if(*p == 0) 556 return p; 557 if(*p != ' ' && *p != '\t' && *p != '\n') 558 return 0; 559 while(*p == ' ' || *p == '\t' || *p == '\n') 560 p++; 561 return p; 562 } 563 564 void 565 hnputv(void *p, uvlong v) 566 { 567 uchar *a; 568 569 a = p; 570 hnputl(a, v>>32); 571 hnputl(a+4, v); 572 } 573 574 void 575 hnputl(void *p, uint v) 576 { 577 uchar *a; 578 579 a = p; 580 a[0] = v>>24; 581 a[1] = v>>16; 582 a[2] = v>>8; 583 a[3] = v; 584 } 585 586 void 587 hnputs(void *p, ushort v) 588 { 589 uchar *a; 590 591 a = p; 592 a[0] = v>>8; 593 a[1] = v; 594 } 595 596 uvlong 597 nhgetv(void *p) 598 { 599 uchar *a; 600 601 a = p; 602 return ((vlong)nhgetl(a) << 32) | nhgetl(a+4); 603 } 604 605 uint 606 nhgetl(void *p) 607 { 608 uchar *a; 609 610 a = p; 611 return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0); 612 } 613 614 ushort 615 nhgets(void *p) 616 { 617 uchar *a; 618 619 a = p; 620 return (a[0]<<8)|(a[1]<<0); 621 } 622 623 static ulong 624 hash(uchar *a, int len) 625 { 626 ulong sum = 0; 627 628 while(len-- > 0) 629 sum = (sum << 1) + *a++; 630 return sum%Nmhash; 631 } 632 633 int 634 activemulti(Netif *nif, uchar *addr, int alen) 635 { 636 Netaddr *hp; 637 638 for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext) 639 if(memcmp(addr, hp->addr, alen) == 0){ 640 if(hp->ref) 641 return 1; 642 else 643 break; 644 } 645 return 0; 646 } 647 648 static int 649 parseaddr(uchar *to, char *from, int alen) 650 { 651 char nip[4]; 652 char *p; 653 int i; 654 655 p = from; 656 for(i = 0; i < alen; i++){ 657 if(*p == 0) 658 return -1; 659 nip[0] = *p++; 660 if(*p == 0) 661 return -1; 662 nip[1] = *p++; 663 nip[2] = 0; 664 to[i] = strtoul(nip, 0, 16); 665 if(*p == ':') 666 p++; 667 } 668 return 0; 669 } 670 671 /* 672 * keep track of multicast addresses 673 */ 674 static char* 675 netmulti(Netif *nif, Netfile *f, uchar *addr, int add) 676 { 677 Netaddr **l, *ap; 678 int i; 679 ulong h; 680 681 if(nif->multicast == nil) 682 return "interface does not support multicast"; 683 684 l = &nif->maddr; 685 i = 0; 686 for(ap = *l; ap; ap = *l){ 687 if(memcmp(addr, ap->addr, nif->alen) == 0) 688 break; 689 i++; 690 l = &ap->next; 691 } 692 693 if(add){ 694 if(ap == 0){ 695 *l = ap = smalloc(sizeof(*ap)); 696 memmove(ap->addr, addr, nif->alen); 697 ap->next = 0; 698 ap->ref = 1; 699 h = hash(addr, nif->alen); 700 ap->hnext = nif->mhash[h]; 701 nif->mhash[h] = ap; 702 } else { 703 ap->ref++; 704 } 705 if(ap->ref == 1){ 706 nif->nmaddr++; 707 nif->multicast(nif->arg, addr, 1); 708 } 709 if(i < 8*sizeof(f->maddr)){ 710 if((f->maddr[i/8] & (1<<(i%8))) == 0) 711 f->nmaddr++; 712 f->maddr[i/8] |= 1<<(i%8); 713 } 714 } else { 715 if(ap == 0 || ap->ref == 0) 716 return 0; 717 ap->ref--; 718 if(ap->ref == 0){ 719 nif->nmaddr--; 720 nif->multicast(nif->arg, addr, 0); 721 } 722 if(i < 8*sizeof(f->maddr)){ 723 if((f->maddr[i/8] & (1<<(i%8))) != 0) 724 f->nmaddr--; 725 f->maddr[i/8] &= ~(1<<(i%8)); 726 } 727 } 728 return 0; 729 } 730