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