1 /** @file 2 The wrap of TCP/IP Socket interface. 3 4 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "IScsiImpl.h" 16 17 /** 18 The common notify function associated with various Tcp4Io events. 19 20 @param[in] Event The event signaled. 21 @param[in] Context The context. 22 **/ 23 VOID 24 EFIAPI 25 Tcp4IoCommonNotify ( 26 IN EFI_EVENT Event, 27 IN VOID *Context 28 ) 29 { 30 *((BOOLEAN *) Context) = TRUE; 31 } 32 33 /** 34 Create a TCP socket with the specified configuration data. 35 36 @param[in] Image The handle of the driver image. 37 @param[in] Controller The handle of the controller. 38 @param[in] ConfigData The Tcp4 configuration data. 39 @param[in] Tcp4Io The Tcp4Io. 40 41 @retval EFI_SUCCESS The TCP socket is created and configured. 42 @retval Others Failed to create the TCP socket or configure it. 43 **/ 44 EFI_STATUS 45 Tcp4IoCreateSocket ( 46 IN EFI_HANDLE Image, 47 IN EFI_HANDLE Controller, 48 IN TCP4_IO_CONFIG_DATA *ConfigData, 49 IN TCP4_IO *Tcp4Io 50 ) 51 { 52 EFI_STATUS Status; 53 EFI_TCP4_PROTOCOL *Tcp4; 54 EFI_TCP4_CONFIG_DATA Tcp4ConfigData; 55 EFI_TCP4_OPTION ControlOption; 56 EFI_TCP4_ACCESS_POINT *AccessPoint; 57 58 Tcp4Io->Handle = NULL; 59 Tcp4Io->ConnToken.CompletionToken.Event = NULL; 60 Tcp4Io->TxToken.CompletionToken.Event = NULL; 61 Tcp4Io->RxToken.CompletionToken.Event = NULL; 62 Tcp4Io->CloseToken.CompletionToken.Event = NULL; 63 Tcp4 = NULL; 64 65 // 66 // Create the TCP4 child instance and get the TCP4 protocol. 67 // 68 Status = NetLibCreateServiceChild ( 69 Controller, 70 Image, 71 &gEfiTcp4ServiceBindingProtocolGuid, 72 &Tcp4Io->Handle 73 ); 74 if (EFI_ERROR (Status)) { 75 return Status; 76 } 77 78 Status = gBS->OpenProtocol ( 79 Tcp4Io->Handle, 80 &gEfiTcp4ProtocolGuid, 81 (VOID **)&Tcp4Io->Tcp4, 82 Image, 83 Controller, 84 EFI_OPEN_PROTOCOL_BY_DRIVER 85 ); 86 if (EFI_ERROR (Status)) { 87 goto ON_ERROR; 88 } 89 90 Tcp4Io->Image = Image; 91 Tcp4Io->Controller = Controller; 92 Tcp4 = Tcp4Io->Tcp4; 93 94 // 95 // Set the configuration parameters. 96 // 97 ControlOption.ReceiveBufferSize = 0x200000; 98 ControlOption.SendBufferSize = 0x200000; 99 ControlOption.MaxSynBackLog = 0; 100 ControlOption.ConnectionTimeout = 0; 101 ControlOption.DataRetries = 6; 102 ControlOption.FinTimeout = 0; 103 ControlOption.TimeWaitTimeout = 0; 104 ControlOption.KeepAliveProbes = 4; 105 ControlOption.KeepAliveTime = 0; 106 ControlOption.KeepAliveInterval = 0; 107 ControlOption.EnableNagle = FALSE; 108 ControlOption.EnableTimeStamp = FALSE; 109 ControlOption.EnableWindowScaling = TRUE; 110 ControlOption.EnableSelectiveAck = FALSE; 111 ControlOption.EnablePathMtuDiscovery = FALSE; 112 113 Tcp4ConfigData.TypeOfService = 8; 114 Tcp4ConfigData.TimeToLive = 255; 115 Tcp4ConfigData.ControlOption = &ControlOption; 116 117 AccessPoint = &Tcp4ConfigData.AccessPoint; 118 119 AccessPoint->UseDefaultAddress = FALSE; 120 AccessPoint->StationPort = 0; 121 AccessPoint->RemotePort = ConfigData->RemotePort; 122 AccessPoint->ActiveFlag = TRUE; 123 124 CopyMem (&AccessPoint->StationAddress, &ConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS)); 125 CopyMem (&AccessPoint->SubnetMask, &ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 126 CopyMem (&AccessPoint->RemoteAddress, &ConfigData->RemoteIp, sizeof (EFI_IPv4_ADDRESS)); 127 128 // 129 // Configure the TCP4 protocol. 130 // 131 Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData); 132 if (EFI_ERROR (Status)) { 133 goto ON_ERROR; 134 } 135 136 if (!EFI_IP4_EQUAL (&ConfigData->Gateway, &mZeroIp4Addr)) { 137 // 138 // the gateway is not zero, add the default route by hand 139 // 140 Status = Tcp4->Routes (Tcp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &ConfigData->Gateway); 141 if (EFI_ERROR (Status)) { 142 goto ON_ERROR; 143 } 144 } 145 // 146 // Create events for variuos asynchronous operations. 147 // 148 Status = gBS->CreateEvent ( 149 EVT_NOTIFY_SIGNAL, 150 TPL_NOTIFY, 151 Tcp4IoCommonNotify, 152 &Tcp4Io->IsConnDone, 153 &Tcp4Io->ConnToken.CompletionToken.Event 154 ); 155 if (EFI_ERROR (Status)) { 156 goto ON_ERROR; 157 } 158 159 Status = gBS->CreateEvent ( 160 EVT_NOTIFY_SIGNAL, 161 TPL_NOTIFY, 162 Tcp4IoCommonNotify, 163 &Tcp4Io->IsTxDone, 164 &Tcp4Io->TxToken.CompletionToken.Event 165 ); 166 if (EFI_ERROR (Status)) { 167 goto ON_ERROR; 168 } 169 170 Status = gBS->CreateEvent ( 171 EVT_NOTIFY_SIGNAL, 172 TPL_NOTIFY, 173 Tcp4IoCommonNotify, 174 &Tcp4Io->IsRxDone, 175 &Tcp4Io->RxToken.CompletionToken.Event 176 ); 177 if (EFI_ERROR (Status)) { 178 goto ON_ERROR; 179 } 180 181 Status = gBS->CreateEvent ( 182 EVT_NOTIFY_SIGNAL, 183 TPL_NOTIFY, 184 Tcp4IoCommonNotify, 185 &Tcp4Io->IsCloseDone, 186 &Tcp4Io->CloseToken.CompletionToken.Event 187 ); 188 if (EFI_ERROR (Status)) { 189 goto ON_ERROR; 190 } 191 192 Tcp4Io->IsTxDone = FALSE; 193 Tcp4Io->IsRxDone = FALSE; 194 195 return EFI_SUCCESS; 196 197 ON_ERROR: 198 199 if (Tcp4Io->RxToken.CompletionToken.Event != NULL) { 200 gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event); 201 } 202 203 if (Tcp4Io->TxToken.CompletionToken.Event != NULL) { 204 gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event); 205 } 206 207 if (Tcp4Io->ConnToken.CompletionToken.Event != NULL) { 208 gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event); 209 } 210 211 if (Tcp4 != NULL) { 212 Tcp4->Configure (Tcp4, NULL); 213 214 gBS->CloseProtocol ( 215 Tcp4Io->Handle, 216 &gEfiTcp4ProtocolGuid, 217 Image, 218 Controller 219 ); 220 } 221 222 NetLibDestroyServiceChild ( 223 Controller, 224 Image, 225 &gEfiTcp4ServiceBindingProtocolGuid, 226 Tcp4Io->Handle 227 ); 228 229 return Status; 230 } 231 232 /** 233 Destroy the socket. 234 235 @param[in] Tcp4Io The Tcp4Io which wraps the socket to be destroyeds. 236 **/ 237 VOID 238 Tcp4IoDestroySocket ( 239 IN TCP4_IO *Tcp4Io 240 ) 241 { 242 EFI_TCP4_PROTOCOL *Tcp4; 243 244 Tcp4 = Tcp4Io->Tcp4; 245 246 Tcp4->Configure (Tcp4, NULL); 247 248 gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event); 249 gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event); 250 gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event); 251 252 gBS->CloseProtocol ( 253 Tcp4Io->Handle, 254 &gEfiTcp4ProtocolGuid, 255 Tcp4Io->Image, 256 Tcp4Io->Controller 257 ); 258 259 NetLibDestroyServiceChild ( 260 Tcp4Io->Controller, 261 Tcp4Io->Image, 262 &gEfiTcp4ServiceBindingProtocolGuid, 263 Tcp4Io->Handle 264 ); 265 } 266 267 /** 268 Connect to the other endpoint of the TCP socket. 269 270 @param[in, out] Tcp4Io The Tcp4Io wrapping the TCP socket. 271 @param[in] Timeout The time to wait for connection done. 272 273 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket successfully. 274 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the TCP socket in the specified time period. 275 @retval Others Other errors as indicated. 276 **/ 277 EFI_STATUS 278 Tcp4IoConnect ( 279 IN OUT TCP4_IO *Tcp4Io, 280 IN EFI_EVENT Timeout 281 ) 282 { 283 EFI_TCP4_PROTOCOL *Tcp4; 284 EFI_STATUS Status; 285 286 Tcp4Io->IsConnDone = FALSE; 287 Tcp4 = Tcp4Io->Tcp4; 288 Status = Tcp4->Connect (Tcp4, &Tcp4Io->ConnToken); 289 if (EFI_ERROR (Status)) { 290 return Status; 291 } 292 293 while (!Tcp4Io->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) { 294 Tcp4->Poll (Tcp4); 295 } 296 297 if (!Tcp4Io->IsConnDone) { 298 Status = EFI_TIMEOUT; 299 } else { 300 Status = Tcp4Io->ConnToken.CompletionToken.Status; 301 } 302 303 return Status; 304 } 305 306 /** 307 Reset the socket. 308 309 @param[in, out] Tcp4Io The Tcp4Io wrapping the TCP socket. 310 **/ 311 VOID 312 Tcp4IoReset ( 313 IN OUT TCP4_IO *Tcp4Io 314 ) 315 { 316 EFI_STATUS Status; 317 EFI_TCP4_PROTOCOL *Tcp4; 318 319 Tcp4Io->CloseToken.AbortOnClose = TRUE; 320 Tcp4Io->IsCloseDone = FALSE; 321 322 Tcp4 = Tcp4Io->Tcp4; 323 Status = Tcp4->Close (Tcp4, &Tcp4Io->CloseToken); 324 if (EFI_ERROR (Status)) { 325 return ; 326 } 327 328 while (!Tcp4Io->IsCloseDone) { 329 Tcp4->Poll (Tcp4); 330 } 331 } 332 333 /** 334 Transmit the Packet to the other endpoint of the socket. 335 336 @param[in] Tcp4Io The Tcp4Io wrapping the TCP socket. 337 @param[in] Packet The packet to transmit. 338 339 @retval EFI_SUCCESS The packet is trasmitted. 340 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. 341 @retval Others Other errors as indicated. 342 **/ 343 EFI_STATUS 344 Tcp4IoTransmit ( 345 IN TCP4_IO *Tcp4Io, 346 IN NET_BUF *Packet 347 ) 348 { 349 EFI_TCP4_TRANSMIT_DATA *TxData; 350 EFI_TCP4_PROTOCOL *Tcp4; 351 EFI_STATUS Status; 352 353 TxData = AllocatePool (sizeof (EFI_TCP4_TRANSMIT_DATA) + (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA)); 354 if (TxData == NULL) { 355 return EFI_OUT_OF_RESOURCES; 356 } 357 358 TxData->Push = TRUE; 359 TxData->Urgent = FALSE; 360 TxData->DataLength = Packet->TotalSize; 361 362 // 363 // Build the fragment table. 364 // 365 TxData->FragmentCount = Packet->BlockOpNum; 366 NetbufBuildExt (Packet, (NET_FRAGMENT *) &TxData->FragmentTable[0], &TxData->FragmentCount); 367 368 Tcp4Io->TxToken.Packet.TxData = TxData; 369 370 // 371 // Trasnmit the packet. 372 // 373 Tcp4 = Tcp4Io->Tcp4; 374 Status = Tcp4->Transmit (Tcp4, &Tcp4Io->TxToken); 375 if (EFI_ERROR (Status)) { 376 goto ON_EXIT; 377 } 378 379 while (!Tcp4Io->IsTxDone) { 380 Tcp4->Poll (Tcp4); 381 } 382 383 Tcp4Io->IsTxDone = FALSE; 384 385 Status = Tcp4Io->TxToken.CompletionToken.Status; 386 387 ON_EXIT: 388 389 FreePool (TxData); 390 391 return Status; 392 } 393 394 /** 395 Receive data from the socket. 396 397 @param[in] Tcp4Io The Tcp4Io which wraps the socket to be destroyed. 398 @param[in] Packet The buffer to hold the data copy from the soket rx buffer. 399 @param[in] AsyncMode Is this receive asyncronous or not. 400 @param[in] Timeout The time to wait for receiving the amount of data the Packet 401 can hold. 402 403 @retval EFI_SUCCESS The required amount of data is received from the socket. 404 @retval EFI_OUT_OF_RESOURCES Failed to allocate momery. 405 @retval EFI_TIMEOUT Failed to receive the required amount of data in the 406 specified time period. 407 @retval Others Other errors as indicated. 408 **/ 409 EFI_STATUS 410 Tcp4IoReceive ( 411 IN TCP4_IO *Tcp4Io, 412 IN NET_BUF *Packet, 413 IN BOOLEAN AsyncMode, 414 IN EFI_EVENT Timeout 415 ) 416 { 417 EFI_TCP4_PROTOCOL *Tcp4; 418 EFI_TCP4_RECEIVE_DATA RxData; 419 EFI_STATUS Status; 420 NET_FRAGMENT *Fragment; 421 UINT32 FragmentCount; 422 UINT32 CurrentFragment; 423 424 FragmentCount = Packet->BlockOpNum; 425 Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT)); 426 if (Fragment == NULL) { 427 return EFI_OUT_OF_RESOURCES; 428 } 429 // 430 // Build the fragment table. 431 // 432 NetbufBuildExt (Packet, Fragment, &FragmentCount); 433 434 RxData.FragmentCount = 1; 435 Tcp4Io->RxToken.Packet.RxData = &RxData; 436 CurrentFragment = 0; 437 Tcp4 = Tcp4Io->Tcp4; 438 Status = EFI_SUCCESS; 439 440 while (CurrentFragment < FragmentCount) { 441 RxData.DataLength = Fragment[CurrentFragment].Len; 442 RxData.FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len; 443 RxData.FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk; 444 445 Status = Tcp4->Receive (Tcp4, &Tcp4Io->RxToken); 446 if (EFI_ERROR (Status)) { 447 goto ON_EXIT; 448 } 449 450 while (!Tcp4Io->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) { 451 // 452 // Poll until some data is received or something error happens. 453 // 454 Tcp4->Poll (Tcp4); 455 } 456 457 if (!Tcp4Io->IsRxDone) { 458 // 459 // Timeout occurs, cancel the receive request. 460 // 461 Tcp4->Cancel (Tcp4, &Tcp4Io->RxToken.CompletionToken); 462 463 Status = EFI_TIMEOUT; 464 goto ON_EXIT; 465 } else { 466 Tcp4Io->IsRxDone = FALSE; 467 } 468 469 if (EFI_ERROR (Tcp4Io->RxToken.CompletionToken.Status)) { 470 Status = Tcp4Io->RxToken.CompletionToken.Status; 471 goto ON_EXIT; 472 } 473 474 Fragment[CurrentFragment].Len -= RxData.FragmentTable[0].FragmentLength; 475 if (Fragment[CurrentFragment].Len == 0) { 476 CurrentFragment++; 477 } else { 478 Fragment[CurrentFragment].Bulk += RxData.FragmentTable[0].FragmentLength; 479 } 480 } 481 482 ON_EXIT: 483 Tcp4Io->RxToken.Packet.RxData = NULL; 484 FreePool (Fragment); 485 486 return Status; 487 } 488