1 /** @file 2 TCP output process routines. 3 4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php. 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "TcpMain.h" 17 18 UINT8 mTcpOutFlag[] = { 19 0, // TCP_CLOSED 20 0, // TCP_LISTEN 21 TCP_FLG_SYN, // TCP_SYN_SENT 22 TCP_FLG_SYN | TCP_FLG_ACK, // TCP_SYN_RCVD 23 TCP_FLG_ACK, // TCP_ESTABLISHED 24 TCP_FLG_FIN | TCP_FLG_ACK, // TCP_FIN_WAIT_1 25 TCP_FLG_ACK, // TCP_FIN_WAIT_2 26 TCP_FLG_ACK | TCP_FLG_FIN, // TCP_CLOSING 27 TCP_FLG_ACK, // TCP_TIME_WAIT 28 TCP_FLG_ACK, // TCP_CLOSE_WAIT 29 TCP_FLG_FIN | TCP_FLG_ACK // TCP_LAST_ACK 30 }; 31 32 /** 33 Compute the sequence space left in the old receive window. 34 35 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 36 37 @return The sequence space left in the old receive window. 38 39 **/ 40 UINT32 41 TcpRcvWinOld ( 42 IN TCP_CB *Tcb 43 ) 44 { 45 UINT32 OldWin; 46 47 OldWin = 0; 48 49 if (TCP_SEQ_GT (Tcb->RcvWl2 + Tcb->RcvWnd, Tcb->RcvNxt)) { 50 51 OldWin = TCP_SUB_SEQ ( 52 Tcb->RcvWl2 + Tcb->RcvWnd, 53 Tcb->RcvNxt 54 ); 55 } 56 57 return OldWin; 58 } 59 60 /** 61 Compute the current receive window. 62 63 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 64 65 @return The size of the current receive window, in bytes. 66 67 **/ 68 UINT32 69 TcpRcvWinNow ( 70 IN TCP_CB *Tcb 71 ) 72 { 73 SOCKET *Sk; 74 UINT32 Win; 75 UINT32 Increase; 76 UINT32 OldWin; 77 78 Sk = Tcb->Sk; 79 ASSERT (Sk != NULL); 80 81 OldWin = TcpRcvWinOld (Tcb); 82 83 Win = SockGetFreeSpace (Sk, SOCK_RCV_BUF); 84 85 Increase = 0; 86 if (Win > OldWin) { 87 Increase = Win - OldWin; 88 } 89 90 // 91 // Receiver's SWS: don't advertise a bigger window 92 // unless it can be increased by at least one Mss or 93 // half of the receive buffer. 94 // 95 if ((Increase > Tcb->SndMss) || (2 * Increase >= GET_RCV_BUFFSIZE (Sk))) { 96 97 return Win; 98 } 99 100 return OldWin; 101 } 102 103 /** 104 Compute the value to fill in the window size field of the outgoing segment. 105 106 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 107 @param[in] Syn The flag to indicate whether the outgoing segment 108 is a SYN segment. 109 110 @return The value of the local receive window size used to fill the outgoing segment. 111 112 **/ 113 UINT16 114 TcpComputeWnd ( 115 IN OUT TCP_CB *Tcb, 116 IN BOOLEAN Syn 117 ) 118 { 119 UINT32 Wnd; 120 121 // 122 // RFC requires that initial window not be scaled 123 // 124 if (Syn) { 125 126 Wnd = GET_RCV_BUFFSIZE (Tcb->Sk); 127 } else { 128 129 Wnd = TcpRcvWinNow (Tcb); 130 131 Tcb->RcvWnd = Wnd; 132 } 133 134 Wnd = MIN (Wnd >> Tcb->RcvWndScale, 0xffff); 135 return NTOHS ((UINT16) Wnd); 136 } 137 138 /** 139 Get the maximum SndNxt. 140 141 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 142 143 @return The sequence number of the maximum SndNxt. 144 145 **/ 146 TCP_SEQNO 147 TcpGetMaxSndNxt ( 148 IN TCP_CB *Tcb 149 ) 150 { 151 LIST_ENTRY *Entry; 152 NET_BUF *Nbuf; 153 154 if (IsListEmpty (&Tcb->SndQue)) { 155 return Tcb->SndNxt; 156 } 157 158 Entry = Tcb->SndQue.BackLink; 159 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 160 161 ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf)->End, Tcb->SndNxt)); 162 return TCPSEG_NETBUF (Nbuf)->End; 163 } 164 165 /** 166 Compute how much data to send. 167 168 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 169 @param[in] Force If TRUE, to ignore the sender's SWS avoidance algorithm and send 170 out data by force. 171 172 @return The length of the data can be sent. If 0, no data can be sent. 173 174 **/ 175 UINT32 176 TcpDataToSend ( 177 IN TCP_CB *Tcb, 178 IN INTN Force 179 ) 180 { 181 SOCKET *Sk; 182 UINT32 Win; 183 UINT32 Len; 184 UINT32 Left; 185 UINT32 Limit; 186 187 Sk = Tcb->Sk; 188 ASSERT (Sk != NULL); 189 190 // 191 // TCP should NOT send data beyond the send window 192 // and congestion window. The right edge of send 193 // window is defined as SND.WL2 + SND.WND. The right 194 // edge of congestion window is defined as SND.UNA + 195 // CWND. 196 // 197 Win = 0; 198 Limit = Tcb->SndWl2 + Tcb->SndWnd; 199 200 if (TCP_SEQ_GT (Limit, Tcb->SndUna + Tcb->CWnd)) { 201 202 Limit = Tcb->SndUna + Tcb->CWnd; 203 } 204 205 if (TCP_SEQ_GT (Limit, Tcb->SndNxt)) { 206 Win = TCP_SUB_SEQ (Limit, Tcb->SndNxt); 207 } 208 209 // 210 // The data to send contains two parts: the data on the 211 // socket send queue, and the data on the TCB's send 212 // buffer. The later can be non-zero if the peer shrinks 213 // its advertised window. 214 // 215 Left = GET_SND_DATASIZE (Sk) + TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb), Tcb->SndNxt); 216 217 Len = MIN (Win, Left); 218 219 if (Len > Tcb->SndMss) { 220 Len = Tcb->SndMss; 221 } 222 223 if ((Force != 0)|| (Len == 0 && Left == 0)) { 224 return Len; 225 } 226 227 if (Len == 0 && Left != 0) { 228 goto SetPersistTimer; 229 } 230 231 // 232 // Sender's SWS avoidance: Don't send a small segment unless 233 // a)A full-sized segment can be sent, 234 // b)At least one-half of the maximum sized windows that 235 // the other end has ever advertised. 236 // c)It can send everything it has, and either it isn't 237 // expecting an ACK, or the Nagle algorithm is disabled. 238 // 239 if ((Len == Tcb->SndMss) || (2 * Len >= Tcb->SndWndMax)) { 240 241 return Len; 242 } 243 244 if ((Len == Left) && 245 ((Tcb->SndNxt == Tcb->SndUna) || TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE)) 246 ) { 247 248 return Len; 249 } 250 251 // 252 // RFC1122 suggests to set a timer when SWSA forbids TCP 253 // sending more data, and combines it with a probe timer. 254 // 255 SetPersistTimer: 256 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) { 257 258 DEBUG ( 259 (EFI_D_WARN, 260 "TcpDataToSend: enter persistent state for TCB %p\n", 261 Tcb) 262 ); 263 264 if (!Tcb->ProbeTimerOn) { 265 TcpSetProbeTimer (Tcb); 266 } 267 } 268 269 return 0; 270 } 271 272 /** 273 Build the TCP header of the TCP segment and transmit the segment by IP. 274 275 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 276 @param[in] Nbuf Pointer to the buffer containing the segment to be 277 sent out. 278 279 @retval 0 The segment was sent out successfully. 280 @retval -1 An error condition occurred. 281 282 **/ 283 INTN 284 TcpTransmitSegment ( 285 IN OUT TCP_CB *Tcb, 286 IN NET_BUF *Nbuf 287 ) 288 { 289 UINT16 Len; 290 TCP_HEAD *Head; 291 TCP_SEG *Seg; 292 BOOLEAN Syn; 293 UINT32 DataLen; 294 295 ASSERT ((Nbuf != NULL) && (Nbuf->Tcp == NULL) && (TcpVerifySegment (Nbuf) != 0)); 296 297 DataLen = Nbuf->TotalSize; 298 299 Seg = TCPSEG_NETBUF (Nbuf); 300 Syn = TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN); 301 302 if (Syn) { 303 304 Len = TcpSynBuildOption (Tcb, Nbuf); 305 } else { 306 307 Len = TcpBuildOption (Tcb, Nbuf); 308 } 309 310 ASSERT ((Len % 4 == 0) && (Len <= 40)); 311 312 Len += sizeof (TCP_HEAD); 313 314 Head = (TCP_HEAD *) NetbufAllocSpace ( 315 Nbuf, 316 sizeof (TCP_HEAD), 317 NET_BUF_HEAD 318 ); 319 320 ASSERT (Head != NULL); 321 322 Nbuf->Tcp = Head; 323 324 Head->SrcPort = Tcb->LocalEnd.Port; 325 Head->DstPort = Tcb->RemoteEnd.Port; 326 Head->Seq = NTOHL (Seg->Seq); 327 Head->Ack = NTOHL (Tcb->RcvNxt); 328 Head->HeadLen = (UINT8) (Len >> 2); 329 Head->Res = 0; 330 Head->Wnd = TcpComputeWnd (Tcb, Syn); 331 Head->Checksum = 0; 332 333 // 334 // Check whether to set the PSH flag. 335 // 336 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_PSH); 337 338 if (DataLen != 0) { 339 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_PSH) && 340 TCP_SEQ_BETWEEN (Seg->Seq, Tcb->SndPsh, Seg->End) 341 ) { 342 343 TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH); 344 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH); 345 346 } else if ((Seg->End == Tcb->SndNxt) && (GET_SND_DATASIZE (Tcb->Sk) == 0)) { 347 348 TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH); 349 } 350 } 351 352 // 353 // Check whether to set the URG flag and the urgent pointer. 354 // 355 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG); 356 357 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) && TCP_SEQ_LEQ (Seg->Seq, Tcb->SndUp)) { 358 359 TCP_SET_FLG (Seg->Flag, TCP_FLG_URG); 360 361 if (TCP_SEQ_LT (Tcb->SndUp, Seg->End)) { 362 363 Seg->Urg = (UINT16) TCP_SUB_SEQ (Tcb->SndUp, Seg->Seq); 364 } else { 365 366 Seg->Urg = (UINT16) MIN ( 367 TCP_SUB_SEQ (Tcb->SndUp, 368 Seg->Seq), 369 0xffff 370 ); 371 } 372 } 373 374 Head->Flag = Seg->Flag; 375 Head->Urg = NTOHS (Seg->Urg); 376 Head->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum); 377 378 // 379 // Update the TCP session's control information. 380 // 381 Tcb->RcvWl2 = Tcb->RcvNxt; 382 if (Syn) { 383 Tcb->RcvWnd = NTOHS (Head->Wnd); 384 } 385 386 // 387 // Clear the delayedack flag. 388 // 389 Tcb->DelayedAck = 0; 390 391 return TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion); 392 } 393 394 /** 395 Get a segment from the Tcb's SndQue. 396 397 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 398 @param[in] Seq The sequence number of the segment. 399 @param[in] Len The maximum length of the segment. 400 401 @return Pointer to the segment. If NULL, some error occurred. 402 403 **/ 404 NET_BUF * 405 TcpGetSegmentSndQue ( 406 IN TCP_CB *Tcb, 407 IN TCP_SEQNO Seq, 408 IN UINT32 Len 409 ) 410 { 411 LIST_ENTRY *Head; 412 LIST_ENTRY *Cur; 413 NET_BUF *Node; 414 TCP_SEG *Seg; 415 NET_BUF *Nbuf; 416 TCP_SEQNO End; 417 UINT8 *Data; 418 UINT8 Flag; 419 INT32 Offset; 420 INT32 CopyLen; 421 422 ASSERT ((Tcb != NULL) && TCP_SEQ_LEQ (Seq, Tcb->SndNxt) && (Len > 0)); 423 424 // 425 // Find the segment that contains the Seq. 426 // 427 Head = &Tcb->SndQue; 428 429 Node = NULL; 430 Seg = NULL; 431 432 NET_LIST_FOR_EACH (Cur, Head) { 433 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List); 434 Seg = TCPSEG_NETBUF (Node); 435 436 if (TCP_SEQ_LT (Seq, Seg->End) && TCP_SEQ_LEQ (Seg->Seq, Seq)) { 437 438 break; 439 } 440 } 441 442 if ((Cur == Head) || (Seg == NULL) || (Node == NULL)) { 443 return NULL; 444 } 445 446 // 447 // Return the buffer if it can be returned without 448 // adjustment: 449 // 450 if ((Seg->Seq == Seq) && 451 TCP_SEQ_LEQ (Seg->End, Seg->Seq + Len) && 452 !NET_BUF_SHARED (Node) 453 ) { 454 455 NET_GET_REF (Node); 456 return Node; 457 } 458 459 // 460 // Create a new buffer and copy data there. 461 // 462 Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD); 463 464 if (Nbuf == NULL) { 465 return NULL; 466 } 467 468 NetbufReserve (Nbuf, TCP_MAX_HEAD); 469 470 Flag = Seg->Flag; 471 End = Seg->End; 472 473 if (TCP_SEQ_LT (Seq + Len, Seg->End)) { 474 End = Seq + Len; 475 } 476 477 CopyLen = TCP_SUB_SEQ (End, Seq); 478 Offset = TCP_SUB_SEQ (Seq, Seg->Seq); 479 480 // 481 // If SYN is set and out of the range, clear the flag. 482 // Becuase the sequence of the first byte is SEG.SEQ+1, 483 // adjust Offset by -1. If SYN is in the range, copy 484 // one byte less. 485 // 486 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) { 487 488 if (TCP_SEQ_LT (Seg->Seq, Seq)) { 489 490 TCP_CLEAR_FLG (Flag, TCP_FLG_SYN); 491 Offset--; 492 } else { 493 494 CopyLen--; 495 } 496 } 497 498 // 499 // If FIN is set and in the range, copy one byte less, 500 // and if it is out of the range, clear the flag. 501 // 502 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) { 503 504 if (Seg->End == End) { 505 506 CopyLen--; 507 } else { 508 509 TCP_CLEAR_FLG (Flag, TCP_FLG_FIN); 510 } 511 } 512 513 ASSERT (CopyLen >= 0); 514 515 // 516 // Copy data to the segment 517 // 518 if (CopyLen != 0) { 519 Data = NetbufAllocSpace (Nbuf, CopyLen, NET_BUF_TAIL); 520 ASSERT (Data != NULL); 521 522 if ((INT32) NetbufCopy (Node, Offset, CopyLen, Data) != CopyLen) { 523 goto OnError; 524 } 525 } 526 527 CopyMem (TCPSEG_NETBUF (Nbuf), Seg, sizeof (TCP_SEG)); 528 529 TCPSEG_NETBUF (Nbuf)->Seq = Seq; 530 TCPSEG_NETBUF (Nbuf)->End = End; 531 TCPSEG_NETBUF (Nbuf)->Flag = Flag; 532 533 return Nbuf; 534 535 OnError: 536 NetbufFree (Nbuf); 537 return NULL; 538 } 539 540 /** 541 Get a segment from the Tcb's socket buffer. 542 543 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 544 @param[in] Seq The sequence number of the segment. 545 @param[in] Len The maximum length of the segment. 546 547 @return Pointer to the segment. If NULL, some error occurred. 548 549 **/ 550 NET_BUF * 551 TcpGetSegmentSock ( 552 IN TCP_CB *Tcb, 553 IN TCP_SEQNO Seq, 554 IN UINT32 Len 555 ) 556 { 557 NET_BUF *Nbuf; 558 UINT8 *Data; 559 UINT32 DataGet; 560 561 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL)); 562 563 Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD); 564 565 if (Nbuf == NULL) { 566 DEBUG ( 567 (EFI_D_ERROR, 568 "TcpGetSegmentSock: failed to allocate a netbuf for TCB %p\n", 569 Tcb) 570 ); 571 572 return NULL; 573 } 574 575 NetbufReserve (Nbuf, TCP_MAX_HEAD); 576 577 DataGet = 0; 578 579 if (Len != 0) { 580 // 581 // copy data to the segment. 582 // 583 Data = NetbufAllocSpace (Nbuf, Len, NET_BUF_TAIL); 584 ASSERT (Data != NULL); 585 586 DataGet = SockGetDataToSend (Tcb->Sk, 0, Len, Data); 587 } 588 589 NET_GET_REF (Nbuf); 590 591 TCPSEG_NETBUF (Nbuf)->Seq = Seq; 592 TCPSEG_NETBUF (Nbuf)->End = Seq + Len; 593 594 InsertTailList (&(Tcb->SndQue), &(Nbuf->List)); 595 596 if (DataGet != 0) { 597 598 SockDataSent (Tcb->Sk, DataGet); 599 } 600 601 return Nbuf; 602 } 603 604 /** 605 Get a segment starting from sequence Seq of a maximum 606 length of Len. 607 608 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 609 @param[in] Seq The sequence number of the segment. 610 @param[in] Len The maximum length of the segment. 611 612 @return Pointer to the segment. If NULL, some error occurred. 613 614 **/ 615 NET_BUF * 616 TcpGetSegment ( 617 IN TCP_CB *Tcb, 618 IN TCP_SEQNO Seq, 619 IN UINT32 Len 620 ) 621 { 622 NET_BUF *Nbuf; 623 624 ASSERT (Tcb != NULL); 625 626 // 627 // Compare the SndNxt with the max sequence number sent. 628 // 629 if ((Len != 0) && TCP_SEQ_LT (Seq, TcpGetMaxSndNxt (Tcb))) { 630 631 Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len); 632 } else { 633 634 Nbuf = TcpGetSegmentSock (Tcb, Seq, Len); 635 } 636 637 ASSERT (TcpVerifySegment (Nbuf) != 0); 638 return Nbuf; 639 } 640 641 /** 642 Retransmit the segment from sequence Seq. 643 644 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 645 @param[in] Seq The sequence number of the segment to be retransmitted. 646 647 @retval 0 Retransmission succeeded. 648 @retval -1 Error condition occurred. 649 650 **/ 651 INTN 652 TcpRetransmit ( 653 IN TCP_CB *Tcb, 654 IN TCP_SEQNO Seq 655 ) 656 { 657 NET_BUF *Nbuf; 658 UINT32 Len; 659 660 // 661 // Compute the maxium length of retransmission. It is 662 // limited by three factors: 663 // 1. Less than SndMss 664 // 2. Must in the current send window 665 // 3. Will not change the boundaries of queued segments. 666 // 667 if (TCP_SEQ_LT (Tcb->SndWl2 + Tcb->SndWnd, Seq)) { 668 DEBUG ( 669 (EFI_D_WARN, 670 "TcpRetransmit: retransmission cancelled because send window too small for TCB %p\n", 671 Tcb) 672 ); 673 674 return 0; 675 } 676 677 Len = TCP_SUB_SEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq); 678 Len = MIN (Len, Tcb->SndMss); 679 680 Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len); 681 if (Nbuf == NULL) { 682 return -1; 683 } 684 685 ASSERT (TcpVerifySegment (Nbuf) != 0); 686 687 if (TcpTransmitSegment (Tcb, Nbuf) != 0) { 688 goto OnError; 689 } 690 691 // 692 // The retransmitted buffer may be on the SndQue, 693 // trim TCP head because all the buffers on SndQue 694 // are headless. 695 // 696 ASSERT (Nbuf->Tcp != NULL); 697 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD); 698 Nbuf->Tcp = NULL; 699 700 NetbufFree (Nbuf); 701 return 0; 702 703 OnError: 704 if (Nbuf != NULL) { 705 NetbufFree (Nbuf); 706 } 707 708 return -1; 709 } 710 711 /** 712 Verify that all the segments in SndQue are in good shape. 713 714 @param[in] Head Pointer to the head node of the SndQue. 715 716 @retval 0 At least one segment is broken. 717 @retval 1 All segments in the specific queue are in good shape. 718 719 **/ 720 INTN 721 TcpCheckSndQue ( 722 IN LIST_ENTRY *Head 723 ) 724 { 725 LIST_ENTRY *Entry; 726 NET_BUF *Nbuf; 727 TCP_SEQNO Seq; 728 729 if (IsListEmpty (Head)) { 730 return 1; 731 } 732 // 733 // Initialize the Seq. 734 // 735 Entry = Head->ForwardLink; 736 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 737 Seq = TCPSEG_NETBUF (Nbuf)->Seq; 738 739 NET_LIST_FOR_EACH (Entry, Head) { 740 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 741 742 if (TcpVerifySegment (Nbuf) == 0) { 743 return 0; 744 } 745 746 // 747 // All the node in the SndQue should has: 748 // SEG.SEQ = LAST_SEG.END 749 // 750 if (Seq != TCPSEG_NETBUF (Nbuf)->Seq) { 751 return 0; 752 } 753 754 Seq = TCPSEG_NETBUF (Nbuf)->End; 755 } 756 757 return 1; 758 } 759 760 /** 761 Check whether to send data/SYN/FIN and piggyback an ACK. 762 763 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 764 @param[in] Force If TRUE, ignore the sender's SWS avoidance algorithm 765 and send out data by force. 766 767 @return The number of bytes sent. 768 769 **/ 770 INTN 771 TcpToSendData ( 772 IN OUT TCP_CB *Tcb, 773 IN INTN Force 774 ) 775 { 776 UINT32 Len; 777 INTN Sent; 778 UINT8 Flag; 779 NET_BUF *Nbuf; 780 TCP_SEG *Seg; 781 TCP_SEQNO Seq; 782 TCP_SEQNO End; 783 784 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL) && (Tcb->State != TCP_LISTEN)); 785 786 Sent = 0; 787 788 if ((Tcb->State == TCP_CLOSED) || TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT)) { 789 790 return 0; 791 } 792 793 do { 794 // 795 // Compute how much data can be sent 796 // 797 Len = TcpDataToSend (Tcb, Force); 798 Seq = Tcb->SndNxt; 799 800 ASSERT ((Tcb->State) < (ARRAY_SIZE (mTcpOutFlag))); 801 Flag = mTcpOutFlag[Tcb->State]; 802 803 if ((Flag & TCP_FLG_SYN) != 0) { 804 805 Seq = Tcb->Iss; 806 Len = 0; 807 } 808 809 // 810 // Only send a segment without data if SYN or 811 // FIN is set. 812 // 813 if ((Len == 0) && ((Flag & (TCP_FLG_SYN | TCP_FLG_FIN)) == 0)) { 814 return Sent; 815 } 816 817 Nbuf = TcpGetSegment (Tcb, Seq, Len); 818 819 if (Nbuf == NULL) { 820 DEBUG ( 821 (EFI_D_ERROR, 822 "TcpToSendData: failed to get a segment for TCB %p\n", 823 Tcb) 824 ); 825 826 goto OnError; 827 } 828 829 Seg = TCPSEG_NETBUF (Nbuf); 830 831 // 832 // Set the TcpSeg in Nbuf. 833 // 834 Len = Nbuf->TotalSize; 835 End = Seq + Len; 836 if (TCP_FLG_ON (Flag, TCP_FLG_SYN)) { 837 End++; 838 } 839 840 if ((Flag & TCP_FLG_FIN) != 0) { 841 // 842 // Send FIN if all data is sent, and FIN is 843 // in the window 844 // 845 if ((TcpGetMaxSndNxt (Tcb) == Tcb->SndNxt) && 846 (GET_SND_DATASIZE (Tcb->Sk) == 0) && 847 TCP_SEQ_LT (End + 1, Tcb->SndWnd + Tcb->SndWl2) 848 ) { 849 DEBUG ( 850 (EFI_D_NET, 851 "TcpToSendData: send FIN to peer for TCB %p in state %s\n", 852 Tcb, 853 mTcpStateName[Tcb->State]) 854 ); 855 856 End++; 857 } else { 858 TCP_CLEAR_FLG (Flag, TCP_FLG_FIN); 859 } 860 } 861 862 Seg->Seq = Seq; 863 Seg->End = End; 864 Seg->Flag = Flag; 865 866 ASSERT (TcpVerifySegment (Nbuf) != 0); 867 ASSERT (TcpCheckSndQue (&Tcb->SndQue) != 0); 868 869 // 870 // Don't send an empty segment here. 871 // 872 if (Seg->End == Seg->Seq) { 873 DEBUG ( 874 (EFI_D_WARN, 875 "TcpToSendData: created a empty segment for TCB %p, free it now\n", 876 Tcb) 877 ); 878 879 NetbufFree (Nbuf); 880 return Sent; 881 } 882 883 if (TcpTransmitSegment (Tcb, Nbuf) != 0) { 884 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD); 885 Nbuf->Tcp = NULL; 886 887 if ((Flag & TCP_FLG_FIN) != 0) { 888 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT); 889 } 890 891 goto OnError; 892 } 893 894 Sent += TCP_SUB_SEQ (End, Seq); 895 896 // 897 // All the buffers in the SndQue are headless. 898 // 899 ASSERT (Nbuf->Tcp != NULL); 900 901 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD); 902 Nbuf->Tcp = NULL; 903 904 NetbufFree (Nbuf); 905 906 // 907 // Update the status in TCB. 908 // 909 Tcb->DelayedAck = 0; 910 911 if ((Flag & TCP_FLG_FIN) != 0) { 912 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT); 913 } 914 915 if (TCP_SEQ_GT (End, Tcb->SndNxt)) { 916 Tcb->SndNxt = End; 917 } 918 919 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) { 920 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto); 921 } 922 923 // 924 // Enable RTT measurement only if not in retransmit. 925 // Karn's algorithm requires not to update RTT when in loss. 926 // 927 if ((Tcb->CongestState == TCP_CONGEST_OPEN) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) { 928 929 DEBUG ( 930 (EFI_D_NET, 931 "TcpToSendData: set RTT measure sequence %d for TCB %p\n", 932 Seq, 933 Tcb) 934 ); 935 936 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON); 937 Tcb->RttSeq = Seq; 938 Tcb->RttMeasure = 0; 939 } 940 941 } while (Len == Tcb->SndMss); 942 943 return Sent; 944 945 OnError: 946 if (Nbuf != NULL) { 947 NetbufFree (Nbuf); 948 } 949 950 return Sent; 951 } 952 953 /** 954 Send an ACK immediately. 955 956 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 957 958 **/ 959 VOID 960 TcpSendAck ( 961 IN OUT TCP_CB *Tcb 962 ) 963 { 964 NET_BUF *Nbuf; 965 TCP_SEG *Seg; 966 967 Nbuf = NetbufAlloc (TCP_MAX_HEAD); 968 969 if (Nbuf == NULL) { 970 return; 971 } 972 973 NetbufReserve (Nbuf, TCP_MAX_HEAD); 974 975 Seg = TCPSEG_NETBUF (Nbuf); 976 Seg->Seq = Tcb->SndNxt; 977 Seg->End = Tcb->SndNxt; 978 Seg->Flag = TCP_FLG_ACK; 979 980 if (TcpTransmitSegment (Tcb, Nbuf) == 0) { 981 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW); 982 Tcb->DelayedAck = 0; 983 } 984 985 NetbufFree (Nbuf); 986 } 987 988 /** 989 Send a zero probe segment. It can be used by keepalive and zero window probe. 990 991 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 992 993 @retval 0 The zero probe segment was sent out successfully. 994 @retval other An error condition occurred. 995 996 **/ 997 INTN 998 TcpSendZeroProbe ( 999 IN OUT TCP_CB *Tcb 1000 ) 1001 { 1002 NET_BUF *Nbuf; 1003 TCP_SEG *Seg; 1004 INTN Result; 1005 1006 Nbuf = NetbufAlloc (TCP_MAX_HEAD); 1007 1008 if (Nbuf == NULL) { 1009 return -1; 1010 } 1011 1012 NetbufReserve (Nbuf, TCP_MAX_HEAD); 1013 1014 // 1015 // SndNxt-1 is out of window. The peer should respond 1016 // with an ACK. 1017 // 1018 Seg = TCPSEG_NETBUF (Nbuf); 1019 Seg->Seq = Tcb->SndNxt - 1; 1020 Seg->End = Tcb->SndNxt - 1; 1021 Seg->Flag = TCP_FLG_ACK; 1022 1023 Result = TcpTransmitSegment (Tcb, Nbuf); 1024 NetbufFree (Nbuf); 1025 1026 return Result; 1027 } 1028 1029 /** 1030 Check whether to send an ACK or delayed ACK. 1031 1032 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 1033 1034 **/ 1035 VOID 1036 TcpToSendAck ( 1037 IN OUT TCP_CB *Tcb 1038 ) 1039 { 1040 UINT32 TcpNow; 1041 1042 // 1043 // Generally, TCP should send a delayed ACK unless: 1044 // 1. ACK at least every other FULL sized segment received. 1045 // 2. Packets received out of order. 1046 // 3. Receiving window is open. 1047 // 1048 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Tcb->DelayedAck >= 1)) { 1049 TcpSendAck (Tcb); 1050 return; 1051 } 1052 1053 TcpNow = TcpRcvWinNow (Tcb); 1054 1055 if (TcpNow > TcpRcvWinOld (Tcb)) { 1056 TcpSendAck (Tcb); 1057 return; 1058 } 1059 1060 DEBUG ( 1061 (EFI_D_NET, 1062 "TcpToSendAck: scheduled a delayed ACK for TCB %p\n", 1063 Tcb) 1064 ); 1065 1066 // 1067 // Schedule a delayed ACK. 1068 // 1069 Tcb->DelayedAck++; 1070 } 1071 1072 /** 1073 Send a RESET segment in response to the segment received. 1074 1075 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. May be NULL. 1076 @param[in] Head TCP header of the segment that triggers the reset. 1077 @param[in] Len Length of the segment that triggers the reset. 1078 @param[in] Local Local IP address. 1079 @param[in] Remote Remote peer's IP address. 1080 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack, 1081 IP_VERSION_6 indicates TCP is running on IP6 stack. 1082 1083 @retval 0 A reset was sent or there is no need to send it. 1084 @retval -1 No reset is sent. 1085 1086 **/ 1087 INTN 1088 TcpSendReset ( 1089 IN TCP_CB *Tcb, 1090 IN TCP_HEAD *Head, 1091 IN INT32 Len, 1092 IN EFI_IP_ADDRESS *Local, 1093 IN EFI_IP_ADDRESS *Remote, 1094 IN UINT8 Version 1095 ) 1096 { 1097 NET_BUF *Nbuf; 1098 TCP_HEAD *Nhead; 1099 UINT16 HeadSum; 1100 1101 // 1102 // Don't respond to a Reset with reset. 1103 // 1104 if ((Head->Flag & TCP_FLG_RST) != 0) { 1105 return 0; 1106 } 1107 1108 Nbuf = NetbufAlloc (TCP_MAX_HEAD); 1109 1110 if (Nbuf == NULL) { 1111 return -1; 1112 } 1113 1114 Nhead = (TCP_HEAD *) NetbufAllocSpace ( 1115 Nbuf, 1116 sizeof (TCP_HEAD), 1117 NET_BUF_TAIL 1118 ); 1119 1120 ASSERT (Nhead != NULL); 1121 1122 Nbuf->Tcp = Nhead; 1123 Nhead->Flag = TCP_FLG_RST; 1124 1125 // 1126 // Derive Seq/ACK from the segment if no TCB 1127 // is associated with it, otherwise derive from the Tcb. 1128 // 1129 if (Tcb == NULL) { 1130 1131 if (TCP_FLG_ON (Head->Flag, TCP_FLG_ACK)) { 1132 Nhead->Seq = Head->Ack; 1133 Nhead->Ack = 0; 1134 } else { 1135 Nhead->Seq = 0; 1136 TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK); 1137 Nhead->Ack = HTONL (NTOHL (Head->Seq) + Len); 1138 } 1139 } else { 1140 1141 Nhead->Seq = HTONL (Tcb->SndNxt); 1142 Nhead->Ack = HTONL (Tcb->RcvNxt); 1143 TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK); 1144 } 1145 1146 Nhead->SrcPort = Head->DstPort; 1147 Nhead->DstPort = Head->SrcPort; 1148 Nhead->HeadLen = (UINT8) (sizeof (TCP_HEAD) >> 2); 1149 Nhead->Res = 0; 1150 Nhead->Wnd = HTONS (0xFFFF); 1151 Nhead->Checksum = 0; 1152 Nhead->Urg = 0; 1153 1154 if (Version == IP_VERSION_4) { 1155 HeadSum = NetPseudoHeadChecksum (Local->Addr[0], Remote->Addr[0], 6, 0); 1156 } else { 1157 HeadSum = NetIp6PseudoHeadChecksum (&Local->v6, &Remote->v6, 6, 0); 1158 } 1159 1160 Nhead->Checksum = TcpChecksum (Nbuf, HeadSum); 1161 1162 TcpSendIpPacket (Tcb, Nbuf, Local, Remote, Version); 1163 1164 NetbufFree (Nbuf); 1165 1166 return 0; 1167 } 1168 1169 /** 1170 Verify that the segment is in good shape. 1171 1172 @param[in] Nbuf The buffer that contains the segment to be checked. 1173 1174 @retval 0 The segment is broken. 1175 @retval 1 The segment is in good shape. 1176 1177 **/ 1178 INTN 1179 TcpVerifySegment ( 1180 IN NET_BUF *Nbuf 1181 ) 1182 { 1183 TCP_HEAD *Head; 1184 TCP_SEG *Seg; 1185 UINT32 Len; 1186 1187 if (Nbuf == NULL) { 1188 return 1; 1189 } 1190 1191 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 1192 1193 Seg = TCPSEG_NETBUF (Nbuf); 1194 Len = Nbuf->TotalSize; 1195 Head = Nbuf->Tcp; 1196 1197 if (Head != NULL) { 1198 if (Head->Flag != Seg->Flag) { 1199 return 0; 1200 } 1201 1202 Len -= (Head->HeadLen << 2); 1203 } 1204 1205 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) { 1206 Len++; 1207 } 1208 1209 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) { 1210 Len++; 1211 } 1212 1213 if (Seg->Seq + Len != Seg->End) { 1214 return 0; 1215 } 1216 1217 return 1; 1218 } 1219 1220