mirror of https://github.com/acidanthera/audk.git
MdeModulePkg/Network: Add 32bit subnet mask support for IP4 PXE boot.
This patch updates IP4 stack to support 32bit subnet mask in PXE boot process. When 32bit subnet mask is used, the IP4 driver couldn't use the subnet mask to determine whether destination IP address is on-link or not, so it will always try to send all the packets to the destination IP address directly first, if failed it will continue to try the default gateway. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> Reviewed-by: Wu Jiaxin <jiaxin.wu@intel.com>
This commit is contained in:
parent
1e57188216
commit
12ae56cf28
|
@ -422,8 +422,9 @@ NetGetIpClass (
|
|||
|
||||
If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address,
|
||||
except when the originator is one of the endpoints of a point-to-point link with a 31-bit
|
||||
mask (RFC3021).
|
||||
|
||||
mask (RFC3021), or a 32bit NetMask (all 0xFF) is used for special network environment (e.g.
|
||||
PPP link).
|
||||
|
||||
@param[in] Ip The IP to check against.
|
||||
@param[in] NetMask The mask of the IP.
|
||||
|
||||
|
|
|
@ -654,8 +654,9 @@ NetGetIpClass (
|
|||
|
||||
If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address,
|
||||
except when the originator is one of the endpoints of a point-to-point link with a 31-bit
|
||||
mask (RFC3021).
|
||||
|
||||
mask (RFC3021), or a 32bit NetMask (all 0xFF) is used for special network environment (e.g.
|
||||
PPP link).
|
||||
|
||||
@param[in] Ip The IP to check against.
|
||||
@param[in] NetMask The mask of the IP.
|
||||
|
||||
|
@ -669,18 +670,20 @@ NetIp4IsUnicast (
|
|||
IN IP4_ADDR NetMask
|
||||
)
|
||||
{
|
||||
INTN MaskLength;
|
||||
|
||||
ASSERT (NetMask != 0);
|
||||
|
||||
if (Ip == 0 || IP4_IS_LOCAL_BROADCAST (Ip)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (NetGetMaskLength (NetMask) != 31) {
|
||||
MaskLength = NetGetMaskLength (NetMask);
|
||||
ASSERT ((MaskLength >= 0) && (MaskLength <= IP4_MASK_NUM));
|
||||
if (MaskLength < 31) {
|
||||
if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
|
@ -55,7 +55,7 @@ typedef struct _IP4_SERVICE IP4_SERVICE;
|
|||
/// Compose the fragment field to be used in the IP4 header.
|
||||
///
|
||||
#define IP4_HEAD_FRAGMENT_FIELD(Df, Mf, Offset) \
|
||||
((UINT16)(((Df) ? 0x4000 : 0) | ((Mf) ? 0x2000 : 0) | (((Offset) >> 3) & 0x1fff)))
|
||||
((UINT16)(((Df) ? IP4_HEAD_DF_MASK : 0) | ((Mf) ? IP4_HEAD_MF_MASK : 0) | (((Offset) >> 3) & IP4_HEAD_OFFSET_MASK)))
|
||||
|
||||
#define IP4_LAST_FRAGMENT(FragmentField) \
|
||||
(((FragmentField) & IP4_HEAD_MF_MASK) == 0)
|
||||
|
|
|
@ -138,6 +138,7 @@ Ip4CancelFrameArp (
|
|||
@param[in] CallBack Call back function to execute if transmission
|
||||
finished.
|
||||
@param[in] Context Opaque parameter to the call back.
|
||||
@param[in] IpSb The pointer to the IP4 service binding instance.
|
||||
|
||||
@retval Token The wrapped token if succeed
|
||||
@retval NULL The wrapped token if NULL
|
||||
|
@ -149,7 +150,8 @@ Ip4WrapLinkTxToken (
|
|||
IN IP4_PROTOCOL *IpInstance OPTIONAL,
|
||||
IN NET_BUF *Packet,
|
||||
IN IP4_FRAME_CALLBACK CallBack,
|
||||
IN VOID *Context
|
||||
IN VOID *Context,
|
||||
IN IP4_SERVICE *IpSb
|
||||
)
|
||||
{
|
||||
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
|
||||
|
@ -170,6 +172,7 @@ Ip4WrapLinkTxToken (
|
|||
|
||||
Token->Interface = Interface;
|
||||
Token->IpInstance = IpInstance;
|
||||
Token->IpSb = IpSb;
|
||||
Token->CallBack = CallBack;
|
||||
Token->Packet = Packet;
|
||||
Token->Context = Context;
|
||||
|
@ -792,9 +795,89 @@ Ip4FreeInterface (
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This function tries to send all the queued frames in ArpQue to the default gateway if
|
||||
the ARP resolve for direct destination address is failed when using /32 subnet mask.
|
||||
|
||||
@param[in] ArpQue The ARP queue of a failed request.
|
||||
|
||||
@retval EFI_SUCCESS All the queued frames have been send to the default route.
|
||||
@retval Others Failed to send the queued frames.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ip4SendFrameToDefaultRoute (
|
||||
IN IP4_ARP_QUE *ArpQue
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
|
||||
IP4_LINK_TX_TOKEN *Token;
|
||||
IP4_ADDR Gateway;
|
||||
EFI_STATUS Status;
|
||||
IP4_ROUTE_ENTRY *DefaultRoute;
|
||||
|
||||
//
|
||||
// ARP resolve failed when using /32 subnet mask.
|
||||
//
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
|
||||
RemoveEntryList (Entry);
|
||||
Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
|
||||
ASSERT (Token->Interface->SubnetMask == IP4_ALLONE_ADDRESS);
|
||||
//
|
||||
// Find the default gateway IP address. The default route was saved to the RtCacheEntry->Tag in Ip4Route().
|
||||
//
|
||||
RtCacheEntry = NULL;
|
||||
if (Token->IpInstance != NULL) {
|
||||
RtCacheEntry = Ip4FindRouteCache (Token->IpInstance->RouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);
|
||||
}
|
||||
if (RtCacheEntry == NULL) {
|
||||
RtCacheEntry = Ip4FindRouteCache (Token->IpSb->DefaultRouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);
|
||||
}
|
||||
if (RtCacheEntry == NULL) {
|
||||
Status= EFI_NO_MAPPING;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
DefaultRoute = (IP4_ROUTE_ENTRY*)RtCacheEntry->Tag;
|
||||
if (DefaultRoute == NULL) {
|
||||
Status= EFI_NO_MAPPING;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
//
|
||||
// Try to send the frame to the default route.
|
||||
//
|
||||
Gateway = DefaultRoute->NextHop;
|
||||
if (ArpQue->Ip == Gateway) {
|
||||
//
|
||||
// ARP resolve for the default route is failed, return error to caller.
|
||||
//
|
||||
Status= EFI_NO_MAPPING;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
RtCacheEntry->NextHop = Gateway;
|
||||
Status = Ip4SendFrame (Token->Interface,Token->IpInstance,Token->Packet,Gateway,Token->CallBack,Token->Context,Token->IpSb);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Status= EFI_NO_MAPPING;
|
||||
goto ON_ERROR;
|
||||
}
|
||||
Ip4FreeRouteCacheEntry (RtCacheEntry);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_ERROR:
|
||||
if (RtCacheEntry != NULL) {
|
||||
Ip4FreeRouteCacheEntry (RtCacheEntry);
|
||||
}
|
||||
Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
|
||||
Ip4FreeLinkTxToken (Token);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Callback function when ARP request are finished. It will cancelled
|
||||
Callback function when ARP request are finished. It will cancel
|
||||
all the queued frame if the ARP requests failed. Or transmit them
|
||||
if the request succeed.
|
||||
|
||||
|
@ -814,6 +897,7 @@ Ip4OnArpResolvedDpc (
|
|||
IP4_INTERFACE *Interface;
|
||||
IP4_LINK_TX_TOKEN *Token;
|
||||
EFI_STATUS Status;
|
||||
EFI_STATUS IoStatus;
|
||||
|
||||
ArpQue = (IP4_ARP_QUE *) Context;
|
||||
NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
|
||||
|
@ -821,14 +905,23 @@ Ip4OnArpResolvedDpc (
|
|||
RemoveEntryList (&ArpQue->Link);
|
||||
|
||||
//
|
||||
// ARP resolve failed for some reason. Release all the frame
|
||||
// and ARP queue itself. Ip4FreeArpQue will call the frame's
|
||||
// owner back.
|
||||
// ARP resolve failed for some reason.
|
||||
//
|
||||
if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
|
||||
Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
|
||||
|
||||
return ;
|
||||
if (ArpQue->Interface->SubnetMask != IP4_ALLONE_ADDRESS) {
|
||||
//
|
||||
// Release all the frame and ARP queue itself. Ip4FreeArpQue will call the frame's
|
||||
// owner back.
|
||||
//
|
||||
IoStatus = EFI_NO_MAPPING;
|
||||
} else {
|
||||
//
|
||||
// ARP resolve failed when using 32bit subnet mask, try to send the packets to the
|
||||
// default route.
|
||||
//
|
||||
IoStatus = Ip4SendFrameToDefaultRoute (ArpQue);
|
||||
}
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -836,6 +929,7 @@ Ip4OnArpResolvedDpc (
|
|||
// queue. It isn't necessary for us to cache the ARP binding because
|
||||
// we always check the ARP cache first before transmit.
|
||||
//
|
||||
IoStatus = EFI_SUCCESS;
|
||||
Interface = ArpQue->Interface;
|
||||
|
||||
NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
|
||||
|
@ -863,7 +957,8 @@ Ip4OnArpResolvedDpc (
|
|||
}
|
||||
}
|
||||
|
||||
Ip4FreeArpQue (ArpQue, EFI_SUCCESS);
|
||||
ON_EXIT:
|
||||
Ip4FreeArpQue (ArpQue, IoStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -957,6 +1052,7 @@ Ip4OnFrameSent (
|
|||
to.
|
||||
@param[in] CallBack Function to call back when transmit finished.
|
||||
@param[in] Context Opaque parameter to the call back.
|
||||
@param[in] IpSb The pointer to the IP4 service binding instance.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame
|
||||
@retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop
|
||||
|
@ -971,7 +1067,8 @@ Ip4SendFrame (
|
|||
IN NET_BUF *Packet,
|
||||
IN IP4_ADDR NextHop,
|
||||
IN IP4_FRAME_CALLBACK CallBack,
|
||||
IN VOID *Context
|
||||
IN VOID *Context,
|
||||
IN IP4_SERVICE *IpSb
|
||||
)
|
||||
{
|
||||
IP4_LINK_TX_TOKEN *Token;
|
||||
|
@ -982,7 +1079,7 @@ Ip4SendFrame (
|
|||
|
||||
ASSERT (Interface->Configured);
|
||||
|
||||
Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);
|
||||
Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context, IpSb);
|
||||
|
||||
if (Token == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef struct {
|
|||
LIST_ENTRY Link;
|
||||
|
||||
IP4_INTERFACE *Interface;
|
||||
IP4_SERVICE *IpSb;
|
||||
|
||||
IP4_PROTOCOL *IpInstance;
|
||||
IP4_FRAME_CALLBACK CallBack;
|
||||
|
@ -262,6 +263,7 @@ Ip4FreeInterface (
|
|||
to.
|
||||
@param[in] CallBack Function to call back when transmit finished.
|
||||
@param[in] Context Opaque parameter to the call back.
|
||||
@param[in] IpSb The pointer to the IP4 service binding instance.
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame
|
||||
@retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop
|
||||
|
@ -276,7 +278,8 @@ Ip4SendFrame (
|
|||
IN NET_BUF *Packet,
|
||||
IN IP4_ADDR NextHop,
|
||||
IN IP4_FRAME_CALLBACK CallBack,
|
||||
IN VOID *Context
|
||||
IN VOID *Context,
|
||||
IN IP4_SERVICE *IpSb
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -1259,7 +1259,7 @@ EfiIp4Routes (
|
|||
// the gateway address must be a unicast on the connected network if not zero.
|
||||
//
|
||||
if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
|
||||
(!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
|
||||
((IpIf->SubnetMask != IP4_ALLONE_ADDRESS && !IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask)) ||
|
||||
IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
|
||||
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
|
|
|
@ -309,15 +309,15 @@ Ip4Output (
|
|||
// Route the packet unless overrided, that is, GateWay isn't zero.
|
||||
//
|
||||
if (IpInstance == NULL) {
|
||||
CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src);
|
||||
CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, TRUE);
|
||||
} else {
|
||||
CacheEntry = Ip4Route (IpInstance->RouteTable, Head->Dst, Head->Src);
|
||||
CacheEntry = Ip4Route (IpInstance->RouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, FALSE);
|
||||
//
|
||||
// If failed to route the packet by using the instance's route table,
|
||||
// try to use the default route table.
|
||||
//
|
||||
if (CacheEntry == NULL) {
|
||||
CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src);
|
||||
CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,7 +386,8 @@ Ip4Output (
|
|||
Fragment,
|
||||
GateWay,
|
||||
Ip4SysPacketSent,
|
||||
Packet
|
||||
Packet,
|
||||
IpSb
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
|
@ -429,7 +430,7 @@ Ip4Output (
|
|||
// upper layer's packets.
|
||||
//
|
||||
Ip4PrependHead (Packet, Head, Option, OptLen);
|
||||
Status = Ip4SendFrame (IpIf, IpInstance, Packet, GateWay, Callback, Context);
|
||||
Status = Ip4SendFrame (IpIf, IpInstance, Packet, GateWay, Callback, Context, IpSb);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
|
|
|
@ -494,6 +494,11 @@ Ip4FindRouteEntry (
|
|||
@param[in] RtTable The route table to search from
|
||||
@param[in] Dest The destination address to search for
|
||||
@param[in] Src The source address to search for
|
||||
@param[in] SubnetMask The subnet mask of the Src address, this field is
|
||||
used to check if the station is using /32 subnet.
|
||||
@param[in] AlwaysTryDestAddr Always try to use the dest address as next hop even
|
||||
though we can't find a matching route entry. This
|
||||
field is only valid when using /32 subnet.
|
||||
|
||||
@return NULL if failed to route packet, otherwise a route cache
|
||||
entry that can be used to route packet.
|
||||
|
@ -503,7 +508,9 @@ IP4_ROUTE_CACHE_ENTRY *
|
|||
Ip4Route (
|
||||
IN IP4_ROUTE_TABLE *RtTable,
|
||||
IN IP4_ADDR Dest,
|
||||
IN IP4_ADDR Src
|
||||
IN IP4_ADDR Src,
|
||||
IN IP4_ADDR SubnetMask,
|
||||
IN BOOLEAN AlwaysTryDestAddr
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Head;
|
||||
|
@ -535,7 +542,11 @@ Ip4Route (
|
|||
RtEntry = Ip4FindRouteEntry (RtTable, Dest);
|
||||
|
||||
if (RtEntry == NULL) {
|
||||
return NULL;
|
||||
if (SubnetMask != IP4_ALLONE_ADDRESS) {
|
||||
return NULL;
|
||||
} else if (!AlwaysTryDestAddr) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -544,16 +555,23 @@ Ip4Route (
|
|||
// network. Otherwise, it is an indirect route, the packet will be
|
||||
// sent to the next hop router.
|
||||
//
|
||||
if ((RtEntry->Flag & IP4_DIRECT_ROUTE) != 0) {
|
||||
// When using /32 subnet mask, the packet will always be sent to the direct
|
||||
// destination first, if we can't find a matching route cache.
|
||||
//
|
||||
if (SubnetMask == IP4_ALLONE_ADDRESS || ((RtEntry->Flag & IP4_DIRECT_ROUTE) != 0)) {
|
||||
NextHop = Dest;
|
||||
} else {
|
||||
NextHop = RtEntry->NextHop;
|
||||
}
|
||||
|
||||
Ip4FreeRouteEntry (RtEntry);
|
||||
if (RtEntry != NULL) {
|
||||
Ip4FreeRouteEntry (RtEntry);
|
||||
}
|
||||
|
||||
//
|
||||
// Create a route cache entry, and tag it as spawned from this route entry
|
||||
// For /32 subnet mask, the default route in RtEntry will be used if failed
|
||||
// to send the packet to driect destination address.
|
||||
//
|
||||
RtCacheEntry = Ip4CreateRouteCacheEntry (Dest, Src, NextHop, (UINTN) RtEntry);
|
||||
|
||||
|
|
|
@ -194,6 +194,11 @@ Ip4FreeRouteCacheEntry (
|
|||
@param[in] RtTable The route table to search from
|
||||
@param[in] Dest The destination address to search for
|
||||
@param[in] Src The source address to search for
|
||||
@param[in] SubnetMask The subnet mask of the Src address, this field is
|
||||
used to check if the station is using /32 subnet.
|
||||
@param[in] AlwaysTryDestAddr Always try to use the dest address as next hop even
|
||||
though we can't find a matching route entry. This
|
||||
field is only valid when using /32 subnet.
|
||||
|
||||
@return NULL if failed to route packet, otherwise a route cache
|
||||
entry that can be used to route packet.
|
||||
|
@ -203,7 +208,9 @@ IP4_ROUTE_CACHE_ENTRY *
|
|||
Ip4Route (
|
||||
IN IP4_ROUTE_TABLE *RtTable,
|
||||
IN IP4_ADDR Dest,
|
||||
IN IP4_ADDR Src
|
||||
IN IP4_ADDR Src,
|
||||
IN IP4_ADDR SubnetMask,
|
||||
IN BOOLEAN AlwaysTryDestAddr
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -509,8 +509,9 @@ Mtftp4Start (
|
|||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
gBS->RestoreTPL(OldTpl);
|
||||
|
||||
if (Token->Event != NULL) {
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -522,7 +523,6 @@ Mtftp4Start (
|
|||
This->Poll (This);
|
||||
}
|
||||
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
return Token->Status;
|
||||
|
||||
ON_ERROR:
|
||||
|
@ -682,7 +682,7 @@ EfiMtftp4Configure (
|
|||
}
|
||||
|
||||
if ((Gateway != 0) &&
|
||||
(!IP4_NET_EQUAL (Gateway, Ip, Netmask) || (Netmask != 0 && !NetIp4IsUnicast (Gateway, Netmask)))) {
|
||||
((Netmask != 0xFFFFFFFF && !IP4_NET_EQUAL (Gateway, Ip, Netmask)) || (Netmask != 0 && !NetIp4IsUnicast (Gateway, Netmask)))) {
|
||||
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue