diff -rupN keepalived-1.2.7/keepalived/include/vrrp.h keepalived-1.2.7-unicast/keepalived/include/vrrp.h
--- keepalived-1.2.7/keepalived/include/vrrp.h	2012-08-29 00:05:12.000000000 +0200
+++ keepalived-1.2.7-unicast/keepalived/include/vrrp.h	2013-05-24 09:39:17.614831300 +0200
@@ -100,6 +100,8 @@ typedef struct _vrrp_rt {
 	list track_ifp;		/* Interface state we monitor */
 	list track_script;	/* Script state we monitor */
 	uint32_t mcast_saddr;	/* Src IP address to use in VRRP IP header */
+	uint32_t unicast_bind;	/* listen to this IP if mcast is not possible */
+	uint32_t unicast_peer;	/* send to this IP if mcast is not possible */
 	char *lvs_syncd_if;	/* handle LVS sync daemon state using this
 				 * instance FSM & running on specific interface
 				 * => eth0 for example.
@@ -216,8 +218,8 @@ typedef struct _vrrp_rt {
 
 /* prototypes */
 extern vrrp_pkt *vrrp_get_header(sa_family_t, char *, int *, uint32_t *);
-extern int open_vrrp_send_socket(sa_family_t, int, int);
-extern int open_vrrp_socket(sa_family_t, int, int);
+extern int open_vrrp_send_socket(sa_family_t, int, int, int);
+extern int open_vrrp_socket(sa_family_t, int, int, int);
 extern int new_vrrp_socket(vrrp_rt *);
 extern void close_vrrp_socket(vrrp_rt *);
 extern void vrrp_send_link_update(vrrp_rt *);
diff -rupN keepalived-1.2.7/keepalived/include/vrrp.h.orig keepalived-1.2.7-unicast/keepalived/include/vrrp.h.orig
--- keepalived-1.2.7/keepalived/include/vrrp.h.orig	1970-01-01 01:00:00.000000000 +0100
+++ keepalived-1.2.7-unicast/keepalived/include/vrrp.h.orig	2012-08-29 00:05:12.000000000 +0200
@@ -0,0 +1,238 @@
+/*
+ * Soft:        Vrrpd is an implementation of VRRPv2 as specified in rfc2338.
+ *              VRRP is a protocol which elect a master server on a LAN. If the
+ *              master fails, a backup server takes over.
+ *              The original implementation has been made by jerome etienne.
+ *
+ * Part:        vrrp.c program include file.
+ *
+ * Author:      Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ *              This program is distributed in the hope that it will be useful, 
+ *              but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ *              See the GNU General Public License for more details.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2001-2012 Alexandre Cassen, <acassen@gmail.com>
+ */
+
+#ifndef _VRRP_H
+#define _VRRP_H
+
+/* system include */
+#include <unistd.h>
+
+/* local include */
+#include "vrrp_ipaddress.h"
+#include "vrrp_iproute.h"
+#include "vrrp_ipsecah.h"
+#include "vrrp_if.h"
+#include "vrrp_track.h"
+#include "timer.h"
+#include "utils.h"
+#include "vector.h"
+#include "list.h"
+
+typedef struct {		/* rfc2338.5.1 */
+	uint8_t vers_type;	/* 0-3=type, 4-7=version */
+	uint8_t vrid;		/* virtual router id */
+	uint8_t priority;	/* router priority */
+	uint8_t naddr;		/* address counter */
+	uint8_t auth_type;	/* authentification type */
+	uint8_t adver_int;	/* advertissement interval(in sec) */
+	uint16_t chksum;	/* checksum (ip-like one) */
+/* here <naddr> ip addresses */
+/* here authentification infos */
+} vrrp_pkt;
+
+/* protocol constants */
+#define INADDR_VRRP_GROUP	0xe0000012	/* multicast addr - rfc2338.5.2.2 */
+#define VRRP_IP_TTL		255		/* in and out pkt ttl -- rfc2338.5.2.3 */
+#define IPPROTO_VRRP		112		/* IP protocol number -- rfc2338.5.2.4 */
+#define VRRP_VERSION		2		/* current version -- rfc2338.5.3.1 */
+#define VRRP_PKT_ADVERT		1		/* packet type -- rfc2338.5.3.2 */
+#define VRRP_PRIO_OWNER		255		/* priority of the ip owner -- rfc2338.5.3.4 */
+#define VRRP_PRIO_DFL		100		/* default priority -- rfc2338.5.3.4 */
+#define VRRP_PRIO_STOP		0		/* priority to stop -- rfc2338.5.3.4 */
+#define VRRP_AUTH_NONE		0		/* no authentification -- rfc2338.5.3.6 */
+#define VRRP_AUTH_PASS		1		/* password authentification -- rfc2338.5.3.6 */
+#define VRRP_AUTH_AH		2		/* AH(IPSec) authentification - rfc2338.5.3.6 */
+#define VRRP_ADVER_DFL		1		/* advert. interval (in sec) -- rfc2338.5.3.7 */
+#define VRRP_GARP_DELAY 	(5 * TIMER_HZ)	/* Default delay to launch gratuitous arp */
+
+/*
+ * parameters per vrrp sync group. A vrrp_sync_group is a set
+ * of VRRP instances that need to be state sync together.
+ */
+typedef struct _vrrp_sgroup {
+	char *gname;		/* Group name */
+	vector_t *iname;	/* Set of VRRP instances in this group */
+	list index_list;	/* List of VRRP instances */
+	int state;		/* current stable state */
+	int global_tracking;	/* Use floating priority and scripts
+				 * All VRRP must share same tracking conf
+				 */
+
+	/* State transition notification */
+	int notify_exec;
+	char *script_backup;
+	char *script_master;
+	char *script_fault;
+	char *script;
+	int smtp_alert;
+} vrrp_sgroup;
+
+/* parameters per virtual router -- rfc2338.6.1.2 */
+typedef struct _vrrp_rt {
+	sa_family_t family;	/* AF_INET|AF_INET6 */
+	char *iname;		/* Instance Name */
+	vrrp_sgroup *sync;	/* Sync group we belong to */
+	interface *ifp;		/* Interface we belong to */
+	int dont_track_primary; /* If set ignores ifp faults */
+	int vmac;		/* If set try to set VRRP VMAC */
+	char vmac_ifname[IFNAMSIZ]; /* Name of VRRP VMAC interface */
+	unsigned int vmac_ifindex;	/* ifindex of vmac interface */
+	list track_ifp;		/* Interface state we monitor */
+	list track_script;	/* Script state we monitor */
+	uint32_t mcast_saddr;	/* Src IP address to use in VRRP IP header */
+	char *lvs_syncd_if;	/* handle LVS sync daemon state using this
+				 * instance FSM & running on specific interface
+				 * => eth0 for example.
+				 */
+	int garp_delay;		/* Delay to launch gratuitous ARP */
+	int vrid;		/* virtual id. from 1(!) to 255 */
+	int base_priority;	/* configured priority value */
+	int effective_priority;	/* effective priority value */
+	int vipset;		/* All the vips are set ? */
+	list vip;		/* list of virtual ip addresses */
+	list evip;		/* list of protocol excluded VIPs.
+				 * Those VIPs will not be presents into the
+				 * VRRP adverts
+				 */
+	list vroutes;		/* list of virtual routes */
+	int adver_int;		/* delay between advertisements(in sec) */
+	int nopreempt;          /* true if higher prio does not preempt lower */
+	long preempt_delay;     /* Seconds*TIMER_HZ after startup until
+				 * preemption based on higher prio over lower
+				 * prio is allowed.  0 means no delay.
+				 */
+	timeval_t preempt_time; /* Time after which preemption can happen */
+	int state;		/* internal state (init/backup/master) */
+	int init_state;		/* the initial state of the instance */
+	int wantstate;		/* user explicitly wants a state (back/mast) */
+	int fd_in;		/* IN socket descriptor */
+	int fd_out;		/* OUT socket descriptor */
+
+	int debug;		/* Debug level 0-4 */
+
+	/* State transition notification */
+	int smtp_alert;
+	int notify_exec;
+	char *script_backup;
+	char *script_master;
+	char *script_fault;
+	char *script_stop;
+	char *script;
+
+	/* rfc2336.6.2 */
+	uint32_t ms_down_timer;
+	struct timeval sands;
+
+	/* Sending buffer */
+	char *send_buffer;	/* Allocated send buffer */
+	int send_buffer_size;
+
+	/* Authentication data */
+	int auth_type;		/* authentification type. VRRP_AUTH_* */
+	uint8_t auth_data[8];	/* authentification data */
+
+	/*
+	 * To have my own ip_id creates collision with kernel ip->id
+	 * but it should be ok because the packets are unlikely to be
+	 * fragmented (they are non routable and small)
+	 * This packet isnt routed, i can check the outgoing MTU
+	 * to warn the user only if the outoing mtu is too small
+	 */
+	int ip_id;
+
+	/* IPSEC AH counter def --rfc2402.3.3.2 */
+	seq_counter *ipsecah_counter;
+} vrrp_rt;
+
+/* VRRP state machine -- rfc2338.6.4 */
+#define VRRP_STATE_INIT			0	/* rfc2338.6.4.1 */
+#define VRRP_STATE_BACK			1	/* rfc2338.6.4.2 */
+#define VRRP_STATE_MAST			2	/* rfc2338.6.4.3 */
+#define VRRP_STATE_FAULT		3	/* internal */
+#define VRRP_STATE_GOTO_MASTER		4	/* internal */
+#define VRRP_STATE_LEAVE_MASTER		5	/* internal */
+#define VRRP_STATE_GOTO_FAULT 		98	/* internal */
+#define VRRP_DISPATCHER 		99	/* internal */
+#define VRRP_MCAST_RETRY		10	/* internal */
+#define VRRP_MAX_FSM_STATE		4	/* internal */
+
+/* VRRP packet handling */
+#define VRRP_PACKET_OK       0
+#define VRRP_PACKET_KO       1
+#define VRRP_PACKET_DROP     2
+#define VRRP_PACKET_NULL     3
+#define VRRP_PACKET_OTHER    4	/* Muliple VRRP on LAN, Identify "other" VRRP */
+
+/* VRRP Packet fixed lenght */
+#define VRRP_MAX_VIP		20
+#define VRRP_PACKET_TEMP_LEN	1024
+#define VRRP_AUTH_LEN		8
+#define VRRP_VIP_TYPE		(1 << 0)
+#define VRRP_EVIP_TYPE		(1 << 1)
+
+/* VRRP macro */
+#define VRRP_IS_BAD_VID(id)		((id)<1 || (id)>255)	/* rfc2338.6.1.vrid */
+#define VRRP_IS_BAD_PRIORITY(p)		((p)<1 || (p)>255)	/* rfc2338.6.1.prio */
+#define VRRP_IS_BAD_ADVERT_INT(d) 	((d)<1)
+#define VRRP_IS_BAD_DEBUG_INT(d)	((d)<0 || (d)>4)
+#define VRRP_IS_BAD_PREEMPT_DELAY(d)	((d)<0 || (d)>TIMER_MAX_SEC)
+#define VRRP_SEND_BUFFER(V)		((V)->send_buffer)
+#define VRRP_SEND_BUFFER_SIZE(V)	((V)->send_buffer_size)
+
+#define VRRP_TIMER_SKEW(svr)	((256-(svr)->base_priority)*TIMER_HZ/256)
+#define VRRP_VIP_ISSET(V)	((V)->vipset)
+
+#define VRRP_MIN(a, b)	((a) < (b)?(a):(b))
+#define VRRP_MAX(a, b)	((a) > (b)?(a):(b))
+
+#define VRRP_PKT_SADDR(V) (((V)->mcast_saddr) ? (V)->mcast_saddr : IF_ADDR((V)->ifp))
+
+#define VRRP_IF_ISUP(V)        ((IF_ISUP((V)->ifp) || (V)->dont_track_primary) & \
+                               ((!LIST_ISEMPTY((V)->track_ifp)) ? TRACK_ISUP((V)->track_ifp) : 1))
+
+#define VRRP_SCRIPT_ISUP(V)    ((!LIST_ISEMPTY((V)->track_script)) ? SCRIPT_ISUP((V)->track_script) : 1)
+
+#define VRRP_ISUP(V)           (VRRP_IF_ISUP(V) && VRRP_SCRIPT_ISUP(V))
+
+/* prototypes */
+extern vrrp_pkt *vrrp_get_header(sa_family_t, char *, int *, uint32_t *);
+extern int open_vrrp_send_socket(sa_family_t, int, int);
+extern int open_vrrp_socket(sa_family_t, int, int);
+extern int new_vrrp_socket(vrrp_rt *);
+extern void close_vrrp_socket(vrrp_rt *);
+extern void vrrp_send_link_update(vrrp_rt *);
+extern int vrrp_send_adv(vrrp_rt *, int);
+extern int vrrp_state_fault_rx(vrrp_rt *, char *, int);
+extern int vrrp_state_master_rx(vrrp_rt *, char *, int);
+extern int vrrp_state_master_tx(vrrp_rt *, const int);
+extern void vrrp_state_backup(vrrp_rt *, char *, int);
+extern void vrrp_state_goto_master(vrrp_rt *);
+extern void vrrp_state_leave_master(vrrp_rt *);
+extern int vrrp_ipsecah_len(void);
+extern int vrrp_complete_init(void);
+extern void shutdown_vrrp_instances(void);
+extern void clear_diff_vrrp(void);
+extern void clear_diff_script(void);
+extern void vrrp_restore_interface(vrrp_rt *, int);
+
+#endif
diff -rupN keepalived-1.2.7/keepalived/include/vrrp_if.h keepalived-1.2.7-unicast/keepalived/include/vrrp_if.h
--- keepalived-1.2.7/keepalived/include/vrrp_if.h	2012-08-13 20:50:25.000000000 +0200
+++ keepalived-1.2.7-unicast/keepalived/include/vrrp_if.h	2013-05-24 09:39:17.618831600 +0200
@@ -117,7 +117,7 @@ extern void init_interface_linkbeat(void
 extern void free_interface_queue(void);
 extern void dump_if(void *);
 extern int if_join_vrrp_group(sa_family_t, int *, interface *, int);
-extern int if_leave_vrrp_group(sa_family_t, int, interface *);
+extern int if_leave_vrrp_group(sa_family_t, int, interface *, int);
 extern int if_setsockopt_bindtodevice(int *, interface *);
 extern int if_setsockopt_hdrincl(int *);
 extern int if_setsockopt_mcast_loop(sa_family_t, int *);
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp.c keepalived-1.2.7-unicast/keepalived/vrrp/vrrp.c
--- keepalived-1.2.7/keepalived/vrrp/vrrp.c	2012-08-17 01:21:28.000000000 +0200
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp.c	2013-05-24 09:41:33.101580700 +0200
@@ -387,8 +387,8 @@ vrrp_build_ip(vrrp_rt * vrrp, char *buff
 	/* fill protocol type --rfc2402.2 */
 	ip->protocol =
 	    (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP;
-	ip->saddr = VRRP_PKT_SADDR(vrrp);
-	ip->daddr = htonl(INADDR_VRRP_GROUP);
+	ip->saddr = vrrp->unicast_bind ? vrrp->unicast_bind : VRRP_PKT_SADDR(vrrp);
+	ip->daddr = vrrp->unicast_peer ? vrrp->unicast_peer : htonl(INADDR_VRRP_GROUP);
 
 	/* checksum must be done last */
 	ip->check = in_csum((u_short *) ip, ip->ihl * 4, 0);
@@ -584,7 +584,7 @@ vrrp_send_pkt(vrrp_rt * vrrp)
 	if (vrrp->family == AF_INET) {
 		memset(&dst4, 0, sizeof(dst4));
 		dst4.sin_family = AF_INET;
-		dst4.sin_addr.s_addr = htonl(INADDR_VRRP_GROUP);
+		dst4.sin_addr.s_addr = vrrp->unicast_peer ? vrrp->unicast_peer : htonl(INADDR_VRRP_GROUP);
 
 		msg.msg_name = &dst4;
 		msg.msg_namelen = sizeof(dst4);
@@ -998,7 +998,7 @@ chk_min_cfg(vrrp_rt * vrrp)
 
 /* open a VRRP sending socket */
 int
-open_vrrp_send_socket(sa_family_t family, int proto, int idx)
+open_vrrp_send_socket(sa_family_t family, int proto, int idx, int unicast)
 {
 	interface *ifp;
 	int fd = -1;
@@ -1017,18 +1017,18 @@ open_vrrp_send_socket(sa_family_t family
 		/* Set v4 related */
 		if_setsockopt_hdrincl(&fd);
 		if_setsockopt_bindtodevice(&fd, ifp);
-		if_setsockopt_mcast_loop(family, &fd);
-		if_setsockopt_priority(&fd);
-		if (fd < 0)
-			return -1;
+//		if_setsockopt_mcast_loop(family, &fd);
+//		if_setsockopt_priority(&fd);
+//		if (fd < 0)
+//			return -1;
 	} else if (family == AF_INET6) {
 		/* Set v6 related */
 		if_setsockopt_mcast_hops(family, &fd);
 		if_setsockopt_mcast_if(family, &fd, ifp);
-		if_setsockopt_mcast_loop(family, &fd);
-		if_setsockopt_priority(&fd);
-		if (fd < 0)
-			return -1;
+//		if_setsockopt_mcast_loop(family, &fd);
+//		if_setsockopt_priority(&fd);
+//		if (fd < 0)
+//			return -1;
 	} else {
 		log_message(LOG_INFO, "cant open raw socket. unknow family=%d"
 				    , family);
@@ -1036,12 +1036,17 @@ open_vrrp_send_socket(sa_family_t family
 		return -1;
 	}
 
+	if (!unicast)
+		if_setsockopt_mcast_loop(family, &fd);
+	if (fd < 0)
+		return -1;
+
 	return fd;
 }
 
 /* open a VRRP socket and join the multicast group. */
 int
-open_vrrp_socket(sa_family_t family, int proto, int idx)
+open_vrrp_socket(sa_family_t family, int proto, int idx, int unicast)
 {
 	interface *ifp;
 	int fd = -1;
@@ -1058,7 +1063,8 @@ open_vrrp_socket(sa_family_t family, int
 	}
 
 	/* Join the VRRP MCAST group */
-	if_join_vrrp_group(family, &fd, ifp, proto);
+	if (!unicast)
+		if_join_vrrp_group(family, &fd, ifp, proto);
 	if (fd < 0)
 		return -1;
 
@@ -1073,7 +1079,7 @@ open_vrrp_socket(sa_family_t family, int
 void
 close_vrrp_socket(vrrp_rt * vrrp)
 {
-	if_leave_vrrp_group(vrrp->family, vrrp->fd_in, vrrp->ifp);
+	if_leave_vrrp_group(vrrp->family, vrrp->fd_in, vrrp->ifp, !vrrp->unicast_peer);
 	close(vrrp->fd_out);
 }
 
@@ -1087,8 +1093,8 @@ new_vrrp_socket(vrrp_rt * vrrp)
 	close_vrrp_socket(vrrp);
 	remove_vrrp_fd_bucket(vrrp);
 	proto = (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP;
-	vrrp->fd_in = open_vrrp_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp));
-	vrrp->fd_out = open_vrrp_send_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp));
+	vrrp->fd_in = open_vrrp_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp), !vrrp->unicast_peer);
+	vrrp->fd_out = open_vrrp_send_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp), !vrrp->unicast_peer);
 	alloc_vrrp_fd_bucket(vrrp);
 
 	/* Sync the other desc */
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp.c.orig keepalived-1.2.7-unicast/keepalived/vrrp/vrrp.c.orig
--- keepalived-1.2.7/keepalived/vrrp/vrrp.c.orig	1970-01-01 01:00:00.000000000 +0100
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp.c.orig	2012-08-17 01:21:28.000000000 +0200
@@ -0,0 +1,1327 @@
+/*
+ * Soft:        Keepalived is a failover program for the LVS project
+ *              <www.linuxvirtualserver.org>. It monitor & manipulate
+ *              a loadbalanced server pool using multi-layer checks.
+ *
+ * Part:        VRRP implementation of VRRPv2 as specified in rfc2338.
+ *              VRRP is a protocol which elect a master server on a LAN. If the
+ *              master fails, a backup server takes over.
+ *              The original implementation has been made by jerome etienne.
+ *
+ * Author:      Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ *              This program is distributed in the hope that it will be useful, 
+ *              but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ *              See the GNU General Public License for more details.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2001-2012 Alexandre Cassen, <acassen@gmail.com>
+ */
+
+/* local include */
+#include <ctype.h>
+#include <sys/uio.h>
+#include "vrrp_arp.h"
+#include "vrrp_ndisc.h"
+#include "vrrp_scheduler.h"
+#include "vrrp_notify.h"
+#include "ipvswrapper.h"
+#include "vrrp.h"
+#include "vrrp_data.h"
+#include "vrrp_sync.h"
+#include "vrrp_index.h"
+#include "vrrp_vmac.h"
+#ifdef _WITH_SNMP_
+#include "vrrp_snmp.h"
+#endif
+#include "memory.h"
+#include "list.h"
+#include "logger.h"
+#include "main.h"
+#include "utils.h"
+#include "notify.h"
+
+/* add/remove Virtual IP addresses */
+static int
+vrrp_handle_ipaddress(vrrp_rt * vrrp, int cmd, int type)
+{
+	if (debug & 32)
+		log_message(LOG_INFO, "VRRP_Instance(%s) %s protocol %s", vrrp->iname,
+		       (cmd == IPADDRESS_ADD) ? "setting" : "removing",
+		       (type == VRRP_VIP_TYPE) ? "VIPs." : "E-VIPs.");
+	netlink_iplist((type == VRRP_VIP_TYPE) ? vrrp->vip : vrrp->evip, cmd);
+	return 1;
+}
+
+/* add/remove Virtual routes */
+static int
+vrrp_handle_iproutes(vrrp_rt * vrrp, int cmd)
+{
+	if (debug & 32)
+		log_message(LOG_INFO, "VRRP_Instance(%s) %s protocol Virtual Routes",
+		       vrrp->iname,
+		       (cmd == IPROUTE_ADD) ? "setting" : "removing");
+	netlink_rtlist_ipv4(vrrp->vroutes, cmd);
+	return 1;
+}
+
+/* IP header length */
+static int
+vrrp_iphdr_len(vrrp_rt * vrrp)
+{
+	return sizeof (struct iphdr);
+}
+
+/* IPSEC AH header length */
+int
+vrrp_ipsecah_len(void)
+{
+	return sizeof (ipsec_ah);
+}
+
+/* VRRP header length */
+static int
+vrrp_hd_len(vrrp_rt * vrrp)
+{
+	int len = sizeof (vrrp_pkt);
+	if (vrrp->family == AF_INET)
+		len += VRRP_AUTH_LEN + ((!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) * sizeof (uint32_t) : 0);
+        return len;
+}
+
+/* VRRP header pointer from buffer */
+vrrp_pkt *
+vrrp_get_header(sa_family_t family, char *buf, int *proto, uint32_t *saddr)
+{
+	struct iphdr *iph;
+	vrrp_pkt *hd = NULL;
+
+	if (family == AF_INET) {
+		iph = (struct iphdr *) buf;
+		*saddr = iph->saddr;
+
+		/* Fill the VRRP header */
+		switch (iph->protocol) {
+		case IPPROTO_IPSEC_AH:
+			*proto = IPPROTO_IPSEC_AH;
+			hd = (vrrp_pkt *) ((char *) iph + (iph->ihl << 2) +
+					   vrrp_ipsecah_len());
+			break;
+		case IPPROTO_VRRP:
+			*proto = IPPROTO_VRRP;
+			hd = (vrrp_pkt *) ((char *) iph + (iph->ihl << 2));
+			break;
+		}
+	} else if (family == AF_INET6) {
+		*proto = IPPROTO_VRRP;
+		*saddr = 0;
+		hd = (vrrp_pkt *) buf;
+	}
+
+	return hd;
+}
+
+/*
+ * IPSEC AH incoming packet check.
+ * return 0 for a valid pkt, != 0 otherwise.
+ */
+static int
+vrrp_in_chk_ipsecah(vrrp_rt * vrrp, char *buffer)
+{
+	struct iphdr *ip = (struct iphdr *) (buffer);
+	ipsec_ah *ah = (ipsec_ah *) ((char *) ip + (ip->ihl << 2));
+	unsigned char *digest;
+	uint32_t backup_auth_data[3];
+
+	/* first verify that the SPI value is equal to src IP */
+	if (ah->spi != ip->saddr) {
+		log_message(LOG_INFO,
+		       "IPSEC AH : invalid IPSEC SPI value. %d and expect %d",
+		       ip->saddr, ah->spi);
+		return 1;
+	}
+
+	/*
+	 * then proceed with the sequence number to prevent against replay attack.
+	 * For inbound processing, we increment seq_number counter to audit 
+	 * sender counter.
+	 */
+	vrrp->ipsecah_counter->seq_number++;
+	if (ntohl(ah->seq_number) >= vrrp->ipsecah_counter->seq_number || vrrp->sync) {
+		vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number);
+	} else {
+		log_message(LOG_INFO,
+		       "VRRP_Instance(%s) IPSEC-AH : sequence number %d"
+		       " already proceeded. Packet dropped. Local(%d)", vrrp->iname
+		       , ntohl(ah->seq_number), vrrp->ipsecah_counter->seq_number);
+		return 1;
+	}
+
+	/*
+	 * then compute a ICV to compare with the one present in AH pkt.
+	 * alloc a temp memory space to stock the ip mutable fields
+	 */
+	digest = (unsigned char *) MALLOC(16 * sizeof (unsigned char *));
+
+	/* zero the ip mutable fields */
+	ip->tos = 0;
+	ip->frag_off = 0;
+	ip->check = 0;
+	memcpy(backup_auth_data, ah->auth_data, sizeof (ah->auth_data));
+	memset(ah->auth_data, 0, sizeof (ah->auth_data));
+
+	/* Compute the ICV */
+	hmac_md5((unsigned char *) buffer,
+		 vrrp_iphdr_len(vrrp) + vrrp_ipsecah_len() + vrrp_hd_len(vrrp)
+		 , vrrp->auth_data, sizeof (vrrp->auth_data)
+		 , digest);
+
+	if (memcmp(backup_auth_data, digest, HMAC_MD5_TRUNC) != 0) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : invalid"
+		       " IPSEC HMAC-MD5 value. Due to fields mutation"
+		       " or bad password !", vrrp->iname);
+		return 1;
+	}
+
+	FREE(digest);
+	return 0;
+}
+
+/* check if ipaddr is present in VIP buffer */
+static int
+vrrp_in_chk_vips(vrrp_rt * vrrp, ip_address *ipaddress, unsigned char *buffer)
+{
+	int i;
+	uint32_t ipbuf;
+
+	/* Just skip IPv6 address, when we are using a mixed v4/v6 vips
+	 * set inside se same VRRP instance.
+	 */
+	if (IP_IS6(ipaddress))
+		return 1;
+
+	for (i = 0; i < LIST_SIZE(vrrp->vip); i++) {
+		bcopy(buffer + i * sizeof (uint32_t), &ipbuf,
+		      sizeof (uint32_t));
+		if (ipaddress->u.sin.sin_addr.s_addr == ipbuf)
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * VRRP incoming packet check.
+ * return 0 if the pkt is valid, != 0 otherwise.
+ */
+static int
+vrrp_in_chk(vrrp_rt * vrrp, char *buffer)
+{
+	struct iphdr *ip;
+	int ihl, vrrp_pkt_len;
+	ipsec_ah *ah;
+	vrrp_pkt *hd;
+	unsigned char *vips;
+	ip_address *ipaddress;
+	element e;
+
+	/* IPv4 related */
+	if (vrrp->family == AF_INET) {
+
+		ip = (struct iphdr *) (buffer);
+		ihl = ip->ihl << 2;
+
+		if (vrrp->auth_type == VRRP_AUTH_AH) {
+			ah = (ipsec_ah *) (buffer + ihl);
+			hd = (vrrp_pkt *) (ah + vrrp_ipsecah_len());
+		} else {
+			hd = (vrrp_pkt *) (buffer + ihl);
+		}
+	
+		/* pointer to vrrp vips pkt zone */
+		vips = (unsigned char *) ((char *) hd + sizeof (vrrp_pkt));
+	
+		/* MUST verify that the IP TTL is 255 */
+		if (ip->ttl != VRRP_IP_TTL) {
+			log_message(LOG_INFO, "invalid ttl. %d and expect %d", ip->ttl,
+			       VRRP_IP_TTL);
+			return VRRP_PACKET_KO;
+		}
+	
+		/*
+		 * MUST verify that the received packet length is greater than or
+		 * equal to the VRRP header
+		 */
+		if ((ntohs(ip->tot_len) - ihl) <= sizeof (vrrp_pkt)) {
+			log_message(LOG_INFO,
+			       "ip payload too short. %d and expect at least %d",
+			       ntohs(ip->tot_len) - ihl, sizeof (vrrp_pkt));
+			return VRRP_PACKET_KO;
+		}
+
+		if (!LIST_ISEMPTY(vrrp->vip)) {
+			/*
+			 * MAY verify that the IP address(es) associated with the
+			 * VRID are valid
+			 */
+			if (hd->naddr != LIST_SIZE(vrrp->vip)) {
+				log_message(LOG_INFO,
+				       "receive an invalid ip number count associated with VRID!");
+				return VRRP_PACKET_KO;
+			}
+
+			for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) {
+				ipaddress = ELEMENT_DATA(e);
+				if (!vrrp_in_chk_vips(vrrp, ipaddress, vips)) {
+					log_message(LOG_INFO, "ip address associated with VRID"
+					       " not present in received packet : %s",
+					       inet_ntop2(ipaddress->u.sin.sin_addr.s_addr));
+					log_message(LOG_INFO,
+					       "one or more VIP associated with"
+					       " VRID mismatch actual MASTER advert");
+					return VRRP_PACKET_KO;
+				}
+			}
+		}
+
+		/* check the authentication if it is a passwd */
+		if (hd->auth_type == VRRP_AUTH_PASS) {
+			char *pw = (char *) ip + ntohs(ip->tot_len)
+			    - sizeof (vrrp->auth_data);
+			if (memcmp(pw, vrrp->auth_data, sizeof(vrrp->auth_data)) != 0) {
+				log_message(LOG_INFO, "receive an invalid passwd!");
+				return VRRP_PACKET_KO;
+			}
+		}
+
+		/* check the authenicaion if it is ipsec ah */
+		if (hd->auth_type == VRRP_AUTH_AH)
+			return (vrrp_in_chk_ipsecah(vrrp, buffer));
+
+		/* Set expected vrrp packet lenght */
+		vrrp_pkt_len = sizeof(vrrp_pkt) + VRRP_AUTH_LEN + hd->naddr * sizeof(uint32_t);
+
+	} else if (vrrp->family == AF_INET6) { /* IPv6 related */
+
+		hd = (vrrp_pkt *) buffer;
+		vrrp_pkt_len = sizeof(vrrp_pkt);
+
+	} else {
+		return VRRP_PACKET_KO;
+	}
+
+	/* MUST verify the VRRP version */
+	if ((hd->vers_type >> 4) != VRRP_VERSION) {
+		log_message(LOG_INFO, "invalid version. %d and expect %d",
+		       (hd->vers_type >> 4), VRRP_VERSION);
+		return VRRP_PACKET_KO;
+	}
+
+	/* MUST verify the VRRP checksum */
+	if (in_csum((u_short *) hd, vrrp_pkt_len, 0)) {
+		log_message(LOG_INFO, "Invalid vrrp checksum");
+		return VRRP_PACKET_KO;
+	}
+
+	/*
+	 * MUST perform authentication specified by Auth Type 
+	 * check the authentication type
+	 */
+	if (vrrp->auth_type != hd->auth_type) {
+		log_message(LOG_INFO, "receive a %d auth, expecting %d!",
+		       hd->auth_type, vrrp->auth_type);
+		return VRRP_PACKET_KO;
+	}
+
+	/* MUST verify that the VRID is valid on the receiving interface */
+	if (vrrp->vrid != hd->vrid) {
+		log_message(LOG_INFO,
+		       "received VRID mismatch. Received %d, Expected %d",
+		       hd->vrid, vrrp->vrid);
+		return VRRP_PACKET_DROP;
+	}
+
+	if (LIST_ISEMPTY(vrrp->vip) && hd->naddr > 0) {
+		log_message(LOG_INFO, "receive an invalid ip number count associated with VRID!");
+		return VRRP_PACKET_KO;
+	}
+
+	/*
+	 * MUST verify that the Adver Interval in the packet is the same as
+	 * the locally configured for this virtual router
+	 */
+	if (vrrp->adver_int / TIMER_HZ != hd->adver_int) {
+		log_message(LOG_INFO, "advertissement interval mismatch mine=%d rcved=%d",
+		       vrrp->adver_int, hd->adver_int);
+		/* to prevent concurent VRID running => multiple master in 1 VRID */
+		return VRRP_PACKET_DROP;
+	}
+
+	return VRRP_PACKET_OK;
+}
+
+/* build IP header */
+static void
+vrrp_build_ip(vrrp_rt * vrrp, char *buffer, int buflen)
+{
+	struct iphdr *ip = (struct iphdr *) (buffer);
+
+	ip->ihl = 5;
+	ip->version = 4;
+	/* set tos to internet network control */
+	ip->tos = 0xc0;
+	ip->tot_len = ip->ihl * 4 + vrrp_hd_len(vrrp);
+	ip->tot_len = htons(ip->tot_len);
+	ip->id = htons(++vrrp->ip_id);
+	/* kernel will fill in ID if left to 0, so we overflow to 1 */
+	if (vrrp->ip_id == 65535)
+		vrrp->ip_id = 1;
+	ip->frag_off = 0;
+	ip->ttl = VRRP_IP_TTL;
+
+	/* fill protocol type --rfc2402.2 */
+	ip->protocol =
+	    (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP;
+	ip->saddr = VRRP_PKT_SADDR(vrrp);
+	ip->daddr = htonl(INADDR_VRRP_GROUP);
+
+	/* checksum must be done last */
+	ip->check = in_csum((u_short *) ip, ip->ihl * 4, 0);
+}
+
+/* build IPSEC AH header */
+static void
+vrrp_build_ipsecah(vrrp_rt * vrrp, char *buffer, int buflen)
+{
+	ICV_mutable_fields *ip_mutable_fields;
+	unsigned char *digest;
+	struct iphdr *ip = (struct iphdr *) (buffer);
+	ipsec_ah *ah = (ipsec_ah *) (buffer + sizeof (struct iphdr));
+
+	/* alloc a temp memory space to stock the ip mutable fields */
+	ip_mutable_fields = (ICV_mutable_fields *) MALLOC(sizeof (ICV_mutable_fields));
+
+	/* fill in next header filed --rfc2402.2.1 */
+	ah->next_header = IPPROTO_VRRP;
+
+	/* update IP header total length value */
+	ip->tot_len = ip->ihl * 4 + vrrp_ipsecah_len() + vrrp_hd_len(vrrp);
+	ip->tot_len = htons(ip->tot_len);
+
+	/* update ip checksum */
+	ip->check = 0;
+	ip->check = in_csum((u_short *) ip, ip->ihl * 4, 0);
+
+	/* backup the ip mutable fields */
+	ip_mutable_fields->tos = ip->tos;
+	ip_mutable_fields->frag_off = ip->frag_off;
+	ip_mutable_fields->check = ip->check;
+
+	/* zero the ip mutable fields */
+	ip->tos = 0;
+	ip->frag_off = 0;
+	ip->check = 0;
+
+	/* fill in the Payload len field */
+	ah->payload_len = IPSEC_AH_PLEN;
+
+	/* The SPI value is filled with the ip header source address.
+	   SPI uniquely identify the Security Association (SA). This value
+	   is chosen by the recipient itself when setting up the SA. In a 
+	   multicast environment, this becomes unfeasible.
+
+	   If left to the sender, the choice of the SPI value should be done
+	   so by the sender that it cannot possibly conflict with SPI values
+	   chosen by other entities sending IPSEC traffic to any of the receivers.
+	   To overpass this problem, the rule I have chosen to implement here is
+	   that the SPI value chosen by the sender is based on unique information
+	   such as its IP address.
+	   -- INTERNET draft : <draft-paridaens-xcast-sec-framework-01.txt>
+	 */
+	ah->spi = ip->saddr;
+
+	/* Processing sequence number.
+	   Cycled assumed if 0xFFFFFFFD reached. So the MASTER state is free for another srv.
+	   Here can result a flapping MASTER state owner when max seq_number value reached.
+	   => Much work needed here.
+	   In the current implementation if counter has cycled, we stop sending adverts and 
+	   become BACKUP. If all the master are down we reset the counter for becoming MASTER.
+	 */
+	if (vrrp->ipsecah_counter->seq_number > 0xFFFFFFFD) {
+		vrrp->ipsecah_counter->cycle = 1;
+	} else {
+		vrrp->ipsecah_counter->seq_number++;
+	}
+
+	ah->seq_number = htonl(vrrp->ipsecah_counter->seq_number);
+
+	/* Compute the ICV & trunc the digest to 96bits
+	   => No padding needed.
+	   -- rfc2402.3.3.3.1.1.1 & rfc2401.5
+	 */
+	digest = (unsigned char *) MALLOC(16 * sizeof (unsigned char *));
+	hmac_md5((unsigned char *) buffer, buflen, vrrp->auth_data, sizeof (vrrp->auth_data)
+		 , digest);
+	memcpy(ah->auth_data, digest, HMAC_MD5_TRUNC);
+
+	/* Restore the ip mutable fields */
+	ip->tos = ip_mutable_fields->tos;
+	ip->frag_off = ip_mutable_fields->frag_off;
+	ip->check = ip_mutable_fields->check;
+
+	FREE(ip_mutable_fields);
+	FREE(digest);
+}
+
+/* build VRRP header */
+static int
+vrrp_build_vrrp(vrrp_rt * vrrp, int prio, char *buffer)
+{
+	int i = 0;
+	vrrp_pkt *hd = (vrrp_pkt *) buffer;
+	uint32_t *iparr;
+	element e;
+	ip_address *ip_addr;
+
+	/* Family independant */
+	hd->vers_type = (VRRP_VERSION << 4) | VRRP_PKT_ADVERT;
+	hd->vrid = vrrp->vrid;
+	hd->priority = prio;
+	hd->naddr = (!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) : 0;
+	hd->auth_type = vrrp->auth_type;
+	hd->adver_int = vrrp->adver_int / TIMER_HZ;
+
+	/* Family specific */
+	if (vrrp->family == AF_INET) {
+		/* copy the ip addresses */
+		iparr = (uint32_t *) ((char *) hd + sizeof (*hd));
+		if (!LIST_ISEMPTY(vrrp->vip)) {
+			for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) {
+				ip_addr = ELEMENT_DATA(e);
+				if (IP_IS6(ip_addr))
+					continue;
+				else
+					iparr[i++] = ip_addr->u.sin.sin_addr.s_addr;
+			}
+		}
+
+		/* copy the passwd if the authentication is VRRP_AH_PASS */
+		if (vrrp->auth_type == VRRP_AUTH_PASS) {
+			int vip_count = (!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) : 0;
+			char *pw = (char *) hd + sizeof (*hd) + vip_count * 4;
+			memcpy(pw, vrrp->auth_data, sizeof (vrrp->auth_data));
+		}
+	}
+
+	/* finaly compute vrrp checksum */
+	hd->chksum = in_csum((u_short *) hd, vrrp_hd_len(vrrp), 0);
+
+	return 0;
+}
+
+/* build VRRP packet */
+static void
+vrrp_build_pkt(vrrp_rt * vrrp, int prio)
+{
+	char *bufptr;
+	int len;
+
+	/* save reference values */
+	bufptr = VRRP_SEND_BUFFER(vrrp);
+	len = VRRP_SEND_BUFFER_SIZE(vrrp);
+
+	if (vrrp->family == AF_INET) {
+		/* build the ip header */
+		vrrp_build_ip(vrrp, VRRP_SEND_BUFFER(vrrp), VRRP_SEND_BUFFER_SIZE(vrrp));
+
+		/* build the vrrp header */
+		vrrp->send_buffer += vrrp_iphdr_len(vrrp);
+
+		if (vrrp->auth_type == VRRP_AUTH_AH)
+			vrrp->send_buffer += vrrp_ipsecah_len();
+		vrrp->send_buffer_size -= vrrp_iphdr_len(vrrp);
+
+		if (vrrp->auth_type == VRRP_AUTH_AH)
+			vrrp->send_buffer_size -= vrrp_ipsecah_len();
+		vrrp_build_vrrp(vrrp, prio, vrrp->send_buffer);
+
+		/* build the IPSEC AH header */
+		if (vrrp->auth_type == VRRP_AUTH_AH) {
+			vrrp->send_buffer_size += vrrp_iphdr_len(vrrp) + vrrp_ipsecah_len();
+			vrrp_build_ipsecah(vrrp, bufptr, VRRP_SEND_BUFFER_SIZE(vrrp));
+		}
+	} else if (vrrp->family == AF_INET6) {
+		vrrp_build_vrrp(vrrp, prio, VRRP_SEND_BUFFER(vrrp));
+	}
+
+	/* restore reference values */
+	vrrp->send_buffer = bufptr;
+	vrrp->send_buffer_size = len;
+}
+
+/* send VRRP packet */
+static int
+vrrp_send_pkt(vrrp_rt * vrrp)
+{
+	struct sockaddr_in6 dst6;
+	struct sockaddr_in dst4;
+	struct msghdr msg;
+	struct iovec iov;
+
+	/* Build the message data */
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	iov.iov_base = VRRP_SEND_BUFFER(vrrp);
+	iov.iov_len = VRRP_SEND_BUFFER_SIZE(vrrp);
+
+	/* Sending path */
+	if (vrrp->family == AF_INET) {
+		memset(&dst4, 0, sizeof(dst4));
+		dst4.sin_family = AF_INET;
+		dst4.sin_addr.s_addr = htonl(INADDR_VRRP_GROUP);
+
+		msg.msg_name = &dst4;
+		msg.msg_namelen = sizeof(dst4);
+	} else if (vrrp->family == AF_INET6) {
+		memset(&dst6, 0, sizeof(dst6));
+		dst6.sin6_family = AF_INET6;
+		dst6.sin6_port = htons(IPPROTO_VRRP);
+		dst6.sin6_addr.s6_addr16[0] = htons(0xff02);
+		dst6.sin6_addr.s6_addr16[7] = htons(0x12);
+
+		msg.msg_name = &dst6;
+		msg.msg_namelen = sizeof(dst6);
+	}
+
+	/* Send the packet */
+	return sendmsg(vrrp->fd_out, &msg, MSG_DONTROUTE);
+}
+
+/* Allocate the sending buffer */
+static void
+vrrp_alloc_send_buffer(vrrp_rt * vrrp)
+{
+	vrrp->send_buffer_size = vrrp_hd_len(vrrp);
+
+	if (vrrp->family == AF_INET) {
+		vrrp->send_buffer_size = vrrp_iphdr_len(vrrp) + vrrp_hd_len(vrrp);
+		if (vrrp->auth_type == VRRP_AUTH_AH)
+			vrrp->send_buffer_size += vrrp_ipsecah_len();
+	}
+
+	vrrp->send_buffer = MALLOC(VRRP_SEND_BUFFER_SIZE(vrrp));
+}
+
+/* send VRRP advertissement */
+int
+vrrp_send_adv(vrrp_rt * vrrp, int prio)
+{
+	/* alloc send buffer */
+	if (!vrrp->send_buffer)
+		vrrp_alloc_send_buffer(vrrp);
+	else
+		memset(vrrp->send_buffer, 0, VRRP_SEND_BUFFER_SIZE(vrrp));
+
+	/* build the packet */
+	vrrp_build_pkt(vrrp, prio);
+
+	/* send it */
+	return vrrp_send_pkt(vrrp);
+}
+
+/* Received packet processing */
+int
+vrrp_check_packet(vrrp_rt * vrrp, char *buf, int buflen)
+{
+	int ret;
+
+	if (buflen > 0) {
+		ret = vrrp_in_chk(vrrp, buf);
+
+		if (ret == VRRP_PACKET_DROP) {
+			log_message(LOG_INFO, "Sync instance needed on %s !!!",
+			       IF_NAME(vrrp->ifp));
+		}
+
+		if (ret == VRRP_PACKET_KO)
+			log_message(LOG_INFO, "bogus VRRP packet received on %s !!!",
+			       IF_NAME(vrrp->ifp));
+		return ret;
+	}
+
+	return VRRP_PACKET_NULL;
+}
+
+/* Gratuitous ARP on each VIP */
+static void
+vrrp_send_update(vrrp_rt * vrrp, ip_address * ipaddress, int idx)
+{
+	char *msg;
+	char addr_str[41];
+
+	if (!IP_IS6(ipaddress)) {
+		msg = "gratuitous ARPs";
+		inet_ntop(AF_INET, &ipaddress->u.sin.sin_addr, addr_str, 41);
+		send_gratuitous_arp(ipaddress);
+	} else {
+		msg = "Unsolicited Neighbour Adverts";
+		inet_ntop(AF_INET6, &ipaddress->u.sin6_addr, addr_str, 41);
+		ndisc_send_unsolicited_na(ipaddress);
+	}
+
+	if (0 == idx && debug & 32) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) Sending %s on %s for %s",
+			    vrrp->iname, msg, IF_NAME(ipaddress->ifp), addr_str);
+	}
+}
+
+void
+vrrp_send_link_update(vrrp_rt * vrrp)
+{
+	int j;
+	ip_address *ipaddress;
+	element e;
+
+	/* Only send gratuitous ARP if VIP are set */
+	if (!VRRP_VIP_ISSET(vrrp))
+		return;
+
+	/* send gratuitous arp for each virtual ip */
+	for (j = 0; j < 5; j++) {
+		if (!LIST_ISEMPTY(vrrp->vip)) {
+			for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) {
+				ipaddress = ELEMENT_DATA(e);
+				vrrp_send_update(vrrp, ipaddress, j);
+			}
+		}
+
+		if (!LIST_ISEMPTY(vrrp->evip)) {
+			for (e = LIST_HEAD(vrrp->evip); e; ELEMENT_NEXT(e)) {
+				ipaddress = ELEMENT_DATA(e);
+				vrrp_send_update(vrrp, ipaddress, j);
+			}
+		}
+	}
+}
+
+/* becoming master */
+void
+vrrp_state_become_master(vrrp_rt * vrrp)
+{
+	/* add the ip addresses */
+	if (!LIST_ISEMPTY(vrrp->vip))
+		vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_VIP_TYPE);
+	if (!LIST_ISEMPTY(vrrp->evip))
+		vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_EVIP_TYPE);
+	vrrp->vipset = 1;
+
+	/* add virtual routes */
+	if (!LIST_ISEMPTY(vrrp->vroutes))
+		vrrp_handle_iproutes(vrrp, IPROUTE_ADD);
+
+	/* remotes neighbour update */
+	vrrp_send_link_update(vrrp);
+
+	/* Check if notify is needed */
+	notify_instance_exec(vrrp, VRRP_STATE_MAST);
+
+#ifdef _WITH_SNMP_
+	vrrp_snmp_instance_trap(vrrp);
+#endif
+
+#ifdef _HAVE_IPVS_SYNCD_
+	/* Check if sync daemon handling is needed */
+	if (vrrp->lvs_syncd_if)
+		ipvs_syncd_master(vrrp->lvs_syncd_if, vrrp->vrid);
+#endif
+}
+
+void
+vrrp_state_goto_master(vrrp_rt * vrrp)
+{
+	/*
+	 * Send an advertisement. To force a new master
+	 * election.
+	 */
+        if (vrrp->sync && !vrrp_sync_goto_master(vrrp))
+	      return;
+	vrrp_send_adv(vrrp, vrrp->effective_priority);
+
+	vrrp->state = VRRP_STATE_MAST;
+	log_message(LOG_INFO, "VRRP_Instance(%s) Transition to MASTER STATE",
+	       vrrp->iname);
+}
+
+/* leaving master state */
+void
+vrrp_restore_interface(vrrp_rt * vrrp, int advF)
+{
+        /* if we stop vrrp, warn the other routers to speed up the recovery */
+	if (advF) {
+	        syslog(LOG_INFO, "VRRP_Instance(%s) sending 0 priority",
+		       vrrp->iname);
+		vrrp_send_adv(vrrp, VRRP_PRIO_STOP);
+	}
+
+	/* remove virtual routes */
+	if (!LIST_ISEMPTY(vrrp->vroutes))
+		vrrp_handle_iproutes(vrrp, IPROUTE_DEL);
+
+	/*
+	 * Remove the ip addresses.
+	 *
+	 * If started with "--dont-release-vrrp" (debug & 8) then try to remove
+	 * addresses even if we didn't add them during this run.
+	 */
+	if (debug & 8 || VRRP_VIP_ISSET(vrrp)) {
+		if (!LIST_ISEMPTY(vrrp->vip))
+			vrrp_handle_ipaddress(vrrp, IPADDRESS_DEL,
+					      VRRP_VIP_TYPE);
+		if (!LIST_ISEMPTY(vrrp->evip))
+			vrrp_handle_ipaddress(vrrp, IPADDRESS_DEL,
+					      VRRP_EVIP_TYPE);
+		vrrp->vipset = 0;
+	}
+
+}
+
+void
+vrrp_state_leave_master(vrrp_rt * vrrp)
+{
+	if (VRRP_VIP_ISSET(vrrp)) {
+#ifdef _HAVE_IPVS_SYNCD_
+		/* Check if sync daemon handling is needed */
+		if (vrrp->lvs_syncd_if)
+			ipvs_syncd_backup(vrrp->lvs_syncd_if, vrrp->vrid);
+#endif
+	}
+
+	/* set the new vrrp state */
+	switch (vrrp->wantstate) {
+	case VRRP_STATE_BACK:
+		log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE", vrrp->iname);
+		vrrp_restore_interface(vrrp, 0);
+		vrrp->state = vrrp->wantstate;
+		notify_instance_exec(vrrp, VRRP_STATE_BACK);
+#ifdef _WITH_SNMP_
+		vrrp_snmp_instance_trap(vrrp);
+#endif
+		break;
+	case VRRP_STATE_GOTO_FAULT:
+		log_message(LOG_INFO, "VRRP_Instance(%s) Entering FAULT STATE", vrrp->iname);
+		vrrp_restore_interface(vrrp, 0);
+		vrrp->state = VRRP_STATE_FAULT;
+		notify_instance_exec(vrrp, VRRP_STATE_FAULT);
+#ifdef _WITH_SNMP_
+		vrrp_snmp_instance_trap(vrrp);
+#endif
+		break;
+	}
+
+	/* Set the down timer */
+	vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+}
+
+/* BACKUP state processing */
+void
+vrrp_state_backup(vrrp_rt * vrrp, char *buf, int buflen)
+{
+	vrrp_pkt *hd;
+	uint32_t saddr;
+	int ret = 0, proto;
+
+	/* Process the incoming packet */
+	hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr);
+	ret = vrrp_check_packet(vrrp, buf, buflen);
+
+	if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_NULL) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) ignoring received advertisment..."
+			            ,  vrrp->iname);
+		vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+	} else if (hd->priority == 0) {
+		vrrp->ms_down_timer = VRRP_TIMER_SKEW(vrrp);
+	} else if (vrrp->nopreempt || hd->priority >= vrrp->effective_priority ||
+		   timer_cmp(vrrp->preempt_time, timer_now()) > 0) {
+		vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+	} else if (hd->priority < vrrp->effective_priority) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) forcing a new MASTER election"
+				    , vrrp->iname);
+		vrrp->wantstate = VRRP_STATE_GOTO_MASTER;
+		vrrp_send_adv(vrrp, vrrp->effective_priority);
+	}
+}
+
+/* MASTER state processing */
+int
+vrrp_state_master_tx(vrrp_rt * vrrp, const int prio)
+{
+	int ret = 0;
+
+	if (!VRRP_VIP_ISSET(vrrp)) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) Entering MASTER STATE"
+				    , vrrp->iname);
+		vrrp_state_become_master(vrrp);
+		ret = 1;
+	}
+
+	vrrp_send_adv(vrrp,
+		      (prio == VRRP_PRIO_OWNER) ? VRRP_PRIO_OWNER :
+						  vrrp->effective_priority);
+	return ret;
+}
+
+int
+vrrp_state_master_rx(vrrp_rt * vrrp, char *buf, int buflen)
+{
+	vrrp_pkt *hd = NULL;
+	int ret = 0, proto = 0;
+	uint32_t saddr = 0;
+	ipsec_ah *ah;
+
+	/* return on link failure */
+	if (vrrp->wantstate == VRRP_STATE_GOTO_FAULT) {
+		vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+		vrrp->state = VRRP_STATE_FAULT;
+		notify_instance_exec(vrrp, VRRP_STATE_FAULT);
+		return 1;
+	}
+
+	/* Process the incoming packet */
+	hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr);
+	ret = vrrp_check_packet(vrrp, buf, buflen);
+
+	if (ret == VRRP_PACKET_KO ||
+	    ret == VRRP_PACKET_NULL || ret == VRRP_PACKET_DROP) {
+		log_message(LOG_INFO,
+		       "VRRP_Instance(%s) Dropping received VRRP packet...",
+		       vrrp->iname);
+		return 0;
+	} else if (hd->priority < vrrp->effective_priority) {
+		/* We receive a lower prio adv we just refresh remote ARP cache */
+		log_message(LOG_INFO, "VRRP_Instance(%s) Received lower prio advert"
+				      ", forcing new election", vrrp->iname);
+		if (proto == IPPROTO_IPSEC_AH) {
+			ah = (ipsec_ah *) (buf + sizeof(struct iphdr));
+			log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : Syncing seq_num"
+					      " - Increment seq"
+					    , vrrp->iname);
+			vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number) + 1;
+			vrrp->ipsecah_counter->cycle = 0;
+		}
+		vrrp_send_adv(vrrp, vrrp->effective_priority);
+		vrrp_send_link_update(vrrp);
+		return 0;
+	} else if (hd->priority == 0) {
+		vrrp_send_adv(vrrp, vrrp->effective_priority);
+		return 0;
+	} else if (vrrp->family == AF_INET) {
+		if (hd->priority > vrrp->effective_priority ||
+		    (hd->priority == vrrp->effective_priority &&
+		     ntohl(saddr) > VRRP_PKT_SADDR(vrrp))) {
+			log_message(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert"
+					    , vrrp->iname);
+			if (proto == IPPROTO_IPSEC_AH) {
+				ah = (ipsec_ah *) (buf + sizeof(struct iphdr));
+				log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : Syncing seq_num"
+						      " - Decrement seq"
+						    , vrrp->iname);
+				vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number) - 1;
+				vrrp->ipsecah_counter->cycle = 0;
+			}
+			vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+			vrrp->wantstate = VRRP_STATE_BACK;
+			vrrp->state = VRRP_STATE_BACK;
+			return 1;
+		}
+	} else if (vrrp->family == AF_INET6) {
+		/* FIXME: compare v6 saddr to link local when prio are equal !!! */
+		if (hd->priority > vrrp->effective_priority) {
+			log_message(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert"
+					    , vrrp->iname);
+			vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+			vrrp->wantstate = VRRP_STATE_BACK;
+			vrrp->state = VRRP_STATE_BACK;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int
+vrrp_state_fault_rx(vrrp_rt * vrrp, char *buf, int buflen)
+{
+	vrrp_pkt *hd;
+	uint32_t saddr;
+	int ret = 0, proto;
+
+	/* Process the incoming packet */
+	hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr);
+	ret = vrrp_check_packet(vrrp, buf, buflen);
+
+	if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_NULL || ret == VRRP_PACKET_DROP) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) Dropping received VRRP packet..."
+				    , vrrp->iname);
+		return 0;
+	} else if (vrrp->effective_priority > hd->priority ||
+		   hd->priority == VRRP_PRIO_OWNER) {
+		if (!vrrp->nopreempt)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* check for minimum configuration requirements */
+static int
+chk_min_cfg(vrrp_rt * vrrp)
+{
+	if (vrrp->vrid == 0) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) the virtual id must be set!",
+		       vrrp->iname);
+		return 0;
+	}
+	if (!vrrp->ifp) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) Unknown interface !",
+		       vrrp->iname);
+		return 0;
+	}
+
+	return 1;
+}
+
+/* open a VRRP sending socket */
+int
+open_vrrp_send_socket(sa_family_t family, int proto, int idx)
+{
+	interface *ifp;
+	int fd = -1;
+
+	/* Retreive interface */
+	ifp = if_get_by_ifindex(idx);
+
+	/* Create and init socket descriptor */
+	fd = socket(family, SOCK_RAW, proto);
+	if (fd < 0) {
+		log_message(LOG_INFO, "cant open raw socket. errno=%d", errno);
+		return -1;
+	}
+
+	if (family == AF_INET) {
+		/* Set v4 related */
+		if_setsockopt_hdrincl(&fd);
+		if_setsockopt_bindtodevice(&fd, ifp);
+		if_setsockopt_mcast_loop(family, &fd);
+		if_setsockopt_priority(&fd);
+		if (fd < 0)
+			return -1;
+	} else if (family == AF_INET6) {
+		/* Set v6 related */
+		if_setsockopt_mcast_hops(family, &fd);
+		if_setsockopt_mcast_if(family, &fd, ifp);
+		if_setsockopt_mcast_loop(family, &fd);
+		if_setsockopt_priority(&fd);
+		if (fd < 0)
+			return -1;
+	} else {
+		log_message(LOG_INFO, "cant open raw socket. unknow family=%d"
+				    , family);
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+/* open a VRRP socket and join the multicast group. */
+int
+open_vrrp_socket(sa_family_t family, int proto, int idx)
+{
+	interface *ifp;
+	int fd = -1;
+
+	/* Retreive interface */
+	ifp = if_get_by_ifindex(idx);
+
+	/* open the socket */
+	fd = socket(family, SOCK_RAW, proto);
+	if (fd < 0) {
+		int err = errno;
+		log_message(LOG_INFO, "cant open raw socket. errno=%d", err);
+		return -1;
+	}
+
+	/* Join the VRRP MCAST group */
+	if_join_vrrp_group(family, &fd, ifp, proto);
+	if (fd < 0)
+		return -1;
+
+	if (family == AF_INET) {
+		/* Bind inbound stream */
+		if_setsockopt_bindtodevice(&fd, ifp);
+	}
+
+	return fd;
+}
+
+void
+close_vrrp_socket(vrrp_rt * vrrp)
+{
+	if_leave_vrrp_group(vrrp->family, vrrp->fd_in, vrrp->ifp);
+	close(vrrp->fd_out);
+}
+
+int
+new_vrrp_socket(vrrp_rt * vrrp)
+{
+	int old_fd = vrrp->fd_in;
+	int proto;
+
+	/* close the desc & open a new one */
+	close_vrrp_socket(vrrp);
+	remove_vrrp_fd_bucket(vrrp);
+	proto = (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP;
+	vrrp->fd_in = open_vrrp_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp));
+	vrrp->fd_out = open_vrrp_send_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp));
+	alloc_vrrp_fd_bucket(vrrp);
+
+	/* Sync the other desc */
+	set_vrrp_fd_bucket(old_fd, vrrp);
+
+	return vrrp->fd_in;
+}
+
+/* handle terminate state */
+void
+shutdown_vrrp_instances(void)
+{
+	list l = vrrp_data->vrrp;
+	element e;
+	vrrp_rt *vrrp;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+
+		/* Remove VIPs/VROUTEs */
+		if (vrrp->state == VRRP_STATE_MAST)
+			vrrp_restore_interface(vrrp, 1);
+
+		/* Remove VMAC */
+		if (vrrp->vmac)
+			netlink_link_del_vmac(vrrp);
+
+		/* Run stop script */
+		if (vrrp->script_stop)
+			notify_exec(vrrp->script_stop);
+
+#ifdef _HAVE_IPVS_SYNCD_
+		/*
+		 * Stop stalled syncd. IPVS syncd state is the
+		 * same as VRRP instance one. We need here to
+		 * stop stalled syncd thread according to last
+		 * VRRP instance state.
+		 */
+		if (vrrp->lvs_syncd_if)
+			ipvs_syncd_cmd(IPVS_STOPDAEMON, NULL,
+				       (vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER:
+									  IPVS_BACKUP,
+				       vrrp->vrid);
+#endif
+	}
+}
+
+/* complete vrrp structure */
+static int
+vrrp_complete_instance(vrrp_rt * vrrp)
+{
+	vrrp->state = VRRP_STATE_INIT;
+	if (!vrrp->adver_int)
+		vrrp->adver_int = VRRP_ADVER_DFL * TIMER_HZ;
+	if (!vrrp->effective_priority)
+		vrrp->effective_priority = VRRP_PRIO_DFL;
+
+	return (chk_min_cfg(vrrp));
+}
+
+int
+vrrp_complete_init(void)
+{
+	list l;
+	element e;
+	vrrp_rt *vrrp;
+	vrrp_sgroup *sgroup;
+
+	/* Complete VRRP instance initialization */
+	l = vrrp_data->vrrp;
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		if (!vrrp_complete_instance(vrrp))
+			return 0;
+	}
+
+	/* Build synchronization group index */
+	l = vrrp_data->vrrp_sync_group;
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		sgroup = ELEMENT_DATA(e);
+		vrrp_sync_set_group(sgroup);
+	}
+
+	return 1;
+}
+
+/* Try to find a VRRP instance */
+static vrrp_rt *
+vrrp_exist(vrrp_rt * old_vrrp)
+{
+	element e;
+	list l = vrrp_data->vrrp;
+	vrrp_rt *vrrp;
+
+	if (LIST_ISEMPTY(l))
+		return NULL;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		if (!strcmp(vrrp->iname, old_vrrp->iname))
+			return vrrp;
+	}
+
+	return NULL;
+}
+
+/* Clear VIP|EVIP not present into the new data */
+static void
+clear_diff_vrrp_vip(vrrp_rt * old_vrrp, int type)
+{
+	vrrp_rt *vrrp = vrrp_exist(old_vrrp);
+	list l = (type == VRRP_VIP_TYPE) ? old_vrrp->vip : old_vrrp->evip;
+	list n = (type == VRRP_VIP_TYPE) ? vrrp->vip : vrrp->evip;
+	clear_diff_address(l, n);
+}
+
+/* Clear virtual routes not present in the new data */
+static void
+clear_diff_vrrp_vroutes(vrrp_rt * old_vrrp)
+{
+	vrrp_rt *vrrp = vrrp_exist(old_vrrp);
+	clear_diff_routes(old_vrrp->vroutes, vrrp->vroutes);
+}
+
+/* Keep the state from before reload */
+static void
+reset_vrrp_state(vrrp_rt * old_vrrp)
+{
+	/* Keep VRRP state, ipsec AH seq_number */
+	vrrp_rt *vrrp = vrrp_exist(old_vrrp);
+	vrrp->state = old_vrrp->state;
+	vrrp->init_state = old_vrrp->state;
+	vrrp->wantstate = old_vrrp->state;
+	if (!old_vrrp->sync)
+		vrrp->effective_priority = old_vrrp->effective_priority;
+	memcpy(vrrp->ipsecah_counter, old_vrrp->ipsecah_counter, sizeof(seq_counter));
+
+#ifdef _HAVE_IPVS_SYNCD_
+	if (old_vrrp->lvs_syncd_if)
+		ipvs_syncd_cmd(IPVS_STOPDAEMON, NULL,
+			       (old_vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER:
+								      IPVS_BACKUP,
+			       old_vrrp->vrid);
+	if (vrrp->lvs_syncd_if)
+		ipvs_syncd_cmd(IPVS_STARTDAEMON, NULL,
+			       (vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER:
+								  IPVS_BACKUP,
+			       vrrp->vrid);
+#endif
+
+	/* Remember if we had vips up and add new ones if needed */
+	vrrp->vipset = old_vrrp->vipset;
+	if (vrrp->vipset) {
+		if (!LIST_ISEMPTY(vrrp->vip))
+			vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_VIP_TYPE);
+		if (!LIST_ISEMPTY(vrrp->evip))
+			vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_EVIP_TYPE);
+		if (!LIST_ISEMPTY(vrrp->vroutes))
+			vrrp_handle_iproutes(vrrp, IPROUTE_ADD);
+	}
+}
+
+/* Diff when reloading configuration */
+void
+clear_diff_vrrp(void)
+{
+	element e;
+	list l = old_vrrp_data->vrrp;
+	vrrp_rt *vrrp;
+
+	if (LIST_ISEMPTY(l))
+		return;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		vrrp_rt *new_vrrp;
+
+		/*
+		 * Try to find this vrrp into the new conf data
+		 * reloaded.
+		 */
+		new_vrrp = vrrp_exist(vrrp);
+		if (!new_vrrp) {
+			vrrp_restore_interface(vrrp, 1);
+
+			/* Remove VMAC if one was created */
+			if (vrrp->vmac) 
+				netlink_link_del_vmac(vrrp);
+		} else {
+			/*
+			 * If this vrrp instance exist in new
+			 * data, then perform a VIP|EVIP diff.
+			 */
+			clear_diff_vrrp_vip(vrrp, VRRP_VIP_TYPE);
+			clear_diff_vrrp_vip(vrrp, VRRP_EVIP_TYPE);
+
+			/* virtual routes diff */
+			clear_diff_vrrp_vroutes(vrrp);
+
+			/* 
+			 * Remove VMAC if it existed in old vrrp instance,
+			 * but not the new one.
+			 */
+			if (vrrp->vmac && !new_vrrp->vmac) {
+				netlink_link_del_vmac(vrrp);
+			}
+
+			/* reset the state */
+			reset_vrrp_state(vrrp);
+		}
+	}
+}
+
+/* Set script status to a sensible value on reload */
+void
+clear_diff_script(void)
+{
+	element e;
+	list l = old_vrrp_data->vrrp_script;
+	vrrp_script *vscript, *nvscript;
+
+	if (LIST_ISEMPTY(l))
+		return;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vscript = ELEMENT_DATA(e);
+		if (vscript->result >= vscript->rise) {
+			nvscript = find_script_by_name(vscript->sname);
+			if (nvscript) {
+				log_message(LOG_INFO, "VRRP_Script(%s) considered successful on reload",
+					   nvscript->sname);
+				nvscript->result = VRRP_SCRIPT_STATUS_INIT_GOOD;
+			}
+		}
+	}
+}
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp.c~ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp.c~
--- keepalived-1.2.7/keepalived/vrrp/vrrp.c~	1970-01-01 01:00:00.000000000 +0100
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp.c~	2013-05-24 09:39:17.000000000 +0200
@@ -0,0 +1,1333 @@
+/*
+ * Soft:        Keepalived is a failover program for the LVS project
+ *              <www.linuxvirtualserver.org>. It monitor & manipulate
+ *              a loadbalanced server pool using multi-layer checks.
+ *
+ * Part:        VRRP implementation of VRRPv2 as specified in rfc2338.
+ *              VRRP is a protocol which elect a master server on a LAN. If the
+ *              master fails, a backup server takes over.
+ *              The original implementation has been made by jerome etienne.
+ *
+ * Author:      Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ *              This program is distributed in the hope that it will be useful, 
+ *              but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ *              See the GNU General Public License for more details.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2001-2012 Alexandre Cassen, <acassen@gmail.com>
+ */
+
+/* local include */
+#include <ctype.h>
+#include <sys/uio.h>
+#include "vrrp_arp.h"
+#include "vrrp_ndisc.h"
+#include "vrrp_scheduler.h"
+#include "vrrp_notify.h"
+#include "ipvswrapper.h"
+#include "vrrp.h"
+#include "vrrp_data.h"
+#include "vrrp_sync.h"
+#include "vrrp_index.h"
+#include "vrrp_vmac.h"
+#ifdef _WITH_SNMP_
+#include "vrrp_snmp.h"
+#endif
+#include "memory.h"
+#include "list.h"
+#include "logger.h"
+#include "main.h"
+#include "utils.h"
+#include "notify.h"
+
+/* add/remove Virtual IP addresses */
+static int
+vrrp_handle_ipaddress(vrrp_rt * vrrp, int cmd, int type)
+{
+	if (debug & 32)
+		log_message(LOG_INFO, "VRRP_Instance(%s) %s protocol %s", vrrp->iname,
+		       (cmd == IPADDRESS_ADD) ? "setting" : "removing",
+		       (type == VRRP_VIP_TYPE) ? "VIPs." : "E-VIPs.");
+	netlink_iplist((type == VRRP_VIP_TYPE) ? vrrp->vip : vrrp->evip, cmd);
+	return 1;
+}
+
+/* add/remove Virtual routes */
+static int
+vrrp_handle_iproutes(vrrp_rt * vrrp, int cmd)
+{
+	if (debug & 32)
+		log_message(LOG_INFO, "VRRP_Instance(%s) %s protocol Virtual Routes",
+		       vrrp->iname,
+		       (cmd == IPROUTE_ADD) ? "setting" : "removing");
+	netlink_rtlist_ipv4(vrrp->vroutes, cmd);
+	return 1;
+}
+
+/* IP header length */
+static int
+vrrp_iphdr_len(vrrp_rt * vrrp)
+{
+	return sizeof (struct iphdr);
+}
+
+/* IPSEC AH header length */
+int
+vrrp_ipsecah_len(void)
+{
+	return sizeof (ipsec_ah);
+}
+
+/* VRRP header length */
+static int
+vrrp_hd_len(vrrp_rt * vrrp)
+{
+	int len = sizeof (vrrp_pkt);
+	if (vrrp->family == AF_INET)
+		len += VRRP_AUTH_LEN + ((!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) * sizeof (uint32_t) : 0);
+        return len;
+}
+
+/* VRRP header pointer from buffer */
+vrrp_pkt *
+vrrp_get_header(sa_family_t family, char *buf, int *proto, uint32_t *saddr)
+{
+	struct iphdr *iph;
+	vrrp_pkt *hd = NULL;
+
+	if (family == AF_INET) {
+		iph = (struct iphdr *) buf;
+		*saddr = iph->saddr;
+
+		/* Fill the VRRP header */
+		switch (iph->protocol) {
+		case IPPROTO_IPSEC_AH:
+			*proto = IPPROTO_IPSEC_AH;
+			hd = (vrrp_pkt *) ((char *) iph + (iph->ihl << 2) +
+					   vrrp_ipsecah_len());
+			break;
+		case IPPROTO_VRRP:
+			*proto = IPPROTO_VRRP;
+			hd = (vrrp_pkt *) ((char *) iph + (iph->ihl << 2));
+			break;
+		}
+	} else if (family == AF_INET6) {
+		*proto = IPPROTO_VRRP;
+		*saddr = 0;
+		hd = (vrrp_pkt *) buf;
+	}
+
+	return hd;
+}
+
+/*
+ * IPSEC AH incoming packet check.
+ * return 0 for a valid pkt, != 0 otherwise.
+ */
+static int
+vrrp_in_chk_ipsecah(vrrp_rt * vrrp, char *buffer)
+{
+	struct iphdr *ip = (struct iphdr *) (buffer);
+	ipsec_ah *ah = (ipsec_ah *) ((char *) ip + (ip->ihl << 2));
+	unsigned char *digest;
+	uint32_t backup_auth_data[3];
+
+	/* first verify that the SPI value is equal to src IP */
+	if (ah->spi != ip->saddr) {
+		log_message(LOG_INFO,
+		       "IPSEC AH : invalid IPSEC SPI value. %d and expect %d",
+		       ip->saddr, ah->spi);
+		return 1;
+	}
+
+	/*
+	 * then proceed with the sequence number to prevent against replay attack.
+	 * For inbound processing, we increment seq_number counter to audit 
+	 * sender counter.
+	 */
+	vrrp->ipsecah_counter->seq_number++;
+	if (ntohl(ah->seq_number) >= vrrp->ipsecah_counter->seq_number || vrrp->sync) {
+		vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number);
+	} else {
+		log_message(LOG_INFO,
+		       "VRRP_Instance(%s) IPSEC-AH : sequence number %d"
+		       " already proceeded. Packet dropped. Local(%d)", vrrp->iname
+		       , ntohl(ah->seq_number), vrrp->ipsecah_counter->seq_number);
+		return 1;
+	}
+
+	/*
+	 * then compute a ICV to compare with the one present in AH pkt.
+	 * alloc a temp memory space to stock the ip mutable fields
+	 */
+	digest = (unsigned char *) MALLOC(16 * sizeof (unsigned char *));
+
+	/* zero the ip mutable fields */
+	ip->tos = 0;
+	ip->frag_off = 0;
+	ip->check = 0;
+	memcpy(backup_auth_data, ah->auth_data, sizeof (ah->auth_data));
+	memset(ah->auth_data, 0, sizeof (ah->auth_data));
+
+	/* Compute the ICV */
+	hmac_md5((unsigned char *) buffer,
+		 vrrp_iphdr_len(vrrp) + vrrp_ipsecah_len() + vrrp_hd_len(vrrp)
+		 , vrrp->auth_data, sizeof (vrrp->auth_data)
+		 , digest);
+
+	if (memcmp(backup_auth_data, digest, HMAC_MD5_TRUNC) != 0) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : invalid"
+		       " IPSEC HMAC-MD5 value. Due to fields mutation"
+		       " or bad password !", vrrp->iname);
+		return 1;
+	}
+
+	FREE(digest);
+	return 0;
+}
+
+/* check if ipaddr is present in VIP buffer */
+static int
+vrrp_in_chk_vips(vrrp_rt * vrrp, ip_address *ipaddress, unsigned char *buffer)
+{
+	int i;
+	uint32_t ipbuf;
+
+	/* Just skip IPv6 address, when we are using a mixed v4/v6 vips
+	 * set inside se same VRRP instance.
+	 */
+	if (IP_IS6(ipaddress))
+		return 1;
+
+	for (i = 0; i < LIST_SIZE(vrrp->vip); i++) {
+		bcopy(buffer + i * sizeof (uint32_t), &ipbuf,
+		      sizeof (uint32_t));
+		if (ipaddress->u.sin.sin_addr.s_addr == ipbuf)
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * VRRP incoming packet check.
+ * return 0 if the pkt is valid, != 0 otherwise.
+ */
+static int
+vrrp_in_chk(vrrp_rt * vrrp, char *buffer)
+{
+	struct iphdr *ip;
+	int ihl, vrrp_pkt_len;
+	ipsec_ah *ah;
+	vrrp_pkt *hd;
+	unsigned char *vips;
+	ip_address *ipaddress;
+	element e;
+
+	/* IPv4 related */
+	if (vrrp->family == AF_INET) {
+
+		ip = (struct iphdr *) (buffer);
+		ihl = ip->ihl << 2;
+
+		if (vrrp->auth_type == VRRP_AUTH_AH) {
+			ah = (ipsec_ah *) (buffer + ihl);
+			hd = (vrrp_pkt *) (ah + vrrp_ipsecah_len());
+		} else {
+			hd = (vrrp_pkt *) (buffer + ihl);
+		}
+	
+		/* pointer to vrrp vips pkt zone */
+		vips = (unsigned char *) ((char *) hd + sizeof (vrrp_pkt));
+	
+		/* MUST verify that the IP TTL is 255 */
+		if (ip->ttl != VRRP_IP_TTL) {
+			log_message(LOG_INFO, "invalid ttl. %d and expect %d", ip->ttl,
+			       VRRP_IP_TTL);
+			return VRRP_PACKET_KO;
+		}
+	
+		/*
+		 * MUST verify that the received packet length is greater than or
+		 * equal to the VRRP header
+		 */
+		if ((ntohs(ip->tot_len) - ihl) <= sizeof (vrrp_pkt)) {
+			log_message(LOG_INFO,
+			       "ip payload too short. %d and expect at least %d",
+			       ntohs(ip->tot_len) - ihl, sizeof (vrrp_pkt));
+			return VRRP_PACKET_KO;
+		}
+
+		if (!LIST_ISEMPTY(vrrp->vip)) {
+			/*
+			 * MAY verify that the IP address(es) associated with the
+			 * VRID are valid
+			 */
+			if (hd->naddr != LIST_SIZE(vrrp->vip)) {
+				log_message(LOG_INFO,
+				       "receive an invalid ip number count associated with VRID!");
+				return VRRP_PACKET_KO;
+			}
+
+			for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) {
+				ipaddress = ELEMENT_DATA(e);
+				if (!vrrp_in_chk_vips(vrrp, ipaddress, vips)) {
+					log_message(LOG_INFO, "ip address associated with VRID"
+					       " not present in received packet : %s",
+					       inet_ntop2(ipaddress->u.sin.sin_addr.s_addr));
+					log_message(LOG_INFO,
+					       "one or more VIP associated with"
+					       " VRID mismatch actual MASTER advert");
+					return VRRP_PACKET_KO;
+				}
+			}
+		}
+
+		/* check the authentication if it is a passwd */
+		if (hd->auth_type == VRRP_AUTH_PASS) {
+			char *pw = (char *) ip + ntohs(ip->tot_len)
+			    - sizeof (vrrp->auth_data);
+			if (memcmp(pw, vrrp->auth_data, sizeof(vrrp->auth_data)) != 0) {
+				log_message(LOG_INFO, "receive an invalid passwd!");
+				return VRRP_PACKET_KO;
+			}
+		}
+
+		/* check the authenicaion if it is ipsec ah */
+		if (hd->auth_type == VRRP_AUTH_AH)
+			return (vrrp_in_chk_ipsecah(vrrp, buffer));
+
+		/* Set expected vrrp packet lenght */
+		vrrp_pkt_len = sizeof(vrrp_pkt) + VRRP_AUTH_LEN + hd->naddr * sizeof(uint32_t);
+
+	} else if (vrrp->family == AF_INET6) { /* IPv6 related */
+
+		hd = (vrrp_pkt *) buffer;
+		vrrp_pkt_len = sizeof(vrrp_pkt);
+
+	} else {
+		return VRRP_PACKET_KO;
+	}
+
+	/* MUST verify the VRRP version */
+	if ((hd->vers_type >> 4) != VRRP_VERSION) {
+		log_message(LOG_INFO, "invalid version. %d and expect %d",
+		       (hd->vers_type >> 4), VRRP_VERSION);
+		return VRRP_PACKET_KO;
+	}
+
+	/* MUST verify the VRRP checksum */
+	if (in_csum((u_short *) hd, vrrp_pkt_len, 0)) {
+		log_message(LOG_INFO, "Invalid vrrp checksum");
+		return VRRP_PACKET_KO;
+	}
+
+	/*
+	 * MUST perform authentication specified by Auth Type 
+	 * check the authentication type
+	 */
+	if (vrrp->auth_type != hd->auth_type) {
+		log_message(LOG_INFO, "receive a %d auth, expecting %d!",
+		       hd->auth_type, vrrp->auth_type);
+		return VRRP_PACKET_KO;
+	}
+
+	/* MUST verify that the VRID is valid on the receiving interface */
+	if (vrrp->vrid != hd->vrid) {
+		log_message(LOG_INFO,
+		       "received VRID mismatch. Received %d, Expected %d",
+		       hd->vrid, vrrp->vrid);
+		return VRRP_PACKET_DROP;
+	}
+
+	if (LIST_ISEMPTY(vrrp->vip) && hd->naddr > 0) {
+		log_message(LOG_INFO, "receive an invalid ip number count associated with VRID!");
+		return VRRP_PACKET_KO;
+	}
+
+	/*
+	 * MUST verify that the Adver Interval in the packet is the same as
+	 * the locally configured for this virtual router
+	 */
+	if (vrrp->adver_int / TIMER_HZ != hd->adver_int) {
+		log_message(LOG_INFO, "advertissement interval mismatch mine=%d rcved=%d",
+		       vrrp->adver_int, hd->adver_int);
+		/* to prevent concurent VRID running => multiple master in 1 VRID */
+		return VRRP_PACKET_DROP;
+	}
+
+	return VRRP_PACKET_OK;
+}
+
+/* build IP header */
+static void
+vrrp_build_ip(vrrp_rt * vrrp, char *buffer, int buflen)
+{
+	struct iphdr *ip = (struct iphdr *) (buffer);
+
+	ip->ihl = 5;
+	ip->version = 4;
+	/* set tos to internet network control */
+	ip->tos = 0xc0;
+	ip->tot_len = ip->ihl * 4 + vrrp_hd_len(vrrp);
+	ip->tot_len = htons(ip->tot_len);
+	ip->id = htons(++vrrp->ip_id);
+	/* kernel will fill in ID if left to 0, so we overflow to 1 */
+	if (vrrp->ip_id == 65535)
+		vrrp->ip_id = 1;
+	ip->frag_off = 0;
+	ip->ttl = VRRP_IP_TTL;
+
+	/* fill protocol type --rfc2402.2 */
+	ip->protocol =
+	    (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP;
+	ip->saddr = vrrp->unicast_bind ? vrrp->unicast_bind : VRRP_PKT_SADDR(vrrp);
+	ip->daddr = vrrp->unicast_peer ? vrrp->unicast_peer : htonl(INADDR_VRRP_GROUP);
+
+	/* checksum must be done last */
+	ip->check = in_csum((u_short *) ip, ip->ihl * 4, 0);
+}
+
+/* build IPSEC AH header */
+static void
+vrrp_build_ipsecah(vrrp_rt * vrrp, char *buffer, int buflen)
+{
+	ICV_mutable_fields *ip_mutable_fields;
+	unsigned char *digest;
+	struct iphdr *ip = (struct iphdr *) (buffer);
+	ipsec_ah *ah = (ipsec_ah *) (buffer + sizeof (struct iphdr));
+
+	/* alloc a temp memory space to stock the ip mutable fields */
+	ip_mutable_fields = (ICV_mutable_fields *) MALLOC(sizeof (ICV_mutable_fields));
+
+	/* fill in next header filed --rfc2402.2.1 */
+	ah->next_header = IPPROTO_VRRP;
+
+	/* update IP header total length value */
+	ip->tot_len = ip->ihl * 4 + vrrp_ipsecah_len() + vrrp_hd_len(vrrp);
+	ip->tot_len = htons(ip->tot_len);
+
+	/* update ip checksum */
+	ip->check = 0;
+	ip->check = in_csum((u_short *) ip, ip->ihl * 4, 0);
+
+	/* backup the ip mutable fields */
+	ip_mutable_fields->tos = ip->tos;
+	ip_mutable_fields->frag_off = ip->frag_off;
+	ip_mutable_fields->check = ip->check;
+
+	/* zero the ip mutable fields */
+	ip->tos = 0;
+	ip->frag_off = 0;
+	ip->check = 0;
+
+	/* fill in the Payload len field */
+	ah->payload_len = IPSEC_AH_PLEN;
+
+	/* The SPI value is filled with the ip header source address.
+	   SPI uniquely identify the Security Association (SA). This value
+	   is chosen by the recipient itself when setting up the SA. In a 
+	   multicast environment, this becomes unfeasible.
+
+	   If left to the sender, the choice of the SPI value should be done
+	   so by the sender that it cannot possibly conflict with SPI values
+	   chosen by other entities sending IPSEC traffic to any of the receivers.
+	   To overpass this problem, the rule I have chosen to implement here is
+	   that the SPI value chosen by the sender is based on unique information
+	   such as its IP address.
+	   -- INTERNET draft : <draft-paridaens-xcast-sec-framework-01.txt>
+	 */
+	ah->spi = ip->saddr;
+
+	/* Processing sequence number.
+	   Cycled assumed if 0xFFFFFFFD reached. So the MASTER state is free for another srv.
+	   Here can result a flapping MASTER state owner when max seq_number value reached.
+	   => Much work needed here.
+	   In the current implementation if counter has cycled, we stop sending adverts and 
+	   become BACKUP. If all the master are down we reset the counter for becoming MASTER.
+	 */
+	if (vrrp->ipsecah_counter->seq_number > 0xFFFFFFFD) {
+		vrrp->ipsecah_counter->cycle = 1;
+	} else {
+		vrrp->ipsecah_counter->seq_number++;
+	}
+
+	ah->seq_number = htonl(vrrp->ipsecah_counter->seq_number);
+
+	/* Compute the ICV & trunc the digest to 96bits
+	   => No padding needed.
+	   -- rfc2402.3.3.3.1.1.1 & rfc2401.5
+	 */
+	digest = (unsigned char *) MALLOC(16 * sizeof (unsigned char *));
+	hmac_md5((unsigned char *) buffer, buflen, vrrp->auth_data, sizeof (vrrp->auth_data)
+		 , digest);
+	memcpy(ah->auth_data, digest, HMAC_MD5_TRUNC);
+
+	/* Restore the ip mutable fields */
+	ip->tos = ip_mutable_fields->tos;
+	ip->frag_off = ip_mutable_fields->frag_off;
+	ip->check = ip_mutable_fields->check;
+
+	FREE(ip_mutable_fields);
+	FREE(digest);
+}
+
+/* build VRRP header */
+static int
+vrrp_build_vrrp(vrrp_rt * vrrp, int prio, char *buffer)
+{
+	int i = 0;
+	vrrp_pkt *hd = (vrrp_pkt *) buffer;
+	uint32_t *iparr;
+	element e;
+	ip_address *ip_addr;
+
+	/* Family independant */
+	hd->vers_type = (VRRP_VERSION << 4) | VRRP_PKT_ADVERT;
+	hd->vrid = vrrp->vrid;
+	hd->priority = prio;
+	hd->naddr = (!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) : 0;
+	hd->auth_type = vrrp->auth_type;
+	hd->adver_int = vrrp->adver_int / TIMER_HZ;
+
+	/* Family specific */
+	if (vrrp->family == AF_INET) {
+		/* copy the ip addresses */
+		iparr = (uint32_t *) ((char *) hd + sizeof (*hd));
+		if (!LIST_ISEMPTY(vrrp->vip)) {
+			for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) {
+				ip_addr = ELEMENT_DATA(e);
+				if (IP_IS6(ip_addr))
+					continue;
+				else
+					iparr[i++] = ip_addr->u.sin.sin_addr.s_addr;
+			}
+		}
+
+		/* copy the passwd if the authentication is VRRP_AH_PASS */
+		if (vrrp->auth_type == VRRP_AUTH_PASS) {
+			int vip_count = (!LIST_ISEMPTY(vrrp->vip)) ? LIST_SIZE(vrrp->vip) : 0;
+			char *pw = (char *) hd + sizeof (*hd) + vip_count * 4;
+			memcpy(pw, vrrp->auth_data, sizeof (vrrp->auth_data));
+		}
+	}
+
+	/* finaly compute vrrp checksum */
+	hd->chksum = in_csum((u_short *) hd, vrrp_hd_len(vrrp), 0);
+
+	return 0;
+}
+
+/* build VRRP packet */
+static void
+vrrp_build_pkt(vrrp_rt * vrrp, int prio)
+{
+	char *bufptr;
+	int len;
+
+	/* save reference values */
+	bufptr = VRRP_SEND_BUFFER(vrrp);
+	len = VRRP_SEND_BUFFER_SIZE(vrrp);
+
+	if (vrrp->family == AF_INET) {
+		/* build the ip header */
+		vrrp_build_ip(vrrp, VRRP_SEND_BUFFER(vrrp), VRRP_SEND_BUFFER_SIZE(vrrp));
+
+		/* build the vrrp header */
+		vrrp->send_buffer += vrrp_iphdr_len(vrrp);
+
+		if (vrrp->auth_type == VRRP_AUTH_AH)
+			vrrp->send_buffer += vrrp_ipsecah_len();
+		vrrp->send_buffer_size -= vrrp_iphdr_len(vrrp);
+
+		if (vrrp->auth_type == VRRP_AUTH_AH)
+			vrrp->send_buffer_size -= vrrp_ipsecah_len();
+		vrrp_build_vrrp(vrrp, prio, vrrp->send_buffer);
+
+		/* build the IPSEC AH header */
+		if (vrrp->auth_type == VRRP_AUTH_AH) {
+			vrrp->send_buffer_size += vrrp_iphdr_len(vrrp) + vrrp_ipsecah_len();
+			vrrp_build_ipsecah(vrrp, bufptr, VRRP_SEND_BUFFER_SIZE(vrrp));
+		}
+	} else if (vrrp->family == AF_INET6) {
+		vrrp_build_vrrp(vrrp, prio, VRRP_SEND_BUFFER(vrrp));
+	}
+
+	/* restore reference values */
+	vrrp->send_buffer = bufptr;
+	vrrp->send_buffer_size = len;
+}
+
+/* send VRRP packet */
+static int
+vrrp_send_pkt(vrrp_rt * vrrp)
+{
+	struct sockaddr_in6 dst6;
+	struct sockaddr_in dst4;
+	struct msghdr msg;
+	struct iovec iov;
+
+	/* Build the message data */
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	iov.iov_base = VRRP_SEND_BUFFER(vrrp);
+	iov.iov_len = VRRP_SEND_BUFFER_SIZE(vrrp);
+
+	/* Sending path */
+	if (vrrp->family == AF_INET) {
+		memset(&dst4, 0, sizeof(dst4));
+		dst4.sin_family = AF_INET;
+		dst4.sin_addr.s_addr = vrrp->unicast_peer ? vrrp->unicast_peer : htonl(INADDR_VRRP_GROUP);
+
+		msg.msg_name = &dst4;
+		msg.msg_namelen = sizeof(dst4);
+	} else if (vrrp->family == AF_INET6) {
+		memset(&dst6, 0, sizeof(dst6));
+		dst6.sin6_family = AF_INET6;
+		dst6.sin6_port = htons(IPPROTO_VRRP);
+		dst6.sin6_addr.s6_addr16[0] = htons(0xff02);
+		dst6.sin6_addr.s6_addr16[7] = htons(0x12);
+
+		msg.msg_name = &dst6;
+		msg.msg_namelen = sizeof(dst6);
+	}
+
+	/* Send the packet */
+	return sendmsg(vrrp->fd_out, &msg, MSG_DONTROUTE);
+}
+
+/* Allocate the sending buffer */
+static void
+vrrp_alloc_send_buffer(vrrp_rt * vrrp)
+{
+	vrrp->send_buffer_size = vrrp_hd_len(vrrp);
+
+	if (vrrp->family == AF_INET) {
+		vrrp->send_buffer_size = vrrp_iphdr_len(vrrp) + vrrp_hd_len(vrrp);
+		if (vrrp->auth_type == VRRP_AUTH_AH)
+			vrrp->send_buffer_size += vrrp_ipsecah_len();
+	}
+
+	vrrp->send_buffer = MALLOC(VRRP_SEND_BUFFER_SIZE(vrrp));
+}
+
+/* send VRRP advertissement */
+int
+vrrp_send_adv(vrrp_rt * vrrp, int prio)
+{
+	/* alloc send buffer */
+	if (!vrrp->send_buffer)
+		vrrp_alloc_send_buffer(vrrp);
+	else
+		memset(vrrp->send_buffer, 0, VRRP_SEND_BUFFER_SIZE(vrrp));
+
+	/* build the packet */
+	vrrp_build_pkt(vrrp, prio);
+
+	/* send it */
+	return vrrp_send_pkt(vrrp);
+}
+
+/* Received packet processing */
+int
+vrrp_check_packet(vrrp_rt * vrrp, char *buf, int buflen)
+{
+	int ret;
+
+	if (buflen > 0) {
+		ret = vrrp_in_chk(vrrp, buf);
+
+		if (ret == VRRP_PACKET_DROP) {
+			log_message(LOG_INFO, "Sync instance needed on %s !!!",
+			       IF_NAME(vrrp->ifp));
+		}
+
+		if (ret == VRRP_PACKET_KO)
+			log_message(LOG_INFO, "bogus VRRP packet received on %s !!!",
+			       IF_NAME(vrrp->ifp));
+		return ret;
+	}
+
+	return VRRP_PACKET_NULL;
+}
+
+/* Gratuitous ARP on each VIP */
+static void
+vrrp_send_update(vrrp_rt * vrrp, ip_address * ipaddress, int idx)
+{
+	char *msg;
+	char addr_str[41];
+
+	if (!IP_IS6(ipaddress)) {
+		msg = "gratuitous ARPs";
+		inet_ntop(AF_INET, &ipaddress->u.sin.sin_addr, addr_str, 41);
+		send_gratuitous_arp(ipaddress);
+	} else {
+		msg = "Unsolicited Neighbour Adverts";
+		inet_ntop(AF_INET6, &ipaddress->u.sin6_addr, addr_str, 41);
+		ndisc_send_unsolicited_na(ipaddress);
+	}
+
+	if (0 == idx && debug & 32) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) Sending %s on %s for %s",
+			    vrrp->iname, msg, IF_NAME(ipaddress->ifp), addr_str);
+	}
+}
+
+void
+vrrp_send_link_update(vrrp_rt * vrrp)
+{
+	int j;
+	ip_address *ipaddress;
+	element e;
+
+	/* Only send gratuitous ARP if VIP are set */
+	if (!VRRP_VIP_ISSET(vrrp))
+		return;
+
+	/* send gratuitous arp for each virtual ip */
+	for (j = 0; j < 5; j++) {
+		if (!LIST_ISEMPTY(vrrp->vip)) {
+			for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) {
+				ipaddress = ELEMENT_DATA(e);
+				vrrp_send_update(vrrp, ipaddress, j);
+			}
+		}
+
+		if (!LIST_ISEMPTY(vrrp->evip)) {
+			for (e = LIST_HEAD(vrrp->evip); e; ELEMENT_NEXT(e)) {
+				ipaddress = ELEMENT_DATA(e);
+				vrrp_send_update(vrrp, ipaddress, j);
+			}
+		}
+	}
+}
+
+/* becoming master */
+void
+vrrp_state_become_master(vrrp_rt * vrrp)
+{
+	/* add the ip addresses */
+	if (!LIST_ISEMPTY(vrrp->vip))
+		vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_VIP_TYPE);
+	if (!LIST_ISEMPTY(vrrp->evip))
+		vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_EVIP_TYPE);
+	vrrp->vipset = 1;
+
+	/* add virtual routes */
+	if (!LIST_ISEMPTY(vrrp->vroutes))
+		vrrp_handle_iproutes(vrrp, IPROUTE_ADD);
+
+	/* remotes neighbour update */
+	vrrp_send_link_update(vrrp);
+
+	/* Check if notify is needed */
+	notify_instance_exec(vrrp, VRRP_STATE_MAST);
+
+#ifdef _WITH_SNMP_
+	vrrp_snmp_instance_trap(vrrp);
+#endif
+
+#ifdef _HAVE_IPVS_SYNCD_
+	/* Check if sync daemon handling is needed */
+	if (vrrp->lvs_syncd_if)
+		ipvs_syncd_master(vrrp->lvs_syncd_if, vrrp->vrid);
+#endif
+}
+
+void
+vrrp_state_goto_master(vrrp_rt * vrrp)
+{
+	/*
+	 * Send an advertisement. To force a new master
+	 * election.
+	 */
+        if (vrrp->sync && !vrrp_sync_goto_master(vrrp))
+	      return;
+	vrrp_send_adv(vrrp, vrrp->effective_priority);
+
+	vrrp->state = VRRP_STATE_MAST;
+	log_message(LOG_INFO, "VRRP_Instance(%s) Transition to MASTER STATE",
+	       vrrp->iname);
+}
+
+/* leaving master state */
+void
+vrrp_restore_interface(vrrp_rt * vrrp, int advF)
+{
+        /* if we stop vrrp, warn the other routers to speed up the recovery */
+	if (advF) {
+	        syslog(LOG_INFO, "VRRP_Instance(%s) sending 0 priority",
+		       vrrp->iname);
+		vrrp_send_adv(vrrp, VRRP_PRIO_STOP);
+	}
+
+	/* remove virtual routes */
+	if (!LIST_ISEMPTY(vrrp->vroutes))
+		vrrp_handle_iproutes(vrrp, IPROUTE_DEL);
+
+	/*
+	 * Remove the ip addresses.
+	 *
+	 * If started with "--dont-release-vrrp" (debug & 8) then try to remove
+	 * addresses even if we didn't add them during this run.
+	 */
+	if (debug & 8 || VRRP_VIP_ISSET(vrrp)) {
+		if (!LIST_ISEMPTY(vrrp->vip))
+			vrrp_handle_ipaddress(vrrp, IPADDRESS_DEL,
+					      VRRP_VIP_TYPE);
+		if (!LIST_ISEMPTY(vrrp->evip))
+			vrrp_handle_ipaddress(vrrp, IPADDRESS_DEL,
+					      VRRP_EVIP_TYPE);
+		vrrp->vipset = 0;
+	}
+
+}
+
+void
+vrrp_state_leave_master(vrrp_rt * vrrp)
+{
+	if (VRRP_VIP_ISSET(vrrp)) {
+#ifdef _HAVE_IPVS_SYNCD_
+		/* Check if sync daemon handling is needed */
+		if (vrrp->lvs_syncd_if)
+			ipvs_syncd_backup(vrrp->lvs_syncd_if, vrrp->vrid);
+#endif
+	}
+
+	/* set the new vrrp state */
+	switch (vrrp->wantstate) {
+	case VRRP_STATE_BACK:
+		log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE", vrrp->iname);
+		vrrp_restore_interface(vrrp, 0);
+		vrrp->state = vrrp->wantstate;
+		notify_instance_exec(vrrp, VRRP_STATE_BACK);
+#ifdef _WITH_SNMP_
+		vrrp_snmp_instance_trap(vrrp);
+#endif
+		break;
+	case VRRP_STATE_GOTO_FAULT:
+		log_message(LOG_INFO, "VRRP_Instance(%s) Entering FAULT STATE", vrrp->iname);
+		vrrp_restore_interface(vrrp, 0);
+		vrrp->state = VRRP_STATE_FAULT;
+		notify_instance_exec(vrrp, VRRP_STATE_FAULT);
+#ifdef _WITH_SNMP_
+		vrrp_snmp_instance_trap(vrrp);
+#endif
+		break;
+	}
+
+	/* Set the down timer */
+	vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+}
+
+/* BACKUP state processing */
+void
+vrrp_state_backup(vrrp_rt * vrrp, char *buf, int buflen)
+{
+	vrrp_pkt *hd;
+	uint32_t saddr;
+	int ret = 0, proto;
+
+	/* Process the incoming packet */
+	hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr);
+	ret = vrrp_check_packet(vrrp, buf, buflen);
+
+	if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_NULL) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) ignoring received advertisment..."
+			            ,  vrrp->iname);
+		vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+	} else if (hd->priority == 0) {
+		vrrp->ms_down_timer = VRRP_TIMER_SKEW(vrrp);
+	} else if (vrrp->nopreempt || hd->priority >= vrrp->effective_priority ||
+		   timer_cmp(vrrp->preempt_time, timer_now()) > 0) {
+		vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+	} else if (hd->priority < vrrp->effective_priority) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) forcing a new MASTER election"
+				    , vrrp->iname);
+		vrrp->wantstate = VRRP_STATE_GOTO_MASTER;
+		vrrp_send_adv(vrrp, vrrp->effective_priority);
+	}
+}
+
+/* MASTER state processing */
+int
+vrrp_state_master_tx(vrrp_rt * vrrp, const int prio)
+{
+	int ret = 0;
+
+	if (!VRRP_VIP_ISSET(vrrp)) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) Entering MASTER STATE"
+				    , vrrp->iname);
+		vrrp_state_become_master(vrrp);
+		ret = 1;
+	}
+
+	vrrp_send_adv(vrrp,
+		      (prio == VRRP_PRIO_OWNER) ? VRRP_PRIO_OWNER :
+						  vrrp->effective_priority);
+	return ret;
+}
+
+int
+vrrp_state_master_rx(vrrp_rt * vrrp, char *buf, int buflen)
+{
+	vrrp_pkt *hd = NULL;
+	int ret = 0, proto = 0;
+	uint32_t saddr = 0;
+	ipsec_ah *ah;
+
+	/* return on link failure */
+	if (vrrp->wantstate == VRRP_STATE_GOTO_FAULT) {
+		vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+		vrrp->state = VRRP_STATE_FAULT;
+		notify_instance_exec(vrrp, VRRP_STATE_FAULT);
+		return 1;
+	}
+
+	/* Process the incoming packet */
+	hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr);
+	ret = vrrp_check_packet(vrrp, buf, buflen);
+
+	if (ret == VRRP_PACKET_KO ||
+	    ret == VRRP_PACKET_NULL || ret == VRRP_PACKET_DROP) {
+		log_message(LOG_INFO,
+		       "VRRP_Instance(%s) Dropping received VRRP packet...",
+		       vrrp->iname);
+		return 0;
+	} else if (hd->priority < vrrp->effective_priority) {
+		/* We receive a lower prio adv we just refresh remote ARP cache */
+		log_message(LOG_INFO, "VRRP_Instance(%s) Received lower prio advert"
+				      ", forcing new election", vrrp->iname);
+		if (proto == IPPROTO_IPSEC_AH) {
+			ah = (ipsec_ah *) (buf + sizeof(struct iphdr));
+			log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : Syncing seq_num"
+					      " - Increment seq"
+					    , vrrp->iname);
+			vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number) + 1;
+			vrrp->ipsecah_counter->cycle = 0;
+		}
+		vrrp_send_adv(vrrp, vrrp->effective_priority);
+		vrrp_send_link_update(vrrp);
+		return 0;
+	} else if (hd->priority == 0) {
+		vrrp_send_adv(vrrp, vrrp->effective_priority);
+		return 0;
+	} else if (vrrp->family == AF_INET) {
+		if (hd->priority > vrrp->effective_priority ||
+		    (hd->priority == vrrp->effective_priority &&
+		     ntohl(saddr) > VRRP_PKT_SADDR(vrrp))) {
+			log_message(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert"
+					    , vrrp->iname);
+			if (proto == IPPROTO_IPSEC_AH) {
+				ah = (ipsec_ah *) (buf + sizeof(struct iphdr));
+				log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : Syncing seq_num"
+						      " - Decrement seq"
+						    , vrrp->iname);
+				vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number) - 1;
+				vrrp->ipsecah_counter->cycle = 0;
+			}
+			vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+			vrrp->wantstate = VRRP_STATE_BACK;
+			vrrp->state = VRRP_STATE_BACK;
+			return 1;
+		}
+	} else if (vrrp->family == AF_INET6) {
+		/* FIXME: compare v6 saddr to link local when prio are equal !!! */
+		if (hd->priority > vrrp->effective_priority) {
+			log_message(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert"
+					    , vrrp->iname);
+			vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+			vrrp->wantstate = VRRP_STATE_BACK;
+			vrrp->state = VRRP_STATE_BACK;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int
+vrrp_state_fault_rx(vrrp_rt * vrrp, char *buf, int buflen)
+{
+	vrrp_pkt *hd;
+	uint32_t saddr;
+	int ret = 0, proto;
+
+	/* Process the incoming packet */
+	hd = vrrp_get_header(vrrp->family, buf, &proto, &saddr);
+	ret = vrrp_check_packet(vrrp, buf, buflen);
+
+	if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_NULL || ret == VRRP_PACKET_DROP) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) Dropping received VRRP packet..."
+				    , vrrp->iname);
+		return 0;
+	} else if (vrrp->effective_priority > hd->priority ||
+		   hd->priority == VRRP_PRIO_OWNER) {
+		if (!vrrp->nopreempt)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* check for minimum configuration requirements */
+static int
+chk_min_cfg(vrrp_rt * vrrp)
+{
+	if (vrrp->vrid == 0) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) the virtual id must be set!",
+		       vrrp->iname);
+		return 0;
+	}
+	if (!vrrp->ifp) {
+		log_message(LOG_INFO, "VRRP_Instance(%s) Unknown interface !",
+		       vrrp->iname);
+		return 0;
+	}
+
+	return 1;
+}
+
+/* open a VRRP sending socket */
+int
+open_vrrp_send_socket(sa_family_t family, int proto, int idx, int unicast)
+{
+	interface *ifp;
+	int fd = -1;
+
+	/* Retreive interface */
+	ifp = if_get_by_ifindex(idx);
+
+	/* Create and init socket descriptor */
+	fd = socket(family, SOCK_RAW, proto);
+	if (fd < 0) {
+		log_message(LOG_INFO, "cant open raw socket. errno=%d", errno);
+		return -1;
+	}
+
+	if (family == AF_INET) {
+		/* Set v4 related */
+		if_setsockopt_hdrincl(&fd);
+		if_setsockopt_bindtodevice(&fd, ifp);
+		if_setsockopt_mcast_loop(family, &fd);
+		if_setsockopt_priority(&fd);
+		if (fd < 0)
+			return -1;
+	} else if (family == AF_INET6) {
+		/* Set v6 related */
+		if_setsockopt_mcast_hops(family, &fd);
+		if_setsockopt_mcast_if(family, &fd, ifp);
+		if_setsockopt_mcast_loop(family, &fd);
+		if_setsockopt_priority(&fd);
+		if (fd < 0)
+			return -1;
+	} else {
+		log_message(LOG_INFO, "cant open raw socket. unknow family=%d"
+				    , family);
+		close(fd);
+		return -1;
+	}
+
+	if (!unicast)
+		if_setsockopt_mcast_loop(family, &fd);
+	if (fd < 0)
+		return -1;
+
+	return fd;
+}
+
+/* open a VRRP socket and join the multicast group. */
+int
+open_vrrp_socket(sa_family_t family, int proto, int idx, int unicast)
+{
+	interface *ifp;
+	int fd = -1;
+
+	/* Retreive interface */
+	ifp = if_get_by_ifindex(idx);
+
+	/* open the socket */
+	fd = socket(family, SOCK_RAW, proto);
+	if (fd < 0) {
+		int err = errno;
+		log_message(LOG_INFO, "cant open raw socket. errno=%d", err);
+		return -1;
+	}
+
+	/* Join the VRRP MCAST group */
+	if (!unicast)
+		if_join_vrrp_group(family, &fd, ifp, proto);
+	if (fd < 0)
+		return -1;
+
+	if (family == AF_INET) {
+		/* Bind inbound stream */
+		if_setsockopt_bindtodevice(&fd, ifp);
+	}
+
+	return fd;
+}
+
+void
+close_vrrp_socket(vrrp_rt * vrrp)
+{
+	if_leave_vrrp_group(vrrp->family, vrrp->fd_in, vrrp->ifp, !vrrp->unicast_peer);
+	close(vrrp->fd_out);
+}
+
+int
+new_vrrp_socket(vrrp_rt * vrrp)
+{
+	int old_fd = vrrp->fd_in;
+	int proto;
+
+	/* close the desc & open a new one */
+	close_vrrp_socket(vrrp);
+	remove_vrrp_fd_bucket(vrrp);
+	proto = (vrrp->auth_type == VRRP_AUTH_AH) ? IPPROTO_IPSEC_AH : IPPROTO_VRRP;
+	vrrp->fd_in = open_vrrp_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp), !vrrp->unicast_peer);
+	vrrp->fd_out = open_vrrp_send_socket(vrrp->family, proto, IF_INDEX(vrrp->ifp), !vrrp->unicast_peer);
+	alloc_vrrp_fd_bucket(vrrp);
+
+	/* Sync the other desc */
+	set_vrrp_fd_bucket(old_fd, vrrp);
+
+	return vrrp->fd_in;
+}
+
+/* handle terminate state */
+void
+shutdown_vrrp_instances(void)
+{
+	list l = vrrp_data->vrrp;
+	element e;
+	vrrp_rt *vrrp;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+
+		/* Remove VIPs/VROUTEs */
+		if (vrrp->state == VRRP_STATE_MAST)
+			vrrp_restore_interface(vrrp, 1);
+
+		/* Remove VMAC */
+		if (vrrp->vmac)
+			netlink_link_del_vmac(vrrp);
+
+		/* Run stop script */
+		if (vrrp->script_stop)
+			notify_exec(vrrp->script_stop);
+
+#ifdef _HAVE_IPVS_SYNCD_
+		/*
+		 * Stop stalled syncd. IPVS syncd state is the
+		 * same as VRRP instance one. We need here to
+		 * stop stalled syncd thread according to last
+		 * VRRP instance state.
+		 */
+		if (vrrp->lvs_syncd_if)
+			ipvs_syncd_cmd(IPVS_STOPDAEMON, NULL,
+				       (vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER:
+									  IPVS_BACKUP,
+				       vrrp->vrid);
+#endif
+	}
+}
+
+/* complete vrrp structure */
+static int
+vrrp_complete_instance(vrrp_rt * vrrp)
+{
+	vrrp->state = VRRP_STATE_INIT;
+	if (!vrrp->adver_int)
+		vrrp->adver_int = VRRP_ADVER_DFL * TIMER_HZ;
+	if (!vrrp->effective_priority)
+		vrrp->effective_priority = VRRP_PRIO_DFL;
+
+	return (chk_min_cfg(vrrp));
+}
+
+int
+vrrp_complete_init(void)
+{
+	list l;
+	element e;
+	vrrp_rt *vrrp;
+	vrrp_sgroup *sgroup;
+
+	/* Complete VRRP instance initialization */
+	l = vrrp_data->vrrp;
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		if (!vrrp_complete_instance(vrrp))
+			return 0;
+	}
+
+	/* Build synchronization group index */
+	l = vrrp_data->vrrp_sync_group;
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		sgroup = ELEMENT_DATA(e);
+		vrrp_sync_set_group(sgroup);
+	}
+
+	return 1;
+}
+
+/* Try to find a VRRP instance */
+static vrrp_rt *
+vrrp_exist(vrrp_rt * old_vrrp)
+{
+	element e;
+	list l = vrrp_data->vrrp;
+	vrrp_rt *vrrp;
+
+	if (LIST_ISEMPTY(l))
+		return NULL;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		if (!strcmp(vrrp->iname, old_vrrp->iname))
+			return vrrp;
+	}
+
+	return NULL;
+}
+
+/* Clear VIP|EVIP not present into the new data */
+static void
+clear_diff_vrrp_vip(vrrp_rt * old_vrrp, int type)
+{
+	vrrp_rt *vrrp = vrrp_exist(old_vrrp);
+	list l = (type == VRRP_VIP_TYPE) ? old_vrrp->vip : old_vrrp->evip;
+	list n = (type == VRRP_VIP_TYPE) ? vrrp->vip : vrrp->evip;
+	clear_diff_address(l, n);
+}
+
+/* Clear virtual routes not present in the new data */
+static void
+clear_diff_vrrp_vroutes(vrrp_rt * old_vrrp)
+{
+	vrrp_rt *vrrp = vrrp_exist(old_vrrp);
+	clear_diff_routes(old_vrrp->vroutes, vrrp->vroutes);
+}
+
+/* Keep the state from before reload */
+static void
+reset_vrrp_state(vrrp_rt * old_vrrp)
+{
+	/* Keep VRRP state, ipsec AH seq_number */
+	vrrp_rt *vrrp = vrrp_exist(old_vrrp);
+	vrrp->state = old_vrrp->state;
+	vrrp->init_state = old_vrrp->state;
+	vrrp->wantstate = old_vrrp->state;
+	if (!old_vrrp->sync)
+		vrrp->effective_priority = old_vrrp->effective_priority;
+	memcpy(vrrp->ipsecah_counter, old_vrrp->ipsecah_counter, sizeof(seq_counter));
+
+#ifdef _HAVE_IPVS_SYNCD_
+	if (old_vrrp->lvs_syncd_if)
+		ipvs_syncd_cmd(IPVS_STOPDAEMON, NULL,
+			       (old_vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER:
+								      IPVS_BACKUP,
+			       old_vrrp->vrid);
+	if (vrrp->lvs_syncd_if)
+		ipvs_syncd_cmd(IPVS_STARTDAEMON, NULL,
+			       (vrrp->state == VRRP_STATE_MAST) ? IPVS_MASTER:
+								  IPVS_BACKUP,
+			       vrrp->vrid);
+#endif
+
+	/* Remember if we had vips up and add new ones if needed */
+	vrrp->vipset = old_vrrp->vipset;
+	if (vrrp->vipset) {
+		if (!LIST_ISEMPTY(vrrp->vip))
+			vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_VIP_TYPE);
+		if (!LIST_ISEMPTY(vrrp->evip))
+			vrrp_handle_ipaddress(vrrp, IPADDRESS_ADD, VRRP_EVIP_TYPE);
+		if (!LIST_ISEMPTY(vrrp->vroutes))
+			vrrp_handle_iproutes(vrrp, IPROUTE_ADD);
+	}
+}
+
+/* Diff when reloading configuration */
+void
+clear_diff_vrrp(void)
+{
+	element e;
+	list l = old_vrrp_data->vrrp;
+	vrrp_rt *vrrp;
+
+	if (LIST_ISEMPTY(l))
+		return;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		vrrp_rt *new_vrrp;
+
+		/*
+		 * Try to find this vrrp into the new conf data
+		 * reloaded.
+		 */
+		new_vrrp = vrrp_exist(vrrp);
+		if (!new_vrrp) {
+			vrrp_restore_interface(vrrp, 1);
+
+			/* Remove VMAC if one was created */
+			if (vrrp->vmac) 
+				netlink_link_del_vmac(vrrp);
+		} else {
+			/*
+			 * If this vrrp instance exist in new
+			 * data, then perform a VIP|EVIP diff.
+			 */
+			clear_diff_vrrp_vip(vrrp, VRRP_VIP_TYPE);
+			clear_diff_vrrp_vip(vrrp, VRRP_EVIP_TYPE);
+
+			/* virtual routes diff */
+			clear_diff_vrrp_vroutes(vrrp);
+
+			/* 
+			 * Remove VMAC if it existed in old vrrp instance,
+			 * but not the new one.
+			 */
+			if (vrrp->vmac && !new_vrrp->vmac) {
+				netlink_link_del_vmac(vrrp);
+			}
+
+			/* reset the state */
+			reset_vrrp_state(vrrp);
+		}
+	}
+}
+
+/* Set script status to a sensible value on reload */
+void
+clear_diff_script(void)
+{
+	element e;
+	list l = old_vrrp_data->vrrp_script;
+	vrrp_script *vscript, *nvscript;
+
+	if (LIST_ISEMPTY(l))
+		return;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vscript = ELEMENT_DATA(e);
+		if (vscript->result >= vscript->rise) {
+			nvscript = find_script_by_name(vscript->sname);
+			if (nvscript) {
+				log_message(LOG_INFO, "VRRP_Script(%s) considered successful on reload",
+					   nvscript->sname);
+				nvscript->result = VRRP_SCRIPT_STATUS_INIT_GOOD;
+			}
+		}
+	}
+}
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_data.c keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_data.c
--- keepalived-1.2.7/keepalived/vrrp/vrrp_data.c	2012-08-29 00:05:12.000000000 +0200
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_data.c	2013-05-24 09:39:17.631832300 +0200
@@ -142,7 +142,7 @@ free_sock(void *sock_data)
 	interface *ifp;
 	if (sock->fd_in > 0) {
 		ifp = if_get_by_ifindex(sock->ifindex);
-		if_leave_vrrp_group(sock->family, sock->fd_in, ifp);
+		if_leave_vrrp_group(sock->family, sock->fd_in, ifp, 0);
 	}
 	if (sock->fd_out > 0)
 		close(sock->fd_out);
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_data.c.orig keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_data.c.orig
--- keepalived-1.2.7/keepalived/vrrp/vrrp_data.c.orig	1970-01-01 01:00:00.000000000 +0100
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_data.c.orig	2012-08-29 00:05:12.000000000 +0200
@@ -0,0 +1,462 @@
+/*
+ * Soft:        Keepalived is a failover program for the LVS project
+ *              <www.linuxvirtualserver.org>. It monitor & manipulate
+ *              a loadbalanced server pool using multi-layer checks.
+ *
+ * Part:        Dynamic data structure definition.
+ *
+ * Author:      Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ *              This program is distributed in the hope that it will be useful,
+ *              but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *              See the GNU General Public License for more details.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2001-2012 Alexandre Cassen, <acassen@gmail.com>
+ */
+
+#include "vrrp_data.h"
+#include "vrrp_index.h"
+#include "vrrp_sync.h"
+#include "vrrp_if.h"
+#include "vrrp.h"
+#include "memory.h"
+#include "utils.h"
+#include "logger.h"
+
+/* global vars */
+vrrp_conf_data *vrrp_data = NULL;
+vrrp_conf_data *old_vrrp_data = NULL;
+char *vrrp_buffer;
+
+/* Static addresses facility function */
+void
+alloc_saddress(vector_t *strvec)
+{
+	if (LIST_ISEMPTY(vrrp_data->static_addresses))
+		vrrp_data->static_addresses = alloc_list(free_ipaddress, dump_ipaddress);
+	alloc_ipaddress(vrrp_data->static_addresses, strvec, NULL);
+}
+
+/* Static routes facility function */
+void
+alloc_sroute(vector_t *strvec)
+{
+	if (LIST_ISEMPTY(vrrp_data->static_routes))
+		vrrp_data->static_routes = alloc_list(free_iproute, dump_iproute);
+	alloc_route(vrrp_data->static_routes, strvec);
+}
+
+/* VRRP facility functions */
+static void
+free_vgroup(void *data)
+{
+	vrrp_sgroup *vgroup = data;
+
+	FREE(vgroup->gname);
+	free_strvec(vgroup->iname);
+	free_list(vgroup->index_list);
+	FREE_PTR(vgroup->script_backup);
+	FREE_PTR(vgroup->script_master);
+	FREE_PTR(vgroup->script_fault);
+	FREE_PTR(vgroup->script);
+	FREE(vgroup);
+}
+static void
+dump_vgroup(void *data)
+{
+	vrrp_sgroup *vgroup = data;
+	int i;
+	char *str;
+
+	log_message(LOG_INFO, " VRRP Sync Group = %s, %s", vgroup->gname,
+	       (vgroup->state == VRRP_STATE_MAST) ? "MASTER" : "BACKUP");
+	for (i = 0; i < vector_size(vgroup->iname); i++) {
+		str = vector_slot(vgroup->iname, i);
+		log_message(LOG_INFO, "   monitor = %s", str);
+	}
+	if (vgroup->global_tracking)
+		log_message(LOG_INFO, "   Same tracking for all VRRP instances");
+	if (vgroup->script_backup)
+		log_message(LOG_INFO, "   Backup state transition script = %s",
+		       vgroup->script_backup);
+	if (vgroup->script_master)
+		log_message(LOG_INFO, "   Master state transition script = %s",
+		       vgroup->script_master);
+	if (vgroup->script_fault)
+		log_message(LOG_INFO, "   Fault state transition script = %s",
+		       vgroup->script_fault);
+	if (vgroup->script)
+		log_message(LOG_INFO, "   Generic state transition script = '%s'",
+		       vgroup->script);
+	if (vgroup->smtp_alert)
+		log_message(LOG_INFO, "   Using smtp notification");
+}
+
+static void
+free_vscript(void *data)
+{
+	vrrp_script *vscript = data;
+
+	FREE(vscript->sname);
+	FREE_PTR(vscript->script);
+	FREE(vscript);
+}
+static void
+dump_vscript(void *data)
+{
+	vrrp_script *vscript = data;
+	char *str;
+
+	log_message(LOG_INFO, " VRRP Script = %s", vscript->sname);
+	log_message(LOG_INFO, "   Command = %s", vscript->script);
+	log_message(LOG_INFO, "   Interval = %d sec", vscript->interval / TIMER_HZ);
+	log_message(LOG_INFO, "   Timeout = %d sec", vscript->timeout / TIMER_HZ);
+	log_message(LOG_INFO, "   Weight = %d", vscript->weight);
+	log_message(LOG_INFO, "   Rise = %d", vscript->rise);
+	log_message(LOG_INFO, "   Fall = %d", vscript->fall);
+
+	switch (vscript->result) {
+	case VRRP_SCRIPT_STATUS_INIT:
+		str = "INIT"; break;
+	case VRRP_SCRIPT_STATUS_INIT_GOOD:
+		str = "INIT/GOOD"; break;
+	case VRRP_SCRIPT_STATUS_DISABLED:
+		str = "DISABLED"; break;
+	default:
+		str = (vscript->result >= vscript->rise) ? "GOOD" : "BAD";
+	}
+	log_message(LOG_INFO, "   Status = %s", str);
+}
+
+/* Socket pool functions */
+static void
+free_sock(void *sock_data)
+{
+	sock_t *sock = sock_data;
+	interface *ifp;
+	if (sock->fd_in > 0) {
+		ifp = if_get_by_ifindex(sock->ifindex);
+		if_leave_vrrp_group(sock->family, sock->fd_in, ifp);
+	}
+	if (sock->fd_out > 0)
+		close(sock->fd_out);
+	FREE(sock_data);
+}
+
+static void
+dump_sock(void *sock_data)
+{
+	sock_t *sock = sock_data;
+	log_message(LOG_INFO, "VRRP sockpool: [ifindex(%d), proto(%d), fd(%d,%d)]"
+			    , sock->ifindex
+			    , sock->proto
+			    , sock->fd_in
+			    , sock->fd_out);
+}
+
+static void
+free_vrrp(void *data)
+{
+	vrrp_rt *vrrp = data;
+	element e;
+
+	FREE(vrrp->iname);
+	FREE_PTR(vrrp->send_buffer);
+	FREE_PTR(vrrp->lvs_syncd_if);
+	FREE_PTR(vrrp->script_backup);
+	FREE_PTR(vrrp->script_master);
+	FREE_PTR(vrrp->script_fault);
+	FREE_PTR(vrrp->script_stop);
+	FREE_PTR(vrrp->script);
+	FREE(vrrp->ipsecah_counter);
+
+	if (!LIST_ISEMPTY(vrrp->track_ifp))
+		for (e = LIST_HEAD(vrrp->track_ifp); e; ELEMENT_NEXT(e))
+			FREE(ELEMENT_DATA(e));
+	free_list(vrrp->track_ifp);
+
+	if (!LIST_ISEMPTY(vrrp->track_script))
+		for (e = LIST_HEAD(vrrp->track_script); e; ELEMENT_NEXT(e))
+			FREE(ELEMENT_DATA(e));
+	free_list(vrrp->track_script);
+
+	free_list(vrrp->vip);
+	free_list(vrrp->evip);
+	free_list(vrrp->vroutes);
+	FREE(vrrp);
+}
+static void
+dump_vrrp(void *data)
+{
+	vrrp_rt *vrrp = data;
+	char auth_data[sizeof(vrrp->auth_data) + 1];
+
+	log_message(LOG_INFO, " VRRP Instance = %s", vrrp->iname);
+	if (vrrp->family == AF_INET6)
+		log_message(LOG_INFO, "   Using Native IPv6");
+	if (vrrp->init_state == VRRP_STATE_BACK)
+		log_message(LOG_INFO, "   Want State = BACKUP");
+	else
+		log_message(LOG_INFO, "   Want State = MASTER");
+	log_message(LOG_INFO, "   Runing on device = %s", IF_NAME(vrrp->ifp));
+	if (vrrp->dont_track_primary)
+		log_message(LOG_INFO, "   VRRP interface tracking disabled");
+	if (vrrp->mcast_saddr)
+		log_message(LOG_INFO, "   Using mcast src_ip = %s",
+		       inet_ntop2(vrrp->mcast_saddr));
+	if (vrrp->lvs_syncd_if)
+		log_message(LOG_INFO, "   Runing LVS sync daemon on interface = %s",
+		       vrrp->lvs_syncd_if);
+	if (vrrp->garp_delay)
+		log_message(LOG_INFO, "   Gratuitous ARP delay = %d",
+		       vrrp->garp_delay/TIMER_HZ);
+	log_message(LOG_INFO, "   Virtual Router ID = %d", vrrp->vrid);
+	log_message(LOG_INFO, "   Priority = %d", vrrp->base_priority);
+	log_message(LOG_INFO, "   Advert interval = %dsec",
+	       vrrp->adver_int / TIMER_HZ);
+	if (vrrp->nopreempt)
+		log_message(LOG_INFO, "   Preempt disabled");
+	if (vrrp->preempt_delay)
+		log_message(LOG_INFO, "   Preempt delay = %ld secs",
+		       vrrp->preempt_delay / TIMER_HZ);
+	if (vrrp->auth_type) {
+		log_message(LOG_INFO, "   Authentication type = %s",
+		       (vrrp->auth_type ==
+			VRRP_AUTH_AH) ? "IPSEC_AH" : "SIMPLE_PASSWORD");
+		/* vrrp->auth_data is not \0 terminated */
+		memcpy(auth_data, vrrp->auth_data, sizeof(vrrp->auth_data));
+		auth_data[sizeof(vrrp->auth_data)] = '\0';
+		log_message(LOG_INFO, "   Password = %s", auth_data);
+	}
+	if (!LIST_ISEMPTY(vrrp->track_ifp)) {
+		log_message(LOG_INFO, "   Tracked interfaces = %d", LIST_SIZE(vrrp->track_ifp));
+		dump_list(vrrp->track_ifp);
+	}
+	if (!LIST_ISEMPTY(vrrp->track_script)) {
+		log_message(LOG_INFO, "   Tracked scripts = %d",
+		       LIST_SIZE(vrrp->track_script));
+		dump_list(vrrp->track_script);
+	}
+	if (!LIST_ISEMPTY(vrrp->vip)) {
+		log_message(LOG_INFO, "   Virtual IP = %d", LIST_SIZE(vrrp->vip));
+		dump_list(vrrp->vip);
+	}
+	if (!LIST_ISEMPTY(vrrp->evip)) {
+		log_message(LOG_INFO, "   Virtual IP Excluded = %d", LIST_SIZE(vrrp->evip));
+		dump_list(vrrp->evip);
+	}
+	if (!LIST_ISEMPTY(vrrp->vroutes)) {
+		log_message(LOG_INFO, "   Virtual Routes = %d", LIST_SIZE(vrrp->vroutes));
+		dump_list(vrrp->vroutes);
+	}
+	if (vrrp->script_backup)
+		log_message(LOG_INFO, "   Backup state transition script = %s",
+		       vrrp->script_backup);
+	if (vrrp->script_master)
+		log_message(LOG_INFO, "   Master state transition script = %s",
+		       vrrp->script_master);
+	if (vrrp->script_fault)
+		log_message(LOG_INFO, "   Fault state transition script = %s",
+		       vrrp->script_fault);
+	if (vrrp->script_stop)
+		log_message(LOG_INFO, "   Stop state transition script = %s",
+		       vrrp->script_stop);
+	if (vrrp->script)
+		log_message(LOG_INFO, "   Generic state transition script = '%s'",
+		       vrrp->script);
+	if (vrrp->smtp_alert)
+		log_message(LOG_INFO, "   Using smtp notification");
+}
+
+void
+alloc_vrrp_sync_group(char *gname)
+{
+	int size = strlen(gname);
+	vrrp_sgroup *new;
+
+	/* Allocate new VRRP group structure */
+	new = (vrrp_sgroup *) MALLOC(sizeof (vrrp_sgroup));
+	new->gname = (char *) MALLOC(size + 1);
+	new->state = VRRP_STATE_INIT;
+	memcpy(new->gname, gname, size);
+	new->global_tracking = 0;
+
+	list_add(vrrp_data->vrrp_sync_group, new);
+}
+
+void
+alloc_vrrp(char *iname)
+{
+	int size = strlen(iname);
+	seq_counter *counter;
+	vrrp_rt *new;
+
+	/* Allocate new VRRP structure */
+	new = (vrrp_rt *) MALLOC(sizeof (vrrp_rt));
+	counter = (seq_counter *) MALLOC(sizeof (seq_counter));
+
+	/* Build the structure */
+	new->ipsecah_counter = counter;
+
+	/* Set default values */
+	new->family = AF_INET;
+	new->wantstate = VRRP_STATE_BACK;
+	new->init_state = VRRP_STATE_BACK;
+	new->adver_int = TIMER_HZ;
+	new->iname = (char *) MALLOC(size + 1);
+	memcpy(new->iname, iname, size);
+
+	list_add(vrrp_data->vrrp, new);
+}
+
+void
+alloc_vrrp_track(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+
+	if (LIST_ISEMPTY(vrrp->track_ifp))
+		vrrp->track_ifp = alloc_list(NULL, dump_track);
+	alloc_track(vrrp->track_ifp, strvec);
+}
+
+void
+alloc_vrrp_track_script(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+
+	if (LIST_ISEMPTY(vrrp->track_script))
+		vrrp->track_script = alloc_list(NULL, dump_track_script);
+	alloc_track_script(vrrp->track_script, strvec);
+}
+
+void
+alloc_vrrp_vip(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	if (vrrp->ifp == NULL) {
+		log_message(LOG_ERR, "Configuration error: VRRP definition must belong to an interface");
+	}
+
+	if (LIST_ISEMPTY(vrrp->vip))
+		vrrp->vip = alloc_list(free_ipaddress, dump_ipaddress);
+	alloc_ipaddress(vrrp->vip, strvec, vrrp->ifp);
+}
+void
+alloc_vrrp_evip(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+
+	if (LIST_ISEMPTY(vrrp->evip))
+		vrrp->evip = alloc_list(free_ipaddress, dump_ipaddress);
+	alloc_ipaddress(vrrp->evip, strvec, vrrp->ifp);
+}
+
+void
+alloc_vrrp_vroute(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+
+	if (LIST_ISEMPTY(vrrp->vroutes))
+		vrrp->vroutes = alloc_list(free_iproute, dump_iproute);
+	alloc_route(vrrp->vroutes, strvec);
+}
+
+void
+alloc_vrrp_script(char *sname)
+{
+	int size = strlen(sname);
+	vrrp_script *new;
+
+	/* Allocate new VRRP group structure */
+	new = (vrrp_script *) MALLOC(sizeof (vrrp_script));
+	new->sname = (char *) MALLOC(size + 1);
+	memcpy(new->sname, sname, size + 1);
+	new->interval = VRRP_SCRIPT_DI * TIMER_HZ;
+	new->timeout = VRRP_SCRIPT_DT * TIMER_HZ;
+	new->weight = VRRP_SCRIPT_DW;
+	new->result = VRRP_SCRIPT_STATUS_INIT;
+	new->inuse = 0;
+	new->rise = 1;
+	new->fall = 1;
+	list_add(vrrp_data->vrrp_script, new);
+}
+
+/* data facility functions */
+void
+alloc_vrrp_buffer(void)
+{
+	vrrp_buffer = (char *) MALLOC(VRRP_PACKET_TEMP_LEN);
+}
+
+void
+free_vrrp_buffer(void)
+{
+	FREE(vrrp_buffer);
+}
+
+vrrp_conf_data *
+alloc_vrrp_data(void)
+{
+	vrrp_conf_data *new;
+
+	new = (vrrp_conf_data *) MALLOC(sizeof (vrrp_conf_data));
+	new->vrrp = alloc_list(free_vrrp, dump_vrrp);
+	new->vrrp_index = alloc_mlist(NULL, NULL, 255+1);
+	new->vrrp_index_fd = alloc_mlist(NULL, NULL, 1024+1);
+	new->vrrp_sync_group = alloc_list(free_vgroup, dump_vgroup);
+	new->vrrp_script = alloc_list(free_vscript, dump_vscript);
+	new->vrrp_socket_pool = alloc_list(free_sock, dump_sock);
+
+	return new;
+}
+
+void
+free_vrrp_data(vrrp_conf_data * data)
+{
+	free_list(data->static_addresses);
+	free_list(data->static_routes);
+	free_mlist(data->vrrp_index, 255+1);
+	free_mlist(data->vrrp_index_fd, 1024+1);
+	free_list(data->vrrp);
+	free_list(data->vrrp_sync_group);
+	free_list(data->vrrp_script);
+//	free_list(data->vrrp_socket_pool);
+	FREE(data);
+}
+
+void
+free_vrrp_sockpool(vrrp_conf_data * data)
+{
+	free_list(data->vrrp_socket_pool);
+}
+
+void
+dump_vrrp_data(vrrp_conf_data * data)
+{
+	if (!LIST_ISEMPTY(data->static_addresses)) {
+		log_message(LOG_INFO, "------< Static Addresses >------");
+		dump_list(data->static_addresses);
+	}
+	if (!LIST_ISEMPTY(data->static_routes)) {
+		log_message(LOG_INFO, "------< Static Routes >------");
+		dump_list(data->static_routes);
+	}
+	if (!LIST_ISEMPTY(data->vrrp)) {
+		log_message(LOG_INFO, "------< VRRP Topology >------");
+		dump_list(data->vrrp);
+	}
+	if (!LIST_ISEMPTY(data->vrrp_sync_group)) {
+		log_message(LOG_INFO, "------< VRRP Sync groups >------");
+		dump_list(data->vrrp_sync_group);
+	}
+	if (!LIST_ISEMPTY(data->vrrp_script)) {
+		log_message(LOG_INFO, "------< VRRP Scripts >------");
+		dump_list(data->vrrp_script);
+	}
+}
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_if.c keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_if.c
--- keepalived-1.2.7/keepalived/vrrp/vrrp_if.c	2012-08-17 01:21:28.000000000 +0200
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_if.c	2013-05-24 09:39:17.635832500 +0200
@@ -462,7 +462,7 @@ if_join_vrrp_group(sa_family_t family, i
 }
 
 int
