diff options
Diffstat (limited to 'net/xfrm/xfrm_input.c')
-rw-r--r-- | net/xfrm/xfrm_input.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 4c803f7e74e5..b980095be935 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -9,6 +9,8 @@ | |||
9 | 9 | ||
10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/netdevice.h> | ||
13 | #include <net/dst.h> | ||
12 | #include <net/ip.h> | 14 | #include <net/ip.h> |
13 | #include <net/xfrm.h> | 15 | #include <net/xfrm.h> |
14 | 16 | ||
@@ -94,6 +96,117 @@ int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) | |||
94 | } | 96 | } |
95 | EXPORT_SYMBOL(xfrm_prepare_input); | 97 | EXPORT_SYMBOL(xfrm_prepare_input); |
96 | 98 | ||
99 | int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | ||
100 | { | ||
101 | int err; | ||
102 | __be32 seq; | ||
103 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; | ||
104 | struct xfrm_state *x; | ||
105 | int xfrm_nr = 0; | ||
106 | int decaps = 0; | ||
107 | unsigned int nhoff = XFRM_SPI_SKB_CB(skb)->nhoff; | ||
108 | unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff; | ||
109 | |||
110 | seq = 0; | ||
111 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) | ||
112 | goto drop; | ||
113 | |||
114 | do { | ||
115 | if (xfrm_nr == XFRM_MAX_DEPTH) | ||
116 | goto drop; | ||
117 | |||
118 | x = xfrm_state_lookup((xfrm_address_t *) | ||
119 | (skb_network_header(skb) + daddroff), | ||
120 | spi, nexthdr, AF_INET); | ||
121 | if (x == NULL) | ||
122 | goto drop; | ||
123 | |||
124 | spin_lock(&x->lock); | ||
125 | if (unlikely(x->km.state != XFRM_STATE_VALID)) | ||
126 | goto drop_unlock; | ||
127 | |||
128 | if ((x->encap ? x->encap->encap_type : 0) != encap_type) | ||
129 | goto drop_unlock; | ||
130 | |||
131 | if (x->props.replay_window && xfrm_replay_check(x, seq)) | ||
132 | goto drop_unlock; | ||
133 | |||
134 | if (xfrm_state_check_expire(x)) | ||
135 | goto drop_unlock; | ||
136 | |||
137 | nexthdr = x->type->input(x, skb); | ||
138 | if (nexthdr <= 0) | ||
139 | goto drop_unlock; | ||
140 | |||
141 | skb_network_header(skb)[nhoff] = nexthdr; | ||
142 | |||
143 | /* only the first xfrm gets the encap type */ | ||
144 | encap_type = 0; | ||
145 | |||
146 | if (x->props.replay_window) | ||
147 | xfrm_replay_advance(x, seq); | ||
148 | |||
149 | x->curlft.bytes += skb->len; | ||
150 | x->curlft.packets++; | ||
151 | |||
152 | spin_unlock(&x->lock); | ||
153 | |||
154 | xfrm_vec[xfrm_nr++] = x; | ||
155 | |||
156 | if (x->inner_mode->input(x, skb)) | ||
157 | goto drop; | ||
158 | |||
159 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { | ||
160 | decaps = 1; | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); | ||
165 | if (err < 0) | ||
166 | goto drop; | ||
167 | } while (!err); | ||
168 | |||
169 | /* Allocate new secpath or COW existing one. */ | ||
170 | |||
171 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { | ||
172 | struct sec_path *sp; | ||
173 | sp = secpath_dup(skb->sp); | ||
174 | if (!sp) | ||
175 | goto drop; | ||
176 | if (skb->sp) | ||
177 | secpath_put(skb->sp); | ||
178 | skb->sp = sp; | ||
179 | } | ||
180 | if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) | ||
181 | goto drop; | ||
182 | |||
183 | memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, | ||
184 | xfrm_nr * sizeof(xfrm_vec[0])); | ||
185 | skb->sp->len += xfrm_nr; | ||
186 | |||
187 | nf_reset(skb); | ||
188 | |||
189 | if (decaps) { | ||
190 | dst_release(skb->dst); | ||
191 | skb->dst = NULL; | ||
192 | netif_rx(skb); | ||
193 | return 0; | ||
194 | } else { | ||
195 | return x->inner_mode->afinfo->transport_finish(skb, 0); | ||
196 | } | ||
197 | |||
198 | drop_unlock: | ||
199 | spin_unlock(&x->lock); | ||
200 | xfrm_state_put(x); | ||
201 | drop: | ||
202 | while (--xfrm_nr >= 0) | ||
203 | xfrm_state_put(xfrm_vec[xfrm_nr]); | ||
204 | |||
205 | kfree_skb(skb); | ||
206 | return 0; | ||
207 | } | ||
208 | EXPORT_SYMBOL(xfrm_input); | ||
209 | |||
97 | void __init xfrm_input_init(void) | 210 | void __init xfrm_input_init(void) |
98 | { | 211 | { |
99 | secpath_cachep = kmem_cache_create("secpath_cache", | 212 | secpath_cachep = kmem_cache_create("secpath_cache", |