Blame SOURCES/bz917681-ipv6-send_ua-fix.patch

cf07b3
From 72d9c7dbb01afb26faf141fbec17e2af70ea729c Mon Sep 17 00:00:00 2001
cf07b3
From: David Vossel <dvossel@redhat.com>
cf07b3
Date: Mon, 4 Nov 2013 15:03:23 -0600
cf07b3
Subject: [PATCH] High: IPv6addr: Split send_ua utility out of IPv6addr.c source so it can be re-used in IPaddr2 without requiring cluster-glue.
cf07b3
cf07b3
---
cf07b3
 configure.ac               |    3 +-
cf07b3
 doc/man/Makefile.am        |    2 +-
cf07b3
 heartbeat/IPv6addr.c       |  198 +++-----------------------------------------
cf07b3
 heartbeat/IPv6addr_utils.c |  147 ++++++++++++++++++++++++++++++++
cf07b3
 heartbeat/Makefile.am      |   14 ++-
cf07b3
 heartbeat/send_ua.c        |  127 ++++++++++++++++++++++++++++
cf07b3
 include/IPv6addr.h         |   58 +++++++++++++
cf07b3
 include/Makefile.am        |    2 +-
cf07b3
 8 files changed, 356 insertions(+), 195 deletions(-)
cf07b3
 create mode 100644 heartbeat/IPv6addr_utils.c
cf07b3
 create mode 100644 heartbeat/send_ua.c
cf07b3
 create mode 100644 include/IPv6addr.h
cf07b3
cf07b3
diff --git a/configure.ac b/configure.ac
cf07b3
index f88a20f..ac669d8 100644
cf07b3
--- a/configure.ac
cf07b3
+++ b/configure.ac
cf07b3
@@ -714,7 +714,8 @@ AM_CONDITIONAL(USE_LIBNET, test "x$libnet_version" != "xnone" )
cf07b3
 dnl ************************************************************************
cf07b3
 dnl * Check for netinet/icmp6.h to enable the IPv6addr resource agent
