diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2018-06-12 08:07:07 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2018-06-23 10:07:15 -0400 |
commit | 7e6526404adedf079279aa7aa11722deaca8fe2e (patch) | |
tree | 64a7db3916d2f5bf24dfd17f495f27eb9cc1beca | |
parent | d159ce7957eec306eacda672e5909e26675ca8ef (diff) |
xfrm: Add a new lookup key to match xfrm interfaces.
This patch adds the xfrm interface id as a lookup key
for xfrm states and policies. With this we can assign
states and policies to virtual xfrm interfaces.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Acked-by: Shannon Nelson <shannon.nelson@oracle.com>
Acked-by: Benedict Wong <benedictwong@google.com>
Tested-by: Benedict Wong <benedictwong@google.com>
Tested-by: Antony Antony <antony@phenome.org>
Reviewed-by: Eyal Birger <eyal.birger@gmail.com>
-rw-r--r-- | include/net/xfrm.h | 21 | ||||
-rw-r--r-- | include/uapi/linux/xfrm.h | 1 | ||||
-rw-r--r-- | net/core/pktgen.c | 2 | ||||
-rw-r--r-- | net/key/af_key.c | 6 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 18 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 19 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 54 |
7 files changed, 96 insertions, 25 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 3dc83ba26f62..e8bada4d2a45 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -147,6 +147,7 @@ struct xfrm_state { | |||
147 | struct xfrm_id id; | 147 | struct xfrm_id id; |
148 | struct xfrm_selector sel; | 148 | struct xfrm_selector sel; |
149 | struct xfrm_mark mark; | 149 | struct xfrm_mark mark; |
150 | u32 if_id; | ||
150 | u32 tfcpad; | 151 | u32 tfcpad; |
151 | 152 | ||
152 | u32 genid; | 153 | u32 genid; |
@@ -574,6 +575,7 @@ struct xfrm_policy { | |||
574 | atomic_t genid; | 575 | atomic_t genid; |
575 | u32 priority; | 576 | u32 priority; |
576 | u32 index; | 577 | u32 index; |
578 | u32 if_id; | ||
577 | struct xfrm_mark mark; | 579 | struct xfrm_mark mark; |
578 | struct xfrm_selector selector; | 580 | struct xfrm_selector selector; |
579 | struct xfrm_lifetime_cfg lft; | 581 | struct xfrm_lifetime_cfg lft; |
@@ -1533,7 +1535,7 @@ struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr, | |||
1533 | struct xfrm_tmpl *tmpl, | 1535 | struct xfrm_tmpl *tmpl, |
1534 | struct xfrm_policy *pol, int *err, | 1536 | struct xfrm_policy *pol, int *err, |
1535 | unsigned short family); | 1537 | unsigned short family); |
1536 | struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, | 1538 | struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, |
1537 | xfrm_address_t *daddr, | 1539 | xfrm_address_t *daddr, |
1538 | xfrm_address_t *saddr, | 1540 | xfrm_address_t *saddr, |
1539 | unsigned short family, | 1541 | unsigned short family, |
@@ -1690,20 +1692,20 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, | |||
1690 | void *); | 1692 | void *); |
1691 | void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net); | 1693 | void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net); |
1692 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); | 1694 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); |
1693 | struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, | 1695 | struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id, |
1694 | u8 type, int dir, | 1696 | u8 type, int dir, |
1695 | struct xfrm_selector *sel, | 1697 | struct xfrm_selector *sel, |
1696 | struct xfrm_sec_ctx *ctx, int delete, | 1698 | struct xfrm_sec_ctx *ctx, int delete, |
1697 | int *err); | 1699 | int *err); |
1698 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, | 1700 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u32 if_id, u8, |
1699 | u32 id, int delete, int *err); | 1701 | int dir, u32 id, int delete, int *err); |
1700 | int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); | 1702 | int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); |
1701 | void xfrm_policy_hash_rebuild(struct net *net); | 1703 | void xfrm_policy_hash_rebuild(struct net *net); |
1702 | u32 xfrm_get_acqseq(void); | 1704 | u32 xfrm_get_acqseq(void); |
1703 | int verify_spi_info(u8 proto, u32 min, u32 max); | 1705 | int verify_spi_info(u8 proto, u32 min, u32 max); |
1704 | int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); | 1706 | int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); |
1705 | struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, | 1707 | struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, |
1706 | u8 mode, u32 reqid, u8 proto, | 1708 | u8 mode, u32 reqid, u32 if_id, u8 proto, |
1707 | const xfrm_address_t *daddr, | 1709 | const xfrm_address_t *daddr, |
1708 | const xfrm_address_t *saddr, int create, | 1710 | const xfrm_address_t *saddr, int create, |
1709 | unsigned short family); | 1711 | unsigned short family); |
@@ -2019,6 +2021,15 @@ static inline __u32 xfrm_smark_get(__u32 mark, struct xfrm_state *x) | |||
2019 | return (m->v & m->m) | (mark & ~m->m); | 2021 | return (m->v & m->m) | (mark & ~m->m); |
2020 | } | 2022 | } |
2021 | 2023 | ||
2024 | static inline int xfrm_if_id_put(struct sk_buff *skb, __u32 if_id) | ||
2025 | { | ||
2026 | int ret = 0; | ||
2027 | |||
2028 | if (if_id) | ||
2029 | ret = nla_put_u32(skb, XFRMA_IF_ID, if_id); | ||
2030 | return ret; | ||
2031 | } | ||
2032 | |||
2022 | static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, | 2033 | static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, |
2023 | unsigned int family) | 2034 | unsigned int family) |
2024 | { | 2035 | { |
diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index 5a6ed7ce5a29..5f3b9fec7b5f 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h | |||
@@ -307,6 +307,7 @@ enum xfrm_attr_type_t { | |||
307 | XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ | 307 | XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ |
308 | XFRMA_SET_MARK, /* __u32 */ | 308 | XFRMA_SET_MARK, /* __u32 */ |
309 | XFRMA_SET_MARK_MASK, /* __u32 */ | 309 | XFRMA_SET_MARK_MASK, /* __u32 */ |
310 | XFRMA_IF_ID, /* __u32 */ | ||
310 | __XFRMA_MAX | 311 | __XFRMA_MAX |
311 | 312 | ||
312 | #define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ | 313 | #define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 49368e21d228..6d37dbf0aa64 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -2255,7 +2255,7 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) | |||
2255 | x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); | 2255 | x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); |
2256 | } else { | 2256 | } else { |
2257 | /* slow path: we dont already have xfrm_state */ | 2257 | /* slow path: we dont already have xfrm_state */ |
2258 | x = xfrm_stateonly_find(pn->net, DUMMY_MARK, | 2258 | x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 0, |
2259 | (xfrm_address_t *)&pkt_dev->cur_daddr, | 2259 | (xfrm_address_t *)&pkt_dev->cur_daddr, |
2260 | (xfrm_address_t *)&pkt_dev->cur_saddr, | 2260 | (xfrm_address_t *)&pkt_dev->cur_saddr, |
2261 | AF_INET, | 2261 | AF_INET, |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 8bdc1cbe490a..398ebcd614a0 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -1383,7 +1383,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_ | |||
1383 | } | 1383 | } |
1384 | 1384 | ||
1385 | if (!x) | 1385 | if (!x) |
1386 | x = xfrm_find_acq(net, &dummy_mark, mode, reqid, proto, xdaddr, xsaddr, 1, family); | 1386 | x = xfrm_find_acq(net, &dummy_mark, mode, reqid, 0, proto, xdaddr, xsaddr, 1, family); |
1387 | 1387 | ||
1388 | if (x == NULL) | 1388 | if (x == NULL) |
1389 | return -ENOENT; | 1389 | return -ENOENT; |
@@ -2414,7 +2414,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa | |||
2414 | return err; | 2414 | return err; |
2415 | } | 2415 | } |
2416 | 2416 | ||
2417 | xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN, | 2417 | xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, 0, XFRM_POLICY_TYPE_MAIN, |
2418 | pol->sadb_x_policy_dir - 1, &sel, pol_ctx, | 2418 | pol->sadb_x_policy_dir - 1, &sel, pol_ctx, |
2419 | 1, &err); | 2419 | 1, &err); |
2420 | security_xfrm_policy_free(pol_ctx); | 2420 | security_xfrm_policy_free(pol_ctx); |
@@ -2663,7 +2663,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, const struct sadb_ | |||
2663 | return -EINVAL; | 2663 | return -EINVAL; |
2664 | 2664 | ||
2665 | delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2); | 2665 | delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2); |
2666 | xp = xfrm_policy_byid(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN, | 2666 | xp = xfrm_policy_byid(net, DUMMY_MARK, 0, XFRM_POLICY_TYPE_MAIN, |
2667 | dir, pol->sadb_x_policy_id, delete, &err); | 2667 | dir, pol->sadb_x_policy_id, delete, &err); |
2668 | if (xp == NULL) | 2668 | if (xp == NULL) |
2669 | return -ENOENT; | 2669 | return -ENOENT; |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 7637637717ec..fc0c69312b2c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -747,6 +747,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
747 | newpos = NULL; | 747 | newpos = NULL; |
748 | hlist_for_each_entry(pol, chain, bydst) { | 748 | hlist_for_each_entry(pol, chain, bydst) { |
749 | if (pol->type == policy->type && | 749 | if (pol->type == policy->type && |
750 | pol->if_id == policy->if_id && | ||
750 | !selector_cmp(&pol->selector, &policy->selector) && | 751 | !selector_cmp(&pol->selector, &policy->selector) && |
751 | xfrm_policy_mark_match(policy, pol) && | 752 | xfrm_policy_mark_match(policy, pol) && |
752 | xfrm_sec_ctx_match(pol->security, policy->security) && | 753 | xfrm_sec_ctx_match(pol->security, policy->security) && |
@@ -798,8 +799,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
798 | } | 799 | } |
799 | EXPORT_SYMBOL(xfrm_policy_insert); | 800 | EXPORT_SYMBOL(xfrm_policy_insert); |
800 | 801 | ||
801 | struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, | 802 | struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id, |
802 | int dir, struct xfrm_selector *sel, | 803 | u8 type, int dir, |
804 | struct xfrm_selector *sel, | ||
803 | struct xfrm_sec_ctx *ctx, int delete, | 805 | struct xfrm_sec_ctx *ctx, int delete, |
804 | int *err) | 806 | int *err) |
805 | { | 807 | { |
@@ -812,6 +814,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, | |||
812 | ret = NULL; | 814 | ret = NULL; |
813 | hlist_for_each_entry(pol, chain, bydst) { | 815 | hlist_for_each_entry(pol, chain, bydst) { |
814 | if (pol->type == type && | 816 | if (pol->type == type && |
817 | pol->if_id == if_id && | ||
815 | (mark & pol->mark.m) == pol->mark.v && | 818 | (mark & pol->mark.m) == pol->mark.v && |
816 | !selector_cmp(sel, &pol->selector) && | 819 | !selector_cmp(sel, &pol->selector) && |
817 | xfrm_sec_ctx_match(ctx, pol->security)) { | 820 | xfrm_sec_ctx_match(ctx, pol->security)) { |
@@ -837,8 +840,9 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, | |||
837 | } | 840 | } |
838 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 841 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
839 | 842 | ||
840 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, | 843 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u32 if_id, |
841 | int dir, u32 id, int delete, int *err) | 844 | u8 type, int dir, u32 id, int delete, |
845 | int *err) | ||
842 | { | 846 | { |
843 | struct xfrm_policy *pol, *ret; | 847 | struct xfrm_policy *pol, *ret; |
844 | struct hlist_head *chain; | 848 | struct hlist_head *chain; |
@@ -853,6 +857,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, | |||
853 | ret = NULL; | 857 | ret = NULL; |
854 | hlist_for_each_entry(pol, chain, byidx) { | 858 | hlist_for_each_entry(pol, chain, byidx) { |
855 | if (pol->type == type && pol->index == id && | 859 | if (pol->type == type && pol->index == id && |
860 | pol->if_id == if_id && | ||
856 | (mark & pol->mark.m) == pol->mark.v) { | 861 | (mark & pol->mark.m) == pol->mark.v) { |
857 | xfrm_pol_hold(pol); | 862 | xfrm_pol_hold(pol); |
858 | if (delete) { | 863 | if (delete) { |
@@ -1063,6 +1068,7 @@ static int xfrm_policy_match(const struct xfrm_policy *pol, | |||
1063 | bool match; | 1068 | bool match; |
1064 | 1069 | ||
1065 | if (pol->family != family || | 1070 | if (pol->family != family || |
1071 | pol->if_id != fl->flowi_xfrm.if_id || | ||
1066 | (fl->flowi_mark & pol->mark.m) != pol->mark.v || | 1072 | (fl->flowi_mark & pol->mark.m) != pol->mark.v || |
1067 | pol->type != type) | 1073 | pol->type != type) |
1068 | return ret; | 1074 | return ret; |
@@ -1177,7 +1183,8 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir, | |||
1177 | 1183 | ||
1178 | match = xfrm_selector_match(&pol->selector, fl, family); | 1184 | match = xfrm_selector_match(&pol->selector, fl, family); |
1179 | if (match) { | 1185 | if (match) { |
1180 | if ((sk->sk_mark & pol->mark.m) != pol->mark.v) { | 1186 | if ((sk->sk_mark & pol->mark.m) != pol->mark.v || |
1187 | pol->if_id != fl->flowi_xfrm.if_id) { | ||
1181 | pol = NULL; | 1188 | pol = NULL; |
1182 | goto out; | 1189 | goto out; |
1183 | } | 1190 | } |
@@ -1305,6 +1312,7 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) | |||
1305 | newp->lft = old->lft; | 1312 | newp->lft = old->lft; |
1306 | newp->curlft = old->curlft; | 1313 | newp->curlft = old->curlft; |
1307 | newp->mark = old->mark; | 1314 | newp->mark = old->mark; |
1315 | newp->if_id = old->if_id; | ||
1308 | newp->action = old->action; | 1316 | newp->action = old->action; |
1309 | newp->flags = old->flags; | 1317 | newp->flags = old->flags; |
1310 | newp->xfrm_nr = old->xfrm_nr; | 1318 | newp->xfrm_nr = old->xfrm_nr; |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 8308281f3253..3803b6813fc5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -941,6 +941,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, | |||
941 | int error = 0; | 941 | int error = 0; |
942 | struct xfrm_state *best = NULL; | 942 | struct xfrm_state *best = NULL; |
943 | u32 mark = pol->mark.v & pol->mark.m; | 943 | u32 mark = pol->mark.v & pol->mark.m; |
944 | u32 if_id = fl->flowi_xfrm.if_id; | ||
944 | unsigned short encap_family = tmpl->encap_family; | 945 | unsigned short encap_family = tmpl->encap_family; |
945 | unsigned int sequence; | 946 | unsigned int sequence; |
946 | struct km_event c; | 947 | struct km_event c; |
@@ -955,6 +956,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, | |||
955 | if (x->props.family == encap_family && | 956 | if (x->props.family == encap_family && |
956 | x->props.reqid == tmpl->reqid && | 957 | x->props.reqid == tmpl->reqid && |
957 | (mark & x->mark.m) == x->mark.v && | 958 | (mark & x->mark.m) == x->mark.v && |
959 | x->if_id == if_id && | ||
958 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 960 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
959 | xfrm_state_addr_check(x, daddr, saddr, encap_family) && | 961 | xfrm_state_addr_check(x, daddr, saddr, encap_family) && |
960 | tmpl->mode == x->props.mode && | 962 | tmpl->mode == x->props.mode && |
@@ -971,6 +973,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, | |||
971 | if (x->props.family == encap_family && | 973 | if (x->props.family == encap_family && |
972 | x->props.reqid == tmpl->reqid && | 974 | x->props.reqid == tmpl->reqid && |
973 | (mark & x->mark.m) == x->mark.v && | 975 | (mark & x->mark.m) == x->mark.v && |
976 | x->if_id == if_id && | ||
974 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 977 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
975 | xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && | 978 | xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && |
976 | tmpl->mode == x->props.mode && | 979 | tmpl->mode == x->props.mode && |
@@ -1010,6 +1013,7 @@ found: | |||
1010 | * to current session. */ | 1013 | * to current session. */ |
1011 | xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); | 1014 | xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); |
1012 | memcpy(&x->mark, &pol->mark, sizeof(x->mark)); | 1015 | memcpy(&x->mark, &pol->mark, sizeof(x->mark)); |
1016 | x->if_id = if_id; | ||
1013 | 1017 | ||
1014 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); | 1018 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); |
1015 | if (error) { | 1019 | if (error) { |
@@ -1067,7 +1071,7 @@ out: | |||
1067 | } | 1071 | } |
1068 | 1072 | ||
1069 | struct xfrm_state * | 1073 | struct xfrm_state * |
1070 | xfrm_stateonly_find(struct net *net, u32 mark, | 1074 | xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, |
1071 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1075 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
1072 | unsigned short family, u8 mode, u8 proto, u32 reqid) | 1076 | unsigned short family, u8 mode, u8 proto, u32 reqid) |
1073 | { | 1077 | { |
@@ -1080,6 +1084,7 @@ xfrm_stateonly_find(struct net *net, u32 mark, | |||
1080 | if (x->props.family == family && | 1084 | if (x->props.family == family && |
1081 | x->props.reqid == reqid && | 1085 | x->props.reqid == reqid && |
1082 | (mark & x->mark.m) == x->mark.v && | 1086 | (mark & x->mark.m) == x->mark.v && |
1087 | x->if_id == if_id && | ||
1083 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 1088 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
1084 | xfrm_state_addr_check(x, daddr, saddr, family) && | 1089 | xfrm_state_addr_check(x, daddr, saddr, family) && |
1085 | mode == x->props.mode && | 1090 | mode == x->props.mode && |
@@ -1160,11 +1165,13 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | |||
1160 | struct xfrm_state *x; | 1165 | struct xfrm_state *x; |
1161 | unsigned int h; | 1166 | unsigned int h; |
1162 | u32 mark = xnew->mark.v & xnew->mark.m; | 1167 | u32 mark = xnew->mark.v & xnew->mark.m; |
1168 | u32 if_id = xnew->if_id; | ||
1163 | 1169 | ||
1164 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); | 1170 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); |
1165 | hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { | 1171 | hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { |
1166 | if (x->props.family == family && | 1172 | if (x->props.family == family && |
1167 | x->props.reqid == reqid && | 1173 | x->props.reqid == reqid && |
1174 | x->if_id == if_id && | ||
1168 | (mark & x->mark.m) == x->mark.v && | 1175 | (mark & x->mark.m) == x->mark.v && |
1169 | xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && | 1176 | xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && |
1170 | xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) | 1177 | xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) |
@@ -1187,7 +1194,7 @@ EXPORT_SYMBOL(xfrm_state_insert); | |||
1187 | static struct xfrm_state *__find_acq_core(struct net *net, | 1194 | static struct xfrm_state *__find_acq_core(struct net *net, |
1188 | const struct xfrm_mark *m, | 1195 | const struct xfrm_mark *m, |
1189 | unsigned short family, u8 mode, | 1196 | unsigned short family, u8 mode, |
1190 | u32 reqid, u8 proto, | 1197 | u32 reqid, u32 if_id, u8 proto, |
1191 | const xfrm_address_t *daddr, | 1198 | const xfrm_address_t *daddr, |
1192 | const xfrm_address_t *saddr, | 1199 | const xfrm_address_t *saddr, |
1193 | int create) | 1200 | int create) |
@@ -1242,6 +1249,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, | |||
1242 | x->props.family = family; | 1249 | x->props.family = family; |
1243 | x->props.mode = mode; | 1250 | x->props.mode = mode; |
1244 | x->props.reqid = reqid; | 1251 | x->props.reqid = reqid; |
1252 | x->if_id = if_id; | ||
1245 | x->mark.v = m->v; | 1253 | x->mark.v = m->v; |
1246 | x->mark.m = m->m; | 1254 | x->mark.m = m->m; |
1247 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 1255 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
@@ -1296,7 +1304,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1296 | 1304 | ||
1297 | if (use_spi && !x1) | 1305 | if (use_spi && !x1) |
1298 | x1 = __find_acq_core(net, &x->mark, family, x->props.mode, | 1306 | x1 = __find_acq_core(net, &x->mark, family, x->props.mode, |
1299 | x->props.reqid, x->id.proto, | 1307 | x->props.reqid, x->if_id, x->id.proto, |
1300 | &x->id.daddr, &x->props.saddr, 0); | 1308 | &x->id.daddr, &x->props.saddr, 0); |
1301 | 1309 | ||
1302 | __xfrm_state_bump_genids(x); | 1310 | __xfrm_state_bump_genids(x); |
@@ -1395,6 +1403,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, | |||
1395 | x->props.flags = orig->props.flags; | 1403 | x->props.flags = orig->props.flags; |
1396 | x->props.extra_flags = orig->props.extra_flags; | 1404 | x->props.extra_flags = orig->props.extra_flags; |
1397 | 1405 | ||
1406 | x->if_id = orig->if_id; | ||
1398 | x->tfcpad = orig->tfcpad; | 1407 | x->tfcpad = orig->tfcpad; |
1399 | x->replay_maxdiff = orig->replay_maxdiff; | 1408 | x->replay_maxdiff = orig->replay_maxdiff; |
1400 | x->replay_maxage = orig->replay_maxage; | 1409 | x->replay_maxage = orig->replay_maxage; |
@@ -1619,13 +1628,13 @@ EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | |||
1619 | 1628 | ||
1620 | struct xfrm_state * | 1629 | struct xfrm_state * |
1621 | xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, | 1630 | xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, |
1622 | u8 proto, const xfrm_address_t *daddr, | 1631 | u32 if_id, u8 proto, const xfrm_address_t *daddr, |
1623 | const xfrm_address_t *saddr, int create, unsigned short family) | 1632 | const xfrm_address_t *saddr, int create, unsigned short family) |
1624 | { | 1633 | { |
1625 | struct xfrm_state *x; | 1634 | struct xfrm_state *x; |
1626 | 1635 | ||
1627 | spin_lock_bh(&net->xfrm.xfrm_state_lock); | 1636 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
1628 | x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); | 1637 | x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create); |
1629 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); | 1638 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
1630 | 1639 | ||
1631 | return x; | 1640 | return x; |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 9602cc9e05ab..79245e1c3487 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -594,6 +594,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
594 | 594 | ||
595 | xfrm_smark_init(attrs, &x->props.smark); | 595 | xfrm_smark_init(attrs, &x->props.smark); |
596 | 596 | ||
597 | if (attrs[XFRMA_IF_ID]) | ||
598 | x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]); | ||
599 | |||
597 | err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]); | 600 | err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]); |
598 | if (err) | 601 | if (err) |
599 | goto error; | 602 | goto error; |
@@ -929,7 +932,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
929 | ret = copy_user_offload(&x->xso, skb); | 932 | ret = copy_user_offload(&x->xso, skb); |
930 | if (ret) | 933 | if (ret) |
931 | goto out; | 934 | goto out; |
932 | 935 | if (x->if_id) { | |
936 | ret = nla_put_u32(skb, XFRMA_IF_ID, x->if_id); | ||
937 | if (ret) | ||
938 | goto out; | ||
939 | } | ||
933 | if (x->security) | 940 | if (x->security) |
934 | ret = copy_sec_ctx(x->security, skb); | 941 | ret = copy_sec_ctx(x->security, skb); |
935 | out: | 942 | out: |
@@ -1278,6 +1285,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1278 | int err; | 1285 | int err; |
1279 | u32 mark; | 1286 | u32 mark; |
1280 | struct xfrm_mark m; | 1287 | struct xfrm_mark m; |
1288 | u32 if_id = 0; | ||
1281 | 1289 | ||
1282 | p = nlmsg_data(nlh); | 1290 | p = nlmsg_data(nlh); |
1283 | err = verify_spi_info(p->info.id.proto, p->min, p->max); | 1291 | err = verify_spi_info(p->info.id.proto, p->min, p->max); |
@@ -1290,6 +1298,10 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1290 | x = NULL; | 1298 | x = NULL; |
1291 | 1299 | ||
1292 | mark = xfrm_mark_get(attrs, &m); | 1300 | mark = xfrm_mark_get(attrs, &m); |
1301 | |||
1302 | if (attrs[XFRMA_IF_ID]) | ||
1303 | if_id = nla_get_u32(attrs[XFRMA_IF_ID]); | ||
1304 | |||
1293 | if (p->info.seq) { | 1305 | if (p->info.seq) { |
1294 | x = xfrm_find_acq_byseq(net, mark, p->info.seq); | 1306 | x = xfrm_find_acq_byseq(net, mark, p->info.seq); |
1295 | if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) { | 1307 | if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) { |
@@ -1300,7 +1312,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1300 | 1312 | ||
1301 | if (!x) | 1313 | if (!x) |
1302 | x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, | 1314 | x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, |
1303 | p->info.id.proto, daddr, | 1315 | if_id, p->info.id.proto, daddr, |
1304 | &p->info.saddr, 1, | 1316 | &p->info.saddr, 1, |
1305 | family); | 1317 | family); |
1306 | err = -ENOENT; | 1318 | err = -ENOENT; |
@@ -1588,6 +1600,9 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us | |||
1588 | 1600 | ||
1589 | xfrm_mark_get(attrs, &xp->mark); | 1601 | xfrm_mark_get(attrs, &xp->mark); |
1590 | 1602 | ||
1603 | if (attrs[XFRMA_IF_ID]) | ||
1604 | xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]); | ||
1605 | |||
1591 | return xp; | 1606 | return xp; |
1592 | error: | 1607 | error: |
1593 | *errp = err; | 1608 | *errp = err; |
@@ -1733,6 +1748,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
1733 | err = copy_to_user_policy_type(xp->type, skb); | 1748 | err = copy_to_user_policy_type(xp->type, skb); |
1734 | if (!err) | 1749 | if (!err) |
1735 | err = xfrm_mark_put(skb, &xp->mark); | 1750 | err = xfrm_mark_put(skb, &xp->mark); |
1751 | if (!err) | ||
1752 | err = xfrm_if_id_put(skb, xp->if_id); | ||
1736 | if (err) { | 1753 | if (err) { |
1737 | nlmsg_cancel(skb, nlh); | 1754 | nlmsg_cancel(skb, nlh); |
1738 | return err; | 1755 | return err; |
@@ -1814,6 +1831,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1814 | int delete; | 1831 | int delete; |
1815 | struct xfrm_mark m; | 1832 | struct xfrm_mark m; |
1816 | u32 mark = xfrm_mark_get(attrs, &m); | 1833 | u32 mark = xfrm_mark_get(attrs, &m); |
1834 | u32 if_id = 0; | ||
1817 | 1835 | ||
1818 | p = nlmsg_data(nlh); | 1836 | p = nlmsg_data(nlh); |
1819 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1837 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
@@ -1826,8 +1844,11 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1826 | if (err) | 1844 | if (err) |
1827 | return err; | 1845 | return err; |
1828 | 1846 | ||
1847 | if (attrs[XFRMA_IF_ID]) | ||
1848 | if_id = nla_get_u32(attrs[XFRMA_IF_ID]); | ||
1849 | |||
1829 | if (p->index) | 1850 | if (p->index) |
1830 | xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err); | 1851 | xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, delete, &err); |
1831 | else { | 1852 | else { |
1832 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; | 1853 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
1833 | struct xfrm_sec_ctx *ctx; | 1854 | struct xfrm_sec_ctx *ctx; |
@@ -1844,7 +1865,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1844 | if (err) | 1865 | if (err) |
1845 | return err; | 1866 | return err; |
1846 | } | 1867 | } |
1847 | xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel, | 1868 | xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir, &p->sel, |
1848 | ctx, delete, &err); | 1869 | ctx, delete, &err); |
1849 | security_xfrm_policy_free(ctx); | 1870 | security_xfrm_policy_free(ctx); |
1850 | } | 1871 | } |
@@ -1967,6 +1988,10 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct | |||
1967 | if (err) | 1988 | if (err) |
1968 | goto out_cancel; | 1989 | goto out_cancel; |
1969 | 1990 | ||
1991 | err = xfrm_if_id_put(skb, x->if_id); | ||
1992 | if (err) | ||
1993 | goto out_cancel; | ||
1994 | |||
1970 | nlmsg_end(skb, nlh); | 1995 | nlmsg_end(skb, nlh); |
1971 | return 0; | 1996 | return 0; |
1972 | 1997 | ||
@@ -2109,6 +2134,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2109 | int err = -ENOENT; | 2134 | int err = -ENOENT; |
2110 | struct xfrm_mark m; | 2135 | struct xfrm_mark m; |
2111 | u32 mark = xfrm_mark_get(attrs, &m); | 2136 | u32 mark = xfrm_mark_get(attrs, &m); |
2137 | u32 if_id = 0; | ||
2112 | 2138 | ||
2113 | err = copy_from_user_policy_type(&type, attrs); | 2139 | err = copy_from_user_policy_type(&type, attrs); |
2114 | if (err) | 2140 | if (err) |
@@ -2118,8 +2144,11 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2118 | if (err) | 2144 | if (err) |
2119 | return err; | 2145 | return err; |
2120 | 2146 | ||
2147 | if (attrs[XFRMA_IF_ID]) | ||
2148 | if_id = nla_get_u32(attrs[XFRMA_IF_ID]); | ||
2149 | |||
2121 | if (p->index) | 2150 | if (p->index) |
2122 | xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err); | 2151 | xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, 0, &err); |
2123 | else { | 2152 | else { |
2124 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; | 2153 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
2125 | struct xfrm_sec_ctx *ctx; | 2154 | struct xfrm_sec_ctx *ctx; |
@@ -2136,7 +2165,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2136 | if (err) | 2165 | if (err) |
2137 | return err; | 2166 | return err; |
2138 | } | 2167 | } |
2139 | xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, | 2168 | xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir, |
2140 | &p->sel, ctx, 0, &err); | 2169 | &p->sel, ctx, 0, &err); |
2141 | security_xfrm_policy_free(ctx); | 2170 | security_xfrm_policy_free(ctx); |
2142 | } | 2171 | } |
@@ -2520,6 +2549,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
2520 | [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) }, | 2549 | [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) }, |
2521 | [XFRMA_SET_MARK] = { .type = NLA_U32 }, | 2550 | [XFRMA_SET_MARK] = { .type = NLA_U32 }, |
2522 | [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, | 2551 | [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, |
2552 | [XFRMA_IF_ID] = { .type = NLA_U32 }, | ||
2523 | }; | 2553 | }; |
2524 | 2554 | ||
2525 | static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { | 2555 | static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { |
@@ -2651,6 +2681,10 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct | |||
2651 | if (err) | 2681 | if (err) |
2652 | return err; | 2682 | return err; |
2653 | 2683 | ||
2684 | err = xfrm_if_id_put(skb, x->if_id); | ||
2685 | if (err) | ||
2686 | return err; | ||
2687 | |||
2654 | nlmsg_end(skb, nlh); | 2688 | nlmsg_end(skb, nlh); |
2655 | return 0; | 2689 | return 0; |
2656 | } | 2690 | } |
@@ -2749,6 +2783,8 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x) | |||
2749 | l += nla_total_size(sizeof(x->props.smark.v)); | 2783 | l += nla_total_size(sizeof(x->props.smark.v)); |
2750 | l += nla_total_size(sizeof(x->props.smark.m)); | 2784 | l += nla_total_size(sizeof(x->props.smark.m)); |
2751 | } | 2785 | } |
2786 | if (x->if_id) | ||
2787 | l += nla_total_size(sizeof(x->if_id)); | ||
2752 | 2788 | ||
2753 | /* Must count x->lastused as it may become non-zero behind our back. */ | 2789 | /* Must count x->lastused as it may become non-zero behind our back. */ |
2754 | l += nla_total_size_64bit(sizeof(u64)); | 2790 | l += nla_total_size_64bit(sizeof(u64)); |
@@ -2878,6 +2914,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
2878 | err = copy_to_user_policy_type(xp->type, skb); | 2914 | err = copy_to_user_policy_type(xp->type, skb); |
2879 | if (!err) | 2915 | if (!err) |
2880 | err = xfrm_mark_put(skb, &xp->mark); | 2916 | err = xfrm_mark_put(skb, &xp->mark); |
2917 | if (!err) | ||
2918 | err = xfrm_if_id_put(skb, xp->if_id); | ||
2881 | if (err) { | 2919 | if (err) { |
2882 | nlmsg_cancel(skb, nlh); | 2920 | nlmsg_cancel(skb, nlh); |
2883 | return err; | 2921 | return err; |
@@ -2994,6 +3032,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
2994 | err = copy_to_user_policy_type(xp->type, skb); | 3032 | err = copy_to_user_policy_type(xp->type, skb); |
2995 | if (!err) | 3033 | if (!err) |
2996 | err = xfrm_mark_put(skb, &xp->mark); | 3034 | err = xfrm_mark_put(skb, &xp->mark); |
3035 | if (!err) | ||
3036 | err = xfrm_if_id_put(skb, xp->if_id); | ||
2997 | if (err) { | 3037 | if (err) { |
2998 | nlmsg_cancel(skb, nlh); | 3038 | nlmsg_cancel(skb, nlh); |
2999 | return err; | 3039 | return err; |
@@ -3075,6 +3115,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_e | |||
3075 | err = copy_to_user_policy_type(xp->type, skb); | 3115 | err = copy_to_user_policy_type(xp->type, skb); |
3076 | if (!err) | 3116 | if (!err) |
3077 | err = xfrm_mark_put(skb, &xp->mark); | 3117 | err = xfrm_mark_put(skb, &xp->mark); |
3118 | if (!err) | ||
3119 | err = xfrm_if_id_put(skb, xp->if_id); | ||
3078 | if (err) | 3120 | if (err) |
3079 | goto out_free_skb; | 3121 | goto out_free_skb; |
3080 | 3122 | ||