1 /** @file 2 This file implement the EFI_DHCP4_PROTOCOL interface. 3 4 Copyright (c) 2006 - 2015, 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 16 #include "Dhcp4Impl.h" 17 18 /** 19 Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver. 20 21 The GetModeData() function returns the current operating mode and cached data 22 packet for the EFI DHCPv4 Protocol driver. 23 24 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 25 @param[out] Dhcp4ModeData Pointer to storage for the EFI_DHCP4_MODE_DATA structure. 26 27 @retval EFI_SUCCESS The mode data was returned. 28 @retval EFI_INVALID_PARAMETER This is NULL. 29 30 **/ 31 EFI_STATUS 32 EFIAPI 33 EfiDhcp4GetModeData ( 34 IN EFI_DHCP4_PROTOCOL *This, 35 OUT EFI_DHCP4_MODE_DATA *Dhcp4ModeData 36 ); 37 38 /** 39 Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver. 40 41 The Configure() function is used to initialize, change, or reset the operational 42 settings of the EFI DHCPv4 Protocol driver for the communication device on which 43 the EFI DHCPv4 Service Binding Protocol is installed. This function can be 44 successfully called only if both of the following are true: 45 * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init, 46 Dhcp4InitReboot, or Dhcp4Bound states. 47 * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI 48 DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4 49 Protocol driver. 50 When this driver is in the Dhcp4Stopped state, it can transfer into one of the 51 following two possible initial states: 52 * Dhcp4Init 53 * Dhcp4InitReboot 54 The driver can transfer into these states by calling Configure() with a non-NULL 55 Dhcp4CfgData. The driver will transfer into the appropriate state based on the 56 supplied client network address in the ClientAddress parameter and DHCP options 57 in the OptionList parameter as described in RFC 2131. 58 When Configure() is called successfully while Dhcp4CfgData is set to NULL, the 59 default configuring data will be reset in the EFI DHCPv4 Protocol driver and 60 the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance 61 wants to make it possible for another instance to configure the EFI DHCPv4 Protocol 62 driver, it must call this function with Dhcp4CfgData set to NULL. 63 64 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 65 @param[in] Dhcp4CfgData Pointer to the EFI_DHCP4_CONFIG_DATA. 66 67 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or 68 Dhcp4InitReboot state, if the original state of this driver 69 was Dhcp4Stopped and the value of Dhcp4CfgData was 70 not NULL. Otherwise, the state was left unchanged. 71 @retval EFI_ACCESS_DENIED This instance of the EFI DHCPv4 Protocol driver was not in the 72 Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state; 73 Or onother instance of this EFI DHCPv4 Protocol driver is already 74 in a valid configured state. 75 @retval EFI_INVALID_PARAMETER Some parameter is NULL. 76 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 77 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. 78 79 **/ 80 EFI_STATUS 81 EFIAPI 82 EfiDhcp4Configure ( 83 IN EFI_DHCP4_PROTOCOL *This, 84 IN EFI_DHCP4_CONFIG_DATA *Dhcp4CfgData OPTIONAL 85 ); 86 87 /** 88 Starts the DHCP configuration process. 89 90 The Start() function starts the DHCP configuration process. This function can 91 be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or 92 Dhcp4InitReboot state. 93 If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol 94 driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the 95 Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL. 96 If the process aborts, either by the user or by some unexpected network error, 97 the state is restored to the Dhcp4Init state. The Start() function can be called 98 again to restart the process. 99 Refer to RFC 2131 for precise state transitions during this process. At the 100 time when each event occurs in this process, the callback function that was set 101 by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this 102 opportunity to control the process. 103 104 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 105 @param[in] CompletionEvent If not NULL, indicates the event that will be signaled when the 106 EFI DHCPv4 Protocol driver is transferred into the 107 Dhcp4Bound state or when the DHCP process is aborted. 108 EFI_DHCP4_PROTOCOL.GetModeData() can be called to 109 check the completion status. If NULL, 110 EFI_DHCP4_PROTOCOL.Start() will wait until the driver 111 is transferred into the Dhcp4Bound state or the process fails. 112 113 @retval EFI_SUCCESS The DHCP configuration process has started, or it has completed 114 when CompletionEvent is NULL. 115 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped 116 state. EFI_DHCP4_PROTOCOL. Configure() needs to be called. 117 @retval EFI_INVALID_PARAMETER This is NULL. 118 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 119 @retval EFI_TIMEOUT The DHCP configuration process failed because no response was 120 received from the server within the specified timeout value. 121 @retval EFI_ABORTED The user aborted the DHCP process. 122 @retval EFI_ALREADY_STARTED Some other EFI DHCPv4 Protocol instance already started the 123 DHCP process. 124 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. 125 126 **/ 127 EFI_STATUS 128 EFIAPI 129 EfiDhcp4Start ( 130 IN EFI_DHCP4_PROTOCOL *This, 131 IN EFI_EVENT CompletionEvent OPTIONAL 132 ); 133 134 /** 135 Extends the lease time by sending a request packet. 136 137 The RenewRebind() function is used to manually extend the lease time when the 138 EFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time has 139 not expired yet. This function will send a request packet to the previously 140 found server (or to any server when RebindRequest is TRUE) and transfer the 141 state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is 142 TRUE). When a response is received, the state is returned to Dhcp4Bound. 143 If no response is received before the try count is exceeded (the RequestTryCount 144 field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that 145 was issued by the previous server expires, the driver will return to the Dhcp4Bound 146 state and the previous configuration is restored. The outgoing and incoming packets 147 can be captured by the EFI_DHCP4_CALLBACK function. 148 149 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 150 @param[in] RebindRequest If TRUE, this function broadcasts the request packets and enters 151 the Dhcp4Rebinding state. Otherwise, it sends a unicast 152 request packet and enters the Dhcp4Renewing state. 153 @param[in] CompletionEvent If not NULL, this event is signaled when the renew/rebind phase 154 completes or some error occurs. 155 EFI_DHCP4_PROTOCOL.GetModeData() can be called to 156 check the completion status. If NULL, 157 EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait 158 until the DHCP process finishes. 159 160 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the 161 Dhcp4Renewing state or is back to the Dhcp4Bound state. 162 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped 163 state. EFI_DHCP4_PROTOCOL.Configure() needs to 164 be called. 165 @retval EFI_INVALID_PARAMETER This is NULL. 166 @retval EFI_TIMEOUT There was no response from the server when the try count was 167 exceeded. 168 @retval EFI_ACCESS_DENIED The driver is not in the Dhcp4Bound state. 169 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. 170 171 **/ 172 EFI_STATUS 173 EFIAPI 174 EfiDhcp4RenewRebind ( 175 IN EFI_DHCP4_PROTOCOL *This, 176 IN BOOLEAN RebindRequest, 177 IN EFI_EVENT CompletionEvent OPTIONAL 178 ); 179 180 /** 181 Releases the current address configuration. 182 183 The Release() function releases the current configured IP address by doing either 184 of the following: 185 * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the 186 Dhcp4Bound state 187 * Setting the previously assigned IP address that was provided with the 188 EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in 189 Dhcp4InitReboot state 190 After a successful call to this function, the EFI DHCPv4 Protocol driver returns 191 to the Dhcp4Init state and any subsequent incoming packets will be discarded silently. 192 193 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 194 195 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase. 196 @retval EFI_INVALID_PARAMETER This is NULL. 197 @retval EFI_ACCESS_DENIED The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state. 198 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. 199 200 **/ 201 EFI_STATUS 202 EFIAPI 203 EfiDhcp4Release ( 204 IN EFI_DHCP4_PROTOCOL *This 205 ); 206 207 /** 208 Stops the current address configuration. 209 210 The Stop() function is used to stop the DHCP configuration process. After this 211 function is called successfully, the EFI DHCPv4 Protocol driver is transferred 212 into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called 213 before DHCP configuration process can be started again. This function can be 214 called when the EFI DHCPv4 Protocol driver is in any state. 215 216 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 217 218 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase. 219 @retval EFI_INVALID_PARAMETER This is NULL. 220 221 **/ 222 EFI_STATUS 223 EFIAPI 224 EfiDhcp4Stop ( 225 IN EFI_DHCP4_PROTOCOL *This 226 ); 227 228 /** 229 Builds a DHCP packet, given the options to be appended or deleted or replaced. 230 231 The Build() function is used to assemble a new packet from the original packet 232 by replacing or deleting existing options or appending new options. This function 233 does not change any state of the EFI DHCPv4 Protocol driver and can be used at 234 any time. 235 236 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 237 @param[in] SeedPacket Initial packet to be used as a base for building new packet. 238 @param[in] DeleteCount Number of opcodes in the DeleteList. 239 @param[in] DeleteList List of opcodes to be deleted from the seed packet. 240 Ignored if DeleteCount is zero. 241 @param[in] AppendCount Number of entries in the OptionList. 242 @param[in] AppendList Pointer to a DHCP option list to be appended to SeedPacket. 243 If SeedPacket also contains options in this list, they are 244 replaced by new options (except pad option). Ignored if 245 AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION 246 @param[out] NewPacket Pointer to storage for the pointer to the new allocated packet. 247 Use the EFI Boot Service FreePool() on the resulting pointer 248 when done with the packet. 249 250 @retval EFI_SUCCESS The new packet was built. 251 @retval EFI_OUT_OF_RESOURCES Storage for the new packet could not be allocated. 252 @retval EFI_INVALID_PARAMETER Some parameter is NULL. 253 254 **/ 255 EFI_STATUS 256 EFIAPI 257 EfiDhcp4Build ( 258 IN EFI_DHCP4_PROTOCOL *This, 259 IN EFI_DHCP4_PACKET *SeedPacket, 260 IN UINT32 DeleteCount, 261 IN UINT8 *DeleteList OPTIONAL, 262 IN UINT32 AppendCount, 263 IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL, 264 OUT EFI_DHCP4_PACKET **NewPacket 265 ); 266 267 /** 268 Transmits a DHCP formatted packet and optionally waits for responses. 269 270 The TransmitReceive() function is used to transmit a DHCP packet and optionally 271 wait for the response from servers. This function does not change the state of 272 the EFI DHCPv4 Protocol driver and thus can be used at any time. 273 274 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 275 @param[in] Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure. 276 277 @retval EFI_SUCCESS The packet was successfully queued for transmission. 278 @retval EFI_INVALID_PARAMETER Some parameter is NULL. 279 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call 280 this function after collection process completes. 281 @retval EFI_NO_MAPPING The default station address is not available yet. 282 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 283 @retval Others Some other unexpected error occurred. 284 285 **/ 286 EFI_STATUS 287 EFIAPI 288 EfiDhcp4TransmitReceive ( 289 IN EFI_DHCP4_PROTOCOL *This, 290 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token 291 ); 292 293 /** 294 Parses the packed DHCP option data. 295 296 The Parse() function is used to retrieve the option list from a DHCP packet. 297 If *OptionCount isn't zero, and there is enough space for all the DHCP options 298 in the Packet, each element of PacketOptionList is set to point to somewhere in 299 the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported, 300 the caller should reassemble the parsed DHCP options to get the finial result. 301 If *OptionCount is zero or there isn't enough space for all of them, the number 302 of DHCP options in the Packet is returned in OptionCount. 303 304 @param This Pointer to the EFI_DHCP4_PROTOCOL instance. 305 @param Packet Pointer to packet to be parsed. 306 @param OptionCount On input, the number of entries in the PacketOptionList. 307 On output, the number of entries that were written into the 308 PacketOptionList. 309 @param PacketOptionList List of packet option entries to be filled in. End option or pad 310 options are not included. 311 312 @retval EFI_SUCCESS The packet was successfully parsed. 313 @retval EFI_INVALID_PARAMETER Some parameter is NULL. 314 @retval EFI_BUFFER_TOO_SMALL One or more of the following conditions is TRUE: 315 1) *OptionCount is smaller than the number of options that 316 were found in the Packet. 317 2) PacketOptionList is NULL. 318 319 **/ 320 EFI_STATUS 321 EFIAPI 322 EfiDhcp4Parse ( 323 IN EFI_DHCP4_PROTOCOL *This, 324 IN EFI_DHCP4_PACKET *Packet, 325 IN OUT UINT32 *OptionCount, 326 OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL 327 ); 328 329 EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate = { 330 EfiDhcp4GetModeData, 331 EfiDhcp4Configure, 332 EfiDhcp4Start, 333 EfiDhcp4RenewRebind, 334 EfiDhcp4Release, 335 EfiDhcp4Stop, 336 EfiDhcp4Build, 337 EfiDhcp4TransmitReceive, 338 EfiDhcp4Parse 339 }; 340 341 /** 342 Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver. 343 344 The GetModeData() function returns the current operating mode and cached data 345 packet for the EFI DHCPv4 Protocol driver. 346 347 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 348 @param[out] Dhcp4ModeData Pointer to storage for the EFI_DHCP4_MODE_DATA structure. 349 350 @retval EFI_SUCCESS The mode data was returned. 351 @retval EFI_INVALID_PARAMETER This is NULL. 352 353 **/ 354 EFI_STATUS 355 EFIAPI 356 EfiDhcp4GetModeData ( 357 IN EFI_DHCP4_PROTOCOL *This, 358 OUT EFI_DHCP4_MODE_DATA *Dhcp4ModeData 359 ) 360 { 361 DHCP_PROTOCOL *Instance; 362 DHCP_SERVICE *DhcpSb; 363 DHCP_PARAMETER *Para; 364 EFI_TPL OldTpl; 365 IP4_ADDR Ip; 366 367 // 368 // First validate the parameters. 369 // 370 if ((This == NULL) || (Dhcp4ModeData == NULL)) { 371 return EFI_INVALID_PARAMETER; 372 } 373 374 Instance = DHCP_INSTANCE_FROM_THIS (This); 375 376 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 377 DhcpSb = Instance->Service; 378 379 // 380 // Caller can use GetModeData to retrieve current DHCP states 381 // no matter whether it is the active child or not. 382 // 383 Dhcp4ModeData->State = (EFI_DHCP4_STATE) DhcpSb->DhcpState; 384 CopyMem (&Dhcp4ModeData->ConfigData, &DhcpSb->ActiveConfig, sizeof (Dhcp4ModeData->ConfigData)); 385 CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (Dhcp4ModeData->ClientMacAddress)); 386 387 Ip = HTONL (DhcpSb->ClientAddr); 388 CopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS)); 389 390 Ip = HTONL (DhcpSb->Netmask); 391 CopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS)); 392 393 Ip = HTONL (DhcpSb->ServerAddr); 394 CopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS)); 395 396 Para = DhcpSb->Para; 397 398 if (Para != NULL) { 399 Ip = HTONL (Para->Router); 400 CopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS)); 401 Dhcp4ModeData->LeaseTime = Para->Lease; 402 } else { 403 ZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS)); 404 Dhcp4ModeData->LeaseTime = 0xffffffff; 405 } 406 407 Dhcp4ModeData->ReplyPacket = DhcpSb->Selected; 408 409 gBS->RestoreTPL (OldTpl); 410 return EFI_SUCCESS; 411 } 412 413 414 /** 415 Free the resource related to the configure parameters. 416 DHCP driver will make a copy of the user's configure 417 such as the time out value. 418 419 @param Config The DHCP configure data 420 421 **/ 422 VOID 423 DhcpCleanConfigure ( 424 IN OUT EFI_DHCP4_CONFIG_DATA *Config 425 ) 426 { 427 UINT32 Index; 428 429 if (Config->DiscoverTimeout != NULL) { 430 FreePool (Config->DiscoverTimeout); 431 } 432 433 if (Config->RequestTimeout != NULL) { 434 FreePool (Config->RequestTimeout); 435 } 436 437 if (Config->OptionList != NULL) { 438 for (Index = 0; Index < Config->OptionCount; Index++) { 439 if (Config->OptionList[Index] != NULL) { 440 FreePool (Config->OptionList[Index]); 441 } 442 } 443 444 FreePool (Config->OptionList); 445 } 446 447 ZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA)); 448 } 449 450 451 /** 452 Allocate memory for configure parameter such as timeout value for Dst, 453 then copy the configure parameter from Src to Dst. 454 455 @param[out] Dst The destination DHCP configure data. 456 @param[in] Src The source DHCP configure data. 457 458 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. 459 @retval EFI_SUCCESS The configure is copied. 460 461 **/ 462 EFI_STATUS 463 DhcpCopyConfigure ( 464 OUT EFI_DHCP4_CONFIG_DATA *Dst, 465 IN EFI_DHCP4_CONFIG_DATA *Src 466 ) 467 { 468 EFI_DHCP4_PACKET_OPTION **DstOptions; 469 EFI_DHCP4_PACKET_OPTION **SrcOptions; 470 UINTN Len; 471 UINT32 Index; 472 473 CopyMem (Dst, Src, sizeof (*Dst)); 474 Dst->DiscoverTimeout = NULL; 475 Dst->RequestTimeout = NULL; 476 Dst->OptionList = NULL; 477 478 // 479 // Allocate a memory then copy DiscoverTimeout to it 480 // 481 if (Src->DiscoverTimeout != NULL) { 482 Len = Src->DiscoverTryCount * sizeof (UINT32); 483 Dst->DiscoverTimeout = AllocatePool (Len); 484 485 if (Dst->DiscoverTimeout == NULL) { 486 return EFI_OUT_OF_RESOURCES; 487 } 488 489 for (Index = 0; Index < Src->DiscoverTryCount; Index++) { 490 Dst->DiscoverTimeout[Index] = MAX (Src->DiscoverTimeout[Index], 1); 491 } 492 } 493 494 // 495 // Allocate a memory then copy RequestTimeout to it 496 // 497 if (Src->RequestTimeout != NULL) { 498 Len = Src->RequestTryCount * sizeof (UINT32); 499 Dst->RequestTimeout = AllocatePool (Len); 500 501 if (Dst->RequestTimeout == NULL) { 502 goto ON_ERROR; 503 } 504 505 for (Index = 0; Index < Src->RequestTryCount; Index++) { 506 Dst->RequestTimeout[Index] = MAX (Src->RequestTimeout[Index], 1); 507 } 508 } 509 510 // 511 // Allocate an array of dhcp option point, then allocate memory 512 // for each option and copy the source option to it 513 // 514 if (Src->OptionList != NULL) { 515 Len = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *); 516 Dst->OptionList = AllocateZeroPool (Len); 517 518 if (Dst->OptionList == NULL) { 519 goto ON_ERROR; 520 } 521 522 DstOptions = Dst->OptionList; 523 SrcOptions = Src->OptionList; 524 525 for (Index = 0; Index < Src->OptionCount; Index++) { 526 Len = sizeof (EFI_DHCP4_PACKET_OPTION) + MAX (SrcOptions[Index]->Length - 1, 0); 527 528 DstOptions[Index] = AllocatePool (Len); 529 530 if (DstOptions[Index] == NULL) { 531 goto ON_ERROR; 532 } 533 534 CopyMem (DstOptions[Index], SrcOptions[Index], Len); 535 } 536 } 537 538 return EFI_SUCCESS; 539 540 ON_ERROR: 541 DhcpCleanConfigure (Dst); 542 return EFI_OUT_OF_RESOURCES; 543 } 544 545 546 /** 547 Give up the control of the DHCP service to let other child 548 resume. Don't change the service's DHCP state and the Client 549 address and option list configure as required by RFC2131. 550 551 @param DhcpSb The DHCP service instance. 552 553 **/ 554 VOID 555 DhcpYieldControl ( 556 IN DHCP_SERVICE *DhcpSb 557 ) 558 { 559 EFI_DHCP4_CONFIG_DATA *Config; 560 561 Config = &DhcpSb->ActiveConfig; 562 563 DhcpSb->ServiceState = DHCP_UNCONFIGED; 564 DhcpSb->ActiveChild = NULL; 565 566 if (Config->DiscoverTimeout != NULL) { 567 FreePool (Config->DiscoverTimeout); 568 569 Config->DiscoverTryCount = 0; 570 Config->DiscoverTimeout = NULL; 571 } 572 573 if (Config->RequestTimeout != NULL) { 574 FreePool (Config->RequestTimeout); 575 576 Config->RequestTryCount = 0; 577 Config->RequestTimeout = NULL; 578 } 579 580 Config->Dhcp4Callback = NULL; 581 Config->CallbackContext = NULL; 582 } 583 584 585 /** 586 Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver. 587 588 The Configure() function is used to initialize, change, or reset the operational 589 settings of the EFI DHCPv4 Protocol driver for the communication device on which 590 the EFI DHCPv4 Service Binding Protocol is installed. This function can be 591 successfully called only if both of the following are true: 592 * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init, 593 Dhcp4InitReboot, or Dhcp4Bound states. 594 * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI 595 DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4 596 Protocol driver. 597 When this driver is in the Dhcp4Stopped state, it can transfer into one of the 598 following two possible initial states: 599 * Dhcp4Init 600 * Dhcp4InitReboot 601 The driver can transfer into these states by calling Configure() with a non-NULL 602 Dhcp4CfgData. The driver will transfer into the appropriate state based on the 603 supplied client network address in the ClientAddress parameter and DHCP options 604 in the OptionList parameter as described in RFC 2131. 605 When Configure() is called successfully while Dhcp4CfgData is set to NULL, the 606 default configuring data will be reset in the EFI DHCPv4 Protocol driver and 607 the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance 608 wants to make it possible for another instance to configure the EFI DHCPv4 Protocol 609 driver, it must call this function with Dhcp4CfgData set to NULL. 610 611 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 612 @param[in] Dhcp4CfgData Pointer to the EFI_DHCP4_CONFIG_DATA. 613 614 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or 615 Dhcp4InitReboot state, if the original state of this driver 616 was Dhcp4Stopped and the value of Dhcp4CfgData was 617 not NULL. Otherwise, the state was left unchanged. 618 @retval EFI_ACCESS_DENIED This instance of the EFI DHCPv4 Protocol driver was not in the 619 Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state; 620 Or onother instance of this EFI DHCPv4 Protocol driver is already 621 in a valid configured state. 622 @retval EFI_INVALID_PARAMETER Some parameter is NULL. 623 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 624 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. 625 626 **/ 627 EFI_STATUS 628 EFIAPI 629 EfiDhcp4Configure ( 630 IN EFI_DHCP4_PROTOCOL *This, 631 IN EFI_DHCP4_CONFIG_DATA *Dhcp4CfgData OPTIONAL 632 ) 633 { 634 EFI_DHCP4_CONFIG_DATA *Config; 635 DHCP_PROTOCOL *Instance; 636 DHCP_SERVICE *DhcpSb; 637 EFI_STATUS Status; 638 EFI_TPL OldTpl; 639 UINT32 Index; 640 IP4_ADDR Ip; 641 642 // 643 // First validate the parameters 644 // 645 if (This == NULL) { 646 return EFI_INVALID_PARAMETER; 647 } 648 649 if (Dhcp4CfgData != NULL) { 650 if ((Dhcp4CfgData->DiscoverTryCount != 0) && (Dhcp4CfgData->DiscoverTimeout == NULL)) { 651 return EFI_INVALID_PARAMETER; 652 } 653 654 if ((Dhcp4CfgData->RequestTryCount != 0) && (Dhcp4CfgData->RequestTimeout == NULL)) { 655 return EFI_INVALID_PARAMETER; 656 } 657 658 if ((Dhcp4CfgData->OptionCount != 0) && (Dhcp4CfgData->OptionList == NULL)) { 659 return EFI_INVALID_PARAMETER; 660 } 661 662 CopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR)); 663 664 if ((Ip != 0) && !NetIp4IsUnicast (NTOHL (Ip), 0)) { 665 666 return EFI_INVALID_PARAMETER; 667 } 668 } 669 670 Instance = DHCP_INSTANCE_FROM_THIS (This); 671 672 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) { 673 return EFI_INVALID_PARAMETER; 674 } 675 676 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 677 678 DhcpSb = Instance->Service; 679 Config = &DhcpSb->ActiveConfig; 680 681 Status = EFI_ACCESS_DENIED; 682 683 if ((DhcpSb->DhcpState != Dhcp4Stopped) && 684 (DhcpSb->DhcpState != Dhcp4Init) && 685 (DhcpSb->DhcpState != Dhcp4InitReboot) && 686 (DhcpSb->DhcpState != Dhcp4Bound)) { 687 688 goto ON_EXIT; 689 } 690 691 if ((DhcpSb->ActiveChild != NULL) && (DhcpSb->ActiveChild != Instance)) { 692 goto ON_EXIT; 693 } 694 695 if (Dhcp4CfgData != NULL) { 696 Status = EFI_OUT_OF_RESOURCES; 697 DhcpCleanConfigure (Config); 698 699 if (EFI_ERROR (DhcpCopyConfigure (Config, Dhcp4CfgData))) { 700 goto ON_EXIT; 701 } 702 703 DhcpSb->UserOptionLen = 0; 704 705 for (Index = 0; Index < Dhcp4CfgData->OptionCount; Index++) { 706 DhcpSb->UserOptionLen += Dhcp4CfgData->OptionList[Index]->Length + 2; 707 } 708 709 DhcpSb->ActiveChild = Instance; 710 711 if (DhcpSb->DhcpState == Dhcp4Stopped) { 712 DhcpSb->ClientAddr = EFI_NTOHL (Dhcp4CfgData->ClientAddress); 713 714 if (DhcpSb->ClientAddr != 0) { 715 DhcpSb->DhcpState = Dhcp4InitReboot; 716 } else { 717 DhcpSb->DhcpState = Dhcp4Init; 718 } 719 } 720 721 DhcpSb->ServiceState = DHCP_CONFIGED; 722 Status = EFI_SUCCESS; 723 724 } else if (DhcpSb->ActiveChild == Instance) { 725 Status = EFI_SUCCESS; 726 DhcpYieldControl (DhcpSb); 727 } 728 729 ON_EXIT: 730 gBS->RestoreTPL (OldTpl); 731 return Status; 732 } 733 734 735 /** 736 Starts the DHCP configuration process. 737 738 The Start() function starts the DHCP configuration process. This function can 739 be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or 740 Dhcp4InitReboot state. 741 If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol 742 driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the 743 Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL. 744 If the process aborts, either by the user or by some unexpected network error, 745 the state is restored to the Dhcp4Init state. The Start() function can be called 746 again to restart the process. 747 Refer to RFC 2131 for precise state transitions during this process. At the 748 time when each event occurs in this process, the callback function that was set 749 by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this 750 opportunity to control the process. 751 752 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 753 @param[in] CompletionEvent If not NULL, indicates the event that will be signaled when the 754 EFI DHCPv4 Protocol driver is transferred into the 755 Dhcp4Bound state or when the DHCP process is aborted. 756 EFI_DHCP4_PROTOCOL.GetModeData() can be called to 757 check the completion status. If NULL, 758 EFI_DHCP4_PROTOCOL.Start() will wait until the driver 759 is transferred into the Dhcp4Bound state or the process fails. 760 761 @retval EFI_SUCCESS The DHCP configuration process has started, or it has completed 762 when CompletionEvent is NULL. 763 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped 764 state. EFI_DHCP4_PROTOCOL. Configure() needs to be called. 765 @retval EFI_INVALID_PARAMETER This is NULL. 766 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 767 @retval EFI_TIMEOUT The DHCP configuration process failed because no response was 768 received from the server within the specified timeout value. 769 @retval EFI_ABORTED The user aborted the DHCP process. 770 @retval EFI_ALREADY_STARTED Some other EFI DHCPv4 Protocol instance already started the 771 DHCP process. 772 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. 773 @retval EFI_NO_MEDIA There was a media error. 774 775 **/ 776 EFI_STATUS 777 EFIAPI 778 EfiDhcp4Start ( 779 IN EFI_DHCP4_PROTOCOL *This, 780 IN EFI_EVENT CompletionEvent OPTIONAL 781 ) 782 { 783 DHCP_PROTOCOL *Instance; 784 DHCP_SERVICE *DhcpSb; 785 EFI_STATUS Status; 786 EFI_TPL OldTpl; 787 788 // 789 // First validate the parameters 790 // 791 if (This == NULL) { 792 return EFI_INVALID_PARAMETER; 793 } 794 795 Instance = DHCP_INSTANCE_FROM_THIS (This); 796 797 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) { 798 return EFI_INVALID_PARAMETER; 799 } 800 801 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 802 DhcpSb = Instance->Service; 803 804 if (DhcpSb->DhcpState == Dhcp4Stopped) { 805 Status = EFI_NOT_STARTED; 806 goto ON_ERROR; 807 } 808 809 if ((DhcpSb->DhcpState != Dhcp4Init) && (DhcpSb->DhcpState != Dhcp4InitReboot)) { 810 Status = EFI_ALREADY_STARTED; 811 goto ON_ERROR; 812 } 813 814 DhcpSb->IoStatus = EFI_ALREADY_STARTED; 815 816 if (EFI_ERROR (Status = DhcpInitRequest (DhcpSb))) { 817 goto ON_ERROR; 818 } 819 820 821 Instance->CompletionEvent = CompletionEvent; 822 823 // 824 // Restore the TPL now, don't call poll function at TPL_CALLBACK. 825 // 826 gBS->RestoreTPL (OldTpl); 827 828 if (CompletionEvent == NULL) { 829 while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) { 830 DhcpSb->UdpIo->Protocol.Udp4->Poll (DhcpSb->UdpIo->Protocol.Udp4); 831 } 832 833 return DhcpSb->IoStatus; 834 } 835 836 return EFI_SUCCESS; 837 838 ON_ERROR: 839 gBS->RestoreTPL (OldTpl); 840 return Status; 841 } 842 843 844 /** 845 Extends the lease time by sending a request packet. 846 847 The RenewRebind() function is used to manually extend the lease time when the 848 EFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time has 849 not expired yet. This function will send a request packet to the previously 850 found server (or to any server when RebindRequest is TRUE) and transfer the 851 state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is 852 TRUE). When a response is received, the state is returned to Dhcp4Bound. 853 If no response is received before the try count is exceeded (the RequestTryCount 854 field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that 855 was issued by the previous server expires, the driver will return to the Dhcp4Bound 856 state and the previous configuration is restored. The outgoing and incoming packets 857 can be captured by the EFI_DHCP4_CALLBACK function. 858 859 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 860 @param[in] RebindRequest If TRUE, this function broadcasts the request packets and enters 861 the Dhcp4Rebinding state. Otherwise, it sends a unicast 862 request packet and enters the Dhcp4Renewing state. 863 @param[in] CompletionEvent If not NULL, this event is signaled when the renew/rebind phase 864 completes or some error occurs. 865 EFI_DHCP4_PROTOCOL.GetModeData() can be called to 866 check the completion status. If NULL, 867 EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait 868 until the DHCP process finishes. 869 870 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the 871 Dhcp4Renewing state or is back to the Dhcp4Bound state. 872 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped 873 state. EFI_DHCP4_PROTOCOL.Configure() needs to 874 be called. 875 @retval EFI_INVALID_PARAMETER This is NULL. 876 @retval EFI_TIMEOUT There was no response from the server when the try count was 877 exceeded. 878 @retval EFI_ACCESS_DENIED The driver is not in the Dhcp4Bound state. 879 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. 880 881 **/ 882 EFI_STATUS 883 EFIAPI 884 EfiDhcp4RenewRebind ( 885 IN EFI_DHCP4_PROTOCOL *This, 886 IN BOOLEAN RebindRequest, 887 IN EFI_EVENT CompletionEvent OPTIONAL 888 ) 889 { 890 DHCP_PROTOCOL *Instance; 891 DHCP_SERVICE *DhcpSb; 892 EFI_STATUS Status; 893 EFI_TPL OldTpl; 894 895 // 896 // First validate the parameters 897 // 898 if (This == NULL) { 899 return EFI_INVALID_PARAMETER; 900 } 901 902 Instance = DHCP_INSTANCE_FROM_THIS (This); 903 904 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) { 905 return EFI_INVALID_PARAMETER; 906 } 907 908 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 909 DhcpSb = Instance->Service; 910 911 if (DhcpSb->DhcpState == Dhcp4Stopped) { 912 Status = EFI_NOT_STARTED; 913 goto ON_EXIT; 914 } 915 916 if (DhcpSb->DhcpState != Dhcp4Bound) { 917 Status = EFI_ACCESS_DENIED; 918 goto ON_EXIT; 919 } 920 921 if (DHCP_IS_BOOTP (DhcpSb->Para)) { 922 Status = EFI_SUCCESS; 923 goto ON_EXIT; 924 } 925 926 // 927 // Transit the states then send a extra DHCP request 928 // 929 if (!RebindRequest) { 930 DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE); 931 } else { 932 DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE); 933 } 934 935 // 936 // Clear initial time to make sure that elapsed-time 937 // is set to 0 for first REQUEST in renewal process. 938 // 939 Instance->ElaspedTime = 0; 940 941 Status = DhcpSendMessage ( 942 DhcpSb, 943 DhcpSb->Selected, 944 DhcpSb->Para, 945 DHCP_MSG_REQUEST, 946 (UINT8 *) "Extra renew/rebind by the application" 947 ); 948 949 if (EFI_ERROR (Status)) { 950 DhcpSetState (DhcpSb, Dhcp4Bound, FALSE); 951 goto ON_EXIT; 952 } 953 954 DhcpSb->ExtraRefresh = TRUE; 955 DhcpSb->IoStatus = EFI_ALREADY_STARTED; 956 Instance->RenewRebindEvent = CompletionEvent; 957 958 gBS->RestoreTPL (OldTpl); 959 960 if (CompletionEvent == NULL) { 961 while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) { 962 DhcpSb->UdpIo->Protocol.Udp4->Poll (DhcpSb->UdpIo->Protocol.Udp4); 963 964 } 965 966 return DhcpSb->IoStatus; 967 } 968 969 return EFI_SUCCESS; 970 971 ON_EXIT: 972 gBS->RestoreTPL (OldTpl); 973 return Status; 974 } 975 976 977 /** 978 Releases the current address configuration. 979 980 The Release() function releases the current configured IP address by doing either 981 of the following: 982 * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the 983 Dhcp4Bound state 984 * Setting the previously assigned IP address that was provided with the 985 EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in 986 Dhcp4InitReboot state 987 After a successful call to this function, the EFI DHCPv4 Protocol driver returns 988 to the Dhcp4Init state and any subsequent incoming packets will be discarded silently. 989 990 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 991 992 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase. 993 @retval EFI_INVALID_PARAMETER This is NULL. 994 @retval EFI_ACCESS_DENIED The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state. 995 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. 996 997 **/ 998 EFI_STATUS 999 EFIAPI 1000 EfiDhcp4Release ( 1001 IN EFI_DHCP4_PROTOCOL *This 1002 ) 1003 { 1004 DHCP_PROTOCOL *Instance; 1005 DHCP_SERVICE *DhcpSb; 1006 EFI_STATUS Status; 1007 EFI_TPL OldTpl; 1008 1009 // 1010 // First validate the parameters 1011 // 1012 if (This == NULL) { 1013 return EFI_INVALID_PARAMETER; 1014 } 1015 1016 Instance = DHCP_INSTANCE_FROM_THIS (This); 1017 1018 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) { 1019 return EFI_INVALID_PARAMETER; 1020 } 1021 1022 Status = EFI_SUCCESS; 1023 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 1024 DhcpSb = Instance->Service; 1025 1026 if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) { 1027 Status = EFI_ACCESS_DENIED; 1028 goto ON_EXIT; 1029 } 1030 1031 if (!DHCP_IS_BOOTP (DhcpSb->Para) && (DhcpSb->DhcpState == Dhcp4Bound)) { 1032 Status = DhcpSendMessage ( 1033 DhcpSb, 1034 DhcpSb->Selected, 1035 DhcpSb->Para, 1036 DHCP_MSG_RELEASE, 1037 NULL 1038 ); 1039 1040 if (EFI_ERROR (Status)) { 1041 Status = EFI_DEVICE_ERROR; 1042 goto ON_EXIT; 1043 } 1044 } 1045 1046 DhcpCleanLease (DhcpSb); 1047 1048 ON_EXIT: 1049 gBS->RestoreTPL (OldTpl); 1050 return Status; 1051 } 1052 1053 1054 /** 1055 Stops the current address configuration. 1056 1057 The Stop() function is used to stop the DHCP configuration process. After this 1058 function is called successfully, the EFI DHCPv4 Protocol driver is transferred 1059 into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called 1060 before DHCP configuration process can be started again. This function can be 1061 called when the EFI DHCPv4 Protocol driver is in any state. 1062 1063 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 1064 1065 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase. 1066 @retval EFI_INVALID_PARAMETER This is NULL. 1067 1068 **/ 1069 EFI_STATUS 1070 EFIAPI 1071 EfiDhcp4Stop ( 1072 IN EFI_DHCP4_PROTOCOL *This 1073 ) 1074 { 1075 DHCP_PROTOCOL *Instance; 1076 DHCP_SERVICE *DhcpSb; 1077 EFI_TPL OldTpl; 1078 1079 // 1080 // First validate the parameters 1081 // 1082 if (This == NULL) { 1083 return EFI_INVALID_PARAMETER; 1084 } 1085 1086 Instance = DHCP_INSTANCE_FROM_THIS (This); 1087 1088 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) { 1089 return EFI_INVALID_PARAMETER; 1090 } 1091 1092 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 1093 DhcpSb = Instance->Service; 1094 1095 DhcpCleanLease (DhcpSb); 1096 1097 DhcpSb->DhcpState = Dhcp4Stopped; 1098 DhcpSb->ServiceState = DHCP_UNCONFIGED; 1099 1100 gBS->RestoreTPL (OldTpl); 1101 return EFI_SUCCESS; 1102 } 1103 1104 1105 /** 1106 Builds a DHCP packet, given the options to be appended or deleted or replaced. 1107 1108 The Build() function is used to assemble a new packet from the original packet 1109 by replacing or deleting existing options or appending new options. This function 1110 does not change any state of the EFI DHCPv4 Protocol driver and can be used at 1111 any time. 1112 1113 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 1114 @param[in] SeedPacket Initial packet to be used as a base for building new packet. 1115 @param[in] DeleteCount Number of opcodes in the DeleteList. 1116 @param[in] DeleteList List of opcodes to be deleted from the seed packet. 1117 Ignored if DeleteCount is zero. 1118 @param[in] AppendCount Number of entries in the OptionList. 1119 @param[in] AppendList Pointer to a DHCP option list to be appended to SeedPacket. 1120 If SeedPacket also contains options in this list, they are 1121 replaced by new options (except pad option). Ignored if 1122 AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION 1123 @param[out] NewPacket Pointer to storage for the pointer to the new allocated packet. 1124 Use the EFI Boot Service FreePool() on the resulting pointer 1125 when done with the packet. 1126 1127 @retval EFI_SUCCESS The new packet was built. 1128 @retval EFI_OUT_OF_RESOURCES Storage for the new packet could not be allocated. 1129 @retval EFI_INVALID_PARAMETER Some parameter is NULL. 1130 1131 **/ 1132 EFI_STATUS 1133 EFIAPI 1134 EfiDhcp4Build ( 1135 IN EFI_DHCP4_PROTOCOL *This, 1136 IN EFI_DHCP4_PACKET *SeedPacket, 1137 IN UINT32 DeleteCount, 1138 IN UINT8 *DeleteList OPTIONAL, 1139 IN UINT32 AppendCount, 1140 IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL, 1141 OUT EFI_DHCP4_PACKET **NewPacket 1142 ) 1143 { 1144 // 1145 // First validate the parameters 1146 // 1147 if ((This == NULL) || (NewPacket == NULL)) { 1148 return EFI_INVALID_PARAMETER; 1149 } 1150 1151 if ((SeedPacket == NULL) || (SeedPacket->Dhcp4.Magik != DHCP_OPTION_MAGIC) || 1152 EFI_ERROR (DhcpValidateOptions (SeedPacket, NULL))) { 1153 1154 return EFI_INVALID_PARAMETER; 1155 } 1156 1157 if (((DeleteCount == 0) && (AppendCount == 0)) || 1158 ((DeleteCount != 0) && (DeleteList == NULL)) || 1159 ((AppendCount != 0) && (AppendList == NULL))) { 1160 1161 return EFI_INVALID_PARAMETER; 1162 } 1163 1164 return DhcpBuild ( 1165 SeedPacket, 1166 DeleteCount, 1167 DeleteList, 1168 AppendCount, 1169 AppendList, 1170 NewPacket 1171 ); 1172 } 1173 1174 /** 1175 Callback by UdpIoCreatePort() when creating UdpIo for this Dhcp4 instance. 1176 1177 @param[in] UdpIo The UdpIo being created. 1178 @param[in] Context Dhcp4 instance. 1179 1180 @retval EFI_SUCCESS UdpIo is configured successfully. 1181 @retval other Other error occurs. 1182 **/ 1183 EFI_STATUS 1184 EFIAPI 1185 Dhcp4InstanceConfigUdpIo ( 1186 IN UDP_IO *UdpIo, 1187 IN VOID *Context 1188 ) 1189 { 1190 DHCP_PROTOCOL *Instance; 1191 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token; 1192 EFI_UDP4_CONFIG_DATA UdpConfigData; 1193 IP4_ADDR ClientAddr; 1194 IP4_ADDR Ip; 1195 INTN Class; 1196 IP4_ADDR SubnetMask; 1197 1198 Instance = (DHCP_PROTOCOL *) Context; 1199 Token = Instance->Token; 1200 1201 ZeroMem (&UdpConfigData, sizeof (EFI_UDP4_CONFIG_DATA)); 1202 1203 UdpConfigData.AcceptBroadcast = TRUE; 1204 UdpConfigData.AllowDuplicatePort = TRUE; 1205 UdpConfigData.TimeToLive = 64; 1206 UdpConfigData.DoNotFragment = TRUE; 1207 1208 ClientAddr = EFI_NTOHL (Token->Packet->Dhcp4.Header.ClientAddr); 1209 Ip = HTONL (ClientAddr); 1210 CopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS)); 1211 1212 Class = NetGetIpClass (ClientAddr); 1213 ASSERT (Class < IP4_ADDR_CLASSE); 1214 SubnetMask = gIp4AllMasks[Class << 3]; 1215 Ip = HTONL (SubnetMask); 1216 CopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS)); 1217 1218 if ((Token->ListenPointCount == 0) || (Token->ListenPoints[0].ListenPort == 0)) { 1219 UdpConfigData.StationPort = DHCP_CLIENT_PORT; 1220 } else { 1221 UdpConfigData.StationPort = Token->ListenPoints[0].ListenPort; 1222 } 1223 1224 return UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfigData); 1225 } 1226 1227 /** 1228 Create UdpIo for this Dhcp4 instance. 1229 1230 @param Instance The Dhcp4 instance. 1231 1232 @retval EFI_SUCCESS UdpIo is created successfully. 1233 @retval EFI_OUT_OF_RESOURCES Fails to create UdpIo because of limited 1234 resources or configuration failure. 1235 **/ 1236 EFI_STATUS 1237 Dhcp4InstanceCreateUdpIo ( 1238 IN OUT DHCP_PROTOCOL *Instance 1239 ) 1240 { 1241 DHCP_SERVICE *DhcpSb; 1242 EFI_STATUS Status; 1243 VOID *Udp4; 1244 1245 ASSERT (Instance->Token != NULL); 1246 1247 DhcpSb = Instance->Service; 1248 Instance->UdpIo = UdpIoCreateIo ( 1249 DhcpSb->Controller, 1250 DhcpSb->Image, 1251 Dhcp4InstanceConfigUdpIo, 1252 UDP_IO_UDP4_VERSION, 1253 Instance 1254 ); 1255 if (Instance->UdpIo == NULL) { 1256 return EFI_OUT_OF_RESOURCES; 1257 } else { 1258 Status = gBS->OpenProtocol ( 1259 Instance->UdpIo->UdpHandle, 1260 &gEfiUdp4ProtocolGuid, 1261 (VOID **) &Udp4, 1262 Instance->Service->Image, 1263 Instance->Handle, 1264 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 1265 ); 1266 if (EFI_ERROR (Status)) { 1267 UdpIoFreeIo (Instance->UdpIo); 1268 Instance->UdpIo = NULL; 1269 } 1270 return Status; 1271 } 1272 } 1273 1274 /** 1275 Callback of Dhcp packet. Does nothing. 1276 1277 @param Arg The context. 1278 1279 **/ 1280 VOID 1281 EFIAPI 1282 DhcpDummyExtFree ( 1283 IN VOID *Arg 1284 ) 1285 { 1286 } 1287 1288 /** 1289 Callback of UdpIoRecvDatagram() that handles a Dhcp4 packet. 1290 1291 Only BOOTP responses will be handled that correspond to the Xid of the request 1292 sent out. The packet will be queued to the response queue. 1293 1294 @param UdpPacket The Dhcp4 packet. 1295 @param EndPoint Udp4 address pair. 1296 @param IoStatus Status of the input. 1297 @param Context Extra info for the input. 1298 1299 **/ 1300 VOID 1301 EFIAPI 1302 PxeDhcpInput ( 1303 NET_BUF *UdpPacket, 1304 UDP_END_POINT *EndPoint, 1305 EFI_STATUS IoStatus, 1306 VOID *Context 1307 ) 1308 { 1309 DHCP_PROTOCOL *Instance; 1310 EFI_DHCP4_HEADER *Head; 1311 NET_BUF *Wrap; 1312 EFI_DHCP4_PACKET *Packet; 1313 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token; 1314 UINT32 Len; 1315 EFI_STATUS Status; 1316 1317 Wrap = NULL; 1318 Instance = (DHCP_PROTOCOL *) Context; 1319 Token = Instance->Token; 1320 1321 // 1322 // Don't restart receive if error occurs or DHCP is destroyed. 1323 // 1324 if (EFI_ERROR (IoStatus)) { 1325 return ; 1326 } 1327 1328 ASSERT (UdpPacket != NULL); 1329 1330 // 1331 // Validate the packet received 1332 // 1333 if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) { 1334 goto RESTART; 1335 } 1336 1337 // 1338 // Copy the DHCP message to a continuous memory block, make the buffer size 1339 // of the EFI_DHCP4_PACKET a multiple of 4-byte. 1340 // 1341 Len = NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER), 4); 1342 Wrap = NetbufAlloc (Len); 1343 if (Wrap == NULL) { 1344 goto RESTART; 1345 } 1346 1347 Packet = (EFI_DHCP4_PACKET *) NetbufAllocSpace (Wrap, Len, NET_BUF_TAIL); 1348 ASSERT (Packet != NULL); 1349 1350 Packet->Size = Len; 1351 Head = &Packet->Dhcp4.Header; 1352 Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *) Head); 1353 1354 if (Packet->Length != UdpPacket->TotalSize) { 1355 goto RESTART; 1356 } 1357 1358 // 1359 // Is this packet the answer to our packet? 1360 // 1361 if ((Head->OpCode != BOOTP_REPLY) || 1362 (Head->Xid != Token->Packet->Dhcp4.Header.Xid) || 1363 (CompareMem (&Token->Packet->Dhcp4.Header.ClientHwAddr[0], Head->ClientHwAddr, Head->HwAddrLen) != 0)) { 1364 goto RESTART; 1365 } 1366 1367 // 1368 // Validate the options and retrieve the interested options 1369 // 1370 if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) && 1371 (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) && 1372 EFI_ERROR (DhcpValidateOptions (Packet, NULL))) { 1373 1374 goto RESTART; 1375 } 1376 1377 // 1378 // Keep this packet in the ResponseQueue. 1379 // 1380 NET_GET_REF (Wrap); 1381 NetbufQueAppend (&Instance->ResponseQueue, Wrap); 1382 1383 RESTART: 1384 1385 NetbufFree (UdpPacket); 1386 1387 if (Wrap != NULL) { 1388 NetbufFree (Wrap); 1389 } 1390 1391 Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0); 1392 if (EFI_ERROR (Status)) { 1393 PxeDhcpDone (Instance); 1394 } 1395 } 1396 1397 /** 1398 Complete a Dhcp4 transaction and signal the upper layer. 1399 1400 @param Instance Dhcp4 instance. 1401 1402 **/ 1403 VOID 1404 PxeDhcpDone ( 1405 IN DHCP_PROTOCOL *Instance 1406 ) 1407 { 1408 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token; 1409 1410 Token = Instance->Token; 1411 1412 Token->ResponseCount = Instance->ResponseQueue.BufNum; 1413 if (Token->ResponseCount != 0) { 1414 Token->ResponseList = (EFI_DHCP4_PACKET *) AllocatePool (Instance->ResponseQueue.BufSize); 1415 if (Token->ResponseList == NULL) { 1416 Token->Status = EFI_OUT_OF_RESOURCES; 1417 goto SIGNAL_USER; 1418 } 1419 1420 // 1421 // Copy the received DHCP responses. 1422 // 1423 NetbufQueCopy (&Instance->ResponseQueue, 0, Instance->ResponseQueue.BufSize, (UINT8 *) Token->ResponseList); 1424 Token->Status = EFI_SUCCESS; 1425 } else { 1426 Token->ResponseList = NULL; 1427 Token->Status = EFI_TIMEOUT; 1428 } 1429 1430 SIGNAL_USER: 1431 // 1432 // Clean up the resources dedicated for this transmit receive transaction. 1433 // 1434 NetbufQueFlush (&Instance->ResponseQueue); 1435 UdpIoCleanIo (Instance->UdpIo); 1436 gBS->CloseProtocol ( 1437 Instance->UdpIo->UdpHandle, 1438 &gEfiUdp4ProtocolGuid, 1439 Instance->Service->Image, 1440 Instance->Handle 1441 ); 1442 UdpIoFreeIo (Instance->UdpIo); 1443 Instance->UdpIo = NULL; 1444 Instance->Token = NULL; 1445 1446 if (Token->CompletionEvent != NULL) { 1447 gBS->SignalEvent (Token->CompletionEvent); 1448 } 1449 } 1450 1451 1452 /** 1453 Transmits a DHCP formatted packet and optionally waits for responses. 1454 1455 The TransmitReceive() function is used to transmit a DHCP packet and optionally 1456 wait for the response from servers. This function does not change the state of 1457 the EFI DHCPv4 Protocol driver and thus can be used at any time. 1458 1459 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. 1460 @param[in] Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure. 1461 1462 @retval EFI_SUCCESS The packet was successfully queued for transmission. 1463 @retval EFI_INVALID_PARAMETER Some parameter is NULL. 1464 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call 1465 this function after collection process completes. 1466 @retval EFI_NO_MAPPING The default station address is not available yet. 1467 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1468 @retval Others Some other unexpected error occurred. 1469 1470 **/ 1471 EFI_STATUS 1472 EFIAPI 1473 EfiDhcp4TransmitReceive ( 1474 IN EFI_DHCP4_PROTOCOL *This, 1475 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token 1476 ) 1477 { 1478 DHCP_PROTOCOL *Instance; 1479 EFI_TPL OldTpl; 1480 EFI_STATUS Status; 1481 NET_FRAGMENT Frag; 1482 NET_BUF *Wrap; 1483 UDP_END_POINT EndPoint; 1484 IP4_ADDR Ip; 1485 DHCP_SERVICE *DhcpSb; 1486 EFI_IP_ADDRESS Gateway; 1487 IP4_ADDR ClientAddr; 1488 INTN Class; 1489 IP4_ADDR SubnetMask; 1490 1491 if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) { 1492 return EFI_INVALID_PARAMETER; 1493 } 1494 1495 Instance = DHCP_INSTANCE_FROM_THIS (This); 1496 DhcpSb = Instance->Service; 1497 1498 if (Instance->Token != NULL) { 1499 // 1500 // The previous call to TransmitReceive is not finished. 1501 // 1502 return EFI_NOT_READY; 1503 } 1504 1505 if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) || 1506 (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) || 1507 (Token->TimeoutValue == 0) || 1508 ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL)) || 1509 EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL)) || 1510 EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr) 1511 ) { 1512 // 1513 // The DHCP packet isn't well-formed, the Transaction ID is already used, 1514 // the timeout value is zero, the ListenPoint is invalid, or the 1515 // RemoteAddress is zero. 1516 // 1517 return EFI_INVALID_PARAMETER; 1518 } 1519 1520 ClientAddr = EFI_NTOHL (Token->Packet->Dhcp4.Header.ClientAddr); 1521 1522 if (ClientAddr == 0) { 1523 return EFI_NO_MAPPING; 1524 } 1525 1526 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 1527 1528 // 1529 // Save the token and the timeout value. 1530 // 1531 Instance->Token = Token; 1532 Instance->Timeout = Token->TimeoutValue; 1533 1534 // 1535 // Create a UDP IO for this transmit receive transaction. 1536 // 1537 Status = Dhcp4InstanceCreateUdpIo (Instance); 1538 if (EFI_ERROR (Status)) { 1539 goto ON_ERROR; 1540 } 1541 1542 // 1543 // Save the Client Address is sent out 1544 // 1545 CopyMem ( 1546 &DhcpSb->ClientAddressSendOut[0], 1547 &Token->Packet->Dhcp4.Header.ClientHwAddr[0], 1548 Token->Packet->Dhcp4.Header.HwAddrLen 1549 ); 1550 1551 // 1552 // Wrap the DHCP packet into a net buffer. 1553 // 1554 Frag.Bulk = (UINT8 *) &Token->Packet->Dhcp4; 1555 Frag.Len = Token->Packet->Length; 1556 Wrap = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL); 1557 if (Wrap == NULL) { 1558 Status = EFI_OUT_OF_RESOURCES; 1559 goto ON_ERROR; 1560 } 1561 1562 // 1563 // Set the local address and local port to ZERO. 1564 // 1565 ZeroMem (&EndPoint, sizeof (UDP_END_POINT)); 1566 1567 // 1568 // Set the destination address and destination port. 1569 // 1570 CopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS)); 1571 EndPoint.RemoteAddr.Addr[0] = NTOHL (Ip); 1572 1573 if (Token->RemotePort == 0) { 1574 EndPoint.RemotePort = DHCP_SERVER_PORT; 1575 } else { 1576 EndPoint.RemotePort = Token->RemotePort; 1577 } 1578 1579 // 1580 // Get the gateway. 1581 // 1582 Class = NetGetIpClass (ClientAddr); 1583 ASSERT (Class < IP4_ADDR_CLASSE); 1584 SubnetMask = gIp4AllMasks[Class << 3]; 1585 ZeroMem (&Gateway, sizeof (Gateway)); 1586 if (!IP4_NET_EQUAL (ClientAddr, EndPoint.RemoteAddr.Addr[0], SubnetMask)) { 1587 CopyMem (&Gateway.v4, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS)); 1588 Gateway.Addr[0] = NTOHL (Gateway.Addr[0]); 1589 } 1590 1591 // 1592 // Transmit the DHCP packet. 1593 // 1594 Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, &Gateway, DhcpOnPacketSent, NULL); 1595 if (EFI_ERROR (Status)) { 1596 NetbufFree (Wrap); 1597 goto ON_ERROR; 1598 } 1599 1600 // 1601 // Start to receive the DHCP response. 1602 // 1603 Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0); 1604 if (EFI_ERROR (Status)) { 1605 goto ON_ERROR; 1606 } 1607 1608 ON_ERROR: 1609 1610 if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) { 1611 UdpIoCleanIo (Instance->UdpIo); 1612 gBS->CloseProtocol ( 1613 Instance->UdpIo->UdpHandle, 1614 &gEfiUdp4ProtocolGuid, 1615 Instance->Service->Image, 1616 Instance->Handle 1617 ); 1618 UdpIoFreeIo (Instance->UdpIo); 1619 Instance->UdpIo = NULL; 1620 Instance->Token = NULL; 1621 } 1622 1623 gBS->RestoreTPL (OldTpl); 1624 1625 if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) { 1626 // 1627 // Keep polling until timeout if no error happens and the CompletionEvent 1628 // is NULL. 1629 // 1630 while (TRUE) { 1631 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 1632 // 1633 // Raise TPL to protect the UDPIO in instance, in case that DhcpOnTimerTick 1634 // free it when timeout. 1635 // 1636 if (Instance->Timeout > 0) { 1637 Instance->UdpIo->Protocol.Udp4->Poll (Instance->UdpIo->Protocol.Udp4); 1638 gBS->RestoreTPL (OldTpl); 1639 } else { 1640 gBS->RestoreTPL (OldTpl); 1641 break; 1642 } 1643 } 1644 } 1645 1646 return Status; 1647 } 1648 1649 1650 /** 1651 Callback function for DhcpIterateOptions. This callback sets the 1652 EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point 1653 the individual DHCP option in the packet. 1654 1655 @param[in] Tag The DHCP option type 1656 @param[in] Len Length of the DHCP option data 1657 @param[in] Data The DHCP option data 1658 @param[in] Context The context, to pass several parameters in. 1659 1660 @retval EFI_SUCCESS It always returns EFI_SUCCESS 1661 1662 **/ 1663 EFI_STATUS 1664 Dhcp4ParseCheckOption ( 1665 IN UINT8 Tag, 1666 IN UINT8 Len, 1667 IN UINT8 *Data, 1668 IN VOID *Context 1669 ) 1670 { 1671 DHCP_PARSE_CONTEXT *Parse; 1672 1673 Parse = (DHCP_PARSE_CONTEXT *) Context; 1674 Parse->Index++; 1675 1676 if (Parse->Index <= Parse->OptionCount) { 1677 // 1678 // Use BASE_CR to get the memory position of EFI_DHCP4_PACKET_OPTION for 1679 // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only 1680 // pass in the point to option data. 1681 // 1682 Parse->Option[Parse->Index - 1] = BASE_CR (Data, EFI_DHCP4_PACKET_OPTION, Data); 1683 } 1684 1685 return EFI_SUCCESS; 1686 } 1687 1688 1689 /** 1690 Parses the packed DHCP option data. 1691 1692 The Parse() function is used to retrieve the option list from a DHCP packet. 1693 If *OptionCount isn't zero, and there is enough space for all the DHCP options 1694 in the Packet, each element of PacketOptionList is set to point to somewhere in 1695 the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported, 1696 the caller should reassemble the parsed DHCP options to get the finial result. 1697 If *OptionCount is zero or there isn't enough space for all of them, the number 1698 of DHCP options in the Packet is returned in OptionCount. 1699 1700 @param This Pointer to the EFI_DHCP4_PROTOCOL instance. 1701 @param Packet Pointer to packet to be parsed. 1702 @param OptionCount On input, the number of entries in the PacketOptionList. 1703 On output, the number of entries that were written into the 1704 PacketOptionList. 1705 @param PacketOptionList List of packet option entries to be filled in. End option or pad 1706 options are not included. 1707 1708 @retval EFI_SUCCESS The packet was successfully parsed. 1709 @retval EFI_INVALID_PARAMETER Some parameter is NULL. 1710 @retval EFI_BUFFER_TOO_SMALL One or more of the following conditions is TRUE: 1711 1) *OptionCount is smaller than the number of options that 1712 were found in the Packet. 1713 2) PacketOptionList is NULL. 1714 1715 **/ 1716 EFI_STATUS 1717 EFIAPI 1718 EfiDhcp4Parse ( 1719 IN EFI_DHCP4_PROTOCOL *This, 1720 IN EFI_DHCP4_PACKET *Packet, 1721 IN OUT UINT32 *OptionCount, 1722 OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL 1723 ) 1724 { 1725 DHCP_PARSE_CONTEXT Context; 1726 EFI_STATUS Status; 1727 1728 // 1729 // First validate the parameters 1730 // 1731 if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) { 1732 return EFI_INVALID_PARAMETER; 1733 } 1734 1735 if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) || 1736 (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) || 1737 EFI_ERROR (DhcpValidateOptions (Packet, NULL))) { 1738 1739 return EFI_INVALID_PARAMETER; 1740 } 1741 1742 if ((*OptionCount != 0) && (PacketOptionList == NULL)) { 1743 return EFI_BUFFER_TOO_SMALL; 1744 } 1745 1746 ZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *)); 1747 1748 Context.Option = PacketOptionList; 1749 Context.OptionCount = *OptionCount; 1750 Context.Index = 0; 1751 1752 Status = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context); 1753 1754 if (EFI_ERROR (Status)) { 1755 return Status; 1756 } 1757 1758 *OptionCount = Context.Index; 1759 1760 if (Context.Index > Context.OptionCount) { 1761 return EFI_BUFFER_TOO_SMALL; 1762 } 1763 1764 return EFI_SUCCESS; 1765 } 1766 1767 /** 1768 Set the elapsed time based on the given instance and the pointer to the 1769 elapsed time option. 1770 1771 @param[in] Elapsed The pointer to the position to append. 1772 @param[in] Instance The pointer to the Dhcp4 instance. 1773 **/ 1774 VOID 1775 SetElapsedTime ( 1776 IN UINT16 *Elapsed, 1777 IN DHCP_PROTOCOL *Instance 1778 ) 1779 { 1780 WriteUnaligned16 (Elapsed, HTONS(Instance->ElaspedTime)); 1781 } 1782