net/: Fix some issues with regard to UDP broadcast handling. This is Bitbucket Issue #77. This commit tentatively closes the issues, subject to verification.

This commit is contained in:
Gregory Nutt
2017-11-22 12:06:36 -06:00
parent af65eac4f2
commit c93320ccd6
4 changed files with 177 additions and 123 deletions
+40 -30
View File
@@ -508,6 +508,46 @@ bool net_ipv6addr_maskcmp(const net_ipv6addr_t addr1,
const net_ipv6addr_t mask); const net_ipv6addr_t mask);
#endif #endif
/****************************************************************************
* Name: net_ipv4addr_broadcast
*
* Description:
* Mask out the network part of an IP address, given the address and
* the netmask.
*
* Example:
*
* in_addr_t ipaddr;
* in_addr_t netmask;
* bool isbroadcast;
*
* net_ipaddr(&netmask, 255,255,255,0);
* net_ipaddr(&ipaddr, 192,16,1,255);
* isbroadcast = net_ipv4addr_broadcast(ipaddr, netmask);
*
* Will return isboadcast == true.
*
* net_ipaddr(&ipaddr, 192,16,1,2);
* isbroadcast = net_ipv4addr_broadcast(ipaddr, netmask);
*
* Will return isboadcast == false.
*
* NOTES:
* 1. This function does not check for the broadcast address
* 255.255.255.255. That must be performed as a seperate check.
* 2. You must also separately check if the ipaddress lies on the sub-net
* using, perhaps, net_ipv4addr_maskcmp().
*
* Input Parameters:
* addr - The IPv4 address to check
* mask - The network mask
*
****************************************************************************/
#define net_ipv4addr_broadcast(addr, mask) \
(((in_addr_t)(addr) & ~(in_addr_t)(mask)) == \
((in_addr_t)(0xffffffff) & ~(in_addr_t)(mask)))
/**************************************************************************** /****************************************************************************
* Name: net_ipv6addr_prefixcmp * Name: net_ipv6addr_prefixcmp
* *
@@ -587,36 +627,6 @@ bool net_ipv6addr_maskcmp(const net_ipv6addr_t addr1,
#define net_is_addr_linklocal(a) ((a)[0] == HTONS(0xfe80)) #define net_is_addr_linklocal(a) ((a)[0] == HTONS(0xfe80))
/****************************************************************************
* Name: net_ipaddr_mask
*
* Description:
* Mask out the network part of an IP address, given the address and
* the netmask.
*
* Example:
*
* in_addr_t ipaddr1, ipaddr2, netmask;
*
* net_ipaddr(&ipaddr1, 192,16,1,2);
* net_ipaddr(&netmask, 255,255,255,0);
* net_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask);
*
* In the example above, the variable "ipaddr2" will contain the IP
* address 192.168.1.0.
*
* Input Parameters:
* dest Where the result is to be placed.
* src The IP address.
* mask The netmask.
*
****************************************************************************/
#define net_ipaddr_mask(dest, src, mask) \
do { \
(in_addr_t)(dest) = (in_addr_t)(src) & (in_addr_t)(mask); \
} while (0)
#undef EXTERN #undef EXTERN
#ifdef __cplusplus #ifdef __cplusplus
} }
+21 -7
View File
@@ -169,6 +169,7 @@ void arp_out(FAR struct net_driver_s *dev)
if (net_ipv4addr_hdrcmp(pip->eh_destipaddr, g_broadcast_ipaddr)) if (net_ipv4addr_hdrcmp(pip->eh_destipaddr, g_broadcast_ipaddr))
{ {
memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN); memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
goto finish_header;
} }
#ifdef CONFIG_NET_IGMP #ifdef CONFIG_NET_IGMP
@@ -181,7 +182,7 @@ void arp_out(FAR struct net_driver_s *dev)
* addresses=0xff (ff00::/8.) * addresses=0xff (ff00::/8.)
*/ */
else if (NTOHS(pip->eh_destipaddr[0]) >= 0xe000 && if (NTOHS(pip->eh_destipaddr[0]) >= 0xe000 &&
NTOHS(pip->eh_destipaddr[0]) <= 0xefff) NTOHS(pip->eh_destipaddr[0]) <= 0xefff)
{ {
/* Build the well-known IPv4 IGMP Ethernet address. The first /* Build the well-known IPv4 IGMP Ethernet address. The first
@@ -199,10 +200,11 @@ void arp_out(FAR struct net_driver_s *dev)
peth->dest[3] = ip[2] & 0x7f; peth->dest[3] = ip[2] & 0x7f;
peth->dest[4] = ip[3]; peth->dest[4] = ip[3];
peth->dest[5] = ip[4]; peth->dest[5] = ip[4];
goto finish_header;
} }
#endif #endif
else
{
/* Check if the destination address is on the local network. */ /* Check if the destination address is on the local network. */
destipaddr = net_ip4addr_conv32(pip->eh_destipaddr); destipaddr = net_ip4addr_conv32(pip->eh_destipaddr);
@@ -226,6 +228,18 @@ void arp_out(FAR struct net_driver_s *dev)
net_ipv4addr_copy(ipaddr, dev->d_draddr); net_ipv4addr_copy(ipaddr, dev->d_draddr);
#endif #endif
} }
/* The destination address is on the local network. Check if it is
* the sub-net broadcast address.
*/
else if (net_ipv4addr_broadcast(destipaddr, dev->d_netmask))
{
/* Yes.. then we won't need to know the destination MAC address */
memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
goto finish_header;
}
else else
{ {
/* Else, we use the destination IP address. */ /* Else, we use the destination IP address. */
@@ -236,12 +250,12 @@ void arp_out(FAR struct net_driver_s *dev)
/* Check if we already have this destination address in the ARP table */ /* Check if we already have this destination address in the ARP table */
tabptr = arp_find(ipaddr); tabptr = arp_find(ipaddr);
if (!tabptr) if (tabptr == NULL)
{ {
ninfo("ARP request for IP %08lx\n", (unsigned long)ipaddr); ninfo("ARP request for IP %08lx\n", (unsigned long)ipaddr);
/* The destination address was not in our ARP table, so we /* The destination address was not in our ARP table, so we overwrite
* overwrite the IP packet with an ARP request. * the IP packet with an ARP request.
*/ */
arp_format(dev, ipaddr); arp_format(dev, ipaddr);
@@ -252,10 +266,10 @@ void arp_out(FAR struct net_driver_s *dev)
/* Build an Ethernet header. */ /* Build an Ethernet header. */
memcpy(peth->dest, tabptr->at_ethaddr.ether_addr_octet, ETHER_ADDR_LEN); memcpy(peth->dest, tabptr->at_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
}
/* Finish populating the Ethernet header */ /* Finish populating the Ethernet header */
finish_header:
memcpy(peth->src, dev->d_mac.ether.ether_addr_octet, ETHER_ADDR_LEN); memcpy(peth->src, dev->d_mac.ether.ether_addr_octet, ETHER_ADDR_LEN);
peth->type = HTONS(ETHTYPE_IP); peth->type = HTONS(ETHTYPE_IP);
dev->d_len += ETH_HDRLEN; dev->d_len += ETH_HDRLEN;
+11 -1
View File
@@ -250,7 +250,6 @@ int arp_send(in_addr_t ipaddr)
/* Destination address is not on the local network */ /* Destination address is not on the local network */
#ifdef CONFIG_NET_ROUTE #ifdef CONFIG_NET_ROUTE
/* We have a routing table.. find the correct router to use in /* We have a routing table.. find the correct router to use in
* this case (or, as a fall-back, use the device's default router * this case (or, as a fall-back, use the device's default router
* address). We will use the router IP address instead of the * address). We will use the router IP address instead of the
@@ -268,6 +267,17 @@ int arp_send(in_addr_t ipaddr)
ipaddr = dripaddr; ipaddr = dripaddr;
} }
/* The destination address is on the local network. Check if it is
* the sub-net broadcast address.
*/
else if (net_ipv4addr_broadcast(ipaddr, dev->d_netmask))
{
/* Yes.. We don't need to send the ARP request */
return OK;
}
/* Allocate resources to receive a callback. This and the following /* Allocate resources to receive a callback. This and the following
* initialization is performed with the network lock because we don't * initialization is performed with the network lock because we don't
* want anything to happen until we are ready. * want anything to happen until we are ready.
+31 -11
View File
@@ -321,6 +321,7 @@ nullreturn:
int ipv4_input(FAR struct net_driver_s *dev) int ipv4_input(FAR struct net_driver_s *dev)
{ {
FAR struct ipv4_hdr_s *ipv4 = BUF; FAR struct ipv4_hdr_s *ipv4 = BUF;
in_addr_t destipaddr;
uint16_t hdrlen; uint16_t hdrlen;
uint16_t iplen; uint16_t iplen;
@@ -395,6 +396,10 @@ int ipv4_input(FAR struct net_driver_s *dev)
#endif /* CONFIG_NET_TCP_REASSEMBLY */ #endif /* CONFIG_NET_TCP_REASSEMBLY */
} }
/* Get the destination IP address in a friendlier form */
destipaddr = net_ip4addr_conv32(ipv4->destipaddr);
#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK) #if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK)
/* If IP broadcast support is configured, we check for a broadcast /* If IP broadcast support is configured, we check for a broadcast
* UDP packet, which may be destined to us (even if there is no IP * UDP packet, which may be destined to us (even if there is no IP
@@ -403,8 +408,7 @@ int ipv4_input(FAR struct net_driver_s *dev)
*/ */
if (ipv4->proto == IP_PROTO_UDP && if (ipv4->proto == IP_PROTO_UDP &&
net_ipv4addr_cmp(net_ip4addr_conv32(ipv4->destipaddr), net_ipv4addr_cmp(destipaddr, INADDR_BROADCAST))
INADDR_BROADCAST))
{ {
#ifdef CONFIG_NET_IPFORWARD_BROADCAST #ifdef CONFIG_NET_IPFORWARD_BROADCAST
/* Forward broadcast packets */ /* Forward broadcast packets */
@@ -413,28 +417,45 @@ int ipv4_input(FAR struct net_driver_s *dev)
#endif #endif
return udp_ipv4_input(dev); return udp_ipv4_input(dev);
} }
/* In other cases, the device must be assigned a non-zero IP address. */
else else
#endif #endif
#ifdef CONFIG_NET_ICMP #ifdef CONFIG_NET_ICMP
/* In other cases, the device must be assigned a non-zero IP address. */
if (net_ipv4addr_cmp(dev->d_ipaddr, INADDR_ANY)) if (net_ipv4addr_cmp(dev->d_ipaddr, INADDR_ANY))
{ {
nwarn("WARNING: No IP address assigned\n"); nwarn("WARNING: No IP address assigned\n");
goto drop; goto drop;
} }
/* Check if the packet is destined for our IP address */
else else
#endif #endif
#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK)
/* The address is not the broadcast address and we have been assigned a
* address. So there is also the possibility that the destination address
* is a sub-net broadcast address which we will need to handle just as for
* the broadcast address above.
*/
if (ipv4->proto == IP_PROTO_UDP &&
net_ipv4addr_maskcmp(destipaddr, dev->d_ipaddr, dev->d_netmask) &&
net_ipv4addr_broadcast(destipaddr, dev->d_netmask))
{ {
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
/* Forward broadcast packets */
ipv4_forward_broadcast(dev, ipv4);
#endif
return udp_ipv4_input(dev);
}
else
#endif
/* Check if the packet is destined for our IP address. */ /* Check if the packet is destined for our IP address. */
if (!net_ipv4addr_cmp(net_ip4addr_conv32(ipv4->destipaddr), if (!net_ipv4addr_cmp(destipaddr, dev->d_ipaddr))
dev->d_ipaddr))
{ {
/* Check for an IPv4 IGMP group address */ /* No.. This is not our IP address. Check for an IPv4 IGMP group
* address
*/
#ifdef CONFIG_NET_IGMP #ifdef CONFIG_NET_IGMP
in_addr_t destip = net_ip4addr_conv32(ipv4->destipaddr); in_addr_t destip = net_ip4addr_conv32(ipv4->destipaddr);
@@ -483,7 +504,6 @@ int ipv4_input(FAR struct net_driver_s *dev)
} }
} }
} }
}
if (ipv4_chksum(dev) != 0xffff) if (ipv4_chksum(dev) != 0xffff)
{ {