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