-if_leave_vrrp_group(sa_family_t family, int sd, interface *ifp)
+if_leave_vrrp_group(sa_family_t family, int sd, interface *ifp, int unicast)
 {
 	struct ip_mreqn imr;
 	struct ipv6_mreq imr6;
@@ -472,6 +472,9 @@ if_leave_vrrp_group(sa_family_t family,
 	if (sd < 0 || !ifp)
 		return -1;
 
+	if (unicast)
+		goto skip_mcast_release;
+
 	/* Leaving the VRRP multicast group */
 	if (family == AF_INET) {
 		memset(&imr, 0, sizeof(imr));
@@ -500,6 +503,7 @@ if_leave_vrrp_group(sa_family_t family,
 		return -1;
 	}
 
+skip_mcast_release:
 	/* Finally close the desc */
 	close(sd);
 	return 0;
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_if.c.orig keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_if.c.orig
--- keepalived-1.2.7/keepalived/vrrp/vrrp_if.c.orig	1970-01-01 01:00:00.000000000 +0100
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_if.c.orig	2012-08-17 01:21:28.000000000 +0200
@@ -0,0 +1,641 @@
+/*
+ * Soft:        Keepalived is a failover program for the LVS project
+ *              <www.linuxvirtualserver.org>. It monitor & manipulate
+ *              a loadbalanced server pool using multi-layer checks.
+ *
+ * Part:        Interfaces manipulation.
+ *
+ * Author:      Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ *              This program is distributed in the hope that it will be useful,
+ *              but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *              See the GNU General Public License for more details.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2001-2012 Alexandre Cassen, <acassen@gmail.com>
+ */
+
+/* global include */
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+typedef __uint64_t u64;
+typedef __uint32_t u32;
+typedef __uint16_t u16;
+typedef __uint8_t u8;
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <ctype.h>
+#ifdef use_linux_libc5
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef _KRNL_2_4_
+#include <linux/ethtool.h>
+#endif
+
+/* local include */
+#include "scheduler.h"
+#include "global_data.h"
+#include "vrrp_data.h"
+#include "vrrp.h"
+#include "vrrp_if.h"
+#include "vrrp_netlink.h"
+#include "memory.h"
+#include "utils.h"
+#include "logger.h"
+
+/* Global vars */
+static list if_queue;
+static struct ifreq ifr;
+
+/* Helper functions */
+/* Return interface from interface index */
+interface *
+if_get_by_ifindex(const int ifindex)
+{
+	interface *ifp;
+	element e;
+
+	if (LIST_ISEMPTY(if_queue))
+		return NULL;
+
+	for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) {
+		ifp = ELEMENT_DATA(e);
+		if (ifp->ifindex == ifindex)
+			return ifp;
+	}
+	return NULL;
+}
+
+interface *
+if_get_by_ifname(const char *ifname)
+{
+	interface *ifp;
+	element e;
+
+	if (LIST_ISEMPTY(if_queue)) {
+		log_message(LOG_ERR, "Interface queue is empty");
+		return NULL;
+	}
+
+	for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) {
+		ifp = ELEMENT_DATA(e);
+		if (!strcmp(ifp->ifname, ifname))
+			return ifp;
+	}
+
+	log_message(LOG_ERR, "No such interface, %s", ifname);
+	return NULL;
+}
+
+/* MII Transceiver Registers poller functions */
+static int
+if_mii_read(const int fd, const int phy_id, int location)
+{
+	uint16_t *data = (uint16_t *) (&ifr.ifr_data);
+
+	data[0] = phy_id;
+	data[1] = location;
+
+	if (ioctl(fd, SIOCGMIIREG, &ifr) < 0) {
+		log_message(LOG_ERR, "SIOCGMIIREG on %s failed: %s", ifr.ifr_name,
+		       strerror(errno));
+		return -1;
+	}
+	return data[3];
+}
+
+/*
+static void if_mii_dump(const uint16_t mii_regs[32], unsigned phy_id)
+{
+  int mii_reg;
+
+  printf(" MII PHY #%d transceiver registers:\n", phy_id);
+  for (mii_reg = 0; mii_reg < 32; mii_reg++)
+    printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n ":"", mii_regs[mii_reg]);
+}
+*/
+
+static int
+if_mii_status(const int fd)
+{
+	uint16_t *data = (uint16_t *) (&ifr.ifr_data);
+	unsigned phy_id = data[0];
+	uint16_t mii_regs[32];
+	int mii_reg;
+	uint16_t bmsr, new_bmsr;
+
+	/* Reset MII registers */
+	memset(mii_regs, 0, sizeof (mii_regs));
+
+	for (mii_reg = 0; mii_reg < 32; mii_reg++)
+		mii_regs[mii_reg] = if_mii_read(fd, phy_id, mii_reg);
+
+// if_mii_dump(mii_regs, phy_id);
+
+	if (mii_regs[0] == 0xffff) {
+		log_message(LOG_ERR, "No MII transceiver present for %s !!!",
+		       ifr.ifr_name);
+		return -1;
+	}
+
+	bmsr = mii_regs[1];
+
+	/*
+	 * For Basic Mode Status Register (BMSR).
+	 * Sticky field (Link established & Jabber detected), we need to read
+	 * a second time the BMSR to get current status.
+	 */
+	new_bmsr = if_mii_read(fd, phy_id, 1);
+
+// printf(" \nBasic Mode Status Register 0x%4.4x ... 0x%4.4x\n", bmsr, new_bmsr);
+
+	if (bmsr & 0x0004)
+		return LINK_UP;
+	else if (new_bmsr & 0x0004)
+		return LINK_UP;
+	else
+		return LINK_DOWN;
+}
+
+int
+if_mii_probe(const char *ifname)
+{
+	uint16_t *data = (uint16_t *) (&ifr.ifr_data);
+	int phy_id;
+	int fd = socket(AF_INET, SOCK_DGRAM, 0);
+	int status = 0;
+
+	if (fd < 0)
+		return -1;
+	memset(&ifr, 0, sizeof (struct ifreq));
+	strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+	if (ioctl(fd, SIOCGMIIPHY, &ifr) < 0) {
+		close(fd);
+		return -1;
+	}
+
+	/* check if the driver reports BMSR using the MII interface, as we
+	 * will need this and we already know that some don't support it.
+	 */
+	phy_id = data[0]; /* save it in case it is overwritten */
+	data[1] = 1;
+	if (ioctl(fd, SIOCGMIIREG, &ifr) < 0) {
+		close(fd);
+		return -1;
+	}
+	data[0] = phy_id;
+
+	/* Dump the MII transceiver */
+	status = if_mii_status(fd);
+	close(fd);
+	return status;
+}
+
+static int
+if_ethtool_status(const int fd)
+{
+#ifdef ETHTOOL_GLINK
+	struct ethtool_value edata;
+	int err = 0;
+
+	edata.cmd = ETHTOOL_GLINK;
+	ifr.ifr_data = (caddr_t) & edata;
+	err = ioctl(fd, SIOCETHTOOL, &ifr);
+	if (err == 0)
+		return (edata.data) ? 1 : 0;
+	else
+#endif
+		return -1;
+}
+
+int
+if_ethtool_probe(const char *ifname)
+{
+	int fd = socket(AF_INET, SOCK_DGRAM, 0);
+	int status = 0;
+
+	if (fd < 0)
+		return -1;
+	memset(&ifr, 0, sizeof (struct ifreq));
+	strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+
+	status = if_ethtool_status(fd);
+	close(fd);
+	return status;
+}
+
+void
+if_ioctl_flags(interface * ifp)
+{
+	int fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	if (fd < 0)
+		return;
+	memset(&ifr, 0, sizeof (struct ifreq));
+	strncpy(ifr.ifr_name, ifp->ifname, sizeof (ifr.ifr_name));
+	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+		close(fd);
+		return;
+	}
+	ifp->flags = ifr.ifr_flags;
+	close(fd);
+}
+
+/* Interfaces lookup */
+static void
+free_if(void *data)
+{
+	FREE(data);
+}
+
+void
+dump_if(void *data)
+{
+	interface *ifp = data;
+	char addr_str[41];
+
+	log_message(LOG_INFO, "------< NIC >------");
+	log_message(LOG_INFO, " Name = %s", ifp->ifname);
+	log_message(LOG_INFO, " index = %d", ifp->ifindex);
+	log_message(LOG_INFO, " IPv4 address = %s", inet_ntop2(ifp->sin_addr.s_addr));
+	inet_ntop(AF_INET6, &ifp->sin6_addr, addr_str, 41);
+	log_message(LOG_INFO, " IPv6 address = %s", addr_str);
+
+	/* FIXME: Harcoded for ethernet */
+	if (ifp->hw_type == ARPHRD_ETHER)
+		log_message(LOG_INFO, " MAC = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
+		       ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2]
+		       , ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5]);
+
+	if (ifp->flags & IFF_UP)
+		log_message(LOG_INFO, " is UP");
+
+	if (ifp->flags & IFF_RUNNING)
+		log_message(LOG_INFO, " is RUNNING");
+
+	if (!(ifp->flags & IFF_UP) && !(ifp->flags & IFF_RUNNING))
+		log_message(LOG_INFO, " is DOWN");
+
+	log_message(LOG_INFO, " MTU = %d", ifp->mtu);
+
+	switch (ifp->hw_type) {
+	case ARPHRD_LOOPBACK:
+		log_message(LOG_INFO, " HW Type = LOOPBACK");
+		break;
+	case ARPHRD_ETHER:
+		log_message(LOG_INFO, " HW Type = ETHERNET");
+		break;
+	default:
+		log_message(LOG_INFO, " HW Type = UNKNOWN");
+		break;
+	}
+
+	/* MII channel supported ? */
+	if (IF_MII_SUPPORTED(ifp))
+		log_message(LOG_INFO, " NIC support MII regs");
+	else if (IF_ETHTOOL_SUPPORTED(ifp))
+		log_message(LOG_INFO, " NIC support EHTTOOL GLINK interface");
+	else
+		log_message(LOG_INFO, " Enabling NIC ioctl refresh polling");
+}
+
+static void
+init_if_queue(void)
+{
+	if_queue = alloc_list(free_if, dump_if);
+}
+
+void
+if_add_queue(interface * ifp)
+{
+	list_add(if_queue, ifp);
+}
+
+static int
+if_linkbeat_refresh_thread(thread_t * thread)
+{
+	interface *ifp = THREAD_ARG(thread);
+
+	if (IF_MII_SUPPORTED(ifp))
+		ifp->linkbeat = (if_mii_probe(ifp->ifname)) ? 1 : 0;
+	else if (IF_ETHTOOL_SUPPORTED(ifp))
+		ifp->linkbeat = (if_ethtool_probe(ifp->ifname)) ? 1 : 0;
+	else
+		ifp->linkbeat = 1;
+
+	/*
+	 * update ifp->flags to get the new IFF_RUNNING status.
+	 * Some buggy drivers need this...
+	 */
+	if_ioctl_flags(ifp);
+
+	/* Register next polling thread */
+	thread_add_timer(master, if_linkbeat_refresh_thread, ifp, POLLING_DELAY);
+	return 0;
+}
+
+static void
+init_if_linkbeat(void)
+{
+	interface *ifp;
+	element e;
+	int status;
+
+	for (e = LIST_HEAD(if_queue); e; ELEMENT_NEXT(e)) {
+		ifp = ELEMENT_DATA(e);
+		ifp->lb_type = LB_IOCTL;
+		status = if_mii_probe(ifp->ifname);
+		if (status >= 0) {
+			ifp->lb_type = LB_MII;
+			ifp->linkbeat = (status) ? 1 : 0;
+		} else {
+			status = if_ethtool_probe(ifp->ifname);
+			if (status >= 0) {
+				ifp->lb_type = LB_ETHTOOL;
+				ifp->linkbeat = (status) ? 1 : 0;
+			}
+		}
+
+		/* Register new monitor thread */
+		thread_add_timer(master, if_linkbeat_refresh_thread, ifp, POLLING_DELAY);
+	}
+}
+
+int
+if_linkbeat(const interface * ifp)
+{
+	if (!global_data->linkbeat_use_polling)
+		return 1;
+
+	if (IF_MII_SUPPORTED(ifp) || IF_ETHTOOL_SUPPORTED(ifp))
+		return IF_LINKBEAT(ifp);
+
+	return 1;
+}
+
+/* Interface queue helpers*/
+void
+free_interface_queue(void)
+{
+	if (!LIST_ISEMPTY(if_queue))
+		free_list(if_queue);
+	if_queue = NULL;
+	kernel_netlink_close();
+}
+
+void
+init_interface_queue(void)
+{
+	init_if_queue();
+//	dump_list(if_queue);
+	netlink_interface_lookup();
+}
+
+void
+init_interface_linkbeat(void)
+{
+	if (global_data->linkbeat_use_polling) {
+		log_message(LOG_INFO, "Using MII-BMSR NIC polling thread...");
+		init_if_linkbeat();
+	} else {
+		log_message(LOG_INFO, "Using LinkWatch kernel netlink reflector...");
+	}
+}
+
+int
+if_join_vrrp_group(sa_family_t family, int *sd, interface *ifp, int proto)
+{
+	struct ip_mreqn imr;
+	struct ipv6_mreq imr6;
+	int ret = 0;
+
+	if (*sd < 0)
+		return -1;
+
+	/* -> outbound processing option
+	 * join the multicast group.
+	 * binding the socket to the interface for outbound multicast
+	 * traffic.
+	 */
+
+	if (family == AF_INET) {
+		memset(&imr, 0, sizeof(imr));
+		imr.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
+		imr.imr_address.s_addr = IF_ADDR(ifp);
+		imr.imr_ifindex = IF_INDEX(ifp);
+
+		/* -> Need to handle multicast convergance after takeover.
+		 * We retry until multicast is available on the interface.
+		 */
+		ret = setsockopt(*sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+				 (char *) &imr, sizeof(struct ip_mreqn));
+	} else {
+		memset(&imr6, 0, sizeof(imr6));
+		imr6.ipv6mr_multiaddr.s6_addr16[0] = htons(0xff02);
+		imr6.ipv6mr_multiaddr.s6_addr16[7] = htons(0x12);
+		imr6.ipv6mr_interface = IF_INDEX(ifp);
+		ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
+				 (char *) &imr6, sizeof(struct ipv6_mreq));
+	}
+
+	if (ret < 0) {
+		log_message(LOG_INFO, "cant do IP%s_ADD_MEMBERSHIP errno=%s (%d)",
+			    (family == AF_INET) ? "" : "V6", strerror(errno), errno);
+		close(*sd);
+		*sd = -1;
+        }
+
+	return *sd;
+}
+
+int
+if_leave_vrrp_group(sa_family_t family, int sd, interface *ifp)
+{
+	struct ip_mreqn imr;
+	struct ipv6_mreq imr6;
+	int ret = 0;
+
+	/* If fd is -1 then we add a membership trouble */
+	if (sd < 0 || !ifp)
+		return -1;
+
+	/* Leaving the VRRP multicast group */
+	if (family == AF_INET) {
+		memset(&imr, 0, sizeof(imr));
+		/* FIXME: change this to use struct ip_mreq */
+		imr.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
+		imr.imr_address.s_addr = IF_ADDR(ifp);
+		imr.imr_ifindex = IF_INDEX(ifp);
+		ret = setsockopt(sd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+				 (char *) &imr, sizeof (struct ip_mreqn));
+	} else {
+		memset(&imr6, 0, sizeof(imr6));
+		/* rfc5798.5.1.2.2 : destination IPv6 mcast group is
+		 * ff02:0:0:0:0:0:0:12.
+		 */
+		imr6.ipv6mr_multiaddr.s6_addr16[0] = htons(0xff02);
+		imr6.ipv6mr_multiaddr.s6_addr16[7] = htons(0x12);
+		imr6.ipv6mr_interface = IF_INDEX(ifp);
+		ret = setsockopt(sd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
+				 (char *) &imr6, sizeof(struct ipv6_mreq));
+	}
+
+	if (ret < 0) {
+		log_message(LOG_INFO, "cant do IP%s_DROP_MEMBERSHIP errno=%s (%d)",
+			    (family == AF_INET) ? "" : "V6", strerror(errno), errno);
+		close(sd);
+		return -1;
+	}
+
+	/* Finally close the desc */
+	close(sd);
+	return 0;
+}
+
+int
+if_setsockopt_bindtodevice(int *sd, interface *ifp)
+{
+	int ret;
+
+	if (*sd < 0)
+		return -1;
+
+	/* -> inbound processing option
+	 * Specify the bound_dev_if.
+	 * why IP_ADD_MEMBERSHIP & IP_MULTICAST_IF doesnt set
+	 * sk->bound_dev_if themself ??? !!!
+	 * Needed for filter multicasted advert per interface.
+	 *
+	 * -- If you read this !!! and know the answer to the question
+	 *    please feel free to answer me ! :)
+	 */
+	ret = setsockopt(*sd, SOL_SOCKET, SO_BINDTODEVICE, IF_NAME(ifp), strlen(IF_NAME(ifp)) + 1);
+	if (ret < 0) {
+		log_message(LOG_INFO, "cant bind to device %s. errno=%d. (try to run it as root)",
+			    IF_NAME(ifp), errno);
+		close(*sd);
+		*sd = -1;
+	}
+
+	return *sd;
+}
+
+int
+if_setsockopt_hdrincl(int *sd)
+{
+	int ret;
+	int on = 1;
+
+	if (*sd < 0)
+		return -1;
+
+	/* Include IP header into RAW protocol packet */
+	ret = setsockopt(*sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
+	if (ret < 0) {
+		log_message(LOG_INFO, "cant set HDRINCL IP option. errno=%d (%m)", errno);
+		close(*sd);
+		*sd = -1;
+	}
+
+	return *sd;
+}
+
+int
+if_setsockopt_mcast_loop(sa_family_t family, int *sd)
+{
+	int ret;
+	unsigned char loop = 0;
+	int loopv6 = 0;
+
+	if (*sd < 0)
+		return -1;
+
+	/* Include IP header into RAW protocol packet */
+	if (family == AF_INET)
+		ret = setsockopt(*sd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
+	else
+		ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loopv6, sizeof(loopv6));
+
+	if (ret < 0) {
+		log_message(LOG_INFO, "cant set IP%s_MULTICAST_LOOP IP option. errno=%d (%m)",
+			    (family == AF_INET) ? "" : "V6", errno);
+		close(*sd);
+		*sd = -1;
+	}
+
+	return *sd;
+}
+
+int
+if_setsockopt_mcast_hops(sa_family_t family, int *sd)
+{
+	int ret;
+	int hops = 255;
+
+	/* Not applicable for IPv4 */
+	if (*sd < 0 || family == AF_INET)
+		return -1;
+
+	/* Include IP header into RAW protocol packet */
+	ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
+	if (ret < 0) {
+		log_message(LOG_INFO, "cant set IPV6_MULTICAST_HOPS IP option. errno=%d (%m)", errno);
+		close(*sd);
+		*sd = -1;
+	}
+
+	return *sd;
+}
+
+int
+if_setsockopt_mcast_if(sa_family_t family, int *sd, interface *ifp)
+{
+	int ret;
+	unsigned int ifindex;
+
+	/* Not applicable for IPv4 */
+	if (*sd < 0 || family == AF_INET)
+		return -1;
+
+	/* Include IP header into RAW protocol packet */
+	ifindex = IF_INDEX(ifp);
+	ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex));
+	if (ret < 0) {
+		log_message(LOG_INFO, "cant set IPV6_MULTICAST_IF IP option. errno=%d (%m)", errno);
+		close(*sd);
+		*sd = -1;
+	}
+
+	return *sd;
+}
+
+int if_setsockopt_priority(int *sd) {
+	int ret;
+	int priority = 6;
+
+	if (*sd < 0)
+		return -1;
+
+	/* Set SO_PRIORITY for VRRP traffic */
+	ret = setsockopt(*sd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority));
+	if (ret < 0) {
+		log_message(LOG_INFO, "cant set SO_PRIORITY IP option. errno=%d (%m)", errno);
+		close(*sd);
+		*sd = -1;
+	}
+
+	return *sd;
+}
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_parser.c keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_parser.c
--- keepalived-1.2.7/keepalived/vrrp/vrrp_parser.c	2012-08-29 00:05:12.000000000 +0200
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_parser.c	2013-05-24 09:42:51.076040600 +0200
@@ -185,6 +185,18 @@ vrrp_mcastip_handler(vector_t *strvec)
 	inet_ston(vector_slot(strvec, 1), &vrrp->mcast_saddr);
 }
 static void
