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