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