diff options
Diffstat (limited to 'net/xfrm/xfrm_input.c')
-rw-r--r-- | net/xfrm/xfrm_input.c | 42 |
1 files changed, 15 insertions, 27 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index b980095be935..587f3474ed3d 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -100,19 +100,29 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) { int err; __be32 seq; - struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; struct xfrm_state *x; - int xfrm_nr = 0; int decaps = 0; unsigned int nhoff = XFRM_SPI_SKB_CB(skb)->nhoff; unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff; + /* Allocate new secpath or COW existing one. */ + if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { + struct sec_path *sp; + + sp = secpath_dup(skb->sp); + if (!sp) + goto drop; + if (skb->sp) + secpath_put(skb->sp); + skb->sp = sp; + } + seq = 0; if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) goto drop; do { - if (xfrm_nr == XFRM_MAX_DEPTH) + if (skb->sp->len == XFRM_MAX_DEPTH) goto drop; x = xfrm_state_lookup((xfrm_address_t *) @@ -121,6 +131,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (x == NULL) goto drop; + skb->sp->xvec[skb->sp->len++] = x; + spin_lock(&x->lock); if (unlikely(x->km.state != XFRM_STATE_VALID)) goto drop_unlock; @@ -151,8 +163,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_unlock(&x->lock); - xfrm_vec[xfrm_nr++] = x; - if (x->inner_mode->input(x, skb)) goto drop; @@ -166,24 +176,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) goto drop; } while (!err); - /* Allocate new secpath or COW existing one. */ - - if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { - struct sec_path *sp; - sp = secpath_dup(skb->sp); - if (!sp) - goto drop; - if (skb->sp) - secpath_put(skb->sp); - skb->sp = sp; - } - if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) - goto drop; - - memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, - xfrm_nr * sizeof(xfrm_vec[0])); - skb->sp->len += xfrm_nr; - nf_reset(skb); if (decaps) { @@ -197,11 +189,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) drop_unlock: spin_unlock(&x->lock); - xfrm_state_put(x); drop: - while (--xfrm_nr >= 0) - xfrm_state_put(xfrm_vec[xfrm_nr]); - kfree_skb(skb); return 0; } |