cf07b3
 AC_CHECK_HEADERS(netinet/icmp6.h,[],[],[#include <sys/types.h>])
cf07b3
-AM_CONDITIONAL(USE_IPV6ADDR, test "$ac_cv_header_netinet_icmp6_h" = yes && test "$ac_cv_header_heartbeat_glue_config_h" = yes)
cf07b3
+AM_CONDITIONAL(USE_IPV6ADDR_AGENT, test "$ac_cv_header_netinet_icmp6_h" = yes && test "$ac_cv_header_heartbeat_glue_config_h" = yes)
cf07b3
+AM_CONDITIONAL(IPV6ADDR_COMPATIBLE, test "$ac_cv_header_netinet_icmp6_h" = yes)
cf07b3
 
cf07b3
 dnl ========================================================================
cf07b3
 dnl Compiler flags
cf07b3
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
cf07b3
index 347c145..3bf569a 100644
cf07b3
--- a/doc/man/Makefile.am
cf07b3
+++ b/doc/man/Makefile.am
cf07b3
@@ -134,7 +134,7 @@ man_MANS	       = ocf_heartbeat_AoEtarget.7 \
cf07b3
                           ocf_heartbeat_vmware.7 \
cf07b3
                           ocf_heartbeat_zabbixserver.7
cf07b3
 
cf07b3
-if USE_IPV6ADDR
cf07b3
+if USE_IPV6ADDR_AGENT
cf07b3
 man_MANS           	+= ocf_heartbeat_IPv6addr.7
cf07b3
 endif
cf07b3
 
cf07b3
diff --git a/heartbeat/IPv6addr.c b/heartbeat/IPv6addr.c
cf07b3
index fab59f5..7c1d20d 100644
cf07b3
--- a/heartbeat/IPv6addr.c
cf07b3
+++ b/heartbeat/IPv6addr.c
cf07b3
@@ -86,6 +86,7 @@
cf07b3
  */
cf07b3
 
cf07b3
 #include <config.h>
cf07b3
+#include <IPv6addr.h>
cf07b3
 
cf07b3
 #include <stdio.h>
cf07b3
 #include <stdlib.h>
cf07b3
@@ -134,9 +135,7 @@
cf07b3
 #define	OCF_ERR_CONFIGURED	6
cf07b3
 #define	OCF_NOT_RUNNING		7
cf07b3
 
cf07b3
-const char* IF_INET6	 	= "/proc/net/if_inet6";
cf07b3
 const char* APP_NAME		= "IPv6addr";
cf07b3
-const char* APP_NAME_SUA	= "send_ua";
cf07b3
 
cf07b3
 const char*	START_CMD 	= "start";
cf07b3
 const char*	STOP_CMD  	= "stop";
cf07b3
@@ -148,12 +147,8 @@ const char*	RELOAD_CMD 	= "reload";
cf07b3
 const char*	META_DATA_CMD 	= "meta-data";
cf07b3
 const char*	VALIDATE_CMD 	= "validate-all";
cf07b3
 
cf07b3
-char		BCAST_ADDR[]	= "ff02::1";
cf07b3
-const int	UA_REPEAT_COUNT	= 5;
cf07b3
 const int	QUERY_COUNT	= 5;
cf07b3
 
cf07b3
-#define 	HWADDR_LEN 	6 /* mac address length */
cf07b3
-
cf07b3
 struct in6_ifreq {
cf07b3
 	struct in6_addr ifr6_addr;
cf07b3
 	uint32_t ifr6_prefixlen;
cf07b3
@@ -169,7 +164,6 @@ static int meta_data_addr6(void);
cf07b3
 
cf07b3
 
cf07b3
 static void usage(const char* self);
cf07b3
-static void usage_send_ua(const char* self);
cf07b3
 int write_pid_file(const char *pid_file);
cf07b3
 int create_pid_directory(const char *pid_file);
cf07b3
 static void byebye(int nsig);
cf07b3
@@ -181,7 +175,6 @@ static char* get_if(struct in6_addr* addr_target, int* plen_target, char* prov_i
cf07b3
 static int assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name);
cf07b3
 static int unassign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name);
cf07b3
 int is_addr6_available(struct in6_addr* addr6);
cf07b3
-static int send_ua(struct in6_addr* src_ip, char* if_name);
cf07b3
 
cf07b3
 int
cf07b3
 main(int argc, char* argv[])
cf07b3
@@ -190,40 +183,11 @@ main(int argc, char* argv[])
cf07b3
 	char*		ipv6addr;
cf07b3
 	char*		cidr_netmask;
cf07b3
 	int		ret;
cf07b3
-	int		count = UA_REPEAT_COUNT;
cf07b3
-	int		interval = 1000;	/* default 1000 msec */
cf07b3
-	int		senduaflg = 0;
cf07b3
-	int		ch;
cf07b3
-	int		i;
cf07b3
 	char*		cp;
cf07b3
 	char*		prov_ifname = NULL;
cf07b3
 	int		prefix_len = -1;
cf07b3
 	struct in6_addr	addr6;
cf07b3
 
cf07b3
-	/* Check binary name */
cf07b3
-	if (strcmp(basename(argv[0]), APP_NAME_SUA) == 0) {
cf07b3
-		senduaflg = 1;
cf07b3
-		if (argc < 4) {
cf07b3
-			usage_send_ua(argv[0]);
cf07b3
-			return OCF_ERR_ARGS;
cf07b3
-		}
cf07b3
-		while ((ch = getopt(argc, argv, "h?c:i:")) != EOF) {
cf07b3
-			switch(ch) {
cf07b3
-			case 'c': /* count option */
cf07b3
-				count = atoi(optarg);
cf07b3
-			    break;
cf07b3
-			case 'i': /* interval option */
cf07b3
-				interval = atoi(optarg);
cf07b3
-			    break;
cf07b3
-			case 'h':
cf07b3
-			case '?':
cf07b3
-			default:
cf07b3
-				usage_send_ua(argv[0]);
cf07b3
-				return OCF_ERR_ARGS;
cf07b3
-			}
cf07b3
-		}
cf07b3
-	}
cf07b3
-
cf07b3
 	/* Check the count of parameters first */
cf07b3
 	if (argc < 2) {
cf07b3
 		usage(argv[0]);
cf07b3
@@ -235,11 +199,7 @@ main(int argc, char* argv[])
cf07b3
 	signal(SIGTERM, byebye);
cf07b3
 
cf07b3
 	/* open system log */
cf07b3
-	if (senduaflg) {
cf07b3
-		cl_log_set_entity(APP_NAME_SUA);
cf07b3
-	} else {
cf07b3
-		cl_log_set_entity(APP_NAME);
cf07b3
-	}
cf07b3
+	cl_log_set_entity(APP_NAME);
cf07b3
 	cl_log_set_facility(LOG_DAEMON);
cf07b3
 
cf07b3
 	/* the meta-data dont need any parameter */
cf07b3
@@ -248,12 +208,9 @@ main(int argc, char* argv[])
cf07b3
 		return OCF_SUCCESS;
cf07b3
 	}
cf07b3
 
cf07b3
-	if (senduaflg) {
cf07b3
-		ipv6addr = argv[optind];
cf07b3
-	} else {
cf07b3
-		/* check the OCF_RESKEY_ipv6addr parameter, should be an IPv6 address */
cf07b3
-		ipv6addr = getenv("OCF_RESKEY_ipv6addr");
cf07b3
-	}
cf07b3
+	/* check the OCF_RESKEY_ipv6addr parameter, should be an IPv6 address */
cf07b3
+	ipv6addr = getenv("OCF_RESKEY_ipv6addr");
cf07b3
+
cf07b3
 	if (ipv6addr == NULL) {
cf07b3
 		cl_log(LOG_ERR, "Please set OCF_RESKEY_ipv6addr to the IPv6 address you want to manage.");
cf07b3
 		usage(argv[0]);
cf07b3
@@ -271,12 +228,9 @@ main(int argc, char* argv[])
cf07b3
 		*cp=0;
cf07b3
 	}
cf07b3
 
cf07b3
-	if (senduaflg) {
cf07b3
-		cidr_netmask = argv[optind+1];
cf07b3
-	} else {
cf07b3
-		/* get provided netmask (optional) */
cf07b3
-		cidr_netmask = getenv("OCF_RESKEY_cidr_netmask");
cf07b3
-	}
cf07b3
+	/* get provided netmask (optional) */
cf07b3
+	cidr_netmask = getenv("OCF_RESKEY_cidr_netmask");
cf07b3
+
cf07b3
 	if (cidr_netmask != NULL) {
cf07b3
 		if ((atol(cidr_netmask) < 0) || (atol(cidr_netmask) > 128)) {
cf07b3
 			cl_log(LOG_ERR, "Invalid prefix_len [%s], "
cf07b3
@@ -294,12 +248,9 @@ main(int argc, char* argv[])
cf07b3
 		prefix_len = 0;
cf07b3
 	}
cf07b3
 
cf07b3
-	if (senduaflg) {
cf07b3
-		prov_ifname = argv[optind+2];
cf07b3
-	} else {
cf07b3
-		/* get provided interface name (optional) */
cf07b3
-		prov_ifname = getenv("OCF_RESKEY_nic");
cf07b3
-	}
cf07b3
+	/* get provided interface name (optional) */
cf07b3
+	prov_ifname = getenv("OCF_RESKEY_nic");
cf07b3
+
cf07b3
 	if (inet_pton(AF_INET6, ipv6addr, &addr6) <= 0) {
cf07b3
 		cl_log(LOG_ERR, "Invalid IPv6 address [%s]", ipv6addr);
cf07b3
 		usage(argv[0]);
cf07b3
@@ -312,15 +263,6 @@ main(int argc, char* argv[])
cf07b3
 		return OCF_ERR_GENERIC;
cf07b3
 	}
cf07b3
 
cf07b3
-	if (senduaflg) {
cf07b3
-		/* Send unsolicited advertisement packet to neighbor */
cf07b3
-		for (i = 0; i < count; i++) {
cf07b3
-			send_ua(&addr6, prov_ifname);
cf07b3
-			usleep(interval * 1000);
cf07b3
-		}
cf07b3
-		return OCF_SUCCESS;
cf07b3
-	}
cf07b3
-
cf07b3
 	/* create the pid file so we can make sure that only one IPv6addr
cf07b3
 	 * for this address is running
cf07b3
 	 */
cf07b3
@@ -467,118 +409,6 @@ monitor_addr6(struct in6_addr* addr6, int prefix_len)
cf07b3
 	return OCF_NOT_RUNNING;
cf07b3
 }
cf07b3
 
cf07b3
-/* Send an unsolicited advertisement packet
cf07b3
- * Please refer to rfc4861 / rfc3542
cf07b3
- */
cf07b3
-int
cf07b3
-send_ua(struct in6_addr* src_ip, char* if_name)
cf07b3
-{
cf07b3
-	int status = -1;
cf07b3
-	int fd;
cf07b3
-
cf07b3
-	int ifindex;
cf07b3
-	int hop;
cf07b3
-	struct ifreq ifr;
cf07b3
-	u_int8_t *payload = NULL;
cf07b3
-	int    payload_size;
cf07b3
-	struct nd_neighbor_advert *na;
cf07b3
-	struct nd_opt_hdr *opt;
cf07b3
-	struct sockaddr_in6 src_sin6;
cf07b3
-	struct sockaddr_in6 dst_sin6;
cf07b3
-
cf07b3
-	if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1) {
cf07b3
-		cl_log(LOG_ERR, "socket(IPPROTO_ICMPV6) failed: %s",
cf07b3
-		       strerror(errno));
cf07b3
-		return status;
cf07b3
-	}
cf07b3
-	/* set the outgoing interface */
cf07b3
-	ifindex = if_nametoindex(if_name);
cf07b3
-	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
cf07b3
-		       &ifindex, sizeof(ifindex)) < 0) {
cf07b3
-		cl_log(LOG_ERR, "setsockopt(IPV6_MULTICAST_IF) failed: %s",
cf07b3
-		       strerror(errno));
cf07b3
-		goto err;
cf07b3
-	}
cf07b3
-	/* set the hop limit */
cf07b3
-	hop = 255; /* 255 is required. see rfc4861 7.1.2 */
cf07b3
-	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
cf07b3
-		       &hop, sizeof(hop)) < 0) {
cf07b3
-		cl_log(LOG_ERR, "setsockopt(IPV6_MULTICAST_HOPS) failed: %s",
cf07b3
-		       strerror(errno));
cf07b3
-		goto err;
cf07b3
-	}
cf07b3
-	
cf07b3
-	/* set the source address */
cf07b3
-	memset(&src_sin6, 0, sizeof(src_sin6));
cf07b3
-	src_sin6.sin6_family = AF_INET6;
cf07b3
-	src_sin6.sin6_addr = *src_ip;
cf07b3
-	src_sin6.sin6_port = 0;
cf07b3
-	if (IN6_IS_ADDR_LINKLOCAL(&src_sin6.sin6_addr) ||
cf07b3
-	    IN6_IS_ADDR_MC_LINKLOCAL(&src_sin6.sin6_addr)) {
cf07b3
-		src_sin6.sin6_scope_id = ifindex;
cf07b3
-	}
cf07b3
-
cf07b3
-	if (bind(fd, (struct sockaddr *)&src_sin6, sizeof(src_sin6)) < 0) {
cf07b3
-		cl_log(LOG_ERR, "bind() failed: %s", strerror(errno));
cf07b3
-		goto err;
cf07b3
-	}
cf07b3
-
cf07b3
-
cf07b3
-	/* get the hardware address */
cf07b3
-	memset(&ifr, 0, sizeof(ifr));
cf07b3
-	strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);
cf07b3
-	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
cf07b3
-		cl_log(LOG_ERR, "ioctl(SIOCGIFHWADDR) failed: %s", strerror(errno));
cf07b3
-		goto err;
cf07b3
-	}
cf07b3
-
cf07b3
-	/* build a neighbor advertisement message */
cf07b3
-	payload_size = sizeof(struct nd_neighbor_advert)
cf07b3
-			 + sizeof(struct nd_opt_hdr) + HWADDR_LEN;
cf07b3
-	payload = memalign(sysconf(_SC_PAGESIZE), payload_size);
cf07b3
-	if (!payload) {
cf07b3
-		cl_log(LOG_ERR, "malloc for payload failed");
cf07b3
-		goto err;
cf07b3
-	}
cf07b3
-	memset(payload, 0, payload_size);
cf07b3
-
cf07b3
-	/* Ugly typecast from ia64 hell! */
cf07b3
-	na = (struct nd_neighbor_advert *)((void *)payload);
cf07b3
-	na->nd_na_type = ND_NEIGHBOR_ADVERT;
cf07b3
-	na->nd_na_code = 0;
cf07b3
-	na->nd_na_cksum = 0; /* calculated by kernel */
cf07b3
-	na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
cf07b3
-	na->nd_na_target = *src_ip;
cf07b3
-
cf07b3
-	/* options field; set the target link-layer address */
cf07b3
-	opt = (struct nd_opt_hdr *)(payload + sizeof(struct nd_neighbor_advert));
cf07b3
-	opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
cf07b3
-	opt->nd_opt_len = 1; /* The length of the option in units of 8 octets */
cf07b3
-	memcpy(payload + sizeof(struct nd_neighbor_advert)
cf07b3
-			+ sizeof(struct nd_opt_hdr),
cf07b3
-	       &ifr.ifr_hwaddr.sa_data, HWADDR_LEN);
cf07b3
-
cf07b3
-	/* sending an unsolicited neighbor advertisement to all */
cf07b3
-	memset(&dst_sin6, 0, sizeof(dst_sin6));
cf07b3
-	dst_sin6.sin6_family = AF_INET6;
cf07b3
-	inet_pton(AF_INET6, BCAST_ADDR, &dst_sin6.sin6_addr); /* should not fail */
cf07b3
-
cf07b3
-	if (sendto(fd, payload, payload_size, 0,
cf07b3
-		   (struct sockaddr *)&dst_sin6, sizeof(dst_sin6))
cf07b3
-	    != payload_size) {
cf07b3
-		cl_log(LOG_ERR, "sendto(%s) failed: %s",
cf07b3
-		       if_name, strerror(errno));
cf07b3
-		goto err;
cf07b3
-	}
cf07b3
-
cf07b3
-	status = 0;
cf07b3
-
cf07b3
-err:
cf07b3
-	close(fd);
cf07b3
-	free(payload);
cf07b3
-	return status;
cf07b3
-}
cf07b3
-
cf07b3
 /* find the network interface associated with an address */
