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