]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
ctdb-common: Pass hardware address to arp_build()
authorMartin Schwenke <mschwenke@ddn.com>
Mon, 8 Dec 2025 08:24:33 +0000 (19:24 +1100)
committerMartin Schwenke <martins@samba.org>
Mon, 27 Jul 2026 03:44:35 +0000 (03:44 +0000)
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 <mschwenke@ddn.com>
Reviewed-by: Vinit Agnihotri <vagnihot@redhat.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/common/system_socket.c
ctdb/tests/src/system_socket_test.c

index 7fac07452a9c7156523555fcf7746cf1dca0f66c..051455ddb2b87487a3944c86321821e23baf413a 100644 (file)
@@ -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) {
index edaf1c78a385f3286301dee3643ea184337f131f..58c01ddd1484cd433f981bab8b30686cbe612410 100644 (file)
@@ -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);