]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
[Change summary]:
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / DxeNetLib.c
1 /** @file
2 Network library.
3
4 Copyright (c) 2005 - 2009, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13
14 #include <Uefi.h>
15
16 #include <Protocol/DriverBinding.h>
17 #include <Protocol/ServiceBinding.h>
18 #include <Protocol/SimpleNetwork.h>
19 #include <Protocol/HiiConfigRouting.h>
20 #include <Protocol/ComponentName.h>
21 #include <Protocol/ComponentName2.h>
22
23 #include <Guid/NicIp4ConfigNvData.h>
24
25 #include <Library/NetLib.h>
26 #include <Library/BaseLib.h>
27 #include <Library/DebugLib.h>
28 #include <Library/BaseMemoryLib.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Library/UefiRuntimeServicesTableLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/DevicePathLib.h>
33 #include <Library/HiiLib.h>
34 #include <Library/PrintLib.h>
35
36 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mNetLibHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
37
38 #define NIC_ITEM_CONFIG_SIZE sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE
39
40 //
41 // All the supported IP4 maskes in host byte order.
42 //
43 IP4_ADDR gIp4AllMasks[IP4_MASK_NUM] = {
44 0x00000000,
45 0x80000000,
46 0xC0000000,
47 0xE0000000,
48 0xF0000000,
49 0xF8000000,
50 0xFC000000,
51 0xFE000000,
52
53 0xFF000000,
54 0xFF800000,
55 0xFFC00000,
56 0xFFE00000,
57 0xFFF00000,
58 0xFFF80000,
59 0xFFFC0000,
60 0xFFFE0000,
61
62 0xFFFF0000,
63 0xFFFF8000,
64 0xFFFFC000,
65 0xFFFFE000,
66 0xFFFFF000,
67 0xFFFFF800,
68 0xFFFFFC00,
69 0xFFFFFE00,
70
71 0xFFFFFF00,
72 0xFFFFFF80,
73 0xFFFFFFC0,
74 0xFFFFFFE0,
75 0xFFFFFFF0,
76 0xFFFFFFF8,
77 0xFFFFFFFC,
78 0xFFFFFFFE,
79 0xFFFFFFFF,
80 };
81
82 EFI_IPv4_ADDRESS mZeroIp4Addr = {{0, 0, 0, 0}};
83
84 //
85 // Any error level digitally larger than mNetDebugLevelMax
86 // will be silently discarded.
87 //
88 UINTN mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;
89 UINT32 mSyslogPacketSeq = 0xDEADBEEF;
90
91 //
92 // You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
93 // here to direct the syslog packets to the syslog deamon. The
94 // default is broadcast to both the ethernet and IP.
95 //
96 UINT8 mSyslogDstMac[NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
97 UINT32 mSyslogDstIp = 0xffffffff;
98 UINT32 mSyslogSrcIp = 0;
99
100 CHAR8 *
101 mMonthName[] = {
102 "Jan",
103 "Feb",
104 "Mar",
105 "Apr",
106 "May",
107 "Jun",
108 "Jul",
109 "Aug",
110 "Sep",
111 "Oct",
112 "Nov",
113 "Dec"
114 };
115
116 /**
117 Locate the handles that support SNP, then open one of them
118 to send the syslog packets. The caller isn't required to close
119 the SNP after use because the SNP is opened by HandleProtocol.
120
121 @return The point to SNP if one is properly openned. Otherwise NULL
122
123 **/
124 EFI_SIMPLE_NETWORK_PROTOCOL *
125 SyslogLocateSnp (
126 VOID
127 )
128 {
129 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
130 EFI_STATUS Status;
131 EFI_HANDLE *Handles;
132 UINTN HandleCount;
133 UINTN Index;
134
135 //
136 // Locate the handles which has SNP installed.
137 //
138 Handles = NULL;
139 Status = gBS->LocateHandleBuffer (
140 ByProtocol,
141 &gEfiSimpleNetworkProtocolGuid,
142 NULL,
143 &HandleCount,
144 &Handles
145 );
146
147 if (EFI_ERROR (Status) || (HandleCount == 0)) {
148 return NULL;
149 }
150
151 //
152 // Try to open one of the ethernet SNP protocol to send packet
153 //
154 Snp = NULL;
155
156 for (Index = 0; Index < HandleCount; Index++) {
157 Status = gBS->HandleProtocol (
158 Handles[Index],
159 &gEfiSimpleNetworkProtocolGuid,
160 (VOID **) &Snp
161 );
162
163 if ((Status == EFI_SUCCESS) && (Snp != NULL) &&
164 (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&
165 (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {
166
167 break;
168 }
169
170 Snp = NULL;
171 }
172
173 FreePool (Handles);
174 return Snp;
175 }
176
177 /**
178 Transmit a syslog packet synchronously through SNP. The Packet
179 already has the ethernet header prepended. This function should
180 fill in the source MAC because it will try to locate a SNP each
181 time it is called to avoid the problem if SNP is unloaded.
182 This code snip is copied from MNP.
183
184 @param[in] Packet - The Syslog packet
185 @param[in] Length - The length of the packet
186
187 @retval EFI_DEVICE_ERROR - Failed to locate a usable SNP protocol
188 @retval EFI_TIMEOUT - Timeout happened to send the packet.
189 @retval EFI_SUCCESS - Packet is sent.
190
191 **/
192 EFI_STATUS
193 SyslogSendPacket (
194 IN CHAR8 *Packet,
195 IN UINT32 Length
196 )
197 {
198 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
199 ETHER_HEAD *Ether;
200 EFI_STATUS Status;
201 EFI_EVENT TimeoutEvent;
202 UINT8 *TxBuf;
203
204 Snp = SyslogLocateSnp ();
205
206 if (Snp == NULL) {
207 return EFI_DEVICE_ERROR;
208 }
209
210 Ether = (ETHER_HEAD *) Packet;
211 CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);
212
213 //
214 // Start the timeout event.
215 //
216 Status = gBS->CreateEvent (
217 EVT_TIMER,
218 TPL_NOTIFY,
219 NULL,
220 NULL,
221 &TimeoutEvent
222 );
223
224 if (EFI_ERROR (Status)) {
225 return Status;
226 }
227
228 Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
229
230 if (EFI_ERROR (Status)) {
231 goto ON_EXIT;
232 }
233
234 for (;;) {
235 //
236 // Transmit the packet through SNP.
237 //
238 Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);
239
240 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {
241 Status = EFI_DEVICE_ERROR;
242 break;
243 }
244
245 //
246 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
247 // if Status is EFI_NOT_READY, the transmit engine of the network
248 // interface is busy. Both need to sync SNP.
249 //
250 TxBuf = NULL;
251
252 do {
253 //
254 // Get the recycled transmit buffer status.
255 //
256 Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);
257
258 if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
259 Status = EFI_TIMEOUT;
260 break;
261 }
262
263 } while (TxBuf == NULL);
264
265 if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {
266 break;
267 }
268
269 //
270 // Status is EFI_NOT_READY. Restart the timer event and
271 // call Snp->Transmit again.
272 //
273 gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
274 }
275
276 gBS->SetTimer (TimeoutEvent, TimerCancel, 0);
277
278 ON_EXIT:
279 gBS->CloseEvent (TimeoutEvent);
280 return Status;
281 }
282
283 /**
284 Build a syslog packet, including the Ethernet/Ip/Udp headers
285 and user's message.
286
287 @param[in] Level - Syslog servity level
288 @param[in] Module - The module that generates the log
289 @param[in] File - The file that contains the current log
290 @param[in] Line - The line of code in the File that contains the current log
291 @param[in] Message - The log message
292 @param[in] BufLen - The lenght of the Buf
293 @param[out] Buf - The buffer to put the packet data
294
295 Returns:
296
297 The length of the syslog packet built.
298
299 **/
300 UINT32
301 SyslogBuildPacket (
302 IN UINT32 Level,
303 IN UINT8 *Module,
304 IN UINT8 *File,
305 IN UINT32 Line,
306 IN UINT8 *Message,
307 IN UINT32 BufLen,
308 OUT CHAR8 *Buf
309 )
310 {
311 ETHER_HEAD *Ether;
312 IP4_HEAD *Ip4;
313 EFI_UDP_HEADER *Udp4;
314 EFI_TIME Time;
315 UINT32 Pri;
316 UINT32 Len;
317
318 //
319 // Fill in the Ethernet header. Leave alone the source MAC.
320 // SyslogSendPacket will fill in the address for us.
321 //
322 Ether = (ETHER_HEAD *) Buf;
323 CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);
324 ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);
325
326 Ether->EtherType = HTONS (0x0800); // IPv4 protocol
327
328 Buf += sizeof (ETHER_HEAD);
329 BufLen -= sizeof (ETHER_HEAD);
330
331 //
332 // Fill in the IP header
333 //
334 Ip4 = (IP4_HEAD *) Buf;
335 Ip4->HeadLen = 5;
336 Ip4->Ver = 4;
337 Ip4->Tos = 0;
338 Ip4->TotalLen = 0;
339 Ip4->Id = (UINT16) mSyslogPacketSeq;
340 Ip4->Fragment = 0;
341 Ip4->Ttl = 16;
342 Ip4->Protocol = 0x11;
343 Ip4->Checksum = 0;
344 Ip4->Src = mSyslogSrcIp;
345 Ip4->Dst = mSyslogDstIp;
346
347 Buf += sizeof (IP4_HEAD);
348 BufLen -= sizeof (IP4_HEAD);
349
350 //
351 // Fill in the UDP header, Udp checksum is optional. Leave it zero.
352 //
353 Udp4 = (EFI_UDP_HEADER *) Buf;
354 Udp4->SrcPort = HTONS (514);
355 Udp4->DstPort = HTONS (514);
356 Udp4->Length = 0;
357 Udp4->Checksum = 0;
358
359 Buf += sizeof (EFI_UDP_HEADER);
360 BufLen -= sizeof (EFI_UDP_HEADER);
361
362 //
363 // Build the syslog message body with <PRI> Timestamp machine module Message
364 //
365 Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);
366 gRT->GetTime (&Time, NULL);
367
368 //
369 // Use %a to format the ASCII strings, %s to format UNICODE strings
370 //
371 Len = 0;
372 Len += (UINT32) AsciiSPrint (
373 Buf,
374 BufLen,
375 "<%d> %a %d %d:%d:%d ",
376 Pri,
377 mMonthName [Time.Month-1],
378 Time.Day,
379 Time.Hour,
380 Time.Minute,
381 Time.Second
382 );
383 Len--;
384
385 Len += (UINT32) AsciiSPrint (
386 Buf + Len,
387 BufLen - Len,
388 "Tiano %a: %a (Line: %d File: %a)",
389 Module,
390 Message,
391 Line,
392 File
393 );
394 Len--;
395
396 //
397 // OK, patch the IP length/checksum and UDP length fields.
398 //
399 Len += sizeof (EFI_UDP_HEADER);
400 Udp4->Length = HTONS ((UINT16) Len);
401
402 Len += sizeof (IP4_HEAD);
403 Ip4->TotalLen = HTONS ((UINT16) Len);
404 Ip4->Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD)));
405
406 return Len + sizeof (ETHER_HEAD);
407 }
408
409 /**
410 Allocate a buffer, then format the message to it. This is a
411 help function for the NET_DEBUG_XXX macros. The PrintArg of
412 these macros treats the variable length print parameters as a
413 single parameter, and pass it to the NetDebugASPrint. For
414 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
415 if extracted to:
416
417 NetDebugOutput (
418 NETDEBUG_LEVEL_TRACE,
419 "Tcp",
420 __FILE__,
421 __LINE__,
422 NetDebugASPrint ("State transit to %a\n", Name)
423 )
424
425 @param Format The ASCII format string.
426 @param ... The variable length parameter whose format is determined
427 by the Format string.
428
429 @return The buffer containing the formatted message,
430 or NULL if failed to allocate memory.
431
432 **/
433 CHAR8 *
434 NetDebugASPrint (
435 IN CHAR8 *Format,
436 ...
437 )
438 {
439 VA_LIST Marker;
440 CHAR8 *Buf;
441
442 Buf = (CHAR8 *) AllocatePool (NET_DEBUG_MSG_LEN);
443
444 if (Buf == NULL) {
445 return NULL;
446 }
447
448 VA_START (Marker, Format);
449 AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);
450 VA_END (Marker);
451
452 return Buf;
453 }
454
455 /**
456 Builds an UDP4 syslog packet and send it using SNP.
457
458 This function will locate a instance of SNP then send the message through it.
459 Because it isn't open the SNP BY_DRIVER, apply caution when using it.
460
461 @param Level The servity level of the message.
462 @param Module The Moudle that generates the log.
463 @param File The file that contains the log.
464 @param Line The exact line that contains the log.
465 @param Message The user message to log.
466
467 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
468 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
469 @retval EFI_SUCCESS The log is discard because that it is more verbose
470 than the mNetDebugLevelMax. Or, it has been sent out.
471 **/
472 EFI_STATUS
473 NetDebugOutput (
474 IN UINT32 Level,
475 IN UINT8 *Module,
476 IN UINT8 *File,
477 IN UINT32 Line,
478 IN UINT8 *Message
479 )
480 {
481 CHAR8 *Packet;
482 UINT32 Len;
483 EFI_STATUS Status;
484
485 //
486 // Check whether the message should be sent out
487 //
488 if (Message == NULL) {
489 return EFI_INVALID_PARAMETER;
490 }
491
492 if (Level > mNetDebugLevelMax) {
493 Status = EFI_SUCCESS;
494 goto ON_EXIT;
495 }
496
497 //
498 // Allocate a maxium of 1024 bytes, the caller should ensure
499 // that the message plus the ethernet/ip/udp header is shorter
500 // than this
501 //
502 Packet = (CHAR8 *) AllocatePool (NET_SYSLOG_PACKET_LEN);
503
504 if (Packet == NULL) {
505 Status = EFI_OUT_OF_RESOURCES;
506 goto ON_EXIT;
507 }
508
509 //
510 // Build the message: Ethernet header + IP header + Udp Header + user data
511 //
512 Len = SyslogBuildPacket (
513 Level,
514 Module,
515 File,
516 Line,
517 Message,
518 NET_SYSLOG_PACKET_LEN,
519 Packet
520 );
521
522 mSyslogPacketSeq++;
523 Status = SyslogSendPacket (Packet, Len);
524 FreePool (Packet);
525
526 ON_EXIT:
527 FreePool (Message);
528 return Status;
529 }
530 /**
531 Return the length of the mask.
532
533 Return the length of the mask, the correct value is from 0 to 32.
534 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.
535 NetMask is in the host byte order.
536
537 @param[in] NetMask The netmask to get the length from.
538
539 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.
540
541 **/
542 INTN
543 EFIAPI
544 NetGetMaskLength (
545 IN IP4_ADDR NetMask
546 )
547 {
548 INTN Index;
549
550 for (Index = 0; Index < IP4_MASK_NUM; Index++) {
551 if (NetMask == gIp4AllMasks[Index]) {
552 break;
553 }
554 }
555
556 return Index;
557 }
558
559
560
561 /**
562 Return the class of the IP address, such as class A, B, C.
563 Addr is in host byte order.
564
565 The address of class A starts with 0.
566 If the address belong to class A, return IP4_ADDR_CLASSA.
567 The address of class B starts with 10.
568 If the address belong to class B, return IP4_ADDR_CLASSB.
569 The address of class C starts with 110.
570 If the address belong to class C, return IP4_ADDR_CLASSC.
571 The address of class D starts with 1110.
572 If the address belong to class D, return IP4_ADDR_CLASSD.
573 The address of class E starts with 1111.
574 If the address belong to class E, return IP4_ADDR_CLASSE.
575
576
577 @param[in] Addr The address to get the class from.
578
579 @return IP address class, such as IP4_ADDR_CLASSA.
580
581 **/
582 INTN
583 EFIAPI
584 NetGetIpClass (
585 IN IP4_ADDR Addr
586 )
587 {
588 UINT8 ByteOne;
589
590 ByteOne = (UINT8) (Addr >> 24);
591
592 if ((ByteOne & 0x80) == 0) {
593 return IP4_ADDR_CLASSA;
594
595 } else if ((ByteOne & 0xC0) == 0x80) {
596 return IP4_ADDR_CLASSB;
597
598 } else if ((ByteOne & 0xE0) == 0xC0) {
599 return IP4_ADDR_CLASSC;
600
601 } else if ((ByteOne & 0xF0) == 0xE0) {
602 return IP4_ADDR_CLASSD;
603
604 } else {
605 return IP4_ADDR_CLASSE;
606
607 }
608 }
609
610
611 /**
612 Check whether the IP is a valid unicast address according to
613 the netmask. If NetMask is zero, use the IP address's class to get the default mask.
614
615 If Ip is 0, IP is not a valid unicast address.
616 Class D address is used for multicasting and class E address is reserved for future. If Ip
617 belongs to class D or class E, IP is not a valid unicast address.
618 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address.
619
620 @param[in] Ip The IP to check against.
621 @param[in] NetMask The mask of the IP.
622
623 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
624
625 **/
626 BOOLEAN
627 EFIAPI
628 NetIp4IsUnicast (
629 IN IP4_ADDR Ip,
630 IN IP4_ADDR NetMask
631 )
632 {
633 INTN Class;
634
635 Class = NetGetIpClass (Ip);
636
637 if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {
638 return FALSE;
639 }
640
641 if (NetMask == 0) {
642 NetMask = gIp4AllMasks[Class << 3];
643 }
644
645 if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {
646 return FALSE;
647 }
648
649 return TRUE;
650 }
651
652 /**
653 Check whether the incoming IPv6 address is a valid unicast address.
654
655 If the address is a multicast address has binary 0xFF at the start, it is not
656 a valid unicast address. If the address is unspecified ::, it is not a valid
657 unicast address to be assigned to any node. If the address is loopback address
658 ::1, it is also not a valid unicast address to be assigned to any physical
659 interface.
660
661 @param[in] Ip6 The IPv6 address to check against.
662
663 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
664
665 **/
666 BOOLEAN
667 NetIp6IsValidUnicast (
668 IN EFI_IPv6_ADDRESS *Ip6
669 )
670 {
671 UINT8 Byte;
672 UINT8 Index;
673
674 if (Ip6->Addr[0] == 0xFF) {
675 return FALSE;
676 }
677
678 for (Index = 0; Index < 15; Index++) {
679 if (Ip6->Addr[Index] != 0) {
680 return TRUE;
681 }
682 }
683
684 Byte = Ip6->Addr[Index];
685
686 if (Byte == 0x0 || Byte == 0x1) {
687 return FALSE;
688 }
689
690 return TRUE;
691 }
692
693 /**
694 Check whether the incoming Ipv6 address is the unspecified address or not.
695
696 @param[in] Ip6 - Ip6 address, in network order.
697
698 @retval TRUE - Yes, unspecified
699 @retval FALSE - No
700
701 **/
702 BOOLEAN
703 NetIp6IsUnspecifiedAddr (
704 IN EFI_IPv6_ADDRESS *Ip6
705 )
706 {
707 UINT8 Index;
708
709 for (Index = 0; Index < 16; Index++) {
710 if (Ip6->Addr[Index] != 0) {
711 return FALSE;
712 }
713 }
714
715 return TRUE;
716 }
717
718 /**
719 Check whether the incoming Ipv6 address is a link-local address.
720
721 @param[in] Ip6 - Ip6 address, in network order.
722
723 @retval TRUE - Yes, link-local address
724 @retval FALSE - No
725
726 **/
727 BOOLEAN
728 NetIp6IsLinkLocalAddr (
729 IN EFI_IPv6_ADDRESS *Ip6
730 )
731 {
732 UINT8 Index;
733
734 ASSERT (Ip6 != NULL);
735
736 if (Ip6->Addr[0] != 0xFE) {
737 return FALSE;
738 }
739
740 if (Ip6->Addr[1] != 0x80) {
741 return FALSE;
742 }
743
744 for (Index = 2; Index < 8; Index++) {
745 if (Ip6->Addr[Index] != 0) {
746 return FALSE;
747 }
748 }
749
750 return TRUE;
751 }
752
753 /**
754 Check whether the Ipv6 address1 and address2 are on the connected network.
755
756 @param[in] Ip1 - Ip6 address1, in network order.
757 @param[in] Ip2 - Ip6 address2, in network order.
758 @param[in] PrefixLength - The prefix length of the checking net.
759
760 @retval TRUE - Yes, connected.
761 @retval FALSE - No.
762
763 **/
764 BOOLEAN
765 NetIp6IsNetEqual (
766 EFI_IPv6_ADDRESS *Ip1,
767 EFI_IPv6_ADDRESS *Ip2,
768 UINT8 PrefixLength
769 )
770 {
771 UINT8 Byte;
772 UINT8 Bit;
773 UINT8 Mask;
774
775 ASSERT (Ip1 != NULL && Ip2 != NULL);
776
777 if (PrefixLength == 0) {
778 return TRUE;
779 }
780
781 Byte = (UINT8) (PrefixLength / 8);
782 Bit = (UINT8) (PrefixLength % 8);
783
784 if (CompareMem (Ip1, Ip2, Byte) != 0) {
785 return FALSE;
786 }
787
788 if (Bit > 0) {
789 Mask = (UINT8) (0xFF << (8 - Bit));
790
791 if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {
792 return FALSE;
793 }
794 }
795
796 return TRUE;
797 }
798
799
800 /**
801 Switches the endianess of an IPv6 address
802
803 This function swaps the bytes in a 128-bit IPv6 address to switch the value
804 from little endian to big endian or vice versa. The byte swapped value is
805 returned.
806
807 @param Ip6 Points to an IPv6 address
808
809 @return The byte swapped IPv6 address.
810
811 **/
812 EFI_IPv6_ADDRESS *
813 Ip6Swap128 (
814 EFI_IPv6_ADDRESS *Ip6
815 )
816 {
817 UINT64 High;
818 UINT64 Low;
819
820 CopyMem (&High, Ip6, sizeof (UINT64));
821 CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));
822
823 High = SwapBytes64 (High);
824 Low = SwapBytes64 (Low);
825
826 CopyMem (Ip6, &Low, sizeof (UINT64));
827 CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));
828
829 return Ip6;
830 }
831
832 /**
833 Initialize a random seed using current time.
834
835 Get current time first. Then initialize a random seed based on some basic
836 mathematics operation on the hour, day, minute, second, nanosecond and year
837 of the current time.
838
839 @return The random seed initialized with current time.
840
841 **/
842 UINT32
843 EFIAPI
844 NetRandomInitSeed (
845 VOID
846 )
847 {
848 EFI_TIME Time;
849 UINT32 Seed;
850
851 gRT->GetTime (&Time, NULL);
852 Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);
853 Seed ^= Time.Nanosecond;
854 Seed ^= Time.Year << 7;
855
856 return Seed;
857 }
858
859
860 /**
861 Extract a UINT32 from a byte stream.
862
863 Copy a UINT32 from a byte stream, then converts it from Network
864 byte order to host byte order. Use this function to avoid alignment error.
865
866 @param[in] Buf The buffer to extract the UINT32.
867
868 @return The UINT32 extracted.
869
870 **/
871 UINT32
872 EFIAPI
873 NetGetUint32 (
874 IN UINT8 *Buf
875 )
876 {
877 UINT32 Value;
878
879 CopyMem (&Value, Buf, sizeof (UINT32));
880 return NTOHL (Value);
881 }
882
883
884 /**
885 Put a UINT32 to the byte stream in network byte order.
886
887 Converts a UINT32 from host byte order to network byte order. Then copy it to the
888 byte stream.
889
890 @param[in, out] Buf The buffer to put the UINT32.
891 @param[in] Data The data to put.
892
893 **/
894 VOID
895 EFIAPI
896 NetPutUint32 (
897 IN OUT UINT8 *Buf,
898 IN UINT32 Data
899 )
900 {
901 Data = HTONL (Data);
902 CopyMem (Buf, &Data, sizeof (UINT32));
903 }
904
905
906 /**
907 Remove the first node entry on the list, and return the removed node entry.
908
909 Removes the first node Entry from a doubly linked list. It is up to the caller of
910 this function to release the memory used by the first node if that is required. On
911 exit, the removed node is returned.
912
913 If Head is NULL, then ASSERT().
914 If Head was not initialized, then ASSERT().
915 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
916 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
917 then ASSERT().
918
919 @param[in, out] Head The list header.
920
921 @return The first node entry that is removed from the list, NULL if the list is empty.
922
923 **/
924 LIST_ENTRY *
925 EFIAPI
926 NetListRemoveHead (
927 IN OUT LIST_ENTRY *Head
928 )
929 {
930 LIST_ENTRY *First;
931
932 ASSERT (Head != NULL);
933
934 if (IsListEmpty (Head)) {
935 return NULL;
936 }
937
938 First = Head->ForwardLink;
939 Head->ForwardLink = First->ForwardLink;
940 First->ForwardLink->BackLink = Head;
941
942 DEBUG_CODE (
943 First->ForwardLink = (LIST_ENTRY *) NULL;
944 First->BackLink = (LIST_ENTRY *) NULL;
945 );
946
947 return First;
948 }
949
950
951 /**
952 Remove the last node entry on the list and and return the removed node entry.
953
954 Removes the last node entry from a doubly linked list. It is up to the caller of
955 this function to release the memory used by the first node if that is required. On
956 exit, the removed node is returned.
957
958 If Head is NULL, then ASSERT().
959 If Head was not initialized, then ASSERT().
960 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
961 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
962 then ASSERT().
963
964 @param[in, out] Head The list head.
965
966 @return The last node entry that is removed from the list, NULL if the list is empty.
967
968 **/
969 LIST_ENTRY *
970 EFIAPI
971 NetListRemoveTail (
972 IN OUT LIST_ENTRY *Head
973 )
974 {
975 LIST_ENTRY *Last;
976
977 ASSERT (Head != NULL);
978
979 if (IsListEmpty (Head)) {
980 return NULL;
981 }
982
983 Last = Head->BackLink;
984 Head->BackLink = Last->BackLink;
985 Last->BackLink->ForwardLink = Head;
986
987 DEBUG_CODE (
988 Last->ForwardLink = (LIST_ENTRY *) NULL;
989 Last->BackLink = (LIST_ENTRY *) NULL;
990 );
991
992 return Last;
993 }
994
995
996 /**
997 Insert a new node entry after a designated node entry of a doubly linked list.
998
999 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
1000 of the doubly linked list.
1001
1002 @param[in, out] PrevEntry The previous entry to insert after.
1003 @param[in, out] NewEntry The new entry to insert.
1004
1005 **/
1006 VOID
1007 EFIAPI
1008 NetListInsertAfter (
1009 IN OUT LIST_ENTRY *PrevEntry,
1010 IN OUT LIST_ENTRY *NewEntry
1011 )
1012 {
1013 NewEntry->BackLink = PrevEntry;
1014 NewEntry->ForwardLink = PrevEntry->ForwardLink;
1015 PrevEntry->ForwardLink->BackLink = NewEntry;
1016 PrevEntry->ForwardLink = NewEntry;
1017 }
1018
1019
1020 /**
1021 Insert a new node entry before a designated node entry of a doubly linked list.
1022
1023 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
1024 of the doubly linked list.
1025
1026 @param[in, out] PostEntry The entry to insert before.
1027 @param[in, out] NewEntry The new entry to insert.
1028
1029 **/
1030 VOID
1031 EFIAPI
1032 NetListInsertBefore (
1033 IN OUT LIST_ENTRY *PostEntry,
1034 IN OUT LIST_ENTRY *NewEntry
1035 )
1036 {
1037 NewEntry->ForwardLink = PostEntry;
1038 NewEntry->BackLink = PostEntry->BackLink;
1039 PostEntry->BackLink->ForwardLink = NewEntry;
1040 PostEntry->BackLink = NewEntry;
1041 }
1042
1043
1044 /**
1045 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
1046
1047 Initialize the forward and backward links of two head nodes donated by Map->Used
1048 and Map->Recycled of two doubly linked lists.
1049 Initializes the count of the <Key, Value> pairs in the netmap to zero.
1050
1051 If Map is NULL, then ASSERT().
1052 If the address of Map->Used is NULL, then ASSERT().
1053 If the address of Map->Recycled is NULl, then ASSERT().
1054
1055 @param[in, out] Map The netmap to initialize.
1056
1057 **/
1058 VOID
1059 EFIAPI
1060 NetMapInit (
1061 IN OUT NET_MAP *Map
1062 )
1063 {
1064 ASSERT (Map != NULL);
1065
1066 InitializeListHead (&Map->Used);
1067 InitializeListHead (&Map->Recycled);
1068 Map->Count = 0;
1069 }
1070
1071
1072 /**
1073 To clean up the netmap, that is, release allocated memories.
1074
1075 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
1076 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
1077 The number of the <Key, Value> pairs in the netmap is set to be zero.
1078
1079 If Map is NULL, then ASSERT().
1080
1081 @param[in, out] Map The netmap to clean up.
1082
1083 **/
1084 VOID
1085 EFIAPI
1086 NetMapClean (
1087 IN OUT NET_MAP *Map
1088 )
1089 {
1090 NET_MAP_ITEM *Item;
1091 LIST_ENTRY *Entry;
1092 LIST_ENTRY *Next;
1093
1094 ASSERT (Map != NULL);
1095
1096 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {
1097 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1098
1099 RemoveEntryList (&Item->Link);
1100 Map->Count--;
1101
1102 gBS->FreePool (Item);
1103 }
1104
1105 ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));
1106
1107 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {
1108 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1109
1110 RemoveEntryList (&Item->Link);
1111 gBS->FreePool (Item);
1112 }
1113
1114 ASSERT (IsListEmpty (&Map->Recycled));
1115 }
1116
1117
1118 /**
1119 Test whether the netmap is empty and return true if it is.
1120
1121 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
1122
1123 If Map is NULL, then ASSERT().
1124
1125
1126 @param[in] Map The net map to test.
1127
1128 @return TRUE if the netmap is empty, otherwise FALSE.
1129
1130 **/
1131 BOOLEAN
1132 EFIAPI
1133 NetMapIsEmpty (
1134 IN NET_MAP *Map
1135 )
1136 {
1137 ASSERT (Map != NULL);
1138 return (BOOLEAN) (Map->Count == 0);
1139 }
1140
1141
1142 /**
1143 Return the number of the <Key, Value> pairs in the netmap.
1144
1145 @param[in] Map The netmap to get the entry number.
1146
1147 @return The entry number in the netmap.
1148
1149 **/
1150 UINTN
1151 EFIAPI
1152 NetMapGetCount (
1153 IN NET_MAP *Map
1154 )
1155 {
1156 return Map->Count;
1157 }
1158
1159
1160 /**
1161 Return one allocated item.
1162
1163 If the Recycled doubly linked list of the netmap is empty, it will try to allocate
1164 a batch of items if there are enough resources and add corresponding nodes to the begining
1165 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
1166 the fist node entry of the Recycled doubly linked list and return the corresponding item.
1167
1168 If Map is NULL, then ASSERT().
1169
1170 @param[in, out] Map The netmap to allocate item for.
1171
1172 @return The allocated item. If NULL, the
1173 allocation failed due to resource limit.
1174
1175 **/
1176 NET_MAP_ITEM *
1177 NetMapAllocItem (
1178 IN OUT NET_MAP *Map
1179 )
1180 {
1181 NET_MAP_ITEM *Item;
1182 LIST_ENTRY *Head;
1183 UINTN Index;
1184
1185 ASSERT (Map != NULL);
1186
1187 Head = &Map->Recycled;
1188
1189 if (IsListEmpty (Head)) {
1190 for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {
1191 Item = AllocatePool (sizeof (NET_MAP_ITEM));
1192
1193 if (Item == NULL) {
1194 if (Index == 0) {
1195 return NULL;
1196 }
1197
1198 break;
1199 }
1200
1201 InsertHeadList (Head, &Item->Link);
1202 }
1203 }
1204
1205 Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);
1206 NetListRemoveHead (Head);
1207
1208 return Item;
1209 }
1210
1211
1212 /**
1213 Allocate an item to save the <Key, Value> pair to the head of the netmap.
1214
1215 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1216 to the beginning of the Used doubly linked list. The number of the <Key, Value>
1217 pairs in the netmap increase by 1.
1218
1219 If Map is NULL, then ASSERT().
1220
1221 @param[in, out] Map The netmap to insert into.
1222 @param[in] Key The user's key.
1223 @param[in] Value The user's value for the key.
1224
1225 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1226 @retval EFI_SUCCESS The item is inserted to the head.
1227
1228 **/
1229 EFI_STATUS
1230 EFIAPI
1231 NetMapInsertHead (
1232 IN OUT NET_MAP *Map,
1233 IN VOID *Key,
1234 IN VOID *Value OPTIONAL
1235 )
1236 {
1237 NET_MAP_ITEM *Item;
1238
1239 ASSERT (Map != NULL);
1240
1241 Item = NetMapAllocItem (Map);
1242
1243 if (Item == NULL) {
1244 return EFI_OUT_OF_RESOURCES;
1245 }
1246
1247 Item->Key = Key;
1248 Item->Value = Value;
1249 InsertHeadList (&Map->Used, &Item->Link);
1250
1251 Map->Count++;
1252 return EFI_SUCCESS;
1253 }
1254
1255
1256 /**
1257 Allocate an item to save the <Key, Value> pair to the tail of the netmap.
1258
1259 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1260 to the tail of the Used doubly linked list. The number of the <Key, Value>
1261 pairs in the netmap increase by 1.
1262
1263 If Map is NULL, then ASSERT().
1264
1265 @param[in, out] Map The netmap to insert into.
1266 @param[in] Key The user's key.
1267 @param[in] Value The user's value for the key.
1268
1269 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1270 @retval EFI_SUCCESS The item is inserted to the tail.
1271
1272 **/
1273 EFI_STATUS
1274 EFIAPI
1275 NetMapInsertTail (
1276 IN OUT NET_MAP *Map,
1277 IN VOID *Key,
1278 IN VOID *Value OPTIONAL
1279 )
1280 {
1281 NET_MAP_ITEM *Item;
1282
1283 ASSERT (Map != NULL);
1284
1285 Item = NetMapAllocItem (Map);
1286
1287 if (Item == NULL) {
1288 return EFI_OUT_OF_RESOURCES;
1289 }
1290
1291 Item->Key = Key;
1292 Item->Value = Value;
1293 InsertTailList (&Map->Used, &Item->Link);
1294
1295 Map->Count++;
1296
1297 return EFI_SUCCESS;
1298 }
1299
1300
1301 /**
1302 Check whether the item is in the Map and return TRUE if it is.
1303
1304 @param[in] Map The netmap to search within.
1305 @param[in] Item The item to search.
1306
1307 @return TRUE if the item is in the netmap, otherwise FALSE.
1308
1309 **/
1310 BOOLEAN
1311 NetItemInMap (
1312 IN NET_MAP *Map,
1313 IN NET_MAP_ITEM *Item
1314 )
1315 {
1316 LIST_ENTRY *ListEntry;
1317
1318 NET_LIST_FOR_EACH (ListEntry, &Map->Used) {
1319 if (ListEntry == &Item->Link) {
1320 return TRUE;
1321 }
1322 }
1323
1324 return FALSE;
1325 }
1326
1327
1328 /**
1329 Find the key in the netmap and returns the point to the item contains the Key.
1330
1331 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
1332 item with the key to search. It returns the point to the item contains the Key if found.
1333
1334 If Map is NULL, then ASSERT().
1335
1336 @param[in] Map The netmap to search within.
1337 @param[in] Key The key to search.
1338
1339 @return The point to the item contains the Key, or NULL if Key isn't in the map.
1340
1341 **/
1342 NET_MAP_ITEM *
1343 EFIAPI
1344 NetMapFindKey (
1345 IN NET_MAP *Map,
1346 IN VOID *Key
1347 )
1348 {
1349 LIST_ENTRY *Entry;
1350 NET_MAP_ITEM *Item;
1351
1352 ASSERT (Map != NULL);
1353
1354 NET_LIST_FOR_EACH (Entry, &Map->Used) {
1355 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1356
1357 if (Item->Key == Key) {
1358 return Item;
1359 }
1360 }
1361
1362 return NULL;
1363 }
1364
1365
1366 /**
1367 Remove the node entry of the item from the netmap and return the key of the removed item.
1368
1369 Remove the node entry of the item from the Used doubly linked list of the netmap.
1370 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1371 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
1372 Value will point to the value of the item. It returns the key of the removed item.
1373
1374 If Map is NULL, then ASSERT().
1375 If Item is NULL, then ASSERT().
1376 if item in not in the netmap, then ASSERT().
1377
1378 @param[in, out] Map The netmap to remove the item from.
1379 @param[in, out] Item The item to remove.
1380 @param[out] Value The variable to receive the value if not NULL.
1381
1382 @return The key of the removed item.
1383
1384 **/
1385 VOID *
1386 EFIAPI
1387 NetMapRemoveItem (
1388 IN OUT NET_MAP *Map,
1389 IN OUT NET_MAP_ITEM *Item,
1390 OUT VOID **Value OPTIONAL
1391 )
1392 {
1393 ASSERT ((Map != NULL) && (Item != NULL));
1394 ASSERT (NetItemInMap (Map, Item));
1395
1396 RemoveEntryList (&Item->Link);
1397 Map->Count--;
1398 InsertHeadList (&Map->Recycled, &Item->Link);
1399
1400 if (Value != NULL) {
1401 *Value = Item->Value;
1402 }
1403
1404 return Item->Key;
1405 }
1406
1407
1408 /**
1409 Remove the first node entry on the netmap and return the key of the removed item.
1410
1411 Remove the first node entry from the Used doubly linked list of the netmap.
1412 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1413 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1414 parameter Value will point to the value of the item. It returns the key of the removed item.
1415
1416 If Map is NULL, then ASSERT().
1417 If the Used doubly linked list is empty, then ASSERT().
1418
1419 @param[in, out] Map The netmap to remove the head from.
1420 @param[out] Value The variable to receive the value if not NULL.
1421
1422 @return The key of the item removed.
1423
1424 **/
1425 VOID *
1426 EFIAPI
1427 NetMapRemoveHead (
1428 IN OUT NET_MAP *Map,
1429 OUT VOID **Value OPTIONAL
1430 )
1431 {
1432 NET_MAP_ITEM *Item;
1433
1434 //
1435 // Often, it indicates a programming error to remove
1436 // the first entry in an empty list
1437 //
1438 ASSERT (Map && !IsListEmpty (&Map->Used));
1439
1440 Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);
1441 RemoveEntryList (&Item->Link);
1442 Map->Count--;
1443 InsertHeadList (&Map->Recycled, &Item->Link);
1444
1445 if (Value != NULL) {
1446 *Value = Item->Value;
1447 }
1448
1449 return Item->Key;
1450 }
1451
1452
1453 /**
1454 Remove the last node entry on the netmap and return the key of the removed item.
1455
1456 Remove the last node entry from the Used doubly linked list of the netmap.
1457 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1458 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1459 parameter Value will point to the value of the item. It returns the key of the removed item.
1460
1461 If Map is NULL, then ASSERT().
1462 If the Used doubly linked list is empty, then ASSERT().
1463
1464 @param[in, out] Map The netmap to remove the tail from.
1465 @param[out] Value The variable to receive the value if not NULL.
1466
1467 @return The key of the item removed.
1468
1469 **/
1470 VOID *
1471 EFIAPI
1472 NetMapRemoveTail (
1473 IN OUT NET_MAP *Map,
1474 OUT VOID **Value OPTIONAL
1475 )
1476 {
1477 NET_MAP_ITEM *Item;
1478
1479 //
1480 // Often, it indicates a programming error to remove
1481 // the last entry in an empty list
1482 //
1483 ASSERT (Map && !IsListEmpty (&Map->Used));
1484
1485 Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);
1486 RemoveEntryList (&Item->Link);
1487 Map->Count--;
1488 InsertHeadList (&Map->Recycled, &Item->Link);
1489
1490 if (Value != NULL) {
1491 *Value = Item->Value;
1492 }
1493
1494 return Item->Key;
1495 }
1496
1497
1498 /**
1499 Iterate through the netmap and call CallBack for each item.
1500
1501 It will contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
1502 from the loop. It returns the CallBack's last return value. This function is
1503 delete safe for the current item.
1504
1505 If Map is NULL, then ASSERT().
1506 If CallBack is NULL, then ASSERT().
1507
1508 @param[in] Map The Map to iterate through.
1509 @param[in] CallBack The callback function to call for each item.
1510 @param[in] Arg The opaque parameter to the callback.
1511
1512 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item
1513 return EFI_SUCCESS.
1514 @retval Others It returns the CallBack's last return value.
1515
1516 **/
1517 EFI_STATUS
1518 EFIAPI
1519 NetMapIterate (
1520 IN NET_MAP *Map,
1521 IN NET_MAP_CALLBACK CallBack,
1522 IN VOID *Arg
1523 )
1524 {
1525
1526 LIST_ENTRY *Entry;
1527 LIST_ENTRY *Next;
1528 LIST_ENTRY *Head;
1529 NET_MAP_ITEM *Item;
1530 EFI_STATUS Result;
1531
1532 ASSERT ((Map != NULL) && (CallBack != NULL));
1533
1534 Head = &Map->Used;
1535
1536 if (IsListEmpty (Head)) {
1537 return EFI_SUCCESS;
1538 }
1539
1540 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
1541 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1542 Result = CallBack (Map, Item, Arg);
1543
1544 if (EFI_ERROR (Result)) {
1545 return Result;
1546 }
1547 }
1548
1549 return EFI_SUCCESS;
1550 }
1551
1552
1553 /**
1554 This is the default unload handle for all the network drivers.
1555
1556 Disconnect the driver specified by ImageHandle from all the devices in the handle database.
1557 Uninstall all the protocols installed in the driver entry point.
1558
1559 @param[in] ImageHandle The drivers' driver image.
1560
1561 @retval EFI_SUCCESS The image is unloaded.
1562 @retval Others Failed to unload the image.
1563
1564 **/
1565 EFI_STATUS
1566 EFIAPI
1567 NetLibDefaultUnload (
1568 IN EFI_HANDLE ImageHandle
1569 )
1570 {
1571 EFI_STATUS Status;
1572 EFI_HANDLE *DeviceHandleBuffer;
1573 UINTN DeviceHandleCount;
1574 UINTN Index;
1575 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
1576 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
1577 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
1578
1579 //
1580 // Get the list of all the handles in the handle database.
1581 // If there is an error getting the list, then the unload
1582 // operation fails.
1583 //
1584 Status = gBS->LocateHandleBuffer (
1585 AllHandles,
1586 NULL,
1587 NULL,
1588 &DeviceHandleCount,
1589 &DeviceHandleBuffer
1590 );
1591
1592 if (EFI_ERROR (Status)) {
1593 return Status;
1594 }
1595
1596 //
1597 // Disconnect the driver specified by ImageHandle from all
1598 // the devices in the handle database.
1599 //
1600 for (Index = 0; Index < DeviceHandleCount; Index++) {
1601 Status = gBS->DisconnectController (
1602 DeviceHandleBuffer[Index],
1603 ImageHandle,
1604 NULL
1605 );
1606 }
1607
1608 //
1609 // Uninstall all the protocols installed in the driver entry point
1610 //
1611 for (Index = 0; Index < DeviceHandleCount; Index++) {
1612 Status = gBS->HandleProtocol (
1613 DeviceHandleBuffer[Index],
1614 &gEfiDriverBindingProtocolGuid,
1615 (VOID **) &DriverBinding
1616 );
1617
1618 if (EFI_ERROR (Status)) {
1619 continue;
1620 }
1621
1622 if (DriverBinding->ImageHandle != ImageHandle) {
1623 continue;
1624 }
1625
1626 gBS->UninstallProtocolInterface (
1627 ImageHandle,
1628 &gEfiDriverBindingProtocolGuid,
1629 DriverBinding
1630 );
1631 Status = gBS->HandleProtocol (
1632 DeviceHandleBuffer[Index],
1633 &gEfiComponentNameProtocolGuid,
1634 (VOID **) &ComponentName
1635 );
1636 if (!EFI_ERROR (Status)) {
1637 gBS->UninstallProtocolInterface (
1638 ImageHandle,
1639 &gEfiComponentNameProtocolGuid,
1640 ComponentName
1641 );
1642 }
1643
1644 Status = gBS->HandleProtocol (
1645 DeviceHandleBuffer[Index],
1646 &gEfiComponentName2ProtocolGuid,
1647 (VOID **) &ComponentName2
1648 );
1649 if (!EFI_ERROR (Status)) {
1650 gBS->UninstallProtocolInterface (
1651 ImageHandle,
1652 &gEfiComponentName2ProtocolGuid,
1653 ComponentName2
1654 );
1655 }
1656 }
1657
1658 //
1659 // Free the buffer containing the list of handles from the handle database
1660 //
1661 if (DeviceHandleBuffer != NULL) {
1662 gBS->FreePool (DeviceHandleBuffer);
1663 }
1664
1665 return EFI_SUCCESS;
1666 }
1667
1668
1669
1670 /**
1671 Create a child of the service that is identified by ServiceBindingGuid.
1672
1673 Get the ServiceBinding Protocol first, then use it to create a child.
1674
1675 If ServiceBindingGuid is NULL, then ASSERT().
1676 If ChildHandle is NULL, then ASSERT().
1677
1678 @param[in] Controller The controller which has the service installed.
1679 @param[in] Image The image handle used to open service.
1680 @param[in] ServiceBindingGuid The service's Guid.
1681 @param[in, out] ChildHandle The handle to receive the create child.
1682
1683 @retval EFI_SUCCESS The child is successfully created.
1684 @retval Others Failed to create the child.
1685
1686 **/
1687 EFI_STATUS
1688 EFIAPI
1689 NetLibCreateServiceChild (
1690 IN EFI_HANDLE Controller,
1691 IN EFI_HANDLE Image,
1692 IN EFI_GUID *ServiceBindingGuid,
1693 IN OUT EFI_HANDLE *ChildHandle
1694 )
1695 {
1696 EFI_STATUS Status;
1697 EFI_SERVICE_BINDING_PROTOCOL *Service;
1698
1699
1700 ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));
1701
1702 //
1703 // Get the ServiceBinding Protocol
1704 //
1705 Status = gBS->OpenProtocol (
1706 Controller,
1707 ServiceBindingGuid,
1708 (VOID **) &Service,
1709 Image,
1710 Controller,
1711 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1712 );
1713
1714 if (EFI_ERROR (Status)) {
1715 return Status;
1716 }
1717
1718 //
1719 // Create a child
1720 //
1721 Status = Service->CreateChild (Service, ChildHandle);
1722 return Status;
1723 }
1724
1725
1726 /**
1727 Destory a child of the service that is identified by ServiceBindingGuid.
1728
1729 Get the ServiceBinding Protocol first, then use it to destroy a child.
1730
1731 If ServiceBindingGuid is NULL, then ASSERT().
1732
1733 @param[in] Controller The controller which has the service installed.
1734 @param[in] Image The image handle used to open service.
1735 @param[in] ServiceBindingGuid The service's Guid.
1736 @param[in] ChildHandle The child to destory.
1737
1738 @retval EFI_SUCCESS The child is successfully destoried.
1739 @retval Others Failed to destory the child.
1740
1741 **/
1742 EFI_STATUS
1743 EFIAPI
1744 NetLibDestroyServiceChild (
1745 IN EFI_HANDLE Controller,
1746 IN EFI_HANDLE Image,
1747 IN EFI_GUID *ServiceBindingGuid,
1748 IN EFI_HANDLE ChildHandle
1749 )
1750 {
1751 EFI_STATUS Status;
1752 EFI_SERVICE_BINDING_PROTOCOL *Service;
1753
1754 ASSERT (ServiceBindingGuid != NULL);
1755
1756 //
1757 // Get the ServiceBinding Protocol
1758 //
1759 Status = gBS->OpenProtocol (
1760 Controller,
1761 ServiceBindingGuid,
1762 (VOID **) &Service,
1763 Image,
1764 Controller,
1765 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1766 );
1767
1768 if (EFI_ERROR (Status)) {
1769 return Status;
1770 }
1771
1772 //
1773 // destory the child
1774 //
1775 Status = Service->DestroyChild (Service, ChildHandle);
1776 return Status;
1777 }
1778
1779
1780 /**
1781 Convert the mac address of the simple network protocol installed on
1782 SnpHandle to a unicode string. Callers are responsible for freeing the
1783 string storage.
1784
1785 Get the mac address of the Simple Network protocol from the SnpHandle. Then convert
1786 the mac address into a unicode string. It takes 2 unicode characters to represent
1787 a 1 byte binary buffer. Plus one unicode character for the null-terminator.
1788
1789
1790 @param[in] SnpHandle The handle where the simple network protocol is
1791 installed on.
1792 @param[in] ImageHandle The image handle used to act as the agent handle to
1793 get the simple network protocol.
1794 @param[out] MacString The pointer to store the address of the string
1795 representation of the mac address.
1796
1797 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.
1798 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
1799 @retval Others Failed to open the simple network protocol.
1800
1801 **/
1802 EFI_STATUS
1803 EFIAPI
1804 NetLibGetMacString (
1805 IN EFI_HANDLE SnpHandle,
1806 IN EFI_HANDLE ImageHandle,
1807 OUT CHAR16 **MacString
1808 )
1809 {
1810 EFI_STATUS Status;
1811 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
1812 EFI_SIMPLE_NETWORK_MODE *Mode;
1813 CHAR16 *MacAddress;
1814 UINTN Index;
1815
1816 *MacString = NULL;
1817
1818 //
1819 // Get the Simple Network protocol from the SnpHandle.
1820 //
1821 Status = gBS->OpenProtocol (
1822 SnpHandle,
1823 &gEfiSimpleNetworkProtocolGuid,
1824 (VOID **) &Snp,
1825 ImageHandle,
1826 SnpHandle,
1827 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1828 );
1829 if (EFI_ERROR (Status)) {
1830 return Status;
1831 }
1832
1833 Mode = Snp->Mode;
1834
1835 //
1836 // It takes 2 unicode characters to represent a 1 byte binary buffer.
1837 // Plus one unicode character for the null-terminator.
1838 //
1839 MacAddress = AllocatePool ((2 * Mode->HwAddressSize + 1) * sizeof (CHAR16));
1840 if (MacAddress == NULL) {
1841 return EFI_OUT_OF_RESOURCES;
1842 }
1843
1844 //
1845 // Convert the mac address into a unicode string.
1846 //
1847 for (Index = 0; Index < Mode->HwAddressSize; Index++) {
1848 MacAddress[Index * 2] = (CHAR16) mNetLibHexStr[(Mode->CurrentAddress.Addr[Index] >> 4) & 0x0F];
1849 MacAddress[Index * 2 + 1] = (CHAR16) mNetLibHexStr[Mode->CurrentAddress.Addr[Index] & 0x0F];
1850 }
1851
1852 MacAddress[Mode->HwAddressSize * 2] = L'\0';
1853
1854 *MacString = MacAddress;
1855
1856 return EFI_SUCCESS;
1857 }
1858
1859 /**
1860 Check the default address used by the IPv4 driver is static or dynamic (acquired
1861 from DHCP).
1862
1863 If the controller handle does not have the NIC Ip4 Config Protocol installed, the
1864 default address is static. If the EFI variable to save the configuration is not found,
1865 the default address is static. Otherwise, get the result from the EFI variable which
1866 saving the configuration.
1867
1868 @param[in] Controller The controller handle which has the NIC Ip4 Config Protocol
1869 relative with the default address to judge.
1870
1871 @retval TRUE If the default address is static.
1872 @retval FALSE If the default address is acquired from DHCP.
1873
1874 **/
1875 BOOLEAN
1876 NetLibDefaultAddressIsStatic (
1877 IN EFI_HANDLE Controller
1878 )
1879 {
1880 EFI_STATUS Status;
1881 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
1882 UINTN Len;
1883 NIC_IP4_CONFIG_INFO *ConfigInfo;
1884 BOOLEAN IsStatic;
1885 EFI_STRING ConfigHdr;
1886 EFI_STRING ConfigResp;
1887 EFI_STRING AccessProgress;
1888 EFI_STRING AccessResults;
1889 EFI_STRING String;
1890
1891 ConfigInfo = NULL;
1892 ConfigHdr = NULL;
1893 ConfigResp = NULL;
1894 AccessProgress = NULL;
1895 AccessResults = NULL;
1896 IsStatic = TRUE;
1897
1898 Status = gBS->LocateProtocol (
1899 &gEfiHiiConfigRoutingProtocolGuid,
1900 NULL,
1901 (VOID **) &HiiConfigRouting
1902 );
1903 if (EFI_ERROR (Status)) {
1904 return TRUE;
1905 }
1906
1907 //
1908 // Construct config request string header
1909 //
1910 ConfigHdr = HiiConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, Controller);
1911 if (ConfigHdr == NULL) {
1912 return TRUE;
1913 }
1914
1915 Len = StrLen (ConfigHdr);
1916 ConfigResp = AllocateZeroPool ((Len + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16));
1917 if (ConfigResp == NULL) {
1918 goto ON_EXIT;
1919 }
1920 StrCpy (ConfigResp, ConfigHdr);
1921
1922 String = ConfigResp + Len;
1923 UnicodeSPrint (
1924 String,
1925 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
1926 L"&OFFSET=%04X&WIDTH=%04X",
1927 OFFSET_OF (NIC_IP4_CONFIG_INFO, Source),
1928 sizeof (UINT32)
1929 );
1930
1931 Status = HiiConfigRouting->ExtractConfig (
1932 HiiConfigRouting,
1933 ConfigResp,
1934 &AccessProgress,
1935 &AccessResults
1936 );
1937 if (EFI_ERROR (Status)) {
1938 goto ON_EXIT;
1939 }
1940
1941 ConfigInfo = AllocateZeroPool (sizeof (NIC_ITEM_CONFIG_SIZE));
1942 if (ConfigInfo == NULL) {
1943 goto ON_EXIT;
1944 }
1945
1946 ConfigInfo->Source = IP4_CONFIG_SOURCE_STATIC;
1947 Len = NIC_ITEM_CONFIG_SIZE;
1948 Status = HiiConfigRouting->ConfigToBlock (
1949 HiiConfigRouting,
1950 AccessResults,
1951 (UINT8 *) ConfigInfo,
1952 &Len,
1953 &AccessProgress
1954 );
1955 if (EFI_ERROR (Status)) {
1956 goto ON_EXIT;
1957 }
1958
1959 IsStatic = (BOOLEAN) (ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC);
1960
1961 ON_EXIT:
1962
1963 if (AccessResults != NULL) {
1964 FreePool (AccessResults);
1965 }
1966 if (ConfigInfo != NULL) {
1967 FreePool (ConfigInfo);
1968 }
1969 if (ConfigResp != NULL) {
1970 FreePool (ConfigResp);
1971 }
1972 if (ConfigHdr != NULL) {
1973 FreePool (ConfigHdr);
1974 }
1975
1976 return IsStatic;
1977 }
1978
1979 /**
1980 Create an IPv4 device path node.
1981
1982 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
1983 The header subtype of IPv4 device path node is MSG_IPv4_DP.
1984 The length of the IPv4 device path node in bytes is 19.
1985 Get other info from parameters to make up the whole IPv4 device path node.
1986
1987 @param[in, out] Node Pointer to the IPv4 device path node.
1988 @param[in] Controller The controller handle.
1989 @param[in] LocalIp The local IPv4 address.
1990 @param[in] LocalPort The local port.
1991 @param[in] RemoteIp The remote IPv4 address.
1992 @param[in] RemotePort The remote port.
1993 @param[in] Protocol The protocol type in the IP header.
1994 @param[in] UseDefaultAddress Whether this instance is using default address or not.
1995
1996 **/
1997 VOID
1998 EFIAPI
1999 NetLibCreateIPv4DPathNode (
2000 IN OUT IPv4_DEVICE_PATH *Node,
2001 IN EFI_HANDLE Controller,
2002 IN IP4_ADDR LocalIp,
2003 IN UINT16 LocalPort,
2004 IN IP4_ADDR RemoteIp,
2005 IN UINT16 RemotePort,
2006 IN UINT16 Protocol,
2007 IN BOOLEAN UseDefaultAddress
2008 )
2009 {
2010 Node->Header.Type = MESSAGING_DEVICE_PATH;
2011 Node->Header.SubType = MSG_IPv4_DP;
2012 SetDevicePathNodeLength (&Node->Header, 19);
2013
2014 CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));
2015 CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));
2016
2017 Node->LocalPort = LocalPort;
2018 Node->RemotePort = RemotePort;
2019
2020 Node->Protocol = Protocol;
2021
2022 if (!UseDefaultAddress) {
2023 Node->StaticIpAddress = TRUE;
2024 } else {
2025 Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);
2026 }
2027 }
2028
2029 /**
2030 Create an IPv6 device path node.
2031
2032 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
2033 The header subtype of IPv6 device path node is MSG_IPv6_DP.
2034 Get other info from parameters to make up the whole IPv6 device path node.
2035
2036 @param[in, out] Node Pointer to the IPv6 device path node.
2037 @param[in] Controller The controller handle.
2038 @param[in] LocalIp The local IPv6 address.
2039 @param[in] LocalPort The local port.
2040 @param[in] RemoteIp The remote IPv6 address.
2041 @param[in] RemotePort The remote port.
2042 @param[in] Protocol The protocol type in the IP header.
2043
2044 **/
2045 VOID
2046 EFIAPI
2047 NetLibCreateIPv6DPathNode (
2048 IN OUT IPv6_DEVICE_PATH *Node,
2049 IN EFI_HANDLE Controller,
2050 IN EFI_IPv6_ADDRESS *LocalIp,
2051 IN UINT16 LocalPort,
2052 IN EFI_IPv6_ADDRESS *RemoteIp,
2053 IN UINT16 RemotePort,
2054 IN UINT16 Protocol
2055 )
2056 {
2057 Node->Header.Type = MESSAGING_DEVICE_PATH;
2058 Node->Header.SubType = MSG_IPv6_DP;
2059 SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));
2060
2061 CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));
2062 CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));
2063
2064 Node->LocalPort = LocalPort;
2065 Node->RemotePort = RemotePort;
2066
2067 Node->Protocol = Protocol;
2068 Node->StaticIpAddress = FALSE;
2069 }
2070
2071 /**
2072 Find the UNDI/SNP handle from controller and protocol GUID.
2073
2074 For example, IP will open a MNP child to transmit/receive
2075 packets, when MNP is stopped, IP should also be stopped. IP
2076 needs to find its own private data which is related the IP's
2077 service binding instance that is install on UNDI/SNP handle.
2078 Now, the controller is either a MNP or ARP child handle. But
2079 IP opens these handle BY_DRIVER, use that info, we can get the
2080 UNDI/SNP handle.
2081
2082 @param[in] Controller Then protocol handle to check.
2083 @param[in] ProtocolGuid The protocol that is related with the handle.
2084
2085 @return The UNDI/SNP handle or NULL for errors.
2086
2087 **/
2088 EFI_HANDLE
2089 EFIAPI
2090 NetLibGetNicHandle (
2091 IN EFI_HANDLE Controller,
2092 IN EFI_GUID *ProtocolGuid
2093 )
2094 {
2095 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;
2096 EFI_HANDLE Handle;
2097 EFI_STATUS Status;
2098 UINTN OpenCount;
2099 UINTN Index;
2100
2101 Status = gBS->OpenProtocolInformation (
2102 Controller,
2103 ProtocolGuid,
2104 &OpenBuffer,
2105 &OpenCount
2106 );
2107
2108 if (EFI_ERROR (Status)) {
2109 return NULL;
2110 }
2111
2112 Handle = NULL;
2113
2114 for (Index = 0; Index < OpenCount; Index++) {
2115 if (OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) {
2116 Handle = OpenBuffer[Index].ControllerHandle;
2117 break;
2118 }
2119 }
2120
2121 gBS->FreePool (OpenBuffer);
2122 return Handle;
2123 }