]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c
MdeModulePkg: Update PXE driver to follow edk2 coding standards.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcSupport.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Support functions implementation for UefiPxeBc Driver.\r
3\r
6f2f4116 4 Copyright (c) 2007 - 2016, 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
HT
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
a3bcde70
HT
62 } else {\r
63 ASSERT (SubnetMask != NULL);\r
64 CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));\r
65 CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
66 CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));\r
67 CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
68\r
69 //\r
70 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.\r
71 //\r
72 Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);\r
73 Private->Ip4->Configure (Private->Ip4, NULL);\r
74\r
75 Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData);\r
76 if (EFI_ERROR (Status)) {\r
77 goto ON_EXIT;\r
78 }\r
79\r
80 Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken);\r
a3bcde70
HT
81 }\r
82\r
83ON_EXIT:\r
84 return Status;\r
85}\r
86\r
87\r
88/**\r
89 Notify the callback function when an event is triggered.\r
90\r
91 @param[in] Event The triggered event.\r
92 @param[in] Context The opaque parameter to the function.\r
93\r
94**/\r
95VOID\r
96EFIAPI\r
97PxeBcCommonNotify (\r
98 IN EFI_EVENT Event,\r
99 IN VOID *Context\r
100 )\r
101{\r
102 *((BOOLEAN *) Context) = TRUE;\r
103}\r
104\r
105\r
106/**\r
107 Do arp resolution from arp cache in PxeBcMode.\r
108\r
109 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.\r
110 @param Ip4Addr The Ip4 address for resolution.\r
111 @param MacAddress The resoluted MAC address if the resolution is successful.\r
112 The value is undefined if the resolution fails.\r
113\r
114 @retval TRUE Found an matched entry.\r
115 @retval FALSE Did not find a matched entry.\r
116\r
117**/\r
118BOOLEAN\r
119PxeBcCheckArpCache (\r
120 IN EFI_PXE_BASE_CODE_MODE *Mode,\r
121 IN EFI_IPv4_ADDRESS *Ip4Addr,\r
122 OUT EFI_MAC_ADDRESS *MacAddress\r
123 )\r
124{\r
125 UINT32 Index;\r
126\r
127 ASSERT (!Mode->UsingIpv6);\r
128\r
129 //\r
130 // Check whether the current Arp cache in mode data contains this information or not.\r
131 //\r
132 for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {\r
133 if (EFI_IP4_EQUAL (&Mode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {\r
134 CopyMem (\r
135 MacAddress,\r
136 &Mode->ArpCache[Index].MacAddr,\r
137 sizeof (EFI_MAC_ADDRESS)\r
138 );\r
139 return TRUE;\r
140 }\r
141 }\r
142\r
143 return FALSE;\r
144}\r
145\r
146\r
147/**\r
148 Update the arp cache periodically.\r
149\r
150 @param Event The pointer to EFI_PXE_BC_PROTOCOL.\r
151 @param Context Context of the timer event.\r
152\r
153**/\r
154VOID\r
155EFIAPI\r
156PxeBcArpCacheUpdate (\r
157 IN EFI_EVENT Event,\r
158 IN VOID *Context\r
159 )\r
160{\r
161 PXEBC_PRIVATE_DATA *Private;\r
162 EFI_PXE_BASE_CODE_MODE *Mode;\r
163 EFI_ARP_FIND_DATA *ArpEntry;\r
164 UINT32 EntryLength;\r
165 UINT32 EntryCount;\r
166 UINT32 Index;\r
167 EFI_STATUS Status;\r
168\r
169 Private = (PXEBC_PRIVATE_DATA *) Context;\r
170 Mode = Private->PxeBc.Mode;\r
171\r
172 ASSERT (!Mode->UsingIpv6);\r
173\r
174 //\r
175 // Get the current Arp cache from Arp driver.\r
176 //\r
177 Status = Private->Arp->Find (\r
178 Private->Arp,\r
179 TRUE,\r
180 NULL,\r
181 &EntryLength,\r
182 &EntryCount,\r
183 &ArpEntry,\r
184 TRUE\r
185 );\r
186 if (EFI_ERROR (Status)) {\r
187 return;\r
188 }\r
189\r
190 //\r
191 // Update the Arp cache in mode data.\r
192 //\r
193 Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES);\r
194\r
195 for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {\r
196 CopyMem (\r
197 &Mode->ArpCache[Index].IpAddr,\r
198 ArpEntry + 1,\r
199 ArpEntry->SwAddressLength\r
200 );\r
201 CopyMem (\r
202 &Mode->ArpCache[Index].MacAddr,\r
203 (UINT8 *) (ArpEntry + 1) + ArpEntry->SwAddressLength,\r
204 ArpEntry->HwAddressLength\r
205 );\r
206 ArpEntry = (EFI_ARP_FIND_DATA *) ((UINT8 *) ArpEntry + EntryLength);\r
207 }\r
208}\r
209\r
210\r
211/**\r
212 Notify function to handle the received ICMP message in DPC.\r
213\r
214 @param Context The PXEBC private data.\r
215\r
216**/\r
217VOID\r
218EFIAPI\r
219PxeBcIcmpErrorDpcHandle (\r
220 IN VOID *Context\r
221 )\r
222{\r
223 EFI_STATUS Status;\r
224 EFI_IP4_RECEIVE_DATA *RxData;\r
225 EFI_IP4_PROTOCOL *Ip4;\r
226 PXEBC_PRIVATE_DATA *Private;\r
227 EFI_PXE_BASE_CODE_MODE *Mode;\r
228 UINT8 Type;\r
229 UINTN Index;\r
230 UINT32 CopiedLen;\r
231 UINT8 *IcmpError;\r
232\r
233 Private = (PXEBC_PRIVATE_DATA *) Context;\r
234 Mode = &Private->Mode;\r
235 Status = Private->IcmpToken.Status;\r
236 RxData = Private->IcmpToken.Packet.RxData;\r
237 Ip4 = Private->Ip4;\r
238\r
239 ASSERT (!Mode->UsingIpv6);\r
240\r
241 if (Status == EFI_ABORTED) {\r
242 //\r
243 // It's triggered by user cancellation.\r
244 //\r
245 return;\r
246 }\r
247\r
248 if (RxData == NULL) {\r
249 goto ON_EXIT;\r
250 }\r
251\r
252 if (Status != EFI_ICMP_ERROR) {\r
253 //\r
254 // The return status should be recognized as EFI_ICMP_ERROR.\r
255 //\r
256 gBS->SignalEvent (RxData->RecycleSignal);\r
257 goto ON_EXIT;\r
258 }\r
259\r
260 if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&\r
261 !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {\r
262 //\r
263 // The source address of the received packet should be a valid unicast address.\r
264 //\r
265 gBS->SignalEvent (RxData->RecycleSignal);\r
266 goto ON_EXIT;\r
267 }\r
268\r
269 if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {\r
270 //\r
271 // The destination address of the received packet should be equal to the host address.\r
272 //\r
273 gBS->SignalEvent (RxData->RecycleSignal);\r
274 goto ON_EXIT;\r
275 }\r
276\r
277 if (RxData->Header->Protocol != EFI_IP_PROTO_ICMP) {\r
278 //\r
279 // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP.\r
280 //\r
281 gBS->SignalEvent (RxData->RecycleSignal);\r
282 goto ON_EXIT;\r
283 }\r
284\r
285 Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);\r
286\r
287 if (Type != ICMP_DEST_UNREACHABLE &&\r
288 Type != ICMP_SOURCE_QUENCH &&\r
289 Type != ICMP_REDIRECT &&\r
290 Type != ICMP_TIME_EXCEEDED &&\r
291 Type != ICMP_PARAMETER_PROBLEM) {\r
292 //\r
293 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.\r
294 //\r
295 gBS->SignalEvent (RxData->RecycleSignal);\r
296 goto ON_EXIT;\r
297 }\r
298\r
299 //\r
300 // Copy the right ICMP error message into mode data.\r
301 //\r
302 CopiedLen = 0;\r
303 IcmpError = (UINT8 *) &Mode->IcmpError;\r
304\r
305 for (Index = 0; Index < RxData->FragmentCount; Index++) {\r
306 CopiedLen += RxData->FragmentTable[Index].FragmentLength;\r
307 if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {\r
308 CopyMem (\r
309 IcmpError,\r
310 RxData->FragmentTable[Index].FragmentBuffer,\r
311 RxData->FragmentTable[Index].FragmentLength\r
312 );\r
313 } else {\r
314 CopyMem (\r
315 IcmpError,\r
316 RxData->FragmentTable[Index].FragmentBuffer,\r
317 CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)\r
318 );\r
319 }\r
320 IcmpError += CopiedLen;\r
321 }\r
322\r
323ON_EXIT:\r
324 Private->IcmpToken.Status = EFI_NOT_READY;\r
325 Ip4->Receive (Ip4, &Private->IcmpToken);\r
326}\r
327\r
328\r
329/**\r
330 Callback function to update the latest ICMP6 error message.\r
331\r
332 @param Event The event signalled.\r
333 @param Context The context passed in using the event notifier.\r
334\r
335**/\r
336VOID\r
337EFIAPI\r
338PxeBcIcmpErrorUpdate (\r
339 IN EFI_EVENT Event,\r
340 IN VOID *Context\r
341 )\r
342{\r
343 QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context);\r
344}\r
345\r
346\r
347/**\r
348 Notify function to handle the received ICMP6 message in DPC.\r
349\r
350 @param Context The PXEBC private data.\r
351\r
352**/\r
353VOID\r
354EFIAPI\r
355PxeBcIcmp6ErrorDpcHandle (\r
356 IN VOID *Context\r
357 )\r
358{\r
359 PXEBC_PRIVATE_DATA *Private;\r
360 EFI_IP6_RECEIVE_DATA *RxData;\r
361 EFI_IP6_PROTOCOL *Ip6;\r
362 EFI_PXE_BASE_CODE_MODE *Mode;\r
363 EFI_STATUS Status;\r
364 UINTN Index;\r
365 UINT8 Type;\r
366 UINT32 CopiedLen;\r
367 UINT8 *Icmp6Error;\r
368\r
369 Private = (PXEBC_PRIVATE_DATA *) Context;\r
370 Mode = &Private->Mode;\r
371 Status = Private->Icmp6Token.Status;\r
372 RxData = Private->Icmp6Token.Packet.RxData;\r
373 Ip6 = Private->Ip6;\r
374\r
375 ASSERT (Mode->UsingIpv6);\r
376\r
377 if (Status == EFI_ABORTED) {\r
378 //\r
379 // It's triggered by user cancellation.\r
380 //\r
381 return;\r
382 }\r
383\r
384 if (RxData == NULL) {\r
385 goto ON_EXIT;\r
386 }\r
387\r
388 if (Status != EFI_ICMP_ERROR) {\r
389 //\r
390 // The return status should be recognized as EFI_ICMP_ERROR.\r
391 //\r
392 gBS->SignalEvent (RxData->RecycleSignal);\r
393 goto ON_EXIT;\r
394 }\r
395\r
396 if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) {\r
397 //\r
398 // The source address of the received packet should be a valid unicast address.\r
399 //\r
400 gBS->SignalEvent (RxData->RecycleSignal);\r
401 goto ON_EXIT;\r
402 }\r
403\r
404 if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) &&\r
405 !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v6)) {\r
406 //\r
407 // The destination address of the received packet should be equal to the host address.\r
408 //\r
409 gBS->SignalEvent (RxData->RecycleSignal);\r
410 goto ON_EXIT;\r
411 }\r
412\r
413 if (RxData->Header->NextHeader != IP6_ICMP) {\r
414 //\r
415 // The nextheader in the header of the receveid packet should be IP6_ICMP.\r
416 //\r
417 gBS->SignalEvent (RxData->RecycleSignal);\r
418 goto ON_EXIT;\r
419 }\r
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
425 Type != ICMP_V6_PACKET_TOO_BIG &&\r
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
6f2f4116
FS
492 @param[in] TTL The time to live field of the IP header. \r
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
FS
506 IN BOOLEAN DoNotFragment,\r
507 IN UINT8 TTL,\r
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
FS
518 Udp4CfgData.TypeOfService = ToS;\r
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
1384 while (Length > 0) {\r
1385 Length--;\r
1386 Remainder = Number % 10;\r
1387 Number /= 10;\r
1388 Buffer[Length] = (UINT8) ('0' + Remainder);\r
1389 }\r
1390}\r
1391\r
1392\r
1393/**\r
1394 This function is to convert a UINTN to a ASCII string, and return the\r
1395 actual length of the buffer.\r
1396\r
1397 @param[in] Number Numeric value to be converted.\r
1398 @param[in] Buffer The pointer to the buffer for ASCII string.\r
c960bdc2 1399 @param[in] BufferSize The maxsize of the buffer.\r
a3bcde70
HT
1400\r
1401 @return Length The actual length of the ASCII string.\r
1402\r
1403**/\r
1404UINTN\r
1405PxeBcUintnToAscDec (\r
1406 IN UINTN Number,\r
c960bdc2
ZL
1407 IN UINT8 *Buffer,\r
1408 IN UINTN BufferSize\r
a3bcde70
HT
1409 )\r
1410{\r
1411 UINTN Index;\r
1412 UINTN Length;\r
1413 CHAR8 TempStr[64];\r
1414\r
1415 Index = 63;\r
1416 TempStr[Index] = 0;\r
1417\r
1418 do {\r
1419 Index--;\r
1420 TempStr[Index] = (CHAR8) ('0' + (Number % 10));\r
1421 Number = (UINTN) (Number / 10);\r
1422 } while (Number != 0);\r
1423\r
c960bdc2 1424 AsciiStrCpyS ((CHAR8 *) Buffer, BufferSize, &TempStr[Index]);\r
a3bcde70
HT
1425\r
1426 Length = AsciiStrLen ((CHAR8 *) Buffer);\r
1427\r
1428 return Length;\r
1429}\r
1430\r
1431\r
1432/**\r
1433 This function is to convert unicode hex number to a UINT8.\r
1434\r
1435 @param[out] Digit The converted UINT8 for output.\r
1436 @param[in] Char The unicode hex number to be converted.\r
1437\r
1438 @retval EFI_SUCCESS Successfully converted the unicode hex.\r
1439 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.\r
1440\r
1441**/\r
1442EFI_STATUS\r
1443PxeBcUniHexToUint8 (\r
1444 OUT UINT8 *Digit,\r
1445 IN CHAR16 Char\r
1446 )\r
1447{\r
1448 if ((Char >= L'0') && (Char <= L'9')) {\r
1449 *Digit = (UINT8) (Char - L'0');\r
1450 return EFI_SUCCESS;\r
1451 }\r
1452\r
1453 if ((Char >= L'A') && (Char <= L'F')) {\r
1454 *Digit = (UINT8) (Char - L'A' + 0x0A);\r
1455 return EFI_SUCCESS;\r
1456 }\r
1457\r
1458 if ((Char >= L'a') && (Char <= L'f')) {\r
1459 *Digit = (UINT8) (Char - L'a' + 0x0A);\r
1460 return EFI_SUCCESS;\r
1461 }\r
1462\r
1463 return EFI_INVALID_PARAMETER;\r
1464}\r
129b8b09 1465\r
1466/**\r
f43b7a54 1467 Calculate the elapsed time.\r
129b8b09 1468\r
1469 @param[in] Private The pointer to PXE private data\r
1470\r
1471**/\r
1472VOID\r
1473CalcElapsedTime (\r
1474 IN PXEBC_PRIVATE_DATA *Private\r
1475 )\r
1476{\r
1477 EFI_TIME Time;\r
1478 UINT64 CurrentStamp;\r
1479 UINT64 ElapsedTimeValue;\r
1480\r
1481 //\r
1482 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.\r
1483 //\r
1484 ZeroMem (&Time, sizeof (EFI_TIME));\r
1485 gRT->GetTime (&Time, NULL);\r
1486 CurrentStamp = (UINT64)\r
1487 (\r
1488 ((((((Time.Year - 1900) * 360 +\r
1489 (Time.Month - 1)) * 30 +\r
1490 (Time.Day - 1)) * 24 + Time.Hour) * 60 +\r
1491 Time.Minute) * 60 + Time.Second) * 100\r
1492 + DivU64x32(Time.Nanosecond, 10000000)\r
1493 );\r
1494\r
1495 //\r
1496 // Sentinel value of 0 means that this is the first DHCP packet that we are\r
1497 // sending and that we need to initialize the value. First DHCP Solicit\r
1498 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.\r
1499 //\r
1500 if (Private->ElapsedTime == 0) {\r
1501 Private->ElapsedTime = CurrentStamp;\r
1502 } else {\r
1503 ElapsedTimeValue = CurrentStamp - Private->ElapsedTime;\r
1504\r
1505 //\r
1506 // If elapsed time cannot fit in two bytes, set it to 0xffff.\r
1507 //\r
1508 if (ElapsedTimeValue > 0xffff) {\r
1509 ElapsedTimeValue = 0xffff;\r
1510 }\r
1511 //\r
1512 // Save the elapsed time\r
1513 //\r
1514 Private->ElapsedTime = ElapsedTimeValue;\r
1515 }\r
1516}\r
1517\r