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