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