diff options
-rw-r--r-- | src/include/ipxe/in.h | 2 | ||||
-rw-r--r-- | src/include/ipxe/ip.h | 22 | ||||
-rw-r--r-- | src/net/ipv4.c | 18 |
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; |