]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c
NetworkPkg:Replace unsafe string functions.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcSupport.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Support functions implementation for UefiPxeBc Driver.\r
3\r
c960bdc2 4 Copyright (c) 2007 - 2015, 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
492\r
493 @retval EFI_SUCCESS Successfully configured this instance.\r
494 @retval Others Failed to configure this instance.\r
495\r
496**/\r
497EFI_STATUS\r
498PxeBcConfigUdp4Write (\r
499 IN EFI_UDP4_PROTOCOL *Udp4,\r
500 IN EFI_IPv4_ADDRESS *StationIp,\r
501 IN EFI_IPv4_ADDRESS *SubnetMask,\r
502 IN EFI_IPv4_ADDRESS *Gateway,\r
503 IN OUT UINT16 *SrcPort,\r
504 IN BOOLEAN DoNotFragment\r
505 )\r
506{\r
507 EFI_UDP4_CONFIG_DATA Udp4CfgData;\r
508 EFI_STATUS Status;\r
509\r
510 ZeroMem (&Udp4CfgData, sizeof (Udp4CfgData));\r
511\r
512 Udp4CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;\r
513 Udp4CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;\r
514 Udp4CfgData.TypeOfService = DEFAULT_ToS;\r
515 Udp4CfgData.TimeToLive = DEFAULT_TTL;\r
516 Udp4CfgData.AllowDuplicatePort = TRUE;\r
517 Udp4CfgData.DoNotFragment = DoNotFragment;\r
518\r
519 CopyMem (&Udp4CfgData.StationAddress, StationIp, sizeof (*StationIp));\r
520 CopyMem (&Udp4CfgData.SubnetMask, SubnetMask, sizeof (*SubnetMask));\r
521\r
522 Udp4CfgData.StationPort = *SrcPort;\r
523\r
524 //\r
525 // Reset the UDPv4 instance.\r
526 //\r
527 Udp4->Configure (Udp4, NULL);\r
528\r
529 Status = Udp4->Configure (Udp4, &Udp4CfgData);\r
530 if (!EFI_ERROR (Status) && !EFI_IP4_EQUAL (Gateway, &mZeroIp4Addr)) {\r
531 //\r
532 // The basic configuration is OK, need to add the default route entry\r
533 //\r
534 Status = Udp4->Routes (Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, Gateway);\r
535 if (EFI_ERROR (Status)) {\r
536 Udp4->Configure (Udp4, NULL);\r
537 }\r
538 }\r
539\r
540 if (!EFI_ERROR (Status) && *SrcPort == 0) {\r
541 Udp4->GetModeData (Udp4, &Udp4CfgData, NULL, NULL, NULL);\r
542 *SrcPort = Udp4CfgData.StationPort;\r
543 }\r
544\r
545 return Status;\r
546}\r
547\r
548\r
549/**\r
550 This function is to configure a UDPv6 instance for UdpWrite.\r
551\r
552 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.\r
553 @param[in] StationIp The pointer to the station address.\r
554 @param[in, out] SrcPort The pointer to the source port.\r
555\r
556 @retval EFI_SUCCESS Successfully configured this instance.\r
557 @retval Others Failed to configure this instance.\r
558\r
559**/\r
560EFI_STATUS\r
561PxeBcConfigUdp6Write (\r
562 IN EFI_UDP6_PROTOCOL *Udp6,\r
563 IN EFI_IPv6_ADDRESS *StationIp,\r
564 IN OUT UINT16 *SrcPort\r
565 )\r
566{\r
567 EFI_UDP6_CONFIG_DATA CfgData;\r
568 EFI_STATUS Status;\r
569\r
570 ZeroMem (&CfgData, sizeof (EFI_UDP6_CONFIG_DATA));\r
571\r
572 CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;\r
573 CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;\r
574 CfgData.HopLimit = PXEBC_DEFAULT_HOPLIMIT;\r
575 CfgData.AllowDuplicatePort = TRUE;\r
576 CfgData.StationPort = *SrcPort;\r
577\r
578 CopyMem (&CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));\r
579\r
580 //\r
581 // Reset the UDPv6 instance.\r
582 //\r
583 Udp6->Configure (Udp6, NULL);\r
584\r
585 Status = Udp6->Configure (Udp6, &CfgData);\r
586 if (EFI_ERROR (Status)) {\r
587 return Status;\r
588 }\r
589\r
590 if (!EFI_ERROR (Status) && *SrcPort == 0) {\r
591 Udp6->GetModeData (Udp6, &CfgData, NULL, NULL, NULL);\r
592 *SrcPort = CfgData.StationPort;\r
593 }\r
594\r
595 return Status;\r
596}\r
597\r
598\r
599/**\r
600 This function is to configure a UDPv4 instance for UdpWrite.\r
601\r
602 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.\r
603 @param[in] Session The pointer to the UDP4 session data.\r
604 @param[in] TimeoutEvent The event for timeout.\r
605 @param[in] Gateway The pointer to the gateway address.\r
606 @param[in] HeaderSize An optional field which may be set to the length of a header\r
607 at HeaderPtr to be prefixed to the data at BufferPtr.\r
608 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be\r
609 prefixed to the data at BufferPtr.\r
610 @param[in] BufferSize A pointer to the size of the data at BufferPtr.\r
611 @param[in] BufferPtr A pointer to the data to be written.\r
612\r
613 @retval EFI_SUCCESS Successfully send out data using Udp4Write.\r
614 @retval Others Failed to send out data.\r
615\r
616**/\r
617EFI_STATUS\r
618PxeBcUdp4Write (\r
619 IN EFI_UDP4_PROTOCOL *Udp4,\r
620 IN EFI_UDP4_SESSION_DATA *Session,\r
621 IN EFI_EVENT TimeoutEvent,\r
622 IN EFI_IPv4_ADDRESS *Gateway OPTIONAL,\r
623 IN UINTN *HeaderSize OPTIONAL,\r
624 IN VOID *HeaderPtr OPTIONAL,\r
625 IN UINTN *BufferSize,\r
626 IN VOID *BufferPtr\r
627 )\r
628{\r
629 EFI_UDP4_COMPLETION_TOKEN Token;\r
630 EFI_UDP4_TRANSMIT_DATA *TxData;\r
631 UINT32 TxLength;\r
632 UINT32 FragCount;\r
633 UINT32 DataLength;\r
634 BOOLEAN IsDone;\r
635 EFI_STATUS Status;\r
636\r
637 //\r
638 // Arrange one fragment buffer for data, and another fragment buffer for header if has.\r
639 //\r
640 FragCount = (HeaderSize != NULL) ? 2 : 1;\r
641 TxLength = sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA);\r
642 TxData = (EFI_UDP4_TRANSMIT_DATA *) AllocateZeroPool (TxLength);\r
643 if (TxData == NULL) {\r
644 return EFI_OUT_OF_RESOURCES;\r
645 }\r
646\r
647 TxData->FragmentCount = FragCount;\r
648 TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;\r
649 TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;\r
650 DataLength = (UINT32) *BufferSize;\r
651\r
652 if (HeaderSize != NULL) {\r
653 TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;\r
654 TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;\r
655 DataLength += (UINT32) *HeaderSize;\r
656 }\r
657\r
658 if (Gateway != NULL) {\r
659 TxData->GatewayAddress = Gateway;\r
660 }\r
661\r
662 TxData->UdpSessionData = Session;\r
663 TxData->DataLength = DataLength;\r
664 Token.Packet.TxData = TxData;\r
665 Token.Status = EFI_NOT_READY;\r
666 IsDone = FALSE;\r
667\r
668 Status = gBS->CreateEvent (\r
669 EVT_NOTIFY_SIGNAL,\r
670 TPL_NOTIFY,\r
671 PxeBcCommonNotify,\r
672 &IsDone,\r
673 &Token.Event\r
674 );\r
675 if (EFI_ERROR (Status)) {\r
676 goto ON_EXIT;\r
677 }\r
678\r
679 Status = Udp4->Transmit (Udp4, &Token);\r
680 if (EFI_ERROR (Status)) {\r
681 goto ON_EXIT;\r
682 }\r
683\r
684 //\r
685 // Poll the UDPv6 read instance if no packet received and no timeout triggered.\r
686 //\r
687 while (!IsDone &&\r
688 Token.Status == EFI_NOT_READY &&\r
689 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
690 Udp4->Poll (Udp4);\r
691 }\r
692\r
693 Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;\r
694\r
695ON_EXIT:\r
696 if (Token.Event != NULL) {\r
697 gBS->CloseEvent (Token.Event);\r
698 }\r
699 FreePool (TxData);\r
700\r
701 return Status;\r
702}\r
703\r
704\r
705/**\r
706 This function is to configure a UDPv4 instance for UdpWrite.\r
707\r
708 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.\r
709 @param[in] Session The pointer to the UDP6 session data.\r
710 @param[in] TimeoutEvent The event for timeout.\r
711 @param[in] HeaderSize An optional field which may be set to the length of a header\r
712 at HeaderPtr to be prefixed to the data at BufferPtr.\r
713 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be\r
714 prefixed to the data at BufferPtr.\r
715 @param[in] BufferSize A pointer to the size of the data at BufferPtr.\r
716 @param[in] BufferPtr A pointer to the data to be written.\r
717\r
718 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.\r
719 @retval Others Failed to send out data.\r
720\r
721**/\r
722EFI_STATUS\r
723PxeBcUdp6Write (\r
724 IN EFI_UDP6_PROTOCOL *Udp6,\r
725 IN EFI_UDP6_SESSION_DATA *Session,\r
726 IN EFI_EVENT TimeoutEvent,\r
727 IN UINTN *HeaderSize OPTIONAL,\r
728 IN VOID *HeaderPtr OPTIONAL,\r
729 IN UINTN *BufferSize,\r
730 IN VOID *BufferPtr\r
731 )\r
732{\r
733 EFI_UDP6_COMPLETION_TOKEN Token;\r
734 EFI_UDP6_TRANSMIT_DATA *TxData;\r
735 UINT32 TxLength;\r
736 UINT32 FragCount;\r
737 UINT32 DataLength;\r
738 BOOLEAN IsDone;\r
739 EFI_STATUS Status;\r
740\r
741 //\r
742 // Arrange one fragment buffer for data, and another fragment buffer for header if has.\r
743 //\r
744 FragCount = (HeaderSize != NULL) ? 2 : 1;\r
745 TxLength = sizeof (EFI_UDP6_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA);\r
746 TxData = (EFI_UDP6_TRANSMIT_DATA *) AllocateZeroPool (TxLength);\r
747 if (TxData == NULL) {\r
748 return EFI_OUT_OF_RESOURCES;\r
749 }\r
750\r
751 TxData->FragmentCount = FragCount;\r
752 TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;\r
753 TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;\r
754 DataLength = (UINT32) *BufferSize;\r
755\r
756 if (HeaderSize != NULL) {\r
757 TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;\r
758 TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;\r
759 DataLength += (UINT32) *HeaderSize;\r
760 }\r
761\r
762 TxData->UdpSessionData = Session;\r
763 TxData->DataLength = DataLength;\r
764 Token.Packet.TxData = TxData;\r
765 Token.Status = EFI_NOT_READY;\r
766 IsDone = FALSE;\r
767\r
768 Status = gBS->CreateEvent (\r
769 EVT_NOTIFY_SIGNAL,\r
770 TPL_NOTIFY,\r
771 PxeBcCommonNotify,\r
772 &IsDone,\r
773 &Token.Event\r
774 );\r
775 if (EFI_ERROR (Status)) {\r
776 goto ON_EXIT;\r
777 }\r
778\r
779 Status = Udp6->Transmit (Udp6, &Token);\r
780 if (EFI_ERROR (Status)) {\r
781 goto ON_EXIT;\r
782 }\r
783\r
784 //\r
785 // Poll the UDPv6 read instance if no packet received and no timeout triggered.\r
786 //\r
787 while (!IsDone &&\r
788 Token.Status == EFI_NOT_READY &&\r
789 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
790 Udp6->Poll (Udp6);\r
791 }\r
792\r
793 Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;\r
794\r
795ON_EXIT:\r
796 if (Token.Event != NULL) {\r
797 gBS->CloseEvent (Token.Event);\r
798 }\r
799 FreePool (TxData);\r
800\r
801 return Status;\r
802}\r
803\r
804\r
805/**\r
806 Check the received packet using the Ip filter.\r
807\r
808 @param[in] Mode The pointer to the mode data of PxeBc.\r
809 @param[in] Session The pointer to the current UDPv4 session.\r
810 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.\r
811\r
812 @retval TRUE Passed the Ip filter successfully.\r
813 @retval FALSE Failed to pass the Ip filter.\r
814\r
815**/\r
816BOOLEAN\r
817PxeBcCheckByIpFilter (\r
818 IN EFI_PXE_BASE_CODE_MODE *Mode,\r
819 IN VOID *Session,\r
820 IN UINT16 OpFlags\r
821 )\r
822{\r
823 EFI_IP_ADDRESS DestinationIp;\r
824 UINTN Index;\r
825\r
826 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) == 0) {\r
827 return TRUE;\r
828 }\r
829\r
830 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) {\r
831 return TRUE;\r
832 }\r
833\r
834 //\r
835 // Convert the destination address in session data to host order.\r
836 //\r
837 if (Mode->UsingIpv6) {\r
838 CopyMem (\r
839 &DestinationIp,\r
840 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,\r
841 sizeof (EFI_IPv6_ADDRESS)\r
842 );\r
843 NTOHLLL (&DestinationIp.v6);\r
844 } else {\r
845 ZeroMem (&DestinationIp, sizeof (EFI_IP_ADDRESS));\r
846 CopyMem (\r
847 &DestinationIp,\r
848 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,\r
849 sizeof (EFI_IPv4_ADDRESS)\r
850 );\r
851 EFI_NTOHL (DestinationIp);\r
852 }\r
853\r
854 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0 &&\r
855 (IP4_IS_MULTICAST (DestinationIp.Addr[0]) ||\r
856 IP6_IS_MULTICAST (&DestinationIp))) {\r
857 return TRUE;\r
858 }\r
859\r
860 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0 &&\r
861 IP4_IS_LOCAL_BROADCAST (DestinationIp.Addr[0])) {\r
862 ASSERT (!Mode->UsingIpv6);\r
863 return TRUE;\r
864 }\r
865\r
866 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 &&\r
867 (EFI_IP4_EQUAL (&Mode->StationIp.v4, &DestinationIp) ||\r
868 EFI_IP6_EQUAL (&Mode->StationIp.v6, &DestinationIp))) {\r
869 //\r
870 // Matched if the dest address is equal to the station address.\r
871 //\r
872 return TRUE;\r
873 }\r
874\r
875 for (Index = 0; Index < Mode->IpFilter.IpCnt; Index++) {\r
876 ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT);\r
877 if (EFI_IP4_EQUAL (&Mode->IpFilter.IpList[Index].v4, &DestinationIp) ||\r
878 EFI_IP6_EQUAL (&Mode->IpFilter.IpList[Index].v6, &DestinationIp)) {\r
879 //\r
880 // Matched if the dest address is equal to any of address in the filter list.\r
881 //\r
882 return TRUE;\r
883 }\r
884 }\r
885\r
886 return FALSE;\r
887}\r
888\r
889\r
890/**\r
891 Filter the received packet using the destination Ip.\r
892\r
893 @param[in] Mode The pointer to the mode data of PxeBc.\r
894 @param[in] Session The pointer to the current UDPv4 session.\r
895 @param[in, out] DestIp The pointer to the destination Ip address.\r
896 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.\r
897\r
898 @retval TRUE Passed the IPv4 filter successfully.\r
899 @retval FALSE Failed to pass the IPv4 filter.\r
900\r
901**/\r
902BOOLEAN\r
903PxeBcCheckByDestIp (\r
904 IN EFI_PXE_BASE_CODE_MODE *Mode,\r
905 IN VOID *Session,\r
906 IN OUT EFI_IP_ADDRESS *DestIp,\r
907 IN UINT16 OpFlags\r
908 )\r
909{\r
910 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) {\r
911 //\r
912 // Copy the destination address from the received packet if accept any.\r
913 //\r
914 if (DestIp != NULL) {\r
915 if (Mode->UsingIpv6) {\r
916 CopyMem (\r
917 DestIp,\r
918 &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress,\r
919 sizeof (EFI_IPv6_ADDRESS)\r
920 );\r
921 } else {\r
922 ZeroMem (DestIp, sizeof (EFI_IP_ADDRESS));\r
923 CopyMem (\r
924 DestIp,\r
925 &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress,\r
926 sizeof (EFI_IPv4_ADDRESS)\r
927 );\r
928 }\r
929\r
930 }\r
931 return TRUE;\r
932 } else if (DestIp != NULL &&\r
933 (EFI_IP4_EQUAL (DestIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||\r
934 EFI_IP6_EQUAL (DestIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress))) {\r
935 //\r
936 // The destination address in the received packet is matched if present.\r
937 //\r
938 return TRUE;\r
939 } else if (EFI_IP4_EQUAL (&Mode->StationIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||\r
940 EFI_IP6_EQUAL (&Mode->StationIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress)) {\r
941 //\r
942 // The destination address in the received packet is equal to the host address.\r
943 //\r
944 return TRUE;\r
945 }\r
946\r
947 return FALSE;\r
948}\r
949\r
950\r
951/**\r
952 Check the received packet using the destination port.\r
953\r
76389e18 954 @param[in] Mode The pointer to the mode data of PxeBc.\r
a3bcde70
HT
955 @param[in] Session The pointer to the current UDPv4 session.\r
956 @param[in, out] DestPort The pointer to the destination port.\r
957 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.\r
958\r
959 @retval TRUE Passed the IPv4 filter successfully.\r
960 @retval FALSE Failed to pass the IPv4 filter.\r
961\r
962**/\r
963BOOLEAN\r
964PxeBcCheckByDestPort (\r
965 IN EFI_PXE_BASE_CODE_MODE *Mode,\r
966 IN VOID *Session,\r
967 IN OUT UINT16 *DestPort,\r
968 IN UINT16 OpFlags\r
969 )\r
970{\r
971 UINT16 Port;\r
972\r
973 if (Mode->UsingIpv6) {\r
974 Port = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;\r
975 } else {\r
976 Port = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;\r
977 }\r
978\r
979 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) {\r
980 //\r
981 // Return the destination port in the received packet if accept any.\r
982 //\r
983 if (DestPort != NULL) {\r
984 *DestPort = Port;\r
985 }\r
986 return TRUE;\r
987 } else if (DestPort != NULL && *DestPort == Port) {\r
988 //\r
989 // The destination port in the received packet is matched if present.\r
990 //\r
991 return TRUE;\r
992 }\r
993\r
994 return FALSE;\r
995}\r
996\r
997\r
998/**\r
999 Filter the received packet using the source Ip.\r
1000\r
1001 @param[in] Mode The pointer to the mode data of PxeBc.\r
1002 @param[in] Session The pointer to the current UDPv4 session.\r
1003 @param[in, out] SrcIp The pointer to the source Ip address.\r
1004 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.\r
1005\r
1006 @retval TRUE Passed the IPv4 filter successfully.\r
1007 @retval FALSE Failed to pass the IPv4 filter.\r
1008\r
1009**/\r
1010BOOLEAN\r
1011PxeBcFilterBySrcIp (\r
1012 IN EFI_PXE_BASE_CODE_MODE *Mode,\r
1013 IN VOID *Session,\r
1014 IN OUT EFI_IP_ADDRESS *SrcIp,\r
1015 IN UINT16 OpFlags\r
1016 )\r
1017{\r
1018 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) {\r
1019 //\r
1020 // Copy the source address from the received packet if accept any.\r
1021 //\r
1022 if (SrcIp != NULL) {\r
1023 if (Mode->UsingIpv6) {\r
1024 CopyMem (\r
1025 SrcIp,\r
1026 &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress,\r
1027 sizeof (EFI_IPv6_ADDRESS)\r
1028 );\r
1029 } else {\r
1030 ZeroMem (SrcIp, sizeof (EFI_IP_ADDRESS));\r
1031 CopyMem (\r
1032 SrcIp,\r
1033 &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress,\r
1034 sizeof (EFI_IPv4_ADDRESS)\r
1035 );\r
1036 }\r
1037\r
1038 }\r
1039 return TRUE;\r
1040 } else if (SrcIp != NULL &&\r
1041 (EFI_IP4_EQUAL (SrcIp, &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress) ||\r
1042 EFI_IP6_EQUAL (SrcIp, &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress))) {\r
1043 //\r
1044 // The source address in the received packet is matched if present.\r
1045 //\r
1046 return TRUE;\r
1047 }\r
1048\r
1049 return FALSE;\r
1050}\r
1051\r
1052\r
1053/**\r
1054 Filter the received packet using the source port.\r
1055\r
1056 @param[in] Mode The pointer to the mode data of PxeBc.\r
1057 @param[in] Session The pointer to the current UDPv4 session.\r
1058 @param[in, out] SrcPort The pointer to the source port.\r
1059 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.\r
1060\r
1061 @retval TRUE Passed the IPv4 filter successfully.\r
1062 @retval FALSE Failed to pass the IPv4 filter.\r
1063\r
1064**/\r
1065BOOLEAN\r
1066PxeBcFilterBySrcPort (\r
1067 IN EFI_PXE_BASE_CODE_MODE *Mode,\r
1068 IN VOID *Session,\r
1069 IN OUT UINT16 *SrcPort,\r
1070 IN UINT16 OpFlags\r
1071 )\r
1072{\r
1073 UINT16 Port;\r
1074\r
1075 if (Mode->UsingIpv6) {\r
1076 Port = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;\r
1077 } else {\r
1078 Port = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;\r
1079 }\r
1080\r
1081 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) {\r
1082 //\r
1083 // Return the source port in the received packet if accept any.\r
1084 //\r
1085 if (SrcPort != NULL) {\r
1086 *SrcPort = Port;\r
1087 }\r
1088 return TRUE;\r
1089 } else if (SrcPort != NULL && *SrcPort == Port) {\r
1090 //\r
1091 // The source port in the received packet is matched if present.\r
1092 //\r
1093 return TRUE;\r
1094 }\r
1095\r
1096 return FALSE;\r
1097}\r
1098\r
1099\r
1100/**\r
1101 This function is to receive packet using Udp4Read.\r
1102\r
1103 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.\r
1104 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.\r
1105 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.\r
1106 @param[in] TimeoutEvent The event for timeout.\r
1107 @param[in] OpFlags The UDP operation flags.\r
1108 @param[in] IsDone The pointer to the IsDone flag.\r
1109 @param[out] IsMatched The pointer to the IsMatched flag.\r
1110 @param[in, out] DestIp The pointer to the destination address.\r
1111 @param[in, out] DestPort The pointer to the destination port.\r
1112 @param[in, out] SrcIp The pointer to the source address.\r
1113 @param[in, out] SrcPort The pointer to the source port.\r
1114\r
1115 @retval EFI_SUCCESS Successfully read the data using Udp4.\r
1116 @retval Others Failed to send out data.\r
1117\r
1118**/\r
1119EFI_STATUS\r
1120PxeBcUdp4Read (\r
1121 IN EFI_UDP4_PROTOCOL *Udp4,\r
1122 IN EFI_UDP4_COMPLETION_TOKEN *Token,\r
1123 IN EFI_PXE_BASE_CODE_MODE *Mode,\r
1124 IN EFI_EVENT TimeoutEvent,\r
1125 IN UINT16 OpFlags,\r
1126 IN BOOLEAN *IsDone,\r
1127 OUT BOOLEAN *IsMatched,\r
1128 IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,\r
1129 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,\r
1130 IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,\r
1131 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL\r
1132 )\r
1133{\r
1134 EFI_UDP4_RECEIVE_DATA *RxData;\r
1135 EFI_UDP4_SESSION_DATA *Session;\r
1136 EFI_STATUS Status;\r
1137\r
1138 Token->Status = EFI_NOT_READY;\r
1139 *IsDone = FALSE;\r
1140\r
1141 Status = Udp4->Receive (Udp4, Token);\r
1142 if (EFI_ERROR (Status)) {\r
1143 return Status;\r
1144 }\r
1145\r
1146 //\r
1147 // Poll the UDPv6 read instance if no packet received and no timeout triggered.\r
1148 //\r
1149 while (!(*IsDone) &&\r
1150 Token->Status == EFI_NOT_READY &&\r
1151 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
1152 //\r
1153 // Poll the token utill reply/ICMPv6 error message received or timeout.\r
1154 //\r
1155 Udp4->Poll (Udp4);\r
1156 if (Token->Status == EFI_ICMP_ERROR ||\r
1157 Token->Status == EFI_NETWORK_UNREACHABLE ||\r
1158 Token->Status == EFI_HOST_UNREACHABLE ||\r
1159 Token->Status == EFI_PROTOCOL_UNREACHABLE ||\r
1160 Token->Status == EFI_PORT_UNREACHABLE) {\r
1161 break;\r
1162 }\r
1163 }\r
1164\r
1165 Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;\r
1166\r
1167 if (!EFI_ERROR (Status)) {\r
1168 //\r
1169 // check whether this packet matches the filters\r
1170 //\r
1171 RxData = Token->Packet.RxData;\r
1172 Session = &RxData->UdpSession;\r
1173\r
1174 *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);\r
1175\r
1176 if (*IsMatched) {\r
1177 *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);\r
1178 }\r
1179\r
1180 if (*IsMatched) {\r
1181 *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);\r
1182 }\r
1183\r
1184 if (*IsMatched) {\r
1185 *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);\r
1186 }\r
1187\r
1188 if (*IsMatched) {\r
1189 *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);\r
1190 }\r
1191\r
1192 if (!(*IsMatched)) {\r
1193 //\r
1194 // Recycle the receiving buffer if not matched.\r
1195 //\r
1196 gBS->SignalEvent (RxData->RecycleSignal);\r
1197 }\r
1198 }\r
1199\r
1200 return Status;\r
1201}\r
1202\r
1203\r
1204/**\r
1205 This function is to receive packets using Udp6Read.\r
1206\r
1207 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.\r
1208 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.\r
1209 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.\r
1210 @param[in] TimeoutEvent The event for timeout.\r
1211 @param[in] OpFlags The UDP operation flags.\r
1212 @param[in] IsDone The pointer to the IsDone flag.\r
1213 @param[out] IsMatched The pointer to the IsMatched flag.\r
1214 @param[in, out] DestIp The pointer to the destination address.\r
1215 @param[in, out] DestPort The pointer to the destination port.\r
1216 @param[in, out] SrcIp The pointer to the source address.\r
1217 @param[in, out] SrcPort The pointer to the source port.\r
1218\r
1219 @retval EFI_SUCCESS Successfully read data using Udp6.\r
1220 @retval Others Failed to send out data.\r
1221\r
1222**/\r
1223EFI_STATUS\r
1224PxeBcUdp6Read (\r
1225 IN EFI_UDP6_PROTOCOL *Udp6,\r
1226 IN EFI_UDP6_COMPLETION_TOKEN *Token,\r
1227 IN EFI_PXE_BASE_CODE_MODE *Mode,\r
1228 IN EFI_EVENT TimeoutEvent,\r
1229 IN UINT16 OpFlags,\r
1230 IN BOOLEAN *IsDone,\r
1231 OUT BOOLEAN *IsMatched,\r
1232 IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,\r
1233 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,\r
1234 IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,\r
1235 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL\r
1236 )\r
1237{\r
1238 EFI_UDP6_RECEIVE_DATA *RxData;\r
1239 EFI_UDP6_SESSION_DATA *Session;\r
1240 EFI_STATUS Status;\r
1241\r
1242 Token->Status = EFI_NOT_READY;\r
1243 *IsDone = FALSE;\r
1244\r
1245 Status = Udp6->Receive (Udp6, Token);\r
1246 if (EFI_ERROR (Status)) {\r
1247 return Status;\r
1248 }\r
1249\r
1250 //\r
1251 // Poll the UDPv6 read instance if no packet received and no timeout triggered.\r
1252 //\r
1253 while (!(*IsDone) &&\r
1254 Token->Status == EFI_NOT_READY &&\r
1255 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
1256 //\r
1257 // Poll the token utill reply/ICMPv6 error message received or timeout.\r
1258 //\r
1259 Udp6->Poll (Udp6);\r
1260 if (Token->Status == EFI_ICMP_ERROR ||\r
1261 Token->Status == EFI_NETWORK_UNREACHABLE ||\r
1262 Token->Status == EFI_HOST_UNREACHABLE ||\r
1263 Token->Status == EFI_PROTOCOL_UNREACHABLE ||\r
1264 Token->Status == EFI_PORT_UNREACHABLE) {\r
1265 break;\r
1266 }\r
1267 }\r
1268\r
1269 Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;\r
1270\r
1271 if (!EFI_ERROR (Status)) {\r
1272 //\r
1273 // check whether this packet matches the filters\r
1274 //\r
1275 RxData = Token->Packet.RxData;\r
1276 Session = &RxData->UdpSession;\r
1277\r
1278 *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);\r
1279\r
1280 if (*IsMatched) {\r
1281 *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);\r
1282 }\r
1283\r
1284 if (*IsMatched) {\r
1285 *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);\r
1286 }\r
1287\r
1288 if (*IsMatched) {\r
1289 *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);\r
1290 }\r
1291\r
1292 if (*IsMatched) {\r
1293 *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);\r
1294 }\r
1295\r
1296 if (!(*IsMatched)) {\r
1297 //\r
1298 // Recycle the receiving buffer if not matched.\r
1299 //\r
1300 gBS->SignalEvent (RxData->RecycleSignal);\r
1301 }\r
1302 }\r
1303\r
1304 return Status;\r
1305}\r
1306\r
1307\r
1308/**\r
1309 This function is to display the IPv4 address.\r
1310\r
1311 @param[in] Ip The pointer to the IPv4 address.\r
1312\r
1313**/\r
1314VOID\r
1315PxeBcShowIp4Addr (\r
1316 IN EFI_IPv4_ADDRESS *Ip\r
1317 )\r
1318{\r
1319 UINTN Index;\r
1320\r
1321 for (Index = 0; Index < 4; Index++) {\r
1322 AsciiPrint ("%d", Ip->Addr[Index]);\r
1323 if (Index < 3) {\r
1324 AsciiPrint (".");\r
1325 }\r
1326 }\r
1327}\r
1328\r
1329\r
1330/**\r
1331 This function is to display the IPv6 address.\r
1332\r
1333 @param[in] Ip The pointer to the IPv6 address.\r
1334\r
1335**/\r
1336VOID\r
1337PxeBcShowIp6Addr (\r
1338 IN EFI_IPv6_ADDRESS *Ip\r
1339 )\r
1340{\r
1341 UINTN Index;\r
1342\r
1343 for (Index = 0; Index < 16; Index++) {\r
1344\r
1345 if (Ip->Addr[Index] != 0) {\r
1346 AsciiPrint ("%x", Ip->Addr[Index]);\r
1347 }\r
1348 Index++;\r
1349 if (Index > 15) {\r
1350 return;\r
1351 }\r
1352 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {\r
1353 AsciiPrint ("0");\r
1354 }\r
1355 AsciiPrint ("%x", Ip->Addr[Index]);\r
1356 if (Index < 15) {\r
1357 AsciiPrint (":");\r
1358 }\r
1359 }\r
1360}\r
1361\r
1362\r
1363/**\r
1364 This function is to convert UINTN to ASCII string with the required formatting.\r
1365\r
1366 @param[in] Number Numeric value to be converted.\r
1367 @param[in] Buffer The pointer to the buffer for ASCII string.\r
1368 @param[in] Length The length of the required format.\r
1369\r
1370**/\r
1371VOID\r
1372PxeBcUintnToAscDecWithFormat (\r
1373 IN UINTN Number,\r
1374 IN UINT8 *Buffer,\r
1375 IN INTN Length\r
1376 )\r
1377{\r
1378 UINTN Remainder;\r
1379\r
1380 while (Length > 0) {\r
1381 Length--;\r
1382 Remainder = Number % 10;\r
1383 Number /= 10;\r
1384 Buffer[Length] = (UINT8) ('0' + Remainder);\r
1385 }\r
1386}\r
1387\r
1388\r
1389/**\r
1390 This function is to convert a UINTN to a ASCII string, and return the\r
1391 actual length of the buffer.\r
1392\r
1393 @param[in] Number Numeric value to be converted.\r
1394 @param[in] Buffer The pointer to the buffer for ASCII string.\r
c960bdc2 1395 @param[in] BufferSize The maxsize of the buffer.\r
a3bcde70
HT
1396\r
1397 @return Length The actual length of the ASCII string.\r
1398\r
1399**/\r
1400UINTN\r
1401PxeBcUintnToAscDec (\r
1402 IN UINTN Number,\r
c960bdc2
ZL
1403 IN UINT8 *Buffer,\r
1404 IN UINTN BufferSize\r
a3bcde70
HT
1405 )\r
1406{\r
1407 UINTN Index;\r
1408 UINTN Length;\r
1409 CHAR8 TempStr[64];\r
1410\r
1411 Index = 63;\r
1412 TempStr[Index] = 0;\r
1413\r
1414 do {\r
1415 Index--;\r
1416 TempStr[Index] = (CHAR8) ('0' + (Number % 10));\r
1417 Number = (UINTN) (Number / 10);\r
1418 } while (Number != 0);\r
1419\r
c960bdc2 1420 AsciiStrCpyS ((CHAR8 *) Buffer, BufferSize, &TempStr[Index]);\r
a3bcde70
HT
1421\r
1422 Length = AsciiStrLen ((CHAR8 *) Buffer);\r
1423\r
1424 return Length;\r
1425}\r
1426\r
1427\r
1428/**\r
1429 This function is to convert unicode hex number to a UINT8.\r
1430\r
1431 @param[out] Digit The converted UINT8 for output.\r
1432 @param[in] Char The unicode hex number to be converted.\r
1433\r
1434 @retval EFI_SUCCESS Successfully converted the unicode hex.\r
1435 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.\r
1436\r
1437**/\r
1438EFI_STATUS\r
1439PxeBcUniHexToUint8 (\r
1440 OUT UINT8 *Digit,\r
1441 IN CHAR16 Char\r
1442 )\r
1443{\r
1444 if ((Char >= L'0') && (Char <= L'9')) {\r
1445 *Digit = (UINT8) (Char - L'0');\r
1446 return EFI_SUCCESS;\r
1447 }\r
1448\r
1449 if ((Char >= L'A') && (Char <= L'F')) {\r
1450 *Digit = (UINT8) (Char - L'A' + 0x0A);\r
1451 return EFI_SUCCESS;\r
1452 }\r
1453\r
1454 if ((Char >= L'a') && (Char <= L'f')) {\r
1455 *Digit = (UINT8) (Char - L'a' + 0x0A);\r
1456 return EFI_SUCCESS;\r
1457 }\r
1458\r
1459 return EFI_INVALID_PARAMETER;\r
1460}\r
129b8b09 1461\r
1462/**\r
f43b7a54 1463 Calculate the elapsed time.\r
129b8b09 1464\r
1465 @param[in] Private The pointer to PXE private data\r
1466\r
1467**/\r
1468VOID\r
1469CalcElapsedTime (\r
1470 IN PXEBC_PRIVATE_DATA *Private\r
1471 )\r
1472{\r
1473 EFI_TIME Time;\r
1474 UINT64 CurrentStamp;\r
1475 UINT64 ElapsedTimeValue;\r
1476\r
1477 //\r
1478 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.\r
1479 //\r
1480 ZeroMem (&Time, sizeof (EFI_TIME));\r
1481 gRT->GetTime (&Time, NULL);\r
1482 CurrentStamp = (UINT64)\r
1483 (\r
1484 ((((((Time.Year - 1900) * 360 +\r
1485 (Time.Month - 1)) * 30 +\r
1486 (Time.Day - 1)) * 24 + Time.Hour) * 60 +\r
1487 Time.Minute) * 60 + Time.Second) * 100\r
1488 + DivU64x32(Time.Nanosecond, 10000000)\r
1489 );\r
1490\r
1491 //\r
1492 // Sentinel value of 0 means that this is the first DHCP packet that we are\r
1493 // sending and that we need to initialize the value. First DHCP Solicit\r
1494 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.\r
1495 //\r
1496 if (Private->ElapsedTime == 0) {\r
1497 Private->ElapsedTime = CurrentStamp;\r
1498 } else {\r
1499 ElapsedTimeValue = CurrentStamp - Private->ElapsedTime;\r
1500\r
1501 //\r
1502 // If elapsed time cannot fit in two bytes, set it to 0xffff.\r
1503 //\r
1504 if (ElapsedTimeValue > 0xffff) {\r
1505 ElapsedTimeValue = 0xffff;\r
1506 }\r
1507 //\r
1508 // Save the elapsed time\r
1509 //\r
1510 Private->ElapsedTime = ElapsedTimeValue;\r
1511 }\r
1512}\r
1513\r