aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/ipxe/in.h2
-rw-r--r--src/include/ipxe/ip.h22
-rw-r--r--src/net/ipv4.c18
3 files changed, 36 insertions, 6 deletions
diff --git a/src/include/ipxe/in.h b/src/include/ipxe/in.h
index 3044d6316..05a8122ef 100644
--- a/src/include/ipxe/in.h
+++ b/src/include/ipxe/in.h
@@ -33,6 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define IN_IS_MULTICAST( addr ) \
( ( (addr) & htonl ( 0xf0000000 ) ) == htonl ( 0xe0000000 ) )
+#define IN_IS_SMALL( mask ) ( (mask) & htonl ( 0x00000003 ) )
+
/**
* IP address structure
*/
diff --git a/src/include/ipxe/ip.h b/src/include/ipxe/ip.h
index 285be6dcd..b1b5cb2e7 100644
--- a/src/include/ipxe/ip.h
+++ b/src/include/ipxe/ip.h
@@ -64,9 +64,27 @@ struct ipv4_miniroute {
/** IPv4 address */
struct in_addr address;
- /** Subnet mask */
+ /** Subnet mask
+ *
+ * An address with all of these bits in common with our IPv4
+ * address is in the local subnet.
+ */
struct in_addr netmask;
- /** Gateway address */
+ /** Host mask
+ *
+ * An address in the local subnet with all of these bits set
+ * to zero represents the network address, and an address in
+ * the local subnet with all of these bits set to one
+ * represents the directed broadcast address. All other
+ * addresses in the local subnet are valid host addresses.
+ *
+ * For most subnets, this is the inverse of the subnet mask.
+ * In a small subnet (/31 or /32) there is no network address
+ * or directed broadcast address, and all addresses in the
+ * subnet are valid host addresses.
+ */
+ struct in_addr hostmask;
+ /** Gateway address, or zero for no gateway */
struct in_addr gateway;
};
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index b91fa2ad0..5d0cb0f9a 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -85,9 +85,18 @@ static int add_ipv4_miniroute ( struct net_device *netdev,
struct in_addr address, struct in_addr netmask,
struct in_addr gateway ) {
struct ipv4_miniroute *miniroute;
+ struct in_addr hostmask;
+ struct in_addr broadcast;
+ /* Calculate host mask */
+ hostmask.s_addr = ( IN_IS_SMALL ( netmask.s_addr ) ?
+ INADDR_NONE : ~netmask.s_addr );
+ broadcast.s_addr = ( address.s_addr | hostmask.s_addr );
+
+ /* Print debugging information */
DBGC ( netdev, "IPv4 add %s", inet_ntoa ( address ) );
DBGC ( netdev, "/%s ", inet_ntoa ( netmask ) );
+ DBGC ( netdev, "bc %s ", inet_ntoa ( broadcast ) );
if ( gateway.s_addr )
DBGC ( netdev, "gw %s ", inet_ntoa ( gateway ) );
DBGC ( netdev, "via %s\n", netdev->name );
@@ -103,8 +112,9 @@ static int add_ipv4_miniroute ( struct net_device *netdev,
miniroute->netdev = netdev_get ( netdev );
miniroute->address = address;
miniroute->netmask = netmask;
+ miniroute->hostmask = hostmask;
miniroute->gateway = gateway;
-
+
/* Add to end of list if we have a gateway, otherwise
* to start of list.
*/
@@ -310,7 +320,7 @@ static int ipv4_tx ( struct io_buffer *iobuf,
struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
struct ipv4_miniroute *miniroute;
struct in_addr next_hop;
- struct in_addr netmask = { .s_addr = 0 };
+ struct in_addr hostmask = { .s_addr = INADDR_NONE };
uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
const void *ll_dest;
int rc;
@@ -338,7 +348,7 @@ static int ipv4_tx ( struct io_buffer *iobuf,
( ( miniroute = ipv4_route ( sin_dest->sin_scope_id,
&next_hop ) ) != NULL ) ) {
iphdr->src = miniroute->address;
- netmask = miniroute->netmask;
+ hostmask = miniroute->hostmask;
netdev = miniroute->netdev;
}
if ( ! netdev ) {
@@ -373,7 +383,7 @@ static int ipv4_tx ( struct io_buffer *iobuf,
ntohs ( iphdr->chksum ) );
/* Calculate link-layer destination address, if possible */
- if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){
+ if ( ( ( ~next_hop.s_addr ) & hostmask.s_addr ) == 0 ) {
/* Broadcast address */
ipv4_stats.out_bcast_pkts++;
ll_dest = netdev->ll_broadcast;