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