diff -ru a/include/linux/in.h b/include/linux/in.h --- a/include/linux/in.h +++ b/include/linux/in.h @@ -77,6 +77,7 @@ #define IP_PASSSEC 18 #define IP_TRANSPARENT 19 #define IP_IPSEC_REFINFO 30 /* used with CONFIG_INET_IPSEC_SAREF */ +#define IP_IPSEC_BINDREF 31 /* BSD compatibility */ #define IP_RECVRETOPTS IP_RETOPTS diff -ru a/include/net/sock.h b/include/net/sock.h --- a/include/net/sock.h +++ b/include/net/sock.h @@ -369,6 +369,7 @@ #endif __u32 sk_mark; u32 sk_classid; + __u32 sk_saref; struct cg_proto *sk_cgrp; void (*sk_state_change)(struct sock *sk); void (*sk_data_ready)(struct sock *sk, int bytes); diff -ru a/include/net/xfrm.h b/include/net/xfrm.h --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1015,6 +1015,21 @@ extern struct sec_path *secpath_dup(struct sec_path *src); +/* + * Attach IPsec SAref value to skb, if appropriate. + */ +static inline void skb_sec_assign_sk_saref(struct sk_buff *skb, struct sock *sk) +{ +#if defined(CONFIG_XFRM) + if (sk->sk_saref) { + if (!skb->sp) + skb->sp = secpath_dup(NULL); + if (skb->sp) + skb->sp->ref = sk->sk_saref; + } +#endif +} + static inline void secpath_reset(struct sk_buff *skb) { diff -ru a/net/core/sock.c b/net/core/sock.c --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1627,6 +1627,9 @@ if (skb) { int i; + /* associate the skb with the socket's SAref */ + skb_sec_assign_sk_saref(skb, sk); + /* No pages, we're done... */ if (!data_len) break; diff -ru a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -556,6 +556,7 @@ case IP_RECVORIGDSTADDR: #ifdef CONFIG_INET_IPSEC_SAREF case IP_IPSEC_REFINFO: + case IP_IPSEC_BINDREF: #endif if (optlen >= sizeof(int)) { if (get_user(val, (int __user *) optval)) @@ -662,6 +661,9 @@ else inet->cmsg_flags &= ~IP_CMSG_IPSEC_REFINFO; break; + case IP_IPSEC_BINDREF: + sk->sk_saref = val; + break; #endif case IP_TOS: /* This sets both TOS and Precedence */ if (sk->sk_type == SOCK_STREAM) { @@ -1149,6 +1145,7 @@ optname != IP_XFRM_POLICY && #ifdef CONFIG_INET_IPSEC_SAREF optname != IP_IPSEC_REFINFO && + optname != IP_IPSEC_BINDREF && #endif !ip_mroute_opt(optname)) { lock_sock(sk); @@ -1182,6 +1177,7 @@ optname != IP_XFRM_POLICY && #ifdef CONFIG_INET_IPSEC_SAREF optname != IP_IPSEC_REFINFO && + optname != IP_IPSEC_BINDREF && #endif !ip_mroute_opt(optname)) { lock_sock(sk); @@ -1271,6 +1265,9 @@ case IP_IPSEC_REFINFO: val = (inet->cmsg_flags & IP_CMSG_IPSEC_REFINFO) != 0; break; + case IP_IPSEC_BINDREF: + val = sk->sk_saref; + break; #endif case IP_RECVORIGDSTADDR: val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0; diff -ru a/net/ipv4/tcp.c b/net/ipv4/tcp.c --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -699,6 +699,9 @@ skb = alloc_skb_fclone(size + sk->sk_prot->max_header, gfp); if (skb) { if (sk_wmem_schedule(sk, skb->truesize)) { + /* associate the skb with the socket's SAref */ + skb_sec_assign_sk_saref(skb, sk); + skb_reserve(skb, sk->sk_prot->max_header); /* * Make sure that we have exactly size bytes diff -ru a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -35,6 +35,7 @@ */ #include +#include #include #include @@ -824,6 +823,9 @@ return -ENOBUFS; } + /* associate the skb with the socket's SAref */ + skb_sec_assign_sk_saref(skb, sk); + inet = inet_sk(sk); tp = tcp_sk(sk); tcb = TCP_SKB_CB(skb); @@ -2648,6 +2644,9 @@ if (unlikely(buff == NULL)) return -ENOBUFS; + /* associate the skb with the socket's SAref */ + skb_sec_assign_sk_saref(buff, sk); + /* Reserve space for headers. */ skb_reserve(buff, MAX_TCP_HEADER);