diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-11-19 21:50:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:53:54 -0500 |
commit | 1bf06cd2e338fd6fc29169d30eaf0df982338285 (patch) | |
tree | 351bf1c8e5063fdfb8c820470972169d398729fe | |
parent | 60d5fcfb19d8a958fc563e52240cd05ec23f36c9 (diff) |
[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>
-rw-r--r-- | include/net/xfrm.h | 1 | ||||
-rw-r--r-- | net/ipv4/xfrm4_input.c | 3 | ||||
-rw-r--r-- | net/ipv6/xfrm6_input.c | 3 | ||||
-rw-r--r-- | net/xfrm/xfrm_input.c | 38 |
4 files changed, 40 insertions, 5 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index cf85dc9dc420..37a086d71baf 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -1138,6 +1138,7 @@ extern int xfrm_init_state(struct xfrm_state *x); | |||
1138 | extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); | 1138 | extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); |
1139 | extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, | 1139 | extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, |
1140 | int encap_type); | 1140 | int encap_type); |
1141 | extern int xfrm_input_resume(struct sk_buff *skb, int nexthdr); | ||
1141 | extern int xfrm_output_resume(struct sk_buff *skb, int err); | 1142 | extern int xfrm_output_resume(struct sk_buff *skb, int err); |
1142 | extern int xfrm_output(struct sk_buff *skb); | 1143 | extern int xfrm_output(struct sk_buff *skb); |
1143 | extern int xfrm4_extract_header(struct sk_buff *skb); | 1144 | extern int xfrm4_extract_header(struct sk_buff *skb); |
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 662d1e86cfbf..d5890c84a492 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c | |||
@@ -59,6 +59,9 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) | |||
59 | xfrm4_rcv_encap_finish); | 59 | xfrm4_rcv_encap_finish); |
60 | return 0; | 60 | return 0; |
61 | #else | 61 | #else |
62 | if (async) | ||
63 | return xfrm4_rcv_encap_finish(skb); | ||
64 | |||
62 | return -iph->protocol; | 65 | return -iph->protocol; |
63 | #endif | 66 | #endif |
64 | } | 67 | } |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 5c006c845943..e317d0855468 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
@@ -41,6 +41,9 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) | |||
41 | ip6_rcv_finish); | 41 | ip6_rcv_finish); |
42 | return -1; | 42 | return -1; |
43 | #else | 43 | #else |
44 | if (async) | ||
45 | return ip6_rcv_finish(skb); | ||
46 | |||
44 | return 1; | 47 | return 1; |
45 | #endif | 48 | #endif |
46 | } | 49 | } |
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index cce9d4586045..96f42c1d2e8e 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -101,8 +101,17 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
101 | int err; | 101 | int err; |
102 | __be32 seq; | 102 | __be32 seq; |
103 | struct xfrm_state *x; | 103 | struct xfrm_state *x; |
104 | xfrm_address_t *daddr; | ||
104 | int decaps = 0; | 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 | /* Allocate new secpath or COW existing one. */ | 116 | /* Allocate new secpath or COW existing one. */ |
108 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { | 117 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { |
@@ -116,6 +125,9 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
116 | skb->sp = sp; | 125 | skb->sp = sp; |
117 | } | 126 | } |
118 | 127 | ||
128 | daddr = (xfrm_address_t *)(skb_network_header(skb) + | ||
129 | XFRM_SPI_SKB_CB(skb)->daddroff); | ||
130 | |||
119 | seq = 0; | 131 | seq = 0; |
120 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) | 132 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) |
121 | goto drop; | 133 | goto drop; |
@@ -124,9 +136,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
124 | if (skb->sp->len == XFRM_MAX_DEPTH) | 136 | if (skb->sp->len == XFRM_MAX_DEPTH) |
125 | goto drop; | 137 | goto drop; |
126 | 138 | ||
127 | x = xfrm_state_lookup((xfrm_address_t *) | 139 | x = xfrm_state_lookup(daddr, spi, nexthdr, AF_INET); |
128 | (skb_network_header(skb) + daddroff), | ||
129 | spi, nexthdr, AF_INET); | ||
130 | if (x == NULL) | 140 | if (x == NULL) |
131 | goto drop; | 141 | goto drop; |
132 | 142 | ||
@@ -147,8 +157,14 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
147 | 157 | ||
148 | spin_unlock(&x->lock); | 158 | spin_unlock(&x->lock); |
149 | 159 | ||
160 | XFRM_SKB_CB(skb)->seq = seq; | ||
161 | |||
150 | nexthdr = x->type->input(x, skb); | 162 | nexthdr = x->type->input(x, skb); |
151 | 163 | ||
164 | if (nexthdr == -EINPROGRESS) | ||
165 | return 0; | ||
166 | |||
167 | resume: | ||
152 | spin_lock(&x->lock); | 168 | spin_lock(&x->lock); |
153 | if (nexthdr <= 0) { | 169 | if (nexthdr <= 0) { |
154 | if (nexthdr == -EBADMSG) | 170 | if (nexthdr == -EBADMSG) |
@@ -177,6 +193,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
177 | break; | 193 | break; |
178 | } | 194 | } |
179 | 195 | ||
196 | /* | ||
197 | * We need the inner address. However, we only get here for | ||
198 | * transport mode so the outer address is identical. | ||
199 | */ | ||
200 | daddr = &x->id.daddr; | ||
201 | |||
180 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); | 202 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); |
181 | if (err < 0) | 203 | if (err < 0) |
182 | goto drop; | 204 | goto drop; |
@@ -190,7 +212,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
190 | netif_rx(skb); | 212 | netif_rx(skb); |
191 | return 0; | 213 | return 0; |
192 | } else { | 214 | } else { |
193 | return x->inner_mode->afinfo->transport_finish(skb, 0); | 215 | return x->inner_mode->afinfo->transport_finish(skb, async); |
194 | } | 216 | } |
195 | 217 | ||
196 | drop_unlock: | 218 | drop_unlock: |
@@ -201,6 +223,12 @@ drop: | |||
201 | } | 223 | } |
202 | EXPORT_SYMBOL(xfrm_input); | 224 | EXPORT_SYMBOL(xfrm_input); |
203 | 225 | ||
226 | int xfrm_input_resume(struct sk_buff *skb, int nexthdr) | ||
227 | { | ||
228 | return xfrm_input(skb, nexthdr, 0, -1); | ||
229 | } | ||
230 | EXPORT_SYMBOL(xfrm_input_resume); | ||
231 | |||
204 | void __init xfrm_input_init(void) | 232 | void __init xfrm_input_init(void) |
205 | { | 233 | { |
206 | secpath_cachep = kmem_cache_create("secpath_cache", | 234 | secpath_cachep = kmem_cache_create("secpath_cache", |