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