Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * xfrm6_input.c: based on net/ipv4/xfrm4_input.c 4 : : * 5 : : * Authors: 6 : : * Mitsuru KANDA @USAGI 7 : : * Kazunori MIYAZAWA @USAGI 8 : : * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 9 : : * YOSHIFUJI Hideaki @USAGI 10 : : * IPv6 support 11 : : */ 12 : : 13 : : #include <linux/module.h> 14 : : #include <linux/string.h> 15 : : #include <linux/netfilter.h> 16 : : #include <linux/netfilter_ipv6.h> 17 : : #include <net/ipv6.h> 18 : : #include <net/xfrm.h> 19 : : 20 : 0 : int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb) 21 : : { 22 : 0 : return xfrm6_extract_header(skb); 23 : : } 24 : : 25 : 0 : int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi, 26 : : struct ip6_tnl *t) 27 : : { 28 : 0 : XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; 29 : 0 : XFRM_SPI_SKB_CB(skb)->family = AF_INET6; 30 : 0 : XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); 31 : 0 : return xfrm_input(skb, nexthdr, spi, 0); 32 : : } 33 : : EXPORT_SYMBOL(xfrm6_rcv_spi); 34 : : 35 : 0 : static int xfrm6_transport_finish2(struct net *net, struct sock *sk, 36 : : struct sk_buff *skb) 37 : : { 38 : 0 : if (xfrm_trans_queue(skb, ip6_rcv_finish)) 39 : 0 : __kfree_skb(skb); 40 : 0 : return -1; 41 : : } 42 : : 43 : 0 : int xfrm6_transport_finish(struct sk_buff *skb, int async) 44 : : { 45 : 0 : struct xfrm_offload *xo = xfrm_offload(skb); 46 : 0 : int nhlen = skb->data - skb_network_header(skb); 47 : : 48 : 0 : skb_network_header(skb)[IP6CB(skb)->nhoff] = 49 : 0 : XFRM_MODE_SKB_CB(skb)->protocol; 50 : : 51 : : #ifndef CONFIG_NETFILTER 52 : : if (!async) 53 : : return 1; 54 : : #endif 55 : : 56 : 0 : __skb_push(skb, nhlen); 57 : 0 : ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); 58 : 0 : skb_postpush_rcsum(skb, skb_network_header(skb), nhlen); 59 : : 60 : 0 : if (xo && (xo->flags & XFRM_GRO)) { 61 : 0 : skb_mac_header_rebuild(skb); 62 : : skb_reset_transport_header(skb); 63 : 0 : return -1; 64 : : } 65 : : 66 : 0 : NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, 67 : 0 : dev_net(skb->dev), NULL, skb, skb->dev, NULL, 68 : : xfrm6_transport_finish2); 69 : 0 : return -1; 70 : : } 71 : : 72 : 0 : int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t) 73 : : { 74 : 0 : return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 75 : : 0, t); 76 : : } 77 : : EXPORT_SYMBOL(xfrm6_rcv_tnl); 78 : : 79 : 0 : int xfrm6_rcv(struct sk_buff *skb) 80 : : { 81 : 0 : return xfrm6_rcv_tnl(skb, NULL); 82 : : } 83 : : EXPORT_SYMBOL(xfrm6_rcv); 84 : 0 : int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 85 : : xfrm_address_t *saddr, u8 proto) 86 : : { 87 : 0 : struct net *net = dev_net(skb->dev); 88 : : struct xfrm_state *x = NULL; 89 : : struct sec_path *sp; 90 : : int i = 0; 91 : : 92 : 0 : sp = secpath_set(skb); 93 : 0 : if (!sp) { 94 : : XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); 95 : : goto drop; 96 : : } 97 : : 98 : 0 : if (1 + sp->len == XFRM_MAX_DEPTH) { 99 : : XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); 100 : : goto drop; 101 : : } 102 : : 103 : 0 : for (i = 0; i < 3; i++) { 104 : : xfrm_address_t *dst, *src; 105 : : 106 : 0 : switch (i) { 107 : : case 0: 108 : : dst = daddr; 109 : : src = saddr; 110 : 0 : break; 111 : : case 1: 112 : : /* lookup state with wild-card source address */ 113 : : dst = daddr; 114 : : src = (xfrm_address_t *)&in6addr_any; 115 : 0 : break; 116 : : default: 117 : : /* lookup state with wild-card addresses */ 118 : : dst = (xfrm_address_t *)&in6addr_any; 119 : : src = (xfrm_address_t *)&in6addr_any; 120 : : break; 121 : : } 122 : : 123 : 0 : x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6); 124 : 0 : if (!x) 125 : 0 : continue; 126 : : 127 : : spin_lock(&x->lock); 128 : : 129 : 0 : if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) && 130 : 0 : likely(x->km.state == XFRM_STATE_VALID) && 131 : 0 : !xfrm_state_check_expire(x)) { 132 : : spin_unlock(&x->lock); 133 : 0 : if (x->type->input(x, skb) > 0) { 134 : : /* found a valid state */ 135 : : break; 136 : : } 137 : : } else 138 : : spin_unlock(&x->lock); 139 : : 140 : 0 : xfrm_state_put(x); 141 : : x = NULL; 142 : : } 143 : : 144 : 0 : if (!x) { 145 : : XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); 146 : 0 : xfrm_audit_state_notfound_simple(skb, AF_INET6); 147 : 0 : goto drop; 148 : : } 149 : : 150 : 0 : sp->xvec[sp->len++] = x; 151 : : 152 : : spin_lock(&x->lock); 153 : : 154 : 0 : x->curlft.bytes += skb->len; 155 : 0 : x->curlft.packets++; 156 : : 157 : : spin_unlock(&x->lock); 158 : : 159 : 0 : return 1; 160 : : 161 : : drop: 162 : : return -1; 163 : : } 164 : : EXPORT_SYMBOL(xfrm6_input_addr);