1 #include "dat.h" 2 #include "fns.h" 3 #include "error.h" 4 #include "ip.h" 5 6 enum 7 { 8 Qtopdir = 1, /* top level directory */ 9 Qtopbase, 10 Qarp= Qtopbase, 11 /* Qiproute, */ 12 /* Qipselftab, */ 13 Qndb, 14 15 Qprotodir, /* directory for a protocol */ 16 Qprotobase, 17 Qclone= Qprotobase, 18 Qstats, 19 20 Qconvdir, /* directory for a conversation */ 21 Qconvbase, 22 Qctl= Qconvbase, 23 Qdata, 24 Qlisten, 25 Qlocal, 26 Qremote, 27 Qstatus, 28 29 Logtype= 5, 30 Masktype= (1<<Logtype)-1, 31 Logconv= 12, 32 Maskconv= (1<<Logconv)-1, 33 Shiftconv= Logtype, 34 Logproto= 8, 35 Maskproto= (1<<Logproto)-1, 36 Shiftproto= Logtype + Logconv, 37 38 Statelen = 256, 39 40 Nfs= 1, 41 42 Maxproto = 4, 43 MAXCONV = 4096 44 }; 45 #define TYPE(x) ( ((ulong)(x).path) & Masktype ) 46 #define CONV(x) ( (((ulong)(x).path) >> Shiftconv) & Maskconv ) 47 #define PROTO(x) ( (((ulong)(x).path) >> Shiftproto) & Maskproto ) 48 #define QID(p, c, y) ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) ) 49 50 enum 51 { 52 Idle= 0, 53 Announcing= 1, 54 Announced= 2, 55 Connecting= 3, 56 Connected= 4, 57 Hungup= 5, 58 }; 59 60 struct Conv 61 { 62 QLock l; 63 64 int x; /* conversation index */ 65 Proto* p; 66 67 uchar laddr[IPaddrlen]; /* local IP address */ 68 uchar raddr[IPaddrlen]; /* remote IP address */ 69 int restricted; /* remote port is restricted */ 70 ushort lport; /* local port number */ 71 ushort rport; /* remote port number */ 72 73 char* owner; /* protections */ 74 int perm; 75 int inuse; /* opens of listen/data/ctl */ 76 int state; 77 78 /* udp specific */ 79 int headers; /* data src/dst headers in udp */ 80 81 char cerr[ERRMAX]; 82 83 QLock listenq; 84 85 void* ptcl; /* protocol specific stuff */ 86 87 int sfd; 88 QLock wlock; /* prevent data from being split by concurrent writes */ 89 }; 90 91 struct Proto 92 { 93 QLock l; 94 int x; 95 int ipproto; 96 int stype; 97 char* name; 98 int maxconv; 99 Fs* f; /* file system this proto is part of */ 100 Conv** conv; /* array of conversations */ 101 int pctlsize; /* size of per protocol ctl block */ 102 int nc; /* number of conversations */ 103 int ac; 104 Qid qid; /* qid for protocol directory */ 105 /* port allocation isn't done here when hosted */ 106 107 void* priv; 108 }; 109 110 /* 111 * one per IP protocol stack 112 */ 113 struct Fs 114 { 115 RWlock l; 116 int dev; 117 118 int np; 119 Proto* p[Maxproto+1]; /* list of supported protocols */ 120 Proto* t2p[256]; /* vector of all protocols */ 121 122 char ndb[1024]; /* an ndb entry for this interface */ 123 int ndbvers; 124 long ndbmtime; 125 }; 126 127 static Fs *ipfs[Nfs]; /* attached fs's */ 128 static char network[] = "network"; 129 static char* ipstates[] = { 130 "Closed", /* Idle */ 131 "Announcing", 132 "Announced", 133 "Connecting", 134 "Established", /* Connected */ 135 "Closed", /* Hungup */ 136 }; 137 138 static Conv* protoclone(Proto*, char*, int); 139 static Conv* newconv(Proto*, Conv **); 140 static void setladdr(Conv*); 141 142 static int 143 ip3gen(Chan *c, int i, Dir *dp) 144 { 145 Qid q; 146 Conv *cv; 147 char *p; 148 149 cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)]; 150 if(cv->owner == nil) 151 kstrdup(&cv->owner, eve); 152 mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); 153 154 switch(i) { 155 default: 156 return -1; 157 case Qctl: 158 devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); 159 return 1; 160 case Qdata: 161 devdir(c, q, "data", 0, cv->owner, cv->perm, dp); 162 return 1; 163 case Qlisten: 164 devdir(c, q, "listen", 0, cv->owner, cv->perm, dp); 165 return 1; 166 case Qlocal: 167 p = "local"; 168 break; 169 case Qremote: 170 p = "remote"; 171 break; 172 case Qstatus: 173 p = "status"; 174 break; 175 } 176 devdir(c, q, p, 0, cv->owner, 0444, dp); 177 return 1; 178 } 179 180 static int 181 ip2gen(Chan *c, int i, Dir *dp) 182 { 183 Qid q; 184 185 switch(i) { 186 case Qclone: 187 mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE); 188 devdir(c, q, "clone", 0, network, 0666, dp); 189 return 1; 190 case Qstats: 191 mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE); 192 devdir(c, q, "stats", 0, network, 0444, dp); 193 return 1; 194 } 195 return -1; 196 } 197 198 static int 199 ip1gen(Chan *c, int i, Dir *dp) 200 { 201 Qid q; 202 char *p; 203 int prot; 204 int len = 0; 205 Fs *f; 206 extern ulong kerndate; 207 208 f = ipfs[c->dev]; 209 210 prot = 0664; 211 mkqid(&q, QID(0, 0, i), 0, QTFILE); 212 switch(i) { 213 default: 214 return -1; 215 case Qarp: 216 p = "arp"; 217 break; 218 case Qndb: 219 p = "ndb"; 220 len = strlen(ipfs[c->dev]->ndb); 221 break; 222 /* case Qiproute: 223 p = "iproute"; 224 break; 225 case Qipselftab: 226 p = "ipselftab"; 227 prot = 0444; 228 break; 229 case Qiprouter: 230 p = "iprouter"; 231 break; 232 case Qlog: 233 p = "log"; 234 break; 235 */ 236 } 237 devdir(c, q, p, len, network, prot, dp); 238 if(i == Qndb && f->ndbmtime > kerndate) 239 dp->mtime = f->ndbmtime; 240 return 1; 241 } 242 243 static int 244 ipgen(Chan *c, char *name, Dirtab *tab, int x, int s, Dir *dp) 245 { 246 Qid q; 247 Conv *cv; 248 Fs *f; 249 250 USED(name); 251 USED(tab); 252 USED(x); 253 f = ipfs[c->dev]; 254 255 switch(TYPE(c->qid)) { 256 case Qtopdir: 257 if(s == DEVDOTDOT){ 258 mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); 259 sprint(up->genbuf, "#I%lud", c->dev); 260 devdir(c, q, up->genbuf, 0, network, 0555, dp); 261 return 1; 262 } 263 if(s < f->np) { 264 /* if(f->p[s]->connect == nil) 265 return 0; /* protocol with no user interface */ 266 mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); 267 devdir(c, q, f->p[s]->name, 0, network, 0555, dp); 268 return 1; 269 } 270 s -= f->np; 271 return ip1gen(c, s+Qtopbase, dp); 272 case Qarp: 273 case Qndb: 274 /* case Qiproute: 275 case Qiprouter: 276 case Qipselftab: */ 277 return ip1gen(c, TYPE(c->qid), dp); 278 case Qprotodir: 279 if(s == DEVDOTDOT){ 280 mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); 281 sprint(up->genbuf, "#I%lud", c->dev); 282 devdir(c, q, up->genbuf, 0, network, 0555, dp); 283 return 1; 284 } 285 if(s < f->p[PROTO(c->qid)]->ac) { 286 cv = f->p[PROTO(c->qid)]->conv[s]; 287 sprint(up->genbuf, "%d", s); 288 mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR); 289 devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp); 290 return 1; 291 } 292 s -= f->p[PROTO(c->qid)]->ac; 293 return ip2gen(c, s+Qprotobase, dp); 294 case Qclone: 295 case Qstats: 296 return ip2gen(c, TYPE(c->qid), dp); 297 case Qconvdir: 298 if(s == DEVDOTDOT){ 299 s = PROTO(c->qid); 300 mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); 301 devdir(c, q, f->p[s]->name, 0, network, 0555, dp); 302 return 1; 303 } 304 return ip3gen(c, s+Qconvbase, dp); 305 case Qctl: 306 case Qdata: 307 case Qlisten: 308 case Qlocal: 309 case Qremote: 310 case Qstatus: 311 return ip3gen(c, TYPE(c->qid), dp); 312 } 313 return -1; 314 } 315 316 static void 317 newproto(char *name, int type, int maxconv) 318 { 319 Proto *p; 320 321 p = smalloc(sizeof(*p)); 322 p->name = name; 323 p->stype = type; 324 p->ipproto = type+1; /* temporary */ 325 p->nc = maxconv; 326 if(Fsproto(ipfs[0], p)) 327 panic("can't newproto %s", name); 328 } 329 330 void 331 ipinit(void) 332 { 333 ipfs[0] = malloc(sizeof(Fs)); 334 if(ipfs[0] == nil) 335 panic("no memory for IP stack"); 336 337 newproto("udp", S_UDP, 64); 338 newproto("tcp", S_TCP, 2048); 339 340 fmtinstall('i', eipfmt); 341 fmtinstall('I', eipfmt); 342 fmtinstall('E', eipfmt); 343 fmtinstall('V', eipfmt); 344 fmtinstall('M', eipfmt); 345 } 346 347 Chan * 348 ipattach(char *spec) 349 { 350 Chan *c; 351 352 if(atoi(spec) != 0) 353 error("bad specification"); 354 355 c = devattach('I', spec); 356 mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR); 357 c->dev = 0; 358 359 return c; 360 } 361 362 static Walkqid* 363 ipwalk(Chan* c, Chan *nc, char **name, int nname) 364 { 365 return devwalk(c, nc, name, nname, nil, 0, ipgen); 366 } 367 368 static int 369 ipstat(Chan *c, uchar *db, int n) 370 { 371 return devstat(c, db, n, 0, 0, ipgen); 372 } 373 374 static int m2p[] = { 375 4, 376 2, 377 6, 378 }; 379 380 static Chan * 381 ipopen(Chan *c, int omode) 382 { 383 Conv *cv, *nc; 384 Proto *p; 385 uchar raddr[IPaddrlen]; 386 ushort rport; 387 int perm, sfd; 388 Fs *f; 389 390 perm = m2p[omode&3]; 391 392 f = ipfs[c->dev]; 393 394 switch(TYPE(c->qid)) { 395 default: 396 break; 397 case Qtopdir: 398 case Qprotodir: 399 case Qconvdir: 400 case Qstatus: 401 case Qremote: 402 case Qlocal: 403 case Qstats: 404 /* case Qipselftab: */ 405 if(omode != OREAD) 406 error(Eperm); 407 break; 408 case Qndb: 409 if(omode & (OWRITE|OTRUNC) && !iseve()) 410 error(Eperm); 411 if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)){ 412 f->ndb[0] = 0; 413 f->ndbvers++; 414 } 415 break; 416 case Qclone: 417 p = f->p[PROTO(c->qid)]; 418 cv = protoclone(p, up->env->user, -1); 419 if(cv == 0) 420 error(Enodev); 421 mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE); 422 break; 423 case Qdata: 424 case Qctl: 425 p = f->p[PROTO(c->qid)]; 426 qlock(&p->l); 427 cv = p->conv[CONV(c->qid)]; 428 qlock(&cv->l); 429 if(waserror()){ 430 qunlock(&cv->l); 431 qunlock(&p->l); 432 nexterror(); 433 } 434 if((perm & (cv->perm>>6)) != perm) { 435 if(strcmp(up->env->user, cv->owner) != 0) 436 error(Eperm); 437 if((perm & cv->perm) != perm) 438 error(Eperm); 439 } 440 cv->inuse++; 441 if(cv->inuse == 1) { 442 kstrdup(&cv->owner, up->env->user); 443 cv->perm = 0660; 444 if(cv->sfd < 0) 445 cv->sfd = so_socket(p->stype); 446 } 447 poperror(); 448 qunlock(&cv->l); 449 qunlock(&p->l); 450 break; 451 case Qlisten: 452 p = f->p[PROTO(c->qid)]; 453 cv = p->conv[CONV(c->qid)]; 454 if((perm & (cv->perm>>6)) != perm){ 455 if(strcmp(up->env->user, cv->owner) != 0) 456 error(Eperm); 457 if((perm & cv->perm) != perm) 458 error(Eperm); 459 } 460 461 if(cv->state != Announced) 462 error("not announced"); 463 464 qlock(&cv->listenq); 465 if(waserror()){ 466 qunlock(&cv->listenq); 467 nexterror(); 468 } 469 470 sfd = so_accept(cv->sfd, raddr, &rport); 471 472 nc = protoclone(p, up->env->user, sfd); 473 if(nc == 0) { 474 so_close(sfd); 475 error(Enodev); 476 } 477 memmove(nc->raddr, raddr, IPaddrlen); 478 nc->rport = rport; 479 setladdr(nc); 480 nc->state = Connected; 481 mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE); 482 483 poperror(); 484 qunlock(&cv->listenq); 485 break; 486 } 487 c->mode = openmode(omode); 488 c->flag |= COPEN; 489 c->offset = 0; 490 return c; 491 } 492 493 static void 494 closeconv(Conv *cv) 495 { 496 int fd; 497 498 qlock(&cv->l); 499 500 if(--cv->inuse > 0) { 501 qunlock(&cv->l); 502 return; 503 } 504 505 if(waserror()){ 506 qunlock(&cv->l); 507 return; 508 } 509 kstrdup(&cv->owner, network); 510 cv->perm = 0660; 511 /* cv->p->close(cv); */ 512 cv->state = Idle; 513 cv->restricted = 0; 514 fd = cv->sfd; 515 cv->sfd = -1; 516 if(fd >= 0) 517 so_close(fd); 518 poperror(); 519 qunlock(&cv->l); 520 } 521 522 static void 523 ipclose(Chan *c) 524 { 525 Fs *f; 526 527 f = ipfs[c->dev]; 528 switch(TYPE(c->qid)) { 529 case Qdata: 530 case Qctl: 531 if(c->flag & COPEN) 532 closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]); 533 break; 534 } 535 } 536 537 static long 538 ipread(Chan *ch, void *a, long n, vlong off) 539 { 540 int r; 541 Conv *c; 542 Proto *x; 543 char *p, *s; 544 Fs *f; 545 ulong offset = off; 546 547 f = ipfs[ch->dev]; 548 549 p = a; 550 switch(TYPE(ch->qid)) { 551 default: 552 error(Eperm); 553 case Qprotodir: 554 case Qtopdir: 555 case Qconvdir: 556 return devdirread(ch, a, n, 0, 0, ipgen); 557 case Qarp: 558 error(Eperm); /* TO DO */ 559 case Qndb: 560 return readstr(off, a, n, f->ndb); 561 case Qctl: 562 sprint(up->genbuf, "%lud", CONV(ch->qid)); 563 return readstr(offset, p, n, up->genbuf); 564 case Qremote: 565 x = f->p[PROTO(ch->qid)]; 566 c = x->conv[CONV(ch->qid)]; 567 sprint(up->genbuf, "%I!%d\n", c->raddr, c->rport); 568 return readstr(offset, p, n, up->genbuf); 569 case Qlocal: 570 x = f->p[PROTO(ch->qid)]; 571 c = x->conv[CONV(ch->qid)]; 572 sprint(up->genbuf, "%I!%d\n", c->laddr, c->lport); 573 return readstr(offset, p, n, up->genbuf); 574 case Qstatus: 575 x = f->p[PROTO(ch->qid)]; 576 c = x->conv[CONV(ch->qid)]; 577 s = smalloc(Statelen); 578 if(waserror()){ 579 free(s); 580 nexterror(); 581 } 582 snprint(s, Statelen, "%s\n", ipstates[c->state]); 583 n = readstr(offset, p, n, s); 584 poperror(); 585 free(s); 586 return n; 587 case Qdata: 588 x = f->p[PROTO(ch->qid)]; 589 c = x->conv[CONV(ch->qid)]; 590 if(c->sfd < 0) 591 error(Ehungup); 592 if(c->headers) { 593 if(n < c->headers) 594 error(Ebadarg); 595 p = a; 596 r = so_recv(c->sfd, p + c->headers, n - c->headers, p, c->headers); 597 if(r > 0) 598 r += c->headers; 599 } else 600 r = so_recv(c->sfd, a, n, nil, 0); 601 if(r < 0) 602 oserror(); 603 return r; 604 case Qstats: 605 error("stats not implemented"); 606 return n; 607 } 608 } 609 610 static void 611 setladdr(Conv *c) 612 { 613 /* TO DO: this can't be right for hosts with several addresses before connect/accept */ 614 so_getsockname(c->sfd, c->laddr, &c->lport); 615 } 616 617 /* 618 * pick a local port and set it 619 */ 620 static void 621 setlport(Conv *c) 622 { 623 uchar laddr[IPaddrlen]; 624 ushort p; 625 626 so_bind(c->sfd, c->restricted, c->laddr, c->lport); 627 if(c->lport == 0 || ipcmp(c->laddr, IPnoaddr) == 0){ 628 so_getsockname(c->sfd, laddr, &p); 629 if(c->lport == 0) 630 c->lport = p; 631 if(ipcmp(c->laddr, IPnoaddr) == 0) 632 memmove(c->laddr, laddr, sizeof laddr); 633 } 634 } 635 636 static int 637 portno(char *p) 638 { 639 long n; 640 char *e; 641 642 n = strtoul(p, &e, 0); 643 if(p == e) 644 error("non-numeric port number"); 645 return n; 646 } 647 648 /* 649 * set a local address and port from a string of the form 650 * [address!]port[!r] 651 */ 652 static void 653 setladdrport(Conv *c, char *str, int announcing) 654 { 655 char *p; 656 int lport; 657 658 /* 659 * ignore restricted part if it exists. it's 660 * meaningless on local ports. 661 */ 662 p = strchr(str, '!'); 663 if(p != nil){ 664 *p++ = 0; 665 if(strcmp(p, "r") == 0) 666 p = nil; 667 } 668 669 c->lport = 0; 670 if(p == nil){ 671 if(announcing) 672 ipmove(c->laddr, IPnoaddr); 673 else if(0) 674 setladdr(c); 675 p = str; 676 } else { 677 if(strcmp(str, "*") == 0) 678 ipmove(c->laddr, IPnoaddr); 679 else if(parseip(c->laddr, str) == 0) 680 error("invalid IP address"); 681 } 682 683 if(announcing && strcmp(p, "*") == 0){ 684 if(!iseve()) 685 error(Eperm); 686 c->lport = 0; 687 setlport(c); 688 return; 689 } 690 691 lport = portno(p); 692 if(lport <= 0) 693 c->lport = 0; 694 else 695 c->lport = lport; 696 697 setlport(c); 698 } 699 700 static char* 701 setraddrport(Conv *c, char *str) 702 { 703 char *p; 704 705 p = strchr(str, '!'); 706 if(p == nil) 707 return "malformed address"; 708 *p++ = 0; 709 if(parseip(c->raddr, str) == 0) 710 return "invalid IP address"; 711 c->rport = portno(p); 712 p = strchr(p, '!'); 713 if(p){ 714 if(strstr(p, "!r") != nil) 715 c->restricted = 1; 716 } 717 return nil; 718 } 719 720 static void 721 connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb) 722 { 723 char *p; 724 725 USED(x); 726 if(c->state != Idle) 727 error(Econinuse); 728 c->state = Connecting; 729 c->cerr[0] = '\0'; 730 switch(cb->nf) { 731 default: 732 error("bad args to connect"); 733 case 2: 734 p = setraddrport(c, cb->f[1]); 735 if(p != nil) 736 error(p); 737 break; 738 case 3: 739 p = setraddrport(c, cb->f[1]); 740 if(p != nil) 741 error(p); 742 c->lport = portno(cb->f[2]); 743 setlport(c); 744 break; 745 } 746 qunlock(&c->l); 747 if(waserror()){ 748 qlock(&c->l); 749 c->state = Connected; /* sic */ 750 nexterror(); 751 } 752 /* p = x->connect(c, cb->f, cb->nf); */ 753 so_connect(c->sfd, c->raddr, c->rport); 754 qlock(&c->l); 755 poperror(); 756 setladdr(c); 757 c->state = Connected; 758 } 759 760 static void 761 announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb) 762 { 763 if(c->state != Idle) 764 error(Econinuse); 765 c->state = Announcing; 766 c->cerr[0] = '\0'; 767 ipmove(c->raddr, IPnoaddr); 768 c->rport = 0; 769 switch(cb->nf){ 770 default: 771 error("bad args to announce"); 772 case 2: 773 setladdrport(c, cb->f[1], 1); 774 break; 775 } 776 USED(x); 777 /* p = x->announce(c, cb->f, cb->nf); */ 778 if(c->p->stype != S_UDP){ 779 qunlock(&c->l); 780 if(waserror()){ 781 c->state = Announced; /* sic */ 782 qlock(&c->l); 783 nexterror(); 784 } 785 so_listen(c->sfd); 786 qlock(&c->l); 787 poperror(); 788 } 789 c->state = Announced; 790 } 791 792 static void 793 bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb) 794 { 795 USED(x); 796 switch(cb->nf){ 797 default: 798 error("bad args to bind"); 799 case 2: 800 setladdrport(c, cb->f[1], 0); 801 break; 802 } 803 } 804 805 static long 806 ipwrite(Chan *ch, void *a, long n, vlong off) 807 { 808 Conv *c; 809 Proto *x; 810 char *p; 811 Cmdbuf *cb; 812 Fs *f; 813 814 f = ipfs[ch->dev]; 815 816 switch(TYPE(ch->qid)) { 817 default: 818 error(Eperm); 819 case Qdata: 820 x = f->p[PROTO(ch->qid)]; 821 c = x->conv[CONV(ch->qid)]; 822 if(c->sfd < 0) 823 error(Ehungup); 824 qlock(&c->wlock); 825 if(waserror()){ 826 qunlock(&c->wlock); 827 nexterror(); 828 } 829 if(c->headers) { 830 if(n < c->headers) 831 error(Eshort); 832 p = a; 833 n = so_send(c->sfd, p + c->headers, n - c->headers, p, c->headers); 834 if(n >= 0) 835 n += c->headers; 836 } else 837 n = so_send(c->sfd, a, n, nil, 0); 838 poperror(); 839 qunlock(&c->wlock); 840 if(n < 0) 841 oserror(); 842 break; 843 case Qarp: 844 return arpwrite(a, n); 845 case Qndb: 846 if(off > strlen(f->ndb)) 847 error(Eio); 848 if(off+n >= sizeof(f->ndb)-1) 849 error(Eio); 850 memmove(f->ndb+off, a, n); 851 f->ndb[off+n] = 0; 852 f->ndbvers++; 853 f->ndbmtime = seconds(); 854 break; 855 case Qctl: 856 x = f->p[PROTO(ch->qid)]; 857 c = x->conv[CONV(ch->qid)]; 858 cb = parsecmd(a, n); 859 qlock(&c->l); 860 if(waserror()){ 861 qunlock(&c->l); 862 free(cb); 863 nexterror(); 864 } 865 if(cb->nf < 1) 866 error("short control request"); 867 if(strcmp(cb->f[0], "connect") == 0) 868 connectctlmsg(x, c, cb); 869 else if(strcmp(cb->f[0], "announce") == 0) 870 announcectlmsg(x, c, cb); 871 else if(strcmp(cb->f[0], "bind") == 0) 872 bindctlmsg(x, c, cb); 873 else if(strcmp(cb->f[0], "ttl") == 0){ 874 /* ignored */ 875 } else if(strcmp(cb->f[0], "tos") == 0){ 876 /* ignored */ 877 } else if(strcmp(cb->f[0], "ignoreadvice") == 0){ 878 /* ignored */ 879 } else if(strcmp(cb->f[0], "headers4") == 0){ 880 if(c->p->stype != S_UDP) 881 error(Enoctl); 882 c->headers = OUdphdrlenv4; 883 } else if(strcmp(cb->f[0], "oldheaders") == 0){ 884 if(c->p->stype != S_UDP) 885 error(Enoctl); 886 c->headers = OUdphdrlen; 887 } else if(strcmp(cb->f[0], "headers") == 0){ 888 if(c->p->stype != S_UDP) 889 error(Enoctl); 890 c->headers = Udphdrlen; 891 } else if(strcmp(cb->f[0], "hangup") == 0){ 892 if(c->p->stype != S_TCP) 893 error(Enoctl); 894 qunlock(&c->l); 895 if(waserror()){ 896 qlock(&c->l); 897 nexterror(); 898 } 899 /* TO DO: check fd status if socket close/hangup interrupted */ 900 if(c->sfd >= 0 && so_hangup(c->sfd, 1) < 0) 901 oserror(); 902 qlock(&c->l); 903 poperror(); 904 c->sfd = -1; 905 c->state = Hungup; 906 } else if(strcmp(cb->f[0], "keepalive") == 0){ 907 if(c->p->stype != S_TCP) 908 error(Enoctl); 909 if(c->sfd < 0) 910 error("not connected"); 911 so_keepalive(c->sfd, cb->nf>1? atoi(cb->f[1]): 0); 912 } else 913 error(Enoctl); 914 poperror(); 915 qunlock(&c->l); 916 free(cb); 917 break; 918 } 919 return n; 920 } 921 922 static int 923 ipwstat(Chan *c, uchar *dp, int n) 924 { 925 Dir *d; 926 Conv *cv; 927 Proto *p; 928 Fs *f; 929 930 f = ipfs[c->dev]; 931 switch(TYPE(c->qid)) { 932 default: 933 error(Eperm); 934 break; 935 case Qctl: 936 case Qdata: 937 break; 938 } 939 940 d = smalloc(sizeof(*d)+n); 941 if(waserror()){ 942 free(d); 943 nexterror(); 944 } 945 n = convM2D(dp, n, d, (char*)&d[1]); 946 if(n == 0) 947 error(Eshortstat); 948 p = f->p[PROTO(c->qid)]; 949 cv = p->conv[CONV(c->qid)]; 950 if(!iseve() && strcmp(up->env->user, cv->owner) != 0) 951 error(Eperm); 952 if(!emptystr(d->uid)) 953 kstrdup(&cv->owner, d->uid); 954 if(d->mode != ~0UL) 955 cv->perm = d->mode & 0777; 956 poperror(); 957 free(d); 958 return n; 959 } 960 961 static Conv* 962 protoclone(Proto *p, char *user, int nfd) 963 { 964 Conv *c, **pp, **ep, **np; 965 int maxconv; 966 967 c = 0; 968 qlock(&p->l); 969 if(waserror()) { 970 qunlock(&p->l); 971 nexterror(); 972 } 973 ep = &p->conv[p->nc]; 974 for(pp = p->conv; pp < ep; pp++) { 975 c = *pp; 976 if(c == 0) { 977 c = newconv(p, pp); 978 break; 979 } 980 if(canqlock(&c->l)){ 981 if(c->inuse == 0) 982 break; 983 qunlock(&c->l); 984 } 985 } 986 if(pp >= ep) { 987 if(p->nc >= MAXCONV) { 988 qunlock(&p->l); 989 poperror(); 990 return 0; 991 } 992 maxconv = 2 * p->nc; 993 if(maxconv > MAXCONV) 994 maxconv = MAXCONV; 995 np = realloc(p->conv, sizeof(Conv*) * maxconv); 996 if(np == nil) 997 error(Enomem); 998 p->conv = np; 999 pp = &p->conv[p->nc]; 1000 memset(pp, 0, sizeof(Conv*)*(maxconv - p->nc)); 1001 p->nc = maxconv; 1002 c = newconv(p, pp); 1003 } 1004 1005 c->inuse = 1; 1006 kstrdup(&c->owner, user); 1007 c->perm = 0660; 1008 c->state = Idle; 1009 ipmove(c->laddr, IPnoaddr); 1010 ipmove(c->raddr, IPnoaddr); 1011 c->lport = 0; 1012 c->rport = 0; 1013 c->restricted = 0; 1014 c->headers = 0; 1015 c->sfd = nfd; 1016 if(nfd == -1) 1017 c->sfd = so_socket(p->stype); 1018 1019 qunlock(&c->l); 1020 qunlock(&p->l); 1021 poperror(); 1022 return c; 1023 } 1024 1025 static Conv* 1026 newconv(Proto *p, Conv **pp) 1027 { 1028 Conv *c; 1029 1030 *pp = c = malloc(sizeof(Conv)); 1031 if(c == 0) 1032 error(Enomem); 1033 qlock(&c->l); 1034 c->inuse = 1; 1035 c->p = p; 1036 c->x = pp - p->conv; 1037 p->ac++; 1038 return c; 1039 } 1040 1041 int 1042 arpwrite(char *s, int len) 1043 { 1044 int n; 1045 char *f[4], buf[256]; 1046 1047 if(len >= sizeof(buf)) 1048 len = sizeof(buf)-1; 1049 memmove(buf, s, len); 1050 buf[len] = 0; 1051 if(len > 0 && buf[len-1] == '\n') 1052 buf[len-1] = 0; 1053 1054 n = getfields(buf, f, 4, 1, " "); 1055 if(strcmp(f[0], "add") == 0) { 1056 if(n == 3) { 1057 arpadd(f[1], f[2], n); 1058 return len; 1059 } 1060 } 1061 error("bad arp request"); 1062 1063 return len; 1064 } 1065 1066 Dev ipdevtab = { 1067 'I', 1068 "ip", 1069 1070 ipinit, 1071 ipattach, 1072 ipwalk, 1073 ipstat, 1074 ipopen, 1075 devcreate, 1076 ipclose, 1077 ipread, 1078 devbread, 1079 ipwrite, 1080 devbwrite, 1081 devremove, 1082 ipwstat 1083 }; 1084 1085 int 1086 Fsproto(Fs *f, Proto *p) 1087 { 1088 if(f->np >= Maxproto) 1089 return -1; 1090 1091 p->f = f; 1092 1093 if(p->ipproto > 0){ 1094 if(f->t2p[p->ipproto] != nil) 1095 return -1; 1096 f->t2p[p->ipproto] = p; 1097 } 1098 1099 p->qid.type = QTDIR; 1100 p->qid.path = QID(f->np, 0, Qprotodir); 1101 p->conv = malloc(sizeof(Conv*)*(p->nc+1)); 1102 if(p->conv == nil) 1103 panic("Fsproto"); 1104 1105 p->x = f->np; 1106 f->p[f->np++] = p; 1107 1108 return 0; 1109 } 1110 1111 /* 1112 * return true if this protocol is 1113 * built in 1114 */ 1115 int 1116 Fsbuiltinproto(Fs* f, uchar proto) 1117 { 1118 return f->t2p[proto] != nil; 1119 } 1120