ctdb-common: Move ctdb_sys_send_arp() to ctdb_socket.[ch]
authorMartin Schwenke <martin@meltin.net>
Thu, 28 Jun 2018 10:57:08 +0000 (20:57 +1000)
committerMartin Schwenke <martins@samba.org>
Mon, 2 Jul 2018 06:51:21 +0000 (08:51 +0200)
The system_<os>.c files contain a lot of duplication, making
maintenance difficult.  These functions are being merged into
system_socket.c and system.c.

Bring a copy of tcp_checksum6(), renamed to ip6_checksum().

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/common/system.h
ctdb/common/system_aix.c
ctdb/common/system_freebsd.c
ctdb/common/system_gnu.c
ctdb/common/system_kfreebsd.c
ctdb/common/system_linux.c
ctdb/common/system_socket.c
ctdb/common/system_socket.h

index d63fb91db6b69cc863bbc710c8914dea4baaf701..a0d379210f368eff01df83d5956c1ffb32cc0505 100644 (file)
@@ -24,7 +24,6 @@
 
 /* From system_<os>.c */
 
-int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface);
 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
                      const ctdb_sock_addr *src,
                      uint32_t seq, uint32_t ack, int rst);
index b19e7569929b30cda16336e2fb785d80995dc319..1856ae299a133cfe57b910dcba9354199e2d8264 100644 (file)
@@ -205,22 +205,6 @@ int ctdb_sys_close_capture_socket(void *private_data)
        return 0;
 }
 
-
-
-/*
-  send gratuitous arp reply after we have taken over an ip address
-
-  saddr is the address we are trying to claim
-  iface is the interface name we will be using to claim the address
- */
-int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
-{
-       /* FIXME AIX: We don't do gratuitous arp yet */
-       return -1;
-}
-
-
-
 /*
   get ethernet MAC address on AIX
  */
index 9632fb209fadc84dc0785413e8244f134ed3968d..48e34ed859b8ebbf21b253382d9b7a1d440daf05 100644 (file)
@@ -75,19 +75,6 @@ static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
        return sum2;
 }
 
-/*
-  send gratuitous arp reply after we have taken over an ip address
-
-  saddr is the address we are trying to claim
-  iface is the interface name we will be using to claim the address
- */
-int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
-{
-       /* FIXME FreeBSD: We don't do gratuitous arp yet */
-       return -1;
-}
-
-
 /*
   simple TCP checksum - assumes data is multiple of 2 bytes long
  */
index c45c6e930d46b1e0da2896745e083d1d33cf1ee4..43fa66fdc8cd456c68e0b266cdf3f68847fd2ecc 100644 (file)
@@ -74,19 +74,6 @@ static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
        return sum2;
 }
 
-/*
-  send gratuitous arp reply after we have taken over an ip address
-
-  saddr is the address we are trying to claim
-  iface is the interface name we will be using to claim the address
- */
-int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
-{
-       /* FIXME GNU/Hurd: We don't do gratuitous arp yet */
-       return -1;
-}
-
-
 /*
   simple TCP checksum - assumes data is multiple of 2 bytes long
  */
index 694ae58a37cd9c9d6e2bfdc49284f801a7fecff1..8969849aec5f1bb4bc9bb554d6f1f880b8556c93 100644 (file)
@@ -74,19 +74,6 @@ static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
        return sum2;
 }
 
-/*
-  send gratuitous arp reply after we have taken over an ip address
-
-  saddr is the address we are trying to claim
-  iface is the interface name we will be using to claim the address
- */
-int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
-{
-       /* FIXME kFreeBSD: We don't do gratuitous arp yet */
-       return -1;
-}
-
-
 /*
   simple TCP checksum - assumes data is multiple of 2 bytes long
  */
index a95076dc5f3b71f3eba4f8b1b715e0f9ff006d66..991dc531e43d5b75c2dce1acc07520b50f521847 100644 (file)
@@ -71,230 +71,6 @@ static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
        return sum2;
 }
 
