aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-11-14 00:44:23 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:53:50 -0500
commit716062fd4c2f88a33ab409f62a1e7397ad0a7e33 (patch)
tree73f2618fe99bca3870a0dbdc35acf6466ab3b976
parentc6581a457e661b7070e484ad723bbf555b17aca2 (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>
-rw-r--r--include/net/xfrm.h22
-rw-r--r--net/ipv4/xfrm4_input.c126
-rw-r--r--net/ipv4/xfrm4_state.c1
-rw-r--r--net/ipv6/xfrm6_input.c118
-rw-r--r--net/ipv6/xfrm6_state.c1
-rw-r--r--net/xfrm/xfrm_input.c113
6 files changed, 164 insertions, 217 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 99677207a4ce..329de412c0ba 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -274,6 +274,8 @@ struct xfrm_state_afinfo {
274 struct sk_buff *skb); 274 struct sk_buff *skb);
275 int (*extract_output)(struct xfrm_state *x, 275 int (*extract_output)(struct xfrm_state *x,
276 struct sk_buff *skb); 276 struct sk_buff *skb);
277 int (*transport_finish)(struct sk_buff *skb,
278 int async);
277}; 279};
278 280
279extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); 281extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
@@ -522,6 +524,22 @@ struct xfrm_mode_skb_cb {
522 524
523#define XFRM_MODE_SKB_CB(__skb) ((struct xfrm_mode_skb_cb *)&((__skb)->cb[0])) 525#define XFRM_MODE_SKB_CB(__skb) ((struct xfrm_mode_skb_cb *)&((__skb)->cb[0]))
524 526
527/*
528 * This structure is used by the input processing to locate the SPI and
529 * related information.
530 */
531struct xfrm_spi_skb_cb {
532 union {
533 struct inet_skb_parm h4;
534 struct inet6_skb_parm h6;
535 } header;
536
537 unsigned int nhoff;
538 unsigned int daddroff;
539};
540
541#define XFRM_SPI_SKB_CB(__skb) ((struct xfrm_spi_skb_cb *)&((__skb)->cb[0]))
542
525/* Audit Information */ 543/* Audit Information */
526struct xfrm_audit 544struct xfrm_audit
527{ 545{
@@ -1119,12 +1137,15 @@ extern void xfrm_replay_notify(struct xfrm_state *x, int event);
1119extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); 1137extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
1120extern int xfrm_init_state(struct xfrm_state *x); 1138extern int xfrm_init_state(struct xfrm_state *x);
1121extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); 1139extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb);
1140extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi,
1141 int encap_type);
1122extern int xfrm_output_resume(struct sk_buff *skb, int err); 1142extern int xfrm_output_resume(struct sk_buff *skb, int err);
1123extern int xfrm_output(struct sk_buff *skb); 1143extern int xfrm_output(struct sk_buff *skb);
1124extern int xfrm4_extract_header(struct sk_buff *skb); 1144extern int xfrm4_extract_header(struct sk_buff *skb);
1125extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); 1145extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb);
1126extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, 1146extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
1127 int encap_type); 1147 int encap_type);
1148extern int xfrm4_transport_finish(struct sk_buff *skb, int async);
1128extern int xfrm4_rcv(struct sk_buff *skb); 1149extern int xfrm4_rcv(struct sk_buff *skb);
1129 1150
1130static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) 1151static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
@@ -1140,6 +1161,7 @@ extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short f
1140extern int xfrm6_extract_header(struct sk_buff *skb); 1161extern int xfrm6_extract_header(struct sk_buff *skb);
1141extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); 1162extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
1142extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); 1163extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
1164extern int xfrm6_transport_finish(struct sk_buff *skb, int async);
1143extern int xfrm6_rcv(struct sk_buff *skb); 1165extern int xfrm6_rcv(struct sk_buff *skb);
1144extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 1166extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
1145 xfrm_address_t *saddr, u8 proto); 1167 xfrm_address_t *saddr, u8 proto);
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:
41int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, 41int 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; 48EXPORT_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) { 50int 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
151drop_unlock:
152 spin_unlock(&x->lock);
153 xfrm_state_put(x);
154drop:
155 while (--xfrm_nr >= 0)
156 xfrm_state_put(xfrm_vec[xfrm_nr]);
157
158 kfree_skb(skb);
159 return 0;
160} 63}
161EXPORT_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
79void __init xfrm4_state_init(void) 80void __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
24int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) 24int 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; 30EXPORT_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) { 32int 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
126drop_unlock:
127 spin_unlock(&x->lock);
128 xfrm_state_put(x);
129drop:
130 while (--xfrm_nr >= 0)
131 xfrm_state_put(xfrm_vec[xfrm_nr]);
132 kfree_skb(skb);
133 return -1;
134} 44}
135 45
136EXPORT_SYMBOL(xfrm6_rcv_spi);
137
138int xfrm6_rcv(struct sk_buff *skb) 46int 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
203void __init xfrm6_state_init(void) 204void __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}
95EXPORT_SYMBOL(xfrm_prepare_input); 97EXPORT_SYMBOL(xfrm_prepare_input);
96 98
99int 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
198drop_unlock:
199 spin_unlock(&x->lock);
200 xfrm_state_put(x);
201drop:
202 while (--xfrm_nr >= 0)
203 xfrm_state_put(xfrm_vec[xfrm_nr]);
204
205 kfree_skb(skb);
206 return 0;
207}
208EXPORT_SYMBOL(xfrm_input);
209
97void __init xfrm_input_init(void) 210void __init xfrm_input_init(void)
98{ 211{
99 secpath_cachep = kmem_cache_create("secpath_cache", 212 secpath_cachep = kmem_cache_create("secpath_cache",