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