1/** @file
2  Tcp request dispatcher implementation.
3
4(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php<BR>
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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**/
37EFI_STATUS
38Tcp4Route (
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**/
72EFI_STATUS
73Tcp4GetMode (
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**/
154EFI_STATUS
155Tcp4Bind (
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**/
214VOID
215Tcp4FlushPcb (
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**/
255EFI_STATUS
256Tcp4AttachPcb (
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**/
321VOID
322Tcp4DetachPcb (
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**/
366EFI_STATUS
367Tcp4ConfigurePcb (
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
599OnExit:
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**/
620EFI_STATUS
621Tcp4Dispatcher (
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