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