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