Commit 1669cb98 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next

Steffen Klassert says:

====================
pull request (net-next): ipsec-next 2013-12-19

1) Use the user supplied policy index instead of a generated one
   if present. From Fan Du.

2) Make xfrm migration namespace aware. From Fan Du.

3) Make the xfrm state and policy locks namespace aware. From Fan Du.

4) Remove ancient sleeping when the SA is in acquire state,
   we now queue packets to the policy instead. This replaces the
   sleeping code.

5) Remove FLOWI_FLAG_CAN_SLEEP. This was used to notify xfrm about the
   posibility to sleep. The sleeping code is gone, so remove it.

6) Check user specified spi for IPComp. Thr spi for IPcomp is only
   16 bit wide, so check for a valid value. From Fan Du.

7) Export verify_userspi_info to check for valid user supplied spi ranges
   with pfkey and netlink. From Fan Du.

8) RFC3173 states that if the total size of a compressed payload and the IPComp
   header is not smaller than the size of the original payload, the IP datagram
   must be sent in the original non-compressed form. These packets are dropped
   by the inbound policy check because they are not transformed. Document the need
   to set 'level use' for IPcomp to receive such packets anyway. From Fan Du.

Please pull or let me know if there are problems.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cb4eae3d b3c6efbc
Here documents known IPsec corner cases which need to be keep in mind when
deploy various IPsec configuration in real world production environment.
1. IPcomp: Small IP packet won't get compressed at sender, and failed on
policy check on receiver.
Quote from RFC3173:
2.2. Non-Expansion Policy
If the total size of a compressed payload and the IPComp header, as
defined in section 3, is not smaller than the size of the original
payload, the IP datagram MUST be sent in the original non-compressed
form. To clarify: If an IP datagram is sent non-compressed, no
IPComp header is added to the datagram. This policy ensures saving
the decompression processing cycles and avoiding incurring IP
datagram fragmentation when the expanded datagram is larger than the
MTU.
Small IP datagrams are likely to expand as a result of compression.
Therefore, a numeric threshold should be applied before compression,
where IP datagrams of size smaller than the threshold are sent in the
original form without attempting compression. The numeric threshold
is implementation dependent.
Current IPComp implementation is indeed by the book, while as in practice
when sending non-compressed packet to the peer(whether or not packet len
is smaller than the threshold or the compressed len is large than original
packet len), the packet is dropped when checking the policy as this packet
matches the selector but not coming from any XFRM layer, i.e., with no
security path. Such naked packet will not eventually make it to upper layer.
The result is much more wired to the user when ping peer with different
payload length.
One workaround is try to set "level use" for each policy if user observed
above scenario. The consequence of doing so is small packet(uncompressed)
will skip policy checking on receiver side.
......@@ -20,8 +20,7 @@ struct flowi_common {
__u8 flowic_proto;
__u8 flowic_flags;
#define FLOWI_FLAG_ANYSRC 0x01
#define FLOWI_FLAG_CAN_SLEEP 0x02
#define FLOWI_FLAG_KNOWN_NH 0x04
#define FLOWI_FLAG_KNOWN_NH 0x02
__u32 flowic_secid;
};
......
......@@ -718,11 +718,9 @@ void ip6_flush_pending_frames(struct sock *sk);
int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6);
struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
const struct in6_addr *final_dst,
bool can_sleep);
const struct in6_addr *final_dst);
struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
const struct in6_addr *final_dst,
bool can_sleep);
const struct in6_addr *final_dst);
struct dst_entry *ip6_blackhole_route(struct net *net,
struct dst_entry *orig_dst);
......
......@@ -33,8 +33,6 @@ struct netns_xfrm {
struct hlist_head state_gc_list;
struct work_struct state_gc_work;
wait_queue_head_t km_waitq;
struct list_head policy_all;
struct hlist_head *policy_byidx;
unsigned int policy_idx_hmask;
......@@ -59,6 +57,10 @@ struct netns_xfrm {
#if IS_ENABLED(CONFIG_IPV6)
struct dst_ops xfrm6_dst_ops;
#endif
spinlock_t xfrm_state_lock;
spinlock_t xfrm_policy_sk_bundle_lock;
rwlock_t xfrm_policy_lock;
struct mutex xfrm_cfg_mutex;
};
#endif
......@@ -239,14 +239,12 @@ static inline char rt_tos2priority(u8 tos)
static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 src,
u32 tos, int oif, u8 protocol,
__be16 sport, __be16 dport,
struct sock *sk, bool can_sleep)
struct sock *sk)
{
__u8 flow_flags = 0;
if (inet_sk(sk)->transparent)
flow_flags |= FLOWI_FLAG_ANYSRC;
if (can_sleep)
flow_flags |= FLOWI_FLAG_CAN_SLEEP;
flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
protocol, flow_flags, dst, src, dport, sport);
......@@ -256,13 +254,13 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
__be32 dst, __be32 src, u32 tos,
int oif, u8 protocol,
__be16 sport, __be16 dport,
struct sock *sk, bool can_sleep)
struct sock *sk)
{
struct net *net = sock_net(sk);
struct rtable *rt;
ip_route_connect_init(fl4, dst, src, tos, oif, protocol,
sport, dport, sk, can_sleep);
sport, dport, sk);
if (!dst || !src) {
rt = __ip_route_output_key(net, fl4);
......
......@@ -53,7 +53,6 @@
#define XFRM_INC_STATS_USER(net, field) ((void)(net))
#endif
extern struct mutex xfrm_cfg_mutex;
/* Organization of SPD aka "XFRM rules"
------------------------------------
......@@ -1409,7 +1408,7 @@ static inline void xfrm_sysctl_fini(struct net *net)
void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto);
int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
int (*func)(struct xfrm_state *, int, void*), void *);
void xfrm_state_walk_done(struct xfrm_state_walk *walk);
void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net);
struct xfrm_state *xfrm_state_alloc(struct net *net);
struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr,
const xfrm_address_t *saddr,
......@@ -1436,12 +1435,12 @@ struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark,
unsigned short family);
#ifdef CONFIG_XFRM_SUB_POLICY
int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
unsigned short family);
unsigned short family, struct net *net);
int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
unsigned short family);
#else
static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src,
int n, unsigned short family)
int n, unsigned short family, struct net *net)
{
return -ENOSYS;
}
......@@ -1553,7 +1552,7 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
int (*func)(struct xfrm_policy *, int, int, void*),
void *);
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk);
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
u8 type, int dir,
......@@ -1564,6 +1563,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir,
u32 id, int delete, int *err);
int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info);
u32 xfrm_get_acqseq(void);
int verify_spi_info(u8 proto, u32 min, u32 max);
int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark,
u8 mode, u32 reqid, u8 proto,
......@@ -1576,12 +1576,12 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_bundles,
const struct xfrm_kmaddress *k);
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m);
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net);
struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
struct xfrm_migrate *m);
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_bundles,
struct xfrm_kmaddress *k);
struct xfrm_kmaddress *k, struct net *net);
#endif
int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
......
......@@ -75,7 +75,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
rt = ip_route_connect(fl4, nexthop, inet->inet_saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_DCCP,
orig_sport, orig_dport, sk, true);
orig_sport, orig_dport, sk);
if (IS_ERR(rt))
return PTR_ERR(rt);
......
......@@ -240,7 +240,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
final_p = fl6_update_dst(&fl6, np->opt, &final);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
dst = NULL;
......@@ -304,7 +304,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
/* sk = NULL, but it is safe for now. RST socket required. */
dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
if (!IS_ERR(dst)) {
skb_dst_set(skb, dst);
ip6_xmit(ctl_sk, skb, &fl6, NULL, 0);
......@@ -515,7 +515,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
fl6.fl6_sport = htons(ireq->ir_num);
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst))
goto out;
}
......@@ -934,7 +934,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
final_p = fl6_update_dst(&fl6, np->opt, &final);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
goto failure;
......
......@@ -1288,8 +1288,6 @@ int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *fl, stru
err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD);
if (err == 0 && fl->flowidn_proto) {
if (!(flags & MSG_DONTWAIT))
fl->flowidn_flags |= FLOWI_FLAG_CAN_SLEEP;
*pprt = xfrm_lookup(&init_net, *pprt,
flowidn_to_flowi(fl), sk, 0);
if (IS_ERR(*pprt)) {
......
......@@ -1130,7 +1130,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
fl4 = &inet->cork.fl.u.ip4;
rt = ip_route_connect(fl4, daddr, 0, RT_CONN_FLAGS(sk),
sk->sk_bound_dev_if, sk->sk_protocol,
inet->inet_sport, inet->inet_dport, sk, false);
inet->inet_sport, inet->inet_dport, sk);
if (IS_ERR(rt))
return PTR_ERR(rt);
......
......@@ -53,7 +53,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr,
RT_CONN_FLAGS(sk), oif,
sk->sk_protocol,
inet->inet_sport, usin->sin_port, sk, true);
inet->inet_sport, usin->sin_port, sk);
if (IS_ERR(rt)) {
err = PTR_ERR(rt);
if (err == -ENETUNREACH)
......
......@@ -575,7 +575,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
RT_SCOPE_UNIVERSE,
inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP |
inet_sk_flowi_flags(sk) |
(inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
daddr, saddr, 0, 0);
......
......@@ -173,7 +173,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
rt = ip_route_connect(fl4, nexthop, inet->inet_saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_TCP,
orig_sport, orig_dport, sk, true);
orig_sport, orig_dport, sk);
if (IS_ERR(rt)) {
err = PTR_ERR(rt);
if (err == -ENETUNREACH)
......
......@@ -986,7 +986,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
fl4 = &fl4_stack;
flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos,
RT_SCOPE_UNIVERSE, sk->sk_protocol,
inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP,
inet_sk_flowi_flags(sk),
faddr, saddr, dport, inet->inet_sport);
security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
......
......@@ -661,7 +661,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
final_p = fl6_update_dst(&fl6, np->opt, &final);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
sk->sk_route_caps = 0;
sk->sk_err_soft = -PTR_ERR(dst);
......
......@@ -170,7 +170,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
opt = flowlabel ? flowlabel->opt : np->opt;
final_p = fl6_update_dst(&fl6, opt, &final);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
err = 0;
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
......
......@@ -86,7 +86,7 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
fl6->fl6_sport = htons(ireq->ir_num);
security_req_classify_flow(req, flowi6_to_flowi(fl6));
dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
if (IS_ERR(dst))
return NULL;
......@@ -216,7 +216,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
dst = __inet6_csk_dst_check(sk, np->dst_cookie);
if (!dst) {
dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
if (!IS_ERR(dst))
__inet6_csk_dst_store(sk, dst, NULL, NULL);
......
......@@ -941,7 +941,6 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup);
* @sk: socket which provides route info
* @fl6: flow to lookup
* @final_dst: final destination address for ipsec lookup
* @can_sleep: we are in a sleepable context
*
* This function performs a route lookup on the given flow.
*
......@@ -949,8 +948,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup);
* error code.
*/
struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
const struct in6_addr *final_dst,
bool can_sleep)
const struct in6_addr *final_dst)
{
struct dst_entry *dst = NULL;
int err;
......@@ -960,8 +958,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
return ERR_PTR(err);
if (final_dst)
fl6->daddr = *final_dst;
if (can_sleep)
fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP;
return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
}
......@@ -972,7 +968,6 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
* @sk: socket which provides the dst cache and route info
* @fl6: flow to lookup
* @final_dst: final destination address for ipsec lookup
* @can_sleep: we are in a sleepable context
*
* This function performs a route lookup on the given flow with the
* possibility of using the cached route in the socket if it is valid.
......@@ -983,8 +978,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
* error code.
*/
struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
const struct in6_addr *final_dst,
bool can_sleep)
const struct in6_addr *final_dst)
{
struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
int err;
......@@ -996,8 +990,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
return ERR_PTR(err);
if (final_dst)
fl6->daddr = *final_dst;
if (can_sleep)
fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP;
return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
}
......
......@@ -145,7 +145,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
else if (!fl6.flowi6_oif)
fl6.flowi6_oif = np->ucast_oif;
dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, 1);
dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr);
if (IS_ERR(dst))
return PTR_ERR(dst);
rt = (struct rt6_info *) dst;
......
......@@ -864,7 +864,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
fl6.flowi6_oif = np->ucast_oif;
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
goto out;
......
......@@ -247,7 +247,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
fl6.fl6_sport = inet_sk(sk)->inet_sport;
security_req_classify_flow(req, flowi6_to_flowi(&fl6));
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst))
goto out_free;
}
......
......@@ -257,7 +257,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
goto failure;
......@@ -803,7 +803,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
* Underlying function will use this to retrieve the network
* namespace
*/
dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
if (!IS_ERR(dst)) {
skb_dst_set(buff, dst);
ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
......
......@@ -1223,7 +1223,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p, true);
dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
dst = NULL;
......
......@@ -1340,6 +1340,12 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_
max_spi = range->sadb_spirange_max;
}
err = verify_spi_info(x->id.proto, min_spi, max_spi);
if (err) {
xfrm_state_put(x);
return err;
}
err = xfrm_alloc_spi(x, min_spi, max_spi);
resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x);
......@@ -1380,10 +1386,9 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, const struct sadb
return 0;
spin_lock_bh(&x->lock);
if (x->km.state == XFRM_STATE_ACQ) {
if (x->km.state == XFRM_STATE_ACQ)
x->km.state = XFRM_STATE_ERROR;
wake_up(&net->xfrm.km_waitq);
}
spin_unlock_bh(&x->lock);
xfrm_state_put(x);
return 0;
......@@ -1785,7 +1790,9 @@ static int pfkey_dump_sa(struct pfkey_sock *pfk)
static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
{
xfrm_state_walk_done(&pfk->dump.u.state);
struct net *net = sock_net(&pfk->sk);
xfrm_state_walk_done(&pfk->dump.u.state, net);
}
static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
......@@ -1861,7 +1868,7 @@ static u32 gen_reqid(struct net *net)
reqid = IPSEC_MANUAL_REQID_MAX+1;
xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid);
xfrm_policy_walk_done(&walk);
xfrm_policy_walk_done(&walk, net);
if (rc != -EEXIST)
return reqid;
} while (reqid != start);
......@@ -2485,6 +2492,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
struct xfrm_selector sel;
struct xfrm_migrate m[XFRM_MAX_DEPTH];
struct xfrm_kmaddress k;
struct net *net = sock_net(sk);
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1],
ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
......@@ -2558,7 +2566,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
}
return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
kma ? &k : NULL);
kma ? &k : NULL, net);
out:
return err;
......@@ -2659,7 +2667,9 @@ static int pfkey_dump_sp(struct pfkey_sock *pfk)
static void pfkey_dump_sp_done(struct pfkey_sock *pfk)
{
xfrm_policy_walk_done(&pfk->dump.u.policy);
struct net *net = sock_net((struct sock *)pfk);
xfrm_policy_walk_done(&pfk->dump.u.policy, net);
}
static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
......@@ -3569,6 +3579,7 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
struct sk_buff *skb = NULL;
struct sadb_msg *hdr = NULL;
int err;
struct net *net = sock_net(sk);
err = -EOPNOTSUPP;
if (msg->msg_flags & MSG_OOB)
......@@ -3591,9 +3602,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
if (!hdr)
goto out;
mutex_lock(&xfrm_cfg_mutex);
mutex_lock(&net->xfrm.xfrm_cfg_mutex);
err = pfkey_process(sk, skb, hdr);
mutex_unlock(&xfrm_cfg_mutex);
mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
out:
if (err && hdr && pfkey_error(hdr, err, sk) == 0)
......
......@@ -597,7 +597,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
goto out;
......
......@@ -262,7 +262,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
}
final_p = fl6_update_dst(fl6, np->opt, &final);
dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
if (!asoc || saddr)
goto out;
......@@ -321,7 +321,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
fl6->saddr = baddr->v6.sin6_addr;
fl6->fl6_sport = baddr->v6.sin6_port;
final_p = fl6_update_dst(fl6, np->opt, &final);
dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
}
out:
......
......@@ -39,12 +39,7 @@
#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
#define XFRM_MAX_QUEUE_LEN 100
DEFINE_MUTEX(xfrm_cfg_mutex);
EXPORT_SYMBOL(xfrm_cfg_mutex);
static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock);
static struct dst_entry *xfrm_policy_sk_bundles;
static DEFINE_RWLOCK(xfrm_policy_lock);
static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
......@@ -438,7 +433,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
if (!ndst)
return;
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
for (i = hmask; i >= 0; i--)
xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
......@@ -446,7 +441,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
net->xfrm.policy_bydst[dir].table = ndst;
net->xfrm.policy_bydst[dir].hmask = nhashmask;
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
}
......@@ -463,7 +458,7 @@ static void xfrm_byidx_resize(struct net *net, int total)
if (!nidx)
return;
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
for (i = hmask; i >= 0; i--)
xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
......@@ -471,7 +466,7 @@ static void xfrm_byidx_resize(struct net *net, int total)
net->xfrm.policy_byidx = nidx;
net->xfrm.policy_idx_hmask = nhashmask;
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
}
......@@ -504,7 +499,7 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total)
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
{
read_lock_bh(&xfrm_policy_lock);
read_lock_bh(&net->xfrm.xfrm_policy_lock);
si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN];
si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT];
si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD];
......@@ -513,7 +508,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
si->spdhcnt = net->xfrm.policy_idx_hmask;
si->spdhmcnt = xfrm_policy_hashmax;
read_unlock_bh(&xfrm_policy_lock);
read_unlock_bh(&net->xfrm.xfrm_policy_lock);
}
EXPORT_SYMBOL(xfrm_spd_getinfo);
......@@ -538,7 +533,7 @@ static void xfrm_hash_resize(struct work_struct *work)
/* Generate new index... KAME seems to generate them ordered by cost
* of an absolute inpredictability of ordering of rules. This will not pass. */
static u32 xfrm_gen_index(struct net *net, int dir)
static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
{
static u32 idx_generator;
......@@ -548,8 +543,14 @@ static u32 xfrm_gen_index(struct net *net, int dir)
u32 idx;
int found;
if (!index) {
idx = (idx_generator | dir);
idx_generator += 8;
} else {
idx = index;
index = 0;
}
if (idx == 0)
idx = 8;
list = net->xfrm.policy_byidx + idx_hash(net, idx);
......@@ -630,7 +631,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
struct hlist_head *chain;
struct hlist_node *newpos;
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
delpol = NULL;
newpos = NULL;
......@@ -641,7 +642,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
xfrm_sec_ctx_match(pol->security, policy->security) &&
!WARN_ON(delpol)) {
if (excl) {
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return -EEXIST;
}
delpol = pol;
......@@ -672,14 +673,14 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
xfrm_policy_requeue(delpol, policy);
__xfrm_policy_unlink(delpol, dir);
}
policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir);
policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index);
hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
policy->curlft.add_time = get_seconds();
policy->curlft.use_time = 0;
if (!mod_timer(&policy->timer, jiffies + HZ))
xfrm_pol_hold(policy);
list_add(&policy->walk.all, &net->xfrm.policy_all);
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (delpol)
xfrm_policy_kill(delpol);
......@@ -699,7 +700,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
struct hlist_head *chain;
*err = 0;
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, sel, sel->family, dir);
ret = NULL;
hlist_for_each_entry(pol, chain, bydst) {
......@@ -712,7 +713,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
*err = security_xfrm_policy_delete(
pol->security);
if (*err) {
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol;
}
__xfrm_policy_unlink(pol, dir);
......@@ -721,7 +722,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
break;
}
}
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete)
xfrm_policy_kill(ret);
......@@ -740,7 +741,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
return NULL;
*err = 0;
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = net->xfrm.policy_byidx + idx_hash(net, id);
ret = NULL;
hlist_for_each_entry(pol, chain, byidx) {
......@@ -751,7 +752,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
*err = security_xfrm_policy_delete(
pol->security);
if (*err) {
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol;
}
__xfrm_policy_unlink(pol, dir);
......@@ -760,7 +761,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
break;
}
}
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete)
xfrm_policy_kill(ret);
......@@ -823,7 +824,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
{
int dir, err = 0, cnt = 0;
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
err = xfrm_policy_flush_secctx_check(net, type, audit_info);
if (err)
......@@ -839,7 +840,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (pol->type != type)
continue;
__xfrm_policy_unlink(pol, dir);
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
cnt++;
xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
......@@ -848,7 +849,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
xfrm_policy_kill(pol);
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
goto again1;
}
......@@ -860,7 +861,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (pol->type != type)
continue;
__xfrm_policy_unlink(pol, dir);
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
cnt++;
xfrm_audit_policy_delete(pol, 1,
......@@ -869,7 +870,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
audit_info->secid);
xfrm_policy_kill(pol);
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
goto again2;
}
}
......@@ -878,7 +879,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (!cnt)
err = -ESRCH;
out:
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return err;
}
EXPORT_SYMBOL(xfrm_policy_flush);
......@@ -898,7 +899,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
if (list_empty(&walk->walk.all) && walk->seq != 0)
return 0;
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
if (list_empty(&walk->walk.all))
x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
else
......@@ -924,7 +925,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
}
list_del_init(&walk->walk.all);
out:
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return error;
}
EXPORT_SYMBOL(xfrm_policy_walk);
......@@ -938,14 +939,14 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
}
EXPORT_SYMBOL(xfrm_policy_walk_init);
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net)
{
if (list_empty(&walk->walk.all))
return;
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */
list_del(&walk->walk.all);
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
}
EXPORT_SYMBOL(xfrm_policy_walk_done);
......@@ -990,7 +991,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
if (unlikely(!daddr || !saddr))
return NULL;
read_lock_bh(&xfrm_policy_lock);
read_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_direct(net, daddr, saddr, family, dir);
ret = NULL;
hlist_for_each_entry(pol, chain, bydst) {
......@@ -1026,7 +1027,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
if (ret)
xfrm_pol_hold(ret);
fail:
read_unlock_bh(&xfrm_policy_lock);
read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return ret;
}
......@@ -1103,8 +1104,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
const struct flowi *fl)
{
struct xfrm_policy *pol;
struct net *net = sock_net(sk);
read_lock_bh(&xfrm_policy_lock);
read_lock_bh(&net->xfrm.xfrm_policy_lock);
if ((pol = sk->sk_policy[dir]) != NULL) {
bool match = xfrm_selector_match(&pol->selector, fl,
sk->sk_family);
......@@ -1128,7 +1130,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
pol = NULL;
}
out:
read_unlock_bh(&xfrm_policy_lock);
read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol;
}
......@@ -1166,9 +1168,11 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
{
write_lock_bh(&xfrm_policy_lock);
struct net *net = xp_net(pol);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
pol = __xfrm_policy_unlink(pol, dir);
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (pol) {
xfrm_policy_kill(pol);
return 0;
......@@ -1187,12 +1191,12 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
return -EINVAL;
#endif
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
old_pol = sk->sk_policy[dir];
sk->sk_policy[dir] = pol;
if (pol) {
pol->curlft.add_time = get_seconds();
pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir);
pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
__xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
}
if (old_pol) {
......@@ -1204,7 +1208,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
*/
__xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir);
}
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (old_pol) {
xfrm_policy_kill(old_pol);
......@@ -1215,6 +1219,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
{
struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC);
struct net *net = xp_net(old);
if (newp) {
newp->selector = old->selector;
......@@ -1233,9 +1238,9 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
newp->type = old->type;
memcpy(newp->xfrm_vec, old->xfrm_vec,
newp->xfrm_nr*sizeof(struct xfrm_tmpl));
write_lock_bh(&xfrm_policy_lock);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
__xfrm_policy_link(newp, XFRM_POLICY_MAX+dir);
write_unlock_bh(&xfrm_policy_lock);
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_pol_put(newp);
}
return newp;
......@@ -1896,8 +1901,7 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
if (IS_ERR(xdst))
return xdst;
if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0 ||
(fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP))
if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0)
return xdst;
dst1 = &xdst->u.dst;
......@@ -2072,7 +2076,6 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
restart:
dst = NULL;
xdst = NULL;
route = NULL;
......@@ -2106,10 +2109,10 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
dst_hold(&xdst->u.dst);
spin_lock_bh(&xfrm_policy_sk_bundle_lock);
spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
xdst->u.dst.next = xfrm_policy_sk_bundles;
xfrm_policy_sk_bundles = &xdst->u.dst;
spin_unlock_bh(&xfrm_policy_sk_bundle_lock);
spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
route = xdst->route;
}
......@@ -2152,22 +2155,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
return make_blackhole(net, family, dst_orig);
}
if (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP) {
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&net->xfrm.km_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
set_current_state(TASK_RUNNING);
remove_wait_queue(&net->xfrm.km_waitq, &wait);
if (!signal_pending(current)) {
dst_release(dst);
goto restart;
}
err = -ERESTART;
} else
err = -EAGAIN;
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
......@@ -2434,7 +2422,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
}
xfrm_nr = ti;
if (npols > 1) {
xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net);
tpp = stp;
}
......@@ -2563,10 +2551,10 @@ static void __xfrm_garbage_collect(struct net *net)
{
struct dst_entry *head, *next;
spin_lock_bh(&xfrm_policy_sk_bundle_lock);
spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
head = xfrm_policy_sk_bundles;
xfrm_policy_sk_bundles = NULL;
spin_unlock_bh(&xfrm_policy_sk_bundle_lock);
spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
while (head) {
next = head->next;
......@@ -2950,6 +2938,13 @@ static int __net_init xfrm_net_init(struct net *net)
rv = xfrm_sysctl_init(net);
if (rv < 0)
goto out_sysctl;
/* Initialize the per-net locks here */
spin_lock_init(&net->xfrm.xfrm_state_lock);
rwlock_init(&net->xfrm.xfrm_policy_lock);
spin_lock_init(&net->xfrm.xfrm_policy_sk_bundle_lock);
mutex_init(&net->xfrm.xfrm_cfg_mutex);
return 0;
out_sysctl:
......@@ -3070,14 +3065,14 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
}
static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector *sel,
u8 dir, u8 type)
u8 dir, u8 type, struct net *net)
{
struct xfrm_policy *pol, *ret = NULL;
struct hlist_head *chain;
u32 priority = ~0U;
read_lock_bh(&xfrm_policy_lock);
chain = policy_hash_direct(&init_net, &sel->daddr, &sel->saddr, sel->family, dir);
read_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME*/
chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
hlist_for_each_entry(pol, chain, bydst) {
if (xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type) {
......@@ -3086,7 +3081,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
break;
}
}
chain = &init_net.xfrm.policy_inexact[dir];
chain = &net->xfrm.policy_inexact[dir];
hlist_for_each_entry(pol, chain, bydst) {
if (xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type &&
......@@ -3099,7 +3094,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
if (ret)
xfrm_pol_hold(ret);
read_unlock_bh(&xfrm_policy_lock);
read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return ret;
}
......@@ -3210,7 +3205,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_migrate,
struct xfrm_kmaddress *k)
struct xfrm_kmaddress *k, struct net *net)
{
int i, err, nx_cur = 0, nx_new = 0;
struct xfrm_policy *pol = NULL;
......@@ -3223,14 +3218,14 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
goto out;
/* Stage 1 - find policy */
if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) {
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
err = -ENOENT;
goto out;
}
/* Stage 2 - find and update state(s) */
for (i = 0, mp = m; i < num_migrate; i++, mp++) {
if ((x = xfrm_migrate_state_find(mp))) {
if ((x = xfrm_migrate_state_find(mp, net))) {
x_cur[nx_cur] = x;
nx_cur++;
if ((xc = xfrm_state_migrate(x, mp))) {
......
......@@ -35,8 +35,6 @@
destination/tunnel endpoint. (output)
*/
static DEFINE_SPINLOCK(xfrm_state_lock);
static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
static inline unsigned int xfrm_dst_hash(struct net *net,
......@@ -127,7 +125,7 @@ static void xfrm_hash_resize(struct work_struct *work)
goto out_unlock;
}
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
for (i = net->xfrm.state_hmask; i >= 0; i--)
......@@ -144,7 +142,7 @@ static void xfrm_hash_resize(struct work_struct *work)
net->xfrm.state_byspi = nspi;
net->xfrm.state_hmask = nhashmask;
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
osize = (ohashmask + 1) * sizeof(struct hlist_head);
xfrm_hash_free(odst, osize);
......@@ -374,8 +372,6 @@ static void xfrm_state_gc_task(struct work_struct *work)
hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
xfrm_state_gc_destroy(x);
wake_up(&net->xfrm.km_waitq);
}
static inline unsigned long make_jiffies(long secs)
......@@ -390,7 +386,6 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
{
struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer);
struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer);
struct net *net = xs_net(x);
unsigned long now = get_seconds();
long next = LONG_MAX;
int warn = 0;
......@@ -460,12 +455,8 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
goto out;
expired:
if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0)
x->km.state = XFRM_STATE_EXPIRED;
wake_up(&net->xfrm.km_waitq);
next = 2;
goto resched;
}
err = __xfrm_state_delete(x);
if (!err)
......@@ -535,14 +526,14 @@ int __xfrm_state_delete(struct xfrm_state *x)
if (x->km.state != XFRM_STATE_DEAD) {
x->km.state = XFRM_STATE_DEAD;
spin_lock(&xfrm_state_lock);
spin_lock(&net->xfrm.xfrm_state_lock);
list_del(&x->km.all);
hlist_del(&x->bydst);
hlist_del(&x->bysrc);
if (x->id.spi)
hlist_del(&x->byspi);
net->xfrm.state_num--;
spin_unlock(&xfrm_state_lock);
spin_unlock(&net->xfrm.xfrm_state_lock);
/* All xfrm_state objects are created by xfrm_state_alloc.
* The xfrm_state_alloc call gives a reference, and that
......@@ -603,7 +594,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
{
int i, err = 0, cnt = 0;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
err = xfrm_state_flush_secctx_check(net, proto, audit_info);
if (err)
goto out;
......@@ -616,7 +607,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
if (!xfrm_state_kern(x) &&
xfrm_id_proto_match(x->id.proto, proto)) {
xfrm_state_hold(x);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
err = xfrm_state_delete(x);
xfrm_audit_state_delete(x, err ? 0 : 1,
......@@ -627,7 +618,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
if (!err)
cnt++;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
goto restart;
}
}
......@@ -636,19 +627,18 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
err = 0;
out:
spin_unlock_bh(&xfrm_state_lock);
wake_up(&net->xfrm.km_waitq);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return err;
}
EXPORT_SYMBOL(xfrm_state_flush);
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si)
{
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
si->sadcnt = net->xfrm.state_num;
si->sadhcnt = net->xfrm.state_hmask;
si->sadhmcnt = xfrm_state_hashmax;
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
}
EXPORT_SYMBOL(xfrm_sad_getinfo);
......@@ -801,7 +791,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
to_put = NULL;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.family == encap_family &&
......@@ -886,7 +876,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
xfrm_state_hold(x);
else
*err = acquire_in_progress ? -EAGAIN : error;
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (to_put)
xfrm_state_put(to_put);
return x;
......@@ -900,7 +890,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
unsigned int h;
struct xfrm_state *rx = NULL, *x = NULL;
spin_lock(&xfrm_state_lock);
spin_lock(&net->xfrm.xfrm_state_lock);
h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.family == family &&
......@@ -918,7 +908,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
if (rx)
xfrm_state_hold(rx);
spin_unlock(&xfrm_state_lock);
spin_unlock(&net->xfrm.xfrm_state_lock);
return rx;
......@@ -950,14 +940,12 @@ static void __xfrm_state_insert(struct xfrm_state *x)
if (x->replay_maxage)
mod_timer(&x->rtimer, jiffies + x->replay_maxage);
wake_up(&net->xfrm.km_waitq);
net->xfrm.state_num++;
xfrm_hash_grow_check(net, x->bydst.next != NULL);
}
/* xfrm_state_lock is held */
/* net->xfrm.xfrm_state_lock is held */
static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
{
struct net *net = xs_net(xnew);
......@@ -980,14 +968,16 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
void xfrm_state_insert(struct xfrm_state *x)
{
spin_lock_bh(&xfrm_state_lock);
struct net *net = xs_net(x);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
__xfrm_state_bump_genids(x);
__xfrm_state_insert(x);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
}
EXPORT_SYMBOL(xfrm_state_insert);
/* xfrm_state_lock is held */
/* net->xfrm.xfrm_state_lock is held */
static struct xfrm_state *__find_acq_core(struct net *net,
const struct xfrm_mark *m,
unsigned short family, u8 mode,
......@@ -1079,7 +1069,7 @@ int xfrm_state_add(struct xfrm_state *x)
to_put = NULL;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
x1 = __xfrm_state_locate(x, use_spi, family);
if (x1) {
......@@ -1108,7 +1098,7 @@ int xfrm_state_add(struct xfrm_state *x)
err = 0;
out:
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (x1) {
xfrm_state_delete(x1);
......@@ -1203,16 +1193,16 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
return NULL;
}
/* xfrm_state_lock is held */
struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
/* net->xfrm.xfrm_state_lock is held */
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
{
unsigned int h;
struct xfrm_state *x;
if (m->reqid) {
h = xfrm_dst_hash(&init_net, &m->old_daddr, &m->old_saddr,
h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
m->reqid, m->old_family);
hlist_for_each_entry(x, init_net.xfrm.state_bydst+h, bydst) {
hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.mode != m->mode ||
x->id.proto != m->proto)
continue;
......@@ -1227,9 +1217,9 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
return x;
}
} else {
h = xfrm_src_hash(&init_net, &m->old_daddr, &m->old_saddr,
h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
m->old_family);
hlist_for_each_entry(x, init_net.xfrm.state_bysrc+h, bysrc) {
hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) {
if (x->props.mode != m->mode ||
x->id.proto != m->proto)
continue;
......@@ -1283,10 +1273,11 @@ int xfrm_state_update(struct xfrm_state *x)
struct xfrm_state *x1, *to_put;
int err;
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
struct net *net = xs_net(x);
to_put = NULL;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
x1 = __xfrm_state_locate(x, use_spi, x->props.family);
err = -ESRCH;
......@@ -1306,7 +1297,7 @@ int xfrm_state_update(struct xfrm_state *x)
err = 0;
out:
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (to_put)
xfrm_state_put(to_put);
......@@ -1377,9 +1368,9 @@ xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32
{
struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x;
}
EXPORT_SYMBOL(xfrm_state_lookup);
......@@ -1391,9 +1382,9 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark,
{
struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x;
}
EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
......@@ -1405,9 +1396,9 @@ xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
{
struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x;
}
......@@ -1416,17 +1407,17 @@ EXPORT_SYMBOL(xfrm_find_acq);
#ifdef CONFIG_XFRM_SUB_POLICY
int
xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
unsigned short family)
unsigned short family, struct net *net)
{
int err = 0;
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
if (!afinfo)
return -EAFNOSUPPORT;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/
if (afinfo->tmpl_sort)
err = afinfo->tmpl_sort(dst, src, n);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
xfrm_state_put_afinfo(afinfo);
return err;
}
......@@ -1438,13 +1429,15 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
{
int err = 0;
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
struct net *net = xs_net(*dst);
if (!afinfo)
return -EAFNOSUPPORT;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
if (afinfo->state_sort)
err = afinfo->state_sort(dst, src, n);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
xfrm_state_put_afinfo(afinfo);
return err;
}
......@@ -1476,9 +1469,9 @@ struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
{
struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __xfrm_find_acq_byseq(net, mark, seq);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x;
}
EXPORT_SYMBOL(xfrm_find_acq_byseq);
......@@ -1496,6 +1489,30 @@ u32 xfrm_get_acqseq(void)
}
EXPORT_SYMBOL(xfrm_get_acqseq);
int verify_spi_info(u8 proto, u32 min, u32 max)
{
switch (proto) {
case IPPROTO_AH:
case IPPROTO_ESP:
break;
case IPPROTO_COMP:
/* IPCOMP spi is 16-bits. */
if (max >= 0x10000)
return -EINVAL;
break;
default:
return -EINVAL;
}
if (min > max)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL(verify_spi_info);
int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
{
struct net *net = xs_net(x);
......@@ -1536,10 +1553,10 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
}
}
if (x->id.spi) {
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
err = 0;
}
......@@ -1562,7 +1579,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
if (walk->seq != 0 && list_empty(&walk->all))
return 0;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
if (list_empty(&walk->all))
x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
else
......@@ -1586,7 +1603,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
}
list_del_init(&walk->all);
out:
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return err;
}
EXPORT_SYMBOL(xfrm_state_walk);
......@@ -1600,14 +1617,14 @@ void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
}
EXPORT_SYMBOL(xfrm_state_walk_init);
void xfrm_state_walk_done(struct xfrm_state_walk *walk)
void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net)
{
if (list_empty(&walk->all))
return;
spin_lock_bh(&xfrm_state_lock);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
list_del(&walk->all);
spin_unlock_bh(&xfrm_state_lock);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
}
EXPORT_SYMBOL(xfrm_state_walk_done);
......@@ -1655,16 +1672,12 @@ EXPORT_SYMBOL(km_state_notify);
void km_state_expired(struct xfrm_state *x, int hard, u32 portid)
{
struct net *net = xs_net(x);
struct km_event c;
c.data.hard = hard;
c.portid = portid;
c.event = XFRM_MSG_EXPIRE;
km_state_notify(x, &c);
if (hard)
wake_up(&net->xfrm.km_waitq);
}
EXPORT_SYMBOL(km_state_expired);
......@@ -1707,16 +1720,12 @@ EXPORT_SYMBOL(km_new_mapping);
void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid)
{
struct net *net = xp_net(pol);
struct km_event c;
c.data.hard = hard;
c.portid = portid;
c.event = XFRM_MSG_POLEXPIRE;
km_policy_notify(pol, dir, &c);
if (hard)
wake_up(&net->xfrm.km_waitq);
}
EXPORT_SYMBOL(km_policy_expired);
......@@ -2025,7 +2034,7 @@ int __net_init xfrm_state_init(struct net *net)
INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
init_waitqueue_head(&net->xfrm.km_waitq);
spin_lock_init(&net->xfrm.xfrm_state_lock);
return 0;
out_byspi:
......
......@@ -181,7 +181,9 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_ALG_COMP] ||
attrs[XFRMA_TFCPAD])
attrs[XFRMA_TFCPAD] ||
(ntohl(p->id.spi) >= 0x10000))
goto out;
break;
......@@ -877,7 +879,10 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
static int xfrm_dump_sa_done(struct netlink_callback *cb)
{
struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
xfrm_state_walk_done(walk);
struct sock *sk = cb->skb->sk;
struct net *net = sock_net(sk);
xfrm_state_walk_done(walk, net);
return 0;
}
......@@ -1074,29 +1079,6 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
return err;
}
static int verify_userspi_info(struct xfrm_userspi_info *p)
{
switch (p->info.id.proto) {
case IPPROTO_AH:
case IPPROTO_ESP:
break;
case IPPROTO_COMP:
/* IPCOMP spi is 16-bits. */
if (p->max >= 0x10000)
return -EINVAL;
break;
default:
return -EINVAL;
}
if (p->min > p->max)
return -EINVAL;
return 0;
}
static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
{
......@@ -1111,7 +1093,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
struct xfrm_mark m;
p = nlmsg_data(nlh);
err = verify_userspi_info(p);
err = verify_spi_info(p->info.id.proto, p->min, p->max);
if (err)
goto out_noput;
......@@ -1189,6 +1171,8 @@ static int verify_policy_type(u8 type)
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
{
int ret;
switch (p->share) {
case XFRM_SHARE_ANY:
case XFRM_SHARE_SESSION:
......@@ -1224,7 +1208,13 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
return -EINVAL;
}
return verify_policy_dir(p->dir);
ret = verify_policy_dir(p->dir);
if (ret)
return ret;
if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir))
return -EINVAL;
return 0;
}
static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs)
......@@ -1547,8 +1537,9 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
static int xfrm_dump_policy_done(struct netlink_callback *cb)
{
struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
struct net *net = sock_net(cb->skb->sk);
xfrm_policy_walk_done(walk);
xfrm_policy_walk_done(walk, net);
return 0;
}
......@@ -2129,6 +2120,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
u8 type;
int err;
int n = 0;
struct net *net = sock_net(skb->sk);
if (attrs[XFRMA_MIGRATE] == NULL)
return -EINVAL;
......@@ -2146,7 +2138,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!n)
return 0;
xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp);
xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net);
return 0;
}
......@@ -2394,9 +2386,11 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
static void xfrm_netlink_rcv(struct sk_buff *skb)
{
mutex_lock(&xfrm_cfg_mutex);
struct net *net = sock_net(skb->sk);
mutex_lock(&net->xfrm.xfrm_cfg_mutex);
netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
mutex_unlock(&xfrm_cfg_mutex);
mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
}
static inline size_t xfrm_expire_msgsize(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment