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