1 /** @file 2 Dhcp6 internal functions implementation. 3 4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> 5 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> 6 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions of the BSD License 9 which accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php. 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "Dhcp6Impl.h" 18 19 20 /** 21 Enqueue the packet into the retry list in case of timeout. 22 23 @param[in] Instance The pointer to the Dhcp6 instance. 24 @param[in] Packet The pointer to the Dhcp6 packet to retry. 25 @param[in] Elapsed The pointer to the elapsed time value in the packet. 26 @param[in] RetryCtl The pointer to the transmission control of the packet. 27 This parameter is optional and may be NULL. 28 29 @retval EFI_SUCCESS Successfully enqueued the packet into the retry list according 30 to its message type. 31 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 32 @retval EFI_DEVICE_ERROR An unexpected message type. 33 34 **/ 35 EFI_STATUS 36 Dhcp6EnqueueRetry ( 37 IN DHCP6_INSTANCE *Instance, 38 IN EFI_DHCP6_PACKET *Packet, 39 IN UINT16 *Elapsed, 40 IN EFI_DHCP6_RETRANSMISSION *RetryCtl OPTIONAL 41 ) 42 { 43 DHCP6_TX_CB *TxCb; 44 DHCP6_IA_CB *IaCb; 45 46 ASSERT (Packet != NULL); 47 48 IaCb = &Instance->IaCb; 49 TxCb = AllocateZeroPool (sizeof (DHCP6_TX_CB)); 50 51 if (TxCb == NULL) { 52 return EFI_OUT_OF_RESOURCES; 53 } 54 55 // 56 // Save tx packet pointer, and it will be destroyed when reply received. 57 // 58 TxCb->TxPacket = Packet; 59 TxCb->Xid = Packet->Dhcp6.Header.TransactionId; 60 61 // 62 // Save pointer to elapsed-time value so we can update it on retransmits. 63 // 64 TxCb->Elapsed = Elapsed; 65 66 // 67 // Calculate the retransmission according to the the message type. 68 // 69 switch (Packet->Dhcp6.Header.MessageType) { 70 case Dhcp6MsgSolicit: 71 // 72 // Calculate the retransmission threshold value for solicit packet. 73 // Use the default value by rfc-3315 if user doesn't configure. 74 // 75 if (RetryCtl == NULL) { 76 TxCb->RetryCtl.Irt = DHCP6_SOL_IRT; 77 TxCb->RetryCtl.Mrc = DHCP6_SOL_MRC; 78 TxCb->RetryCtl.Mrt = DHCP6_SOL_MRT; 79 TxCb->RetryCtl.Mrd = DHCP6_SOL_MRD; 80 } else { 81 TxCb->RetryCtl.Irt = (RetryCtl->Irt != 0) ? RetryCtl->Irt : DHCP6_SOL_IRT; 82 TxCb->RetryCtl.Mrc = (RetryCtl->Mrc != 0) ? RetryCtl->Mrc : DHCP6_SOL_MRC; 83 TxCb->RetryCtl.Mrt = (RetryCtl->Mrt != 0) ? RetryCtl->Mrt : DHCP6_SOL_MRT; 84 TxCb->RetryCtl.Mrd = (RetryCtl->Mrd != 0) ? RetryCtl->Mrd : DHCP6_SOL_MRD; 85 } 86 87 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 88 TxCb->RetryCtl.Irt, 89 TRUE, 90 FALSE 91 ); 92 break; 93 94 case Dhcp6MsgRequest: 95 // 96 // Calculate the retransmission threshold value for request packet. 97 // 98 TxCb->RetryCtl.Irt = DHCP6_REQ_IRT; 99 TxCb->RetryCtl.Mrc = DHCP6_REQ_MRC; 100 TxCb->RetryCtl.Mrt = DHCP6_REQ_MRT; 101 TxCb->RetryCtl.Mrd = DHCP6_REQ_MRD; 102 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 103 TxCb->RetryCtl.Irt, 104 TRUE, 105 TRUE 106 ); 107 break; 108 109 case Dhcp6MsgConfirm: 110 // 111 // Calculate the retransmission threshold value for confirm packet. 112 // 113 TxCb->RetryCtl.Irt = DHCP6_CNF_IRT; 114 TxCb->RetryCtl.Mrc = DHCP6_CNF_MRC; 115 TxCb->RetryCtl.Mrt = DHCP6_CNF_MRT; 116 TxCb->RetryCtl.Mrd = DHCP6_CNF_MRD; 117 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 118 TxCb->RetryCtl.Irt, 119 TRUE, 120 TRUE 121 ); 122 break; 123 124 case Dhcp6MsgRenew: 125 // 126 // Calculate the retransmission threshold value for renew packet. 127 // 128 TxCb->RetryCtl.Irt = DHCP6_REB_IRT; 129 TxCb->RetryCtl.Mrc = DHCP6_REB_MRC; 130 TxCb->RetryCtl.Mrt = DHCP6_REB_MRT; 131 TxCb->RetryCtl.Mrd = IaCb->T2 - IaCb->T1; 132 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 133 TxCb->RetryCtl.Irt, 134 TRUE, 135 TRUE 136 ); 137 break; 138 139 case Dhcp6MsgRebind: 140 // 141 // Calculate the retransmission threshold value for rebind packet. 142 // 143 TxCb->RetryCtl.Irt = DHCP6_REN_IRT; 144 TxCb->RetryCtl.Mrc = DHCP6_REN_MRC; 145 TxCb->RetryCtl.Mrt = DHCP6_REN_MRT; 146 TxCb->RetryCtl.Mrd = IaCb->AllExpireTime - IaCb->T2; 147 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 148 TxCb->RetryCtl.Irt, 149 TRUE, 150 TRUE 151 ); 152 break; 153 154 case Dhcp6MsgDecline: 155 // 156 // Calculate the retransmission threshold value for decline packet. 157 // 158 TxCb->RetryCtl.Irt = DHCP6_DEC_IRT; 159 TxCb->RetryCtl.Mrc = DHCP6_DEC_MRC; 160 TxCb->RetryCtl.Mrt = DHCP6_DEC_MRT; 161 TxCb->RetryCtl.Mrd = DHCP6_DEC_MRD; 162 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 163 TxCb->RetryCtl.Irt, 164 TRUE, 165 TRUE 166 ); 167 break; 168 169 case Dhcp6MsgRelease: 170 // 171 // Calculate the retransmission threshold value for release packet. 172 // 173 TxCb->RetryCtl.Irt = DHCP6_REL_IRT; 174 TxCb->RetryCtl.Mrc = DHCP6_REL_MRC; 175 TxCb->RetryCtl.Mrt = DHCP6_REL_MRT; 176 TxCb->RetryCtl.Mrd = DHCP6_REL_MRD; 177 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 178 TxCb->RetryCtl.Irt, 179 TRUE, 180 TRUE 181 ); 182 break; 183 184 case Dhcp6MsgInfoRequest: 185 // 186 // Calculate the retransmission threshold value for info-request packet. 187 // Use the default value by rfc-3315 if user doesn't configure. 188 // 189 if (RetryCtl == NULL) { 190 TxCb->RetryCtl.Irt = DHCP6_INF_IRT; 191 TxCb->RetryCtl.Mrc = DHCP6_INF_MRC; 192 TxCb->RetryCtl.Mrt = DHCP6_INF_MRT; 193 TxCb->RetryCtl.Mrd = DHCP6_INF_MRD; 194 } else { 195 TxCb->RetryCtl.Irt = (RetryCtl->Irt != 0) ? RetryCtl->Irt : DHCP6_INF_IRT; 196 TxCb->RetryCtl.Mrc = (RetryCtl->Mrc != 0) ? RetryCtl->Mrc : DHCP6_INF_MRC; 197 TxCb->RetryCtl.Mrt = (RetryCtl->Mrt != 0) ? RetryCtl->Mrt : DHCP6_INF_MRT; 198 TxCb->RetryCtl.Mrd = (RetryCtl->Mrd != 0) ? RetryCtl->Mrd : DHCP6_INF_MRD; 199 } 200 201 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 202 TxCb->RetryCtl.Irt, 203 TRUE, 204 TRUE 205 ); 206 break; 207 208 default: 209 // 210 // Unexpected message type. 211 // 212 return EFI_DEVICE_ERROR; 213 } 214 215 // 216 // Insert into the retransmit list of the instance. 217 // 218 InsertTailList (&Instance->TxList, &TxCb->Link); 219 220 return EFI_SUCCESS; 221 } 222 223 224 /** 225 Dequeue the packet from retry list if reply received or timeout at last. 226 227 @param[in] Instance The pointer to the Dhcp6 instance. 228 @param[in] PacketXid The packet transaction id to match. 229 @param[in] NeedSignal If TRUE, then an timeout event need be signaled when it is existed. 230 Otherwise, this parameter is ignored. 231 232 @retval EFI_SUCCESS Successfully dequeued the packet into retry list . 233 @retval EFI_NOT_FOUND There is no xid matched in retry list. 234 235 **/ 236 EFI_STATUS 237 Dhcp6DequeueRetry ( 238 IN DHCP6_INSTANCE *Instance, 239 IN UINT32 PacketXid, 240 IN BOOLEAN NeedSignal 241 ) 242 { 243 LIST_ENTRY *Entry; 244 LIST_ENTRY *NextEntry; 245 DHCP6_TX_CB *TxCb; 246 DHCP6_INF_CB *InfCb; 247 248 // 249 // Seek the retransmit node in the retransmit list by packet xid. 250 // 251 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) { 252 253 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link); 254 ASSERT(TxCb->TxPacket); 255 256 if (TxCb->Xid == PacketXid) { 257 258 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) { 259 260 // 261 // Seek the info-request node in the info-request list by packet xid. 262 // 263 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->InfList) { 264 265 InfCb = NET_LIST_USER_STRUCT (Entry, DHCP6_INF_CB, Link); 266 267 if (InfCb->Xid == PacketXid) { 268 // 269 // Remove the info-request node, and signal the event if timeout. 270 // 271 if (InfCb->TimeoutEvent != NULL && NeedSignal) { 272 gBS->SignalEvent (InfCb->TimeoutEvent); 273 } 274 275 RemoveEntryList (&InfCb->Link); 276 FreePool (InfCb); 277 } 278 } 279 } 280 // 281 // Remove the retransmit node. 282 // 283 RemoveEntryList (&TxCb->Link); 284 ASSERT(TxCb->TxPacket); 285 FreePool (TxCb->TxPacket); 286 FreePool (TxCb); 287 return EFI_SUCCESS; 288 } 289 } 290 291 return EFI_NOT_FOUND; 292 } 293 294 295 /** 296 Clean up the specific nodes in the retry list. 297 298 @param[in] Instance The pointer to the Dhcp6 instance. 299 @param[in] Scope The scope of cleanup nodes. 300 301 **/ 302 VOID 303 Dhcp6CleanupRetry ( 304 IN DHCP6_INSTANCE *Instance, 305 IN UINT32 Scope 306 ) 307 { 308 LIST_ENTRY *Entry; 309 LIST_ENTRY *NextEntry; 310 DHCP6_TX_CB *TxCb; 311 DHCP6_INF_CB *InfCb; 312 313 // 314 // Clean up all the stateful messages from the retransmit list. 315 // 316 if (Scope == DHCP6_PACKET_STATEFUL || Scope == DHCP6_PACKET_ALL) { 317 318 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) { 319 320 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link); 321 ASSERT(TxCb->TxPacket); 322 323 if (TxCb->TxPacket->Dhcp6.Header.MessageType != Dhcp6MsgInfoRequest) { 324 RemoveEntryList (&TxCb->Link); 325 FreePool (TxCb->TxPacket); 326 FreePool (TxCb); 327 } 328 } 329 } 330 331 // 332 // Clean up all the stateless messages from the retransmit list. 333 // 334 if (Scope == DHCP6_PACKET_STATELESS || Scope == DHCP6_PACKET_ALL) { 335 336 // 337 // Clean up all the retransmit list for stateless messages. 338 // 339 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) { 340 341 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link); 342 ASSERT(TxCb->TxPacket); 343 344 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) { 345 RemoveEntryList (&TxCb->Link); 346 FreePool (TxCb->TxPacket); 347 FreePool (TxCb); 348 } 349 } 350 351 // 352 // Clean up all the info-request messages list. 353 // 354 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->InfList) { 355 356 InfCb = NET_LIST_USER_STRUCT (Entry, DHCP6_INF_CB, Link); 357 358 if (InfCb->TimeoutEvent != NULL) { 359 gBS->SignalEvent (InfCb->TimeoutEvent); 360 } 361 RemoveEntryList (&InfCb->Link); 362 FreePool (InfCb); 363 } 364 } 365 } 366 367 /** 368 Check whether the TxCb is still a valid control block in the instance's retry list. 369 370 @param[in] Instance The pointer to DHCP6_INSTANCE. 371 @param[in] TxCb The control block for a transmitted message. 372 373 @retval TRUE The control block is in Instance's retry list. 374 @retval FALSE The control block is NOT in Instance's retry list. 375 376 **/ 377 BOOLEAN 378 Dhcp6IsValidTxCb ( 379 IN DHCP6_INSTANCE *Instance, 380 IN DHCP6_TX_CB *TxCb 381 ) 382 { 383 LIST_ENTRY *Entry; 384 385 NET_LIST_FOR_EACH (Entry, &Instance->TxList) { 386 if (TxCb == NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link)) { 387 return TRUE; 388 } 389 } 390 391 return FALSE; 392 } 393 394 /** 395 Clean up the session of the instance stateful exchange. 396 397 @param[in, out] Instance The pointer to the Dhcp6 instance. 398 @param[in] Status The return status from udp. 399 400 **/ 401 VOID 402 Dhcp6CleanupSession ( 403 IN OUT DHCP6_INSTANCE *Instance, 404 IN EFI_STATUS Status 405 ) 406 { 407 UINTN Index; 408 EFI_DHCP6_IA *Ia; 409 410 ASSERT(Instance->Config); 411 ASSERT(Instance->IaCb.Ia); 412 413 // 414 // Clean up the retransmit list for stateful messages. 415 // 416 Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATEFUL); 417 418 if (Instance->Unicast != NULL) { 419 FreePool (Instance->Unicast); 420 } 421 422 if (Instance->AdSelect != NULL) { 423 FreePool (Instance->AdSelect); 424 } 425 426 if (Instance->IaCb.Ia->ReplyPacket != NULL) { 427 FreePool (Instance->IaCb.Ia->ReplyPacket); 428 } 429 430 // 431 // Reinitialize the Ia fields of the instance. 432 // 433 Instance->UdpSts = Status; 434 Instance->AdSelect = NULL; 435 Instance->AdPref = 0; 436 Instance->Unicast = NULL; 437 Instance->IaCb.T1 = 0; 438 Instance->IaCb.T2 = 0; 439 Instance->IaCb.AllExpireTime = 0; 440 Instance->IaCb.LeaseTime = 0; 441 442 // 443 // Clear start time 444 // 445 Instance->StartTime = 0; 446 447 Ia = Instance->IaCb.Ia; 448 Ia->State = Dhcp6Init; 449 Ia->ReplyPacket = NULL; 450 451 // 452 // Set the addresses as zero lifetime, and then the notify 453 // function in Ip6Config will remove these timeout address. 454 // 455 for (Index = 0; Index < Ia->IaAddressCount; Index++) { 456 Ia->IaAddress[Index].PreferredLifetime = 0; 457 Ia->IaAddress[Index].ValidLifetime = 0; 458 } 459 460 // 461 // 462 // Signal the Ia information updated event to informal user. 463 // 464 if (Instance->Config->IaInfoEvent != NULL) { 465 gBS->SignalEvent (Instance->Config->IaInfoEvent); 466 } 467 } 468 469 470 /** 471 Callback to user when Dhcp6 transmit/receive occurs. 472 473 @param[in] Instance The pointer to the Dhcp6 instance. 474 @param[in] Event The current Dhcp6 event. 475 @param[in, out] Packet The pointer to the packet sending or received. 476 477 @retval EFI_SUCCESS The user function returns success. 478 @retval EFI_NOT_READY Direct the caller to continue collecting the offer. 479 @retval EFI_ABORTED The user function ask it to abort. 480 481 **/ 482 EFI_STATUS 483 EFIAPI 484 Dhcp6CallbackUser ( 485 IN DHCP6_INSTANCE *Instance, 486 IN EFI_DHCP6_EVENT Event, 487 IN OUT EFI_DHCP6_PACKET **Packet 488 ) 489 { 490 EFI_STATUS Status; 491 EFI_DHCP6_PACKET *NewPacket; 492 EFI_DHCP6_CALLBACK Callback; 493 VOID *Context; 494 495 ASSERT (Packet != NULL); 496 ASSERT (Instance->Config != NULL); 497 ASSERT (Instance->IaCb.Ia != NULL); 498 499 NewPacket = NULL; 500 Status = EFI_SUCCESS; 501 Callback = Instance->Config->Dhcp6Callback; 502 Context = Instance->Config->CallbackContext; 503 504 // 505 // Callback to user with the new message if has. 506 // 507 if (Callback != NULL) { 508 509 Status = Callback ( 510 &Instance->Dhcp6, 511 Context, 512 Instance->IaCb.Ia->State, 513 Event, 514 *Packet, 515 &NewPacket 516 ); 517 // 518 // Updated the new packet from user to replace the original one. 519 // 520 if (NewPacket != NULL) { 521 ASSERT (*Packet != NULL); 522 FreePool (*Packet); 523 *Packet = NewPacket; 524 } 525 } 526 527 return Status; 528 } 529 530 531 /** 532 Update Ia according to the new reply message. 533 534 @param[in, out] Instance The pointer to the Dhcp6 instance. 535 @param[in] Packet The pointer to reply messages. 536 537 @retval EFI_SUCCESS Updated the Ia information successfully. 538 @retval EFI_DEVICE_ERROR An unexpected error. 539 540 **/ 541 EFI_STATUS 542 Dhcp6UpdateIaInfo ( 543 IN OUT DHCP6_INSTANCE *Instance, 544 IN EFI_DHCP6_PACKET *Packet 545 ) 546 { 547 EFI_STATUS Status; 548 UINT8 *Option; 549 UINT8 *IaInnerOpt; 550 UINT16 IaInnerLen; 551 UINT16 StsCode; 552 UINT32 T1; 553 UINT32 T2; 554 555 ASSERT (Instance->Config != NULL); 556 // 557 // If the reply was received in reponse to a solicit with rapid commit option, 558 // request, renew or rebind message, the client updates the information it has 559 // recorded about IAs from the IA options contained in the reply message: 560 // 1. record the T1 and T2 times 561 // 2. add any new addresses in the IA 562 // 3. discard any addresses from the IA, that have a valid lifetime of 0 563 // 4. update lifetimes for any addresses that alread recorded 564 // 5. leave unchanged any information about addresses 565 // 566 // See details in the section-18.1.8 of rfc-3315. 567 // 568 Option = Dhcp6SeekIaOption ( 569 Packet->Dhcp6.Option, 570 Packet->Length - sizeof (EFI_DHCP6_HEADER), 571 &Instance->Config->IaDescriptor 572 ); 573 if (Option == NULL) { 574 return EFI_DEVICE_ERROR; 575 } 576 577 // 578 // The format of the IA_NA option is: 579 // 580 // 0 1 2 3 581 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 582 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 583 // | OPTION_IA_NA | option-len | 584 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 585 // | IAID (4 octets) | 586 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 587 // | T1 | 588 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 589 // | T2 | 590 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 591 // | | 592 // . IA_NA-options . 593 // . . 594 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 595 // 596 // The format of the IA_TA option is: 597 // 598 // 0 1 2 3 599 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 600 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 601 // | OPTION_IA_TA | option-len | 602 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 603 // | IAID (4 octets) | 604 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 605 // | | 606 // . IA_TA-options . 607 // . . 608 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 609 // 610 611 // 612 // sizeof (option-code + option-len + IaId) = 8 613 // sizeof (option-code + option-len + IaId + T1) = 12 614 // sizeof (option-code + option-len + IaId + T1 + T2) = 16 615 // 616 // The inner options still start with 2 bytes option-code and 2 bytes option-len. 617 // 618 if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) { 619 T1 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 8))); 620 T2 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 12))); 621 // 622 // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2, 623 // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes 624 // the remainder of the message as though the server had not included the invalid IA_NA option. 625 // 626 if (T1 > T2 && T2 > 0) { 627 return EFI_DEVICE_ERROR; 628 } 629 IaInnerOpt = Option + 16; 630 IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 12); 631 } else { 632 T1 = 0; 633 T2 = 0; 634 IaInnerOpt = Option + 8; 635 IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 4); 636 } 637 638 // 639 // The format of the Status Code option is: 640 // 641 // 0 1 2 3 642 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 643 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 644 // | OPTION_STATUS_CODE | option-len | 645 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 646 // | status-code | | 647 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 648 // . . 649 // . status-message . 650 // . . 651 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 652 // 653 654 // 655 // sizeof (option-code + option-len) = 4 656 // 657 StsCode = Dhcp6StsSuccess; 658 Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode); 659 660 if (Option != NULL) { 661 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4))); 662 if (StsCode != Dhcp6StsSuccess) { 663 return EFI_DEVICE_ERROR; 664 } 665 } 666 667 // 668 // Generate control block for the Ia. 669 // 670 Status = Dhcp6GenerateIaCb ( 671 Instance, 672 IaInnerOpt, 673 IaInnerLen, 674 T1, 675 T2 676 ); 677 678 return Status; 679 } 680 681 682 683 /** 684 Seek StatusCode Option in package. A Status Code option may appear in the 685 options field of a DHCP message and/or in the options field of another option. 686 See details in section 22.13, RFC3315. 687 688 @param[in] Instance The pointer to the Dhcp6 instance. 689 @param[in] Packet The pointer to reply messages. 690 @param[out] Option The pointer to status code option. 691 692 @retval EFI_SUCCESS Seek status code option successfully. 693 @retval EFI_DEVICE_ERROR An unexpected error. 694 695 **/ 696 EFI_STATUS 697 Dhcp6SeekStsOption ( 698 IN DHCP6_INSTANCE *Instance, 699 IN EFI_DHCP6_PACKET *Packet, 700 OUT UINT8 **Option 701 ) 702 { 703 UINT8 *IaInnerOpt; 704 UINT16 IaInnerLen; 705 UINT16 StsCode; 706 707 // 708 // Seek StatusCode option directly in DHCP message body. That is, search in 709 // non-encapsulated option fields. 710 // 711 *Option = Dhcp6SeekOption ( 712 Packet->Dhcp6.Option, 713 Packet->Length - 4, 714 Dhcp6OptStatusCode 715 ); 716 717 if (*Option != NULL) { 718 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 4))); 719 if (StsCode != Dhcp6StsSuccess) { 720 return EFI_DEVICE_ERROR; 721 } 722 } 723 724 // 725 // Seek in encapsulated options, IA_NA and IA_TA. 726 // 727 *Option = Dhcp6SeekIaOption ( 728 Packet->Dhcp6.Option, 729 Packet->Length - sizeof (EFI_DHCP6_HEADER), 730 &Instance->Config->IaDescriptor 731 ); 732 if (*Option == NULL) { 733 return EFI_SUCCESS; 734 } 735 736 // 737 // The format of the IA_NA option is: 738 // 739 // 0 1 2 3 740 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 741 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 742 // | OPTION_IA_NA | option-len | 743 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 744 // | IAID (4 octets) | 745 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 746 // | T1 | 747 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 748 // | T2 | 749 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 750 // | | 751 // . IA_NA-options . 752 // . . 753 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 754 // 755 // The format of the IA_TA option is: 756 // 757 // 0 1 2 3 758 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 759 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 760 // | OPTION_IA_TA | option-len | 761 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 762 // | IAID (4 octets) | 763 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 764 // | | 765 // . IA_TA-options . 766 // . . 767 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 768 // 769 770 // 771 // sizeof (option-code + option-len + IaId) = 8 772 // sizeof (option-code + option-len + IaId + T1) = 12 773 // sizeof (option-code + option-len + IaId + T1 + T2) = 16 774 // 775 // The inner options still start with 2 bytes option-code and 2 bytes option-len. 776 // 777 if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) { 778 IaInnerOpt = *Option + 16; 779 IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 2))) - 12); 780 } else { 781 IaInnerOpt = *Option + 8; 782 IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 2))) - 4); 783 } 784 785 // 786 // The format of the Status Code option is: 787 // 788 // 0 1 2 3 789 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 790 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 791 // | OPTION_STATUS_CODE | option-len | 792 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 793 // | status-code | | 794 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 795 // . . 796 // . status-message . 797 // . . 798 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 799 // 800 801 // 802 // sizeof (option-code + option-len) = 4 803 // 804 *Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode); 805 if (*Option != NULL) { 806 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 4))); 807 if (StsCode != Dhcp6StsSuccess) { 808 return EFI_DEVICE_ERROR; 809 } 810 } 811 812 return EFI_SUCCESS; 813 } 814 815 816 /** 817 Transmit Dhcp6 message by udpio. 818 819 @param[in] Instance The pointer to the Dhcp6 instance. 820 @param[in] Packet The pointer to transmit message. 821 @param[in] Elapsed The pointer to the elapsed time value to fill in. 822 823 @retval EFI_SUCCESS Successfully transmitted the packet. 824 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 825 @retval Others Failed to transmit the packet. 826 827 **/ 828 EFI_STATUS 829 Dhcp6TransmitPacket ( 830 IN DHCP6_INSTANCE *Instance, 831 IN EFI_DHCP6_PACKET *Packet, 832 IN UINT16 *Elapsed 833 ) 834 { 835 EFI_STATUS Status; 836 NET_BUF *Wrap; 837 NET_FRAGMENT Frag; 838 UDP_END_POINT EndPt; 839 DHCP6_SERVICE *Service; 840 841 Service = Instance->Service; 842 843 // 844 // Wrap it into a netbuf then send it. 845 // 846 Frag.Bulk = (UINT8 *) &Packet->Dhcp6.Header; 847 Frag.Len = Packet->Length; 848 849 // 850 // Do not register free packet here, which will be handled in retry list. 851 // 852 Wrap = NetbufFromExt (&Frag, 1, 0, 0, Dhcp6DummyExtFree, NULL); 853 854 if (Wrap == NULL) { 855 return EFI_OUT_OF_RESOURCES; 856 } 857 858 // 859 // Multicast the Dhcp6 message, unless get the unicast server address by option. 860 // 861 ZeroMem (&EndPt, sizeof (UDP_END_POINT)); 862 863 if (Instance->Unicast != NULL) { 864 CopyMem ( 865 &EndPt.RemoteAddr, 866 Instance->Unicast, 867 sizeof (EFI_IPv6_ADDRESS) 868 ); 869 } else { 870 CopyMem ( 871 &EndPt.RemoteAddr, 872 &mAllDhcpRelayAndServersAddress, 873 sizeof (EFI_IPv6_ADDRESS) 874 ); 875 } 876 877 EndPt.RemotePort = DHCP6_PORT_SERVER; 878 EndPt.LocalPort = DHCP6_PORT_CLIENT; 879 880 // 881 // Update the elapsed time value. 882 // 883 if (Elapsed != NULL) { 884 SetElapsedTime (Elapsed, Instance); 885 } 886 887 // 888 // Send out the message by the configured Udp6Io. 889 // 890 Status = UdpIoSendDatagram ( 891 Service->UdpIo, 892 Wrap, 893 &EndPt, 894 NULL, 895 Dhcp6OnTransmitted, 896 NULL 897 ); 898 899 if (EFI_ERROR (Status)) { 900 NetbufFree (Wrap); 901 return Status; 902 } 903 904 return EFI_SUCCESS; 905 } 906 907 908 /** 909 Create the solicit message and send it. 910 911 @param[in] Instance The pointer to the Dhcp6 instance. 912 913 @retval EFI_SUCCESS Created and sent the solicit message successfully. 914 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 915 @retval Others Failed to send the solicit message. 916 917 **/ 918 EFI_STATUS 919 Dhcp6SendSolicitMsg ( 920 IN DHCP6_INSTANCE *Instance 921 ) 922 { 923 EFI_STATUS Status; 924 EFI_DHCP6_PACKET *Packet; 925 EFI_DHCP6_PACKET_OPTION *UserOpt; 926 EFI_DHCP6_DUID *ClientId; 927 DHCP6_SERVICE *Service; 928 UINT8 *Cursor; 929 UINT16 *Elapsed; 930 UINT32 UserLen; 931 UINTN Index; 932 UINT16 Length; 933 934 Service = Instance->Service; 935 ClientId = Service->ClientId; 936 UserLen = 0; 937 938 ASSERT (Service->ClientId != NULL); 939 ASSERT (Instance->Config != NULL); 940 ASSERT (Instance->IaCb.Ia != NULL); 941 942 // 943 // Calculate the added length of customized option list. 944 // 945 for (Index = 0; Index < Instance->Config->OptionCount; Index++) { 946 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4); 947 } 948 949 // 950 // Create the Dhcp6 packet and initialize commone fields. 951 // 952 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); 953 if (Packet == NULL) { 954 return EFI_OUT_OF_RESOURCES; 955 } 956 957 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; 958 Packet->Length = sizeof (EFI_DHCP6_HEADER); 959 Packet->Dhcp6.Header.MessageType = Dhcp6MsgSolicit; 960 Packet->Dhcp6.Header.TransactionId = Service->Xid++; 961 962 // 963 // Assembly Dhcp6 options for solicit message. 964 // 965 Cursor = Packet->Dhcp6.Option; 966 967 Length = HTONS (ClientId->Length); 968 Cursor = Dhcp6AppendOption ( 969 Cursor, 970 HTONS (Dhcp6OptClientId), 971 Length, 972 ClientId->Duid 973 ); 974 975 Cursor = Dhcp6AppendETOption ( 976 Cursor, 977 Instance, 978 &Elapsed 979 ); 980 981 Cursor = Dhcp6AppendIaOption ( 982 Cursor, 983 Instance->IaCb.Ia, 984 Instance->IaCb.T1, 985 Instance->IaCb.T2, 986 Packet->Dhcp6.Header.MessageType 987 ); 988 989 // 990 // Append user-defined when configurate Dhcp6 service. 991 // 992 for (Index = 0; Index < Instance->Config->OptionCount; Index++) { 993 994 UserOpt = Instance->Config->OptionList[Index]; 995 Cursor = Dhcp6AppendOption( 996 Cursor, 997 UserOpt->OpCode, 998 UserOpt->OpLen, 999 UserOpt->Data 1000 ); 1001 } 1002 1003 // 1004 // Determine the size/length of packet. 1005 // 1006 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option); 1007 ASSERT (Packet->Size > Packet->Length + 8); 1008 1009 // 1010 // Callback to user with the packet to be sent and check the user's feedback. 1011 // 1012 Status = Dhcp6CallbackUser (Instance, Dhcp6SendSolicit, &Packet); 1013 1014 if (EFI_ERROR (Status)) { 1015 FreePool (Packet); 1016 return Status; 1017 } 1018 1019 // 1020 // Send solicit packet with the state transition from Dhcp6init to 1021 // Dhcp6selecting. 1022 // 1023 Instance->IaCb.Ia->State = Dhcp6Selecting; 1024 // 1025 // Clear initial time for current transaction. 1026 // 1027 Instance->StartTime = 0; 1028 1029 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); 1030 1031 if (EFI_ERROR (Status)) { 1032 FreePool (Packet); 1033 return Status; 1034 } 1035 1036 // 1037 // Enqueue the sent packet for the retransmission in case reply timeout. 1038 // 1039 return Dhcp6EnqueueRetry ( 1040 Instance, 1041 Packet, 1042 Elapsed, 1043 Instance->Config->SolicitRetransmission 1044 ); 1045 } 1046 1047 /** 1048 Configure some parameter to initiate SolicitMsg. 1049 1050 @param[in] Instance The pointer to the Dhcp6 instance. 1051 1052 @retval EFI_SUCCESS Created and sent the solicit message successfully. 1053 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1054 @retval Others Failed to send the solicit message. 1055 1056 **/ 1057 EFI_STATUS 1058 Dhcp6InitSolicitMsg ( 1059 IN DHCP6_INSTANCE *Instance 1060 ) 1061 { 1062 Instance->IaCb.T1 = 0; 1063 Instance->IaCb.T2 = 0; 1064 Instance->IaCb.Ia->IaAddressCount = 0; 1065 1066 return Dhcp6SendSolicitMsg (Instance); 1067 } 1068 1069 1070 /** 1071 Create the request message and send it. 1072 1073 @param[in] Instance The pointer to the Dhcp6 instance. 1074 1075 @retval EFI_SUCCESS Created and sent the request message successfully. 1076 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1077 @retval EFI_DEVICE_ERROR An unexpected error. 1078 @retval Others Failed to send the request message. 1079 1080 **/ 1081 EFI_STATUS 1082 Dhcp6SendRequestMsg ( 1083 IN DHCP6_INSTANCE *Instance 1084 ) 1085 { 1086 EFI_STATUS Status; 1087 EFI_DHCP6_PACKET *Packet; 1088 EFI_DHCP6_PACKET_OPTION *UserOpt; 1089 EFI_DHCP6_DUID *ClientId; 1090 EFI_DHCP6_DUID *ServerId; 1091 DHCP6_SERVICE *Service; 1092 UINT8 *Option; 1093 UINT8 *Cursor; 1094 UINT16 *Elapsed; 1095 UINT32 UserLen; 1096 UINTN Index; 1097 UINT16 Length; 1098 1099 ASSERT(Instance->AdSelect != NULL); 1100 ASSERT(Instance->Config != NULL); 1101 ASSERT(Instance->IaCb.Ia != NULL); 1102 ASSERT(Instance->Service != NULL); 1103 1104 Service = Instance->Service; 1105 ClientId = Service->ClientId; 1106 1107 ASSERT(ClientId != NULL); 1108 1109 // 1110 // Get the server Id from the selected advertisement message. 1111 // 1112 Option = Dhcp6SeekOption ( 1113 Instance->AdSelect->Dhcp6.Option, 1114 Instance->AdSelect->Length - 4, 1115 Dhcp6OptServerId 1116 ); 1117 if (Option == NULL) { 1118 return EFI_DEVICE_ERROR; 1119 } 1120 1121 ServerId = (EFI_DHCP6_DUID *) (Option + 2); 1122 1123 // 1124 // Calculate the added length of customized option list. 1125 // 1126 UserLen = 0; 1127 for (Index = 0; Index < Instance->Config->OptionCount; Index++) { 1128 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4); 1129 } 1130 1131 // 1132 // Create the Dhcp6 packet and initialize commone fields. 1133 // 1134 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); 1135 if (Packet == NULL) { 1136 return EFI_OUT_OF_RESOURCES; 1137 } 1138 1139 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; 1140 Packet->Length = sizeof (EFI_DHCP6_HEADER); 1141 Packet->Dhcp6.Header.MessageType = Dhcp6MsgRequest; 1142 Packet->Dhcp6.Header.TransactionId = Service->Xid++; 1143 1144 // 1145 // Assembly Dhcp6 options for request message. 1146 // 1147 Cursor = Packet->Dhcp6.Option; 1148 1149 Length = HTONS (ClientId->Length); 1150 Cursor = Dhcp6AppendOption ( 1151 Cursor, 1152 HTONS (Dhcp6OptClientId), 1153 Length, 1154 ClientId->Duid 1155 ); 1156 1157 Cursor = Dhcp6AppendETOption ( 1158 Cursor, 1159 Instance, 1160 &Elapsed 1161 ); 1162 1163 Cursor = Dhcp6AppendOption ( 1164 Cursor, 1165 HTONS (Dhcp6OptServerId), 1166 ServerId->Length, 1167 ServerId->Duid 1168 ); 1169 1170 Cursor = Dhcp6AppendIaOption ( 1171 Cursor, 1172 Instance->IaCb.Ia, 1173 Instance->IaCb.T1, 1174 Instance->IaCb.T2, 1175 Packet->Dhcp6.Header.MessageType 1176 ); 1177 1178 // 1179 // Append user-defined when configurate Dhcp6 service. 1180 // 1181 for (Index = 0; Index < Instance->Config->OptionCount; Index++) { 1182 1183 UserOpt = Instance->Config->OptionList[Index]; 1184 Cursor = Dhcp6AppendOption( 1185 Cursor, 1186 UserOpt->OpCode, 1187 UserOpt->OpLen, 1188 UserOpt->Data 1189 ); 1190 } 1191 1192 // 1193 // Determine the size/length of packet. 1194 // 1195 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option); 1196 ASSERT (Packet->Size > Packet->Length + 8); 1197 1198 // 1199 // Callback to user with the packet to be sent and check the user's feedback. 1200 // 1201 Status = Dhcp6CallbackUser (Instance, Dhcp6SendRequest, &Packet); 1202 1203 if (EFI_ERROR (Status)) { 1204 FreePool (Packet); 1205 return Status; 1206 } 1207 1208 // 1209 // Send request packet with the state transition from Dhcp6selecting to 1210 // Dhcp6requesting. 1211 // 1212 Instance->IaCb.Ia->State = Dhcp6Requesting; 1213 // 1214 // Clear initial time for current transaction. 1215 // 1216 Instance->StartTime = 0; 1217 1218 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); 1219 1220 if (EFI_ERROR (Status)) { 1221 FreePool (Packet); 1222 return Status; 1223 } 1224 1225 // 1226 // Enqueue the sent packet for the retransmission in case reply timeout. 1227 // 1228 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); 1229 } 1230 1231 1232 /** 1233 Create the decline message and send it. 1234 1235 @param[in] Instance The pointer to the Dhcp6 instance. 1236 @param[in] DecIa The pointer to the decline Ia. 1237 1238 @retval EFI_SUCCESS Created and sent the decline message successfully. 1239 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1240 @retval EFI_DEVICE_ERROR An unexpected error. 1241 @retval Others Failed to send the decline message. 1242 1243 **/ 1244 EFI_STATUS 1245 Dhcp6SendDeclineMsg ( 1246 IN DHCP6_INSTANCE *Instance, 1247 IN EFI_DHCP6_IA *DecIa 1248 ) 1249 { 1250 EFI_STATUS Status; 1251 EFI_DHCP6_PACKET *Packet; 1252 EFI_DHCP6_PACKET *LastReply; 1253 EFI_DHCP6_DUID *ClientId; 1254 EFI_DHCP6_DUID *ServerId; 1255 DHCP6_SERVICE *Service; 1256 UINT8 *Option; 1257 UINT8 *Cursor; 1258 UINT16 *Elapsed; 1259 UINT16 Length; 1260 1261 ASSERT (Instance->Config != NULL); 1262 ASSERT (Instance->IaCb.Ia != NULL); 1263 ASSERT (Instance->Service != NULL); 1264 1265 Service = Instance->Service; 1266 ClientId = Service->ClientId; 1267 LastReply = Instance->IaCb.Ia->ReplyPacket; 1268 1269 ASSERT (ClientId != NULL); 1270 ASSERT (LastReply != NULL); 1271 1272 // 1273 // Get the server Id from the last reply message. 1274 // 1275 Option = Dhcp6SeekOption ( 1276 LastReply->Dhcp6.Option, 1277 LastReply->Length - 4, 1278 Dhcp6OptServerId 1279 ); 1280 if (Option == NULL) { 1281 return EFI_DEVICE_ERROR; 1282 } 1283 1284 // 1285 // EFI_DHCP6_DUID contains a length field of 2 bytes. 1286 // 1287 ServerId = (EFI_DHCP6_DUID *) (Option + 2); 1288 1289 // 1290 // Create the Dhcp6 packet and initialize commone fields. 1291 // 1292 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE); 1293 if (Packet == NULL) { 1294 return EFI_OUT_OF_RESOURCES; 1295 } 1296 1297 Packet->Size = DHCP6_BASE_PACKET_SIZE; 1298 Packet->Length = sizeof (EFI_DHCP6_HEADER); 1299 Packet->Dhcp6.Header.MessageType = Dhcp6MsgDecline; 1300 Packet->Dhcp6.Header.TransactionId = Service->Xid++; 1301 1302 // 1303 // Assembly Dhcp6 options for rebind/renew message. 1304 // 1305 Cursor = Packet->Dhcp6.Option; 1306 1307 Length = HTONS (ClientId->Length); 1308 Cursor = Dhcp6AppendOption ( 1309 Cursor, 1310 HTONS (Dhcp6OptClientId), 1311 Length, 1312 ClientId->Duid 1313 ); 1314 1315 Cursor = Dhcp6AppendETOption ( 1316 Cursor, 1317 Instance, 1318 &Elapsed 1319 ); 1320 1321 Cursor = Dhcp6AppendOption ( 1322 Cursor, 1323 HTONS (Dhcp6OptServerId), 1324 ServerId->Length, 1325 ServerId->Duid 1326 ); 1327 1328 Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType); 1329 1330 // 1331 // Determine the size/length of packet. 1332 // 1333 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option); 1334 ASSERT (Packet->Size > Packet->Length + 8); 1335 1336 // 1337 // Callback to user with the packet to be sent and check the user's feedback. 1338 // 1339 Status = Dhcp6CallbackUser (Instance, Dhcp6SendDecline, &Packet); 1340 1341 if (EFI_ERROR (Status)) { 1342 FreePool (Packet); 1343 return Status; 1344 } 1345 1346 // 1347 // Send decline packet with the state transition from Dhcp6bound to 1348 // Dhcp6declining. 1349 // 1350 Instance->IaCb.Ia->State = Dhcp6Declining; 1351 // 1352 // Clear initial time for current transaction. 1353 // 1354 Instance->StartTime = 0; 1355 1356 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); 1357 1358 if (EFI_ERROR (Status)) { 1359 FreePool (Packet); 1360 return Status; 1361 } 1362 1363 // 1364 // Enqueue the sent packet for the retransmission in case reply timeout. 1365 // 1366 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); 1367 } 1368 1369 1370 /** 1371 Create the release message and send it. 1372 1373 @param[in] Instance The pointer to the Dhcp6 instance. 1374 @param[in] RelIa The pointer to the release Ia. 1375 1376 @retval EFI_SUCCESS Created and sent the release message successfully. 1377 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1378 @retval EFI_DEVICE_ERROR An unexpected error. 1379 @retval Others Failed to send the release message. 1380 1381 **/ 1382 EFI_STATUS 1383 Dhcp6SendReleaseMsg ( 1384 IN DHCP6_INSTANCE *Instance, 1385 IN EFI_DHCP6_IA *RelIa 1386 ) 1387 { 1388 EFI_STATUS Status; 1389 EFI_DHCP6_PACKET *Packet; 1390 EFI_DHCP6_PACKET *LastReply; 1391 EFI_DHCP6_DUID *ClientId; 1392 EFI_DHCP6_DUID *ServerId; 1393 DHCP6_SERVICE *Service; 1394 UINT8 *Option; 1395 UINT8 *Cursor; 1396 UINT16 *Elapsed; 1397 UINT16 Length; 1398 1399 ASSERT(Instance->Config); 1400 ASSERT(Instance->IaCb.Ia); 1401 1402 Service = Instance->Service; 1403 ClientId = Service->ClientId; 1404 LastReply = Instance->IaCb.Ia->ReplyPacket; 1405 1406 ASSERT(ClientId); 1407 ASSERT(LastReply); 1408 1409 // 1410 // Get the server Id from the last reply message. 1411 // 1412 Option = Dhcp6SeekOption ( 1413 LastReply->Dhcp6.Option, 1414 LastReply->Length - 4, 1415 Dhcp6OptServerId 1416 ); 1417 if (Option == NULL) { 1418 return EFI_DEVICE_ERROR; 1419 } 1420 1421 ServerId = (EFI_DHCP6_DUID *) (Option + 2); 1422 1423 // 1424 // Create the Dhcp6 packet and initialize commone fields. 1425 // 1426 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE); 1427 if (Packet == NULL) { 1428 return EFI_OUT_OF_RESOURCES; 1429 } 1430 1431 Packet->Size = DHCP6_BASE_PACKET_SIZE; 1432 Packet->Length = sizeof (EFI_DHCP6_HEADER); 1433 Packet->Dhcp6.Header.MessageType = Dhcp6MsgRelease; 1434 Packet->Dhcp6.Header.TransactionId = Service->Xid++; 1435 1436 // 1437 // Assembly Dhcp6 options for rebind/renew message 1438 // 1439 Cursor = Packet->Dhcp6.Option; 1440 1441 Length = HTONS (ClientId->Length); 1442 Cursor = Dhcp6AppendOption ( 1443 Cursor, 1444 HTONS (Dhcp6OptClientId), 1445 Length, 1446 ClientId->Duid 1447 ); 1448 1449 // 1450 // ServerId is extracted from packet, it's network order. 1451 // 1452 Cursor = Dhcp6AppendOption ( 1453 Cursor, 1454 HTONS (Dhcp6OptServerId), 1455 ServerId->Length, 1456 ServerId->Duid 1457 ); 1458 1459 Cursor = Dhcp6AppendETOption ( 1460 Cursor, 1461 Instance, 1462 &Elapsed 1463 ); 1464 1465 Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType); 1466 1467 // 1468 // Determine the size/length of packet 1469 // 1470 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option); 1471 ASSERT (Packet->Size > Packet->Length + 8); 1472 1473 // 1474 // Callback to user with the packet to be sent and check the user's feedback. 1475 // 1476 Status = Dhcp6CallbackUser (Instance, Dhcp6SendRelease, &Packet); 1477 1478 if (EFI_ERROR (Status)) { 1479 FreePool (Packet); 1480 return Status; 1481 } 1482 1483 // 1484 // Send release packet with the state transition from Dhcp6bound to 1485 // Dhcp6releasing. 1486 // 1487 Instance->IaCb.Ia->State = Dhcp6Releasing; 1488 1489 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); 1490 1491 if (EFI_ERROR (Status)) { 1492 FreePool (Packet); 1493 return Status; 1494 } 1495 1496 // 1497 // Enqueue the sent packet for the retransmission in case reply timeout. 1498 // 1499 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); 1500 } 1501 1502 1503 /** 1504 Create the renew/rebind message and send it. 1505 1506 @param[in] Instance The pointer to the Dhcp6 instance. 1507 @param[in] RebindRequest If TRUE, it is a Rebind type message. 1508 Otherwise, it is a Renew type message. 1509 1510 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully. 1511 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1512 @retval EFI_DEVICE_ERROR An unexpected error. 1513 @retval Others Failed to send the renew/rebind message. 1514 1515 **/ 1516 EFI_STATUS 1517 Dhcp6SendRenewRebindMsg ( 1518 IN DHCP6_INSTANCE *Instance, 1519 IN BOOLEAN RebindRequest 1520 ) 1521 { 1522 EFI_STATUS Status; 1523 EFI_DHCP6_PACKET *Packet; 1524 EFI_DHCP6_PACKET *LastReply; 1525 EFI_DHCP6_PACKET_OPTION *UserOpt; 1526 EFI_DHCP6_DUID *ClientId; 1527 EFI_DHCP6_DUID *ServerId; 1528 EFI_DHCP6_STATE State; 1529 EFI_DHCP6_EVENT Event; 1530 DHCP6_SERVICE *Service; 1531 UINT8 *Option; 1532 UINT8 *Cursor; 1533 UINT16 *Elapsed; 1534 UINT32 UserLen; 1535 UINTN Index; 1536 UINT16 Length; 1537 1538 ASSERT(Instance->Config); 1539 ASSERT(Instance->IaCb.Ia); 1540 1541 Service = Instance->Service; 1542 ClientId = Service->ClientId; 1543 1544 ASSERT(ClientId); 1545 1546 // 1547 // Calculate the added length of customized option list. 1548 // 1549 UserLen = 0; 1550 for (Index = 0; Index < Instance->Config->OptionCount; Index++) { 1551 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4); 1552 } 1553 1554 // 1555 // Create the Dhcp6 packet and initialize commone fields. 1556 // 1557 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); 1558 if (Packet == NULL) { 1559 return EFI_OUT_OF_RESOURCES; 1560 } 1561 1562 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; 1563 Packet->Length = sizeof (EFI_DHCP6_HEADER); 1564 Packet->Dhcp6.Header.MessageType = RebindRequest ? Dhcp6MsgRebind : Dhcp6MsgRenew; 1565 Packet->Dhcp6.Header.TransactionId = Service->Xid++; 1566 1567 // 1568 // Assembly Dhcp6 options for rebind/renew message. 1569 // 1570 Cursor = Packet->Dhcp6.Option; 1571 1572 Length = HTONS (ClientId->Length); 1573 Cursor = Dhcp6AppendOption ( 1574 Cursor, 1575 HTONS (Dhcp6OptClientId), 1576 Length, 1577 ClientId->Duid 1578 ); 1579 1580 Cursor = Dhcp6AppendETOption ( 1581 Cursor, 1582 Instance, 1583 &Elapsed 1584 ); 1585 1586 Cursor = Dhcp6AppendIaOption ( 1587 Cursor, 1588 Instance->IaCb.Ia, 1589 Instance->IaCb.T1, 1590 Instance->IaCb.T2, 1591 Packet->Dhcp6.Header.MessageType 1592 ); 1593 1594 if (!RebindRequest) { 1595 // 1596 // Get the server Id from the last reply message and 1597 // insert it for rebind request. 1598 // 1599 LastReply = Instance->IaCb.Ia->ReplyPacket; 1600 ASSERT (LastReply); 1601 1602 Option = Dhcp6SeekOption ( 1603 LastReply->Dhcp6.Option, 1604 LastReply->Length - 4, 1605 Dhcp6OptServerId 1606 ); 1607 if (Option == NULL) { 1608 FreePool (Packet); 1609 return EFI_DEVICE_ERROR; 1610 } 1611 1612 ServerId = (EFI_DHCP6_DUID *) (Option + 2); 1613 1614 Cursor = Dhcp6AppendOption ( 1615 Cursor, 1616 HTONS (Dhcp6OptServerId), 1617 ServerId->Length, 1618 ServerId->Duid 1619 ); 1620 } 1621 1622 // 1623 // Append user-defined when configurate Dhcp6 service. 1624 // 1625 for (Index = 0; Index < Instance->Config->OptionCount; Index++) { 1626 1627 UserOpt = Instance->Config->OptionList[Index]; 1628 Cursor = Dhcp6AppendOption( 1629 Cursor, 1630 UserOpt->OpCode, 1631 UserOpt->OpLen, 1632 UserOpt->Data 1633 ); 1634 } 1635 1636 // 1637 // Determine the size/length of packet. 1638 // 1639 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option); 1640 ASSERT (Packet->Size > Packet->Length + 8); 1641 1642 // 1643 // Callback to user with the packet to be sent and check the user's feedback. 1644 // 1645 State = (RebindRequest) ? Dhcp6Rebinding : Dhcp6Renewing; 1646 Event = (RebindRequest) ? Dhcp6EnterRebinding : Dhcp6EnterRenewing; 1647 1648 Status = Dhcp6CallbackUser (Instance, Event, &Packet); 1649 1650 if (EFI_ERROR (Status)) { 1651 FreePool (Packet); 1652 return Status; 1653 } 1654 1655 // 1656 // Send renew/rebind packet with the state transition from Dhcp6bound to 1657 // Dhcp6renew/rebind. 1658 // And sync the lease time when send renew/rebind, in case that user send 1659 // renew/rebind actively. 1660 // 1661 Instance->IaCb.Ia->State = State; 1662 Instance->IaCb.LeaseTime = (RebindRequest) ? Instance->IaCb.T2 : Instance->IaCb.T1; 1663 // 1664 // Clear initial time for current transaction. 1665 // 1666 Instance->StartTime = 0; 1667 1668 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); 1669 1670 if (EFI_ERROR (Status)) { 1671 FreePool (Packet); 1672 return Status; 1673 } 1674 1675 // 1676 // Enqueue the sent packet for the retransmission in case reply timeout. 1677 // 1678 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); 1679 } 1680 1681 /** 1682 Start the information request process. 1683 1684 @param[in] Instance The pointer to the Dhcp6 instance. 1685 @param[in] SendClientId If TRUE, the client identifier option will be included in 1686 information request message. Otherwise, the client identifier 1687 option will not be included. 1688 @param[in] OptionRequest The pointer to the option request option. 1689 @param[in] OptionCount The number options in the OptionList. 1690 @param[in] OptionList The array pointers to the appended options. 1691 @param[in] Retransmission The pointer to the retransmission control. 1692 @param[in] TimeoutEvent The event of timeout. 1693 @param[in] ReplyCallback The callback function when the reply was received. 1694 @param[in] CallbackContext The pointer to the parameter passed to the callback. 1695 1696 @retval EFI_SUCCESS Start the info-request process successfully. 1697 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1698 @retval EFI_NO_MAPPING No source address is available for use. 1699 @retval Others Failed to start the info-request process. 1700 1701 **/ 1702 EFI_STATUS 1703 Dhcp6StartInfoRequest ( 1704 IN DHCP6_INSTANCE *Instance, 1705 IN BOOLEAN SendClientId, 1706 IN EFI_DHCP6_PACKET_OPTION *OptionRequest, 1707 IN UINT32 OptionCount, 1708 IN EFI_DHCP6_PACKET_OPTION *OptionList[] OPTIONAL, 1709 IN EFI_DHCP6_RETRANSMISSION *Retransmission, 1710 IN EFI_EVENT TimeoutEvent OPTIONAL, 1711 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback, 1712 IN VOID *CallbackContext OPTIONAL 1713 ) 1714 { 1715 EFI_STATUS Status; 1716 DHCP6_INF_CB *InfCb; 1717 DHCP6_SERVICE *Service; 1718 EFI_TPL OldTpl; 1719 1720 Service = Instance->Service; 1721 1722 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 1723 Instance->UdpSts = EFI_ALREADY_STARTED; 1724 // 1725 // Create and initialize the control block for the info-request. 1726 // 1727 InfCb = AllocateZeroPool (sizeof(DHCP6_INF_CB)); 1728 1729 if (InfCb == NULL) { 1730 gBS->RestoreTPL (OldTpl); 1731 return EFI_OUT_OF_RESOURCES; 1732 } 1733 1734 InfCb->ReplyCallback = ReplyCallback; 1735 InfCb->CallbackContext = CallbackContext; 1736 InfCb->TimeoutEvent = TimeoutEvent; 1737 1738 InsertTailList (&Instance->InfList, &InfCb->Link); 1739 1740 // 1741 // Send the info-request message to start exchange process. 1742 // 1743 Status = Dhcp6SendInfoRequestMsg ( 1744 Instance, 1745 InfCb, 1746 SendClientId, 1747 OptionRequest, 1748 OptionCount, 1749 OptionList, 1750 Retransmission 1751 ); 1752 1753 if (EFI_ERROR (Status)) { 1754 goto ON_ERROR; 1755 } 1756 1757 // 1758 // Register receive callback for the stateless exchange process. 1759 // 1760 Status = UdpIoRecvDatagram( 1761 Service->UdpIo, 1762 Dhcp6ReceivePacket, 1763 Service, 1764 0 1765 ); 1766 1767 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { 1768 goto ON_ERROR; 1769 } 1770 1771 gBS->RestoreTPL (OldTpl); 1772 return EFI_SUCCESS; 1773 1774 ON_ERROR: 1775 gBS->RestoreTPL (OldTpl); 1776 RemoveEntryList (&InfCb->Link); 1777 FreePool (InfCb); 1778 1779 return Status; 1780 } 1781 1782 /** 1783 Create the information request message and send it. 1784 1785 @param[in] Instance The pointer to the Dhcp6 instance. 1786 @param[in] InfCb The pointer to the information request control block. 1787 @param[in] SendClientId If TRUE, the client identifier option will be included in 1788 information request message. Otherwise, the client identifier 1789 option will not be included. 1790 @param[in] OptionRequest The pointer to the option request option. 1791 @param[in] OptionCount The number options in the OptionList. 1792 @param[in] OptionList The array pointers to the appended options. 1793 @param[in] Retransmission The pointer to the retransmission control. 1794 1795 @retval EFI_SUCCESS Created and sent the info-request message successfully. 1796 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1797 @retval Others Failed to send the info-request message. 1798 1799 **/ 1800 EFI_STATUS 1801 Dhcp6SendInfoRequestMsg ( 1802 IN DHCP6_INSTANCE *Instance, 1803 IN DHCP6_INF_CB *InfCb, 1804 IN BOOLEAN SendClientId, 1805 IN EFI_DHCP6_PACKET_OPTION *OptionRequest, 1806 IN UINT32 OptionCount, 1807 IN EFI_DHCP6_PACKET_OPTION *OptionList[], 1808 IN EFI_DHCP6_RETRANSMISSION *Retransmission 1809 ) 1810 { 1811 EFI_STATUS Status; 1812 EFI_DHCP6_PACKET *Packet; 1813 EFI_DHCP6_PACKET_OPTION *UserOpt; 1814 EFI_DHCP6_DUID *ClientId; 1815 DHCP6_SERVICE *Service; 1816 UINT8 *Cursor; 1817 UINT16 *Elapsed; 1818 UINT32 UserLen; 1819 UINTN Index; 1820 UINT16 Length; 1821 1822 ASSERT(OptionRequest); 1823 1824 Service = Instance->Service; 1825 ClientId = Service->ClientId; 1826 UserLen = NTOHS (OptionRequest->OpLen) + 4; 1827 1828 ASSERT(ClientId); 1829 1830 // 1831 // Calculate the added length of customized option list. 1832 // 1833 for (Index = 0; Index < OptionCount; Index++) { 1834 UserLen += (NTOHS (OptionList[Index]->OpLen) + 4); 1835 } 1836 1837 // 1838 // Create the Dhcp6 packet and initialize commone fields. 1839 // 1840 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); 1841 if (Packet == NULL) { 1842 return EFI_OUT_OF_RESOURCES; 1843 } 1844 1845 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; 1846 Packet->Length = sizeof (EFI_DHCP6_HEADER); 1847 Packet->Dhcp6.Header.MessageType = Dhcp6MsgInfoRequest; 1848 Packet->Dhcp6.Header.TransactionId = Service->Xid++; 1849 1850 InfCb->Xid = Packet->Dhcp6.Header.TransactionId; 1851 1852 // 1853 // Assembly Dhcp6 options for info-request message. 1854 // 1855 Cursor = Packet->Dhcp6.Option; 1856 1857 if (SendClientId) { 1858 Length = HTONS (ClientId->Length); 1859 Cursor = Dhcp6AppendOption ( 1860 Cursor, 1861 HTONS (Dhcp6OptClientId), 1862 Length, 1863 ClientId->Duid 1864 ); 1865 } 1866 1867 Cursor = Dhcp6AppendETOption ( 1868 Cursor, 1869 Instance, 1870 &Elapsed 1871 ); 1872 1873 Cursor = Dhcp6AppendOption ( 1874 Cursor, 1875 OptionRequest->OpCode, 1876 OptionRequest->OpLen, 1877 OptionRequest->Data 1878 ); 1879 1880 // 1881 // Append user-defined when configurate Dhcp6 service. 1882 // 1883 for (Index = 0; Index < OptionCount; Index++) { 1884 1885 UserOpt = OptionList[Index]; 1886 Cursor = Dhcp6AppendOption( 1887 Cursor, 1888 UserOpt->OpCode, 1889 UserOpt->OpLen, 1890 UserOpt->Data 1891 ); 1892 } 1893 1894 // 1895 // Determine the size/length of packet. 1896 // 1897 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option); 1898 ASSERT (Packet->Size > Packet->Length + 8); 1899 1900 // 1901 // Clear initial time for current transaction. 1902 // 1903 Instance->StartTime = 0; 1904 1905 // 1906 // Send info-request packet with no state. 1907 // 1908 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); 1909 1910 if (EFI_ERROR (Status)) { 1911 FreePool (Packet); 1912 return Status; 1913 } 1914 1915 // 1916 // Enqueue the sent packet for the retransmission in case reply timeout. 1917 // 1918 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission); 1919 } 1920 1921 1922 /** 1923 Create the Confirm message and send it. 1924 1925 @param[in] Instance The pointer to the Dhcp6 instance. 1926 1927 @retval EFI_SUCCESS Created and sent the confirm message successfully. 1928 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 1929 @retval EFI_DEVICE_ERROR An unexpected error. 1930 @retval Others Failed to send the confirm message. 1931 1932 **/ 1933 EFI_STATUS 1934 Dhcp6SendConfirmMsg ( 1935 IN DHCP6_INSTANCE *Instance 1936 ) 1937 { 1938 UINT8 *Cursor; 1939 UINTN Index; 1940 UINT16 Length; 1941 UINT32 UserLen; 1942 EFI_STATUS Status; 1943 DHCP6_SERVICE *Service; 1944 EFI_DHCP6_DUID *ClientId; 1945 EFI_DHCP6_PACKET *Packet; 1946 EFI_DHCP6_PACKET_OPTION *UserOpt; 1947 UINT16 *Elapsed; 1948 1949 ASSERT (Instance->Config != NULL); 1950 ASSERT (Instance->IaCb.Ia != NULL); 1951 ASSERT (Instance->Service != NULL); 1952 1953 Service = Instance->Service; 1954 ClientId = Service->ClientId; 1955 ASSERT (ClientId != NULL); 1956 1957 // 1958 // Calculate the added length of customized option list. 1959 // 1960 UserLen = 0; 1961 for (Index = 0; Index < Instance->Config->OptionCount; Index++) { 1962 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4); 1963 } 1964 1965 // 1966 // Create the Dhcp6 packet and initialize common fields. 1967 // 1968 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); 1969 if (Packet == NULL) { 1970 return EFI_OUT_OF_RESOURCES; 1971 } 1972 1973 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; 1974 Packet->Length = sizeof (EFI_DHCP6_HEADER); 1975 Packet->Dhcp6.Header.MessageType = Dhcp6MsgConfirm; 1976 Packet->Dhcp6.Header.TransactionId = Service->Xid++; 1977 1978 // 1979 // Assembly Dhcp6 options for solicit message. 1980 // 1981 Cursor = Packet->Dhcp6.Option; 1982 1983 Length = HTONS (ClientId->Length); 1984 Cursor = Dhcp6AppendOption ( 1985 Cursor, 1986 HTONS (Dhcp6OptClientId), 1987 Length, 1988 ClientId->Duid 1989 ); 1990 1991 Cursor = Dhcp6AppendETOption ( 1992 Cursor, 1993 Instance, 1994 &Elapsed 1995 ); 1996 1997 Cursor = Dhcp6AppendIaOption ( 1998 Cursor, 1999 Instance->IaCb.Ia, 2000 Instance->IaCb.T1, 2001 Instance->IaCb.T2, 2002 Packet->Dhcp6.Header.MessageType 2003 ); 2004 2005 // 2006 // Append user-defined when configurate Dhcp6 service. 2007 // 2008 for (Index = 0; Index < Instance->Config->OptionCount; Index++) { 2009 UserOpt = Instance->Config->OptionList[Index]; 2010 Cursor = Dhcp6AppendOption ( 2011 Cursor, 2012 UserOpt->OpCode, 2013 UserOpt->OpLen, 2014 UserOpt->Data 2015 ); 2016 } 2017 2018 // 2019 // Determine the size/length of packet. 2020 // 2021 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option); 2022 ASSERT (Packet->Size > Packet->Length + 8); 2023 2024 // 2025 // Callback to user with the packet to be sent and check the user's feedback. 2026 // 2027 Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet); 2028 2029 if (EFI_ERROR (Status)) { 2030 FreePool (Packet); 2031 return Status; 2032 } 2033 2034 // 2035 // Send confirm packet with the state transition from Dhcp6Bound to 2036 // Dhcp6Confirming. 2037 // 2038 Instance->IaCb.Ia->State = Dhcp6Confirming; 2039 // 2040 // Clear initial time for current transaction. 2041 // 2042 Instance->StartTime = 0; 2043 2044 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); 2045 2046 if (EFI_ERROR (Status)) { 2047 FreePool (Packet); 2048 return Status; 2049 } 2050 2051 // 2052 // Enqueue the sent packet for the retransmission in case reply timeout. 2053 // 2054 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); 2055 } 2056 2057 2058 2059 /** 2060 Handle with the Dhcp6 reply message. 2061 2062 @param[in] Instance The pointer to Dhcp6 instance. 2063 @param[in] Packet The pointer to the Dhcp6 reply message. 2064 2065 @retval EFI_SUCCESS Processed the reply message successfully. 2066 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 2067 @retval EFI_DEVICE_ERROR An unexpected error. 2068 @retval Others Failed to process the reply message. 2069 2070 **/ 2071 EFI_STATUS 2072 Dhcp6HandleReplyMsg ( 2073 IN DHCP6_INSTANCE *Instance, 2074 IN EFI_DHCP6_PACKET *Packet 2075 ) 2076 { 2077 EFI_STATUS Status; 2078 UINT8 *Option; 2079 UINT16 StsCode; 2080 2081 ASSERT (Instance->Config != NULL); 2082 ASSERT (Instance->IaCb.Ia != NULL); 2083 ASSERT (Packet != NULL); 2084 2085 Status = EFI_SUCCESS; 2086 2087 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) { 2088 return EFI_DEVICE_ERROR; 2089 } 2090 2091 // 2092 // If the client subsequently receives a valid reply message that includes a 2093 // rapid commit option since send a solicit with rapid commit option before, 2094 // preocess the reply message and discard any reply messages received in 2095 // response to the request message. 2096 // See details in the section-17.1.4 of rfc-3315. 2097 // 2098 Option = Dhcp6SeekOption ( 2099 Packet->Dhcp6.Option, 2100 Packet->Length - 4, 2101 Dhcp6OptRapidCommit 2102 ); 2103 2104 if ((Option != NULL && !Instance->Config->RapidCommit) || (Option == NULL && Instance->Config->RapidCommit)) { 2105 return EFI_DEVICE_ERROR; 2106 } 2107 2108 // 2109 // As to a valid reply packet in response to a request/renew/rebind packet, 2110 // ignore the packet if not contains the Ia option 2111 // 2112 if (Instance->IaCb.Ia->State == Dhcp6Requesting || 2113 Instance->IaCb.Ia->State == Dhcp6Renewing || 2114 Instance->IaCb.Ia->State == Dhcp6Rebinding 2115 ) { 2116 2117 Option = Dhcp6SeekIaOption ( 2118 Packet->Dhcp6.Option, 2119 Packet->Length, 2120 &Instance->Config->IaDescriptor 2121 ); 2122 if (Option == NULL) { 2123 return EFI_SUCCESS; 2124 } 2125 } 2126 2127 // 2128 // Callback to user with the received packet and check the user's feedback. 2129 // 2130 Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdReply, &Packet); 2131 2132 if (EFI_ERROR (Status)) { 2133 return Status; 2134 } 2135 2136 // 2137 // When receive a valid reply packet in response to a decline/release packet, 2138 // the client considers the decline/release event completed regardless of the 2139 // status code. 2140 // 2141 if (Instance->IaCb.Ia->State == Dhcp6Declining || Instance->IaCb.Ia->State == Dhcp6Releasing) { 2142 2143 if (Instance->IaCb.Ia->IaAddressCount != 0) { 2144 Instance->IaCb.Ia->State = Dhcp6Bound; 2145 } else { 2146 ASSERT (Instance->IaCb.Ia->ReplyPacket); 2147 FreePool (Instance->IaCb.Ia->ReplyPacket); 2148 Instance->IaCb.Ia->ReplyPacket = NULL; 2149 Instance->IaCb.Ia->State = Dhcp6Init; 2150 } 2151 2152 // 2153 // For sync, set the success flag out of polling in decline/release. 2154 // 2155 Instance->UdpSts = EFI_SUCCESS; 2156 2157 // 2158 // For async, signal the Ia event to inform Ia infomation update. 2159 // 2160 if (Instance->Config->IaInfoEvent != NULL) { 2161 gBS->SignalEvent (Instance->Config->IaInfoEvent); 2162 } 2163 2164 // 2165 // Reset start time for next exchange. 2166 // 2167 Instance->StartTime = 0; 2168 2169 Status = EFI_SUCCESS; 2170 goto ON_EXIT; 2171 } 2172 2173 // 2174 // Upon the receipt of a valid reply packet in response to a solicit, request, 2175 // confirm, renew and rebind, the behavior depends on the status code option. 2176 // See the details in the section-18.1.8 of rfc-3315. 2177 // 2178 Option = NULL; 2179 Status = Dhcp6SeekStsOption ( 2180 Instance, 2181 Packet, 2182 &Option 2183 ); 2184 2185 if (!EFI_ERROR (Status)) { 2186 // 2187 // No status code or no error status code means succeed to reply. 2188 // 2189 Status = Dhcp6UpdateIaInfo (Instance, Packet); 2190 if (!EFI_ERROR (Status)) { 2191 // 2192 // Reset start time for next exchange. 2193 // 2194 Instance->StartTime = 0; 2195 2196 // 2197 // Set bound state and store the reply packet. 2198 // 2199 if (Instance->IaCb.Ia->ReplyPacket != NULL) { 2200 FreePool (Instance->IaCb.Ia->ReplyPacket); 2201 } 2202 2203 Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size); 2204 2205 if (Instance->IaCb.Ia->ReplyPacket == NULL) { 2206 Status = EFI_OUT_OF_RESOURCES; 2207 goto ON_EXIT; 2208 } 2209 2210 CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size); 2211 2212 Instance->IaCb.Ia->State = Dhcp6Bound; 2213 2214 // 2215 // For sync, set the success flag out of polling in start/renewrebind. 2216 // 2217 Instance->UdpSts = EFI_SUCCESS; 2218 2219 // 2220 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink 2221 // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that 2222 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP 2223 // consumers can be notified to flush old address. 2224 // 2225 Dhcp6AppendCacheIa (Instance); 2226 2227 // 2228 // For async, signal the Ia event to inform Ia infomation update. 2229 // 2230 if (Instance->Config->IaInfoEvent != NULL) { 2231 gBS->SignalEvent (Instance->Config->IaInfoEvent); 2232 } 2233 } else if (Status == EFI_NOT_FOUND) { 2234 // 2235 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, 2236 // the client sends a Renew or Rebind if the IA is not in the Reply message. 2237 // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process. 2238 // 2239 return EFI_SUCCESS; 2240 } 2241 2242 goto ON_EXIT; 2243 2244 } else if (Option != NULL) { 2245 // 2246 // Any error status code option is found. 2247 // 2248 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4))); 2249 switch (StsCode) { 2250 case Dhcp6StsUnspecFail: 2251 // 2252 // It indicates the server is unable to process the message due to an 2253 // unspecified failure condition, so just retry if possible. 2254 // 2255 break; 2256 2257 case Dhcp6StsUseMulticast: 2258 // 2259 // It indicates the server receives a message via unicast from a client 2260 // to which the server has not sent a unicast option, so retry it by 2261 // multi-cast address. 2262 // 2263 if (Instance->Unicast != NULL) { 2264 FreePool (Instance->Unicast); 2265 Instance->Unicast = NULL; 2266 } 2267 break; 2268 2269 case Dhcp6StsNotOnLink: 2270 if (Instance->IaCb.Ia->State == Dhcp6Confirming) { 2271 // 2272 // Before initiate new round DHCP, cache the current IA. 2273 // 2274 Status = Dhcp6CacheIa (Instance); 2275 if (EFI_ERROR (Status)) { 2276 return Status; 2277 } 2278 2279 // 2280 // Restart S.A.R.R process to acquire new address. 2281 // 2282 Status = Dhcp6InitSolicitMsg (Instance); 2283 if (EFI_ERROR (Status)) { 2284 return Status; 2285 } 2286 } 2287 break; 2288 2289 case Dhcp6StsNoBinding: 2290 if (Instance->IaCb.Ia->State == Dhcp6Renewing || Instance->IaCb.Ia->State == Dhcp6Rebinding) { 2291 // 2292 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client 2293 // sends a Request message if the IA contained a Status Code option with the NoBinding status. 2294 // 2295 Status = Dhcp6SendRequestMsg(Instance); 2296 if (EFI_ERROR (Status)) { 2297 return Status; 2298 } 2299 } 2300 break; 2301 2302 default: 2303 // 2304 // The other status code, just restart solicitation. 2305 // 2306 break; 2307 } 2308 } 2309 2310 return EFI_SUCCESS; 2311 2312 ON_EXIT: 2313 2314 if (!EFI_ERROR(Status)) { 2315 Status = Dhcp6DequeueRetry ( 2316 Instance, 2317 Packet->Dhcp6.Header.TransactionId, 2318 FALSE 2319 ); 2320 } 2321 2322 return Status; 2323 } 2324 2325 2326 /** 2327 Select the appointed Dhcp6 advertisement message. 2328 2329 @param[in] Instance The pointer to the Dhcp6 instance. 2330 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message. 2331 2332 @retval EFI_SUCCESS Selected the right advertisement message successfully. 2333 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 2334 @retval Others Failed to select the advertise message. 2335 2336 **/ 2337 EFI_STATUS 2338 Dhcp6SelectAdvertiseMsg ( 2339 IN DHCP6_INSTANCE *Instance, 2340 IN EFI_DHCP6_PACKET *AdSelect 2341 ) 2342 { 2343 EFI_STATUS Status; 2344 UINT8 *Option; 2345 2346 ASSERT (AdSelect != NULL); 2347 2348 // 2349 // Callback to user with the selected advertisement packet, and the user 2350 // might overwrite it. 2351 // 2352 Status = Dhcp6CallbackUser (Instance, Dhcp6SelectAdvertise, &AdSelect); 2353 2354 if (EFI_ERROR (Status)) { 2355 return Status; 2356 } 2357 2358 Instance->AdSelect = AdSelect; 2359 2360 // 2361 // Dequeue the sent packet for the retransmission since advertisement selected. 2362 // 2363 Status = Dhcp6DequeueRetry ( 2364 Instance, 2365 AdSelect->Dhcp6.Header.TransactionId, 2366 FALSE 2367 ); 2368 2369 if (EFI_ERROR(Status)) { 2370 return Status; 2371 } 2372 2373 // 2374 // Check whether there is server unicast option in the selected advertise 2375 // packet, and update it. 2376 // 2377 Option = Dhcp6SeekOption( 2378 AdSelect->Dhcp6.Option, 2379 AdSelect->Length - 4, 2380 Dhcp6OptServerUnicast 2381 ); 2382 2383 if (Option != NULL) { 2384 2385 Instance->Unicast = AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS)); 2386 2387 if (Instance->Unicast == NULL) { 2388 return EFI_OUT_OF_RESOURCES; 2389 } 2390 2391 CopyMem (Instance->Unicast, Option + 4, sizeof(EFI_IPv6_ADDRESS)); 2392 } 2393 2394 // 2395 // Update the information of the Ia by the selected advertisement message. 2396 // 2397 Status = Dhcp6UpdateIaInfo (Instance, AdSelect); 2398 2399 if (EFI_ERROR (Status)) { 2400 return Status; 2401 } 2402 2403 // 2404 // Send the request message to continue the S.A.R.R. process. 2405 // 2406 return Dhcp6SendRequestMsg (Instance); 2407 } 2408 2409 2410 /** 2411 Handle with the Dhcp6 advertisement message. 2412 2413 @param[in] Instance The pointer to the Dhcp6 instance. 2414 @param[in] Packet The pointer to the Dhcp6 advertisement message. 2415 2416 @retval EFI_SUCCESS Processed the advertisement message successfully. 2417 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. 2418 @retval EFI_DEVICE_ERROR An unexpected error. 2419 @retval Others Failed to process the advertise message. 2420 2421 **/ 2422 EFI_STATUS 2423 Dhcp6HandleAdvertiseMsg ( 2424 IN DHCP6_INSTANCE *Instance, 2425 IN EFI_DHCP6_PACKET *Packet 2426 ) 2427 { 2428 EFI_STATUS Status; 2429 UINT8 *Option; 2430 BOOLEAN Timeout; 2431 2432 ASSERT(Instance->Config); 2433 ASSERT(Instance->IaCb.Ia); 2434 2435 Timeout = FALSE; 2436 2437 // 2438 // If the client does receives a valid reply message that includes a rapid 2439 // commit option since a solicit with rapid commit optioin sent before, select 2440 // this reply message. Or else, process the advertise messages as normal. 2441 // See details in the section-17.1.4 of rfc-3315. 2442 // 2443 Option = Dhcp6SeekOption( 2444 Packet->Dhcp6.Option, 2445 Packet->Length - 4, 2446 Dhcp6OptRapidCommit 2447 ); 2448 2449 if (Option != NULL && Instance->Config->RapidCommit && Packet->Dhcp6.Header.MessageType == Dhcp6MsgReply) { 2450 2451 return Dhcp6HandleReplyMsg (Instance, Packet); 2452 } 2453 2454 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise) { 2455 return EFI_DEVICE_ERROR; 2456 } 2457 2458 // 2459 // Client must ignore any advertise message that includes a status code option 2460 // containing the value noaddrsavail, with the exception that the client may 2461 // display the associated status message to the user. 2462 // See the details in the section-17.1.3 of rfc-3315. 2463 // 2464 Status = Dhcp6SeekStsOption ( 2465 Instance, 2466 Packet, 2467 &Option 2468 ); 2469 if (EFI_ERROR (Status)) { 2470 return EFI_DEVICE_ERROR; 2471 } 2472 2473 // 2474 // Callback to user with the received packet and check the user's feedback. 2475 // 2476 Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdAdvertise, &Packet); 2477 2478 if (!EFI_ERROR (Status)) { 2479 // 2480 // Success means user choose the current advertisement packet. 2481 // 2482 if (Instance->AdSelect != NULL) { 2483 FreePool (Instance->AdSelect); 2484 } 2485 2486 // 2487 // Store the selected advertisement packet and set a flag. 2488 // 2489 Instance->AdSelect = AllocateZeroPool (Packet->Size); 2490 2491 if (Instance->AdSelect == NULL) { 2492 return EFI_OUT_OF_RESOURCES; 2493 } 2494 2495 CopyMem (Instance->AdSelect, Packet, Packet->Size); 2496 2497 Instance->AdPref = 0xff; 2498 2499 } else if (Status == EFI_NOT_READY) { 2500 // 2501 // Not_ready means user wants to continue to receive more advertise packets. 2502 // 2503 if (Instance->AdPref == 0xff && Instance->AdSelect == NULL) { 2504 // 2505 // It's a tricky point. The timer routine set adpref as 0xff if the first 2506 // rt timeout and no advertisement received, which means any advertisement 2507 // received will be selected after the first rt. 2508 // 2509 Timeout = TRUE; 2510 } 2511 2512 // 2513 // Check whether the current packet has a 255 preference option or not. 2514 // Take non-preference option as 0 value. 2515 // 2516 Option = Dhcp6SeekOption( 2517 Packet->Dhcp6.Option, 2518 Packet->Length - 4, 2519 Dhcp6OptPreference 2520 ); 2521 2522 if (Instance->AdSelect == NULL || (Option != NULL && *(Option + 4) > Instance->AdPref)) { 2523 // 2524 // No advertisements received before or preference is more than other 2525 // advertisements received before. Then store the new packet and the 2526 // preference value. 2527 // 2528 if (Instance->AdSelect != NULL) { 2529 FreePool (Instance->AdSelect); 2530 } 2531 2532 Instance->AdSelect = AllocateZeroPool (Packet->Size); 2533 2534 if (Instance->AdSelect == NULL) { 2535 return EFI_OUT_OF_RESOURCES; 2536 } 2537 2538 CopyMem (Instance->AdSelect, Packet, Packet->Size); 2539 2540 if (Option != NULL) { 2541 Instance->AdPref = *(Option + 4); 2542 } 2543 } else { 2544 // 2545 // Non-preference and other advertisements received before or current 2546 // preference is less than other advertisements received before. 2547 // Leave the packet alone. 2548 } 2549 2550 } else { 2551 // 2552 // Other error status means termination. 2553 // 2554 return Status; 2555 } 2556 2557 // 2558 // Client must collect advertise messages as more as possible until the first 2559 // RT has elapsed, or get a highest preference 255 advertise. 2560 // See details in the section-17.1.2 of rfc-3315. 2561 // 2562 if (Instance->AdPref == 0xff || Timeout) { 2563 Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect); 2564 } 2565 2566 return Status; 2567 } 2568 2569 2570 /** 2571 The Dhcp6 stateful exchange process routine. 2572 2573 @param[in] Instance The pointer to the Dhcp6 instance. 2574 @param[in] Packet The pointer to the received Dhcp6 message. 2575 2576 **/ 2577 VOID 2578 Dhcp6HandleStateful ( 2579 IN DHCP6_INSTANCE *Instance, 2580 IN EFI_DHCP6_PACKET *Packet 2581 ) 2582 { 2583 EFI_STATUS Status; 2584 EFI_DHCP6_DUID *ClientId; 2585 DHCP6_SERVICE *Service; 2586 UINT8 *Option; 2587 2588 Service = Instance->Service; 2589 ClientId = Service->ClientId; 2590 Status = EFI_SUCCESS; 2591 2592 if (Instance->Config == NULL) { 2593 goto ON_CONTINUE; 2594 } 2595 2596 ASSERT (ClientId); 2597 ASSERT (Instance->Config); 2598 ASSERT (Instance->IaCb.Ia); 2599 2600 // 2601 // Discard the packet if not advertisement or reply packet. 2602 // 2603 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise && Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) { 2604 goto ON_CONTINUE; 2605 } 2606 2607 // 2608 // Check whether include client Id or not. 2609 // 2610 Option = Dhcp6SeekOption( 2611 Packet->Dhcp6.Option, 2612 Packet->Length - 4, 2613 Dhcp6OptClientId 2614 ); 2615 2616 if (Option == NULL || CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0) { 2617 goto ON_CONTINUE; 2618 } 2619 2620 // 2621 // Check whether include server Id or not. 2622 // 2623 Option = Dhcp6SeekOption( 2624 Packet->Dhcp6.Option, 2625 Packet->Length - 4, 2626 Dhcp6OptServerId 2627 ); 2628 2629 if (Option == NULL) { 2630 goto ON_CONTINUE; 2631 } 2632 2633 switch (Instance->IaCb.Ia->State) { 2634 case Dhcp6Selecting: 2635 // 2636 // Handle the advertisement message when in the Dhcp6Selecting state. 2637 // Do not need check return status, if failed, just continue to the next. 2638 // 2639 Dhcp6HandleAdvertiseMsg (Instance, Packet); 2640 break; 2641 2642 case Dhcp6Requesting: 2643 case Dhcp6Confirming: 2644 case Dhcp6Renewing: 2645 case Dhcp6Rebinding: 2646 case Dhcp6Releasing: 2647 case Dhcp6Declining: 2648 // 2649 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing 2650 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state. 2651 // If failed here, it should reset the current session. 2652 // 2653 Status = Dhcp6HandleReplyMsg (Instance, Packet); 2654 if (EFI_ERROR (Status)) { 2655 goto ON_EXIT; 2656 } 2657 break; 2658 default: 2659 // 2660 // Other state has not supported yet. 2661 // 2662 break; 2663 } 2664 2665 ON_CONTINUE: 2666 // 2667 // Continue to receive the following Dhcp6 message. 2668 // 2669 Status = UdpIoRecvDatagram ( 2670 Service->UdpIo, 2671 Dhcp6ReceivePacket, 2672 Service, 2673 0 2674 ); 2675 ON_EXIT: 2676 if (EFI_ERROR (Status)) { 2677 Dhcp6CleanupSession (Instance, Status); 2678 } 2679 } 2680 2681 2682 /** 2683 The Dhcp6 stateless exchange process routine. 2684 2685 @param[in] Instance The pointer to the Dhcp6 instance. 2686 @param[in] Packet The pointer to the received Dhcp6 message. 2687 2688 **/ 2689 VOID 2690 Dhcp6HandleStateless ( 2691 IN DHCP6_INSTANCE *Instance, 2692 IN EFI_DHCP6_PACKET *Packet 2693 ) 2694 { 2695 EFI_STATUS Status; 2696 DHCP6_SERVICE *Service; 2697 DHCP6_INF_CB *InfCb; 2698 UINT8 *Option; 2699 BOOLEAN IsMatched; 2700 2701 Service = Instance->Service; 2702 Status = EFI_SUCCESS; 2703 IsMatched = FALSE; 2704 InfCb = NULL; 2705 2706 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) { 2707 goto ON_EXIT; 2708 } 2709 2710 // 2711 // Check whether it's a desired Info-request message by Xid. 2712 // 2713 while (!IsListEmpty (&Instance->InfList)) { 2714 InfCb = NET_LIST_HEAD (&Instance->InfList, DHCP6_INF_CB, Link); 2715 if (InfCb->Xid == Packet->Dhcp6.Header.TransactionId) { 2716 IsMatched = TRUE; 2717 break; 2718 } 2719 } 2720 2721 if (!IsMatched) { 2722 goto ON_EXIT; 2723 } 2724 2725 // 2726 // Check whether include server Id or not. 2727 // 2728 Option = Dhcp6SeekOption ( 2729 Packet->Dhcp6.Option, 2730 Packet->Length - 4, 2731 Dhcp6OptServerId 2732 ); 2733 2734 if (Option == NULL) { 2735 goto ON_EXIT; 2736 } 2737 2738 // 2739 // Callback to user with the received packet and check the user's feedback. 2740 // 2741 Status = InfCb->ReplyCallback ( 2742 &Instance->Dhcp6, 2743 InfCb->CallbackContext, 2744 Packet 2745 ); 2746 2747 if (Status == EFI_NOT_READY) { 2748 // 2749 // Success or aborted will both stop this info-request exchange process, 2750 // but not ready means user wants to continue to receive reply. 2751 // 2752 goto ON_EXIT; 2753 } 2754 2755 // 2756 // Dequeue the sent packet from the txlist if the xid matched, and ignore 2757 // if no xid matched. 2758 // 2759 Dhcp6DequeueRetry ( 2760 Instance, 2761 Packet->Dhcp6.Header.TransactionId, 2762 FALSE 2763 ); 2764 2765 // 2766 // For sync, set the status out of polling for info-request. 2767 // 2768 Instance->UdpSts = Status; 2769 2770 ON_EXIT: 2771 2772 Status = UdpIoRecvDatagram ( 2773 Service->UdpIo, 2774 Dhcp6ReceivePacket, 2775 Service, 2776 0 2777 ); 2778 2779 if (EFI_ERROR (Status)) { 2780 Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATELESS); 2781 } 2782 } 2783 2784 2785 /** 2786 The receive callback function for Dhcp6 exchange process. 2787 2788 @param[in] Udp6Wrap The pointer to the received net buffer. 2789 @param[in] EndPoint The pointer to the udp end point. 2790 @param[in] IoStatus The return status from udp io. 2791 @param[in] Context The opaque parameter to the function. 2792 2793 **/ 2794 VOID 2795 EFIAPI 2796 Dhcp6ReceivePacket ( 2797 IN NET_BUF *Udp6Wrap, 2798 IN UDP_END_POINT *EndPoint, 2799 IN EFI_STATUS IoStatus, 2800 IN VOID *Context 2801 ) 2802 { 2803 EFI_DHCP6_HEADER *Head; 2804 EFI_DHCP6_PACKET *Packet; 2805 DHCP6_SERVICE *Service; 2806 DHCP6_INSTANCE *Instance; 2807 DHCP6_TX_CB *TxCb; 2808 UINT32 Size; 2809 BOOLEAN IsDispatched; 2810 BOOLEAN IsStateless; 2811 LIST_ENTRY *Entry1; 2812 LIST_ENTRY *Next1; 2813 LIST_ENTRY *Entry2; 2814 LIST_ENTRY *Next2; 2815 EFI_STATUS Status; 2816 2817 ASSERT (Udp6Wrap != NULL); 2818 ASSERT (Context != NULL); 2819 2820 Service = (DHCP6_SERVICE *) Context; 2821 Instance = NULL; 2822 Packet = NULL; 2823 IsDispatched = FALSE; 2824 IsStateless = FALSE; 2825 2826 if (EFI_ERROR (IoStatus)) { 2827 return ; 2828 } 2829 2830 // 2831 // Copy the net buffer received from upd6 to a Dhcp6 packet. 2832 // 2833 Size = sizeof (EFI_DHCP6_PACKET) + Udp6Wrap->TotalSize; 2834 Packet = (EFI_DHCP6_PACKET *) AllocateZeroPool (Size); 2835 2836 if (Packet == NULL) { 2837 goto ON_CONTINUE; 2838 } 2839 2840 Packet->Size = Size; 2841 Head = &Packet->Dhcp6.Header; 2842 Packet->Length = NetbufCopy (Udp6Wrap, 0, Udp6Wrap->TotalSize, (UINT8 *) Head); 2843 2844 if (Packet->Length == 0) { 2845 goto ON_CONTINUE; 2846 } 2847 2848 // 2849 // Dispatch packet to right instance by transaction id. 2850 // 2851 NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) { 2852 2853 Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link); 2854 2855 NET_LIST_FOR_EACH_SAFE (Entry2, Next2, &Instance->TxList) { 2856 2857 TxCb = NET_LIST_USER_STRUCT (Entry2, DHCP6_TX_CB, Link); 2858 2859 if (Packet->Dhcp6.Header.TransactionId == TxCb->Xid) { 2860 // 2861 // Find the corresponding packet in tx list, and check it whether belongs 2862 // to stateful exchange process. 2863 // 2864 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) { 2865 IsStateless = TRUE; 2866 } 2867 IsDispatched = TRUE; 2868 break; 2869 } 2870 } 2871 2872 if (IsDispatched) { 2873 break; 2874 } 2875 } 2876 2877 // 2878 // Skip this packet if not dispatched to any instance. 2879 // 2880 if (!IsDispatched) { 2881 goto ON_CONTINUE; 2882 } 2883 2884 // 2885 // Dispatch the received packet ot the right instance. 2886 // 2887 if (IsStateless) { 2888 Dhcp6HandleStateless (Instance, Packet); 2889 } else { 2890 Dhcp6HandleStateful (Instance, Packet); 2891 } 2892 2893 ON_CONTINUE: 2894 2895 if (!IsDispatched) { 2896 Status = UdpIoRecvDatagram ( 2897 Service->UdpIo, 2898 Dhcp6ReceivePacket, 2899 Service, 2900 0 2901 ); 2902 if (EFI_ERROR (Status)) { 2903 NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) { 2904 Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link); 2905 Dhcp6CleanupRetry (Instance, DHCP6_PACKET_ALL); 2906 } 2907 } 2908 } 2909 2910 NetbufFree (Udp6Wrap); 2911 2912 if (Packet != NULL) { 2913 FreePool (Packet); 2914 } 2915 } 2916 2917 /** 2918 Detect Link movement for specified network device. 2919 2920 This routine will try to invoke Snp->GetStatus() to get the media status. 2921 If media present status switches from unpresent to present, a link movement 2922 is detected. Note that the underlying UNDI driver may not support reporting 2923 media status from GET_STATUS command. If that, fail to detect link movement. 2924 2925 @param[in] Instance The pointer to DHCP6_INSTANCE. 2926 2927 @retval TRUE A link movement is detected. 2928 @retval FALSE A link movement is not detected. 2929 2930 **/ 2931 BOOLEAN 2932 Dhcp6LinkMovDetect ( 2933 IN DHCP6_INSTANCE *Instance 2934 ) 2935 { 2936 UINT32 InterruptStatus; 2937 BOOLEAN MediaPresent; 2938 EFI_STATUS Status; 2939 EFI_SIMPLE_NETWORK_PROTOCOL *Snp; 2940 2941 ASSERT (Instance != NULL); 2942 Snp = Instance->Service->Snp; 2943 MediaPresent = Instance->MediaPresent; 2944 2945 // 2946 // Check whether SNP support media detection 2947 // 2948 if (!Snp->Mode->MediaPresentSupported) { 2949 return FALSE; 2950 } 2951 2952 // 2953 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data 2954 // 2955 Status = Snp->GetStatus (Snp, &InterruptStatus, NULL); 2956 if (EFI_ERROR (Status)) { 2957 return FALSE; 2958 } 2959 2960 Instance->MediaPresent = Snp->Mode->MediaPresent; 2961 // 2962 // Media transimit Unpresent to Present means new link movement is detected. 2963 // 2964 if (!MediaPresent && Instance->MediaPresent) { 2965 return TRUE; 2966 } 2967 return FALSE; 2968 } 2969 2970 2971 /** 2972 The timer routine of the Dhcp6 instance for each second. 2973 2974 @param[in] Event The timer event. 2975 @param[in] Context The opaque parameter to the function. 2976 2977 **/ 2978 VOID 2979 EFIAPI 2980 Dhcp6OnTimerTick ( 2981 IN EFI_EVENT Event, 2982 IN VOID *Context 2983 ) 2984 { 2985 LIST_ENTRY *Entry; 2986 LIST_ENTRY *NextEntry; 2987 DHCP6_INSTANCE *Instance; 2988 DHCP6_TX_CB *TxCb; 2989 DHCP6_IA_CB *IaCb; 2990 UINT32 LossTime; 2991 EFI_STATUS Status; 2992 2993 ASSERT (Context != NULL); 2994 2995 Instance = (DHCP6_INSTANCE *) Context; 2996 2997 // 2998 // 1. Loop the tx list, count live time of every tx packet to check whether 2999 // need re-transmit or not. 3000 // 3001 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) { 3002 3003 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link); 3004 3005 TxCb->TickTime++; 3006 3007 if (TxCb->TickTime > TxCb->RetryExp) { 3008 // 3009 // Handle the first rt in the transmission of solicit specially. 3010 // 3011 if ((TxCb->RetryCnt == 0 || TxCb->SolicitRetry) && TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) { 3012 if (Instance->AdSelect == NULL) { 3013 // 3014 // Set adpref as 0xff here to indicate select any advertisement 3015 // afterwards. 3016 // 3017 Instance->AdPref = 0xff; 3018 } else { 3019 // 3020 // Select the advertisement received before. 3021 // 3022 Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect); 3023 if (Status == EFI_ABORTED) { 3024 goto ON_CLOSE; 3025 } else if (EFI_ERROR (Status)) { 3026 TxCb->RetryCnt++; 3027 } 3028 return; 3029 } 3030 } 3031 // 3032 // Increase the retry count for the packet and add up the total loss time. 3033 // 3034 TxCb->RetryCnt++; 3035 TxCb->RetryLos += TxCb->RetryExp; 3036 3037 // 3038 // Check whether overflow the max retry count limit for this packet 3039 // 3040 if (TxCb->RetryCtl.Mrc != 0 && TxCb->RetryCtl.Mrc < TxCb->RetryCnt) { 3041 Status = EFI_NO_RESPONSE; 3042 goto ON_CLOSE; 3043 } 3044 3045 // 3046 // Check whether overflow the max retry duration for this packet 3047 // 3048 if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd <= TxCb->RetryLos) { 3049 Status = EFI_NO_RESPONSE; 3050 goto ON_CLOSE; 3051 } 3052 3053 // 3054 // Re-calculate retry expire timeout for the next time. 3055 // 3056 // Firstly, Check the new calculated time whether overflow the max retry 3057 // expire time. 3058 // 3059 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 3060 TxCb->RetryExp, 3061 FALSE, 3062 TRUE 3063 ); 3064 3065 if (TxCb->RetryCtl.Mrt != 0 && TxCb->RetryCtl.Mrt < TxCb->RetryExp) { 3066 TxCb->RetryExp = Dhcp6CalculateExpireTime ( 3067 TxCb->RetryCtl.Mrt, 3068 TRUE, 3069 TRUE 3070 ); 3071 } 3072 3073 // 3074 // Secondly, Check the new calculated time whether overflow the max retry 3075 // duration time. 3076 // 3077 LossTime = TxCb->RetryLos + TxCb->RetryExp; 3078 if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd < LossTime) { 3079 TxCb->RetryExp = TxCb->RetryCtl.Mrd - TxCb->RetryLos; 3080 } 3081 3082 // 3083 // Reset the tick time for the next retransmission 3084 // 3085 TxCb->TickTime = 0; 3086 3087 // 3088 // Retransmit the last sent packet again. 3089 // 3090 Dhcp6TransmitPacket (Instance, TxCb->TxPacket, TxCb->Elapsed); 3091 TxCb->SolicitRetry = FALSE; 3092 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) { 3093 TxCb->SolicitRetry = TRUE; 3094 } 3095 } 3096 } 3097 3098 // 3099 // 2. Check the configured Ia, count lease time of every valid Ia to check 3100 // whether need to renew or rebind this Ia. 3101 // 3102 IaCb = &Instance->IaCb; 3103 3104 if (Instance->Config == NULL || IaCb->Ia == NULL) { 3105 return; 3106 } 3107 3108 if (IaCb->Ia->State == Dhcp6Bound || IaCb->Ia->State == Dhcp6Renewing || IaCb->Ia->State == Dhcp6Rebinding) { 3109 3110 IaCb->LeaseTime++; 3111 3112 if (IaCb->LeaseTime > IaCb->T2 && IaCb->Ia->State == Dhcp6Bound) { 3113 // 3114 // Exceed t2, send rebind packet to extend the Ia lease. 3115 // 3116 Dhcp6SendRenewRebindMsg (Instance, TRUE); 3117 3118 } else if (IaCb->LeaseTime > IaCb->T1 && IaCb->Ia->State == Dhcp6Bound) { 3119 3120 // 3121 // Exceed t1, send renew packet to extend the Ia lease. 3122 // 3123 Dhcp6SendRenewRebindMsg (Instance, FALSE); 3124 } 3125 } 3126 3127 // 3128 // 3. In any situation when a client may have moved to a new link, the 3129 // client MUST initiate a Confirm/Reply message exchange. 3130 // 3131 if (Dhcp6LinkMovDetect (Instance) && (IaCb->Ia->State == Dhcp6Bound)) { 3132 Dhcp6SendConfirmMsg (Instance); 3133 } 3134 3135 return; 3136 3137 ON_CLOSE: 3138 3139 if (Dhcp6IsValidTxCb (Instance, TxCb) && 3140 TxCb->TxPacket != NULL && 3141 (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest || 3142 TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew || 3143 TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm) 3144 ) { 3145 // 3146 // The failure of renew/Confirm will still switch to the bound state. 3147 // 3148 if ((TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew) || 3149 (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm)) { 3150 ASSERT (Instance->IaCb.Ia); 3151 Instance->IaCb.Ia->State = Dhcp6Bound; 3152 } 3153 // 3154 // The failure of info-request will return no response. 3155 // 3156 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) { 3157 Instance->UdpSts = EFI_NO_RESPONSE; 3158 } 3159 Dhcp6DequeueRetry ( 3160 Instance, 3161 TxCb->Xid, 3162 TRUE 3163 ); 3164 } else { 3165 // 3166 // The failure of the others will terminate current state machine if timeout. 3167 // 3168 Dhcp6CleanupSession (Instance, Status); 3169 } 3170 } 3171