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