Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IPSEC]: Add async resume support on input

This patch adds support for async resumptions on input. To do so, the
transform would return -EINPROGRESS and subsequently invoke the
function xfrm_input_resume to resume processing.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Herbert Xu and committed by
David S. Miller
1bf06cd2 60d5fcfb

+40 -5
+1
include/net/xfrm.h
··· 1138 1138 extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); 1139 1139 extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, 1140 1140 int encap_type); 1141 + extern int xfrm_input_resume(struct sk_buff *skb, int nexthdr); 1141 1142 extern int xfrm_output_resume(struct sk_buff *skb, int err); 1142 1143 extern int xfrm_output(struct sk_buff *skb); 1143 1144 extern int xfrm4_extract_header(struct sk_buff *skb);
+3
net/ipv4/xfrm4_input.c
··· 59 59 xfrm4_rcv_encap_finish); 60 60 return 0; 61 61 #else 62 + if (async) 63 + return xfrm4_rcv_encap_finish(skb); 64 + 62 65 return -iph->protocol; 63 66 #endif 64 67 }
+3
net/ipv6/xfrm6_input.c
··· 41 41 ip6_rcv_finish); 42 42 return -1; 43 43 #else 44 + if (async) 45 + return ip6_rcv_finish(skb); 46 + 44 47 return 1; 45 48 #endif 46 49 }
+33 -5
net/xfrm/xfrm_input.c
··· 101 101 int err; 102 102 __be32 seq; 103 103 struct xfrm_state *x; 104 + xfrm_address_t *daddr; 104 105 int decaps = 0; 105 - unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff; 106 + int async = 0; 107 + 108 + /* A negative encap_type indicates async resumption. */ 109 + if (encap_type < 0) { 110 + async = 1; 111 + x = skb->sp->xvec[skb->sp->len - 1]; 112 + seq = XFRM_SKB_CB(skb)->seq; 113 + goto resume; 114 + } 106 115 107 116 /* Allocate new secpath or COW existing one. */ 108 117 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { ··· 125 116 skb->sp = sp; 126 117 } 127 118 119 + daddr = (xfrm_address_t *)(skb_network_header(skb) + 120 + XFRM_SPI_SKB_CB(skb)->daddroff); 121 + 128 122 seq = 0; 129 123 if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) 130 124 goto drop; ··· 136 124 if (skb->sp->len == XFRM_MAX_DEPTH) 137 125 goto drop; 138 126 139 - x = xfrm_state_lookup((xfrm_address_t *) 140 - (skb_network_header(skb) + daddroff), 141 - spi, nexthdr, AF_INET); 127 + x = xfrm_state_lookup(daddr, spi, nexthdr, AF_INET); 142 128 if (x == NULL) 143 129 goto drop; 144 130 ··· 157 147 158 148 spin_unlock(&x->lock); 159 149 150 + XFRM_SKB_CB(skb)->seq = seq; 151 + 160 152 nexthdr = x->type->input(x, skb); 161 153 154 + if (nexthdr == -EINPROGRESS) 155 + return 0; 156 + 157 + resume: 162 158 spin_lock(&x->lock); 163 159 if (nexthdr <= 0) { 164 160 if (nexthdr == -EBADMSG) ··· 193 177 break; 194 178 } 195 179 180 + /* 181 + * We need the inner address. However, we only get here for 182 + * transport mode so the outer address is identical. 183 + */ 184 + daddr = &x->id.daddr; 185 + 196 186 err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); 197 187 if (err < 0) 198 188 goto drop; ··· 212 190 netif_rx(skb); 213 191 return 0; 214 192 } else { 215 - return x->inner_mode->afinfo->transport_finish(skb, 0); 193 + return x->inner_mode->afinfo->transport_finish(skb, async); 216 194 } 217 195 218 196 drop_unlock: ··· 222 200 return 0; 223 201 } 224 202 EXPORT_SYMBOL(xfrm_input); 203 + 204 + int xfrm_input_resume(struct sk_buff *skb, int nexthdr) 205 + { 206 + return xfrm_input(skb, nexthdr, 0, -1); 207 + } 208 + EXPORT_SYMBOL(xfrm_input_resume); 225 209 226 210 void __init xfrm_input_init(void) 227 211 {