aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2019-04-30 09:26:13 -0400
committerDavid S. Miller <davem@davemloft.net>2019-04-30 09:26:13 -0400
commita658a3f2ecbabba60dafa9ba94f12fc25c18474f (patch)
tree964095a11024f13be1347c787bec2140a7d82673 /net/ipv6
parent7a1d8390d015a13c42b1effa1f22fda0858fe6f9 (diff)
parentbb9cd077e216b886438c5698e1cd75f762ecd3c9 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next
Steffen Klassert says: ==================== pull request (net-next): ipsec-next 2019-04-30 1) A lot of work to remove indirections from the xfrm code. From Florian Westphal. 2) Support ESP offload in combination with gso partial. From Boris Pismenny. 3) Remove some duplicated code from vti4. From Jeremy Sowden. Please note that there is merge conflict between commit: 8742dc86d0c7 ("xfrm4: Fix uninitialized memory read in _decode_session4") from the ipsec tree and commit: c53ac41e3720 ("xfrm: remove decode_session indirection from afinfo_policy") from the ipsec-next tree. The merge conflict will appear when those trees get merged during the merge window. The conflict can be solved as it is done in linux-next: https://lkml.org/lkml/2019/4/25/1207 Please pull or let me know if there are problems. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Kconfig35
-rw-r--r--net/ipv6/Makefile4
-rw-r--r--net/ipv6/esp6_offload.c40
-rw-r--r--net/ipv6/ip6_vti.c6
-rw-r--r--net/ipv6/xfrm6_mode_beet.c131
-rw-r--r--net/ipv6/xfrm6_mode_ro.c85
-rw-r--r--net/ipv6/xfrm6_mode_transport.c121
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c151
-rw-r--r--net/ipv6/xfrm6_output.c36
-rw-r--r--net/ipv6/xfrm6_policy.c126
-rw-r--r--net/ipv6/xfrm6_protocol.c3
11 files changed, 63 insertions, 675 deletions
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
138config 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
147config 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
156config 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
165config INET6_XFRM_MODE_ROUTEOPTIMIZATION
166 tristate "IPv6: MIPv6 route optimization mode"
167 select XFRM
168 ---help---
169 Support for MIPv6 route optimization mode.
170
171config IPV6_VTI 138config IPV6_VTI
172tristate "Virtual (secure) IPv6: tunneling" 139tristate "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
35obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o 35obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
36obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o 36obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
37obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o 37obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
38obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
39obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
40obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o
41obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o
42obj-$(CONFIG_IPV6_MIP6) += mip6.o 38obj-$(CONFIG_IPV6_MIP6) += mip6.o
43obj-$(CONFIG_IPV6_ILA) += ila/ 39obj-$(CONFIG_IPV6_ILA) += ila/
44obj-$(CONFIG_NETFILTER) += netfilter/ 40obj-$(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
137static 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
145static 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
161static 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
137static struct sk_buff *esp6_gso_segment(struct sk_buff *skb, 175static 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
178static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb) 216static 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
22static 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 */
40static 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
80static 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;
101out:
102 return err;
103}
104
105static 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
115static int __init xfrm6_beet_init(void)
116{
117 return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6);
118}
119
120static 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
128module_init(xfrm6_beet_init);
129module_exit(xfrm6_beet_exit);
130MODULE_LICENSE("GPL");
131MODULE_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 */
41static 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
63static struct xfrm_mode xfrm6_ro_mode = {
64 .output = xfrm6_ro_output,
65 .owner = THIS_MODULE,
66 .encap = XFRM_MODE_ROUTEOPTIMIZATION,
67};
68
69static int __init xfrm6_ro_init(void)
70{
71 return xfrm_register_mode(&xfrm6_ro_mode, AF_INET6);
72}
73
74static 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
82module_init(xfrm6_ro_init);
83module_exit(xfrm6_ro_exit);
84MODULE_LICENSE("GPL");
85MODULE_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 */
23static 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 */
51static 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
66static 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
82static 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
96static 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
105static int __init xfrm6_transport_init(void)
106{
107 return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6);
108}
109
110static 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
118module_init(xfrm6_transport_init);
119module_exit(xfrm6_transport_exit);
120MODULE_LICENSE("GPL");
121MODULE_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
21static 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 */
33static 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
74static 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
100out:
101 return err;
102}
103
104static 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
112static 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
123static 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
135static int __init xfrm6_mode_tunnel_init(void)
136{
137 return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6);
138}
139
140static 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
148module_init(xfrm6_mode_tunnel_init);
149module_exit(xfrm6_mode_tunnel_exit);
150MODULE_LICENSE("GPL");
151MODULE_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
114int 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}
127EXPORT_SYMBOL(xfrm6_prepare_output);
128
129int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb) 114int 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
125static 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
140static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 142static 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
147static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) 149static 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
185skip_frag: 187skip_frag:
186 return x->outer_mode->afinfo->output_finish(sk, skb); 188 return __xfrm6_output_state_finish(x, sk, skb);
187} 189}
188 190
189int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) 191int 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
29static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, 26static 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
74static int xfrm6_get_tos(const struct flowi *fl)
75{
76 return 0;
77}
78
79static 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
92static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, 71static 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
121static 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
223static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, 100static 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
49int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) 49static 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}
64EXPORT_SYMBOL(xfrm6_rcv_cb);
65 64
66static int xfrm6_esp_rcv(struct sk_buff *skb) 65static int xfrm6_esp_rcv(struct sk_buff *skb)
67{ 66{