From: Martin Schwenke Date: Mon, 8 Dec 2025 08:24:33 +0000 (+1100) Subject: ctdb-common: Pass hardware address to arp_build() X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=dce91dd4d28fef6c6f5eb7ed8a598dddfeaa15d8;p=thirdparty%2Fsamba.git ctdb-common: Pass hardware address to arp_build() Use the address, length and hardware type. arp_build() now works for any supported hardware address length. Update the test code to construct the required sockaddr_ll structure. Signed-off-by: Martin Schwenke Reviewed-by: Vinit Agnihotri Reviewed-by: Amitay Isaacs --- diff --git a/ctdb/common/system_socket.c b/ctdb/common/system_socket.c index 7fac07452a9..051455ddb2b 100644 --- a/ctdb/common/system_socket.c +++ b/ctdb/common/system_socket.c @@ -460,7 +460,7 @@ done: static int arp_build(uint8_t *buffer, size_t buflen, const struct sockaddr_in *addr, - const struct ether_addr *hwaddr, + const struct sockaddr_ll *hardware_addr, uint16_t arpop, size_t *len) { @@ -488,9 +488,9 @@ static int arp_build(uint8_t *buffer, * standard. */ l = sizeof(struct arphdr) + - ETH_ALEN + + hardware_addr->sll_halen + sizeof(addr->sin_addr) + - ETH_ALEN + + hardware_addr->sll_halen + sizeof(addr->sin_addr); if (buflen < l) { return EMSGSIZE; @@ -500,23 +500,23 @@ static int arp_build(uint8_t *buffer, p = buffer; ah = (struct arphdr *)p; - ah->ar_hrd = htons(ARPHRD_ETHER); + ah->ar_hrd = htons(hardware_addr->sll_hatype); ah->ar_pro = htons(ETH_P_IP); - ah->ar_hln = ETH_ALEN; + ah->ar_hln = hardware_addr->sll_halen; ah->ar_pln = sizeof(addr->sin_addr); ah->ar_op = htons(arpop); p += sizeof(struct arphdr); - memcpy(p, hwaddr, ETH_ALEN); - p += ETH_ALEN; + memcpy(p, &hardware_addr->sll_addr, hardware_addr->sll_halen); + p += hardware_addr->sll_halen; memcpy(p, &addr->sin_addr, sizeof(addr->sin_addr)); p += sizeof(addr->sin_addr); if (arpop == ARPOP_REQUEST) { /* Field must be all 0s - already done by memset() above */ } else { - memcpy(p, hwaddr, ETH_ALEN); + memcpy(p, hardware_addr->sll_addr, hardware_addr->sll_halen); } - p += ETH_ALEN; + p += hardware_addr->sll_halen; memcpy(p, &addr->sin_addr, sizeof(addr->sin_addr)); *len = l; @@ -794,6 +794,7 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface) switch (addr->ip.sin_family) { case AF_INET: /* Send gratuitous ARP */ + hardware_addr_ll->sll_protocol = htons(ETH_P_ARP); broadcast_addr_ll->sll_protocol = htons(ETH_P_ARP); /* * Unlikely to be different to previous dest_len @@ -804,7 +805,7 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface) ret = arp_build(buffer, sizeof(buffer), &addr->ip, - hwaddr, + hardware_addr_ll, ARPOP_REQUEST, &len); if (ret != 0) { @@ -828,7 +829,7 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface) ret = arp_build(buffer, sizeof(buffer), &addr->ip, - hwaddr, + hardware_addr_ll, ARPOP_REPLY, &len); if (ret != 0) { diff --git a/ctdb/tests/src/system_socket_test.c b/ctdb/tests/src/system_socket_test.c index edaf1c78a38..58c01ddd148 100644 --- a/ctdb/tests/src/system_socket_test.c +++ b/ctdb/tests/src/system_socket_test.c @@ -71,12 +71,34 @@ static void test_types(void) #ifdef CTDB_CAN_SEND_ARPS +static void hwaddr_to_sockaddr_ll(const char *asc, struct sockaddr_ll *sall) +{ + struct ether_addr *hw = NULL; + + *sall = (struct sockaddr_ll) { + .sll_family = AF_PACKET, + .sll_protocol = htons(ETH_P_ALL), + .sll_ifindex = 2, + .sll_pkttype = PACKET_HOST, + .sll_hatype = ARPHRD_ETHER, + .sll_halen = ETH_ALEN, + }; + + hw = ether_aton(asc); + assert(hw != NULL); + + memcpy(&sall->sll_addr[0], hw, ETH_ALEN); +} + static void test_arp(const char *addr_str, const char *hwaddr_str, uint16_t arpop) { ctdb_sock_addr addr; - struct ether_addr *hw = NULL; + struct sockaddr_storage hardware_addr = {}; + struct sockaddr_ll *sall = (struct sockaddr_ll *)&hardware_addr; + /* Temporarily used for IPv6 - it still takes an ethernet address */ + struct ether_addr *hw = (struct ether_addr *)&sall->sll_addr[0]; uint8_t buf[512]; size_t buflen = sizeof(buf); size_t len; @@ -85,12 +107,11 @@ static void test_arp(const char *addr_str, ret = ctdb_sock_addr_from_string(addr_str, &addr, false); assert(ret == 0); - hw = ether_aton(hwaddr_str); - assert(hw != NULL); + hwaddr_to_sockaddr_ll(hwaddr_str, sall); switch (addr.ip.sin_family) { case AF_INET: - ret = arp_build(buf, buflen, &addr.ip, hw, arpop, &len); + ret = arp_build(buf, buflen, &addr.ip, sall, arpop, &len); break; case AF_INET6: ret = ip6_na_build(buf, buflen, &addr.ip6, hw, &len);