123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- /** @file
- The implementation of common functions shared by IP6 driver.
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Ip6Impl.h"
- /**
- Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
- of EFI_IP6_ADDRESS_INFO is also returned. If AddressList is NULL,
- only the address count is returned.
- @param[in] IpSb The IP6 service binding instance.
- @param[out] AddressCount The number of returned addresses.
- @param[out] AddressList The pointer to the array of EFI_IP6_ADDRESS_INFO.
- This is an optional parameter.
- @retval EFI_SUCCESS The address array successfully built.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the address info.
- @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
- **/
- EFI_STATUS
- Ip6BuildEfiAddressList (
- IN IP6_SERVICE *IpSb,
- OUT UINT32 *AddressCount,
- OUT EFI_IP6_ADDRESS_INFO **AddressList OPTIONAL
- )
- {
- UINT32 Count;
- LIST_ENTRY *Entry;
- EFI_IP6_ADDRESS_INFO *EfiAddrInfo;
- IP6_ADDRESS_INFO *AddrInfo;
- if (AddressCount == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (IpSb->LinkLocalOk) {
- Count = 1 + IpSb->DefaultInterface->AddressCount;
- } else {
- Count = 0;
- }
- *AddressCount = Count;
- if ((AddressList == NULL) || (Count == 0)) {
- return EFI_SUCCESS;
- }
- if (*AddressList == NULL) {
- *AddressList = AllocatePool (sizeof (EFI_IP6_ADDRESS_INFO) * Count);
- if (*AddressList == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
- EfiAddrInfo = *AddressList;
- IP6_COPY_ADDRESS (&EfiAddrInfo->Address, &IpSb->LinkLocalAddr);
- EfiAddrInfo->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
- EfiAddrInfo++;
- Count = 1;
- NET_LIST_FOR_EACH (Entry, &IpSb->DefaultInterface->AddressList) {
- AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
- IP6_COPY_ADDRESS (&EfiAddrInfo->Address, &AddrInfo->Address);
- EfiAddrInfo->PrefixLength = AddrInfo->PrefixLength;
- EfiAddrInfo++;
- Count++;
- }
- ASSERT (Count == *AddressCount);
- return EFI_SUCCESS;
- }
- /**
- Generate the multicast addresses identify the group of all IPv6 nodes or IPv6
- routers defined in RFC4291.
- All Nodes Addresses: FF01::1, FF02::1.
- All Router Addresses: FF01::2, FF02::2, FF05::2.
- @param[in] Router If TRUE, generate all routers addresses,
- else generate all node addresses.
- @param[in] Scope interface-local(1), link-local(2), or site-local(5)
- @param[out] Ip6Addr The generated multicast address.
- @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
- @retval EFI_SUCCESS The address is generated.
- **/
- EFI_STATUS
- Ip6SetToAllNodeMulticast (
- IN BOOLEAN Router,
- IN UINT8 Scope,
- OUT EFI_IPv6_ADDRESS *Ip6Addr
- )
- {
- if (Ip6Addr == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (!Router && (Scope == IP6_SITE_LOCAL_SCOPE)) {
- return EFI_INVALID_PARAMETER;
- }
- ZeroMem (Ip6Addr, sizeof (EFI_IPv6_ADDRESS));
- Ip6Addr->Addr[0] = 0xFF;
- Ip6Addr->Addr[1] = Scope;
- if (!Router) {
- Ip6Addr->Addr[15] = 0x1;
- } else {
- Ip6Addr->Addr[15] = 0x2;
- }
- return EFI_SUCCESS;
- }
- /**
- This function converts MAC address to 64 bits interface ID according to RFC4291
- and returns the interface ID. Currently only 48-bit MAC address is supported by
- this function.
- @param[in, out] IpSb The IP6 service binding instance.
- @retval NULL The operation fails.
- @return Pointer to the generated interface ID.
- **/
- UINT8 *
- Ip6CreateInterfaceID (
- IN OUT IP6_SERVICE *IpSb
- )
- {
- UINT8 InterfaceId[8];
- UINT8 Byte;
- EFI_MAC_ADDRESS *MacAddr;
- UINT32 AddrLen;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- AddrLen = IpSb->SnpMode.HwAddressSize;
- //
- // Currently only IEEE 802 48-bit MACs are supported to create link local address.
- //
- if ((AddrLen != IP6_MAC_LEN) || (IpSb->InterfaceIdLen != IP6_IF_ID_LEN)) {
- return NULL;
- }
- MacAddr = &IpSb->SnpMode.CurrentAddress;
- //
- // Convert MAC address to 64 bits interface ID according to Appendix A of RFC4291:
- // 1. Insert 0xFFFE to the middle
- // 2. Invert the universal/local bit - bit 6 in network order
- //
- CopyMem (InterfaceId, MacAddr, 3);
- InterfaceId[3] = 0xFF;
- InterfaceId[4] = 0xFE;
- CopyMem (&InterfaceId[5], &MacAddr->Addr[3], 3);
- Byte = (UINT8)(InterfaceId[0] & IP6_U_BIT);
- if (Byte == IP6_U_BIT) {
- InterfaceId[0] &= ~IP6_U_BIT;
- } else {
- InterfaceId[0] |= IP6_U_BIT;
- }
- //
- // Return the interface ID.
- //
- return AllocateCopyPool (IpSb->InterfaceIdLen, InterfaceId);
- }
- /**
- This function creates link-local address from interface identifier. The
- interface identifier is normally created from MAC address. It might be manually
- configured by administrator if the link-local address created from MAC address
- is a duplicate address.
- @param[in, out] IpSb The IP6 service binding instance.
- @retval NULL If the operation fails.
- @return The generated Link Local address, in network order.
- **/
- EFI_IPv6_ADDRESS *
- Ip6CreateLinkLocalAddr (
- IN OUT IP6_SERVICE *IpSb
- )
- {
- EFI_IPv6_ADDRESS *Ip6Addr;
- EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
- UINTN DataSize;
- EFI_IP6_CONFIG_INTERFACE_ID InterfaceId;
- EFI_STATUS Status;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- if (IpSb->InterfaceId != NULL) {
- FreePool (IpSb->InterfaceId);
- }
- //
- // Get the interface id if it is manually configured.
- //
- Ip6Config = &IpSb->Ip6ConfigInstance.Ip6Config;
- DataSize = sizeof (EFI_IP6_CONFIG_INTERFACE_ID);
- ZeroMem (&InterfaceId, DataSize);
- Status = Ip6Config->GetData (
- Ip6Config,
- Ip6ConfigDataTypeAltInterfaceId,
- &DataSize,
- &InterfaceId
- );
- if (Status == EFI_NOT_FOUND) {
- //
- // Since the interface id is not configured, generate the interface id from
- // MAC address.
- //
- IpSb->InterfaceId = Ip6CreateInterfaceID (IpSb);
- if (IpSb->InterfaceId == NULL) {
- return NULL;
- }
- CopyMem (&InterfaceId, IpSb->InterfaceId, IpSb->InterfaceIdLen);
- //
- // Record the interface id.
- //
- Status = Ip6Config->SetData (
- Ip6Config,
- Ip6ConfigDataTypeAltInterfaceId,
- DataSize,
- &InterfaceId
- );
- if (EFI_ERROR (Status)) {
- FreePool (IpSb->InterfaceId);
- IpSb->InterfaceId = NULL;
- return NULL;
- }
- } else if (!EFI_ERROR (Status)) {
- IpSb->InterfaceId = AllocateCopyPool (DataSize, &InterfaceId);
- if (IpSb->InterfaceId == NULL) {
- return NULL;
- }
- } else {
- return NULL;
- }
- //
- // Append FE80::/64 to the left of IPv6 address then return.
- //
- Ip6Addr = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
- if (Ip6Addr == NULL) {
- FreePool (IpSb->InterfaceId);
- IpSb->InterfaceId = NULL;
- return NULL;
- }
- CopyMem (&Ip6Addr->Addr[8], IpSb->InterfaceId, IpSb->InterfaceIdLen);
- Ip6Addr->Addr[1] = 0x80;
- Ip6Addr->Addr[0] = 0xFE;
- return Ip6Addr;
- }
- /**
- Compute the solicited-node multicast address for an unicast or anycast address,
- by taking the low-order 24 bits of this address, and appending those bits to
- the prefix FF02:0:0:0:0:1:FF00::/104.
- @param[in] Ip6Addr The unicast or anycast address, in network order.
- @param[out] MulticastAddr The generated solicited-node multicast address,
- in network order.
- **/
- VOID
- Ip6CreateSNMulticastAddr (
- IN EFI_IPv6_ADDRESS *Ip6Addr,
- OUT EFI_IPv6_ADDRESS *MulticastAddr
- )
- {
- ASSERT (Ip6Addr != NULL && MulticastAddr != NULL);
- ZeroMem (MulticastAddr, sizeof (EFI_IPv6_ADDRESS));
- MulticastAddr->Addr[0] = 0xFF;
- MulticastAddr->Addr[1] = 0x02;
- MulticastAddr->Addr[11] = 0x1;
- MulticastAddr->Addr[12] = 0xFF;
- CopyMem (&MulticastAddr->Addr[13], &Ip6Addr->Addr[13], 3);
- }
- /**
- Insert a node IP6_ADDRESS_INFO to an IP6 interface.
- @param[in, out] IpIf Points to an IP6 interface.
- @param[in] AddrInfo Points to IP6_ADDRESS_INFO
- **/
- VOID
- Ip6AddAddr (
- IN OUT IP6_INTERFACE *IpIf,
- IN IP6_ADDRESS_INFO *AddrInfo
- )
- {
- InsertHeadList (&IpIf->AddressList, &AddrInfo->Link);
- IpIf->AddressCount++;
- }
- /**
- Callback function which provided by user to remove one node in NetDestroyLinkList process.
- @param[in] Entry The entry to be removed.
- @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
- @retval EFI_SUCCESS The entry has been removed successfully.
- @retval Others Fail to remove the entry.
- **/
- EFI_STATUS
- EFIAPI
- Ip6DestroyChildEntryByAddr (
- IN LIST_ENTRY *Entry,
- IN VOID *Context
- )
- {
- IP6_PROTOCOL *Instance;
- EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
- EFI_IPv6_ADDRESS *Address;
- Instance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
- ServiceBinding = ((IP6_DESTROY_CHILD_BY_ADDR_CALLBACK_CONTEXT *)Context)->ServiceBinding;
- Address = ((IP6_DESTROY_CHILD_BY_ADDR_CALLBACK_CONTEXT *)Context)->Address;
- if ((Instance->State == IP6_STATE_CONFIGED) && EFI_IP6_EQUAL (&Instance->ConfigData.StationAddress, Address)) {
- return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
- }
- return EFI_SUCCESS;
- }
- /**
- Destroy the IP instance if its StationAddress is removed. It is the help function
- for Ip6RemoveAddr().
- @param[in, out] IpSb Points to an IP6 service binding instance.
- @param[in] Address The to be removed address
- **/
- VOID
- Ip6DestroyInstanceByAddress (
- IN OUT IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *Address
- )
- {
- LIST_ENTRY *List;
- IP6_DESTROY_CHILD_BY_ADDR_CALLBACK_CONTEXT Context;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- List = &IpSb->Children;
- Context.ServiceBinding = &IpSb->ServiceBinding;
- Context.Address = Address;
- NetDestroyLinkList (
- List,
- Ip6DestroyChildEntryByAddr,
- &Context,
- NULL
- );
- }
- /**
- Remove the IPv6 address from the address list node points to IP6_ADDRESS_INFO.
- This function removes the matching IPv6 addresses from the address list and
- adjusts the address count of the address list. If IpSb is not NULL, this function
- calls Ip6LeaveGroup to see whether it should call Mnp->Groups() to remove the
- its solicited-node multicast MAC address from the filter list and sends out
- a Multicast Listener Done. If Prefix is NULL, all address in the address list
- will be removed. If Prefix is not NULL, the address that matching the Prefix
- with PrefixLength in the address list will be removed.
- @param[in] IpSb NULL or points to IP6 service binding instance.
- @param[in, out] AddressList Address list array.
- @param[in, out] AddressCount The count of addresses in address list array.
- @param[in] Prefix NULL or an IPv6 address prefix.
- @param[in] PrefixLength The length of Prefix.
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_NOT_FOUND The address matching the Prefix with PrefixLength
- cannot be found in the address list.
- @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
- **/
- EFI_STATUS
- Ip6RemoveAddr (
- IN IP6_SERVICE *IpSb OPTIONAL,
- IN OUT LIST_ENTRY *AddressList,
- IN OUT UINT32 *AddressCount,
- IN EFI_IPv6_ADDRESS *Prefix OPTIONAL,
- IN UINT8 PrefixLength
- )
- {
- EFI_STATUS Status;
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP6_ADDRESS_INFO *AddrInfo;
- EFI_IPv6_ADDRESS SnMCastAddr;
- if (IsListEmpty (AddressList) || (*AddressCount < 1) || (PrefixLength > IP6_PREFIX_MAX)) {
- return EFI_INVALID_PARAMETER;
- }
- Status = EFI_NOT_FOUND;
- NET_LIST_FOR_EACH_SAFE (Entry, Next, AddressList) {
- AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
- if ((Prefix == NULL) ||
- ((PrefixLength == 128) && EFI_IP6_EQUAL (Prefix, &AddrInfo->Address)) ||
- ((PrefixLength == AddrInfo->PrefixLength) && NetIp6IsNetEqual (Prefix, &AddrInfo->Address, PrefixLength))
- )
- {
- if (IpSb != NULL) {
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- Ip6CreateSNMulticastAddr (&AddrInfo->Address, &SnMCastAddr);
- Ip6LeaveGroup (IpSb, &SnMCastAddr);
- //
- // Destroy any instance who is using the dying address as the source address.
- //
- Ip6DestroyInstanceByAddress (IpSb, &AddrInfo->Address);
- }
- RemoveEntryList (Entry);
- FreePool (AddrInfo);
- (*AddressCount)--;
- Status = EFI_SUCCESS;
- }
- }
- return Status;
- }
- /**
- Check whether the incoming Ipv6 address is a solicited-node multicast address.
- @param[in] Ip6 Ip6 address, in network order.
- @retval TRUE Yes, solicited-node multicast address
- @retval FALSE No
- **/
- BOOLEAN
- Ip6IsSNMulticastAddr (
- IN EFI_IPv6_ADDRESS *Ip6
- )
- {
- EFI_IPv6_ADDRESS Sn;
- BOOLEAN Flag;
- Ip6CreateSNMulticastAddr (Ip6, &Sn);
- Flag = FALSE;
- if (CompareMem (Sn.Addr, Ip6->Addr, 13) == 0) {
- Flag = TRUE;
- }
- return Flag;
- }
- /**
- Check whether the incoming IPv6 address is one of the maintained addresses in
- the IP6 service binding instance.
- @param[in] IpSb Points to a IP6 service binding instance.
- @param[in] Address The IP6 address to be checked.
- @param[out] Interface If not NULL, output the IP6 interface which
- maintains the Address.
- @param[out] AddressInfo If not NULL, output the IP6 address information
- of the Address.
- @retval TRUE Yes, it is one of the maintained address.
- @retval FALSE No, it is not one of the maintained address.
- **/
- BOOLEAN
- Ip6IsOneOfSetAddress (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *Address,
- OUT IP6_INTERFACE **Interface OPTIONAL,
- OUT IP6_ADDRESS_INFO **AddressInfo OPTIONAL
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Entry2;
- IP6_INTERFACE *IpIf;
- IP6_ADDRESS_INFO *TmpAddressInfo;
- //
- // Check link-local address first
- //
- if (IpSb->LinkLocalOk && EFI_IP6_EQUAL (&IpSb->LinkLocalAddr, Address)) {
- if (Interface != NULL) {
- *Interface = IpSb->DefaultInterface;
- }
- if (AddressInfo != NULL) {
- *AddressInfo = NULL;
- }
- return TRUE;
- }
- NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
- IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
- NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
- TmpAddressInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
- if (EFI_IP6_EQUAL (&TmpAddressInfo->Address, Address)) {
- if (Interface != NULL) {
- *Interface = IpIf;
- }
- if (AddressInfo != NULL) {
- *AddressInfo = TmpAddressInfo;
- }
- return TRUE;
- }
- }
- }
- return FALSE;
- }
- /**
- Check whether the incoming MAC address is valid.
- @param[in] IpSb Points to a IP6 service binding instance.
- @param[in] LinkAddress The MAC address.
- @retval TRUE Yes, it is valid.
- @retval FALSE No, it is not valid.
- **/
- BOOLEAN
- Ip6IsValidLinkAddress (
- IN IP6_SERVICE *IpSb,
- IN EFI_MAC_ADDRESS *LinkAddress
- )
- {
- UINT32 Index;
- //
- // TODO: might be updated later to be more acceptable.
- //
- for (Index = IpSb->SnpMode.HwAddressSize; Index < sizeof (EFI_MAC_ADDRESS); Index++) {
- if (LinkAddress->Addr[Index] != 0) {
- return FALSE;
- }
- }
- return TRUE;
- }
- /**
- Copy the PrefixLength bits from Src to Dest.
- @param[out] Dest A pointer to the buffer to copy to.
- @param[in] Src A pointer to the buffer to copy from.
- @param[in] PrefixLength The number of bits to copy.
- **/
- VOID
- Ip6CopyAddressByPrefix (
- OUT EFI_IPv6_ADDRESS *Dest,
- IN EFI_IPv6_ADDRESS *Src,
- IN UINT8 PrefixLength
- )
- {
- UINT8 Byte;
- UINT8 Bit;
- UINT8 Mask;
- ASSERT (Dest != NULL && Src != NULL);
- ASSERT (PrefixLength <= IP6_PREFIX_MAX);
- Byte = (UINT8)(PrefixLength / 8);
- Bit = (UINT8)(PrefixLength % 8);
- ZeroMem (Dest, sizeof (EFI_IPv6_ADDRESS));
- CopyMem (Dest, Src, Byte);
- if (Bit > 0) {
- Mask = (UINT8)(0xFF << (8 - Bit));
- ASSERT (Byte < 16);
- Dest->Addr[Byte] = (UINT8)(Src->Addr[Byte] & Mask);
- }
- }
- /**
- Get the MAC address for a multicast IP address. Call
- Mnp's McastIpToMac to find the MAC address instead of
- hard-coding the NIC to be Ethernet.
- @param[in] Mnp The Mnp instance to get the MAC address.
- @param[in] Multicast The multicast IP address to translate.
- @param[out] Mac The buffer to hold the translated address.
- @retval EFI_SUCCESS The multicast IP successfully
- translated to a multicast MAC address.
- @retval Other The address is not converted because an error occurred.
- **/
- EFI_STATUS
- Ip6GetMulticastMac (
- IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
- IN EFI_IPv6_ADDRESS *Multicast,
- OUT EFI_MAC_ADDRESS *Mac
- )
- {
- EFI_IP_ADDRESS EfiIp;
- IP6_COPY_ADDRESS (&EfiIp.v6, Multicast);
- return Mnp->McastIpToMac (Mnp, TRUE, &EfiIp, Mac);
- }
- /**
- Convert the multibyte field in IP header's byter order.
- In spite of its name, it can also be used to convert from
- host to network byte order.
- @param[in, out] Head The IP head to convert.
- @return Point to the converted IP head.
- **/
- EFI_IP6_HEADER *
- Ip6NtohHead (
- IN OUT EFI_IP6_HEADER *Head
- )
- {
- Head->FlowLabelL = NTOHS (Head->FlowLabelL);
- Head->PayloadLength = NTOHS (Head->PayloadLength);
- return Head;
- }
|