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 sprint(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 j = snprint(p, READSTR, "in: %d\n", nif->inpackets); 217 j += snprint(p+j, READSTR-j, "link: %d\n", nif->link); 218 j += snprint(p+j, READSTR-j, "out: %d\n", nif->outpackets); 219 j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs); 220 j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows); 221 j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows); 222 j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames); 223 j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs); 224 j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs); 225 j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom); 226 j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps); 227 j += snprint(p+j, READSTR-j, "addr: "); 228 for(i = 0; i < nif->alen; i++) 229 j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]); 230 snprint(p+j, READSTR-j, "\n"); 231 n = readstr(offset, a, n, p); 232 free(p); 233 return n; 234 case Naddrqid: 235 p = malloc(READSTR); 236 j = 0; 237 for(i = 0; i < nif->alen; i++) 238 j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]); 239 n = readstr(offset, a, n, p); 240 free(p); 241 return n; 242 case Ntypeqid: 243 f = nif->f[NETID(c->qid.path)]; 244 return readnum(offset, a, n, f->type, NUMSIZE); 245 case Nifstatqid: 246 return 0; 247 } 248 error(Ebadarg); 249 return -1; /* not reached */ 250 } 251 252 Block* 253 netifbread(Netif *nif, Chan *c, long n, ulong offset) 254 { 255 if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid) 256 return devbread(c, n, offset); 257 258 return qbread(nif->f[NETID(c->qid.path)]->in, n); 259 } 260 261 /* 262 * make sure this type isn't already in use on this device 263 */ 264 static int 265 typeinuse(Netif *nif, int type) 266 { 267 Netfile *f, **fp, **efp; 268 269 if(type <= 0) 270 return 0; 271 272 efp = &nif->f[nif->nfile]; 273 for(fp = nif->f; fp < efp; fp++){ 274 f = *fp; 275 if(f == 0) 276 continue; 277 if(f->type == type) 278 return 1; 279 } 280 return 0; 281 } 282 283 /* 284 * the devxxx.c that calls us handles writing data, it knows best 285 */ 286 long 287 netifwrite(Netif *nif, Chan *c, void *a, long n) 288 { 289 Netfile *f; 290 int type; 291 char *p, buf[64]; 292 uchar binaddr[Nmaxaddr]; 293 294 if(NETTYPE(c->qid.path) != Nctlqid) 295 error(Eperm); 296 297 if(n >= sizeof(buf)) 298 n = sizeof(buf)-1; 299 memmove(buf, a, n); 300 buf[n] = 0; 301 302 if(waserror()){ 303 qunlock(nif); 304 nexterror(); 305 } 306 307 qlock(nif); 308 f = nif->f[NETID(c->qid.path)]; 309 if((p = matchtoken(buf, "connect")) != 0){ 310 type = atoi(p); 311 if(typeinuse(nif, type)) 312 error(Einuse); 313 f->type = type; 314 if(f->type < 0) 315 nif->all++; 316 } else if(matchtoken(buf, "promiscuous")){ 317 if(f->prom == 0){ 318 if(nif->prom == 0 && nif->promiscuous != nil) 319 nif->promiscuous(nif->arg, 1); 320 f->prom = 1; 321 nif->prom++; 322 } 323 } else if((p = matchtoken(buf, "scanbs")) != 0){ 324 /* scan for base stations */ 325 if(f->scan == 0){ 326 type = atoi(p); 327 if(type < 5) 328 type = 5; 329 if(nif->scanbs != nil) 330 nif->scanbs(nif->arg, type); 331 f->scan = type; 332 nif->scan++; 333 } 334 } else if(matchtoken(buf, "bridge")){ 335 f->bridge = 1; 336 } else if(matchtoken(buf, "headersonly")){ 337 f->headersonly = 1; 338 } else if((p = matchtoken(buf, "addmulti")) != 0){ 339 if(parseaddr(binaddr, p, nif->alen) < 0) 340 error("bad address"); 341 p = netmulti(nif, f, binaddr, 1); 342 if(p) 343 error(p); 344 } else if((p = matchtoken(buf, "remmulti")) != 0){ 345 if(parseaddr(binaddr, p, nif->alen) < 0) 346 error("bad address"); 347 p = netmulti(nif, f, binaddr, 0); 348 if(p) 349 error(p); 350 } else 351 n = -1; 352 qunlock(nif); 353 poperror(); 354 return n; 355 } 356 357 int 358 netifwstat(Netif *nif, Chan *c, uchar *db, int n) 359 { 360 Dir *dir; 361 Netfile *f; 362 int m; 363 364 f = nif->f[NETID(c->qid.path)]; 365 if(f == 0) 366 error(Enonexist); 367 368 if(netown(f, up->user, OWRITE) < 0) 369 error(Eperm); 370 371 dir = smalloc(sizeof(Dir)+n); 372 m = convM2D(db, n, &dir[0], (char*)&dir[1]); 373 if(m == 0){ 374 free(dir); 375 error(Eshortstat); 376 } 377 if(!emptystr(dir[0].uid)) 378 strncpy(f->owner, dir[0].uid, KNAMELEN); 379 if(dir[0].mode != ~0UL) 380 f->mode = dir[0].mode; 381 free(dir); 382 return m; 383 } 384 385 int 386 netifstat(Netif *nif, Chan *c, uchar *db, int n) 387 { 388 return devstat(c, db, n, (Dirtab *)nif, 0, netifgen); 389 } 390 391 void 392 netifclose(Netif *nif, Chan *c) 393 { 394 Netfile *f; 395 int t; 396 Netaddr *ap; 397 398 if((c->flag & COPEN) == 0) 399 return; 400 401 t = NETTYPE(c->qid.path); 402 if(t != Ndataqid && t != Nctlqid) 403 return; 404 405 f = nif->f[NETID(c->qid.path)]; 406 qlock(f); 407 if(--(f->inuse) == 0){ 408 if(f->prom){ 409 qlock(nif); 410 if(--(nif->prom) == 0 && nif->promiscuous != nil) 411 nif->promiscuous(nif->arg, 0); 412 qunlock(nif); 413 f->prom = 0; 414 } 415 if(f->scan){ 416 qlock(nif); 417 if(--(nif->scan) == 0 && nif->scanbs != nil) 418 nif->scanbs(nif->arg, 0); 419 qunlock(nif); 420 f->prom = 0; 421 f->scan = 0; 422 } 423 if(f->nmaddr){ 424 qlock(nif); 425 t = 0; 426 for(ap = nif->maddr; ap; ap = ap->next){ 427 if(f->maddr[t/8] & (1<<(t%8))) 428 netmulti(nif, f, ap->addr, 0); 429 } 430 qunlock(nif); 431 f->nmaddr = 0; 432 } 433 if(f->type < 0){ 434 qlock(nif); 435 --(nif->all); 436 qunlock(nif); 437 } 438 f->owner[0] = 0; 439 f->type = 0; 440 f->bridge = 0; 441 f->headersonly = 0; 442 qclose(f->in); 443 } 444 qunlock(f); 445 } 446 447 Lock netlock; 448 449 static int 450 netown(Netfile *p, char *o, int omode) 451 { 452 static int access[] = { 0400, 0200, 0600, 0100 }; 453 int mode; 454 int t; 455 456 lock(&netlock); 457 if(*p->owner){ 458 if(strncmp(o, p->owner, KNAMELEN) == 0) /* User */ 459 mode = p->mode; 460 else if(strncmp(o, eve, KNAMELEN) == 0) /* Bootes is group */ 461 mode = p->mode<<3; 462 else 463 mode = p->mode<<6; /* Other */ 464 465 t = access[omode&3]; 466 if((t & mode) == t){ 467 unlock(&netlock); 468 return 0; 469 } else { 470 unlock(&netlock); 471 return -1; 472 } 473 } 474 strncpy(p->owner, o, KNAMELEN); 475 p->mode = 0660; 476 unlock(&netlock); 477 return 0; 478 } 479 480 /* 481 * Increment the reference count of a network device. 482 * If id < 0, return an unused ether device. 483 */ 484 static int 485 openfile(Netif *nif, int id) 486 { 487 Netfile *f, **fp, **efp; 488 489 if(id >= 0){ 490 f = nif->f[id]; 491 if(f == 0) 492 error(Enodev); 493 qlock(f); 494 qreopen(f->in); 495 f->inuse++; 496 qunlock(f); 497 return id; 498 } 499 500 qlock(nif); 501 if(waserror()){ 502 qunlock(nif); 503 nexterror(); 504 } 505 efp = &nif->f[nif->nfile]; 506 for(fp = nif->f; fp < efp; fp++){ 507 f = *fp; 508 if(f == 0){ 509 f = malloc(sizeof(Netfile)); 510 if(f == 0) 511 exhausted("memory"); 512 f->in = qopen(nif->limit, Qmsg, 0, 0); 513 if(f->in == nil){ 514 free(f); 515 exhausted("memory"); 516 } 517 *fp = f; 518 qlock(f); 519 } else { 520 qlock(f); 521 if(f->inuse){ 522 qunlock(f); 523 continue; 524 } 525 } 526 f->inuse = 1; 527 qreopen(f->in); 528 netown(f, up->user, 0); 529 qunlock(f); 530 qunlock(nif); 531 poperror(); 532 return fp - nif->f; 533 } 534 error(Enodev); 535 return -1; /* not reached */ 536 } 537 538 /* 539 * look for a token starting a string, 540 * return a pointer to first non-space char after it 541 */ 542 static char* 543 matchtoken(char *p, char *token) 544 { 545 int n; 546 547 n = strlen(token); 548 if(strncmp(p, token, n)) 549 return 0; 550 p += n; 551 if(*p == 0) 552 return p; 553 if(*p != ' ' && *p != '\t' && *p != '\n') 554 return 0; 555 while(*p == ' ' || *p == '\t' || *p == '\n') 556 p++; 557 return p; 558 } 559 560 void 561 hnputv(void *p, uvlong v) 562 { 563 uchar *a; 564 565 a = p; 566 hnputl(a, v>>32); 567 hnputl(a+4, v); 568 } 569 570 void 571 hnputl(void *p, uint v) 572 { 573 uchar *a; 574 575 a = p; 576 a[0] = v>>24; 577 a[1] = v>>16; 578 a[2] = v>>8; 579 a[3] = v; 580 } 581 582 void 583 hnputs(void *p, ushort v) 584 { 585 uchar *a; 586 587 a = p; 588 a[0] = v>>8; 589 a[1] = v; 590 } 591 592 uvlong 593 nhgetv(void *p) 594 { 595 uchar *a; 596 597 a = p; 598 return ((vlong)nhgetl(a) << 32) | nhgetl(a+4); 599 } 600 601 uint 602 nhgetl(void *p) 603 { 604 uchar *a; 605 606 a = p; 607 return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0); 608 } 609 610 ushort 611 nhgets(void *p) 612 { 613 uchar *a; 614 615 a = p; 616 return (a[0]<<8)|(a[1]<<0); 617 } 618 619 static ulong 620 hash(uchar *a, int len) 621 { 622 ulong sum = 0; 623 624 while(len-- > 0) 625 sum = (sum << 1) + *a++; 626 return sum%Nmhash; 627 } 628 629 int 630 activemulti(Netif *nif, uchar *addr, int alen) 631 { 632 Netaddr *hp; 633 634 for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext) 635 if(memcmp(addr, hp->addr, alen) == 0){ 636 if(hp->ref) 637 return 1; 638 else 639 break; 640 } 641 return 0; 642 } 643 644 static int 645 parseaddr(uchar *to, char *from, int alen) 646 { 647 char nip[4]; 648 char *p; 649 int i; 650 651 p = from; 652 for(i = 0; i < alen; i++){ 653 if(*p == 0) 654 return -1; 655 nip[0] = *p++; 656 if(*p == 0) 657 return -1; 658 nip[1] = *p++; 659 nip[2] = 0; 660 to[i] = strtoul(nip, 0, 16); 661 if(*p == ':') 662 p++; 663 } 664 return 0; 665 } 666 667 /* 668 * keep track of multicast addresses 669 */ 670 static char* 671 netmulti(Netif *nif, Netfile *f, uchar *addr, int add) 672 { 673 Netaddr **l, *ap; 674 int i; 675 ulong h; 676 677 if(nif->multicast == nil) 678 return "interface does not support multicast"; 679 680 l = &nif->maddr; 681 i = 0; 682 for(ap = *l; ap; ap = *l){ 683 if(memcmp(addr, ap->addr, nif->alen) == 0) 684 break; 685 i++; 686 l = &ap->next; 687 } 688 689 if(add){ 690 if(ap == 0){ 691 *l = ap = smalloc(sizeof(*ap)); 692 memmove(ap->addr, addr, nif->alen); 693 ap->next = 0; 694 ap->ref = 1; 695 h = hash(addr, nif->alen); 696 ap->hnext = nif->mhash[h]; 697 nif->mhash[h] = ap; 698 } else { 699 ap->ref++; 700 } 701 if(ap->ref == 1){ 702 nif->nmaddr++; 703 nif->multicast(nif->arg, addr, 1); 704 } 705 if(i < 8*sizeof(f->maddr)){ 706 if((f->maddr[i/8] & (1<<(i%8))) == 0) 707 f->nmaddr++; 708 f->maddr[i/8] |= 1<<(i%8); 709 } 710 } else { 711 if(ap == 0 || ap->ref == 0) 712 return 0; 713 ap->ref--; 714 if(ap->ref == 0){ 715 nif->nmaddr--; 716 nif->multicast(nif->arg, addr, 0); 717 } 718 if(i < 8*sizeof(f->maddr)){ 719 if((f->maddr[i/8] & (1<<(i%8))) != 0) 720 f->nmaddr--; 721 f->maddr[i/8] &= ~(1<<(i%8)); 722 } 723 } 724 return 0; 725 } 726