summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c')
-rw-r--r--MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c208
1 files changed, 156 insertions, 52 deletions
diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
index f4ce3ea025..74bf7f76eb 100644
--- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
+++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
@@ -868,6 +868,7 @@ Ip4ConfigProtocol (
EFI_STATUS Status;
IP4_ADDR Ip;
IP4_ADDR Netmask;
+ EFI_ARP_PROTOCOL *Arp;
IpSb = IpInstance->Service;
@@ -972,6 +973,20 @@ Ip4ConfigProtocol (
}
IpInstance->Interface = IpIf;
+ if (IpIf->Arp != NULL) {
+ Arp = NULL;
+ Status = gBS->OpenProtocol (
+ IpIf->ArpHandle,
+ &gEfiArpProtocolGuid,
+ (VOID **) &Arp,
+ gIp4DriverBinding.DriverBindingHandle,
+ IpInstance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
@@ -1028,6 +1043,14 @@ Ip4CleanProtocol (
if (IpInstance->Interface != NULL) {
RemoveEntryList (&IpInstance->AddrLink);
+ if (IpInstance->Interface->Arp != NULL) {
+ gBS->CloseProtocol (
+ IpInstance->Interface->ArpHandle,
+ &gEfiArpProtocolGuid,
+ gIp4DriverBinding.DriverBindingHandle,
+ IpInstance->Handle
+ );
+ }
Ip4FreeInterface (IpInstance->Interface, IpInstance);
IpInstance->Interface = NULL;
}
@@ -1193,14 +1216,6 @@ EfiIp4Configure (
// Validate the configuration first.
//
if (IpConfigData != NULL) {
- //
- // This implementation doesn't support RawData
- //
- if (IpConfigData->RawData) {
- Status = EFI_UNSUPPORTED;
- goto ON_EXIT;
- }
-
CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
@@ -1620,22 +1635,23 @@ Ip4TokenExist (
return EFI_SUCCESS;
}
-
/**
Validate the user's token against current station address.
- @param[in] Token User's token to validate
- @param[in] IpIf The IP4 child's interface.
+ @param[in] Token User's token to validate.
+ @param[in] IpIf The IP4 child's interface.
+ @param[in] RawData Set to TRUE to send unformatted packets.
- @retval EFI_INVALID_PARAMETER Some parameters are invalid
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
@retval EFI_BAD_BUFFER_SIZE The user's option/data is too long.
- @retval EFI_SUCCESS The token is OK
+ @retval EFI_SUCCESS The token is valid.
**/
EFI_STATUS
Ip4TxTokenValid (
IN EFI_IP4_COMPLETION_TOKEN *Token,
- IN IP4_INTERFACE *IpIf
+ IN IP4_INTERFACE *IpIf,
+ IN BOOLEAN RawData
)
{
EFI_IP4_TRANSMIT_DATA *TxData;
@@ -1653,20 +1669,7 @@ Ip4TxTokenValid (
TxData = Token->Packet.TxData;
//
- // Check the IP options: no more than 40 bytes and format is OK
- //
- if (TxData->OptionsLength != 0) {
- if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- //
- // Check the fragment table: no empty fragment, and length isn't bogus
+ // Check the fragment table: no empty fragment, and length isn't bogus.
//
if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
return EFI_INVALID_PARAMETER;
@@ -1674,6 +1677,10 @@ Ip4TxTokenValid (
Offset = TxData->TotalDataLength;
+ if (Offset > IP4_MAX_PACKET_SIZE) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
for (Index = 0; Index < TxData->FragmentCount; Index++) {
if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
(TxData->FragmentTable[Index].FragmentLength == 0)) {
@@ -1689,6 +1696,27 @@ Ip4TxTokenValid (
}
//
+ // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData
+ // is TRUE.
+ //
+ if (RawData) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check the IP options: no more than 40 bytes and format is OK
+ //
+ if (TxData->OptionsLength != 0) {
+ if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
// Check the source and gateway: they must be a valid unicast.
// Gateway must also be on the connected network.
//
@@ -1888,6 +1916,10 @@ EfiIp4Transmit (
EFI_TPL OldTpl;
BOOLEAN DontFragment;
UINT32 HeadLen;
+ UINT8 RawHdrLen;
+ UINT32 OptionsLength;
+ UINT8 *OptionsBuffer;
+ VOID *FirstFragment;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
@@ -1913,7 +1945,7 @@ EfiIp4Transmit (
//
// make sure that token is properly formated
//
- Status = Ip4TxTokenValid (Token, IpIf);
+ Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
@@ -1933,32 +1965,82 @@ EfiIp4Transmit (
//
TxData = Token->Packet.TxData;
- CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
- Head.Dst = NTOHL (Head.Dst);
+ FirstFragment = NULL;
- if (TxData->OverrideData != NULL) {
- Override = TxData->OverrideData;
- Head.Protocol = Override->Protocol;
- Head.Tos = Override->TypeOfService;
- Head.Ttl = Override->TimeToLive;
- DontFragment = Override->DoNotFragment;
+ if (Config->RawData) {
+ //
+ // When RawData is TRUE, first buffer in FragmentTable points to a raw
+ // IPv4 fragment including IPv4 header and options.
+ //
+ FirstFragment = TxData->FragmentTable[0].FragmentBuffer;
+ CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));
- CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
- CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
+ RawHdrLen = (UINT8) (RawHdrLen & 0x0f);
+ if (RawHdrLen < 5) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RawHdrLen = (UINT8) (RawHdrLen << 2);
+
+ CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);
+
+ Ip4NtohHead (&Head);
+ HeadLen = 0;
+ DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);
- Head.Src = NTOHL (Head.Src);
- GateWay = NTOHL (GateWay);
+ if (!DontFragment) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GateWay = IP4_ALLZERO_ADDRESS;
+
+ //
+ // Get IPv4 options from first fragment.
+ //
+ if (RawHdrLen == IP4_MIN_HEADLEN) {
+ OptionsLength = 0;
+ OptionsBuffer = NULL;
+ } else {
+ OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;
+ OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;
+ }
+
+ //
+ // Trim off IPv4 header and options from first fragment.
+ //
+ TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;
+ TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;
} else {
- Head.Src = IpIf->Ip;
- GateWay = IP4_ALLZERO_ADDRESS;
- Head.Protocol = Config->DefaultProtocol;
- Head.Tos = Config->TypeOfService;
- Head.Ttl = Config->TimeToLive;
- DontFragment = Config->DoNotFragment;
- }
+ CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
+ Head.Dst = NTOHL (Head.Dst);
- Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
- HeadLen = (TxData->OptionsLength + 3) & (~0x03);
+ if (TxData->OverrideData != NULL) {
+ Override = TxData->OverrideData;
+ Head.Protocol = Override->Protocol;
+ Head.Tos = Override->TypeOfService;
+ Head.Ttl = Override->TimeToLive;
+ DontFragment = Override->DoNotFragment;
+
+ CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
+ CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
+
+ Head.Src = NTOHL (Head.Src);
+ GateWay = NTOHL (GateWay);
+ } else {
+ Head.Src = IpIf->Ip;
+ GateWay = IP4_ALLZERO_ADDRESS;
+ Head.Protocol = Config->DefaultProtocol;
+ Head.Tos = Config->TypeOfService;
+ Head.Ttl = Config->TimeToLive;
+ DontFragment = Config->DoNotFragment;
+ }
+
+ Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
+ HeadLen = (TxData->OptionsLength + 3) & (~0x03);
+
+ OptionsLength = TxData->OptionsLength;
+ OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);
+ }
//
// If don't fragment and fragment needed, return error
@@ -2004,6 +2086,13 @@ EfiIp4Transmit (
// free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
// enqueued.
//
+ if (Config->RawData) {
+ //
+ // Restore pointer of first fragment in RawData mode.
+ //
+ TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
+ }
+
NetbufFree (Wrap->Packet);
goto ON_EXIT;
}
@@ -2019,8 +2108,8 @@ EfiIp4Transmit (
IpInstance,
Wrap->Packet,
&Head,
- TxData->OptionsBuffer,
- TxData->OptionsLength,
+ OptionsBuffer,
+ OptionsLength,
GateWay,
Ip4OnPacketSent,
Wrap
@@ -2028,9 +2117,24 @@ EfiIp4Transmit (
if (EFI_ERROR (Status)) {
Wrap->Sent = FALSE;
+
+ if (Config->RawData) {
+ //
+ // Restore pointer of first fragment in RawData mode.
+ //
+ TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
+ }
+
NetbufFree (Wrap->Packet);
}
+ if (Config->RawData) {
+ //
+ // Restore pointer of first fragment in RawData mode.
+ //
+ TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
+ }
+
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;