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