]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
NetworkPkg: comments clean up.
[mirror_edk2.git] / NetworkPkg / Dhcp6Dxe / Dhcp6Io.c
1 /** @file
2 Dhcp6 internal functions implementation.
3
4 Copyright (c) 2009 - 2010, 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 destoryed 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 /**
1631 Create the information request message and send it.
1632
1633 @param[in] Instance The pointer to the Dhcp6 instance.
1634 @param[in] InfCb The pointer to the information request control block.
1635 @param[in] SendClientId If TRUE, the client identifier option will be included in
1636 information request message. Otherwise, the client identifier
1637 option will not be included.
1638 @param[in] OptionRequest The pointer to the option request option.
1639 @param[in] OptionCount The number options in the OptionList.
1640 @param[in] OptionList The array pointers to the appended options.
1641 @param[in] Retransmission The pointer to the retransmission control.
1642
1643 @retval EFI_SUCCESS Created and sent the info-request message successfully.
1644 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1645 @retval Others Failed to send the info-request message.
1646
1647 **/
1648 EFI_STATUS
1649 Dhcp6SendInfoRequestMsg (
1650 IN DHCP6_INSTANCE *Instance,
1651 IN DHCP6_INF_CB *InfCb,
1652 IN BOOLEAN SendClientId,
1653 IN EFI_DHCP6_PACKET_OPTION *OptionRequest,
1654 IN UINT32 OptionCount,
1655 IN EFI_DHCP6_PACKET_OPTION *OptionList[],
1656 IN EFI_DHCP6_RETRANSMISSION *Retransmission
1657 )
1658 {
1659 EFI_STATUS Status;
1660 EFI_DHCP6_PACKET *Packet;
1661 EFI_DHCP6_PACKET_OPTION *UserOpt;
1662 EFI_DHCP6_DUID *ClientId;
1663 DHCP6_SERVICE *Service;
1664 UINT8 *Cursor;
1665 UINT16 *Elapsed;
1666 UINT32 UserLen;
1667 UINTN Index;
1668 UINT16 Length;
1669
1670 ASSERT(OptionRequest);
1671
1672 Service = Instance->Service;
1673 ClientId = Service->ClientId;
1674 UserLen = NTOHS (OptionRequest->OpLen) + 4;
1675
1676 ASSERT(ClientId);
1677
1678 //
1679 // Calculate the added length of customized option list.
1680 //
1681 for (Index = 0; Index < OptionCount; Index++) {
1682 UserLen += (NTOHS (OptionList[Index]->OpLen) + 4);
1683 }
1684
1685 //
1686 // Create the Dhcp6 packet and initialize commone fields.
1687 //
1688 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
1689 if (Packet == NULL) {
1690 return EFI_OUT_OF_RESOURCES;
1691 }
1692
1693 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;
1694 Packet->Length = sizeof (EFI_DHCP6_HEADER);
1695 Packet->Dhcp6.Header.MessageType = Dhcp6MsgInfoRequest;
1696 Packet->Dhcp6.Header.TransactionId = Service->Xid++;
1697
1698 InfCb->Xid = Packet->Dhcp6.Header.TransactionId;
1699
1700 //
1701 // Assembly Dhcp6 options for info-request message.
1702 //
1703 Cursor = Packet->Dhcp6.Option;
1704
1705 if (SendClientId) {
1706 Length = HTONS (ClientId->Length);
1707 Cursor = Dhcp6AppendOption (
1708 Cursor,
1709 HTONS (Dhcp6OptClientId),
1710 Length,
1711 ClientId->Duid
1712 );
1713 }
1714
1715 Cursor = Dhcp6AppendETOption (
1716 Cursor,
1717 Instance,
1718 &Elapsed
1719 );
1720
1721 Cursor = Dhcp6AppendOption (
1722 Cursor,
1723 OptionRequest->OpCode,
1724 OptionRequest->OpLen,
1725 OptionRequest->Data
1726 );
1727
1728 //
1729 // Append user-defined when configurate Dhcp6 service.
1730 //
1731 for (Index = 0; Index < OptionCount; Index++) {
1732
1733 UserOpt = OptionList[Index];
1734 Cursor = Dhcp6AppendOption(
1735 Cursor,
1736 UserOpt->OpCode,
1737 UserOpt->OpLen,
1738 UserOpt->Data
1739 );
1740 }
1741
1742 //
1743 // Determine the size/length of packet.
1744 //
1745 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
1746 ASSERT (Packet->Size > Packet->Length + 8);
1747
1748 //
1749 // Send info-request packet with no state.
1750 //
1751 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
1752
1753 if (EFI_ERROR (Status)) {
1754 FreePool (Packet);
1755 return Status;
1756 }
1757
1758 //
1759 // Enqueue the sent packet for the retransmission in case reply timeout.
1760 //
1761 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission);
1762 }
1763
1764
1765 /**
1766 Create the Confirm message and send it.
1767
1768 @param[in] Instance The pointer to the Dhcp6 instance.
1769
1770 @retval EFI_SUCCESS Created and sent the confirm message successfully.
1771 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1772 @retval EFI_DEVICE_ERROR An unexpected error.
1773 @retval Others Failed to send the confirm message.
1774
1775 **/
1776 EFI_STATUS
1777 Dhcp6SendConfirmMsg (
1778 IN DHCP6_INSTANCE *Instance
1779 )
1780 {
1781 UINT8 *Cursor;
1782 UINTN Index;
1783 UINT16 Length;
1784 UINT32 UserLen;
1785 EFI_STATUS Status;
1786 DHCP6_SERVICE *Service;
1787 EFI_DHCP6_DUID *ClientId;
1788 EFI_DHCP6_PACKET *Packet;
1789 EFI_DHCP6_PACKET_OPTION *UserOpt;
1790 UINT16 *Elapsed;
1791
1792 ASSERT (Instance->Config != NULL);
1793 ASSERT (Instance->IaCb.Ia != NULL);
1794 ASSERT (Instance->Service != NULL);
1795
1796 Service = Instance->Service;
1797 ClientId = Service->ClientId;
1798 ASSERT (ClientId != NULL);
1799
1800 //
1801 // Calculate the added length of customized option list.
1802 //
1803 UserLen = 0;
1804 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
1805 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
1806 }
1807
1808 //
1809 // Create the Dhcp6 packet and initialize common fields.
1810 //
1811 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
1812 if (Packet == NULL) {
1813 return EFI_OUT_OF_RESOURCES;
1814 }
1815
1816 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;
1817 Packet->Length = sizeof (EFI_DHCP6_HEADER);
1818 Packet->Dhcp6.Header.MessageType = Dhcp6MsgConfirm;
1819 Packet->Dhcp6.Header.TransactionId = Service->Xid++;
1820
1821 //
1822 // Assembly Dhcp6 options for solicit message.
1823 //
1824 Cursor = Packet->Dhcp6.Option;
1825
1826 Length = HTONS (ClientId->Length);
1827 Cursor = Dhcp6AppendOption (
1828 Cursor,
1829 HTONS (Dhcp6OptClientId),
1830 Length,
1831 ClientId->Duid
1832 );
1833
1834 Cursor = Dhcp6AppendETOption (
1835 Cursor,
1836 Instance,
1837 &Elapsed
1838 );
1839
1840 Cursor = Dhcp6AppendIaOption (
1841 Cursor,
1842 Instance->IaCb.Ia,
1843 Instance->IaCb.T1,
1844 Instance->IaCb.T2
1845 );
1846
1847 //
1848 // Append user-defined when configurate Dhcp6 service.
1849 //
1850 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
1851 UserOpt = Instance->Config->OptionList[Index];
1852 Cursor = Dhcp6AppendOption (
1853 Cursor,
1854 UserOpt->OpCode,
1855 UserOpt->OpLen,
1856 UserOpt->Data
1857 );
1858 }
1859
1860 //
1861 // Determine the size/length of packet.
1862 //
1863 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
1864 ASSERT (Packet->Size > Packet->Length + 8);
1865
1866 //
1867 // Callback to user with the packet to be sent and check the user's feedback.
1868 //
1869 Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet);
1870
1871 if (EFI_ERROR (Status)) {
1872 FreePool (Packet);
1873 return Status;
1874 }
1875
1876 //
1877 // Send confirm packet with the state transition from Dhcp6Bound to
1878 // Dhcp6Confirming.
1879 //
1880 Instance->IaCb.Ia->State = Dhcp6Confirming;
1881
1882 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
1883
1884 if (EFI_ERROR (Status)) {
1885 FreePool (Packet);
1886 return Status;
1887 }
1888
1889 //
1890 // Enqueue the sent packet for the retransmission in case reply timeout.
1891 //
1892 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
1893 }
1894
1895
1896
1897 /**
1898 Handle with the Dhcp6 reply message.
1899
1900 @param[in] Instance The pointer to Dhcp6 instance.
1901 @param[in] Packet The pointer to the Dhcp6 reply message.
1902
1903 @retval EFI_SUCCESS Processed the reply message successfully.
1904 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1905 @retval EFI_DEVICE_ERROR An unexpected error.
1906 @retval Others Failed to process the reply message.
1907
1908 **/
1909 EFI_STATUS
1910 Dhcp6HandleReplyMsg (
1911 IN DHCP6_INSTANCE *Instance,
1912 IN EFI_DHCP6_PACKET *Packet
1913 )
1914 {
1915 EFI_STATUS Status;
1916 UINT8 *Option;
1917 UINT16 StsCode;
1918
1919 ASSERT (Instance->Config != NULL);
1920 ASSERT (Instance->IaCb.Ia != NULL);
1921 ASSERT (Packet != NULL);
1922
1923 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
1924 return EFI_DEVICE_ERROR;
1925 }
1926
1927 //
1928 // If the client subsequently receives a valid reply message that includes a
1929 // rapid commit option since send a solicit with rapid commit option before,
1930 // preocess the reply message and discard any reply messages received in
1931 // response to the request message.
1932 // See details in the section-17.1.4 of rfc-3315.
1933 //
1934 Option = Dhcp6SeekOption (
1935 Packet->Dhcp6.Option,
1936 Packet->Length - 4,
1937 Dhcp6OptRapidCommit
1938 );
1939
1940 if ((Option != NULL && !Instance->Config->RapidCommit) || (Option == NULL && Instance->Config->RapidCommit)) {
1941 return EFI_DEVICE_ERROR;
1942 }
1943
1944 //
1945 // As to a valid reply packet in response to a request/renew/rebind packet,
1946 // ignore the packet if not contains the Ia option
1947 //
1948 if (Instance->IaCb.Ia->State == Dhcp6Requesting ||
1949 Instance->IaCb.Ia->State == Dhcp6Renewing ||
1950 Instance->IaCb.Ia->State == Dhcp6Rebinding
1951 ) {
1952
1953 Option = Dhcp6SeekIaOption (
1954 Packet->Dhcp6.Option,
1955 Packet->Length,
1956 &Instance->Config->IaDescriptor
1957 );
1958 if (Option == NULL) {
1959 return EFI_DEVICE_ERROR;
1960 }
1961 }
1962
1963 //
1964 // Callback to user with the received packet and check the user's feedback.
1965 //
1966 Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdReply, &Packet);
1967
1968 if (EFI_ERROR (Status)) {
1969 return Status;
1970 }
1971
1972 //
1973 // Dequeue the sent packet from retransmit list since reply received.
1974 //
1975 Status = Dhcp6DequeueRetry (
1976 Instance,
1977 Packet->Dhcp6.Header.TransactionId,
1978 FALSE
1979 );
1980
1981 if (EFI_ERROR (Status)) {
1982 return Status;
1983 }
1984
1985 //
1986 // When receive a valid reply packet in response to a decline/release packet,
1987 // the client considers the decline/release event completed regardless of the
1988 // status code.
1989 //
1990 if (Instance->IaCb.Ia->State == Dhcp6Declining || Instance->IaCb.Ia->State == Dhcp6Releasing) {
1991
1992 if (Instance->IaCb.Ia->IaAddressCount != 0) {
1993 Instance->IaCb.Ia->State = Dhcp6Bound;
1994 } else {
1995 ASSERT (Instance->IaCb.Ia->ReplyPacket);
1996 FreePool (Instance->IaCb.Ia->ReplyPacket);
1997 Instance->IaCb.Ia->ReplyPacket = NULL;
1998 Instance->IaCb.Ia->State = Dhcp6Init;
1999 }
2000
2001 //
2002 // For sync, set the success flag out of polling in decline/release.
2003 //
2004 Instance->UdpSts = EFI_SUCCESS;
2005
2006 //
2007 // For async, signal the Ia event to inform Ia infomation update.
2008 //
2009 if (Instance->Config->IaInfoEvent != NULL) {
2010 gBS->SignalEvent (Instance->Config->IaInfoEvent);
2011 }
2012
2013 //
2014 // Reset start time for next exchange.
2015 //
2016 Instance->StartTime = 0;
2017
2018 return EFI_SUCCESS;
2019 }
2020
2021 //
2022 // Upon the receipt of a valid reply packet in response to a solicit, request,
2023 // confirm, renew and rebind, the behavior depends on the status code option.
2024 // See the details in the section-18.1.8 of rfc-3315.
2025 //
2026 Option = NULL;
2027 Status = Dhcp6SeekStsOption (
2028 Instance,
2029 Packet,
2030 &Option
2031 );
2032
2033 if (!EFI_ERROR (Status)) {
2034 //
2035 // Reset start time for next exchange.
2036 //
2037 Instance->StartTime = 0;
2038
2039 //
2040 // No status code or no error status code means succeed to reply.
2041 //
2042 Status = Dhcp6UpdateIaInfo (Instance, Packet);
2043
2044 if (EFI_ERROR (Status)) {
2045 return Status;
2046 }
2047
2048 //
2049 // Set bound state and store the reply packet.
2050 //
2051 if (Instance->IaCb.Ia->ReplyPacket != NULL) {
2052 FreePool (Instance->IaCb.Ia->ReplyPacket);
2053 }
2054
2055 Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);
2056
2057 if (Instance->IaCb.Ia->ReplyPacket == NULL) {
2058 return EFI_OUT_OF_RESOURCES;
2059 }
2060
2061 CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);
2062
2063 Instance->IaCb.Ia->State = Dhcp6Bound;
2064
2065 //
2066 // For sync, set the success flag out of polling in start/renewrebind.
2067 //
2068 Instance->UdpSts = EFI_SUCCESS;
2069
2070 //
2071 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
2072 // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
2073 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
2074 // consumers can be notified to flush old address.
2075 //
2076 Dhcp6AppendCacheIa (Instance);
2077
2078 //
2079 // For async, signal the Ia event to inform Ia infomation update.
2080 //
2081 if (Instance->Config->IaInfoEvent != NULL) {
2082 gBS->SignalEvent (Instance->Config->IaInfoEvent);
2083 }
2084 } else if (Option != NULL) {
2085 //
2086 // Any error status code option is found.
2087 //
2088 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));
2089 switch (StsCode) {
2090 case Dhcp6StsUnspecFail:
2091 //
2092 // It indicates the server is unable to process the message due to an
2093 // unspecified failure condition, so just retry if possible.
2094 //
2095 break;
2096
2097 case Dhcp6StsUseMulticast:
2098 //
2099 // It indicates the server receives a message via unicast from a client
2100 // to which the server has not sent a unicast option, so retry it by
2101 // multi-cast address.
2102 //
2103 if (Instance->Unicast != NULL) {
2104 FreePool (Instance->Unicast);
2105 Instance->Unicast = NULL;
2106 }
2107 break;
2108
2109 case Dhcp6StsNotOnLink:
2110 if (Instance->IaCb.Ia->State == Dhcp6Confirming) {
2111 //
2112 // Before initiate new round DHCP, cache the current IA.
2113 //
2114 Status = Dhcp6CacheIa (Instance);
2115 if (EFI_ERROR (Status)) {
2116 return Status;
2117 }
2118
2119 //
2120 // Restart S.A.R.R process to acquire new address.
2121 //
2122 Status = Dhcp6InitSolicitMsg (Instance);
2123 if (EFI_ERROR (Status)) {
2124 return Status;
2125 }
2126 }
2127 break;
2128
2129 default:
2130 //
2131 // The other status code, just restart solicitation.
2132 //
2133 break;
2134 }
2135 }
2136
2137 return EFI_SUCCESS;
2138 }
2139
2140
2141 /**
2142 Select the appointed Dhcp6 advertisement message.
2143
2144 @param[in] Instance The pointer to the Dhcp6 instance.
2145 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
2146
2147 @retval EFI_SUCCESS Selected the right advertisement message successfully.
2148 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2149 @retval Others Failed to select the advertise message.
2150
2151 **/
2152 EFI_STATUS
2153 Dhcp6SelectAdvertiseMsg (
2154 IN DHCP6_INSTANCE *Instance,
2155 IN EFI_DHCP6_PACKET *AdSelect
2156 )
2157 {
2158 EFI_STATUS Status;
2159 UINT8 *Option;
2160
2161 ASSERT (AdSelect != NULL);
2162
2163 //
2164 // Callback to user with the selected advertisement packet, and the user
2165 // might overwrite it.
2166 //
2167 Status = Dhcp6CallbackUser (Instance, Dhcp6SelectAdvertise, &AdSelect);
2168
2169 if (EFI_ERROR (Status)) {
2170 return Status;
2171 }
2172
2173 Instance->AdSelect = AdSelect;
2174
2175 //
2176 // Dequeue the sent packet for the retransmission since advertisement selected.
2177 //
2178 Status = Dhcp6DequeueRetry (
2179 Instance,
2180 AdSelect->Dhcp6.Header.TransactionId,
2181 FALSE
2182 );
2183
2184 if (EFI_ERROR(Status)) {
2185 return Status;
2186 }
2187
2188 //
2189 // Check whether there is server unicast option in the selected advertise
2190 // packet, and update it.
2191 //
2192 Option = Dhcp6SeekOption(
2193 AdSelect->Dhcp6.Option,
2194 AdSelect->Length - 4,
2195 Dhcp6OptServerUnicast
2196 );
2197
2198 if (Option != NULL) {
2199
2200 Instance->Unicast = AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS));
2201
2202 if (Instance->Unicast == NULL) {
2203 return EFI_OUT_OF_RESOURCES;
2204 }
2205
2206 CopyMem (Instance->Unicast, Option + 4, sizeof(EFI_IPv6_ADDRESS));
2207 }
2208
2209 //
2210 // Update the information of the Ia by the selected advertisement message.
2211 //
2212 Status = Dhcp6UpdateIaInfo (Instance, AdSelect);
2213
2214 if (EFI_ERROR (Status)) {
2215 return Status;
2216 }
2217
2218 //
2219 // Send the request message to continue the S.A.R.R. process.
2220 //
2221 return Dhcp6SendRequestMsg (Instance);
2222 }
2223
2224
2225 /**
2226 Handle with the Dhcp6 advertisement message.
2227
2228 @param[in] Instance The pointer to the Dhcp6 instance.
2229 @param[in] Packet The pointer to the Dhcp6 advertisement message.
2230
2231 @retval EFI_SUCCESS Processed the advertisement message successfully.
2232 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2233 @retval EFI_DEVICE_ERROR An unexpected error.
2234 @retval Others Failed to process the advertise message.
2235
2236 **/
2237 EFI_STATUS
2238 Dhcp6HandleAdvertiseMsg (
2239 IN DHCP6_INSTANCE *Instance,
2240 IN EFI_DHCP6_PACKET *Packet
2241 )
2242 {
2243 EFI_STATUS Status;
2244 UINT8 *Option;
2245 UINT16 StsCode;
2246 BOOLEAN Timeout;
2247
2248 ASSERT(Instance->Config);
2249 ASSERT(Instance->IaCb.Ia);
2250
2251 Timeout = FALSE;
2252 StsCode = Dhcp6StsSuccess;
2253
2254 //
2255 // If the client does receives a valid reply message that includes a rapid
2256 // commit option since a solicit with rapid commit optioin sent before, select
2257 // this reply message. Or else, process the advertise messages as normal.
2258 // See details in the section-17.1.4 of rfc-3315.
2259 //
2260 Option = Dhcp6SeekOption(
2261 Packet->Dhcp6.Option,
2262 Packet->Length - 4,
2263 Dhcp6OptRapidCommit
2264 );
2265
2266 if (Option != NULL && Instance->Config->RapidCommit && Packet->Dhcp6.Header.MessageType == Dhcp6MsgReply) {
2267
2268 return Dhcp6HandleReplyMsg (Instance, Packet);
2269 }
2270
2271 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise) {
2272 return EFI_DEVICE_ERROR;
2273 }
2274
2275 //
2276 // Client must ignore any advertise message that includes a status code option
2277 // containing the value noaddrsavail, with the exception that the client may
2278 // display the associated status message to the user.
2279 // See the details in the section-17.1.3 of rfc-3315.
2280 //
2281 Option = Dhcp6SeekOption(
2282 Packet->Dhcp6.Option,
2283 Packet->Length - 4,
2284 Dhcp6OptStatusCode
2285 );
2286
2287 if (Option != NULL) {
2288 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));
2289 if (StsCode != Dhcp6StsSuccess) {
2290 return EFI_DEVICE_ERROR;
2291 }
2292 }
2293
2294 //
2295 // Callback to user with the received packet and check the user's feedback.
2296 //
2297 Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdAdvertise, &Packet);
2298
2299 if (!EFI_ERROR (Status)) {
2300 //
2301 // Success means user choose the current advertisement packet.
2302 //
2303 if (Instance->AdSelect != NULL) {
2304 FreePool (Instance->AdSelect);
2305 }
2306
2307 //
2308 // Store the selected advertisement packet and set a flag.
2309 //
2310 Instance->AdSelect = AllocateZeroPool (Packet->Size);
2311
2312 if (Instance->AdSelect == NULL) {
2313 return EFI_OUT_OF_RESOURCES;
2314 }
2315
2316 CopyMem (Instance->AdSelect, Packet, Packet->Size);
2317
2318 Instance->AdPref = 0xff;
2319
2320 } else if (Status == EFI_NOT_READY) {
2321 //
2322 // Not_ready means user wants to continue to receive more advertise packets.
2323 //
2324 if (Instance->AdPref == 0xff && Instance->AdSelect == NULL) {
2325 //
2326 // It's a tricky point. The timer routine set adpref as 0xff if the first
2327 // rt timeout and no advertisement received, which means any advertisement
2328 // received will be selected after the first rt.
2329 //
2330 Timeout = TRUE;
2331 }
2332
2333 //
2334 // Check whether the current packet has a 255 preference option or not.
2335 // Take non-preference option as 0 value.
2336 //
2337 Option = Dhcp6SeekOption(
2338 Packet->Dhcp6.Option,
2339 Packet->Length - 4,
2340 Dhcp6OptPreference
2341 );
2342
2343 if (Instance->AdSelect == NULL || (Option != NULL && *(Option + 4) > Instance->AdPref)) {
2344 //
2345 // No advertisements received before or preference is more than other
2346 // advertisements received before. Then store the new packet and the
2347 // preference value.
2348 //
2349 if (Instance->AdSelect != NULL) {
2350 FreePool (Instance->AdSelect);
2351 }
2352
2353 Instance->AdSelect = AllocateZeroPool (Packet->Size);
2354
2355 if (Instance->AdSelect == NULL) {
2356 return EFI_OUT_OF_RESOURCES;
2357 }
2358
2359 CopyMem (Instance->AdSelect, Packet, Packet->Size);
2360
2361 if (Option != NULL) {
2362 Instance->AdPref = *(Option + 4);
2363 }
2364 } else {
2365 //
2366 // Non-preference and other advertisements received before or current
2367 // preference is less than other advertisements received before.
2368 // Leave the packet alone.
2369 }
2370
2371 } else {
2372 //
2373 // Other error status means termination.
2374 //
2375 return Status;
2376 }
2377
2378 //
2379 // Client must collect advertise messages as more as possible until the first
2380 // RT has elapsed, or get a highest preference 255 advertise.
2381 // See details in the section-17.1.2 of rfc-3315.
2382 //
2383 if (Instance->AdPref == 0xff || Timeout) {
2384 Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);
2385 }
2386
2387 return Status;
2388 }
2389
2390
2391 /**
2392 The Dhcp6 stateful exchange process routine.
2393
2394 @param[in] Instance The pointer to the Dhcp6 instance.
2395 @param[in] Packet The pointer to the received Dhcp6 message.
2396
2397 **/
2398 VOID
2399 Dhcp6HandleStateful (
2400 IN DHCP6_INSTANCE *Instance,
2401 IN EFI_DHCP6_PACKET *Packet
2402 )
2403 {
2404 EFI_STATUS Status;
2405 EFI_DHCP6_DUID *ClientId;
2406 DHCP6_SERVICE *Service;
2407 UINT8 *Option;
2408
2409 Service = Instance->Service;
2410 ClientId = Service->ClientId;
2411 Status = EFI_SUCCESS;
2412
2413 if (Instance->InDestory || Instance->Config == NULL) {
2414 goto ON_CONTINUE;
2415 }
2416
2417 ASSERT (ClientId);
2418 ASSERT (Instance->Config);
2419 ASSERT (Instance->IaCb.Ia);
2420
2421 //
2422 // Discard the packet if not advertisement or reply packet.
2423 //
2424 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise && Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
2425 goto ON_CONTINUE;
2426 }
2427
2428 //
2429 // Check whether include client Id or not.
2430 //
2431 Option = Dhcp6SeekOption(
2432 Packet->Dhcp6.Option,
2433 Packet->Length - 4,
2434 Dhcp6OptClientId
2435 );
2436
2437 if (Option == NULL || CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0) {
2438 goto ON_CONTINUE;
2439 }
2440
2441 //
2442 // Check whether include server Id or not.
2443 //
2444 Option = Dhcp6SeekOption(
2445 Packet->Dhcp6.Option,
2446 Packet->Length - 4,
2447 Dhcp6OptServerId
2448 );
2449
2450 if (Option == NULL) {
2451 goto ON_CONTINUE;
2452 }
2453
2454 switch (Instance->IaCb.Ia->State) {
2455 case Dhcp6Selecting:
2456 //
2457 // Handle the advertisement message when in the Dhcp6Selecting state.
2458 // Do not need check return status, if failed, just continue to the next.
2459 //
2460 Dhcp6HandleAdvertiseMsg (Instance, Packet);
2461 break;
2462
2463 case Dhcp6Requesting:
2464 case Dhcp6Confirming:
2465 case Dhcp6Renewing:
2466 case Dhcp6Rebinding:
2467 case Dhcp6Releasing:
2468 case Dhcp6Declining:
2469 //
2470 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
2471 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
2472 // If failed here, it should reset the current session.
2473 //
2474 Status = Dhcp6HandleReplyMsg (Instance, Packet);
2475 if (EFI_ERROR (Status)) {
2476 goto ON_EXIT;
2477 }
2478 break;
2479 default:
2480 //
2481 // Other state has not supported yet.
2482 //
2483 break;
2484 }
2485
2486 ON_CONTINUE:
2487 //
2488 // Continue to receive the following Dhcp6 message.
2489 //
2490 Status = UdpIoRecvDatagram (
2491 Service->UdpIo,
2492 Dhcp6ReceivePacket,
2493 Service,
2494 0
2495 );
2496 ON_EXIT:
2497 if (EFI_ERROR (Status)) {
2498 Dhcp6CleanupSession (Instance, Status);
2499 }
2500 }
2501
2502
2503 /**
2504 The Dhcp6 stateless exchange process routine.
2505
2506 @param[in] Instance The pointer to the Dhcp6 instance.
2507 @param[in] Packet The pointer to the received Dhcp6 message.
2508
2509 **/
2510 VOID
2511 Dhcp6HandleStateless (
2512 IN DHCP6_INSTANCE *Instance,
2513 IN EFI_DHCP6_PACKET *Packet
2514 )
2515 {
2516 EFI_STATUS Status;
2517 DHCP6_SERVICE *Service;
2518 DHCP6_INF_CB *InfCb;
2519 UINT8 *Option;
2520 BOOLEAN IsMatched;
2521
2522 Service = Instance->Service;
2523 Status = EFI_SUCCESS;
2524 IsMatched = FALSE;
2525 InfCb = NULL;
2526
2527 if (Instance->InDestory) {
2528 goto ON_EXIT;
2529 }
2530
2531 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
2532 goto ON_EXIT;
2533 }
2534
2535 //
2536 // Check whether it's a desired Info-request message by Xid.
2537 //
2538 while (!IsListEmpty (&Instance->InfList)) {
2539 InfCb = NET_LIST_HEAD (&Instance->InfList, DHCP6_INF_CB, Link);
2540 if (InfCb->Xid == Packet->Dhcp6.Header.TransactionId) {
2541 IsMatched = TRUE;
2542 break;
2543 }
2544 }
2545
2546 if (!IsMatched) {
2547 goto ON_EXIT;
2548 }
2549
2550 //
2551 // Check whether include server Id or not.
2552 //
2553 Option = Dhcp6SeekOption (
2554 Packet->Dhcp6.Option,
2555 Packet->Length - 4,
2556 Dhcp6OptServerId
2557 );
2558
2559 if (Option == NULL) {
2560 goto ON_EXIT;
2561 }
2562
2563 //
2564 // Callback to user with the received packet and check the user's feedback.
2565 //
2566 Status = InfCb->ReplyCallback (
2567 &Instance->Dhcp6,
2568 InfCb->CallbackContext,
2569 Packet
2570 );
2571
2572 if (Status == EFI_NOT_READY) {
2573 //
2574 // Success or aborted will both stop this info-request exchange process,
2575 // but not ready means user wants to continue to receive reply.
2576 //
2577 goto ON_EXIT;
2578 }
2579
2580 //
2581 // Dequeue the sent packet from the txlist if the xid matched, and ignore
2582 // if no xid matched.
2583 //
2584 Dhcp6DequeueRetry (
2585 Instance,
2586 Packet->Dhcp6.Header.TransactionId,
2587 FALSE
2588 );
2589
2590 //
2591 // For sync, set the status out of polling for info-request.
2592 //
2593 Instance->UdpSts = Status;
2594
2595 ON_EXIT:
2596
2597 Status = UdpIoRecvDatagram (
2598 Service->UdpIo,
2599 Dhcp6ReceivePacket,
2600 Service,
2601 0
2602 );
2603
2604 if (EFI_ERROR (Status)) {
2605 Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATELESS);
2606 }
2607 }
2608
2609
2610 /**
2611 The receive callback function for Dhcp6 exchange process.
2612
2613 @param[in] Udp6Wrap The pointer to the received net buffer.
2614 @param[in] EndPoint The pointer to the udp end point.
2615 @param[in] IoStatus The return status from udp io.
2616 @param[in] Context The opaque parameter to the function.
2617
2618 **/
2619 VOID
2620 EFIAPI
2621 Dhcp6ReceivePacket (
2622 IN NET_BUF *Udp6Wrap,
2623 IN UDP_END_POINT *EndPoint,
2624 IN EFI_STATUS IoStatus,
2625 IN VOID *Context
2626 )
2627 {
2628 EFI_DHCP6_HEADER *Head;
2629 EFI_DHCP6_PACKET *Packet;
2630 DHCP6_SERVICE *Service;
2631 DHCP6_INSTANCE *Instance;
2632 DHCP6_TX_CB *TxCb;
2633 UINT32 Size;
2634 BOOLEAN IsDispatched;
2635 BOOLEAN IsStateless;
2636 LIST_ENTRY *Entry1;
2637 LIST_ENTRY *Next1;
2638 LIST_ENTRY *Entry2;
2639 LIST_ENTRY *Next2;
2640
2641 ASSERT (Udp6Wrap != NULL);
2642 ASSERT (Context != NULL);
2643
2644 Service = (DHCP6_SERVICE *) Context;
2645 Instance = NULL;
2646 Packet = NULL;
2647 IsDispatched = FALSE;
2648 IsStateless = FALSE;
2649
2650 if (EFI_ERROR (IoStatus)) {
2651 return ;
2652 }
2653
2654 //
2655 // Copy the net buffer received from upd6 to a Dhcp6 packet.
2656 //
2657 Size = sizeof (EFI_DHCP6_PACKET) + Udp6Wrap->TotalSize;
2658 Packet = (EFI_DHCP6_PACKET *) AllocateZeroPool (Size);
2659
2660 if (Packet == NULL) {
2661 goto ON_CONTINUE;
2662 }
2663
2664 Packet->Size = Size;
2665 Head = &Packet->Dhcp6.Header;
2666 Packet->Length = NetbufCopy (Udp6Wrap, 0, Udp6Wrap->TotalSize, (UINT8 *) Head);
2667
2668 if (Packet->Length == 0) {
2669 goto ON_CONTINUE;
2670 }
2671
2672 //
2673 // Dispatch packet to right instance by transaction id.
2674 //
2675 NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {
2676
2677 Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);
2678
2679 NET_LIST_FOR_EACH_SAFE (Entry2, Next2, &Instance->TxList) {
2680
2681 TxCb = NET_LIST_USER_STRUCT (Entry2, DHCP6_TX_CB, Link);
2682
2683 if (Packet->Dhcp6.Header.TransactionId == TxCb->Xid) {
2684 //
2685 // Find the corresponding packet in tx list, and check it whether belongs
2686 // to stateful exchange process.
2687 //
2688 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
2689 IsStateless = TRUE;
2690 }
2691 IsDispatched = TRUE;
2692 break;
2693 }
2694 }
2695
2696 if (IsDispatched) {
2697 break;
2698 }
2699 }
2700
2701 //
2702 // Skip this packet if not dispatched to any instance.
2703 //
2704 if (!IsDispatched) {
2705 goto ON_CONTINUE;
2706 }
2707
2708 //
2709 // Dispatch the received packet ot the right instance.
2710 //
2711 if (IsStateless) {
2712 Dhcp6HandleStateless (Instance, Packet);
2713 } else {
2714 Dhcp6HandleStateful (Instance, Packet);
2715 }
2716
2717 ON_CONTINUE:
2718
2719 NetbufFree (Udp6Wrap);
2720
2721 if (Packet != NULL) {
2722 FreePool (Packet);
2723 }
2724 }
2725
2726 /**
2727 Detect Link movement for specified network device.
2728
2729 This routine will try to invoke Snp->GetStatus() to get the media status.
2730 If media present status switches from unpresent to present, a link movement
2731 is detected. Note that the underlying UNDI driver may not support reporting
2732 media status from GET_STATUS command. If that, fail to detect link movement.
2733
2734 @param[in] Instance The pointer to DHCP6_INSTANCE.
2735
2736 @retval TRUE A link movement is detected.
2737 @retval FALSE A link movement is not detected.
2738
2739 **/
2740 BOOLEAN
2741 Dhcp6LinkMovDetect (
2742 IN DHCP6_INSTANCE *Instance
2743 )
2744 {
2745 UINT32 InterruptStatus;
2746 BOOLEAN MediaPresent;
2747 EFI_STATUS Status;
2748 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
2749
2750 ASSERT (Instance != NULL);
2751 Snp = Instance->Service->Snp;
2752 MediaPresent = Instance->MediaPresent;
2753
2754 //
2755 // Check whether SNP support media detection
2756 //
2757 if (!Snp->Mode->MediaPresentSupported) {
2758 return FALSE;
2759 }
2760
2761 //
2762 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2763 //
2764 Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);
2765 if (EFI_ERROR (Status)) {
2766 return FALSE;
2767 }
2768
2769 Instance->MediaPresent = Snp->Mode->MediaPresent;
2770 //
2771 // Media transimit Unpresent to Present means new link movement is detected.
2772 //
2773 if (!MediaPresent && Instance->MediaPresent) {
2774 return TRUE;
2775 }
2776 return FALSE;
2777 }
2778
2779
2780 /**
2781 The timer routine of the Dhcp6 instance for each second.
2782
2783 @param[in] Event The timer event.
2784 @param[in] Context The opaque parameter to the function.
2785
2786 **/
2787 VOID
2788 EFIAPI
2789 Dhcp6OnTimerTick (
2790 IN EFI_EVENT Event,
2791 IN VOID *Context
2792 )
2793 {
2794 LIST_ENTRY *Entry;
2795 LIST_ENTRY *NextEntry;
2796 DHCP6_INSTANCE *Instance;
2797 DHCP6_TX_CB *TxCb;
2798 DHCP6_IA_CB *IaCb;
2799 UINT32 LossTime;
2800
2801 ASSERT (Context != NULL);
2802
2803 Instance = (DHCP6_INSTANCE *) Context;
2804
2805 //
2806 // 1. Loop the tx list, count live time of every tx packet to check whether
2807 // need re-transmit or not.
2808 //
2809 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
2810
2811 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
2812
2813 TxCb->TickTime++;
2814
2815 if (TxCb->TickTime > TxCb->RetryExp) {
2816 //
2817 // Handle the first rt in the transmission of solicit specially.
2818 //
2819 if (TxCb->RetryCnt == 0 && TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {
2820 if (Instance->AdSelect == NULL) {
2821 //
2822 // Set adpref as 0xff here to indicate select any advertisement
2823 // afterwards.
2824 //
2825 Instance->AdPref = 0xff;
2826 } else {
2827 //
2828 // Select the advertisement received before.
2829 //
2830 Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);
2831 return;
2832 }
2833 }
2834 //
2835 // Increase the retry count for the packet and add up the total loss time.
2836 //
2837 TxCb->RetryCnt++;
2838 TxCb->RetryLos += TxCb->RetryExp;
2839
2840 //
2841 // Check whether overflow the max retry count limit for this packet
2842 //
2843 if (TxCb->RetryCtl.Mrc != 0 && TxCb->RetryCtl.Mrc < TxCb->RetryCnt) {
2844 goto ON_CLOSE;
2845 }
2846
2847 //
2848 // Check whether overflow the max retry duration for this packet
2849 //
2850 if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd <= TxCb->RetryLos) {
2851 goto ON_CLOSE;
2852 }
2853
2854 //
2855 // Re-calculate retry expire timeout for the next time.
2856 //
2857 // Firstly, Check the new calculated time whether overflow the max retry
2858 // expire time.
2859 //
2860 TxCb->RetryExp = Dhcp6CalculateExpireTime (
2861 TxCb->RetryExp,
2862 FALSE,
2863 TRUE
2864 );
2865
2866 if (TxCb->RetryCtl.Mrt != 0 && TxCb->RetryCtl.Mrt < TxCb->RetryExp) {
2867 TxCb->RetryExp = Dhcp6CalculateExpireTime (
2868 TxCb->RetryCtl.Mrt,
2869 TRUE,
2870 TRUE
2871 );
2872 }
2873
2874 //
2875 // Secondly, Check the new calculated time whether overflow the max retry
2876 // duration time.
2877 //
2878 LossTime = TxCb->RetryLos + TxCb->RetryExp;
2879 if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd < LossTime) {
2880 TxCb->RetryExp = TxCb->RetryCtl.Mrd - TxCb->RetryLos;
2881 }
2882
2883 //
2884 // Reset the tick time for the next retransmission
2885 //
2886 TxCb->TickTime = 0;
2887
2888 //
2889 // Retransmit the last sent packet again.
2890 //
2891 Dhcp6TransmitPacket (Instance, TxCb->TxPacket, TxCb->Elapsed);
2892 }
2893 }
2894
2895 //
2896 // 2. Check the configured Ia, count lease time of every valid Ia to check
2897 // whether need to renew or rebind this Ia.
2898 //
2899 IaCb = &Instance->IaCb;
2900
2901 if (Instance->Config == NULL || IaCb->Ia == NULL) {
2902 return;
2903 }
2904
2905 if (IaCb->Ia->State == Dhcp6Bound || IaCb->Ia->State == Dhcp6Renewing || IaCb->Ia->State == Dhcp6Rebinding) {
2906
2907 IaCb->LeaseTime++;
2908
2909 if (IaCb->LeaseTime > IaCb->T2 && IaCb->Ia->State == Dhcp6Bound) {
2910 //
2911 // Exceed t2, send rebind packet to extend the Ia lease.
2912 //
2913 Dhcp6SendRenewRebindMsg (Instance, TRUE);
2914
2915 } else if (IaCb->LeaseTime > IaCb->T1 && IaCb->Ia->State == Dhcp6Bound) {
2916
2917 //
2918 // Exceed t1, send renew packet to extend the Ia lease.
2919 //
2920 Dhcp6SendRenewRebindMsg (Instance, FALSE);
2921 }
2922 }
2923
2924 //
2925 // 3. In any situation when a client may have moved to a new link, the
2926 // client MUST initiate a Confirm/Reply message exchange.
2927 //
2928 if (Dhcp6LinkMovDetect (Instance) && (IaCb->Ia->State == Dhcp6Bound)) {
2929 Dhcp6SendConfirmMsg (Instance);
2930 }
2931
2932 return;
2933
2934 ON_CLOSE:
2935
2936 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest ||
2937 TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew ||
2938 TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm
2939 ) {
2940 //
2941 // The failure of renew/Confirm will still switch to the bound state.
2942 //
2943 if ((TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew) ||
2944 (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm)) {
2945 ASSERT (Instance->IaCb.Ia);
2946 Instance->IaCb.Ia->State = Dhcp6Bound;
2947 }
2948 //
2949 // The failure of info-request will return no response.
2950 //
2951 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
2952 Instance->UdpSts = EFI_NO_RESPONSE;
2953 }
2954 Dhcp6DequeueRetry (
2955 Instance,
2956 TxCb->Xid,
2957 TRUE
2958 );
2959 } else {
2960 //
2961 // The failure of the others will terminate current state machine if timeout.
2962 //
2963 Dhcp6CleanupSession (Instance, EFI_NO_RESPONSE);
2964 }
2965 }