-/*
-  send gratuitous arp reply after we have taken over an ip address
-
-  saddr is the address we are trying to claim
-  iface is the interface name we will be using to claim the address
- */
-int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
-{
-       int s, ret;
-       struct sockaddr_ll sall;
-       struct ether_header *eh;
-       struct arphdr *ah;
-       struct ip6_hdr *ip6;
-       struct nd_neighbor_advert *nd_na;
-       struct nd_opt_hdr *nd_oh;
-       struct ifreq if_hwaddr;
-       /* Size of IPv6 neighbor advertisement (with option) */
-       unsigned char buffer[sizeof(struct ether_header) +
-                            sizeof(struct ip6_hdr) +
-                            sizeof(struct nd_neighbor_advert) +
-                            sizeof(struct nd_opt_hdr) + ETH_ALEN];
-       char *ptr;
-       char bdcast[] = {0xff,0xff,0xff,0xff,0xff,0xff};
-       struct ifreq ifr;
-
-       ZERO_STRUCT(sall);
-       ZERO_STRUCT(ifr);
-       ZERO_STRUCT(if_hwaddr);
-
-       switch (addr->ip.sin_family) {
-       case AF_INET:
-               s = socket(AF_PACKET, SOCK_RAW, 0);
-               if (s == -1){
-                       DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
-                       return -1;
-               }
-
-               DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
-               strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
-               if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-                       DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
-                       close(s);
-                       return -1;
-               }
-
-               /* get the mac address */
-               strlcpy(if_hwaddr.ifr_name, iface, sizeof(if_hwaddr.ifr_name));
-               ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
-               if ( ret < 0 ) {
-                       close(s);
-                       DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
-                       return -1;
-               }
-               if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
-                       DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
-                       close(s);
-                       return 0;
-               }
-               if (if_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
-                       close(s);
-                       errno = EINVAL;
-                       DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
-                                if_hwaddr.ifr_hwaddr.sa_family));
-                       return -1;
-               }
-
-
-               memset(buffer, 0 , 64);
-               eh = (struct ether_header *)buffer;
-               memset(eh->ether_dhost, 0xff, ETH_ALEN);
-               memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-               eh->ether_type = htons(ETHERTYPE_ARP);
-       
-               ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
-               ah->ar_hrd = htons(ARPHRD_ETHER);
-               ah->ar_pro = htons(ETH_P_IP);
-               ah->ar_hln = ETH_ALEN;
-               ah->ar_pln = 4;
-
-               /* send a gratious arp */
-               ah->ar_op  = htons(ARPOP_REQUEST);
-               ptr = (char *)&ah[1];
-               memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-               ptr+=ETH_ALEN;
-               memcpy(ptr, &addr->ip.sin_addr, 4);       
-               ptr+=4;
-               memset(ptr, 0, ETH_ALEN); 
-               ptr+=ETH_ALEN;
-               memcpy(ptr, &addr->ip.sin_addr, 4);       
-               ptr+=4;
-       
-               sall.sll_family = AF_PACKET;
-               sall.sll_halen = 6;
-               memcpy(&sall.sll_addr[0], bdcast, sall.sll_halen);
-               sall.sll_protocol = htons(ETH_P_ALL);
-               sall.sll_ifindex = ifr.ifr_ifindex;
-               ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
-               if (ret < 0 ){
-                       close(s);
-                       DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
-                       return -1;
-               }       
-
-               /* send unsolicited arp reply broadcast */
-               ah->ar_op  = htons(ARPOP_REPLY);
-               ptr = (char *)&ah[1];
-               memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-               ptr+=ETH_ALEN;
-               memcpy(ptr, &addr->ip.sin_addr, 4);       
-               ptr+=4;
-               memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-               ptr+=ETH_ALEN;
-               memcpy(ptr, &addr->ip.sin_addr, 4);       
-               ptr+=4;
-
-               ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
-               if (ret < 0 ){
-                       DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
-                       close(s);
-                       return -1;
-               }
-
-               close(s);
-               break;
-       case AF_INET6:
-               s = socket(AF_PACKET, SOCK_RAW, 0);
-               if (s == -1){
-                       DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
-                       return -1;
-               }
-
-               DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
-               strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
-               if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-                       DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
-                       close(s);
-                       return -1;
-               }
-
-               /* get the mac address */
-               strlcpy(if_hwaddr.ifr_name, iface, sizeof(if_hwaddr.ifr_name));
-               ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
-               if ( ret < 0 ) {
-                       close(s);
-                       DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
-                       return -1;
-               }
-               if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
-                       DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
-                       close(s);
-                       return 0;
-               }
-               if (if_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
-                       close(s);
-                       errno = EINVAL;
-                       DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
-                                if_hwaddr.ifr_hwaddr.sa_family));
-                       return -1;
-               }
-
-               memset(buffer, 0 , sizeof(buffer));
-               eh = (struct ether_header *)buffer;
-               /* Ethernet multicast: 33:33:00:00:00:01 (see RFC2464,
-                * section 7) - note zeroes above! */
-               eh->ether_dhost[0] = eh->ether_dhost[1] = 0x33;
-               eh->ether_dhost[5] = 0x01;
-               memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-               eh->ether_type = htons(ETHERTYPE_IP6);
-
-               ip6 = (struct ip6_hdr *)(eh+1);
-               ip6->ip6_vfc  = 0x60;
-               ip6->ip6_plen = htons(sizeof(*nd_na) +
-                                     sizeof(struct nd_opt_hdr) +
-                                     ETH_ALEN);
-               ip6->ip6_nxt  = IPPROTO_ICMPV6;
-               ip6->ip6_hlim = 255;
-               ip6->ip6_src  = addr->ip6.sin6_addr;
-               /* all-nodes multicast */
-
-               ret = inet_pton(AF_INET6, "ff02::1", &ip6->ip6_dst);
-               if (ret != 1) {
-                       close(s);
-                       DEBUG(DEBUG_CRIT,(__location__ " failed inet_pton\n"));
-                       return -1;
-               }
-
-               nd_na = (struct nd_neighbor_advert *)(ip6+1);
-               nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
-               nd_na->nd_na_code = 0;
-               nd_na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
-               nd_na->nd_na_target = addr->ip6.sin6_addr;
-               /* Option: Target link-layer address */
-               nd_oh = (struct nd_opt_hdr *)(nd_na+1);
-               nd_oh->nd_opt_type = ND_OPT_TARGET_LINKADDR;
-               nd_oh->nd_opt_len = 1;
-               memcpy(&(nd_oh+1)[0], if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-
-               nd_na->nd_na_cksum = tcp_checksum6((uint16_t *)nd_na,
-                                                  ntohs(ip6->ip6_plen), ip6);
-
-               sall.sll_family = AF_PACKET;
-               sall.sll_halen = 6;
-               memcpy(&sall.sll_addr[0], &eh->ether_dhost[0], sall.sll_halen);
-               sall.sll_protocol = htons(ETH_P_ALL);
-               sall.sll_ifindex = ifr.ifr_ifindex;
-               ret = sendto(s, buffer, sizeof(buffer),
-                            0, (struct sockaddr *)&sall, sizeof(sall));
-               if (ret < 0 ){
-                       close(s);
-                       DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
-                       return -1;
-               }       
-
-               close(s);
-               break;
-       default:
-               DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/ipv6 address (family is %u)\n", addr->ip.sin_family));
-               return -1;
-       }
-
-       return 0;
-}
-
-
 /*
   simple TCP checksum - assumes data is multiple of 2 bytes long
  */