+vrrp_unicast_bind_handler(vector strvec)
+{
+       vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+       inet_ston(VECTOR_SLOT(strvec, 1), &vrrp->unicast_bind);
+}
+static void
+vrrp_unicast_peer_handler(vector strvec)
+{
+       vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+       inet_ston(VECTOR_SLOT(strvec, 1), &vrrp->unicast_peer);
+}
+static void
 vrrp_vrid_handler(vector_t *strvec)
 {
 	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
@@ -484,6 +496,8 @@ vrrp_init_keywords(void)
 	install_keyword("track_interface", &vrrp_track_int_handler);
 	install_keyword("track_script", &vrrp_track_scr_handler);
 	install_keyword("mcast_src_ip", &vrrp_mcastip_handler);
+	install_keyword("vrrp_unicast_bind", &vrrp_unicast_bind_handler);
+	install_keyword("vrrp_unicast_peer", &vrrp_unicast_peer_handler);
 	install_keyword("virtual_router_id", &vrrp_vrid_handler);
 	install_keyword("priority", &vrrp_prio_handler);
 	install_keyword("advert_int", &vrrp_adv_handler);
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_parser.c.orig keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_parser.c.orig
--- keepalived-1.2.7/keepalived/vrrp/vrrp_parser.c.orig	1970-01-01 01:00:00.000000000 +0100
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_parser.c.orig	2012-08-29 00:05:12.000000000 +0200
@@ -0,0 +1,519 @@
+/* 
+ * Soft:        Keepalived is a failover program for the LVS project
+ *              <www.linuxvirtualserver.org>. It monitor & manipulate
+ *              a loadbalanced server pool using multi-layer checks.
+ * 
+ * Part:        Configuration file parser/reader. Place into the dynamic
+ *              data structure representation the conf file representing
+ *              the loadbalanced server pool.
+ *  
+ * Author:      Alexandre Cassen, <acassen@linux-vs.org>
+ *              
+ *              This program is distributed in the hope that it will be useful,
+ *              but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *              See the GNU General Public License for more details.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2001-2012 Alexandre Cassen, <acassen@gmail.com>
+ */
+
+#include "vrrp_parser.h"
+#include "vrrp_data.h"
+#include "vrrp_sync.h"
+#include "vrrp_index.h"
+#include "vrrp_if.h"
+#include "vrrp_vmac.h"
+#include "vrrp.h"
+#include "global_data.h"
+#include "global_parser.h"
+#include "logger.h"
+#include "parser.h"
+#include "memory.h"
+
+/* Static addresses handler */
+static void
+static_addresses_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_saddress);
+}
+
+/* Static routes handler */
+static void
+static_routes_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_sroute);
+}
+
+/* VRRP handlers */
+static void
+vrrp_sync_group_handler(vector_t *strvec)
+{
+	alloc_vrrp_sync_group(vector_slot(strvec, 1));
+}
+static void
+vrrp_group_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->iname = read_value_block();
+}
+static void
+vrrp_gnotify_backup_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->script_backup = set_value(strvec);
+	vgroup->notify_exec = 1;
+}
+static void
+vrrp_gnotify_master_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->script_master = set_value(strvec);
+	vgroup->notify_exec = 1;
+}
+static void
+vrrp_gnotify_fault_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->script_fault = set_value(strvec);
+	vgroup->notify_exec = 1;
+}
+static void
+vrrp_gnotify_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->script = set_value(strvec);
+	vgroup->notify_exec = 1;
+}
+static void
+vrrp_gsmtp_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->smtp_alert = 1;
+}
+static void
+vrrp_gglobal_tracking_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->global_tracking = 1;
+}
+static void
+vrrp_handler(vector_t *strvec)
+{
+	alloc_vrrp(vector_slot(strvec, 1));
+}
+static void
+vrrp_vmac_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->vmac = 1;
+	if (!vrrp->mcast_saddr)
+		vrrp->mcast_saddr  = IF_ADDR(vrrp->ifp);
+	if (vector_size(strvec) == 2) {
+		strncpy(vrrp->vmac_ifname, vector_slot(strvec, 1),
+			IFNAMSIZ - 1);
+	} else if (vrrp->vrid) {
+		snprintf(vrrp->vmac_ifname, IFNAMSIZ, "vrrp.%d", vrrp->vrid);
+	}
+
+	if (strlen(vrrp->vmac_ifname)) {
+		log_message(LOG_INFO, "vmac_ifname=%s for vrrp_instace %s"
+				    , vrrp->vmac_ifname
+				    , vrrp->iname);
+	}
+	if (vrrp->ifp && !(vrrp->vmac & 2))
+		netlink_link_add_vmac(vrrp);
+}
+static void
+vrrp_native_ipv6_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->family = AF_INET6;
+
+	if (vrrp->auth_type != VRRP_AUTH_NONE)
+		vrrp->auth_type = VRRP_AUTH_NONE;
+}
+static void
+vrrp_state_handler(vector_t *strvec)
+{
+	char *str = vector_slot(strvec, 1);
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp_sgroup *vgroup = vrrp->sync;
+
+	if (!strcmp(str, "MASTER")) {
+		vrrp->wantstate = VRRP_STATE_MAST;
+		vrrp->init_state = VRRP_STATE_MAST;
+	}
+
+	/* set eventual sync group */
+	if (vgroup)
+		vgroup->state = vrrp->wantstate;
+}
+static void
+vrrp_int_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	char *name = vector_slot(strvec, 1);
+	vrrp->ifp = if_get_by_ifname(name);
+	if (vrrp->vmac && !(vrrp->vmac & 2))
+		netlink_link_add_vmac(vrrp);
+}
+static void
+vrrp_track_int_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_vrrp_track);
+}
+static void
+vrrp_track_scr_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_vrrp_track_script);
+}
+static void
+vrrp_dont_track_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->dont_track_primary = 1;
+}
+static void
+vrrp_mcastip_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	inet_ston(vector_slot(strvec, 1), &vrrp->mcast_saddr);
+}
+static void
+vrrp_vrid_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->vrid = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_VID(vrrp->vrid)) {
+		log_message(LOG_INFO, "VRRP Error : VRID not valid !");
+		log_message(LOG_INFO,
+		       "             must be between 1 & 255. reconfigure !");
+	} else {
+		alloc_vrrp_bucket(vrrp);
+		if (vrrp->vmac && strlen(vrrp->vmac_ifname) == 0) {
+			snprintf(vrrp->vmac_ifname, IFNAMSIZ, "vrrp.%d"
+						  , vrrp->vrid);
+			log_message(LOG_INFO, "vmac_ifname=%s for vrrp_instace %s"
+					    , vrrp->vmac_ifname
+					    , vrrp->iname);
+		}
+	}
+}
+static void
+vrrp_prio_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->effective_priority = vrrp->base_priority = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_PRIORITY(vrrp->base_priority)) {
+		log_message(LOG_INFO, "VRRP Error : Priority not valid !");
+		log_message(LOG_INFO,
+		       "             must be between 1 & 255. reconfigure !");
+		log_message(LOG_INFO,
+			    "             Using default value : %d\n", VRRP_PRIO_DFL);
+		vrrp->effective_priority = vrrp->base_priority = VRRP_PRIO_DFL;
+	}
+}
+static void
+vrrp_adv_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->adver_int = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_ADVERT_INT(vrrp->adver_int)) {
+		log_message(LOG_INFO, "VRRP Error : Advert interval not valid !");
+		log_message(LOG_INFO,
+		       "             must be between less than 1sec.");
+		log_message(LOG_INFO, "             Using default value : 1sec");
+		vrrp->adver_int = 1;
+	}
+	vrrp->adver_int *= TIMER_HZ;
+}
+static void
+vrrp_debug_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->debug = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_DEBUG_INT(vrrp->debug)) {
+		log_message(LOG_INFO, "VRRP Error : Debug interval not valid !");
+		log_message(LOG_INFO, "             must be between 0-4");
+		vrrp->debug = 0;
+	}
+}
+static void
+vrrp_nopreempt_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->nopreempt = 1;
+}
+static void	/* backwards compatibility */
+vrrp_preempt_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->nopreempt = 0;
+}
+static void
+vrrp_preempt_delay_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->preempt_delay = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_PREEMPT_DELAY(vrrp->preempt_delay)) {
+		log_message(LOG_INFO, "VRRP Error : Preempt_delay not valid !");
+		log_message(LOG_INFO, "             must be between 0-%d",
+		       TIMER_MAX_SEC);
+		vrrp->preempt_delay = 0;
+	}
+	vrrp->preempt_delay *= TIMER_HZ;
+	vrrp->preempt_time = timer_add_long(timer_now(), vrrp->preempt_delay);
+}
+static void
+vrrp_notify_backup_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script_backup = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_notify_master_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script_master = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_notify_fault_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script_fault = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_notify_stop_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script_stop = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_notify_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_smtp_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->smtp_alert = 1;
+}
+static void
+vrrp_lvs_syncd_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->lvs_syncd_if = set_value(strvec);
+}
+static void
+vrrp_garp_delay_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->garp_delay = atoi(vector_slot(strvec, 1)) * TIMER_HZ;
+	if (vrrp->garp_delay < TIMER_HZ)
+		vrrp->garp_delay = TIMER_HZ;
+}
+static void
+vrrp_auth_type_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	char *str = vector_slot(strvec, 1);
+
+	if (!strcmp(str, "AH") && vrrp->family == AF_INET)
+		vrrp->auth_type = VRRP_AUTH_AH;
+	else if (!strcmp(str, "PASS") && vrrp->family == AF_INET)
+		vrrp->auth_type = VRRP_AUTH_PASS;
+}
+static void
+vrrp_auth_pass_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	char *str = vector_slot(strvec, 1);
+	int max_size = sizeof (vrrp->auth_data);
+	int str_len = strlen(str);
+
+	if (str_len > max_size) {
+		str_len = max_size;
+		log_message(LOG_INFO,
+			    "Truncating auth_pass to %d characters", max_size);
+	}
+
+	memset(vrrp->auth_data, 0, max_size);
+	memcpy(vrrp->auth_data, str, str_len);
+}
+static void
+vrrp_vip_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	char *buf;
+	char *str = NULL;
+	vector_t *vec = NULL;
+	int nbvip = 0;
+
+	buf = (char *) MALLOC(MAXBUF);
+	while (read_line(buf, MAXBUF)) {
+		vec = alloc_strvec(buf);
+		if (vec) {
+			str = vector_slot(vec, 0);
+			if (!strcmp(str, EOB)) {
+				free_strvec(vec);
+				break;
+			}
+
+			if (vector_size(vec)) {
+				nbvip++;
+				if (nbvip > VRRP_MAX_VIP) {
+					log_message(LOG_INFO,
+					       "VRRP_Instance(%s) "
+					       "trunc to the first %d VIPs.",
+					       vrrp->iname, VRRP_MAX_VIP);
+					log_message(LOG_INFO,
+					       "  => Declare others VIPs into"
+					       " the excluded vip block");
+				} else
+					alloc_vrrp_vip(vec);
+			}
+
+			free_strvec(vec);
+		}
+		memset(buf, 0, MAXBUF);
+	}
+	FREE(buf);
+}
+static void
+vrrp_evip_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_vrrp_evip);
+}
+static void
+vrrp_vroutes_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_vrrp_vroute);
+}
+static void
+vrrp_script_handler(vector_t *strvec)
+{
+	alloc_vrrp_script(vector_slot(strvec, 1));
+}
+static void
+vrrp_vscript_script_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->script = set_value(strvec);
+}
+static void
+vrrp_vscript_interval_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->interval = atoi(vector_slot(strvec, 1)) * TIMER_HZ;
+	if (vscript->interval < TIMER_HZ)
+		vscript->interval = TIMER_HZ;
+}
+static void
+vrrp_vscript_timeout_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->timeout = atoi(vector_slot(strvec, 1)) * TIMER_HZ;
+	if (vscript->timeout < TIMER_HZ)
+		vscript->timeout = TIMER_HZ;
+}
+static void
+vrrp_vscript_weight_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->weight = atoi(vector_slot(strvec, 1));
+}
+static void
+vrrp_vscript_rise_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->rise = atoi(vector_slot(strvec, 1));
+	if (vscript->rise < 1)
+		vscript->rise = 1;
+}
+static void
+vrrp_vscript_fall_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->fall = atoi(vector_slot(strvec, 1));
+	if (vscript->fall < 1)
+		vscript->fall = 1;
+}
+
+vector_t *
+vrrp_init_keywords(void)
+{
+	/* global definitions mapping */
+	global_init_keywords();
+
+	/* Static routes mapping */
+	install_keyword_root("static_ipaddress", &static_addresses_handler);
+	install_keyword_root("static_routes", &static_routes_handler);
+
+	/* VRRP Instance mapping */
+	install_keyword_root("vrrp_sync_group", &vrrp_sync_group_handler);
+	install_keyword("group", &vrrp_group_handler);
+	install_keyword("notify_backup", &vrrp_gnotify_backup_handler);
+	install_keyword("notify_master", &vrrp_gnotify_master_handler);
+	install_keyword("notify_fault", &vrrp_gnotify_fault_handler);
+	install_keyword("notify", &vrrp_gnotify_handler);
+	install_keyword("smtp_alert", &vrrp_gsmtp_handler);
+	install_keyword("global_tracking", &vrrp_gglobal_tracking_handler);
+	install_keyword_root("vrrp_instance", &vrrp_handler);
+	install_keyword("use_vmac", &vrrp_vmac_handler);
+	install_keyword("native_ipv6", &vrrp_native_ipv6_handler);
+	install_keyword("state", &vrrp_state_handler);
+	install_keyword("interface", &vrrp_int_handler);
+	install_keyword("dont_track_primary", &vrrp_dont_track_handler);
+	install_keyword("track_interface", &vrrp_track_int_handler);
+	install_keyword("track_script", &vrrp_track_scr_handler);
+	install_keyword("mcast_src_ip", &vrrp_mcastip_handler);
+	install_keyword("virtual_router_id", &vrrp_vrid_handler);
+	install_keyword("priority", &vrrp_prio_handler);
+	install_keyword("advert_int", &vrrp_adv_handler);
+	install_keyword("virtual_ipaddress", &vrrp_vip_handler);
+	install_keyword("virtual_ipaddress_excluded", &vrrp_evip_handler);
+	install_keyword("virtual_routes", &vrrp_vroutes_handler);
+	install_keyword("preempt", &vrrp_preempt_handler);
+	install_keyword("nopreempt", &vrrp_nopreempt_handler);
+	install_keyword("preempt_delay", &vrrp_preempt_delay_handler);
+	install_keyword("debug", &vrrp_debug_handler);
+	install_keyword("notify_backup", &vrrp_notify_backup_handler);
+	install_keyword("notify_master", &vrrp_notify_master_handler);
+	install_keyword("notify_fault", &vrrp_notify_fault_handler);
+	install_keyword("notify_stop", &vrrp_notify_stop_handler);
+	install_keyword("notify", &vrrp_notify_handler);
+	install_keyword("smtp_alert", &vrrp_smtp_handler);
+	install_keyword("lvs_sync_daemon_interface", &vrrp_lvs_syncd_handler);
+	install_keyword("garp_master_delay", &vrrp_garp_delay_handler);
+	install_keyword("authentication", NULL);
+	install_sublevel();
+	install_keyword("auth_type", &vrrp_auth_type_handler);
+	install_keyword("auth_pass", &vrrp_auth_pass_handler);
+	install_sublevel_end();
+	install_keyword_root("vrrp_script", &vrrp_script_handler);
+	install_keyword("script", &vrrp_vscript_script_handler);
+	install_keyword("interval", &vrrp_vscript_interval_handler);
+	install_keyword("timeout", &vrrp_vscript_timeout_handler);
+	install_keyword("weight", &vrrp_vscript_weight_handler);
+	install_keyword("rise", &vrrp_vscript_rise_handler);
+	install_keyword("fall", &vrrp_vscript_fall_handler);
+
+	return keywords;
+}
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_parser.c~ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_parser.c~
--- keepalived-1.2.7/keepalived/vrrp/vrrp_parser.c~	1970-01-01 01:00:00.000000000 +0100
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_parser.c~	2013-05-24 09:39:17.000000000 +0200
@@ -0,0 +1,521 @@
+/* 
+ * Soft:        Keepalived is a failover program for the LVS project
+ *              <www.linuxvirtualserver.org>. It monitor & manipulate
+ *              a loadbalanced server pool using multi-layer checks.
+ * 
+ * Part:        Configuration file parser/reader. Place into the dynamic
+ *              data structure representation the conf file representing
+ *              the loadbalanced server pool.
+ *  
+ * Author:      Alexandre Cassen, <acassen@linux-vs.org>
+ *              
+ *              This program is distributed in the hope that it will be useful,
+ *              but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *              See the GNU General Public License for more details.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2001-2012 Alexandre Cassen, <acassen@gmail.com>
+ */
+
+#include "vrrp_parser.h"
+#include "vrrp_data.h"
+#include "vrrp_sync.h"
+#include "vrrp_index.h"
+#include "vrrp_if.h"
+#include "vrrp_vmac.h"
+#include "vrrp.h"
+#include "global_data.h"
+#include "global_parser.h"
+#include "logger.h"
+#include "parser.h"
+#include "memory.h"
+
+/* Static addresses handler */
+static void
+static_addresses_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_saddress);
+}
+
+/* Static routes handler */
+static void
+static_routes_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_sroute);
+}
+
+/* VRRP handlers */
+static void
+vrrp_sync_group_handler(vector_t *strvec)
+{
+	alloc_vrrp_sync_group(vector_slot(strvec, 1));
+}
+static void
+vrrp_group_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->iname = read_value_block();
+}
+static void
+vrrp_gnotify_backup_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->script_backup = set_value(strvec);
+	vgroup->notify_exec = 1;
+}
+static void
+vrrp_gnotify_master_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->script_master = set_value(strvec);
+	vgroup->notify_exec = 1;
+}
+static void
+vrrp_gnotify_fault_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->script_fault = set_value(strvec);
+	vgroup->notify_exec = 1;
+}
+static void
+vrrp_gnotify_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->script = set_value(strvec);
+	vgroup->notify_exec = 1;
+}
+static void
+vrrp_gsmtp_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->smtp_alert = 1;
+}
+static void
+vrrp_gglobal_tracking_handler(vector_t *strvec)
+{
+	vrrp_sgroup *vgroup = LIST_TAIL_DATA(vrrp_data->vrrp_sync_group);
+	vgroup->global_tracking = 1;
+}
+static void
+vrrp_handler(vector_t *strvec)
+{
+	alloc_vrrp(vector_slot(strvec, 1));
+}
+static void
+vrrp_vmac_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->vmac = 1;
+	if (!vrrp->mcast_saddr)
+		vrrp->mcast_saddr  = IF_ADDR(vrrp->ifp);
+	if (vector_size(strvec) == 2) {
+		strncpy(vrrp->vmac_ifname, vector_slot(strvec, 1),
+			IFNAMSIZ - 1);
+	} else if (vrrp->vrid) {
+		snprintf(vrrp->vmac_ifname, IFNAMSIZ, "vrrp.%d", vrrp->vrid);
+	}
+
+	if (strlen(vrrp->vmac_ifname)) {
+		log_message(LOG_INFO, "vmac_ifname=%s for vrrp_instace %s"
+				    , vrrp->vmac_ifname
+				    , vrrp->iname);
+	}
+	if (vrrp->ifp && !(vrrp->vmac & 2))
+		netlink_link_add_vmac(vrrp);
+}
+static void
+vrrp_native_ipv6_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->family = AF_INET6;
+
+	if (vrrp->auth_type != VRRP_AUTH_NONE)
+		vrrp->auth_type = VRRP_AUTH_NONE;
+}
+static void
+vrrp_state_handler(vector_t *strvec)
+{
+	char *str = vector_slot(strvec, 1);
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp_sgroup *vgroup = vrrp->sync;
+
+	if (!strcmp(str, "MASTER")) {
+		vrrp->wantstate = VRRP_STATE_MAST;
+		vrrp->init_state = VRRP_STATE_MAST;
+	}
+
+	/* set eventual sync group */
+	if (vgroup)
+		vgroup->state = vrrp->wantstate;
+}
+static void
+vrrp_int_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	char *name = vector_slot(strvec, 1);
+	vrrp->ifp = if_get_by_ifname(name);
+	if (vrrp->vmac && !(vrrp->vmac & 2))
+		netlink_link_add_vmac(vrrp);
+}
+static void
+vrrp_track_int_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_vrrp_track);
+}
+static void
+vrrp_track_scr_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_vrrp_track_script);
+}
+static void
+vrrp_dont_track_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->dont_track_primary = 1;
+}
+static void
+vrrp_mcastip_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	inet_ston(vector_slot(strvec, 1), &vrrp->mcast_saddr);
+}
+static void
+vrrp_vrid_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->vrid = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_VID(vrrp->vrid)) {
+		log_message(LOG_INFO, "VRRP Error : VRID not valid !");
+		log_message(LOG_INFO,
+		       "             must be between 1 & 255. reconfigure !");
+	} else {
+		alloc_vrrp_bucket(vrrp);
+		if (vrrp->vmac && strlen(vrrp->vmac_ifname) == 0) {
+			snprintf(vrrp->vmac_ifname, IFNAMSIZ, "vrrp.%d"
+						  , vrrp->vrid);
+			log_message(LOG_INFO, "vmac_ifname=%s for vrrp_instace %s"
+					    , vrrp->vmac_ifname
+					    , vrrp->iname);
+		}
+	}
+}
+static void
+vrrp_prio_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->effective_priority = vrrp->base_priority = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_PRIORITY(vrrp->base_priority)) {
+		log_message(LOG_INFO, "VRRP Error : Priority not valid !");
+		log_message(LOG_INFO,
+		       "             must be between 1 & 255. reconfigure !");
+		log_message(LOG_INFO,
+			    "             Using default value : %d\n", VRRP_PRIO_DFL);
+		vrrp->effective_priority = vrrp->base_priority = VRRP_PRIO_DFL;
+	}
+}
+static void
+vrrp_adv_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->adver_int = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_ADVERT_INT(vrrp->adver_int)) {
+		log_message(LOG_INFO, "VRRP Error : Advert interval not valid !");
+		log_message(LOG_INFO,
+		       "             must be between less than 1sec.");
+		log_message(LOG_INFO, "             Using default value : 1sec");
+		vrrp->adver_int = 1;
+	}
+	vrrp->adver_int *= TIMER_HZ;
+}
+static void
+vrrp_debug_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->debug = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_DEBUG_INT(vrrp->debug)) {
+		log_message(LOG_INFO, "VRRP Error : Debug interval not valid !");
+		log_message(LOG_INFO, "             must be between 0-4");
+		vrrp->debug = 0;
+	}
+}
+static void
+vrrp_nopreempt_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->nopreempt = 1;
+}
+static void	/* backwards compatibility */
+vrrp_preempt_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->nopreempt = 0;
+}
+static void
+vrrp_preempt_delay_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->preempt_delay = atoi(vector_slot(strvec, 1));
+
+	if (VRRP_IS_BAD_PREEMPT_DELAY(vrrp->preempt_delay)) {
+		log_message(LOG_INFO, "VRRP Error : Preempt_delay not valid !");
+		log_message(LOG_INFO, "             must be between 0-%d",
+		       TIMER_MAX_SEC);
+		vrrp->preempt_delay = 0;
+	}
+	vrrp->preempt_delay *= TIMER_HZ;
+	vrrp->preempt_time = timer_add_long(timer_now(), vrrp->preempt_delay);
+}
+static void
+vrrp_notify_backup_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script_backup = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_notify_master_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script_master = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_notify_fault_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script_fault = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_notify_stop_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script_stop = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_notify_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->script = set_value(strvec);
+	vrrp->notify_exec = 1;
+}
+static void
+vrrp_smtp_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->smtp_alert = 1;
+}
+static void
+vrrp_lvs_syncd_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->lvs_syncd_if = set_value(strvec);
+}
+static void
+vrrp_garp_delay_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	vrrp->garp_delay = atoi(vector_slot(strvec, 1)) * TIMER_HZ;
+	if (vrrp->garp_delay < TIMER_HZ)
+		vrrp->garp_delay = TIMER_HZ;
+}
+static void
+vrrp_auth_type_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	char *str = vector_slot(strvec, 1);
+
+	if (!strcmp(str, "AH") && vrrp->family == AF_INET)
+		vrrp->auth_type = VRRP_AUTH_AH;
+	else if (!strcmp(str, "PASS") && vrrp->family == AF_INET)
+		vrrp->auth_type = VRRP_AUTH_PASS;
+}
+static void
+vrrp_auth_pass_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	char *str = vector_slot(strvec, 1);
+	int max_size = sizeof (vrrp->auth_data);
+	int str_len = strlen(str);
+
+	if (str_len > max_size) {
+		str_len = max_size;
+		log_message(LOG_INFO,
+			    "Truncating auth_pass to %d characters", max_size);
+	}
+
+	memset(vrrp->auth_data, 0, max_size);
+	memcpy(vrrp->auth_data, str, str_len);
+}
+static void
+vrrp_vip_handler(vector_t *strvec)
+{
+	vrrp_rt *vrrp = LIST_TAIL_DATA(vrrp_data->vrrp);
+	char *buf;
+	char *str = NULL;
+	vector_t *vec = NULL;
+	int nbvip = 0;
+
+	buf = (char *) MALLOC(MAXBUF);
+	while (read_line(buf, MAXBUF)) {
+		vec = alloc_strvec(buf);
+		if (vec) {
+			str = vector_slot(vec, 0);
+			if (!strcmp(str, EOB)) {
+				free_strvec(vec);
+				break;
+			}
+
+			if (vector_size(vec)) {
+				nbvip++;
+				if (nbvip > VRRP_MAX_VIP) {
+					log_message(LOG_INFO,
+					       "VRRP_Instance(%s) "
+					       "trunc to the first %d VIPs.",
+					       vrrp->iname, VRRP_MAX_VIP);
+					log_message(LOG_INFO,
+					       "  => Declare others VIPs into"
+					       " the excluded vip block");
+				} else
+					alloc_vrrp_vip(vec);
+			}
+
+			free_strvec(vec);
+		}
+		memset(buf, 0, MAXBUF);
+	}
+	FREE(buf);
+}
+static void
+vrrp_evip_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_vrrp_evip);
+}
+static void
+vrrp_vroutes_handler(vector_t *strvec)
+{
+	alloc_value_block(strvec, alloc_vrrp_vroute);
+}
+static void
+vrrp_script_handler(vector_t *strvec)
+{
+	alloc_vrrp_script(vector_slot(strvec, 1));
+}
+static void
+vrrp_vscript_script_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->script = set_value(strvec);
+}
+static void
+vrrp_vscript_interval_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->interval = atoi(vector_slot(strvec, 1)) * TIMER_HZ;
+	if (vscript->interval < TIMER_HZ)
+		vscript->interval = TIMER_HZ;
+}
+static void
+vrrp_vscript_timeout_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->timeout = atoi(vector_slot(strvec, 1)) * TIMER_HZ;
+	if (vscript->timeout < TIMER_HZ)
+		vscript->timeout = TIMER_HZ;
+}
+static void
+vrrp_vscript_weight_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->weight = atoi(vector_slot(strvec, 1));
+}
+static void
+vrrp_vscript_rise_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->rise = atoi(vector_slot(strvec, 1));
+	if (vscript->rise < 1)
+		vscript->rise = 1;
+}
+static void
+vrrp_vscript_fall_handler(vector_t *strvec)
+{
+	vrrp_script *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
+	vscript->fall = atoi(vector_slot(strvec, 1));
+	if (vscript->fall < 1)
+		vscript->fall = 1;
+}
+
+vector_t *
+vrrp_init_keywords(void)
+{
+	/* global definitions mapping */
+	global_init_keywords();
+
+	/* Static routes mapping */
+	install_keyword_root("static_ipaddress", &static_addresses_handler);
+	install_keyword_root("static_routes", &static_routes_handler);
+
+	/* VRRP Instance mapping */
+	install_keyword_root("vrrp_sync_group", &vrrp_sync_group_handler);
+	install_keyword("group", &vrrp_group_handler);
+	install_keyword("notify_backup", &vrrp_gnotify_backup_handler);
+	install_keyword("notify_master", &vrrp_gnotify_master_handler);
+	install_keyword("notify_fault", &vrrp_gnotify_fault_handler);
+	install_keyword("notify", &vrrp_gnotify_handler);
+	install_keyword("smtp_alert", &vrrp_gsmtp_handler);
+	install_keyword("global_tracking", &vrrp_gglobal_tracking_handler);
+	install_keyword_root("vrrp_instance", &vrrp_handler);
+	install_keyword("use_vmac", &vrrp_vmac_handler);
+	install_keyword("native_ipv6", &vrrp_native_ipv6_handler);
+	install_keyword("state", &vrrp_state_handler);
+	install_keyword("interface", &vrrp_int_handler);
+	install_keyword("dont_track_primary", &vrrp_dont_track_handler);
+	install_keyword("track_interface", &vrrp_track_int_handler);
+	install_keyword("track_script", &vrrp_track_scr_handler);
+	install_keyword("mcast_src_ip", &vrrp_mcastip_handler);
+	install_keyword("vrrp_unicast_bind", &vrrp_unicast_bind_handler);
+	install_keyword("vrrp_unicast_peer", &vrrp_unicast_peer_handler);
+	install_keyword("virtual_router_id", &vrrp_vrid_handler);
+	install_keyword("priority", &vrrp_prio_handler);
+	install_keyword("advert_int", &vrrp_adv_handler);
+	install_keyword("virtual_ipaddress", &vrrp_vip_handler);
+	install_keyword("virtual_ipaddress_excluded", &vrrp_evip_handler);
+	install_keyword("virtual_routes", &vrrp_vroutes_handler);
+	install_keyword("preempt", &vrrp_preempt_handler);
+	install_keyword("nopreempt", &vrrp_nopreempt_handler);
+	install_keyword("preempt_delay", &vrrp_preempt_delay_handler);
+	install_keyword("debug", &vrrp_debug_handler);
+	install_keyword("notify_backup", &vrrp_notify_backup_handler);
+	install_keyword("notify_master", &vrrp_notify_master_handler);
+	install_keyword("notify_fault", &vrrp_notify_fault_handler);
+	install_keyword("notify_stop", &vrrp_notify_stop_handler);
+	install_keyword("notify", &vrrp_notify_handler);
+	install_keyword("smtp_alert", &vrrp_smtp_handler);
+	install_keyword("lvs_sync_daemon_interface", &vrrp_lvs_syncd_handler);
+	install_keyword("garp_master_delay", &vrrp_garp_delay_handler);
+	install_keyword("authentication", NULL);
+	install_sublevel();
+	install_keyword("auth_type", &vrrp_auth_type_handler);
+	install_keyword("auth_pass", &vrrp_auth_pass_handler);
+	install_sublevel_end();
+	install_keyword_root("vrrp_script", &vrrp_script_handler);
+	install_keyword("script", &vrrp_vscript_script_handler);
+	install_keyword("interval", &vrrp_vscript_interval_handler);
+	install_keyword("timeout", &vrrp_vscript_timeout_handler);
+	install_keyword("weight", &vrrp_vscript_weight_handler);
+	install_keyword("rise", &vrrp_vscript_rise_handler);
+	install_keyword("fall", &vrrp_vscript_fall_handler);
+
+	return keywords;
+}
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_scheduler.c keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_scheduler.c
--- keepalived-1.2.7/keepalived/vrrp/vrrp_scheduler.c	2012-08-29 01:18:29.000000000 +0200
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_scheduler.c	2013-05-24 09:39:17.645833100 +0200
@@ -468,12 +468,12 @@ vrrp_open_sockpool(list l)
 	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
 		sock = ELEMENT_DATA(e);
 		sock->fd_in = open_vrrp_socket(sock->family, sock->proto,
-						   sock->ifindex);
+						   sock->ifindex, 0);
 		if (sock->fd_in == -1)
 			sock->fd_out = -1;
 		else
 			sock->fd_out = open_vrrp_send_socket(sock->family, sock->proto,
-								 sock->ifindex);
+								 sock->ifindex, 0);
 	}
 }
 
