| .. | .. |
|---|
| 21 | 21 | #include <net/ip_tunnels.h> |
|---|
| 22 | 22 | #include <net/ip6_tunnel.h> |
|---|
| 23 | 23 | |
|---|
| 24 | +#include "xfrm_inout.h" |
|---|
| 25 | + |
|---|
| 24 | 26 | struct xfrm_trans_tasklet { |
|---|
| 25 | 27 | struct tasklet_struct tasklet; |
|---|
| 26 | 28 | struct sk_buff_head queue; |
|---|
| .. | .. |
|---|
| 34 | 36 | #endif |
|---|
| 35 | 37 | } header; |
|---|
| 36 | 38 | int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb); |
|---|
| 39 | + struct net *net; |
|---|
| 37 | 40 | }; |
|---|
| 38 | 41 | |
|---|
| 39 | 42 | #define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0])) |
|---|
| 40 | 43 | |
|---|
| 41 | | -static struct kmem_cache *secpath_cachep __ro_after_init; |
|---|
| 42 | | - |
|---|
| 43 | 44 | static DEFINE_SPINLOCK(xfrm_input_afinfo_lock); |
|---|
| 44 | | -static struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[AF_INET6 + 1]; |
|---|
| 45 | +static struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[2][AF_INET6 + 1]; |
|---|
| 45 | 46 | |
|---|
| 46 | 47 | static struct gro_cells gro_cells; |
|---|
| 47 | 48 | static struct net_device xfrm_napi_dev; |
|---|
| .. | .. |
|---|
| 52 | 53 | { |
|---|
| 53 | 54 | int err = 0; |
|---|
| 54 | 55 | |
|---|
| 55 | | - if (WARN_ON(afinfo->family >= ARRAY_SIZE(xfrm_input_afinfo))) |
|---|
| 56 | + if (WARN_ON(afinfo->family > AF_INET6)) |
|---|
| 56 | 57 | return -EAFNOSUPPORT; |
|---|
| 57 | 58 | |
|---|
| 58 | 59 | spin_lock_bh(&xfrm_input_afinfo_lock); |
|---|
| 59 | | - if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL)) |
|---|
| 60 | + if (unlikely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family])) |
|---|
| 60 | 61 | err = -EEXIST; |
|---|
| 61 | 62 | else |
|---|
| 62 | | - rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo); |
|---|
| 63 | + rcu_assign_pointer(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family], afinfo); |
|---|
| 63 | 64 | spin_unlock_bh(&xfrm_input_afinfo_lock); |
|---|
| 64 | 65 | return err; |
|---|
| 65 | 66 | } |
|---|
| .. | .. |
|---|
| 70 | 71 | int err = 0; |
|---|
| 71 | 72 | |
|---|
| 72 | 73 | spin_lock_bh(&xfrm_input_afinfo_lock); |
|---|
| 73 | | - if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) { |
|---|
| 74 | | - if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo)) |
|---|
| 74 | + if (likely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family])) { |
|---|
| 75 | + if (unlikely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family] != afinfo)) |
|---|
| 75 | 76 | err = -EINVAL; |
|---|
| 76 | 77 | else |
|---|
| 77 | | - RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL); |
|---|
| 78 | + RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family], NULL); |
|---|
| 78 | 79 | } |
|---|
| 79 | 80 | spin_unlock_bh(&xfrm_input_afinfo_lock); |
|---|
| 80 | 81 | synchronize_rcu(); |
|---|
| .. | .. |
|---|
| 82 | 83 | } |
|---|
| 83 | 84 | EXPORT_SYMBOL(xfrm_input_unregister_afinfo); |
|---|
| 84 | 85 | |
|---|
| 85 | | -static const struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family) |
|---|
| 86 | +static const struct xfrm_input_afinfo *xfrm_input_get_afinfo(u8 family, bool is_ipip) |
|---|
| 86 | 87 | { |
|---|
| 87 | 88 | const struct xfrm_input_afinfo *afinfo; |
|---|
| 88 | 89 | |
|---|
| 89 | | - if (WARN_ON_ONCE(family >= ARRAY_SIZE(xfrm_input_afinfo))) |
|---|
| 90 | + if (WARN_ON_ONCE(family > AF_INET6)) |
|---|
| 90 | 91 | return NULL; |
|---|
| 91 | 92 | |
|---|
| 92 | 93 | rcu_read_lock(); |
|---|
| 93 | | - afinfo = rcu_dereference(xfrm_input_afinfo[family]); |
|---|
| 94 | + afinfo = rcu_dereference(xfrm_input_afinfo[is_ipip][family]); |
|---|
| 94 | 95 | if (unlikely(!afinfo)) |
|---|
| 95 | 96 | rcu_read_unlock(); |
|---|
| 96 | 97 | return afinfo; |
|---|
| .. | .. |
|---|
| 99 | 100 | static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol, |
|---|
| 100 | 101 | int err) |
|---|
| 101 | 102 | { |
|---|
| 103 | + bool is_ipip = (protocol == IPPROTO_IPIP || protocol == IPPROTO_IPV6); |
|---|
| 104 | + const struct xfrm_input_afinfo *afinfo; |
|---|
| 102 | 105 | int ret; |
|---|
| 103 | | - const struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family); |
|---|
| 104 | 106 | |
|---|
| 107 | + afinfo = xfrm_input_get_afinfo(family, is_ipip); |
|---|
| 105 | 108 | if (!afinfo) |
|---|
| 106 | 109 | return -EAFNOSUPPORT; |
|---|
| 107 | 110 | |
|---|
| .. | .. |
|---|
| 111 | 114 | return ret; |
|---|
| 112 | 115 | } |
|---|
| 113 | 116 | |
|---|
| 114 | | -void __secpath_destroy(struct sec_path *sp) |
|---|
| 117 | +struct sec_path *secpath_set(struct sk_buff *skb) |
|---|
| 115 | 118 | { |
|---|
| 116 | | - int i; |
|---|
| 117 | | - for (i = 0; i < sp->len; i++) |
|---|
| 118 | | - xfrm_state_put(sp->xvec[i]); |
|---|
| 119 | | - kmem_cache_free(secpath_cachep, sp); |
|---|
| 120 | | -} |
|---|
| 121 | | -EXPORT_SYMBOL(__secpath_destroy); |
|---|
| 119 | + struct sec_path *sp, *tmp = skb_ext_find(skb, SKB_EXT_SEC_PATH); |
|---|
| 122 | 120 | |
|---|
| 123 | | -struct sec_path *secpath_dup(struct sec_path *src) |
|---|
| 124 | | -{ |
|---|
| 125 | | - struct sec_path *sp; |
|---|
| 126 | | - |
|---|
| 127 | | - sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC); |
|---|
| 121 | + sp = skb_ext_add(skb, SKB_EXT_SEC_PATH); |
|---|
| 128 | 122 | if (!sp) |
|---|
| 129 | 123 | return NULL; |
|---|
| 130 | 124 | |
|---|
| 131 | | - sp->len = 0; |
|---|
| 132 | | - sp->olen = 0; |
|---|
| 125 | + if (tmp) /* reused existing one (was COW'd if needed) */ |
|---|
| 126 | + return sp; |
|---|
| 133 | 127 | |
|---|
| 128 | + /* allocated new secpath */ |
|---|
| 134 | 129 | memset(sp->ovec, 0, sizeof(sp->ovec)); |
|---|
| 130 | + sp->olen = 0; |
|---|
| 131 | + sp->len = 0; |
|---|
| 132 | + sp->verified_cnt = 0; |
|---|
| 135 | 133 | |
|---|
| 136 | | - if (src) { |
|---|
| 137 | | - int i; |
|---|
| 138 | | - |
|---|
| 139 | | - memcpy(sp, src, sizeof(*sp)); |
|---|
| 140 | | - for (i = 0; i < sp->len; i++) |
|---|
| 141 | | - xfrm_state_hold(sp->xvec[i]); |
|---|
| 142 | | - } |
|---|
| 143 | | - refcount_set(&sp->refcnt, 1); |
|---|
| 144 | 134 | return sp; |
|---|
| 145 | | -} |
|---|
| 146 | | -EXPORT_SYMBOL(secpath_dup); |
|---|
| 147 | | - |
|---|
| 148 | | -int secpath_set(struct sk_buff *skb) |
|---|
| 149 | | -{ |
|---|
| 150 | | - struct sec_path *sp; |
|---|
| 151 | | - |
|---|
| 152 | | - /* Allocate new secpath or COW existing one. */ |
|---|
| 153 | | - if (!skb->sp || refcount_read(&skb->sp->refcnt) != 1) { |
|---|
| 154 | | - sp = secpath_dup(skb->sp); |
|---|
| 155 | | - if (!sp) |
|---|
| 156 | | - return -ENOMEM; |
|---|
| 157 | | - |
|---|
| 158 | | - if (skb->sp) |
|---|
| 159 | | - secpath_put(skb->sp); |
|---|
| 160 | | - skb->sp = sp; |
|---|
| 161 | | - } |
|---|
| 162 | | - return 0; |
|---|
| 163 | 135 | } |
|---|
| 164 | 136 | EXPORT_SYMBOL(secpath_set); |
|---|
| 165 | 137 | |
|---|
| .. | .. |
|---|
| 200 | 172 | } |
|---|
| 201 | 173 | EXPORT_SYMBOL(xfrm_parse_spi); |
|---|
| 202 | 174 | |
|---|
| 203 | | -int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) |
|---|
| 175 | +static int xfrm4_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb) |
|---|
| 204 | 176 | { |
|---|
| 205 | | - struct xfrm_mode *inner_mode = x->inner_mode; |
|---|
| 177 | + struct iphdr *iph; |
|---|
| 178 | + int optlen = 0; |
|---|
| 179 | + int err = -EINVAL; |
|---|
| 180 | + |
|---|
| 181 | + if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) { |
|---|
| 182 | + struct ip_beet_phdr *ph; |
|---|
| 183 | + int phlen; |
|---|
| 184 | + |
|---|
| 185 | + if (!pskb_may_pull(skb, sizeof(*ph))) |
|---|
| 186 | + goto out; |
|---|
| 187 | + |
|---|
| 188 | + ph = (struct ip_beet_phdr *)skb->data; |
|---|
| 189 | + |
|---|
| 190 | + phlen = sizeof(*ph) + ph->padlen; |
|---|
| 191 | + optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen); |
|---|
| 192 | + if (optlen < 0 || optlen & 3 || optlen > 250) |
|---|
| 193 | + goto out; |
|---|
| 194 | + |
|---|
| 195 | + XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr; |
|---|
| 196 | + |
|---|
| 197 | + if (!pskb_may_pull(skb, phlen)) |
|---|
| 198 | + goto out; |
|---|
| 199 | + __skb_pull(skb, phlen); |
|---|
| 200 | + } |
|---|
| 201 | + |
|---|
| 202 | + skb_push(skb, sizeof(*iph)); |
|---|
| 203 | + skb_reset_network_header(skb); |
|---|
| 204 | + skb_mac_header_rebuild(skb); |
|---|
| 205 | + |
|---|
| 206 | + xfrm4_beet_make_header(skb); |
|---|
| 207 | + |
|---|
| 208 | + iph = ip_hdr(skb); |
|---|
| 209 | + |
|---|
| 210 | + iph->ihl += optlen / 4; |
|---|
| 211 | + iph->tot_len = htons(skb->len); |
|---|
| 212 | + iph->daddr = x->sel.daddr.a4; |
|---|
| 213 | + iph->saddr = x->sel.saddr.a4; |
|---|
| 214 | + iph->check = 0; |
|---|
| 215 | + iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); |
|---|
| 216 | + err = 0; |
|---|
| 217 | +out: |
|---|
| 218 | + return err; |
|---|
| 219 | +} |
|---|
| 220 | + |
|---|
| 221 | +static void ipip_ecn_decapsulate(struct sk_buff *skb) |
|---|
| 222 | +{ |
|---|
| 223 | + struct iphdr *inner_iph = ipip_hdr(skb); |
|---|
| 224 | + |
|---|
| 225 | + if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) |
|---|
| 226 | + IP_ECN_set_ce(inner_iph); |
|---|
| 227 | +} |
|---|
| 228 | + |
|---|
| 229 | +static int xfrm4_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) |
|---|
| 230 | +{ |
|---|
| 231 | + int err = -EINVAL; |
|---|
| 232 | + |
|---|
| 233 | + if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) |
|---|
| 234 | + goto out; |
|---|
| 235 | + |
|---|
| 236 | + if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
|---|
| 237 | + goto out; |
|---|
| 238 | + |
|---|
| 239 | + err = skb_unclone(skb, GFP_ATOMIC); |
|---|
| 240 | + if (err) |
|---|
| 241 | + goto out; |
|---|
| 242 | + |
|---|
| 243 | + if (x->props.flags & XFRM_STATE_DECAP_DSCP) |
|---|
| 244 | + ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); |
|---|
| 245 | + if (!(x->props.flags & XFRM_STATE_NOECN)) |
|---|
| 246 | + ipip_ecn_decapsulate(skb); |
|---|
| 247 | + |
|---|
| 248 | + skb_reset_network_header(skb); |
|---|
| 249 | + skb_mac_header_rebuild(skb); |
|---|
| 250 | + if (skb->mac_len) |
|---|
| 251 | + eth_hdr(skb)->h_proto = skb->protocol; |
|---|
| 252 | + |
|---|
| 253 | + err = 0; |
|---|
| 254 | + |
|---|
| 255 | +out: |
|---|
| 256 | + return err; |
|---|
| 257 | +} |
|---|
| 258 | + |
|---|
| 259 | +static void ipip6_ecn_decapsulate(struct sk_buff *skb) |
|---|
| 260 | +{ |
|---|
| 261 | + struct ipv6hdr *inner_iph = ipipv6_hdr(skb); |
|---|
| 262 | + |
|---|
| 263 | + if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) |
|---|
| 264 | + IP6_ECN_set_ce(skb, inner_iph); |
|---|
| 265 | +} |
|---|
| 266 | + |
|---|
| 267 | +static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) |
|---|
| 268 | +{ |
|---|
| 269 | + int err = -EINVAL; |
|---|
| 270 | + |
|---|
| 271 | + if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) |
|---|
| 272 | + goto out; |
|---|
| 273 | + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
|---|
| 274 | + goto out; |
|---|
| 275 | + |
|---|
| 276 | + err = skb_unclone(skb, GFP_ATOMIC); |
|---|
| 277 | + if (err) |
|---|
| 278 | + goto out; |
|---|
| 279 | + |
|---|
| 280 | + if (x->props.flags & XFRM_STATE_DECAP_DSCP) |
|---|
| 281 | + ipv6_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipipv6_hdr(skb)); |
|---|
| 282 | + if (!(x->props.flags & XFRM_STATE_NOECN)) |
|---|
| 283 | + ipip6_ecn_decapsulate(skb); |
|---|
| 284 | + |
|---|
| 285 | + skb_reset_network_header(skb); |
|---|
| 286 | + skb_mac_header_rebuild(skb); |
|---|
| 287 | + if (skb->mac_len) |
|---|
| 288 | + eth_hdr(skb)->h_proto = skb->protocol; |
|---|
| 289 | + |
|---|
| 290 | + err = 0; |
|---|
| 291 | + |
|---|
| 292 | +out: |
|---|
| 293 | + return err; |
|---|
| 294 | +} |
|---|
| 295 | + |
|---|
| 296 | +static int xfrm6_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb) |
|---|
| 297 | +{ |
|---|
| 298 | + struct ipv6hdr *ip6h; |
|---|
| 299 | + int size = sizeof(struct ipv6hdr); |
|---|
| 206 | 300 | int err; |
|---|
| 207 | 301 | |
|---|
| 208 | | - err = x->outer_mode->afinfo->extract_input(x, skb); |
|---|
| 302 | + err = skb_cow_head(skb, size + skb->mac_len); |
|---|
| 209 | 303 | if (err) |
|---|
| 210 | | - return err; |
|---|
| 304 | + goto out; |
|---|
| 305 | + |
|---|
| 306 | + __skb_push(skb, size); |
|---|
| 307 | + skb_reset_network_header(skb); |
|---|
| 308 | + skb_mac_header_rebuild(skb); |
|---|
| 309 | + |
|---|
| 310 | + xfrm6_beet_make_header(skb); |
|---|
| 311 | + |
|---|
| 312 | + ip6h = ipv6_hdr(skb); |
|---|
| 313 | + ip6h->payload_len = htons(skb->len - size); |
|---|
| 314 | + ip6h->daddr = x->sel.daddr.in6; |
|---|
| 315 | + ip6h->saddr = x->sel.saddr.in6; |
|---|
| 316 | + err = 0; |
|---|
| 317 | +out: |
|---|
| 318 | + return err; |
|---|
| 319 | +} |
|---|
| 320 | + |
|---|
| 321 | +/* Remove encapsulation header. |
|---|
| 322 | + * |
|---|
| 323 | + * The IP header will be moved over the top of the encapsulation |
|---|
| 324 | + * header. |
|---|
| 325 | + * |
|---|
| 326 | + * On entry, the transport header shall point to where the IP header |
|---|
| 327 | + * should be and the network header shall be set to where the IP |
|---|
| 328 | + * header currently is. skb->data shall point to the start of the |
|---|
| 329 | + * payload. |
|---|
| 330 | + */ |
|---|
| 331 | +static int |
|---|
| 332 | +xfrm_inner_mode_encap_remove(struct xfrm_state *x, |
|---|
| 333 | + const struct xfrm_mode *inner_mode, |
|---|
| 334 | + struct sk_buff *skb) |
|---|
| 335 | +{ |
|---|
| 336 | + switch (inner_mode->encap) { |
|---|
| 337 | + case XFRM_MODE_BEET: |
|---|
| 338 | + if (inner_mode->family == AF_INET) |
|---|
| 339 | + return xfrm4_remove_beet_encap(x, skb); |
|---|
| 340 | + if (inner_mode->family == AF_INET6) |
|---|
| 341 | + return xfrm6_remove_beet_encap(x, skb); |
|---|
| 342 | + break; |
|---|
| 343 | + case XFRM_MODE_TUNNEL: |
|---|
| 344 | + if (inner_mode->family == AF_INET) |
|---|
| 345 | + return xfrm4_remove_tunnel_encap(x, skb); |
|---|
| 346 | + if (inner_mode->family == AF_INET6) |
|---|
| 347 | + return xfrm6_remove_tunnel_encap(x, skb); |
|---|
| 348 | + break; |
|---|
| 349 | + } |
|---|
| 350 | + |
|---|
| 351 | + WARN_ON_ONCE(1); |
|---|
| 352 | + return -EOPNOTSUPP; |
|---|
| 353 | +} |
|---|
| 354 | + |
|---|
| 355 | +static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) |
|---|
| 356 | +{ |
|---|
| 357 | + const struct xfrm_mode *inner_mode = &x->inner_mode; |
|---|
| 358 | + |
|---|
| 359 | + switch (x->outer_mode.family) { |
|---|
| 360 | + case AF_INET: |
|---|
| 361 | + xfrm4_extract_header(skb); |
|---|
| 362 | + break; |
|---|
| 363 | + case AF_INET6: |
|---|
| 364 | + xfrm6_extract_header(skb); |
|---|
| 365 | + break; |
|---|
| 366 | + default: |
|---|
| 367 | + WARN_ON_ONCE(1); |
|---|
| 368 | + return -EAFNOSUPPORT; |
|---|
| 369 | + } |
|---|
| 211 | 370 | |
|---|
| 212 | 371 | if (x->sel.family == AF_UNSPEC) { |
|---|
| 213 | 372 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
|---|
| 214 | | - if (inner_mode == NULL) |
|---|
| 373 | + if (!inner_mode) |
|---|
| 215 | 374 | return -EAFNOSUPPORT; |
|---|
| 216 | 375 | } |
|---|
| 217 | 376 | |
|---|
| 218 | | - skb->protocol = inner_mode->afinfo->eth_proto; |
|---|
| 219 | | - return inner_mode->input2(x, skb); |
|---|
| 377 | + switch (inner_mode->family) { |
|---|
| 378 | + case AF_INET: |
|---|
| 379 | + skb->protocol = htons(ETH_P_IP); |
|---|
| 380 | + break; |
|---|
| 381 | + case AF_INET6: |
|---|
| 382 | + skb->protocol = htons(ETH_P_IPV6); |
|---|
| 383 | + break; |
|---|
| 384 | + default: |
|---|
| 385 | + WARN_ON_ONCE(1); |
|---|
| 386 | + break; |
|---|
| 387 | + } |
|---|
| 388 | + |
|---|
| 389 | + return xfrm_inner_mode_encap_remove(x, inner_mode, skb); |
|---|
| 220 | 390 | } |
|---|
| 221 | | -EXPORT_SYMBOL(xfrm_prepare_input); |
|---|
| 391 | + |
|---|
| 392 | +/* Remove encapsulation header. |
|---|
| 393 | + * |
|---|
| 394 | + * The IP header will be moved over the top of the encapsulation header. |
|---|
| 395 | + * |
|---|
| 396 | + * On entry, skb_transport_header() shall point to where the IP header |
|---|
| 397 | + * should be and skb_network_header() shall be set to where the IP header |
|---|
| 398 | + * currently is. skb->data shall point to the start of the payload. |
|---|
| 399 | + */ |
|---|
| 400 | +static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) |
|---|
| 401 | +{ |
|---|
| 402 | + int ihl = skb->data - skb_transport_header(skb); |
|---|
| 403 | + |
|---|
| 404 | + if (skb->transport_header != skb->network_header) { |
|---|
| 405 | + memmove(skb_transport_header(skb), |
|---|
| 406 | + skb_network_header(skb), ihl); |
|---|
| 407 | + skb->network_header = skb->transport_header; |
|---|
| 408 | + } |
|---|
| 409 | + ip_hdr(skb)->tot_len = htons(skb->len + ihl); |
|---|
| 410 | + skb_reset_transport_header(skb); |
|---|
| 411 | + return 0; |
|---|
| 412 | +} |
|---|
| 413 | + |
|---|
| 414 | +static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) |
|---|
| 415 | +{ |
|---|
| 416 | +#if IS_ENABLED(CONFIG_IPV6) |
|---|
| 417 | + int ihl = skb->data - skb_transport_header(skb); |
|---|
| 418 | + |
|---|
| 419 | + if (skb->transport_header != skb->network_header) { |
|---|
| 420 | + memmove(skb_transport_header(skb), |
|---|
| 421 | + skb_network_header(skb), ihl); |
|---|
| 422 | + skb->network_header = skb->transport_header; |
|---|
| 423 | + } |
|---|
| 424 | + ipv6_hdr(skb)->payload_len = htons(skb->len + ihl - |
|---|
| 425 | + sizeof(struct ipv6hdr)); |
|---|
| 426 | + skb_reset_transport_header(skb); |
|---|
| 427 | + return 0; |
|---|
| 428 | +#else |
|---|
| 429 | + WARN_ON_ONCE(1); |
|---|
| 430 | + return -EAFNOSUPPORT; |
|---|
| 431 | +#endif |
|---|
| 432 | +} |
|---|
| 433 | + |
|---|
| 434 | +static int xfrm_inner_mode_input(struct xfrm_state *x, |
|---|
| 435 | + const struct xfrm_mode *inner_mode, |
|---|
| 436 | + struct sk_buff *skb) |
|---|
| 437 | +{ |
|---|
| 438 | + switch (inner_mode->encap) { |
|---|
| 439 | + case XFRM_MODE_BEET: |
|---|
| 440 | + case XFRM_MODE_TUNNEL: |
|---|
| 441 | + return xfrm_prepare_input(x, skb); |
|---|
| 442 | + case XFRM_MODE_TRANSPORT: |
|---|
| 443 | + if (inner_mode->family == AF_INET) |
|---|
| 444 | + return xfrm4_transport_input(x, skb); |
|---|
| 445 | + if (inner_mode->family == AF_INET6) |
|---|
| 446 | + return xfrm6_transport_input(x, skb); |
|---|
| 447 | + break; |
|---|
| 448 | + case XFRM_MODE_ROUTEOPTIMIZATION: |
|---|
| 449 | + WARN_ON_ONCE(1); |
|---|
| 450 | + break; |
|---|
| 451 | + default: |
|---|
| 452 | + WARN_ON_ONCE(1); |
|---|
| 453 | + break; |
|---|
| 454 | + } |
|---|
| 455 | + |
|---|
| 456 | + return -EOPNOTSUPP; |
|---|
| 457 | +} |
|---|
| 222 | 458 | |
|---|
| 223 | 459 | int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) |
|---|
| 224 | 460 | { |
|---|
| 461 | + const struct xfrm_state_afinfo *afinfo; |
|---|
| 225 | 462 | struct net *net = dev_net(skb->dev); |
|---|
| 463 | + const struct xfrm_mode *inner_mode; |
|---|
| 226 | 464 | int err; |
|---|
| 227 | 465 | __be32 seq; |
|---|
| 228 | 466 | __be32 seq_hi; |
|---|
| 229 | 467 | struct xfrm_state *x = NULL; |
|---|
| 230 | 468 | xfrm_address_t *daddr; |
|---|
| 231 | | - struct xfrm_mode *inner_mode; |
|---|
| 232 | 469 | u32 mark = skb->mark; |
|---|
| 233 | 470 | unsigned int family = AF_UNSPEC; |
|---|
| 234 | 471 | int decaps = 0; |
|---|
| .. | .. |
|---|
| 236 | 473 | bool xfrm_gro = false; |
|---|
| 237 | 474 | bool crypto_done = false; |
|---|
| 238 | 475 | struct xfrm_offload *xo = xfrm_offload(skb); |
|---|
| 476 | + struct sec_path *sp; |
|---|
| 239 | 477 | |
|---|
| 240 | 478 | if (encap_type < 0) { |
|---|
| 241 | 479 | x = xfrm_input_state(skb); |
|---|
| .. | .. |
|---|
| 252 | 490 | goto drop; |
|---|
| 253 | 491 | } |
|---|
| 254 | 492 | |
|---|
| 255 | | - family = x->outer_mode->afinfo->family; |
|---|
| 493 | + family = x->outer_mode.family; |
|---|
| 256 | 494 | |
|---|
| 257 | 495 | /* An encap_type of -1 indicates async resumption. */ |
|---|
| 258 | 496 | if (encap_type == -1) { |
|---|
| .. | .. |
|---|
| 315 | 553 | break; |
|---|
| 316 | 554 | } |
|---|
| 317 | 555 | |
|---|
| 318 | | - err = secpath_set(skb); |
|---|
| 319 | | - if (err) { |
|---|
| 556 | + sp = secpath_set(skb); |
|---|
| 557 | + if (!sp) { |
|---|
| 320 | 558 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); |
|---|
| 321 | 559 | goto drop; |
|---|
| 322 | 560 | } |
|---|
| .. | .. |
|---|
| 331 | 569 | daddr = (xfrm_address_t *)(skb_network_header(skb) + |
|---|
| 332 | 570 | XFRM_SPI_SKB_CB(skb)->daddroff); |
|---|
| 333 | 571 | do { |
|---|
| 334 | | - if (skb->sp->len == XFRM_MAX_DEPTH) { |
|---|
| 572 | + sp = skb_sec_path(skb); |
|---|
| 573 | + |
|---|
| 574 | + if (sp->len == XFRM_MAX_DEPTH) { |
|---|
| 335 | 575 | secpath_reset(skb); |
|---|
| 336 | 576 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); |
|---|
| 337 | 577 | goto drop; |
|---|
| .. | .. |
|---|
| 347 | 587 | |
|---|
| 348 | 588 | skb->mark = xfrm_smark_get(skb->mark, x); |
|---|
| 349 | 589 | |
|---|
| 350 | | - skb->sp->xvec[skb->sp->len++] = x; |
|---|
| 590 | + sp->xvec[sp->len++] = x; |
|---|
| 351 | 591 | |
|---|
| 352 | 592 | skb_dst_force(skb); |
|---|
| 353 | 593 | if (!skb_dst(skb)) { |
|---|
| .. | .. |
|---|
| 434 | 674 | |
|---|
| 435 | 675 | XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; |
|---|
| 436 | 676 | |
|---|
| 437 | | - inner_mode = x->inner_mode; |
|---|
| 677 | + inner_mode = &x->inner_mode; |
|---|
| 438 | 678 | |
|---|
| 439 | 679 | if (x->sel.family == AF_UNSPEC) { |
|---|
| 440 | 680 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
|---|
| .. | .. |
|---|
| 444 | 684 | } |
|---|
| 445 | 685 | } |
|---|
| 446 | 686 | |
|---|
| 447 | | - if (inner_mode->input(x, skb)) { |
|---|
| 687 | + if (xfrm_inner_mode_input(x, inner_mode, skb)) { |
|---|
| 448 | 688 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); |
|---|
| 449 | 689 | goto drop; |
|---|
| 450 | 690 | } |
|---|
| 451 | 691 | |
|---|
| 452 | | - if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { |
|---|
| 692 | + if (x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL) { |
|---|
| 453 | 693 | decaps = 1; |
|---|
| 454 | 694 | break; |
|---|
| 455 | 695 | } |
|---|
| .. | .. |
|---|
| 459 | 699 | * transport mode so the outer address is identical. |
|---|
| 460 | 700 | */ |
|---|
| 461 | 701 | daddr = &x->id.daddr; |
|---|
| 462 | | - family = x->outer_mode->afinfo->family; |
|---|
| 702 | + family = x->outer_mode.family; |
|---|
| 463 | 703 | |
|---|
| 464 | 704 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); |
|---|
| 465 | 705 | if (err < 0) { |
|---|
| .. | .. |
|---|
| 473 | 713 | if (err) |
|---|
| 474 | 714 | goto drop; |
|---|
| 475 | 715 | |
|---|
| 476 | | - nf_reset(skb); |
|---|
| 716 | + nf_reset_ct(skb); |
|---|
| 477 | 717 | |
|---|
| 478 | 718 | if (decaps) { |
|---|
| 479 | | - if (skb->sp) |
|---|
| 480 | | - skb->sp->olen = 0; |
|---|
| 719 | + sp = skb_sec_path(skb); |
|---|
| 720 | + if (sp) |
|---|
| 721 | + sp->olen = 0; |
|---|
| 481 | 722 | skb_dst_drop(skb); |
|---|
| 482 | 723 | gro_cells_receive(&gro_cells, skb); |
|---|
| 483 | 724 | return 0; |
|---|
| .. | .. |
|---|
| 486 | 727 | if (xo) |
|---|
| 487 | 728 | xfrm_gro = xo->flags & XFRM_GRO; |
|---|
| 488 | 729 | |
|---|
| 489 | | - err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async); |
|---|
| 730 | + err = -EAFNOSUPPORT; |
|---|
| 731 | + rcu_read_lock(); |
|---|
| 732 | + afinfo = xfrm_state_afinfo_get_rcu(x->inner_mode.family); |
|---|
| 733 | + if (likely(afinfo)) |
|---|
| 734 | + err = afinfo->transport_finish(skb, xfrm_gro || async); |
|---|
| 735 | + rcu_read_unlock(); |
|---|
| 490 | 736 | if (xfrm_gro) { |
|---|
| 491 | | - if (skb->sp) |
|---|
| 492 | | - skb->sp->olen = 0; |
|---|
| 737 | + sp = skb_sec_path(skb); |
|---|
| 738 | + if (sp) |
|---|
| 739 | + sp->olen = 0; |
|---|
| 493 | 740 | skb_dst_drop(skb); |
|---|
| 494 | 741 | gro_cells_receive(&gro_cells, skb); |
|---|
| 495 | 742 | return err; |
|---|
| .. | .. |
|---|
| 523 | 770 | skb_queue_splice_init(&trans->queue, &queue); |
|---|
| 524 | 771 | |
|---|
| 525 | 772 | while ((skb = __skb_dequeue(&queue))) |
|---|
| 526 | | - XFRM_TRANS_SKB_CB(skb)->finish(dev_net(skb->dev), NULL, skb); |
|---|
| 773 | + XFRM_TRANS_SKB_CB(skb)->finish(XFRM_TRANS_SKB_CB(skb)->net, |
|---|
| 774 | + NULL, skb); |
|---|
| 527 | 775 | } |
|---|
| 528 | 776 | |
|---|
| 529 | | -int xfrm_trans_queue(struct sk_buff *skb, |
|---|
| 530 | | - int (*finish)(struct net *, struct sock *, |
|---|
| 531 | | - struct sk_buff *)) |
|---|
| 777 | +int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb, |
|---|
| 778 | + int (*finish)(struct net *, struct sock *, |
|---|
| 779 | + struct sk_buff *)) |
|---|
| 532 | 780 | { |
|---|
| 533 | 781 | struct xfrm_trans_tasklet *trans; |
|---|
| 534 | 782 | |
|---|
| 535 | 783 | trans = this_cpu_ptr(&xfrm_trans_tasklet); |
|---|
| 536 | 784 | |
|---|
| 537 | | - if (skb_queue_len(&trans->queue) >= netdev_max_backlog) |
|---|
| 785 | + if (skb_queue_len(&trans->queue) >= READ_ONCE(netdev_max_backlog)) |
|---|
| 538 | 786 | return -ENOBUFS; |
|---|
| 539 | 787 | |
|---|
| 788 | + BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb)); |
|---|
| 789 | + |
|---|
| 540 | 790 | XFRM_TRANS_SKB_CB(skb)->finish = finish; |
|---|
| 791 | + XFRM_TRANS_SKB_CB(skb)->net = net; |
|---|
| 541 | 792 | __skb_queue_tail(&trans->queue, skb); |
|---|
| 542 | 793 | tasklet_schedule(&trans->tasklet); |
|---|
| 543 | 794 | return 0; |
|---|
| 795 | +} |
|---|
| 796 | +EXPORT_SYMBOL(xfrm_trans_queue_net); |
|---|
| 797 | + |
|---|
| 798 | +int xfrm_trans_queue(struct sk_buff *skb, |
|---|
| 799 | + int (*finish)(struct net *, struct sock *, |
|---|
| 800 | + struct sk_buff *)) |
|---|
| 801 | +{ |
|---|
| 802 | + return xfrm_trans_queue_net(dev_net(skb->dev), skb, finish); |
|---|
| 544 | 803 | } |
|---|
| 545 | 804 | EXPORT_SYMBOL(xfrm_trans_queue); |
|---|
| 546 | 805 | |
|---|
| .. | .. |
|---|
| 553 | 812 | err = gro_cells_init(&gro_cells, &xfrm_napi_dev); |
|---|
| 554 | 813 | if (err) |
|---|
| 555 | 814 | gro_cells.cells = NULL; |
|---|
| 556 | | - |
|---|
| 557 | | - secpath_cachep = kmem_cache_create("secpath_cache", |
|---|
| 558 | | - sizeof(struct sec_path), |
|---|
| 559 | | - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
|---|
| 560 | | - NULL); |
|---|
| 561 | 815 | |
|---|
| 562 | 816 | for_each_possible_cpu(i) { |
|---|
| 563 | 817 | struct xfrm_trans_tasklet *trans; |
|---|