1 /** @file
2 Support functions implementation for UefiPxeBc Driver.
3
4 Copyright (c) 2007 - 2015, 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 "PxeBcImpl.h"
17
18
19 /**
20 Flush the previous configration using the new station Ip address.
21
22 @param[in] Private The pointer to the PxeBc private data.
23 @param[in] StationIp The pointer to the station Ip address.
24 @param[in] SubnetMask The pointer to the subnet mask address for v4.
25
26 @retval EFI_SUCCESS Successfully flushed the previous configuration.
27 @retval Others Failed to flush using the new station Ip.
28
29 **/
30 EFI_STATUS
PxeBcFlushStationIp(PXEBC_PRIVATE_DATA * Private,EFI_IP_ADDRESS * StationIp,EFI_IP_ADDRESS * SubnetMask OPTIONAL)31 PxeBcFlushStationIp (
32 PXEBC_PRIVATE_DATA *Private,
33 EFI_IP_ADDRESS *StationIp,
34 EFI_IP_ADDRESS *SubnetMask OPTIONAL
35 )
36 {
37 EFI_PXE_BASE_CODE_MODE *Mode;
38 EFI_STATUS Status;
39
40 ASSERT (StationIp != NULL);
41
42 Mode = Private->PxeBc.Mode;
43 Status = EFI_SUCCESS;
44
45 if (Mode->UsingIpv6) {
46
47 CopyMem (&Private->Udp6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
48 CopyMem (&Private->Ip6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
49
50 //
51 // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
52 //
53 Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token);
54 Private->Ip6->Configure (Private->Ip6, NULL);
55
56 Status = Private->Ip6->Configure (Private->Ip6, &Private->Ip6CfgData);
57 if (EFI_ERROR (Status)) {
58 goto ON_EXIT;
59 }
60
61 Status = Private->Ip6->Receive (Private->Ip6, &Private->Icmp6Token);
62 } else {
63 ASSERT (SubnetMask != NULL);
64 CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
65 CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
66 CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
67 CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
68
69 //
70 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
71 //
72 Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);
73 Private->Ip4->Configure (Private->Ip4, NULL);
74
75 Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData);
76 if (EFI_ERROR (Status)) {
77 goto ON_EXIT;
78 }
79
80 Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken);
81 }
82
83 ON_EXIT:
84 return Status;
85 }
86
87
88 /**
89 Notify the callback function when an event is triggered.
90
91 @param[in] Event The triggered event.
92 @param[in] Context The opaque parameter to the function.
93
94 **/
95 VOID
96 EFIAPI
PxeBcCommonNotify(IN EFI_EVENT Event,IN VOID * Context)97 PxeBcCommonNotify (
98 IN EFI_EVENT Event,
99 IN VOID *Context
100 )
101 {
102 *((BOOLEAN *) Context) = TRUE;
103 }
104
105
106 /**
107 Do arp resolution from arp cache in PxeBcMode.
108
109 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
110 @param Ip4Addr The Ip4 address for resolution.
111 @param MacAddress The resoluted MAC address if the resolution is successful.
112 The value is undefined if the resolution fails.
113
114 @retval TRUE Found an matched entry.
115 @retval FALSE Did not find a matched entry.
116
117 **/
118 BOOLEAN
PxeBcCheckArpCache(IN EFI_PXE_BASE_CODE_MODE * Mode,IN EFI_IPv4_ADDRESS * Ip4Addr,OUT EFI_MAC_ADDRESS * MacAddress)119 PxeBcCheckArpCache (
120 IN EFI_PXE_BASE_CODE_MODE *Mode,
121 IN EFI_IPv4_ADDRESS *Ip4Addr,
122 OUT EFI_MAC_ADDRESS *MacAddress
123 )
124 {
125 UINT32 Index;
126
127 ASSERT (!Mode->UsingIpv6);
128
129 //
130 // Check whether the current Arp cache in mode data contains this information or not.
131 //
132 for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
133 if (EFI_IP4_EQUAL (&Mode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {
134 CopyMem (
135 MacAddress,
136 &Mode->ArpCache[Index].MacAddr,
137 sizeof (EFI_MAC_ADDRESS)
138 );
139 return TRUE;
140 }
141 }
142
143 return FALSE;
144 }
145
146
147 /**
148 Update the arp cache periodically.
149
150 @param Event The pointer to EFI_PXE_BC_PROTOCOL.
151 @param Context Context of the timer event.
152
153 **/
154 VOID
155 EFIAPI
PxeBcArpCacheUpdate(IN EFI_EVENT Event,IN VOID * Context)156 PxeBcArpCacheUpdate (
157 IN EFI_EVENT Event,
158 IN VOID *Context
159 )
160 {
161 PXEBC_PRIVATE_DATA *Private;
162 EFI_PXE_BASE_CODE_MODE *Mode;
163 EFI_ARP_FIND_DATA *ArpEntry;
164 UINT32 EntryLength;
165 UINT32 EntryCount;
166 UINT32 Index;
167 EFI_STATUS Status;
168
169 Private = (PXEBC_PRIVATE_DATA *) Context;
170 Mode = Private->PxeBc.Mode;
171
172 ASSERT (!Mode->UsingIpv6);
173
174 //
175 // Get the current Arp cache from Arp driver.
176 //
177 Status = Private->Arp->Find (
178 Private->Arp,
179 TRUE,
180 NULL,
181 &EntryLength,
182 &EntryCount,
183 &ArpEntry,
184 TRUE
185 );
186 if (EFI_ERROR (Status)) {
187 return;
188 }
189
190 //
191 // Update the Arp cache in mode data.
192 //
193 Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES);
194
195 for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
196 CopyMem (
197 &Mode->ArpCache[Index].IpAddr,
198 ArpEntry + 1,
199 ArpEntry->SwAddressLength
200 );
201 CopyMem (
202 &Mode->ArpCache[Index].MacAddr,
203 (UINT8 *) (ArpEntry + 1) + ArpEntry->SwAddressLength,
204 ArpEntry->HwAddressLength
205 );
206 ArpEntry = (EFI_ARP_FIND_DATA *) ((UINT8 *) ArpEntry + EntryLength);
207 }
208 }
209
210
211 /**
212 Notify function to handle the received ICMP message in DPC.
213
214 @param Context The PXEBC private data.
215
216 **/
217 VOID
218 EFIAPI
PxeBcIcmpErrorDpcHandle(IN VOID * Context)219 PxeBcIcmpErrorDpcHandle (
220 IN VOID *Context
221 )
222 {
223 EFI_STATUS Status;
224 EFI_IP4_RECEIVE_DATA *RxData;
225 EFI_IP4_PROTOCOL *Ip4;
226 PXEBC_PRIVATE_DATA *Private;
227 EFI_PXE_BASE_CODE_MODE *Mode;
228 UINT8 Type;
229 UINTN Index;
230 UINT32 CopiedLen;
231 UINT8 *IcmpError;
232
233 Private = (PXEBC_PRIVATE_DATA *) Context;
234 Mode = &Private->Mode;
235 Status = Private->IcmpToken.Status;
236 RxData = Private->IcmpToken.Packet.RxData;
237 Ip4 = Private->Ip4;
238
239 ASSERT (!Mode->UsingIpv6);
240
241 if (Status == EFI_ABORTED) {
242 //
243 // It's triggered by user cancellation.
244 //
245 return;
246 }
247
248 if (RxData == NULL) {
249 goto ON_EXIT;
250 }
251
252 if (Status != EFI_ICMP_ERROR) {
253 //
254 // The return status should be recognized as EFI_ICMP_ERROR.
255 //
256 gBS->SignalEvent (RxData->RecycleSignal);
257 goto ON_EXIT;
258 }
259
260 if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&
261 !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {
262 //
263 // The source address of the received packet should be a valid unicast address.
264 //
265 gBS->SignalEvent (RxData->RecycleSignal);
266 goto ON_EXIT;
267 }
268
269 if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {
270 //
271 // The destination address of the received packet should be equal to the host address.
272 //
273 gBS->SignalEvent (RxData->RecycleSignal);
274 goto ON_EXIT;
275 }
276
277 if (RxData->Header->Protocol != EFI_IP_PROTO_ICMP) {
278 //
279 // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP.
280 //
281 gBS->SignalEvent (RxData->RecycleSignal);
282 goto ON_EXIT;
283 }
284
285 Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);
286
287 if (Type != ICMP_DEST_UNREACHABLE &&
288 Type != ICMP_SOURCE_QUENCH &&
289 Type != ICMP_REDIRECT &&
290 Type != ICMP_TIME_EXCEEDED &&
291 Type != ICMP_PARAMETER_PROBLEM) {
292 //
293 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
294 //
295 gBS->SignalEvent (RxData->RecycleSignal);
296 goto ON_EXIT;
297 }
298
299 //
300 // Copy the right ICMP error message into mode data.
301 //
302 CopiedLen = 0;
303 IcmpError = (UINT8 *) &Mode->IcmpError;
304
305 for (Index = 0; Index < RxData->FragmentCount; Index++) {
306 CopiedLen += RxData->FragmentTable[Index].FragmentLength;
307 if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
308 CopyMem (
309 IcmpError,
310 RxData->FragmentTable[Index].FragmentBuffer,
311 RxData->FragmentTable[Index].FragmentLength
312 );
313 } else {
314 CopyMem (
315 IcmpError,
316 RxData->FragmentTable[Index].FragmentBuffer,
317 CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
318 );
319 }
320 IcmpError += CopiedLen;
321 }
322
323 ON_EXIT:
324 Private->IcmpToken.Status = EFI_NOT_READY;
325 Ip4->Receive (Ip4, &Private->IcmpToken);
326 }
327
328
329 /**
330 Callback function to update the latest ICMP6 error message.
331
332 @param Event The event signalled.
333 @param Context The context passed in using the event notifier.
334
335 **/
336 VOID
337 EFIAPI
PxeBcIcmpErrorUpdate(IN EFI_EVENT Event,IN VOID * Context)338 PxeBcIcmpErrorUpdate (
339 IN EFI_EVENT Event,
340 IN VOID *Context
341 )
342 {
343 QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context);
344 }
345
346
347 /**
348 Notify function to handle the received ICMP6 message in DPC.
349
350 @param Context The PXEBC private data.
351
352 **/
353 VOID
354 EFIAPI
PxeBcIcmp6ErrorDpcHandle(IN VOID * Context)355 PxeBcIcmp6ErrorDpcHandle (
356 IN VOID *Context
357 )
358 {
359 PXEBC_PRIVATE_DATA *Private;
360 EFI_IP6_RECEIVE_DATA *RxData;
361 EFI_IP6_PROTOCOL *Ip6;
362 EFI_PXE_BASE_CODE_MODE *Mode;
363 EFI_STATUS Status;
364 UINTN Index;
365 UINT8 Type;
366 UINT32 CopiedLen;
367 UINT8 *Icmp6Error;
368
369 Private = (PXEBC_PRIVATE_DATA *) Context;
370 Mode = &Private->Mode;
371 Status = Private->Icmp6Token.Status;
372 RxData = Private->Icmp6Token.Packet.RxData;
373 Ip6 = Private->Ip6;
374
375 ASSERT (Mode->UsingIpv6);
376
377 if (Status == EFI_ABORTED) {
378 //
379 // It's triggered by user cancellation.
380 //
381 return;
382 }
383
384 if (RxData == NULL) {
385 goto ON_EXIT;
386 }
387
388 if (Status != EFI_ICMP_ERROR) {
389 //
390 // The return status should be recognized as EFI_ICMP_ERROR.
391 //
392 gBS->SignalEvent (RxData->RecycleSignal);
393 goto ON_EXIT;
394 }
395
396 if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) {
397 //
398 // The source address of the received packet should be a valid unicast address.
399 //
400 gBS->SignalEvent (RxData->RecycleSignal);
401 goto ON_EXIT;
402 }
403
404 if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) &&
405 !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v6)) {
406 //
407 // The destination address of the received packet should be equal to the host address.
408 //
409 gBS->SignalEvent (RxData->RecycleSignal);
410 goto ON_EXIT;
411 }
412
413 if (RxData->Header->NextHeader != IP6_ICMP) {
414 //
415 // The nextheader in the header of the receveid packet should be IP6_ICMP.
416 //
417 gBS->SignalEvent (RxData->RecycleSignal);
418 goto ON_EXIT;
419 }
420
421 Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);
422
423 if (Type != ICMP_V6_DEST_UNREACHABLE &&
424 Type != ICMP_V6_PACKET_TOO_BIG &&
425 Type != ICMP_V6_PACKET_TOO_BIG &&
426 Type != ICMP_V6_PARAMETER_PROBLEM) {
427 //
428 // The type of the receveid packet should be an ICMP6 error message.
429 //
430 gBS->SignalEvent (RxData->RecycleSignal);
431 goto ON_EXIT;
432 }
433
434 //
435 // Copy the right ICMP6 error message into mode data.
436 //
437 CopiedLen = 0;
438 Icmp6Error = (UINT8 *) &Mode->IcmpError;
439
440 for (Index = 0; Index < RxData->FragmentCount; Index++) {
441 CopiedLen += RxData->FragmentTable[Index].FragmentLength;
442 if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
443 CopyMem (
444 Icmp6Error,
445 RxData->FragmentTable[Index].FragmentBuffer,
446 RxData->FragmentTable[Index].FragmentLength
447 );
448 } else {
449 CopyMem (
450 Icmp6Error,
451 RxData->FragmentTable[Index].FragmentBuffer,
452 CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
453 );
454 }
455 Icmp6Error += CopiedLen;
456 }
457
458 ON_EXIT:
459 Private->Icmp6Token.Status = EFI_NOT_READY;
460 Ip6->Receive (Ip6, &Private->Icmp6Token);
461 }
462
463
464 /**
465 Callback function to update the latest ICMP6 error message.
466
467 @param Event The event signalled.
468 @param Context The context passed in using the event notifier.
469
470 **/
471 VOID
472 EFIAPI
PxeBcIcmp6ErrorUpdate(IN EFI_EVENT Event,IN VOID * Context)473 PxeBcIcmp6ErrorUpdate (
474 IN EFI_EVENT Event,
475 IN VOID *Context
476 )
477 {
478 QueueDpc (TPL_CALLBACK, PxeBcIcmp6ErrorDpcHandle, Context);
479 }
480
481
482 /**
483 This function is to configure a UDPv4 instance for UdpWrite.
484
485 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
486 @param[in] StationIp The pointer to the station address.
487 @param[in] SubnetMask The pointer to the subnet mask.
488 @param[in] Gateway The pointer to the gateway address.
489 @param[in, out] SrcPort The pointer to the source port.
490 @param[in] DoNotFragment If TRUE, fragment is not enabled.
491 Otherwise, fragment is enabled.
492
493 @retval EFI_SUCCESS Successfully configured this instance.
494 @retval Others Failed to configure this instance.
495
496 **/
497 EFI_STATUS
PxeBcConfigUdp4Write(IN EFI_UDP4_PROTOCOL * Udp4,IN EFI_IPv4_ADDRESS * StationIp,IN EFI_IPv4_ADDRESS * SubnetMask,IN EFI_IPv4_ADDRESS * Gateway,IN OUT UINT16 * SrcPort,IN BOOLEAN DoNotFragment)498 PxeBcConfigUdp4Write (
499 IN EFI_UDP4_PROTOCOL *Udp4,
500 IN EFI_IPv4_ADDRESS *StationIp,
501 IN EFI_IPv4_ADDRESS *SubnetMask,
502 IN EFI_IPv4_ADDRESS *Gateway,
503 IN OUT UINT16 *SrcPort,
504 IN BOOLEAN DoNotFragment
505 )
506 {
507 EFI_UDP4_CONFIG_DATA Udp4CfgData;
508 EFI_STATUS Status;
509
510 ZeroMem (&Udp4CfgData, sizeof (Udp4CfgData));
511
512 Udp4CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
513 Udp4CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
514 Udp4CfgData.TypeOfService = DEFAULT_ToS;
515 Udp4CfgData.TimeToLive = DEFAULT_TTL;
516 Udp4CfgData.AllowDuplicatePort = TRUE;
517 Udp4CfgData.DoNotFragment = DoNotFragment;
518
519 CopyMem (&Udp4CfgData.StationAddress, StationIp, sizeof (*StationIp));
520 CopyMem (&Udp4CfgData.SubnetMask, SubnetMask, sizeof (*SubnetMask));
521
522 Udp4CfgData.StationPort = *SrcPort;
523
524 //
525 // Reset the UDPv4 instance.
526 //
527 Udp4->Configure (Udp4, NULL);
528
529 Status = Udp4->Configure (Udp4, &Udp4CfgData);
530 if (!EFI_ERROR (Status) && !EFI_IP4_EQUAL (Gateway, &mZeroIp4Addr)) {
531 //
532 // The basic configuration is OK, need to add the default route entry
533 //
534 Status = Udp4->Routes (Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, Gateway);
535 if (EFI_ERROR (Status)) {
536 Udp4->Configure (Udp4, NULL);
537 }
538 }
539
540 if (!EFI_ERROR (Status) && *SrcPort == 0) {
541 Udp4->GetModeData (Udp4, &Udp4CfgData, NULL, NULL, NULL);
542 *SrcPort = Udp4CfgData.StationPort;
543 }
544
545 return Status;
546 }
547
548
549 /**
550 This function is to configure a UDPv6 instance for UdpWrite.
551
552 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
553 @param[in] StationIp The pointer to the station address.
554 @param[in, out] SrcPort The pointer to the source port.
555
556 @retval EFI_SUCCESS Successfully configured this instance.
557 @retval Others Failed to configure this instance.
558
559 **/
560 EFI_STATUS
PxeBcConfigUdp6Write(IN EFI_UDP6_PROTOCOL * Udp6,IN EFI_IPv6_ADDRESS * StationIp,IN OUT UINT16 * SrcPort)561 PxeBcConfigUdp6Write (
562 IN EFI_UDP6_PROTOCOL *Udp6,
563 IN EFI_IPv6_ADDRESS *StationIp,
564 IN OUT UINT16 *SrcPort
565 )
566 {
567 EFI_UDP6_CONFIG_DATA CfgData;
568 EFI_STATUS Status;
569
570 ZeroMem (&CfgData, sizeof (EFI_UDP6_CONFIG_DATA));
571
572 CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
573 CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
574 CfgData.HopLimit = PXEBC_DEFAULT_HOPLIMIT;
575 CfgData.AllowDuplicatePort = TRUE;
576 CfgData.StationPort = *SrcPort;
577
578 CopyMem (&CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
579
580 //
581 // Reset the UDPv6 instance.
582 //
583 Udp6->Configure (Udp6, NULL);
584
585 Status = Udp6->Configure (Udp6, &CfgData);
586 if (EFI_ERROR (Status)) {
587 return Status;
588 }
589
590 if (!EFI_ERROR (Status) && *SrcPort == 0) {
591 Udp6->GetModeData (Udp6, &CfgData, NULL, NULL, NULL);
592 *SrcPort = CfgData.StationPort;
593 }
594
595 return Status;
596 }
597
598
599 /**
600 This function is to configure a UDPv4 instance for UdpWrite.
601
602 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
603 @param[in] Session The pointer to the UDP4 session data.
604 @param[in] TimeoutEvent The event for timeout.
605 @param[in] Gateway The pointer to the gateway address.
606 @param[in] HeaderSize An optional field which may be set to the length of a header
607 at HeaderPtr to be prefixed to the data at BufferPtr.
608 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
609 prefixed to the data at BufferPtr.
610 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
611 @param[in] BufferPtr A pointer to the data to be written.
612
613 @retval EFI_SUCCESS Successfully send out data using Udp4Write.
614 @retval Others Failed to send out data.
615
616 **/
617 EFI_STATUS
PxeBcUdp4Write(IN EFI_UDP4_PROTOCOL * Udp4,IN EFI_UDP4_SESSION_DATA * Session,IN EFI_EVENT TimeoutEvent,IN EFI_IPv4_ADDRESS * Gateway OPTIONAL,IN UINTN * HeaderSize OPTIONAL,IN VOID * HeaderPtr OPTIONAL,IN UINTN * BufferSize,IN VOID * BufferPtr)618 PxeBcUdp4Write (
619 IN EFI_UDP4_PROTOCOL *Udp4,
620 IN EFI_UDP4_SESSION_DATA *Session,
621 IN EFI_EVENT TimeoutEvent,
622 IN EFI_IPv4_ADDRESS *Gateway OPTIONAL,
623 IN UINTN *HeaderSize OPTIONAL,
624 IN VOID *HeaderPtr OPTIONAL,
625 IN UINTN *BufferSize,
626 IN VOID *BufferPtr
627 )
628 {
629 EFI_UDP4_COMPLETION_TOKEN Token;
630 EFI_UDP4_TRANSMIT_DATA *TxData;
631 UINT32 TxLength;
632 UINT32 FragCount;
633 UINT32 DataLength;
634 BOOLEAN IsDone;
635 EFI_STATUS Status;
636
637 //
638 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
639 //
640 FragCount = (HeaderSize != NULL) ? 2 : 1;
641 TxLength = sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA);
642 TxData = (EFI_UDP4_TRANSMIT_DATA *) AllocateZeroPool (TxLength);
643 if (TxData == NULL) {
644 return EFI_OUT_OF_RESOURCES;
645 }
646
647 TxData->FragmentCount = FragCount;
648 TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
649 TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
650 DataLength = (UINT32) *BufferSize;
651
652 if (HeaderSize != NULL) {
653 TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
654 TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
655 DataLength += (UINT32) *HeaderSize;
656 }
657
658 if (Gateway != NULL) {
659 TxData->GatewayAddress = Gateway;
660 }
661
662 TxData->UdpSessionData = Session;
663 TxData->DataLength = DataLength;
664 Token.Packet.TxData = TxData;
665 Token.Status = EFI_NOT_READY;
666 IsDone = FALSE;
667
668 Status = gBS->CreateEvent (
669 EVT_NOTIFY_SIGNAL,
670 TPL_NOTIFY,
671 PxeBcCommonNotify,
672 &IsDone,
673 &Token.Event
674 );
675 if (EFI_ERROR (Status)) {
676 goto ON_EXIT;
677 }
678
679 Status = Udp4->Transmit (Udp4, &Token);
680 if (EFI_ERROR (Status)) {
681 goto ON_EXIT;
682 }
683
684 //
685 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
686 //
687 while (!IsDone &&
688 Token.Status == EFI_NOT_READY &&
689 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
690 Udp4->Poll (Udp4);
691 }
692
693 Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
694
695 ON_EXIT:
696 if (Token.Event != NULL) {
697 gBS->CloseEvent (Token.Event);
698 }
699 FreePool (TxData);
700
701 return Status;
702 }
703
704
705 /**
706 This function is to configure a UDPv4 instance for UdpWrite.
707
708 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
709 @param[in] Session The pointer to the UDP6 session data.
710 @param[in] TimeoutEvent The event for timeout.
711 @param[in] HeaderSize An optional field which may be set to the length of a header
712 at HeaderPtr to be prefixed to the data at BufferPtr.
713 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
714 prefixed to the data at BufferPtr.
715 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
716 @param[in] BufferPtr A pointer to the data to be written.
717
718 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
719 @retval Others Failed to send out data.
720
721 **/
722 EFI_STATUS
PxeBcUdp6Write(IN EFI_UDP6_PROTOCOL * Udp6,IN EFI_UDP6_SESSION_DATA * Session,IN EFI_EVENT TimeoutEvent,IN UINTN * HeaderSize OPTIONAL,IN VOID * HeaderPtr OPTIONAL,IN UINTN * BufferSize,IN VOID * BufferPtr)723 PxeBcUdp6Write (
724 IN EFI_UDP6_PROTOCOL *Udp6,
725 IN EFI_UDP6_SESSION_DATA *Session,
726 IN EFI_EVENT TimeoutEvent,
727 IN UINTN *HeaderSize OPTIONAL,
728 IN VOID *HeaderPtr OPTIONAL,
729 IN UINTN *BufferSize,
730 IN VOID *BufferPtr
731 )
732 {
733 EFI_UDP6_COMPLETION_TOKEN Token;
734 EFI_UDP6_TRANSMIT_DATA *TxData;
735 UINT32 TxLength;
736 UINT32 FragCount;
737 UINT32 DataLength;
738 BOOLEAN IsDone;
739 EFI_STATUS Status;
740
741 //
742 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
743 //
744 FragCount = (HeaderSize != NULL) ? 2 : 1;
745 TxLength = sizeof (EFI_UDP6_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA);
746 TxData = (EFI_UDP6_TRANSMIT_DATA *) AllocateZeroPool (TxLength);
747 if (TxData == NULL) {
748 return EFI_OUT_OF_RESOURCES;
749 }
750
751 TxData->FragmentCount = FragCount;
752 TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
753 TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
754 DataLength = (UINT32) *BufferSize;
755
756 if (HeaderSize != NULL) {
757 TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
758 TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
759 DataLength += (UINT32) *HeaderSize;
760 }
761
762 TxData->UdpSessionData = Session;
763 TxData->DataLength = DataLength;
764 Token.Packet.TxData = TxData;
765 Token.Status = EFI_NOT_READY;
766 IsDone = FALSE;
767
768 Status = gBS->CreateEvent (
769 EVT_NOTIFY_SIGNAL,
770 TPL_NOTIFY,
771 PxeBcCommonNotify,
772 &IsDone,
773 &Token.Event
774 );
775 if (EFI_ERROR (Status)) {
776 goto ON_EXIT;
777 }
778
779 Status = Udp6->Transmit (Udp6, &Token);
780 if (EFI_ERROR (Status)) {
781 goto ON_EXIT;
782 }
783
784 //
785 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
786 //
787 while (!IsDone &&
788 Token.Status == EFI_NOT_READY &&
789 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
790 Udp6->Poll (Udp6);
791 }
792
793 Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
794
795 ON_EXIT:
796 if (Token.Event != NULL) {
797 gBS->CloseEvent (Token.Event);
798 }
799 FreePool (TxData);
800
801 return Status;
802 }
803
804
805 /**
806 Check the received packet using the Ip filter.
807
808 @param[in] Mode The pointer to the mode data of PxeBc.
809 @param[in] Session The pointer to the current UDPv4 session.
810 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
811
812 @retval TRUE Passed the Ip filter successfully.
813 @retval FALSE Failed to pass the Ip filter.
814
815 **/
816 BOOLEAN
PxeBcCheckByIpFilter(IN EFI_PXE_BASE_CODE_MODE * Mode,IN VOID * Session,IN UINT16 OpFlags)817 PxeBcCheckByIpFilter (
818 IN EFI_PXE_BASE_CODE_MODE *Mode,
819 IN VOID *Session,
820 IN UINT16 OpFlags
821 )
822 {
823 EFI_IP_ADDRESS DestinationIp;
824 UINTN Index;
825
826 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) == 0) {
827 return TRUE;
828 }
829
830 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) {
831 return TRUE;
832 }
833
834 //
835 // Convert the destination address in session data to host order.
836 //
837 if (Mode->UsingIpv6) {
838 CopyMem (
839 &DestinationIp,
840 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
841 sizeof (EFI_IPv6_ADDRESS)
842 );
843 NTOHLLL (&DestinationIp.v6);
844 } else {
845 ZeroMem (&DestinationIp, sizeof (EFI_IP_ADDRESS));
846 CopyMem (
847 &DestinationIp,
848 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
849 sizeof (EFI_IPv4_ADDRESS)
850 );
851 EFI_NTOHL (DestinationIp);
852 }
853
854 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0 &&
855 (IP4_IS_MULTICAST (DestinationIp.Addr[0]) ||
856 IP6_IS_MULTICAST (&DestinationIp))) {
857 return TRUE;
858 }
859
860 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0 &&
861 IP4_IS_LOCAL_BROADCAST (DestinationIp.Addr[0])) {
862 ASSERT (!Mode->UsingIpv6);
863 return TRUE;
864 }
865
866 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 &&
867 (EFI_IP4_EQUAL (&Mode->StationIp.v4, &DestinationIp) ||
868 EFI_IP6_EQUAL (&Mode->StationIp.v6, &DestinationIp))) {
869 //
870 // Matched if the dest address is equal to the station address.
871 //
872 return TRUE;
873 }
874
875 for (Index = 0; Index < Mode->IpFilter.IpCnt; Index++) {
876 ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT);
877 if (EFI_IP4_EQUAL (&Mode->IpFilter.IpList[Index].v4, &DestinationIp) ||
878 EFI_IP6_EQUAL (&Mode->IpFilter.IpList[Index].v6, &DestinationIp)) {
879 //
880 // Matched if the dest address is equal to any of address in the filter list.
881 //
882 return TRUE;
883 }
884 }
885
886 return FALSE;
887 }
888
889
890 /**
891 Filter the received packet using the destination Ip.
892
893 @param[in] Mode The pointer to the mode data of PxeBc.
894 @param[in] Session The pointer to the current UDPv4 session.
895 @param[in, out] DestIp The pointer to the destination Ip address.
896 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
897
898 @retval TRUE Passed the IPv4 filter successfully.
899 @retval FALSE Failed to pass the IPv4 filter.
900
901 **/
902 BOOLEAN
PxeBcCheckByDestIp(IN EFI_PXE_BASE_CODE_MODE * Mode,IN VOID * Session,IN OUT EFI_IP_ADDRESS * DestIp,IN UINT16 OpFlags)903 PxeBcCheckByDestIp (
904 IN EFI_PXE_BASE_CODE_MODE *Mode,
905 IN VOID *Session,
906 IN OUT EFI_IP_ADDRESS *DestIp,
907 IN UINT16 OpFlags
908 )
909 {
910 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) {
911 //
912 // Copy the destination address from the received packet if accept any.
913 //
914 if (DestIp != NULL) {
915 if (Mode->UsingIpv6) {
916 CopyMem (
917 DestIp,
918 &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress,
919 sizeof (EFI_IPv6_ADDRESS)
920 );
921 } else {
922 ZeroMem (DestIp, sizeof (EFI_IP_ADDRESS));
923 CopyMem (
924 DestIp,
925 &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress,
926 sizeof (EFI_IPv4_ADDRESS)
927 );
928 }
929
930 }
931 return TRUE;
932 } else if (DestIp != NULL &&
933 (EFI_IP4_EQUAL (DestIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
934 EFI_IP6_EQUAL (DestIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress))) {
935 //
936 // The destination address in the received packet is matched if present.
937 //
938 return TRUE;
939 } else if (EFI_IP4_EQUAL (&Mode->StationIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
940 EFI_IP6_EQUAL (&Mode->StationIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress)) {
941 //
942 // The destination address in the received packet is equal to the host address.
943 //
944 return TRUE;
945 }
946
947 return FALSE;
948 }
949
950
951 /**
952 Check the received packet using the destination port.
953
954 @param[in] Mode The pointer to the mode data of PxeBc.
955 @param[in] Session The pointer to the current UDPv4 session.
956 @param[in, out] DestPort The pointer to the destination port.
957 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
958
959 @retval TRUE Passed the IPv4 filter successfully.
960 @retval FALSE Failed to pass the IPv4 filter.
961
962 **/
963 BOOLEAN
PxeBcCheckByDestPort(IN EFI_PXE_BASE_CODE_MODE * Mode,IN VOID * Session,IN OUT UINT16 * DestPort,IN UINT16 OpFlags)964 PxeBcCheckByDestPort (
965 IN EFI_PXE_BASE_CODE_MODE *Mode,
966 IN VOID *Session,
967 IN OUT UINT16 *DestPort,
968 IN UINT16 OpFlags
969 )
970 {
971 UINT16 Port;
972
973 if (Mode->UsingIpv6) {
974 Port = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
975 } else {
976 Port = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
977 }
978
979 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) {
980 //
981 // Return the destination port in the received packet if accept any.
982 //
983 if (DestPort != NULL) {
984 *DestPort = Port;
985 }
986 return TRUE;
987 } else if (DestPort != NULL && *DestPort == Port) {
988 //
989 // The destination port in the received packet is matched if present.
990 //
991 return TRUE;
992 }
993
994 return FALSE;
995 }
996
997
998 /**
999 Filter the received packet using the source Ip.
1000
1001 @param[in] Mode The pointer to the mode data of PxeBc.
1002 @param[in] Session The pointer to the current UDPv4 session.
1003 @param[in, out] SrcIp The pointer to the source Ip address.
1004 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1005
1006 @retval TRUE Passed the IPv4 filter successfully.
1007 @retval FALSE Failed to pass the IPv4 filter.
1008
1009 **/
1010 BOOLEAN
PxeBcFilterBySrcIp(IN EFI_PXE_BASE_CODE_MODE * Mode,IN VOID * Session,IN OUT EFI_IP_ADDRESS * SrcIp,IN UINT16 OpFlags)1011 PxeBcFilterBySrcIp (
1012 IN EFI_PXE_BASE_CODE_MODE *Mode,
1013 IN VOID *Session,
1014 IN OUT EFI_IP_ADDRESS *SrcIp,
1015 IN UINT16 OpFlags
1016 )
1017 {
1018 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) {
1019 //
1020 // Copy the source address from the received packet if accept any.
1021 //
1022 if (SrcIp != NULL) {
1023 if (Mode->UsingIpv6) {
1024 CopyMem (
1025 SrcIp,
1026 &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress,
1027 sizeof (EFI_IPv6_ADDRESS)
1028 );
1029 } else {
1030 ZeroMem (SrcIp, sizeof (EFI_IP_ADDRESS));
1031 CopyMem (
1032 SrcIp,
1033 &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress,
1034 sizeof (EFI_IPv4_ADDRESS)
1035 );
1036 }
1037
1038 }
1039 return TRUE;
1040 } else if (SrcIp != NULL &&
1041 (EFI_IP4_EQUAL (SrcIp, &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress) ||
1042 EFI_IP6_EQUAL (SrcIp, &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress))) {
1043 //
1044 // The source address in the received packet is matched if present.
1045 //
1046 return TRUE;
1047 }
1048
1049 return FALSE;
1050 }
1051
1052
1053 /**
1054 Filter the received packet using the source port.
1055
1056 @param[in] Mode The pointer to the mode data of PxeBc.
1057 @param[in] Session The pointer to the current UDPv4 session.
1058 @param[in, out] SrcPort The pointer to the source port.
1059 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1060
1061 @retval TRUE Passed the IPv4 filter successfully.
1062 @retval FALSE Failed to pass the IPv4 filter.
1063
1064 **/
1065 BOOLEAN
PxeBcFilterBySrcPort(IN EFI_PXE_BASE_CODE_MODE * Mode,IN VOID * Session,IN OUT UINT16 * SrcPort,IN UINT16 OpFlags)1066 PxeBcFilterBySrcPort (
1067 IN EFI_PXE_BASE_CODE_MODE *Mode,
1068 IN VOID *Session,
1069 IN OUT UINT16 *SrcPort,
1070 IN UINT16 OpFlags
1071 )
1072 {
1073 UINT16 Port;
1074
1075 if (Mode->UsingIpv6) {
1076 Port = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
1077 } else {
1078 Port = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
1079 }
1080
1081 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) {
1082 //
1083 // Return the source port in the received packet if accept any.
1084 //
1085 if (SrcPort != NULL) {
1086 *SrcPort = Port;
1087 }
1088 return TRUE;
1089 } else if (SrcPort != NULL && *SrcPort == Port) {
1090 //
1091 // The source port in the received packet is matched if present.
1092 //
1093 return TRUE;
1094 }
1095
1096 return FALSE;
1097 }
1098
1099
1100 /**
1101 This function is to receive packet using Udp4Read.
1102
1103 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
1104 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
1105 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1106 @param[in] TimeoutEvent The event for timeout.
1107 @param[in] OpFlags The UDP operation flags.
1108 @param[in] IsDone The pointer to the IsDone flag.
1109 @param[out] IsMatched The pointer to the IsMatched flag.
1110 @param[in, out] DestIp The pointer to the destination address.
1111 @param[in, out] DestPort The pointer to the destination port.
1112 @param[in, out] SrcIp The pointer to the source address.
1113 @param[in, out] SrcPort The pointer to the source port.
1114
1115 @retval EFI_SUCCESS Successfully read the data using Udp4.
1116 @retval Others Failed to send out data.
1117
1118 **/
1119 EFI_STATUS
PxeBcUdp4Read(IN EFI_UDP4_PROTOCOL * Udp4,IN EFI_UDP4_COMPLETION_TOKEN * Token,IN EFI_PXE_BASE_CODE_MODE * Mode,IN EFI_EVENT TimeoutEvent,IN UINT16 OpFlags,IN BOOLEAN * IsDone,OUT BOOLEAN * IsMatched,IN OUT EFI_IP_ADDRESS * DestIp OPTIONAL,IN OUT EFI_PXE_BASE_CODE_UDP_PORT * DestPort OPTIONAL,IN OUT EFI_IP_ADDRESS * SrcIp OPTIONAL,IN OUT EFI_PXE_BASE_CODE_UDP_PORT * SrcPort OPTIONAL)1120 PxeBcUdp4Read (
1121 IN EFI_UDP4_PROTOCOL *Udp4,
1122 IN EFI_UDP4_COMPLETION_TOKEN *Token,
1123 IN EFI_PXE_BASE_CODE_MODE *Mode,
1124 IN EFI_EVENT TimeoutEvent,
1125 IN UINT16 OpFlags,
1126 IN BOOLEAN *IsDone,
1127 OUT BOOLEAN *IsMatched,
1128 IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,
1129 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,
1130 IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,
1131 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL
1132 )
1133 {
1134 EFI_UDP4_RECEIVE_DATA *RxData;
1135 EFI_UDP4_SESSION_DATA *Session;
1136 EFI_STATUS Status;
1137
1138 Token->Status = EFI_NOT_READY;
1139 *IsDone = FALSE;
1140
1141 Status = Udp4->Receive (Udp4, Token);
1142 if (EFI_ERROR (Status)) {
1143 return Status;
1144 }
1145
1146 //
1147 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1148 //
1149 while (!(*IsDone) &&
1150 Token->Status == EFI_NOT_READY &&
1151 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
1152 //
1153 // Poll the token utill reply/ICMPv6 error message received or timeout.
1154 //
1155 Udp4->Poll (Udp4);
1156 if (Token->Status == EFI_ICMP_ERROR ||
1157 Token->Status == EFI_NETWORK_UNREACHABLE ||
1158 Token->Status == EFI_HOST_UNREACHABLE ||
1159 Token->Status == EFI_PROTOCOL_UNREACHABLE ||
1160 Token->Status == EFI_PORT_UNREACHABLE) {
1161 break;
1162 }
1163 }
1164
1165 Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
1166
1167 if (!EFI_ERROR (Status)) {
1168 //
1169 // check whether this packet matches the filters
1170 //
1171 RxData = Token->Packet.RxData;
1172 Session = &RxData->UdpSession;
1173
1174 *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
1175
1176 if (*IsMatched) {
1177 *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
1178 }
1179
1180 if (*IsMatched) {
1181 *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
1182 }
1183
1184 if (*IsMatched) {
1185 *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
1186 }
1187
1188 if (*IsMatched) {
1189 *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
1190 }
1191
1192 if (!(*IsMatched)) {
1193 //
1194 // Recycle the receiving buffer if not matched.
1195 //
1196 gBS->SignalEvent (RxData->RecycleSignal);
1197 }
1198 }
1199
1200 return Status;
1201 }
1202
1203
1204 /**
1205 This function is to receive packets using Udp6Read.
1206
1207 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
1208 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.
1209 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1210 @param[in] TimeoutEvent The event for timeout.
1211 @param[in] OpFlags The UDP operation flags.
1212 @param[in] IsDone The pointer to the IsDone flag.
1213 @param[out] IsMatched The pointer to the IsMatched flag.
1214 @param[in, out] DestIp The pointer to the destination address.
1215 @param[in, out] DestPort The pointer to the destination port.
1216 @param[in, out] SrcIp The pointer to the source address.
1217 @param[in, out] SrcPort The pointer to the source port.
1218
1219 @retval EFI_SUCCESS Successfully read data using Udp6.
1220 @retval Others Failed to send out data.
1221
1222 **/
1223 EFI_STATUS
PxeBcUdp6Read(IN EFI_UDP6_PROTOCOL * Udp6,IN EFI_UDP6_COMPLETION_TOKEN * Token,IN EFI_PXE_BASE_CODE_MODE * Mode,IN EFI_EVENT TimeoutEvent,IN UINT16 OpFlags,IN BOOLEAN * IsDone,OUT BOOLEAN * IsMatched,IN OUT EFI_IP_ADDRESS * DestIp OPTIONAL,IN OUT EFI_PXE_BASE_CODE_UDP_PORT * DestPort OPTIONAL,IN OUT EFI_IP_ADDRESS * SrcIp OPTIONAL,IN OUT EFI_PXE_BASE_CODE_UDP_PORT * SrcPort OPTIONAL)1224 PxeBcUdp6Read (
1225 IN EFI_UDP6_PROTOCOL *Udp6,
1226 IN EFI_UDP6_COMPLETION_TOKEN *Token,
1227 IN EFI_PXE_BASE_CODE_MODE *Mode,
1228 IN EFI_EVENT TimeoutEvent,
1229 IN UINT16 OpFlags,
1230 IN BOOLEAN *IsDone,
1231 OUT BOOLEAN *IsMatched,
1232 IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,
1233 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,
1234 IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,
1235 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL
1236 )
1237 {
1238 EFI_UDP6_RECEIVE_DATA *RxData;
1239 EFI_UDP6_SESSION_DATA *Session;
1240 EFI_STATUS Status;
1241
1242 Token->Status = EFI_NOT_READY;
1243 *IsDone = FALSE;
1244
1245 Status = Udp6->Receive (Udp6, Token);
1246 if (EFI_ERROR (Status)) {
1247 return Status;
1248 }
1249
1250 //
1251 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1252 //
1253 while (!(*IsDone) &&
1254 Token->Status == EFI_NOT_READY &&
1255 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
1256 //
1257 // Poll the token utill reply/ICMPv6 error message received or timeout.
1258 //
1259 Udp6->Poll (Udp6);
1260 if (Token->Status == EFI_ICMP_ERROR ||
1261 Token->Status == EFI_NETWORK_UNREACHABLE ||
1262 Token->Status == EFI_HOST_UNREACHABLE ||
1263 Token->Status == EFI_PROTOCOL_UNREACHABLE ||
1264 Token->Status == EFI_PORT_UNREACHABLE) {
1265 break;
1266 }
1267 }
1268
1269 Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
1270
1271 if (!EFI_ERROR (Status)) {
1272 //
1273 // check whether this packet matches the filters
1274 //
1275 RxData = Token->Packet.RxData;
1276 Session = &RxData->UdpSession;
1277
1278 *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
1279
1280 if (*IsMatched) {
1281 *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
1282 }
1283
1284 if (*IsMatched) {
1285 *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
1286 }
1287
1288 if (*IsMatched) {
1289 *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
1290 }
1291
1292 if (*IsMatched) {
1293 *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
1294 }
1295
1296 if (!(*IsMatched)) {
1297 //
1298 // Recycle the receiving buffer if not matched.
1299 //
1300 gBS->SignalEvent (RxData->RecycleSignal);
1301 }
1302 }
1303
1304 return Status;
1305 }
1306
1307
1308 /**
1309 This function is to display the IPv4 address.
1310
1311 @param[in] Ip The pointer to the IPv4 address.
1312
1313 **/
1314 VOID
PxeBcShowIp4Addr(IN EFI_IPv4_ADDRESS * Ip)1315 PxeBcShowIp4Addr (
1316 IN EFI_IPv4_ADDRESS *Ip
1317 )
1318 {
1319 UINTN Index;
1320
1321 for (Index = 0; Index < 4; Index++) {
1322 AsciiPrint ("%d", Ip->Addr[Index]);
1323 if (Index < 3) {
1324 AsciiPrint (".");
1325 }
1326 }
1327 }
1328
1329
1330 /**
1331 This function is to display the IPv6 address.
1332
1333 @param[in] Ip The pointer to the IPv6 address.
1334
1335 **/
1336 VOID
PxeBcShowIp6Addr(IN EFI_IPv6_ADDRESS * Ip)1337 PxeBcShowIp6Addr (
1338 IN EFI_IPv6_ADDRESS *Ip
1339 )
1340 {
1341 UINTN Index;
1342
1343 for (Index = 0; Index < 16; Index++) {
1344
1345 if (Ip->Addr[Index] != 0) {
1346 AsciiPrint ("%x", Ip->Addr[Index]);
1347 }
1348 Index++;
1349 if (Index > 15) {
1350 return;
1351 }
1352 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {
1353 AsciiPrint ("0");
1354 }
1355 AsciiPrint ("%x", Ip->Addr[Index]);
1356 if (Index < 15) {
1357 AsciiPrint (":");
1358 }
1359 }
1360 }
1361
1362
1363 /**
1364 This function is to convert UINTN to ASCII string with the required formatting.
1365
1366 @param[in] Number Numeric value to be converted.
1367 @param[in] Buffer The pointer to the buffer for ASCII string.
1368 @param[in] Length The length of the required format.
1369
1370 **/
1371 VOID
PxeBcUintnToAscDecWithFormat(IN UINTN Number,IN UINT8 * Buffer,IN INTN Length)1372 PxeBcUintnToAscDecWithFormat (
1373 IN UINTN Number,
1374 IN UINT8 *Buffer,
1375 IN INTN Length
1376 )
1377 {
1378 UINTN Remainder;
1379
1380 while (Length > 0) {
1381 Length--;
1382 Remainder = Number % 10;
1383 Number /= 10;
1384 Buffer[Length] = (UINT8) ('0' + Remainder);
1385 }
1386 }
1387
1388
1389 /**
1390 This function is to convert a UINTN to a ASCII string, and return the
1391 actual length of the buffer.
1392
1393 @param[in] Number Numeric value to be converted.
1394 @param[in] Buffer The pointer to the buffer for ASCII string.
1395 @param[in] BufferSize The maxsize of the buffer.
1396
1397 @return Length The actual length of the ASCII string.
1398
1399 **/
1400 UINTN
PxeBcUintnToAscDec(IN UINTN Number,IN UINT8 * Buffer,IN UINTN BufferSize)1401 PxeBcUintnToAscDec (
1402 IN UINTN Number,
1403 IN UINT8 *Buffer,
1404 IN UINTN BufferSize
1405 )
1406 {
1407 UINTN Index;
1408 UINTN Length;
1409 CHAR8 TempStr[64];
1410
1411 Index = 63;
1412 TempStr[Index] = 0;
1413
1414 do {
1415 Index--;
1416 TempStr[Index] = (CHAR8) ('0' + (Number % 10));
1417 Number = (UINTN) (Number / 10);
1418 } while (Number != 0);
1419
1420 AsciiStrCpyS ((CHAR8 *) Buffer, BufferSize, &TempStr[Index]);
1421
1422 Length = AsciiStrLen ((CHAR8 *) Buffer);
1423
1424 return Length;
1425 }
1426
1427
1428 /**
1429 This function is to convert unicode hex number to a UINT8.
1430
1431 @param[out] Digit The converted UINT8 for output.
1432 @param[in] Char The unicode hex number to be converted.
1433
1434 @retval EFI_SUCCESS Successfully converted the unicode hex.
1435 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1436
1437 **/
1438 EFI_STATUS
PxeBcUniHexToUint8(OUT UINT8 * Digit,IN CHAR16 Char)1439 PxeBcUniHexToUint8 (
1440 OUT UINT8 *Digit,
1441 IN CHAR16 Char
1442 )
1443 {
1444 if ((Char >= L'0') && (Char <= L'9')) {
1445 *Digit = (UINT8) (Char - L'0');
1446 return EFI_SUCCESS;
1447 }
1448
1449 if ((Char >= L'A') && (Char <= L'F')) {
1450 *Digit = (UINT8) (Char - L'A' + 0x0A);
1451 return EFI_SUCCESS;
1452 }
1453
1454 if ((Char >= L'a') && (Char <= L'f')) {
1455 *Digit = (UINT8) (Char - L'a' + 0x0A);
1456 return EFI_SUCCESS;
1457 }
1458
1459 return EFI_INVALID_PARAMETER;
1460 }
1461
1462 /**
1463 Calculate the elapsed time.
1464
1465 @param[in] Private The pointer to PXE private data
1466
1467 **/
1468 VOID
CalcElapsedTime(IN PXEBC_PRIVATE_DATA * Private)1469 CalcElapsedTime (
1470 IN PXEBC_PRIVATE_DATA *Private
1471 )
1472 {
1473 EFI_TIME Time;
1474 UINT64 CurrentStamp;
1475 UINT64 ElapsedTimeValue;
1476
1477 //
1478 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
1479 //
1480 ZeroMem (&Time, sizeof (EFI_TIME));
1481 gRT->GetTime (&Time, NULL);
1482 CurrentStamp = (UINT64)
1483 (
1484 ((((((Time.Year - 1900) * 360 +
1485 (Time.Month - 1)) * 30 +
1486 (Time.Day - 1)) * 24 + Time.Hour) * 60 +
1487 Time.Minute) * 60 + Time.Second) * 100
1488 + DivU64x32(Time.Nanosecond, 10000000)
1489 );
1490
1491 //
1492 // Sentinel value of 0 means that this is the first DHCP packet that we are
1493 // sending and that we need to initialize the value. First DHCP Solicit
1494 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
1495 //
1496 if (Private->ElapsedTime == 0) {
1497 Private->ElapsedTime = CurrentStamp;
1498 } else {
1499 ElapsedTimeValue = CurrentStamp - Private->ElapsedTime;
1500
1501 //
1502 // If elapsed time cannot fit in two bytes, set it to 0xffff.
1503 //
1504 if (ElapsedTimeValue > 0xffff) {
1505 ElapsedTimeValue = 0xffff;
1506 }
1507 //
1508 // Save the elapsed time
1509 //
1510 Private->ElapsedTime = ElapsedTimeValue;
1511 }
1512 }
1513
1514