cf07b3
 char*
cf07b3
 scan_if(struct in6_addr* addr_target, int* plen_target, int use_mask, char* prov_ifname)
cf07b3
@@ -822,12 +652,6 @@ static void usage(const char* self)
cf07b3
 	return;
cf07b3
 }
cf07b3
 
cf07b3
-static void usage_send_ua(const char* self)
cf07b3
-{
cf07b3
-	printf("usage: %s [-i[=Interval]] [-c[=Count]] [-h] IPv6-Address Prefix Interface\n",self);
cf07b3
-	return;
cf07b3
-}
cf07b3
-
cf07b3
 /* Following code is copied from send_arp.c, linux-HA project. */
cf07b3
 void
cf07b3
 byebye(int nsig)
cf07b3
diff --git a/heartbeat/IPv6addr_utils.c b/heartbeat/IPv6addr_utils.c
cf07b3
new file mode 100644
cf07b3
index 0000000..7672b70
cf07b3
--- /dev/null
cf07b3
+++ b/heartbeat/IPv6addr_utils.c
cf07b3
@@ -0,0 +1,147 @@
cf07b3
+
cf07b3
+/*
cf07b3
+ * This program manages IPv6 address with OCF Resource Agent standard.
cf07b3
+ *
cf07b3
+ * Author: Huang Zhen <zhenh@cn.ibm.com>
cf07b3
+ * Copyright (c) 2004 International Business Machines
cf07b3
+ *
cf07b3
+ * This library is free software; you can redistribute it and/or
cf07b3
+ * modify it under the terms of the GNU General Public License
cf07b3
+ * as published by the Free Software Foundation; either version 2
cf07b3
+ * of the License, or (at your option) any later version.
cf07b3
+ *
cf07b3
+ * This library is distributed in the hope that it will be useful,
cf07b3
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
cf07b3
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
cf07b3
+ * GNU General Public License for more details.
cf07b3
+ *
cf07b3
+ * You should have received a copy of the GNU General Public License
cf07b3
+ * along with this program; if not, write to the Free Software
cf07b3
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
cf07b3
+ */
cf07b3
+
cf07b3
+#include <IPv6addr.h>
cf07b3
+
cf07b3
+#include <stdio.h>
cf07b3
+#include <stdlib.h>
cf07b3
+#include <malloc.h>
cf07b3
+#include <unistd.h>
cf07b3
+#include <sys/socket.h>
cf07b3
+#include <arpa/inet.h> /* for inet_pton */
cf07b3
+#include <net/if.h> /* for if_nametoindex */
cf07b3
+#include <sys/ioctl.h>
cf07b3
+#include <fcntl.h>
cf07b3
+#include <signal.h>
cf07b3
+#include <errno.h>
cf07b3
+
cf07b3
+/* Send an unsolicited advertisement packet
cf07b3
+ * Please refer to rfc4861 / rfc3542
cf07b3
+ */
cf07b3
+int
cf07b3
+send_ua(struct in6_addr* src_ip, char* if_name)
cf07b3
+{
cf07b3
+	int status = -1;
cf07b3
+	int fd;
cf07b3
+
cf07b3
+	int ifindex;
cf07b3
+	int hop;
cf07b3
+	struct ifreq ifr;
cf07b3
+	u_int8_t *payload = NULL;
cf07b3
+	int    payload_size;
cf07b3
+	struct nd_neighbor_advert *na;
cf07b3
+	struct nd_opt_hdr *opt;
cf07b3
+	struct sockaddr_in6 src_sin6;
cf07b3
+	struct sockaddr_in6 dst_sin6;
cf07b3
+
cf07b3
+	if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1) {
cf07b3
+		printf("ERROR: socket(IPPROTO_ICMPV6) failed: %s",
cf07b3
+		       strerror(errno));
cf07b3
+		return status;
cf07b3
+	}
cf07b3
+	/* set the outgoing interface */
cf07b3
+	ifindex = if_nametoindex(if_name);
cf07b3
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
cf07b3
+		       &ifindex, sizeof(ifindex)) < 0) {
cf07b3
+		printf("ERROR: setsockopt(IPV6_MULTICAST_IF) failed: %s",
cf07b3
+		       strerror(errno));
cf07b3
+		goto err;
cf07b3
+	}
cf07b3
+	/* set the hop limit */
cf07b3
+	hop = 255; /* 255 is required. see rfc4861 7.1.2 */
cf07b3
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
cf07b3
+		       &hop, sizeof(hop)) < 0) {
cf07b3
+		printf("ERROR: setsockopt(IPV6_MULTICAST_HOPS) failed: %s",
cf07b3
+		       strerror(errno));
cf07b3
+		goto err;
cf07b3
+	}
cf07b3
+
cf07b3
+	/* set the source address */
cf07b3
+	memset(&src_sin6, 0, sizeof(src_sin6));
cf07b3
+	src_sin6.sin6_family = AF_INET6;
cf07b3
+	src_sin6.sin6_addr = *src_ip;
cf07b3
+	src_sin6.sin6_port = 0;
cf07b3
+	if (IN6_IS_ADDR_LINKLOCAL(&src_sin6.sin6_addr) ||
cf07b3
+	    IN6_IS_ADDR_MC_LINKLOCAL(&src_sin6.sin6_addr)) {
cf07b3
+		src_sin6.sin6_scope_id = ifindex;
cf07b3
+	}
cf07b3
+
cf07b3
+	if (bind(fd, (struct sockaddr *)&src_sin6, sizeof(src_sin6)) < 0) {
cf07b3
+		printf("ERROR: bind() failed: %s", strerror(errno));
cf07b3
+		goto err;
cf07b3
+	}
cf07b3
+
cf07b3
+
cf07b3
+	/* get the hardware address */
cf07b3
+	memset(&ifr, 0, sizeof(ifr));
cf07b3
+	strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);
cf07b3
+	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
cf07b3
+		printf("ERROR: ioctl(SIOCGIFHWADDR) failed: %s", strerror(errno));
cf07b3
+		goto err;
cf07b3
+	}
cf07b3
+
cf07b3
+	/* build a neighbor advertisement message */
cf07b3
+	payload_size = sizeof(struct nd_neighbor_advert)
cf07b3
+			 + sizeof(struct nd_opt_hdr) + HWADDR_LEN;
cf07b3
+	payload = memalign(sysconf(_SC_PAGESIZE), payload_size);
cf07b3
+	if (!payload) {
cf07b3
+		printf("ERROR: malloc for payload failed");
cf07b3
+		goto err;
cf07b3
+	}
cf07b3
+	memset(payload, 0, payload_size);
cf07b3
+
cf07b3
+	/* Ugly typecast from ia64 hell! */
cf07b3
+	na = (struct nd_neighbor_advert *)((void *)payload);
cf07b3
+	na->nd_na_type = ND_NEIGHBOR_ADVERT;
cf07b3
+	na->nd_na_code = 0;
cf07b3
+	na->nd_na_cksum = 0; /* calculated by kernel */
cf07b3
+	na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
cf07b3
+	na->nd_na_target = *src_ip;
cf07b3
+
cf07b3
+	/* options field; set the target link-layer address */
cf07b3
+	opt = (struct nd_opt_hdr *)(payload + sizeof(struct nd_neighbor_advert));
cf07b3
+	opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
cf07b3
+	opt->nd_opt_len = 1; /* The length of the option in units of 8 octets */
cf07b3
+	memcpy(payload + sizeof(struct nd_neighbor_advert)
cf07b3
+			+ sizeof(struct nd_opt_hdr),
cf07b3
+	       &ifr.ifr_hwaddr.sa_data, HWADDR_LEN);
cf07b3
+
cf07b3
+	/* sending an unsolicited neighbor advertisement to all */
cf07b3
+	memset(&dst_sin6, 0, sizeof(dst_sin6));
cf07b3
+	dst_sin6.sin6_family = AF_INET6;
cf07b3
+	inet_pton(AF_INET6, BCAST_ADDR, &dst_sin6.sin6_addr); /* should not fail */
cf07b3
+
cf07b3
+	if (sendto(fd, payload, payload_size, 0,
cf07b3
+		   (struct sockaddr *)&dst_sin6, sizeof(dst_sin6))
cf07b3
+	    != payload_size) {
cf07b3
+		printf("ERROR: sendto(%s) failed: %s",
cf07b3
+		       if_name, strerror(errno));
cf07b3
+		goto err;
cf07b3
+	}
cf07b3
+
cf07b3
+	status = 0;
cf07b3
+
cf07b3
+err:
cf07b3
+	close(fd);
cf07b3
+	free(payload);
cf07b3
+	return status;
cf07b3
+}
cf07b3
diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am
cf07b3
index 0ce1c13..3393640 100644
cf07b3
--- a/heartbeat/Makefile.am
cf07b3
+++ b/heartbeat/Makefile.am
cf07b3
@@ -32,19 +32,23 @@ ocfdir		        = $(OCF_RA_DIR_PREFIX)/heartbeat
cf07b3
 dtddir			= $(datadir)/$(PACKAGE_NAME)
