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