diff options
Diffstat (limited to 'net/ipv6/xfrm6_input.c')
-rw-r--r-- | net/ipv6/xfrm6_input.c | 118 |
1 files changed, 13 insertions, 105 deletions
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index c458d0a2e684..3b9eedf5b24a 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
@@ -23,118 +23,26 @@ int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb) | |||
23 | 23 | ||
24 | int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) | 24 | int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) |
25 | { | 25 | { |
26 | int err; | 26 | XFRM_SPI_SKB_CB(skb)->nhoff = IP6CB(skb)->nhoff; |
27 | __be32 seq; | 27 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); |
28 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; | 28 | return xfrm_input(skb, nexthdr, spi, 0); |
29 | struct xfrm_state *x; | 29 | } |
30 | int xfrm_nr = 0; | 30 | EXPORT_SYMBOL(xfrm6_rcv_spi); |
31 | int decaps = 0; | ||
32 | unsigned int nhoff; | ||
33 | |||
34 | nhoff = IP6CB(skb)->nhoff; | ||
35 | |||
36 | seq = 0; | ||
37 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) | ||
38 | goto drop; | ||
39 | |||
40 | do { | ||
41 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
42 | |||
43 | if (xfrm_nr == XFRM_MAX_DEPTH) | ||
44 | goto drop; | ||
45 | |||
46 | x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, | ||
47 | nexthdr, AF_INET6); | ||
48 | if (x == NULL) | ||
49 | goto drop; | ||
50 | spin_lock(&x->lock); | ||
51 | if (unlikely(x->km.state != XFRM_STATE_VALID)) | ||
52 | goto drop_unlock; | ||
53 | |||
54 | if (x->props.replay_window && xfrm_replay_check(x, seq)) | ||
55 | goto drop_unlock; | ||
56 | |||
57 | if (xfrm_state_check_expire(x)) | ||
58 | goto drop_unlock; | ||
59 | |||
60 | nexthdr = x->type->input(x, skb); | ||
61 | if (nexthdr <= 0) | ||
62 | goto drop_unlock; | ||
63 | |||
64 | skb_network_header(skb)[nhoff] = nexthdr; | ||
65 | |||
66 | if (x->props.replay_window) | ||
67 | xfrm_replay_advance(x, seq); | ||
68 | |||
69 | x->curlft.bytes += skb->len; | ||
70 | x->curlft.packets++; | ||
71 | |||
72 | spin_unlock(&x->lock); | ||
73 | |||
74 | xfrm_vec[xfrm_nr++] = x; | ||
75 | |||
76 | if (x->inner_mode->input(x, skb)) | ||
77 | goto drop; | ||
78 | |||
79 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { | ||
80 | decaps = 1; | ||
81 | break; | ||
82 | } | ||
83 | |||
84 | if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) | ||
85 | goto drop; | ||
86 | } while (!err); | ||
87 | |||
88 | /* Allocate new secpath or COW existing one. */ | ||
89 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { | ||
90 | struct sec_path *sp; | ||
91 | sp = secpath_dup(skb->sp); | ||
92 | if (!sp) | ||
93 | goto drop; | ||
94 | if (skb->sp) | ||
95 | secpath_put(skb->sp); | ||
96 | skb->sp = sp; | ||
97 | } | ||
98 | |||
99 | if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) | ||
100 | goto drop; | ||
101 | |||
102 | memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, | ||
103 | xfrm_nr * sizeof(xfrm_vec[0])); | ||
104 | skb->sp->len += xfrm_nr; | ||
105 | |||
106 | nf_reset(skb); | ||
107 | 31 | ||
108 | if (decaps) { | 32 | int xfrm6_transport_finish(struct sk_buff *skb, int async) |
109 | dst_release(skb->dst); | 33 | { |
110 | skb->dst = NULL; | ||
111 | netif_rx(skb); | ||
112 | return -1; | ||
113 | } else { | ||
114 | #ifdef CONFIG_NETFILTER | 34 | #ifdef CONFIG_NETFILTER |
115 | ipv6_hdr(skb)->payload_len = htons(skb->len); | 35 | ipv6_hdr(skb)->payload_len = htons(skb->len); |
116 | __skb_push(skb, skb->data - skb_network_header(skb)); | 36 | __skb_push(skb, skb->data - skb_network_header(skb)); |
117 | 37 | ||
118 | NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, | 38 | NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, |
119 | ip6_rcv_finish); | 39 | ip6_rcv_finish); |
120 | return -1; | 40 | return -1; |
121 | #else | 41 | #else |
122 | return 1; | 42 | return 1; |
123 | #endif | 43 | #endif |
124 | } | ||
125 | |||
126 | drop_unlock: | ||
127 | spin_unlock(&x->lock); | ||
128 | xfrm_state_put(x); | ||
129 | drop: | ||
130 | while (--xfrm_nr >= 0) | ||
131 | xfrm_state_put(xfrm_vec[xfrm_nr]); | ||
132 | kfree_skb(skb); | ||
133 | return -1; | ||
134 | } | 44 | } |
135 | 45 | ||
136 | EXPORT_SYMBOL(xfrm6_rcv_spi); | ||
137 | |||
138 | int xfrm6_rcv(struct sk_buff *skb) | 46 | int xfrm6_rcv(struct sk_buff *skb) |
139 | { | 47 | { |
140 | return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], | 48 | return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], |