|
|
1.1 ! root 1: /* ! 2: * tcp_device.c ! 3: */ ! 4: ! 5: #include "tcp.h" ! 6: #if NTCP ! 7: #include "../h/param.h" ! 8: #include "../h/systm.h" ! 9: #include "../h/stream.h" ! 10: #include "../h/inio.h" ! 11: #include "../h/ttyio.h" ! 12: #include "../h/ttyld.h" ! 13: #include "../h/buf.h" ! 14: #include "../h/conf.h" ! 15: #include "../h/dir.h" ! 16: #include "../h/user.h" ! 17: #include "../h/inet/in.h" ! 18: #include "../h/inet/mbuf.h" ! 19: #include "../h/inet/tcp.h" ! 20: #include "../h/inet/tcp_timer.h" ! 21: #include "../h/inet/tcp_seq.h" ! 22: #include "../h/inet/tcp_var.h" ! 23: #include "../h/inet/tcp_user.h" ! 24: #include "../h/inet/tcp_fsm.h" ! 25: #include "../h/inet/socket.h" ! 26: ! 27: extern int tcp_busy; /* set to discourage timers & ensuing panics */ ! 28: ! 29: int nodev(), tcpdopen(), tcpdclose(), tcpdput(); ! 30: int tcpdosrv(), tcpdisrv(); ! 31: static struct qinit tcpdrinit = { nodev, tcpdisrv, tcpdopen, tcpdclose, 2048, 64 }; ! 32: struct qinit tcpdwinit = { tcpdput, tcpdosrv, tcpdopen, tcpdclose, 2048,64}; ! 33: struct streamtab tcpdinfo = { &tcpdrinit, &tcpdwinit }; ! 34: ! 35: int Ntcp = NTCP; /* for netstat */ ! 36: struct tcpcb tcpcb[NTCP]; ! 37: struct socket tcpsocks[NTCP]; ! 38: ! 39: tcpdopen(q, dev) ! 40: register struct queue *q; ! 41: dev_t dev; ! 42: { ! 43: struct socket *so; ! 44: ! 45: dev = minor(dev); ! 46: if(dev >= NTCP) ! 47: return(0); ! 48: so = &tcpsocks[dev]; ! 49: if((dev&01) == 0 && (so->so_state&SS_ACTIVE) == 0) ! 50: return(0); ! 51: if(so->so_state&SS_WAITING) ! 52: return(0); ! 53: if((so->so_options&SO_ACCEPTCONN) && (so->so_state&SS_OPEN)) ! 54: return(0); ! 55: if((so->so_state & (SS_ACTIVE|SS_OPEN|SS_PLEASEOPEN)) == SS_ACTIVE) ! 56: return(0); ! 57: if(q->ptr && dev&01) /* re-opening outgoing port */ ! 58: return(0); ! 59: if(q->ptr) ! 60: return(1); ! 61: tcp_busy++; ! 62: if((so->so_state & SS_PLEASEOPEN) == 0){ ! 63: bzero(so, sizeof(struct socket)); ! 64: so->so_state |= SS_WAITING; ! 65: } ! 66: so->so_state |= SS_OPEN; ! 67: so->so_dev = dev; ! 68: so->so_rq = q; ! 69: so->so_wq = WR(q); ! 70: q->ptr = (caddr_t)so; ! 71: WR(q)->flag |= QNOENB|QBIGB; ! 72: WR(q)->ptr = (caddr_t)so; ! 73: --tcp_busy; ! 74: if(so->so_state & SS_PLEASEOPEN){ ! 75: so->so_state &= ~SS_PLEASEOPEN; ! 76: qenable(WR(q)); /* to force out rcv wnd update */ ! 77: } ! 78: return(1); ! 79: } ! 80: ! 81: tcpdclose(q) ! 82: register struct queue *q; ! 83: { ! 84: struct socket *so; ! 85: struct tcpcb *tp; ! 86: ! 87: so = (struct socket *)q->ptr; ! 88: tcp_busy++; ! 89: so->so_state &= ~(SS_OPEN|SS_WAITING); ! 90: so->so_rq = so->so_wq = (struct queue *) 0; ! 91: so->so_wcount = so->so_rcount = 0; ! 92: tp = so->so_tcpcb; ! 93: if(tp == 0){ ! 94: --tcp_busy; ! 95: return; ! 96: } ! 97: if(tp->t_state > TCPS_LISTEN) ! 98: tcp_disconnect(tp); ! 99: else ! 100: tcp_close(tp); ! 101: --tcp_busy; ! 102: } ! 103: ! 104: tcpdput(q, bp) ! 105: register struct queue *q; ! 106: register struct block *bp; ! 107: { ! 108: struct socket *so; ! 109: int s, x; ! 110: register union stmsg *sp; ! 111: struct tcpcb *tp; ! 112: struct block *nbp; ! 113: struct foo { ! 114: int com; ! 115: struct tcpuser rep; ! 116: }; ! 117: struct foo *fp; ! 118: ! 119: so = (struct socket *)q->ptr; ! 120: switch(bp->type){ ! 121: case M_IOCTL: ! 122: sp = (union stmsg *)bp->rptr; ! 123: bp->type = M_IOCACK; ! 124: switch(sp->ioc0.com){ ! 125: case TIOCSETP: ! 126: case TIOCSETN: ! 127: x = sp->ioc1.sb.sg_ispeed; ! 128: bp->wptr = bp->rptr; ! 129: bp->type = M_IOCACK; ! 130: qreply(q, bp); ! 131: if(x == 0) ! 132: tcp_putctl(OTHERQ(q), M_HANGUP); ! 133: return; ! 134: case TIOCGETP: ! 135: sp->ioc1.sb.sg_ispeed = ! 136: sp->ioc1.sb.sg_ospeed = B9600; ! 137: break; ! 138: case TCPGETADDR: ! 139: nbp = allocb(sizeof(struct foo)); ! 140: if (nbp == NULL) { ! 141: bp->type = M_IOCNAK; ! 142: printf("tcpdput: out of blocks\n"); ! 143: break; ! 144: } ! 145: nbp->type = M_IOCACK; ! 146: fp = (struct foo *)nbp->rptr; ! 147: fp->com = sp->ioc1.com; ! 148: fp->rep.lport = so->so_lport; ! 149: fp->rep.fport = so->so_fport; ! 150: fp->rep.laddr = so->so_laddr; ! 151: fp->rep.faddr = so->so_faddr; ! 152: nbp->wptr = nbp->rptr + sizeof(struct foo); ! 153: freeb(bp); ! 154: bp = nbp; ! 155: break; ! 156: case TCPIOHUP: ! 157: so->so_state |= SS_HANGUP; ! 158: bp->wptr = bp->rptr; ! 159: bp->type = M_IOCACK; ! 160: qreply(q, bp); ! 161: return; ! 162: default: ! 163: bp->type = M_IOCNAK; ! 164: } ! 165: qreply(q, bp); ! 166: return; ! 167: case M_DATA: ! 168: if(socantsendmore(so)){ ! 169: freeb(bp); ! 170: return; ! 171: } ! 172: s = spl6(); ! 173: so->so_delimcnt = 0; ! 174: so->so_wcount += BLEN(bp); /* BEFORE the putq */ ! 175: putq(q, bp); ! 176: splx(s); ! 177: if((so->so_options&SO_ACCEPTCONN) == 0 ! 178: && (so->so_state&SS_WAITING) == 0 ! 179: && (tp = so->so_tcpcb)){ ! 180: /* so as to invoke tcp_output() */ ! 181: if(tp->t_state > TCPS_CLOSE_WAIT) ! 182: printf("data after CLOSE_WAIT?\n"); ! 183: qenable(q); ! 184: } ! 185: break; ! 186: case M_DELIM: ! 187: if(so->so_options&SO_ACCEPTCONN){ ! 188: printf("DELIM on listener\n"); ! 189: } else if(so->so_state & SS_WAITING){ ! 190: putq(q, bp); ! 191: /* to invoke tcpduser */ ! 192: qenable(q); ! 193: } else { ! 194: /* two back to back delims constitute logical eof */ ! 195: freeb(bp); ! 196: s = spl6(); ! 197: if(socantsendmore(so)){ ! 198: splx(s); ! 199: return; ! 200: } ! 201: if(++(so->so_delimcnt) > 1){ ! 202: splx(s); ! 203: qenable(q); ! 204: } else ! 205: splx(s); ! 206: } ! 207: break; ! 208: default: ! 209: freeb(bp); ! 210: break; ! 211: } ! 212: } ! 213: ! 214: tcpdosrv(q) ! 215: struct queue *q; ! 216: { ! 217: register struct socket *so; ! 218: register struct tcpcb *tp; ! 219: ! 220: so = (struct socket *)q->ptr; ! 221: if (so->so_state&SS_WCLOSED) ! 222: return; ! 223: tcp_busy++; ! 224: if(so->so_delimcnt > 1){ ! 225: so->so_state |= SS_WCLOSED; ! 226: if((tp = so->so_tcpcb) == 0){ ! 227: printf("delimcnt but no tp\n"); ! 228: --tcp_busy; ! 229: return; ! 230: } ! 231: tp = tcp_usrclosed(tp); ! 232: if(tp) ! 233: tcp_output(tp); ! 234: } else { ! 235: if((so->so_options&SO_ACCEPTCONN) == 0 ! 236: && (so->so_state&SS_WAITING) == 0 ! 237: && (tp = so->so_tcpcb)){ ! 238: tcp_output(tp); ! 239: } else { ! 240: tcpduser(so); ! 241: } ! 242: } ! 243: --tcp_busy; ! 244: } ! 245: ! 246: tcpdrint(bp, so) ! 247: register struct block *bp; ! 248: struct socket *so; ! 249: { ! 250: register struct block *bp1; ! 251: register struct queue *q; ! 252: ! 253: q = so->so_rq; ! 254: if(q){ ! 255: while(bp){ ! 256: bp1 = bp->next; ! 257: so->so_rcount += bp->wptr - bp->rptr; ! 258: if(bp->wptr == bp->rptr) ! 259: freeb(bp); ! 260: else ! 261: putq(q, bp); ! 262: bp = bp1; ! 263: } ! 264: } else { ! 265: printf("tcpdrint but no so->so_rq\n"); ! 266: bp_free(bp); ! 267: } ! 268: } ! 269: ! 270: tcpdisrv(q) ! 271: struct queue *q; ! 272: { ! 273: struct socket *so = (struct socket *)(q->ptr); ! 274: struct block *bp; ! 275: ! 276: while((q->next->flag&QFULL) == 0){ ! 277: if(bp = getq(q)){ ! 278: if(bp->type == M_DATA) ! 279: so->so_rcount -= bp->wptr - bp->rptr; ! 280: if(so->so_rcount < 0) ! 281: panic("so_rcount"); ! 282: (*q->next->qinfo->putp)(q->next, bp); ! 283: } else ! 284: break; ! 285: } ! 286: if(q->count <= q->qinfo->lolimit) ! 287: qenable(OTHERQ(q)); /* update remote send window */ ! 288: } ! 289: ! 290: /* ! 291: * imitation tcp_usrreq ! 292: */ ! 293: tcpduser(so) ! 294: register struct socket *so; ! 295: { ! 296: extern struct ipif *ip_ifwithaddr(); ! 297: struct tcpuser *tu; ! 298: struct block *bp, *bp1, *head; ! 299: register struct tcpcb *tp; ! 300: ! 301: bp = bp1 = head = NULL; ! 302: while(bp = getq(so->so_wq)){ ! 303: if(bp->type != M_DATA){ ! 304: freeb(bp); ! 305: } else if(bp1 == NULL){ ! 306: bp1 = head = bp; ! 307: bp->next = NULL; ! 308: } else { ! 309: bp1->next = bp; ! 310: bp1 = bp; ! 311: bp->next = NULL; ! 312: } ! 313: } ! 314: if(head == NULL) ! 315: return; ! 316: so->so_wcount = 0; ! 317: bp = head; ! 318: if(BLEN(bp) < sizeof(struct tcpuser)){ ! 319: /* ! 320: printf("tcpuser short\n"); ! 321: */ ! 322: bp_free(bp); ! 323: return; ! 324: } ! 325: tu = (struct tcpuser *)bp->rptr; ! 326: if(so->so_tcpcb) ! 327: printf("%d: tcpduser w/ tcpcb\n", so->so_dev); ! 328: switch(tu->code){ ! 329: case TCPC_CONNECT: ! 330: if(so->so_state&SS_ACTIVE) ! 331: goto bad; ! 332: if (tu->laddr != INADDR_ANY) { ! 333: /* has the user has specified a legal local address? */ ! 334: if (ip_ifwithaddr(tu->laddr) == 0) ! 335: goto bad; ! 336: } else { ! 337: /* pick a local address related to the destination */ ! 338: tu->laddr = ip_hoston(tu->faddr); ! 339: if(tu->laddr == INADDR_ANY) ! 340: goto bad; ! 341: } ! 342: if(tcp_attach(so)) ! 343: goto bad; ! 344: if(sobind(so, tu->laddr, tu->lport)) ! 345: goto bad; ! 346: tp = so->so_tcpcb; ! 347: so->so_fport = tu->fport; ! 348: so->so_faddr = tu->faddr; ! 349: so->so_options = tu->param; ! 350: if (so->so_options & SO_KEEPALIVE) ! 351: tcp_timers(tp, TCPT_KEEP); ! 352: tp->t_template = tcp_template(tp); ! 353: if(tp->t_template == 0) ! 354: goto bad; ! 355: soisconnecting(so); ! 356: tp->t_state = TCPS_SYN_SENT; ! 357: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; ! 358: tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; ! 359: tcp_sendseqinit(tp); ! 360: so->so_state &= ~SS_WAITING; ! 361: tcp_output(tp); ! 362: break; ! 363: case TCPC_LISTEN: ! 364: if(so->so_state&SS_ACTIVE) ! 365: goto bad; ! 366: if (tu->laddr != INADDR_ANY) { ! 367: /* has the user has specified a legal local address? */ ! 368: if (ip_ifwithaddr(tu->laddr) == 0) ! 369: goto bad; ! 370: } ! 371: if(tcp_attach(so)) ! 372: goto bad; ! 373: if(sobind(so, tu->laddr, tu->lport)) ! 374: goto bad; ! 375: tp = so->so_tcpcb; ! 376: tp->t_state = TCPS_LISTEN; ! 377: so->so_options |= SO_ACCEPTCONN; ! 378: so->so_fport = tu->fport==0 ? TCPPORT_ANY : tu->fport; ! 379: so->so_faddr = tu->faddr; ! 380: so->so_state &= ~SS_WAITING; ! 381: tcp_isconnected(so); ! 382: break; ! 383: default: ! 384: goto bad; ! 385: } ! 386: bp_free(bp); ! 387: return; ! 388: bad: ! 389: bp_free(bp); ! 390: tcp_hungup(so); ! 391: } ! 392: ! 393: tcp_attach(so) ! 394: struct socket *so; ! 395: { ! 396: register struct tcpcb *tp; ! 397: extern struct tcpcb *tcp_newtcpcb(); ! 398: ! 399: tp = tcp_newtcpcb(so); ! 400: if(tp == 0) ! 401: return(1); ! 402: tp->t_socket = so; ! 403: tp->t_state = TCPS_CLOSED; ! 404: return(0); ! 405: } ! 406: ! 407: struct tcpcb * ! 408: tcp_disconnect(tp) ! 409: register struct tcpcb *tp; ! 410: { ! 411: struct socket *so = tp->t_socket; ! 412: ! 413: if(tp->t_state < TCPS_ESTABLISHED) ! 414: tp = tcp_close(tp); ! 415: else { ! 416: soisdisconnecting(so); ! 417: tp = tcp_usrclosed(tp); ! 418: if(tp) ! 419: tcp_output(tp); ! 420: } ! 421: return(tp); ! 422: } ! 423: ! 424: struct tcpcb * ! 425: tcp_usrclosed(tp) ! 426: register struct tcpcb *tp; ! 427: { ! 428: ! 429: switch(tp->t_state){ ! 430: ! 431: case TCPS_CLOSED: ! 432: case TCPS_LISTEN: ! 433: case TCPS_SYN_SENT: ! 434: tp->t_state = TCPS_CLOSED; ! 435: tp = tcp_close(tp); ! 436: break; ! 437: ! 438: case TCPS_SYN_RECEIVED: ! 439: case TCPS_ESTABLISHED: ! 440: tp->t_state = TCPS_FIN_WAIT_1; ! 441: tp->t_socket->so_options |= SO_KEEPALIVE; ! 442: tcp_timers(tp, TCPT_KEEP); ! 443: break; ! 444: ! 445: case TCPS_CLOSE_WAIT: ! 446: tp->t_state = TCPS_LAST_ACK; ! 447: tp->t_socket->so_options |= SO_KEEPALIVE; ! 448: tcp_timers(tp, TCPT_KEEP); ! 449: break; ! 450: } ! 451: if(tp && tp->t_state >= TCPS_FIN_WAIT_2) ! 452: soisdisconnected(tp->t_socket); ! 453: return(tp); ! 454: } ! 455: ! 456: tcp_isconnected(so) ! 457: struct socket *so; ! 458: { ! 459: struct block *bp; ! 460: struct tcpuser *tu; ! 461: struct socket *rso; ! 462: ! 463: if(so->so_head) ! 464: rso = so->so_head; ! 465: else ! 466: rso = so; ! 467: if((rso->so_state & SS_OPEN) == 0){ ! 468: printf("isconnected, no fd ref\n"); ! 469: return; ! 470: } ! 471: bp = allocb(64); ! 472: if(bp == 0) ! 473: return; ! 474: bp->next = NULL; ! 475: bp->type = M_DATA; ! 476: bp->wptr += sizeof(struct tcpuser); ! 477: tu = (struct tcpuser *)bp->rptr; ! 478: tu->code = TCPC_OK; ! 479: tu->fport = so->so_fport; ! 480: tu->faddr = so->so_faddr; ! 481: tu->lport = so->so_lport; ! 482: tu->laddr = so->so_laddr; ! 483: tu->param = so->so_dev; ! 484: tcpdrint(bp, rso); ! 485: } ! 486: ! 487: tcp_hungup(so) ! 488: register struct socket *so; ! 489: { ! 490: register struct queue *q; ! 491: ! 492: q = so->so_rq; ! 493: if(q == 0) ! 494: return; ! 495: tcp_putctl(q, M_HANGUP); ! 496: } ! 497: ! 498: /* ! 499: * find a spare odd tcp device for a new passive-end ! 500: * connection. ! 501: */ ! 502: struct socket * ! 503: tcp_newconn(so) ! 504: struct socket *so; ! 505: { ! 506: struct socket *nso; ! 507: ! 508: if(so->so_rq && (so->so_rq->flag&QFULL)){ ! 509: printf("listen %d q full\n", so->so_lport); ! 510: return(0); ! 511: } ! 512: for(nso = &tcpsocks[0]; nso < &tcpsocks[NTCP]; nso += 2){ ! 513: if((nso->so_state & (SS_OPEN|SS_ACTIVE)) == 0){ ! 514: bzero(nso, sizeof(struct socket)); ! 515: nso->so_head = so; ! 516: nso->so_dev = nso - tcpsocks; ! 517: return(nso); ! 518: } ! 519: } ! 520: return(0); ! 521: } ! 522: ! 523: struct socket * ! 524: so_lookup(faddr, fport, laddr, lport) ! 525: in_addr faddr, laddr; ! 526: tcp_port fport, lport; ! 527: { ! 528: register struct socket *so, *match = 0; ! 529: int highscore = 0, score; ! 530: ! 531: for(so = &tcpsocks[0]; so < &tcpsocks[NTCP]; so++){ ! 532: if(so->so_tcpcb == 0) ! 533: continue; ! 534: if((so->so_state&(SS_OPEN|SS_ACTIVE)) == 0) ! 535: continue; ! 536: if(so->so_state & SS_WAITING) ! 537: continue; ! 538: score = 11; ! 539: if(so->so_faddr != faddr) { ! 540: if(so->so_faddr != INADDR_ANY) ! 541: continue; ! 542: else ! 543: score -=4; ! 544: } ! 545: if(so->so_fport != fport) { ! 546: if(so->so_fport != TCPPORT_ANY) ! 547: continue; ! 548: else ! 549: score -=4; ! 550: } ! 551: if(so->so_laddr != laddr) { ! 552: if(so->so_laddr != INADDR_ANY) ! 553: continue; ! 554: else ! 555: score -=1; ! 556: } ! 557: if(so->so_lport != lport) { ! 558: if(so->so_lport != TCPPORT_ANY) ! 559: continue; ! 560: else ! 561: score -=2; ! 562: } ! 563: if (score==11) ! 564: return so; ! 565: if (score<highscore) ! 566: continue; ! 567: match = so; ! 568: highscore = score; ! 569: } ! 570: return(match); ! 571: } ! 572: ! 573: /* n chars were acked; drop them now */ ! 574: sbsnddrop(so, n) ! 575: register struct socket *so; ! 576: register int n; ! 577: { ! 578: register struct queue *q; ! 579: register int i; ! 580: register struct block *bp; ! 581: ! 582: q = so->so_wq; ! 583: if(q == 0) ! 584: return; ! 585: bp = 0; ! 586: while(n > 0 && (bp = getq(q))){ ! 587: i = MIN(BLEN(bp), n); ! 588: bp->rptr += i; ! 589: n -= i; ! 590: so->so_wcount -= i; ! 591: if(bp->rptr >= bp->wptr){ ! 592: freeb(bp); ! 593: bp = 0; ! 594: } else if(n > 0){ ! 595: panic("sbsnddrop"); ! 596: } ! 597: } ! 598: if(bp) ! 599: putbq(q, bp); ! 600: } ! 601: ! 602: static tcp_port portnext[] = { 600, 1024 }; ! 603: static tcp_port portlow[] = { 600, 1024 }; ! 604: static tcp_port porthigh[] = { 1024, 2048 }; ! 605: ! 606: sobind(so, addr, port) ! 607: register struct socket *so; ! 608: register in_addr addr; ! 609: register tcp_port port; ! 610: { ! 611: register struct socket *sp; ! 612: register int i; ! 613: ! 614: so->so_lport = 0; ! 615: if(port){ ! 616: /* what about, for instance, restarting rlogind when ! 617: * people are rlogin'd here? ! 618: */ ! 619: for(sp = &tcpsocks[0]; sp < &tcpsocks[NTCP]; sp++){ ! 620: if(sp->so_tcpcb == 0) ! 621: continue; ! 622: if((sp->so_state&(SS_OPEN|SS_ACTIVE)) == 0) ! 623: continue; ! 624: if(sp->so_lport == port && sp->so_laddr == addr) { ! 625: return(1); ! 626: } ! 627: } ! 628: so->so_lport = port; ! 629: so->so_laddr = addr; ! 630: return(0); ! 631: } ! 632: /* pick one for him */ ! 633: i = u.u_uid==0 ? 0 : 1; ! 634: if(portnext[i] >= porthigh[i]) ! 635: portnext[i] = portlow[i]; ! 636: port = portnext[i]; ! 637: while(1){ ! 638: if(sobind(so, addr, portnext[i]) == 0){ ! 639: portnext[i]++; ! 640: return(0); ! 641: } ! 642: portnext[i]++; ! 643: if(portnext[i] >= porthigh[i]) ! 644: portnext[i] = portlow[i]; ! 645: if(portnext[i] == port) /* tried them all */ ! 646: break; ! 647: } ! 648: return(1); ! 649: } ! 650: ! 651: tcp_cantrcvmore(so) ! 652: register struct socket *so; ! 653: { ! 654: register struct queue *q; ! 655: ! 656: q = so->so_rq; ! 657: if(q == NULL) ! 658: return; ! 659: if(so->so_state & SS_HANGUP) ! 660: tcp_putctl(q, M_HANGUP); ! 661: else { ! 662: /* two delims ensure a zero length read at the process */ ! 663: tcp_putctl(q, M_DELIM); ! 664: tcp_putctl(q, M_DELIM); ! 665: } ! 666: } ! 667: ! 668: tcp_putctl(q, c) ! 669: register struct queue *q; ! 670: { ! 671: register struct block *bp; ! 672: ! 673: if ((bp = allocb(0)) == NULL) { ! 674: printf("tcp_putctl: no more blocks\n"); ! 675: return(0); ! 676: } ! 677: bp->type = c; ! 678: putq(q, bp); ! 679: return(1); ! 680: } ! 681: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.