|
|
1.1 ! root 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 "arp.h" ! 8: #include "../port/ipdat.h" ! 9: ! 10: #include "devtab.h" ! 11: ! 12: enum ! 13: { ! 14: Nrprotocol = 4, /* Number of protocols supported by this driver */ ! 15: Nipsubdir = 4, /* Number of subdirectory entries per connection */ ! 16: Nfrag = 32, /* Ip reassembly queue entries */ ! 17: Nifc = 4, /* max interfaces */ ! 18: }; ! 19: ! 20: int udpsum = 1; ! 21: Ipifc *ipifc[Nrprotocol+1]; ! 22: QLock ipalloc; /* Protocol port allocation lock */ ! 23: Ipconv **tcpbase; ! 24: ! 25: Streamput udpstiput, udpstoput, tcpstiput, tcpstoput; ! 26: Streamput iliput, iloput, bsdiput, bsdoput; ! 27: Streamopen udpstopen, tcpstopen, ilopen, bsdopen; ! 28: Streamclose udpstclose, tcpstclose, ilclose, bsdclose; ! 29: ! 30: Qinfo tcpinfo = { tcpstiput, tcpstoput, tcpstopen, tcpstclose, "tcp", 0, 1 }; ! 31: Qinfo udpinfo = { udpstiput, udpstoput, udpstopen, udpstclose, "udp" }; ! 32: Qinfo ilinfo = { iliput, iloput, ilopen, ilclose, "il" }; ! 33: Qinfo bsdinfo = { bsdiput, bsdoput, bsdopen, bsdclose, "bsd", 0, 1 }; ! 34: ! 35: Qinfo *protocols[] = { &tcpinfo, &udpinfo, &ilinfo, 0 }; ! 36: ! 37: void ! 38: ipinitifc(Ipifc *ifc, Qinfo *stproto) ! 39: { ! 40: ifc->conv = xalloc(Nipconv * sizeof(Ipconv*)); ! 41: ifc->protop = stproto; ! 42: ifc->nconv = Nipconv; ! 43: ifc->devp = &ipconvinfo; ! 44: if(stproto != &udpinfo) ! 45: ifc->listen = iplisten; ! 46: ifc->clone = ipclonecon; ! 47: ifc->ninfo = 3; ! 48: ifc->info[0].name = "remote"; ! 49: ifc->info[0].fill = ipremotefill; ! 50: ifc->info[1].name = "local"; ! 51: ifc->info[1].fill = iplocalfill; ! 52: ifc->info[2].name = "status"; ! 53: ifc->info[2].fill = ipstatusfill; ! 54: ifc->name = stproto->name; ! 55: } ! 56: ! 57: void ! 58: ipreset(void) ! 59: { ! 60: int i; ! 61: ! 62: for(i = 0; protocols[i]; i++) { ! 63: ipifc[i] = xalloc(sizeof(Ipifc)); ! 64: ipinitifc(ipifc[i], protocols[i]); ! 65: newqinfo(protocols[i]); ! 66: } ! 67: ! 68: initfrag(Nfrag); ! 69: } ! 70: ! 71: void ! 72: ipinit(void) ! 73: { ! 74: } ! 75: ! 76: Chan * ! 77: ipattach(char *spec) ! 78: { ! 79: int i; ! 80: Chan *c; ! 81: ! 82: if(ipd[0].q == 0) ! 83: error("no ip multiplexor"); ! 84: ! 85: for(i = 0; protocols[i]; i++) { ! 86: if(strcmp(spec, protocols[i]->name) == 0) { ! 87: c = devattach('I', spec); ! 88: c->dev = i; ! 89: ! 90: return (c); ! 91: } ! 92: } ! 93: ! 94: error(Enoproto); ! 95: return 0; /* not reached */ ! 96: } ! 97: ! 98: Chan * ! 99: ipclone(Chan *c, Chan *nc) ! 100: { ! 101: return devclone(c, nc); ! 102: } ! 103: ! 104: int ! 105: ipwalk(Chan *c, char *name) ! 106: { ! 107: return netwalk(c, name, ipifc[c->dev]); ! 108: } ! 109: ! 110: void ! 111: ipstat(Chan *c, char *db) ! 112: { ! 113: netstat(c, db, ipifc[c->dev]); ! 114: } ! 115: ! 116: Chan * ! 117: ipopen(Chan *c, int omode) ! 118: { ! 119: return netopen(c, omode, ipifc[c->dev]); ! 120: } ! 121: ! 122: int ! 123: ipclonecon(Chan *c) ! 124: { ! 125: Ipconv *new; ! 126: ! 127: new = ipincoming(ipifc[c->dev], 0); ! 128: if(new == 0) ! 129: error(Enodev); ! 130: return new->id; ! 131: } ! 132: ! 133: /* ! 134: * create a new conversation structure if none exists for this conversation slot ! 135: */ ! 136: Ipconv* ! 137: ipcreateconv(Ipifc *ifc, int id) ! 138: { ! 139: Ipconv **p; ! 140: Ipconv *new; ! 141: ! 142: p = &ifc->conv[id]; ! 143: if(*p) ! 144: return *p; ! 145: qlock(ifc); ! 146: p = &ifc->conv[id]; ! 147: if(*p){ ! 148: qunlock(ifc); ! 149: return *p; ! 150: } ! 151: if(waserror()){ ! 152: qunlock(ifc); ! 153: nexterror(); ! 154: } ! 155: new = smalloc(sizeof(Ipconv)); ! 156: new->ifc = ifc; ! 157: netadd(ifc, new, p - ifc->conv); ! 158: new->ref = 1; ! 159: *p = new; ! 160: qunlock(ifc); ! 161: poperror(); ! 162: return new; ! 163: } ! 164: ! 165: /* ! 166: * allocate a conversation structure. ! 167: */ ! 168: Ipconv* ! 169: ipincoming(Ipifc *ifc, Ipconv *from) ! 170: { ! 171: Ipconv *new; ! 172: Ipconv **p, **etab; ! 173: ! 174: /* look for an unused existing conversation */ ! 175: etab = &ifc->conv[Nipconv]; ! 176: for(p = ifc->conv; p < etab; p++) { ! 177: new = *p; ! 178: if(new == 0) ! 179: break; ! 180: if(new->ref == 0 && canqlock(new)) { ! 181: if(new->ref || ipconbusy(new)) { ! 182: qunlock(new); ! 183: continue; ! 184: } ! 185: if(from) /* copy ownership from listening channel */ ! 186: netown(new, from->owner, 0); ! 187: else /* current user becomes owner */ ! 188: netown(new, u->p->user, 0); ! 189: ! 190: new->ref = 1; ! 191: qunlock(new); ! 192: return new; ! 193: } ! 194: } ! 195: ! 196: /* create one */ ! 197: qlock(ifc); ! 198: etab = &ifc->conv[Nipconv]; ! 199: for(p = ifc->conv; ; p++){ ! 200: if(p == etab){ ! 201: qunlock(ifc); ! 202: return 0; ! 203: } ! 204: if(*p == 0) ! 205: break; ! 206: } ! 207: if(waserror()){ ! 208: qunlock(ifc); ! 209: nexterror(); ! 210: } ! 211: new = smalloc(sizeof(Ipconv)); ! 212: new->ifc = ifc; ! 213: netadd(ifc, new, p - ifc->conv); ! 214: qlock(new); ! 215: *p = new; ! 216: qunlock(ifc); ! 217: poperror(); ! 218: if(from) /* copy ownership from listening channel */ ! 219: netown(new, from->owner, 0); ! 220: else /* current user becomes owner */ ! 221: netown(new, u->p->user, 0); ! 222: new->ref = 1; ! 223: qunlock(new); ! 224: return new; ! 225: } ! 226: ! 227: void ! 228: ipcreate(Chan *c, char *name, int omode, ulong perm) ! 229: { ! 230: USED(c, name, omode, perm); ! 231: error(Eperm); ! 232: } ! 233: ! 234: void ! 235: ipremove(Chan *c) ! 236: { ! 237: USED(c); ! 238: error(Eperm); ! 239: } ! 240: ! 241: void ! 242: ipwstat(Chan *c, char *dp) ! 243: { ! 244: netwstat(c, dp, ipifc[c->dev]); ! 245: } ! 246: ! 247: void ! 248: ipclose(Chan *c) ! 249: { ! 250: if(c->stream) ! 251: streamclose(c); ! 252: } ! 253: ! 254: long ! 255: ipread(Chan *c, void *a, long n, ulong offset) ! 256: { ! 257: return netread(c, a, n, offset, ipifc[c->dev]); ! 258: } ! 259: ! 260: long ! 261: ipwrite(Chan *c, char *a, long n, ulong offset) ! 262: { ! 263: int m, backlog, type, priv; ! 264: char *field[5], *ctlarg[5], buf[256]; ! 265: Port port; ! 266: Ipconv *cp; ! 267: uchar dst[4]; ! 268: ! 269: USED(offset); ! 270: type = STREAMTYPE(c->qid.path); ! 271: if (type == Sdataqid) ! 272: return streamwrite(c, a, n, 0); ! 273: ! 274: if (type != Sctlqid) ! 275: error(Eperm); ! 276: ! 277: cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); ! 278: ! 279: m = n; ! 280: if(m > sizeof(buf)-1) ! 281: m = sizeof(buf)-1; ! 282: strncpy(buf, a, m); ! 283: buf[m] = '\0'; ! 284: ! 285: m = getfields(buf, field, 5, " "); ! 286: if(m < 1) ! 287: error(Ebadarg); ! 288: ! 289: if(strncmp(field[0], "connect", 7) == 0) { ! 290: if(ipconbusy(cp)) ! 291: error(Enetbusy); ! 292: ! 293: if(m < 2) ! 294: error(Ebadarg); ! 295: ! 296: switch(getfields(field[1], ctlarg, 5, "!")) { ! 297: default: ! 298: error(Eneedservice); ! 299: case 2: ! 300: priv = 0; ! 301: break; ! 302: case 3: ! 303: if(strcmp(ctlarg[2], "r") != 0) ! 304: error(Eperm); ! 305: priv = 1; ! 306: break; ! 307: } ! 308: cp->dst = ipparse(ctlarg[0]); ! 309: hnputl(dst, cp->dst); ! 310: cp->src = ipgetsrc(dst); ! 311: cp->pdst = atoi(ctlarg[1]); ! 312: ! 313: /* If we have no local port assign one */ ! 314: qlock(&ipalloc); ! 315: if(m == 3){ ! 316: port = atoi(field[2]); ! 317: if(portused(ipifc[c->dev], cp->psrc)){ ! 318: qunlock(&ipalloc); ! 319: error(Einuse); ! 320: } ! 321: cp->psrc = port; ! 322: } ! 323: if(cp->psrc == 0) ! 324: cp->psrc = nextport(ipifc[c->dev], priv); ! 325: qunlock(&ipalloc); ! 326: ! 327: if(cp->ifc->protop == &tcpinfo) ! 328: tcpstart(cp, TCP_ACTIVE, Streamhi, 0); ! 329: else if(cp->ifc->protop == &ilinfo) ! 330: ilstart(cp, IL_ACTIVE, 20); ! 331: ! 332: /* ! 333: * stupid hack for BSD port's 512, 513, & 514 ! 334: * to make it harder for user to lie about his ! 335: * identity. -- presotto ! 336: */ ! 337: switch(cp->pdst){ ! 338: case 512: ! 339: case 513: ! 340: case 514: ! 341: pushq(c->stream, &bsdinfo); ! 342: break; ! 343: } ! 344: ! 345: memmove(cp->text, u->p->text, NAMELEN); ! 346: } ! 347: else if(strncmp(field[0], "disconnect", 10) == 0) { ! 348: if(cp->ifc->protop != &udpinfo) ! 349: error(Eperm); ! 350: ! 351: cp->dst = 0; ! 352: cp->pdst = 0; ! 353: } ! 354: else if(strncmp(field[0], "bind", 4) == 0) { ! 355: if(ipconbusy(cp)) ! 356: error(Enetbusy); ! 357: ! 358: port = atoi(field[1]); ! 359: ! 360: if(port){ ! 361: qlock(&ipalloc); ! 362: if(portused(ipifc[c->dev], port)) { ! 363: qunlock(&ipalloc); ! 364: error(Einuse); ! 365: } ! 366: cp->psrc = port; ! 367: qunlock(&ipalloc); ! 368: } else if(*field[1] != '*'){ ! 369: qlock(&ipalloc); ! 370: cp->psrc = nextport(ipifc[c->dev], 0); ! 371: qunlock(&ipalloc); ! 372: } else ! 373: cp->psrc = 0; ! 374: } ! 375: else if(strncmp(field[0], "announce", 8) == 0) { ! 376: if(ipconbusy(cp)) ! 377: error(Enetbusy); ! 378: ! 379: if(m != 2) ! 380: error(Ebadarg); ! 381: ! 382: port = atoi(field[1]); ! 383: ! 384: if(port){ ! 385: qlock(&ipalloc); ! 386: if(portused(ipifc[c->dev], port)) { ! 387: qunlock(&ipalloc); ! 388: error(Einuse); ! 389: } ! 390: cp->psrc = port; ! 391: qunlock(&ipalloc); ! 392: } else if(*field[1] != '*'){ ! 393: qlock(&ipalloc); ! 394: cp->psrc = nextport(ipifc[c->dev], 0); ! 395: qunlock(&ipalloc); ! 396: } else ! 397: cp->psrc = 0; ! 398: ! 399: if(cp->ifc->protop == &tcpinfo) ! 400: tcpstart(cp, TCP_PASSIVE, Streamhi, 0); ! 401: else if(cp->ifc->protop == &ilinfo) ! 402: ilstart(cp, IL_PASSIVE, 10); ! 403: ! 404: if(cp->backlog == 0) ! 405: cp->backlog = 3; ! 406: ! 407: memmove(cp->text, u->p->text, NAMELEN); ! 408: } ! 409: else if(strncmp(field[0], "backlog", 7) == 0) { ! 410: if(m != 2) ! 411: error(Ebadarg); ! 412: backlog = atoi(field[1]); ! 413: if(backlog == 0) ! 414: error(Ebadarg); ! 415: if(backlog > 5) ! 416: backlog = 5; ! 417: cp->backlog = backlog; ! 418: } ! 419: else if(strncmp(field[0], "headers", 7) == 0) { ! 420: cp->headers = 1; /* include addr/port in user packet */ ! 421: } ! 422: else ! 423: return streamwrite(c, a, n, 0); ! 424: ! 425: return n; ! 426: } ! 427: ! 428: int ! 429: ipconbusy(Ipconv *cp) ! 430: { ! 431: if(cp->ifc->protop == &tcpinfo) ! 432: if(cp->tcpctl.state != Closed) ! 433: return 1; ! 434: ! 435: if(cp->ifc->protop == &ilinfo) ! 436: if(cp->ilctl.state != Ilclosed) ! 437: return 1; ! 438: ! 439: return 0; ! 440: } ! 441: ! 442: void ! 443: udpstiput(Queue *q, Block *bp) ! 444: { ! 445: PUTNEXT(q, bp); ! 446: } ! 447: ! 448: /* ! 449: * udprcvmsg - called by stip to multiplex udp ports onto conversations ! 450: */ ! 451: void ! 452: udprcvmsg(Ipifc *ifc, Block *bp) ! 453: { ! 454: Ipconv *cp, **p, **etab; ! 455: Udphdr *uh; ! 456: Port dport, sport; ! 457: ushort sum, len; ! 458: Ipaddr addr; ! 459: Block *nbp; ! 460: ! 461: uh = (Udphdr *)(bp->rptr); ! 462: ! 463: /* Put back pseudo header for checksum */ ! 464: uh->Unused = 0; ! 465: len = nhgets(uh->udplen); ! 466: hnputs(uh->udpplen, len); ! 467: ! 468: addr = nhgetl(uh->udpsrc); ! 469: ! 470: if(udpsum && nhgets(uh->udpcksum)) { ! 471: if(sum = ptcl_csum(bp, UDP_EHSIZE, len+UDP_PHDRSIZE)) { ! 472: print("udp: checksum error %x (%d.%d.%d.%d)\n", ! 473: sum, fmtaddr(addr)); ! 474: ! 475: freeb(bp); ! 476: return; ! 477: } ! 478: } ! 479: ! 480: dport = nhgets(uh->udpdport); ! 481: sport = nhgets(uh->udpsport); ! 482: ! 483: /* Look for a conversation structure for this port */ ! 484: etab = &ifc->conv[Nipconv]; ! 485: for(p = ifc->conv; p < etab; p++) { ! 486: cp = *p; ! 487: if(cp == 0) ! 488: break; ! 489: if(cp->ref) ! 490: if(cp->psrc == dport) ! 491: if(cp->pdst == 0 || cp->pdst == sport) { ! 492: /* Trim the packet down to data size */ ! 493: len = len - (UDP_HDRSIZE-UDP_PHDRSIZE); ! 494: bp = btrim(bp, UDP_EHSIZE+UDP_HDRSIZE, len); ! 495: if(bp == 0) ! 496: return; ! 497: ! 498: if(cp->headers){ ! 499: /* pass the src address to the stream head */ ! 500: nbp = allocb(Udphdrsize); ! 501: nbp->next = bp; ! 502: bp = nbp; ! 503: hnputl(bp->wptr, addr); ! 504: bp->wptr += 4; ! 505: hnputs(bp->wptr, sport); ! 506: bp->wptr += 2; ! 507: } else { ! 508: /* save the src address in the conversation struct */ ! 509: cp->dst = addr; ! 510: cp->pdst = sport; ! 511: } ! 512: cp->src = 0; ! 513: PUTNEXT(cp->readq, bp); ! 514: return; ! 515: } ! 516: } ! 517: ! 518: freeb(bp); ! 519: } ! 520: ! 521: void ! 522: udpstoput(Queue *q, Block *bp) ! 523: { ! 524: Ipconv *cp; ! 525: Udphdr *uh; ! 526: int dlen, ptcllen, newlen; ! 527: Ipaddr addr; ! 528: Port port; ! 529: if(bp->type == M_CTL) { ! 530: PUTNEXT(q, bp); ! 531: return; ! 532: } ! 533: ! 534: cp = (Ipconv *)(q->ptr); ! 535: if(cp->psrc == 0){ ! 536: freeb(bp); ! 537: error(Enoport); ! 538: } ! 539: ! 540: if(bp->type != M_DATA) { ! 541: freeb(bp); ! 542: error(Ebadctl); ! 543: } ! 544: ! 545: /* Only allow atomic udp writes to form datagrams */ ! 546: if(!(bp->flags & S_DELIM)) { ! 547: freeb(bp); ! 548: error(Emsgsize); ! 549: } ! 550: ! 551: /* ! 552: * if we're in header mode, rip off the first 64 bytes as the ! 553: * destination. The destination is in ascii in the form ! 554: * %d.%d.%d.%d!%d ! 555: */ ! 556: if(cp->headers){ ! 557: /* get user specified addresses */ ! 558: bp = pullup(bp, Udphdrsize); ! 559: if(bp == 0){ ! 560: freeb(bp); ! 561: error(Emsgsize); ! 562: } ! 563: addr = nhgetl(bp->rptr); ! 564: bp->rptr += 4; ! 565: port = nhgets(bp->rptr); ! 566: bp->rptr += 2; ! 567: } else ! 568: addr = port = 0; ! 569: ! 570: /* Round packet up to even number of bytes and check we can ! 571: * send it ! 572: */ ! 573: dlen = blen(bp); ! 574: if(dlen > UDP_DATMAX) { ! 575: freeb(bp); ! 576: error(Emsgsize); ! 577: } ! 578: newlen = dlen /*bround(bp, 1)*/; ! 579: ! 580: /* Make space to fit udp & ip & ethernet header */ ! 581: bp = padb(bp, UDP_EHSIZE + UDP_HDRSIZE); ! 582: ! 583: uh = (Udphdr *)(bp->rptr); ! 584: ! 585: ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); ! 586: uh->Unused = 0; ! 587: uh->udpproto = IP_UDPPROTO; ! 588: uh->frag[0] = 0; ! 589: uh->frag[1] = 0; ! 590: hnputs(uh->udpplen, ptcllen); ! 591: hnputs(uh->udpsport, cp->psrc); ! 592: if(cp->headers) { ! 593: hnputl(uh->udpdst, addr); ! 594: hnputs(uh->udpdport, port); ! 595: } ! 596: else { ! 597: hnputl(uh->udpdst, cp->dst); ! 598: hnputs(uh->udpdport, cp->pdst); ! 599: } ! 600: if(cp->src == 0) ! 601: cp->src = ipgetsrc(uh->udpdst); ! 602: hnputl(uh->udpsrc, cp->src); ! 603: hnputs(uh->udplen, ptcllen); ! 604: uh->udpcksum[0] = 0; ! 605: uh->udpcksum[1] = 0; ! 606: ! 607: hnputs(uh->udpcksum, ptcl_csum(bp, UDP_EHSIZE, newlen+UDP_HDRSIZE)); ! 608: PUTNEXT(q, bp); ! 609: } ! 610: ! 611: void ! 612: udpstclose(Queue *q) ! 613: { ! 614: Ipconv *ipc; ! 615: ! 616: ipc = (Ipconv *)(q->ptr); ! 617: ! 618: ipc->headers = 0; ! 619: ipc->psrc = 0; ! 620: ipc->pdst = 0; ! 621: ipc->dst = 0; ! 622: } ! 623: ! 624: void ! 625: udpstopen(Queue *q, Stream *s) ! 626: { ! 627: Ipconv *ipc; ! 628: ! 629: ipc = ipcreateconv(ipifc[s->dev], s->id); ! 630: initipifc(ipifc[s->dev], IP_UDPPROTO, udprcvmsg); ! 631: ! 632: ipc->readq = RD(q); ! 633: RD(q)->ptr = (void *)ipc; ! 634: WR(q)->next->ptr = (void *)ipc->ifc; ! 635: WR(q)->ptr = (void *)ipc; ! 636: } ! 637: ! 638: void ! 639: tcpstiput(Queue *q, Block *bp) ! 640: { ! 641: PUTNEXT(q, bp); ! 642: } ! 643: ! 644: tcproominq(void *a) ! 645: { ! 646: return !((Tcpctl *)a)->sndfull; ! 647: } ! 648: ! 649: void ! 650: tcpstoput(Queue *q, Block *bp) ! 651: { ! 652: Ipconv *s; ! 653: Tcpctl *tcb; ! 654: Block *f; ! 655: ! 656: s = (Ipconv *)(q->ptr); ! 657: tcb = &s->tcpctl; ! 658: ! 659: if(bp->type == M_CTL) { ! 660: PUTNEXT(q, bp); ! 661: return; ! 662: } ! 663: ! 664: if(s->psrc == 0) ! 665: error(Enoport); ! 666: ! 667: /* Report asynchronous errors */ ! 668: if(s->err) ! 669: error(s->err); ! 670: ! 671: switch(tcb->state) { ! 672: case Listen: ! 673: tcb->flags |= ACTIVE; ! 674: tcpsndsyn(tcb); ! 675: tcpsetstate(s, Syn_sent); ! 676: ! 677: /* No break */ ! 678: case Syn_sent: ! 679: case Syn_received: ! 680: case Established: ! 681: /* ! 682: * Process flow control ! 683: */ ! 684: if(tcb->sndfull){ ! 685: qlock(&tcb->sndrlock); ! 686: if(waserror()) { ! 687: qunlock(&tcb->sndrlock); ! 688: freeb(bp); ! 689: nexterror(); ! 690: } ! 691: sleep(&tcb->sndr, tcproominq, tcb); ! 692: poperror(); ! 693: qunlock(&tcb->sndrlock); ! 694: } ! 695: ! 696: /* ! 697: * Push data ! 698: */ ! 699: qlock(tcb); ! 700: if(waserror()) { ! 701: qunlock(tcb); ! 702: nexterror(); ! 703: } ! 704: ! 705: /* make sure we don't queue onto something that just closed */ ! 706: switch(tcb->state) { ! 707: case Syn_sent: ! 708: case Syn_received: ! 709: case Established: ! 710: break; ! 711: default: ! 712: freeb(bp); ! 713: error(Ehungup); ! 714: } ! 715: ! 716: tcb->sndcnt += blen(bp); ! 717: if(tcb->sndcnt > Streamhi) ! 718: tcb->sndfull = 1; ! 719: if(tcb->sndq == 0) ! 720: tcb->sndq = bp; ! 721: else { ! 722: for(f = tcb->sndq; f->next; f = f->next) ! 723: ; ! 724: f->next = bp; ! 725: } ! 726: tcprcvwin(s); ! 727: tcpoutput(s); ! 728: poperror(); ! 729: qunlock(tcb); ! 730: break; ! 731: ! 732: case Close_wait: ! 733: default: ! 734: freeb(bp); ! 735: error(Ehungup); ! 736: } ! 737: } ! 738: ! 739: void ! 740: tcpstopen(Queue *q, Stream *s) ! 741: { ! 742: Ipconv *ipc; ! 743: Ipifc *ifc; ! 744: Tcpctl *tcb; ! 745: Block *bp; ! 746: static int tcpkprocs; ! 747: ! 748: /* Flow control and tcp timer processes */ ! 749: if(tcpkprocs == 0) { ! 750: tcpkprocs = 1; ! 751: kproc("tcpack", tcpackproc, 0); ! 752: kproc("tcpflow", tcpflow, ipifc[s->dev]); ! 753: ! 754: } ! 755: ! 756: if(tcpbase == 0) ! 757: tcpbase = ipifc[s->dev]->conv; ! 758: ifc = ipifc[s->dev]; ! 759: initipifc(ifc, IP_TCPPROTO, tcpinput); ! 760: ipc = ipcreateconv(ifc, s->id); ! 761: ! 762: ipc->readq = RD(q); ! 763: ipc->readq->rp = &tcpflowr; ! 764: ipc->err = 0; ! 765: ! 766: RD(q)->ptr = (void *)ipc; ! 767: WR(q)->ptr = (void *)ipc; ! 768: ! 769: /* pass any waiting data upstream */ ! 770: tcb = &ipc->tcpctl; ! 771: qlock(tcb); ! 772: while(bp = getb(&tcb->rcvq)) ! 773: PUTNEXT(ipc->readq, bp); ! 774: qunlock(tcb); ! 775: } ! 776: ! 777: void ! 778: ipremotefill(Chan *c, char *buf, int len) ! 779: { ! 780: Ipconv *cp; ! 781: ! 782: if(len < 24) ! 783: error(Ebadarg); ! 784: cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); ! 785: sprint(buf, "%d.%d.%d.%d!%d\n", fmtaddr(cp->dst), cp->pdst); ! 786: } ! 787: ! 788: void ! 789: iplocalfill(Chan *c, char *buf, int len) ! 790: { ! 791: Ipconv *cp; ! 792: ! 793: if(len < 24) ! 794: error(Ebadarg); ! 795: cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); ! 796: sprint(buf, "%d.%d.%d.%d!%d\n", fmtaddr(ipd[0].Myip[Myself]), cp->psrc); ! 797: } ! 798: ! 799: void ! 800: ipstatusfill(Chan *c, char *buf, int len) ! 801: { ! 802: Ipconv *cp; ! 803: int connection; ! 804: ! 805: if(len < 64) ! 806: error(Ebadarg); ! 807: connection = STREAMID(c->qid.path); ! 808: cp = ipcreateconv(ipifc[c->dev], connection); ! 809: if(cp->ifc->protop == &tcpinfo) ! 810: sprint(buf, "tcp/%d %d %s %s %s %d+%d\n", connection, cp->ref, ! 811: tcpstate[cp->tcpctl.state], ! 812: cp->tcpctl.flags & CLONE ? "listen" : "connect", ! 813: cp->text, ! 814: cp->tcpctl.srtt, cp->tcpctl.mdev); ! 815: else if(cp->ifc->protop == &ilinfo) ! 816: sprint(buf, "il/%d %d %s rtt %d ms %d csum\n", connection, cp->ref, ! 817: ilstate[cp->ilctl.state], cp->ilctl.rtt, ! 818: cp->ifc ? cp->ifc->chkerrs : 0); ! 819: else ! 820: sprint(buf, "%s/%d %d Datagram\n", ! 821: cp->ifc->protop->name, connection, cp->ref); ! 822: } ! 823: ! 824: int ! 825: iphavecon(Ipconv *s) ! 826: { ! 827: return s->curlog; ! 828: } ! 829: ! 830: int ! 831: iplisten(Chan *c) ! 832: { ! 833: Ipconv *s; ! 834: int connection; ! 835: Ipconv **p, **etab, *new; ! 836: ! 837: connection = STREAMID(c->qid.path); ! 838: s = ipcreateconv(ipifc[c->dev], connection); ! 839: ! 840: if(s->ifc->protop == &tcpinfo) ! 841: if(s->tcpctl.state != Listen) ! 842: error(Enolisten); ! 843: ! 844: if(s->ifc->protop == &ilinfo) ! 845: if(s->ilctl.state != Illistening) ! 846: error(Enolisten); ! 847: ! 848: for(;;) { ! 849: qlock(&s->listenq); /* single thread for the sleep */ ! 850: if(waserror()) { ! 851: qunlock(&s->listenq); ! 852: nexterror(); ! 853: } ! 854: sleep(&s->listenr, iphavecon, s); ! 855: poperror(); ! 856: etab = &ipifc[c->dev]->conv[Nipconv]; ! 857: for(p = ipifc[c->dev]->conv; p < etab; p++) { ! 858: new = *p; ! 859: if(new == 0) ! 860: break; ! 861: if(new->newcon == s) { ! 862: qlock(s); ! 863: s->curlog--; ! 864: qunlock(s); ! 865: new->newcon = 0; ! 866: qunlock(&s->listenq); ! 867: return new->id; ! 868: } ! 869: } ! 870: qunlock(&s->listenq); ! 871: print("iplisten: no newcon\n"); ! 872: } ! 873: return -1; /* not reached */ ! 874: } ! 875: ! 876: void ! 877: tcpstclose(Queue *q) ! 878: { ! 879: Ipconv *s, *new; ! 880: Ipconv **etab, **p; ! 881: Tcpctl *tcb; ! 882: ! 883: s = (Ipconv *)(q->ptr); ! 884: tcb = &s->tcpctl; ! 885: ! 886: /* Not interested in data anymore */ ! 887: qlock(s); ! 888: s->readq = 0; ! 889: qunlock(s); ! 890: ! 891: switch(tcb->state){ ! 892: case Listen: ! 893: /* ! 894: * reset any incoming calls to this listener ! 895: */ ! 896: qlock(s); ! 897: s->backlog = 0; ! 898: s->curlog = 0; ! 899: etab = &tcpbase[Nipconv]; ! 900: for(p = tcpbase; p < etab; p++){ ! 901: new = *p; ! 902: if(new == 0) ! 903: break; ! 904: if(new->newcon == s){ ! 905: new->newcon = 0; ! 906: tcpflushincoming(new); ! 907: new->ref = 0; ! 908: } ! 909: } ! 910: qunlock(s); ! 911: ! 912: qlock(tcb); ! 913: localclose(s, 0); ! 914: qunlock(tcb); ! 915: break; ! 916: ! 917: case Closed: ! 918: case Syn_sent: ! 919: qlock(tcb); ! 920: localclose(s, 0); ! 921: qunlock(tcb); ! 922: break; ! 923: ! 924: case Syn_received: ! 925: case Established: ! 926: tcb->sndcnt++; ! 927: tcb->snd.nxt++; ! 928: tcpsetstate(s, Finwait1); ! 929: goto output; ! 930: ! 931: case Close_wait: ! 932: tcb->sndcnt++; ! 933: tcb->snd.nxt++; ! 934: tcpsetstate(s, Last_ack); ! 935: output: ! 936: qlock(tcb); ! 937: if(waserror()) { ! 938: qunlock(tcb); ! 939: nexterror(); ! 940: } ! 941: tcpoutput(s); ! 942: poperror(); ! 943: qunlock(tcb); ! 944: break; ! 945: } ! 946: } ! 947: ! 948: ! 949: static short endian = 1; ! 950: static char* aendian = (char*)&endian; ! 951: #define LITTLE *aendian ! 952: ! 953: ushort ! 954: ptcl_bsum(uchar *addr, int len) ! 955: { ! 956: ulong losum, hisum, mdsum, x; ! 957: ulong t1, t2; ! 958: ! 959: losum = 0; ! 960: hisum = 0; ! 961: mdsum = 0; ! 962: ! 963: x = 0; ! 964: if((ulong)addr & 1) { ! 965: if(len) { ! 966: hisum += addr[0]; ! 967: len--; ! 968: addr++; ! 969: } ! 970: x = 1; ! 971: } ! 972: while(len >= 16) { ! 973: t1 = *(ushort*)(addr+0); ! 974: t2 = *(ushort*)(addr+2); mdsum += t1; ! 975: t1 = *(ushort*)(addr+4); mdsum += t2; ! 976: t2 = *(ushort*)(addr+6); mdsum += t1; ! 977: t1 = *(ushort*)(addr+8); mdsum += t2; ! 978: t2 = *(ushort*)(addr+10); mdsum += t1; ! 979: t1 = *(ushort*)(addr+12); mdsum += t2; ! 980: t2 = *(ushort*)(addr+14); mdsum += t1; ! 981: mdsum += t2; ! 982: len -= 16; ! 983: addr += 16; ! 984: } ! 985: while(len >= 2) { ! 986: mdsum += *(ushort*)addr; ! 987: len -= 2; ! 988: addr += 2; ! 989: } ! 990: if(x) { ! 991: if(len) ! 992: losum += addr[0]; ! 993: if(LITTLE) ! 994: losum += mdsum; ! 995: else ! 996: hisum += mdsum; ! 997: } else { ! 998: if(len) ! 999: hisum += addr[0]; ! 1000: if(LITTLE) ! 1001: hisum += mdsum; ! 1002: else ! 1003: losum += mdsum; ! 1004: } ! 1005: ! 1006: losum += hisum >> 8; ! 1007: losum += (hisum & 0xff) << 8; ! 1008: while(hisum = losum>>16) ! 1009: losum = hisum + (losum & 0xffff); ! 1010: ! 1011: return losum & 0xffff; ! 1012: } ! 1013: ! 1014: ushort ! 1015: ptcl_csum(Block *bp, int offset, int len) ! 1016: { ! 1017: uchar *addr; ! 1018: ulong losum, hisum; ! 1019: ushort csum; ! 1020: int odd, blen, x; ! 1021: ! 1022: /* Correct to front of data area */ ! 1023: while(bp && offset && offset >= BLEN(bp)) { ! 1024: offset -= BLEN(bp); ! 1025: bp = bp->next; ! 1026: } ! 1027: if(bp == 0) ! 1028: return 0; ! 1029: ! 1030: addr = bp->rptr + offset; ! 1031: blen = BLEN(bp) - offset; ! 1032: ! 1033: if(bp->next == 0) ! 1034: return ~ptcl_bsum(addr, MIN(len, blen)) & 0xffff; ! 1035: ! 1036: losum = 0; ! 1037: hisum = 0; ! 1038: ! 1039: odd = 0; ! 1040: while(len) { ! 1041: x = MIN(len, blen); ! 1042: csum = ptcl_bsum(addr, x); ! 1043: if(odd) ! 1044: hisum += csum; ! 1045: else ! 1046: losum += csum; ! 1047: odd = (odd+x) & 1; ! 1048: len -= x; ! 1049: ! 1050: bp = bp->next; ! 1051: if(bp == 0) ! 1052: break; ! 1053: blen = BLEN(bp); ! 1054: addr = bp->rptr; ! 1055: } ! 1056: ! 1057: losum += hisum>>8; ! 1058: losum += (hisum&0xff)<<8; ! 1059: while((csum = losum>>16) != 0) ! 1060: losum = csum + (losum & 0xffff); ! 1061: ! 1062: return ~losum & 0xffff; ! 1063: } ! 1064: ! 1065: Block * ! 1066: btrim(Block *bp, int offset, int len) ! 1067: { ! 1068: Block *nb, *startb; ! 1069: ulong l; ! 1070: ! 1071: if(blen(bp) < offset+len) { ! 1072: freeb(bp); ! 1073: return 0; ! 1074: } ! 1075: ! 1076: while((l = BLEN(bp)) < offset) { ! 1077: offset -= l; ! 1078: nb = bp->next; ! 1079: bp->next = 0; ! 1080: freeb(bp); ! 1081: bp = nb; ! 1082: } ! 1083: ! 1084: startb = bp; ! 1085: bp->rptr += offset; ! 1086: ! 1087: while((l = BLEN(bp)) < len) { ! 1088: len -= l; ! 1089: bp = bp->next; ! 1090: } ! 1091: ! 1092: bp->wptr -= (BLEN(bp) - len); ! 1093: bp->flags |= S_DELIM; ! 1094: ! 1095: if(bp->next) { ! 1096: freeb(bp->next); ! 1097: bp->next = 0; ! 1098: } ! 1099: ! 1100: return(startb); ! 1101: } ! 1102: ! 1103: Ipconv * ! 1104: portused(Ipifc *ifc, Port port) ! 1105: { ! 1106: Ipconv **p, **etab; ! 1107: Ipconv *cp; ! 1108: ! 1109: if(port == 0) ! 1110: return 0; ! 1111: ! 1112: etab = &ifc->conv[Nipconv]; ! 1113: for(p = ifc->conv; p < etab; p++){ ! 1114: cp = *p; ! 1115: if(cp == 0) ! 1116: break; ! 1117: if(cp->psrc == port) ! 1118: return cp; ! 1119: } ! 1120: ! 1121: return 0; ! 1122: } ! 1123: ! 1124: static Port lastport[2] = { PORTALLOC-1, PRIVPORTALLOC-1 }; ! 1125: ! 1126: Port ! 1127: nextport(Ipifc *ifc, int priv) ! 1128: { ! 1129: Port base; ! 1130: Port max; ! 1131: Port *p; ! 1132: Port i; ! 1133: ! 1134: if(priv){ ! 1135: base = PRIVPORTALLOC; ! 1136: max = UNPRIVPORTALLOC; ! 1137: p = &lastport[1]; ! 1138: } else { ! 1139: base = PORTALLOC; ! 1140: max = PORTMAX; ! 1141: p = &lastport[0]; ! 1142: } ! 1143: ! 1144: for(i = *p + 1; i < max; i++) ! 1145: if(!portused(ifc, i)) ! 1146: return(*p = i); ! 1147: for(i = base ; i <= *p; i++) ! 1148: if(!portused(ifc, i)) ! 1149: return(*p = i); ! 1150: ! 1151: return(0); ! 1152: } ! 1153: ! 1154: /* NEEDS HASHING ! */ ! 1155: ! 1156: Ipconv* ! 1157: ip_conn(Ipifc *ifc, Port dst, Port src, Ipaddr dest) ! 1158: { ! 1159: Ipconv **p, *s, **etab; ! 1160: ! 1161: /* Look for a conversation structure for this port */ ! 1162: etab = &ifc->conv[Nipconv]; ! 1163: for(p = ifc->conv; p < etab; p++) { ! 1164: s = *p; ! 1165: if(s == 0) ! 1166: break; ! 1167: if(s->psrc == dst) ! 1168: if(s->pdst == src) ! 1169: if(s->dst == dest || dest == 0) ! 1170: return s; ! 1171: } ! 1172: ! 1173: return 0; ! 1174: } ! 1175: ! 1176: /* ! 1177: * ! 1178: * BSD authentication protocol, used on ports 512, 513, & 514. ! 1179: * This makes sure that a user can only write the REAL user id. ! 1180: * ! 1181: * q->ptr is number of nulls seen ! 1182: */ ! 1183: void ! 1184: bsdopen(Queue *q, Stream *s) ! 1185: { ! 1186: USED(s); ! 1187: RD(q)->ptr = q; ! 1188: WR(q)->ptr = q; ! 1189: } ! 1190: void ! 1191: bsdclose(Queue *q) ! 1192: { ! 1193: Block *bp; ! 1194: ! 1195: bp = allocb(0); ! 1196: bp->type = M_HANGUP; ! 1197: PUTNEXT(q->other, bp); ! 1198: } ! 1199: void ! 1200: bsdiput(Queue *q, Block *bp) ! 1201: { ! 1202: PUTNEXT(q, bp); ! 1203: } ! 1204: void ! 1205: bsdoput(Queue *q, Block *bp) ! 1206: { ! 1207: uchar *luser; ! 1208: Block *nbp; ! 1209: ! 1210: /* just pass it on if we've done authentication */ ! 1211: if(q->ptr == 0 || bp->type != M_DATA){ ! 1212: PUTNEXT(q, bp); ! 1213: return; ! 1214: } ! 1215: ! 1216: /* collect into a single block */ ! 1217: qlock(&q->rlock); ! 1218: if(q->first == 0) ! 1219: q->first = pullup(bp, blen(bp)); ! 1220: else{ ! 1221: nbp = q->first; ! 1222: nbp->next = bp; ! 1223: q->first = pullup(nbp, blen(nbp)); ! 1224: } ! 1225: bp = q->first; ! 1226: if(bp == 0){ ! 1227: qunlock(&q->rlock); ! 1228: bsdclose(q); ! 1229: return; ! 1230: } ! 1231: ! 1232: /* look for 2 nulls to indicate stderr port and local user */ ! 1233: luser = memchr(bp->rptr, 0, BLEN(bp)); ! 1234: if(luser == 0){ ! 1235: qunlock(&q->rlock); ! 1236: return; ! 1237: } ! 1238: luser++; ! 1239: if(memchr(luser, 0, bp->wptr - luser) == 0){ ! 1240: qunlock(&q->rlock); ! 1241: return; ! 1242: } ! 1243: ! 1244: /* if luser is a lie, hangup */ ! 1245: if(memcmp(luser, u->p->user, strlen(u->p->user)+1) != 0) ! 1246: bsdclose(q); ! 1247: ! 1248: /* mark queue as authenticated and pass data to remote side */ ! 1249: q->ptr = 0; ! 1250: q->first = 0; ! 1251: bp->flags |= S_DELIM; ! 1252: PUTNEXT(q, bp); ! 1253: qunlock(&q->rlock); ! 1254: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.