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