Blame view
net/ipv4/xfrm4_protocol.c
6.63 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
3328715e6 xfrm4: Add IPsec ... |
2 3 4 5 6 7 8 9 10 |
/* xfrm4_protocol.c - Generic xfrm protocol multiplexer. * * Copyright (C) 2013 secunet Security Networks AG * * Author: * Steffen Klassert <steffen.klassert@secunet.com> * * Based on: * net/ipv4/tunnel4.c |
3328715e6 xfrm4: Add IPsec ... |
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
*/ #include <linux/init.h> #include <linux/mutex.h> #include <linux/skbuff.h> #include <net/icmp.h> #include <net/ip.h> #include <net/protocol.h> #include <net/xfrm.h> static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly; static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly; static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly; static DEFINE_MUTEX(xfrm4_protocol_mutex); static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol) { switch (protocol) { case IPPROTO_ESP: return &esp4_handlers; case IPPROTO_AH: return &ah4_handlers; case IPPROTO_COMP: return &ipcomp4_handlers; } return NULL; } #define for_each_protocol_rcu(head, handler) \ for (handler = rcu_dereference(head); \ handler != NULL; \ handler = rcu_dereference(handler->next)) \ |
bb9cd077e xfrm: remove unne... |
44 |
static int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err) |
3328715e6 xfrm4: Add IPsec ... |
45 46 47 |
{ int ret; struct xfrm4_protocol *handler; |
61622cc6f xfrm4: Properly h... |
48 |
struct xfrm4_protocol __rcu **head = proto_handlers(protocol); |
3328715e6 xfrm4: Add IPsec ... |
49 |
|
61622cc6f xfrm4: Properly h... |
50 51 52 53 |
if (!head) return 0; for_each_protocol_rcu(*head, handler) |
3328715e6 xfrm4: Add IPsec ... |
54 55 56 57 58 |
if ((ret = handler->cb_handler(skb, err)) <= 0) return ret; return 0; } |
3328715e6 xfrm4: Add IPsec ... |
59 60 61 62 63 64 |
int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) { int ret; struct xfrm4_protocol *handler; |
61622cc6f xfrm4: Properly h... |
65 |
struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr); |
3328715e6 xfrm4: Add IPsec ... |
66 |
|
70be6c91c xfrm: Add xfrm_tu... |
67 |
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; |
3328715e6 xfrm4: Add IPsec ... |
68 69 |
XFRM_SPI_SKB_CB(skb)->family = AF_INET; XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); |
61622cc6f xfrm4: Properly h... |
70 71 |
if (!head) goto out; |
cac3c7160 xfrm: add route l... |
72 73 74 75 76 77 78 |
if (!skb_dst(skb)) { const struct iphdr *iph = ip_hdr(skb); if (ip_route_input_noref(skb, iph->daddr, iph->saddr, iph->tos, skb->dev)) goto drop; } |
61622cc6f xfrm4: Properly h... |
79 |
for_each_protocol_rcu(*head, handler) |
3328715e6 xfrm4: Add IPsec ... |
80 81 |
if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL) return ret; |
61622cc6f xfrm4: Properly h... |
82 |
out: |
3328715e6 xfrm4: Add IPsec ... |
83 |
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
cac3c7160 xfrm: add route l... |
84 |
drop: |
3328715e6 xfrm4: Add IPsec ... |
85 86 87 88 89 90 91 92 93 |
kfree_skb(skb); return 0; } EXPORT_SYMBOL(xfrm4_rcv_encap); static int xfrm4_esp_rcv(struct sk_buff *skb) { int ret; struct xfrm4_protocol *handler; |
70be6c91c xfrm: Add xfrm_tu... |
94 |
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; |
3328715e6 xfrm4: Add IPsec ... |
95 96 97 98 99 100 101 102 103 |
for_each_protocol_rcu(esp4_handlers, handler) if ((ret = handler->handler(skb)) != -EINVAL) return ret; icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); kfree_skb(skb); return 0; } |
32bbd8793 net: Convert prot... |
104 |
static int xfrm4_esp_err(struct sk_buff *skb, u32 info) |
3328715e6 xfrm4: Add IPsec ... |
105 106 107 108 109 |
{ struct xfrm4_protocol *handler; for_each_protocol_rcu(esp4_handlers, handler) if (!handler->err_handler(skb, info)) |
32bbd8793 net: Convert prot... |
110 111 112 |
return 0; return -ENOENT; |
3328715e6 xfrm4: Add IPsec ... |
113 114 115 116 117 118 |
} static int xfrm4_ah_rcv(struct sk_buff *skb) { int ret; struct xfrm4_protocol *handler; |
70be6c91c xfrm: Add xfrm_tu... |
119 |
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; |
3328715e6 xfrm4: Add IPsec ... |
120 121 |
for_each_protocol_rcu(ah4_handlers, handler) if ((ret = handler->handler(skb)) != -EINVAL) |
1759389e8 xfrm4: Remove dup... |
122 |
return ret; |
3328715e6 xfrm4: Add IPsec ... |
123 124 125 126 127 128 |
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); kfree_skb(skb); return 0; } |
32bbd8793 net: Convert prot... |
129 |
static int xfrm4_ah_err(struct sk_buff *skb, u32 info) |
3328715e6 xfrm4: Add IPsec ... |
130 131 132 133 134 |
{ struct xfrm4_protocol *handler; for_each_protocol_rcu(ah4_handlers, handler) if (!handler->err_handler(skb, info)) |
32bbd8793 net: Convert prot... |
135 136 137 |
return 0; return -ENOENT; |
3328715e6 xfrm4: Add IPsec ... |
138 139 140 141 142 143 |
} static int xfrm4_ipcomp_rcv(struct sk_buff *skb) { int ret; struct xfrm4_protocol *handler; |
70be6c91c xfrm: Add xfrm_tu... |
144 |
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; |
3328715e6 xfrm4: Add IPsec ... |
145 146 147 148 149 150 151 152 153 |
for_each_protocol_rcu(ipcomp4_handlers, handler) if ((ret = handler->handler(skb)) != -EINVAL) return ret; icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); kfree_skb(skb); return 0; } |
32bbd8793 net: Convert prot... |
154 |
static int xfrm4_ipcomp_err(struct sk_buff *skb, u32 info) |
3328715e6 xfrm4: Add IPsec ... |
155 156 157 158 159 |
{ struct xfrm4_protocol *handler; for_each_protocol_rcu(ipcomp4_handlers, handler) if (!handler->err_handler(skb, info)) |
32bbd8793 net: Convert prot... |
160 161 162 |
return 0; return -ENOENT; |
3328715e6 xfrm4: Add IPsec ... |
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
} static const struct net_protocol esp4_protocol = { .handler = xfrm4_esp_rcv, .err_handler = xfrm4_esp_err, .no_policy = 1, .netns_ok = 1, }; static const struct net_protocol ah4_protocol = { .handler = xfrm4_ah_rcv, .err_handler = xfrm4_ah_err, .no_policy = 1, .netns_ok = 1, }; static const struct net_protocol ipcomp4_protocol = { .handler = xfrm4_ipcomp_rcv, .err_handler = xfrm4_ipcomp_err, .no_policy = 1, .netns_ok = 1, }; |
960fdfdeb xfrm: input: cons... |
185 |
static const struct xfrm_input_afinfo xfrm4_input_afinfo = { |
2f32b51b6 xfrm: Introduce x... |
186 |
.family = AF_INET, |
2f32b51b6 xfrm: Introduce x... |
187 188 |
.callback = xfrm4_rcv_cb, }; |
3328715e6 xfrm4: Add IPsec ... |
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
static inline const struct net_protocol *netproto(unsigned char protocol) { switch (protocol) { case IPPROTO_ESP: return &esp4_protocol; case IPPROTO_AH: return &ah4_protocol; case IPPROTO_COMP: return &ipcomp4_protocol; } return NULL; } int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol) { struct xfrm4_protocol __rcu **pprev; struct xfrm4_protocol *t; bool add_netproto = false; |
3328715e6 xfrm4: Add IPsec ... |
209 210 |
int ret = -EEXIST; int priority = handler->priority; |
61622cc6f xfrm4: Properly h... |
211 212 |
if (!proto_handlers(protocol) || !netproto(protocol)) return -EINVAL; |
3328715e6 xfrm4: Add IPsec ... |
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
mutex_lock(&xfrm4_protocol_mutex); if (!rcu_dereference_protected(*proto_handlers(protocol), lockdep_is_held(&xfrm4_protocol_mutex))) add_netproto = true; for (pprev = proto_handlers(protocol); (t = rcu_dereference_protected(*pprev, lockdep_is_held(&xfrm4_protocol_mutex))) != NULL; pprev = &t->next) { if (t->priority < priority) break; if (t->priority == priority) goto err; } handler->next = *pprev; rcu_assign_pointer(*pprev, handler); ret = 0; err: mutex_unlock(&xfrm4_protocol_mutex); if (add_netproto) { if (inet_add_protocol(netproto(protocol), protocol)) { pr_err("%s: can't add protocol ", __func__); ret = -EAGAIN; } } return ret; } EXPORT_SYMBOL(xfrm4_protocol_register); int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char protocol) { struct xfrm4_protocol __rcu **pprev; struct xfrm4_protocol *t; int ret = -ENOENT; |
61622cc6f xfrm4: Properly h... |
255 256 |
if (!proto_handlers(protocol) || !netproto(protocol)) return -EINVAL; |
3328715e6 xfrm4: Add IPsec ... |
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
mutex_lock(&xfrm4_protocol_mutex); for (pprev = proto_handlers(protocol); (t = rcu_dereference_protected(*pprev, lockdep_is_held(&xfrm4_protocol_mutex))) != NULL; pprev = &t->next) { if (t == handler) { *pprev = handler->next; ret = 0; break; } } if (!rcu_dereference_protected(*proto_handlers(protocol), lockdep_is_held(&xfrm4_protocol_mutex))) { if (inet_del_protocol(netproto(protocol), protocol) < 0) { pr_err("%s: can't remove protocol ", __func__); ret = -EAGAIN; } } mutex_unlock(&xfrm4_protocol_mutex); synchronize_net(); return ret; } EXPORT_SYMBOL(xfrm4_protocol_deregister); |
2f32b51b6 xfrm: Introduce x... |
286 287 288 289 290 291 |
void __init xfrm4_protocol_init(void) { xfrm_input_register_afinfo(&xfrm4_input_afinfo); } EXPORT_SYMBOL(xfrm4_protocol_init); |