diff options
| -rw-r--r-- | include/net/xfrm.h | 23 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_mode_tunnel.c | 2 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_output.c | 2 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 2 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_output.c | 2 | ||||
| -rw-r--r-- | net/key/af_key.c | 2 | ||||
| -rw-r--r-- | net/xfrm/xfrm_input.c | 22 | ||||
| -rw-r--r-- | net/xfrm/xfrm_output.c | 18 | ||||
| -rw-r--r-- | net/xfrm/xfrm_state.c | 54 | ||||
| -rw-r--r-- | net/xfrm/xfrm_user.c | 7 |
10 files changed, 113 insertions, 21 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 619c53bc3cd2..4e6f9568cbe7 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
| @@ -204,6 +204,7 @@ struct xfrm_state | |||
| 204 | * transformer. */ | 204 | * transformer. */ |
| 205 | const struct xfrm_type *type; | 205 | const struct xfrm_type *type; |
| 206 | struct xfrm_mode *inner_mode; | 206 | struct xfrm_mode *inner_mode; |
| 207 | struct xfrm_mode *inner_mode_iaf; | ||
| 207 | struct xfrm_mode *outer_mode; | 208 | struct xfrm_mode *outer_mode; |
| 208 | 209 | ||
| 209 | /* Security context */ | 210 | /* Security context */ |
| @@ -387,6 +388,27 @@ enum { | |||
| 387 | extern int xfrm_register_mode(struct xfrm_mode *mode, int family); | 388 | extern int xfrm_register_mode(struct xfrm_mode *mode, int family); |
| 388 | extern int xfrm_unregister_mode(struct xfrm_mode *mode, int family); | 389 | extern int xfrm_unregister_mode(struct xfrm_mode *mode, int family); |
| 389 | 390 | ||
| 391 | static inline int xfrm_af2proto(unsigned int family) | ||
| 392 | { | ||
| 393 | switch(family) { | ||
| 394 | case AF_INET: | ||
| 395 | return IPPROTO_IPIP; | ||
| 396 | case AF_INET6: | ||
| 397 | return IPPROTO_IPV6; | ||
| 398 | default: | ||
| 399 | return 0; | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | static inline struct xfrm_mode *xfrm_ip2inner_mode(struct xfrm_state *x, int ipproto) | ||
| 404 | { | ||
| 405 | if ((ipproto == IPPROTO_IPIP && x->props.family == AF_INET) || | ||
| 406 | (ipproto == IPPROTO_IPV6 && x->props.family == AF_INET6)) | ||
| 407 | return x->inner_mode; | ||
| 408 | else | ||
| 409 | return x->inner_mode_iaf; | ||
| 410 | } | ||
| 411 | |||
| 390 | struct xfrm_tmpl | 412 | struct xfrm_tmpl |
| 391 | { | 413 | { |
| 392 | /* id in template is interpreted as: | 414 | /* id in template is interpreted as: |
| @@ -1253,6 +1275,7 @@ extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, | |||
| 1253 | extern int xfrm_input_resume(struct sk_buff *skb, int nexthdr); | 1275 | extern int xfrm_input_resume(struct sk_buff *skb, int nexthdr); |
| 1254 | extern int xfrm_output_resume(struct sk_buff *skb, int err); | 1276 | extern int xfrm_output_resume(struct sk_buff *skb, int err); |
| 1255 | extern int xfrm_output(struct sk_buff *skb); | 1277 | extern int xfrm_output(struct sk_buff *skb); |
| 1278 | extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); | ||
| 1256 | extern int xfrm4_extract_header(struct sk_buff *skb); | 1279 | extern int xfrm4_extract_header(struct sk_buff *skb); |
| 1257 | extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); | 1280 | extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); |
| 1258 | extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, | 1281 | extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, |
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 8dee617ee900..584e6d74e3a9 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
| @@ -41,7 +41,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 41 | top_iph->ihl = 5; | 41 | top_iph->ihl = 5; |
| 42 | top_iph->version = 4; | 42 | top_iph->version = 4; |
| 43 | 43 | ||
| 44 | top_iph->protocol = x->inner_mode->afinfo->proto; | 44 | top_iph->protocol = xfrm_af2proto(skb->dst->ops->family); |
| 45 | 45 | ||
| 46 | /* DS disclosed */ | 46 | /* DS disclosed */ |
| 47 | top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos, | 47 | top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos, |
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index d5a58a818021..8c3180adddbf 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
| @@ -56,7 +56,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 56 | { | 56 | { |
| 57 | int err; | 57 | int err; |
| 58 | 58 | ||
| 59 | err = x->inner_mode->afinfo->extract_output(x, skb); | 59 | err = xfrm_inner_extract_output(x, skb); |
| 60 | if (err) | 60 | if (err) |
| 61 | return err; | 61 | return err; |
| 62 | 62 | ||
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 0c742faaa30b..e20529b4c825 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
| @@ -45,7 +45,7 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 45 | 45 | ||
| 46 | memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | 46 | memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, |
| 47 | sizeof(top_iph->flow_lbl)); | 47 | sizeof(top_iph->flow_lbl)); |
| 48 | top_iph->nexthdr = x->inner_mode->afinfo->proto; | 48 | top_iph->nexthdr = xfrm_af2proto(skb->dst->ops->family); |
| 49 | 49 | ||
| 50 | dsfield = XFRM_MODE_SKB_CB(skb)->tos; | 50 | dsfield = XFRM_MODE_SKB_CB(skb)->tos; |
| 51 | dsfield = INET_ECN_encapsulate(dsfield, dsfield); | 51 | dsfield = INET_ECN_encapsulate(dsfield, dsfield); |
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 79ccfb080733..0af823cf7f1f 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
| @@ -62,7 +62,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 62 | { | 62 | { |
| 63 | int err; | 63 | int err; |
| 64 | 64 | ||
| 65 | err = x->inner_mode->afinfo->extract_output(x, skb); | 65 | err = xfrm_inner_extract_output(x, skb); |
| 66 | if (err) | 66 | if (err) |
| 67 | return err; | 67 | return err; |
| 68 | 68 | ||
diff --git a/net/key/af_key.c b/net/key/af_key.c index 8b5f486ac80f..e9ef9af4a53b 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
| @@ -1219,7 +1219,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, | |||
| 1219 | x->sel.prefixlen_s = addr->sadb_address_prefixlen; | 1219 | x->sel.prefixlen_s = addr->sadb_address_prefixlen; |
| 1220 | } | 1220 | } |
| 1221 | 1221 | ||
| 1222 | if (!x->sel.family) | 1222 | if (x->props.mode == XFRM_MODE_TRANSPORT) |
| 1223 | x->sel.family = x->props.family; | 1223 | x->sel.family = x->props.family; |
| 1224 | 1224 | ||
| 1225 | if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) { | 1225 | if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) { |
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 62188c6a06dd..75279402ccf4 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
| @@ -84,14 +84,21 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) | |||
| 84 | 84 | ||
| 85 | int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) | 85 | int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) |
| 86 | { | 86 | { |
| 87 | struct xfrm_mode *inner_mode = x->inner_mode; | ||
| 87 | int err; | 88 | int err; |
| 88 | 89 | ||
| 89 | err = x->outer_mode->afinfo->extract_input(x, skb); | 90 | err = x->outer_mode->afinfo->extract_input(x, skb); |
| 90 | if (err) | 91 | if (err) |
| 91 | return err; | 92 | return err; |
| 92 | 93 | ||
| 93 | skb->protocol = x->inner_mode->afinfo->eth_proto; | 94 | if (x->sel.family == AF_UNSPEC) { |
| 94 | return x->inner_mode->input2(x, skb); | 95 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
| 96 | if (inner_mode == NULL) | ||
| 97 | return -EAFNOSUPPORT; | ||
| 98 | } | ||
| 99 | |||
| 100 | skb->protocol = inner_mode->afinfo->eth_proto; | ||
| 101 | return inner_mode->input2(x, skb); | ||
| 95 | } | 102 | } |
| 96 | EXPORT_SYMBOL(xfrm_prepare_input); | 103 | EXPORT_SYMBOL(xfrm_prepare_input); |
| 97 | 104 | ||
| @@ -101,6 +108,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
| 101 | __be32 seq; | 108 | __be32 seq; |
| 102 | struct xfrm_state *x; | 109 | struct xfrm_state *x; |
| 103 | xfrm_address_t *daddr; | 110 | xfrm_address_t *daddr; |
| 111 | struct xfrm_mode *inner_mode; | ||
| 104 | unsigned int family; | 112 | unsigned int family; |
| 105 | int decaps = 0; | 113 | int decaps = 0; |
| 106 | int async = 0; | 114 | int async = 0; |
| @@ -207,7 +215,15 @@ resume: | |||
| 207 | 215 | ||
| 208 | XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; | 216 | XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; |
| 209 | 217 | ||
| 210 | if (x->inner_mode->input(x, skb)) { | 218 | inner_mode = x->inner_mode; |
| 219 | |||
| 220 | if (x->sel.family == AF_UNSPEC) { | ||
| 221 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); | ||
| 222 | if (inner_mode == NULL) | ||
| 223 | goto drop; | ||
| 224 | } | ||
| 225 | |||
| 226 | if (inner_mode->input(x, skb)) { | ||
| 211 | XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR); | 227 | XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR); |
| 212 | goto drop; | 228 | goto drop; |
| 213 | } | 229 | } |
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 569d377932c4..2519129c6d21 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c | |||
| @@ -124,7 +124,7 @@ int xfrm_output_resume(struct sk_buff *skb, int err) | |||
| 124 | if (!x) | 124 | if (!x) |
| 125 | return dst_output(skb); | 125 | return dst_output(skb); |
| 126 | 126 | ||
| 127 | err = nf_hook(x->inner_mode->afinfo->family, | 127 | err = nf_hook(skb->dst->ops->family, |
| 128 | NF_INET_POST_ROUTING, skb, | 128 | NF_INET_POST_ROUTING, skb, |
| 129 | NULL, skb->dst->dev, xfrm_output2); | 129 | NULL, skb->dst->dev, xfrm_output2); |
| 130 | if (unlikely(err != 1)) | 130 | if (unlikely(err != 1)) |
| @@ -193,4 +193,20 @@ int xfrm_output(struct sk_buff *skb) | |||
| 193 | 193 | ||
| 194 | return xfrm_output2(skb); | 194 | return xfrm_output2(skb); |
| 195 | } | 195 | } |
| 196 | |||
| 197 | int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 198 | { | ||
| 199 | struct xfrm_mode *inner_mode; | ||
| 200 | if (x->sel.family == AF_UNSPEC) | ||
| 201 | inner_mode = xfrm_ip2inner_mode(x, | ||
| 202 | xfrm_af2proto(skb->dst->ops->family)); | ||
| 203 | else | ||
| 204 | inner_mode = x->inner_mode; | ||
| 205 | |||
| 206 | if (inner_mode == NULL) | ||
| 207 | return -EAFNOSUPPORT; | ||
| 208 | return inner_mode->afinfo->extract_output(x, skb); | ||
| 209 | } | ||
| 210 | |||
| 196 | EXPORT_SYMBOL_GPL(xfrm_output); | 211 | EXPORT_SYMBOL_GPL(xfrm_output); |
| 212 | EXPORT_SYMBOL_GPL(xfrm_inner_extract_output); | ||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 7ba65e82941c..58f1f9347b54 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -388,6 +388,8 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
| 388 | kfree(x->coaddr); | 388 | kfree(x->coaddr); |
| 389 | if (x->inner_mode) | 389 | if (x->inner_mode) |
| 390 | xfrm_put_mode(x->inner_mode); | 390 | xfrm_put_mode(x->inner_mode); |
| 391 | if (x->inner_mode_iaf) | ||
| 392 | xfrm_put_mode(x->inner_mode_iaf); | ||
| 391 | if (x->outer_mode) | 393 | if (x->outer_mode) |
| 392 | xfrm_put_mode(x->outer_mode); | 394 | xfrm_put_mode(x->outer_mode); |
| 393 | if (x->type) { | 395 | if (x->type) { |
| @@ -523,6 +525,8 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
| 523 | x->lft.hard_packet_limit = XFRM_INF; | 525 | x->lft.hard_packet_limit = XFRM_INF; |
| 524 | x->replay_maxage = 0; | 526 | x->replay_maxage = 0; |
| 525 | x->replay_maxdiff = 0; | 527 | x->replay_maxdiff = 0; |
| 528 | x->inner_mode = NULL; | ||
| 529 | x->inner_mode_iaf = NULL; | ||
| 526 | spin_lock_init(&x->lock); | 530 | spin_lock_init(&x->lock); |
| 527 | } | 531 | } |
| 528 | return x; | 532 | return x; |
| @@ -796,7 +800,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 796 | selector. | 800 | selector. |
| 797 | */ | 801 | */ |
| 798 | if (x->km.state == XFRM_STATE_VALID) { | 802 | if (x->km.state == XFRM_STATE_VALID) { |
| 799 | if (!xfrm_selector_match(&x->sel, fl, x->sel.family) || | 803 | if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) || |
| 800 | !security_xfrm_state_pol_flow_match(x, pol, fl)) | 804 | !security_xfrm_state_pol_flow_match(x, pol, fl)) |
| 801 | continue; | 805 | continue; |
| 802 | if (!best || | 806 | if (!best || |
| @@ -1944,6 +1948,7 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) | |||
| 1944 | int xfrm_init_state(struct xfrm_state *x) | 1948 | int xfrm_init_state(struct xfrm_state *x) |
| 1945 | { | 1949 | { |
| 1946 | struct xfrm_state_afinfo *afinfo; | 1950 | struct xfrm_state_afinfo *afinfo; |
| 1951 | struct xfrm_mode *inner_mode; | ||
| 1947 | int family = x->props.family; | 1952 | int family = x->props.family; |
| 1948 | int err; | 1953 | int err; |
| 1949 | 1954 | ||
| @@ -1962,13 +1967,48 @@ int xfrm_init_state(struct xfrm_state *x) | |||
| 1962 | goto error; | 1967 | goto error; |
| 1963 | 1968 | ||
| 1964 | err = -EPROTONOSUPPORT; | 1969 | err = -EPROTONOSUPPORT; |
| 1965 | x->inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); | ||
| 1966 | if (x->inner_mode == NULL) | ||
| 1967 | goto error; | ||
| 1968 | 1970 | ||
| 1969 | if (!(x->inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && | 1971 | if (x->sel.family != AF_UNSPEC) { |
| 1970 | family != x->sel.family) | 1972 | inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); |
| 1971 | goto error; | 1973 | if (inner_mode == NULL) |
| 1974 | goto error; | ||
| 1975 | |||
| 1976 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && | ||
| 1977 | family != x->sel.family) { | ||
| 1978 | xfrm_put_mode(inner_mode); | ||
| 1979 | goto error; | ||
| 1980 | } | ||
| 1981 | |||
| 1982 | x->inner_mode = inner_mode; | ||
| 1983 | } else { | ||
| 1984 | struct xfrm_mode *inner_mode_iaf; | ||
| 1985 | |||
| 1986 | inner_mode = xfrm_get_mode(x->props.mode, AF_INET); | ||
| 1987 | if (inner_mode == NULL) | ||
| 1988 | goto error; | ||
| 1989 | |||
| 1990 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { | ||
| 1991 | xfrm_put_mode(inner_mode); | ||
| 1992 | goto error; | ||
| 1993 | } | ||
| 1994 | |||
| 1995 | inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6); | ||
| 1996 | if (inner_mode_iaf == NULL) | ||
| 1997 | goto error; | ||
| 1998 | |||
| 1999 | if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) { | ||
| 2000 | xfrm_put_mode(inner_mode_iaf); | ||
| 2001 | goto error; | ||
| 2002 | } | ||
| 2003 | |||
| 2004 | if (x->props.family == AF_INET) { | ||
| 2005 | x->inner_mode = inner_mode; | ||
| 2006 | x->inner_mode_iaf = inner_mode_iaf; | ||
| 2007 | } else { | ||
| 2008 | x->inner_mode = inner_mode_iaf; | ||
| 2009 | x->inner_mode_iaf = inner_mode; | ||
| 2010 | } | ||
| 2011 | } | ||
| 1972 | 2012 | ||
| 1973 | x->type = xfrm_get_type(x->id.proto, family); | 2013 | x->type = xfrm_get_type(x->id.proto, family); |
| 1974 | if (x->type == NULL) | 2014 | if (x->type == NULL) |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index f971ca5645f8..5d96f2728dc6 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
| @@ -288,12 +288,9 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * | |||
| 288 | memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr)); | 288 | memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr)); |
| 289 | x->props.flags = p->flags; | 289 | x->props.flags = p->flags; |
| 290 | 290 | ||
| 291 | /* | 291 | if (x->props.mode == XFRM_MODE_TRANSPORT) |
| 292 | * Set inner address family if the KM left it as zero. | ||
| 293 | * See comment in validate_tmpl. | ||
| 294 | */ | ||
| 295 | if (!x->sel.family) | ||
| 296 | x->sel.family = p->family; | 292 | x->sel.family = p->family; |
| 293 | |||
| 297 | } | 294 | } |
| 298 | 295 | ||
| 299 | /* | 296 | /* |
