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)
{
* 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;
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;
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
ret = arp_build(buffer,
sizeof(buffer),
&addr->ip,
- hwaddr,
+ hardware_addr_ll,
ARPOP_REQUEST,
&len);
if (ret != 0) {
ret = arp_build(buffer,
sizeof(buffer),
&addr->ip,
- hwaddr,
+ hardware_addr_ll,
ARPOP_REPLY,
&len);
if (ret != 0) {
#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;
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);