TcpDispatcher.c revision d551cc64cdf1f943744294819220b78a60b10822
1/** @file
2  The implementation of a dispatch routine for processing TCP requests.
3
4  Copyright (c) 2009 - 2014, 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/**
19  Add or remove a route entry in the IP route table associated with this TCP instance.
20
21  @param[in]  Tcb               Pointer to the TCP_CB of this TCP instance.
22  @param[in]  RouteInfo         Pointer to the route information to be processed.
23
24  @retval EFI_SUCCESS           The operation completed successfully.
25  @retval EFI_NOT_STARTED       The driver instance has not been started.
26  @retval EFI_NO_MAPPING        When using the default address, configuration(DHCP,
27                                BOOTP, RARP, etc.) is not finished yet.
28  @retval EFI_OUT_OF_RESOURCES  Could not add the entry to the routing table.
29  @retval EFI_NOT_FOUND         This route is not in the routing table
30                                (when RouteInfo->DeleteRoute is TRUE).
31  @retval EFI_ACCESS_DENIED     The route is already defined in the routing table
32                                (when RouteInfo->DeleteRoute is FALSE).
33**/
34EFI_STATUS
35Tcp4Route (
36  IN TCP_CB           *Tcb,
37  IN TCP4_ROUTE_INFO  *RouteInfo
38  )
39{
40  IP_IO_IP_PROTOCOL   Ip;
41
42  Ip = Tcb->IpInfo->Ip;
43
44  ASSERT (Ip.Ip4!= NULL);
45
46  return Ip.Ip4->Routes (
47                   Ip.Ip4,
48                   RouteInfo->DeleteRoute,
49                   RouteInfo->SubnetAddress,
50                   RouteInfo->SubnetMask,
51                   RouteInfo->GatewayAddress
52                   );
53
54}
55
56/**
57  Get the operational settings of this TCPv4 instance.
58
59  @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.
60  @param[in, out]  Mode          Pointer to the buffer to store the operational
61                                 settings.
62
63  @retval EFI_SUCCESS            The mode data was read.
64  @retval EFI_NOT_STARTED        No configuration data is available because this
65                                 instance hasn't been started.
66
67**/
68EFI_STATUS
69Tcp4GetMode (
70  IN     TCP_CB         *Tcb,
71  IN OUT TCP4_MODE_DATA *Mode
72  )
73{
74  SOCKET                *Sock;
75  EFI_TCP4_CONFIG_DATA  *ConfigData;
76  EFI_TCP4_ACCESS_POINT *AccessPoint;
77  EFI_TCP4_OPTION       *Option;
78  EFI_IP4_PROTOCOL      *Ip;
79
80  Sock = Tcb->Sk;
81
82  if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {
83    return EFI_NOT_STARTED;
84  }
85
86  if (Mode->Tcp4State != NULL) {
87    *(Mode->Tcp4State) = (EFI_TCP4_CONNECTION_STATE) Tcb->State;
88  }
89
90  if (Mode->Tcp4ConfigData != NULL) {
91
92    ConfigData                       = Mode->Tcp4ConfigData;
93    AccessPoint                      = &(ConfigData->AccessPoint);
94    Option                           = ConfigData->ControlOption;
95
96    ConfigData->TypeOfService        = Tcb->Tos;
97    ConfigData->TimeToLive           = Tcb->Ttl;
98
99    AccessPoint->UseDefaultAddress   = Tcb->UseDefaultAddr;
100
101    CopyMem (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
102
103    AccessPoint->SubnetMask          = Tcb->SubnetMask;
104    AccessPoint->StationPort         = NTOHS (Tcb->LocalEnd.Port);
105
106    CopyMem (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
107
108    AccessPoint->RemotePort          = NTOHS (Tcb->RemoteEnd.Port);
109    AccessPoint->ActiveFlag          = (BOOLEAN) (Tcb->State != TCP_LISTEN);
110
111    if (Option != NULL) {
112      Option->ReceiveBufferSize      = GET_RCV_BUFFSIZE (Tcb->Sk);
113      Option->SendBufferSize         = GET_SND_BUFFSIZE (Tcb->Sk);
114      Option->MaxSynBackLog          = GET_BACKLOG (Tcb->Sk);
115
116      Option->ConnectionTimeout      = Tcb->ConnectTimeout / TCP_TICK_HZ;
117      Option->DataRetries            = Tcb->MaxRexmit;
118      Option->FinTimeout             = Tcb->FinWait2Timeout / TCP_TICK_HZ;
119      Option->TimeWaitTimeout        = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
120      Option->KeepAliveProbes        = Tcb->MaxKeepAlive;
121      Option->KeepAliveTime          = Tcb->KeepAliveIdle / TCP_TICK_HZ;
122      Option->KeepAliveInterval      = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
123
124      Option->EnableNagle            = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
125      Option->EnableTimeStamp        = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
126      Option->EnableWindowScaling    = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
127
128      Option->EnableSelectiveAck     = FALSE;
129      Option->EnablePathMtuDiscovery = FALSE;
130    }
131  }
132
133  Ip = Tcb->IpInfo->Ip.Ip4;
134  ASSERT (Ip != NULL);
135
136  return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
137}
138
139/**
140  Get the operational settings of this TCPv6 instance.
141
142  @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.
143  @param[in, out]  Mode          Pointer to the buffer to store the operational
144                                 settings.
145
146  @retval EFI_SUCCESS            The mode data was read.
147  @retval EFI_NOT_STARTED        No configuration data is available because this
148                                 instance hasn't been started.
149
150**/
151EFI_STATUS
152Tcp6GetMode (
153  IN     TCP_CB         *Tcb,
154  IN OUT TCP6_MODE_DATA *Mode
155  )
156{
157  SOCKET                *Sock;
158  EFI_TCP6_CONFIG_DATA  *ConfigData;
159  EFI_TCP6_ACCESS_POINT *AccessPoint;
160  EFI_TCP6_OPTION       *Option;
161  EFI_IP6_PROTOCOL      *Ip;
162
163  Sock = Tcb->Sk;
164
165  if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp6ConfigData != NULL)) {
166    return EFI_NOT_STARTED;
167  }
168
169  if (Mode->Tcp6State != NULL) {
170    *(Mode->Tcp6State) = (EFI_TCP6_CONNECTION_STATE) (Tcb->State);
171  }
172
173  if (Mode->Tcp6ConfigData != NULL) {
174
175    ConfigData                       = Mode->Tcp6ConfigData;
176    AccessPoint                      = &(ConfigData->AccessPoint);
177    Option                           = ConfigData->ControlOption;
178
179    ConfigData->TrafficClass         = Tcb->Tos;
180    ConfigData->HopLimit             = Tcb->Ttl;
181
182    AccessPoint->StationPort         = NTOHS (Tcb->LocalEnd.Port);
183    AccessPoint->RemotePort          = NTOHS (Tcb->RemoteEnd.Port);
184    AccessPoint->ActiveFlag          = (BOOLEAN) (Tcb->State != TCP_LISTEN);
185
186    IP6_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip);
187    IP6_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip);
188
189    if (Option != NULL) {
190      Option->ReceiveBufferSize      = GET_RCV_BUFFSIZE (Tcb->Sk);
191      Option->SendBufferSize         = GET_SND_BUFFSIZE (Tcb->Sk);
192      Option->MaxSynBackLog          = GET_BACKLOG (Tcb->Sk);
193
194      Option->ConnectionTimeout      = Tcb->ConnectTimeout / TCP_TICK_HZ;
195      Option->DataRetries            = Tcb->MaxRexmit;
196      Option->FinTimeout             = Tcb->FinWait2Timeout / TCP_TICK_HZ;
197      Option->TimeWaitTimeout        = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
198      Option->KeepAliveProbes        = Tcb->MaxKeepAlive;
199      Option->KeepAliveTime          = Tcb->KeepAliveIdle / TCP_TICK_HZ;
200      Option->KeepAliveInterval      = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
201
202      Option->EnableNagle            = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
203      Option->EnableTimeStamp        = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
204      Option->EnableWindowScaling    = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
205
206      Option->EnableSelectiveAck     = FALSE;
207      Option->EnablePathMtuDiscovery = FALSE;
208    }
209  }
210
211  Ip = Tcb->IpInfo->Ip.Ip6;
212  ASSERT (Ip != NULL);
213
214  return Ip->GetModeData (Ip, Mode->Ip6ModeData, Mode->MnpConfigData, Mode->SnpModeData);
215}
216
217/**
218  If TcpAp->StationPort isn't zero, check whether the access point
219  is registered, else generate a random station port for this
220  access point.
221
222  @param[in]  TcpAp              Pointer to the access point.
223  @param[in]  IpVersion          IP_VERSION_4 or IP_VERSION_6
224
225  @retval EFI_SUCCESS            The check passed or the port is assigned.
226  @retval EFI_INVALID_PARAMETER  The non-zero station port is already used.
227  @retval EFI_OUT_OF_RESOURCES   No port can be allocated.
228
229**/
230EFI_STATUS
231TcpBind (
232  IN TCP_ACCESS_POINT  *TcpAp,
233  IN UINT8             IpVersion
234  )
235{
236  BOOLEAN         Cycle;
237  EFI_IP_ADDRESS  Local;
238  UINT16          *Port;
239  UINT16          *RandomPort;
240
241  if (IpVersion == IP_VERSION_4) {
242    CopyMem (&Local, &TcpAp->Tcp4Ap.StationAddress, sizeof (EFI_IPv4_ADDRESS));
243    Port       = &TcpAp->Tcp4Ap.StationPort;
244    RandomPort = &mTcp4RandomPort;
245  } else {
246    IP6_COPY_ADDRESS (&Local, &TcpAp->Tcp6Ap.StationAddress);
247    Port       = &TcpAp->Tcp6Ap.StationPort;
248    RandomPort = &mTcp6RandomPort;
249  }
250
251  if (0 != *Port) {
252    //
253    // Check if a same endpoing is bound.
254    //
255    if (TcpFindTcbByPeer (&Local, *Port, IpVersion)) {
256
257      return EFI_INVALID_PARAMETER;
258    }
259  } else {
260    //
261    // generate a random port
262    //
263    Cycle = FALSE;
264
265    if (TCP_PORT_USER_RESERVED == *RandomPort) {
266      *RandomPort = TCP_PORT_KNOWN;
267    }
268
269    (*RandomPort)++;
270
271    while (TcpFindTcbByPeer (&Local, *RandomPort, IpVersion)) {
272      (*RandomPort)++;
273
274      if (*RandomPort <= TCP_PORT_KNOWN) {
275        if (Cycle) {
276          DEBUG (
277            (EFI_D_ERROR,
278            "TcpBind: no port can be allocated for this pcb\n")
279            );
280          return EFI_OUT_OF_RESOURCES;
281        }
282
283        *RandomPort = TCP_PORT_KNOWN + 1;
284
285        Cycle       = TRUE;
286      }
287    }
288
289    *Port = *RandomPort;
290  }
291
292  return EFI_SUCCESS;
293}
294
295/**
296  Flush the Tcb add its associated protocols.
297
298  @param[in, out]  Tcb      Pointer to the TCP_CB to be flushed.
299
300**/
301VOID
302TcpFlushPcb (
303  IN OUT TCP_CB *Tcb
304  )
305{
306  SOCKET                    *Sock;
307  TCP_PROTO_DATA            *TcpProto;
308
309  IpIoConfigIp (Tcb->IpInfo, NULL);
310
311  Sock     = Tcb->Sk;
312  TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;
313
314  if (SOCK_IS_CONFIGURED (Sock)) {
315    RemoveEntryList (&Tcb->List);
316
317    if (Sock->DevicePath != NULL) {
318      //
319      // Uninstall the device path protocl.
320      //
321      gBS->UninstallProtocolInterface (
322             Sock->SockHandle,
323             &gEfiDevicePathProtocolGuid,
324             Sock->DevicePath
325             );
326
327      FreePool (Sock->DevicePath);
328      Sock->DevicePath = NULL;
329    }
330  }
331
332  NetbufFreeList (&Tcb->SndQue);
333  NetbufFreeList (&Tcb->RcvQue);
334  Tcb->State = TCP_CLOSED;
335  Tcb->RemoteIpZero = FALSE;
336}
337
338/**
339  Attach a Pcb to the socket.
340
341  @param[in]  Sk                 Pointer to the socket of this TCP instance.
342
343  @retval EFI_SUCCESS            The operation completed successfully.
344  @retval EFI_OUT_OF_RESOURCES   Failed due to resource limits.
345
346**/
347EFI_STATUS
348TcpAttachPcb (
349  IN SOCKET  *Sk
350  )
351{
352  TCP_CB          *Tcb;
353  TCP_PROTO_DATA  *ProtoData;
354  IP_IO           *IpIo;
355  EFI_STATUS      Status;
356  VOID            *Ip;
357  EFI_GUID        *IpProtocolGuid;
358
359  if (Sk->IpVersion == IP_VERSION_4) {
360    IpProtocolGuid = &gEfiIp4ProtocolGuid;
361  } else {
362    IpProtocolGuid = &gEfiIp6ProtocolGuid;
363  }
364
365  Tcb = AllocateZeroPool (sizeof (TCP_CB));
366
367  if (Tcb == NULL) {
368
369    DEBUG ((EFI_D_ERROR, "TcpConfigurePcb: failed to allocate a TCB\n"));
370
371    return EFI_OUT_OF_RESOURCES;
372  }
373
374  ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
375  IpIo      = ProtoData->TcpService->IpIo;
376
377  //
378  // Create an IpInfo for this Tcb.
379  //
380  Tcb->IpInfo = IpIoAddIp (IpIo);
381  if (Tcb->IpInfo == NULL) {
382
383    FreePool (Tcb);
384    return EFI_OUT_OF_RESOURCES;
385  }
386
387  //
388  // Open the new created IP instance BY_CHILD.
389  //
390  Status = gBS->OpenProtocol (
391                  Tcb->IpInfo->ChildHandle,
392                  IpProtocolGuid,
393                  &Ip,
394                  IpIo->Image,
395                  Sk->SockHandle,
396                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
397                  );
398  if (EFI_ERROR (Status)) {
399    IpIoRemoveIp (IpIo, Tcb->IpInfo);
400    return Status;
401  }
402
403  InitializeListHead (&Tcb->List);
404  InitializeListHead (&Tcb->SndQue);
405  InitializeListHead (&Tcb->RcvQue);
406
407  Tcb->State        = TCP_CLOSED;
408  Tcb->Sk           = Sk;
409  ProtoData->TcpPcb = Tcb;
410
411  return EFI_SUCCESS;
412}
413
414/**
415  Detach the Pcb of the socket.
416
417  @param[in, out]  Sk           Pointer to the socket of this TCP instance.
418
419**/
420VOID
421TcpDetachPcb (
422  IN OUT SOCKET    *Sk
423  )
424{
425  TCP_PROTO_DATA   *ProtoData;
426  TCP_CB           *Tcb;
427  EFI_GUID         *IpProtocolGuid;
428
429  if (Sk->IpVersion == IP_VERSION_4) {
430    IpProtocolGuid = &gEfiIp4ProtocolGuid;
431  } else {
432    IpProtocolGuid = &gEfiIp6ProtocolGuid;
433  }
434
435  ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
436  Tcb       = ProtoData->TcpPcb;
437
438  ASSERT (Tcb != NULL);
439
440  TcpFlushPcb (Tcb);
441
442  //
443  // Close the IP protocol.
444  //
445  gBS->CloseProtocol (
446         Tcb->IpInfo->ChildHandle,
447         IpProtocolGuid,
448         ProtoData->TcpService->IpIo->Image,
449         Sk->SockHandle
450         );
451
452  IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
453
454  FreePool (Tcb);
455
456  ProtoData->TcpPcb = NULL;
457}
458
459/**
460  Configure the Pcb using CfgData.
461
462  @param[in]  Sk                 Pointer to the socket of this TCP instance.
463  @param[in]  CfgData            Pointer to the TCP configuration data.
464
465  @retval EFI_SUCCESS            The operation completed successfully.
466  @retval EFI_INVALID_PARAMETER  A same access point has been configured in
467                                 another TCP instance.
468  @retval EFI_OUT_OF_RESOURCES   Failed due to resource limits.
469
470**/
471EFI_STATUS
472TcpConfigurePcb (
473  IN SOCKET           *Sk,
474  IN TCP_CONFIG_DATA  *CfgData
475  )
476{
477  IP_IO_IP_CONFIG_DATA IpCfgData;
478  EFI_STATUS           Status;
479  EFI_TCP4_OPTION      *Option;
480  TCP_PROTO_DATA       *TcpProto;
481  TCP_CB               *Tcb;
482  TCP_ACCESS_POINT     *TcpAp;
483
484  ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL));
485
486  TcpProto = (TCP_PROTO_DATA *) Sk->ProtoReserved;
487  Tcb      = TcpProto->TcpPcb;
488
489  ASSERT (Tcb != NULL);
490
491  if (Sk->IpVersion == IP_VERSION_4) {
492    //
493    // Add Ip for send pkt to the peer
494    //
495    CopyMem (&IpCfgData.Ip4CfgData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA));
496    IpCfgData.Ip4CfgData.DefaultProtocol    = EFI_IP_PROTO_TCP;
497    IpCfgData.Ip4CfgData.TypeOfService      = CfgData->Tcp4CfgData.TypeOfService;
498    IpCfgData.Ip4CfgData.TimeToLive         = CfgData->Tcp4CfgData.TimeToLive;
499    IpCfgData.Ip4CfgData.UseDefaultAddress  = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
500    IpCfgData.Ip4CfgData.SubnetMask         = CfgData->Tcp4CfgData.AccessPoint.SubnetMask;
501    IpCfgData.Ip4CfgData.ReceiveTimeout     = (UINT32) (-1);
502    CopyMem (
503      &IpCfgData.Ip4CfgData.StationAddress,
504      &CfgData->Tcp4CfgData.AccessPoint.StationAddress,
505      sizeof (EFI_IPv4_ADDRESS)
506      );
507
508  } else {
509    ASSERT (Sk->IpVersion == IP_VERSION_6);
510
511    CopyMem (&IpCfgData.Ip6CfgData, &mIp6IoDefaultIpConfigData, sizeof (EFI_IP6_CONFIG_DATA));
512    IpCfgData.Ip6CfgData.DefaultProtocol    = EFI_IP_PROTO_TCP;
513    IpCfgData.Ip6CfgData.TrafficClass       = CfgData->Tcp6CfgData.TrafficClass;
514    IpCfgData.Ip6CfgData.HopLimit           = CfgData->Tcp6CfgData.HopLimit;
515    IpCfgData.Ip6CfgData.ReceiveTimeout     = (UINT32) (-1);
516    IP6_COPY_ADDRESS (
517      &IpCfgData.Ip6CfgData.StationAddress,
518      &CfgData->Tcp6CfgData.AccessPoint.StationAddress
519      );
520    IP6_COPY_ADDRESS (
521      &IpCfgData.Ip6CfgData.DestinationAddress,
522      &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress
523      );
524  }
525
526  //
527  // Configure the IP instance this Tcb consumes.
528  //
529  Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
530  if (EFI_ERROR (Status)) {
531    goto OnExit;
532  }
533
534  if (Sk->IpVersion == IP_VERSION_4) {
535    //
536    // Get the default address information if the instance is configured to use default address.
537    //
538    CfgData->Tcp4CfgData.AccessPoint.StationAddress = IpCfgData.Ip4CfgData.StationAddress;
539    CfgData->Tcp4CfgData.AccessPoint.SubnetMask     = IpCfgData.Ip4CfgData.SubnetMask;
540
541    TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp4CfgData.AccessPoint;
542  } else {
543    IP6_COPY_ADDRESS (
544      &CfgData->Tcp6CfgData.AccessPoint.StationAddress,
545      &IpCfgData.Ip6CfgData.StationAddress
546      );
547
548    TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp6CfgData.AccessPoint;
549  }
550
551  //
552  // check if we can bind this endpoint in CfgData
553  //
554  Status = TcpBind (TcpAp, Sk->IpVersion);
555
556  if (EFI_ERROR (Status)) {
557    DEBUG (
558      (EFI_D_ERROR,
559      "TcpConfigurePcb: Bind endpoint failed with %r\n",
560      Status)
561      );
562
563    goto OnExit;
564  }
565
566  //
567  // Initalize the operating information in this Tcb
568  //
569  ASSERT (Tcb->State == TCP_CLOSED &&
570    IsListEmpty (&Tcb->SndQue) &&
571    IsListEmpty (&Tcb->RcvQue));
572
573  TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
574  Tcb->State            = TCP_CLOSED;
575
576  Tcb->SndMss           = 536;
577  Tcb->RcvMss           = TcpGetRcvMss (Sk);
578
579  Tcb->SRtt             = 0;
580  Tcb->Rto              = 3 * TCP_TICK_HZ;
581
582  Tcb->CWnd             = Tcb->SndMss;
583  Tcb->Ssthresh         = 0xffffffff;
584
585  Tcb->CongestState     = TCP_CONGEST_OPEN;
586
587  Tcb->KeepAliveIdle    = TCP_KEEPALIVE_IDLE_MIN;
588  Tcb->KeepAlivePeriod  = TCP_KEEPALIVE_PERIOD;
589  Tcb->MaxKeepAlive     = TCP_MAX_KEEPALIVE;
590  Tcb->MaxRexmit        = TCP_MAX_LOSS;
591  Tcb->FinWait2Timeout  = TCP_FIN_WAIT2_TIME;
592  Tcb->TimeWaitTimeout  = TCP_TIME_WAIT_TIME;
593  Tcb->ConnectTimeout   = TCP_CONNECT_TIME;
594
595  if (Sk->IpVersion == IP_VERSION_4) {
596    //
597    // initialize Tcb in the light of CfgData
598    //
599    Tcb->Ttl            = CfgData->Tcp4CfgData.TimeToLive;
600    Tcb->Tos            = CfgData->Tcp4CfgData.TypeOfService;
601
602    Tcb->UseDefaultAddr = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
603
604    CopyMem (&Tcb->LocalEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.StationAddress, sizeof (IP4_ADDR));
605    Tcb->LocalEnd.Port  = HTONS (CfgData->Tcp4CfgData.AccessPoint.StationPort);
606    Tcb->SubnetMask     = CfgData->Tcp4CfgData.AccessPoint.SubnetMask;
607
608    CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
609    Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.RemotePort);
610
611    Option              = CfgData->Tcp4CfgData.ControlOption;
612  } else {
613    Tcb->Ttl            = CfgData->Tcp6CfgData.HopLimit;
614    Tcb->Tos            = CfgData->Tcp6CfgData.TrafficClass;
615
616    IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.StationAddress);
617    Tcb->LocalEnd.Port  = HTONS (CfgData->Tcp6CfgData.AccessPoint.StationPort);
618
619    IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress);
620    Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.RemotePort);
621
622    //
623    // Type EFI_TCP4_OPTION and EFI_TCP6_OPTION are the same.
624    //
625    Option              = (EFI_TCP4_OPTION *) CfgData->Tcp6CfgData.ControlOption;
626  }
627
628  if (Option != NULL) {
629    SET_RCV_BUFFSIZE (
630      Sk,
631      (UINT32) (TCP_COMP_VAL (
632                  TCP_RCV_BUF_SIZE_MIN,
633                  TCP_RCV_BUF_SIZE,
634                  TCP_RCV_BUF_SIZE,
635                  Option->ReceiveBufferSize
636                  )
637               )
638      );
639    SET_SND_BUFFSIZE (
640      Sk,
641      (UINT32) (TCP_COMP_VAL (
642                  TCP_SND_BUF_SIZE_MIN,
643                  TCP_SND_BUF_SIZE,
644                  TCP_SND_BUF_SIZE,
645                  Option->SendBufferSize
646                  )
647               )
648      );
649
650    SET_BACKLOG (
651      Sk,
652      (UINT32) (TCP_COMP_VAL (
653                  TCP_BACKLOG_MIN,
654                  TCP_BACKLOG,
655                  TCP_BACKLOG,
656                  Option->MaxSynBackLog
657                  )
658               )
659      );
660
661    Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
662                                TCP_MAX_LOSS_MIN,
663                                TCP_MAX_LOSS,
664                                TCP_MAX_LOSS,
665                                Option->DataRetries
666                                );
667    Tcb->FinWait2Timeout = TCP_COMP_VAL (
668                              TCP_FIN_WAIT2_TIME,
669                              TCP_FIN_WAIT2_TIME_MAX,
670                              TCP_FIN_WAIT2_TIME,
671                              (UINT32) (Option->FinTimeout * TCP_TICK_HZ)
672                              );
673
674    if (Option->TimeWaitTimeout != 0) {
675      Tcb->TimeWaitTimeout = TCP_COMP_VAL (
676                               TCP_TIME_WAIT_TIME,
677                               TCP_TIME_WAIT_TIME_MAX,
678                               TCP_TIME_WAIT_TIME,
679                               (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
680                               );
681    } else {
682      Tcb->TimeWaitTimeout = 0;
683    }
684
685    if (Option->KeepAliveProbes != 0) {
686      TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
687
688      Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
689                                    TCP_MAX_KEEPALIVE_MIN,
690                                    TCP_MAX_KEEPALIVE,
691                                    TCP_MAX_KEEPALIVE,
692                                    Option->KeepAliveProbes
693                                    );
694      Tcb->KeepAliveIdle = TCP_COMP_VAL (
695                             TCP_KEEPALIVE_IDLE_MIN,
696                             TCP_KEEPALIVE_IDLE_MAX,
697                             TCP_KEEPALIVE_IDLE_MIN,
698                             (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
699                             );
700      Tcb->KeepAlivePeriod = TCP_COMP_VAL (
701                               TCP_KEEPALIVE_PERIOD_MIN,
702                               TCP_KEEPALIVE_PERIOD,
703                               TCP_KEEPALIVE_PERIOD,
704                               (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
705                               );
706    }
707
708    Tcb->ConnectTimeout = TCP_COMP_VAL (
709                            TCP_CONNECT_TIME_MIN,
710                            TCP_CONNECT_TIME,
711                            TCP_CONNECT_TIME,
712                            (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
713                            );
714
715    if (!Option->EnableNagle) {
716      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
717    }
718
719    if (!Option->EnableTimeStamp) {
720      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
721    }
722
723    if (!Option->EnableWindowScaling) {
724      TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
725    }
726  }
727
728  //
729  // The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is
730  // determined, construct the IP device path and install it.
731  //
732  Status = TcpInstallDevicePath (Sk);
733  if (EFI_ERROR (Status)) {
734    goto OnExit;
735  }
736
737  //
738  // update state of Tcb and socket
739  //
740  if (((Sk->IpVersion == IP_VERSION_4) && !CfgData->Tcp4CfgData.AccessPoint.ActiveFlag) ||
741      ((Sk->IpVersion == IP_VERSION_6) && !CfgData->Tcp6CfgData.AccessPoint.ActiveFlag)
742      ) {
743
744    TcpSetState (Tcb, TCP_LISTEN);
745    SockSetState (Sk, SO_LISTENING);
746
747    Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
748  } else {
749
750    Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
751  }
752
753  if (Sk->IpVersion == IP_VERSION_6) {
754    Tcb->Tick          = TCP6_REFRESH_NEIGHBOR_TICK;
755
756    if (NetIp6IsUnspecifiedAddr (&Tcb->RemoteEnd.Ip.v6)) {
757      Tcb->RemoteIpZero = TRUE;
758    }
759  }
760
761  TcpInsertTcb (Tcb);
762
763OnExit:
764
765  return Status;
766}
767
768/**
769  The procotol handler provided to the socket layer, which is used to
770  dispatch the socket level requests by calling the corresponding
771  TCP layer functions.
772
773  @param[in]  Sock               Pointer to the socket of this TCP instance.
774  @param[in]  Request            The code of this operation request.
775  @param[in]  Data               Pointer to the operation specific data passed in
776                                 together with the operation request. This is an
777                                 optional parameter that may be NULL.
778
779  @retval EFI_SUCCESS            The socket request completed successfully.
780  @retval other                  The error status returned by the corresponding TCP
781                                 layer function.
782
783**/
784EFI_STATUS
785TcpDispatcher (
786  IN SOCKET                  *Sock,
787  IN UINT8                   Request,
788  IN VOID                    *Data    OPTIONAL
789  )
790{
791  TCP_CB          *Tcb;
792  TCP_PROTO_DATA  *ProtoData;
793
794  ProtoData = (TCP_PROTO_DATA *) Sock->ProtoReserved;
795  Tcb       = ProtoData->TcpPcb;
796
797  switch (Request) {
798  case SOCK_POLL:
799    if (Tcb->Sk->IpVersion == IP_VERSION_4) {
800      ProtoData->TcpService->IpIo->Ip.Ip4->Poll (ProtoData->TcpService->IpIo->Ip.Ip4);
801    } else {
802      ProtoData->TcpService->IpIo->Ip.Ip6->Poll (ProtoData->TcpService->IpIo->Ip.Ip6);
803    }
804
805    break;
806
807  case SOCK_CONSUMED:
808    //
809    // After user received data from socket buffer, socket will
810    // notify TCP using this message to give it a chance to send out
811    // window update information
812    //
813    ASSERT (Tcb != NULL);
814    TcpOnAppConsume (Tcb);
815    break;
816
817  case SOCK_SND:
818
819    ASSERT (Tcb != NULL);
820    TcpOnAppSend (Tcb);
821    break;
822
823  case SOCK_CLOSE:
824
825    TcpOnAppClose (Tcb);
826
827    break;
828
829  case SOCK_ABORT:
830
831    TcpOnAppAbort (Tcb);
832
833    break;
834
835  case SOCK_SNDPUSH:
836    Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
837    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
838
839    break;
840
841  case SOCK_SNDURG:
842    Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
843    TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
844
845    break;
846
847  case SOCK_CONNECT:
848
849    TcpOnAppConnect (Tcb);
850
851    break;
852
853  case SOCK_ATTACH:
854
855    return TcpAttachPcb (Sock);
856
857    break;
858
859  case SOCK_FLUSH:
860
861    TcpFlushPcb (Tcb);
862
863    break;
864
865  case SOCK_DETACH:
866
867    TcpDetachPcb (Sock);
868
869    break;
870
871  case SOCK_CONFIGURE:
872
873    return TcpConfigurePcb (
874            Sock,
875            (TCP_CONFIG_DATA *) Data
876            );
877
878    break;
879
880  case SOCK_MODE:
881
882    ASSERT ((Data != NULL) && (Tcb != NULL));
883
884    if (Tcb->Sk->IpVersion == IP_VERSION_4) {
885
886      return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
887    } else {
888
889      return Tcp6GetMode (Tcb, (TCP6_MODE_DATA *) Data);
890    }
891
892    break;
893
894  case SOCK_ROUTE:
895
896    ASSERT ((Data != NULL) && (Tcb != NULL) && (Tcb->Sk->IpVersion == IP_VERSION_4));
897
898    return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
899
900  default:
901
902    return EFI_UNSUPPORTED;
903  }
904
905  return EFI_SUCCESS;
906}
907