diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_input.c | 38 |
1 files changed, 33 insertions, 5 deletions
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", |