diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/ip_vti.c | 5 | ||||
-rw-r--r-- | net/ipv4/xfrm4_output.c | 32 | ||||
-rw-r--r-- | net/ipv4/xfrm4_protocol.c | 19 | ||||
-rw-r--r-- | net/ipv6/ip6_vti.c | 8 | ||||
-rw-r--r-- | net/ipv6/xfrm6_output.c | 22 | ||||
-rw-r--r-- | net/ipv6/xfrm6_protocol.c | 11 |
6 files changed, 66 insertions, 31 deletions
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index afcee51b90ed..13ef00f1e17b 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
@@ -239,6 +239,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
239 | static int vti4_err(struct sk_buff *skb, u32 info) | 239 | static int vti4_err(struct sk_buff *skb, u32 info) |
240 | { | 240 | { |
241 | __be32 spi; | 241 | __be32 spi; |
242 | __u32 mark; | ||
242 | struct xfrm_state *x; | 243 | struct xfrm_state *x; |
243 | struct ip_tunnel *tunnel; | 244 | struct ip_tunnel *tunnel; |
244 | struct ip_esp_hdr *esph; | 245 | struct ip_esp_hdr *esph; |
@@ -254,6 +255,8 @@ static int vti4_err(struct sk_buff *skb, u32 info) | |||
254 | if (!tunnel) | 255 | if (!tunnel) |
255 | return -1; | 256 | return -1; |
256 | 257 | ||
258 | mark = be32_to_cpu(tunnel->parms.o_key); | ||
259 | |||
257 | switch (protocol) { | 260 | switch (protocol) { |
258 | case IPPROTO_ESP: | 261 | case IPPROTO_ESP: |
259 | esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); | 262 | esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); |
@@ -281,7 +284,7 @@ static int vti4_err(struct sk_buff *skb, u32 info) | |||
281 | return 0; | 284 | return 0; |
282 | } | 285 | } |
283 | 286 | ||
284 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, | 287 | x = xfrm_state_lookup(net, mark, (const xfrm_address_t *)&iph->daddr, |
285 | spi, protocol, AF_INET); | 288 | spi, protocol, AF_INET); |
286 | if (!x) | 289 | if (!x) |
287 | return 0; | 290 | return 0; |
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 40e701f2e1e0..186a8ecf92fa 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
@@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | |||
62 | if (err) | 62 | if (err) |
63 | return err; | 63 | return err; |
64 | 64 | ||
65 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | 65 | IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; |
66 | IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED; | ||
67 | |||
68 | skb->protocol = htons(ETH_P_IP); | ||
69 | 66 | ||
70 | return x->outer_mode->output2(x, skb); | 67 | return x->outer_mode->output2(x, skb); |
71 | } | 68 | } |
@@ -73,27 +70,34 @@ EXPORT_SYMBOL(xfrm4_prepare_output); | |||
73 | 70 | ||
74 | int xfrm4_output_finish(struct sk_buff *skb) | 71 | int xfrm4_output_finish(struct sk_buff *skb) |
75 | { | 72 | { |
73 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | ||
74 | skb->protocol = htons(ETH_P_IP); | ||
75 | |||
76 | #ifdef CONFIG_NETFILTER | ||
77 | IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; | ||
78 | #endif | ||
79 | |||
80 | return xfrm_output(skb); | ||
81 | } | ||
82 | |||
83 | static int __xfrm4_output(struct sk_buff *skb) | ||
84 | { | ||
85 | struct xfrm_state *x = skb_dst(skb)->xfrm; | ||
86 | |||
76 | #ifdef CONFIG_NETFILTER | 87 | #ifdef CONFIG_NETFILTER |
77 | if (!skb_dst(skb)->xfrm) { | 88 | if (!x) { |
78 | IPCB(skb)->flags |= IPSKB_REROUTED; | 89 | IPCB(skb)->flags |= IPSKB_REROUTED; |
79 | return dst_output(skb); | 90 | return dst_output(skb); |
80 | } | 91 | } |
81 | |||
82 | IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; | ||
83 | #endif | 92 | #endif |
84 | 93 | ||
85 | skb->protocol = htons(ETH_P_IP); | 94 | return x->outer_mode->afinfo->output_finish(skb); |
86 | return xfrm_output(skb); | ||
87 | } | 95 | } |
88 | 96 | ||
89 | int xfrm4_output(struct sock *sk, struct sk_buff *skb) | 97 | int xfrm4_output(struct sock *sk, struct sk_buff *skb) |
90 | { | 98 | { |
91 | struct dst_entry *dst = skb_dst(skb); | ||
92 | struct xfrm_state *x = dst->xfrm; | ||
93 | |||
94 | return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, | 99 | return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, |
95 | NULL, dst->dev, | 100 | NULL, skb_dst(skb)->dev, __xfrm4_output, |
96 | x->outer_mode->afinfo->output_finish, | ||
97 | !(IPCB(skb)->flags & IPSKB_REROUTED)); | 101 | !(IPCB(skb)->flags & IPSKB_REROUTED)); |
98 | } | 102 | } |
99 | 103 | ||
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index 7f7b243e8139..a2ce0101eaac 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c | |||
@@ -50,8 +50,12 @@ 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; |
53 | struct xfrm4_protocol __rcu **head = proto_handlers(protocol); | ||
53 | 54 | ||
54 | for_each_protocol_rcu(*proto_handlers(protocol), handler) | 55 | if (!head) |
56 | return 0; | ||
57 | |||
58 | for_each_protocol_rcu(*head, handler) | ||
55 | if ((ret = handler->cb_handler(skb, err)) <= 0) | 59 | if ((ret = handler->cb_handler(skb, err)) <= 0) |
56 | return ret; | 60 | return ret; |
57 | 61 | ||
@@ -64,15 +68,20 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, | |||
64 | { | 68 | { |
65 | int ret; | 69 | int ret; |
66 | struct xfrm4_protocol *handler; | 70 | struct xfrm4_protocol *handler; |
71 | struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr); | ||
67 | 72 | ||
68 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; | 73 | XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; |
69 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; | 74 | XFRM_SPI_SKB_CB(skb)->family = AF_INET; |
70 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); | 75 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); |
71 | 76 | ||
72 | for_each_protocol_rcu(*proto_handlers(nexthdr), handler) | 77 | if (!head) |
78 | goto out; | ||
79 | |||
80 | for_each_protocol_rcu(*head, handler) | ||
73 | if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL) | 81 | if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL) |
74 | return ret; | 82 | return ret; |
75 | 83 | ||
84 | out: | ||
76 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 85 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
77 | 86 | ||
78 | kfree_skb(skb); | 87 | kfree_skb(skb); |
@@ -208,6 +217,9 @@ int xfrm4_protocol_register(struct xfrm4_protocol *handler, | |||
208 | int ret = -EEXIST; | 217 | int ret = -EEXIST; |
209 | int priority = handler->priority; | 218 | int priority = handler->priority; |
210 | 219 | ||
220 | if (!proto_handlers(protocol) || !netproto(protocol)) | ||
221 | return -EINVAL; | ||
222 | |||
211 | mutex_lock(&xfrm4_protocol_mutex); | 223 | mutex_lock(&xfrm4_protocol_mutex); |
212 | 224 | ||
213 | if (!rcu_dereference_protected(*proto_handlers(protocol), | 225 | if (!rcu_dereference_protected(*proto_handlers(protocol), |
@@ -250,6 +262,9 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, | |||
250 | struct xfrm4_protocol *t; | 262 | struct xfrm4_protocol *t; |
251 | int ret = -ENOENT; | 263 | int ret = -ENOENT; |
252 | 264 | ||
265 | if (!proto_handlers(protocol) || !netproto(protocol)) | ||
266 | return -EINVAL; | ||
267 | |||
253 | mutex_lock(&xfrm4_protocol_mutex); | 268 | mutex_lock(&xfrm4_protocol_mutex); |
254 | 269 | ||
255 | for (pprev = proto_handlers(protocol); | 270 | for (pprev = proto_handlers(protocol); |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index b7c0f827140b..6cc9f9371cc5 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
@@ -511,6 +511,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
511 | u8 type, u8 code, int offset, __be32 info) | 511 | u8 type, u8 code, int offset, __be32 info) |
512 | { | 512 | { |
513 | __be32 spi; | 513 | __be32 spi; |
514 | __u32 mark; | ||
514 | struct xfrm_state *x; | 515 | struct xfrm_state *x; |
515 | struct ip6_tnl *t; | 516 | struct ip6_tnl *t; |
516 | struct ip_esp_hdr *esph; | 517 | struct ip_esp_hdr *esph; |
@@ -524,6 +525,8 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
524 | if (!t) | 525 | if (!t) |
525 | return -1; | 526 | return -1; |
526 | 527 | ||
528 | mark = be32_to_cpu(t->parms.o_key); | ||
529 | |||
527 | switch (protocol) { | 530 | switch (protocol) { |
528 | case IPPROTO_ESP: | 531 | case IPPROTO_ESP: |
529 | esph = (struct ip_esp_hdr *)(skb->data + offset); | 532 | esph = (struct ip_esp_hdr *)(skb->data + offset); |
@@ -545,7 +548,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
545 | type != NDISC_REDIRECT) | 548 | type != NDISC_REDIRECT) |
546 | return 0; | 549 | return 0; |
547 | 550 | ||
548 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, | 551 | x = xfrm_state_lookup(net, mark, (const xfrm_address_t *)&iph->daddr, |
549 | spi, protocol, AF_INET6); | 552 | spi, protocol, AF_INET6); |
550 | if (!x) | 553 | if (!x) |
551 | return 0; | 554 | return 0; |
@@ -1097,7 +1100,6 @@ static int __init vti6_tunnel_init(void) | |||
1097 | 1100 | ||
1098 | err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); | 1101 | err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); |
1099 | if (err < 0) { | 1102 | if (err < 0) { |
1100 | unregister_pernet_device(&vti6_net_ops); | ||
1101 | pr_err("%s: can't register vti6 protocol\n", __func__); | 1103 | pr_err("%s: can't register vti6 protocol\n", __func__); |
1102 | 1104 | ||
1103 | goto out; | 1105 | goto out; |
@@ -1106,7 +1108,6 @@ static int __init vti6_tunnel_init(void) | |||
1106 | err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); | 1108 | err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); |
1107 | if (err < 0) { | 1109 | if (err < 0) { |
1108 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | 1110 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); |
1109 | unregister_pernet_device(&vti6_net_ops); | ||
1110 | pr_err("%s: can't register vti6 protocol\n", __func__); | 1111 | pr_err("%s: can't register vti6 protocol\n", __func__); |
1111 | 1112 | ||
1112 | goto out; | 1113 | goto out; |
@@ -1116,7 +1117,6 @@ static int __init vti6_tunnel_init(void) | |||
1116 | if (err < 0) { | 1117 | if (err < 0) { |
1117 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); | 1118 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); |
1118 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | 1119 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); |
1119 | unregister_pernet_device(&vti6_net_ops); | ||
1120 | pr_err("%s: can't register vti6 protocol\n", __func__); | 1120 | pr_err("%s: can't register vti6 protocol\n", __func__); |
1121 | 1121 | ||
1122 | goto out; | 1122 | goto out; |
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 19ef329bdbf8..b930d080c66f 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | |||
114 | if (err) | 114 | if (err) |
115 | return err; | 115 | return err; |
116 | 116 | ||
117 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); | ||
118 | #ifdef CONFIG_NETFILTER | ||
119 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; | ||
120 | #endif | ||
121 | |||
122 | skb->protocol = htons(ETH_P_IPV6); | ||
123 | skb->local_df = 1; | 117 | skb->local_df = 1; |
124 | 118 | ||
125 | return x->outer_mode->output2(x, skb); | 119 | return x->outer_mode->output2(x, skb); |
@@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output); | |||
128 | 122 | ||
129 | int xfrm6_output_finish(struct sk_buff *skb) | 123 | int xfrm6_output_finish(struct sk_buff *skb) |
130 | { | 124 | { |
125 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); | ||
126 | skb->protocol = htons(ETH_P_IPV6); | ||
127 | |||
131 | #ifdef CONFIG_NETFILTER | 128 | #ifdef CONFIG_NETFILTER |
132 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; | 129 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; |
133 | #endif | 130 | #endif |
134 | 131 | ||
135 | skb->protocol = htons(ETH_P_IPV6); | ||
136 | return xfrm_output(skb); | 132 | return xfrm_output(skb); |
137 | } | 133 | } |
138 | 134 | ||
@@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb) | |||
142 | struct xfrm_state *x = dst->xfrm; | 138 | struct xfrm_state *x = dst->xfrm; |
143 | int mtu; | 139 | int mtu; |
144 | 140 | ||
141 | #ifdef CONFIG_NETFILTER | ||
142 | if (!x) { | ||
143 | IP6CB(skb)->flags |= IP6SKB_REROUTED; | ||
144 | return dst_output(skb); | ||
145 | } | ||
146 | #endif | ||
147 | |||
145 | if (skb->protocol == htons(ETH_P_IPV6)) | 148 | if (skb->protocol == htons(ETH_P_IPV6)) |
146 | mtu = ip6_skb_dst_mtu(skb); | 149 | mtu = ip6_skb_dst_mtu(skb); |
147 | else | 150 | else |
@@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb) | |||
165 | 168 | ||
166 | int xfrm6_output(struct sock *sk, struct sk_buff *skb) | 169 | int xfrm6_output(struct sock *sk, struct sk_buff *skb) |
167 | { | 170 | { |
168 | return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, | 171 | return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, |
169 | skb_dst(skb)->dev, __xfrm6_output); | 172 | NULL, skb_dst(skb)->dev, __xfrm6_output, |
173 | !(IP6CB(skb)->flags & IP6SKB_REROUTED)); | ||
170 | } | 174 | } |
diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c index 6ab989c486f7..54d13f8dbbae 100644 --- a/net/ipv6/xfrm6_protocol.c +++ b/net/ipv6/xfrm6_protocol.c | |||
@@ -50,6 +50,10 @@ 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; |
53 | struct xfrm6_protocol __rcu **head = proto_handlers(protocol); | ||
54 | |||
55 | if (!head) | ||
56 | return 0; | ||
53 | 57 | ||
54 | for_each_protocol_rcu(*proto_handlers(protocol), handler) | 58 | for_each_protocol_rcu(*proto_handlers(protocol), handler) |
55 | if ((ret = handler->cb_handler(skb, err)) <= 0) | 59 | if ((ret = handler->cb_handler(skb, err)) <= 0) |
@@ -184,10 +188,12 @@ int xfrm6_protocol_register(struct xfrm6_protocol *handler, | |||
184 | struct xfrm6_protocol __rcu **pprev; | 188 | struct xfrm6_protocol __rcu **pprev; |
185 | struct xfrm6_protocol *t; | 189 | struct xfrm6_protocol *t; |
186 | bool add_netproto = false; | 190 | bool add_netproto = false; |
187 | |||
188 | int ret = -EEXIST; | 191 | int ret = -EEXIST; |
189 | int priority = handler->priority; | 192 | int priority = handler->priority; |
190 | 193 | ||
194 | if (!proto_handlers(protocol) || !netproto(protocol)) | ||
195 | return -EINVAL; | ||
196 | |||
191 | mutex_lock(&xfrm6_protocol_mutex); | 197 | mutex_lock(&xfrm6_protocol_mutex); |
192 | 198 | ||
193 | if (!rcu_dereference_protected(*proto_handlers(protocol), | 199 | if (!rcu_dereference_protected(*proto_handlers(protocol), |
@@ -230,6 +236,9 @@ int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, | |||
230 | struct xfrm6_protocol *t; | 236 | struct xfrm6_protocol *t; |
231 | int ret = -ENOENT; | 237 | int ret = -ENOENT; |
232 | 238 | ||
239 | if (!proto_handlers(protocol) || !netproto(protocol)) | ||
240 | return -EINVAL; | ||
241 | |||
233 | mutex_lock(&xfrm6_protocol_mutex); | 242 | mutex_lock(&xfrm6_protocol_mutex); |
234 | 243 | ||
235 | for (pprev = proto_handlers(protocol); | 244 | for (pprev = proto_handlers(protocol); |