diff -r 4cb047de70e7 include/linux/in.h
--- a/include/linux/in.h	Wed Mar 30 10:40:36 2011 +0900
+++ b/include/linux/in.h	Wed Mar 30 13:59:23 2011 +0900
@@ -72,6 +72,7 @@
 #define IP_FREEBIND	15
 #define IP_IPSEC_POLICY	16
 #define IP_XFRM_POLICY	17
+#define IP_IPSEC_REFINFO 30     /* used with CONFIG_INET_IPSEC_SAREF */
 
 /* BSD compatibility */
 #define IP_RECVRETOPTS	IP_RETOPTS
diff -r 4cb047de70e7 include/net/ip.h
--- a/include/net/ip.h	Wed Mar 30 10:40:36 2011 +0900
+++ b/include/net/ip.h	Wed Mar 30 13:59:23 2011 +0900
@@ -49,6 +49,9 @@
 	u32			addr;
 	int			oif;
 	struct ip_options	*opt;
+#ifdef CONFIG_INET_IPSEC_SAREF
+	struct sec_path         *sp;
+#endif
 };
 
 #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
diff -r 4cb047de70e7 include/net/xfrm.h
--- a/include/net/xfrm.h	Wed Mar 30 10:40:36 2011 +0900
+++ b/include/net/xfrm.h	Wed Mar 30 13:59:23 2011 +0900
@@ -624,13 +624,31 @@
 	struct xfrm_decap_state decap;
 };
 
+#ifdef CONFIG_INET_IPSEC_SAREF
+typedef unsigned int xfrm_sec_unique_t;
+#endif
+
 struct sec_path
 {
 	atomic_t		refcnt;
+#ifdef CONFIG_INET_IPSEC_SAREF
+	xfrm_sec_unique_t       ref;       /*reference to high-level policy*/
+#endif
 	int			len;
 	struct sec_decap_state	x[XFRM_MAX_DEPTH];
 };
 
