|
|
1.1 ! root 1: #include <string.h> ! 2: #include <stdlib.h> ! 3: #include <stdio.h> ! 4: #include <assert.h> ! 5: #include <errno.h> ! 6: #include <byteswap.h> ! 7: #include <ipxe/timer.h> ! 8: #include <ipxe/iobuf.h> ! 9: #include <ipxe/malloc.h> ! 10: #include <ipxe/retry.h> ! 11: #include <ipxe/refcnt.h> ! 12: #include <ipxe/xfer.h> ! 13: #include <ipxe/open.h> ! 14: #include <ipxe/uri.h> ! 15: #include <ipxe/netdevice.h> ! 16: #include <ipxe/tcpip.h> ! 17: #include <ipxe/tcp.h> ! 18: ! 19: /** @file ! 20: * ! 21: * TCP protocol ! 22: * ! 23: */ ! 24: ! 25: FILE_LICENCE ( GPL2_OR_LATER ); ! 26: ! 27: /** A TCP connection */ ! 28: struct tcp_connection { ! 29: /** Reference counter */ ! 30: struct refcnt refcnt; ! 31: /** List of TCP connections */ ! 32: struct list_head list; ! 33: ! 34: /** Flags */ ! 35: unsigned int flags; ! 36: ! 37: /** Data transfer interface */ ! 38: struct interface xfer; ! 39: ! 40: /** Remote socket address */ ! 41: struct sockaddr_tcpip peer; ! 42: /** Local port */ ! 43: unsigned int local_port; ! 44: ! 45: /** Current TCP state */ ! 46: unsigned int tcp_state; ! 47: /** Previous TCP state ! 48: * ! 49: * Maintained only for debug messages ! 50: */ ! 51: unsigned int prev_tcp_state; ! 52: /** Current sequence number ! 53: * ! 54: * Equivalent to SND.UNA in RFC 793 terminology. ! 55: */ ! 56: uint32_t snd_seq; ! 57: /** Unacknowledged sequence count ! 58: * ! 59: * Equivalent to (SND.NXT-SND.UNA) in RFC 793 terminology. ! 60: */ ! 61: uint32_t snd_sent; ! 62: /** Send window ! 63: * ! 64: * Equivalent to SND.WND in RFC 793 terminology ! 65: */ ! 66: uint32_t snd_win; ! 67: /** Current acknowledgement number ! 68: * ! 69: * Equivalent to RCV.NXT in RFC 793 terminology. ! 70: */ ! 71: uint32_t rcv_ack; ! 72: /** Receive window ! 73: * ! 74: * Equivalent to RCV.WND in RFC 793 terminology. ! 75: */ ! 76: uint32_t rcv_win; ! 77: /** Received timestamp value ! 78: * ! 79: * Updated when a packet is received; copied to ts_recent when ! 80: * the window is advanced. ! 81: */ ! 82: uint32_t ts_val; ! 83: /** Most recent received timestamp that advanced the window ! 84: * ! 85: * Equivalent to TS.Recent in RFC 1323 terminology. ! 86: */ ! 87: uint32_t ts_recent; ! 88: ! 89: /** Transmit queue */ ! 90: struct list_head tx_queue; ! 91: /** Receive queue */ ! 92: struct list_head rx_queue; ! 93: /** Retransmission timer */ ! 94: struct retry_timer timer; ! 95: /** Shutdown (TIME_WAIT) timer */ ! 96: struct retry_timer wait; ! 97: }; ! 98: ! 99: /** TCP flags */ ! 100: enum tcp_flags { ! 101: /** TCP data transfer interface has been closed */ ! 102: TCP_XFER_CLOSED = 0x0001, ! 103: /** TCP timestamps are enabled */ ! 104: TCP_TS_ENABLED = 0x0002, ! 105: /** TCP acknowledgement is pending */ ! 106: TCP_ACK_PENDING = 0x0004, ! 107: }; ! 108: ! 109: /** TCP internal header ! 110: * ! 111: * This is the header that replaces the TCP header for packets ! 112: * enqueued on the receive queue. ! 113: */ ! 114: struct tcp_rx_queued_header { ! 115: /** SEQ value, in host-endian order ! 116: * ! 117: * This represents the SEQ value at the time the packet is ! 118: * enqueued, and so excludes the SYN, if present. ! 119: */ ! 120: uint32_t seq; ! 121: /** Flags ! 122: * ! 123: * Only FIN is valid within this flags byte; all other flags ! 124: * have already been processed by the time the packet is ! 125: * enqueued. ! 126: */ ! 127: uint8_t flags; ! 128: /** Reserved */ ! 129: uint8_t reserved[3]; ! 130: }; ! 131: ! 132: /** ! 133: * List of registered TCP connections ! 134: */ ! 135: static LIST_HEAD ( tcp_conns ); ! 136: ! 137: /* Forward declarations */ ! 138: static struct interface_descriptor tcp_xfer_desc; ! 139: static void tcp_expired ( struct retry_timer *timer, int over ); ! 140: static void tcp_wait_expired ( struct retry_timer *timer, int over ); ! 141: static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, ! 142: uint32_t win ); ! 143: ! 144: /** ! 145: * Name TCP state ! 146: * ! 147: * @v state TCP state ! 148: * @ret name Name of TCP state ! 149: */ ! 150: static inline __attribute__ (( always_inline )) const char * ! 151: tcp_state ( int state ) { ! 152: switch ( state ) { ! 153: case TCP_CLOSED: return "CLOSED"; ! 154: case TCP_LISTEN: return "LISTEN"; ! 155: case TCP_SYN_SENT: return "SYN_SENT"; ! 156: case TCP_SYN_RCVD: return "SYN_RCVD"; ! 157: case TCP_ESTABLISHED: return "ESTABLISHED"; ! 158: case TCP_FIN_WAIT_1: return "FIN_WAIT_1"; ! 159: case TCP_FIN_WAIT_2: return "FIN_WAIT_2"; ! 160: case TCP_CLOSING_OR_LAST_ACK: return "CLOSING/LAST_ACK"; ! 161: case TCP_TIME_WAIT: return "TIME_WAIT"; ! 162: case TCP_CLOSE_WAIT: return "CLOSE_WAIT"; ! 163: default: return "INVALID"; ! 164: } ! 165: } ! 166: ! 167: /** ! 168: * Dump TCP state transition ! 169: * ! 170: * @v tcp TCP connection ! 171: */ ! 172: static inline __attribute__ (( always_inline )) void ! 173: tcp_dump_state ( struct tcp_connection *tcp ) { ! 174: ! 175: if ( tcp->tcp_state != tcp->prev_tcp_state ) { ! 176: DBGC ( tcp, "TCP %p transitioned from %s to %s\n", tcp, ! 177: tcp_state ( tcp->prev_tcp_state ), ! 178: tcp_state ( tcp->tcp_state ) ); ! 179: } ! 180: tcp->prev_tcp_state = tcp->tcp_state; ! 181: } ! 182: ! 183: /** ! 184: * Dump TCP flags ! 185: * ! 186: * @v flags TCP flags ! 187: */ ! 188: static inline __attribute__ (( always_inline )) void ! 189: tcp_dump_flags ( struct tcp_connection *tcp, unsigned int flags ) { ! 190: if ( flags & TCP_RST ) ! 191: DBGC2 ( tcp, " RST" ); ! 192: if ( flags & TCP_SYN ) ! 193: DBGC2 ( tcp, " SYN" ); ! 194: if ( flags & TCP_PSH ) ! 195: DBGC2 ( tcp, " PSH" ); ! 196: if ( flags & TCP_FIN ) ! 197: DBGC2 ( tcp, " FIN" ); ! 198: if ( flags & TCP_ACK ) ! 199: DBGC2 ( tcp, " ACK" ); ! 200: } ! 201: ! 202: /*************************************************************************** ! 203: * ! 204: * Open and close ! 205: * ! 206: *************************************************************************** ! 207: */ ! 208: ! 209: /** ! 210: * Bind TCP connection to local port ! 211: * ! 212: * @v tcp TCP connection ! 213: * @v port Local port number ! 214: * @ret rc Return status code ! 215: * ! 216: * If the port is 0, the connection is assigned an available port ! 217: * between 1024 and 65535. ! 218: */ ! 219: static int tcp_bind ( struct tcp_connection *tcp, unsigned int port ) { ! 220: struct tcp_connection *existing; ! 221: uint16_t try_port; ! 222: unsigned int i; ! 223: ! 224: /* If no port is specified, find an available port */ ! 225: if ( ! port ) { ! 226: try_port = random(); ! 227: for ( i = 0 ; i < 65536 ; i++ ) { ! 228: try_port++; ! 229: if ( try_port < 1024 ) ! 230: continue; ! 231: if ( tcp_bind ( tcp, try_port ) == 0 ) ! 232: return 0; ! 233: } ! 234: DBGC ( tcp, "TCP %p could not bind: no free ports\n", tcp ); ! 235: return -EADDRINUSE; ! 236: } ! 237: ! 238: /* Attempt bind to local port */ ! 239: list_for_each_entry ( existing, &tcp_conns, list ) { ! 240: if ( existing->local_port == port ) { ! 241: DBGC ( tcp, "TCP %p could not bind: port %d in use\n", ! 242: tcp, port ); ! 243: return -EADDRINUSE; ! 244: } ! 245: } ! 246: tcp->local_port = port; ! 247: ! 248: DBGC ( tcp, "TCP %p bound to port %d\n", tcp, port ); ! 249: return 0; ! 250: } ! 251: ! 252: /** ! 253: * Open a TCP connection ! 254: * ! 255: * @v xfer Data transfer interface ! 256: * @v peer Peer socket address ! 257: * @v local Local socket address, or NULL ! 258: * @ret rc Return status code ! 259: */ ! 260: static int tcp_open ( struct interface *xfer, struct sockaddr *peer, ! 261: struct sockaddr *local ) { ! 262: struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer; ! 263: struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local; ! 264: struct tcp_connection *tcp; ! 265: unsigned int bind_port; ! 266: int rc; ! 267: ! 268: /* Allocate and initialise structure */ ! 269: tcp = zalloc ( sizeof ( *tcp ) ); ! 270: if ( ! tcp ) ! 271: return -ENOMEM; ! 272: DBGC ( tcp, "TCP %p allocated\n", tcp ); ! 273: ref_init ( &tcp->refcnt, NULL ); ! 274: intf_init ( &tcp->xfer, &tcp_xfer_desc, &tcp->refcnt ); ! 275: timer_init ( &tcp->timer, tcp_expired, &tcp->refcnt ); ! 276: timer_init ( &tcp->wait, tcp_wait_expired, &tcp->refcnt ); ! 277: tcp->prev_tcp_state = TCP_CLOSED; ! 278: tcp->tcp_state = TCP_STATE_SENT ( TCP_SYN ); ! 279: tcp_dump_state ( tcp ); ! 280: tcp->snd_seq = random(); ! 281: INIT_LIST_HEAD ( &tcp->tx_queue ); ! 282: INIT_LIST_HEAD ( &tcp->rx_queue ); ! 283: memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) ); ! 284: ! 285: /* Bind to local port */ ! 286: bind_port = ( st_local ? ntohs ( st_local->st_port ) : 0 ); ! 287: if ( ( rc = tcp_bind ( tcp, bind_port ) ) != 0 ) ! 288: goto err; ! 289: ! 290: /* Start timer to initiate SYN */ ! 291: start_timer_nodelay ( &tcp->timer ); ! 292: ! 293: /* Attach parent interface, transfer reference to connection ! 294: * list and return ! 295: */ ! 296: intf_plug_plug ( &tcp->xfer, xfer ); ! 297: list_add ( &tcp->list, &tcp_conns ); ! 298: return 0; ! 299: ! 300: err: ! 301: ref_put ( &tcp->refcnt ); ! 302: return rc; ! 303: } ! 304: ! 305: /** ! 306: * Close TCP connection ! 307: * ! 308: * @v tcp TCP connection ! 309: * @v rc Reason for close ! 310: * ! 311: * Closes the data transfer interface. If the TCP state machine is in ! 312: * a suitable state, the connection will be deleted. ! 313: */ ! 314: static void tcp_close ( struct tcp_connection *tcp, int rc ) { ! 315: struct io_buffer *iobuf; ! 316: struct io_buffer *tmp; ! 317: ! 318: /* Close data transfer interface */ ! 319: intf_shutdown ( &tcp->xfer, rc ); ! 320: tcp->flags |= TCP_XFER_CLOSED; ! 321: ! 322: /* If we are in CLOSED, or have otherwise not yet received a ! 323: * SYN (i.e. we are in LISTEN or SYN_SENT), just delete the ! 324: * connection. ! 325: */ ! 326: if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) { ! 327: ! 328: /* Transition to CLOSED for the sake of debugging messages */ ! 329: tcp->tcp_state = TCP_CLOSED; ! 330: tcp_dump_state ( tcp ); ! 331: ! 332: /* Free any unprocessed I/O buffers */ ! 333: list_for_each_entry_safe ( iobuf, tmp, &tcp->rx_queue, list ) { ! 334: list_del ( &iobuf->list ); ! 335: free_iob ( iobuf ); ! 336: } ! 337: ! 338: /* Free any unsent I/O buffers */ ! 339: list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) { ! 340: list_del ( &iobuf->list ); ! 341: free_iob ( iobuf ); ! 342: } ! 343: ! 344: /* Remove from list and drop reference */ ! 345: stop_timer ( &tcp->timer ); ! 346: list_del ( &tcp->list ); ! 347: ref_put ( &tcp->refcnt ); ! 348: DBGC ( tcp, "TCP %p connection deleted\n", tcp ); ! 349: return; ! 350: } ! 351: ! 352: /* If we have not had our SYN acknowledged (i.e. we are in ! 353: * SYN_RCVD), pretend that it has been acknowledged so that we ! 354: * can send a FIN without breaking things. ! 355: */ ! 356: if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) ) ! 357: tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 ); ! 358: ! 359: /* If we have no data remaining to send, start sending FIN */ ! 360: if ( list_empty ( &tcp->tx_queue ) ) { ! 361: tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN ); ! 362: tcp_dump_state ( tcp ); ! 363: } ! 364: } ! 365: ! 366: /*************************************************************************** ! 367: * ! 368: * Transmit data path ! 369: * ! 370: *************************************************************************** ! 371: */ ! 372: ! 373: /** ! 374: * Calculate transmission window ! 375: * ! 376: * @v tcp TCP connection ! 377: * @ret len Maximum length that can be sent in a single packet ! 378: */ ! 379: static size_t tcp_xmit_win ( struct tcp_connection *tcp ) { ! 380: size_t len; ! 381: ! 382: /* Not ready if we're not in a suitable connection state */ ! 383: if ( ! TCP_CAN_SEND_DATA ( tcp->tcp_state ) ) ! 384: return 0; ! 385: ! 386: /* Length is the minimum of the receiver's window and the path MTU */ ! 387: len = tcp->snd_win; ! 388: if ( len > TCP_PATH_MTU ) ! 389: len = TCP_PATH_MTU; ! 390: ! 391: return len; ! 392: } ! 393: ! 394: /** ! 395: * Process TCP transmit queue ! 396: * ! 397: * @v tcp TCP connection ! 398: * @v max_len Maximum length to process ! 399: * @v dest I/O buffer to fill with data, or NULL ! 400: * @v remove Remove data from queue ! 401: * @ret len Length of data processed ! 402: * ! 403: * This processes at most @c max_len bytes from the TCP connection's ! 404: * transmit queue. Data will be copied into the @c dest I/O buffer ! 405: * (if provided) and, if @c remove is true, removed from the transmit ! 406: * queue. ! 407: */ ! 408: static size_t tcp_process_tx_queue ( struct tcp_connection *tcp, size_t max_len, ! 409: struct io_buffer *dest, int remove ) { ! 410: struct io_buffer *iobuf; ! 411: struct io_buffer *tmp; ! 412: size_t frag_len; ! 413: size_t len = 0; ! 414: ! 415: list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) { ! 416: frag_len = iob_len ( iobuf ); ! 417: if ( frag_len > max_len ) ! 418: frag_len = max_len; ! 419: if ( dest ) { ! 420: memcpy ( iob_put ( dest, frag_len ), iobuf->data, ! 421: frag_len ); ! 422: } ! 423: if ( remove ) { ! 424: iob_pull ( iobuf, frag_len ); ! 425: if ( ! iob_len ( iobuf ) ) { ! 426: list_del ( &iobuf->list ); ! 427: free_iob ( iobuf ); ! 428: } ! 429: } ! 430: len += frag_len; ! 431: max_len -= frag_len; ! 432: } ! 433: return len; ! 434: } ! 435: ! 436: /** ! 437: * Transmit any outstanding data ! 438: * ! 439: * @v tcp TCP connection ! 440: * ! 441: * Transmits any outstanding data on the connection. ! 442: * ! 443: * Note that even if an error is returned, the retransmission timer ! 444: * will have been started if necessary, and so the stack will ! 445: * eventually attempt to retransmit the failed packet. ! 446: */ ! 447: static int tcp_xmit ( struct tcp_connection *tcp ) { ! 448: struct io_buffer *iobuf; ! 449: struct tcp_header *tcphdr; ! 450: struct tcp_mss_option *mssopt; ! 451: struct tcp_timestamp_padded_option *tsopt; ! 452: void *payload; ! 453: unsigned int flags; ! 454: size_t len = 0; ! 455: uint32_t seq_len; ! 456: uint32_t app_win; ! 457: uint32_t max_rcv_win; ! 458: int rc; ! 459: ! 460: /* If retransmission timer is already running, do nothing */ ! 461: if ( timer_running ( &tcp->timer ) ) ! 462: return 0; ! 463: ! 464: /* Calculate both the actual (payload) and sequence space ! 465: * lengths that we wish to transmit. ! 466: */ ! 467: if ( TCP_CAN_SEND_DATA ( tcp->tcp_state ) ) { ! 468: len = tcp_process_tx_queue ( tcp, tcp_xmit_win ( tcp ), ! 469: NULL, 0 ); ! 470: } ! 471: seq_len = len; ! 472: flags = TCP_FLAGS_SENDING ( tcp->tcp_state ); ! 473: if ( flags & ( TCP_SYN | TCP_FIN ) ) { ! 474: /* SYN or FIN consume one byte, and we can never send both */ ! 475: assert ( ! ( ( flags & TCP_SYN ) && ( flags & TCP_FIN ) ) ); ! 476: seq_len++; ! 477: } ! 478: tcp->snd_sent = seq_len; ! 479: ! 480: /* If we have nothing to transmit, stop now */ ! 481: if ( ( seq_len == 0 ) && ! ( tcp->flags & TCP_ACK_PENDING ) ) ! 482: return 0; ! 483: ! 484: /* If we are transmitting anything that requires ! 485: * acknowledgement (i.e. consumes sequence space), start the ! 486: * retransmission timer. Do this before attempting to ! 487: * allocate the I/O buffer, in case allocation itself fails. ! 488: */ ! 489: if ( seq_len ) ! 490: start_timer ( &tcp->timer ); ! 491: ! 492: /* Allocate I/O buffer */ ! 493: iobuf = alloc_iob ( len + MAX_LL_NET_HEADER_LEN ); ! 494: if ( ! iobuf ) { ! 495: DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x " ! 496: "%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ), ! 497: tcp->rcv_ack ); ! 498: return -ENOMEM; ! 499: } ! 500: iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); ! 501: ! 502: /* Fill data payload from transmit queue */ ! 503: tcp_process_tx_queue ( tcp, len, iobuf, 0 ); ! 504: ! 505: /* Expand receive window if possible */ ! 506: max_rcv_win = ( ( freemem * 3 ) / 4 ); ! 507: if ( max_rcv_win > TCP_MAX_WINDOW_SIZE ) ! 508: max_rcv_win = TCP_MAX_WINDOW_SIZE; ! 509: app_win = xfer_window ( &tcp->xfer ); ! 510: if ( max_rcv_win > app_win ) ! 511: max_rcv_win = app_win; ! 512: max_rcv_win &= ~0x03; /* Keep everything dword-aligned */ ! 513: if ( tcp->rcv_win < max_rcv_win ) ! 514: tcp->rcv_win = max_rcv_win; ! 515: ! 516: /* Fill up the TCP header */ ! 517: payload = iobuf->data; ! 518: if ( flags & TCP_SYN ) { ! 519: mssopt = iob_push ( iobuf, sizeof ( *mssopt ) ); ! 520: mssopt->kind = TCP_OPTION_MSS; ! 521: mssopt->length = sizeof ( *mssopt ); ! 522: mssopt->mss = htons ( TCP_MSS ); ! 523: } ! 524: if ( ( flags & TCP_SYN ) || ( tcp->flags & TCP_TS_ENABLED ) ) { ! 525: tsopt = iob_push ( iobuf, sizeof ( *tsopt ) ); ! 526: memset ( tsopt->nop, TCP_OPTION_NOP, sizeof ( tsopt->nop ) ); ! 527: tsopt->tsopt.kind = TCP_OPTION_TS; ! 528: tsopt->tsopt.length = sizeof ( tsopt->tsopt ); ! 529: tsopt->tsopt.tsval = htonl ( currticks() ); ! 530: tsopt->tsopt.tsecr = htonl ( tcp->ts_recent ); ! 531: } ! 532: if ( len != 0 ) ! 533: flags |= TCP_PSH; ! 534: tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) ); ! 535: memset ( tcphdr, 0, sizeof ( *tcphdr ) ); ! 536: tcphdr->src = htons ( tcp->local_port ); ! 537: tcphdr->dest = tcp->peer.st_port; ! 538: tcphdr->seq = htonl ( tcp->snd_seq ); ! 539: tcphdr->ack = htonl ( tcp->rcv_ack ); ! 540: tcphdr->hlen = ( ( payload - iobuf->data ) << 2 ); ! 541: tcphdr->flags = flags; ! 542: tcphdr->win = htons ( tcp->rcv_win ); ! 543: tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) ); ! 544: ! 545: /* Dump header */ ! 546: DBGC2 ( tcp, "TCP %p TX %d->%d %08x..%08x %08x %4zd", ! 547: tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), ! 548: ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + seq_len ), ! 549: ntohl ( tcphdr->ack ), len ); ! 550: tcp_dump_flags ( tcp, tcphdr->flags ); ! 551: DBGC2 ( tcp, "\n" ); ! 552: ! 553: /* Transmit packet */ ! 554: if ( ( rc = tcpip_tx ( iobuf, &tcp_protocol, NULL, &tcp->peer, NULL, ! 555: &tcphdr->csum ) ) != 0 ) { ! 556: DBGC ( tcp, "TCP %p could not transmit %08x..%08x %08x: %s\n", ! 557: tcp, tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ), ! 558: tcp->rcv_ack, strerror ( rc ) ); ! 559: return rc; ! 560: } ! 561: ! 562: /* Clear ACK-pending flag */ ! 563: tcp->flags &= ~TCP_ACK_PENDING; ! 564: ! 565: return 0; ! 566: } ! 567: ! 568: /** ! 569: * Retransmission timer expired ! 570: * ! 571: * @v timer Retransmission timer ! 572: * @v over Failure indicator ! 573: */ ! 574: static void tcp_expired ( struct retry_timer *timer, int over ) { ! 575: struct tcp_connection *tcp = ! 576: container_of ( timer, struct tcp_connection, timer ); ! 577: ! 578: DBGC ( tcp, "TCP %p timer %s in %s for %08x..%08x %08x\n", tcp, ! 579: ( over ? "expired" : "fired" ), tcp_state ( tcp->tcp_state ), ! 580: tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack ); ! 581: ! 582: assert ( ( tcp->tcp_state == TCP_SYN_SENT ) || ! 583: ( tcp->tcp_state == TCP_SYN_RCVD ) || ! 584: ( tcp->tcp_state == TCP_ESTABLISHED ) || ! 585: ( tcp->tcp_state == TCP_FIN_WAIT_1 ) || ! 586: ( tcp->tcp_state == TCP_CLOSE_WAIT ) || ! 587: ( tcp->tcp_state == TCP_CLOSING_OR_LAST_ACK ) ); ! 588: ! 589: if ( over ) { ! 590: /* If we have finally timed out and given up, ! 591: * terminate the connection ! 592: */ ! 593: tcp->tcp_state = TCP_CLOSED; ! 594: tcp_dump_state ( tcp ); ! 595: tcp_close ( tcp, -ETIMEDOUT ); ! 596: } else { ! 597: /* Otherwise, retransmit the packet */ ! 598: tcp_xmit ( tcp ); ! 599: } ! 600: } ! 601: ! 602: /** ! 603: * Shutdown timer expired ! 604: * ! 605: * @v timer Shutdown timer ! 606: * @v over Failure indicator ! 607: */ ! 608: static void tcp_wait_expired ( struct retry_timer *timer, int over __unused ) { ! 609: struct tcp_connection *tcp = ! 610: container_of ( timer, struct tcp_connection, wait ); ! 611: ! 612: assert ( tcp->tcp_state == TCP_TIME_WAIT ); ! 613: ! 614: DBGC ( tcp, "TCP %p wait complete in %s for %08x..%08x %08x\n", tcp, ! 615: tcp_state ( tcp->tcp_state ), tcp->snd_seq, ! 616: ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack ); ! 617: ! 618: tcp->tcp_state = TCP_CLOSED; ! 619: tcp_dump_state ( tcp ); ! 620: tcp_close ( tcp, 0 ); ! 621: } ! 622: ! 623: /** ! 624: * Send RST response to incoming packet ! 625: * ! 626: * @v in_tcphdr TCP header of incoming packet ! 627: * @ret rc Return status code ! 628: */ ! 629: static int tcp_xmit_reset ( struct tcp_connection *tcp, ! 630: struct sockaddr_tcpip *st_dest, ! 631: struct tcp_header *in_tcphdr ) { ! 632: struct io_buffer *iobuf; ! 633: struct tcp_header *tcphdr; ! 634: int rc; ! 635: ! 636: /* Allocate space for dataless TX buffer */ ! 637: iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN ); ! 638: if ( ! iobuf ) { ! 639: DBGC ( tcp, "TCP %p could not allocate iobuf for RST " ! 640: "%08x..%08x %08x\n", tcp, ntohl ( in_tcphdr->ack ), ! 641: ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ) ); ! 642: return -ENOMEM; ! 643: } ! 644: iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); ! 645: ! 646: /* Construct RST response */ ! 647: tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) ); ! 648: memset ( tcphdr, 0, sizeof ( *tcphdr ) ); ! 649: tcphdr->src = in_tcphdr->dest; ! 650: tcphdr->dest = in_tcphdr->src; ! 651: tcphdr->seq = in_tcphdr->ack; ! 652: tcphdr->ack = in_tcphdr->seq; ! 653: tcphdr->hlen = ( ( sizeof ( *tcphdr ) / 4 ) << 4 ); ! 654: tcphdr->flags = ( TCP_RST | TCP_ACK ); ! 655: tcphdr->win = htons ( TCP_MAX_WINDOW_SIZE ); ! 656: tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) ); ! 657: ! 658: /* Dump header */ ! 659: DBGC2 ( tcp, "TCP %p TX %d->%d %08x..%08x %08x %4d", ! 660: tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), ! 661: ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) ), ! 662: ntohl ( tcphdr->ack ), 0 ); ! 663: tcp_dump_flags ( tcp, tcphdr->flags ); ! 664: DBGC2 ( tcp, "\n" ); ! 665: ! 666: /* Transmit packet */ ! 667: if ( ( rc = tcpip_tx ( iobuf, &tcp_protocol, NULL, st_dest, ! 668: NULL, &tcphdr->csum ) ) != 0 ) { ! 669: DBGC ( tcp, "TCP %p could not transmit RST %08x..%08x %08x: " ! 670: "%s\n", tcp, ntohl ( in_tcphdr->ack ), ! 671: ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ), ! 672: strerror ( rc ) ); ! 673: return rc; ! 674: } ! 675: ! 676: return 0; ! 677: } ! 678: ! 679: /*************************************************************************** ! 680: * ! 681: * Receive data path ! 682: * ! 683: *************************************************************************** ! 684: */ ! 685: ! 686: /** ! 687: * Identify TCP connection by local port number ! 688: * ! 689: * @v local_port Local port ! 690: * @ret tcp TCP connection, or NULL ! 691: */ ! 692: static struct tcp_connection * tcp_demux ( unsigned int local_port ) { ! 693: struct tcp_connection *tcp; ! 694: ! 695: list_for_each_entry ( tcp, &tcp_conns, list ) { ! 696: if ( tcp->local_port == local_port ) ! 697: return tcp; ! 698: } ! 699: return NULL; ! 700: } ! 701: ! 702: /** ! 703: * Parse TCP received options ! 704: * ! 705: * @v tcp TCP connection ! 706: * @v data Raw options data ! 707: * @v len Raw options length ! 708: * @v options Options structure to fill in ! 709: */ ! 710: static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data, ! 711: size_t len, struct tcp_options *options ) { ! 712: const void *end = ( data + len ); ! 713: const struct tcp_option *option; ! 714: unsigned int kind; ! 715: ! 716: memset ( options, 0, sizeof ( *options ) ); ! 717: while ( data < end ) { ! 718: option = data; ! 719: kind = option->kind; ! 720: if ( kind == TCP_OPTION_END ) ! 721: return; ! 722: if ( kind == TCP_OPTION_NOP ) { ! 723: data++; ! 724: continue; ! 725: } ! 726: switch ( kind ) { ! 727: case TCP_OPTION_MSS: ! 728: options->mssopt = data; ! 729: break; ! 730: case TCP_OPTION_TS: ! 731: options->tsopt = data; ! 732: break; ! 733: default: ! 734: DBGC ( tcp, "TCP %p received unknown option %d\n", ! 735: tcp, kind ); ! 736: break; ! 737: } ! 738: data += option->length; ! 739: } ! 740: } ! 741: ! 742: /** ! 743: * Consume received sequence space ! 744: * ! 745: * @v tcp TCP connection ! 746: * @v seq_len Sequence space length to consume ! 747: */ ! 748: static void tcp_rx_seq ( struct tcp_connection *tcp, uint32_t seq_len ) { ! 749: ! 750: /* Sanity check */ ! 751: assert ( seq_len > 0 ); ! 752: ! 753: /* Update acknowledgement number */ ! 754: tcp->rcv_ack += seq_len; ! 755: ! 756: /* Update window */ ! 757: if ( tcp->rcv_win > seq_len ) { ! 758: tcp->rcv_win -= seq_len; ! 759: } else { ! 760: tcp->rcv_win = 0; ! 761: } ! 762: ! 763: /* Update timestamp */ ! 764: tcp->ts_recent = tcp->ts_val; ! 765: ! 766: /* Mark ACK as pending */ ! 767: tcp->flags |= TCP_ACK_PENDING; ! 768: } ! 769: ! 770: /** ! 771: * Handle TCP received SYN ! 772: * ! 773: * @v tcp TCP connection ! 774: * @v seq SEQ value (in host-endian order) ! 775: * @v options TCP options ! 776: * @ret rc Return status code ! 777: */ ! 778: static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq, ! 779: struct tcp_options *options ) { ! 780: ! 781: /* Synchronise sequence numbers on first SYN */ ! 782: if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) { ! 783: tcp->rcv_ack = seq; ! 784: if ( options->tsopt ) ! 785: tcp->flags |= TCP_TS_ENABLED; ! 786: } ! 787: ! 788: /* Ignore duplicate SYN */ ! 789: if ( seq != tcp->rcv_ack ) ! 790: return 0; ! 791: ! 792: /* Acknowledge SYN */ ! 793: tcp_rx_seq ( tcp, 1 ); ! 794: ! 795: /* Mark SYN as received and start sending ACKs with each packet */ ! 796: tcp->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) | ! 797: TCP_STATE_RCVD ( TCP_SYN ) ); ! 798: ! 799: return 0; ! 800: } ! 801: ! 802: /** ! 803: * Handle TCP received ACK ! 804: * ! 805: * @v tcp TCP connection ! 806: * @v ack ACK value (in host-endian order) ! 807: * @v win WIN value (in host-endian order) ! 808: * @ret rc Return status code ! 809: */ ! 810: static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, ! 811: uint32_t win ) { ! 812: uint32_t ack_len = ( ack - tcp->snd_seq ); ! 813: size_t len; ! 814: unsigned int acked_flags; ! 815: ! 816: /* Check for out-of-range or old duplicate ACKs */ ! 817: if ( ack_len > tcp->snd_sent ) { ! 818: DBGC ( tcp, "TCP %p received ACK for %08x..%08x, " ! 819: "sent only %08x..%08x\n", tcp, tcp->snd_seq, ! 820: ( tcp->snd_seq + ack_len ), tcp->snd_seq, ! 821: ( tcp->snd_seq + tcp->snd_sent ) ); ! 822: ! 823: if ( TCP_HAS_BEEN_ESTABLISHED ( tcp->tcp_state ) ) { ! 824: /* Just ignore what might be old duplicate ACKs */ ! 825: return 0; ! 826: } else { ! 827: /* Send RST if an out-of-range ACK is received ! 828: * on a not-yet-established connection, as per ! 829: * RFC 793. ! 830: */ ! 831: return -EINVAL; ! 832: } ! 833: } ! 834: ! 835: /* Ignore ACKs that don't actually acknowledge any new data. ! 836: * (In particular, do not stop the retransmission timer; this ! 837: * avoids creating a sorceror's apprentice syndrome when a ! 838: * duplicate ACK is received and we still have data in our ! 839: * transmit queue.) ! 840: */ ! 841: if ( ack_len == 0 ) ! 842: return 0; ! 843: ! 844: /* Stop the retransmission timer */ ! 845: stop_timer ( &tcp->timer ); ! 846: ! 847: /* Determine acknowledged flags and data length */ ! 848: len = ack_len; ! 849: acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) & ! 850: ( TCP_SYN | TCP_FIN ) ); ! 851: if ( acked_flags ) ! 852: len--; ! 853: ! 854: /* Update SEQ and sent counters, and window size */ ! 855: tcp->snd_seq = ack; ! 856: tcp->snd_sent = 0; ! 857: tcp->snd_win = win; ! 858: ! 859: /* Remove any acknowledged data from transmit queue */ ! 860: tcp_process_tx_queue ( tcp, len, NULL, 1 ); ! 861: ! 862: /* Mark SYN/FIN as acknowledged if applicable. */ ! 863: if ( acked_flags ) ! 864: tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags ); ! 865: ! 866: /* Start sending FIN if we've had all possible data ACKed */ ! 867: if ( list_empty ( &tcp->tx_queue ) && ( tcp->flags & TCP_XFER_CLOSED ) ) ! 868: tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN ); ! 869: ! 870: return 0; ! 871: } ! 872: ! 873: /** ! 874: * Handle TCP received data ! 875: * ! 876: * @v tcp TCP connection ! 877: * @v seq SEQ value (in host-endian order) ! 878: * @v iobuf I/O buffer ! 879: * @ret rc Return status code ! 880: * ! 881: * This function takes ownership of the I/O buffer. ! 882: */ ! 883: static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq, ! 884: struct io_buffer *iobuf ) { ! 885: uint32_t already_rcvd; ! 886: uint32_t len; ! 887: int rc; ! 888: ! 889: /* Ignore duplicate or out-of-order data */ ! 890: already_rcvd = ( tcp->rcv_ack - seq ); ! 891: len = iob_len ( iobuf ); ! 892: if ( already_rcvd >= len ) { ! 893: free_iob ( iobuf ); ! 894: return 0; ! 895: } ! 896: iob_pull ( iobuf, already_rcvd ); ! 897: len -= already_rcvd; ! 898: ! 899: /* Acknowledge new data */ ! 900: tcp_rx_seq ( tcp, len ); ! 901: ! 902: /* Deliver data to application */ ! 903: if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) { ! 904: DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n", ! 905: tcp, seq, ( seq + len ), strerror ( rc ) ); ! 906: return rc; ! 907: } ! 908: ! 909: return 0; ! 910: } ! 911: ! 912: /** ! 913: * Handle TCP received FIN ! 914: * ! 915: * @v tcp TCP connection ! 916: * @v seq SEQ value (in host-endian order) ! 917: * @ret rc Return status code ! 918: */ ! 919: static int tcp_rx_fin ( struct tcp_connection *tcp, uint32_t seq ) { ! 920: ! 921: /* Ignore duplicate or out-of-order FIN */ ! 922: if ( seq != tcp->rcv_ack ) ! 923: return 0; ! 924: ! 925: /* Acknowledge FIN */ ! 926: tcp_rx_seq ( tcp, 1 ); ! 927: ! 928: /* Mark FIN as received */ ! 929: tcp->tcp_state |= TCP_STATE_RCVD ( TCP_FIN ); ! 930: ! 931: /* Close connection */ ! 932: tcp_close ( tcp, 0 ); ! 933: ! 934: return 0; ! 935: } ! 936: ! 937: /** ! 938: * Handle TCP received RST ! 939: * ! 940: * @v tcp TCP connection ! 941: * @v seq SEQ value (in host-endian order) ! 942: * @ret rc Return status code ! 943: */ ! 944: static int tcp_rx_rst ( struct tcp_connection *tcp, uint32_t seq ) { ! 945: ! 946: /* Accept RST only if it falls within the window. If we have ! 947: * not yet received a SYN, then we have no window to test ! 948: * against, so fall back to checking that our SYN has been ! 949: * ACKed. ! 950: */ ! 951: if ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) { ! 952: if ( ! tcp_in_window ( seq, tcp->rcv_ack, tcp->rcv_win ) ) ! 953: return 0; ! 954: } else { ! 955: if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) ) ! 956: return 0; ! 957: } ! 958: ! 959: /* Abort connection */ ! 960: tcp->tcp_state = TCP_CLOSED; ! 961: tcp_dump_state ( tcp ); ! 962: tcp_close ( tcp, -ECONNRESET ); ! 963: ! 964: DBGC ( tcp, "TCP %p connection reset by peer\n", tcp ); ! 965: return -ECONNRESET; ! 966: } ! 967: ! 968: /** ! 969: * Enqueue received TCP packet ! 970: * ! 971: * @v tcp TCP connection ! 972: * @v seq SEQ value (in host-endian order) ! 973: * @v flags TCP flags ! 974: * @v iobuf I/O buffer ! 975: */ ! 976: static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq, ! 977: uint8_t flags, struct io_buffer *iobuf ) { ! 978: struct tcp_rx_queued_header *tcpqhdr; ! 979: struct io_buffer *queued; ! 980: size_t len; ! 981: uint32_t seq_len; ! 982: ! 983: /* Calculate remaining flags and sequence length. Note that ! 984: * SYN, if present, has already been processed by this point. ! 985: */ ! 986: flags &= TCP_FIN; ! 987: len = iob_len ( iobuf ); ! 988: seq_len = ( len + ( flags ? 1 : 0 ) ); ! 989: ! 990: /* Discard immediately (to save memory) if: ! 991: * ! 992: * a) we have not yet received a SYN (and so have no defined ! 993: * receive window), or ! 994: * b) the packet lies entirely outside the receive window, or ! 995: * c) there is no further content to process. ! 996: */ ! 997: if ( ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) || ! 998: ( tcp_cmp ( seq, tcp->rcv_ack + tcp->rcv_win ) >= 0 ) || ! 999: ( tcp_cmp ( seq + seq_len, tcp->rcv_ack ) < 0 ) || ! 1000: ( seq_len == 0 ) ) { ! 1001: free_iob ( iobuf ); ! 1002: return; ! 1003: } ! 1004: ! 1005: /* Add internal header */ ! 1006: tcpqhdr = iob_push ( iobuf, sizeof ( *tcpqhdr ) ); ! 1007: tcpqhdr->seq = seq; ! 1008: tcpqhdr->flags = flags; ! 1009: ! 1010: /* Add to RX queue */ ! 1011: list_for_each_entry ( queued, &tcp->rx_queue, list ) { ! 1012: tcpqhdr = queued->data; ! 1013: if ( tcp_cmp ( seq, tcpqhdr->seq ) < 0 ) ! 1014: break; ! 1015: } ! 1016: list_add_tail ( &iobuf->list, &queued->list ); ! 1017: } ! 1018: ! 1019: /** ! 1020: * Process receive queue ! 1021: * ! 1022: * @v tcp TCP connection ! 1023: */ ! 1024: static void tcp_process_rx_queue ( struct tcp_connection *tcp ) { ! 1025: struct io_buffer *iobuf; ! 1026: struct tcp_rx_queued_header *tcpqhdr; ! 1027: uint32_t seq; ! 1028: unsigned int flags; ! 1029: size_t len; ! 1030: ! 1031: /* Process all applicable received buffers. Note that we ! 1032: * cannot use list_for_each_entry() to iterate over the RX ! 1033: * queue, since tcp_discard() may remove packets from the RX ! 1034: * queue while we are processing. ! 1035: */ ! 1036: while ( ( iobuf = list_first_entry ( &tcp->rx_queue, struct io_buffer, ! 1037: list ) ) ) { ! 1038: ! 1039: /* Stop processing when we hit the first gap */ ! 1040: tcpqhdr = iobuf->data; ! 1041: if ( tcp_cmp ( tcpqhdr->seq, tcp->rcv_ack ) > 0 ) ! 1042: break; ! 1043: ! 1044: /* Strip internal header and remove from RX queue */ ! 1045: list_del ( &iobuf->list ); ! 1046: seq = tcpqhdr->seq; ! 1047: flags = tcpqhdr->flags; ! 1048: iob_pull ( iobuf, sizeof ( *tcpqhdr ) ); ! 1049: len = iob_len ( iobuf ); ! 1050: ! 1051: /* Handle new data, if any */ ! 1052: tcp_rx_data ( tcp, seq, iob_disown ( iobuf ) ); ! 1053: seq += len; ! 1054: ! 1055: /* Handle FIN, if present */ ! 1056: if ( flags & TCP_FIN ) { ! 1057: tcp_rx_fin ( tcp, seq ); ! 1058: seq++; ! 1059: } ! 1060: } ! 1061: } ! 1062: ! 1063: /** ! 1064: * Process received packet ! 1065: * ! 1066: * @v iobuf I/O buffer ! 1067: * @v st_src Partially-filled source address ! 1068: * @v st_dest Partially-filled destination address ! 1069: * @v pshdr_csum Pseudo-header checksum ! 1070: * @ret rc Return status code ! 1071: */ ! 1072: static int tcp_rx ( struct io_buffer *iobuf, ! 1073: struct sockaddr_tcpip *st_src, ! 1074: struct sockaddr_tcpip *st_dest __unused, ! 1075: uint16_t pshdr_csum ) { ! 1076: struct tcp_header *tcphdr = iobuf->data; ! 1077: struct tcp_connection *tcp; ! 1078: struct tcp_options options; ! 1079: size_t hlen; ! 1080: uint16_t csum; ! 1081: uint32_t seq; ! 1082: uint32_t ack; ! 1083: uint32_t win; ! 1084: unsigned int flags; ! 1085: size_t len; ! 1086: uint32_t seq_len; ! 1087: int rc; ! 1088: ! 1089: /* Sanity check packet */ ! 1090: if ( iob_len ( iobuf ) < sizeof ( *tcphdr ) ) { ! 1091: DBG ( "TCP packet too short at %zd bytes (min %zd bytes)\n", ! 1092: iob_len ( iobuf ), sizeof ( *tcphdr ) ); ! 1093: rc = -EINVAL; ! 1094: goto discard; ! 1095: } ! 1096: hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4; ! 1097: if ( hlen < sizeof ( *tcphdr ) ) { ! 1098: DBG ( "TCP header too short at %zd bytes (min %zd bytes)\n", ! 1099: hlen, sizeof ( *tcphdr ) ); ! 1100: rc = -EINVAL; ! 1101: goto discard; ! 1102: } ! 1103: if ( hlen > iob_len ( iobuf ) ) { ! 1104: DBG ( "TCP header too long at %zd bytes (max %zd bytes)\n", ! 1105: hlen, iob_len ( iobuf ) ); ! 1106: rc = -EINVAL; ! 1107: goto discard; ! 1108: } ! 1109: csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ! 1110: iob_len ( iobuf ) ); ! 1111: if ( csum != 0 ) { ! 1112: DBG ( "TCP checksum incorrect (is %04x including checksum " ! 1113: "field, should be 0000)\n", csum ); ! 1114: rc = -EINVAL; ! 1115: goto discard; ! 1116: } ! 1117: ! 1118: /* Parse parameters from header and strip header */ ! 1119: tcp = tcp_demux ( ntohs ( tcphdr->dest ) ); ! 1120: seq = ntohl ( tcphdr->seq ); ! 1121: ack = ntohl ( tcphdr->ack ); ! 1122: win = ntohs ( tcphdr->win ); ! 1123: flags = tcphdr->flags; ! 1124: tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ), ! 1125: ( hlen - sizeof ( *tcphdr ) ), &options ); ! 1126: if ( options.tsopt ) ! 1127: tcp->ts_val = ntohl ( options.tsopt->tsval ); ! 1128: iob_pull ( iobuf, hlen ); ! 1129: len = iob_len ( iobuf ); ! 1130: seq_len = ( len + ( ( flags & TCP_SYN ) ? 1 : 0 ) + ! 1131: ( ( flags & TCP_FIN ) ? 1 : 0 ) ); ! 1132: ! 1133: /* Dump header */ ! 1134: DBGC2 ( tcp, "TCP %p RX %d<-%d %08x %08x..%08x %4zd", ! 1135: tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ), ! 1136: ntohl ( tcphdr->ack ), ntohl ( tcphdr->seq ), ! 1137: ( ntohl ( tcphdr->seq ) + seq_len ), len ); ! 1138: tcp_dump_flags ( tcp, tcphdr->flags ); ! 1139: DBGC2 ( tcp, "\n" ); ! 1140: ! 1141: /* If no connection was found, send RST */ ! 1142: if ( ! tcp ) { ! 1143: tcp_xmit_reset ( tcp, st_src, tcphdr ); ! 1144: rc = -ENOTCONN; ! 1145: goto discard; ! 1146: } ! 1147: ! 1148: /* Handle ACK, if present */ ! 1149: if ( flags & TCP_ACK ) { ! 1150: if ( ( rc = tcp_rx_ack ( tcp, ack, win ) ) != 0 ) { ! 1151: tcp_xmit_reset ( tcp, st_src, tcphdr ); ! 1152: goto discard; ! 1153: } ! 1154: } ! 1155: ! 1156: /* Force an ACK if this packet is out of order */ ! 1157: if ( ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) && ! 1158: ( seq != tcp->rcv_ack ) ) { ! 1159: tcp->flags |= TCP_ACK_PENDING; ! 1160: } ! 1161: ! 1162: /* Handle SYN, if present */ ! 1163: if ( flags & TCP_SYN ) { ! 1164: tcp_rx_syn ( tcp, seq, &options ); ! 1165: seq++; ! 1166: } ! 1167: ! 1168: /* Handle RST, if present */ ! 1169: if ( flags & TCP_RST ) { ! 1170: if ( ( rc = tcp_rx_rst ( tcp, seq ) ) != 0 ) ! 1171: goto discard; ! 1172: } ! 1173: ! 1174: /* Enqueue received data */ ! 1175: tcp_rx_enqueue ( tcp, seq, flags, iob_disown ( iobuf ) ); ! 1176: ! 1177: /* Process receive queue */ ! 1178: tcp_process_rx_queue ( tcp ); ! 1179: ! 1180: /* Dump out any state change as a result of the received packet */ ! 1181: tcp_dump_state ( tcp ); ! 1182: ! 1183: /* Send out any pending data */ ! 1184: tcp_xmit ( tcp ); ! 1185: ! 1186: /* If this packet was the last we expect to receive, set up ! 1187: * timer to expire and cause the connection to be freed. ! 1188: */ ! 1189: if ( TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) { ! 1190: stop_timer ( &tcp->wait ); ! 1191: start_timer_fixed ( &tcp->wait, ( 2 * TCP_MSL ) ); ! 1192: } ! 1193: ! 1194: return 0; ! 1195: ! 1196: discard: ! 1197: /* Free received packet */ ! 1198: free_iob ( iobuf ); ! 1199: return rc; ! 1200: } ! 1201: ! 1202: /** TCP protocol */ ! 1203: struct tcpip_protocol tcp_protocol __tcpip_protocol = { ! 1204: .name = "TCP", ! 1205: .rx = tcp_rx, ! 1206: .tcpip_proto = IP_TCP, ! 1207: }; ! 1208: ! 1209: /** ! 1210: * Discard some cached TCP data ! 1211: * ! 1212: * @ret discarded Number of cached items discarded ! 1213: */ ! 1214: static unsigned int tcp_discard ( void ) { ! 1215: struct tcp_connection *tcp; ! 1216: struct io_buffer *iobuf; ! 1217: unsigned int discarded = 0; ! 1218: ! 1219: /* Try to drop one queued RX packet from each connection */ ! 1220: list_for_each_entry ( tcp, &tcp_conns, list ) { ! 1221: list_for_each_entry_reverse ( iobuf, &tcp->rx_queue, list ) { ! 1222: list_del ( &iobuf->list ); ! 1223: free_iob ( iobuf ); ! 1224: discarded++; ! 1225: break; ! 1226: } ! 1227: } ! 1228: ! 1229: return discarded; ! 1230: } ! 1231: ! 1232: /** TCP cache discarder */ ! 1233: struct cache_discarder tcp_cache_discarder __cache_discarder = { ! 1234: .discard = tcp_discard, ! 1235: }; ! 1236: ! 1237: /*************************************************************************** ! 1238: * ! 1239: * Data transfer interface ! 1240: * ! 1241: *************************************************************************** ! 1242: */ ! 1243: ! 1244: /** ! 1245: * Close interface ! 1246: * ! 1247: * @v tcp TCP connection ! 1248: * @v rc Reason for close ! 1249: */ ! 1250: static void tcp_xfer_close ( struct tcp_connection *tcp, int rc ) { ! 1251: ! 1252: /* Close data transfer interface */ ! 1253: tcp_close ( tcp, rc ); ! 1254: ! 1255: /* Transmit FIN, if possible */ ! 1256: tcp_xmit ( tcp ); ! 1257: } ! 1258: ! 1259: /** ! 1260: * Check flow control window ! 1261: * ! 1262: * @v tcp TCP connection ! 1263: * @ret len Length of window ! 1264: */ ! 1265: static size_t tcp_xfer_window ( struct tcp_connection *tcp ) { ! 1266: ! 1267: /* Not ready if data queue is non-empty. This imposes a limit ! 1268: * of only one unACKed packet in the TX queue at any time; we ! 1269: * do this to conserve memory usage. ! 1270: */ ! 1271: if ( ! list_empty ( &tcp->tx_queue ) ) ! 1272: return 0; ! 1273: ! 1274: /* Return TCP window length */ ! 1275: return tcp_xmit_win ( tcp ); ! 1276: } ! 1277: ! 1278: /** ! 1279: * Deliver datagram as I/O buffer ! 1280: * ! 1281: * @v tcp TCP connection ! 1282: * @v iobuf Datagram I/O buffer ! 1283: * @v meta Data transfer metadata ! 1284: * @ret rc Return status code ! 1285: */ ! 1286: static int tcp_xfer_deliver ( struct tcp_connection *tcp, ! 1287: struct io_buffer *iobuf, ! 1288: struct xfer_metadata *meta __unused ) { ! 1289: ! 1290: /* Enqueue packet */ ! 1291: list_add_tail ( &iobuf->list, &tcp->tx_queue ); ! 1292: ! 1293: /* Transmit data, if possible */ ! 1294: tcp_xmit ( tcp ); ! 1295: ! 1296: return 0; ! 1297: } ! 1298: ! 1299: /** TCP data transfer interface operations */ ! 1300: static struct interface_operation tcp_xfer_operations[] = { ! 1301: INTF_OP ( xfer_deliver, struct tcp_connection *, tcp_xfer_deliver ), ! 1302: INTF_OP ( xfer_window, struct tcp_connection *, tcp_xfer_window ), ! 1303: INTF_OP ( intf_close, struct tcp_connection *, tcp_xfer_close ), ! 1304: }; ! 1305: ! 1306: /** TCP data transfer interface descriptor */ ! 1307: static struct interface_descriptor tcp_xfer_desc = ! 1308: INTF_DESC ( struct tcp_connection, xfer, tcp_xfer_operations ); ! 1309: ! 1310: /*************************************************************************** ! 1311: * ! 1312: * Openers ! 1313: * ! 1314: *************************************************************************** ! 1315: */ ! 1316: ! 1317: /** TCP socket opener */ ! 1318: struct socket_opener tcp_socket_opener __socket_opener = { ! 1319: .semantics = TCP_SOCK_STREAM, ! 1320: .family = AF_INET, ! 1321: .open = tcp_open, ! 1322: }; ! 1323: ! 1324: /** Linkage hack */ ! 1325: int tcp_sock_stream = TCP_SOCK_STREAM; ! 1326: ! 1327: /** ! 1328: * Open TCP URI ! 1329: * ! 1330: * @v xfer Data transfer interface ! 1331: * @v uri URI ! 1332: * @ret rc Return status code ! 1333: */ ! 1334: static int tcp_open_uri ( struct interface *xfer, struct uri *uri ) { ! 1335: struct sockaddr_tcpip peer; ! 1336: ! 1337: /* Sanity check */ ! 1338: if ( ! uri->host ) ! 1339: return -EINVAL; ! 1340: ! 1341: memset ( &peer, 0, sizeof ( peer ) ); ! 1342: peer.st_port = htons ( uri_port ( uri, 0 ) ); ! 1343: return xfer_open_named_socket ( xfer, SOCK_STREAM, ! 1344: ( struct sockaddr * ) &peer, ! 1345: uri->host, NULL ); ! 1346: } ! 1347: ! 1348: /** TCP URI opener */ ! 1349: struct uri_opener tcp_uri_opener __uri_opener = { ! 1350: .scheme = "tcp", ! 1351: .open = tcp_open_uri, ! 1352: }; ! 1353:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.