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 #include #include +#include #include #include #include @@ -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<= 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;