1 /** @file 2 EFI DHCP protocol implementation. 3 4 Copyright (c) 2006 - 2016, 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 UINT32 mDhcp4DefaultTimeout[4] = { 4, 8, 16, 32 }; 19 20 21 /** 22 Send an initial DISCOVER or REQUEST message according to the 23 DHCP service's current state. 24 25 @param[in] DhcpSb The DHCP service instance 26 27 @retval EFI_SUCCESS The request has been sent 28 @retval other Some error occurs when sending the request. 29 30 **/ 31 EFI_STATUS 32 DhcpInitRequest ( 33 IN DHCP_SERVICE *DhcpSb 34 ) 35 { 36 EFI_STATUS Status; 37 38 ASSERT ((DhcpSb->DhcpState == Dhcp4Init) || (DhcpSb->DhcpState == Dhcp4InitReboot)); 39 40 // 41 // Clear initial time to make sure that elapsed-time is set to 0 for first Discover or REQUEST message. 42 // 43 DhcpSb->ActiveChild->ElaspedTime= 0; 44 45 if (DhcpSb->DhcpState == Dhcp4Init) { 46 DhcpSetState (DhcpSb, Dhcp4Selecting, FALSE); 47 Status = DhcpSendMessage (DhcpSb, NULL, NULL, DHCP_MSG_DISCOVER, NULL); 48 49 if (EFI_ERROR (Status)) { 50 DhcpSb->DhcpState = Dhcp4Init; 51 return Status; 52 } 53 } else { 54 DhcpSetState (DhcpSb, Dhcp4Rebooting, FALSE); 55 Status = DhcpSendMessage (DhcpSb, NULL, NULL, DHCP_MSG_REQUEST, NULL); 56 57 if (EFI_ERROR (Status)) { 58 DhcpSb->DhcpState = Dhcp4InitReboot; 59 return Status; 60 } 61 } 62 63 return EFI_SUCCESS; 64 } 65 66 67 /** 68 Call user provided callback function, and return the value the 69 function returns. If the user doesn't provide a callback, a 70 proper return value is selected to let the caller continue the 71 normal process. 72 73 @param[in] DhcpSb The DHCP service instance 74 @param[in] Event The event as defined in the spec 75 @param[in] Packet The current packet trigger the event 76 @param[out] NewPacket The user's return new packet 77 78 @retval EFI_NOT_READY Direct the caller to continue collecting the offer. 79 @retval EFI_SUCCESS The user function returns success. 80 @retval EFI_ABORTED The user function ask it to abort. 81 82 **/ 83 EFI_STATUS 84 DhcpCallUser ( 85 IN DHCP_SERVICE *DhcpSb, 86 IN EFI_DHCP4_EVENT Event, 87 IN EFI_DHCP4_PACKET *Packet, OPTIONAL 88 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL 89 ) 90 { 91 EFI_DHCP4_CONFIG_DATA *Config; 92 EFI_STATUS Status; 93 94 if (NewPacket != NULL) { 95 *NewPacket = NULL; 96 } 97 98 // 99 // If user doesn't provide the call back function, return the value 100 // that directs the client to continue the normal process. 101 // In Dhcp4Selecting EFI_SUCCESS tells the client to stop collecting 102 // the offers and select a offer, EFI_NOT_READY tells the client to 103 // collect more offers. 104 // 105 Config = &DhcpSb->ActiveConfig; 106 107 if (Config->Dhcp4Callback == NULL) { 108 if (Event == Dhcp4RcvdOffer) { 109 return EFI_NOT_READY; 110 } 111 112 return EFI_SUCCESS; 113 } 114 115 Status = Config->Dhcp4Callback ( 116 &DhcpSb->ActiveChild->Dhcp4Protocol, 117 Config->CallbackContext, 118 (EFI_DHCP4_STATE) DhcpSb->DhcpState, 119 Event, 120 Packet, 121 NewPacket 122 ); 123 124 // 125 // User's callback should only return EFI_SUCCESS, EFI_NOT_READY, 126 // and EFI_ABORTED. If it returns values other than those, assume 127 // it to be EFI_ABORTED. 128 // 129 if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_READY)) { 130 return Status; 131 } 132 133 return EFI_ABORTED; 134 } 135 136 137 /** 138 Notify the user about the operation result. 139 140 @param DhcpSb DHCP service instance 141 @param Which Which notify function to signal 142 143 **/ 144 VOID 145 DhcpNotifyUser ( 146 IN DHCP_SERVICE *DhcpSb, 147 IN INTN Which 148 ) 149 { 150 DHCP_PROTOCOL *Child; 151 152 if ((Child = DhcpSb->ActiveChild) == NULL) { 153 return ; 154 } 155 156 if ((Child->CompletionEvent != NULL) && 157 ((Which == DHCP_NOTIFY_COMPLETION) || (Which == DHCP_NOTIFY_ALL)) 158 ) { 159 160 gBS->SignalEvent (Child->CompletionEvent); 161 Child->CompletionEvent = NULL; 162 } 163 164 if ((Child->RenewRebindEvent != NULL) && 165 ((Which == DHCP_NOTIFY_RENEWREBIND) || (Which == DHCP_NOTIFY_ALL)) 166 ) { 167 168 gBS->SignalEvent (Child->RenewRebindEvent); 169 Child->RenewRebindEvent = NULL; 170 } 171 } 172 173 174 175 /** 176 Set the DHCP state. If CallUser is true, it will try to notify 177 the user before change the state by DhcpNotifyUser. It returns 178 EFI_ABORTED if the user return EFI_ABORTED, otherwise, it returns 179 EFI_SUCCESS. If CallUser is FALSE, it isn't necessary to test 180 the return value of this function. 181 182 @param DhcpSb The DHCP service instance 183 @param State The new DHCP state to change to 184 @param CallUser Whether we need to call user 185 186 @retval EFI_SUCCESS The state is changed 187 @retval EFI_ABORTED The user asks to abort the DHCP process. 188 189 **/ 190 EFI_STATUS 191 DhcpSetState ( 192 IN OUT DHCP_SERVICE *DhcpSb, 193 IN INTN State, 194 IN BOOLEAN CallUser 195 ) 196 { 197 EFI_STATUS Status; 198 199 if (CallUser) { 200 Status = EFI_SUCCESS; 201 202 if (State == Dhcp4Renewing) { 203 Status = DhcpCallUser (DhcpSb, Dhcp4EnterRenewing, NULL, NULL); 204 205 } else if (State == Dhcp4Rebinding) { 206 Status = DhcpCallUser (DhcpSb, Dhcp4EnterRebinding, NULL, NULL); 207 208 } else if (State == Dhcp4Bound) { 209 Status = DhcpCallUser (DhcpSb, Dhcp4BoundCompleted, NULL, NULL); 210 211 } 212 213 if (EFI_ERROR (Status)) { 214 return Status; 215 } 216 } 217 218 // 219 // Update the retransmission timer during the state transition. 220 // This will clear the retry count. This is also why the rule 221 // first transit the state, then send packets. 222 // 223 if (State == Dhcp4Selecting) { 224 DhcpSb->MaxRetries = DhcpSb->ActiveConfig.DiscoverTryCount; 225 } else { 226 DhcpSb->MaxRetries = DhcpSb->ActiveConfig.RequestTryCount; 227 } 228 229 if (DhcpSb->MaxRetries == 0) { 230 DhcpSb->MaxRetries = 4; 231 } 232 233 DhcpSb->CurRetry = 0; 234 DhcpSb->PacketToLive = 0; 235 DhcpSb->LastTimeout = 0; 236 DhcpSb->DhcpState = State; 237 return EFI_SUCCESS; 238 } 239 240 241 /** 242 Set the retransmit timer for the packet. It will select from either 243 the discover timeouts/request timeouts or the default timeout values. 244 245 @param DhcpSb The DHCP service instance. 246 247 **/ 248 VOID 249 DhcpSetTransmitTimer ( 250 IN OUT DHCP_SERVICE *DhcpSb 251 ) 252 { 253 UINT32 *Times; 254 255 ASSERT (DhcpSb->MaxRetries > DhcpSb->CurRetry); 256 257 if (DhcpSb->DhcpState == Dhcp4Selecting) { 258 Times = DhcpSb->ActiveConfig.DiscoverTimeout; 259 } else { 260 Times = DhcpSb->ActiveConfig.RequestTimeout; 261 } 262 263 if (Times == NULL) { 264 Times = mDhcp4DefaultTimeout; 265 } 266 267 DhcpSb->PacketToLive = Times[DhcpSb->CurRetry]; 268 DhcpSb->LastTimeout = DhcpSb->PacketToLive; 269 270 return; 271 } 272 273 /** 274 Compute the lease. If the server grants a permanent lease, just 275 process it as a normal timeout value since the lease will last 276 more than 100 years. 277 278 @param DhcpSb The DHCP service instance 279 @param Para The DHCP parameter extracted from the server's 280 response. 281 **/ 282 VOID 283 DhcpComputeLease ( 284 IN OUT DHCP_SERVICE *DhcpSb, 285 IN DHCP_PARAMETER *Para 286 ) 287 { 288 ASSERT (Para != NULL); 289 290 DhcpSb->Lease = Para->Lease; 291 DhcpSb->T2 = Para->T2; 292 DhcpSb->T1 = Para->T1; 293 294 if (DhcpSb->Lease == 0) { 295 DhcpSb->Lease = DHCP_DEFAULT_LEASE; 296 } 297 298 if ((DhcpSb->T2 == 0) || (DhcpSb->T2 >= Para->Lease)) { 299 DhcpSb->T2 = Para->Lease - (Para->Lease >> 3); 300 } 301 302 if ((DhcpSb->T1 == 0) || (DhcpSb->T1 >= Para->T2)) { 303 DhcpSb->T1 = DhcpSb->Lease >> 1; 304 } 305 } 306 307 308 /** 309 Configure a UDP IO port to use the acquired lease address. 310 DHCP driver needs this port to unicast packet to the server 311 such as DHCP release. 312 313 @param[in] UdpIo The UDP IO to configure 314 @param[in] Context Dhcp service instance. 315 316 @retval EFI_SUCCESS The UDP IO port is successfully configured. 317 @retval Others It failed to configure the port. 318 319 **/ 320 EFI_STATUS 321 EFIAPI 322 DhcpConfigLeaseIoPort ( 323 IN UDP_IO *UdpIo, 324 IN VOID *Context 325 ) 326 { 327 EFI_UDP4_CONFIG_DATA UdpConfigData; 328 EFI_IPv4_ADDRESS Subnet; 329 EFI_IPv4_ADDRESS Gateway; 330 DHCP_SERVICE *DhcpSb; 331 EFI_STATUS Status; 332 IP4_ADDR Ip; 333 334 DhcpSb = (DHCP_SERVICE *) Context; 335 336 UdpConfigData.AcceptBroadcast = FALSE; 337 UdpConfigData.AcceptPromiscuous = FALSE; 338 UdpConfigData.AcceptAnyPort = FALSE; 339 UdpConfigData.AllowDuplicatePort = TRUE; 340 UdpConfigData.TypeOfService = 0; 341 UdpConfigData.TimeToLive = 64; 342 UdpConfigData.DoNotFragment = FALSE; 343 UdpConfigData.ReceiveTimeout = 1; 344 UdpConfigData.TransmitTimeout = 0; 345 346 UdpConfigData.UseDefaultAddress = FALSE; 347 UdpConfigData.StationPort = DHCP_CLIENT_PORT; 348 UdpConfigData.RemotePort = DHCP_SERVER_PORT; 349 350 Ip = HTONL (DhcpSb->ClientAddr); 351 CopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS)); 352 353 Ip = HTONL (DhcpSb->Netmask); 354 CopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS)); 355 356 ZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS)); 357 358 Status = UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfigData); 359 360 if (EFI_ERROR (Status)) { 361 return Status; 362 } 363 364 // 365 // Add a default route if received from the server. 366 // 367 if ((DhcpSb->Para != NULL) && (DhcpSb->Para->Router != 0)) { 368 ZeroMem (&Subnet, sizeof (EFI_IPv4_ADDRESS)); 369 370 Ip = HTONL (DhcpSb->Para->Router); 371 CopyMem (&Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS)); 372 373 UdpIo->Protocol.Udp4->Routes (UdpIo->Protocol.Udp4, FALSE, &Subnet, &Subnet, &Gateway); 374 } 375 376 return EFI_SUCCESS; 377 } 378 379 380 /** 381 Update the lease states when a new lease is acquired. It will not only 382 save the acquired the address and lease time, it will also create a UDP 383 child to provide address resolution for the address. 384 385 @param DhcpSb The DHCP service instance 386 387 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. 388 @retval EFI_SUCCESS The lease is recorded. 389 390 **/ 391 EFI_STATUS 392 DhcpLeaseAcquired ( 393 IN OUT DHCP_SERVICE *DhcpSb 394 ) 395 { 396 DhcpSb->ClientAddr = EFI_NTOHL (DhcpSb->Selected->Dhcp4.Header.YourAddr); 397 398 if (DhcpSb->Para != NULL) { 399 DhcpSb->Netmask = DhcpSb->Para->NetMask; 400 DhcpSb->ServerAddr = DhcpSb->Para->ServerId; 401 } 402 403 if (DhcpSb->Netmask == 0) { 404 return EFI_ABORTED; 405 } 406 407 if (DhcpSb->LeaseIoPort != NULL) { 408 UdpIoFreeIo (DhcpSb->LeaseIoPort); 409 } 410 411 // 412 // Create a UDP/IP child to provide ARP service for the Leased IP, 413 // and transmit unicast packet with it as source address. Don't 414 // start receive on this port, the queued packet will be timeout. 415 // 416 DhcpSb->LeaseIoPort = UdpIoCreateIo ( 417 DhcpSb->Controller, 418 DhcpSb->Image, 419 DhcpConfigLeaseIoPort, 420 UDP_IO_UDP4_VERSION, 421 DhcpSb 422 ); 423 424 if (DhcpSb->LeaseIoPort == NULL) { 425 return EFI_OUT_OF_RESOURCES; 426 } 427 428 if (!DHCP_IS_BOOTP (DhcpSb->Para)) { 429 DhcpComputeLease (DhcpSb, DhcpSb->Para); 430 } 431 432 return DhcpSetState (DhcpSb, Dhcp4Bound, TRUE); 433 } 434 435 436 /** 437 Clean up the DHCP related states, IoStatus isn't reset. 438 439 @param DhcpSb The DHCP instance service. 440 441 **/ 442 VOID 443 DhcpCleanLease ( 444 IN DHCP_SERVICE *DhcpSb 445 ) 446 { 447 DhcpSb->DhcpState = Dhcp4Init; 448 DhcpSb->Xid = DhcpSb->Xid + 1; 449 DhcpSb->ClientAddr = 0; 450 DhcpSb->Netmask = 0; 451 DhcpSb->ServerAddr = 0; 452 453 if (DhcpSb->LastOffer != NULL) { 454 FreePool (DhcpSb->LastOffer); 455 DhcpSb->LastOffer = NULL; 456 } 457 458 if (DhcpSb->Selected != NULL) { 459 FreePool (DhcpSb->Selected); 460 DhcpSb->Selected = NULL; 461 } 462 463 if (DhcpSb->Para != NULL) { 464 FreePool (DhcpSb->Para); 465 DhcpSb->Para = NULL; 466 } 467 468 DhcpSb->Lease = 0; 469 DhcpSb->T1 = 0; 470 DhcpSb->T2 = 0; 471 DhcpSb->ExtraRefresh = FALSE; 472 473 if (DhcpSb->LeaseIoPort != NULL) { 474 UdpIoFreeIo (DhcpSb->LeaseIoPort); 475 DhcpSb->LeaseIoPort = NULL; 476 } 477 478 if (DhcpSb->LastPacket != NULL) { 479 FreePool (DhcpSb->LastPacket); 480 DhcpSb->LastPacket = NULL; 481 } 482 483 DhcpSb->PacketToLive = 0; 484 DhcpSb->LastTimeout = 0; 485 DhcpSb->CurRetry = 0; 486 DhcpSb->MaxRetries = 0; 487 DhcpSb->LeaseLife = 0; 488 489 // 490 // Clean active config data. 491 // 492 DhcpCleanConfigure (&DhcpSb->ActiveConfig); 493 } 494 495 496 /** 497 Select a offer among all the offers collected. If the offer selected is 498 of BOOTP, the lease is recorded and user notified. If the offer is of 499 DHCP, it will request the offer from the server. 500 501 @param[in] DhcpSb The DHCP service instance. 502 503 @retval EFI_SUCCESS One of the offer is selected. 504 505 **/ 506 EFI_STATUS 507 DhcpChooseOffer ( 508 IN DHCP_SERVICE *DhcpSb 509 ) 510 { 511 EFI_DHCP4_PACKET *Selected; 512 EFI_DHCP4_PACKET *NewPacket; 513 EFI_DHCP4_PACKET *TempPacket; 514 EFI_STATUS Status; 515 516 ASSERT (DhcpSb->LastOffer != NULL); 517 518 // 519 // User will cache previous offers if he wants to select 520 // from multiple offers. If user provides an invalid packet, 521 // use the last offer, otherwise use the provided packet. 522 // 523 NewPacket = NULL; 524 Status = DhcpCallUser (DhcpSb, Dhcp4SelectOffer, DhcpSb->LastOffer, &NewPacket); 525 526 if (EFI_ERROR (Status)) { 527 return Status; 528 } 529 530 Selected = DhcpSb->LastOffer; 531 532 if ((NewPacket != NULL) && !EFI_ERROR (DhcpValidateOptions (NewPacket, NULL))) { 533 TempPacket = (EFI_DHCP4_PACKET *) AllocatePool (NewPacket->Size); 534 if (TempPacket != NULL) { 535 CopyMem (TempPacket, NewPacket, NewPacket->Size); 536 FreePool (Selected); 537 Selected = TempPacket; 538 } 539 } 540 541 DhcpSb->Selected = Selected; 542 DhcpSb->LastOffer = NULL; 543 DhcpSb->Para = NULL; 544 DhcpValidateOptions (Selected, &DhcpSb->Para); 545 546 // 547 // A bootp offer has been selected, save the lease status, 548 // enter bound state then notify the user. 549 // 550 if (DHCP_IS_BOOTP (DhcpSb->Para)) { 551 Status = DhcpLeaseAcquired (DhcpSb); 552 553 if (EFI_ERROR (Status)) { 554 return Status; 555 } 556 557 DhcpSb->IoStatus = EFI_SUCCESS; 558 DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_ALL); 559 return EFI_SUCCESS; 560 } 561 562 // 563 // Send a DHCP requests 564 // 565 Status = DhcpSetState (DhcpSb, Dhcp4Requesting, TRUE); 566 567 if (EFI_ERROR (Status)) { 568 return Status; 569 } 570 571 return DhcpSendMessage (DhcpSb, Selected, DhcpSb->Para, DHCP_MSG_REQUEST, NULL); 572 } 573 574 575 /** 576 Terminate the current address acquire. All the allocated resources 577 are released. Be careful when calling this function. A rule related 578 to this is: only call DhcpEndSession at the highest level, such as 579 DhcpInput, DhcpOnTimerTick...At the other level, just return error. 580 581 @param[in] DhcpSb The DHCP service instance 582 @param[in] Status The result of the DHCP process. 583 584 **/ 585 VOID 586 DhcpEndSession ( 587 IN DHCP_SERVICE *DhcpSb, 588 IN EFI_STATUS Status 589 ) 590 { 591 if (DHCP_CONNECTED (DhcpSb->DhcpState)) { 592 DhcpCallUser (DhcpSb, Dhcp4AddressLost, NULL, NULL); 593 } else { 594 DhcpCallUser (DhcpSb, Dhcp4Fail, NULL, NULL); 595 } 596 597 DhcpCleanLease (DhcpSb); 598 599 DhcpSb->IoStatus = Status; 600 DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_ALL); 601 } 602 603 604 /** 605 Handle packets in DHCP select state. 606 607 @param[in] DhcpSb The DHCP service instance 608 @param[in] Packet The DHCP packet received 609 @param[in] Para The DHCP parameter extracted from the packet. That 610 is, all the option value that we care. 611 612 @retval EFI_SUCCESS The packet is successfully processed. 613 @retval Others Some error occured. 614 615 **/ 616 EFI_STATUS 617 DhcpHandleSelect ( 618 IN DHCP_SERVICE *DhcpSb, 619 IN EFI_DHCP4_PACKET *Packet, 620 IN DHCP_PARAMETER *Para 621 ) 622 { 623 EFI_STATUS Status; 624 625 Status = EFI_SUCCESS; 626 627 // 628 // First validate the message: 629 // 1. the offer is a unicast 630 // 2. if it is a DHCP message, it must contains a server ID. 631 // Don't return a error for these two case otherwise the session is ended. 632 // 633 if (!DHCP_IS_BOOTP (Para) && 634 ((Para->DhcpType != DHCP_MSG_OFFER) || (Para->ServerId == 0)) 635 ) { 636 goto ON_EXIT; 637 } 638 639 // 640 // Call the user's callback. The action according to the return is as: 641 // 1. EFI_SUCESS: stop waiting for more offers, select the offer now 642 // 2. EFI_NOT_READY: wait for more offers 643 // 3. EFI_ABORTED: abort the address acquiring. 644 // 645 Status = DhcpCallUser (DhcpSb, Dhcp4RcvdOffer, Packet, NULL); 646 647 if (Status == EFI_SUCCESS) { 648 if (DhcpSb->LastOffer != NULL) { 649 FreePool (DhcpSb->LastOffer); 650 } 651 652 DhcpSb->LastOffer = Packet; 653 654 return DhcpChooseOffer (DhcpSb); 655 656 } else if (Status == EFI_NOT_READY) { 657 if (DhcpSb->LastOffer != NULL) { 658 FreePool (DhcpSb->LastOffer); 659 } 660 661 DhcpSb->LastOffer = Packet; 662 663 } else if (Status == EFI_ABORTED) { 664 // 665 // DhcpInput will end the session upon error return. Remember 666 // only to call DhcpEndSession at the top level call. 667 // 668 goto ON_EXIT; 669 } 670 671 return EFI_SUCCESS; 672 673 ON_EXIT: 674 FreePool (Packet); 675 return Status; 676 } 677 678 679 /** 680 Handle packets in DHCP request state. 681 682 @param[in] DhcpSb The DHCP service instance 683 @param[in] Packet The DHCP packet received 684 @param[in] Para The DHCP parameter extracted from the packet. That 685 is, all the option value that we care. 686 687 @retval EFI_SUCCESS The packet is successfully processed. 688 @retval Others Some error occured. 689 690 **/ 691 EFI_STATUS 692 DhcpHandleRequest ( 693 IN DHCP_SERVICE *DhcpSb, 694 IN EFI_DHCP4_PACKET *Packet, 695 IN DHCP_PARAMETER *Para 696 ) 697 { 698 EFI_DHCP4_HEADER *Head; 699 EFI_DHCP4_HEADER *Selected; 700 EFI_STATUS Status; 701 UINT8 *Message; 702 703 ASSERT (!DHCP_IS_BOOTP (DhcpSb->Para)); 704 705 Head = &Packet->Dhcp4.Header; 706 Selected = &DhcpSb->Selected->Dhcp4.Header; 707 708 // 709 // Ignore the BOOTP message and DHCP messages other than DHCP ACK/NACK. 710 // 711 if (DHCP_IS_BOOTP (Para) || 712 (Para->ServerId != DhcpSb->Para->ServerId) || 713 ((Para->DhcpType != DHCP_MSG_ACK) && (Para->DhcpType != DHCP_MSG_NAK)) 714 ) { 715 716 Status = EFI_SUCCESS; 717 goto ON_EXIT; 718 } 719 720 // 721 // Received a NAK, end the session no matter what the user returns 722 // 723 Status = EFI_DEVICE_ERROR; 724 725 if (Para->DhcpType == DHCP_MSG_NAK) { 726 DhcpCallUser (DhcpSb, Dhcp4RcvdNak, Packet, NULL); 727 goto ON_EXIT; 728 } 729 730 // 731 // Check whether the ACK matches the selected offer 732 // 733 Message = NULL; 734 735 if (!EFI_IP4_EQUAL (&Head->YourAddr, &Selected->YourAddr)) { 736 Message = (UINT8 *) "Lease confirmed isn't the same as that in the offer"; 737 goto REJECT; 738 } 739 740 Status = DhcpCallUser (DhcpSb, Dhcp4RcvdAck, Packet, NULL); 741 742 if (EFI_ERROR (Status)) { 743 Message = (UINT8 *) "Lease is denied upon received ACK"; 744 goto REJECT; 745 } 746 747 // 748 // Record the lease, transit to BOUND state, then notify the user 749 // 750 Status = DhcpLeaseAcquired (DhcpSb); 751 752 if (EFI_ERROR (Status)) { 753 Message = (UINT8 *) "Lease is denied upon entering bound"; 754 goto REJECT; 755 } 756 757 DhcpSb->IoStatus = EFI_SUCCESS; 758 DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_COMPLETION); 759 760 FreePool (Packet); 761 return EFI_SUCCESS; 762 763 REJECT: 764 DhcpSendMessage (DhcpSb, DhcpSb->Selected, DhcpSb->Para, DHCP_MSG_DECLINE, Message); 765 766 ON_EXIT: 767 FreePool (Packet); 768 return Status; 769 } 770 771 772 /** 773 Handle packets in DHCP renew/rebound state. 774 775 @param[in] DhcpSb The DHCP service instance 776 @param[in] Packet The DHCP packet received 777 @param[in] Para The DHCP parameter extracted from the packet. That 778 is, all the option value that we care. 779 780 @retval EFI_SUCCESS The packet is successfully processed. 781 @retval Others Some error occured. 782 783 **/ 784 EFI_STATUS 785 DhcpHandleRenewRebind ( 786 IN DHCP_SERVICE *DhcpSb, 787 IN EFI_DHCP4_PACKET *Packet, 788 IN DHCP_PARAMETER *Para 789 ) 790 { 791 EFI_DHCP4_HEADER *Head; 792 EFI_DHCP4_HEADER *Selected; 793 EFI_STATUS Status; 794 795 ASSERT (!DHCP_IS_BOOTP (DhcpSb->Para)); 796 797 Head = &Packet->Dhcp4.Header; 798 Selected = &DhcpSb->Selected->Dhcp4.Header; 799 800 // 801 // Ignore the BOOTP message and DHCP messages other than DHCP ACK/NACK 802 // 803 if (DHCP_IS_BOOTP (Para) || 804 (Para->ServerId != DhcpSb->Para->ServerId) || 805 ((Para->DhcpType != DHCP_MSG_ACK) && (Para->DhcpType != DHCP_MSG_NAK)) 806 ) { 807 808 Status = EFI_SUCCESS; 809 goto ON_EXIT; 810 } 811 812 // 813 // Received a NAK, ignore the user's return then terminate the process 814 // 815 Status = EFI_DEVICE_ERROR; 816 817 if (Para->DhcpType == DHCP_MSG_NAK) { 818 DhcpCallUser (DhcpSb, Dhcp4RcvdNak, Packet, NULL); 819 goto ON_EXIT; 820 } 821 822 // 823 // The lease is different from the selected. Don't send a DECLINE 824 // since it isn't existed in the client's FSM. 825 // 826 if (!EFI_IP4_EQUAL (&Head->YourAddr, &Selected->YourAddr)) { 827 goto ON_EXIT; 828 } 829 830 Status = DhcpCallUser (DhcpSb, Dhcp4RcvdAck, Packet, NULL); 831 832 if (EFI_ERROR (Status)) { 833 goto ON_EXIT; 834 } 835 836 // 837 // Record the lease, start timer for T1 and T2, 838 // 839 DhcpComputeLease (DhcpSb, Para); 840 DhcpSb->LeaseLife = 0; 841 DhcpSetState (DhcpSb, Dhcp4Bound, TRUE); 842 843 if (DhcpSb->ExtraRefresh != 0) { 844 DhcpSb->ExtraRefresh = FALSE; 845 846 DhcpSb->IoStatus = EFI_SUCCESS; 847 DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_RENEWREBIND); 848 } 849 850 ON_EXIT: 851 FreePool (Packet); 852 return Status; 853 } 854 855 856 /** 857 Handle packets in DHCP reboot state. 858 859 @param[in] DhcpSb The DHCP service instance 860 @param[in] Packet The DHCP packet received 861 @param[in] Para The DHCP parameter extracted from the packet. That 862 is, all the option value that we care. 863 864 @retval EFI_SUCCESS The packet is successfully processed. 865 @retval Others Some error occured. 866 867 **/ 868 EFI_STATUS 869 DhcpHandleReboot ( 870 IN DHCP_SERVICE *DhcpSb, 871 IN EFI_DHCP4_PACKET *Packet, 872 IN DHCP_PARAMETER *Para 873 ) 874 { 875 EFI_DHCP4_HEADER *Head; 876 EFI_STATUS Status; 877 878 Head = &Packet->Dhcp4.Header; 879 880 // 881 // Ignore the BOOTP message and DHCP messages other than DHCP ACK/NACK 882 // 883 if (DHCP_IS_BOOTP (Para) || 884 ((Para->DhcpType != DHCP_MSG_ACK) && (Para->DhcpType != DHCP_MSG_NAK)) 885 ) { 886 887 Status = EFI_SUCCESS; 888 goto ON_EXIT; 889 } 890 891 // 892 // If a NAK is received, transit to INIT and try again. 893 // 894 if (Para->DhcpType == DHCP_MSG_NAK) { 895 DhcpCallUser (DhcpSb, Dhcp4RcvdNak, Packet, NULL); 896 897 DhcpSb->ClientAddr = 0; 898 DhcpSb->DhcpState = Dhcp4Init; 899 900 Status = DhcpInitRequest (DhcpSb); 901 goto ON_EXIT; 902 } 903 904 // 905 // Check whether the ACK matches the selected offer 906 // 907 if (EFI_NTOHL (Head->YourAddr) != DhcpSb->ClientAddr) { 908 Status = EFI_DEVICE_ERROR; 909 goto ON_EXIT; 910 } 911 912 Status = DhcpCallUser (DhcpSb, Dhcp4RcvdAck, Packet, NULL); 913 if (EFI_ERROR (Status)) { 914 goto ON_EXIT; 915 } 916 917 // 918 // OK, get the parameter from server, record the lease 919 // 920 DhcpSb->Para = AllocateCopyPool (sizeof (DHCP_PARAMETER), Para); 921 if (DhcpSb->Para == NULL) { 922 Status = EFI_OUT_OF_RESOURCES; 923 goto ON_EXIT; 924 } 925 926 DhcpSb->Selected = Packet; 927 Status = DhcpLeaseAcquired (DhcpSb); 928 if (EFI_ERROR (Status)) { 929 return Status; 930 } 931 932 DhcpSb->IoStatus = EFI_SUCCESS; 933 DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_COMPLETION); 934 return EFI_SUCCESS; 935 936 ON_EXIT: 937 FreePool (Packet); 938 return Status; 939 } 940 941 942 /** 943 Handle the received DHCP packets. This function drives the DHCP 944 state machine. 945 946 @param UdpPacket The UDP packets received. 947 @param EndPoint The local/remote UDP access point 948 @param IoStatus The status of the UDP receive 949 @param Context The opaque parameter to the function. 950 951 **/ 952 VOID 953 EFIAPI 954 DhcpInput ( 955 NET_BUF *UdpPacket, 956 UDP_END_POINT *EndPoint, 957 EFI_STATUS IoStatus, 958 VOID *Context 959 ) 960 { 961 DHCP_SERVICE *DhcpSb; 962 EFI_DHCP4_HEADER *Head; 963 EFI_DHCP4_PACKET *Packet; 964 DHCP_PARAMETER *Para; 965 EFI_STATUS Status; 966 UINT32 Len; 967 968 Packet = NULL; 969 DhcpSb = (DHCP_SERVICE *) Context; 970 971 // 972 // Don't restart receive if error occurs or DHCP is destroyed. 973 // 974 if (EFI_ERROR (IoStatus)) { 975 return ; 976 } else if (DhcpSb->ServiceState == DHCP_DESTROY) { 977 NetbufFree (UdpPacket); 978 return ; 979 } 980 981 ASSERT (UdpPacket != NULL); 982 983 if (DhcpSb->DhcpState == Dhcp4Stopped) { 984 goto RESTART; 985 } 986 987 // 988 // Validate the packet received 989 // 990 if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) { 991 goto RESTART; 992 } 993 994 // 995 // Copy the DHCP message to a continuous memory block 996 // 997 Len = sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER); 998 Packet = (EFI_DHCP4_PACKET *) AllocatePool (Len); 999 1000 if (Packet == NULL) { 1001 goto RESTART; 1002 } 1003 1004 Packet->Size = Len; 1005 Head = &Packet->Dhcp4.Header; 1006 Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *) Head); 1007 1008 if (Packet->Length != UdpPacket->TotalSize) { 1009 goto RESTART; 1010 } 1011 1012 // 1013 // Is this packet the answer to our packet? 1014 // 1015 if ((Head->OpCode != BOOTP_REPLY) || 1016 (NTOHL (Head->Xid) != DhcpSb->Xid) || 1017 (CompareMem (DhcpSb->ClientAddressSendOut, Head->ClientHwAddr, Head->HwAddrLen) != 0)) { 1018 goto RESTART; 1019 } 1020 1021 // 1022 // Validate the options and retrieve the interested options 1023 // 1024 Para = NULL; 1025 if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) && 1026 (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) && 1027 EFI_ERROR (DhcpValidateOptions (Packet, &Para))) { 1028 1029 goto RESTART; 1030 } 1031 1032 // 1033 // Call the handler for each state. The handler should return 1034 // EFI_SUCCESS if the process can go on no matter whether the 1035 // packet is ignored or not. If the return is EFI_ERROR, the 1036 // session will be terminated. Packet's ownership is handled 1037 // over to the handlers. If operation succeeds, the handler 1038 // must notify the user. It isn't necessary to do if EFI_ERROR 1039 // is returned because the DhcpEndSession will notify the user. 1040 // 1041 Status = EFI_SUCCESS; 1042 1043 switch (DhcpSb->DhcpState) { 1044 case Dhcp4Selecting: 1045 Status = DhcpHandleSelect (DhcpSb, Packet, Para); 1046 break; 1047 1048 case Dhcp4Requesting: 1049 Status = DhcpHandleRequest (DhcpSb, Packet, Para); 1050 break; 1051 1052 case Dhcp4InitReboot: 1053 case Dhcp4Init: 1054 case Dhcp4Bound: 1055 // 1056 // Ignore the packet in INITREBOOT, INIT and BOUND states 1057 // 1058 FreePool (Packet); 1059 Status = EFI_SUCCESS; 1060 break; 1061 1062 case Dhcp4Renewing: 1063 case Dhcp4Rebinding: 1064 Status = DhcpHandleRenewRebind (DhcpSb, Packet, Para); 1065 break; 1066 1067 case Dhcp4Rebooting: 1068 Status = DhcpHandleReboot (DhcpSb, Packet, Para); 1069 break; 1070 } 1071 1072 if (Para != NULL) { 1073 FreePool (Para); 1074 } 1075 1076 Packet = NULL; 1077 1078 if (EFI_ERROR (Status)) { 1079 NetbufFree (UdpPacket); 1080 UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0); 1081 DhcpEndSession (DhcpSb, Status); 1082 return ; 1083 } 1084 1085 RESTART: 1086 NetbufFree (UdpPacket); 1087 1088 if (Packet != NULL) { 1089 FreePool (Packet); 1090 } 1091 1092 Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0); 1093 1094 if (EFI_ERROR (Status)) { 1095 DhcpEndSession (DhcpSb, EFI_DEVICE_ERROR); 1096 } 1097 } 1098 1099 1100 /** 1101 Release the packet. 1102 1103 @param[in] Arg The packet to release 1104 1105 **/ 1106 VOID 1107 EFIAPI 1108 DhcpReleasePacket ( 1109 IN VOID *Arg 1110 ) 1111 { 1112 FreePool (Arg); 1113 } 1114 1115 1116 /** 1117 Release the net buffer when packet is sent. 1118 1119 @param UdpPacket The UDP packets received. 1120 @param EndPoint The local/remote UDP access point 1121 @param IoStatus The status of the UDP receive 1122 @param Context The opaque parameter to the function. 1123 1124 **/ 1125 VOID 1126 EFIAPI 1127 DhcpOnPacketSent ( 1128 NET_BUF *Packet, 1129 UDP_END_POINT *EndPoint, 1130 EFI_STATUS IoStatus, 1131 VOID *Context 1132 ) 1133 { 1134 NetbufFree (Packet); 1135 } 1136 1137 1138 1139 /** 1140 Build and transmit a DHCP message according to the current states. 1141 This function implement the Table 5. of RFC 2131. Always transits 1142 the state (as defined in Figure 5. of the same RFC) before sending 1143 a DHCP message. The table is adjusted accordingly. 1144 1145 @param[in] DhcpSb The DHCP service instance 1146 @param[in] Seed The seed packet which the new packet is based on 1147 @param[in] Para The DHCP parameter of the Seed packet 1148 @param[in] Type The message type to send 1149 @param[in] Msg The human readable message to include in the packet 1150 sent. 1151 1152 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources for the packet 1153 @retval EFI_ACCESS_DENIED Failed to transmit the packet through UDP 1154 @retval EFI_SUCCESS The message is sent 1155 @retval other Other error occurs 1156 1157 **/ 1158 EFI_STATUS 1159 DhcpSendMessage ( 1160 IN DHCP_SERVICE *DhcpSb, 1161 IN EFI_DHCP4_PACKET *Seed, 1162 IN DHCP_PARAMETER *Para, 1163 IN UINT8 Type, 1164 IN UINT8 *Msg 1165 ) 1166 { 1167 EFI_DHCP4_CONFIG_DATA *Config; 1168 EFI_DHCP4_PACKET *Packet; 1169 EFI_DHCP4_PACKET *NewPacket; 1170 EFI_DHCP4_HEADER *Head; 1171 EFI_DHCP4_HEADER *SeedHead; 1172 UDP_IO *UdpIo; 1173 UDP_END_POINT EndPoint; 1174 NET_BUF *Wrap; 1175 NET_FRAGMENT Frag; 1176 EFI_STATUS Status; 1177 IP4_ADDR IpAddr; 1178 UINT8 *Buf; 1179 UINT16 MaxMsg; 1180 UINT32 Len; 1181 UINT32 Index; 1182 1183 // 1184 // Allocate a big enough memory block to hold the DHCP packet 1185 // 1186 Len = sizeof (EFI_DHCP4_PACKET) + 128 + DhcpSb->UserOptionLen; 1187 1188 if (Msg != NULL) { 1189 Len += (UINT32)AsciiStrLen ((CHAR8 *) Msg); 1190 } 1191 1192 Packet = AllocatePool (Len); 1193 1194 if (Packet == NULL) { 1195 return EFI_OUT_OF_RESOURCES; 1196 } 1197 1198 Packet->Size = Len; 1199 Packet->Length = sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32); 1200 1201 // 1202 // Fill in the DHCP header fields 1203 // 1204 Config = &DhcpSb->ActiveConfig; 1205 SeedHead = NULL; 1206 1207 if (Seed != NULL) { 1208 SeedHead = &Seed->Dhcp4.Header; 1209 } 1210 1211 Head = &Packet->Dhcp4.Header; 1212 ZeroMem (Head, sizeof (EFI_DHCP4_HEADER)); 1213 1214 Head->OpCode = BOOTP_REQUEST; 1215 Head->HwType = DhcpSb->HwType; 1216 Head->HwAddrLen = DhcpSb->HwLen; 1217 Head->Xid = HTONL (DhcpSb->Xid); 1218 Head->Reserved = HTONS (0x8000); //Server, broadcast the message please. 1219 1220 EFI_IP4 (Head->ClientAddr) = HTONL (DhcpSb->ClientAddr); 1221 CopyMem (Head->ClientHwAddr, DhcpSb->Mac.Addr, DhcpSb->HwLen); 1222 1223 if ((Type == DHCP_MSG_DECLINE) || (Type == DHCP_MSG_RELEASE)) { 1224 Head->Seconds = 0; 1225 } else if ((Type == DHCP_MSG_REQUEST) && (DhcpSb->DhcpState == Dhcp4Requesting)) { 1226 // 1227 // Use the same value as the original DHCPDISCOVER message. 1228 // 1229 Head->Seconds = DhcpSb->LastPacket->Dhcp4.Header.Seconds; 1230 } else { 1231 SetElapsedTime(&Head->Seconds, DhcpSb->ActiveChild); 1232 } 1233 1234 // 1235 // Append the DHCP message type 1236 // 1237 Packet->Dhcp4.Magik = DHCP_OPTION_MAGIC; 1238 Buf = Packet->Dhcp4.Option; 1239 Buf = DhcpAppendOption (Buf, DHCP4_TAG_MSG_TYPE, 1, &Type); 1240 1241 // 1242 // Append the serverid option if necessary: 1243 // 1. DHCP decline message 1244 // 2. DHCP release message 1245 // 3. DHCP request to confirm one lease. 1246 // 1247 if ((Type == DHCP_MSG_DECLINE) || (Type == DHCP_MSG_RELEASE) || 1248 ((Type == DHCP_MSG_REQUEST) && (DhcpSb->DhcpState == Dhcp4Requesting)) 1249 ) { 1250 1251 ASSERT ((Para != NULL) && (Para->ServerId != 0)); 1252 1253 IpAddr = HTONL (Para->ServerId); 1254 Buf = DhcpAppendOption (Buf, DHCP4_TAG_SERVER_ID, 4, (UINT8 *) &IpAddr); 1255 } 1256 1257 // 1258 // Append the requested IP option if necessary: 1259 // 1. DHCP request to use the previously allocated address 1260 // 2. DHCP request to confirm one lease 1261 // 3. DHCP decline to decline one lease 1262 // 1263 IpAddr = 0; 1264 1265 if (Type == DHCP_MSG_REQUEST) { 1266 if (DhcpSb->DhcpState == Dhcp4Rebooting) { 1267 IpAddr = EFI_IP4 (Config->ClientAddress); 1268 1269 } else if (DhcpSb->DhcpState == Dhcp4Requesting) { 1270 ASSERT (SeedHead != NULL); 1271 IpAddr = EFI_IP4 (SeedHead->YourAddr); 1272 } 1273 1274 } else if (Type == DHCP_MSG_DECLINE) { 1275 ASSERT (SeedHead != NULL); 1276 IpAddr = EFI_IP4 (SeedHead->YourAddr); 1277 } 1278 1279 if (IpAddr != 0) { 1280 Buf = DhcpAppendOption (Buf, DHCP4_TAG_REQUEST_IP, 4, (UINT8 *) &IpAddr); 1281 } 1282 1283 // 1284 // Append the Max Message Length option if it isn't a DECLINE 1285 // or RELEASE to direct the server use large messages instead of 1286 // override the BOOTFILE and SERVER fields in the message head. 1287 // 1288 if ((Type != DHCP_MSG_DECLINE) && (Type != DHCP_MSG_RELEASE)) { 1289 MaxMsg = HTONS (0xFF00); 1290 Buf = DhcpAppendOption (Buf, DHCP4_TAG_MAXMSG, 2, (UINT8 *) &MaxMsg); 1291 } 1292 1293 // 1294 // Append the user's message if it isn't NULL 1295 // 1296 if (Msg != NULL) { 1297 Len = MIN ((UINT32) AsciiStrLen ((CHAR8 *) Msg), 255); 1298 Buf = DhcpAppendOption (Buf, DHCP4_TAG_MESSAGE, (UINT16) Len, Msg); 1299 } 1300 1301 // 1302 // Append the user configured options 1303 // 1304 if (DhcpSb->UserOptionLen != 0) { 1305 for (Index = 0; Index < Config->OptionCount; Index++) { 1306 // 1307 // We can't use any option other than the client ID from user 1308 // if it is a DHCP decline or DHCP release . 1309 // 1310 if (((Type == DHCP_MSG_DECLINE) || (Type == DHCP_MSG_RELEASE)) && 1311 (Config->OptionList[Index]->OpCode != DHCP4_TAG_CLIENT_ID)) { 1312 continue; 1313 } 1314 1315 Buf = DhcpAppendOption ( 1316 Buf, 1317 Config->OptionList[Index]->OpCode, 1318 Config->OptionList[Index]->Length, 1319 Config->OptionList[Index]->Data 1320 ); 1321 } 1322 } 1323 1324 *(Buf++) = DHCP4_TAG_EOP; 1325 Packet->Length += (UINT32) (Buf - Packet->Dhcp4.Option); 1326 1327 // 1328 // OK, the message is built, call the user to override it. 1329 // 1330 Status = EFI_SUCCESS; 1331 NewPacket = NULL; 1332 1333 if (Type == DHCP_MSG_DISCOVER) { 1334 Status = DhcpCallUser (DhcpSb, Dhcp4SendDiscover, Packet, &NewPacket); 1335 1336 } else if (Type == DHCP_MSG_REQUEST) { 1337 Status = DhcpCallUser (DhcpSb, Dhcp4SendRequest, Packet, &NewPacket); 1338 1339 } else if (Type == DHCP_MSG_DECLINE) { 1340 Status = DhcpCallUser (DhcpSb, Dhcp4SendDecline, Packet, &NewPacket); 1341 } 1342 1343 if (EFI_ERROR (Status)) { 1344 FreePool (Packet); 1345 return Status; 1346 } 1347 1348 if (NewPacket != NULL) { 1349 FreePool (Packet); 1350 Packet = NewPacket; 1351 } 1352 1353 // 1354 // Save the Client Address will be sent out 1355 // 1356 CopyMem ( 1357 &DhcpSb->ClientAddressSendOut[0], 1358 &Packet->Dhcp4.Header.ClientHwAddr[0], 1359 Packet->Dhcp4.Header.HwAddrLen 1360 ); 1361 1362 1363 // 1364 // Wrap it into a netbuf then send it. 1365 // 1366 Frag.Bulk = (UINT8 *) &Packet->Dhcp4.Header; 1367 Frag.Len = Packet->Length; 1368 Wrap = NetbufFromExt (&Frag, 1, 0, 0, DhcpReleasePacket, Packet); 1369 1370 if (Wrap == NULL) { 1371 FreePool (Packet); 1372 return EFI_OUT_OF_RESOURCES; 1373 } 1374 1375 // 1376 // Save it as the last sent packet for retransmission 1377 // 1378 if (DhcpSb->LastPacket != NULL) { 1379 FreePool (DhcpSb->LastPacket); 1380 } 1381 1382 DhcpSb->LastPacket = Packet; 1383 DhcpSetTransmitTimer (DhcpSb); 1384 1385 // 1386 // Broadcast the message, unless we know the server address. 1387 // Use the lease UdpIo port to send the unicast packet. 1388 // 1389 EndPoint.RemoteAddr.Addr[0] = 0xffffffff; 1390 EndPoint.LocalAddr.Addr[0] = 0; 1391 EndPoint.RemotePort = DHCP_SERVER_PORT; 1392 EndPoint.LocalPort = DHCP_CLIENT_PORT; 1393 UdpIo = DhcpSb->UdpIo; 1394 1395 if ((DhcpSb->DhcpState == Dhcp4Renewing) || (Type == DHCP_MSG_RELEASE)) { 1396 EndPoint.RemoteAddr.Addr[0] = DhcpSb->ServerAddr; 1397 EndPoint.LocalAddr.Addr[0] = DhcpSb->ClientAddr; 1398 UdpIo = DhcpSb->LeaseIoPort; 1399 } 1400 1401 ASSERT (UdpIo != NULL); 1402 NET_GET_REF (Wrap); 1403 1404 Status = UdpIoSendDatagram ( 1405 UdpIo, 1406 Wrap, 1407 &EndPoint, 1408 NULL, 1409 DhcpOnPacketSent, 1410 DhcpSb 1411 ); 1412 1413 if (EFI_ERROR (Status)) { 1414 NET_PUT_REF (Wrap); 1415 return EFI_ACCESS_DENIED; 1416 } 1417 1418 return EFI_SUCCESS; 1419 } 1420 1421 1422 /** 1423 Retransmit a saved packet. Only DISCOVER and REQUEST messages 1424 will be retransmitted. 1425 1426 @param[in] DhcpSb The DHCP service instance 1427 1428 @retval EFI_ACCESS_DENIED Failed to transmit packet through UDP port 1429 @retval EFI_SUCCESS The packet is retransmitted. 1430 1431 **/ 1432 EFI_STATUS 1433 DhcpRetransmit ( 1434 IN DHCP_SERVICE *DhcpSb 1435 ) 1436 { 1437 UDP_IO *UdpIo; 1438 UDP_END_POINT EndPoint; 1439 NET_BUF *Wrap; 1440 NET_FRAGMENT Frag; 1441 EFI_STATUS Status; 1442 1443 ASSERT (DhcpSb->LastPacket != NULL); 1444 1445 // 1446 // For REQUEST message in Dhcp4Requesting state, do not change the secs fields. 1447 // 1448 if (DhcpSb->DhcpState != Dhcp4Requesting) { 1449 SetElapsedTime(&DhcpSb->LastPacket->Dhcp4.Header.Seconds, DhcpSb->ActiveChild); 1450 } 1451 1452 // 1453 // Wrap it into a netbuf then send it. 1454 // 1455 Frag.Bulk = (UINT8 *) &DhcpSb->LastPacket->Dhcp4.Header; 1456 Frag.Len = DhcpSb->LastPacket->Length; 1457 Wrap = NetbufFromExt (&Frag, 1, 0, 0, DhcpReleasePacket, DhcpSb->LastPacket); 1458 1459 if (Wrap == NULL) { 1460 return EFI_OUT_OF_RESOURCES; 1461 } 1462 1463 // 1464 // Broadcast the message, unless we know the server address. 1465 // 1466 EndPoint.RemotePort = DHCP_SERVER_PORT; 1467 EndPoint.LocalPort = DHCP_CLIENT_PORT; 1468 EndPoint.RemoteAddr.Addr[0] = 0xffffffff; 1469 EndPoint.LocalAddr.Addr[0] = 0; 1470 UdpIo = DhcpSb->UdpIo; 1471 1472 if (DhcpSb->DhcpState == Dhcp4Renewing) { 1473 EndPoint.RemoteAddr.Addr[0] = DhcpSb->ServerAddr; 1474 EndPoint.LocalAddr.Addr[0] = DhcpSb->ClientAddr; 1475 UdpIo = DhcpSb->LeaseIoPort; 1476 } 1477 1478 ASSERT (UdpIo != NULL); 1479 1480 NET_GET_REF (Wrap); 1481 Status = UdpIoSendDatagram ( 1482 UdpIo, 1483 Wrap, 1484 &EndPoint, 1485 NULL, 1486 DhcpOnPacketSent, 1487 DhcpSb 1488 ); 1489 1490 if (EFI_ERROR (Status)) { 1491 NET_PUT_REF (Wrap); 1492 return EFI_ACCESS_DENIED; 1493 } 1494 1495 return EFI_SUCCESS; 1496 } 1497 1498 1499 /** 1500 Each DHCP service has three timer. Two of them are count down timer. 1501 One for the packet retransmission. The other is to collect the offers. 1502 The third timer increaments the lease life which is compared to T1, T2, 1503 and lease to determine the time to renew and rebind the lease. 1504 DhcpOnTimerTick will be called once every second. 1505 1506 @param[in] Event The timer event 1507 @param[in] Context The context, which is the DHCP service instance. 1508 1509 **/ 1510 VOID 1511 EFIAPI 1512 DhcpOnTimerTick ( 1513 IN EFI_EVENT Event, 1514 IN VOID *Context 1515 ) 1516 { 1517 LIST_ENTRY *Entry; 1518 LIST_ENTRY *Next; 1519 DHCP_SERVICE *DhcpSb; 1520 DHCP_PROTOCOL *Instance; 1521 EFI_STATUS Status; 1522 1523 DhcpSb = (DHCP_SERVICE *) Context; 1524 Instance = DhcpSb->ActiveChild; 1525 1526 // 1527 // 0xffff is the maximum supported value for elapsed time according to RFC. 1528 // 1529 if (Instance != NULL && Instance->ElaspedTime < 0xffff) { 1530 Instance->ElaspedTime++; 1531 } 1532 1533 // 1534 // Check the retransmit timer 1535 // 1536 if ((DhcpSb->PacketToLive > 0) && (--DhcpSb->PacketToLive == 0)) { 1537 1538 // 1539 // Select offer at each timeout if any offer received. 1540 // 1541 if (DhcpSb->DhcpState == Dhcp4Selecting && DhcpSb->LastOffer != NULL) { 1542 1543 Status = DhcpChooseOffer (DhcpSb); 1544 1545 if (EFI_ERROR(Status)) { 1546 if (DhcpSb->LastOffer != NULL) { 1547 FreePool (DhcpSb->LastOffer); 1548 DhcpSb->LastOffer = NULL; 1549 } 1550 } else { 1551 goto ON_EXIT; 1552 } 1553 } 1554 1555 if (++DhcpSb->CurRetry < DhcpSb->MaxRetries) { 1556 // 1557 // Still has another try 1558 // 1559 DhcpRetransmit (DhcpSb); 1560 DhcpSetTransmitTimer (DhcpSb); 1561 1562 } else if (DHCP_CONNECTED (DhcpSb->DhcpState)) { 1563 1564 // 1565 // Retransmission failed, if the DHCP request is initiated by 1566 // user, adjust the current state according to the lease life. 1567 // Otherwise do nothing to wait the lease to timeout 1568 // 1569 if (DhcpSb->ExtraRefresh != 0) { 1570 Status = EFI_SUCCESS; 1571 1572 if (DhcpSb->LeaseLife < DhcpSb->T1) { 1573 Status = DhcpSetState (DhcpSb, Dhcp4Bound, FALSE); 1574 1575 } else if (DhcpSb->LeaseLife < DhcpSb->T2) { 1576 Status = DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE); 1577 1578 } else if (DhcpSb->LeaseLife < DhcpSb->Lease) { 1579 Status = DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE); 1580 1581 } else { 1582 goto END_SESSION; 1583 1584 } 1585 1586 DhcpSb->IoStatus = EFI_TIMEOUT; 1587 DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_RENEWREBIND); 1588 } 1589 } else { 1590 goto END_SESSION; 1591 } 1592 } 1593 1594 // 1595 // If an address has been acquired, check whether need to 1596 // refresh or whether it has expired. 1597 // 1598 if (DHCP_CONNECTED (DhcpSb->DhcpState)) { 1599 DhcpSb->LeaseLife++; 1600 1601 // 1602 // Don't timeout the lease, only count the life if user is 1603 // requesting extra renew/rebind. Adjust the state after that. 1604 // 1605 if (DhcpSb->ExtraRefresh != 0) { 1606 return ; 1607 } 1608 1609 if (DhcpSb->LeaseLife == DhcpSb->Lease) { 1610 // 1611 // Lease expires, end the session 1612 // 1613 goto END_SESSION; 1614 1615 } else if (DhcpSb->LeaseLife == DhcpSb->T2) { 1616 // 1617 // T2 expires, transit to rebinding then send a REQUEST to any server 1618 // 1619 if (EFI_ERROR (DhcpSetState (DhcpSb, Dhcp4Rebinding, TRUE))) { 1620 goto END_SESSION; 1621 } 1622 1623 if (Instance != NULL) { 1624 Instance->ElaspedTime= 0; 1625 } 1626 1627 Status = DhcpSendMessage ( 1628 DhcpSb, 1629 DhcpSb->Selected, 1630 DhcpSb->Para, 1631 DHCP_MSG_REQUEST, 1632 NULL 1633 ); 1634 1635 if (EFI_ERROR (Status)) { 1636 goto END_SESSION; 1637 } 1638 1639 } else if (DhcpSb->LeaseLife == DhcpSb->T1) { 1640 // 1641 // T1 expires, transit to renewing, then send a REQUEST to the server 1642 // 1643 if (EFI_ERROR (DhcpSetState (DhcpSb, Dhcp4Renewing, TRUE))) { 1644 goto END_SESSION; 1645 } 1646 1647 if (Instance != NULL) { 1648 Instance->ElaspedTime= 0; 1649 } 1650 1651 Status = DhcpSendMessage ( 1652 DhcpSb, 1653 DhcpSb->Selected, 1654 DhcpSb->Para, 1655 DHCP_MSG_REQUEST, 1656 NULL 1657 ); 1658 1659 if (EFI_ERROR (Status)) { 1660 goto END_SESSION; 1661 } 1662 } 1663 } 1664 1665 ON_EXIT: 1666 // 1667 // Iterate through all the DhcpSb Children. 1668 // 1669 NET_LIST_FOR_EACH_SAFE (Entry, Next, &DhcpSb->Children) { 1670 Instance = NET_LIST_USER_STRUCT (Entry, DHCP_PROTOCOL, Link); 1671 1672 if ((Instance != NULL) && (Instance->Token != NULL)) { 1673 Instance->Timeout--; 1674 if (Instance->Timeout == 0) { 1675 PxeDhcpDone (Instance); 1676 } 1677 } 1678 } 1679 1680 return ; 1681 1682 END_SESSION: 1683 DhcpEndSession (DhcpSb, EFI_TIMEOUT); 1684 1685 return ; 1686 } 1687