]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Output.c
add security check.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Output.c
1 /** @file
2 TCP output process routines.
3
4 Copyright (c) 2005 - 2009, 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 ASSERT (Node != NULL);
450 ASSERT (Seg != NULL);
451
452 //
453 // Return the buffer if it can be returned without
454 // adjustment:
455 //
456 if ((Seg->Seq == Seq) &&
457 TCP_SEQ_LEQ (Seg->End, Seg->Seq + Len) &&
458 !NET_BUF_SHARED (Node)) {
459
460 NET_GET_REF (Node);
461 return Node;
462 }
463
464 //
465 // Create a new buffer and copy data there.
466 //
467 Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);
468
469 if (Nbuf == NULL) {
470 return NULL;
471 }
472
473 NetbufReserve (Nbuf, TCP_MAX_HEAD);
474
475 Flag = Seg->Flag;
476 End = Seg->End;
477
478 if (TCP_SEQ_LT (Seq + Len, Seg->End)) {
479 End = Seq + Len;
480 }
481
482 CopyLen = TCP_SUB_SEQ (End, Seq);
483 Offset = TCP_SUB_SEQ (Seq, Seg->Seq);
484
485 //
486 // If SYN is set and out of the range, clear the flag.
487 // Becuase the sequence of the first byte is SEG.SEQ+1,
488 // adjust Offset by -1. If SYN is in the range, copy
489 // one byte less.
490 //
491 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
492
493 if (TCP_SEQ_LT (Seg->Seq, Seq)) {
494
495 TCP_CLEAR_FLG (Flag, TCP_FLG_SYN);
496 Offset--;
497 } else {
498
499 CopyLen--;
500 }
501 }
502
503 //
504 // If FIN is set and in the range, copy one byte less,
505 // and if it is out of the range, clear the flag.
506 //
507 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
508
509 if (Seg->End == End) {
510
511 CopyLen--;
512 } else {
513
514 TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);
515 }
516 }
517
518 ASSERT (CopyLen >= 0);
519
520 //
521 // copy data to the segment
522 //
523 if (CopyLen != 0) {
524 Data = NetbufAllocSpace (Nbuf, CopyLen, NET_BUF_TAIL);
525 ASSERT (Data != NULL);
526
527 if ((INT32) NetbufCopy (Node, Offset, CopyLen, Data) != CopyLen) {
528 goto OnError;
529 }
530 }
531
532 CopyMem (TCPSEG_NETBUF (Nbuf), Seg, sizeof (TCP_SEG));
533
534 TCPSEG_NETBUF (Nbuf)->Seq = Seq;
535 TCPSEG_NETBUF (Nbuf)->End = End;
536 TCPSEG_NETBUF (Nbuf)->Flag = Flag;
537
538 return Nbuf;
539
540 OnError:
541 NetbufFree (Nbuf);
542 return NULL;
543 }
544
545
546 /**
547 Get a segment from the Tcb's socket buffer.
548
549 @param Tcb Pointer to the TCP_CB of this TCP instance.
550 @param Seq The sequence number of the segment.
551 @param Len The maximum length of the segment.
552
553 @return Pointer to the segment, if NULL some error occurred.
554
555 **/
556 NET_BUF *
557 TcpGetSegmentSock (
558 IN TCP_CB *Tcb,
559 IN TCP_SEQNO Seq,
560 IN UINT32 Len
561 )
562 {
563 NET_BUF *Nbuf;
564 UINT8 *Data;
565 UINT32 DataGet;
566
567 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
568
569 Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);
570
571 if (Nbuf == NULL) {
572 DEBUG ((EFI_D_ERROR, "TcpGetSegmentSock: failed to allocate "
573 "a netbuf for TCB %p\n",Tcb));
574
575 return NULL;
576 }
577
578 NetbufReserve (Nbuf, TCP_MAX_HEAD);
579
580 DataGet = 0;
581
582 if (Len != 0) {
583 //
584 // copy data to the segment.
585 //
586 Data = NetbufAllocSpace (Nbuf, Len, NET_BUF_TAIL);
587 ASSERT (Data != NULL);
588
589 DataGet = SockGetDataToSend (Tcb->Sk, 0, Len, Data);
590 }
591
592 NET_GET_REF (Nbuf);
593
594 TCPSEG_NETBUF (Nbuf)->Seq = Seq;
595 TCPSEG_NETBUF (Nbuf)->End = Seq + Len;
596
597 InsertTailList (&(Tcb->SndQue), &(Nbuf->List));
598
599 if (DataGet != 0) {
600
601 SockDataSent (Tcb->Sk, DataGet);
602 }
603
604 return Nbuf;
605 }
606
607
608 /**
609 Get a segment starting from sequence Seq of a maximum
610 length of Len.
611
612 @param Tcb Pointer to the TCP_CB of this TCP instance.
613 @param Seq The sequence number of the segment.
614 @param Len The maximum length of the segment.
615
616 @return Pointer to the segment, if NULL some error occurred.
617
618 **/
619 NET_BUF *
620 TcpGetSegment (
621 IN TCP_CB *Tcb,
622 IN TCP_SEQNO Seq,
623 IN UINT32 Len
624 )
625 {
626 NET_BUF *Nbuf;
627
628 ASSERT (Tcb != NULL);
629
630 //
631 // Compare the SndNxt with the max sequence number sent.
632 //
633 if ((Len != 0) && TCP_SEQ_LT (Seq, TcpGetMaxSndNxt (Tcb))) {
634
635 Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);
636 } else {
637
638 Nbuf = TcpGetSegmentSock (Tcb, Seq, Len);
639 }
640
641 ASSERT (TcpVerifySegment (Nbuf) != 0);
642 return Nbuf;
643 }
644
645
646 /**
647 Retransmit the segment from sequence Seq.
648
649 @param Tcb Pointer to the TCP_CB of this TCP instance.
650 @param Seq The sequence number of the segment to be retransmitted.
651
652 @retval 0 Retransmission succeeded.
653 @retval -1 Error condition occurred.
654
655 **/
656 INTN
657 TcpRetransmit (
658 IN TCP_CB *Tcb,
659 IN TCP_SEQNO Seq
660 )
661 {
662 NET_BUF *Nbuf;
663 UINT32 Len;
664
665 //
666 // Compute the maxium length of retransmission. It is
667 // limited by three factors:
668 // 1. Less than SndMss
669 // 2. must in the current send window
670 // 3. will not change the boundaries of queued segments.
671 //
672 if (TCP_SEQ_LT (Tcb->SndWl2 + Tcb->SndWnd, Seq)) {
673 DEBUG ((EFI_D_WARN, "TcpRetransmit: retransmission cancelled "
674 "because send window too small for TCB %p\n", Tcb));
675
676 return 0;
677 }
678
679 Len = TCP_SUB_SEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq);
680 Len = MIN (Len, Tcb->SndMss);
681
682 Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);
683 if (Nbuf == NULL) {
684 return -1;
685 }
686
687 ASSERT (TcpVerifySegment (Nbuf) != 0);
688
689 if (TcpTransmitSegment (Tcb, Nbuf) != 0) {
690 goto OnError;
691 }
692
693 //
694 // The retransmitted buffer may be on the SndQue,
695 // trim TCP head because all the buffer on SndQue
696 // are headless.
697 //
698 ASSERT (Nbuf->Tcp != NULL);
699 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
700 Nbuf->Tcp = NULL;
701
702 NetbufFree (Nbuf);
703 return 0;
704
705 OnError:
706 if (Nbuf != NULL) {
707 NetbufFree (Nbuf);
708 }
709
710 return -1;
711 }
712
713
714 /**
715 Check whether to send data/SYN/FIN and piggy back an ACK.
716
717 @param Tcb Pointer to the TCP_CB of this TCP instance.
718 @param Force Whether to ignore the sender's SWS avoidance algorithm and send
719 out data by force.
720
721 @return The number of bytes sent.
722
723 **/
724 INTN
725 TcpToSendData (
726 IN OUT TCP_CB *Tcb,
727 IN INTN Force
728 )
729 {
730 UINT32 Len;
731 INTN Sent;
732 UINT8 Flag;
733 NET_BUF *Nbuf;
734 TCP_SEG *Seg;
735 TCP_SEQNO Seq;
736 TCP_SEQNO End;
737
738 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL) && (Tcb->State != TCP_LISTEN));
739
740 Sent = 0;
741
742 if ((Tcb->State == TCP_CLOSED) ||
743 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT)) {
744
745 return 0;
746 }
747
748 SEND_AGAIN:
749 //
750 // compute how much data can be sent
751 //
752 Len = TcpDataToSend (Tcb, Force);
753 Seq = Tcb->SndNxt;
754
755 ASSERT ((Tcb->State) < (sizeof (mTcpOutFlag) / sizeof (mTcpOutFlag[0])));
756 Flag = mTcpOutFlag[Tcb->State];
757
758 if ((Flag & TCP_FLG_SYN) != 0) {
759
760 Seq = Tcb->Iss;
761 Len = 0;
762 }
763
764 //
765 // only send a segment without data if SYN or
766 // FIN is set.
767 //
768 if ((Len == 0) &&
769 ((Flag & (TCP_FLG_SYN | TCP_FLG_FIN)) == 0)) {
770 return Sent;
771 }
772
773 Nbuf = TcpGetSegment (Tcb, Seq, Len);
774
775 if (Nbuf == NULL) {
776 DEBUG (
777 (EFI_D_ERROR,
778 "TcpToSendData: failed to get a segment for TCB %p\n",
779 Tcb)
780 );
781
782 goto OnError;
783 }
784
785 Seg = TCPSEG_NETBUF (Nbuf);
786
787 //
788 // Set the TcpSeg in Nbuf.
789 //
790 Len = Nbuf->TotalSize;
791 End = Seq + Len;
792 if (TCP_FLG_ON (Flag, TCP_FLG_SYN)) {
793 End++;
794 }
795
796 if ((Flag & TCP_FLG_FIN) != 0) {
797 //
798 // Send FIN if all data is sent, and FIN is
799 // in the window
800 //
801 if ((TcpGetMaxSndNxt (Tcb) == Tcb->SndNxt) &&
802 (GET_SND_DATASIZE (Tcb->Sk) == 0) &&
803 TCP_SEQ_LT (End + 1, Tcb->SndWnd + Tcb->SndWl2)) {
804
805 DEBUG (
806 (EFI_D_INFO,
807 "TcpToSendData: send FIN "
808 "to peer for TCB %p in state %s\n",
809 Tcb,
810 mTcpStateName[Tcb->State])
811 );
812
813 End++;
814 } else {
815 TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);
816 }
817 }
818
819 Seg->Seq = Seq;
820 Seg->End = End;
821 Seg->Flag = Flag;
822
823 ASSERT (TcpVerifySegment (Nbuf) != 0);
824 ASSERT (TcpCheckSndQue (&Tcb->SndQue) != 0);
825
826 //
827 // don't send an empty segment here.
828 //
829 if (Seg->End == Seg->Seq) {
830 DEBUG ((EFI_D_WARN, "TcpToSendData: created a empty"
831 " segment for TCB %p, free it now\n", Tcb));
832
833 NetbufFree (Nbuf);
834 return Sent;
835 }
836
837 if (TcpTransmitSegment (Tcb, Nbuf) != 0) {
838 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
839 Nbuf->Tcp = NULL;
840
841 if ((Flag & TCP_FLG_FIN) != 0) {
842 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);
843 }
844
845 goto OnError;
846 }
847
848 Sent += TCP_SUB_SEQ (End, Seq);
849
850 //
851 // All the buffer in the SndQue is headless
852 //
853 ASSERT (Nbuf->Tcp != NULL);
854
855 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
856 Nbuf->Tcp = NULL;
857
858 NetbufFree (Nbuf);
859
860 //
861 // update status in TCB
862 //
863 Tcb->DelayedAck = 0;
864
865 if ((Flag & TCP_FLG_FIN) != 0) {
866 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);
867 }
868
869 if (TCP_SEQ_GT (End, Tcb->SndNxt)) {
870 Tcb->SndNxt = End;
871 }
872
873 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {
874 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
875 }
876
877 //
878 // Enable RTT measurement only if not in retransmit.
879 // Karn's algorithm reqires not to update RTT when in loss.
880 //
881 if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&
882 !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
883
884 DEBUG ((EFI_D_INFO, "TcpToSendData: set RTT measure "
885 "sequence %d for TCB %p\n", Seq, Tcb));
886
887 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
888 Tcb->RttSeq = Seq;
889 Tcb->RttMeasure = 0;
890 }
891
892 if (Len == Tcb->SndMss) {
893 goto SEND_AGAIN;
894 }
895
896 return Sent;
897
898 OnError:
899 if (Nbuf != NULL) {
900 NetbufFree (Nbuf);
901 }
902
903 return Sent;
904 }
905
906
907 /**
908 Send an ACK immediately.
909
910 @param Tcb Pointer to the TCP_CB of this TCP instance.
911
912 **/
913 VOID
914 TcpSendAck (
915 IN OUT TCP_CB *Tcb
916 )
917 {
918 NET_BUF *Nbuf;
919 TCP_SEG *Seg;
920
921 Nbuf = NetbufAlloc (TCP_MAX_HEAD);
922
923 if (Nbuf == NULL) {
924 return;
925 }
926
927 NetbufReserve (Nbuf, TCP_MAX_HEAD);
928
929 Seg = TCPSEG_NETBUF (Nbuf);
930 Seg->Seq = Tcb->SndNxt;
931 Seg->End = Tcb->SndNxt;
932 Seg->Flag = TCP_FLG_ACK;
933
934 if (TcpTransmitSegment (Tcb, Nbuf) == 0) {
935 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
936 Tcb->DelayedAck = 0;
937 }
938
939 NetbufFree (Nbuf);
940 }
941
942
943 /**
944 Send a zero probe segment. It can be used by keepalive and zero window probe.
945
946 @param Tcb Pointer to the TCP_CB of this TCP instance.
947
948 @retval 0 The zero probe segment was sent out successfully.
949 @retval other Error condition occurred.
950
951 **/
952 INTN
953 TcpSendZeroProbe (
954 IN OUT TCP_CB *Tcb
955 )
956 {
957 NET_BUF *Nbuf;
958 TCP_SEG *Seg;
959 INTN Result;
960
961 Nbuf = NetbufAlloc (TCP_MAX_HEAD);
962
963 if (Nbuf == NULL) {
964 return -1;
965 }
966
967 NetbufReserve (Nbuf, TCP_MAX_HEAD);
968
969 //
970 // SndNxt-1 is out of window. The peer should respond
971 // with an ACK.
972 //
973 Seg = TCPSEG_NETBUF (Nbuf);
974 Seg->Seq = Tcb->SndNxt - 1;
975 Seg->End = Tcb->SndNxt - 1;
976 Seg->Flag = TCP_FLG_ACK;
977
978 Result = TcpTransmitSegment (Tcb, Nbuf);
979 NetbufFree (Nbuf);
980
981 return Result;
982 }
983
984
985 /**
986 Check whether to send an ACK or delayed ACK.
987
988 @param Tcb Pointer to the TCP_CB of this TCP instance.
989
990 **/
991 VOID
992 TcpToSendAck (
993 IN OUT TCP_CB *Tcb
994 )
995 {
996 UINT32 TcpNow;
997
998 TcpNow = TcpRcvWinNow (Tcb);
999 //
1000 // Generally, TCP should send a delayed ACK unless:
1001 // 1. ACK at least every other FULL sized segment received,
1002 // 2. Packets received out of order
1003 // 3. Receiving window is open
1004 //
1005 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) ||
1006 (Tcb->DelayedAck >= 1) ||
1007 (TcpNow > TcpRcvWinOld (Tcb))) {
1008 TcpSendAck (Tcb);
1009 return;
1010 }
1011
1012 DEBUG ((EFI_D_INFO, "TcpToSendAck: scheduled a delayed"
1013 " ACK for TCB %p\n", Tcb));
1014
1015 //
1016 // schedule a delayed ACK
1017 //
1018 Tcb->DelayedAck++;
1019 }
1020
1021
1022 /**
1023 Send a RESET segment in response to the segment received.
1024
1025 @param Tcb Pointer to the TCP_CB of this TCP instance, may be NULL.
1026 @param Head TCP header of the segment that triggers the reset.
1027 @param Len Length of the segment that triggers the reset.
1028 @param Local Local IP address.
1029 @param Remote Remote peer's IP address.
1030
1031 @retval 0 A reset is sent or no need to send it.
1032 @retval -1 No reset is sent.
1033
1034 **/
1035 INTN
1036 TcpSendReset (
1037 IN TCP_CB *Tcb,
1038 IN TCP_HEAD *Head,
1039 IN INT32 Len,
1040 IN UINT32 Local,
1041 IN UINT32 Remote
1042 )
1043 {
1044 NET_BUF *Nbuf;
1045 TCP_HEAD *Nhead;
1046 UINT16 HeadSum;
1047
1048 //
1049 // Don't respond to a Reset with reset
1050 //
1051 if ((Head->Flag & TCP_FLG_RST) != 0) {
1052 return 0;
1053 }
1054
1055 Nbuf = NetbufAlloc (TCP_MAX_HEAD);
1056
1057 if (Nbuf == NULL) {
1058 return -1;
1059 }
1060
1061 Nhead = (TCP_HEAD *) NetbufAllocSpace (
1062 Nbuf,
1063 sizeof (TCP_HEAD),
1064 NET_BUF_TAIL
1065 );
1066
1067 ASSERT (Nhead != NULL);
1068
1069 Nbuf->Tcp = Nhead;
1070 Nhead->Flag = TCP_FLG_RST;
1071
1072 //
1073 // Derive Seq/ACK from the segment if no TCB
1074 // associated with it, otherwise from the Tcb
1075 //
1076 if (Tcb == NULL) {
1077
1078 if (TCP_FLG_ON (Head->Flag, TCP_FLG_ACK)) {
1079 Nhead->Seq = Head->Ack;
1080 Nhead->Ack = 0;
1081 } else {
1082 Nhead->Seq = 0;
1083 TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);
1084 Nhead->Ack = HTONL (NTOHL (Head->Seq) + Len);
1085 }
1086 } else {
1087
1088 Nhead->Seq = HTONL (Tcb->SndNxt);
1089 Nhead->Ack = HTONL (Tcb->RcvNxt);
1090 TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);
1091 }
1092
1093 Nhead->SrcPort = Head->DstPort;
1094 Nhead->DstPort = Head->SrcPort;
1095 Nhead->HeadLen = (sizeof (TCP_HEAD) >> 2);
1096 Nhead->Res = 0;
1097 Nhead->Wnd = HTONS (0xFFFF);
1098 Nhead->Checksum = 0;
1099 Nhead->Urg = 0;
1100
1101 HeadSum = NetPseudoHeadChecksum (Local, Remote, 6, 0);
1102 Nhead->Checksum = TcpChecksum (Nbuf, HeadSum);
1103
1104 TcpSendIpPacket (Tcb, Nbuf, Local, Remote);
1105
1106 NetbufFree (Nbuf);
1107 return 0;
1108 }
1109
1110
1111 /**
1112 Verify that the segment is in good shape.
1113
1114 @param Nbuf Buffer that contains the segment to be checked.
1115
1116 @retval 0 The segment is broken.
1117 @retval 1 The segment is in good shape.
1118
1119 **/
1120 INTN
1121 TcpVerifySegment (
1122 IN NET_BUF *Nbuf
1123 )
1124 {
1125 TCP_HEAD *Head;
1126 TCP_SEG *Seg;
1127 UINT32 Len;
1128
1129 if (Nbuf == NULL) {
1130 return 1;
1131 }
1132
1133 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1134
1135 Seg = TCPSEG_NETBUF (Nbuf);
1136 Len = Nbuf->TotalSize;
1137 Head = Nbuf->Tcp;
1138
1139 if (Head != NULL) {
1140 if (Head->Flag != Seg->Flag) {
1141 return 0;
1142 }
1143
1144 Len -= (Head->HeadLen << 2);
1145 }
1146
1147 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
1148 Len++;
1149 }
1150
1151 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
1152 Len++;
1153 }
1154
1155 if (Seg->Seq + Len != Seg->End) {
1156 return 0;
1157 }
1158
1159 return 1;
1160 }
1161
1162
1163 /**
1164 Verify that all the segments in SndQue are in good shape.
1165
1166 @param Head Pointer to the head node of the SndQue.
1167
1168 @retval 0 At least one segment is broken.
1169 @retval 1 All segments in the specific queue are in good shape.
1170
1171 **/
1172 INTN
1173 TcpCheckSndQue (
1174 IN LIST_ENTRY *Head
1175 )
1176 {
1177 LIST_ENTRY *Entry;
1178 NET_BUF *Nbuf;
1179 TCP_SEQNO Seq;
1180
1181 if (IsListEmpty (Head)) {
1182 return 1;
1183 }
1184 //
1185 // Initialize the Seq
1186 //
1187 Entry = Head->ForwardLink;
1188 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1189 Seq = TCPSEG_NETBUF (Nbuf)->Seq;
1190
1191 NET_LIST_FOR_EACH (Entry, Head) {
1192 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1193
1194 if (TcpVerifySegment (Nbuf) == 0) {
1195 return 0;
1196 }
1197
1198 //
1199 // All the node in the SndQue should has:
1200 // SEG.SEQ = LAST_SEG.END
1201 //
1202 if (Seq != TCPSEG_NETBUF (Nbuf)->Seq) {
1203 return 0;
1204 }
1205
1206 Seq = TCPSEG_NETBUF (Nbuf)->End;
1207 }
1208
1209 return 1;
1210 }