X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=net%2Fxfrm%2Fxfrm_input.c;h=75279402ccf46f085f249cd65eda2a9e69db40a2;hb=ce97e13e52848c6388598696b7d44748598db759;hp=8b2b1b59133ec20e28e96dc83f1499aca6eafe31;hpb=2fcb45b6b87914f072314e5b5d9c196f45984683;p=linux-2.6-omap-h63xx.git diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 8b2b1b59133..75279402ccf 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -81,18 +81,24 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) *seq = *(__be32*)(skb_transport_header(skb) + offset_seq); return 0; } -EXPORT_SYMBOL(xfrm_parse_spi); int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) { + struct xfrm_mode *inner_mode = x->inner_mode; int err; err = x->outer_mode->afinfo->extract_input(x, skb); if (err) return err; - skb->protocol = x->inner_mode->afinfo->eth_proto; - return x->inner_mode->input2(x, skb); + if (x->sel.family == AF_UNSPEC) { + inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); + if (inner_mode == NULL) + return -EAFNOSUPPORT; + } + + skb->protocol = inner_mode->afinfo->eth_proto; + return inner_mode->input2(x, skb); } EXPORT_SYMBOL(xfrm_prepare_input); @@ -102,6 +108,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) __be32 seq; struct xfrm_state *x; xfrm_address_t *daddr; + struct xfrm_mode *inner_mode; unsigned int family; int decaps = 0; int async = 0; @@ -109,8 +116,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) /* A negative encap_type indicates async resumption. */ if (encap_type < 0) { async = 1; - x = skb->sp->xvec[skb->sp->len - 1]; - seq = XFRM_SKB_CB(skb)->seq; + x = xfrm_input_state(skb); + seq = XFRM_SKB_CB(skb)->seq.input; goto resume; } @@ -119,8 +126,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) struct sec_path *sp; sp = secpath_dup(skb->sp); - if (!sp) + if (!sp) { + XFRM_INC_STATS(LINUX_MIB_XFRMINERROR); goto drop; + } if (skb->sp) secpath_put(skb->sp); skb->sp = sp; @@ -131,35 +140,50 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) family = XFRM_SPI_SKB_CB(skb)->family; seq = 0; - if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) + if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { + XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); goto drop; + } do { - if (skb->sp->len == XFRM_MAX_DEPTH) + if (skb->sp->len == XFRM_MAX_DEPTH) { + XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR); goto drop; + } x = xfrm_state_lookup(daddr, spi, nexthdr, family); - if (x == NULL) + if (x == NULL) { + XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); + xfrm_audit_state_notfound(skb, family, spi, seq); goto drop; + } skb->sp->xvec[skb->sp->len++] = x; spin_lock(&x->lock); - if (unlikely(x->km.state != XFRM_STATE_VALID)) + if (unlikely(x->km.state != XFRM_STATE_VALID)) { + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID); goto drop_unlock; + } - if ((x->encap ? x->encap->encap_type : 0) != encap_type) + if ((x->encap ? x->encap->encap_type : 0) != encap_type) { + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMISMATCH); goto drop_unlock; + } - if (x->props.replay_window && xfrm_replay_check(x, seq)) + if (x->props.replay_window && xfrm_replay_check(x, skb, seq)) { + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATESEQERROR); goto drop_unlock; + } - if (xfrm_state_check_expire(x)) + if (xfrm_state_check_expire(x)) { + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEEXPIRED); goto drop_unlock; + } spin_unlock(&x->lock); - XFRM_SKB_CB(skb)->seq = seq; + XFRM_SKB_CB(skb)->seq.input = seq; nexthdr = x->type->input(x, skb); @@ -169,8 +193,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) resume: spin_lock(&x->lock); if (nexthdr <= 0) { - if (nexthdr == -EBADMSG) + if (nexthdr == -EBADMSG) { + xfrm_audit_state_icvfail(x, skb, + x->type->proto); x->stats.integrity_failed++; + } + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEPROTOERROR); goto drop_unlock; } @@ -187,8 +215,18 @@ resume: XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; - if (x->inner_mode->input(x, skb)) + inner_mode = x->inner_mode; + + if (x->sel.family == AF_UNSPEC) { + inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); + if (inner_mode == NULL) + goto drop; + } + + if (inner_mode->input(x, skb)) { + XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR); goto drop; + } if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { decaps = 1; @@ -203,8 +241,10 @@ resume: family = x->outer_mode->afinfo->family; err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); - if (err < 0) + if (err < 0) { + XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); goto drop; + } } while (!err); nf_reset(skb);