X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FNetwork%2FIp4Dxe%2FIp4Input.c;h=d888e18e4cc7d6b8cc83b12d9a28afa092bec47e;hb=a167ecb13fc20bf4a2a45ef9aeda976e0498bf61;hp=b495e75deb88689eb6f6e0268c9ed020216c6546;hpb=d8d26fb207e02aa5ef57e2bcb213f9dda16166cc;p=mirror_edk2.git diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c index b495e75deb..d888e18e4c 100644 --- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c +++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c @@ -1,8 +1,8 @@ /** @file IP4 input process. -Copyright (c) 2005 - 2009, Intel Corporation.
-All rights reserved. This program and the accompanying materials +Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php @@ -85,7 +85,7 @@ Ip4FreeAssembleEntry ( NetbufFree (Fragment); } - gBS->FreePool (Assemble); + FreePool (Assemble); } @@ -188,6 +188,7 @@ Ip4TrimPacket ( **/ VOID +EFIAPI Ip4OnFreeFragments ( IN VOID *Arg ) @@ -228,7 +229,7 @@ Ip4Reassemble ( NET_BUF *NewPacket; INTN Index; - IpHead = Packet->Ip; + IpHead = Packet->Ip.Ip4; This = IP4_GET_CLIP_INFO (Packet); ASSERT (IpHead != NULL); @@ -291,7 +292,7 @@ Ip4Reassemble ( // check whether THIS.Start < PREV.End for overlap. If two fragments // overlaps, trim the overlapped part off THIS fragment. // - if ((Prev = Cur->ForwardLink) != Head) { + if ((Cur != Head) && ((Prev = Cur->BackLink) != Head)) { Fragment = NET_LIST_USER_STRUCT (Prev, NET_BUF, List); Node = IP4_GET_CLIP_INFO (Fragment); @@ -417,7 +418,7 @@ Ip4Reassemble ( return NULL; } - NewPacket->Ip = Assemble->Head; + NewPacket->Ip.Ip4 = Assemble->Head; CopyMem (IP4_GET_CLIP_INFO (NewPacket), Assemble->Info, sizeof (*IP4_GET_CLIP_INFO (NewPacket))); return NewPacket; } @@ -429,6 +430,220 @@ DROP: return NULL; } +/** + The callback function for the net buffer which wraps the packet processed by + IPsec. It releases the wrap packet and also signals IPsec to free the resources. + + @param[in] Arg The wrap context + +**/ +VOID +EFIAPI +Ip4IpSecFree ( + IN VOID *Arg + ) +{ + IP4_IPSEC_WRAP *Wrap; + + Wrap = (IP4_IPSEC_WRAP *) Arg; + + if (Wrap->IpSecRecycleSignal != NULL) { + gBS->SignalEvent (Wrap->IpSecRecycleSignal); + } + + NetbufFree (Wrap->Packet); + + FreePool (Wrap); + + return; +} + +/** + The work function to locate IPsec protocol to process the inbound or + outbound IP packets. The process routine handls the packet with following + actions: bypass the packet, discard the packet, or protect the packet. + + @param[in] IpSb The IP4 service instance + @param[in] Head The The caller supplied IP4 header. + @param[in, out] Netbuf The IP4 packet to be processed by IPsec + @param[in] Options The caller supplied options + @param[in] OptionsLen The length of the option + @param[in] Direction The directionality in an SPD entry, + EfiIPsecInBound or EfiIPsecOutBound + @param[in] Context The token's wrap + + @retval EFI_SUCCESS The IPsec protocol is not available or disabled. + @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same. + @retval EFI_SUCCESS The packet was protected. + @retval EFI_ACCESS_DENIED The packet was discarded. + @retval EFI_OUT_OF_RESOURCES There is no suffcient resource to complete the operation. + @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than the + number of input data blocks when build a fragment table. + +**/ +EFI_STATUS +Ip4IpSecProcessPacket ( + IN IP4_SERVICE *IpSb, + IN IP4_HEAD *Head, + IN OUT NET_BUF **Netbuf, + IN UINT8 *Options, + IN UINT32 OptionsLen, + IN EFI_IPSEC_TRAFFIC_DIR Direction, + IN VOID *Context + ) +{ + NET_FRAGMENT *FragmentTable; + UINT32 FragmentCount; + EFI_EVENT RecycleEvent; + NET_BUF *Packet; + IP4_TXTOKEN_WRAP *TxWrap; + IP4_IPSEC_WRAP *IpSecWrap; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + Packet = *Netbuf; + RecycleEvent = NULL; + IpSecWrap = NULL; + FragmentTable = NULL; + TxWrap = (IP4_TXTOKEN_WRAP *) Context; + FragmentCount = Packet->BlockOpNum; + + if (mIpSec == NULL) { + gBS->LocateProtocol (&gEfiIpSecProtocolGuid, NULL, (VOID **) &mIpSec); + if (mIpSec != NULL) { + // + // Save the original MTU + // + IpSb->OldMaxPacketSize = IpSb->MaxPacketSize; + } + } + + // + // Check whether the IPsec protocol is available. + // + if (mIpSec == NULL) { + goto ON_EXIT; + } + // + // Check whether the IPsec enable variable is set. + // + if (mIpSec->DisabledFlag) { + // + // If IPsec is disabled, restore the original MTU + // + IpSb->MaxPacketSize = IpSb->OldMaxPacketSize; + goto ON_EXIT; + } else { + // + // If IPsec is enabled, use the MTU which reduce the IPsec header length. + // + IpSb->MaxPacketSize = IpSb->OldMaxPacketSize - IP4_MAX_IPSEC_HEADLEN; + } + + // + // Rebuild fragment table from netbuf to ease IPsec process. + // + FragmentTable = AllocateZeroPool (FragmentCount * sizeof (NET_FRAGMENT)); + + if (FragmentTable == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = NetbufBuildExt (Packet, FragmentTable, &FragmentCount); + + if (EFI_ERROR (Status)) { + FreePool (FragmentTable); + goto ON_EXIT; + } + + // + // Convert host byte order to network byte order + // + Ip4NtohHead (Head); + + Status = mIpSec->Process ( + mIpSec, + IpSb->Controller, + IP_VERSION_4, + (VOID *) Head, + &Head->Protocol, + NULL, + 0, + (EFI_IPSEC_FRAGMENT_DATA **) (&FragmentTable), + &FragmentCount, + Direction, + &RecycleEvent + ); + // + // Convert back to host byte order + // + Ip4NtohHead (Head); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (Direction == EfiIPsecOutBound && TxWrap != NULL) { + + TxWrap->IpSecRecycleSignal = RecycleEvent; + TxWrap->Packet = NetbufFromExt ( + FragmentTable, + FragmentCount, + IP4_MAX_HEADLEN, + 0, + Ip4FreeTxToken, + TxWrap + ); + if (TxWrap->Packet == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + *Netbuf = TxWrap->Packet; + + } else { + + IpSecWrap = AllocateZeroPool (sizeof (IP4_IPSEC_WRAP)); + + if (IpSecWrap == NULL) { + goto ON_EXIT; + } + + IpSecWrap->IpSecRecycleSignal = RecycleEvent; + IpSecWrap->Packet = Packet; + Packet = NetbufFromExt ( + FragmentTable, + FragmentCount, + IP4_MAX_HEADLEN, + 0, + Ip4IpSecFree, + IpSecWrap + ); + + if (Packet == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + if (Direction == EfiIPsecInBound) { + Ip4PrependHead (Packet, Head, Options, OptionsLen); + Ip4NtohHead (Packet->Ip.Ip4); + NetbufTrim (Packet, (Head->HeadLen << 2), TRUE); + + CopyMem ( + IP4_GET_CLIP_INFO (Packet), + IP4_GET_CLIP_INFO (IpSecWrap->Packet), + sizeof (IP4_CLIP_INFO) + ); + } + + *Netbuf = Packet; + } + +ON_EXIT: + return Status; +} /** The IP4 input routine. It is called by the IP4_INTERFACE when a @@ -459,6 +674,7 @@ Ip4AccpetFrame ( UINT32 OptionLen; UINT32 TotalLen; UINT16 Checksum; + EFI_STATUS Status; IpSb = (IP4_SERVICE *) Context; @@ -501,7 +717,7 @@ Ip4AccpetFrame ( // // Convert the IP header to host byte order, then get the per packet info. // - Packet->Ip = Ip4NtohHead (Head); + Packet->Ip.Ip4 = Ip4NtohHead (Head); Info = IP4_GET_CLIP_INFO (Packet); Info->LinkFlag = Flag; @@ -566,15 +782,31 @@ Ip4AccpetFrame ( } // + // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer, + // and no need consider any other ahead ext headers. + // + Status = Ip4IpSecProcessPacket ( + IpSb, + Head, + &Packet, + NULL, + 0, + EfiIPsecInBound, + NULL + ); + + if (EFI_ERROR(Status)) { + goto RESTART; + } // Packet may have been changed. Head, HeadLen, TotalLen, and // info must be reloaded bofore use. The ownership of the packet // is transfered to the packet process logic. // - Head = Packet->Ip; + Head = Packet->Ip.Ip4; IP4_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS; switch (Head->Protocol) { - case IP4_PROTO_ICMP: + case EFI_IP_PROTO_ICMP: Ip4IcmpHandle (IpSb, Head, Packet); break; @@ -651,11 +883,11 @@ Ip4InstanceFrameAcceptable ( // // Use protocol from the IP header embedded in the ICMP error // message to filter, instead of ICMP itself. ICMP handle will - // can Ip4Demultiplex to deliver ICMP errors. + // call Ip4Demultiplex to deliver ICMP errors. // Proto = Head->Protocol; - if (Proto == IP4_PROTO_ICMP) { + if ((Proto == EFI_IP_PROTO_ICMP) && (!Config->AcceptAnyProtocol) && (Proto != Config->DefaultProtocol)) { NetbufCopy (Packet, 0, sizeof (Icmp.Head), (UINT8 *) &Icmp.Head); if (mIcmpClass[Icmp.Head.Type].IcmpClass == ICMP_ERROR_MESSAGE) { @@ -794,7 +1026,7 @@ Ip4OnRecyclePacket ( NetbufFree (Wrap->Packet); gBS->CloseEvent (Wrap->RxData.RecycleSignal); - gBS->FreePool (Wrap); + FreePool (Wrap); } @@ -846,17 +1078,17 @@ Ip4WrapRxData ( ); if (EFI_ERROR (Status)) { - gBS->FreePool (Wrap); + FreePool (Wrap); return NULL; } - ASSERT (Packet->Ip != NULL); + ASSERT (Packet->Ip.Ip4 != NULL); // // The application expects a network byte order header. // - RxData->HeaderLength = (Packet->Ip->HeadLen << 2); - RxData->Header = (EFI_IP4_HEADER *) Ip4NtohHead (Packet->Ip); + RxData->HeaderLength = (Packet->Ip.Ip4->HeadLen << 2); + RxData->Header = (EFI_IP4_HEADER *) Ip4NtohHead (Packet->Ip.Ip4); RxData->OptionsLength = RxData->HeaderLength - IP4_MIN_HEADLEN; RxData->Options = NULL; @@ -938,9 +1170,9 @@ Ip4InstanceDeliverPacket ( // may be not continuous before the data. // Head = NetbufAllocSpace (Dup, IP4_MAX_HEADLEN, NET_BUF_HEAD); - Dup->Ip = (IP4_HEAD *) Head; + Dup->Ip.Ip4 = (IP4_HEAD *) Head; - CopyMem (Head, Packet->Ip, Packet->Ip->HeadLen << 2); + CopyMem (Head, Packet->Ip.Ip4, Packet->Ip.Ip4->HeadLen << 2); NetbufTrim (Dup, IP4_MAX_HEADLEN, TRUE); Wrap = Ip4WrapRxData (IpInstance, Dup);