1 /** @file
2   TCP output process routines.
3 
4   Copyright (c) 2009 - 2010, 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
TcpRcvWinOld(IN TCP_CB * Tcb)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
TcpRcvWinNow(IN TCP_CB * Tcb)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
TcpComputeWnd(IN OUT TCP_CB * Tcb,IN BOOLEAN Syn)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
TcpGetMaxSndNxt(IN TCP_CB * Tcb)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
TcpDataToSend(IN TCP_CB * Tcb,IN INTN Force)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
TcpTransmitSegment(IN OUT TCP_CB * Tcb,IN NET_BUF * Nbuf)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 *
TcpGetSegmentSndQue(IN TCP_CB * Tcb,IN TCP_SEQNO Seq,IN UINT32 Len)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 *
TcpGetSegmentSock(IN TCP_CB * Tcb,IN TCP_SEQNO Seq,IN UINT32 Len)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 *
TcpGetSegment(IN TCP_CB * Tcb,IN TCP_SEQNO Seq,IN UINT32 Len)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
TcpRetransmit(IN TCP_CB * Tcb,IN TCP_SEQNO Seq)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
TcpCheckSndQue(IN LIST_ENTRY * Head)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
TcpToSendData(IN OUT TCP_CB * Tcb,IN INTN Force)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) < (sizeof (mTcpOutFlag) / sizeof (mTcpOutFlag[0])));
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_INFO,
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_INFO,
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
TcpSendAck(IN OUT TCP_CB * Tcb)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
TcpSendZeroProbe(IN OUT TCP_CB * Tcb)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
TcpToSendAck(IN OUT TCP_CB * Tcb)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_INFO,
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
TcpSendReset(IN TCP_CB * Tcb,IN TCP_HEAD * Head,IN INT32 Len,IN EFI_IP_ADDRESS * Local,IN EFI_IP_ADDRESS * Remote,IN UINT8 Version)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
TcpVerifySegment(IN NET_BUF * Nbuf)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