diff options
Diffstat (limited to 'net')
30 files changed, 1226 insertions, 1499 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index f3f5a78cd062..319ad5490fb3 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
| @@ -2521,7 +2521,7 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) | |||
| 2521 | skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF; | 2521 | skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF; |
| 2522 | 2522 | ||
| 2523 | rcu_read_lock_bh(); | 2523 | rcu_read_lock_bh(); |
| 2524 | err = x->outer_mode->output(x, skb); | 2524 | err = pktgen_xfrm_outer_mode_output(x, skb); |
| 2525 | rcu_read_unlock_bh(); | 2525 | rcu_read_unlock_bh(); |
| 2526 | if (err) { | 2526 | if (err) { |
| 2527 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); | 2527 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); |
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 32cae39cdff6..8108e97d4285 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
| @@ -304,7 +304,7 @@ config NET_IPVTI | |||
| 304 | tristate "Virtual (secure) IP: tunneling" | 304 | tristate "Virtual (secure) IP: tunneling" |
| 305 | select INET_TUNNEL | 305 | select INET_TUNNEL |
| 306 | select NET_IP_TUNNEL | 306 | select NET_IP_TUNNEL |
| 307 | depends on INET_XFRM_MODE_TUNNEL | 307 | select XFRM |
| 308 | ---help--- | 308 | ---help--- |
| 309 | Tunneling means encapsulating data of one protocol type within | 309 | Tunneling means encapsulating data of one protocol type within |
| 310 | another protocol and sending it over a channel that understands the | 310 | another protocol and sending it over a channel that understands the |
| @@ -396,33 +396,6 @@ config INET_TUNNEL | |||
| 396 | tristate | 396 | tristate |
| 397 | default n | 397 | default n |
| 398 | 398 | ||
| 399 | config INET_XFRM_MODE_TRANSPORT | ||
| 400 | tristate "IP: IPsec transport mode" | ||
| 401 | default y | ||
| 402 | select XFRM | ||
| 403 | ---help--- | ||
| 404 | Support for IPsec transport mode. | ||
| 405 | |||
| 406 | If unsure, say Y. | ||
| 407 | |||
| 408 | config INET_XFRM_MODE_TUNNEL | ||
| 409 | tristate "IP: IPsec tunnel mode" | ||
| 410 | default y | ||
| 411 | select XFRM | ||
| 412 | ---help--- | ||
| 413 | Support for IPsec tunnel mode. | ||
| 414 | |||
| 415 | If unsure, say Y. | ||
| 416 | |||
| 417 | config INET_XFRM_MODE_BEET | ||
| 418 | tristate "IP: IPsec BEET mode" | ||
| 419 | default y | ||
| 420 | select XFRM | ||
| 421 | ---help--- | ||
| 422 | Support for IPsec BEET mode. | ||
| 423 | |||
| 424 | If unsure, say Y. | ||
| 425 | |||
| 426 | config INET_DIAG | 399 | config INET_DIAG |
| 427 | tristate "INET: socket monitoring interface" | 400 | tristate "INET: socket monitoring interface" |
| 428 | default y | 401 | default y |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 58629314eae9..000a61994c8f 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
| @@ -37,10 +37,7 @@ obj-$(CONFIG_INET_ESP) += esp4.o | |||
| 37 | obj-$(CONFIG_INET_ESP_OFFLOAD) += esp4_offload.o | 37 | obj-$(CONFIG_INET_ESP_OFFLOAD) += esp4_offload.o |
| 38 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o | 38 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o |
| 39 | obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o | 39 | obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o |
| 40 | obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o | ||
| 41 | obj-$(CONFIG_INET_TUNNEL) += tunnel4.o | 40 | obj-$(CONFIG_INET_TUNNEL) += tunnel4.o |
| 42 | obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o | ||
| 43 | obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o | ||
| 44 | obj-$(CONFIG_IP_PNP) += ipconfig.o | 41 | obj-$(CONFIG_IP_PNP) += ipconfig.o |
| 45 | obj-$(CONFIG_NETFILTER) += netfilter.o netfilter/ | 42 | obj-$(CONFIG_NETFILTER) += netfilter.o netfilter/ |
| 46 | obj-$(CONFIG_INET_DIAG) += inet_diag.o | 43 | obj-$(CONFIG_INET_DIAG) += inet_diag.o |
diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c index 8756e0e790d2..b61a8ff558f9 100644 --- a/net/ipv4/esp4_offload.c +++ b/net/ipv4/esp4_offload.c | |||
| @@ -107,6 +107,44 @@ static void esp4_gso_encap(struct xfrm_state *x, struct sk_buff *skb) | |||
| 107 | xo->proto = proto; | 107 | xo->proto = proto; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x, | ||
| 111 | struct sk_buff *skb, | ||
| 112 | netdev_features_t features) | ||
| 113 | { | ||
| 114 | __skb_push(skb, skb->mac_len); | ||
| 115 | return skb_mac_gso_segment(skb, features); | ||
| 116 | } | ||
| 117 | |||
| 118 | static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x, | ||
| 119 | struct sk_buff *skb, | ||
| 120 | netdev_features_t features) | ||
| 121 | { | ||
| 122 | const struct net_offload *ops; | ||
| 123 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 124 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 125 | |||
| 126 | skb->transport_header += x->props.header_len; | ||
| 127 | ops = rcu_dereference(inet_offloads[xo->proto]); | ||
| 128 | if (likely(ops && ops->callbacks.gso_segment)) | ||
| 129 | segs = ops->callbacks.gso_segment(skb, features); | ||
| 130 | |||
| 131 | return segs; | ||
| 132 | } | ||
| 133 | |||
| 134 | static struct sk_buff *xfrm4_outer_mode_gso_segment(struct xfrm_state *x, | ||
| 135 | struct sk_buff *skb, | ||
| 136 | netdev_features_t features) | ||
| 137 | { | ||
| 138 | switch (x->outer_mode.encap) { | ||
| 139 | case XFRM_MODE_TUNNEL: | ||
| 140 | return xfrm4_tunnel_gso_segment(x, skb, features); | ||
| 141 | case XFRM_MODE_TRANSPORT: | ||
| 142 | return xfrm4_transport_gso_segment(x, skb, features); | ||
| 143 | } | ||
| 144 | |||
| 145 | return ERR_PTR(-EOPNOTSUPP); | ||
| 146 | } | ||
| 147 | |||
| 110 | static struct sk_buff *esp4_gso_segment(struct sk_buff *skb, | 148 | static struct sk_buff *esp4_gso_segment(struct sk_buff *skb, |
| 111 | netdev_features_t features) | 149 | netdev_features_t features) |
| 112 | { | 150 | { |
| @@ -138,14 +176,16 @@ static struct sk_buff *esp4_gso_segment(struct sk_buff *skb, | |||
| 138 | 176 | ||
| 139 | skb->encap_hdr_csum = 1; | 177 | skb->encap_hdr_csum = 1; |
| 140 | 178 | ||
| 141 | if (!(features & NETIF_F_HW_ESP) || x->xso.dev != skb->dev) | 179 | if ((!(skb->dev->gso_partial_features & NETIF_F_HW_ESP) && |
| 180 | !(features & NETIF_F_HW_ESP)) || x->xso.dev != skb->dev) | ||
| 142 | esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK); | 181 | esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK); |
| 143 | else if (!(features & NETIF_F_HW_ESP_TX_CSUM)) | 182 | else if (!(features & NETIF_F_HW_ESP_TX_CSUM) && |
| 183 | !(skb->dev->gso_partial_features & NETIF_F_HW_ESP_TX_CSUM)) | ||
| 144 | esp_features = features & ~NETIF_F_CSUM_MASK; | 184 | esp_features = features & ~NETIF_F_CSUM_MASK; |
| 145 | 185 | ||
| 146 | xo->flags |= XFRM_GSO_SEGMENT; | 186 | xo->flags |= XFRM_GSO_SEGMENT; |
| 147 | 187 | ||
| 148 | return x->outer_mode->gso_segment(x, skb, esp_features); | 188 | return xfrm4_outer_mode_gso_segment(x, skb, esp_features); |
| 149 | } | 189 | } |
| 150 | 190 | ||
| 151 | static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb) | 191 | static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb) |
| @@ -181,7 +221,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_ | |||
| 181 | if (!xo) | 221 | if (!xo) |
| 182 | return -EINVAL; | 222 | return -EINVAL; |
| 183 | 223 | ||
| 184 | if (!(features & NETIF_F_HW_ESP) || x->xso.dev != skb->dev) { | 224 | if ((!(features & NETIF_F_HW_ESP) && |
| 225 | !(skb->dev->gso_partial_features & NETIF_F_HW_ESP)) || | ||
| 226 | x->xso.dev != skb->dev) { | ||
| 185 | xo->flags |= CRYPTO_FALLBACK; | 227 | xo->flags |= CRYPTO_FALLBACK; |
| 186 | hw_offload = false; | 228 | hw_offload = false; |
| 187 | } | 229 | } |
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 68a21bf75dd0..cc5d9c0a8a10 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
| @@ -50,7 +50,7 @@ static unsigned int vti_net_id __read_mostly; | |||
| 50 | static int vti_tunnel_init(struct net_device *dev); | 50 | static int vti_tunnel_init(struct net_device *dev); |
| 51 | 51 | ||
| 52 | static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi, | 52 | static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi, |
| 53 | int encap_type) | 53 | int encap_type, bool update_skb_dev) |
| 54 | { | 54 | { |
| 55 | struct ip_tunnel *tunnel; | 55 | struct ip_tunnel *tunnel; |
| 56 | const struct iphdr *iph = ip_hdr(skb); | 56 | const struct iphdr *iph = ip_hdr(skb); |
| @@ -65,6 +65,9 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi, | |||
| 65 | 65 | ||
| 66 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel; | 66 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel; |
| 67 | 67 | ||
| 68 | if (update_skb_dev) | ||
| 69 | skb->dev = tunnel->dev; | ||
| 70 | |||
| 68 | return xfrm_input(skb, nexthdr, spi, encap_type); | 71 | return xfrm_input(skb, nexthdr, spi, encap_type); |
| 69 | } | 72 | } |
| 70 | 73 | ||
| @@ -74,47 +77,28 @@ drop: | |||
| 74 | return 0; | 77 | return 0; |
| 75 | } | 78 | } |
| 76 | 79 | ||
| 77 | static int vti_input_ipip(struct sk_buff *skb, int nexthdr, __be32 spi, | 80 | static int vti_input_proto(struct sk_buff *skb, int nexthdr, __be32 spi, |
| 78 | int encap_type) | 81 | int encap_type) |
| 79 | { | 82 | { |
| 80 | struct ip_tunnel *tunnel; | 83 | return vti_input(skb, nexthdr, spi, encap_type, false); |
| 81 | const struct iphdr *iph = ip_hdr(skb); | ||
| 82 | struct net *net = dev_net(skb->dev); | ||
| 83 | struct ip_tunnel_net *itn = net_generic(net, vti_net_id); | ||
| 84 | |||
| 85 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, | ||
| 86 | iph->saddr, iph->daddr, 0); | ||
| 87 | if (tunnel) { | ||
| 88 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) | ||
| 89 | goto drop; | ||
| 90 | |||
| 91 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel; | ||
| 92 | |||
| 93 | skb->dev = tunnel->dev; | ||
| 94 | |||
| 95 | return xfrm_input(skb, nexthdr, spi, encap_type); | ||
| 96 | } | ||
| 97 | |||
| 98 | return -EINVAL; | ||
| 99 | drop: | ||
| 100 | kfree_skb(skb); | ||
| 101 | return 0; | ||
| 102 | } | 84 | } |
| 103 | 85 | ||
| 104 | static int vti_rcv(struct sk_buff *skb) | 86 | static int vti_rcv(struct sk_buff *skb, __be32 spi, bool update_skb_dev) |
| 105 | { | 87 | { |
| 106 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; | 88 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; |
| 107 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); | 89 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); |
| 108 | 90 | ||
| 109 | return vti_input(skb, ip_hdr(skb)->protocol, 0, 0); | 91 | return vti_input(skb, ip_hdr(skb)->protocol, spi, 0, update_skb_dev); |
| 110 | } | 92 | } |
| 111 | 93 | ||
| 112 | static int vti_rcv_ipip(struct sk_buff *skb) | 94 | static int vti_rcv_proto(struct sk_buff *skb) |
| 113 | { | 95 | { |
| 114 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; | 96 | return vti_rcv(skb, 0, false); |
| 115 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); | 97 | } |
| 116 | 98 | ||
| 117 | return vti_input_ipip(skb, ip_hdr(skb)->protocol, ip_hdr(skb)->saddr, 0); | 99 | static int vti_rcv_tunnel(struct sk_buff *skb) |
| 100 | { | ||
| 101 | return vti_rcv(skb, ip_hdr(skb)->saddr, true); | ||
| 118 | } | 102 | } |
| 119 | 103 | ||
| 120 | static int vti_rcv_cb(struct sk_buff *skb, int err) | 104 | static int vti_rcv_cb(struct sk_buff *skb, int err) |
| @@ -123,7 +107,7 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) | |||
| 123 | struct net_device *dev; | 107 | struct net_device *dev; |
| 124 | struct pcpu_sw_netstats *tstats; | 108 | struct pcpu_sw_netstats *tstats; |
| 125 | struct xfrm_state *x; | 109 | struct xfrm_state *x; |
| 126 | struct xfrm_mode *inner_mode; | 110 | const struct xfrm_mode *inner_mode; |
| 127 | struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4; | 111 | struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4; |
| 128 | u32 orig_mark = skb->mark; | 112 | u32 orig_mark = skb->mark; |
| 129 | int ret; | 113 | int ret; |
| @@ -142,7 +126,7 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) | |||
| 142 | 126 | ||
| 143 | x = xfrm_input_state(skb); | 127 | x = xfrm_input_state(skb); |
| 144 | 128 | ||
| 145 | inner_mode = x->inner_mode; | 129 | inner_mode = &x->inner_mode; |
| 146 | 130 | ||
| 147 | if (x->sel.family == AF_UNSPEC) { | 131 | if (x->sel.family == AF_UNSPEC) { |
| 148 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); | 132 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
| @@ -153,7 +137,7 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) | |||
| 153 | } | 137 | } |
| 154 | } | 138 | } |
| 155 | 139 | ||
| 156 | family = inner_mode->afinfo->family; | 140 | family = inner_mode->family; |
| 157 | 141 | ||
| 158 | skb->mark = be32_to_cpu(tunnel->parms.i_key); | 142 | skb->mark = be32_to_cpu(tunnel->parms.i_key); |
| 159 | ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family); | 143 | ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family); |
| @@ -447,31 +431,31 @@ static void __net_init vti_fb_tunnel_init(struct net_device *dev) | |||
| 447 | } | 431 | } |
| 448 | 432 | ||
| 449 | static struct xfrm4_protocol vti_esp4_protocol __read_mostly = { | 433 | static struct xfrm4_protocol vti_esp4_protocol __read_mostly = { |
| 450 | .handler = vti_rcv, | 434 | .handler = vti_rcv_proto, |
| 451 | .input_handler = vti_input, | 435 | .input_handler = vti_input_proto, |
| 452 | .cb_handler = vti_rcv_cb, | 436 | .cb_handler = vti_rcv_cb, |
| 453 | .err_handler = vti4_err, | 437 | .err_handler = vti4_err, |
| 454 | .priority = 100, | 438 | .priority = 100, |
| 455 | }; | 439 | }; |
| 456 | 440 | ||
| 457 | static struct xfrm4_protocol vti_ah4_protocol __read_mostly = { | 441 | static struct xfrm4_protocol vti_ah4_protocol __read_mostly = { |
| 458 | .handler = vti_rcv, | 442 | .handler = vti_rcv_proto, |
| 459 | .input_handler = vti_input, | 443 | .input_handler = vti_input_proto, |
| 460 | .cb_handler = vti_rcv_cb, | 444 | .cb_handler = vti_rcv_cb, |
| 461 | .err_handler = vti4_err, | 445 | .err_handler = vti4_err, |
| 462 | .priority = 100, | 446 | .priority = 100, |
| 463 | }; | 447 | }; |
| 464 | 448 | ||
| 465 | static struct xfrm4_protocol vti_ipcomp4_protocol __read_mostly = { | 449 | static struct xfrm4_protocol vti_ipcomp4_protocol __read_mostly = { |
| 466 | .handler = vti_rcv, | 450 | .handler = vti_rcv_proto, |
| 467 | .input_handler = vti_input, | 451 | .input_handler = vti_input_proto, |
| 468 | .cb_handler = vti_rcv_cb, | 452 | .cb_handler = vti_rcv_cb, |
| 469 | .err_handler = vti4_err, | 453 | .err_handler = vti4_err, |
| 470 | .priority = 100, | 454 | .priority = 100, |
| 471 | }; | 455 | }; |
| 472 | 456 | ||
| 473 | static struct xfrm_tunnel ipip_handler __read_mostly = { | 457 | static struct xfrm_tunnel ipip_handler __read_mostly = { |
| 474 | .handler = vti_rcv_ipip, | 458 | .handler = vti_rcv_tunnel, |
| 475 | .err_handler = vti4_err, | 459 | .err_handler = vti4_err, |
| 476 | .priority = 0, | 460 | .priority = 0, |
| 477 | }; | 461 | }; |
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c deleted file mode 100644 index 856d2dfdb44b..000000000000 --- a/net/ipv4/xfrm4_mode_beet.c +++ /dev/null | |||
| @@ -1,155 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com> | ||
| 5 | * Miika Komu <miika@iki.fi> | ||
| 6 | * Herbert Xu <herbert@gondor.apana.org.au> | ||
| 7 | * Abhinav Pathak <abhinav.pathak@hiit.fi> | ||
| 8 | * Jeff Ahrenholz <ahrenholz@gmail.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/stringify.h> | ||
| 16 | #include <net/dst.h> | ||
| 17 | #include <net/ip.h> | ||
| 18 | #include <net/xfrm.h> | ||
| 19 | |||
| 20 | static void xfrm4_beet_make_header(struct sk_buff *skb) | ||
| 21 | { | ||
| 22 | struct iphdr *iph = ip_hdr(skb); | ||
| 23 | |||
| 24 | iph->ihl = 5; | ||
| 25 | iph->version = 4; | ||
| 26 | |||
| 27 | iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol; | ||
| 28 | iph->tos = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 29 | |||
| 30 | iph->id = XFRM_MODE_SKB_CB(skb)->id; | ||
| 31 | iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off; | ||
| 32 | iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl; | ||
| 33 | } | ||
| 34 | |||
| 35 | /* Add encapsulation header. | ||
| 36 | * | ||
| 37 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
| 38 | */ | ||
| 39 | static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 40 | { | ||
| 41 | struct ip_beet_phdr *ph; | ||
| 42 | struct iphdr *top_iph; | ||
| 43 | int hdrlen, optlen; | ||
| 44 | |||
| 45 | hdrlen = 0; | ||
| 46 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | ||
| 47 | if (unlikely(optlen)) | ||
| 48 | hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
| 49 | |||
| 50 | skb_set_network_header(skb, -x->props.header_len - | ||
| 51 | hdrlen + (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph))); | ||
| 52 | if (x->sel.family != AF_INET6) | ||
| 53 | skb->network_header += IPV4_BEET_PHMAXLEN; | ||
| 54 | skb->mac_header = skb->network_header + | ||
| 55 | offsetof(struct iphdr, protocol); | ||
| 56 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 57 | |||
| 58 | xfrm4_beet_make_header(skb); | ||
| 59 | |||
| 60 | ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen); | ||
| 61 | |||
| 62 | top_iph = ip_hdr(skb); | ||
| 63 | |||
| 64 | if (unlikely(optlen)) { | ||
| 65 | BUG_ON(optlen < 0); | ||
| 66 | |||
| 67 | ph->padlen = 4 - (optlen & 4); | ||
| 68 | ph->hdrlen = optlen / 8; | ||
| 69 | ph->nexthdr = top_iph->protocol; | ||
| 70 | if (ph->padlen) | ||
| 71 | memset(ph + 1, IPOPT_NOP, ph->padlen); | ||
| 72 | |||
| 73 | top_iph->protocol = IPPROTO_BEETPH; | ||
| 74 | top_iph->ihl = sizeof(struct iphdr) / 4; | ||
| 75 | } | ||
| 76 | |||
| 77 | top_iph->saddr = x->props.saddr.a4; | ||
| 78 | top_iph->daddr = x->id.daddr.a4; | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 84 | { | ||
| 85 | struct iphdr *iph; | ||
| 86 | int optlen = 0; | ||
| 87 | int err = -EINVAL; | ||
| 88 | |||
| 89 | if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) { | ||
| 90 | struct ip_beet_phdr *ph; | ||
| 91 | int phlen; | ||
| 92 | |||
| 93 | if (!pskb_may_pull(skb, sizeof(*ph))) | ||
| 94 | goto out; | ||
| 95 | |||
| 96 | ph = (struct ip_beet_phdr *)skb->data; | ||
| 97 | |||
| 98 | phlen = sizeof(*ph) + ph->padlen; | ||
| 99 | optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen); | ||
| 100 | if (optlen < 0 || optlen & 3 || optlen > 250) | ||
| 101 | goto out; | ||
| 102 | |||
| 103 | XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr; | ||
| 104 | |||
| 105 | if (!pskb_may_pull(skb, phlen)) | ||
| 106 | goto out; | ||
| 107 | __skb_pull(skb, phlen); | ||
| 108 | } | ||
| 109 | |||
| 110 | skb_push(skb, sizeof(*iph)); | ||
| 111 | skb_reset_network_header(skb); | ||
| 112 | skb_mac_header_rebuild(skb); | ||
| 113 | |||
| 114 | xfrm4_beet_make_header(skb); | ||
| 115 | |||
| 116 | iph = ip_hdr(skb); | ||
| 117 | |||
| 118 | iph->ihl += optlen / 4; | ||
| 119 | iph->tot_len = htons(skb->len); | ||
| 120 | iph->daddr = x->sel.daddr.a4; | ||
| 121 | iph->saddr = x->sel.saddr.a4; | ||
| 122 | iph->check = 0; | ||
| 123 | iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); | ||
| 124 | err = 0; | ||
| 125 | out: | ||
| 126 | return err; | ||
| 127 | } | ||
| 128 | |||
| 129 | static struct xfrm_mode xfrm4_beet_mode = { | ||
| 130 | .input2 = xfrm4_beet_input, | ||
| 131 | .input = xfrm_prepare_input, | ||
| 132 | .output2 = xfrm4_beet_output, | ||
| 133 | .output = xfrm4_prepare_output, | ||
| 134 | .owner = THIS_MODULE, | ||
| 135 | .encap = XFRM_MODE_BEET, | ||
| 136 | .flags = XFRM_MODE_FLAG_TUNNEL, | ||
| 137 | }; | ||
| 138 | |||
| 139 | static int __init xfrm4_beet_init(void) | ||
| 140 | { | ||
| 141 | return xfrm_register_mode(&xfrm4_beet_mode, AF_INET); | ||
| 142 | } | ||
| 143 | |||
| 144 | static void __exit xfrm4_beet_exit(void) | ||
| 145 | { | ||
| 146 | int err; | ||
| 147 | |||
| 148 | err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET); | ||
| 149 | BUG_ON(err); | ||
| 150 | } | ||
| 151 | |||
| 152 | module_init(xfrm4_beet_init); | ||
| 153 | module_exit(xfrm4_beet_exit); | ||
| 154 | MODULE_LICENSE("GPL"); | ||
| 155 | MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET); | ||
diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c deleted file mode 100644 index 1ad2c2c4e250..000000000000 --- a/net/ipv4/xfrm4_mode_transport.c +++ /dev/null | |||
| @@ -1,114 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * xfrm4_mode_transport.c - Transport mode encapsulation for IPv4. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/init.h> | ||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/skbuff.h> | ||
| 11 | #include <linux/stringify.h> | ||
| 12 | #include <net/dst.h> | ||
| 13 | #include <net/ip.h> | ||
| 14 | #include <net/xfrm.h> | ||
| 15 | #include <net/protocol.h> | ||
| 16 | |||
| 17 | /* Add encapsulation header. | ||
| 18 | * | ||
| 19 | * The IP header will be moved forward to make space for the encapsulation | ||
| 20 | * header. | ||
| 21 | */ | ||
| 22 | static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 23 | { | ||
| 24 | struct iphdr *iph = ip_hdr(skb); | ||
| 25 | int ihl = iph->ihl * 4; | ||
| 26 | |||
| 27 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 28 | |||
| 29 | skb_set_network_header(skb, -x->props.header_len); | ||
| 30 | skb->mac_header = skb->network_header + | ||
| 31 | offsetof(struct iphdr, protocol); | ||
| 32 | skb->transport_header = skb->network_header + ihl; | ||
| 33 | __skb_pull(skb, ihl); | ||
| 34 | memmove(skb_network_header(skb), iph, ihl); | ||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | /* Remove encapsulation header. | ||
| 39 | * | ||
| 40 | * The IP header will be moved over the top of the encapsulation header. | ||
| 41 | * | ||
| 42 | * On entry, skb->h shall point to where the IP header should be and skb->nh | ||
| 43 | * shall be set to where the IP header currently is. skb->data shall point | ||
| 44 | * to the start of the payload. | ||
| 45 | */ | ||
| 46 | static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 47 | { | ||
| 48 | int ihl = skb->data - skb_transport_header(skb); | ||
| 49 | |||
| 50 | if (skb->transport_header != skb->network_header) { | ||
| 51 | memmove(skb_transport_header(skb), | ||
| 52 | skb_network_header(skb), ihl); | ||
| 53 | skb->network_header = skb->transport_header; | ||
| 54 | } | ||
| 55 | ip_hdr(skb)->tot_len = htons(skb->len + ihl); | ||
| 56 | skb_reset_transport_header(skb); | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x, | ||
| 61 | struct sk_buff *skb, | ||
| 62 | netdev_features_t features) | ||
| 63 | { | ||
| 64 | const struct net_offload *ops; | ||
| 65 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 66 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 67 | |||
| 68 | skb->transport_header += x->props.header_len; | ||
| 69 | ops = rcu_dereference(inet_offloads[xo->proto]); | ||
| 70 | if (likely(ops && ops->callbacks.gso_segment)) | ||
| 71 | segs = ops->callbacks.gso_segment(skb, features); | ||
| 72 | |||
| 73 | return segs; | ||
| 74 | } | ||
| 75 | |||
| 76 | static void xfrm4_transport_xmit(struct xfrm_state *x, struct sk_buff *skb) | ||
| 77 | { | ||
| 78 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 79 | |||
| 80 | skb_reset_mac_len(skb); | ||
| 81 | pskb_pull(skb, skb->mac_len + sizeof(struct iphdr) + x->props.header_len); | ||
| 82 | |||
| 83 | if (xo->flags & XFRM_GSO_SEGMENT) { | ||
| 84 | skb_reset_transport_header(skb); | ||
| 85 | skb->transport_header -= x->props.header_len; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | static struct xfrm_mode xfrm4_transport_mode = { | ||
| 90 | .input = xfrm4_transport_input, | ||
| 91 | .output = xfrm4_transport_output, | ||
| 92 | .gso_segment = xfrm4_transport_gso_segment, | ||
| 93 | .xmit = xfrm4_transport_xmit, | ||
| 94 | .owner = THIS_MODULE, | ||
| 95 | .encap = XFRM_MODE_TRANSPORT, | ||
| 96 | }; | ||
| 97 | |||
| 98 | static int __init xfrm4_transport_init(void) | ||
| 99 | { | ||
| 100 | return xfrm_register_mode(&xfrm4_transport_mode, AF_INET); | ||
| 101 | } | ||
| 102 | |||
| 103 | static void __exit xfrm4_transport_exit(void) | ||
| 104 | { | ||
| 105 | int err; | ||
| 106 | |||
| 107 | err = xfrm_unregister_mode(&xfrm4_transport_mode, AF_INET); | ||
| 108 | BUG_ON(err); | ||
| 109 | } | ||
| 110 | |||
| 111 | module_init(xfrm4_transport_init); | ||
| 112 | module_exit(xfrm4_transport_exit); | ||
| 113 | MODULE_LICENSE("GPL"); | ||
| 114 | MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TRANSPORT); | ||
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c deleted file mode 100644 index 2a9764bd1719..000000000000 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ /dev/null | |||
| @@ -1,152 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * xfrm4_mode_tunnel.c - Tunnel mode encapsulation for IPv4. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/gfp.h> | ||
| 8 | #include <linux/init.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/skbuff.h> | ||
| 12 | #include <linux/stringify.h> | ||
| 13 | #include <net/dst.h> | ||
| 14 | #include <net/inet_ecn.h> | ||
| 15 | #include <net/ip.h> | ||
| 16 | #include <net/xfrm.h> | ||
| 17 | |||
| 18 | static inline void ipip_ecn_decapsulate(struct sk_buff *skb) | ||
| 19 | { | ||
| 20 | struct iphdr *inner_iph = ipip_hdr(skb); | ||
| 21 | |||
| 22 | if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) | ||
| 23 | IP_ECN_set_ce(inner_iph); | ||
| 24 | } | ||
| 25 | |||
| 26 | /* Add encapsulation header. | ||
| 27 | * | ||
| 28 | * The top IP header will be constructed per RFC 2401. | ||
| 29 | */ | ||
| 30 | static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 31 | { | ||
| 32 | struct dst_entry *dst = skb_dst(skb); | ||
| 33 | struct iphdr *top_iph; | ||
| 34 | int flags; | ||
| 35 | |||
| 36 | skb_set_inner_network_header(skb, skb_network_offset(skb)); | ||
| 37 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 38 | |||
| 39 | skb_set_network_header(skb, -x->props.header_len); | ||
| 40 | skb->mac_header = skb->network_header + | ||
| 41 | offsetof(struct iphdr, protocol); | ||
| 42 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 43 | top_iph = ip_hdr(skb); | ||
| 44 | |||
| 45 | top_iph->ihl = 5; | ||
| 46 | top_iph->version = 4; | ||
| 47 | |||
| 48 | top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); | ||
| 49 | |||
| 50 | /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */ | ||
| 51 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) | ||
| 52 | top_iph->tos = 0; | ||
| 53 | else | ||
| 54 | top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 55 | top_iph->tos = INET_ECN_encapsulate(top_iph->tos, | ||
| 56 | XFRM_MODE_SKB_CB(skb)->tos); | ||
| 57 | |||
| 58 | flags = x->props.flags; | ||
| 59 | if (flags & XFRM_STATE_NOECN) | ||
| 60 | IP_ECN_clear(top_iph); | ||
| 61 | |||
| 62 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
| 63 | 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); | ||
| 64 | |||
| 65 | top_iph->ttl = ip4_dst_hoplimit(xfrm_dst_child(dst)); | ||
| 66 | |||
| 67 | top_iph->saddr = x->props.saddr.a4; | ||
| 68 | top_iph->daddr = x->id.daddr.a4; | ||
| 69 | ip_select_ident(dev_net(dst->dev), skb, NULL); | ||
| 70 | |||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 75 | { | ||
| 76 | int err = -EINVAL; | ||
| 77 | |||
| 78 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) | ||
| 79 | goto out; | ||
| 80 | |||
| 81 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | ||
| 82 | goto out; | ||
| 83 | |||
| 84 | err = skb_unclone(skb, GFP_ATOMIC); | ||
| 85 | if (err) | ||
| 86 | goto out; | ||
| 87 | |||
| 88 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
| 89 | ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); | ||
| 90 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
| 91 | ipip_ecn_decapsulate(skb); | ||
| 92 | |||
| 93 | skb_reset_network_header(skb); | ||
| 94 | skb_mac_header_rebuild(skb); | ||
| 95 | if (skb->mac_len) | ||
| 96 | eth_hdr(skb)->h_proto = skb->protocol; | ||
| 97 | |||
| 98 | err = 0; | ||
| 99 | |||
| 100 | out: | ||
| 101 | return err; | ||
| 102 | } | ||
| 103 | |||
| 104 | static struct sk_buff *xfrm4_mode_tunnel_gso_segment(struct xfrm_state *x, | ||
| 105 | struct sk_buff *skb, | ||
| 106 | netdev_features_t features) | ||
| 107 | { | ||
| 108 | __skb_push(skb, skb->mac_len); | ||
| 109 | return skb_mac_gso_segment(skb, features); | ||
| 110 | } | ||
| 111 | |||
| 112 | static void xfrm4_mode_tunnel_xmit(struct xfrm_state *x, struct sk_buff *skb) | ||
| 113 | { | ||
| 114 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 115 | |||
| 116 | if (xo->flags & XFRM_GSO_SEGMENT) | ||
| 117 | skb->transport_header = skb->network_header + | ||
| 118 | sizeof(struct iphdr); | ||
| 119 | |||
| 120 | skb_reset_mac_len(skb); | ||
| 121 | pskb_pull(skb, skb->mac_len + x->props.header_len); | ||
| 122 | } | ||
| 123 | |||
| 124 | static struct xfrm_mode xfrm4_tunnel_mode = { | ||
| 125 | .input2 = xfrm4_mode_tunnel_input, | ||
| 126 | .input = xfrm_prepare_input, | ||
| 127 | .output2 = xfrm4_mode_tunnel_output, | ||
| 128 | .output = xfrm4_prepare_output, | ||
| 129 | .gso_segment = xfrm4_mode_tunnel_gso_segment, | ||
| 130 | .xmit = xfrm4_mode_tunnel_xmit, | ||
| 131 | .owner = THIS_MODULE, | ||
| 132 | .encap = XFRM_MODE_TUNNEL, | ||
| 133 | .flags = XFRM_MODE_FLAG_TUNNEL, | ||
| 134 | }; | ||
| 135 | |||
| 136 | static int __init xfrm4_mode_tunnel_init(void) | ||
| 137 | { | ||
| 138 | return xfrm_register_mode(&xfrm4_tunnel_mode, AF_INET); | ||
| 139 | } | ||
| 140 | |||
| 141 | static void __exit xfrm4_mode_tunnel_exit(void) | ||
| 142 | { | ||
| 143 | int err; | ||
| 144 | |||
| 145 | err = xfrm_unregister_mode(&xfrm4_tunnel_mode, AF_INET); | ||
| 146 | BUG_ON(err); | ||
| 147 | } | ||
| 148 | |||
| 149 | module_init(xfrm4_mode_tunnel_init); | ||
| 150 | module_exit(xfrm4_mode_tunnel_exit); | ||
| 151 | MODULE_LICENSE("GPL"); | ||
| 152 | MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TUNNEL); | ||
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index be980c195fc5..9bb8905088c7 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
| @@ -58,21 +58,6 @@ int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 58 | return xfrm4_extract_header(skb); | 58 | return xfrm4_extract_header(skb); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 62 | { | ||
| 63 | int err; | ||
| 64 | |||
| 65 | err = xfrm_inner_extract_output(x, skb); | ||
| 66 | if (err) | ||
| 67 | return err; | ||
| 68 | |||
| 69 | IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; | ||
| 70 | skb->protocol = htons(ETH_P_IP); | ||
| 71 | |||
| 72 | return x->outer_mode->output2(x, skb); | ||
| 73 | } | ||
| 74 | EXPORT_SYMBOL(xfrm4_prepare_output); | ||
| 75 | |||
| 76 | int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb) | 61 | int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb) |
| 77 | { | 62 | { |
| 78 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | 63 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); |
| @@ -87,6 +72,8 @@ int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb) | |||
| 87 | static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) | 72 | static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) |
| 88 | { | 73 | { |
| 89 | struct xfrm_state *x = skb_dst(skb)->xfrm; | 74 | struct xfrm_state *x = skb_dst(skb)->xfrm; |
| 75 | const struct xfrm_state_afinfo *afinfo; | ||
| 76 | int ret = -EAFNOSUPPORT; | ||
| 90 | 77 | ||
| 91 | #ifdef CONFIG_NETFILTER | 78 | #ifdef CONFIG_NETFILTER |
| 92 | if (!x) { | 79 | if (!x) { |
| @@ -95,7 +82,15 @@ static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) | |||
| 95 | } | 82 | } |
| 96 | #endif | 83 | #endif |
| 97 | 84 | ||
| 98 | return x->outer_mode->afinfo->output_finish(sk, skb); | 85 | rcu_read_lock(); |
| 86 | afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode.family); | ||
| 87 | if (likely(afinfo)) | ||
| 88 | ret = afinfo->output_finish(sk, skb); | ||
| 89 | else | ||
| 90 | kfree_skb(skb); | ||
| 91 | rcu_read_unlock(); | ||
| 92 | |||
| 93 | return ret; | ||
| 99 | } | 94 | } |
| 100 | 95 | ||
| 101 | int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) | 96 | int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 72d19b1838ed..cdef8f9a3b01 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include <linux/err.h> | 12 | #include <linux/err.h> |
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/inetdevice.h> | 14 | #include <linux/inetdevice.h> |
| 15 | #include <linux/if_tunnel.h> | ||
| 16 | #include <net/dst.h> | 15 | #include <net/dst.h> |
| 17 | #include <net/xfrm.h> | 16 | #include <net/xfrm.h> |
| 18 | #include <net/ip.h> | 17 | #include <net/ip.h> |
| @@ -69,17 +68,6 @@ static int xfrm4_get_saddr(struct net *net, int oif, | |||
| 69 | return 0; | 68 | return 0; |
| 70 | } | 69 | } |
| 71 | 70 | ||
| 72 | static int xfrm4_get_tos(const struct flowi *fl) | ||
| 73 | { | ||
| 74 | return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos; /* Strip ECN bits */ | ||
| 75 | } | ||
| 76 | |||
| 77 | static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, | ||
| 78 | int nfheader_len) | ||
| 79 | { | ||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | 71 | static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
| 84 | const struct flowi *fl) | 72 | const struct flowi *fl) |
| 85 | { | 73 | { |
| @@ -110,118 +98,6 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
| 110 | return 0; | 98 | return 0; |
| 111 | } | 99 | } |
| 112 | 100 | ||
| 113 | static void | ||
| 114 | _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | ||
| 115 | { | ||
| 116 | const struct iphdr *iph = ip_hdr(skb); | ||
| 117 | u8 *xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 118 | struct flowi4 *fl4 = &fl->u.ip4; | ||
| 119 | int oif = 0; | ||
| 120 | |||
| 121 | if (skb_dst(skb)) | ||
| 122 | oif = skb_dst(skb)->dev->ifindex; | ||
| 123 | |||
| 124 | memset(fl4, 0, sizeof(struct flowi4)); | ||
| 125 | fl4->flowi4_mark = skb->mark; | ||
| 126 | fl4->flowi4_oif = reverse ? skb->skb_iif : oif; | ||
| 127 | |||
| 128 | if (!ip_is_fragment(iph)) { | ||
| 129 | switch (iph->protocol) { | ||
| 130 | case IPPROTO_UDP: | ||
| 131 | case IPPROTO_UDPLITE: | ||
| 132 | case IPPROTO_TCP: | ||
| 133 | case IPPROTO_SCTP: | ||
| 134 | case IPPROTO_DCCP: | ||
| 135 | if (xprth + 4 < skb->data || | ||
| 136 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 137 | __be16 *ports; | ||
| 138 | |||
| 139 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 140 | ports = (__be16 *)xprth; | ||
| 141 | |||
| 142 | fl4->fl4_sport = ports[!!reverse]; | ||
| 143 | fl4->fl4_dport = ports[!reverse]; | ||
| 144 | } | ||
| 145 | break; | ||
| 146 | |||
| 147 | case IPPROTO_ICMP: | ||
| 148 | if (xprth + 2 < skb->data || | ||
| 149 | pskb_may_pull(skb, xprth + 2 - skb->data)) { | ||
| 150 | u8 *icmp; | ||
| 151 | |||
| 152 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 153 | icmp = xprth; | ||
| 154 | |||
| 155 | fl4->fl4_icmp_type = icmp[0]; | ||
| 156 | fl4->fl4_icmp_code = icmp[1]; | ||
| 157 | } | ||
| 158 | break; | ||
| 159 | |||
| 160 | case IPPROTO_ESP: | ||
| 161 | if (xprth + 4 < skb->data || | ||
| 162 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 163 | __be32 *ehdr; | ||
| 164 | |||
| 165 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 166 | ehdr = (__be32 *)xprth; | ||
| 167 | |||
| 168 | fl4->fl4_ipsec_spi = ehdr[0]; | ||
| 169 | } | ||
| 170 | break; | ||
| 171 | |||
| 172 | case IPPROTO_AH: | ||
| 173 | if (xprth + 8 < skb->data || | ||
| 174 | pskb_may_pull(skb, xprth + 8 - skb->data)) { | ||
| 175 | __be32 *ah_hdr; | ||
| 176 | |||
| 177 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 178 | ah_hdr = (__be32 *)xprth; | ||
| 179 | |||
| 180 | fl4->fl4_ipsec_spi = ah_hdr[1]; | ||
| 181 | } | ||
| 182 | break; | ||
| 183 | |||
| 184 | case IPPROTO_COMP: | ||
| 185 | if (xprth + 4 < skb->data || | ||
| 186 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 187 | __be16 *ipcomp_hdr; | ||
| 188 | |||
| 189 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 190 | ipcomp_hdr = (__be16 *)xprth; | ||
| 191 | |||
| 192 | fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); | ||
| 193 | } | ||
| 194 | break; | ||
| 195 | |||
| 196 | case IPPROTO_GRE: | ||
| 197 | if (xprth + 12 < skb->data || | ||
| 198 | pskb_may_pull(skb, xprth + 12 - skb->data)) { | ||
| 199 | __be16 *greflags; | ||
| 200 | __be32 *gre_hdr; | ||
| 201 | |||
| 202 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 203 | greflags = (__be16 *)xprth; | ||
| 204 | gre_hdr = (__be32 *)xprth; | ||
| 205 | |||
| 206 | if (greflags[0] & GRE_KEY) { | ||
| 207 | if (greflags[0] & GRE_CSUM) | ||
| 208 | gre_hdr++; | ||
| 209 | fl4->fl4_gre_key = gre_hdr[1]; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | break; | ||
| 213 | |||
| 214 | default: | ||
| 215 | fl4->fl4_ipsec_spi = 0; | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | fl4->flowi4_proto = iph->protocol; | ||
| 220 | fl4->daddr = reverse ? iph->saddr : iph->daddr; | ||
| 221 | fl4->saddr = reverse ? iph->daddr : iph->saddr; | ||
| 222 | fl4->flowi4_tos = iph->tos; | ||
| 223 | } | ||
| 224 | |||
| 225 | static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk, | 101 | static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| 226 | struct sk_buff *skb, u32 mtu) | 102 | struct sk_buff *skb, u32 mtu) |
| 227 | { | 103 | { |
| @@ -274,9 +150,6 @@ static const struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | |||
| 274 | .dst_ops = &xfrm4_dst_ops_template, | 150 | .dst_ops = &xfrm4_dst_ops_template, |
| 275 | .dst_lookup = xfrm4_dst_lookup, | 151 | .dst_lookup = xfrm4_dst_lookup, |
| 276 | .get_saddr = xfrm4_get_saddr, | 152 | .get_saddr = xfrm4_get_saddr, |
| 277 | .decode_session = _decode_session4, | ||
| 278 | .get_tos = xfrm4_get_tos, | ||
| 279 | .init_path = xfrm4_init_path, | ||
| 280 | .fill_dst = xfrm4_fill_dst, | 153 | .fill_dst = xfrm4_fill_dst, |
| 281 | .blackhole_route = ipv4_blackhole_route, | 154 | .blackhole_route = ipv4_blackhole_route, |
| 282 | }; | 155 | }; |
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index 35c54865dc42..bcab48944c15 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c | |||
| @@ -46,7 +46,7 @@ static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol) | |||
| 46 | handler != NULL; \ | 46 | handler != NULL; \ |
| 47 | handler = rcu_dereference(handler->next)) \ | 47 | handler = rcu_dereference(handler->next)) \ |
| 48 | 48 | ||
| 49 | int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err) | 49 | static int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err) |
| 50 | { | 50 | { |
| 51 | int ret; | 51 | int ret; |
| 52 | struct xfrm4_protocol *handler; | 52 | struct xfrm4_protocol *handler; |
| @@ -61,7 +61,6 @@ int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err) | |||
| 61 | 61 | ||
| 62 | return 0; | 62 | return 0; |
| 63 | } | 63 | } |
| 64 | EXPORT_SYMBOL(xfrm4_rcv_cb); | ||
| 65 | 64 | ||
| 66 | int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, | 65 | int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, |
| 67 | int encap_type) | 66 | int encap_type) |
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 613282c65a10..cd915e332c98 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
| @@ -135,44 +135,11 @@ config INET6_TUNNEL | |||
| 135 | tristate | 135 | tristate |
| 136 | default n | 136 | default n |
| 137 | 137 | ||
| 138 | config INET6_XFRM_MODE_TRANSPORT | ||
| 139 | tristate "IPv6: IPsec transport mode" | ||
| 140 | default IPV6 | ||
| 141 | select XFRM | ||
| 142 | ---help--- | ||
| 143 | Support for IPsec transport mode. | ||
| 144 | |||
| 145 | If unsure, say Y. | ||
| 146 | |||
| 147 | config INET6_XFRM_MODE_TUNNEL | ||
| 148 | tristate "IPv6: IPsec tunnel mode" | ||
| 149 | default IPV6 | ||
| 150 | select XFRM | ||
| 151 | ---help--- | ||
| 152 | Support for IPsec tunnel mode. | ||
| 153 | |||
| 154 | If unsure, say Y. | ||
| 155 | |||
| 156 | config INET6_XFRM_MODE_BEET | ||
| 157 | tristate "IPv6: IPsec BEET mode" | ||
| 158 | default IPV6 | ||
| 159 | select XFRM | ||
| 160 | ---help--- | ||
| 161 | Support for IPsec BEET mode. | ||
| 162 | |||
| 163 | If unsure, say Y. | ||
| 164 | |||
| 165 | config INET6_XFRM_MODE_ROUTEOPTIMIZATION | ||
| 166 | tristate "IPv6: MIPv6 route optimization mode" | ||
| 167 | select XFRM | ||
| 168 | ---help--- | ||
| 169 | Support for MIPv6 route optimization mode. | ||
| 170 | |||
| 171 | config IPV6_VTI | 138 | config IPV6_VTI |
| 172 | tristate "Virtual (secure) IPv6: tunneling" | 139 | tristate "Virtual (secure) IPv6: tunneling" |
| 173 | select IPV6_TUNNEL | 140 | select IPV6_TUNNEL |
| 174 | select NET_IP_TUNNEL | 141 | select NET_IP_TUNNEL |
| 175 | depends on INET6_XFRM_MODE_TUNNEL | 142 | select XFRM |
| 176 | ---help--- | 143 | ---help--- |
| 177 | Tunneling means encapsulating data of one protocol type within | 144 | Tunneling means encapsulating data of one protocol type within |
| 178 | another protocol and sending it over a channel that understands the | 145 | another protocol and sending it over a channel that understands the |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index e0026fa1261b..8ccf35514015 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
| @@ -35,10 +35,6 @@ obj-$(CONFIG_INET6_ESP_OFFLOAD) += esp6_offload.o | |||
| 35 | obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o | 35 | obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o |
| 36 | obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o | 36 | obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o |
| 37 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o | 37 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o |
| 38 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o | ||
| 39 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o | ||
| 40 | obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o | ||
| 41 | obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o | ||
| 42 | obj-$(CONFIG_IPV6_MIP6) += mip6.o | 38 | obj-$(CONFIG_IPV6_MIP6) += mip6.o |
| 43 | obj-$(CONFIG_IPV6_ILA) += ila/ | 39 | obj-$(CONFIG_IPV6_ILA) += ila/ |
| 44 | obj-$(CONFIG_NETFILTER) += netfilter/ | 40 | obj-$(CONFIG_NETFILTER) += netfilter/ |
diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c index d46b4eb645c2..bff83279d76f 100644 --- a/net/ipv6/esp6_offload.c +++ b/net/ipv6/esp6_offload.c | |||
| @@ -134,6 +134,44 @@ static void esp6_gso_encap(struct xfrm_state *x, struct sk_buff *skb) | |||
| 134 | xo->proto = proto; | 134 | xo->proto = proto; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x, | ||
| 138 | struct sk_buff *skb, | ||
| 139 | netdev_features_t features) | ||
| 140 | { | ||
| 141 | __skb_push(skb, skb->mac_len); | ||
| 142 | return skb_mac_gso_segment(skb, features); | ||
| 143 | } | ||
| 144 | |||
| 145 | static struct sk_buff *xfrm6_transport_gso_segment(struct xfrm_state *x, | ||
| 146 | struct sk_buff *skb, | ||
| 147 | netdev_features_t features) | ||
| 148 | { | ||
| 149 | const struct net_offload *ops; | ||
| 150 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 151 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 152 | |||
| 153 | skb->transport_header += x->props.header_len; | ||
| 154 | ops = rcu_dereference(inet6_offloads[xo->proto]); | ||
| 155 | if (likely(ops && ops->callbacks.gso_segment)) | ||
| 156 | segs = ops->callbacks.gso_segment(skb, features); | ||
| 157 | |||
| 158 | return segs; | ||
| 159 | } | ||
| 160 | |||
| 161 | static struct sk_buff *xfrm6_outer_mode_gso_segment(struct xfrm_state *x, | ||
| 162 | struct sk_buff *skb, | ||
| 163 | netdev_features_t features) | ||
| 164 | { | ||
| 165 | switch (x->outer_mode.encap) { | ||
| 166 | case XFRM_MODE_TUNNEL: | ||
| 167 | return xfrm6_tunnel_gso_segment(x, skb, features); | ||
| 168 | case XFRM_MODE_TRANSPORT: | ||
| 169 | return xfrm6_transport_gso_segment(x, skb, features); | ||
| 170 | } | ||
| 171 | |||
| 172 | return ERR_PTR(-EOPNOTSUPP); | ||
| 173 | } | ||
| 174 | |||
| 137 | static struct sk_buff *esp6_gso_segment(struct sk_buff *skb, | 175 | static struct sk_buff *esp6_gso_segment(struct sk_buff *skb, |
| 138 | netdev_features_t features) | 176 | netdev_features_t features) |
| 139 | { | 177 | { |
| @@ -172,7 +210,7 @@ static struct sk_buff *esp6_gso_segment(struct sk_buff *skb, | |||
| 172 | 210 | ||
| 173 | xo->flags |= XFRM_GSO_SEGMENT; | 211 | xo->flags |= XFRM_GSO_SEGMENT; |
| 174 | 212 | ||
| 175 | return x->outer_mode->gso_segment(x, skb, esp_features); | 213 | return xfrm6_outer_mode_gso_segment(x, skb, esp_features); |
| 176 | } | 214 | } |
| 177 | 215 | ||
| 178 | static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb) | 216 | static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb) |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 8b6eefff2f7e..218a0dedc8f4 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
| @@ -342,7 +342,7 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err) | |||
| 342 | struct net_device *dev; | 342 | struct net_device *dev; |
| 343 | struct pcpu_sw_netstats *tstats; | 343 | struct pcpu_sw_netstats *tstats; |
| 344 | struct xfrm_state *x; | 344 | struct xfrm_state *x; |
| 345 | struct xfrm_mode *inner_mode; | 345 | const struct xfrm_mode *inner_mode; |
| 346 | struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6; | 346 | struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6; |
| 347 | u32 orig_mark = skb->mark; | 347 | u32 orig_mark = skb->mark; |
| 348 | int ret; | 348 | int ret; |
| @@ -361,7 +361,7 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err) | |||
| 361 | 361 | ||
| 362 | x = xfrm_input_state(skb); | 362 | x = xfrm_input_state(skb); |
| 363 | 363 | ||
| 364 | inner_mode = x->inner_mode; | 364 | inner_mode = &x->inner_mode; |
| 365 | 365 | ||
| 366 | if (x->sel.family == AF_UNSPEC) { | 366 | if (x->sel.family == AF_UNSPEC) { |
| 367 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); | 367 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
| @@ -372,7 +372,7 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err) | |||
| 372 | } | 372 | } |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | family = inner_mode->afinfo->family; | 375 | family = inner_mode->family; |
| 376 | 376 | ||
| 377 | skb->mark = be32_to_cpu(t->parms.i_key); | 377 | skb->mark = be32_to_cpu(t->parms.i_key); |
| 378 | ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family); | 378 | ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family); |
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c deleted file mode 100644 index 57fd314ec2b8..000000000000 --- a/net/ipv6/xfrm6_mode_beet.c +++ /dev/null | |||
| @@ -1,131 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com> | ||
| 5 | * Miika Komu <miika@iki.fi> | ||
| 6 | * Herbert Xu <herbert@gondor.apana.org.au> | ||
| 7 | * Abhinav Pathak <abhinav.pathak@hiit.fi> | ||
| 8 | * Jeff Ahrenholz <ahrenholz@gmail.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/stringify.h> | ||
| 16 | #include <net/dsfield.h> | ||
| 17 | #include <net/dst.h> | ||
| 18 | #include <net/inet_ecn.h> | ||
| 19 | #include <net/ipv6.h> | ||
| 20 | #include <net/xfrm.h> | ||
| 21 | |||
| 22 | static void xfrm6_beet_make_header(struct sk_buff *skb) | ||
| 23 | { | ||
| 24 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 25 | |||
| 26 | iph->version = 6; | ||
| 27 | |||
| 28 | memcpy(iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | ||
| 29 | sizeof(iph->flow_lbl)); | ||
| 30 | iph->nexthdr = XFRM_MODE_SKB_CB(skb)->protocol; | ||
| 31 | |||
| 32 | ipv6_change_dsfield(iph, 0, XFRM_MODE_SKB_CB(skb)->tos); | ||
| 33 | iph->hop_limit = XFRM_MODE_SKB_CB(skb)->ttl; | ||
| 34 | } | ||
| 35 | |||
| 36 | /* Add encapsulation header. | ||
| 37 | * | ||
| 38 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
| 39 | */ | ||
| 40 | static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 41 | { | ||
| 42 | struct ipv6hdr *top_iph; | ||
| 43 | struct ip_beet_phdr *ph; | ||
| 44 | int optlen, hdr_len; | ||
| 45 | |||
| 46 | hdr_len = 0; | ||
| 47 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | ||
| 48 | if (unlikely(optlen)) | ||
| 49 | hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
| 50 | |||
| 51 | skb_set_network_header(skb, -x->props.header_len - hdr_len); | ||
| 52 | if (x->sel.family != AF_INET6) | ||
| 53 | skb->network_header += IPV4_BEET_PHMAXLEN; | ||
| 54 | skb->mac_header = skb->network_header + | ||
| 55 | offsetof(struct ipv6hdr, nexthdr); | ||
| 56 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 57 | ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdr_len); | ||
| 58 | |||
| 59 | xfrm6_beet_make_header(skb); | ||
| 60 | |||
| 61 | top_iph = ipv6_hdr(skb); | ||
| 62 | if (unlikely(optlen)) { | ||
| 63 | |||
| 64 | BUG_ON(optlen < 0); | ||
| 65 | |||
| 66 | ph->padlen = 4 - (optlen & 4); | ||
| 67 | ph->hdrlen = optlen / 8; | ||
| 68 | ph->nexthdr = top_iph->nexthdr; | ||
| 69 | if (ph->padlen) | ||
| 70 | memset(ph + 1, IPOPT_NOP, ph->padlen); | ||
| 71 | |||
| 72 | top_iph->nexthdr = IPPROTO_BEETPH; | ||
| 73 | } | ||
| 74 | |||
| 75 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; | ||
| 76 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 81 | { | ||
| 82 | struct ipv6hdr *ip6h; | ||
| 83 | int size = sizeof(struct ipv6hdr); | ||
| 84 | int err; | ||
| 85 | |||
| 86 | err = skb_cow_head(skb, size + skb->mac_len); | ||
| 87 | if (err) | ||
| 88 | goto out; | ||
| 89 | |||
| 90 | __skb_push(skb, size); | ||
| 91 | skb_reset_network_header(skb); | ||
| 92 | skb_mac_header_rebuild(skb); | ||
| 93 | |||
| 94 | xfrm6_beet_make_header(skb); | ||
| 95 | |||
| 96 | ip6h = ipv6_hdr(skb); | ||
| 97 | ip6h->payload_len = htons(skb->len - size); | ||
| 98 | ip6h->daddr = x->sel.daddr.in6; | ||
| 99 | ip6h->saddr = x->sel.saddr.in6; | ||
| 100 | err = 0; | ||
| 101 | out: | ||
| 102 | return err; | ||
| 103 | } | ||
| 104 | |||
| 105 | static struct xfrm_mode xfrm6_beet_mode = { | ||
| 106 | .input2 = xfrm6_beet_input, | ||
| 107 | .input = xfrm_prepare_input, | ||
| 108 | .output2 = xfrm6_beet_output, | ||
| 109 | .output = xfrm6_prepare_output, | ||
| 110 | .owner = THIS_MODULE, | ||
| 111 | .encap = XFRM_MODE_BEET, | ||
| 112 | .flags = XFRM_MODE_FLAG_TUNNEL, | ||
| 113 | }; | ||
| 114 | |||
| 115 | static int __init xfrm6_beet_init(void) | ||
| 116 | { | ||
| 117 | return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6); | ||
| 118 | } | ||
| 119 | |||
| 120 | static void __exit xfrm6_beet_exit(void) | ||
| 121 | { | ||
| 122 | int err; | ||
| 123 | |||
| 124 | err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6); | ||
| 125 | BUG_ON(err); | ||
| 126 | } | ||
| 127 | |||
| 128 | module_init(xfrm6_beet_init); | ||
| 129 | module_exit(xfrm6_beet_exit); | ||
| 130 | MODULE_LICENSE("GPL"); | ||
| 131 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET); | ||
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c deleted file mode 100644 index da28e4407b8f..000000000000 --- a/net/ipv6/xfrm6_mode_ro.c +++ /dev/null | |||
| @@ -1,85 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * xfrm6_mode_ro.c - Route optimization mode for IPv6. | ||
| 3 | * | ||
| 4 | * Copyright (C)2003-2006 Helsinki University of Technology | ||
| 5 | * Copyright (C)2003-2006 USAGI/WIDE Project | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | /* | ||
| 21 | * Authors: | ||
| 22 | * Noriaki TAKAMIYA @USAGI | ||
| 23 | * Masahide NAKAMURA @USAGI | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/skbuff.h> | ||
| 30 | #include <linux/spinlock.h> | ||
| 31 | #include <linux/stringify.h> | ||
| 32 | #include <linux/time.h> | ||
| 33 | #include <net/ipv6.h> | ||
| 34 | #include <net/xfrm.h> | ||
| 35 | |||
| 36 | /* Add route optimization header space. | ||
| 37 | * | ||
| 38 | * The IP header and mutable extension headers will be moved forward to make | ||
| 39 | * space for the route optimization header. | ||
| 40 | */ | ||
| 41 | static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 42 | { | ||
| 43 | struct ipv6hdr *iph; | ||
| 44 | u8 *prevhdr; | ||
| 45 | int hdr_len; | ||
| 46 | |||
| 47 | iph = ipv6_hdr(skb); | ||
| 48 | |||
| 49 | hdr_len = x->type->hdr_offset(x, skb, &prevhdr); | ||
| 50 | if (hdr_len < 0) | ||
| 51 | return hdr_len; | ||
| 52 | skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); | ||
| 53 | skb_set_network_header(skb, -x->props.header_len); | ||
| 54 | skb->transport_header = skb->network_header + hdr_len; | ||
| 55 | __skb_pull(skb, hdr_len); | ||
| 56 | memmove(ipv6_hdr(skb), iph, hdr_len); | ||
| 57 | |||
| 58 | x->lastused = ktime_get_real_seconds(); | ||
| 59 | |||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | static struct xfrm_mode xfrm6_ro_mode = { | ||
| 64 | .output = xfrm6_ro_output, | ||
| 65 | .owner = THIS_MODULE, | ||
| 66 | .encap = XFRM_MODE_ROUTEOPTIMIZATION, | ||
| 67 | }; | ||
| 68 | |||
| 69 | static int __init xfrm6_ro_init(void) | ||
| 70 | { | ||
| 71 | return xfrm_register_mode(&xfrm6_ro_mode, AF_INET6); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void __exit xfrm6_ro_exit(void) | ||
| 75 | { | ||
| 76 | int err; | ||
| 77 | |||
| 78 | err = xfrm_unregister_mode(&xfrm6_ro_mode, AF_INET6); | ||
| 79 | BUG_ON(err); | ||
| 80 | } | ||
| 81 | |||
| 82 | module_init(xfrm6_ro_init); | ||
| 83 | module_exit(xfrm6_ro_exit); | ||
| 84 | MODULE_LICENSE("GPL"); | ||
| 85 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_ROUTEOPTIMIZATION); | ||
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c deleted file mode 100644 index 3c29da5defe6..000000000000 --- a/net/ipv6/xfrm6_mode_transport.c +++ /dev/null | |||
| @@ -1,121 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * xfrm6_mode_transport.c - Transport mode encapsulation for IPv6. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 USAGI/WIDE Project | ||
| 5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/init.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/skbuff.h> | ||
| 12 | #include <linux/stringify.h> | ||
| 13 | #include <net/dst.h> | ||
| 14 | #include <net/ipv6.h> | ||
| 15 | #include <net/xfrm.h> | ||
| 16 | #include <net/protocol.h> | ||
| 17 | |||
| 18 | /* Add encapsulation header. | ||
| 19 | * | ||
| 20 | * The IP header and mutable extension headers will be moved forward to make | ||
| 21 | * space for the encapsulation header. | ||
| 22 | */ | ||
| 23 | static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 24 | { | ||
| 25 | struct ipv6hdr *iph; | ||
| 26 | u8 *prevhdr; | ||
| 27 | int hdr_len; | ||
| 28 | |||
| 29 | iph = ipv6_hdr(skb); | ||
| 30 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 31 | |||
| 32 | hdr_len = x->type->hdr_offset(x, skb, &prevhdr); | ||
| 33 | if (hdr_len < 0) | ||
| 34 | return hdr_len; | ||
| 35 | skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); | ||
| 36 | skb_set_network_header(skb, -x->props.header_len); | ||
| 37 | skb->transport_header = skb->network_header + hdr_len; | ||
| 38 | __skb_pull(skb, hdr_len); | ||
| 39 | memmove(ipv6_hdr(skb), iph, hdr_len); | ||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | /* Remove encapsulation header. | ||
| 44 | * | ||
| 45 | * The IP header will be moved over the top of the encapsulation header. | ||
| 46 | * | ||
| 47 | * On entry, skb->h shall point to where the IP header should be and skb->nh | ||
| 48 | * shall be set to where the IP header currently is. skb->data shall point | ||
| 49 | * to the start of the payload. | ||
| 50 | */ | ||
| 51 | static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 52 | { | ||
| 53 | int ihl = skb->data - skb_transport_header(skb); | ||
| 54 | |||
| 55 | if (skb->transport_header != skb->network_header) { | ||
| 56 | memmove(skb_transport_header(skb), | ||
| 57 | skb_network_header(skb), ihl); | ||
| 58 | skb->network_header = skb->transport_header; | ||
| 59 | } | ||
| 60 | ipv6_hdr(skb)->payload_len = htons(skb->len + ihl - | ||
| 61 | sizeof(struct ipv6hdr)); | ||
| 62 | skb_reset_transport_header(skb); | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x, | ||
| 67 | struct sk_buff *skb, | ||
| 68 | netdev_features_t features) | ||
| 69 | { | ||
| 70 | const struct net_offload *ops; | ||
| 71 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 72 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 73 | |||
| 74 | skb->transport_header += x->props.header_len; | ||
| 75 | ops = rcu_dereference(inet6_offloads[xo->proto]); | ||
| 76 | if (likely(ops && ops->callbacks.gso_segment)) | ||
| 77 | segs = ops->callbacks.gso_segment(skb, features); | ||
| 78 | |||
| 79 | return segs; | ||
| 80 | } | ||
| 81 | |||
| 82 | static void xfrm6_transport_xmit(struct xfrm_state *x, struct sk_buff *skb) | ||
| 83 | { | ||
| 84 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 85 | |||
| 86 | skb_reset_mac_len(skb); | ||
| 87 | pskb_pull(skb, skb->mac_len + sizeof(struct ipv6hdr) + x->props.header_len); | ||
| 88 | |||
| 89 | if (xo->flags & XFRM_GSO_SEGMENT) { | ||
| 90 | skb_reset_transport_header(skb); | ||
| 91 | skb->transport_header -= x->props.header_len; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | static struct xfrm_mode xfrm6_transport_mode = { | ||
| 97 | .input = xfrm6_transport_input, | ||
| 98 | .output = xfrm6_transport_output, | ||
| 99 | .gso_segment = xfrm4_transport_gso_segment, | ||
| 100 | .xmit = xfrm6_transport_xmit, | ||
| 101 | .owner = THIS_MODULE, | ||
| 102 | .encap = XFRM_MODE_TRANSPORT, | ||
| 103 | }; | ||
| 104 | |||
| 105 | static int __init xfrm6_transport_init(void) | ||
| 106 | { | ||
| 107 | return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6); | ||
| 108 | } | ||
| 109 | |||
| 110 | static void __exit xfrm6_transport_exit(void) | ||
| 111 | { | ||
| 112 | int err; | ||
| 113 | |||
| 114 | err = xfrm_unregister_mode(&xfrm6_transport_mode, AF_INET6); | ||
| 115 | BUG_ON(err); | ||
| 116 | } | ||
| 117 | |||
| 118 | module_init(xfrm6_transport_init); | ||
| 119 | module_exit(xfrm6_transport_exit); | ||
| 120 | MODULE_LICENSE("GPL"); | ||
| 121 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TRANSPORT); | ||
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c deleted file mode 100644 index de1b0b8c53b0..000000000000 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ /dev/null | |||
| @@ -1,151 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * xfrm6_mode_tunnel.c - Tunnel mode encapsulation for IPv6. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 USAGI/WIDE Project | ||
| 5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/gfp.h> | ||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/skbuff.h> | ||
| 13 | #include <linux/stringify.h> | ||
| 14 | #include <net/dsfield.h> | ||
| 15 | #include <net/dst.h> | ||
| 16 | #include <net/inet_ecn.h> | ||
| 17 | #include <net/ip6_route.h> | ||
| 18 | #include <net/ipv6.h> | ||
| 19 | #include <net/xfrm.h> | ||
| 20 | |||
| 21 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | ||
| 22 | { | ||
| 23 | struct ipv6hdr *inner_iph = ipipv6_hdr(skb); | ||
| 24 | |||
| 25 | if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) | ||
| 26 | IP6_ECN_set_ce(skb, inner_iph); | ||
| 27 | } | ||
| 28 | |||
| 29 | /* Add encapsulation header. | ||
| 30 | * | ||
| 31 | * The top IP header will be constructed per RFC 2401. | ||
| 32 | */ | ||
| 33 | static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 34 | { | ||
| 35 | struct dst_entry *dst = skb_dst(skb); | ||
| 36 | struct ipv6hdr *top_iph; | ||
| 37 | int dsfield; | ||
| 38 | |||
| 39 | skb_set_inner_network_header(skb, skb_network_offset(skb)); | ||
| 40 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 41 | |||
| 42 | skb_set_network_header(skb, -x->props.header_len); | ||
| 43 | skb->mac_header = skb->network_header + | ||
| 44 | offsetof(struct ipv6hdr, nexthdr); | ||
| 45 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 46 | top_iph = ipv6_hdr(skb); | ||
| 47 | |||
| 48 | top_iph->version = 6; | ||
| 49 | |||
| 50 | memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | ||
| 51 | sizeof(top_iph->flow_lbl)); | ||
| 52 | top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); | ||
| 53 | |||
| 54 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) | ||
| 55 | dsfield = 0; | ||
| 56 | else | ||
| 57 | dsfield = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 58 | dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos); | ||
| 59 | if (x->props.flags & XFRM_STATE_NOECN) | ||
| 60 | dsfield &= ~INET_ECN_MASK; | ||
| 61 | ipv6_change_dsfield(top_iph, 0, dsfield); | ||
| 62 | top_iph->hop_limit = ip6_dst_hoplimit(xfrm_dst_child(dst)); | ||
| 63 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; | ||
| 64 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | #define for_each_input_rcu(head, handler) \ | ||
| 69 | for (handler = rcu_dereference(head); \ | ||
| 70 | handler != NULL; \ | ||
| 71 | handler = rcu_dereference(handler->next)) | ||
| 72 | |||
| 73 | |||
| 74 | static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 75 | { | ||
| 76 | int err = -EINVAL; | ||
| 77 | |||
| 78 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) | ||
| 79 | goto out; | ||
| 80 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
| 81 | goto out; | ||
| 82 | |||
| 83 | err = skb_unclone(skb, GFP_ATOMIC); | ||
| 84 | if (err) | ||
| 85 | goto out; | ||
| 86 | |||
| 87 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
| 88 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)), | ||
| 89 | ipipv6_hdr(skb)); | ||
| 90 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
| 91 | ipip6_ecn_decapsulate(skb); | ||
| 92 | |||
| 93 | skb_reset_network_header(skb); | ||
| 94 | skb_mac_header_rebuild(skb); | ||
| 95 | if (skb->mac_len) | ||
| 96 | eth_hdr(skb)->h_proto = skb->protocol; | ||
| 97 | |||
| 98 | err = 0; | ||
| 99 | |||
| 100 | out: | ||
| 101 | return err; | ||
| 102 | } | ||
| 103 | |||
| 104 | static struct sk_buff *xfrm6_mode_tunnel_gso_segment(struct xfrm_state *x, | ||
| 105 | struct sk_buff *skb, | ||
| 106 | netdev_features_t features) | ||
| 107 | { | ||
| 108 | __skb_push(skb, skb->mac_len); | ||
| 109 | return skb_mac_gso_segment(skb, features); | ||
| 110 | } | ||
| 111 | |||
| 112 | static void xfrm6_mode_tunnel_xmit(struct xfrm_state *x, struct sk_buff *skb) | ||
| 113 | { | ||
| 114 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 115 | |||
| 116 | if (xo->flags & XFRM_GSO_SEGMENT) | ||
| 117 | skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); | ||
| 118 | |||
| 119 | skb_reset_mac_len(skb); | ||
| 120 | pskb_pull(skb, skb->mac_len + x->props.header_len); | ||
| 121 | } | ||
| 122 | |||
| 123 | static struct xfrm_mode xfrm6_tunnel_mode = { | ||
| 124 | .input2 = xfrm6_mode_tunnel_input, | ||
| 125 | .input = xfrm_prepare_input, | ||
| 126 | .output2 = xfrm6_mode_tunnel_output, | ||
| 127 | .output = xfrm6_prepare_output, | ||
| 128 | .gso_segment = xfrm6_mode_tunnel_gso_segment, | ||
| 129 | .xmit = xfrm6_mode_tunnel_xmit, | ||
| 130 | .owner = THIS_MODULE, | ||
| 131 | .encap = XFRM_MODE_TUNNEL, | ||
| 132 | .flags = XFRM_MODE_FLAG_TUNNEL, | ||
| 133 | }; | ||
| 134 | |||
| 135 | static int __init xfrm6_mode_tunnel_init(void) | ||
| 136 | { | ||
| 137 | return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6); | ||
| 138 | } | ||
| 139 | |||
| 140 | static void __exit xfrm6_mode_tunnel_exit(void) | ||
| 141 | { | ||
| 142 | int err; | ||
| 143 | |||
| 144 | err = xfrm_unregister_mode(&xfrm6_tunnel_mode, AF_INET6); | ||
| 145 | BUG_ON(err); | ||
| 146 | } | ||
| 147 | |||
| 148 | module_init(xfrm6_mode_tunnel_init); | ||
| 149 | module_exit(xfrm6_mode_tunnel_exit); | ||
| 150 | MODULE_LICENSE("GPL"); | ||
| 151 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TUNNEL); | ||
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 6a74080005cf..8ad5e54eb8ca 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
| @@ -111,21 +111,6 @@ int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 111 | return xfrm6_extract_header(skb); | 111 | return xfrm6_extract_header(skb); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 115 | { | ||
| 116 | int err; | ||
| 117 | |||
| 118 | err = xfrm_inner_extract_output(x, skb); | ||
| 119 | if (err) | ||
| 120 | return err; | ||
| 121 | |||
| 122 | skb->ignore_df = 1; | ||
| 123 | skb->protocol = htons(ETH_P_IPV6); | ||
| 124 | |||
| 125 | return x->outer_mode->output2(x, skb); | ||
| 126 | } | ||
| 127 | EXPORT_SYMBOL(xfrm6_prepare_output); | ||
| 128 | |||
| 129 | int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb) | 114 | int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb) |
| 130 | { | 115 | { |
| 131 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); | 116 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); |
| @@ -137,11 +122,28 @@ int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb) | |||
| 137 | return xfrm_output(sk, skb); | 122 | return xfrm_output(sk, skb); |
| 138 | } | 123 | } |
| 139 | 124 | ||
| 125 | static int __xfrm6_output_state_finish(struct xfrm_state *x, struct sock *sk, | ||
| 126 | struct sk_buff *skb) | ||
| 127 | { | ||
| 128 | const struct xfrm_state_afinfo *afinfo; | ||
| 129 | int ret = -EAFNOSUPPORT; | ||
| 130 | |||
| 131 | rcu_read_lock(); | ||
| 132 | afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode.family); | ||
| 133 | if (likely(afinfo)) | ||
| 134 | ret = afinfo->output_finish(sk, skb); | ||
| 135 | else | ||
| 136 | kfree_skb(skb); | ||
| 137 | rcu_read_unlock(); | ||
| 138 | |||
| 139 | return ret; | ||
| 140 | } | ||
| 141 | |||
| 140 | static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb) | 142 | static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb) |
| 141 | { | 143 | { |
| 142 | struct xfrm_state *x = skb_dst(skb)->xfrm; | 144 | struct xfrm_state *x = skb_dst(skb)->xfrm; |
| 143 | 145 | ||
| 144 | return x->outer_mode->afinfo->output_finish(sk, skb); | 146 | return __xfrm6_output_state_finish(x, sk, skb); |
| 145 | } | 147 | } |
| 146 | 148 | ||
| 147 | static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) | 149 | static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) |
| @@ -183,7 +185,7 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) | |||
| 183 | __xfrm6_output_finish); | 185 | __xfrm6_output_finish); |
| 184 | 186 | ||
| 185 | skip_frag: | 187 | skip_frag: |
| 186 | return x->outer_mode->afinfo->output_finish(sk, skb); | 188 | return __xfrm6_output_state_finish(x, sk, skb); |
| 187 | } | 189 | } |
| 188 | 190 | ||
| 189 | int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) | 191 | int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 769f8f78d3b8..699e0730ce8e 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
| @@ -22,9 +22,6 @@ | |||
| 22 | #include <net/ipv6.h> | 22 | #include <net/ipv6.h> |
| 23 | #include <net/ip6_route.h> | 23 | #include <net/ip6_route.h> |
| 24 | #include <net/l3mdev.h> | 24 | #include <net/l3mdev.h> |
| 25 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 26 | #include <net/mip6.h> | ||
| 27 | #endif | ||
| 28 | 25 | ||
| 29 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, | 26 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, |
| 30 | const xfrm_address_t *saddr, | 27 | const xfrm_address_t *saddr, |
| @@ -71,24 +68,6 @@ static int xfrm6_get_saddr(struct net *net, int oif, | |||
| 71 | return 0; | 68 | return 0; |
| 72 | } | 69 | } |
| 73 | 70 | ||
| 74 | static int xfrm6_get_tos(const struct flowi *fl) | ||
| 75 | { | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, | ||
| 80 | int nfheader_len) | ||
| 81 | { | ||
| 82 | if (dst->ops->family == AF_INET6) { | ||
| 83 | struct rt6_info *rt = (struct rt6_info *)dst; | ||
| 84 | path->path_cookie = rt6_get_cookie(rt); | ||
| 85 | } | ||
| 86 | |||
| 87 | path->u.rt6.rt6i_nfheader_len = nfheader_len; | ||
| 88 | |||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | 71 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
| 93 | const struct flowi *fl) | 72 | const struct flowi *fl) |
| 94 | { | 73 | { |
| @@ -118,108 +97,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
| 118 | return 0; | 97 | return 0; |
| 119 | } | 98 | } |
| 120 | 99 | ||
| 121 | static inline void | ||
| 122 | _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | ||
| 123 | { | ||
| 124 | struct flowi6 *fl6 = &fl->u.ip6; | ||
| 125 | int onlyproto = 0; | ||
| 126 | const struct ipv6hdr *hdr = ipv6_hdr(skb); | ||
| 127 | u32 offset = sizeof(*hdr); | ||
| 128 | struct ipv6_opt_hdr *exthdr; | ||
| 129 | const unsigned char *nh = skb_network_header(skb); | ||
| 130 | u16 nhoff = IP6CB(skb)->nhoff; | ||
| 131 | int oif = 0; | ||
| 132 | u8 nexthdr; | ||
| 133 | |||
| 134 | if (!nhoff) | ||
| 135 | nhoff = offsetof(struct ipv6hdr, nexthdr); | ||
| 136 | |||
| 137 | nexthdr = nh[nhoff]; | ||
| 138 | |||
| 139 | if (skb_dst(skb)) | ||
| 140 | oif = skb_dst(skb)->dev->ifindex; | ||
| 141 | |||
| 142 | memset(fl6, 0, sizeof(struct flowi6)); | ||
| 143 | fl6->flowi6_mark = skb->mark; | ||
| 144 | fl6->flowi6_oif = reverse ? skb->skb_iif : oif; | ||
| 145 | |||
| 146 | fl6->daddr = reverse ? hdr->saddr : hdr->daddr; | ||
| 147 | fl6->saddr = reverse ? hdr->daddr : hdr->saddr; | ||
| 148 | |||
| 149 | while (nh + offset + sizeof(*exthdr) < skb->data || | ||
| 150 | pskb_may_pull(skb, nh + offset + sizeof(*exthdr) - skb->data)) { | ||
| 151 | nh = skb_network_header(skb); | ||
| 152 | exthdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 153 | |||
| 154 | switch (nexthdr) { | ||
| 155 | case NEXTHDR_FRAGMENT: | ||
| 156 | onlyproto = 1; | ||
| 157 | /* fall through */ | ||
| 158 | case NEXTHDR_ROUTING: | ||
| 159 | case NEXTHDR_HOP: | ||
| 160 | case NEXTHDR_DEST: | ||
| 161 | offset += ipv6_optlen(exthdr); | ||
| 162 | nexthdr = exthdr->nexthdr; | ||
| 163 | exthdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 164 | break; | ||
| 165 | |||
| 166 | case IPPROTO_UDP: | ||
| 167 | case IPPROTO_UDPLITE: | ||
| 168 | case IPPROTO_TCP: | ||
| 169 | case IPPROTO_SCTP: | ||
| 170 | case IPPROTO_DCCP: | ||
| 171 | if (!onlyproto && (nh + offset + 4 < skb->data || | ||
| 172 | pskb_may_pull(skb, nh + offset + 4 - skb->data))) { | ||
| 173 | __be16 *ports; | ||
| 174 | |||
| 175 | nh = skb_network_header(skb); | ||
| 176 | ports = (__be16 *)(nh + offset); | ||
| 177 | fl6->fl6_sport = ports[!!reverse]; | ||
| 178 | fl6->fl6_dport = ports[!reverse]; | ||
| 179 | } | ||
| 180 | fl6->flowi6_proto = nexthdr; | ||
| 181 | return; | ||
| 182 | |||
| 183 | case IPPROTO_ICMPV6: | ||
| 184 | if (!onlyproto && (nh + offset + 2 < skb->data || | ||
| 185 | pskb_may_pull(skb, nh + offset + 2 - skb->data))) { | ||
| 186 | u8 *icmp; | ||
| 187 | |||
| 188 | nh = skb_network_header(skb); | ||
| 189 | icmp = (u8 *)(nh + offset); | ||
| 190 | fl6->fl6_icmp_type = icmp[0]; | ||
| 191 | fl6->fl6_icmp_code = icmp[1]; | ||
| 192 | } | ||
| 193 | fl6->flowi6_proto = nexthdr; | ||
| 194 | return; | ||
| 195 | |||
| 196 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 197 | case IPPROTO_MH: | ||
| 198 | offset += ipv6_optlen(exthdr); | ||
| 199 | if (!onlyproto && (nh + offset + 3 < skb->data || | ||
| 200 | pskb_may_pull(skb, nh + offset + 3 - skb->data))) { | ||
| 201 | struct ip6_mh *mh; | ||
| 202 | |||
| 203 | nh = skb_network_header(skb); | ||
| 204 | mh = (struct ip6_mh *)(nh + offset); | ||
| 205 | fl6->fl6_mh_type = mh->ip6mh_type; | ||
| 206 | } | ||
| 207 | fl6->flowi6_proto = nexthdr; | ||
| 208 | return; | ||
| 209 | #endif | ||
| 210 | |||
| 211 | /* XXX Why are there these headers? */ | ||
| 212 | case IPPROTO_AH: | ||
| 213 | case IPPROTO_ESP: | ||
| 214 | case IPPROTO_COMP: | ||
| 215 | default: | ||
| 216 | fl6->fl6_ipsec_spi = 0; | ||
| 217 | fl6->flowi6_proto = nexthdr; | ||
| 218 | return; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, | 100 | static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| 224 | struct sk_buff *skb, u32 mtu) | 101 | struct sk_buff *skb, u32 mtu) |
| 225 | { | 102 | { |
| @@ -291,9 +168,6 @@ static const struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
| 291 | .dst_ops = &xfrm6_dst_ops_template, | 168 | .dst_ops = &xfrm6_dst_ops_template, |
| 292 | .dst_lookup = xfrm6_dst_lookup, | 169 | .dst_lookup = xfrm6_dst_lookup, |
| 293 | .get_saddr = xfrm6_get_saddr, | 170 | .get_saddr = xfrm6_get_saddr, |
| 294 | .decode_session = _decode_session6, | ||
| 295 | .get_tos = xfrm6_get_tos, | ||
| 296 | .init_path = xfrm6_init_path, | ||
| 297 | .fill_dst = xfrm6_fill_dst, | 171 | .fill_dst = xfrm6_fill_dst, |
| 298 | .blackhole_route = ip6_blackhole_route, | 172 | .blackhole_route = ip6_blackhole_route, |
| 299 | }; | 173 | }; |
diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c index cc979b702c89..aaacac7fdbce 100644 --- a/net/ipv6/xfrm6_protocol.c +++ b/net/ipv6/xfrm6_protocol.c | |||
| @@ -46,7 +46,7 @@ static inline struct xfrm6_protocol __rcu **proto_handlers(u8 protocol) | |||
| 46 | handler != NULL; \ | 46 | handler != NULL; \ |
| 47 | handler = rcu_dereference(handler->next)) \ | 47 | handler = rcu_dereference(handler->next)) \ |
| 48 | 48 | ||
| 49 | int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) | 49 | static int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) |
| 50 | { | 50 | { |
| 51 | int ret; | 51 | int ret; |
| 52 | struct xfrm6_protocol *handler; | 52 | struct xfrm6_protocol *handler; |
| @@ -61,7 +61,6 @@ int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) | |||
| 61 | 61 | ||
| 62 | return 0; | 62 | return 0; |
| 63 | } | 63 | } |
| 64 | EXPORT_SYMBOL(xfrm6_rcv_cb); | ||
| 65 | 64 | ||
| 66 | static int xfrm6_esp_rcv(struct sk_buff *skb) | 65 | static int xfrm6_esp_rcv(struct sk_buff *skb) |
| 67 | { | 66 | { |
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index 5d43aaa17027..1ec8071226b2 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | config XFRM | 4 | config XFRM |
| 5 | bool | 5 | bool |
| 6 | depends on NET | 6 | depends on INET |
| 7 | select GRO_CELLS | 7 | select GRO_CELLS |
| 8 | select SKB_EXTENSIONS | 8 | select SKB_EXTENSIONS |
| 9 | 9 | ||
| @@ -15,9 +15,9 @@ config XFRM_ALGO | |||
| 15 | select XFRM | 15 | select XFRM |
| 16 | select CRYPTO | 16 | select CRYPTO |
| 17 | 17 | ||
| 18 | if INET | ||
| 18 | config XFRM_USER | 19 | config XFRM_USER |
| 19 | tristate "Transformation user configuration interface" | 20 | tristate "Transformation user configuration interface" |
| 20 | depends on INET | ||
| 21 | select XFRM_ALGO | 21 | select XFRM_ALGO |
| 22 | ---help--- | 22 | ---help--- |
| 23 | Support for Transformation(XFRM) user configuration interface | 23 | Support for Transformation(XFRM) user configuration interface |
| @@ -56,7 +56,7 @@ config XFRM_MIGRATE | |||
| 56 | 56 | ||
| 57 | config XFRM_STATISTICS | 57 | config XFRM_STATISTICS |
| 58 | bool "Transformation statistics" | 58 | bool "Transformation statistics" |
| 59 | depends on INET && XFRM && PROC_FS | 59 | depends on XFRM && PROC_FS |
| 60 | ---help--- | 60 | ---help--- |
| 61 | This statistics is not a SNMP/MIB specification but shows | 61 | This statistics is not a SNMP/MIB specification but shows |
| 62 | statistics about transformation error (or almost error) factor | 62 | statistics about transformation error (or almost error) factor |
| @@ -95,3 +95,5 @@ config NET_KEY_MIGRATE | |||
| 95 | <draft-sugimoto-mip6-pfkey-migrate>. | 95 | <draft-sugimoto-mip6-pfkey-migrate>. |
| 96 | 96 | ||
| 97 | If unsure, say N. | 97 | If unsure, say N. |
| 98 | |||
| 99 | endif # INET | ||
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 2db1626557c5..b24cd86a02c3 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c | |||
| @@ -23,6 +23,60 @@ | |||
| 23 | #include <linux/notifier.h> | 23 | #include <linux/notifier.h> |
| 24 | 24 | ||
| 25 | #ifdef CONFIG_XFRM_OFFLOAD | 25 | #ifdef CONFIG_XFRM_OFFLOAD |
| 26 | static void __xfrm_transport_prep(struct xfrm_state *x, struct sk_buff *skb, | ||
| 27 | unsigned int hsize) | ||
| 28 | { | ||
| 29 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 30 | |||
| 31 | skb_reset_mac_len(skb); | ||
| 32 | pskb_pull(skb, skb->mac_len + hsize + x->props.header_len); | ||
| 33 | |||
| 34 | if (xo->flags & XFRM_GSO_SEGMENT) { | ||
| 35 | skb_reset_transport_header(skb); | ||
| 36 | skb->transport_header -= x->props.header_len; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | static void __xfrm_mode_tunnel_prep(struct xfrm_state *x, struct sk_buff *skb, | ||
| 41 | unsigned int hsize) | ||
| 42 | |||
| 43 | { | ||
| 44 | struct xfrm_offload *xo = xfrm_offload(skb); | ||
| 45 | |||
| 46 | if (xo->flags & XFRM_GSO_SEGMENT) | ||
| 47 | skb->transport_header = skb->network_header + hsize; | ||
| 48 | |||
| 49 | skb_reset_mac_len(skb); | ||
| 50 | pskb_pull(skb, skb->mac_len + x->props.header_len); | ||
| 51 | } | ||
| 52 | |||
| 53 | /* Adjust pointers into the packet when IPsec is done at layer2 */ | ||
| 54 | static void xfrm_outer_mode_prep(struct xfrm_state *x, struct sk_buff *skb) | ||
| 55 | { | ||
| 56 | switch (x->outer_mode.encap) { | ||
| 57 | case XFRM_MODE_TUNNEL: | ||
| 58 | if (x->outer_mode.family == AF_INET) | ||
| 59 | return __xfrm_mode_tunnel_prep(x, skb, | ||
| 60 | sizeof(struct iphdr)); | ||
| 61 | if (x->outer_mode.family == AF_INET6) | ||
| 62 | return __xfrm_mode_tunnel_prep(x, skb, | ||
| 63 | sizeof(struct ipv6hdr)); | ||
| 64 | break; | ||
| 65 | case XFRM_MODE_TRANSPORT: | ||
| 66 | if (x->outer_mode.family == AF_INET) | ||
| 67 | return __xfrm_transport_prep(x, skb, | ||
| 68 | sizeof(struct iphdr)); | ||
| 69 | if (x->outer_mode.family == AF_INET6) | ||
| 70 | return __xfrm_transport_prep(x, skb, | ||
| 71 | sizeof(struct ipv6hdr)); | ||
| 72 | break; | ||
| 73 | case XFRM_MODE_ROUTEOPTIMIZATION: | ||
| 74 | case XFRM_MODE_IN_TRIGGER: | ||
| 75 | case XFRM_MODE_BEET: | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 26 | struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again) | 80 | struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again) |
| 27 | { | 81 | { |
| 28 | int err; | 82 | int err; |
| @@ -78,7 +132,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur | |||
| 78 | } | 132 | } |
| 79 | 133 | ||
| 80 | if (!skb->next) { | 134 | if (!skb->next) { |
| 81 | x->outer_mode->xmit(x, skb); | 135 | esp_features |= skb->dev->gso_partial_features; |
| 136 | xfrm_outer_mode_prep(x, skb); | ||
| 82 | 137 | ||
| 83 | xo->flags |= XFRM_DEV_RESUME; | 138 | xo->flags |= XFRM_DEV_RESUME; |
| 84 | 139 | ||
| @@ -101,12 +156,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur | |||
| 101 | 156 | ||
| 102 | do { | 157 | do { |
| 103 | struct sk_buff *nskb = skb2->next; | 158 | struct sk_buff *nskb = skb2->next; |
| 159 | |||
| 160 | esp_features |= skb->dev->gso_partial_features; | ||
| 104 | skb_mark_not_on_list(skb2); | 161 | skb_mark_not_on_list(skb2); |
| 105 | 162 | ||
| 106 | xo = xfrm_offload(skb2); | 163 | xo = xfrm_offload(skb2); |
| 107 | xo->flags |= XFRM_DEV_RESUME; | 164 | xo->flags |= XFRM_DEV_RESUME; |
| 108 | 165 | ||
| 109 | x->outer_mode->xmit(x, skb2); | 166 | xfrm_outer_mode_prep(x, skb2); |
| 110 | 167 | ||
| 111 | err = x->type_offload->xmit(x, skb2, esp_features); | 168 | err = x->type_offload->xmit(x, skb2, esp_features); |
| 112 | if (!err) { | 169 | if (!err) { |
diff --git a/net/xfrm/xfrm_inout.h b/net/xfrm/xfrm_inout.h new file mode 100644 index 000000000000..c7b0318938e2 --- /dev/null +++ b/net/xfrm/xfrm_inout.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #include <linux/ipv6.h> | ||
| 3 | #include <net/dsfield.h> | ||
| 4 | #include <net/xfrm.h> | ||
| 5 | |||
| 6 | #ifndef XFRM_INOUT_H | ||
| 7 | #define XFRM_INOUT_H 1 | ||
| 8 | |||
| 9 | static inline void xfrm6_beet_make_header(struct sk_buff *skb) | ||
| 10 | { | ||
| 11 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 12 | |||
| 13 | iph->version = 6; | ||
| 14 | |||
| 15 | memcpy(iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | ||
| 16 | sizeof(iph->flow_lbl)); | ||
| 17 | iph->nexthdr = XFRM_MODE_SKB_CB(skb)->protocol; | ||
| 18 | |||
| 19 | ipv6_change_dsfield(iph, 0, XFRM_MODE_SKB_CB(skb)->tos); | ||
| 20 | iph->hop_limit = XFRM_MODE_SKB_CB(skb)->ttl; | ||
| 21 | } | ||
| 22 | |||
| 23 | static inline void xfrm4_beet_make_header(struct sk_buff *skb) | ||
| 24 | { | ||
| 25 | struct iphdr *iph = ip_hdr(skb); | ||
| 26 | |||
| 27 | iph->ihl = 5; | ||
| 28 | iph->version = 4; | ||
| 29 | |||
| 30 | iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol; | ||
| 31 | iph->tos = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 32 | |||
| 33 | iph->id = XFRM_MODE_SKB_CB(skb)->id; | ||
| 34 | iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off; | ||
| 35 | iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl; | ||
| 36 | } | ||
| 37 | |||
| 38 | #endif | ||
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index b3b613660d44..314973aaa414 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
| @@ -21,6 +21,8 @@ | |||
| 21 | #include <net/ip_tunnels.h> | 21 | #include <net/ip_tunnels.h> |
| 22 | #include <net/ip6_tunnel.h> | 22 | #include <net/ip6_tunnel.h> |
| 23 | 23 | ||
| 24 | #include "xfrm_inout.h" | ||
| 25 | |||
| 24 | struct xfrm_trans_tasklet { | 26 | struct xfrm_trans_tasklet { |
| 25 | struct tasklet_struct tasklet; | 27 | struct tasklet_struct tasklet; |
| 26 | struct sk_buff_head queue; | 28 | struct sk_buff_head queue; |
| @@ -166,35 +168,299 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) | |||
| 166 | } | 168 | } |
| 167 | EXPORT_SYMBOL(xfrm_parse_spi); | 169 | EXPORT_SYMBOL(xfrm_parse_spi); |
| 168 | 170 | ||
| 169 | int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) | 171 | static int xfrm4_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb) |
| 172 | { | ||
| 173 | struct iphdr *iph; | ||
| 174 | int optlen = 0; | ||
| 175 | int err = -EINVAL; | ||
| 176 | |||
| 177 | if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) { | ||
| 178 | struct ip_beet_phdr *ph; | ||
| 179 | int phlen; | ||
| 180 | |||
| 181 | if (!pskb_may_pull(skb, sizeof(*ph))) | ||
| 182 | goto out; | ||
| 183 | |||
| 184 | ph = (struct ip_beet_phdr *)skb->data; | ||
| 185 | |||
| 186 | phlen = sizeof(*ph) + ph->padlen; | ||
| 187 | optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen); | ||
| 188 | if (optlen < 0 || optlen & 3 || optlen > 250) | ||
| 189 | goto out; | ||
| 190 | |||
| 191 | XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr; | ||
| 192 | |||
| 193 | if (!pskb_may_pull(skb, phlen)) | ||
| 194 | goto out; | ||
| 195 | __skb_pull(skb, phlen); | ||
| 196 | } | ||
| 197 | |||
| 198 | skb_push(skb, sizeof(*iph)); | ||
| 199 | skb_reset_network_header(skb); | ||
| 200 | skb_mac_header_rebuild(skb); | ||
| 201 | |||
| 202 | xfrm4_beet_make_header(skb); | ||
| 203 | |||
| 204 | iph = ip_hdr(skb); | ||
| 205 | |||
| 206 | iph->ihl += optlen / 4; | ||
| 207 | iph->tot_len = htons(skb->len); | ||
| 208 | iph->daddr = x->sel.daddr.a4; | ||
| 209 | iph->saddr = x->sel.saddr.a4; | ||
| 210 | iph->check = 0; | ||
| 211 | iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); | ||
| 212 | err = 0; | ||
| 213 | out: | ||
| 214 | return err; | ||
| 215 | } | ||
| 216 | |||
| 217 | static void ipip_ecn_decapsulate(struct sk_buff *skb) | ||
| 218 | { | ||
| 219 | struct iphdr *inner_iph = ipip_hdr(skb); | ||
| 220 | |||
| 221 | if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) | ||
| 222 | IP_ECN_set_ce(inner_iph); | ||
| 223 | } | ||
| 224 | |||
| 225 | static int xfrm4_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) | ||
| 170 | { | 226 | { |
| 171 | struct xfrm_mode *inner_mode = x->inner_mode; | 227 | int err = -EINVAL; |
| 228 | |||
| 229 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) | ||
| 230 | goto out; | ||
| 231 | |||
| 232 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | ||
| 233 | goto out; | ||
| 234 | |||
| 235 | err = skb_unclone(skb, GFP_ATOMIC); | ||
| 236 | if (err) | ||
| 237 | goto out; | ||
| 238 | |||
| 239 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
| 240 | ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); | ||
| 241 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
| 242 | ipip_ecn_decapsulate(skb); | ||
| 243 | |||
| 244 | skb_reset_network_header(skb); | ||
| 245 | skb_mac_header_rebuild(skb); | ||
| 246 | if (skb->mac_len) | ||
| 247 | eth_hdr(skb)->h_proto = skb->protocol; | ||
| 248 | |||
| 249 | err = 0; | ||
| 250 | |||
| 251 | out: | ||
| 252 | return err; | ||
| 253 | } | ||
| 254 | |||
| 255 | static void ipip6_ecn_decapsulate(struct sk_buff *skb) | ||
| 256 | { | ||
| 257 | struct ipv6hdr *inner_iph = ipipv6_hdr(skb); | ||
| 258 | |||
| 259 | if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) | ||
| 260 | IP6_ECN_set_ce(skb, inner_iph); | ||
| 261 | } | ||
| 262 | |||
| 263 | static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) | ||
| 264 | { | ||
| 265 | int err = -EINVAL; | ||
| 266 | |||
| 267 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) | ||
| 268 | goto out; | ||
| 269 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
| 270 | goto out; | ||
| 271 | |||
| 272 | err = skb_unclone(skb, GFP_ATOMIC); | ||
| 273 | if (err) | ||
| 274 | goto out; | ||
| 275 | |||
| 276 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
| 277 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)), | ||
| 278 | ipipv6_hdr(skb)); | ||
| 279 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
| 280 | ipip6_ecn_decapsulate(skb); | ||
| 281 | |||
| 282 | skb_reset_network_header(skb); | ||
| 283 | skb_mac_header_rebuild(skb); | ||
| 284 | if (skb->mac_len) | ||
| 285 | eth_hdr(skb)->h_proto = skb->protocol; | ||
| 286 | |||
| 287 | err = 0; | ||
| 288 | |||
| 289 | out: | ||
| 290 | return err; | ||
| 291 | } | ||
| 292 | |||
| 293 | static int xfrm6_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb) | ||
| 294 | { | ||
| 295 | struct ipv6hdr *ip6h; | ||
| 296 | int size = sizeof(struct ipv6hdr); | ||
| 172 | int err; | 297 | int err; |
| 173 | 298 | ||
| 174 | err = x->outer_mode->afinfo->extract_input(x, skb); | 299 | err = skb_cow_head(skb, size + skb->mac_len); |
| 175 | if (err) | 300 | if (err) |
| 301 | goto out; | ||
| 302 | |||
| 303 | __skb_push(skb, size); | ||
| 304 | skb_reset_network_header(skb); | ||
| 305 | skb_mac_header_rebuild(skb); | ||
| 306 | |||
| 307 | xfrm6_beet_make_header(skb); | ||
| 308 | |||
| 309 | ip6h = ipv6_hdr(skb); | ||
| 310 | ip6h->payload_len = htons(skb->len - size); | ||
| 311 | ip6h->daddr = x->sel.daddr.in6; | ||
| 312 | ip6h->saddr = x->sel.saddr.in6; | ||
| 313 | err = 0; | ||
| 314 | out: | ||
| 315 | return err; | ||
| 316 | } | ||
| 317 | |||
| 318 | /* Remove encapsulation header. | ||
| 319 | * | ||
| 320 | * The IP header will be moved over the top of the encapsulation | ||
| 321 | * header. | ||
| 322 | * | ||
| 323 | * On entry, the transport header shall point to where the IP header | ||
| 324 | * should be and the network header shall be set to where the IP | ||
| 325 | * header currently is. skb->data shall point to the start of the | ||
| 326 | * payload. | ||
| 327 | */ | ||
| 328 | static int | ||
| 329 | xfrm_inner_mode_encap_remove(struct xfrm_state *x, | ||
| 330 | const struct xfrm_mode *inner_mode, | ||
| 331 | struct sk_buff *skb) | ||
| 332 | { | ||
| 333 | switch (inner_mode->encap) { | ||
| 334 | case XFRM_MODE_BEET: | ||
| 335 | if (inner_mode->family == AF_INET) | ||
| 336 | return xfrm4_remove_beet_encap(x, skb); | ||
| 337 | if (inner_mode->family == AF_INET6) | ||
| 338 | return xfrm6_remove_beet_encap(x, skb); | ||
| 339 | break; | ||
| 340 | case XFRM_MODE_TUNNEL: | ||
| 341 | if (inner_mode->family == AF_INET) | ||
| 342 | return xfrm4_remove_tunnel_encap(x, skb); | ||
| 343 | if (inner_mode->family == AF_INET6) | ||
| 344 | return xfrm6_remove_tunnel_encap(x, skb); | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | |||
| 348 | WARN_ON_ONCE(1); | ||
| 349 | return -EOPNOTSUPP; | ||
| 350 | } | ||
| 351 | |||
| 352 | static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 353 | { | ||
| 354 | const struct xfrm_mode *inner_mode = &x->inner_mode; | ||
| 355 | const struct xfrm_state_afinfo *afinfo; | ||
| 356 | int err = -EAFNOSUPPORT; | ||
| 357 | |||
| 358 | rcu_read_lock(); | ||
| 359 | afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode.family); | ||
| 360 | if (likely(afinfo)) | ||
| 361 | err = afinfo->extract_input(x, skb); | ||
| 362 | |||
| 363 | if (err) { | ||
| 364 | rcu_read_unlock(); | ||
| 176 | return err; | 365 | return err; |
| 366 | } | ||
| 177 | 367 | ||
| 178 | if (x->sel.family == AF_UNSPEC) { | 368 | if (x->sel.family == AF_UNSPEC) { |
| 179 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); | 369 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
| 180 | if (inner_mode == NULL) | 370 | if (!inner_mode) { |
| 371 | rcu_read_unlock(); | ||
| 181 | return -EAFNOSUPPORT; | 372 | return -EAFNOSUPPORT; |
| 373 | } | ||
| 182 | } | 374 | } |
| 183 | 375 | ||
| 184 | skb->protocol = inner_mode->afinfo->eth_proto; | 376 | afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family); |
| 185 | return inner_mode->input2(x, skb); | 377 | if (unlikely(!afinfo)) { |
| 378 | rcu_read_unlock(); | ||
| 379 | return -EAFNOSUPPORT; | ||
| 380 | } | ||
| 381 | |||
| 382 | skb->protocol = afinfo->eth_proto; | ||
| 383 | rcu_read_unlock(); | ||
| 384 | return xfrm_inner_mode_encap_remove(x, inner_mode, skb); | ||
| 385 | } | ||
| 386 | |||
| 387 | /* Remove encapsulation header. | ||
| 388 | * | ||
| 389 | * The IP header will be moved over the top of the encapsulation header. | ||
| 390 | * | ||
| 391 | * On entry, skb_transport_header() shall point to where the IP header | ||
| 392 | * should be and skb_network_header() shall be set to where the IP header | ||
| 393 | * currently is. skb->data shall point to the start of the payload. | ||
| 394 | */ | ||
| 395 | static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 396 | { | ||
| 397 | int ihl = skb->data - skb_transport_header(skb); | ||
| 398 | |||
| 399 | if (skb->transport_header != skb->network_header) { | ||
| 400 | memmove(skb_transport_header(skb), | ||
| 401 | skb_network_header(skb), ihl); | ||
| 402 | skb->network_header = skb->transport_header; | ||
| 403 | } | ||
| 404 | ip_hdr(skb)->tot_len = htons(skb->len + ihl); | ||
| 405 | skb_reset_transport_header(skb); | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 410 | { | ||
| 411 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 412 | int ihl = skb->data - skb_transport_header(skb); | ||
| 413 | |||
| 414 | if (skb->transport_header != skb->network_header) { | ||
| 415 | memmove(skb_transport_header(skb), | ||
| 416 | skb_network_header(skb), ihl); | ||
| 417 | skb->network_header = skb->transport_header; | ||
| 418 | } | ||
| 419 | ipv6_hdr(skb)->payload_len = htons(skb->len + ihl - | ||
| 420 | sizeof(struct ipv6hdr)); | ||
| 421 | skb_reset_transport_header(skb); | ||
| 422 | return 0; | ||
| 423 | #else | ||
| 424 | WARN_ON_ONCE(1); | ||
| 425 | return -EAFNOSUPPORT; | ||
| 426 | #endif | ||
| 427 | } | ||
| 428 | |||
| 429 | static int xfrm_inner_mode_input(struct xfrm_state *x, | ||
| 430 | const struct xfrm_mode *inner_mode, | ||
| 431 | struct sk_buff *skb) | ||
| 432 | { | ||
| 433 | switch (inner_mode->encap) { | ||
| 434 | case XFRM_MODE_BEET: | ||
| 435 | case XFRM_MODE_TUNNEL: | ||
| 436 | return xfrm_prepare_input(x, skb); | ||
| 437 | case XFRM_MODE_TRANSPORT: | ||
| 438 | if (inner_mode->family == AF_INET) | ||
| 439 | return xfrm4_transport_input(x, skb); | ||
| 440 | if (inner_mode->family == AF_INET6) | ||
| 441 | return xfrm6_transport_input(x, skb); | ||
| 442 | break; | ||
| 443 | case XFRM_MODE_ROUTEOPTIMIZATION: | ||
| 444 | WARN_ON_ONCE(1); | ||
| 445 | break; | ||
| 446 | default: | ||
| 447 | WARN_ON_ONCE(1); | ||
| 448 | break; | ||
| 449 | } | ||
| 450 | |||
| 451 | return -EOPNOTSUPP; | ||
| 186 | } | 452 | } |
| 187 | EXPORT_SYMBOL(xfrm_prepare_input); | ||
| 188 | 453 | ||
| 189 | int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | 454 | int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) |
| 190 | { | 455 | { |
| 456 | const struct xfrm_state_afinfo *afinfo; | ||
| 191 | struct net *net = dev_net(skb->dev); | 457 | struct net *net = dev_net(skb->dev); |
| 458 | const struct xfrm_mode *inner_mode; | ||
| 192 | int err; | 459 | int err; |
| 193 | __be32 seq; | 460 | __be32 seq; |
| 194 | __be32 seq_hi; | 461 | __be32 seq_hi; |
| 195 | struct xfrm_state *x = NULL; | 462 | struct xfrm_state *x = NULL; |
| 196 | xfrm_address_t *daddr; | 463 | xfrm_address_t *daddr; |
| 197 | struct xfrm_mode *inner_mode; | ||
| 198 | u32 mark = skb->mark; | 464 | u32 mark = skb->mark; |
| 199 | unsigned int family = AF_UNSPEC; | 465 | unsigned int family = AF_UNSPEC; |
| 200 | int decaps = 0; | 466 | int decaps = 0; |
| @@ -216,7 +482,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
| 216 | goto drop; | 482 | goto drop; |
| 217 | } | 483 | } |
| 218 | 484 | ||
| 219 | family = x->outer_mode->afinfo->family; | 485 | family = x->outer_mode.family; |
| 220 | 486 | ||
| 221 | /* An encap_type of -1 indicates async resumption. */ | 487 | /* An encap_type of -1 indicates async resumption. */ |
| 222 | if (encap_type == -1) { | 488 | if (encap_type == -1) { |
| @@ -400,7 +666,7 @@ resume: | |||
| 400 | 666 | ||
| 401 | XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; | 667 | XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; |
| 402 | 668 | ||
| 403 | inner_mode = x->inner_mode; | 669 | inner_mode = &x->inner_mode; |
| 404 | 670 | ||
| 405 | if (x->sel.family == AF_UNSPEC) { | 671 | if (x->sel.family == AF_UNSPEC) { |
| 406 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); | 672 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
| @@ -410,12 +676,12 @@ resume: | |||
| 410 | } | 676 | } |
| 411 | } | 677 | } |
| 412 | 678 | ||
| 413 | if (inner_mode->input(x, skb)) { | 679 | if (xfrm_inner_mode_input(x, inner_mode, skb)) { |
| 414 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); | 680 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); |
| 415 | goto drop; | 681 | goto drop; |
| 416 | } | 682 | } |
| 417 | 683 | ||
| 418 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { | 684 | if (x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL) { |
| 419 | decaps = 1; | 685 | decaps = 1; |
| 420 | break; | 686 | break; |
| 421 | } | 687 | } |
| @@ -425,7 +691,7 @@ resume: | |||
| 425 | * transport mode so the outer address is identical. | 691 | * transport mode so the outer address is identical. |
| 426 | */ | 692 | */ |
| 427 | daddr = &x->id.daddr; | 693 | daddr = &x->id.daddr; |
| 428 | family = x->outer_mode->afinfo->family; | 694 | family = x->outer_mode.family; |
| 429 | 695 | ||
| 430 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); | 696 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); |
| 431 | if (err < 0) { | 697 | if (err < 0) { |
| @@ -453,7 +719,12 @@ resume: | |||
| 453 | if (xo) | 719 | if (xo) |
| 454 | xfrm_gro = xo->flags & XFRM_GRO; | 720 | xfrm_gro = xo->flags & XFRM_GRO; |
| 455 | 721 | ||
| 456 | err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async); | 722 | err = -EAFNOSUPPORT; |
| 723 | rcu_read_lock(); | ||
| 724 | afinfo = xfrm_state_afinfo_get_rcu(x->inner_mode.family); | ||
| 725 | if (likely(afinfo)) | ||
| 726 | err = afinfo->transport_finish(skb, xfrm_gro || async); | ||
| 727 | rcu_read_unlock(); | ||
| 457 | if (xfrm_gro) { | 728 | if (xfrm_gro) { |
| 458 | sp = skb_sec_path(skb); | 729 | sp = skb_sec_path(skb); |
| 459 | if (sp) | 730 | if (sp) |
diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index dbb3c1945b5c..b9f118530db6 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c | |||
| @@ -244,8 +244,8 @@ static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet) | |||
| 244 | 244 | ||
| 245 | static int xfrmi_rcv_cb(struct sk_buff *skb, int err) | 245 | static int xfrmi_rcv_cb(struct sk_buff *skb, int err) |
| 246 | { | 246 | { |
| 247 | const struct xfrm_mode *inner_mode; | ||
| 247 | struct pcpu_sw_netstats *tstats; | 248 | struct pcpu_sw_netstats *tstats; |
| 248 | struct xfrm_mode *inner_mode; | ||
| 249 | struct net_device *dev; | 249 | struct net_device *dev; |
| 250 | struct xfrm_state *x; | 250 | struct xfrm_state *x; |
| 251 | struct xfrm_if *xi; | 251 | struct xfrm_if *xi; |
| @@ -273,7 +273,7 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err) | |||
| 273 | xnet = !net_eq(xi->net, dev_net(skb->dev)); | 273 | xnet = !net_eq(xi->net, dev_net(skb->dev)); |
| 274 | 274 | ||
| 275 | if (xnet) { | 275 | if (xnet) { |
| 276 | inner_mode = x->inner_mode; | 276 | inner_mode = &x->inner_mode; |
| 277 | 277 | ||
| 278 | if (x->sel.family == AF_UNSPEC) { | 278 | if (x->sel.family == AF_UNSPEC) { |
| 279 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); | 279 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
| @@ -285,7 +285,7 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err) | |||
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, | 287 | if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, |
| 288 | inner_mode->afinfo->family)) | 288 | inner_mode->family)) |
| 289 | return -EPERM; | 289 | return -EPERM; |
| 290 | } | 290 | } |
| 291 | 291 | ||
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 9333153bafda..a55510f9ff35 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c | |||
| @@ -17,9 +17,13 @@ | |||
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
| 19 | #include <net/dst.h> | 19 | #include <net/dst.h> |
| 20 | #include <net/inet_ecn.h> | ||
| 20 | #include <net/xfrm.h> | 21 | #include <net/xfrm.h> |
| 21 | 22 | ||
| 23 | #include "xfrm_inout.h" | ||
| 24 | |||
| 22 | static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb); | 25 | static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb); |
| 26 | static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); | ||
| 23 | 27 | ||
| 24 | static int xfrm_skb_check_space(struct sk_buff *skb) | 28 | static int xfrm_skb_check_space(struct sk_buff *skb) |
| 25 | { | 29 | { |
| @@ -50,6 +54,360 @@ static struct dst_entry *skb_dst_pop(struct sk_buff *skb) | |||
| 50 | return child; | 54 | return child; |
| 51 | } | 55 | } |
| 52 | 56 | ||
| 57 | /* Add encapsulation header. | ||
| 58 | * | ||
| 59 | * The IP header will be moved forward to make space for the encapsulation | ||
| 60 | * header. | ||
| 61 | */ | ||
| 62 | static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 63 | { | ||
| 64 | struct iphdr *iph = ip_hdr(skb); | ||
| 65 | int ihl = iph->ihl * 4; | ||
| 66 | |||
| 67 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 68 | |||
| 69 | skb_set_network_header(skb, -x->props.header_len); | ||
| 70 | skb->mac_header = skb->network_header + | ||
| 71 | offsetof(struct iphdr, protocol); | ||
| 72 | skb->transport_header = skb->network_header + ihl; | ||
| 73 | __skb_pull(skb, ihl); | ||
| 74 | memmove(skb_network_header(skb), iph, ihl); | ||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | /* Add encapsulation header. | ||
| 79 | * | ||
| 80 | * The IP header and mutable extension headers will be moved forward to make | ||
| 81 | * space for the encapsulation header. | ||
| 82 | */ | ||
| 83 | static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 84 | { | ||
| 85 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 86 | struct ipv6hdr *iph; | ||
| 87 | u8 *prevhdr; | ||
| 88 | int hdr_len; | ||
| 89 | |||
| 90 | iph = ipv6_hdr(skb); | ||
| 91 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 92 | |||
| 93 | hdr_len = x->type->hdr_offset(x, skb, &prevhdr); | ||
| 94 | if (hdr_len < 0) | ||
| 95 | return hdr_len; | ||
| 96 | skb_set_mac_header(skb, | ||
| 97 | (prevhdr - x->props.header_len) - skb->data); | ||
| 98 | skb_set_network_header(skb, -x->props.header_len); | ||
| 99 | skb->transport_header = skb->network_header + hdr_len; | ||
| 100 | __skb_pull(skb, hdr_len); | ||
| 101 | memmove(ipv6_hdr(skb), iph, hdr_len); | ||
| 102 | return 0; | ||
| 103 | #else | ||
| 104 | WARN_ON_ONCE(1); | ||
| 105 | return -EAFNOSUPPORT; | ||
| 106 | #endif | ||
| 107 | } | ||
| 108 | |||
| 109 | /* Add route optimization header space. | ||
| 110 | * | ||
| 111 | * The IP header and mutable extension headers will be moved forward to make | ||
| 112 | * space for the route optimization header. | ||
| 113 | */ | ||
| 114 | static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 115 | { | ||
| 116 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 117 | struct ipv6hdr *iph; | ||
| 118 | u8 *prevhdr; | ||
| 119 | int hdr_len; | ||
| 120 | |||
| 121 | iph = ipv6_hdr(skb); | ||
| 122 | |||
| 123 | hdr_len = x->type->hdr_offset(x, skb, &prevhdr); | ||
| 124 | if (hdr_len < 0) | ||
| 125 | return hdr_len; | ||
| 126 | skb_set_mac_header(skb, | ||
| 127 | (prevhdr - x->props.header_len) - skb->data); | ||
| 128 | skb_set_network_header(skb, -x->props.header_len); | ||
| 129 | skb->transport_header = skb->network_header + hdr_len; | ||
| 130 | __skb_pull(skb, hdr_len); | ||
| 131 | memmove(ipv6_hdr(skb), iph, hdr_len); | ||
| 132 | |||
| 133 | x->lastused = ktime_get_real_seconds(); | ||
| 134 | |||
| 135 | return 0; | ||
| 136 | #else | ||
| 137 | WARN_ON_ONCE(1); | ||
| 138 | return -EAFNOSUPPORT; | ||
| 139 | #endif | ||
| 140 | } | ||
| 141 | |||
| 142 | /* Add encapsulation header. | ||
| 143 | * | ||
| 144 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
| 145 | */ | ||
| 146 | static int xfrm4_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb) | ||
| 147 | { | ||
| 148 | struct ip_beet_phdr *ph; | ||
| 149 | struct iphdr *top_iph; | ||
| 150 | int hdrlen, optlen; | ||
| 151 | |||
| 152 | hdrlen = 0; | ||
| 153 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | ||
| 154 | if (unlikely(optlen)) | ||
| 155 | hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
| 156 | |||
| 157 | skb_set_network_header(skb, -x->props.header_len - hdrlen + | ||
| 158 | (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph))); | ||
| 159 | if (x->sel.family != AF_INET6) | ||
| 160 | skb->network_header += IPV4_BEET_PHMAXLEN; | ||
| 161 | skb->mac_header = skb->network_header + | ||
| 162 | offsetof(struct iphdr, protocol); | ||
| 163 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 164 | |||
| 165 | xfrm4_beet_make_header(skb); | ||
| 166 | |||
| 167 | ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen); | ||
| 168 | |||
| 169 | top_iph = ip_hdr(skb); | ||
| 170 | |||
| 171 | if (unlikely(optlen)) { | ||
| 172 | if (WARN_ON(optlen < 0)) | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | ph->padlen = 4 - (optlen & 4); | ||
| 176 | ph->hdrlen = optlen / 8; | ||
| 177 | ph->nexthdr = top_iph->protocol; | ||
| 178 | if (ph->padlen) | ||
| 179 | memset(ph + 1, IPOPT_NOP, ph->padlen); | ||
| 180 | |||
| 181 | top_iph->protocol = IPPROTO_BEETPH; | ||
| 182 | top_iph->ihl = sizeof(struct iphdr) / 4; | ||
| 183 | } | ||
| 184 | |||
| 185 | top_iph->saddr = x->props.saddr.a4; | ||
| 186 | top_iph->daddr = x->id.daddr.a4; | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | /* Add encapsulation header. | ||
| 192 | * | ||
| 193 | * The top IP header will be constructed per RFC 2401. | ||
| 194 | */ | ||
| 195 | static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) | ||
| 196 | { | ||
| 197 | struct dst_entry *dst = skb_dst(skb); | ||
| 198 | struct iphdr *top_iph; | ||
| 199 | int flags; | ||
| 200 | |||
| 201 | skb_set_inner_network_header(skb, skb_network_offset(skb)); | ||
| 202 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 203 | |||
| 204 | skb_set_network_header(skb, -x->props.header_len); | ||
| 205 | skb->mac_header = skb->network_header + | ||
| 206 | offsetof(struct iphdr, protocol); | ||
| 207 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 208 | top_iph = ip_hdr(skb); | ||
| 209 | |||
| 210 | top_iph->ihl = 5; | ||
| 211 | top_iph->version = 4; | ||
| 212 | |||
| 213 | top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); | ||
| 214 | |||
| 215 | /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */ | ||
| 216 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) | ||
| 217 | top_iph->tos = 0; | ||
| 218 | else | ||
| 219 | top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 220 | top_iph->tos = INET_ECN_encapsulate(top_iph->tos, | ||
| 221 | XFRM_MODE_SKB_CB(skb)->tos); | ||
| 222 | |||
| 223 | flags = x->props.flags; | ||
| 224 | if (flags & XFRM_STATE_NOECN) | ||
| 225 | IP_ECN_clear(top_iph); | ||
| 226 | |||
| 227 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
| 228 | 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); | ||
| 229 | |||
| 230 | top_iph->ttl = ip4_dst_hoplimit(xfrm_dst_child(dst)); | ||
| 231 | |||
| 232 | top_iph->saddr = x->props.saddr.a4; | ||
| 233 | top_iph->daddr = x->id.daddr.a4; | ||
| 234 | ip_select_ident(dev_net(dst->dev), skb, NULL); | ||
| 235 | |||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 240 | static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb) | ||
| 241 | { | ||
| 242 | struct dst_entry *dst = skb_dst(skb); | ||
| 243 | struct ipv6hdr *top_iph; | ||
| 244 | int dsfield; | ||
| 245 | |||
| 246 | skb_set_inner_network_header(skb, skb_network_offset(skb)); | ||
| 247 | skb_set_inner_transport_header(skb, skb_transport_offset(skb)); | ||
| 248 | |||
| 249 | skb_set_network_header(skb, -x->props.header_len); | ||
| 250 | skb->mac_header = skb->network_header + | ||
| 251 | offsetof(struct ipv6hdr, nexthdr); | ||
| 252 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 253 | top_iph = ipv6_hdr(skb); | ||
| 254 | |||
| 255 | top_iph->version = 6; | ||
| 256 | |||
| 257 | memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | ||
| 258 | sizeof(top_iph->flow_lbl)); | ||
| 259 | top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); | ||
| 260 | |||
| 261 | if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) | ||
| 262 | dsfield = 0; | ||
| 263 | else | ||
| 264 | dsfield = XFRM_MODE_SKB_CB(skb)->tos; | ||
| 265 | dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos); | ||
| 266 | if (x->props.flags & XFRM_STATE_NOECN) | ||
| 267 | dsfield &= ~INET_ECN_MASK; | ||
| 268 | ipv6_change_dsfield(top_iph, 0, dsfield); | ||
| 269 | top_iph->hop_limit = ip6_dst_hoplimit(xfrm_dst_child(dst)); | ||
| 270 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; | ||
| 271 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | ||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | static int xfrm6_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb) | ||
| 276 | { | ||
| 277 | struct ipv6hdr *top_iph; | ||
| 278 | struct ip_beet_phdr *ph; | ||
| 279 | int optlen, hdr_len; | ||
| 280 | |||
| 281 | hdr_len = 0; | ||
| 282 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | ||
| 283 | if (unlikely(optlen)) | ||
| 284 | hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
| 285 | |||
| 286 | skb_set_network_header(skb, -x->props.header_len - hdr_len); | ||
| 287 | if (x->sel.family != AF_INET6) | ||
| 288 | skb->network_header += IPV4_BEET_PHMAXLEN; | ||
| 289 | skb->mac_header = skb->network_header + | ||
| 290 | offsetof(struct ipv6hdr, nexthdr); | ||
| 291 | skb->transport_header = skb->network_header + sizeof(*top_iph); | ||
| 292 | ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdr_len); | ||
| 293 | |||
| 294 | xfrm6_beet_make_header(skb); | ||
| 295 | |||
| 296 | top_iph = ipv6_hdr(skb); | ||
| 297 | if (unlikely(optlen)) { | ||
| 298 | if (WARN_ON(optlen < 0)) | ||
| 299 | return -EINVAL; | ||
| 300 | |||
| 301 | ph->padlen = 4 - (optlen & 4); | ||
| 302 | ph->hdrlen = optlen / 8; | ||
| 303 | ph->nexthdr = top_iph->nexthdr; | ||
| 304 | if (ph->padlen) | ||
| 305 | memset(ph + 1, IPOPT_NOP, ph->padlen); | ||
| 306 | |||
| 307 | top_iph->nexthdr = IPPROTO_BEETPH; | ||
| 308 | } | ||
| 309 | |||
| 310 | top_iph->saddr = *(struct in6_addr *)&x->props.saddr; | ||
| 311 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | #endif | ||
| 315 | |||
| 316 | /* Add encapsulation header. | ||
| 317 | * | ||
| 318 | * On exit, the transport header will be set to the start of the | ||
| 319 | * encapsulation header to be filled in by x->type->output and the mac | ||
| 320 | * header will be set to the nextheader (protocol for IPv4) field of the | ||
| 321 | * extension header directly preceding the encapsulation header, or in | ||
| 322 | * its absence, that of the top IP header. | ||
| 323 | * The value of the network header will always point to the top IP header | ||
| 324 | * while skb->data will point to the payload. | ||
| 325 | */ | ||
| 326 | static int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 327 | { | ||
| 328 | int err; | ||
| 329 | |||
| 330 | err = xfrm_inner_extract_output(x, skb); | ||
| 331 | if (err) | ||
| 332 | return err; | ||
| 333 | |||
| 334 | IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; | ||
| 335 | skb->protocol = htons(ETH_P_IP); | ||
| 336 | |||
| 337 | switch (x->outer_mode.encap) { | ||
| 338 | case XFRM_MODE_BEET: | ||
| 339 | return xfrm4_beet_encap_add(x, skb); | ||
| 340 | case XFRM_MODE_TUNNEL: | ||
| 341 | return xfrm4_tunnel_encap_add(x, skb); | ||
| 342 | } | ||
| 343 | |||
| 344 | WARN_ON_ONCE(1); | ||
| 345 | return -EOPNOTSUPP; | ||
| 346 | } | ||
| 347 | |||
| 348 | static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 349 | { | ||
| 350 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 351 | int err; | ||
| 352 | |||
| 353 | err = xfrm_inner_extract_output(x, skb); | ||
| 354 | if (err) | ||
| 355 | return err; | ||
| 356 | |||
| 357 | skb->ignore_df = 1; | ||
| 358 | skb->protocol = htons(ETH_P_IPV6); | ||
| 359 | |||
| 360 | switch (x->outer_mode.encap) { | ||
| 361 | case XFRM_MODE_BEET: | ||
| 362 | return xfrm6_beet_encap_add(x, skb); | ||
| 363 | case XFRM_MODE_TUNNEL: | ||
| 364 | return xfrm6_tunnel_encap_add(x, skb); | ||
| 365 | default: | ||
| 366 | WARN_ON_ONCE(1); | ||
| 367 | return -EOPNOTSUPP; | ||
| 368 | } | ||
| 369 | #endif | ||
| 370 | WARN_ON_ONCE(1); | ||
| 371 | return -EAFNOSUPPORT; | ||
| 372 | } | ||
| 373 | |||
| 374 | static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 375 | { | ||
| 376 | switch (x->outer_mode.encap) { | ||
| 377 | case XFRM_MODE_BEET: | ||
| 378 | case XFRM_MODE_TUNNEL: | ||
| 379 | if (x->outer_mode.family == AF_INET) | ||
| 380 | return xfrm4_prepare_output(x, skb); | ||
| 381 | if (x->outer_mode.family == AF_INET6) | ||
| 382 | return xfrm6_prepare_output(x, skb); | ||
| 383 | break; | ||
| 384 | case XFRM_MODE_TRANSPORT: | ||
| 385 | if (x->outer_mode.family == AF_INET) | ||
| 386 | return xfrm4_transport_output(x, skb); | ||
| 387 | if (x->outer_mode.family == AF_INET6) | ||
| 388 | return xfrm6_transport_output(x, skb); | ||
| 389 | break; | ||
| 390 | case XFRM_MODE_ROUTEOPTIMIZATION: | ||
| 391 | if (x->outer_mode.family == AF_INET6) | ||
| 392 | return xfrm6_ro_output(x, skb); | ||
| 393 | WARN_ON_ONCE(1); | ||
| 394 | break; | ||
| 395 | default: | ||
| 396 | WARN_ON_ONCE(1); | ||
| 397 | break; | ||
| 398 | } | ||
| 399 | |||
| 400 | return -EOPNOTSUPP; | ||
| 401 | } | ||
| 402 | |||
| 403 | #if IS_ENABLED(CONFIG_NET_PKTGEN) | ||
| 404 | int pktgen_xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb) | ||
| 405 | { | ||
| 406 | return xfrm_outer_mode_output(x, skb); | ||
| 407 | } | ||
| 408 | EXPORT_SYMBOL_GPL(pktgen_xfrm_outer_mode_output); | ||
| 409 | #endif | ||
| 410 | |||
| 53 | static int xfrm_output_one(struct sk_buff *skb, int err) | 411 | static int xfrm_output_one(struct sk_buff *skb, int err) |
| 54 | { | 412 | { |
| 55 | struct dst_entry *dst = skb_dst(skb); | 413 | struct dst_entry *dst = skb_dst(skb); |
| @@ -68,7 +426,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err) | |||
| 68 | 426 | ||
| 69 | skb->mark = xfrm_smark_get(skb->mark, x); | 427 | skb->mark = xfrm_smark_get(skb->mark, x); |
| 70 | 428 | ||
| 71 | err = x->outer_mode->output(x, skb); | 429 | err = xfrm_outer_mode_output(x, skb); |
| 72 | if (err) { | 430 | if (err) { |
| 73 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); | 431 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); |
| 74 | goto error_nolock; | 432 | goto error_nolock; |
| @@ -131,7 +489,7 @@ resume: | |||
| 131 | } | 489 | } |
| 132 | skb_dst_set(skb, dst); | 490 | skb_dst_set(skb, dst); |
| 133 | x = dst->xfrm; | 491 | x = dst->xfrm; |
| 134 | } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)); | 492 | } while (x && !(x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL)); |
| 135 | 493 | ||
| 136 | return 0; | 494 | return 0; |
| 137 | 495 | ||
| @@ -258,20 +616,29 @@ out: | |||
| 258 | } | 616 | } |
| 259 | EXPORT_SYMBOL_GPL(xfrm_output); | 617 | EXPORT_SYMBOL_GPL(xfrm_output); |
| 260 | 618 | ||
| 261 | int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) | 619 | static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) |
| 262 | { | 620 | { |
| 263 | struct xfrm_mode *inner_mode; | 621 | const struct xfrm_state_afinfo *afinfo; |
| 622 | const struct xfrm_mode *inner_mode; | ||
| 623 | int err = -EAFNOSUPPORT; | ||
| 624 | |||
| 264 | if (x->sel.family == AF_UNSPEC) | 625 | if (x->sel.family == AF_UNSPEC) |
| 265 | inner_mode = xfrm_ip2inner_mode(x, | 626 | inner_mode = xfrm_ip2inner_mode(x, |
| 266 | xfrm_af2proto(skb_dst(skb)->ops->family)); | 627 | xfrm_af2proto(skb_dst(skb)->ops->family)); |
| 267 | else | 628 | else |
| 268 | inner_mode = x->inner_mode; | 629 | inner_mode = &x->inner_mode; |
| 269 | 630 | ||
| 270 | if (inner_mode == NULL) | 631 | if (inner_mode == NULL) |
| 271 | return -EAFNOSUPPORT; | 632 | return -EAFNOSUPPORT; |
| 272 | return inner_mode->afinfo->extract_output(x, skb); | 633 | |
| 634 | rcu_read_lock(); | ||
| 635 | afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family); | ||
| 636 | if (likely(afinfo)) | ||
| 637 | err = afinfo->extract_output(x, skb); | ||
| 638 | rcu_read_unlock(); | ||
| 639 | |||
| 640 | return err; | ||
| 273 | } | 641 | } |
| 274 | EXPORT_SYMBOL_GPL(xfrm_inner_extract_output); | ||
| 275 | 642 | ||
| 276 | void xfrm_local_error(struct sk_buff *skb, int mtu) | 643 | void xfrm_local_error(struct sk_buff *skb, int mtu) |
| 277 | { | 644 | { |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 8d1a898d0ba5..03b6bf85d70b 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -27,10 +27,14 @@ | |||
| 27 | #include <linux/cpu.h> | 27 | #include <linux/cpu.h> |
| 28 | #include <linux/audit.h> | 28 | #include <linux/audit.h> |
| 29 | #include <linux/rhashtable.h> | 29 | #include <linux/rhashtable.h> |
| 30 | #include <linux/if_tunnel.h> | ||
| 30 | #include <net/dst.h> | 31 | #include <net/dst.h> |
| 31 | #include <net/flow.h> | 32 | #include <net/flow.h> |
| 32 | #include <net/xfrm.h> | 33 | #include <net/xfrm.h> |
| 33 | #include <net/ip.h> | 34 | #include <net/ip.h> |
| 35 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 36 | #include <net/mip6.h> | ||
| 37 | #endif | ||
| 34 | #ifdef CONFIG_XFRM_STATISTICS | 38 | #ifdef CONFIG_XFRM_STATISTICS |
| 35 | #include <net/snmp.h> | 39 | #include <net/snmp.h> |
| 36 | #endif | 40 | #endif |
| @@ -2450,18 +2454,10 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl, | |||
| 2450 | 2454 | ||
| 2451 | static int xfrm_get_tos(const struct flowi *fl, int family) | 2455 | static int xfrm_get_tos(const struct flowi *fl, int family) |
| 2452 | { | 2456 | { |
| 2453 | const struct xfrm_policy_afinfo *afinfo; | 2457 | if (family == AF_INET) |
| 2454 | int tos; | 2458 | return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos; |
| 2455 | 2459 | ||
| 2456 | afinfo = xfrm_policy_get_afinfo(family); | 2460 | return 0; |
| 2457 | if (!afinfo) | ||
| 2458 | return 0; | ||
| 2459 | |||
| 2460 | tos = afinfo->get_tos(fl); | ||
| 2461 | |||
| 2462 | rcu_read_unlock(); | ||
| 2463 | |||
| 2464 | return tos; | ||
| 2465 | } | 2461 | } |
| 2466 | 2462 | ||
| 2467 | static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) | 2463 | static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) |
| @@ -2499,21 +2495,14 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) | |||
| 2499 | return xdst; | 2495 | return xdst; |
| 2500 | } | 2496 | } |
| 2501 | 2497 | ||
| 2502 | static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, | 2498 | static void xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, |
| 2503 | int nfheader_len) | 2499 | int nfheader_len) |
| 2504 | { | 2500 | { |
| 2505 | const struct xfrm_policy_afinfo *afinfo = | 2501 | if (dst->ops->family == AF_INET6) { |
| 2506 | xfrm_policy_get_afinfo(dst->ops->family); | 2502 | struct rt6_info *rt = (struct rt6_info *)dst; |
| 2507 | int err; | 2503 | path->path_cookie = rt6_get_cookie(rt); |
| 2508 | 2504 | path->u.rt6.rt6i_nfheader_len = nfheader_len; | |
| 2509 | if (!afinfo) | 2505 | } |
| 2510 | return -EINVAL; | ||
| 2511 | |||
| 2512 | err = afinfo->init_path(path, dst, nfheader_len); | ||
| 2513 | |||
| 2514 | rcu_read_unlock(); | ||
| 2515 | |||
| 2516 | return err; | ||
| 2517 | } | 2506 | } |
| 2518 | 2507 | ||
| 2519 | static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | 2508 | static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
| @@ -2545,10 +2534,11 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
| 2545 | const struct flowi *fl, | 2534 | const struct flowi *fl, |
| 2546 | struct dst_entry *dst) | 2535 | struct dst_entry *dst) |
| 2547 | { | 2536 | { |
| 2537 | const struct xfrm_state_afinfo *afinfo; | ||
| 2538 | const struct xfrm_mode *inner_mode; | ||
| 2548 | struct net *net = xp_net(policy); | 2539 | struct net *net = xp_net(policy); |
| 2549 | unsigned long now = jiffies; | 2540 | unsigned long now = jiffies; |
| 2550 | struct net_device *dev; | 2541 | struct net_device *dev; |
| 2551 | struct xfrm_mode *inner_mode; | ||
| 2552 | struct xfrm_dst *xdst_prev = NULL; | 2542 | struct xfrm_dst *xdst_prev = NULL; |
| 2553 | struct xfrm_dst *xdst0 = NULL; | 2543 | struct xfrm_dst *xdst0 = NULL; |
| 2554 | int i = 0; | 2544 | int i = 0; |
| @@ -2594,7 +2584,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
| 2594 | goto put_states; | 2584 | goto put_states; |
| 2595 | } | 2585 | } |
| 2596 | } else | 2586 | } else |
| 2597 | inner_mode = xfrm[i]->inner_mode; | 2587 | inner_mode = &xfrm[i]->inner_mode; |
| 2598 | 2588 | ||
| 2599 | xdst->route = dst; | 2589 | xdst->route = dst; |
| 2600 | dst_copy_metrics(dst1, dst); | 2590 | dst_copy_metrics(dst1, dst); |
| @@ -2622,7 +2612,14 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
| 2622 | dst1->lastuse = now; | 2612 | dst1->lastuse = now; |
| 2623 | 2613 | ||
| 2624 | dst1->input = dst_discard; | 2614 | dst1->input = dst_discard; |
| 2625 | dst1->output = inner_mode->afinfo->output; | 2615 | |
| 2616 | rcu_read_lock(); | ||
| 2617 | afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family); | ||
| 2618 | if (likely(afinfo)) | ||
| 2619 | dst1->output = afinfo->output; | ||
| 2620 | else | ||
| 2621 | dst1->output = dst_discard_out; | ||
| 2622 | rcu_read_unlock(); | ||
| 2626 | 2623 | ||
| 2627 | xdst_prev = xdst; | 2624 | xdst_prev = xdst; |
| 2628 | 2625 | ||
| @@ -3263,20 +3260,229 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star | |||
| 3263 | return start; | 3260 | return start; |
| 3264 | } | 3261 | } |
| 3265 | 3262 | ||
| 3263 | static void | ||
| 3264 | decode_session4(struct sk_buff *skb, struct flowi *fl, bool reverse) | ||
| 3265 | { | ||
| 3266 | const struct iphdr *iph = ip_hdr(skb); | ||
| 3267 | u8 *xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3268 | struct flowi4 *fl4 = &fl->u.ip4; | ||
| 3269 | int oif = 0; | ||
| 3270 | |||
| 3271 | if (skb_dst(skb)) | ||
| 3272 | oif = skb_dst(skb)->dev->ifindex; | ||
| 3273 | |||
| 3274 | memset(fl4, 0, sizeof(struct flowi4)); | ||
| 3275 | fl4->flowi4_mark = skb->mark; | ||
| 3276 | fl4->flowi4_oif = reverse ? skb->skb_iif : oif; | ||
| 3277 | |||
| 3278 | if (!ip_is_fragment(iph)) { | ||
| 3279 | switch (iph->protocol) { | ||
| 3280 | case IPPROTO_UDP: | ||
| 3281 | case IPPROTO_UDPLITE: | ||
| 3282 | case IPPROTO_TCP: | ||
| 3283 | case IPPROTO_SCTP: | ||
| 3284 | case IPPROTO_DCCP: | ||
| 3285 | if (xprth + 4 < skb->data || | ||
| 3286 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 3287 | __be16 *ports; | ||
| 3288 | |||
| 3289 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3290 | ports = (__be16 *)xprth; | ||
| 3291 | |||
| 3292 | fl4->fl4_sport = ports[!!reverse]; | ||
| 3293 | fl4->fl4_dport = ports[!reverse]; | ||
| 3294 | } | ||
| 3295 | break; | ||
| 3296 | case IPPROTO_ICMP: | ||
| 3297 | if (xprth + 2 < skb->data || | ||
| 3298 | pskb_may_pull(skb, xprth + 2 - skb->data)) { | ||
| 3299 | u8 *icmp; | ||
| 3300 | |||
| 3301 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3302 | icmp = xprth; | ||
| 3303 | |||
| 3304 | fl4->fl4_icmp_type = icmp[0]; | ||
| 3305 | fl4->fl4_icmp_code = icmp[1]; | ||
| 3306 | } | ||
| 3307 | break; | ||
| 3308 | case IPPROTO_ESP: | ||
| 3309 | if (xprth + 4 < skb->data || | ||
| 3310 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 3311 | __be32 *ehdr; | ||
| 3312 | |||
| 3313 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3314 | ehdr = (__be32 *)xprth; | ||
| 3315 | |||
| 3316 | fl4->fl4_ipsec_spi = ehdr[0]; | ||
| 3317 | } | ||
| 3318 | break; | ||
| 3319 | case IPPROTO_AH: | ||
| 3320 | if (xprth + 8 < skb->data || | ||
| 3321 | pskb_may_pull(skb, xprth + 8 - skb->data)) { | ||
| 3322 | __be32 *ah_hdr; | ||
| 3323 | |||
| 3324 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3325 | ah_hdr = (__be32 *)xprth; | ||
| 3326 | |||
| 3327 | fl4->fl4_ipsec_spi = ah_hdr[1]; | ||
| 3328 | } | ||
| 3329 | break; | ||
| 3330 | case IPPROTO_COMP: | ||
| 3331 | if (xprth + 4 < skb->data || | ||
| 3332 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | ||
| 3333 | __be16 *ipcomp_hdr; | ||
| 3334 | |||
| 3335 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3336 | ipcomp_hdr = (__be16 *)xprth; | ||
| 3337 | |||
| 3338 | fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); | ||
| 3339 | } | ||
| 3340 | break; | ||
| 3341 | case IPPROTO_GRE: | ||
| 3342 | if (xprth + 12 < skb->data || | ||
| 3343 | pskb_may_pull(skb, xprth + 12 - skb->data)) { | ||
| 3344 | __be16 *greflags; | ||
| 3345 | __be32 *gre_hdr; | ||
| 3346 | |||
| 3347 | xprth = skb_network_header(skb) + iph->ihl * 4; | ||
| 3348 | greflags = (__be16 *)xprth; | ||
| 3349 | gre_hdr = (__be32 *)xprth; | ||
| 3350 | |||
| 3351 | if (greflags[0] & GRE_KEY) { | ||
| 3352 | if (greflags[0] & GRE_CSUM) | ||
| 3353 | gre_hdr++; | ||
| 3354 | fl4->fl4_gre_key = gre_hdr[1]; | ||
| 3355 | } | ||
| 3356 | } | ||
| 3357 | break; | ||
| 3358 | default: | ||
| 3359 | fl4->fl4_ipsec_spi = 0; | ||
| 3360 | break; | ||
| 3361 | } | ||
| 3362 | } | ||
| 3363 | fl4->flowi4_proto = iph->protocol; | ||
| 3364 | fl4->daddr = reverse ? iph->saddr : iph->daddr; | ||
| 3365 | fl4->saddr = reverse ? iph->daddr : iph->saddr; | ||
| 3366 | fl4->flowi4_tos = iph->tos; | ||
| 3367 | } | ||
| 3368 | |||
| 3369 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 3370 | static void | ||
| 3371 | decode_session6(struct sk_buff *skb, struct flowi *fl, bool reverse) | ||
| 3372 | { | ||
| 3373 | struct flowi6 *fl6 = &fl->u.ip6; | ||
| 3374 | int onlyproto = 0; | ||
| 3375 | const struct ipv6hdr *hdr = ipv6_hdr(skb); | ||
| 3376 | u32 offset = sizeof(*hdr); | ||
| 3377 | struct ipv6_opt_hdr *exthdr; | ||
| 3378 | const unsigned char *nh = skb_network_header(skb); | ||
| 3379 | u16 nhoff = IP6CB(skb)->nhoff; | ||
| 3380 | int oif = 0; | ||
| 3381 | u8 nexthdr; | ||
| 3382 | |||
| 3383 | if (!nhoff) | ||
| 3384 | nhoff = offsetof(struct ipv6hdr, nexthdr); | ||
| 3385 | |||
| 3386 | nexthdr = nh[nhoff]; | ||
| 3387 | |||
| 3388 | if (skb_dst(skb)) | ||
| 3389 | oif = skb_dst(skb)->dev->ifindex; | ||
| 3390 | |||
| 3391 | memset(fl6, 0, sizeof(struct flowi6)); | ||
| 3392 | fl6->flowi6_mark = skb->mark; | ||
| 3393 | fl6->flowi6_oif = reverse ? skb->skb_iif : oif; | ||
| 3394 | |||
| 3395 | fl6->daddr = reverse ? hdr->saddr : hdr->daddr; | ||
| 3396 | fl6->saddr = reverse ? hdr->daddr : hdr->saddr; | ||
| 3397 | |||
| 3398 | while (nh + offset + sizeof(*exthdr) < skb->data || | ||
| 3399 | pskb_may_pull(skb, nh + offset + sizeof(*exthdr) - skb->data)) { | ||
| 3400 | nh = skb_network_header(skb); | ||
| 3401 | exthdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 3402 | |||
| 3403 | switch (nexthdr) { | ||
| 3404 | case NEXTHDR_FRAGMENT: | ||
| 3405 | onlyproto = 1; | ||
| 3406 | /* fall through */ | ||
| 3407 | case NEXTHDR_ROUTING: | ||
| 3408 | case NEXTHDR_HOP: | ||
| 3409 | case NEXTHDR_DEST: | ||
| 3410 | offset += ipv6_optlen(exthdr); | ||
| 3411 | nexthdr = exthdr->nexthdr; | ||
| 3412 | exthdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 3413 | break; | ||
| 3414 | case IPPROTO_UDP: | ||
| 3415 | case IPPROTO_UDPLITE: | ||
| 3416 | case IPPROTO_TCP: | ||
| 3417 | case IPPROTO_SCTP: | ||
| 3418 | case IPPROTO_DCCP: | ||
| 3419 | if (!onlyproto && (nh + offset + 4 < skb->data || | ||
| 3420 | pskb_may_pull(skb, nh + offset + 4 - skb->data))) { | ||
| 3421 | __be16 *ports; | ||
| 3422 | |||
| 3423 | nh = skb_network_header(skb); | ||
| 3424 | ports = (__be16 *)(nh + offset); | ||
| 3425 | fl6->fl6_sport = ports[!!reverse]; | ||
| 3426 | fl6->fl6_dport = ports[!reverse]; | ||
| 3427 | } | ||
| 3428 | fl6->flowi6_proto = nexthdr; | ||
| 3429 | return; | ||
| 3430 | case IPPROTO_ICMPV6: | ||
| 3431 | if (!onlyproto && (nh + offset + 2 < skb->data || | ||
| 3432 | pskb_may_pull(skb, nh + offset + 2 - skb->data))) { | ||
| 3433 | u8 *icmp; | ||
| 3434 | |||
| 3435 | nh = skb_network_header(skb); | ||
| 3436 | icmp = (u8 *)(nh + offset); | ||
| 3437 | fl6->fl6_icmp_type = icmp[0]; | ||
| 3438 | fl6->fl6_icmp_code = icmp[1]; | ||
| 3439 | } | ||
| 3440 | fl6->flowi6_proto = nexthdr; | ||
| 3441 | return; | ||
| 3442 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 3443 | case IPPROTO_MH: | ||
| 3444 | offset += ipv6_optlen(exthdr); | ||
| 3445 | if (!onlyproto && (nh + offset + 3 < skb->data || | ||
| 3446 | pskb_may_pull(skb, nh + offset + 3 - skb->data))) { | ||
| 3447 | struct ip6_mh *mh; | ||
| 3448 | |||
| 3449 | nh = skb_network_header(skb); | ||
| 3450 | mh = (struct ip6_mh *)(nh + offset); | ||
| 3451 | fl6->fl6_mh_type = mh->ip6mh_type; | ||
| 3452 | } | ||
| 3453 | fl6->flowi6_proto = nexthdr; | ||
| 3454 | return; | ||
| 3455 | #endif | ||
| 3456 | /* XXX Why are there these headers? */ | ||
| 3457 | case IPPROTO_AH: | ||
| 3458 | case IPPROTO_ESP: | ||
| 3459 | case IPPROTO_COMP: | ||
| 3460 | default: | ||
| 3461 | fl6->fl6_ipsec_spi = 0; | ||
| 3462 | fl6->flowi6_proto = nexthdr; | ||
| 3463 | return; | ||
| 3464 | } | ||
| 3465 | } | ||
| 3466 | } | ||
| 3467 | #endif | ||
| 3468 | |||
| 3266 | int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, | 3469 | int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, |
| 3267 | unsigned int family, int reverse) | 3470 | unsigned int family, int reverse) |
| 3268 | { | 3471 | { |
| 3269 | const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 3472 | switch (family) { |
| 3270 | int err; | 3473 | case AF_INET: |
| 3271 | 3474 | decode_session4(skb, fl, reverse); | |
| 3272 | if (unlikely(afinfo == NULL)) | 3475 | break; |
| 3476 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 3477 | case AF_INET6: | ||
| 3478 | decode_session6(skb, fl, reverse); | ||
| 3479 | break; | ||
| 3480 | #endif | ||
| 3481 | default: | ||
| 3273 | return -EAFNOSUPPORT; | 3482 | return -EAFNOSUPPORT; |
| 3483 | } | ||
| 3274 | 3484 | ||
| 3275 | afinfo->decode_session(skb, fl, reverse); | 3485 | return security_xfrm_decode_session(skb, &fl->flowi_secid); |
| 3276 | |||
| 3277 | err = security_xfrm_decode_session(skb, &fl->flowi_secid); | ||
| 3278 | rcu_read_unlock(); | ||
| 3279 | return err; | ||
| 3280 | } | 3486 | } |
| 3281 | EXPORT_SYMBOL(__xfrm_decode_session); | 3487 | EXPORT_SYMBOL(__xfrm_decode_session); |
| 3282 | 3488 | ||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 1bb971f46fc6..ed25eb81aabe 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -173,7 +173,7 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock); | |||
| 173 | int __xfrm_state_delete(struct xfrm_state *x); | 173 | int __xfrm_state_delete(struct xfrm_state *x); |
| 174 | 174 | ||
| 175 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 175 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
| 176 | bool km_is_alive(const struct km_event *c); | 176 | static bool km_is_alive(const struct km_event *c); |
| 177 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); | 177 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); |
| 178 | 178 | ||
| 179 | static DEFINE_SPINLOCK(xfrm_type_lock); | 179 | static DEFINE_SPINLOCK(xfrm_type_lock); |
| @@ -330,100 +330,67 @@ static void xfrm_put_type_offload(const struct xfrm_type_offload *type) | |||
| 330 | module_put(type->owner); | 330 | module_put(type->owner); |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | static DEFINE_SPINLOCK(xfrm_mode_lock); | 333 | static const struct xfrm_mode xfrm4_mode_map[XFRM_MODE_MAX] = { |
| 334 | int xfrm_register_mode(struct xfrm_mode *mode, int family) | 334 | [XFRM_MODE_BEET] = { |
| 335 | { | 335 | .encap = XFRM_MODE_BEET, |
| 336 | struct xfrm_state_afinfo *afinfo; | 336 | .flags = XFRM_MODE_FLAG_TUNNEL, |
| 337 | struct xfrm_mode **modemap; | 337 | .family = AF_INET, |
| 338 | int err; | 338 | }, |
| 339 | 339 | [XFRM_MODE_TRANSPORT] = { | |
| 340 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | 340 | .encap = XFRM_MODE_TRANSPORT, |
| 341 | return -EINVAL; | 341 | .family = AF_INET, |
| 342 | 342 | }, | |
| 343 | afinfo = xfrm_state_get_afinfo(family); | 343 | [XFRM_MODE_TUNNEL] = { |
| 344 | if (unlikely(afinfo == NULL)) | 344 | .encap = XFRM_MODE_TUNNEL, |
| 345 | return -EAFNOSUPPORT; | 345 | .flags = XFRM_MODE_FLAG_TUNNEL, |
| 346 | 346 | .family = AF_INET, | |
| 347 | err = -EEXIST; | 347 | }, |
| 348 | modemap = afinfo->mode_map; | 348 | }; |
| 349 | spin_lock_bh(&xfrm_mode_lock); | 349 | |
| 350 | if (modemap[mode->encap]) | 350 | static const struct xfrm_mode xfrm6_mode_map[XFRM_MODE_MAX] = { |
| 351 | goto out; | 351 | [XFRM_MODE_BEET] = { |
| 352 | 352 | .encap = XFRM_MODE_BEET, | |
| 353 | err = -ENOENT; | 353 | .flags = XFRM_MODE_FLAG_TUNNEL, |
| 354 | if (!try_module_get(afinfo->owner)) | 354 | .family = AF_INET6, |
| 355 | goto out; | 355 | }, |
| 356 | 356 | [XFRM_MODE_ROUTEOPTIMIZATION] = { | |
| 357 | mode->afinfo = afinfo; | 357 | .encap = XFRM_MODE_ROUTEOPTIMIZATION, |
| 358 | modemap[mode->encap] = mode; | 358 | .family = AF_INET6, |
| 359 | err = 0; | 359 | }, |
| 360 | 360 | [XFRM_MODE_TRANSPORT] = { | |
| 361 | out: | 361 | .encap = XFRM_MODE_TRANSPORT, |
| 362 | spin_unlock_bh(&xfrm_mode_lock); | 362 | .family = AF_INET6, |
| 363 | rcu_read_unlock(); | 363 | }, |
| 364 | return err; | 364 | [XFRM_MODE_TUNNEL] = { |
| 365 | } | 365 | .encap = XFRM_MODE_TUNNEL, |
| 366 | EXPORT_SYMBOL(xfrm_register_mode); | 366 | .flags = XFRM_MODE_FLAG_TUNNEL, |
| 367 | 367 | .family = AF_INET6, | |
| 368 | int xfrm_unregister_mode(struct xfrm_mode *mode, int family) | 368 | }, |
| 369 | { | 369 | }; |
| 370 | struct xfrm_state_afinfo *afinfo; | 370 | |
| 371 | struct xfrm_mode **modemap; | 371 | static const struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) |
| 372 | int err; | 372 | { |
| 373 | 373 | const struct xfrm_mode *mode; | |
| 374 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
| 375 | return -EINVAL; | ||
| 376 | |||
| 377 | afinfo = xfrm_state_get_afinfo(family); | ||
| 378 | if (unlikely(afinfo == NULL)) | ||
| 379 | return -EAFNOSUPPORT; | ||
| 380 | |||
| 381 | err = -ENOENT; | ||
| 382 | modemap = afinfo->mode_map; | ||
| 383 | spin_lock_bh(&xfrm_mode_lock); | ||
| 384 | if (likely(modemap[mode->encap] == mode)) { | ||
| 385 | modemap[mode->encap] = NULL; | ||
| 386 | module_put(mode->afinfo->owner); | ||
| 387 | err = 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | spin_unlock_bh(&xfrm_mode_lock); | ||
| 391 | rcu_read_unlock(); | ||
| 392 | return err; | ||
| 393 | } | ||
| 394 | EXPORT_SYMBOL(xfrm_unregister_mode); | ||
| 395 | |||
| 396 | static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) | ||
| 397 | { | ||
| 398 | struct xfrm_state_afinfo *afinfo; | ||
| 399 | struct xfrm_mode *mode; | ||
| 400 | int modload_attempted = 0; | ||
| 401 | 374 | ||
| 402 | if (unlikely(encap >= XFRM_MODE_MAX)) | 375 | if (unlikely(encap >= XFRM_MODE_MAX)) |
| 403 | return NULL; | 376 | return NULL; |
| 404 | 377 | ||
| 405 | retry: | 378 | switch (family) { |
| 406 | afinfo = xfrm_state_get_afinfo(family); | 379 | case AF_INET: |
| 407 | if (unlikely(afinfo == NULL)) | 380 | mode = &xfrm4_mode_map[encap]; |
| 408 | return NULL; | 381 | if (mode->family == family) |
| 409 | 382 | return mode; | |
| 410 | mode = READ_ONCE(afinfo->mode_map[encap]); | 383 | break; |
| 411 | if (unlikely(mode && !try_module_get(mode->owner))) | 384 | case AF_INET6: |
| 412 | mode = NULL; | 385 | mode = &xfrm6_mode_map[encap]; |
| 413 | 386 | if (mode->family == family) | |
| 414 | rcu_read_unlock(); | 387 | return mode; |
| 415 | if (!mode && !modload_attempted) { | 388 | break; |
| 416 | request_module("xfrm-mode-%d-%d", family, encap); | 389 | default: |
| 417 | modload_attempted = 1; | 390 | break; |
| 418 | goto retry; | ||
| 419 | } | 391 | } |
| 420 | 392 | ||
| 421 | return mode; | 393 | return NULL; |
| 422 | } | ||
| 423 | |||
| 424 | static void xfrm_put_mode(struct xfrm_mode *mode) | ||
| 425 | { | ||
| 426 | module_put(mode->owner); | ||
| 427 | } | 394 | } |
| 428 | 395 | ||
| 429 | void xfrm_state_free(struct xfrm_state *x) | 396 | void xfrm_state_free(struct xfrm_state *x) |
| @@ -444,12 +411,6 @@ static void ___xfrm_state_destroy(struct xfrm_state *x) | |||
| 444 | kfree(x->coaddr); | 411 | kfree(x->coaddr); |
| 445 | kfree(x->replay_esn); | 412 | kfree(x->replay_esn); |
| 446 | kfree(x->preplay_esn); | 413 | kfree(x->preplay_esn); |
| 447 | if (x->inner_mode) | ||
| 448 | xfrm_put_mode(x->inner_mode); | ||
| 449 | if (x->inner_mode_iaf) | ||
| 450 | xfrm_put_mode(x->inner_mode_iaf); | ||
| 451 | if (x->outer_mode) | ||
| 452 | xfrm_put_mode(x->outer_mode); | ||
| 453 | if (x->type_offload) | 414 | if (x->type_offload) |
| 454 | xfrm_put_type_offload(x->type_offload); | 415 | xfrm_put_type_offload(x->type_offload); |
| 455 | if (x->type) { | 416 | if (x->type) { |
| @@ -590,8 +551,6 @@ struct xfrm_state *xfrm_state_alloc(struct net *net) | |||
| 590 | x->lft.hard_packet_limit = XFRM_INF; | 551 | x->lft.hard_packet_limit = XFRM_INF; |
| 591 | x->replay_maxage = 0; | 552 | x->replay_maxage = 0; |
| 592 | x->replay_maxdiff = 0; | 553 | x->replay_maxdiff = 0; |
| 593 | x->inner_mode = NULL; | ||
| 594 | x->inner_mode_iaf = NULL; | ||
| 595 | spin_lock_init(&x->lock); | 554 | spin_lock_init(&x->lock); |
| 596 | } | 555 | } |
| 597 | return x; | 556 | return x; |
| @@ -2066,7 +2025,7 @@ int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address | |||
| 2066 | } | 2025 | } |
| 2067 | EXPORT_SYMBOL(km_report); | 2026 | EXPORT_SYMBOL(km_report); |
| 2068 | 2027 | ||
| 2069 | bool km_is_alive(const struct km_event *c) | 2028 | static bool km_is_alive(const struct km_event *c) |
| 2070 | { | 2029 | { |
| 2071 | struct xfrm_mgr *km; | 2030 | struct xfrm_mgr *km; |
| 2072 | bool is_alive = false; | 2031 | bool is_alive = false; |
| @@ -2082,7 +2041,6 @@ bool km_is_alive(const struct km_event *c) | |||
| 2082 | 2041 | ||
| 2083 | return is_alive; | 2042 | return is_alive; |
| 2084 | } | 2043 | } |
| 2085 | EXPORT_SYMBOL(km_is_alive); | ||
| 2086 | 2044 | ||
| 2087 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) | 2045 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) |
| 2088 | { | 2046 | { |
| @@ -2195,6 +2153,7 @@ struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family) | |||
| 2195 | 2153 | ||
| 2196 | return rcu_dereference(xfrm_state_afinfo[family]); | 2154 | return rcu_dereference(xfrm_state_afinfo[family]); |
| 2197 | } | 2155 | } |
| 2156 | EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu); | ||
| 2198 | 2157 | ||
| 2199 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) | 2158 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) |
| 2200 | { | 2159 | { |
| @@ -2242,8 +2201,9 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) | |||
| 2242 | 2201 | ||
| 2243 | int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | 2202 | int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) |
| 2244 | { | 2203 | { |
| 2245 | struct xfrm_state_afinfo *afinfo; | 2204 | const struct xfrm_state_afinfo *afinfo; |
| 2246 | struct xfrm_mode *inner_mode; | 2205 | const struct xfrm_mode *inner_mode; |
| 2206 | const struct xfrm_mode *outer_mode; | ||
| 2247 | int family = x->props.family; | 2207 | int family = x->props.family; |
| 2248 | int err; | 2208 | int err; |
| 2249 | 2209 | ||
| @@ -2269,25 +2229,22 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | |||
| 2269 | goto error; | 2229 | goto error; |
| 2270 | 2230 | ||
| 2271 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && | 2231 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && |
| 2272 | family != x->sel.family) { | 2232 | family != x->sel.family) |
| 2273 | xfrm_put_mode(inner_mode); | ||
| 2274 | goto error; | 2233 | goto error; |
| 2275 | } | ||
| 2276 | 2234 | ||
| 2277 | x->inner_mode = inner_mode; | 2235 | x->inner_mode = *inner_mode; |
| 2278 | } else { | 2236 | } else { |
| 2279 | struct xfrm_mode *inner_mode_iaf; | 2237 | const struct xfrm_mode *inner_mode_iaf; |
| 2280 | int iafamily = AF_INET; | 2238 | int iafamily = AF_INET; |
| 2281 | 2239 | ||
| 2282 | inner_mode = xfrm_get_mode(x->props.mode, x->props.family); | 2240 | inner_mode = xfrm_get_mode(x->props.mode, x->props.family); |
| 2283 | if (inner_mode == NULL) | 2241 | if (inner_mode == NULL) |
| 2284 | goto error; | 2242 | goto error; |
| 2285 | 2243 | ||
| 2286 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { | 2244 | if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) |
| 2287 | xfrm_put_mode(inner_mode); | ||
| 2288 | goto error; | 2245 | goto error; |
| 2289 | } | 2246 | |
| 2290 | x->inner_mode = inner_mode; | 2247 | x->inner_mode = *inner_mode; |
| 2291 | 2248 | ||
| 2292 | if (x->props.family == AF_INET) | 2249 | if (x->props.family == AF_INET) |
| 2293 | iafamily = AF_INET6; | 2250 | iafamily = AF_INET6; |
| @@ -2295,9 +2252,7 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | |||
| 2295 | inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); | 2252 | inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); |
| 2296 | if (inner_mode_iaf) { | 2253 | if (inner_mode_iaf) { |
| 2297 | if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) | 2254 | if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) |
| 2298 | x->inner_mode_iaf = inner_mode_iaf; | 2255 | x->inner_mode_iaf = *inner_mode_iaf; |
| 2299 | else | ||
| 2300 | xfrm_put_mode(inner_mode_iaf); | ||
| 2301 | } | 2256 | } |
| 2302 | } | 2257 | } |
| 2303 | 2258 | ||
| @@ -2311,12 +2266,13 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | |||
| 2311 | if (err) | 2266 | if (err) |
| 2312 | goto error; | 2267 | goto error; |
| 2313 | 2268 | ||
| 2314 | x->outer_mode = xfrm_get_mode(x->props.mode, family); | 2269 | outer_mode = xfrm_get_mode(x->props.mode, family); |
| 2315 | if (x->outer_mode == NULL) { | 2270 | if (!outer_mode) { |
| 2316 | err = -EPROTONOSUPPORT; | 2271 | err = -EPROTONOSUPPORT; |
| 2317 | goto error; | 2272 | goto error; |
| 2318 | } | 2273 | } |
| 2319 | 2274 | ||
| 2275 | x->outer_mode = *outer_mode; | ||
| 2320 | if (init_replay) { | 2276 | if (init_replay) { |
| 2321 | err = xfrm_init_replay(x); | 2277 | err = xfrm_init_replay(x); |
| 2322 | if (err) | 2278 | if (err) |
