18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * xfrm_input.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Changes: 68c2ecf20Sopenharmony_ci * YOSHIFUJI Hideaki @USAGI 78c2ecf20Sopenharmony_ci * Split up af-specific portion 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bottom_half.h> 128c2ecf20Sopenharmony_ci#include <linux/cache.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/percpu.h> 188c2ecf20Sopenharmony_ci#include <net/dst.h> 198c2ecf20Sopenharmony_ci#include <net/ip.h> 208c2ecf20Sopenharmony_ci#include <net/xfrm.h> 218c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h> 228c2ecf20Sopenharmony_ci#include <net/ip6_tunnel.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "xfrm_inout.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct xfrm_trans_tasklet { 278c2ecf20Sopenharmony_ci struct tasklet_struct tasklet; 288c2ecf20Sopenharmony_ci struct sk_buff_head queue; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct xfrm_trans_cb { 328c2ecf20Sopenharmony_ci union { 338c2ecf20Sopenharmony_ci struct inet_skb_parm h4; 348c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 358c2ecf20Sopenharmony_ci struct inet6_skb_parm h6; 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci } header; 388c2ecf20Sopenharmony_ci int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb); 398c2ecf20Sopenharmony_ci struct net *net; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0])) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(xfrm_input_afinfo_lock); 458c2ecf20Sopenharmony_cistatic struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[2][AF_INET6 + 1]; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic struct gro_cells gro_cells; 488c2ecf20Sopenharmony_cistatic struct net_device xfrm_napi_dev; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct xfrm_trans_tasklet, xfrm_trans_tasklet); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciint xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci int err = 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (WARN_ON(afinfo->family > AF_INET6)) 578c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci spin_lock_bh(&xfrm_input_afinfo_lock); 608c2ecf20Sopenharmony_ci if (unlikely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family])) 618c2ecf20Sopenharmony_ci err = -EEXIST; 628c2ecf20Sopenharmony_ci else 638c2ecf20Sopenharmony_ci rcu_assign_pointer(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family], afinfo); 648c2ecf20Sopenharmony_ci spin_unlock_bh(&xfrm_input_afinfo_lock); 658c2ecf20Sopenharmony_ci return err; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_input_register_afinfo); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciint xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int err = 0; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci spin_lock_bh(&xfrm_input_afinfo_lock); 748c2ecf20Sopenharmony_ci if (likely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family])) { 758c2ecf20Sopenharmony_ci if (unlikely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family] != afinfo)) 768c2ecf20Sopenharmony_ci err = -EINVAL; 778c2ecf20Sopenharmony_ci else 788c2ecf20Sopenharmony_ci RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family], NULL); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci spin_unlock_bh(&xfrm_input_afinfo_lock); 818c2ecf20Sopenharmony_ci synchronize_rcu(); 828c2ecf20Sopenharmony_ci return err; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_input_unregister_afinfo); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic const struct xfrm_input_afinfo *xfrm_input_get_afinfo(u8 family, bool is_ipip) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci const struct xfrm_input_afinfo *afinfo; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(family > AF_INET6)) 918c2ecf20Sopenharmony_ci return NULL; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci rcu_read_lock(); 948c2ecf20Sopenharmony_ci afinfo = rcu_dereference(xfrm_input_afinfo[is_ipip][family]); 958c2ecf20Sopenharmony_ci if (unlikely(!afinfo)) 968c2ecf20Sopenharmony_ci rcu_read_unlock(); 978c2ecf20Sopenharmony_ci return afinfo; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol, 1018c2ecf20Sopenharmony_ci int err) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci bool is_ipip = (protocol == IPPROTO_IPIP || protocol == IPPROTO_IPV6); 1048c2ecf20Sopenharmony_ci const struct xfrm_input_afinfo *afinfo; 1058c2ecf20Sopenharmony_ci int ret; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci afinfo = xfrm_input_get_afinfo(family, is_ipip); 1088c2ecf20Sopenharmony_ci if (!afinfo) 1098c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci ret = afinfo->callback(skb, protocol, err); 1128c2ecf20Sopenharmony_ci rcu_read_unlock(); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return ret; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistruct sec_path *secpath_set(struct sk_buff *skb) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct sec_path *sp, *tmp = skb_ext_find(skb, SKB_EXT_SEC_PATH); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci sp = skb_ext_add(skb, SKB_EXT_SEC_PATH); 1228c2ecf20Sopenharmony_ci if (!sp) 1238c2ecf20Sopenharmony_ci return NULL; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (tmp) /* reused existing one (was COW'd if needed) */ 1268c2ecf20Sopenharmony_ci return sp; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* allocated new secpath */ 1298c2ecf20Sopenharmony_ci memset(sp->ovec, 0, sizeof(sp->ovec)); 1308c2ecf20Sopenharmony_ci sp->olen = 0; 1318c2ecf20Sopenharmony_ci sp->len = 0; 1328c2ecf20Sopenharmony_ci sp->verified_cnt = 0; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return sp; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(secpath_set); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Fetch spi and seq from ipsec header */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciint xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci int offset, offset_seq; 1438c2ecf20Sopenharmony_ci int hlen; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci switch (nexthdr) { 1468c2ecf20Sopenharmony_ci case IPPROTO_AH: 1478c2ecf20Sopenharmony_ci hlen = sizeof(struct ip_auth_hdr); 1488c2ecf20Sopenharmony_ci offset = offsetof(struct ip_auth_hdr, spi); 1498c2ecf20Sopenharmony_ci offset_seq = offsetof(struct ip_auth_hdr, seq_no); 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci case IPPROTO_ESP: 1528c2ecf20Sopenharmony_ci hlen = sizeof(struct ip_esp_hdr); 1538c2ecf20Sopenharmony_ci offset = offsetof(struct ip_esp_hdr, spi); 1548c2ecf20Sopenharmony_ci offset_seq = offsetof(struct ip_esp_hdr, seq_no); 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case IPPROTO_COMP: 1578c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr))) 1588c2ecf20Sopenharmony_ci return -EINVAL; 1598c2ecf20Sopenharmony_ci *spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2))); 1608c2ecf20Sopenharmony_ci *seq = 0; 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci default: 1638c2ecf20Sopenharmony_ci return 1; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, hlen)) 1678c2ecf20Sopenharmony_ci return -EINVAL; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci *spi = *(__be32 *)(skb_transport_header(skb) + offset); 1708c2ecf20Sopenharmony_ci *seq = *(__be32 *)(skb_transport_header(skb) + offset_seq); 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_parse_spi); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int xfrm4_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct iphdr *iph; 1788c2ecf20Sopenharmony_ci int optlen = 0; 1798c2ecf20Sopenharmony_ci int err = -EINVAL; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) { 1828c2ecf20Sopenharmony_ci struct ip_beet_phdr *ph; 1838c2ecf20Sopenharmony_ci int phlen; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(*ph))) 1868c2ecf20Sopenharmony_ci goto out; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci ph = (struct ip_beet_phdr *)skb->data; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci phlen = sizeof(*ph) + ph->padlen; 1918c2ecf20Sopenharmony_ci optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen); 1928c2ecf20Sopenharmony_ci if (optlen < 0 || optlen & 3 || optlen > 250) 1938c2ecf20Sopenharmony_ci goto out; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, phlen)) 1988c2ecf20Sopenharmony_ci goto out; 1998c2ecf20Sopenharmony_ci __skb_pull(skb, phlen); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci skb_push(skb, sizeof(*iph)); 2038c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 2048c2ecf20Sopenharmony_ci skb_mac_header_rebuild(skb); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci xfrm4_beet_make_header(skb); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci iph = ip_hdr(skb); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci iph->ihl += optlen / 4; 2118c2ecf20Sopenharmony_ci iph->tot_len = htons(skb->len); 2128c2ecf20Sopenharmony_ci iph->daddr = x->sel.daddr.a4; 2138c2ecf20Sopenharmony_ci iph->saddr = x->sel.saddr.a4; 2148c2ecf20Sopenharmony_ci iph->check = 0; 2158c2ecf20Sopenharmony_ci iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); 2168c2ecf20Sopenharmony_ci err = 0; 2178c2ecf20Sopenharmony_ciout: 2188c2ecf20Sopenharmony_ci return err; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void ipip_ecn_decapsulate(struct sk_buff *skb) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct iphdr *inner_iph = ipip_hdr(skb); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) 2268c2ecf20Sopenharmony_ci IP_ECN_set_ce(inner_iph); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int xfrm4_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int err = -EINVAL; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) 2348c2ecf20Sopenharmony_ci goto out; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct iphdr))) 2378c2ecf20Sopenharmony_ci goto out; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci err = skb_unclone(skb, GFP_ATOMIC); 2408c2ecf20Sopenharmony_ci if (err) 2418c2ecf20Sopenharmony_ci goto out; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (x->props.flags & XFRM_STATE_DECAP_DSCP) 2448c2ecf20Sopenharmony_ci ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); 2458c2ecf20Sopenharmony_ci if (!(x->props.flags & XFRM_STATE_NOECN)) 2468c2ecf20Sopenharmony_ci ipip_ecn_decapsulate(skb); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 2498c2ecf20Sopenharmony_ci skb_mac_header_rebuild(skb); 2508c2ecf20Sopenharmony_ci if (skb->mac_len) 2518c2ecf20Sopenharmony_ci eth_hdr(skb)->h_proto = skb->protocol; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci err = 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ciout: 2568c2ecf20Sopenharmony_ci return err; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void ipip6_ecn_decapsulate(struct sk_buff *skb) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct ipv6hdr *inner_iph = ipipv6_hdr(skb); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) 2648c2ecf20Sopenharmony_ci IP6_ECN_set_ce(skb, inner_iph); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci int err = -EINVAL; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) 2728c2ecf20Sopenharmony_ci goto out; 2738c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 2748c2ecf20Sopenharmony_ci goto out; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci err = skb_unclone(skb, GFP_ATOMIC); 2778c2ecf20Sopenharmony_ci if (err) 2788c2ecf20Sopenharmony_ci goto out; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (x->props.flags & XFRM_STATE_DECAP_DSCP) 2818c2ecf20Sopenharmony_ci ipv6_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipipv6_hdr(skb)); 2828c2ecf20Sopenharmony_ci if (!(x->props.flags & XFRM_STATE_NOECN)) 2838c2ecf20Sopenharmony_ci ipip6_ecn_decapsulate(skb); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 2868c2ecf20Sopenharmony_ci skb_mac_header_rebuild(skb); 2878c2ecf20Sopenharmony_ci if (skb->mac_len) 2888c2ecf20Sopenharmony_ci eth_hdr(skb)->h_proto = skb->protocol; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci err = 0; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ciout: 2938c2ecf20Sopenharmony_ci return err; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int xfrm6_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct ipv6hdr *ip6h; 2998c2ecf20Sopenharmony_ci int size = sizeof(struct ipv6hdr); 3008c2ecf20Sopenharmony_ci int err; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci err = skb_cow_head(skb, size + skb->mac_len); 3038c2ecf20Sopenharmony_ci if (err) 3048c2ecf20Sopenharmony_ci goto out; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci __skb_push(skb, size); 3078c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 3088c2ecf20Sopenharmony_ci skb_mac_header_rebuild(skb); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci xfrm6_beet_make_header(skb); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ip6h = ipv6_hdr(skb); 3138c2ecf20Sopenharmony_ci ip6h->payload_len = htons(skb->len - size); 3148c2ecf20Sopenharmony_ci ip6h->daddr = x->sel.daddr.in6; 3158c2ecf20Sopenharmony_ci ip6h->saddr = x->sel.saddr.in6; 3168c2ecf20Sopenharmony_ci err = 0; 3178c2ecf20Sopenharmony_ciout: 3188c2ecf20Sopenharmony_ci return err; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/* Remove encapsulation header. 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * The IP header will be moved over the top of the encapsulation 3248c2ecf20Sopenharmony_ci * header. 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * On entry, the transport header shall point to where the IP header 3278c2ecf20Sopenharmony_ci * should be and the network header shall be set to where the IP 3288c2ecf20Sopenharmony_ci * header currently is. skb->data shall point to the start of the 3298c2ecf20Sopenharmony_ci * payload. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_cistatic int 3328c2ecf20Sopenharmony_cixfrm_inner_mode_encap_remove(struct xfrm_state *x, 3338c2ecf20Sopenharmony_ci const struct xfrm_mode *inner_mode, 3348c2ecf20Sopenharmony_ci struct sk_buff *skb) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci switch (inner_mode->encap) { 3378c2ecf20Sopenharmony_ci case XFRM_MODE_BEET: 3388c2ecf20Sopenharmony_ci if (inner_mode->family == AF_INET) 3398c2ecf20Sopenharmony_ci return xfrm4_remove_beet_encap(x, skb); 3408c2ecf20Sopenharmony_ci if (inner_mode->family == AF_INET6) 3418c2ecf20Sopenharmony_ci return xfrm6_remove_beet_encap(x, skb); 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci case XFRM_MODE_TUNNEL: 3448c2ecf20Sopenharmony_ci if (inner_mode->family == AF_INET) 3458c2ecf20Sopenharmony_ci return xfrm4_remove_tunnel_encap(x, skb); 3468c2ecf20Sopenharmony_ci if (inner_mode->family == AF_INET6) 3478c2ecf20Sopenharmony_ci return xfrm6_remove_tunnel_encap(x, skb); 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 3528c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci const struct xfrm_mode *inner_mode = &x->inner_mode; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci switch (x->outer_mode.family) { 3608c2ecf20Sopenharmony_ci case AF_INET: 3618c2ecf20Sopenharmony_ci xfrm4_extract_header(skb); 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci case AF_INET6: 3648c2ecf20Sopenharmony_ci xfrm6_extract_header(skb); 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci default: 3678c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 3688c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (x->sel.family == AF_UNSPEC) { 3728c2ecf20Sopenharmony_ci inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); 3738c2ecf20Sopenharmony_ci if (!inner_mode) 3748c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci switch (inner_mode->family) { 3788c2ecf20Sopenharmony_ci case AF_INET: 3798c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_IP); 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci case AF_INET6: 3828c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_IPV6); 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci default: 3858c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return xfrm_inner_mode_encap_remove(x, inner_mode, skb); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* Remove encapsulation header. 3938c2ecf20Sopenharmony_ci * 3948c2ecf20Sopenharmony_ci * The IP header will be moved over the top of the encapsulation header. 3958c2ecf20Sopenharmony_ci * 3968c2ecf20Sopenharmony_ci * On entry, skb_transport_header() shall point to where the IP header 3978c2ecf20Sopenharmony_ci * should be and skb_network_header() shall be set to where the IP header 3988c2ecf20Sopenharmony_ci * currently is. skb->data shall point to the start of the payload. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_cistatic int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci int ihl = skb->data - skb_transport_header(skb); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (skb->transport_header != skb->network_header) { 4058c2ecf20Sopenharmony_ci memmove(skb_transport_header(skb), 4068c2ecf20Sopenharmony_ci skb_network_header(skb), ihl); 4078c2ecf20Sopenharmony_ci skb->network_header = skb->transport_header; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci ip_hdr(skb)->tot_len = htons(skb->len + ihl); 4108c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 4178c2ecf20Sopenharmony_ci int ihl = skb->data - skb_transport_header(skb); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (skb->transport_header != skb->network_header) { 4208c2ecf20Sopenharmony_ci memmove(skb_transport_header(skb), 4218c2ecf20Sopenharmony_ci skb_network_header(skb), ihl); 4228c2ecf20Sopenharmony_ci skb->network_header = skb->transport_header; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci ipv6_hdr(skb)->payload_len = htons(skb->len + ihl - 4258c2ecf20Sopenharmony_ci sizeof(struct ipv6hdr)); 4268c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci#else 4298c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 4308c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 4318c2ecf20Sopenharmony_ci#endif 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic int xfrm_inner_mode_input(struct xfrm_state *x, 4358c2ecf20Sopenharmony_ci const struct xfrm_mode *inner_mode, 4368c2ecf20Sopenharmony_ci struct sk_buff *skb) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci switch (inner_mode->encap) { 4398c2ecf20Sopenharmony_ci case XFRM_MODE_BEET: 4408c2ecf20Sopenharmony_ci case XFRM_MODE_TUNNEL: 4418c2ecf20Sopenharmony_ci return xfrm_prepare_input(x, skb); 4428c2ecf20Sopenharmony_ci case XFRM_MODE_TRANSPORT: 4438c2ecf20Sopenharmony_ci if (inner_mode->family == AF_INET) 4448c2ecf20Sopenharmony_ci return xfrm4_transport_input(x, skb); 4458c2ecf20Sopenharmony_ci if (inner_mode->family == AF_INET6) 4468c2ecf20Sopenharmony_ci return xfrm6_transport_input(x, skb); 4478c2ecf20Sopenharmony_ci break; 4488c2ecf20Sopenharmony_ci case XFRM_MODE_ROUTEOPTIMIZATION: 4498c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci default: 4528c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ciint xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci const struct xfrm_state_afinfo *afinfo; 4628c2ecf20Sopenharmony_ci struct net *net = dev_net(skb->dev); 4638c2ecf20Sopenharmony_ci const struct xfrm_mode *inner_mode; 4648c2ecf20Sopenharmony_ci int err; 4658c2ecf20Sopenharmony_ci __be32 seq; 4668c2ecf20Sopenharmony_ci __be32 seq_hi; 4678c2ecf20Sopenharmony_ci struct xfrm_state *x = NULL; 4688c2ecf20Sopenharmony_ci xfrm_address_t *daddr; 4698c2ecf20Sopenharmony_ci u32 mark = skb->mark; 4708c2ecf20Sopenharmony_ci unsigned int family = AF_UNSPEC; 4718c2ecf20Sopenharmony_ci int decaps = 0; 4728c2ecf20Sopenharmony_ci int async = 0; 4738c2ecf20Sopenharmony_ci bool xfrm_gro = false; 4748c2ecf20Sopenharmony_ci bool crypto_done = false; 4758c2ecf20Sopenharmony_ci struct xfrm_offload *xo = xfrm_offload(skb); 4768c2ecf20Sopenharmony_ci struct sec_path *sp; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (encap_type < 0) { 4798c2ecf20Sopenharmony_ci x = xfrm_input_state(skb); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (unlikely(x->km.state != XFRM_STATE_VALID)) { 4828c2ecf20Sopenharmony_ci if (x->km.state == XFRM_STATE_ACQ) 4838c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR); 4848c2ecf20Sopenharmony_ci else 4858c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, 4868c2ecf20Sopenharmony_ci LINUX_MIB_XFRMINSTATEINVALID); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (encap_type == -1) 4898c2ecf20Sopenharmony_ci dev_put(skb->dev); 4908c2ecf20Sopenharmony_ci goto drop; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci family = x->outer_mode.family; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* An encap_type of -1 indicates async resumption. */ 4968c2ecf20Sopenharmony_ci if (encap_type == -1) { 4978c2ecf20Sopenharmony_ci async = 1; 4988c2ecf20Sopenharmony_ci seq = XFRM_SKB_CB(skb)->seq.input.low; 4998c2ecf20Sopenharmony_ci goto resume; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* encap_type < -1 indicates a GRO call. */ 5038c2ecf20Sopenharmony_ci encap_type = 0; 5048c2ecf20Sopenharmony_ci seq = XFRM_SPI_SKB_CB(skb)->seq; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (xo && (xo->flags & CRYPTO_DONE)) { 5078c2ecf20Sopenharmony_ci crypto_done = true; 5088c2ecf20Sopenharmony_ci family = XFRM_SPI_SKB_CB(skb)->family; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (!(xo->status & CRYPTO_SUCCESS)) { 5118c2ecf20Sopenharmony_ci if (xo->status & 5128c2ecf20Sopenharmony_ci (CRYPTO_TRANSPORT_AH_AUTH_FAILED | 5138c2ecf20Sopenharmony_ci CRYPTO_TRANSPORT_ESP_AUTH_FAILED | 5148c2ecf20Sopenharmony_ci CRYPTO_TUNNEL_AH_AUTH_FAILED | 5158c2ecf20Sopenharmony_ci CRYPTO_TUNNEL_ESP_AUTH_FAILED)) { 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci xfrm_audit_state_icvfail(x, skb, 5188c2ecf20Sopenharmony_ci x->type->proto); 5198c2ecf20Sopenharmony_ci x->stats.integrity_failed++; 5208c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR); 5218c2ecf20Sopenharmony_ci goto drop; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (xo->status & CRYPTO_INVALID_PROTOCOL) { 5258c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR); 5268c2ecf20Sopenharmony_ci goto drop; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); 5308c2ecf20Sopenharmony_ci goto drop; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { 5348c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); 5358c2ecf20Sopenharmony_ci goto drop; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci goto lock; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci family = XFRM_SPI_SKB_CB(skb)->family; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* if tunnel is present override skb->mark value with tunnel i_key */ 5458c2ecf20Sopenharmony_ci switch (family) { 5468c2ecf20Sopenharmony_ci case AF_INET: 5478c2ecf20Sopenharmony_ci if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4) 5488c2ecf20Sopenharmony_ci mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4->parms.i_key); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci case AF_INET6: 5518c2ecf20Sopenharmony_ci if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6) 5528c2ecf20Sopenharmony_ci mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key); 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci sp = secpath_set(skb); 5578c2ecf20Sopenharmony_ci if (!sp) { 5588c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); 5598c2ecf20Sopenharmony_ci goto drop; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci seq = 0; 5638c2ecf20Sopenharmony_ci if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { 5648c2ecf20Sopenharmony_ci secpath_reset(skb); 5658c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); 5668c2ecf20Sopenharmony_ci goto drop; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci daddr = (xfrm_address_t *)(skb_network_header(skb) + 5708c2ecf20Sopenharmony_ci XFRM_SPI_SKB_CB(skb)->daddroff); 5718c2ecf20Sopenharmony_ci do { 5728c2ecf20Sopenharmony_ci sp = skb_sec_path(skb); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (sp->len == XFRM_MAX_DEPTH) { 5758c2ecf20Sopenharmony_ci secpath_reset(skb); 5768c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); 5778c2ecf20Sopenharmony_ci goto drop; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci x = xfrm_state_lookup(net, mark, daddr, spi, nexthdr, family); 5818c2ecf20Sopenharmony_ci if (x == NULL) { 5828c2ecf20Sopenharmony_ci secpath_reset(skb); 5838c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); 5848c2ecf20Sopenharmony_ci xfrm_audit_state_notfound(skb, family, spi, seq); 5858c2ecf20Sopenharmony_ci goto drop; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci skb->mark = xfrm_smark_get(skb->mark, x); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci sp->xvec[sp->len++] = x; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci skb_dst_force(skb); 5938c2ecf20Sopenharmony_ci if (!skb_dst(skb)) { 5948c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); 5958c2ecf20Sopenharmony_ci goto drop; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cilock: 5998c2ecf20Sopenharmony_ci spin_lock(&x->lock); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (unlikely(x->km.state != XFRM_STATE_VALID)) { 6028c2ecf20Sopenharmony_ci if (x->km.state == XFRM_STATE_ACQ) 6038c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR); 6048c2ecf20Sopenharmony_ci else 6058c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, 6068c2ecf20Sopenharmony_ci LINUX_MIB_XFRMINSTATEINVALID); 6078c2ecf20Sopenharmony_ci goto drop_unlock; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if ((x->encap ? x->encap->encap_type : 0) != encap_type) { 6118c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); 6128c2ecf20Sopenharmony_ci goto drop_unlock; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (x->repl->check(x, skb, seq)) { 6168c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR); 6178c2ecf20Sopenharmony_ci goto drop_unlock; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (xfrm_state_check_expire(x)) { 6218c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED); 6228c2ecf20Sopenharmony_ci goto drop_unlock; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci spin_unlock(&x->lock); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (xfrm_tunnel_check(skb, x, family)) { 6288c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); 6298c2ecf20Sopenharmony_ci goto drop; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci seq_hi = htonl(xfrm_replay_seqhi(x, seq)); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci XFRM_SKB_CB(skb)->seq.input.low = seq; 6358c2ecf20Sopenharmony_ci XFRM_SKB_CB(skb)->seq.input.hi = seq_hi; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci dev_hold(skb->dev); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (crypto_done) 6408c2ecf20Sopenharmony_ci nexthdr = x->type_offload->input_tail(x, skb); 6418c2ecf20Sopenharmony_ci else 6428c2ecf20Sopenharmony_ci nexthdr = x->type->input(x, skb); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (nexthdr == -EINPROGRESS) 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ciresume: 6478c2ecf20Sopenharmony_ci dev_put(skb->dev); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci spin_lock(&x->lock); 6508c2ecf20Sopenharmony_ci if (nexthdr < 0) { 6518c2ecf20Sopenharmony_ci if (nexthdr == -EBADMSG) { 6528c2ecf20Sopenharmony_ci xfrm_audit_state_icvfail(x, skb, 6538c2ecf20Sopenharmony_ci x->type->proto); 6548c2ecf20Sopenharmony_ci x->stats.integrity_failed++; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR); 6578c2ecf20Sopenharmony_ci goto drop_unlock; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* only the first xfrm gets the encap type */ 6618c2ecf20Sopenharmony_ci encap_type = 0; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (x->repl->recheck(x, skb, seq)) { 6648c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR); 6658c2ecf20Sopenharmony_ci goto drop_unlock; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci x->repl->advance(x, seq); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci x->curlft.bytes += skb->len; 6718c2ecf20Sopenharmony_ci x->curlft.packets++; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci spin_unlock(&x->lock); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci inner_mode = &x->inner_mode; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (x->sel.family == AF_UNSPEC) { 6808c2ecf20Sopenharmony_ci inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); 6818c2ecf20Sopenharmony_ci if (inner_mode == NULL) { 6828c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); 6838c2ecf20Sopenharmony_ci goto drop; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (xfrm_inner_mode_input(x, inner_mode, skb)) { 6888c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); 6898c2ecf20Sopenharmony_ci goto drop; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL) { 6938c2ecf20Sopenharmony_ci decaps = 1; 6948c2ecf20Sopenharmony_ci break; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* 6988c2ecf20Sopenharmony_ci * We need the inner address. However, we only get here for 6998c2ecf20Sopenharmony_ci * transport mode so the outer address is identical. 7008c2ecf20Sopenharmony_ci */ 7018c2ecf20Sopenharmony_ci daddr = &x->id.daddr; 7028c2ecf20Sopenharmony_ci family = x->outer_mode.family; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); 7058c2ecf20Sopenharmony_ci if (err < 0) { 7068c2ecf20Sopenharmony_ci XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); 7078c2ecf20Sopenharmony_ci goto drop; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci crypto_done = false; 7108c2ecf20Sopenharmony_ci } while (!err); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci err = xfrm_rcv_cb(skb, family, x->type->proto, 0); 7138c2ecf20Sopenharmony_ci if (err) 7148c2ecf20Sopenharmony_ci goto drop; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci nf_reset_ct(skb); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (decaps) { 7198c2ecf20Sopenharmony_ci sp = skb_sec_path(skb); 7208c2ecf20Sopenharmony_ci if (sp) 7218c2ecf20Sopenharmony_ci sp->olen = 0; 7228c2ecf20Sopenharmony_ci skb_dst_drop(skb); 7238c2ecf20Sopenharmony_ci gro_cells_receive(&gro_cells, skb); 7248c2ecf20Sopenharmony_ci return 0; 7258c2ecf20Sopenharmony_ci } else { 7268c2ecf20Sopenharmony_ci xo = xfrm_offload(skb); 7278c2ecf20Sopenharmony_ci if (xo) 7288c2ecf20Sopenharmony_ci xfrm_gro = xo->flags & XFRM_GRO; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci err = -EAFNOSUPPORT; 7318c2ecf20Sopenharmony_ci rcu_read_lock(); 7328c2ecf20Sopenharmony_ci afinfo = xfrm_state_afinfo_get_rcu(x->inner_mode.family); 7338c2ecf20Sopenharmony_ci if (likely(afinfo)) 7348c2ecf20Sopenharmony_ci err = afinfo->transport_finish(skb, xfrm_gro || async); 7358c2ecf20Sopenharmony_ci rcu_read_unlock(); 7368c2ecf20Sopenharmony_ci if (xfrm_gro) { 7378c2ecf20Sopenharmony_ci sp = skb_sec_path(skb); 7388c2ecf20Sopenharmony_ci if (sp) 7398c2ecf20Sopenharmony_ci sp->olen = 0; 7408c2ecf20Sopenharmony_ci skb_dst_drop(skb); 7418c2ecf20Sopenharmony_ci gro_cells_receive(&gro_cells, skb); 7428c2ecf20Sopenharmony_ci return err; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci return err; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cidrop_unlock: 7498c2ecf20Sopenharmony_ci spin_unlock(&x->lock); 7508c2ecf20Sopenharmony_cidrop: 7518c2ecf20Sopenharmony_ci xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1); 7528c2ecf20Sopenharmony_ci kfree_skb(skb); 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_input); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ciint xfrm_input_resume(struct sk_buff *skb, int nexthdr) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci return xfrm_input(skb, nexthdr, 0, -1); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_input_resume); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic void xfrm_trans_reinject(unsigned long data) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct xfrm_trans_tasklet *trans = (void *)data; 7668c2ecf20Sopenharmony_ci struct sk_buff_head queue; 7678c2ecf20Sopenharmony_ci struct sk_buff *skb; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci __skb_queue_head_init(&queue); 7708c2ecf20Sopenharmony_ci skb_queue_splice_init(&trans->queue, &queue); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&queue))) 7738c2ecf20Sopenharmony_ci XFRM_TRANS_SKB_CB(skb)->finish(XFRM_TRANS_SKB_CB(skb)->net, 7748c2ecf20Sopenharmony_ci NULL, skb); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ciint xfrm_trans_queue_net(struct net *net, struct sk_buff *skb, 7788c2ecf20Sopenharmony_ci int (*finish)(struct net *, struct sock *, 7798c2ecf20Sopenharmony_ci struct sk_buff *)) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct xfrm_trans_tasklet *trans; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci trans = this_cpu_ptr(&xfrm_trans_tasklet); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (skb_queue_len(&trans->queue) >= READ_ONCE(netdev_max_backlog)) 7868c2ecf20Sopenharmony_ci return -ENOBUFS; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb)); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci XFRM_TRANS_SKB_CB(skb)->finish = finish; 7918c2ecf20Sopenharmony_ci XFRM_TRANS_SKB_CB(skb)->net = net; 7928c2ecf20Sopenharmony_ci __skb_queue_tail(&trans->queue, skb); 7938c2ecf20Sopenharmony_ci tasklet_schedule(&trans->tasklet); 7948c2ecf20Sopenharmony_ci return 0; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_trans_queue_net); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ciint xfrm_trans_queue(struct sk_buff *skb, 7998c2ecf20Sopenharmony_ci int (*finish)(struct net *, struct sock *, 8008c2ecf20Sopenharmony_ci struct sk_buff *)) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci return xfrm_trans_queue_net(dev_net(skb->dev), skb, finish); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_trans_queue); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_civoid __init xfrm_input_init(void) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci int err; 8098c2ecf20Sopenharmony_ci int i; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci init_dummy_netdev(&xfrm_napi_dev); 8128c2ecf20Sopenharmony_ci err = gro_cells_init(&gro_cells, &xfrm_napi_dev); 8138c2ecf20Sopenharmony_ci if (err) 8148c2ecf20Sopenharmony_ci gro_cells.cells = NULL; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci for_each_possible_cpu(i) { 8178c2ecf20Sopenharmony_ci struct xfrm_trans_tasklet *trans; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci trans = &per_cpu(xfrm_trans_tasklet, i); 8208c2ecf20Sopenharmony_ci __skb_queue_head_init(&trans->queue); 8218c2ecf20Sopenharmony_ci tasklet_init(&trans->tasklet, xfrm_trans_reinject, 8228c2ecf20Sopenharmony_ci (unsigned long)trans); 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci} 825