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