diff -rupN keepalived-1.2.7/keepalived/vrrp/vrrp_scheduler.c.orig keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_scheduler.c.orig
--- keepalived-1.2.7/keepalived/vrrp/vrrp_scheduler.c.orig	1970-01-01 01:00:00.000000000 +0100
+++ keepalived-1.2.7-unicast/keepalived/vrrp/vrrp_scheduler.c.orig	2012-08-29 01:18:29.000000000 +0200
@@ -0,0 +1,1064 @@
+/*
+ * Soft:        Keepalived is a failover program for the LVS project
+ *              <www.linuxvirtualserver.org>. It monitor & manipulate
+ *              a loadbalanced server pool using multi-layer checks.
+ *
+ * Part:        Sheduling framework for vrrp code.
+ *
+ * Author:      Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ *              This program is distributed in the hope that it will be useful,
+ *              but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *              See the GNU General Public License for more details.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2001-2012 Alexandre Cassen, <acassen@gmail.com>
+ */
+
+#include "vrrp_scheduler.h"
+#include "vrrp_ipsecah.h"
+#include "vrrp_if.h"
+#include "vrrp.h"
+#include "vrrp_sync.h"
+#include "vrrp_notify.h"
+#include "vrrp_netlink.h"
+#include "vrrp_data.h"
+#include "vrrp_index.h"
+#include "ipvswrapper.h"
+#include "memory.h"
+#include "notify.h"
+#include "list.h"
+#include "logger.h"
+#include "main.h"
+#include "smtp.h"
+#include "signals.h"
+#ifdef _WITH_SNMP_
+#include "vrrp_snmp.h"
+#endif
+
+/* VRRP FSM (Finite State Machine) design.
+ *
+ * The state transition diagram implemented is :
+ *
+ *                         +---------------+
+ *        +----------------|               |----------------+
+ *        |                |     Fault     |                |
+ *        |  +------------>|               |<------------+  |
+ *        |  |             +---------------+             |  |
+ *        |  |                     |                     |  |
+ *        |  |                     V                     |  |
+ *        |  |             +---------------+             |  |
+ *        |  |  +--------->|               |<---------+  |  |
+ *        |  |  |          |  Initialize   |          |  |  |
+ *        |  |  |  +-------|               |-------+  |  |  |
+ *        |  |  |  |       +---------------+       |  |  |  |
+ *        |  |  |  |                               |  |  |  |
+ *        V  |  |  V                               V  |  |  V
+ *     +---------------+                       +---------------+
+ *     |               |---------------------->|               |
+ *     |    Master     |                       |    Backup     |
+ *     |               |<----------------------|               |
+ *     +---------------+                       +---------------+
+ */
+static void vrrp_backup(vrrp_rt *, char *, int);
+static void vrrp_leave_master(vrrp_rt *, char *, int);
+static void vrrp_leave_fault(vrrp_rt *, char *, int);
+static void vrrp_become_master(vrrp_rt *, char *, int);
+
+static void vrrp_goto_master(vrrp_rt *);
+static void vrrp_master(vrrp_rt *);
+static void vrrp_fault(vrrp_rt *);
+
+static int vrrp_update_priority(thread_t * thread);
+static int vrrp_script_child_timeout_thread(thread_t * thread);
+static int vrrp_script_child_thread(thread_t * thread);
+static int vrrp_script_thread(thread_t * thread);
+
+struct {
+	void (*read) (vrrp_rt *, char *, int);
+	void (*read_to) (vrrp_rt *);
+} VRRP_FSM[VRRP_MAX_FSM_STATE + 1] =
+{
+/*    Stream Read Handlers      |    Stream Read_to handlers   *
+ *------------------------------+------------------------------*/
+	{NULL, 				NULL},
+	{vrrp_backup,			vrrp_goto_master},	/*  BACKUP          */
+	{vrrp_leave_master,		vrrp_master},		/*  MASTER          */
+	{vrrp_leave_fault,		vrrp_fault},		/*  FAULT           */
+	{vrrp_become_master,		vrrp_goto_master}	/*  GOTO_MASTER     */
+};
+
+/* VRRP TSM (Transition State Matrix) design.
+ *
+ * Introducing the Synchronization extension to VRRP
+ * protocol, introduce the need for a transition machinery.
+ * This mecanism can be designed using a diagonal matrix.
+ * We call this matrix the VRRP TSM:
+ *
+ *   \ E |  B  |  M  |  F  |
+ *   S \ |     |     |     |
+ * ------+-----+-----+-----+     Legend:
+ *   B   |  x     1     2  |       B: VRRP BACKUP state
+ * ------+                 |       M: VRRP MASTER state
+ *   M   |  3     x     4  |       F: VRRP FAULT state
+ * ------+                 |       S: VRRP start state (before transition)
+ *   F   |  5     6     x  |       E: VRRP end state (after transition)
+ * ------+-----------------+       [1..6]: Handler functions.
+ *
+ * So we have have to implement n(n-1) handlers in order to deal with
+ * all transitions possible. This matrix defines the maximum handlers
+ * to implement for having the most time optimized transition machine.
+ * For example:
+ *     . The handler (1) will sync all the BACKUP VRRP instances of a
+ *       group to MASTER state => we will call it vrrp_sync_master.
+ *     .... and so on for all other state ....
+ *
+ * This matrix is the strict implementation way. For readability and
+ * performance we have implemented some handlers directly into the VRRP
+ * FSM. For instance the handlers (5) & (6) are directly into the VRRP
+ * FSM since it will speed up convergence to init state.
+ * Additionnaly, we have implemented some other handlers into the matrix
+ * in order to speed up group synchronization takeover. For instance
+ * transitions : 
+ *    o B->B: To catch wantstate MASTER transition to force sync group
+ *            to this transition state too.
+ *    o F->F: To speed up FAULT state transition if group is not already
+ *            synced to FAULT state.
+ */
+struct {
+	void (*handler) (vrrp_rt *);
+} VRRP_TSM[VRRP_MAX_TSM_STATE + 1][VRRP_MAX_TSM_STATE + 1] =
+{
+  { {NULL}, {NULL},                      {NULL},             {NULL}            },
+  { {NULL}, {vrrp_sync_master_election}, {vrrp_sync_master}, {vrrp_sync_fault} },
+  { {NULL}, {vrrp_sync_backup},          {vrrp_sync_master}, {vrrp_sync_fault} },
+  { {NULL}, {vrrp_sync_backup},          {vrrp_sync_master}, {vrrp_sync_fault} }
+};
+
+/* SMTP alert notifier */
+static void
+vrrp_smtp_notifier(vrrp_rt * vrrp)
+{
+	if (vrrp->smtp_alert) {
+		if (vrrp->state == VRRP_STATE_MAST)
+			smtp_alert(NULL, vrrp, NULL,
+				   "Entering MASTER state",
+				   "=> VRRP Instance is now owning VRRP VIPs <=");
+		if (vrrp->state == VRRP_STATE_BACK)
+			smtp_alert(NULL, vrrp, NULL,
+				   "Entering BACKUP state",
+				   "=> VRRP Instance is nolonger owning VRRP VIPs <=");
+	}
+}
+
+/* Log interface message */
+static void vrrp_log_int_down(vrrp_rt *vrrp)
+{
+	if (!IF_ISUP(vrrp->ifp))
+		log_message(LOG_INFO, "Kernel is reporting: interface %s DOWN",
+		       IF_NAME(vrrp->ifp));
+	if (!LIST_ISEMPTY(vrrp->track_ifp))
+		vrrp_log_tracked_down(vrrp->track_ifp);
+}
+
+static void vrrp_log_int_up(vrrp_rt *vrrp)
+{
+	if (IF_ISUP(vrrp->ifp))
+		log_message(LOG_INFO, "Kernel is reporting: interface %s UP",
+		       IF_NAME(vrrp->ifp));
+	if (!LIST_ISEMPTY(vrrp->track_ifp))
+		log_message(LOG_INFO, "Kernel is reporting: tracked interface are UP");
+}
+
+/*
+ * Initialize state handling
+ * --rfc2338.6.4.1
+ */
+static void
+vrrp_init_state(list l)
+{
+	vrrp_rt *vrrp;
+	vrrp_sgroup *vgroup;
+	element e;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+
+		/* In case of VRRP SYNC, we have to carefully check that we are
+		 * not running floating priorities on any VRRP instance.
+		 */
+		if (vrrp->sync && !vrrp->sync->global_tracking) {
+			element e2;
+			tracked_sc *sc;
+			tracked_if *tip;
+			int warning = 0;
+
+			if (!LIST_ISEMPTY(vrrp->track_ifp)) {
+				for (e2 = LIST_HEAD(vrrp->track_ifp); e2; ELEMENT_NEXT(e2)) {
+					tip = ELEMENT_DATA(e2);
+					if (tip->weight) {
+						tip->weight = 0;
+						warning++;
+					}
+				}
+			}
+
+			if (!LIST_ISEMPTY(vrrp->track_script)) {
+				for (e2 = LIST_HEAD(vrrp->track_script); e2; ELEMENT_NEXT(e2)) {
+					sc = ELEMENT_DATA(e2);
+					if (sc->weight) {
+						sc->scr->inuse--;
+						warning++;
+					}
+				}
+			}
+
+			if (warning > 0) {
+				log_message(LOG_INFO, "VRRP_Instance(%s) : ignoring "
+						 "tracked script with weights due to SYNC group",
+				       vrrp->iname);
+			}
+		} else {
+			/* Register new priority update thread */
+			thread_add_timer(master, vrrp_update_priority,
+					 vrrp, vrrp->adver_int);
+		}
+
+		if (vrrp->base_priority == VRRP_PRIO_OWNER ||
+		    vrrp->wantstate == VRRP_STATE_MAST) {
+#ifdef _HAVE_IPVS_SYNCD_
+			/* Check if sync daemon handling is needed */
+			if (vrrp->lvs_syncd_if)
+				ipvs_syncd_cmd(IPVS_STARTDAEMON,
+					       vrrp->lvs_syncd_if, IPVS_MASTER,
+					       vrrp->vrid);
+#endif
+			vrrp->state = VRRP_STATE_GOTO_MASTER;
+		} else {
+			vrrp->ms_down_timer = 3 * vrrp->adver_int
+			    + VRRP_TIMER_SKEW(vrrp);
+#ifdef _HAVE_IPVS_SYNCD_
+			/* Check if sync daemon handling is needed */
+			if (vrrp->lvs_syncd_if)
+				ipvs_syncd_cmd(IPVS_STARTDAEMON,
+					       vrrp->lvs_syncd_if, IPVS_BACKUP,
+					       vrrp->vrid);
+#endif
+			log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE",
+			       vrrp->iname);
+
+			/* Set BACKUP state */
+			vrrp_restore_interface(vrrp, 0);
+			vrrp->state = VRRP_STATE_BACK;
+			vrrp_smtp_notifier(vrrp);
+			notify_instance_exec(vrrp, VRRP_STATE_BACK);
+#ifdef _WITH_SNMP_
+			vrrp_snmp_instance_trap(vrrp);
+#endif
+
+			/* Init group if needed  */
+			if ((vgroup = vrrp->sync)) {
+				if (GROUP_STATE(vgroup) != VRRP_STATE_BACK) {
+					vgroup->state = VRRP_STATE_BACK;
+					vrrp_sync_smtp_notifier(vgroup);
+					notify_group_exec(vgroup, VRRP_STATE_BACK);
+#ifdef _WITH_SNMP_
+					vrrp_snmp_group_trap(vgroup);
+#endif
+				}
+			}
+		}
+	}
+}
+
+static void
+vrrp_init_sands(list l)
+{
+	vrrp_rt *vrrp;
+	element e;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		vrrp_init_instance_sands(vrrp);
+	}
+}
+
+/* if run after vrrp_init_state(), it will be able to detect scripts that
+ * have been disabled because of a sync group and will avoid to start them.
+ */
+static void
+vrrp_init_script(list l)
+{
+	vrrp_script *vscript;
+	element e;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vscript = ELEMENT_DATA(e);
+		if (vscript->inuse == 0)
+			vscript->result = VRRP_SCRIPT_STATUS_DISABLED;
+
+		if (vscript->result == VRRP_SCRIPT_STATUS_INIT) {
+			vscript->result = vscript->rise - 1; /* one success is enough */
+			thread_add_event(master, vrrp_script_thread, vscript, vscript->interval);
+		} else if (vscript->result == VRRP_SCRIPT_STATUS_INIT_GOOD) {
+			vscript->result = vscript->rise; /* one failure is enough */
+			thread_add_event(master, vrrp_script_thread, vscript, vscript->interval);
+		}
+	}
+}
+
+/* Timer functions */
+static timeval_t
+vrrp_compute_timer(const int fd)
+{
+	vrrp_rt *vrrp;
+	element e;
+	list l = &vrrp_data->vrrp_index_fd[fd%1024 + 1];
+	timeval_t timer;
+
+	/* Multiple instances on the same interface */
+	timer_reset(timer);
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		if (timer_cmp(vrrp->sands, timer) < 0 ||
+		    timer_isnull(timer))
+			timer = timer_dup(vrrp->sands);
+	}
+
+	return timer;
+}
+
+static long
+vrrp_timer_fd(const int fd)
+{
+	timeval_t timer, vrrp_timer;
+	long vrrp_long;
+
+	timer = vrrp_compute_timer(fd);
+	vrrp_timer = timer_sub(timer, time_now);
+	vrrp_long = timer_long(vrrp_timer);
+
+	return (vrrp_long < 0) ? TIMER_MAX_SEC : vrrp_long;
+}
+
+static int
+vrrp_timer_vrid_timeout(const int fd)
+{
+	vrrp_rt *vrrp;
+	element e;
+	list l = &vrrp_data->vrrp_index_fd[fd%1024 + 1];
+	timeval_t timer;
+	int vrid = 0;
+
+	/* Multiple instances on the same interface */
+	timer_reset(timer);
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		if (timer_cmp(vrrp->sands, timer) < 0 ||
+		    timer_isnull(timer)) {
+			timer = timer_dup(vrrp->sands);
+			vrid = vrrp->vrid;
+		}
+	}
+	return vrid;
+}
+
+/* Thread functions */
+static void
+vrrp_register_workers(list l)
+{
+	sock_t *sock;
+	timeval_t timer;
+	long vrrp_timer = 0;
+	element e;
+
+	/* Init compute timer */
+	memset(&timer, 0, sizeof (struct timeval));
+
+	/* Init the VRRP instances state */
+	vrrp_init_state(vrrp_data->vrrp);
+
+	/* Init VRRP instances sands */
+	vrrp_init_sands(vrrp_data->vrrp);
+
+	/* Init VRRP tracking scripts */
+	if (!LIST_ISEMPTY(vrrp_data->vrrp_script))
+		vrrp_init_script(vrrp_data->vrrp_script);
+
+	/* Register VRRP workers threads */
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		sock = ELEMENT_DATA(e);
+		/* jump to asynchronous handling */
+		vrrp_timer = vrrp_timer_fd(sock->fd_in);
+
+		/* Register a timer thread if interface is shut */
+		if (sock->fd_in == -1)
+			thread_add_timer(master, vrrp_read_dispatcher_thread,
+					 sock, vrrp_timer);
+		else
+			thread_add_read(master, vrrp_read_dispatcher_thread,
+					sock, sock->fd_in, vrrp_timer);
+	}
+}
+
+/* VRRP dispatcher functions */
+static int
+already_exist_sock(list l, sa_family_t family, int proto, int ifindex)
+{
+	sock_t *sock;
+	element e;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		sock = ELEMENT_DATA(e);
+		if ((sock->family == family) &&
+		    (sock->proto == proto)	 &&
+		    (sock->ifindex == ifindex))
+			return 1;
+	}
+	return 0;
+}
+
+void
+alloc_sock(sa_family_t family, list l, int proto, int ifindex)
+{
+	sock_t *new;
+
+	new = (sock_t *) MALLOC(sizeof (sock_t));
+	new->family = family;
+	new->proto = proto;
+	new->ifindex = ifindex;
+
+	list_add(l, new);
+}
+
+static void
+vrrp_create_sockpool(list l)
+{
+	vrrp_rt *vrrp;
+	list p = vrrp_data->vrrp;
+	element e;
+	int ifindex;
+	int proto;
+
+	for (e = LIST_HEAD(p); e; ELEMENT_NEXT(e)) {
+		vrrp = ELEMENT_DATA(e);
+		ifindex = IF_INDEX(vrrp->ifp);
+		if (vrrp->auth_type == VRRP_AUTH_AH)
+			proto = IPPROTO_IPSEC_AH;
+		else
+			proto = IPPROTO_VRRP;
+
+		/* add the vrrp element if not exist */
+		if (!already_exist_sock(l, vrrp->family, proto, ifindex))
+			alloc_sock(vrrp->family, l, proto, ifindex);
+	}
+}
+
+static void
+vrrp_open_sockpool(list l)
+{
+	sock_t *sock;
+	element e;
+
+	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
+		sock = ELEMENT_DATA(e);
+		sock->fd_in = open_vrrp_socket(sock->family, sock->proto,
+						   sock->ifindex);
+		if (sock->fd_in == -1)
+			sock->fd_out = -1;
+		else
+			sock->fd_out = open_vrrp_send_socket(sock->family, sock->proto,
+								 sock->ifindex);
+	}
+}
+
+static void
+vrrp_set_fds(list l)
+{
+	sock_t *sock;
+	vrrp_rt *vrrp;
+	list p = vrrp_data->vrrp;
+	element e_sock;
+	element e_vrrp;
+	int proto;
+
+	for (e_sock = LIST_HEAD(l); e_sock; ELEMENT_NEXT(e_sock)) {
+		sock = ELEMENT_DATA(e_sock);
+		for (e_vrrp = LIST_HEAD(p); e_vrrp; ELEMENT_NEXT(e_vrrp)) {
+			vrrp = ELEMENT_DATA(e_vrrp);
+			if (vrrp->auth_type == VRRP_AUTH_AH)
+				proto = IPPROTO_IPSEC_AH;
+			else
+				proto = IPPROTO_VRRP;
+
+			if ((sock->ifindex == IF_INDEX(vrrp->ifp)) &&
+			    (sock->proto == proto)) {
+				vrrp->fd_in = sock->fd_in;
+				vrrp->fd_out = sock->fd_out;
+
+				/* append to hash index */
+				alloc_vrrp_fd_bucket(vrrp);
+			}
+		}
+	}
+}
+
+/*
+ * We create & allocate a socket pool here. The soft design
+ * can be sum up by the following sketch :
+ *
+ *    fd1  fd2    fd3  fd4          fdi  fdi+1
+ * -----\__/--------\__/---........---\__/---
+ *    | ETH0 |    | ETH1 |          | ETHn |
+ *    +------+    +------+          +------+
+ *
+ * Here we have n physical NIC. Each NIC own a maximum of 2 fds.
+ * (one for VRRP the other for IPSEC_AH). All our VRRP instances
+ * are multiplexed through this fds. So our design can handle 2*n
+ * multiplexing points.
+ */
+int
+vrrp_dispatcher_init(thread_t * thread)
+{
+	/* create the VRRP socket pool list */
+	vrrp_create_sockpool(vrrp_data->vrrp_socket_pool);
+
+	/* open the VRRP socket pool */
+	vrrp_open_sockpool(vrrp_data->vrrp_socket_pool);
+
+	/* set VRRP instance fds to sockpool */
+	vrrp_set_fds(vrrp_data->vrrp_socket_pool);
+
+	/* register read dispatcher worker thread */
+	vrrp_register_workers(vrrp_data->vrrp_socket_pool);
+
+	/* Dump socket pool */
+	if (debug & 32)
+		dump_list(vrrp_data->vrrp_socket_pool);
+	return 1;
+}
+
+void
+vrrp_dispatcher_release(vrrp_conf_data *conf_data)
+{
+	free_list(conf_data->vrrp_socket_pool);
+}
+
+static void
+vrrp_backup(vrrp_rt * vrrp, char *buffer, int len)
+{
+	struct iphdr *iph;
+	ipsec_ah *ah;
+
+	if (vrrp->family == AF_INET) {
+		iph = (struct iphdr *) buffer;
+
+		if (iph->protocol == IPPROTO_IPSEC_AH) {
+			ah = (ipsec_ah *) (buffer + sizeof (struct iphdr));
+			if (ntohl(ah->seq_number) >= vrrp->ipsecah_counter->seq_number)
+				vrrp->ipsecah_counter->cycle = 0;
+		}
+	}
+
+	vrrp_state_backup(vrrp, buffer, len);
+}
+
+static void
+vrrp_become_master(vrrp_rt * vrrp, char *buffer, int len)
+{
+	struct iphdr *iph;
+	ipsec_ah *ah;
+
+	if (vrrp->family == AF_INET) {
+		iph = (struct iphdr *) buffer;
+
+		/*
+		 * If we are in IPSEC AH mode, we must be sync
+		 * with the remote IPSEC AH VRRP instance counter.
+		 */
+		if (iph->protocol == IPPROTO_IPSEC_AH) {
+			log_message(LOG_INFO, "VRRP_Instance(%s) IPSEC-AH : seq_num sync",
+			       vrrp->iname);
+			ah = (ipsec_ah *) (buffer + sizeof (struct iphdr));
+			vrrp->ipsecah_counter->seq_number = ntohl(ah->seq_number) + 1;
+			vrrp->ipsecah_counter->cycle = 0;
+		}
+	}
+
+	/* Then jump to master state */
+	vrrp->wantstate = VRRP_STATE_MAST;
+	vrrp_state_goto_master(vrrp);
+}
+
+static void
+vrrp_leave_master(vrrp_rt * vrrp, char *buffer, int len)
+{
+	if (!VRRP_ISUP(vrrp)) {
+		vrrp_log_int_down(vrrp);
+		vrrp->wantstate = VRRP_STATE_GOTO_FAULT;
+		vrrp_state_leave_master(vrrp);
+	} else if (vrrp_state_master_rx(vrrp, buffer, len)) {
+		vrrp_state_leave_master(vrrp);
+		vrrp_smtp_notifier(vrrp);
+	}
+}
+
+static void
+vrrp_ah_sync(vrrp_rt *vrrp)
+{
+	/*
+	 * Transition to BACKUP state for AH
+	 * seq number synchronization.
+	 */
+	log_message(LOG_INFO, "VRRP_Instance(%s) in FAULT state jump to AH sync",
+	       vrrp->iname);
+	vrrp->wantstate = VRRP_STATE_BACK;
+	vrrp_state_leave_master(vrrp);
+}
+
+static void
+vrrp_leave_fault(vrrp_rt * vrrp, char *buffer, int len)
+{
+	if (!VRRP_ISUP(vrrp))
+		return;
+
+	if (vrrp_state_fault_rx(vrrp, buffer, len)) {
+		if (vrrp->sync) {
+			if (vrrp_sync_leave_fault(vrrp)) {
+				log_message(LOG_INFO,
+				       "VRRP_Instance(%s) prio is higher than received advert",
+				       vrrp->iname);
+				vrrp_become_master(vrrp, buffer, len);
+			}
+		} else {
+			log_message(LOG_INFO,
+			       "VRRP_Instance(%s) prio is higher than received advert",
+			       vrrp->iname);
+			vrrp_become_master(vrrp, buffer, len);
+		}
+	} else {
+		if (vrrp->sync) {
+			if (vrrp_sync_leave_fault(vrrp)) {
+				log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE",
+				       vrrp->iname);
+				vrrp->state = VRRP_STATE_BACK;
+				vrrp_smtp_notifier(vrrp);
+				notify_instance_exec(vrrp, VRRP_STATE_BACK);
+#ifdef _WITH_SNMP_
+				vrrp_snmp_instance_trap(vrrp);
+#endif
+			}
+		} else {
+			log_message(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE",
+			       vrrp->iname);
+			vrrp->state = VRRP_STATE_BACK;
+			vrrp_smtp_notifier(vrrp);
+			notify_instance_exec(vrrp, VRRP_STATE_BACK);
+#ifdef _WITH_SNMP_
+			vrrp_snmp_instance_trap(vrrp);
+#endif
+		}
+	}
+}
+
+static void
+vrrp_goto_master(vrrp_rt * vrrp)
+{
+	if (!VRRP_ISUP(vrrp)) {
+		vrrp_log_int_down(vrrp);
+		log_message(LOG_INFO, "VRRP_Instance(%s) Now in FAULT state",
+		       vrrp->iname);
+		if (vrrp->state != VRRP_STATE_FAULT)
+			notify_instance_exec(vrrp, VRRP_STATE_FAULT);
+		vrrp->state = VRRP_STATE_FAULT;
+		vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+		notify_instance_exec(vrrp, VRRP_STATE_FAULT);
+#ifdef _WITH_SNMP_
+		vrrp_snmp_instance_trap(vrrp);
+#endif
+	} else {
+		/* If becoming MASTER in IPSEC AH AUTH, we reset the anti-replay */
+		if (vrrp->ipsecah_counter->cycle) {
+			vrrp->ipsecah_counter->cycle = 0;
+			vrrp->ipsecah_counter->seq_number = 0;
+		}
+
+		/* handle master state transition */
+		vrrp->wantstate = VRRP_STATE_MAST;
+		vrrp_state_goto_master(vrrp);
+	}
+}
+
+/* Delayed gratuitous ARP thread */
+int
+vrrp_gratuitous_arp_thread(thread_t * thread)
+{
+	vrrp_rt *vrrp = THREAD_ARG(thread);
+
+	/* Simply broadcast the gratuitous ARP */
+	vrrp_send_link_update(vrrp);
+
+	return 0;
+}
+
+/* Update VRRP effective priority based on multiple checkers.
+ * This is a thread which is executed every adver_int.
+ */
+static int
+vrrp_update_priority(thread_t * thread)
+{
+	vrrp_rt *vrrp = THREAD_ARG(thread);
+	int prio_offset, new_prio;
+
+	/* compute prio_offset right here */
+	prio_offset = 0;
+
+	/* Now we will sum the weights of all interfaces which are tracked. */
+	if ((!vrrp->sync || vrrp->sync->global_tracking) && !LIST_ISEMPTY(vrrp->track_ifp))
+		 prio_offset += vrrp_tracked_weight(vrrp->track_ifp);
+
+	/* Now we will sum the weights of all scripts which are tracked. */
+	if ((!vrrp->sync || vrrp->sync->global_tracking) && !LIST_ISEMPTY(vrrp->track_script))
+		prio_offset += vrrp_script_weight(vrrp->track_script);
+
+	if (vrrp->base_priority == VRRP_PRIO_OWNER) {
+		/* we will not run a PRIO_OWNER into a non-PRIO_OWNER */
+		vrrp->effective_priority = VRRP_PRIO_OWNER;
+	} else {
+		/* WARNING! we must compute new_prio on a signed int in order
+		   to detect overflows and avoid wrapping. */
+		new_prio = vrrp->base_priority + prio_offset;
+		if (new_prio < 1)
+			new_prio = 1;
+		else if (new_prio > 254)
+			new_prio = 254;
+		vrrp->effective_priority = new_prio;
+	}
+
+	/* Register next priority update thread */
+	thread_add_timer(master, vrrp_update_priority, vrrp, vrrp->adver_int);
+	return 0;
+}
+
+static void
+vrrp_master(vrrp_rt * vrrp)
+{
+	/* Check if interface we are running on is UP */
+	if (vrrp->wantstate != VRRP_STATE_GOTO_FAULT) {
+		if (!VRRP_ISUP(vrrp)) {
+			vrrp_log_int_down(vrrp);
+			vrrp->wantstate = VRRP_STATE_GOTO_FAULT;
+		}
+	}
+
+	/* Then perform the state transition */
+	if (vrrp->wantstate == VRRP_STATE_GOTO_FAULT ||
+	    vrrp->wantstate == VRRP_STATE_BACK ||
+	    vrrp->ipsecah_counter->cycle) {
+		vrrp->ms_down_timer = 3 * vrrp->adver_int + VRRP_TIMER_SKEW(vrrp);
+
+		/* handle backup state transition */
+		vrrp_state_leave_master(vrrp);
+
+		if (vrrp->state == VRRP_STATE_BACK)
+			log_message(LOG_INFO, "VRRP_Instance(%s) Now in BACKUP state",
+				    vrrp->iname);
+		if (vrrp->state == VRRP_STATE_FAULT)
+			log_message(LOG_INFO, "VRRP_Instance(%s) Now in FAULT state",
+				    vrrp->iname);
+	} else if (vrrp->state == VRRP_STATE_MAST) {
+		/*
+		 * Send the VRRP advert.
+		 * If we catch the master transition
+		 * <=> vrrp_state_master_tx(...) = 1
+		 * register a gratuitous arp thread delayed to 5 secs.
+		 */
+		if (vrrp_state_master_tx(vrrp, 0)) {
+			thread_add_timer(master, vrrp_gratuitous_arp_thread,
+					 vrrp,
+					 (vrrp->garp_delay) ?
+						vrrp->garp_delay : VRRP_GARP_DELAY);
+			vrrp_smtp_notifier(vrrp);
+		}
+	}
+}
+
+static void
+vrrp_fault(vrrp_rt * vrrp)
+{
+	vrrp_sgroup *vgroup = vrrp->sync;
+
+	if (vgroup) {
+		if (!vrrp_sync_leave_fault(vrrp))
+			return;
+	} else if (VRRP_ISUP(vrrp))
+		vrrp_log_int_up(vrrp);
+	else
+		return;
+
+	/* refresh the multicast fd */
+	if (new_vrrp_socket(vrrp) < 0)
+		return;
+
+	/*
+	 * We force the IPSEC AH seq_number sync
+	 * to be done in read advert handler.
+	 * So we ignore this timeouted state until remote
+	 * VRRP MASTER send its advert for the concerned
+	 * instance.
+	 */
+	if (vrrp->auth_type == VRRP_AUTH_AH) {
+		vrrp_ah_sync(vrrp);
+	} else {
+		/* Otherwise, we transit to init state */
+		if (vrrp->init_state == VRRP_STATE_BACK) {
+			vrrp->state = VRRP_STATE_BACK;
+			notify_instance_exec(vrrp, VRRP_STATE_BACK);
+#ifdef _WITH_SNMP_
+			vrrp_snmp_instance_trap(vrrp);
+#endif
+		} else {
+			vrrp_goto_master(vrrp);
+		}
+	}
+}
+
+/* Handle dispatcher read timeout */
+static int
+vrrp_dispatcher_read_to(int fd)
+{
+	vrrp_rt *vrrp;
+	int vrid = 0;
+	int prev_state = 0;
+
+	/* Searching for matching instance */
+	vrid = vrrp_timer_vrid_timeout(fd);
+	vrrp = vrrp_index_lookup(vrid, fd);
+
+	/* Run the FSM handler */
+	prev_state = vrrp->state;
+	VRRP_FSM_READ_TO(vrrp);
+
+	/* handle instance synchronization */
+//	printf("Send [%s] TSM transtition : [%d,%d] Wantstate = [%d]\n"
+//	       , vrrp->iname
+//	       , prev_state
+//	       , vrrp->state
+//	       , vrrp->wantstate);
+	VRRP_TSM_HANDLE(prev_state, vrrp);
+
+	/*
+	 * We are sure the instance exist. So we can
+	 * compute new sands timer safely.
+	 */
+	vrrp_init_instance_sands(vrrp);
+	return vrrp->fd_in;
+}
+
+/* Handle dispatcher read packet */
+static int
+vrrp_dispatcher_read(sock_t * sock)
+{
+	vrrp_rt *vrrp;
+	vrrp_pkt *hd;
+	int len = 0, prev_state = 0, proto = 0;
+	uint32_t saddr;
+
+	/* Clean the read buffer */
+	memset(vrrp_buffer, 0, VRRP_PACKET_TEMP_LEN);
+
+	/* read & affect received buffer */
+	len = read(sock->fd_in, vrrp_buffer, VRRP_PACKET_TEMP_LEN);
+	hd = vrrp_get_header(sock->family, vrrp_buffer, &proto, &saddr);
+
+	/* Searching for matching instance */
+	vrrp = vrrp_index_lookup(hd->vrid, sock->fd_in);
+
+	/* If no instance found => ignore the advert */
+	if (!vrrp)
+		return sock->fd_in;
+
+	/* Run the FSM handler */
+	prev_state = vrrp->state;
+	VRRP_FSM_READ(vrrp, vrrp_buffer, len);
+
+	/* handle instance synchronization */
+//	printf("Read [%s] TSM transtition : [%d,%d] Wantstate = [%d]\n"
+//	       , vrrp->iname
+//	       , prev_state
+//	       , vrrp->state
+//	       , vrrp->wantstate);
+	VRRP_TSM_HANDLE(prev_state, vrrp);
+
+	/*
+	 * Refresh sands only if found matching instance.
+	 * Otherwize the packet is simply ignored...
+	 */
+	vrrp_init_instance_sands(vrrp);
+
+	return sock->fd_in;
+}
+
+/* Our read packet dispatcher */
+int
+vrrp_read_dispatcher_thread(thread_t * thread)
+{
+	long vrrp_timer = 0;
+	sock_t *sock;
+	int fd;
+
+	/* Fetch thread arg */
+	sock = THREAD_ARG(thread);
+
+	/* Dispatcher state handler */
+	if (thread->type == THREAD_READ_TIMEOUT || sock->fd_in == -1)
+		fd = vrrp_dispatcher_read_to(sock->fd_in);
+	else
+		fd = vrrp_dispatcher_read(sock);
+
+	/* register next dispatcher thread */
+	vrrp_timer = vrrp_timer_fd(fd);
+	if (fd == -1)
+		thread_add_timer(thread->master, vrrp_read_dispatcher_thread,
+				 sock, vrrp_timer);
+	else
+		thread_add_read(thread->master, vrrp_read_dispatcher_thread,
+				sock, fd, vrrp_timer);
+
+	return 0;
+}
+
+/* Script tracking threads */
+static int
+vrrp_script_thread(thread_t * thread)
+{
+	vrrp_script *vscript = THREAD_ARG(thread);
+	int status, ret;
+	pid_t pid;
+
+	/* Register next timer tracker */
+	thread_add_timer(thread->master, vrrp_script_thread, vscript,
+			 vscript->interval);
+
+	/* Daemonization to not degrade our scheduling timer */
+	pid = fork();
+
+	/* In case of fork is error. */
+	if (pid < 0) {
+		log_message(LOG_INFO, "Failed fork process");
+		return -1;
+	}
+
+	/* In case of this is parent process */
+	if (pid) {
+		thread_add_child(thread->master, vrrp_script_child_thread,
+				 vscript, pid,
+				 (vscript->timeout) ? vscript->timeout : vscript->interval);
+		return 0;
+	}
+
+	/* Child part */
+	signal_handler_destroy();
+	closeall(0);
+	open("/dev/null", O_RDWR);
+	ret = dup(0);
+	if (ret < 0) {
+		log_message(LOG_INFO, "dup(0) error");
+	}
+
+	ret = dup(0);
+	if (ret < 0) {
+		log_message(LOG_INFO, "dup(0) error");
+	}
+
+	status = system_call(vscript->script);
+
+	if (status < 0 || !WIFEXITED(status))
+		status = 0; /* Script errors aren't server errors */
+	else
+		status = WEXITSTATUS(status);
+
+	exit(status);
+}
+
+static int
+vrrp_script_child_thread(thread_t * thread)
+{
+	int wait_status;
+	vrrp_script *vscript = THREAD_ARG(thread);
+
+	if (thread->type == THREAD_CHILD_TIMEOUT) {
+		pid_t pid;
+
+		pid = THREAD_CHILD_PID(thread);
+
+		/* The child hasn't responded. Kill it off. */
+		if (vscript->result > vscript->rise) {
+			vscript->result--;
+		} else {
+			if (vscript->result == vscript->rise)
+				log_message(LOG_INFO, "VRRP_Script(%s) timed out", vscript->sname);
+			vscript->result = 0;
+		}
+		kill(pid, SIGTERM);
+		thread_add_child(thread->master, vrrp_script_child_timeout_thread,
+				 vscript, pid, 2);
+		return 0;
+	}
+
+	wait_status = THREAD_CHILD_STATUS(thread);
+
+	if (WIFEXITED(wait_status)) {
+		int status;
+		status = WEXITSTATUS(wait_status);
+		if (status == 0) {
+			/* success */
+			if (vscript->result < vscript->rise - 1) {
+				vscript->result++;
+			} else {
+				if (vscript->result < vscript->rise)
+					log_message(LOG_INFO, "VRRP_Script(%s) succeeded", vscript->sname);
+				vscript->result = vscript->rise + vscript->fall - 1;
+			}
+		} else {
+			/* failure */
+			if (vscript->result > vscript->rise) {
+				vscript->result--;
+			} else {
+				if (vscript->result >= vscript->rise)
+					log_message(LOG_INFO, "VRRP_Script(%s) failed", vscript->sname);
+				vscript->result = 0;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int
+vrrp_script_child_timeout_thread(thread_t * thread)
+{
+	pid_t pid;
+
+	if (thread->type != THREAD_CHILD_TIMEOUT)
+		return 0;
+
+	/* OK, it still hasn't exited. Now really kill it off. */
+	pid = THREAD_CHILD_PID(thread);
+	if (kill(pid, SIGKILL) < 0) {
+		/* Its possible it finished while we're handing this */
+		if (errno != ESRCH)
+			DBG("kill error: %s", strerror(errno));
+		return 0;
+	}
+
+	log_message(LOG_WARNING, "Process [%d] didn't respond to SIGTERM", pid);
+	waitpid(pid, NULL, 0);
+
+	return 0;
+}
