diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-11-14 00:44:23 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:53:50 -0500 |
commit | 716062fd4c2f88a33ab409f62a1e7397ad0a7e33 (patch) | |
tree | 73f2618fe99bca3870a0dbdc35acf6466ab3b976 /net | |
parent | c6581a457e661b7070e484ad723bbf555b17aca2 (diff) |
[IPSEC]: Merge most of the input path
As part of the work on asynchronous cryptographic operations, we need
to be able to resume from the spot where they occur. As such, it
helps if we isolate them to one spot.
This patch moves most of the remaining family-specific processing into
the common input code.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/xfrm4_input.c | 126 | ||||
-rw-r--r-- | net/ipv4/xfrm4_state.c | 1 | ||||
-rw-r--r-- | net/ipv6/xfrm6_input.c | 118 | ||||
-rw-r--r-- | net/ipv6/xfrm6_state.c | 1 | ||||
-rw-r--r-- | net/xfrm/xfrm_input.c | 113 |
5 files changed, 142 insertions, 217 deletions
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index c0323d05ab69..e374903dacdf 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c | |||
@@ -41,124 +41,26 @@ drop: | |||
41 | int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, | 41 | int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, |
42 | int encap_type) | 42 | int encap_type) |
43 | { | 43 | { |
44 | int err; | 44 | XFRM_SPI_SKB_CB(skb)->nhoff = offsetof(struct iphdr, protocol); |
45 | __be32 seq; | 45 | XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); |
46 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; | 46 | return xfrm_input(skb, nexthdr, spi, encap_type); |
47 | struct xfrm_state *x; | 47 | } |
48 | int xfrm_nr = 0; | 48 | EXPORT_SYMBOL(xfrm4_rcv_encap); |
49 | int decaps = 0; | ||
50 | unsigned int nhoff = offsetof(struct iphdr, protocol); | ||
51 | |||
52 | seq = 0; | ||
53 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) | ||
54 | goto drop; | ||
55 | |||
56 | do { | ||
57 | const struct iphdr *iph = ip_hdr(skb); | ||
58 | |||
59 | if (xfrm_nr == XFRM_MAX_DEPTH) | ||
60 | goto drop; | ||
61 | |||
62 | x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, | ||
63 | nexthdr, AF_INET); | ||
64 | if (x == NULL) | ||
65 | goto drop; | ||
66 | |||
67 | spin_lock(&x->lock); | ||
68 | if (unlikely(x->km.state != XFRM_STATE_VALID)) | ||
69 | goto drop_unlock; | ||
70 | |||
71 | if ((x->encap ? x->encap->encap_type : 0) != encap_type) | ||
72 | goto drop_unlock; | ||
73 | |||
74 | if (x->props.replay_window && xfrm_replay_check(x, seq)) | ||
75 | goto drop_unlock; | ||
76 | |||
77 | if (xfrm_state_check_expire(x)) | ||
78 | goto drop_unlock; | ||
79 | |||
80 | nexthdr = x->type->input(x, skb); | ||
81 | if (nexthdr <= 0) | ||
82 | goto drop_unlock; | ||
83 | |||
84 | skb_network_header(skb)[nhoff] = nexthdr; | ||
85 | |||
86 | /* only the first xfrm gets the encap type */ | ||
87 | encap_type = 0; | ||
88 | |||
89 | if (x->props.replay_window) | ||
90 | xfrm_replay_advance(x, seq); | ||
91 | |||
92 | x->curlft.bytes += skb->len; | ||
93 | x->curlft.packets++; | ||
94 | |||
95 | spin_unlock(&x->lock); | ||
96 | |||
97 | xfrm_vec[xfrm_nr++] = x; | ||
98 | |||
99 | if (x->inner_mode->input(x, skb)) | ||
100 | goto drop; | ||
101 | |||
102 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { | ||
103 | decaps = 1; | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); | ||
108 | if (err < 0) | ||
109 | goto drop; | ||
110 | } while (!err); | ||
111 | |||
112 | /* Allocate new secpath or COW existing one. */ | ||
113 | |||
114 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { | ||
115 | struct sec_path *sp; | ||
116 | sp = secpath_dup(skb->sp); | ||
117 | if (!sp) | ||
118 | goto drop; | ||
119 | if (skb->sp) | ||
120 | secpath_put(skb->sp); | ||
121 | skb->sp = sp; | ||
122 | } | ||
123 | if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) | ||
124 | goto drop; | ||
125 | |||
126 | memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, | ||
127 | xfrm_nr * sizeof(xfrm_vec[0])); | ||
128 | skb->sp->len += xfrm_nr; | ||
129 | |||
130 | nf_reset(skb); | ||
131 | 49 | ||
132 | if (decaps) { | 50 | int xfrm4_transport_finish(struct sk_buff *skb, int async) |
133 | dst_release(skb->dst); | 51 | { |
134 | skb->dst = NULL; | ||
135 | netif_rx(skb); | ||
136 | return 0; | ||
137 | } else { | ||
138 | #ifdef CONFIG_NETFILTER | 52 | #ifdef CONFIG_NETFILTER |
139 | __skb_push(skb, skb->data - skb_network_header(skb)); | 53 | __skb_push(skb, skb->data - skb_network_header(skb)); |
140 | ip_hdr(skb)->tot_len = htons(skb->len); | 54 | ip_hdr(skb)->tot_len = htons(skb->len); |
141 | ip_send_check(ip_hdr(skb)); | 55 | ip_send_check(ip_hdr(skb)); |
142 | 56 | ||
143 | NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, | 57 | NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, |
144 | xfrm4_rcv_encap_finish); | 58 | xfrm4_rcv_encap_finish); |
145 | return 0; | 59 | return 0; |
146 | #else | 60 | #else |
147 | return -ip_hdr(skb)->protocol; | 61 | return -ip_hdr(skb)->protocol; |
148 | #endif | 62 | #endif |
149 | } | ||
150 | |||
151 | drop_unlock: | ||
152 | spin_unlock(&x->lock); | ||
153 | xfrm_state_put(x); | ||
154 | drop: | ||
155 | while (--xfrm_nr >= 0) | ||
156 | xfrm_state_put(xfrm_vec[xfrm_nr]); | ||
157 | |||
158 | kfree_skb(skb); | ||
159 | return 0; | ||
160 | } | 63 | } |
161 | EXPORT_SYMBOL(xfrm4_rcv_encap); | ||
162 | 64 | ||
163 | /* If it's a keepalive packet, then just eat it. | 65 | /* If it's a keepalive packet, then just eat it. |
164 | * If it's an encapsulated packet, then pass it to the | 66 | * If it's an encapsulated packet, then pass it to the |
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 80292fbf221a..3b067e8b7bfe 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c | |||
@@ -74,6 +74,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = { | |||
74 | .output = xfrm4_output, | 74 | .output = xfrm4_output, |
75 | .extract_input = xfrm4_extract_input, | 75 | .extract_input = xfrm4_extract_input, |
76 | .extract_output = xfrm4_extract_output, | 76 | .extract_output = xfrm4_extract_output, |
77 | .transport_finish = xfrm4_transport_finish, | ||
77 | }; | 78 | }; |
78 | 79 | ||
79 | void __init xfrm4_state_init(void) | 80 | void __init xfrm4_state_init(void) |
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], |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index bb09e85a336d..00360b514e99 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
@@ -198,6 +198,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = { | |||
198 | .output = xfrm6_output, | 198 | .output = xfrm6_output, |
199 | .extract_input = xfrm6_extract_input, | 199 | .extract_input = xfrm6_extract_input, |
200 | .extract_output = xfrm6_extract_output, | 200 | .extract_output = xfrm6_extract_output, |
201 | .transport_finish = xfrm6_transport_finish, | ||
201 | }; | 202 | }; |
202 | 203 | ||
203 | void __init xfrm6_state_init(void) | 204 | void __init xfrm6_state_init(void) |
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", |