cf07b3
 dtd_DATA		= ra-api-1.dtd
cf07b3
 
cf07b3
-if USE_IPV6ADDR
cf07b3
+if USE_IPV6ADDR_AGENT
cf07b3
 ocf_PROGRAMS           = IPv6addr
cf07b3
-halib_PROGRAMS         = send_ua
cf07b3
 else
cf07b3
 ocf_PROGRAMS           =
cf07b3
+endif
cf07b3
+
cf07b3
+if IPV6ADDR_COMPATIBLE
cf07b3
+halib_PROGRAMS         = send_ua
cf07b3
+else
cf07b3
 halib_PROGRAMS         =
cf07b3
 endif
cf07b3
 
cf07b3
-IPv6addr_SOURCES        = IPv6addr.c
cf07b3
-send_ua_SOURCES         = IPv6addr.c
cf07b3
+IPv6addr_SOURCES        = IPv6addr.c IPv6addr_utils.c
cf07b3
+send_ua_SOURCES         = send_ua.c IPv6addr_utils.c
cf07b3
 
cf07b3
 IPv6addr_LDADD          = -lplumb $(LIBNETLIBS)
cf07b3
-send_ua_LDADD           = -lplumb $(LIBNETLIBS)
cf07b3
+send_ua_LDADD           = $(LIBNETLIBS)
cf07b3
 
