1 /** @file
2   Tcp request dispatcher implementation.
3 
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>
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<BR>
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 "Tcp4Main.h"
17 
18 #define TCP_COMP_VAL(Min, Max, Default, Val) \
19   ((((Val) <= (Max)) && ((Val) >= (Min))) ? (Val) : (Default))
20 
21 /**
22   Add or remove a route entry in the IP route table associated with this TCP instance.
23 
24   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
25   @param  RouteInfo             Pointer to the route info to be processed.
26 
27   @retval EFI_SUCCESS           The operation completed successfully.
28   @retval EFI_NOT_STARTED       The driver instance has not been started.
29   @retval EFI_NO_MAPPING        When using the default address, configuration(DHCP,
30                                 BOOTP, RARP, etc.) is not finished yet.
31   @retval EFI_OUT_OF_RESOURCES  Could not add the entry to the routing table.
32   @retval EFI_NOT_FOUND         This route is not in the routing table
33                                 (when RouteInfo->DeleteRoute is TRUE).
34   @retval EFI_ACCESS_DENIED     The route is already defined in the routing table
35                                 (when RouteInfo->DeleteRoute is FALSE).
36 **/
37 EFI_STATUS
Tcp4Route(IN TCP_CB * Tcb,IN TCP4_ROUTE_INFO * RouteInfo)38 Tcp4Route (
39   IN TCP_CB           *Tcb,
40   IN TCP4_ROUTE_INFO  *RouteInfo
41   )
42 {
43   EFI_IP4_PROTOCOL  *Ip4;
44 
45   Ip4 = Tcb->IpInfo->Ip.Ip4;
46 
47   ASSERT (Ip4 != NULL);
48 
49   return Ip4->Routes (
50               Ip4,
51               RouteInfo->DeleteRoute,
52               RouteInfo->SubnetAddress,
53               RouteInfo->SubnetMask,
54               RouteInfo->GatewayAddress
55               );
56 
57 }
58 
59 
60 /**
61   Get the operational settings of this TCP instance.
62 
63   @param  Tcb                    Pointer to the TCP_CB of this TCP instance.
64   @param  Mode                   Pointer to the buffer to store the operational
65                                  settings.
66 
67   @retval EFI_SUCCESS            The mode data is read.
68   @retval EFI_NOT_STARTED        No configuration data is available because this
69                                  instance hasn't been started.
70 
71 **/
72 EFI_STATUS
Tcp4GetMode(IN TCP_CB * Tcb,IN OUT TCP4_MODE_DATA * Mode)73 Tcp4GetMode (
74   IN     TCP_CB         *Tcb,
75   IN OUT TCP4_MODE_DATA *Mode
76   )
77 {
78   SOCKET                *Sock;
79   EFI_TCP4_CONFIG_DATA  *ConfigData;
80   EFI_TCP4_ACCESS_POINT *AccessPoint;
81   EFI_TCP4_OPTION       *Option;
82   EFI_IP4_PROTOCOL      *Ip;
83 
84   Sock = Tcb->Sk;
85 
86   if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {
87     return EFI_NOT_STARTED;
88   }
89 
90   if (Mode->Tcp4State != NULL) {
91     *(Mode->Tcp4State) = (EFI_TCP4_CONNECTION_STATE) Tcb->State;
92   }
93 
94   if (Mode->Tcp4ConfigData != NULL) {
95 
96     ConfigData                      = Mode->Tcp4ConfigData;
97     AccessPoint                     = &(ConfigData->AccessPoint);
98     Option                          = ConfigData->ControlOption;
99 
100     ConfigData->TypeOfService       = Tcb->Tos;
101     ConfigData->TimeToLive          = Tcb->Ttl;
102 
103     AccessPoint->UseDefaultAddress  = Tcb->UseDefaultAddr;
104 
105     IP4_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip);
106     IP4_COPY_ADDRESS (&AccessPoint->SubnetMask, &Tcb->SubnetMask);
107     AccessPoint->StationPort        = NTOHS (Tcb->LocalEnd.Port);
108 
109     IP4_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip);
110     AccessPoint->RemotePort         = NTOHS (Tcb->RemoteEnd.Port);
111     AccessPoint->ActiveFlag         = (BOOLEAN) (Tcb->State != TCP_LISTEN);
112 
113     if (Option != NULL) {
114       Option->ReceiveBufferSize       = GET_RCV_BUFFSIZE (Tcb->Sk);
115       Option->SendBufferSize          = GET_SND_BUFFSIZE (Tcb->Sk);
116       Option->MaxSynBackLog           = GET_BACKLOG (Tcb->Sk);
117 
118       Option->ConnectionTimeout       = Tcb->ConnectTimeout / TCP_TICK_HZ;
119       Option->DataRetries             = Tcb->MaxRexmit;
120       Option->FinTimeout              = Tcb->FinWait2Timeout / TCP_TICK_HZ;
121       Option->TimeWaitTimeout         = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
122       Option->KeepAliveProbes         = Tcb->MaxKeepAlive;
123       Option->KeepAliveTime           = Tcb->KeepAliveIdle / TCP_TICK_HZ;
124       Option->KeepAliveInterval       = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
125 
126       Option->EnableNagle         = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
127       Option->EnableTimeStamp     = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
128       Option->EnableWindowScaling = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
129 
130       Option->EnableSelectiveAck      = FALSE;
131       Option->EnablePathMtuDiscovery  = FALSE;
132     }
133   }
134 
135   Ip = Tcb->IpInfo->Ip.Ip4;
136   ASSERT (Ip != NULL);
137 
138   return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
139 }
140 
141 
142 /**
143   If AP->StationPort isn't zero, check whether the access point
144   is registered, else generate a random station port for this
145   access point.
146 
147   @param  AP                     Pointer to the access point.
148 
149   @retval EFI_SUCCESS            The check is passed or the port is assigned.
150   @retval EFI_INVALID_PARAMETER  The non-zero station port is already used.
151   @retval EFI_OUT_OF_RESOURCES   No port can be allocated.
152 
153 **/
154 EFI_STATUS
Tcp4Bind(IN EFI_TCP4_ACCESS_POINT * AP)155 Tcp4Bind (
156   IN EFI_TCP4_ACCESS_POINT *AP
157   )
158 {
159   BOOLEAN Cycle;
160 
161   if (0 != AP->StationPort) {
162     //
163     // check if a same endpoint is bound
164     //
165     if (TcpFindTcbByPeer (&AP->StationAddress, AP->StationPort)) {
166 
167       return EFI_INVALID_PARAMETER;
168     }
169   } else {
170     //
171     // generate a random port
172     //
173     Cycle = FALSE;
174 
175     if (TCP4_PORT_USER_RESERVED == mTcp4RandomPort) {
176       mTcp4RandomPort = TCP4_PORT_KNOWN;
177     }
178 
179     mTcp4RandomPort++;
180 
181     while (TcpFindTcbByPeer (&AP->StationAddress, mTcp4RandomPort)) {
182 
183       mTcp4RandomPort++;
184 
185       if (mTcp4RandomPort <= TCP4_PORT_KNOWN) {
186 
187         if (Cycle) {
188           DEBUG ((EFI_D_ERROR, "Tcp4Bind: no port can be allocated "
189             "for this pcb\n"));
190 
191           return EFI_OUT_OF_RESOURCES;
192         }
193 
194         mTcp4RandomPort = TCP4_PORT_KNOWN + 1;
195 
196         Cycle = TRUE;
197       }
198 
199     }
200 
201     AP->StationPort = mTcp4RandomPort;
202   }
203 
204   return EFI_SUCCESS;
205 }
206 
207 
208 /**
209   Flush the Tcb add its associated protocols.
210 
211   @param  Tcb                    Pointer to the TCP_CB to be flushed.
212 
213 **/
214 VOID
Tcp4FlushPcb(IN TCP_CB * Tcb)215 Tcp4FlushPcb (
216   IN TCP_CB *Tcb
217   )
218 {
219   SOCKET           *Sock;
220 
221   IpIoConfigIp (Tcb->IpInfo, NULL);
222 
223   Sock     = Tcb->Sk;
224 
225   if (SOCK_IS_CONFIGURED (Sock)) {
226     RemoveEntryList (&Tcb->List);
227 
228     //
229     // Uninstall the device path protocol.
230     //
231     if (Sock->DevicePath != NULL) {
232       gBS->UninstallProtocolInterface (
233              Sock->SockHandle,
234              &gEfiDevicePathProtocolGuid,
235              Sock->DevicePath
236              );
237       FreePool (Sock->DevicePath);
238     }
239   }
240 
241   NetbufFreeList (&Tcb->SndQue);
242   NetbufFreeList (&Tcb->RcvQue);
243   Tcb->State = TCP_CLOSED;
244 }
245 
246 /**
247   Attach a Pcb to the socket.
248 
249   @param  Sk                     Pointer to the socket of this TCP instance.
250 
251   @retval EFI_SUCCESS            The operation is completed successfully.
252   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limit.
253 
254 **/
255 EFI_STATUS
Tcp4AttachPcb(IN SOCKET * Sk)256 Tcp4AttachPcb (
257   IN SOCKET  *Sk
258   )
259 {
260   TCP_CB            *Tcb;
261   TCP4_PROTO_DATA   *ProtoData;
262   IP_IO             *IpIo;
263   EFI_STATUS        Status;
264   VOID              *Ip;
265 
266   Tcb = AllocateZeroPool (sizeof (TCP_CB));
267 
268   if (Tcb == NULL) {
269 
270     DEBUG ((EFI_D_ERROR, "Tcp4ConfigurePcb: failed to allocate a TCB\n"));
271 
272     return EFI_OUT_OF_RESOURCES;
273   }
274 
275   ProtoData  = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
276   IpIo       = ProtoData->TcpService->IpIo;
277 
278   //
279   // Create an IpInfo for this Tcb.
280   //
281   Tcb->IpInfo = IpIoAddIp (IpIo);
282   if (Tcb->IpInfo == NULL) {
283 
284     FreePool (Tcb);
285     return EFI_OUT_OF_RESOURCES;
286   }
287 
288   //
289   // Open the new created IP instance BY_CHILD.
290   //
291   Status = gBS->OpenProtocol (
292                   Tcb->IpInfo->ChildHandle,
293                   &gEfiIp4ProtocolGuid,
294                   &Ip,
295                   IpIo->Image,
296                   Sk->SockHandle,
297                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
298                   );
299   if (EFI_ERROR (Status)) {
300     IpIoRemoveIp (IpIo, Tcb->IpInfo);
301     return Status;
302   }
303 
304   InitializeListHead (&Tcb->List);
305   InitializeListHead (&Tcb->SndQue);
306   InitializeListHead (&Tcb->RcvQue);
307 
308   Tcb->State        = TCP_CLOSED;
309   Tcb->Sk           = Sk;
310   ProtoData->TcpPcb = Tcb;
311 
312   return EFI_SUCCESS;
313 }
314 
315 /**
316   Detach the Pcb of the socket.
317 
318   @param  Sk                     Pointer to the socket of this TCP instance.
319 
320 **/
321 VOID
Tcp4DetachPcb(IN SOCKET * Sk)322 Tcp4DetachPcb (
323   IN SOCKET  *Sk
324   )
325 {
326   TCP4_PROTO_DATA  *ProtoData;
327   TCP_CB           *Tcb;
328 
329   ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
330   Tcb       = ProtoData->TcpPcb;
331 
332   ASSERT (Tcb != NULL);
333 
334   Tcp4FlushPcb (Tcb);
335 
336   //
337   // Close the IP protocol.
338   //
339   gBS->CloseProtocol (
340          Tcb->IpInfo->ChildHandle,
341          &gEfiIp4ProtocolGuid,
342          ProtoData->TcpService->IpIo->Image,
343          Sk->SockHandle
344          );
345 
346   IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
347 
348   FreePool (Tcb);
349 
350   ProtoData->TcpPcb = NULL;
351 }
352 
353 
354 /**
355   Configure the Pcb using CfgData.
356 
357   @param  Sk                     Pointer to the socket of this TCP instance.
358   @param  CfgData                Pointer to the TCP configuration data.
359 
360   @retval EFI_SUCCESS            The operation is completed successfully.
361   @retval EFI_INVALID_PARAMETER  A same access point has been configured in
362                                  another TCP instance.
363   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limit.
364 
365 **/
366 EFI_STATUS
Tcp4ConfigurePcb(IN SOCKET * Sk,IN EFI_TCP4_CONFIG_DATA * CfgData)367 Tcp4ConfigurePcb (
368   IN SOCKET               *Sk,
369   IN EFI_TCP4_CONFIG_DATA *CfgData
370   )
371 {
372   EFI_IP4_CONFIG_DATA IpCfgData;
373   EFI_STATUS          Status;
374   EFI_TCP4_OPTION     *Option;
375   TCP4_PROTO_DATA     *TcpProto;
376   TCP_CB              *Tcb;
377 
378   ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL));
379 
380   TcpProto = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
381   Tcb      = TcpProto->TcpPcb;
382 
383   ASSERT (Tcb != NULL);
384 
385   //
386   // Add Ip for send pkt to the peer
387   //
388   CopyMem (&IpCfgData, &mIp4IoDefaultIpConfigData, sizeof (IpCfgData));
389   IpCfgData.DefaultProtocol   = EFI_IP_PROTO_TCP;
390   IpCfgData.UseDefaultAddress = CfgData->AccessPoint.UseDefaultAddress;
391   IpCfgData.StationAddress    = CfgData->AccessPoint.StationAddress;
392   IpCfgData.SubnetMask        = CfgData->AccessPoint.SubnetMask;
393   IpCfgData.ReceiveTimeout    = (UINT32) (-1);
394 
395   //
396   // Configure the IP instance this Tcb consumes.
397   //
398   Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
399   if (EFI_ERROR (Status)) {
400     goto OnExit;
401   }
402 
403   //
404   // Get the default address info if the instance is configured to use default address.
405   //
406   if (CfgData->AccessPoint.UseDefaultAddress) {
407     CfgData->AccessPoint.StationAddress = IpCfgData.StationAddress;
408     CfgData->AccessPoint.SubnetMask     = IpCfgData.SubnetMask;
409   }
410 
411   //
412   // check if we can bind this endpoint in CfgData
413   //
414   Status = Tcp4Bind (&(CfgData->AccessPoint));
415 
416   if (EFI_ERROR (Status)) {
417     DEBUG ((EFI_D_ERROR, "Tcp4ConfigurePcb: Bind endpoint failed "
418       "with %r\n", Status));
419 
420     goto OnExit;
421   }
422 
423   //
424   // Initalize the operating information in this Tcb
425   //
426   ASSERT (Tcb->State == TCP_CLOSED &&
427     IsListEmpty (&Tcb->SndQue) &&
428     IsListEmpty (&Tcb->RcvQue));
429 
430   TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
431   Tcb->State            = TCP_CLOSED;
432 
433   Tcb->SndMss           = 536;
434   Tcb->RcvMss           = TcpGetRcvMss (Sk);
435 
436   Tcb->SRtt             = 0;
437   Tcb->Rto              = 3 * TCP_TICK_HZ;
438 
439   Tcb->CWnd             = Tcb->SndMss;
440   Tcb->Ssthresh         = 0xffffffff;
441 
442   Tcb->CongestState     = TCP_CONGEST_OPEN;
443 
444   Tcb->KeepAliveIdle    = TCP_KEEPALIVE_IDLE_MIN;
445   Tcb->KeepAlivePeriod  = TCP_KEEPALIVE_PERIOD;
446   Tcb->MaxKeepAlive     = TCP_MAX_KEEPALIVE;
447   Tcb->MaxRexmit        = TCP_MAX_LOSS;
448   Tcb->FinWait2Timeout  = TCP_FIN_WAIT2_TIME;
449   Tcb->TimeWaitTimeout  = TCP_TIME_WAIT_TIME;
450   Tcb->ConnectTimeout   = TCP_CONNECT_TIME;
451 
452   //
453   // initialize Tcb in the light of CfgData
454   //
455   Tcb->Ttl            = CfgData->TimeToLive;
456   Tcb->Tos            = CfgData->TypeOfService;
457 
458   Tcb->UseDefaultAddr = CfgData->AccessPoint.UseDefaultAddress;
459 
460   CopyMem (&Tcb->LocalEnd.Ip, &CfgData->AccessPoint.StationAddress, sizeof (IP4_ADDR));
461   Tcb->LocalEnd.Port  = HTONS (CfgData->AccessPoint.StationPort);
462   IP4_COPY_ADDRESS (&Tcb->SubnetMask, &CfgData->AccessPoint.SubnetMask);
463 
464   if (CfgData->AccessPoint.ActiveFlag) {
465     CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
466     Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort);
467   } else {
468     Tcb->RemoteEnd.Ip   = 0;
469     Tcb->RemoteEnd.Port = 0;
470   }
471 
472   Option              = CfgData->ControlOption;
473 
474   if (Option != NULL) {
475     SET_RCV_BUFFSIZE (
476       Sk,
477       (UINT32) (TCP_COMP_VAL (
478                   TCP_RCV_BUF_SIZE_MIN,
479                   TCP_RCV_BUF_SIZE,
480                   TCP_RCV_BUF_SIZE,
481                   Option->ReceiveBufferSize
482                   )
483                )
484       );
485     SET_SND_BUFFSIZE (
486       Sk,
487       (UINT32) (TCP_COMP_VAL (
488                   TCP_SND_BUF_SIZE_MIN,
489                   TCP_SND_BUF_SIZE,
490                   TCP_SND_BUF_SIZE,
491                   Option->SendBufferSize
492                   )
493                )
494       );
495 
496     SET_BACKLOG (
497       Sk,
498       (UINT32) (TCP_COMP_VAL (
499                   TCP_BACKLOG_MIN,
500                   TCP_BACKLOG,
501                   TCP_BACKLOG,
502                   Option->MaxSynBackLog
503                   )
504                )
505       );
506 
507     Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
508                                 TCP_MAX_LOSS_MIN,
509                                 TCP_MAX_LOSS,
510                                 TCP_MAX_LOSS,
511                                 Option->DataRetries
512                                 );
513     Tcb->FinWait2Timeout = TCP_COMP_VAL (
514                               TCP_FIN_WAIT2_TIME,
515                               TCP_FIN_WAIT2_TIME_MAX,
516                               TCP_FIN_WAIT2_TIME,
517                               (UINT32) (Option->FinTimeout * TCP_TICK_HZ)
518                               );
519 
520     if (Option->TimeWaitTimeout != 0) {
521       Tcb->TimeWaitTimeout = TCP_COMP_VAL (
522                                TCP_TIME_WAIT_TIME,
523                                TCP_TIME_WAIT_TIME_MAX,
524                                TCP_TIME_WAIT_TIME,
525                                (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
526                                );
527     } else {
528       Tcb->TimeWaitTimeout = 0;
529     }
530 
531     if (Option->KeepAliveProbes != 0) {
532       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
533 
534       Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
535                                     TCP_MAX_KEEPALIVE_MIN,
536                                     TCP_MAX_KEEPALIVE,
537                                     TCP_MAX_KEEPALIVE,
538                                     Option->KeepAliveProbes
539                                     );
540       Tcb->KeepAliveIdle = TCP_COMP_VAL (
541                              TCP_KEEPALIVE_IDLE_MIN,
542                              TCP_KEEPALIVE_IDLE_MAX,
543                              TCP_KEEPALIVE_IDLE_MIN,
544                              (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
545                              );
546       Tcb->KeepAlivePeriod = TCP_COMP_VAL (
547                                TCP_KEEPALIVE_PERIOD_MIN,
548                                TCP_KEEPALIVE_PERIOD,
549                                TCP_KEEPALIVE_PERIOD,
550                                (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
551                                );
552     }
553 
554     Tcb->ConnectTimeout = TCP_COMP_VAL (
555                             TCP_CONNECT_TIME_MIN,
556                             TCP_CONNECT_TIME,
557                             TCP_CONNECT_TIME,
558                             (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
559                             );
560 
561     if (!Option->EnableNagle) {
562       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
563     }
564 
565     if (!Option->EnableTimeStamp) {
566       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
567     }
568 
569     if (!Option->EnableWindowScaling) {
570       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
571     }
572   }
573 
574   //
575   // The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is
576   // determined, construct the IP device path and install it.
577   //
578   Status = TcpInstallDevicePath (Sk);
579   if (EFI_ERROR (Status)) {
580     goto OnExit;
581   }
582 
583   //
584   // update state of Tcb and socket
585   //
586   if (!CfgData->AccessPoint.ActiveFlag) {
587 
588     TcpSetState (Tcb, TCP_LISTEN);
589     SockSetState (Sk, SO_LISTENING);
590 
591     Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
592   } else {
593 
594     Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
595   }
596 
597   TcpInsertTcb (Tcb);
598 
599 OnExit:
600 
601   return Status;
602 }
603 
604 
605 /**
606   The procotol handler provided to the socket layer, used to
607   dispatch the socket level requests by calling the corresponding
608   TCP layer functions.
609 
610   @param  Sock                   Pointer to the socket of this TCP instance.
611   @param  Request                The code of this operation request.
612   @param  Data                   Pointer to the operation specific data passed in
613                                  together with the operation request.
614 
615   @retval EFI_SUCCESS            The socket request is completed successfully.
616   @retval other                  The error status returned by the corresponding TCP
617                                  layer function.
618 
619 **/
620 EFI_STATUS
Tcp4Dispatcher(IN SOCKET * Sock,IN UINT8 Request,IN VOID * Data OPTIONAL)621 Tcp4Dispatcher (
622   IN SOCKET                  *Sock,
623   IN UINT8                   Request,
624   IN VOID                    *Data    OPTIONAL
625   )
626 {
627   TCP_CB            *Tcb;
628   TCP4_PROTO_DATA   *ProtoData;
629   EFI_IP4_PROTOCOL  *Ip;
630 
631   ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
632   Tcb       = ProtoData->TcpPcb;
633 
634   switch (Request) {
635   case SOCK_POLL:
636     Ip = ProtoData->TcpService->IpIo->Ip.Ip4;
637     Ip->Poll (Ip);
638     break;
639 
640   case SOCK_CONSUMED:
641     //
642     // After user received data from socket buffer, socket will
643     // notify TCP using this message to give it a chance to send out
644     // window update information
645     //
646     ASSERT (Tcb != NULL);
647     TcpOnAppConsume (Tcb);
648     break;
649 
650   case SOCK_SND:
651 
652     ASSERT (Tcb != NULL);
653     TcpOnAppSend (Tcb);
654     break;
655 
656   case SOCK_CLOSE:
657 
658     TcpOnAppClose (Tcb);
659 
660     break;
661 
662   case SOCK_ABORT:
663 
664     TcpOnAppAbort (Tcb);
665 
666     break;
667 
668   case SOCK_SNDPUSH:
669     Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
670     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
671 
672     break;
673 
674   case SOCK_SNDURG:
675     Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
676     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
677 
678     break;
679 
680   case SOCK_CONNECT:
681 
682     TcpOnAppConnect (Tcb);
683 
684     break;
685 
686   case SOCK_ATTACH:
687 
688     return Tcp4AttachPcb (Sock);
689 
690   case SOCK_FLUSH:
691 
692     Tcp4FlushPcb (Tcb);
693 
694     break;
695 
696   case SOCK_DETACH:
697 
698     Tcp4DetachPcb (Sock);
699 
700     break;
701 
702   case SOCK_CONFIGURE:
703 
704     return Tcp4ConfigurePcb (
705             Sock,
706             (EFI_TCP4_CONFIG_DATA *) Data
707             );
708 
709   case SOCK_MODE:
710 
711     ASSERT ((Data != NULL) && (Tcb != NULL));
712 
713     return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
714 
715   case SOCK_ROUTE:
716 
717     ASSERT ((Data != NULL) && (Tcb != NULL));
718 
719     return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
720 
721   default:
722     return EFI_UNSUPPORTED;
723   }
724 
725   return EFI_SUCCESS;
726 
727 }
728