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