]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
MdeModulePkg/DxeNetLib: Add parameter check and ASSERT handling.
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / DxeNetLib.c
1 /** @file
2 Network library.
3
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 **/
14
15 #include <Uefi.h>
16
17 #include <IndustryStandard/SmBios.h>
18
19 #include <Protocol/DriverBinding.h>
20 #include <Protocol/ServiceBinding.h>
21 #include <Protocol/SimpleNetwork.h>
22 #include <Protocol/AdapterInformation.h>
23 #include <Protocol/ManagedNetwork.h>
24 #include <Protocol/Ip4Config2.h>
25 #include <Protocol/ComponentName.h>
26 #include <Protocol/ComponentName2.h>
27
28 #include <Guid/SmBios.h>
29
30 #include <Library/NetLib.h>
31 #include <Library/BaseLib.h>
32 #include <Library/DebugLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/UefiBootServicesTableLib.h>
35 #include <Library/UefiRuntimeServicesTableLib.h>
36 #include <Library/MemoryAllocationLib.h>
37 #include <Library/DevicePathLib.h>
38 #include <Library/PrintLib.h>
39 #include <Library/UefiLib.h>
40
41 #define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE)
42 #define DEFAULT_ZERO_START ((UINTN) ~0)
43
44 //
45 // All the supported IP4 maskes in host byte order.
46 //
47 GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR gIp4AllMasks[IP4_MASK_NUM] = {
48 0x00000000,
49 0x80000000,
50 0xC0000000,
51 0xE0000000,
52 0xF0000000,
53 0xF8000000,
54 0xFC000000,
55 0xFE000000,
56
57 0xFF000000,
58 0xFF800000,
59 0xFFC00000,
60 0xFFE00000,
61 0xFFF00000,
62 0xFFF80000,
63 0xFFFC0000,
64 0xFFFE0000,
65
66 0xFFFF0000,
67 0xFFFF8000,
68 0xFFFFC000,
69 0xFFFFE000,
70 0xFFFFF000,
71 0xFFFFF800,
72 0xFFFFFC00,
73 0xFFFFFE00,
74
75 0xFFFFFF00,
76 0xFFFFFF80,
77 0xFFFFFFC0,
78 0xFFFFFFE0,
79 0xFFFFFFF0,
80 0xFFFFFFF8,
81 0xFFFFFFFC,
82 0xFFFFFFFE,
83 0xFFFFFFFF,
84 };
85
86 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS mZeroIp4Addr = {{0, 0, 0, 0}};
87
88 //
89 // Any error level digitally larger than mNetDebugLevelMax
90 // will be silently discarded.
91 //
92 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;
93 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq = 0xDEADBEEF;
94
95 //
96 // You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
97 // here to direct the syslog packets to the syslog deamon. The
98 // default is broadcast to both the ethernet and IP.
99 //
100 GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSyslogDstMac[NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
101 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp = 0xffffffff;
102 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp = 0;
103
104 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mMonthName[] = {
105 "Jan",
106 "Feb",
107 "Mar",
108 "Apr",
109 "May",
110 "Jun",
111 "Jul",
112 "Aug",
113 "Sep",
114 "Oct",
115 "Nov",
116 "Dec"
117 };
118
119 //
120 // VLAN device path node template
121 //
122 GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = {
123 {
124 MESSAGING_DEVICE_PATH,
125 MSG_VLAN_DP,
126 {
127 (UINT8) (sizeof (VLAN_DEVICE_PATH)),
128 (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)
129 }
130 },
131 0
132 };
133
134 /**
135 Locate the handles that support SNP, then open one of them
136 to send the syslog packets. The caller isn't required to close
137 the SNP after use because the SNP is opened by HandleProtocol.
138
139 @return The point to SNP if one is properly openned. Otherwise NULL
140
141 **/
142 EFI_SIMPLE_NETWORK_PROTOCOL *
143 SyslogLocateSnp (
144 VOID
145 )
146 {
147 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
148 EFI_STATUS Status;
149 EFI_HANDLE *Handles;
150 UINTN HandleCount;
151 UINTN Index;
152
153 //
154 // Locate the handles which has SNP installed.
155 //
156 Handles = NULL;
157 Status = gBS->LocateHandleBuffer (
158 ByProtocol,
159 &gEfiSimpleNetworkProtocolGuid,
160 NULL,
161 &HandleCount,
162 &Handles
163 );
164
165 if (EFI_ERROR (Status) || (HandleCount == 0)) {
166 return NULL;
167 }
168
169 //
170 // Try to open one of the ethernet SNP protocol to send packet
171 //
172 Snp = NULL;
173
174 for (Index = 0; Index < HandleCount; Index++) {
175 Status = gBS->HandleProtocol (
176 Handles[Index],
177 &gEfiSimpleNetworkProtocolGuid,
178 (VOID **) &Snp
179 );
180
181 if ((Status == EFI_SUCCESS) && (Snp != NULL) &&
182 (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&
183 (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {
184
185 break;
186 }
187
188 Snp = NULL;
189 }
190
191 FreePool (Handles);
192 return Snp;
193 }
194
195 /**
196 Transmit a syslog packet synchronously through SNP. The Packet
197 already has the ethernet header prepended. This function should
198 fill in the source MAC because it will try to locate a SNP each
199 time it is called to avoid the problem if SNP is unloaded.
200 This code snip is copied from MNP.
201 If Packet is NULL, then ASSERT().
202
203 @param[in] Packet The Syslog packet
204 @param[in] Length The length of the packet
205
206 @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol
207 @retval EFI_TIMEOUT Timeout happened to send the packet.
208 @retval EFI_SUCCESS Packet is sent.
209
210 **/
211 EFI_STATUS
212 SyslogSendPacket (
213 IN CHAR8 *Packet,
214 IN UINT32 Length
215 )
216 {
217 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
218 ETHER_HEAD *Ether;
219 EFI_STATUS Status;
220 EFI_EVENT TimeoutEvent;
221 UINT8 *TxBuf;
222
223 ASSERT (Packet != NULL);
224
225 Snp = SyslogLocateSnp ();
226
227 if (Snp == NULL) {
228 return EFI_DEVICE_ERROR;
229 }
230
231 Ether = (ETHER_HEAD *) Packet;
232 CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);
233
234 //
235 // Start the timeout event.
236 //
237 Status = gBS->CreateEvent (
238 EVT_TIMER,
239 TPL_NOTIFY,
240 NULL,
241 NULL,
242 &TimeoutEvent
243 );
244
245 if (EFI_ERROR (Status)) {
246 return Status;
247 }
248
249 Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
250
251 if (EFI_ERROR (Status)) {
252 goto ON_EXIT;
253 }
254
255 for (;;) {
256 //
257 // Transmit the packet through SNP.
258 //
259 Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);
260
261 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {
262 Status = EFI_DEVICE_ERROR;
263 break;
264 }
265
266 //
267 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
268 // if Status is EFI_NOT_READY, the transmit engine of the network
269 // interface is busy. Both need to sync SNP.
270 //
271 TxBuf = NULL;
272
273 do {
274 //
275 // Get the recycled transmit buffer status.
276 //
277 Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);
278
279 if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
280 Status = EFI_TIMEOUT;
281 break;
282 }
283
284 } while (TxBuf == NULL);
285
286 if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {
287 break;
288 }
289
290 //
291 // Status is EFI_NOT_READY. Restart the timer event and
292 // call Snp->Transmit again.
293 //
294 gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
295 }
296
297 gBS->SetTimer (TimeoutEvent, TimerCancel, 0);
298
299 ON_EXIT:
300 gBS->CloseEvent (TimeoutEvent);
301 return Status;
302 }
303
304 /**
305 Build a syslog packet, including the Ethernet/Ip/Udp headers
306 and user's message.
307
308 @param[in] Level Syslog severity level
309 @param[in] Module The module that generates the log
310 @param[in] File The file that contains the current log
311 @param[in] Line The line of code in the File that contains the current log
312 @param[in] Message The log message
313 @param[in] BufLen The lenght of the Buf
314 @param[out] Buf The buffer to put the packet data
315
316 @return The length of the syslog packet built, 0 represents no packet is built.
317
318 **/
319 UINT32
320 SyslogBuildPacket (
321 IN UINT32 Level,
322 IN UINT8 *Module,
323 IN UINT8 *File,
324 IN UINT32 Line,
325 IN UINT8 *Message,
326 IN UINT32 BufLen,
327 OUT CHAR8 *Buf
328 )
329 {
330 EFI_STATUS Status;
331 ETHER_HEAD *Ether;
332 IP4_HEAD *Ip4;
333 EFI_UDP_HEADER *Udp4;
334 EFI_TIME Time;
335 UINT32 Pri;
336 UINT32 Len;
337
338 //
339 // Fill in the Ethernet header. Leave alone the source MAC.
340 // SyslogSendPacket will fill in the address for us.
341 //
342 Ether = (ETHER_HEAD *) Buf;
343 CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);
344 ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);
345
346 Ether->EtherType = HTONS (0x0800); // IPv4 protocol
347
348 Buf += sizeof (ETHER_HEAD);
349 BufLen -= sizeof (ETHER_HEAD);
350
351 //
352 // Fill in the IP header
353 //
354 Ip4 = (IP4_HEAD *) Buf;
355 Ip4->HeadLen = 5;
356 Ip4->Ver = 4;
357 Ip4->Tos = 0;
358 Ip4->TotalLen = 0;
359 Ip4->Id = (UINT16) mSyslogPacketSeq;
360 Ip4->Fragment = 0;
361 Ip4->Ttl = 16;
362 Ip4->Protocol = 0x11;
363 Ip4->Checksum = 0;
364 Ip4->Src = mSyslogSrcIp;
365 Ip4->Dst = mSyslogDstIp;
366
367 Buf += sizeof (IP4_HEAD);
368 BufLen -= sizeof (IP4_HEAD);
369
370 //
371 // Fill in the UDP header, Udp checksum is optional. Leave it zero.
372 //
373 Udp4 = (EFI_UDP_HEADER *) Buf;
374 Udp4->SrcPort = HTONS (514);
375 Udp4->DstPort = HTONS (514);
376 Udp4->Length = 0;
377 Udp4->Checksum = 0;
378
379 Buf += sizeof (EFI_UDP_HEADER);
380 BufLen -= sizeof (EFI_UDP_HEADER);
381
382 //
383 // Build the syslog message body with <PRI> Timestamp machine module Message
384 //
385 Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);
386 Status = gRT->GetTime (&Time, NULL);
387 if (EFI_ERROR (Status)) {
388 return 0;
389 }
390
391 //
392 // Use %a to format the ASCII strings, %s to format UNICODE strings
393 //
394 Len = 0;
395 Len += (UINT32) AsciiSPrint (
396 Buf,
397 BufLen,
398 "<%d> %a %d %d:%d:%d ",
399 Pri,
400 mMonthName [Time.Month-1],
401 Time.Day,
402 Time.Hour,
403 Time.Minute,
404 Time.Second
405 );
406 Len--;
407
408 Len += (UINT32) AsciiSPrint (
409 Buf + Len,
410 BufLen - Len,
411 "Tiano %a: %a (Line: %d File: %a)",
412 Module,
413 Message,
414 Line,
415 File
416 );
417 Len--;
418
419 //
420 // OK, patch the IP length/checksum and UDP length fields.
421 //
422 Len += sizeof (EFI_UDP_HEADER);
423 Udp4->Length = HTONS ((UINT16) Len);
424
425 Len += sizeof (IP4_HEAD);
426 Ip4->TotalLen = HTONS ((UINT16) Len);
427 Ip4->Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD)));
428
429 return Len + sizeof (ETHER_HEAD);
430 }
431
432 /**
433 Allocate a buffer, then format the message to it. This is a
434 help function for the NET_DEBUG_XXX macros. The PrintArg of
435 these macros treats the variable length print parameters as a
436 single parameter, and pass it to the NetDebugASPrint. For
437 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
438 if extracted to:
439
440 NetDebugOutput (
441 NETDEBUG_LEVEL_TRACE,
442 "Tcp",
443 __FILE__,
444 __LINE__,
445 NetDebugASPrint ("State transit to %a\n", Name)
446 )
447
448 If Format is NULL, then ASSERT().
449
450 @param Format The ASCII format string.
451 @param ... The variable length parameter whose format is determined
452 by the Format string.
453
454 @return The buffer containing the formatted message,
455 or NULL if failed to allocate memory.
456
457 **/
458 CHAR8 *
459 EFIAPI
460 NetDebugASPrint (
461 IN CHAR8 *Format,
462 ...
463 )
464 {
465 VA_LIST Marker;
466 CHAR8 *Buf;
467
468 ASSERT (Format != NULL);
469
470 Buf = (CHAR8 *) AllocatePool (NET_DEBUG_MSG_LEN);
471
472 if (Buf == NULL) {
473 return NULL;
474 }
475
476 VA_START (Marker, Format);
477 AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);
478 VA_END (Marker);
479
480 return Buf;
481 }
482
483 /**
484 Builds an UDP4 syslog packet and send it using SNP.
485
486 This function will locate a instance of SNP then send the message through it.
487 Because it isn't open the SNP BY_DRIVER, apply caution when using it.
488
489 @param Level The severity level of the message.
490 @param Module The Moudle that generates the log.
491 @param File The file that contains the log.
492 @param Line The exact line that contains the log.
493 @param Message The user message to log.
494
495 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
496 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
497 @retval EFI_DEVICE_ERROR Device error occurs.
498 @retval EFI_SUCCESS The log is discard because that it is more verbose
499 than the mNetDebugLevelMax. Or, it has been sent out.
500 **/
501 EFI_STATUS
502 EFIAPI
503 NetDebugOutput (
504 IN UINT32 Level,
505 IN UINT8 *Module,
506 IN UINT8 *File,
507 IN UINT32 Line,
508 IN UINT8 *Message
509 )
510 {
511 CHAR8 *Packet;
512 UINT32 Len;
513 EFI_STATUS Status;
514
515 //
516 // Check whether the message should be sent out
517 //
518 if (Message == NULL || File == NULL || Module == NULL) {
519 return EFI_INVALID_PARAMETER;
520 }
521
522 if (Level > mNetDebugLevelMax) {
523 Status = EFI_SUCCESS;
524 goto ON_EXIT;
525 }
526
527 //
528 // Allocate a maxium of 1024 bytes, the caller should ensure
529 // that the message plus the ethernet/ip/udp header is shorter
530 // than this
531 //
532 Packet = (CHAR8 *) AllocatePool (NET_SYSLOG_PACKET_LEN);
533
534 if (Packet == NULL) {
535 Status = EFI_OUT_OF_RESOURCES;
536 goto ON_EXIT;
537 }
538
539 //
540 // Build the message: Ethernet header + IP header + Udp Header + user data
541 //
542 Len = SyslogBuildPacket (
543 Level,
544 Module,
545 File,
546 Line,
547 Message,
548 NET_SYSLOG_PACKET_LEN,
549 Packet
550 );
551 if (Len == 0) {
552 Status = EFI_DEVICE_ERROR;
553 } else {
554 mSyslogPacketSeq++;
555 Status = SyslogSendPacket (Packet, Len);
556 }
557
558 FreePool (Packet);
559
560 ON_EXIT:
561 FreePool (Message);
562 return Status;
563 }
564 /**
565 Return the length of the mask.
566
567 Return the length of the mask, the correct value is from 0 to 32.
568 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.
569 NetMask is in the host byte order.
570
571 @param[in] NetMask The netmask to get the length from.
572
573 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.
574
575 **/
576 INTN
577 EFIAPI
578 NetGetMaskLength (
579 IN IP4_ADDR NetMask
580 )
581 {
582 INTN Index;
583
584 for (Index = 0; Index <= IP4_MASK_MAX; Index++) {
585 if (NetMask == gIp4AllMasks[Index]) {
586 break;
587 }
588 }
589
590 return Index;
591 }
592
593
594
595 /**
596 Return the class of the IP address, such as class A, B, C.
597 Addr is in host byte order.
598
599 [ATTENTION]
600 Classful addressing (IP class A/B/C) has been deprecated according to RFC4632.
601 Caller of this function could only check the returned value against
602 IP4_ADDR_CLASSD (multicast) or IP4_ADDR_CLASSE (reserved) now.
603
604 The address of class A starts with 0.
605 If the address belong to class A, return IP4_ADDR_CLASSA.
606 The address of class B starts with 10.
607 If the address belong to class B, return IP4_ADDR_CLASSB.
608 The address of class C starts with 110.
609 If the address belong to class C, return IP4_ADDR_CLASSC.
610 The address of class D starts with 1110.
611 If the address belong to class D, return IP4_ADDR_CLASSD.
612 The address of class E starts with 1111.
613 If the address belong to class E, return IP4_ADDR_CLASSE.
614
615
616 @param[in] Addr The address to get the class from.
617
618 @return IP address class, such as IP4_ADDR_CLASSA.
619
620 **/
621 INTN
622 EFIAPI
623 NetGetIpClass (
624 IN IP4_ADDR Addr
625 )
626 {
627 UINT8 ByteOne;
628
629 ByteOne = (UINT8) (Addr >> 24);
630
631 if ((ByteOne & 0x80) == 0) {
632 return IP4_ADDR_CLASSA;
633
634 } else if ((ByteOne & 0xC0) == 0x80) {
635 return IP4_ADDR_CLASSB;
636
637 } else if ((ByteOne & 0xE0) == 0xC0) {
638 return IP4_ADDR_CLASSC;
639
640 } else if ((ByteOne & 0xF0) == 0xE0) {
641 return IP4_ADDR_CLASSD;
642
643 } else {
644 return IP4_ADDR_CLASSE;
645
646 }
647 }
648
649
650 /**
651 Check whether the IP is a valid unicast address according to
652 the netmask.
653
654 ASSERT if NetMask is zero.
655
656 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address,
657 except when the originator is one of the endpoints of a point-to-point link with a 31-bit
658 mask (RFC3021).
659
660 @param[in] Ip The IP to check against.
661 @param[in] NetMask The mask of the IP.
662
663 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
664
665 **/
666 BOOLEAN
667 EFIAPI
668 NetIp4IsUnicast (
669 IN IP4_ADDR Ip,
670 IN IP4_ADDR NetMask
671 )
672 {
673 ASSERT (NetMask != 0);
674
675 if (Ip == 0 || IP4_IS_LOCAL_BROADCAST (Ip)) {
676 return FALSE;
677 }
678
679 if (NetGetMaskLength (NetMask) != 31) {
680 if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {
681 return FALSE;
682 }
683 } else {
684 return TRUE;
685 }
686
687 return TRUE;
688 }
689
690 /**
691 Check whether the incoming IPv6 address is a valid unicast address.
692
693 ASSERT if Ip6 is NULL.
694
695 If the address is a multicast address has binary 0xFF at the start, it is not
696 a valid unicast address. If the address is unspecified ::, it is not a valid
697 unicast address to be assigned to any node. If the address is loopback address
698 ::1, it is also not a valid unicast address to be assigned to any physical
699 interface.
700
701 @param[in] Ip6 The IPv6 address to check against.
702
703 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
704
705 **/
706 BOOLEAN
707 EFIAPI
708 NetIp6IsValidUnicast (
709 IN EFI_IPv6_ADDRESS *Ip6
710 )
711 {
712 UINT8 Byte;
713 UINT8 Index;
714
715 ASSERT (Ip6 != NULL);
716
717 if (Ip6->Addr[0] == 0xFF) {
718 return FALSE;
719 }
720
721 for (Index = 0; Index < 15; Index++) {
722 if (Ip6->Addr[Index] != 0) {
723 return TRUE;
724 }
725 }
726
727 Byte = Ip6->Addr[Index];
728
729 if (Byte == 0x0 || Byte == 0x1) {
730 return FALSE;
731 }
732
733 return TRUE;
734 }
735
736 /**
737 Check whether the incoming Ipv6 address is the unspecified address or not.
738
739 ASSERT if Ip6 is NULL.
740
741 @param[in] Ip6 - Ip6 address, in network order.
742
743 @retval TRUE - Yes, unspecified
744 @retval FALSE - No
745
746 **/
747 BOOLEAN
748 EFIAPI
749 NetIp6IsUnspecifiedAddr (
750 IN EFI_IPv6_ADDRESS *Ip6
751 )
752 {
753 UINT8 Index;
754
755 ASSERT (Ip6 != NULL);
756
757 for (Index = 0; Index < 16; Index++) {
758 if (Ip6->Addr[Index] != 0) {
759 return FALSE;
760 }
761 }
762
763 return TRUE;
764 }
765
766 /**
767 Check whether the incoming Ipv6 address is a link-local address.
768
769 ASSERT if Ip6 is NULL.
770
771 @param[in] Ip6 - Ip6 address, in network order.
772
773 @retval TRUE - Yes, link-local address
774 @retval FALSE - No
775
776 **/
777 BOOLEAN
778 EFIAPI
779 NetIp6IsLinkLocalAddr (
780 IN EFI_IPv6_ADDRESS *Ip6
781 )
782 {
783 UINT8 Index;
784
785 ASSERT (Ip6 != NULL);
786
787 if (Ip6->Addr[0] != 0xFE) {
788 return FALSE;
789 }
790
791 if (Ip6->Addr[1] != 0x80) {
792 return FALSE;
793 }
794
795 for (Index = 2; Index < 8; Index++) {
796 if (Ip6->Addr[Index] != 0) {
797 return FALSE;
798 }
799 }
800
801 return TRUE;
802 }
803
804 /**
805 Check whether the Ipv6 address1 and address2 are on the connected network.
806
807 ASSERT if Ip1 or Ip2 is NULL.
808 ASSERT if PrefixLength exceeds IP6_PREFIX_MAX.
809
810 @param[in] Ip1 - Ip6 address1, in network order.
811 @param[in] Ip2 - Ip6 address2, in network order.
812 @param[in] PrefixLength - The prefix length of the checking net.
813
814 @retval TRUE - Yes, connected.
815 @retval FALSE - No.
816
817 **/
818 BOOLEAN
819 EFIAPI
820 NetIp6IsNetEqual (
821 EFI_IPv6_ADDRESS *Ip1,
822 EFI_IPv6_ADDRESS *Ip2,
823 UINT8 PrefixLength
824 )
825 {
826 UINT8 Byte;
827 UINT8 Bit;
828 UINT8 Mask;
829
830 ASSERT ((Ip1 != NULL) && (Ip2 != NULL) && (PrefixLength <= IP6_PREFIX_MAX));
831
832 if (PrefixLength == 0) {
833 return TRUE;
834 }
835
836 Byte = (UINT8) (PrefixLength / 8);
837 Bit = (UINT8) (PrefixLength % 8);
838
839 if (CompareMem (Ip1, Ip2, Byte) != 0) {
840 return FALSE;
841 }
842
843 if (Bit > 0) {
844 Mask = (UINT8) (0xFF << (8 - Bit));
845
846 if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {
847 return FALSE;
848 }
849 }
850
851 return TRUE;
852 }
853
854
855 /**
856 Switches the endianess of an IPv6 address
857
858 ASSERT if Ip6 is NULL.
859
860 This function swaps the bytes in a 128-bit IPv6 address to switch the value
861 from little endian to big endian or vice versa. The byte swapped value is
862 returned.
863
864 @param Ip6 Points to an IPv6 address
865
866 @return The byte swapped IPv6 address.
867
868 **/
869 EFI_IPv6_ADDRESS *
870 EFIAPI
871 Ip6Swap128 (
872 EFI_IPv6_ADDRESS *Ip6
873 )
874 {
875 UINT64 High;
876 UINT64 Low;
877
878 ASSERT (Ip6 != NULL);
879
880 CopyMem (&High, Ip6, sizeof (UINT64));
881 CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));
882
883 High = SwapBytes64 (High);
884 Low = SwapBytes64 (Low);
885
886 CopyMem (Ip6, &Low, sizeof (UINT64));
887 CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));
888
889 return Ip6;
890 }
891
892 /**
893 Initialize a random seed using current time and monotonic count.
894
895 Get current time and monotonic count first. Then initialize a random seed
896 based on some basic mathematics operation on the hour, day, minute, second,
897 nanosecond and year of the current time and the monotonic count value.
898
899 @return The random seed initialized with current time.
900
901 **/
902 UINT32
903 EFIAPI
904 NetRandomInitSeed (
905 VOID
906 )
907 {
908 EFI_TIME Time;
909 UINT32 Seed;
910 UINT64 MonotonicCount;
911
912 gRT->GetTime (&Time, NULL);
913 Seed = (Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);
914 Seed ^= Time.Nanosecond;
915 Seed ^= Time.Year << 7;
916
917 gBS->GetNextMonotonicCount (&MonotonicCount);
918 Seed += (UINT32) MonotonicCount;
919
920 return Seed;
921 }
922
923
924 /**
925 Extract a UINT32 from a byte stream.
926
927 ASSERT if Buf is NULL.
928
929 Copy a UINT32 from a byte stream, then converts it from Network
930 byte order to host byte order. Use this function to avoid alignment error.
931
932 @param[in] Buf The buffer to extract the UINT32.
933
934 @return The UINT32 extracted.
935
936 **/
937 UINT32
938 EFIAPI
939 NetGetUint32 (
940 IN UINT8 *Buf
941 )
942 {
943 UINT32 Value;
944
945 ASSERT (Buf != NULL);
946
947 CopyMem (&Value, Buf, sizeof (UINT32));
948 return NTOHL (Value);
949 }
950
951
952 /**
953 Put a UINT32 to the byte stream in network byte order.
954
955 ASSERT if Buf is NULL.
956
957 Converts a UINT32 from host byte order to network byte order. Then copy it to the
958 byte stream.
959
960 @param[in, out] Buf The buffer to put the UINT32.
961 @param[in] Data The data to be converted and put into the byte stream.
962
963 **/
964 VOID
965 EFIAPI
966 NetPutUint32 (
967 IN OUT UINT8 *Buf,
968 IN UINT32 Data
969 )
970 {
971 ASSERT (Buf != NULL);
972
973 Data = HTONL (Data);
974 CopyMem (Buf, &Data, sizeof (UINT32));
975 }
976
977
978 /**
979 Remove the first node entry on the list, and return the removed node entry.
980
981 Removes the first node Entry from a doubly linked list. It is up to the caller of
982 this function to release the memory used by the first node if that is required. On
983 exit, the removed node is returned.
984
985 If Head is NULL, then ASSERT().
986 If Head was not initialized, then ASSERT().
987 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
988 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
989 then ASSERT().
990
991 @param[in, out] Head The list header.
992
993 @return The first node entry that is removed from the list, NULL if the list is empty.
994
995 **/
996 LIST_ENTRY *
997 EFIAPI
998 NetListRemoveHead (
999 IN OUT LIST_ENTRY *Head
1000 )
1001 {
1002 LIST_ENTRY *First;
1003
1004 ASSERT (Head != NULL);
1005
1006 if (IsListEmpty (Head)) {
1007 return NULL;
1008 }
1009
1010 First = Head->ForwardLink;
1011 Head->ForwardLink = First->ForwardLink;
1012 First->ForwardLink->BackLink = Head;
1013
1014 DEBUG_CODE (
1015 First->ForwardLink = (LIST_ENTRY *) NULL;
1016 First->BackLink = (LIST_ENTRY *) NULL;
1017 );
1018
1019 return First;
1020 }
1021
1022
1023 /**
1024 Remove the last node entry on the list and and return the removed node entry.
1025
1026 Removes the last node entry from a doubly linked list. It is up to the caller of
1027 this function to release the memory used by the first node if that is required. On
1028 exit, the removed node is returned.
1029
1030 If Head is NULL, then ASSERT().
1031 If Head was not initialized, then ASSERT().
1032 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
1033 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
1034 then ASSERT().
1035
1036 @param[in, out] Head The list head.
1037
1038 @return The last node entry that is removed from the list, NULL if the list is empty.
1039
1040 **/
1041 LIST_ENTRY *
1042 EFIAPI
1043 NetListRemoveTail (
1044 IN OUT LIST_ENTRY *Head
1045 )
1046 {
1047 LIST_ENTRY *Last;
1048
1049 ASSERT (Head != NULL);
1050
1051 if (IsListEmpty (Head)) {
1052 return NULL;
1053 }
1054
1055 Last = Head->BackLink;
1056 Head->BackLink = Last->BackLink;
1057 Last->BackLink->ForwardLink = Head;
1058
1059 DEBUG_CODE (
1060 Last->ForwardLink = (LIST_ENTRY *) NULL;
1061 Last->BackLink = (LIST_ENTRY *) NULL;
1062 );
1063
1064 return Last;
1065 }
1066
1067
1068 /**
1069 Insert a new node entry after a designated node entry of a doubly linked list.
1070
1071 ASSERT if PrevEntry or NewEntry is NULL.
1072
1073 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
1074 of the doubly linked list.
1075
1076 @param[in, out] PrevEntry The previous entry to insert after.
1077 @param[in, out] NewEntry The new entry to insert.
1078
1079 **/
1080 VOID
1081 EFIAPI
1082 NetListInsertAfter (
1083 IN OUT LIST_ENTRY *PrevEntry,
1084 IN OUT LIST_ENTRY *NewEntry
1085 )
1086 {
1087 ASSERT (PrevEntry != NULL && NewEntry != NULL);
1088
1089 NewEntry->BackLink = PrevEntry;
1090 NewEntry->ForwardLink = PrevEntry->ForwardLink;
1091 PrevEntry->ForwardLink->BackLink = NewEntry;
1092 PrevEntry->ForwardLink = NewEntry;
1093 }
1094
1095
1096 /**
1097 Insert a new node entry before a designated node entry of a doubly linked list.
1098
1099 ASSERT if PostEntry or NewEntry is NULL.
1100
1101 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
1102 of the doubly linked list.
1103
1104 @param[in, out] PostEntry The entry to insert before.
1105 @param[in, out] NewEntry The new entry to insert.
1106
1107 **/
1108 VOID
1109 EFIAPI
1110 NetListInsertBefore (
1111 IN OUT LIST_ENTRY *PostEntry,
1112 IN OUT LIST_ENTRY *NewEntry
1113 )
1114 {
1115 ASSERT (PostEntry != NULL && NewEntry != NULL);
1116
1117 NewEntry->ForwardLink = PostEntry;
1118 NewEntry->BackLink = PostEntry->BackLink;
1119 PostEntry->BackLink->ForwardLink = NewEntry;
1120 PostEntry->BackLink = NewEntry;
1121 }
1122
1123 /**
1124 Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.
1125
1126 Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.
1127 This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed
1128 has been removed from the list or not.
1129 If it has been removed, then restart the traversal from the head.
1130 If it hasn't been removed, then continue with the next node directly.
1131 This function will end the iterate and return the CallBack's last return value if error happens,
1132 or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.
1133
1134 @param[in] List The head of the list.
1135 @param[in] CallBack Pointer to the callback function to destroy one node in the list.
1136 @param[in] Context Pointer to the callback function's context: corresponds to the
1137 parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.
1138 @param[out] ListLength The length of the link list if the function returns successfully.
1139
1140 @retval EFI_SUCCESS Two complete passes are made with no changes in the number of children.
1141 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
1142 @retval Others Return the CallBack's last return value.
1143
1144 **/
1145 EFI_STATUS
1146 EFIAPI
1147 NetDestroyLinkList (
1148 IN LIST_ENTRY *List,
1149 IN NET_DESTROY_LINK_LIST_CALLBACK CallBack,
1150 IN VOID *Context, OPTIONAL
1151 OUT UINTN *ListLength OPTIONAL
1152 )
1153 {
1154 UINTN PreviousLength;
1155 LIST_ENTRY *Entry;
1156 LIST_ENTRY *Ptr;
1157 UINTN Length;
1158 EFI_STATUS Status;
1159
1160 if (List == NULL || CallBack == NULL) {
1161 return EFI_INVALID_PARAMETER;
1162 }
1163
1164 Length = 0;
1165 do {
1166 PreviousLength = Length;
1167 Entry = GetFirstNode (List);
1168 while (!IsNull (List, Entry)) {
1169 Status = CallBack (Entry, Context);
1170 if (EFI_ERROR (Status)) {
1171 return Status;
1172 }
1173 //
1174 // Walk through the list to see whether the Entry has been removed or not.
1175 // If the Entry still exists, just try to destroy the next one.
1176 // If not, go back to the start point to iterate the list again.
1177 //
1178 for (Ptr = List->ForwardLink; Ptr != List; Ptr = Ptr->ForwardLink) {
1179 if (Ptr == Entry) {
1180 break;
1181 }
1182 }
1183 if (Ptr == Entry) {
1184 Entry = GetNextNode (List, Entry);
1185 } else {
1186 Entry = GetFirstNode (List);
1187 }
1188 }
1189 for (Length = 0, Ptr = List->ForwardLink; Ptr != List; Length++, Ptr = Ptr->ForwardLink);
1190 } while (Length != PreviousLength);
1191
1192 if (ListLength != NULL) {
1193 *ListLength = Length;
1194 }
1195 return EFI_SUCCESS;
1196 }
1197
1198 /**
1199 This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.
1200
1201 @param[in] Handle Handle to be checked.
1202 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.
1203 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1204 if NumberOfChildren is 0.
1205
1206 @retval TRUE Found the input Handle in ChildHandleBuffer.
1207 @retval FALSE Can't find the input Handle in ChildHandleBuffer.
1208
1209 **/
1210 BOOLEAN
1211 EFIAPI
1212 NetIsInHandleBuffer (
1213 IN EFI_HANDLE Handle,
1214 IN UINTN NumberOfChildren,
1215 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
1216 )
1217 {
1218 UINTN Index;
1219
1220 if (NumberOfChildren == 0 || ChildHandleBuffer == NULL) {
1221 return FALSE;
1222 }
1223
1224 for (Index = 0; Index < NumberOfChildren; Index++) {
1225 if (Handle == ChildHandleBuffer[Index]) {
1226 return TRUE;
1227 }
1228 }
1229
1230 return FALSE;
1231 }
1232
1233
1234 /**
1235 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
1236
1237 Initialize the forward and backward links of two head nodes donated by Map->Used
1238 and Map->Recycled of two doubly linked lists.
1239 Initializes the count of the <Key, Value> pairs in the netmap to zero.
1240
1241 If Map is NULL, then ASSERT().
1242 If the address of Map->Used is NULL, then ASSERT().
1243 If the address of Map->Recycled is NULl, then ASSERT().
1244
1245 @param[in, out] Map The netmap to initialize.
1246
1247 **/
1248 VOID
1249 EFIAPI
1250 NetMapInit (
1251 IN OUT NET_MAP *Map
1252 )
1253 {
1254 ASSERT (Map != NULL);
1255
1256 InitializeListHead (&Map->Used);
1257 InitializeListHead (&Map->Recycled);
1258 Map->Count = 0;
1259 }
1260
1261
1262 /**
1263 To clean up the netmap, that is, release allocated memories.
1264
1265 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
1266 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
1267 The number of the <Key, Value> pairs in the netmap is set to be zero.
1268
1269 If Map is NULL, then ASSERT().
1270
1271 @param[in, out] Map The netmap to clean up.
1272
1273 **/
1274 VOID
1275 EFIAPI
1276 NetMapClean (
1277 IN OUT NET_MAP *Map
1278 )
1279 {
1280 NET_MAP_ITEM *Item;
1281 LIST_ENTRY *Entry;
1282 LIST_ENTRY *Next;
1283
1284 ASSERT (Map != NULL);
1285
1286 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {
1287 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1288
1289 RemoveEntryList (&Item->Link);
1290 Map->Count--;
1291
1292 gBS->FreePool (Item);
1293 }
1294
1295 ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));
1296
1297 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {
1298 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1299
1300 RemoveEntryList (&Item->Link);
1301 gBS->FreePool (Item);
1302 }
1303
1304 ASSERT (IsListEmpty (&Map->Recycled));
1305 }
1306
1307
1308 /**
1309 Test whether the netmap is empty and return true if it is.
1310
1311 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
1312
1313 If Map is NULL, then ASSERT().
1314
1315 @param[in] Map The net map to test.
1316
1317 @return TRUE if the netmap is empty, otherwise FALSE.
1318
1319 **/
1320 BOOLEAN
1321 EFIAPI
1322 NetMapIsEmpty (
1323 IN NET_MAP *Map
1324 )
1325 {
1326 ASSERT (Map != NULL);
1327 return (BOOLEAN) (Map->Count == 0);
1328 }
1329
1330
1331 /**
1332 Return the number of the <Key, Value> pairs in the netmap.
1333
1334 If Map is NULL, then ASSERT().
1335
1336 @param[in] Map The netmap to get the entry number.
1337
1338 @return The entry number in the netmap.
1339
1340 **/
1341 UINTN
1342 EFIAPI
1343 NetMapGetCount (
1344 IN NET_MAP *Map
1345 )
1346 {
1347 ASSERT (Map != NULL);
1348 return Map->Count;
1349 }
1350
1351
1352 /**
1353 Return one allocated item.
1354
1355 If the Recycled doubly linked list of the netmap is empty, it will try to allocate
1356 a batch of items if there are enough resources and add corresponding nodes to the begining
1357 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
1358 the fist node entry of the Recycled doubly linked list and return the corresponding item.
1359
1360 If Map is NULL, then ASSERT().
1361
1362 @param[in, out] Map The netmap to allocate item for.
1363
1364 @return The allocated item. If NULL, the
1365 allocation failed due to resource limit.
1366
1367 **/
1368 NET_MAP_ITEM *
1369 NetMapAllocItem (
1370 IN OUT NET_MAP *Map
1371 )
1372 {
1373 NET_MAP_ITEM *Item;
1374 LIST_ENTRY *Head;
1375 UINTN Index;
1376
1377 ASSERT (Map != NULL);
1378
1379 Head = &Map->Recycled;
1380
1381 if (IsListEmpty (Head)) {
1382 for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {
1383 Item = AllocatePool (sizeof (NET_MAP_ITEM));
1384
1385 if (Item == NULL) {
1386 if (Index == 0) {
1387 return NULL;
1388 }
1389
1390 break;
1391 }
1392
1393 InsertHeadList (Head, &Item->Link);
1394 }
1395 }
1396
1397 Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);
1398 NetListRemoveHead (Head);
1399
1400 return Item;
1401 }
1402
1403
1404 /**
1405 Allocate an item to save the <Key, Value> pair to the head of the netmap.
1406
1407 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1408 to the beginning of the Used doubly linked list. The number of the <Key, Value>
1409 pairs in the netmap increase by 1.
1410
1411 If Map is NULL, then ASSERT().
1412 If Key is NULL, then ASSERT().
1413
1414 @param[in, out] Map The netmap to insert into.
1415 @param[in] Key The user's key.
1416 @param[in] Value The user's value for the key.
1417
1418 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1419 @retval EFI_SUCCESS The item is inserted to the head.
1420
1421 **/
1422 EFI_STATUS
1423 EFIAPI
1424 NetMapInsertHead (
1425 IN OUT NET_MAP *Map,
1426 IN VOID *Key,
1427 IN VOID *Value OPTIONAL
1428 )
1429 {
1430 NET_MAP_ITEM *Item;
1431
1432 ASSERT (Map != NULL && Key != NULL);
1433
1434 Item = NetMapAllocItem (Map);
1435
1436 if (Item == NULL) {
1437 return EFI_OUT_OF_RESOURCES;
1438 }
1439
1440 Item->Key = Key;
1441 Item->Value = Value;
1442 InsertHeadList (&Map->Used, &Item->Link);
1443
1444 Map->Count++;
1445 return EFI_SUCCESS;
1446 }
1447
1448
1449 /**
1450 Allocate an item to save the <Key, Value> pair to the tail of the netmap.
1451
1452 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1453 to the tail of the Used doubly linked list. The number of the <Key, Value>
1454 pairs in the netmap increase by 1.
1455
1456 If Map is NULL, then ASSERT().
1457 If Key is NULL, then ASSERT().
1458
1459 @param[in, out] Map The netmap to insert into.
1460 @param[in] Key The user's key.
1461 @param[in] Value The user's value for the key.
1462
1463 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1464 @retval EFI_SUCCESS The item is inserted to the tail.
1465
1466 **/
1467 EFI_STATUS
1468 EFIAPI
1469 NetMapInsertTail (
1470 IN OUT NET_MAP *Map,
1471 IN VOID *Key,
1472 IN VOID *Value OPTIONAL
1473 )
1474 {
1475 NET_MAP_ITEM *Item;
1476
1477 ASSERT (Map != NULL && Key != NULL);
1478
1479 Item = NetMapAllocItem (Map);
1480
1481 if (Item == NULL) {
1482 return EFI_OUT_OF_RESOURCES;
1483 }
1484
1485 Item->Key = Key;
1486 Item->Value = Value;
1487 InsertTailList (&Map->Used, &Item->Link);
1488
1489 Map->Count++;
1490
1491 return EFI_SUCCESS;
1492 }
1493
1494
1495 /**
1496 Check whether the item is in the Map and return TRUE if it is.
1497
1498 If Map is NULL, then ASSERT().
1499 If Item is NULL, then ASSERT().
1500
1501 @param[in] Map The netmap to search within.
1502 @param[in] Item The item to search.
1503
1504 @return TRUE if the item is in the netmap, otherwise FALSE.
1505
1506 **/
1507 BOOLEAN
1508 NetItemInMap (
1509 IN NET_MAP *Map,
1510 IN NET_MAP_ITEM *Item
1511 )
1512 {
1513 LIST_ENTRY *ListEntry;
1514
1515 ASSERT (Map != NULL && Item != NULL);
1516
1517 NET_LIST_FOR_EACH (ListEntry, &Map->Used) {
1518 if (ListEntry == &Item->Link) {
1519 return TRUE;
1520 }
1521 }
1522
1523 return FALSE;
1524 }
1525
1526
1527 /**
1528 Find the key in the netmap and returns the point to the item contains the Key.
1529
1530 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
1531 item with the key to search. It returns the point to the item contains the Key if found.
1532
1533 If Map is NULL, then ASSERT().
1534 If Key is NULL, then ASSERT().
1535
1536 @param[in] Map The netmap to search within.
1537 @param[in] Key The key to search.
1538
1539 @return The point to the item contains the Key, or NULL if Key isn't in the map.
1540
1541 **/
1542 NET_MAP_ITEM *
1543 EFIAPI
1544 NetMapFindKey (
1545 IN NET_MAP *Map,
1546 IN VOID *Key
1547 )
1548 {
1549 LIST_ENTRY *Entry;
1550 NET_MAP_ITEM *Item;
1551
1552 ASSERT (Map != NULL && Key != NULL);
1553
1554 NET_LIST_FOR_EACH (Entry, &Map->Used) {
1555 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1556
1557 if (Item->Key == Key) {
1558 return Item;
1559 }
1560 }
1561
1562 return NULL;
1563 }
1564
1565
1566 /**
1567 Remove the node entry of the item from the netmap and return the key of the removed item.
1568
1569 Remove the node entry of the item from the Used doubly linked list of the netmap.
1570 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1571 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
1572 Value will point to the value of the item. It returns the key of the removed item.
1573
1574 If Map is NULL, then ASSERT().
1575 If Item is NULL, then ASSERT().
1576 if item in not in the netmap, then ASSERT().
1577
1578 @param[in, out] Map The netmap to remove the item from.
1579 @param[in, out] Item The item to remove.
1580 @param[out] Value The variable to receive the value if not NULL.
1581
1582 @return The key of the removed item.
1583
1584 **/
1585 VOID *
1586 EFIAPI
1587 NetMapRemoveItem (
1588 IN OUT NET_MAP *Map,
1589 IN OUT NET_MAP_ITEM *Item,
1590 OUT VOID **Value OPTIONAL
1591 )
1592 {
1593 ASSERT ((Map != NULL) && (Item != NULL));
1594 ASSERT (NetItemInMap (Map, Item));
1595
1596 RemoveEntryList (&Item->Link);
1597 Map->Count--;
1598 InsertHeadList (&Map->Recycled, &Item->Link);
1599
1600 if (Value != NULL) {
1601 *Value = Item->Value;
1602 }
1603
1604 return Item->Key;
1605 }
1606
1607
1608 /**
1609 Remove the first node entry on the netmap and return the key of the removed item.
1610
1611 Remove the first node entry from the Used doubly linked list of the netmap.
1612 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1613 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1614 parameter Value will point to the value of the item. It returns the key of the removed item.
1615
1616 If Map is NULL, then ASSERT().
1617 If the Used doubly linked list is empty, then ASSERT().
1618
1619 @param[in, out] Map The netmap to remove the head from.
1620 @param[out] Value The variable to receive the value if not NULL.
1621
1622 @return The key of the item removed.
1623
1624 **/
1625 VOID *
1626 EFIAPI
1627 NetMapRemoveHead (
1628 IN OUT NET_MAP *Map,
1629 OUT VOID **Value OPTIONAL
1630 )
1631 {
1632 NET_MAP_ITEM *Item;
1633
1634 //
1635 // Often, it indicates a programming error to remove
1636 // the first entry in an empty list
1637 //
1638 ASSERT (Map && !IsListEmpty (&Map->Used));
1639
1640 Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);
1641 RemoveEntryList (&Item->Link);
1642 Map->Count--;
1643 InsertHeadList (&Map->Recycled, &Item->Link);
1644
1645 if (Value != NULL) {
1646 *Value = Item->Value;
1647 }
1648
1649 return Item->Key;
1650 }
1651
1652
1653 /**
1654 Remove the last node entry on the netmap and return the key of the removed item.
1655
1656 Remove the last node entry from the Used doubly linked list of the netmap.
1657 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1658 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1659 parameter Value will point to the value of the item. It returns the key of the removed item.
1660
1661 If Map is NULL, then ASSERT().
1662 If the Used doubly linked list is empty, then ASSERT().
1663
1664 @param[in, out] Map The netmap to remove the tail from.
1665 @param[out] Value The variable to receive the value if not NULL.
1666
1667 @return The key of the item removed.
1668
1669 **/
1670 VOID *
1671 EFIAPI
1672 NetMapRemoveTail (
1673 IN OUT NET_MAP *Map,
1674 OUT VOID **Value OPTIONAL
1675 )
1676 {
1677 NET_MAP_ITEM *Item;
1678
1679 //
1680 // Often, it indicates a programming error to remove
1681 // the last entry in an empty list
1682 //
1683 ASSERT (Map && !IsListEmpty (&Map->Used));
1684
1685 Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);
1686 RemoveEntryList (&Item->Link);
1687 Map->Count--;
1688 InsertHeadList (&Map->Recycled, &Item->Link);
1689
1690 if (Value != NULL) {
1691 *Value = Item->Value;
1692 }
1693
1694 return Item->Key;
1695 }
1696
1697
1698 /**
1699 Iterate through the netmap and call CallBack for each item.
1700
1701 It will continue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
1702 from the loop. It returns the CallBack's last return value. This function is
1703 delete safe for the current item.
1704
1705 If Map is NULL, then ASSERT().
1706 If CallBack is NULL, then ASSERT().
1707
1708 @param[in] Map The Map to iterate through.
1709 @param[in] CallBack The callback function to call for each item.
1710 @param[in] Arg The opaque parameter to the callback.
1711
1712 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item
1713 return EFI_SUCCESS.
1714 @retval Others It returns the CallBack's last return value.
1715
1716 **/
1717 EFI_STATUS
1718 EFIAPI
1719 NetMapIterate (
1720 IN NET_MAP *Map,
1721 IN NET_MAP_CALLBACK CallBack,
1722 IN VOID *Arg OPTIONAL
1723 )
1724 {
1725
1726 LIST_ENTRY *Entry;
1727 LIST_ENTRY *Next;
1728 LIST_ENTRY *Head;
1729 NET_MAP_ITEM *Item;
1730 EFI_STATUS Result;
1731
1732 ASSERT ((Map != NULL) && (CallBack != NULL));
1733
1734 Head = &Map->Used;
1735
1736 if (IsListEmpty (Head)) {
1737 return EFI_SUCCESS;
1738 }
1739
1740 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
1741 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1742 Result = CallBack (Map, Item, Arg);
1743
1744 if (EFI_ERROR (Result)) {
1745 return Result;
1746 }
1747 }
1748
1749 return EFI_SUCCESS;
1750 }
1751
1752
1753 /**
1754 This is the default unload handle for all the network drivers.
1755
1756 Disconnect the driver specified by ImageHandle from all the devices in the handle database.
1757 Uninstall all the protocols installed in the driver entry point.
1758
1759 @param[in] ImageHandle The drivers' driver image.
1760
1761 @retval EFI_SUCCESS The image is unloaded.
1762 @retval Others Failed to unload the image.
1763
1764 **/
1765 EFI_STATUS
1766 EFIAPI
1767 NetLibDefaultUnload (
1768 IN EFI_HANDLE ImageHandle
1769 )
1770 {
1771 EFI_STATUS Status;
1772 EFI_HANDLE *DeviceHandleBuffer;
1773 UINTN DeviceHandleCount;
1774 UINTN Index;
1775 UINTN Index2;
1776 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
1777 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
1778 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
1779
1780 //
1781 // Get the list of all the handles in the handle database.
1782 // If there is an error getting the list, then the unload
1783 // operation fails.
1784 //
1785 Status = gBS->LocateHandleBuffer (
1786 AllHandles,
1787 NULL,
1788 NULL,
1789 &DeviceHandleCount,
1790 &DeviceHandleBuffer
1791 );
1792
1793 if (EFI_ERROR (Status)) {
1794 return Status;
1795 }
1796
1797 for (Index = 0; Index < DeviceHandleCount; Index++) {
1798 Status = gBS->HandleProtocol (
1799 DeviceHandleBuffer[Index],
1800 &gEfiDriverBindingProtocolGuid,
1801 (VOID **) &DriverBinding
1802 );
1803 if (EFI_ERROR (Status)) {
1804 continue;
1805 }
1806
1807 if (DriverBinding->ImageHandle != ImageHandle) {
1808 continue;
1809 }
1810
1811 //
1812 // Disconnect the driver specified by ImageHandle from all
1813 // the devices in the handle database.
1814 //
1815 for (Index2 = 0; Index2 < DeviceHandleCount; Index2++) {
1816 Status = gBS->DisconnectController (
1817 DeviceHandleBuffer[Index2],
1818 DriverBinding->DriverBindingHandle,
1819 NULL
1820 );
1821 }
1822
1823 //
1824 // Uninstall all the protocols installed in the driver entry point
1825 //
1826 gBS->UninstallProtocolInterface (
1827 DriverBinding->DriverBindingHandle,
1828 &gEfiDriverBindingProtocolGuid,
1829 DriverBinding
1830 );
1831
1832 Status = gBS->HandleProtocol (
1833 DeviceHandleBuffer[Index],
1834 &gEfiComponentNameProtocolGuid,
1835 (VOID **) &ComponentName
1836 );
1837 if (!EFI_ERROR (Status)) {
1838 gBS->UninstallProtocolInterface (
1839 DriverBinding->DriverBindingHandle,
1840 &gEfiComponentNameProtocolGuid,
1841 ComponentName
1842 );
1843 }
1844
1845 Status = gBS->HandleProtocol (
1846 DeviceHandleBuffer[Index],
1847 &gEfiComponentName2ProtocolGuid,
1848 (VOID **) &ComponentName2
1849 );
1850 if (!EFI_ERROR (Status)) {
1851 gBS->UninstallProtocolInterface (
1852 DriverBinding->DriverBindingHandle,
1853 &gEfiComponentName2ProtocolGuid,
1854 ComponentName2
1855 );
1856 }
1857 }
1858
1859 //
1860 // Free the buffer containing the list of handles from the handle database
1861 //
1862 if (DeviceHandleBuffer != NULL) {
1863 gBS->FreePool (DeviceHandleBuffer);
1864 }
1865
1866 return EFI_SUCCESS;
1867 }
1868
1869
1870
1871 /**
1872 Create a child of the service that is identified by ServiceBindingGuid.
1873
1874 Get the ServiceBinding Protocol first, then use it to create a child.
1875
1876 If ServiceBindingGuid is NULL, then ASSERT().
1877 If ChildHandle is NULL, then ASSERT().
1878
1879 @param[in] Controller The controller which has the service installed.
1880 @param[in] Image The image handle used to open service.
1881 @param[in] ServiceBindingGuid The service's Guid.
1882 @param[in, out] ChildHandle The handle to receive the create child.
1883
1884 @retval EFI_SUCCESS The child is successfully created.
1885 @retval Others Failed to create the child.
1886
1887 **/
1888 EFI_STATUS
1889 EFIAPI
1890 NetLibCreateServiceChild (
1891 IN EFI_HANDLE Controller,
1892 IN EFI_HANDLE Image,
1893 IN EFI_GUID *ServiceBindingGuid,
1894 IN OUT EFI_HANDLE *ChildHandle
1895 )
1896 {
1897 EFI_STATUS Status;
1898 EFI_SERVICE_BINDING_PROTOCOL *Service;
1899
1900
1901 ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));
1902
1903 //
1904 // Get the ServiceBinding Protocol
1905 //
1906 Status = gBS->OpenProtocol (
1907 Controller,
1908 ServiceBindingGuid,
1909 (VOID **) &Service,
1910 Image,
1911 Controller,
1912 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1913 );
1914
1915 if (EFI_ERROR (Status)) {
1916 return Status;
1917 }
1918
1919 //
1920 // Create a child
1921 //
1922 Status = Service->CreateChild (Service, ChildHandle);
1923 return Status;
1924 }
1925
1926
1927 /**
1928 Destroy a child of the service that is identified by ServiceBindingGuid.
1929
1930 Get the ServiceBinding Protocol first, then use it to destroy a child.
1931
1932 If ServiceBindingGuid is NULL, then ASSERT().
1933
1934 @param[in] Controller The controller which has the service installed.
1935 @param[in] Image The image handle used to open service.
1936 @param[in] ServiceBindingGuid The service's Guid.
1937 @param[in] ChildHandle The child to destroy.
1938
1939 @retval EFI_SUCCESS The child is successfully destroyed.
1940 @retval Others Failed to destroy the child.
1941
1942 **/
1943 EFI_STATUS
1944 EFIAPI
1945 NetLibDestroyServiceChild (
1946 IN EFI_HANDLE Controller,
1947 IN EFI_HANDLE Image,
1948 IN EFI_GUID *ServiceBindingGuid,
1949 IN EFI_HANDLE ChildHandle
1950 )
1951 {
1952 EFI_STATUS Status;
1953 EFI_SERVICE_BINDING_PROTOCOL *Service;
1954
1955 ASSERT (ServiceBindingGuid != NULL);
1956
1957 //
1958 // Get the ServiceBinding Protocol
1959 //
1960 Status = gBS->OpenProtocol (
1961 Controller,
1962 ServiceBindingGuid,
1963 (VOID **) &Service,
1964 Image,
1965 Controller,
1966 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1967 );
1968
1969 if (EFI_ERROR (Status)) {
1970 return Status;
1971 }
1972
1973 //
1974 // destroy the child
1975 //
1976 Status = Service->DestroyChild (Service, ChildHandle);
1977 return Status;
1978 }
1979
1980 /**
1981 Get handle with Simple Network Protocol installed on it.
1982
1983 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
1984 If Simple Network Protocol is already installed on the ServiceHandle, the
1985 ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,
1986 try to find its parent handle with SNP installed.
1987
1988 @param[in] ServiceHandle The handle where network service binding protocols are
1989 installed on.
1990 @param[out] Snp The pointer to store the address of the SNP instance.
1991 This is an optional parameter that may be NULL.
1992
1993 @return The SNP handle, or NULL if not found.
1994
1995 **/
1996 EFI_HANDLE
1997 EFIAPI
1998 NetLibGetSnpHandle (
1999 IN EFI_HANDLE ServiceHandle,
2000 OUT EFI_SIMPLE_NETWORK_PROTOCOL **Snp OPTIONAL
2001 )
2002 {
2003 EFI_STATUS Status;
2004 EFI_SIMPLE_NETWORK_PROTOCOL *SnpInstance;
2005 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2006 EFI_HANDLE SnpHandle;
2007
2008 //
2009 // Try to open SNP from ServiceHandle
2010 //
2011 SnpInstance = NULL;
2012 Status = gBS->HandleProtocol (ServiceHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);
2013 if (!EFI_ERROR (Status)) {
2014 if (Snp != NULL) {
2015 *Snp = SnpInstance;
2016 }
2017 return ServiceHandle;
2018 }
2019
2020 //
2021 // Failed to open SNP, try to get SNP handle by LocateDevicePath()
2022 //
2023 DevicePath = DevicePathFromHandle (ServiceHandle);
2024 if (DevicePath == NULL) {
2025 return NULL;
2026 }
2027
2028 SnpHandle = NULL;
2029 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &DevicePath, &SnpHandle);
2030 if (EFI_ERROR (Status)) {
2031 //
2032 // Failed to find SNP handle
2033 //
2034 return NULL;
2035 }
2036
2037 Status = gBS->HandleProtocol (SnpHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);
2038 if (!EFI_ERROR (Status)) {
2039 if (Snp != NULL) {
2040 *Snp = SnpInstance;
2041 }
2042 return SnpHandle;
2043 }
2044
2045 return NULL;
2046 }
2047
2048 /**
2049 Retrieve VLAN ID of a VLAN device handle.
2050
2051 Search VLAN device path node in Device Path of specified ServiceHandle and
2052 return its VLAN ID. If no VLAN device path node found, then this ServiceHandle
2053 is not a VLAN device handle, and 0 will be returned.
2054
2055 @param[in] ServiceHandle The handle where network service binding protocols are
2056 installed on.
2057
2058 @return VLAN ID of the device handle, or 0 if not a VLAN device.
2059
2060 **/
2061 UINT16
2062 EFIAPI
2063 NetLibGetVlanId (
2064 IN EFI_HANDLE ServiceHandle
2065 )
2066 {
2067 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2068 EFI_DEVICE_PATH_PROTOCOL *Node;
2069
2070 DevicePath = DevicePathFromHandle (ServiceHandle);
2071 if (DevicePath == NULL) {
2072 return 0;
2073 }
2074
2075 Node = DevicePath;
2076 while (!IsDevicePathEnd (Node)) {
2077 if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
2078 return ((VLAN_DEVICE_PATH *) Node)->VlanId;
2079 }
2080 Node = NextDevicePathNode (Node);
2081 }
2082
2083 return 0;
2084 }
2085
2086 /**
2087 Find VLAN device handle with specified VLAN ID.
2088
2089 The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.
2090 This function will append VLAN device path node to the parent device path,
2091 and then use LocateDevicePath() to find the correct VLAN device handle.
2092
2093 @param[in] ControllerHandle The handle where network service binding protocols are
2094 installed on.
2095 @param[in] VlanId The configured VLAN ID for the VLAN device.
2096
2097 @return The VLAN device handle, or NULL if not found.
2098
2099 **/
2100 EFI_HANDLE
2101 EFIAPI
2102 NetLibGetVlanHandle (
2103 IN EFI_HANDLE ControllerHandle,
2104 IN UINT16 VlanId
2105 )
2106 {
2107 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
2108 EFI_DEVICE_PATH_PROTOCOL *VlanDevicePath;
2109 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2110 VLAN_DEVICE_PATH VlanNode;
2111 EFI_HANDLE Handle;
2112
2113 ParentDevicePath = DevicePathFromHandle (ControllerHandle);
2114 if (ParentDevicePath == NULL) {
2115 return NULL;
2116 }
2117
2118 //
2119 // Construct VLAN device path
2120 //
2121 CopyMem (&VlanNode, &mNetVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));
2122 VlanNode.VlanId = VlanId;
2123 VlanDevicePath = AppendDevicePathNode (
2124 ParentDevicePath,
2125 (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode
2126 );
2127 if (VlanDevicePath == NULL) {
2128 return NULL;
2129 }
2130
2131 //
2132 // Find VLAN device handle
2133 //
2134 Handle = NULL;
2135 DevicePath = VlanDevicePath;
2136 gBS->LocateDevicePath (
2137 &gEfiDevicePathProtocolGuid,
2138 &DevicePath,
2139 &Handle
2140 );
2141 if (!IsDevicePathEnd (DevicePath)) {
2142 //
2143 // Device path is not exactly match
2144 //
2145 Handle = NULL;
2146 }
2147
2148 FreePool (VlanDevicePath);
2149 return Handle;
2150 }
2151
2152 /**
2153 Get MAC address associated with the network service handle.
2154
2155 If MacAddress is NULL, then ASSERT().
2156 If AddressSize is NULL, then ASSERT().
2157
2158 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
2159 If SNP is installed on the ServiceHandle or its parent handle, MAC address will
2160 be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.
2161
2162 @param[in] ServiceHandle The handle where network service binding protocols are
2163 installed on.
2164 @param[out] MacAddress The pointer to store the returned MAC address.
2165 @param[out] AddressSize The length of returned MAC address.
2166
2167 @retval EFI_SUCCESS MAC address is returned successfully.
2168 @retval Others Failed to get SNP mode data.
2169
2170 **/
2171 EFI_STATUS
2172 EFIAPI
2173 NetLibGetMacAddress (
2174 IN EFI_HANDLE ServiceHandle,
2175 OUT EFI_MAC_ADDRESS *MacAddress,
2176 OUT UINTN *AddressSize
2177 )
2178 {
2179 EFI_STATUS Status;
2180 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
2181 EFI_SIMPLE_NETWORK_MODE *SnpMode;
2182 EFI_SIMPLE_NETWORK_MODE SnpModeData;
2183 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
2184 EFI_SERVICE_BINDING_PROTOCOL *MnpSb;
2185 EFI_HANDLE *SnpHandle;
2186 EFI_HANDLE MnpChildHandle;
2187
2188 ASSERT (MacAddress != NULL);
2189 ASSERT (AddressSize != NULL);
2190
2191 //
2192 // Try to get SNP handle
2193 //
2194 Snp = NULL;
2195 SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
2196 if (SnpHandle != NULL) {
2197 //
2198 // SNP found, use it directly
2199 //
2200 SnpMode = Snp->Mode;
2201 } else {
2202 //
2203 // Failed to get SNP handle, try to get MAC address from MNP
2204 //
2205 MnpChildHandle = NULL;
2206 Status = gBS->HandleProtocol (
2207 ServiceHandle,
2208 &gEfiManagedNetworkServiceBindingProtocolGuid,
2209 (VOID **) &MnpSb
2210 );
2211 if (EFI_ERROR (Status)) {
2212 return Status;
2213 }
2214
2215 //
2216 // Create a MNP child
2217 //
2218 Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);
2219 if (EFI_ERROR (Status)) {
2220 return Status;
2221 }
2222
2223 //
2224 // Open MNP protocol
2225 //
2226 Status = gBS->HandleProtocol (
2227 MnpChildHandle,
2228 &gEfiManagedNetworkProtocolGuid,
2229 (VOID **) &Mnp
2230 );
2231 if (EFI_ERROR (Status)) {
2232 MnpSb->DestroyChild (MnpSb, MnpChildHandle);
2233 return Status;
2234 }
2235
2236 //
2237 // Try to get SNP mode from MNP
2238 //
2239 Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);
2240 if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
2241 MnpSb->DestroyChild (MnpSb, MnpChildHandle);
2242 return Status;
2243 }
2244 SnpMode = &SnpModeData;
2245
2246 //
2247 // Destroy the MNP child
2248 //
2249 MnpSb->DestroyChild (MnpSb, MnpChildHandle);
2250 }
2251
2252 *AddressSize = SnpMode->HwAddressSize;
2253 CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);
2254
2255 return EFI_SUCCESS;
2256 }
2257
2258 /**
2259 Convert MAC address of the NIC associated with specified Service Binding Handle
2260 to a unicode string. Callers are responsible for freeing the string storage.
2261
2262 If MacString is NULL, then ASSERT().
2263
2264 Locate simple network protocol associated with the Service Binding Handle and
2265 get the mac address from SNP. Then convert the mac address into a unicode
2266 string. It takes 2 unicode characters to represent a 1 byte binary buffer.
2267 Plus one unicode character for the null-terminator.
2268
2269 @param[in] ServiceHandle The handle where network service binding protocol is
2270 installed on.
2271 @param[in] ImageHandle The image handle used to act as the agent handle to
2272 get the simple network protocol. This parameter is
2273 optional and may be NULL.
2274 @param[out] MacString The pointer to store the address of the string
2275 representation of the mac address.
2276
2277 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.
2278 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
2279 @retval Others Failed to open the simple network protocol.
2280
2281 **/
2282 EFI_STATUS
2283 EFIAPI
2284 NetLibGetMacString (
2285 IN EFI_HANDLE ServiceHandle,
2286 IN EFI_HANDLE ImageHandle, OPTIONAL
2287 OUT CHAR16 **MacString
2288 )
2289 {
2290 EFI_STATUS Status;
2291 EFI_MAC_ADDRESS MacAddress;
2292 UINT8 *HwAddress;
2293 UINTN HwAddressSize;
2294 UINT16 VlanId;
2295 CHAR16 *String;
2296 UINTN Index;
2297 UINTN BufferSize;
2298
2299 ASSERT (MacString != NULL);
2300
2301 //
2302 // Get MAC address of the network device
2303 //
2304 Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);
2305 if (EFI_ERROR (Status)) {
2306 return Status;
2307 }
2308
2309 //
2310 // It takes 2 unicode characters to represent a 1 byte binary buffer.
2311 // If VLAN is configured, it will need extra 5 characters like "\0005".
2312 // Plus one unicode character for the null-terminator.
2313 //
2314 BufferSize = (2 * HwAddressSize + 5 + 1) * sizeof (CHAR16);
2315 String = AllocateZeroPool (BufferSize);
2316 if (String == NULL) {
2317 return EFI_OUT_OF_RESOURCES;
2318 }
2319 *MacString = String;
2320
2321 //
2322 // Convert the MAC address into a unicode string.
2323 //
2324 HwAddress = &MacAddress.Addr[0];
2325 for (Index = 0; Index < HwAddressSize; Index++) {
2326 UnicodeValueToStringS (
2327 String,
2328 BufferSize - ((UINTN)String - (UINTN)*MacString),
2329 PREFIX_ZERO | RADIX_HEX,
2330 *(HwAddress++),
2331 2
2332 );
2333 String += StrnLenS (String, (BufferSize - ((UINTN)String - (UINTN)*MacString)) / sizeof (CHAR16));
2334 }
2335
2336 //
2337 // Append VLAN ID if any
2338 //
2339 VlanId = NetLibGetVlanId (ServiceHandle);
2340 if (VlanId != 0) {
2341 *String++ = L'\\';
2342 UnicodeValueToStringS (
2343 String,
2344 BufferSize - ((UINTN)String - (UINTN)*MacString),
2345 PREFIX_ZERO | RADIX_HEX,
2346 VlanId,
2347 4
2348 );
2349 String += StrnLenS (String, (BufferSize - ((UINTN)String - (UINTN)*MacString)) / sizeof (CHAR16));
2350 }
2351
2352 //
2353 // Null terminate the Unicode string
2354 //
2355 *String = L'\0';
2356
2357 return EFI_SUCCESS;
2358 }
2359
2360 /**
2361 Detect media status for specified network device.
2362
2363 If MediaPresent is NULL, then ASSERT().
2364
2365 The underlying UNDI driver may or may not support reporting media status from
2366 GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine
2367 will try to invoke Snp->GetStatus() to get the media status: if media already
2368 present, it return directly; if media not present, it will stop SNP and then
2369 restart SNP to get the latest media status, this give chance to get the correct
2370 media status for old UNDI driver which doesn't support reporting media status
2371 from GET_STATUS command.
2372 Note: there will be two limitations for current algorithm:
2373 1) for UNDI with this capability, in case of cable is not attached, there will
2374 be an redundant Stop/Start() process;
2375 2) for UNDI without this capability, in case that network cable is attached when
2376 Snp->Initialize() is invoked while network cable is unattached later,
2377 NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer
2378 apps to wait for timeout time.
2379
2380 @param[in] ServiceHandle The handle where network service binding protocols are
2381 installed on.
2382 @param[out] MediaPresent The pointer to store the media status.
2383
2384 @retval EFI_SUCCESS Media detection success.
2385 @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.
2386 @retval EFI_UNSUPPORTED Network device does not support media detection.
2387 @retval EFI_DEVICE_ERROR SNP is in unknown state.
2388
2389 **/
2390 EFI_STATUS
2391 EFIAPI
2392 NetLibDetectMedia (
2393 IN EFI_HANDLE ServiceHandle,
2394 OUT BOOLEAN *MediaPresent
2395 )
2396 {
2397 EFI_STATUS Status;
2398 EFI_HANDLE SnpHandle;
2399 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
2400 UINT32 InterruptStatus;
2401 UINT32 OldState;
2402 EFI_MAC_ADDRESS *MCastFilter;
2403 UINT32 MCastFilterCount;
2404 UINT32 EnableFilterBits;
2405 UINT32 DisableFilterBits;
2406 BOOLEAN ResetMCastFilters;
2407
2408 ASSERT (MediaPresent != NULL);
2409
2410 //
2411 // Get SNP handle
2412 //
2413 Snp = NULL;
2414 SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
2415 if (SnpHandle == NULL) {
2416 return EFI_INVALID_PARAMETER;
2417 }
2418
2419 //
2420 // Check whether SNP support media detection
2421 //
2422 if (!Snp->Mode->MediaPresentSupported) {
2423 return EFI_UNSUPPORTED;
2424 }
2425
2426 //
2427 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2428 //
2429 Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);
2430 if (EFI_ERROR (Status)) {
2431 return Status;
2432 }
2433
2434 if (Snp->Mode->MediaPresent) {
2435 //
2436 // Media is present, return directly
2437 //
2438 *MediaPresent = TRUE;
2439 return EFI_SUCCESS;
2440 }
2441
2442 //
2443 // Till now, GetStatus() report no media; while, in case UNDI not support
2444 // reporting media status from GetStatus(), this media status may be incorrect.
2445 // So, we will stop SNP and then restart it to get the correct media status.
2446 //
2447 OldState = Snp->Mode->State;
2448 if (OldState >= EfiSimpleNetworkMaxState) {
2449 return EFI_DEVICE_ERROR;
2450 }
2451
2452 MCastFilter = NULL;
2453
2454 if (OldState == EfiSimpleNetworkInitialized) {
2455 //
2456 // SNP is already in use, need Shutdown/Stop and then Start/Initialize
2457 //
2458
2459 //
2460 // Backup current SNP receive filter settings
2461 //
2462 EnableFilterBits = Snp->Mode->ReceiveFilterSetting;
2463 DisableFilterBits = Snp->Mode->ReceiveFilterMask ^ EnableFilterBits;
2464
2465 ResetMCastFilters = TRUE;
2466 MCastFilterCount = Snp->Mode->MCastFilterCount;
2467 if (MCastFilterCount != 0) {
2468 MCastFilter = AllocateCopyPool (
2469 MCastFilterCount * sizeof (EFI_MAC_ADDRESS),
2470 Snp->Mode->MCastFilter
2471 );
2472 ASSERT (MCastFilter != NULL);
2473 if (MCastFilter == NULL) {
2474 Status = EFI_OUT_OF_RESOURCES;
2475 goto Exit;
2476 }
2477
2478 ResetMCastFilters = FALSE;
2479 }
2480
2481 //
2482 // Shutdown/Stop the simple network
2483 //
2484 Status = Snp->Shutdown (Snp);
2485 if (!EFI_ERROR (Status)) {
2486 Status = Snp->Stop (Snp);
2487 }
2488 if (EFI_ERROR (Status)) {
2489 goto Exit;
2490 }
2491
2492 //
2493 // Start/Initialize the simple network
2494 //
2495 Status = Snp->Start (Snp);
2496 if (!EFI_ERROR (Status)) {
2497 Status = Snp->Initialize (Snp, 0, 0);
2498 }
2499 if (EFI_ERROR (Status)) {
2500 goto Exit;
2501 }
2502
2503 //
2504 // Here we get the correct media status
2505 //
2506 *MediaPresent = Snp->Mode->MediaPresent;
2507
2508 //
2509 // Restore SNP receive filter settings
2510 //
2511 Status = Snp->ReceiveFilters (
2512 Snp,
2513 EnableFilterBits,
2514 DisableFilterBits,
2515 ResetMCastFilters,
2516 MCastFilterCount,
2517 MCastFilter
2518 );
2519
2520 if (MCastFilter != NULL) {
2521 FreePool (MCastFilter);
2522 }
2523
2524 return Status;
2525 }
2526
2527 //
2528 // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted
2529 //
2530 if (OldState == EfiSimpleNetworkStopped) {
2531 //
2532 // SNP not start yet, start it
2533 //
2534 Status = Snp->Start (Snp);
2535 if (EFI_ERROR (Status)) {
2536 goto Exit;
2537 }
2538 }
2539
2540 //
2541 // Initialize the simple network
2542 //
2543 Status = Snp->Initialize (Snp, 0, 0);
2544 if (EFI_ERROR (Status)) {
2545 Status = EFI_DEVICE_ERROR;
2546 goto Exit;
2547 }
2548
2549 //
2550 // Here we get the correct media status
2551 //
2552 *MediaPresent = Snp->Mode->MediaPresent;
2553
2554 //
2555 // Shut down the simple network
2556 //
2557 Snp->Shutdown (Snp);
2558
2559 Exit:
2560 if (OldState == EfiSimpleNetworkStopped) {
2561 //
2562 // Original SNP sate is Stopped, restore to original state
2563 //
2564 Snp->Stop (Snp);
2565 }
2566
2567 if (MCastFilter != NULL) {
2568 FreePool (MCastFilter);
2569 }
2570
2571 return Status;
2572 }
2573
2574 /**
2575
2576 Detect media state for a network device. This routine will wait for a period of time at
2577 a specified checking interval when a certain network is under connecting until connection
2578 process finishs or timeout. If Aip protocol is supported by low layer drivers, three kinds
2579 of media states can be detected: EFI_SUCCESS, EFI_NOT_READY and EFI_NO_MEDIA, represents
2580 connected state, connecting state and no media state respectively. When function detects
2581 the current state is EFI_NOT_READY, it will loop to wait for next time's check until state
2582 turns to be EFI_SUCCESS or EFI_NO_MEDIA. If Aip protocol is not supported, function will
2583 call NetLibDetectMedia() and return state directly.
2584
2585 @param[in] ServiceHandle The handle where network service binding protocols are
2586 installed on.
2587 @param[in] Timeout The maximum number of 100ns units to wait when network
2588 is connecting. Zero value means detect once and return
2589 immediately.
2590 @param[out] MediaState The pointer to the detected media state.
2591
2592 @retval EFI_SUCCESS Media detection success.
2593 @retval EFI_INVALID_PARAMETER ServiceHandle is not a valid network device handle or
2594 MediaState pointer is NULL.
2595 @retval EFI_DEVICE_ERROR A device error occurred.
2596 @retval EFI_TIMEOUT Network is connecting but timeout.
2597
2598 **/
2599 EFI_STATUS
2600 EFIAPI
2601 NetLibDetectMediaWaitTimeout (
2602 IN EFI_HANDLE ServiceHandle,
2603 IN UINT64 Timeout,
2604 OUT EFI_STATUS *MediaState
2605 )
2606 {
2607 EFI_STATUS Status;
2608 EFI_HANDLE SnpHandle;
2609 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
2610 EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
2611 EFI_ADAPTER_INFO_MEDIA_STATE *MediaInfo;
2612 BOOLEAN MediaPresent;
2613 UINTN DataSize;
2614 EFI_STATUS TimerStatus;
2615 EFI_EVENT Timer;
2616 UINT64 TimeRemained;
2617
2618 if (MediaState == NULL) {
2619 return EFI_INVALID_PARAMETER;
2620 }
2621 *MediaState = EFI_SUCCESS;
2622 MediaInfo = NULL;
2623
2624 //
2625 // Get SNP handle
2626 //
2627 Snp = NULL;
2628 SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
2629 if (SnpHandle == NULL) {
2630 return EFI_INVALID_PARAMETER;
2631 }
2632
2633 Status = gBS->HandleProtocol (
2634 SnpHandle,
2635 &gEfiAdapterInformationProtocolGuid,
2636 (VOID *) &Aip
2637 );
2638 if (EFI_ERROR (Status)) {
2639
2640 MediaPresent = TRUE;
2641 Status = NetLibDetectMedia (ServiceHandle, &MediaPresent);
2642 if (!EFI_ERROR (Status)) {
2643 if (MediaPresent) {
2644 *MediaState = EFI_SUCCESS;
2645 } else {
2646 *MediaState = EFI_NO_MEDIA;
2647 }
2648 }
2649
2650 //
2651 // NetLibDetectMedia doesn't support EFI_NOT_READY status, return now!
2652 //
2653 return Status;
2654 }
2655
2656 Status = Aip->GetInformation (
2657 Aip,
2658 &gEfiAdapterInfoMediaStateGuid,
2659 (VOID **) &MediaInfo,
2660 &DataSize
2661 );
2662 if (!EFI_ERROR (Status)) {
2663
2664 *MediaState = MediaInfo->MediaState;
2665 FreePool (MediaInfo);
2666 if (*MediaState != EFI_NOT_READY || Timeout < MEDIA_STATE_DETECT_TIME_INTERVAL) {
2667
2668 return EFI_SUCCESS;
2669 }
2670 } else {
2671
2672 if (MediaInfo != NULL) {
2673 FreePool (MediaInfo);
2674 }
2675
2676 if (Status == EFI_UNSUPPORTED) {
2677
2678 //
2679 // If gEfiAdapterInfoMediaStateGuid is not supported, call NetLibDetectMedia to get media state!
2680 //
2681 MediaPresent = TRUE;
2682 Status = NetLibDetectMedia (ServiceHandle, &MediaPresent);
2683 if (!EFI_ERROR (Status)) {
2684 if (MediaPresent) {
2685 *MediaState = EFI_SUCCESS;
2686 } else {
2687 *MediaState = EFI_NO_MEDIA;
2688 }
2689 }
2690 return Status;
2691 }
2692
2693 return Status;
2694 }
2695
2696 //
2697 // Loop to check media state
2698 //
2699
2700 Timer = NULL;
2701 TimeRemained = Timeout;
2702 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
2703 if (EFI_ERROR (Status)) {
2704 return EFI_DEVICE_ERROR;
2705 }
2706
2707 do {
2708 Status = gBS->SetTimer (
2709 Timer,
2710 TimerRelative,
2711 MEDIA_STATE_DETECT_TIME_INTERVAL
2712 );
2713 if (EFI_ERROR (Status)) {
2714 gBS->CloseEvent(Timer);
2715 return EFI_DEVICE_ERROR;
2716 }
2717
2718 do {
2719 TimerStatus = gBS->CheckEvent (Timer);
2720 if (!EFI_ERROR (TimerStatus)) {
2721
2722 TimeRemained -= MEDIA_STATE_DETECT_TIME_INTERVAL;
2723 Status = Aip->GetInformation (
2724 Aip,
2725 &gEfiAdapterInfoMediaStateGuid,
2726 (VOID **) &MediaInfo,
2727 &DataSize
2728 );
2729 if (!EFI_ERROR (Status)) {
2730
2731 *MediaState = MediaInfo->MediaState;
2732 FreePool (MediaInfo);
2733 } else {
2734
2735 if (MediaInfo != NULL) {
2736 FreePool (MediaInfo);
2737 }
2738 gBS->CloseEvent(Timer);
2739 return Status;
2740 }
2741 }
2742 } while (TimerStatus == EFI_NOT_READY);
2743 } while (*MediaState == EFI_NOT_READY && TimeRemained >= MEDIA_STATE_DETECT_TIME_INTERVAL);
2744
2745 gBS->CloseEvent(Timer);
2746 if (*MediaState == EFI_NOT_READY && TimeRemained < MEDIA_STATE_DETECT_TIME_INTERVAL) {
2747 return EFI_TIMEOUT;
2748 } else {
2749 return EFI_SUCCESS;
2750 }
2751 }
2752
2753 /**
2754 Check the default address used by the IPv4 driver is static or dynamic (acquired
2755 from DHCP).
2756
2757 If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the
2758 default address is static. If failed to get the policy from Ip4 Config2 Protocol,
2759 the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.
2760
2761 @param[in] Controller The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL
2762 relative with the default address to judge.
2763
2764 @retval TRUE If the default address is static.
2765 @retval FALSE If the default address is acquired from DHCP.
2766
2767 **/
2768 BOOLEAN
2769 NetLibDefaultAddressIsStatic (
2770 IN EFI_HANDLE Controller
2771 )
2772 {
2773 EFI_STATUS Status;
2774 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
2775 UINTN DataSize;
2776 EFI_IP4_CONFIG2_POLICY Policy;
2777 BOOLEAN IsStatic;
2778
2779 Ip4Config2 = NULL;
2780
2781 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
2782
2783 IsStatic = TRUE;
2784
2785 //
2786 // Get Ip4Config2 policy.
2787 //
2788 Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
2789 if (EFI_ERROR (Status)) {
2790 goto ON_EXIT;
2791 }
2792
2793 Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypePolicy, &DataSize, &Policy);
2794 if (EFI_ERROR (Status)) {
2795 goto ON_EXIT;
2796 }
2797
2798 IsStatic = (BOOLEAN) (Policy == Ip4Config2PolicyStatic);
2799
2800 ON_EXIT:
2801
2802 return IsStatic;
2803 }
2804
2805 /**
2806 Create an IPv4 device path node.
2807
2808 If Node is NULL, then ASSERT().
2809
2810 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
2811 The header subtype of IPv4 device path node is MSG_IPv4_DP.
2812 Get other info from parameters to make up the whole IPv4 device path node.
2813
2814 @param[in, out] Node Pointer to the IPv4 device path node.
2815 @param[in] Controller The controller handle.
2816 @param[in] LocalIp The local IPv4 address.
2817 @param[in] LocalPort The local port.
2818 @param[in] RemoteIp The remote IPv4 address.
2819 @param[in] RemotePort The remote port.
2820 @param[in] Protocol The protocol type in the IP header.
2821 @param[in] UseDefaultAddress Whether this instance is using default address or not.
2822
2823 **/
2824 VOID
2825 EFIAPI
2826 NetLibCreateIPv4DPathNode (
2827 IN OUT IPv4_DEVICE_PATH *Node,
2828 IN EFI_HANDLE Controller,
2829 IN IP4_ADDR LocalIp,
2830 IN UINT16 LocalPort,
2831 IN IP4_ADDR RemoteIp,
2832 IN UINT16 RemotePort,
2833 IN UINT16 Protocol,
2834 IN BOOLEAN UseDefaultAddress
2835 )
2836 {
2837 ASSERT (Node != NULL);
2838
2839 Node->Header.Type = MESSAGING_DEVICE_PATH;
2840 Node->Header.SubType = MSG_IPv4_DP;
2841 SetDevicePathNodeLength (&Node->Header, sizeof (IPv4_DEVICE_PATH));
2842
2843 CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));
2844 CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));
2845
2846 Node->LocalPort = LocalPort;
2847 Node->RemotePort = RemotePort;
2848
2849 Node->Protocol = Protocol;
2850
2851 if (!UseDefaultAddress) {
2852 Node->StaticIpAddress = TRUE;
2853 } else {
2854 Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);
2855 }
2856
2857 //
2858 // Set the Gateway IP address to default value 0:0:0:0.
2859 // Set the Subnet mask to default value 255:255:255:0.
2860 //
2861 ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
2862 SetMem (&Node->SubnetMask, sizeof (EFI_IPv4_ADDRESS), 0xff);
2863 Node->SubnetMask.Addr[3] = 0;
2864 }
2865
2866 /**
2867 Create an IPv6 device path node.
2868
2869 If Node is NULL, then ASSERT().
2870 If LocalIp is NULL, then ASSERT().
2871 If RemoteIp is NULL, then ASSERT().
2872
2873 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
2874 The header subtype of IPv6 device path node is MSG_IPv6_DP.
2875 Get other info from parameters to make up the whole IPv6 device path node.
2876
2877 @param[in, out] Node Pointer to the IPv6 device path node.
2878 @param[in] Controller The controller handle.
2879 @param[in] LocalIp The local IPv6 address.
2880 @param[in] LocalPort The local port.
2881 @param[in] RemoteIp The remote IPv6 address.
2882 @param[in] RemotePort The remote port.
2883 @param[in] Protocol The protocol type in the IP header.
2884
2885 **/
2886 VOID
2887 EFIAPI
2888 NetLibCreateIPv6DPathNode (
2889 IN OUT IPv6_DEVICE_PATH *Node,
2890 IN EFI_HANDLE Controller,
2891 IN EFI_IPv6_ADDRESS *LocalIp,
2892 IN UINT16 LocalPort,
2893 IN EFI_IPv6_ADDRESS *RemoteIp,
2894 IN UINT16 RemotePort,
2895 IN UINT16 Protocol
2896 )
2897 {
2898 ASSERT (Node != NULL && LocalIp != NULL && RemoteIp != NULL);
2899
2900 Node->Header.Type = MESSAGING_DEVICE_PATH;
2901 Node->Header.SubType = MSG_IPv6_DP;
2902 SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));
2903
2904 CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));
2905 CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));
2906
2907 Node->LocalPort = LocalPort;
2908 Node->RemotePort = RemotePort;
2909
2910 Node->Protocol = Protocol;
2911
2912 //
2913 // Set default value to IPAddressOrigin, PrefixLength.
2914 // Set the Gateway IP address to unspecified address.
2915 //
2916 Node->IpAddressOrigin = 0;
2917 Node->PrefixLength = IP6_PREFIX_LENGTH;
2918 ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
2919 }
2920
2921 /**
2922 Find the UNDI/SNP handle from controller and protocol GUID.
2923
2924 If ProtocolGuid is NULL, then ASSERT().
2925
2926 For example, IP will open a MNP child to transmit/receive
2927 packets, when MNP is stopped, IP should also be stopped. IP
2928 needs to find its own private data which is related the IP's
2929 service binding instance that is install on UNDI/SNP handle.
2930 Now, the controller is either a MNP or ARP child handle. But
2931 IP opens these handle BY_DRIVER, use that info, we can get the
2932 UNDI/SNP handle.
2933
2934 @param[in] Controller Then protocol handle to check.
2935 @param[in] ProtocolGuid The protocol that is related with the handle.
2936
2937 @return The UNDI/SNP handle or NULL for errors.
2938
2939 **/
2940 EFI_HANDLE
2941 EFIAPI
2942 NetLibGetNicHandle (
2943 IN EFI_HANDLE Controller,
2944 IN EFI_GUID *ProtocolGuid
2945 )
2946 {
2947 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;
2948 EFI_HANDLE Handle;
2949 EFI_STATUS Status;
2950 UINTN OpenCount;
2951 UINTN Index;
2952
2953 ASSERT (ProtocolGuid != NULL);
2954
2955 Status = gBS->OpenProtocolInformation (
2956 Controller,
2957 ProtocolGuid,
2958 &OpenBuffer,
2959 &OpenCount
2960 );
2961
2962 if (EFI_ERROR (Status)) {
2963 return NULL;
2964 }
2965
2966 Handle = NULL;
2967
2968 for (Index = 0; Index < OpenCount; Index++) {
2969 if ((OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
2970 Handle = OpenBuffer[Index].ControllerHandle;
2971 break;
2972 }
2973 }
2974
2975 gBS->FreePool (OpenBuffer);
2976 return Handle;
2977 }
2978
2979 /**
2980 Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.
2981
2982 @param[in] String The pointer to the Ascii string.
2983 @param[out] Ip4Address The pointer to the converted IPv4 address.
2984
2985 @retval EFI_SUCCESS Convert to IPv4 address successfully.
2986 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
2987
2988 **/
2989 EFI_STATUS
2990 EFIAPI
2991 NetLibAsciiStrToIp4 (
2992 IN CONST CHAR8 *String,
2993 OUT EFI_IPv4_ADDRESS *Ip4Address
2994 )
2995 {
2996 RETURN_STATUS Status;
2997 CHAR8 *EndPointer;
2998
2999 Status = AsciiStrToIpv4Address (String, &EndPointer, Ip4Address, NULL);
3000 if (RETURN_ERROR (Status) || (*EndPointer != '\0')) {
3001 return EFI_INVALID_PARAMETER;
3002 } else {
3003 return EFI_SUCCESS;
3004 }
3005 }
3006
3007
3008 /**
3009 Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the
3010 string is defined in RFC 4291 - Text Representation of Addresses.
3011
3012 @param[in] String The pointer to the Ascii string.
3013 @param[out] Ip6Address The pointer to the converted IPv6 address.
3014
3015 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3016 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3017
3018 **/
3019 EFI_STATUS
3020 EFIAPI
3021 NetLibAsciiStrToIp6 (
3022 IN CONST CHAR8 *String,
3023 OUT EFI_IPv6_ADDRESS *Ip6Address
3024 )
3025 {
3026 RETURN_STATUS Status;
3027 CHAR8 *EndPointer;
3028
3029 Status = AsciiStrToIpv6Address (String, &EndPointer, Ip6Address, NULL);
3030 if (RETURN_ERROR (Status) || (*EndPointer != '\0')) {
3031 return EFI_INVALID_PARAMETER;
3032 } else {
3033 return EFI_SUCCESS;
3034 }
3035 }
3036
3037
3038 /**
3039 Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.
3040
3041 @param[in] String The pointer to the Ascii string.
3042 @param[out] Ip4Address The pointer to the converted IPv4 address.
3043
3044 @retval EFI_SUCCESS Convert to IPv4 address successfully.
3045 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
3046
3047 **/
3048 EFI_STATUS
3049 EFIAPI
3050 NetLibStrToIp4 (
3051 IN CONST CHAR16 *String,
3052 OUT EFI_IPv4_ADDRESS *Ip4Address
3053 )
3054 {
3055 RETURN_STATUS Status;
3056 CHAR16 *EndPointer;
3057
3058 Status = StrToIpv4Address (String, &EndPointer, Ip4Address, NULL);
3059 if (RETURN_ERROR (Status) || (*EndPointer != L'\0')) {
3060 return EFI_INVALID_PARAMETER;
3061 } else {
3062 return EFI_SUCCESS;
3063 }
3064 }
3065
3066
3067 /**
3068 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS. The format of
3069 the string is defined in RFC 4291 - Text Representation of Addresses.
3070
3071 @param[in] String The pointer to the Ascii string.
3072 @param[out] Ip6Address The pointer to the converted IPv6 address.
3073
3074 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3075 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3076
3077 **/
3078 EFI_STATUS
3079 EFIAPI
3080 NetLibStrToIp6 (
3081 IN CONST CHAR16 *String,
3082 OUT EFI_IPv6_ADDRESS *Ip6Address
3083 )
3084 {
3085 RETURN_STATUS Status;
3086 CHAR16 *EndPointer;
3087
3088 Status = StrToIpv6Address (String, &EndPointer, Ip6Address, NULL);
3089 if (RETURN_ERROR (Status) || (*EndPointer != L'\0')) {
3090 return EFI_INVALID_PARAMETER;
3091 } else {
3092 return EFI_SUCCESS;
3093 }
3094 }
3095
3096 /**
3097 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.
3098 The format of the string is defined in RFC 4291 - Text Representation of Addresses
3099 Prefixes: ipv6-address/prefix-length.
3100
3101 @param[in] String The pointer to the Ascii string.
3102 @param[out] Ip6Address The pointer to the converted IPv6 address.
3103 @param[out] PrefixLength The pointer to the converted prefix length.
3104
3105 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3106 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3107
3108 **/
3109 EFI_STATUS
3110 EFIAPI
3111 NetLibStrToIp6andPrefix (
3112 IN CONST CHAR16 *String,
3113 OUT EFI_IPv6_ADDRESS *Ip6Address,
3114 OUT UINT8 *PrefixLength
3115 )
3116 {
3117 RETURN_STATUS Status;
3118 CHAR16 *EndPointer;
3119
3120 Status = StrToIpv6Address (String, &EndPointer, Ip6Address, PrefixLength);
3121 if (RETURN_ERROR (Status) || (*EndPointer != L'\0')) {
3122 return EFI_INVALID_PARAMETER;
3123 } else {
3124 return EFI_SUCCESS;
3125 }
3126 }
3127
3128 /**
3129
3130 Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.
3131 The text representation of address is defined in RFC 4291.
3132
3133 @param[in] Ip6Address The pointer to the IPv6 address.
3134 @param[out] String The buffer to return the converted string.
3135 @param[in] StringSize The length in bytes of the input String.
3136
3137 @retval EFI_SUCCESS Convert to string successfully.
3138 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
3139 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been
3140 updated with the size needed to complete the request.
3141 **/
3142 EFI_STATUS
3143 EFIAPI
3144 NetLibIp6ToStr (
3145 IN EFI_IPv6_ADDRESS *Ip6Address,
3146 OUT CHAR16 *String,
3147 IN UINTN StringSize
3148 )
3149 {
3150 UINT16 Ip6Addr[8];
3151 UINTN Index;
3152 UINTN LongestZerosStart;
3153 UINTN LongestZerosLength;
3154 UINTN CurrentZerosStart;
3155 UINTN CurrentZerosLength;
3156 CHAR16 Buffer[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
3157 CHAR16 *Ptr;
3158
3159 if (Ip6Address == NULL || String == NULL || StringSize == 0) {
3160 return EFI_INVALID_PARAMETER;
3161 }
3162
3163 //
3164 // Convert the UINT8 array to an UINT16 array for easy handling.
3165 //
3166 ZeroMem (Ip6Addr, sizeof (Ip6Addr));
3167 for (Index = 0; Index < 16; Index++) {
3168 Ip6Addr[Index / 2] |= (Ip6Address->Addr[Index] << ((1 - (Index % 2)) << 3));
3169 }
3170
3171 //
3172 // Find the longest zeros and mark it.
3173 //
3174 CurrentZerosStart = DEFAULT_ZERO_START;
3175 CurrentZerosLength = 0;
3176 LongestZerosStart = DEFAULT_ZERO_START;
3177 LongestZerosLength = 0;
3178 for (Index = 0; Index < 8; Index++) {
3179 if (Ip6Addr[Index] == 0) {
3180 if (CurrentZerosStart == DEFAULT_ZERO_START) {
3181 CurrentZerosStart = Index;
3182 CurrentZerosLength = 1;
3183 } else {
3184 CurrentZerosLength++;
3185 }
3186 } else {
3187 if (CurrentZerosStart != DEFAULT_ZERO_START) {
3188 if (CurrentZerosLength > 2 && (LongestZerosStart == (DEFAULT_ZERO_START) || CurrentZerosLength > LongestZerosLength)) {
3189 LongestZerosStart = CurrentZerosStart;
3190 LongestZerosLength = CurrentZerosLength;
3191 }
3192 CurrentZerosStart = DEFAULT_ZERO_START;
3193 CurrentZerosLength = 0;
3194 }
3195 }
3196 }
3197
3198 if (CurrentZerosStart != DEFAULT_ZERO_START && CurrentZerosLength > 2) {
3199 if (LongestZerosStart == DEFAULT_ZERO_START || LongestZerosLength < CurrentZerosLength) {
3200 LongestZerosStart = CurrentZerosStart;
3201 LongestZerosLength = CurrentZerosLength;
3202 }
3203 }
3204
3205 Ptr = Buffer;
3206 for (Index = 0; Index < 8; Index++) {
3207 if (LongestZerosStart != DEFAULT_ZERO_START && Index >= LongestZerosStart && Index < LongestZerosStart + LongestZerosLength) {
3208 if (Index == LongestZerosStart) {
3209 *Ptr++ = L':';
3210 }
3211 continue;
3212 }
3213 if (Index != 0) {
3214 *Ptr++ = L':';
3215 }
3216 Ptr += UnicodeSPrint(Ptr, 10, L"%x", Ip6Addr[Index]);
3217 }
3218
3219 if (LongestZerosStart != DEFAULT_ZERO_START && LongestZerosStart + LongestZerosLength == 8) {
3220 *Ptr++ = L':';
3221 }
3222 *Ptr = L'\0';
3223
3224 if ((UINTN)Ptr - (UINTN)Buffer > StringSize) {
3225 return EFI_BUFFER_TOO_SMALL;
3226 }
3227
3228 StrCpyS (String, StringSize / sizeof (CHAR16), Buffer);
3229
3230 return EFI_SUCCESS;
3231 }
3232
3233 /**
3234 This function obtains the system guid from the smbios table.
3235
3236 If SystemGuid is NULL, then ASSERT().
3237
3238 @param[out] SystemGuid The pointer of the returned system guid.
3239
3240 @retval EFI_SUCCESS Successfully obtained the system guid.
3241 @retval EFI_NOT_FOUND Did not find the SMBIOS table.
3242
3243 **/
3244 EFI_STATUS
3245 EFIAPI
3246 NetLibGetSystemGuid (
3247 OUT EFI_GUID *SystemGuid
3248 )
3249 {
3250 EFI_STATUS Status;
3251 SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;
3252 SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30Table;
3253 SMBIOS_STRUCTURE_POINTER Smbios;
3254 SMBIOS_STRUCTURE_POINTER SmbiosEnd;
3255 CHAR8 *String;
3256
3257 ASSERT (SystemGuid != NULL);
3258
3259 SmbiosTable = NULL;
3260 Status = EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID **) &Smbios30Table);
3261 if (!(EFI_ERROR (Status) || Smbios30Table == NULL)) {
3262 Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) Smbios30Table->TableAddress;
3263 SmbiosEnd.Raw = (UINT8 *) (UINTN) (Smbios30Table->TableAddress + Smbios30Table->TableMaximumSize);
3264 } else {
3265 Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);
3266 if (EFI_ERROR (Status) || SmbiosTable == NULL) {
3267 return EFI_NOT_FOUND;
3268 }
3269 Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;
3270 SmbiosEnd.Raw = (UINT8 *) ((UINTN) SmbiosTable->TableAddress + SmbiosTable->TableLength);
3271 }
3272
3273 do {
3274 if (Smbios.Hdr->Type == 1) {
3275 if (Smbios.Hdr->Length < 0x19) {
3276 //
3277 // Older version did not support UUID.
3278 //
3279 return EFI_NOT_FOUND;
3280 }
3281
3282 //
3283 // SMBIOS tables are byte packed so we need to do a byte copy to
3284 // prevend alignment faults on Itanium-based platform.
3285 //
3286 CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));
3287 return EFI_SUCCESS;
3288 }
3289
3290 //
3291 // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
3292 // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
3293 // to skip one SMBIOS structure.
3294 //
3295
3296 //
3297 // Step 1: Skip over formatted section.
3298 //
3299 String = (CHAR8 *) (Smbios.Raw + Smbios.Hdr->Length);
3300
3301 //
3302 // Step 2: Skip over unformated string section.
3303 //
3304 do {
3305 //
3306 // Each string is terminated with a NULL(00h) BYTE and the sets of strings
3307 // is terminated with an additional NULL(00h) BYTE.
3308 //
3309 for ( ; *String != 0; String++) {
3310 }
3311
3312 if (*(UINT8*)++String == 0) {
3313 //
3314 // Pointer to the next SMBIOS structure.
3315 //
3316 Smbios.Raw = (UINT8 *)++String;
3317 break;
3318 }
3319 } while (TRUE);
3320 } while (Smbios.Raw < SmbiosEnd.Raw);
3321 return EFI_NOT_FOUND;
3322 }
3323
3324 /**
3325 Create Dns QName according the queried domain name.
3326
3327 If DomainName is NULL, then ASSERT().
3328
3329 QName is a domain name represented as a sequence of labels,
3330 where each label consists of a length octet followed by that
3331 number of octets. The QName terminates with the zero
3332 length octet for the null label of the root. Caller should
3333 take responsibility to free the buffer in returned pointer.
3334
3335 @param DomainName The pointer to the queried domain name string.
3336
3337 @retval NULL Failed to fill QName.
3338 @return QName filled successfully.
3339
3340 **/
3341 CHAR8 *
3342 EFIAPI
3343 NetLibCreateDnsQName (
3344 IN CHAR16 *DomainName
3345 )
3346 {
3347 CHAR8 *QueryName;
3348 UINTN QueryNameSize;
3349 CHAR8 *Header;
3350 CHAR8 *Tail;
3351 UINTN Len;
3352 UINTN Index;
3353
3354 ASSERT (DomainName != NULL);
3355
3356 QueryName = NULL;
3357 QueryNameSize = 0;
3358 Header = NULL;
3359 Tail = NULL;
3360
3361 //
3362 // One byte for first label length, one byte for terminated length zero.
3363 //
3364 QueryNameSize = StrLen (DomainName) + 2;
3365
3366 if (QueryNameSize > DNS_MAX_NAME_SIZE) {
3367 return NULL;
3368 }
3369
3370 QueryName = AllocateZeroPool (QueryNameSize);
3371 if (QueryName == NULL) {
3372 return NULL;
3373 }
3374
3375 Header = QueryName;
3376 Tail = Header + 1;
3377 Len = 0;
3378 for (Index = 0; DomainName[Index] != 0; Index++) {
3379 *Tail = (CHAR8) DomainName[Index];
3380 if (*Tail == '.') {
3381 *Header = (CHAR8) Len;
3382 Header = Tail;
3383 Tail ++;
3384 Len = 0;
3385 } else {
3386 Tail++;
3387 Len++;
3388 }
3389 }
3390 *Header = (CHAR8) Len;
3391 *Tail = 0;
3392
3393 return QueryName;
3394 }