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 */ 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 630 so_bind(c->sfd, c->restricted, c->lport); 631 if(c->lport == 0) 632 so_getsockname(c->sfd, &laddr, &c->lport); 633 } 634 635 static int 636 portno(char *p) 637 { 638 long n; 639 char *e; 640 641 n = strtoul(p, &e, 0); 642 if(p == e) 643 error("non-numeric port number"); 644 return n; 645 } 646 647 /* 648 * set a local address and port from a string of the form 649 * [address!]port[!r] 650 */ 651 static void 652 setladdrport(Conv *c, char *str, int announcing) 653 { 654 char *p; 655 int lport; 656 657 /* 658 * ignore restricted part if it exists. it's 659 * meaningless on local ports. 660 */ 661 p = strchr(str, '!'); 662 if(p != nil){ 663 *p++ = 0; 664 if(strcmp(p, "r") == 0) 665 p = nil; 666 } 667 668 c->lport = 0; 669 if(p == nil){ 670 if(announcing) 671 ipmove(c->laddr, IPnoaddr); 672 else if(0) 673 setladdr(c); 674 p = str; 675 } else { 676 if(strcmp(str, "*") == 0) 677 ipmove(c->laddr, IPnoaddr); 678 else 679 parseip(c->laddr, str); 680 } 681 682 if(announcing && strcmp(p, "*") == 0){ 683 if(!iseve()) 684 error(Eperm); 685 c->lport = 0; 686 setlport(c); 687 return; 688 } 689 690 lport = portno(p); 691 if(lport <= 0) 692 c->lport = 0; 693 else 694 c->lport = lport; 695 696 setlport(c); 697 } 698 699 static char* 700 setraddrport(Conv *c, char *str) 701 { 702 char *p; 703 704 p = strchr(str, '!'); 705 if(p == nil) 706 return "malformed address"; 707 *p++ = 0; 708 parseip(c->raddr, str); 709 c->rport = portno(p); 710 p = strchr(p, '!'); 711 if(p){ 712 if(strstr(p, "!r") != nil) 713 c->restricted = 1; 714 } 715 return nil; 716 } 717 718 static void 719 connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb) 720 { 721 char *p; 722 723 USED(x); 724 if(c->state != Idle) 725 error(Econinuse); 726 c->state = Connecting; 727 c->cerr[0] = '\0'; 728 switch(cb->nf) { 729 default: 730 error("bad args to connect"); 731 case 2: 732 p = setraddrport(c, cb->f[1]); 733 if(p != nil) 734 error(p); 735 break; 736 case 3: 737 p = setraddrport(c, cb->f[1]); 738 if(p != nil) 739 error(p); 740 c->lport = portno(cb->f[2]); 741 setlport(c); 742 break; 743 } 744 qunlock(&c->l); 745 if(waserror()){ 746 qlock(&c->l); 747 c->state = Connected; /* sic */ 748 nexterror(); 749 } 750 /* p = x->connect(c, cb->f, cb->nf); */ 751 so_connect(c->sfd, ip6w(c->raddr), c->rport); 752 qlock(&c->l); 753 poperror(); 754 setladdr(c); 755 c->state = Connected; 756 } 757 758 static void 759 announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb) 760 { 761 if(c->state != Idle) 762 error(Econinuse); 763 c->state = Announcing; 764 c->cerr[0] = '\0'; 765 ipmove(c->raddr, IPnoaddr); 766 c->rport = 0; 767 switch(cb->nf){ 768 default: 769 error("bad args to announce"); 770 case 2: 771 setladdrport(c, cb->f[1], 1); 772 break; 773 } 774 USED(x); 775 /* p = x->announce(c, cb->f, cb->nf); */ 776 if(c->p->stype != S_UDP){ 777 qunlock(&c->l); 778 if(waserror()){ 779 c->state = Announced; /* sic */ 780 qlock(&c->l); 781 nexterror(); 782 } 783 so_listen(c->sfd); 784 qlock(&c->l); 785 poperror(); 786 } 787 c->state = Announced; 788 } 789 790 static void 791 bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb) 792 { 793 USED(x); 794 switch(cb->nf){ 795 default: 796 error("bad args to bind"); 797 case 2: 798 setladdrport(c, cb->f[1], 0); 799 break; 800 } 801 } 802 803 static long 804 ipwrite(Chan *ch, void *a, long n, vlong off) 805 { 806 Conv *c; 807 Proto *x; 808 char *p; 809 Cmdbuf *cb; 810 Fs *f; 811 812 f = ipfs[ch->dev]; 813 814 switch(TYPE(ch->qid)) { 815 default: 816 error(Eperm); 817 case Qdata: 818 x = f->p[PROTO(ch->qid)]; 819 c = x->conv[CONV(ch->qid)]; 820 if(c->sfd < 0) 821 error(Ehungup); 822 qlock(&c->wlock); 823 if(waserror()){ 824 qunlock(&c->wlock); 825 nexterror(); 826 } 827 if(c->headers) { 828 if(n < c->headers) 829 error(Eshort); 830 p = a; 831 n = so_send(c->sfd, p + c->headers, n - c->headers, p, c->headers); 832 if(n >= 0) 833 n += c->headers; 834 } else 835 n = so_send(c->sfd, a, n, nil, 0); 836 poperror(); 837 qunlock(&c->wlock); 838 if(n < 0) 839 oserror(); 840 break; 841 case Qarp: 842 return arpwrite(a, n); 843 case Qndb: 844 if(off > strlen(f->ndb)) 845 error(Eio); 846 if(off+n >= sizeof(f->ndb)-1) 847 error(Eio); 848 memmove(f->ndb+off, a, n); 849 f->ndb[off+n] = 0; 850 f->ndbvers++; 851 f->ndbmtime = seconds(); 852 break; 853 case Qctl: 854 x = f->p[PROTO(ch->qid)]; 855 c = x->conv[CONV(ch->qid)]; 856 cb = parsecmd(a, n); 857 qlock(&c->l); 858 if(waserror()){ 859 qunlock(&c->l); 860 free(cb); 861 nexterror(); 862 } 863 if(cb->nf < 1) 864 error("short control request"); 865 if(strcmp(cb->f[0], "connect") == 0) 866 connectctlmsg(x, c, cb); 867 else if(strcmp(cb->f[0], "announce") == 0) 868 announcectlmsg(x, c, cb); 869 else if(strcmp(cb->f[0], "bind") == 0) 870 bindctlmsg(x, c, cb); 871 else if(strcmp(cb->f[0], "ttl") == 0){ 872 /* ignored */ 873 } else if(strcmp(cb->f[0], "tos") == 0){ 874 /* ignored */ 875 } else if(strcmp(cb->f[0], "ignoreadvice") == 0){ 876 /* ignored */ 877 } else if(strcmp(cb->f[0], "headers4") == 0){ 878 if(c->p->stype != S_UDP) 879 error(Enoctl); 880 c->headers = OUdphdrlenv4; 881 } else if(strcmp(cb->f[0], "oldheaders") == 0){ 882 if(c->p->stype != S_UDP) 883 error(Enoctl); 884 c->headers = OUdphdrlen; 885 } else if(strcmp(cb->f[0], "headers") == 0){ 886 if(c->p->stype != S_UDP) 887 error(Enoctl); 888 c->headers = Udphdrlen; 889 } else if(strcmp(cb->f[0], "hangup") == 0){ 890 if(c->p->stype != S_TCP) 891 error(Enoctl); 892 qunlock(&c->l); 893 if(waserror()){ 894 qlock(&c->l); 895 nexterror(); 896 } 897 /* TO DO: check fd status if socket close/hangup interrupted */ 898 if(c->sfd >= 0 && so_hangup(c->sfd, 1) < 0) 899 oserror(); 900 qlock(&c->l); 901 poperror(); 902 c->sfd = -1; 903 c->state = Hungup; 904 } else if(strcmp(cb->f[0], "keepalive") == 0){ 905 if(c->p->stype != S_TCP) 906 error(Enoctl); 907 if(c->sfd < 0) 908 error("not connected"); 909 so_keepalive(c->sfd, cb->nf>1? atoi(cb->f[1]): 0); 910 } else 911 error(Enoctl); 912 poperror(); 913 qunlock(&c->l); 914 free(cb); 915 break; 916 } 917 return n; 918 } 919 920 static int 921 ipwstat(Chan *c, uchar *dp, int n) 922 { 923 Dir *d; 924 Conv *cv; 925 Proto *p; 926 Fs *f; 927 928 f = ipfs[c->dev]; 929 switch(TYPE(c->qid)) { 930 default: 931 error(Eperm); 932 break; 933 case Qctl: 934 case Qdata: 935 break; 936 } 937 938 d = smalloc(sizeof(*d)+n); 939 if(waserror()){ 940 free(d); 941 nexterror(); 942 } 943 n = convM2D(dp, n, d, (char*)&d[1]); 944 if(n == 0) 945 error(Eshortstat); 946 p = f->p[PROTO(c->qid)]; 947 cv = p->conv[CONV(c->qid)]; 948 if(!iseve() && strcmp(up->env->user, cv->owner) != 0) 949 error(Eperm); 950 if(!emptystr(d->uid)) 951 kstrdup(&cv->owner, d->uid); 952 if(d->mode != ~0UL) 953 cv->perm = d->mode & 0777; 954 poperror(); 955 free(d); 956 return n; 957 } 958 959 static Conv* 960 protoclone(Proto *p, char *user, int nfd) 961 { 962 Conv *c, **pp, **ep, **np; 963 int maxconv; 964 965 c = 0; 966 qlock(&p->l); 967 if(waserror()) { 968 qunlock(&p->l); 969 nexterror(); 970 } 971 ep = &p->conv[p->nc]; 972 for(pp = p->conv; pp < ep; pp++) { 973 c = *pp; 974 if(c == 0) { 975 c = newconv(p, pp); 976 break; 977 } 978 if(canqlock(&c->l)){ 979 if(c->inuse == 0) 980 break; 981 qunlock(&c->l); 982 } 983 } 984 if(pp >= ep) { 985 if(p->nc >= MAXCONV) { 986 qunlock(&p->l); 987 poperror(); 988 return 0; 989 } 990 maxconv = 2 * p->nc; 991 if(maxconv > MAXCONV) 992 maxconv = MAXCONV; 993 np = realloc(p->conv, sizeof(Conv*) * maxconv); 994 if(np == nil) 995 error(Enomem); 996 p->conv = np; 997 pp = &p->conv[p->nc]; 998 memset(pp, 0, sizeof(Conv*)*(maxconv - p->nc)); 999 p->nc = maxconv; 1000 c = newconv(p, pp); 1001 } 1002 1003 c->inuse = 1; 1004 kstrdup(&c->owner, user); 1005 c->perm = 0660; 1006 c->state = Idle; 1007 ipmove(c->laddr, IPnoaddr); 1008 ipmove(c->raddr, IPnoaddr); 1009 c->lport = 0; 1010 c->rport = 0; 1011 c->restricted = 0; 1012 c->sfd = nfd; 1013 if(nfd == -1) 1014 c->sfd = so_socket(p->stype); 1015 1016 qunlock(&c->l); 1017 qunlock(&p->l); 1018 poperror(); 1019 return c; 1020 } 1021 1022 static Conv* 1023 newconv(Proto *p, Conv **pp) 1024 { 1025 Conv *c; 1026 1027 *pp = c = malloc(sizeof(Conv)); 1028 if(c == 0) 1029 error(Enomem); 1030 qlock(&c->l); 1031 c->inuse = 1; 1032 c->p = p; 1033 c->x = pp - p->conv; 1034 p->ac++; 1035 return c; 1036 } 1037 1038 int 1039 arpwrite(char *s, int len) 1040 { 1041 int n; 1042 char *f[4], buf[256]; 1043 1044 if(len >= sizeof(buf)) 1045 len = sizeof(buf)-1; 1046 memmove(buf, s, len); 1047 buf[len] = 0; 1048 if(len > 0 && buf[len-1] == '\n') 1049 buf[len-1] = 0; 1050 1051 n = getfields(buf, f, 4, 1, " "); 1052 if(strcmp(f[0], "add") == 0) { 1053 if(n == 3) { 1054 arpadd(f[1], f[2], n); 1055 return len; 1056 } 1057 } 1058 error("bad arp request"); 1059 1060 return len; 1061 } 1062 1063 Dev ipdevtab = { 1064 'I', 1065 "ip", 1066 1067 ipinit, 1068 ipattach, 1069 ipwalk, 1070 ipstat, 1071 ipopen, 1072 devcreate, 1073 ipclose, 1074 ipread, 1075 devbread, 1076 ipwrite, 1077 devbwrite, 1078 devremove, 1079 ipwstat 1080 }; 1081 1082 int 1083 Fsproto(Fs *f, Proto *p) 1084 { 1085 if(f->np >= Maxproto) 1086 return -1; 1087 1088 p->f = f; 1089 1090 if(p->ipproto > 0){ 1091 if(f->t2p[p->ipproto] != nil) 1092 return -1; 1093 f->t2p[p->ipproto] = p; 1094 } 1095 1096 p->qid.type = QTDIR; 1097 p->qid.path = QID(f->np, 0, Qprotodir); 1098 p->conv = malloc(sizeof(Conv*)*(p->nc+1)); 1099 if(p->conv == nil) 1100 panic("Fsproto"); 1101 1102 p->x = f->np; 1103 f->p[f->np++] = p; 1104 1105 return 0; 1106 } 1107 1108 /* 1109 * return true if this protocol is 1110 * built in 1111 */ 1112 int 1113 Fsbuiltinproto(Fs* f, uchar proto) 1114 { 1115 return f->t2p[proto] != nil; 1116 } 1117 1118 /* 1119 * temporarily convert ipv6 addresses to ipv4 as ulong for 1120 * ipif.c interface 1121 */ 1122 static ulong 1123 ip6w(uchar *a) 1124 { 1125 uchar v4[IPv4addrlen]; 1126 1127 v6tov4(v4, a); 1128 return (((((v4[0]<<8)|v4[1])<<8)|v4[2])<<8)|v4[3]; 1129 } 1130 1131 static void 1132 ipw6(uchar *a, ulong w) 1133 { 1134 memmove(a, v4prefix, IPv4off); 1135 hnputl(a+IPv4off, w); 1136 } 1137