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