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