+#ifdef CONFIG_INET_IPSEC_SAREF
+struct ipcm_cookie;
+struct ipsec_secpath_saref_ops {
+	int (*set_ipc_saref)(struct ipcm_cookie *ipc, xfrm_sec_unique_t saref);
+	void (*get_secpath_sarefs)(struct sec_path *sp,
+			xfrm_sec_unique_t *refme, xfrm_sec_unique_t *refhim);
+};
+extern int register_ipsec_secpath_saref_ops(struct ipsec_secpath_saref_ops *ops);
+extern void unregister_ipsec_secpath_saref_ops(struct ipsec_secpath_saref_ops *ops);
+#endif
+
 static inline struct sec_path *
 secpath_get(struct sec_path *sp)
 {
diff -r 4cb047de70e7 net/ipv4/Kconfig
--- a/net/ipv4/Kconfig	Wed Mar 30 10:40:36 2011 +0900
+++ b/net/ipv4/Kconfig	Wed Mar 30 13:59:23 2011 +0900
@@ -414,6 +414,16 @@
 	  
 	  If unsure, say Y.
 
+config INET_IPSEC_SAREF
+	bool "IP: IPsec SAref interface (KLIPS)"
+	default y
+	select XFRM
+	---help---
+          This exports a mechanism that allows the KLIPS IPsec stack to
+          support mast mode without using nfmark and iptables.
+
+	  If unsure, say Y.
+
 config INET_DIAG
 	tristate "INET: socket monitoring interface"
 	default y
diff -r 4cb047de70e7 net/ipv4/icmp.c
--- a/net/ipv4/icmp.c	Wed Mar 30 10:40:36 2011 +0900
+++ b/net/ipv4/icmp.c	Wed Mar 30 13:59:23 2011 +0900
@@ -385,6 +385,8 @@
 	struct rtable *rt = (struct rtable *)skb->dst;
 	u32 daddr;
 
+	memset(&ipc, 0, sizeof(ipc));
+
 	if (ip_options_echo(&icmp_param->replyopts, skb))
 		return;
 
@@ -441,6 +443,8 @@
 	u32 saddr;
 	u8  tos;
 
+	memset(&ipc, 0, sizeof(ipc));
+
 	if (!rt)
 		goto out;
 
diff -r 4cb047de70e7 net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c	Wed Mar 30 10:40:36 2011 +0900
+++ b/net/ipv4/ip_output.c	Wed Mar 30 13:59:23 2011 +0900
@@ -75,6 +75,7 @@
 #include <net/arp.h>
 #include <net/icmp.h>
 #include <net/checksum.h>
+#include <net/xfrm.h>
 #include <net/inetpeer.h>
 #include <net/checksum.h>
 #include <linux/igmp.h>
@@ -390,6 +391,10 @@
 	/* Copy the flags to each fragment. */
 	IPCB(to)->flags = IPCB(from)->flags;
 
+#ifdef CONFIG_INET_IPSEC_SAREF
+	to->sp = secpath_get(from->sp);
+#endif
+
 #ifdef CONFIG_NET_SCHED
 	to->tc_index = from->tc_index;
 #endif
@@ -921,6 +926,9 @@
 			 */
 			skb->ip_summed = csummode;
 			skb->csum = 0;
+#ifdef CONFIG_INET_IPSEC_SAREF
+			skb->sp = secpath_get(ipc->sp);
+#endif
 			skb_reserve(skb, hh_len);
 
 			/*
@@ -1333,6 +1341,8 @@
 	u32 daddr;
 	struct rtable *rt = (struct rtable*)skb->dst;
 
+	memset(&ipc, 0, sizeof(ipc));
+
 	if (ip_options_echo(&replyopts.opt, skb))
 		return;
 
diff -r 4cb047de70e7 net/ipv4/ip_sockglue.c
--- a/net/ipv4/ip_sockglue.c	Wed Mar 30 10:40:36 2011 +0900
+++ b/net/ipv4/ip_sockglue.c	Wed Mar 30 13:59:23 2011 +0900
@@ -50,6 +50,7 @@
 #define IP_CMSG_TOS		4
 #define IP_CMSG_RECVOPTS	8
 #define IP_CMSG_RETOPTS		16
+#define IP_CMSG_IPSEC_REFINFO   128
 
 /*
  *	SOL_IP control messages.
@@ -110,6 +111,62 @@
 }
 
 
+#ifdef CONFIG_INET_IPSEC_SAREF
+static struct ipsec_secpath_saref_ops *ipsec_secpath_saref_ops = NULL;
+
+int register_ipsec_secpath_saref_ops(struct ipsec_secpath_saref_ops *ops)
+{
+	if (ipsec_secpath_saref_ops)
+		return -EBUSY;
+
+	rcu_assign_pointer(ipsec_secpath_saref_ops, ops);
+
+	return 0;
+}
+EXPORT_SYMBOL(register_ipsec_secpath_saref_ops);
+
+void unregister_ipsec_secpath_saref_ops(struct ipsec_secpath_saref_ops *ops)
+{
+	rcu_assign_pointer(ipsec_secpath_saref_ops, NULL);
+}
+EXPORT_SYMBOL(unregister_ipsec_secpath_saref_ops);
+
+static void ip_cmsg_recv_ipsec_refinfo(struct msghdr *msg, struct sk_buff *skb)
+{
+	struct ipsec_secpath_saref_ops *ops;
+	xfrm_sec_unique_t refs[2] = {0, 0};
+
+	rcu_read_lock_bh();
+	ops = rcu_dereference(ipsec_secpath_saref_ops);
+	if (ops && ops->get_secpath_sarefs)
+		ops->get_secpath_sarefs(skb->sp, &refs[0], &refs[1]);
+	rcu_read_unlock_bh();
+
+	put_cmsg(msg, SOL_IP, IP_IPSEC_REFINFO, sizeof(refs), &refs);
+}
+
+static int ip_cmsg_send_ipsec_refinfo(struct cmsghdr *cmsg, struct ipcm_cookie *ipc)
+{
+	int rc = -EINVAL;
+	struct ipsec_secpath_saref_ops *ops;
+	xfrm_sec_unique_t *ref;
+
+	if(cmsg->cmsg_len != CMSG_LEN(sizeof(xfrm_sec_unique_t)))
+		goto bail;
+
+	ref = (xfrm_sec_unique_t*)CMSG_DATA(cmsg);
+
+	rcu_read_lock_bh();
+	ops = rcu_dereference(ipsec_secpath_saref_ops);
+	if (ops && ops->set_ipc_saref)
+		rc = ops->set_ipc_saref(ipc, *ref);
+	rcu_read_unlock_bh();
+
+bail:
+	return rc;
+}
+#endif
+
 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 {
 	struct inet_sock *inet = inet_sk(skb->sk);
@@ -138,6 +195,19 @@
 
 	if (flags & 1)
 		ip_cmsg_recv_retopts(msg, skb);
+	if ((flags >>= 1) == 0)
+		return;
+
+	if ((flags >>= 1) == 0)
+		return;
+
+	if ((flags >>= 1) == 0)
+		return;
+
+#ifdef CONFIG_INET_IPSEC_SAREF
+	if (flags & 1)
+		ip_cmsg_recv_ipsec_refinfo(msg, skb);
+#endif
 }
 
 int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -167,12 +237,25 @@
 			ipc->addr = info->ipi_spec_dst.s_addr;
 			break;
 		}
+
+#ifdef CONFIG_INET_IPSEC_SAREF
+		case IP_IPSEC_REFINFO:
+		{
+			err = ip_cmsg_send_ipsec_refinfo(cmsg, ipc);
+			if(err)
+				return err;
+
+			break;
+		}
+#endif
+
 		default:
 			return -EINVAL;
 		}
 	}
 	return 0;
 }
+EXPORT_SYMBOL(ip_cmsg_send);
 
 
 /* Special input handler for packets caught by router alert option.
@@ -395,7 +478,11 @@
 			    (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 
 			    (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || 
 				optname == IP_MULTICAST_TTL || 
-				optname == IP_MULTICAST_LOOP) { 
+				optname == IP_MULTICAST_LOOP
+#ifdef CONFIG_INET_IPSEC_SAREF
+	    || optname == IP_IPSEC_REFINFO
+#endif
+	    ) {
 		if (optlen >= sizeof(int)) {
 			if (get_user(val, (int __user *) optval))
 				return -EFAULT;
@@ -478,6 +565,14 @@
 			else
 				inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
 			break;
+#ifdef CONFIG_INET_IPSEC_SAREF
+		case IP_IPSEC_REFINFO:
+			if (val)
+				inet->cmsg_flags |= IP_CMSG_IPSEC_REFINFO;
+			else
+				inet->cmsg_flags &= ~IP_CMSG_IPSEC_REFINFO;
+			break;
+#endif
 		case IP_TOS:	/* This sets both TOS and Precedence */
 			if (sk->sk_type == SOCK_STREAM) {
 				val &= ~3;
@@ -936,6 +1031,11 @@
 		case IP_RETOPTS:
 			val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
 			break;
+#ifdef CONFIG_INET_IPSEC_SAREF
+		case IP_IPSEC_REFINFO:
+			val = (inet->cmsg_flags & IP_CMSG_IPSEC_REFINFO) != 0;
+			break;
+#endif
 		case IP_TOS:
 			val = inet->tos;
 			break;
diff -r 4cb047de70e7 net/ipv4/raw.c
--- a/net/ipv4/raw.c	Wed Mar 30 10:40:36 2011 +0900
+++ b/net/ipv4/raw.c	Wed Mar 30 13:59:23 2011 +0900
@@ -389,6 +389,8 @@
 	u8  tos;
 	int err;
 
+	memset(&ipc, 0, sizeof(ipc));
+
 	err = -EMSGSIZE;
 	if (len > 0xFFFF)
 		goto out;
diff -r 4cb047de70e7 net/ipv4/udp.c
--- a/net/ipv4/udp.c	Wed Mar 30 10:40:36 2011 +0900
+++ b/net/ipv4/udp.c	Wed Mar 30 13:59:23 2011 +0900
@@ -497,6 +497,8 @@
 	int err;
 	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
 
+	memset(&ipc, 0, sizeof(ipc));
+
 	if (len > 0xFFFF)
 		return -EMSGSIZE;
 
@@ -660,6 +662,12 @@
 	ip_rt_put(rt);
 	if (free)
 		kfree(ipc.opt);
+#ifdef CONFIG_INET_IPSEC_SAREF
+	if(ipc.sp) {
+		secpath_put(ipc.sp);
+		ipc.sp=NULL;
+	}
+#endif
 	if (!err) {
 		UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS);
 		return len;
