aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-05-28 02:06:13 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-18 00:28:41 -0400
commit31a4ab93025719e62e7cf7ce899f71c34ecde5a0 (patch)
tree60404c5fd1124882753b38e334656a15f8de0804
parentb59f45d0b2878ab76f8053b0973654e6621828ee (diff)
[IPSEC] proto: Move transport mode input path into xfrm_mode_transport
Now that we have xfrm_mode objects we can move the transport mode specific input decapsulation code into xfrm_mode_transport. This removes duplicate code as well as unnecessary header movement in case of tunnel mode SAs since we will discard the original IP header immediately. This also fixes a minor bug for transport-mode ESP where the IP payload length is set to the correct value minus the header length (with extension headers for IPv6). Of course the other neat thing is that we no longer have to allocate temporary buffers to hold the IP headers for ESP and IPComp. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/ah4.c15
-rw-r--r--net/ipv4/esp4.c18
-rw-r--r--net/ipv4/ipcomp.c23
-rw-r--r--net/ipv4/xfrm4_mode_transport.c14
-rw-r--r--net/ipv6/ah6.c10
-rw-r--r--net/ipv6/esp6.c20
-rw-r--r--net/ipv6/ipcomp6.c27
-rw-r--r--net/ipv6/xfrm6_mode_transport.c15
8 files changed, 59 insertions, 83 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index e2e4771fa4c6..c7782230080d 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -119,6 +119,7 @@ error:
119static int ah_input(struct xfrm_state *x, struct sk_buff *skb) 119static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
120{ 120{
121 int ah_hlen; 121 int ah_hlen;
122 int ihl;
122 struct iphdr *iph; 123 struct iphdr *iph;
123 struct ip_auth_hdr *ah; 124 struct ip_auth_hdr *ah;
124 struct ah_data *ahp; 125 struct ah_data *ahp;
@@ -149,13 +150,14 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
149 ah = (struct ip_auth_hdr*)skb->data; 150 ah = (struct ip_auth_hdr*)skb->data;
150 iph = skb->nh.iph; 151 iph = skb->nh.iph;
151 152
152 memcpy(work_buf, iph, iph->ihl*4); 153 ihl = skb->data - skb->nh.raw;
154 memcpy(work_buf, iph, ihl);
153 155
154 iph->ttl = 0; 156 iph->ttl = 0;
155 iph->tos = 0; 157 iph->tos = 0;
156 iph->frag_off = 0; 158 iph->frag_off = 0;
157 iph->check = 0; 159 iph->check = 0;
158 if (iph->ihl != 5) { 160 if (ihl > sizeof(*iph)) {
159 u32 dummy; 161 u32 dummy;
160 if (ip_clear_mutable_options(iph, &dummy)) 162 if (ip_clear_mutable_options(iph, &dummy))
161 goto out; 163 goto out;
@@ -164,7 +166,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
164 u8 auth_data[MAX_AH_AUTH_LEN]; 166 u8 auth_data[MAX_AH_AUTH_LEN];
165 167
166 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 168 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
167 skb_push(skb, skb->data - skb->nh.raw); 169 skb_push(skb, ihl);
168 ahp->icv(ahp, skb, ah->auth_data); 170 ahp->icv(ahp, skb, ah->auth_data);
169 if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { 171 if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
170 x->stats.integrity_failed++; 172 x->stats.integrity_failed++;
@@ -172,11 +174,8 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
172 } 174 }
173 } 175 }
174 ((struct iphdr*)work_buf)->protocol = ah->nexthdr; 176 ((struct iphdr*)work_buf)->protocol = ah->nexthdr;
175 skb->nh.raw = skb_pull(skb, ah_hlen); 177 skb->h.raw = memcpy(skb->nh.raw += ah_hlen, work_buf, ihl);
176 memcpy(skb->nh.raw, work_buf, iph->ihl*4); 178 __skb_pull(skb, ah_hlen + ihl);
177 skb->nh.iph->tot_len = htons(skb->len);
178 skb_pull(skb, skb->nh.iph->ihl*4);
179 skb->h.raw = skb->data;
180 179
181 return 0; 180 return 0;
182 181
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 9d1881c07a32..9bbdd4494551 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -143,10 +143,9 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
143 int alen = esp->auth.icv_trunc_len; 143 int alen = esp->auth.icv_trunc_len;
144 int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; 144 int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen;
145 int nfrags; 145 int nfrags;
146 int encap_len = 0; 146 int ihl;
147 u8 nexthdr[2]; 147 u8 nexthdr[2];
148 struct scatterlist *sg; 148 struct scatterlist *sg;
149 u8 workbuf[60];
150 int padlen; 149 int padlen;
151 150
152 if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) 151 if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr)))
@@ -177,7 +176,6 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
177 skb->ip_summed = CHECKSUM_NONE; 176 skb->ip_summed = CHECKSUM_NONE;
178 177
179 esph = (struct ip_esp_hdr*)skb->data; 178 esph = (struct ip_esp_hdr*)skb->data;
180 iph = skb->nh.iph;
181 179
182 /* Get ivec. This can be wrong, check against another impls. */ 180 /* Get ivec. This can be wrong, check against another impls. */
183 if (esp->conf.ivlen) 181 if (esp->conf.ivlen)
@@ -204,12 +202,12 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
204 202
205 /* ... check padding bits here. Silly. :-) */ 203 /* ... check padding bits here. Silly. :-) */
206 204
205 iph = skb->nh.iph;
206 ihl = iph->ihl * 4;
207
207 if (x->encap) { 208 if (x->encap) {
208 struct xfrm_encap_tmpl *encap = x->encap; 209 struct xfrm_encap_tmpl *encap = x->encap;
209 struct udphdr *uh; 210 struct udphdr *uh = (void *)(skb->nh.raw + ihl);
210
211 uh = (struct udphdr *)(iph + 1);
212 encap_len = (void*)esph - (void*)uh;
213 211
214 /* 212 /*
215 * 1) if the NAT-T peer's IP or port changed then 213 * 1) if the NAT-T peer's IP or port changed then
@@ -246,11 +244,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
246 244
247 iph->protocol = nexthdr[1]; 245 iph->protocol = nexthdr[1];
248 pskb_trim(skb, skb->len - alen - padlen - 2); 246 pskb_trim(skb, skb->len - alen - padlen - 2);
249 memcpy(workbuf, skb->nh.raw, iph->ihl*4); 247 skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - ihl;
250 skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen);
251 skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
252 memcpy(skb->nh.raw, workbuf, iph->ihl*4);
253 skb->nh.iph->tot_len = htons(skb->len);
254 248
255 return 0; 249 return 0;
256 250
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 95278b22b669..8e243589045f 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -45,7 +45,6 @@ static LIST_HEAD(ipcomp_tfms_list);
45static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb) 45static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
46{ 46{
47 int err, plen, dlen; 47 int err, plen, dlen;
48 struct iphdr *iph;
49 struct ipcomp_data *ipcd = x->data; 48 struct ipcomp_data *ipcd = x->data;
50 u8 *start, *scratch; 49 u8 *start, *scratch;
51 struct crypto_tfm *tfm; 50 struct crypto_tfm *tfm;
@@ -74,8 +73,6 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
74 73
75 skb_put(skb, dlen - plen); 74 skb_put(skb, dlen - plen);
76 memcpy(skb->data, scratch, dlen); 75 memcpy(skb->data, scratch, dlen);
77 iph = skb->nh.iph;
78 iph->tot_len = htons(dlen + iph->ihl * 4);
79out: 76out:
80 put_cpu(); 77 put_cpu();
81 return err; 78 return err;
@@ -83,14 +80,9 @@ out:
83 80
84static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb) 81static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
85{ 82{
86 u8 nexthdr;
87 int err = 0; 83 int err = 0;
88 struct iphdr *iph; 84 struct iphdr *iph;
89 union { 85 struct ip_comp_hdr *ipch;
90 struct iphdr iph;
91 char buf[60];
92 } tmp_iph;
93
94 86
95 if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && 87 if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
96 skb_linearize(skb, GFP_ATOMIC) != 0) { 88 skb_linearize(skb, GFP_ATOMIC) != 0) {
@@ -102,15 +94,10 @@ static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
102 94
103 /* Remove ipcomp header and decompress original payload */ 95 /* Remove ipcomp header and decompress original payload */
104 iph = skb->nh.iph; 96 iph = skb->nh.iph;
105 memcpy(&tmp_iph, iph, iph->ihl * 4); 97 ipch = (void *)skb->data;
106 nexthdr = *(u8 *)skb->data; 98 iph->protocol = ipch->nexthdr;
107 skb_pull(skb, sizeof(struct ip_comp_hdr)); 99 skb->h.raw = skb->nh.raw + sizeof(*ipch);
108 skb->nh.raw += sizeof(struct ip_comp_hdr); 100 __skb_pull(skb, sizeof(*ipch));
109 memcpy(skb->nh.raw, &tmp_iph, tmp_iph.iph.ihl * 4);
110 iph = skb->nh.iph;
111 iph->tot_len = htons(ntohs(iph->tot_len) - sizeof(struct ip_comp_hdr));
112 iph->protocol = nexthdr;
113 skb->h.raw = skb->data;
114 err = ipcomp_decompress(x, skb); 101 err = ipcomp_decompress(x, skb);
115 102
116out: 103out:
diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c
index e46d9a4ccc55..a9e6b3dd19c9 100644
--- a/net/ipv4/xfrm4_mode_transport.c
+++ b/net/ipv4/xfrm4_mode_transport.c
@@ -38,8 +38,22 @@ static int xfrm4_transport_output(struct sk_buff *skb)
38 return 0; 38 return 0;
39} 39}
40 40
41/* Remove encapsulation header.
42 *
43 * The IP header will be moved over the top of the encapsulation header.
44 *
45 * On entry, skb->h shall point to where the IP header should be and skb->nh
46 * shall be set to where the IP header currently is. skb->data shall point
47 * to the start of the payload.
48 */
41static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) 49static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)
42{ 50{
51 int ihl = skb->data - skb->h.raw;
52
53 if (skb->h.raw != skb->nh.raw)
54 skb->nh.raw = memmove(skb->h.raw, skb->nh.raw, ihl);
55 skb->nh.iph->tot_len = htons(skb->len + ihl);
56 skb->h.raw = skb->data;
43 return 0; 57 return 0;
44} 58}
45 59
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 6778173a3dda..d31c0d6c0448 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -292,7 +292,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
292 292
293 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 293 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
294 memset(ah->auth_data, 0, ahp->icv_trunc_len); 294 memset(ah->auth_data, 0, ahp->icv_trunc_len);
295 skb_push(skb, skb->data - skb->nh.raw); 295 skb_push(skb, hdr_len);
296 ahp->icv(ahp, skb, ah->auth_data); 296 ahp->icv(ahp, skb, ah->auth_data);
297 if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { 297 if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
298 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); 298 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");
@@ -301,12 +301,8 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
301 } 301 }
302 } 302 }
303 303
304 skb->nh.raw = skb_pull(skb, ah_hlen); 304 skb->h.raw = memcpy(skb->nh.raw += ah_hlen, tmp_hdr, hdr_len);
305 memcpy(skb->nh.raw, tmp_hdr, hdr_len); 305 __skb_pull(skb, ah_hlen + hdr_len);
306 skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
307 skb_pull(skb, hdr_len);
308 skb->h.raw = skb->data;
309
310 306
311 kfree(tmp_hdr); 307 kfree(tmp_hdr);
312 308
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 22f046079037..a15a6f320f70 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -142,25 +142,17 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
142 142
143 int hdr_len = skb->h.raw - skb->nh.raw; 143 int hdr_len = skb->h.raw - skb->nh.raw;
144 int nfrags; 144 int nfrags;
145 unsigned char *tmp_hdr = NULL;
146 int ret = 0; 145 int ret = 0;
147 146
148 if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) { 147 if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) {
149 ret = -EINVAL; 148 ret = -EINVAL;
150 goto out_nofree; 149 goto out;
151 } 150 }
152 151
153 if (elen <= 0 || (elen & (blksize-1))) { 152 if (elen <= 0 || (elen & (blksize-1))) {
154 ret = -EINVAL; 153 ret = -EINVAL;
155 goto out_nofree; 154 goto out;
156 }
157
158 tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
159 if (!tmp_hdr) {
160 ret = -ENOMEM;
161 goto out_nofree;
162 } 155 }
163 memcpy(tmp_hdr, skb->nh.raw, hdr_len);
164 156
165 /* If integrity check is required, do this. */ 157 /* If integrity check is required, do this. */
166 if (esp->auth.icv_full_len) { 158 if (esp->auth.icv_full_len) {
@@ -222,16 +214,12 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
222 /* ... check padding bits here. Silly. :-) */ 214 /* ... check padding bits here. Silly. :-) */
223 215
224 pskb_trim(skb, skb->len - alen - padlen - 2); 216 pskb_trim(skb, skb->len - alen - padlen - 2);
225 skb->h.raw = skb_pull(skb, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen);
226 skb->nh.raw += sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen;
227 memcpy(skb->nh.raw, tmp_hdr, hdr_len);
228 skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
229 ret = nexthdr[1]; 217 ret = nexthdr[1];
230 } 218 }
231 219
220 skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - hdr_len;
221
232out: 222out:
233 kfree(tmp_hdr);
234out_nofree:
235 return ret; 223 return ret;
236} 224}
237 225
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 48636436028a..cec3be544b69 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -66,10 +66,8 @@ static LIST_HEAD(ipcomp6_tfms_list);
66static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) 66static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
67{ 67{
68 int err = 0; 68 int err = 0;
69 u8 nexthdr = 0;
70 int hdr_len = skb->h.raw - skb->nh.raw;
71 unsigned char *tmp_hdr = NULL;
72 struct ipv6hdr *iph; 69 struct ipv6hdr *iph;
70 struct ipv6_comp_hdr *ipch;
73 int plen, dlen; 71 int plen, dlen;
74 struct ipcomp_data *ipcd = x->data; 72 struct ipcomp_data *ipcd = x->data;
75 u8 *start, *scratch; 73 u8 *start, *scratch;
@@ -86,17 +84,9 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
86 84
87 /* Remove ipcomp header and decompress original payload */ 85 /* Remove ipcomp header and decompress original payload */
88 iph = skb->nh.ipv6h; 86 iph = skb->nh.ipv6h;
89 tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC); 87 ipch = (void *)skb->data;
90 if (!tmp_hdr) 88 skb->h.raw = skb->nh.raw + sizeof(*ipch);
91 goto out; 89 __skb_pull(skb, sizeof(*ipch));
92 memcpy(tmp_hdr, iph, hdr_len);
93 nexthdr = *(u8 *)skb->data;
94 skb_pull(skb, sizeof(struct ipv6_comp_hdr));
95 skb->nh.raw += sizeof(struct ipv6_comp_hdr);
96 memcpy(skb->nh.raw, tmp_hdr, hdr_len);
97 iph = skb->nh.ipv6h;
98 iph->payload_len = htons(ntohs(iph->payload_len) - sizeof(struct ipv6_comp_hdr));
99 skb->h.raw = skb->data;
100 90
101 /* decompression */ 91 /* decompression */
102 plen = skb->len; 92 plen = skb->len;
@@ -125,18 +115,11 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
125 115
126 skb_put(skb, dlen - plen); 116 skb_put(skb, dlen - plen);
127 memcpy(skb->data, scratch, dlen); 117 memcpy(skb->data, scratch, dlen);
118 err = ipch->nexthdr;
128 119
129 iph = skb->nh.ipv6h;
130 iph->payload_len = htons(skb->len);
131
132out_put_cpu: 120out_put_cpu:
133 put_cpu(); 121 put_cpu();
134out: 122out:
135 kfree(tmp_hdr);
136 if (err)
137 goto error_out;
138 return nexthdr;
139error_out:
140 return err; 123 return err;
141} 124}
142 125
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c
index 5efbbae08ef0..711d713e36d8 100644
--- a/net/ipv6/xfrm6_mode_transport.c
+++ b/net/ipv6/xfrm6_mode_transport.c
@@ -42,8 +42,23 @@ static int xfrm6_transport_output(struct sk_buff *skb)
42 return 0; 42 return 0;
43} 43}
44 44
45/* Remove encapsulation header.
46 *
47 * The IP header will be moved over the top of the encapsulation header.
48 *
49 * On entry, skb->h shall point to where the IP header should be and skb->nh
50 * shall be set to where the IP header currently is. skb->data shall point
51 * to the start of the payload.
52 */
45static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) 53static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
46{ 54{
55 int ihl = skb->data - skb->h.raw;
56
57 if (skb->h.raw != skb->nh.raw)
58 skb->nh.raw = memmove(skb->h.raw, skb->nh.raw, ihl);
59 skb->nh.ipv6h->payload_len = htons(skb->len + ihl -
60 sizeof(struct ipv6hdr));
61 skb->h.raw = skb->data;
47 return 0; 62 return 0;
48} 63}
49 64