index 0a9012c1b245cced1040f3a1639c6e8d76085e4a..f5c34e2d873f83e5c26d3a9ee5c719e8d01058b8 100644 (file)
 #include "replace.h"
 #include "system/network.h"
 
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
+#ifdef HAVE_NETINET_IP6_H
+#include <netinet/ip6.h>
+#endif
+#ifdef HAVE_NETINET_ICMP6_H
+#include <netinet/icmp6.h>
+#endif
+#ifdef HAVE_LINUX_IF_PACKET_H
+#include <linux/if_packet.h>
+#endif
+
+#ifndef ETHERTYPE_IP6
+#define ETHERTYPE_IP6 0x86dd
+#endif
+
 #include "lib/util/debug.h"
 
 #include "protocol/protocol.h"
@@ -45,7 +62,6 @@ uint32_t uint16_checksum(uint16_t *data, size_t n)
        return sum;
 }
 
-
 /*
  * See if the given IP is currently on an interface
  */
@@ -215,3 +231,267 @@ bool parse_ip_mask(const char *str,
 
        return ret;
 }
+
+static uint16_t ip6_checksum(uint16_t *data, size_t n, struct ip6_hdr *ip6)
+{
+       uint32_t phdr[2];
+       uint32_t sum = 0;
+       uint16_t sum2;
+
+       sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
+       sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
+
+       phdr[0] = htonl(n);
+       phdr[1] = htonl(ip6->ip6_nxt);
+       sum += uint16_checksum((uint16_t *)phdr, 8);
+
+       sum += uint16_checksum(data, n);
+
+       sum = (sum & 0xFFFF) + (sum >> 16);
+       sum = (sum & 0xFFFF) + (sum >> 16);
+       sum2 = htons(sum);
+       sum2 = ~sum2;
+       if (sum2 == 0) {
+               return 0xFFFF;
+       }
+       return sum2;
+}
+
+/*
+ * Send gratuitous ARP request/reply or IPv6 neighbor advertisement
+ */
+
+#ifdef HAVE_PACKETSOCKET
+
+int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
+{
+       int s, ret;
+       struct sockaddr_ll sall;
+       struct ether_header *eh;
+       struct arphdr *ah;
+       struct ip6_hdr *ip6;
+       struct nd_neighbor_advert *nd_na;
+       struct nd_opt_hdr *nd_oh;
+       struct ifreq if_hwaddr;
+       /* Size of IPv6 neighbor advertisement (with option) */
+       unsigned char buffer[sizeof(struct ether_header) +
+                            sizeof(struct ip6_hdr) +
+                            sizeof(struct nd_neighbor_advert) +
+                            sizeof(struct nd_opt_hdr) + ETH_ALEN];
+       char *ptr;
+       char bdcast[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+       struct ifreq ifr;
+
+       ZERO_STRUCT(sall);
+       ZERO_STRUCT(ifr);
+       ZERO_STRUCT(if_hwaddr);
+
+       switch (addr->ip.sin_family) {
+       case AF_INET:
+               s = socket(AF_PACKET, SOCK_RAW, 0);
+               if (s == -1){
+                       DBG_ERR("Failed to open raw socket\n");
+                       return -1;
+               }
+
+               DBG_DEBUG("Created SOCKET FD:%d for sending arp\n", s);
+               strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+               if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+                       DBG_ERR("Interface '%s' not found\n", iface);
+                       close(s);
+                       return -1;
+               }
+
+               /* get the mac address */
+               strlcpy(if_hwaddr.ifr_name, iface, sizeof(if_hwaddr.ifr_name));
+               ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
+               if ( ret < 0 ) {
+                       close(s);
+                       DBG_ERR("ioctl failed\n");
+                       return -1;
+               }
+               if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
+                       D_DEBUG("Ignoring loopback arp request\n");
+                       close(s);
+                       return 0;
+               }
+               if (if_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+                       close(s);
+                       errno = EINVAL;
+                       DBG_ERR("Not an ethernet address family (0x%x)\n",
+                               if_hwaddr.ifr_hwaddr.sa_family);
+                       return -1;
+               }
+
+
+               memset(buffer, 0 , 64);
+               eh = (struct ether_header *)buffer;
+               memset(eh->ether_dhost, 0xff, ETH_ALEN);
+               memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+               eh->ether_type = htons(ETHERTYPE_ARP);
+
+               ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
+               ah->ar_hrd = htons(ARPHRD_ETHER);
+               ah->ar_pro = htons(ETH_P_IP);
+               ah->ar_hln = ETH_ALEN;
+               ah->ar_pln = 4;
+
+               /* send a gratious arp */
+               ah->ar_op  = htons(ARPOP_REQUEST);
+               ptr = (char *)&ah[1];
+               memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+               ptr+=ETH_ALEN;
+               memcpy(ptr, &addr->ip.sin_addr, 4);
+               ptr+=4;
+               memset(ptr, 0, ETH_ALEN);
+               ptr+=ETH_ALEN;
+               memcpy(ptr, &addr->ip.sin_addr, 4);
+               ptr+=4;
+
+               sall.sll_family = AF_PACKET;
+               sall.sll_halen = 6;
+               memcpy(&sall.sll_addr[0], bdcast, sall.sll_halen);
+               sall.sll_protocol = htons(ETH_P_ALL);
+               sall.sll_ifindex = ifr.ifr_ifindex;
+               ret = sendto(s,buffer, 64, 0,
+                            (struct sockaddr *)&sall, sizeof(sall));
+               if (ret < 0 ){
+                       close(s);
+                       DBG_ERR("Failed sendto\n");
+                       return -1;
+               }
+
+               /* send unsolicited arp reply broadcast */
+               ah->ar_op  = htons(ARPOP_REPLY);
+               ptr = (char *)&ah[1];
+               memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+               ptr+=ETH_ALEN;
+               memcpy(ptr, &addr->ip.sin_addr, 4);
+               ptr+=4;
+               memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+               ptr+=ETH_ALEN;
+               memcpy(ptr, &addr->ip.sin_addr, 4);
+               ptr+=4;
+
+               ret = sendto(s, buffer, 64, 0,
+                            (struct sockaddr *)&sall, sizeof(sall));
+               if (ret < 0 ){
+                       DBG_ERR("Failed sendto\n");
+                       close(s);
+                       return -1;
+               }
+
+               close(s);
+               break;
+       case AF_INET6:
+               s = socket(AF_PACKET, SOCK_RAW, 0);
+               if (s == -1){
+                       DBG_ERR("Failed to open raw socket\n");
+                       return -1;
+               }
+
+               DBG_DEBUG("Created SOCKET FD:%d for sending arp\n", s);
+               strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+               if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+                       DBG_ERR("Interface '%s' not found\n", iface);
+                       close(s);
+                       return -1;
+               }
+
+               /* get the mac address */
+               strlcpy(if_hwaddr.ifr_name, iface, sizeof(if_hwaddr.ifr_name));
+               ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
+               if ( ret < 0 ) {
+                       close(s);
+                       DBG_ERR("ioctl failed\n");
+                       return -1;
+               }
+               if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
+                       DBG_DEBUG("Ignoring loopback arp request\n");
+                       close(s);
+                       return 0;
+               }
+               if (if_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+                       close(s);
+                       errno = EINVAL;
+                       DBG_ERR("Not an ethernet address family (0x%x)\n",
+                               if_hwaddr.ifr_hwaddr.sa_family);
+                       return -1;
+               }
+
+               memset(buffer, 0 , sizeof(buffer));
+               eh = (struct ether_header *)buffer;
+               /*
+                * Ethernet multicast: 33:33:00:00:00:01 (see RFC2464,
+                * section 7) - note zeroes above!
+                */
+               eh->ether_dhost[0] = eh->ether_dhost[1] = 0x33;
+               eh->ether_dhost[5] = 0x01;
+               memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+               eh->ether_type = htons(ETHERTYPE_IP6);
+
+               ip6 = (struct ip6_hdr *)(eh+1);
+               ip6->ip6_vfc  = 0x60;
+               ip6->ip6_plen = htons(sizeof(*nd_na) +
+                                     sizeof(struct nd_opt_hdr) +
+                                     ETH_ALEN);
+               ip6->ip6_nxt  = IPPROTO_ICMPV6;
+               ip6->ip6_hlim = 255;
+               ip6->ip6_src  = addr->ip6.sin6_addr;
+               /* all-nodes multicast */
+
+               ret = inet_pton(AF_INET6, "ff02::1", &ip6->ip6_dst);
+               if (ret != 1) {
+                       close(s);
+                       DBG_ERR("Failed inet_pton\n");
+                       return -1;
+               }
+
+               nd_na = (struct nd_neighbor_advert *)(ip6+1);
+               nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
+               nd_na->nd_na_code = 0;
+               nd_na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
+               nd_na->nd_na_target = addr->ip6.sin6_addr;
+               /* Option: Target link-layer address */
+               nd_oh = (struct nd_opt_hdr *)(nd_na+1);
+               nd_oh->nd_opt_type = ND_OPT_TARGET_LINKADDR;
+               nd_oh->nd_opt_len = 1;
+               memcpy(&(nd_oh+1)[0], if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+               nd_na->nd_na_cksum = ip6_checksum((uint16_t *)nd_na,
+                                                 ntohs(ip6->ip6_plen), ip6);
+
+               sall.sll_family = AF_PACKET;
+               sall.sll_halen = 6;
+               memcpy(&sall.sll_addr[0], &eh->ether_dhost[0], sall.sll_halen);
+               sall.sll_protocol = htons(ETH_P_ALL);
+               sall.sll_ifindex = ifr.ifr_ifindex;
+               ret = sendto(s, buffer, sizeof(buffer),
+                            0, (struct sockaddr *)&sall, sizeof(sall));
+               if (ret < 0 ){
+                       close(s);
+                       DBG_ERR("Failed sendto\n");
+                       return -1;
+               }
+
+               close(s);
+               break;
+       default:
+               DBG_ERR("Not an ipv4/ipv6 address (family is %u)\n",
+                       addr->ip.sin_family);
+               return -1;
+       }
+
+       return 0;
+}
+
+#else /* HAVE_PACKETSOCKET */
+
+int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
+{
+       /* Not implemented */
+       errno = ENOSYS;
+       return -1;
+}
+
+#endif /* HAVE_PACKETSOCKET */
index 505930791482edcc3fc6da470ab5cfa7a706327c..f405c0c35bab1ef8e5789be6e9d814144a919a5b 100644 (file)
@@ -30,4 +30,6 @@ bool parse_ip_mask(const char *str,
                   ctdb_sock_addr *addr,
                   unsigned *mask);
 
+int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface);
+
 #endif /* __CTDB_SYSTEM_SOCKET_H__ */