cf07b3
 ocf_SCRIPTS	     =  ClusterMon		\
cf07b3
 			CTDB			\
cf07b3
diff --git a/heartbeat/send_ua.c b/heartbeat/send_ua.c
cf07b3
new file mode 100644
cf07b3
index 0000000..ef5357b
cf07b3
--- /dev/null
cf07b3
+++ b/heartbeat/send_ua.c
cf07b3
@@ -0,0 +1,127 @@
cf07b3
+
cf07b3
+/*
cf07b3
+ * This program manages IPv6 address with OCF Resource Agent standard.
cf07b3
+ *
cf07b3
+ * Author: Huang Zhen <zhenh@cn.ibm.com>
cf07b3
+ * Copyright (c) 2004 International Business Machines
cf07b3
+ *
cf07b3
+ * This library is free software; you can redistribute it and/or
cf07b3
+ * modify it under the terms of the GNU General Public License
cf07b3
+ * as published by the Free Software Foundation; either version 2
cf07b3
+ * of the License, or (at your option) any later version.
cf07b3
+ *
cf07b3
+ * This library is distributed in the hope that it will be useful,
cf07b3
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
cf07b3
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
cf07b3
+ * GNU General Public License for more details.
cf07b3
+ *
cf07b3
+ * You should have received a copy of the GNU General Public License
cf07b3
+ * along with this program; if not, write to the Free Software
cf07b3
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
cf07b3
+ */
cf07b3
+
cf07b3
+#include <IPv6addr.h>
cf07b3
+
cf07b3
+#include <stdio.h>
cf07b3
+#include <stdlib.h>
cf07b3
+#include <malloc.h>
cf07b3
+#include <unistd.h>
cf07b3
+#include <sys/socket.h>
cf07b3
+#include <arpa/inet.h> /* for inet_pton */
cf07b3
+#include <net/if.h> /* for if_nametoindex */
cf07b3
+#include <sys/ioctl.h>
cf07b3
+#include <fcntl.h>
cf07b3
+#include <signal.h>
cf07b3
+#include <errno.h>
cf07b3
+
cf07b3
+static void usage_send_ua(const char* self);
cf07b3
+static void byebye(int nsig);
cf07b3
+
cf07b3
+int
cf07b3
+main(int argc, char* argv[])
cf07b3
+{
cf07b3
+	char*		ipv6addr;
cf07b3
+	int		count = UA_REPEAT_COUNT;
cf07b3
+	int		interval = 1000;	/* default 1000 msec */
cf07b3
+	int		ch;
cf07b3
+	int		i;
cf07b3
+	char*		cp;
cf07b3
+	char*		prov_ifname = NULL;
cf07b3
+	struct in6_addr	addr6;
cf07b3
+
cf07b3
+	/* Check binary name */
cf07b3
+	if (argc < 4) {
cf07b3
+		usage_send_ua(argv[0]);
cf07b3
+		return OCF_ERR_ARGS;
cf07b3
+	}
cf07b3
+	while ((ch = getopt(argc, argv, "h?c:i:")) != EOF) {
cf07b3
+		switch(ch) {
cf07b3
+		case 'c': /* count option */
cf07b3
+			count = atoi(optarg);
cf07b3
+		    break;
cf07b3
+		case 'i': /* interval option */
cf07b3
+			interval = atoi(optarg);
cf07b3
+		    break;
cf07b3
+		case 'h':
cf07b3
+		case '?':
cf07b3
+		default:
cf07b3
+			usage_send_ua(argv[0]);
cf07b3
+			return OCF_ERR_ARGS;
cf07b3
+		}
cf07b3
+	}
cf07b3
+
cf07b3
+	/* set termination signal */
cf07b3
+	siginterrupt(SIGTERM, 1);
cf07b3
+	signal(SIGTERM, byebye);
cf07b3
+
cf07b3
+	ipv6addr = argv[optind];
cf07b3
+
cf07b3
+	if (ipv6addr == NULL) {
cf07b3
+		printf("ERROR: Please set OCF_RESKEY_ipv6addr to the IPv6 address you want to manage.");
cf07b3
+		usage_send_ua(argv[0]);
cf07b3
+		return OCF_ERR_ARGS;
cf07b3
+	}
cf07b3
+
cf07b3
+	/* legacy option */
cf07b3
+	if ((cp = strchr(ipv6addr, '/'))) {
cf07b3
+		*cp=0;
cf07b3
+	}
cf07b3
+
cf07b3
+	prov_ifname = argv[optind+2];
cf07b3
+
cf07b3
+	if (inet_pton(AF_INET6, ipv6addr, &addr6) <= 0) {
cf07b3
+		printf("ERROR: Invalid IPv6 address [%s]", ipv6addr);
cf07b3
+		usage_send_ua(argv[0]);
cf07b3
+		return OCF_ERR_ARGS;
cf07b3
+	}
cf07b3
+
cf07b3
+	/* Check whether this system supports IPv6 */
cf07b3
+	if (access(IF_INET6, R_OK)) {
cf07b3
+		printf("ERROR: No support for INET6 on this system.");
cf07b3
+		return OCF_ERR_GENERIC;
cf07b3
+	}
cf07b3
+
cf07b3
+	/* Send unsolicited advertisement packet to neighbor */
cf07b3
+	for (i = 0; i < count; i++) {
cf07b3
+		send_ua(&addr6, prov_ifname);
cf07b3
+		usleep(interval * 1000);
cf07b3
+	}
cf07b3
+
cf07b3
+	return OCF_SUCCESS;
cf07b3
+}
cf07b3
+
cf07b3
+static void usage_send_ua(const char* self)
cf07b3
+{
cf07b3
+	printf("usage: %s [-i[=Interval]] [-c[=Count]] [-h] IPv6-Address Prefix Interface\n",self);
cf07b3
+	return;
cf07b3
+}
cf07b3
+
cf07b3
+/* Following code is copied from send_arp.c, linux-HA project. */
cf07b3
+void
cf07b3
+byebye(int nsig)
cf07b3
+{
cf07b3
+	(void)nsig;
cf07b3
+	/* Avoid an "error exit" log message if we're killed */
cf07b3
+	exit(0);
cf07b3
+}
cf07b3
+
cf07b3
diff --git a/include/IPv6addr.h b/include/IPv6addr.h
cf07b3
new file mode 100644
cf07b3
index 0000000..720edf9
cf07b3
--- /dev/null
cf07b3
+++ b/include/IPv6addr.h
cf07b3
@@ -0,0 +1,58 @@
cf07b3
+/*
cf07b3
+ * This program manages IPv6 address with OCF Resource Agent standard.
cf07b3
+ *
cf07b3
+ * Author: Huang Zhen <zhenh@cn.ibm.com>
cf07b3
+ * Copyright (c) 2004 International Business Machines
cf07b3
+ *
cf07b3
+ * This library is free software; you can redistribute it and/or
cf07b3
+ * modify it under the terms of the GNU General Public License
cf07b3
+ * as published by the Free Software Foundation; either version 2
cf07b3
+ * of the License, or (at your option) any later version.
cf07b3
+ *
cf07b3
+ * This library is distributed in the hope that it will be useful,
cf07b3
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
cf07b3
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
cf07b3
+ * GNU General Public License for more details.
cf07b3
+ *
cf07b3
+ * You should have received a copy of the GNU General Public License
cf07b3
+ * along with this program; if not, write to the Free Software
cf07b3
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
cf07b3
+ */
cf07b3
+
cf07b3
+#ifndef OCF_IPV6_HELPER_H
cf07b3
+#define OCF_IPV6_HELPER_H
cf07b3
+#include <netinet/icmp6.h>
cf07b3
+#include <config.h>
cf07b3
+/*
cf07b3
+0	No error, action succeeded completely
cf07b3
+1 	generic or unspecified error (current practice)
cf07b3
+	The "monitor" operation shall return this for a crashed, hung or
cf07b3
+	otherwise non-functional resource.
cf07b3
+2 	invalid or excess argument(s)
cf07b3
+	Likely error code for validate-all, if the instance parameters
cf07b3
+	do not validate. Any other action is free to also return this
cf07b3
+	exit status code for this case.
cf07b3
+3 	unimplemented feature (for example, "reload")
cf07b3
+4 	user had insufficient privilege
cf07b3
+5 	program is not installed
cf07b3
+6 	program is not configured
cf07b3
+7 	program is not running
cf07b3
+8	resource is running in "master" mode and fully operational
cf07b3
+9	resource is in "master" mode but in a failed state
cf07b3
+*/
cf07b3
+#define	OCF_SUCCESS		0
cf07b3
+#define	OCF_ERR_GENERIC		1
cf07b3
+#define	OCF_ERR_ARGS		2
cf07b3
+#define	OCF_ERR_UNIMPLEMENTED	3
cf07b3
+#define	OCF_ERR_PERM		4
cf07b3
+#define	OCF_ERR_INSTALLED	5
cf07b3
+#define	OCF_ERR_CONFIGURED	6
cf07b3
+#define	OCF_NOT_RUNNING		7
cf07b3
+
cf07b3
+#define	HWADDR_LEN 6 /* mac address length */
cf07b3
+#define UA_REPEAT_COUNT	5
cf07b3
+#define  BCAST_ADDR "ff02::1"
cf07b3
+#define IF_INET6 "/proc/net/if_inet6"
cf07b3
+
cf07b3
+int send_ua(struct in6_addr* src_ip, char* if_name);
cf07b3
+#endif
cf07b3
diff --git a/include/Makefile.am b/include/Makefile.am
cf07b3
index 5381ce0..6f46ec3 100644
cf07b3
--- a/include/Makefile.am
cf07b3
+++ b/include/Makefile.am
cf07b3
@@ -21,4 +21,4 @@ MAINTAINERCLEANFILES    = Makefile.in config.h.in config.h.in~
cf07b3
 idir=$(includedir)/heartbeat
cf07b3
 i_HEADERS = agent_config.h
cf07b3
 
cf07b3
-noinst_HEADERS = config.h
cf07b3
+noinst_HEADERS = config.h IPv6addr.h
cf07b3
-- 
cf07b3
1.7.1
cf07b3