Merge tag 'nfsd-5.2' of git://linux-nfs.org/~bfields/linux
[linux-2.6-microblaze.git] / net / ipv6 / xfrm6_protocol.c
1 /* xfrm6_protocol.c - Generic xfrm protocol multiplexer for ipv6.
2  *
3  * Copyright (C) 2013 secunet Security Networks AG
4  *
5  * Author:
6  * Steffen Klassert <steffen.klassert@secunet.com>
7  *
8  * Based on:
9  * net/ipv4/xfrm4_protocol.c
10  *
11  *      This program is free software; you can redistribute it and/or
12  *      modify it under the terms of the GNU General Public License
13  *      as published by the Free Software Foundation; either version
14  *      2 of the License, or (at your option) any later version.
15  */
16
17 #include <linux/init.h>
18 #include <linux/mutex.h>
19 #include <linux/skbuff.h>
20 #include <linux/icmpv6.h>
21 #include <net/ipv6.h>
22 #include <net/protocol.h>
23 #include <net/xfrm.h>
24
25 static struct xfrm6_protocol __rcu *esp6_handlers __read_mostly;
26 static struct xfrm6_protocol __rcu *ah6_handlers __read_mostly;
27 static struct xfrm6_protocol __rcu *ipcomp6_handlers __read_mostly;
28 static DEFINE_MUTEX(xfrm6_protocol_mutex);
29
30 static inline struct xfrm6_protocol __rcu **proto_handlers(u8 protocol)
31 {
32         switch (protocol) {
33         case IPPROTO_ESP:
34                 return &esp6_handlers;
35         case IPPROTO_AH:
36                 return &ah6_handlers;
37         case IPPROTO_COMP:
38                 return &ipcomp6_handlers;
39         }
40
41         return NULL;
42 }
43
44 #define for_each_protocol_rcu(head, handler)            \
45         for (handler = rcu_dereference(head);           \
46              handler != NULL;                           \
47              handler = rcu_dereference(handler->next))  \
48
49 static int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
50 {
51         int ret;
52         struct xfrm6_protocol *handler;
53         struct xfrm6_protocol __rcu **head = proto_handlers(protocol);
54
55         if (!head)
56                 return 0;
57
58         for_each_protocol_rcu(*proto_handlers(protocol), handler)
59                 if ((ret = handler->cb_handler(skb, err)) <= 0)
60                         return ret;
61
62         return 0;
63 }
64
65 static int xfrm6_esp_rcv(struct sk_buff *skb)
66 {
67         int ret;
68         struct xfrm6_protocol *handler;
69
70         XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
71
72         for_each_protocol_rcu(esp6_handlers, handler)
73                 if ((ret = handler->handler(skb)) != -EINVAL)
74                         return ret;
75
76         icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
77
78         kfree_skb(skb);
79         return 0;
80 }
81
82 static int xfrm6_esp_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
83                           u8 type, u8 code, int offset, __be32 info)
84 {
85         struct xfrm6_protocol *handler;
86
87         for_each_protocol_rcu(esp6_handlers, handler)
88                 if (!handler->err_handler(skb, opt, type, code, offset, info))
89                         return 0;
90
91         return -ENOENT;
92 }
93
94 static int xfrm6_ah_rcv(struct sk_buff *skb)
95 {
96         int ret;
97         struct xfrm6_protocol *handler;
98
99         XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
100
101         for_each_protocol_rcu(ah6_handlers, handler)
102                 if ((ret = handler->handler(skb)) != -EINVAL)
103                         return ret;
104
105         icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
106
107         kfree_skb(skb);
108         return 0;
109 }
110
111 static int xfrm6_ah_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
112                          u8 type, u8 code, int offset, __be32 info)
113 {
114         struct xfrm6_protocol *handler;
115
116         for_each_protocol_rcu(ah6_handlers, handler)
117                 if (!handler->err_handler(skb, opt, type, code, offset, info))
118                         return 0;
119
120         return -ENOENT;
121 }
122
123 static int xfrm6_ipcomp_rcv(struct sk_buff *skb)
124 {
125         int ret;
126         struct xfrm6_protocol *handler;
127
128         XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
129
130         for_each_protocol_rcu(ipcomp6_handlers, handler)
131                 if ((ret = handler->handler(skb)) != -EINVAL)
132                         return ret;
133
134         icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
135
136         kfree_skb(skb);
137         return 0;
138 }
139
140 static int xfrm6_ipcomp_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
141                              u8 type, u8 code, int offset, __be32 info)
142 {
143         struct xfrm6_protocol *handler;
144
145         for_each_protocol_rcu(ipcomp6_handlers, handler)
146                 if (!handler->err_handler(skb, opt, type, code, offset, info))
147                         return 0;
148
149         return -ENOENT;
150 }
151
152 static const struct inet6_protocol esp6_protocol = {
153         .handler        =       xfrm6_esp_rcv,
154         .err_handler    =       xfrm6_esp_err,
155         .flags          =       INET6_PROTO_NOPOLICY,
156 };
157
158 static const struct inet6_protocol ah6_protocol = {
159         .handler        =       xfrm6_ah_rcv,
160         .err_handler    =       xfrm6_ah_err,
161         .flags          =       INET6_PROTO_NOPOLICY,
162 };
163
164 static const struct inet6_protocol ipcomp6_protocol = {
165         .handler        =       xfrm6_ipcomp_rcv,
166         .err_handler    =       xfrm6_ipcomp_err,
167         .flags          =       INET6_PROTO_NOPOLICY,
168 };
169
170 static const struct xfrm_input_afinfo xfrm6_input_afinfo = {
171         .family         =       AF_INET6,
172         .callback       =       xfrm6_rcv_cb,
173 };
174
175 static inline const struct inet6_protocol *netproto(unsigned char protocol)
176 {
177         switch (protocol) {
178         case IPPROTO_ESP:
179                 return &esp6_protocol;
180         case IPPROTO_AH:
181                 return &ah6_protocol;
182         case IPPROTO_COMP:
183                 return &ipcomp6_protocol;
184         }
185
186         return NULL;
187 }
188
189 int xfrm6_protocol_register(struct xfrm6_protocol *handler,
190                             unsigned char protocol)
191 {
192         struct xfrm6_protocol __rcu **pprev;
193         struct xfrm6_protocol *t;
194         bool add_netproto = false;
195         int ret = -EEXIST;
196         int priority = handler->priority;
197
198         if (!proto_handlers(protocol) || !netproto(protocol))
199                 return -EINVAL;
200
201         mutex_lock(&xfrm6_protocol_mutex);
202
203         if (!rcu_dereference_protected(*proto_handlers(protocol),
204                                        lockdep_is_held(&xfrm6_protocol_mutex)))
205                 add_netproto = true;
206
207         for (pprev = proto_handlers(protocol);
208              (t = rcu_dereference_protected(*pprev,
209                         lockdep_is_held(&xfrm6_protocol_mutex))) != NULL;
210              pprev = &t->next) {
211                 if (t->priority < priority)
212                         break;
213                 if (t->priority == priority)
214                         goto err;
215         }
216
217         handler->next = *pprev;
218         rcu_assign_pointer(*pprev, handler);
219
220         ret = 0;
221
222 err:
223         mutex_unlock(&xfrm6_protocol_mutex);
224
225         if (add_netproto) {
226                 if (inet6_add_protocol(netproto(protocol), protocol)) {
227                         pr_err("%s: can't add protocol\n", __func__);
228                         ret = -EAGAIN;
229                 }
230         }
231
232         return ret;
233 }
234 EXPORT_SYMBOL(xfrm6_protocol_register);
235
236 int xfrm6_protocol_deregister(struct xfrm6_protocol *handler,
237                               unsigned char protocol)
238 {
239         struct xfrm6_protocol __rcu **pprev;
240         struct xfrm6_protocol *t;
241         int ret = -ENOENT;
242
243         if (!proto_handlers(protocol) || !netproto(protocol))
244                 return -EINVAL;
245
246         mutex_lock(&xfrm6_protocol_mutex);
247
248         for (pprev = proto_handlers(protocol);
249              (t = rcu_dereference_protected(*pprev,
250                         lockdep_is_held(&xfrm6_protocol_mutex))) != NULL;
251              pprev = &t->next) {
252                 if (t == handler) {
253                         *pprev = handler->next;
254                         ret = 0;
255                         break;
256                 }
257         }
258
259         if (!rcu_dereference_protected(*proto_handlers(protocol),
260                                        lockdep_is_held(&xfrm6_protocol_mutex))) {
261                 if (inet6_del_protocol(netproto(protocol), protocol) < 0) {
262                         pr_err("%s: can't remove protocol\n", __func__);
263                         ret = -EAGAIN;
264                 }
265         }
266
267         mutex_unlock(&xfrm6_protocol_mutex);
268
269         synchronize_net();
270
271         return ret;
272 }
273 EXPORT_SYMBOL(xfrm6_protocol_deregister);
274
275 int __init xfrm6_protocol_init(void)
276 {
277         return xfrm_input_register_afinfo(&xfrm6_input_afinfo);
278 }
279
280 void xfrm6_protocol_fini(void)
281 {
282         xfrm_input_unregister_afinfo(&xfrm6_input_afinfo);
283 }