diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 10:55:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 10:55:01 -0500 |
commit | d7fc02c7bae7b1cf69269992cf880a43a350cdaa (patch) | |
tree | a43d56fa72913a1cc98a0bbebe054d08581b3a7c /net/xfrm | |
parent | ee1262dbc65ce0b6234a915d8432171e8d77f518 (diff) | |
parent | 28b4d5cc17c20786848cdc07b7ea237a309776bb (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1815 commits)
mac80211: fix reorder buffer release
iwmc3200wifi: Enable wimax core through module parameter
iwmc3200wifi: Add wifi-wimax coexistence mode as a module parameter
iwmc3200wifi: Coex table command does not expect a response
iwmc3200wifi: Update wiwi priority table
iwlwifi: driver version track kernel version
iwlwifi: indicate uCode type when fail dump error/event log
iwl3945: remove duplicated event logging code
b43: fix two warnings
ipw2100: fix rebooting hang with driver loaded
cfg80211: indent regulatory messages with spaces
iwmc3200wifi: fix NULL pointer dereference in pmkid update
mac80211: Fix TX status reporting for injected data frames
ath9k: enable 2GHz band only if the device supports it
airo: Fix integer overflow warning
rt2x00: Fix padding bug on L2PAD devices.
WE: Fix set events not propagated
b43legacy: avoid PPC fault during resume
b43: avoid PPC fault during resume
tcp: fix a timewait refcnt race
...
Fix up conflicts due to sysctl cleanups (dead sysctl_check code and
CTL_UNNUMBERED removed) in
kernel/sysctl_check.c
net/ipv4/sysctl_net_ipv4.c
net/ipv6/addrconf.c
net/sctp/sysctl.c
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_algo.c | 113 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 32 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 147 |
3 files changed, 184 insertions, 108 deletions
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index faf54c6bf96b..743c0134a6a9 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c | |||
@@ -200,6 +200,40 @@ static struct xfrm_algo_desc aalg_list[] = { | |||
200 | } | 200 | } |
201 | }, | 201 | }, |
202 | { | 202 | { |
203 | .name = "hmac(sha384)", | ||
204 | |||
205 | .uinfo = { | ||
206 | .auth = { | ||
207 | .icv_truncbits = 192, | ||
208 | .icv_fullbits = 384, | ||
209 | } | ||
210 | }, | ||
211 | |||
212 | .desc = { | ||
213 | .sadb_alg_id = SADB_X_AALG_SHA2_384HMAC, | ||
214 | .sadb_alg_ivlen = 0, | ||
215 | .sadb_alg_minbits = 384, | ||
216 | .sadb_alg_maxbits = 384 | ||
217 | } | ||
218 | }, | ||
219 | { | ||
220 | .name = "hmac(sha512)", | ||
221 | |||
222 | .uinfo = { | ||
223 | .auth = { | ||
224 | .icv_truncbits = 256, | ||
225 | .icv_fullbits = 512, | ||
226 | } | ||
227 | }, | ||
228 | |||
229 | .desc = { | ||
230 | .sadb_alg_id = SADB_X_AALG_SHA2_512HMAC, | ||
231 | .sadb_alg_ivlen = 0, | ||
232 | .sadb_alg_minbits = 512, | ||
233 | .sadb_alg_maxbits = 512 | ||
234 | } | ||
235 | }, | ||
236 | { | ||
203 | .name = "hmac(rmd160)", | 237 | .name = "hmac(rmd160)", |
204 | .compat = "rmd160", | 238 | .compat = "rmd160", |
205 | 239 | ||
@@ -365,6 +399,7 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
365 | }, | 399 | }, |
366 | { | 400 | { |
367 | .name = "cbc(camellia)", | 401 | .name = "cbc(camellia)", |
402 | .compat = "camellia", | ||
368 | 403 | ||
369 | .uinfo = { | 404 | .uinfo = { |
370 | .encr = { | 405 | .encr = { |
@@ -689,84 +724,6 @@ int xfrm_count_enc_supported(void) | |||
689 | } | 724 | } |
690 | EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); | 725 | EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); |
691 | 726 | ||
692 | /* Move to common area: it is shared with AH. */ | ||
693 | |||
694 | int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, | ||
695 | int offset, int len, icv_update_fn_t icv_update) | ||
696 | { | ||
697 | int start = skb_headlen(skb); | ||
698 | int i, copy = start - offset; | ||
699 | struct sk_buff *frag_iter; | ||
700 | struct scatterlist sg; | ||
701 | int err; | ||
702 | |||
703 | /* Checksum header. */ | ||
704 | if (copy > 0) { | ||
705 | if (copy > len) | ||
706 | copy = len; | ||
707 | |||
708 | sg_init_one(&sg, skb->data + offset, copy); | ||
709 | |||
710 | err = icv_update(desc, &sg, copy); | ||
711 | if (unlikely(err)) | ||
712 | return err; | ||
713 | |||
714 | if ((len -= copy) == 0) | ||
715 | return 0; | ||
716 | offset += copy; | ||
717 | } | ||
718 | |||
719 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | ||
720 | int end; | ||
721 | |||
722 | WARN_ON(start > offset + len); | ||
723 | |||
724 | end = start + skb_shinfo(skb)->frags[i].size; | ||
725 | if ((copy = end - offset) > 0) { | ||
726 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | ||
727 | |||
728 | if (copy > len) | ||
729 | copy = len; | ||
730 | |||
731 | sg_init_table(&sg, 1); | ||
732 | sg_set_page(&sg, frag->page, copy, | ||
733 | frag->page_offset + offset-start); | ||
734 | |||
735 | err = icv_update(desc, &sg, copy); | ||
736 | if (unlikely(err)) | ||
737 | return err; | ||
738 | |||
739 | if (!(len -= copy)) | ||
740 | return 0; | ||
741 | offset += copy; | ||
742 | } | ||
743 | start = end; | ||
744 | } | ||
745 | |||
746 | skb_walk_frags(skb, frag_iter) { | ||
747 | int end; | ||
748 | |||
749 | WARN_ON(start > offset + len); | ||
750 | |||
751 | end = start + frag_iter->len; | ||
752 | if ((copy = end - offset) > 0) { | ||
753 | if (copy > len) | ||
754 | copy = len; | ||
755 | err = skb_icv_walk(frag_iter, desc, offset-start, | ||
756 | copy, icv_update); | ||
757 | if (unlikely(err)) | ||
758 | return err; | ||
759 | if ((len -= copy) == 0) | ||
760 | return 0; | ||
761 | offset += copy; | ||
762 | } | ||
763 | start = end; | ||
764 | } | ||
765 | BUG_ON(len); | ||
766 | return 0; | ||
767 | } | ||
768 | EXPORT_SYMBOL_GPL(skb_icv_walk); | ||
769 | |||
770 | #if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) | 727 | #if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) |
771 | 728 | ||
772 | void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) | 729 | void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index f2f7c638083e..d847f1a52b44 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #include <linux/cache.h> | 21 | #include <linux/cache.h> |
22 | #include <linux/audit.h> | 22 | #include <linux/audit.h> |
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <linux/ktime.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/kernel.h> | ||
24 | 27 | ||
25 | #include "xfrm_hash.h" | 28 | #include "xfrm_hash.h" |
26 | 29 | ||
@@ -352,7 +355,7 @@ static void xfrm_put_mode(struct xfrm_mode *mode) | |||
352 | 355 | ||
353 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 356 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
354 | { | 357 | { |
355 | del_timer_sync(&x->timer); | 358 | tasklet_hrtimer_cancel(&x->mtimer); |
356 | del_timer_sync(&x->rtimer); | 359 | del_timer_sync(&x->rtimer); |
357 | kfree(x->aalg); | 360 | kfree(x->aalg); |
358 | kfree(x->ealg); | 361 | kfree(x->ealg); |
@@ -398,9 +401,10 @@ static inline unsigned long make_jiffies(long secs) | |||
398 | return secs*HZ; | 401 | return secs*HZ; |
399 | } | 402 | } |
400 | 403 | ||
401 | static void xfrm_timer_handler(unsigned long data) | 404 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me) |
402 | { | 405 | { |
403 | struct xfrm_state *x = (struct xfrm_state*)data; | 406 | struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); |
407 | struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); | ||
404 | struct net *net = xs_net(x); | 408 | struct net *net = xs_net(x); |
405 | unsigned long now = get_seconds(); | 409 | unsigned long now = get_seconds(); |
406 | long next = LONG_MAX; | 410 | long next = LONG_MAX; |
@@ -451,8 +455,9 @@ static void xfrm_timer_handler(unsigned long data) | |||
451 | if (warn) | 455 | if (warn) |
452 | km_state_expired(x, 0, 0); | 456 | km_state_expired(x, 0, 0); |
453 | resched: | 457 | resched: |
454 | if (next != LONG_MAX) | 458 | if (next != LONG_MAX){ |
455 | mod_timer(&x->timer, jiffies + make_jiffies(next)); | 459 | tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL); |
460 | } | ||
456 | 461 | ||
457 | goto out; | 462 | goto out; |
458 | 463 | ||
@@ -474,6 +479,7 @@ expired: | |||
474 | 479 | ||
475 | out: | 480 | out: |
476 | spin_unlock(&x->lock); | 481 | spin_unlock(&x->lock); |
482 | return HRTIMER_NORESTART; | ||
477 | } | 483 | } |
478 | 484 | ||
479 | static void xfrm_replay_timer_handler(unsigned long data); | 485 | static void xfrm_replay_timer_handler(unsigned long data); |
@@ -492,7 +498,7 @@ struct xfrm_state *xfrm_state_alloc(struct net *net) | |||
492 | INIT_HLIST_NODE(&x->bydst); | 498 | INIT_HLIST_NODE(&x->bydst); |
493 | INIT_HLIST_NODE(&x->bysrc); | 499 | INIT_HLIST_NODE(&x->bysrc); |
494 | INIT_HLIST_NODE(&x->byspi); | 500 | INIT_HLIST_NODE(&x->byspi); |
495 | setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x); | 501 | tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler, CLOCK_REALTIME, HRTIMER_MODE_ABS); |
496 | setup_timer(&x->rtimer, xfrm_replay_timer_handler, | 502 | setup_timer(&x->rtimer, xfrm_replay_timer_handler, |
497 | (unsigned long)x); | 503 | (unsigned long)x); |
498 | x->curlft.add_time = get_seconds(); | 504 | x->curlft.add_time = get_seconds(); |
@@ -843,8 +849,7 @@ found: | |||
843 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); | 849 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); |
844 | } | 850 | } |
845 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 851 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
846 | x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; | 852 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
847 | add_timer(&x->timer); | ||
848 | net->xfrm.state_num++; | 853 | net->xfrm.state_num++; |
849 | xfrm_hash_grow_check(net, x->bydst.next != NULL); | 854 | xfrm_hash_grow_check(net, x->bydst.next != NULL); |
850 | } else { | 855 | } else { |
@@ -921,7 +926,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
921 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); | 926 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); |
922 | } | 927 | } |
923 | 928 | ||
924 | mod_timer(&x->timer, jiffies + HZ); | 929 | tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); |
925 | if (x->replay_maxage) | 930 | if (x->replay_maxage) |
926 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); | 931 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); |
927 | 932 | ||
@@ -1019,8 +1024,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
1019 | x->props.reqid = reqid; | 1024 | x->props.reqid = reqid; |
1020 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 1025 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
1021 | xfrm_state_hold(x); | 1026 | xfrm_state_hold(x); |
1022 | x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; | 1027 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
1023 | add_timer(&x->timer); | ||
1024 | list_add(&x->km.all, &net->xfrm.state_all); | 1028 | list_add(&x->km.all, &net->xfrm.state_all); |
1025 | hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); | 1029 | hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); |
1026 | h = xfrm_src_hash(net, daddr, saddr, family); | 1030 | h = xfrm_src_hash(net, daddr, saddr, family); |
@@ -1110,7 +1114,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1110 | x->props.saddr = orig->props.saddr; | 1114 | x->props.saddr = orig->props.saddr; |
1111 | 1115 | ||
1112 | if (orig->aalg) { | 1116 | if (orig->aalg) { |
1113 | x->aalg = xfrm_algo_clone(orig->aalg); | 1117 | x->aalg = xfrm_algo_auth_clone(orig->aalg); |
1114 | if (!x->aalg) | 1118 | if (!x->aalg) |
1115 | goto error; | 1119 | goto error; |
1116 | } | 1120 | } |
@@ -1300,7 +1304,7 @@ out: | |||
1300 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); | 1304 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); |
1301 | x1->km.dying = 0; | 1305 | x1->km.dying = 0; |
1302 | 1306 | ||
1303 | mod_timer(&x1->timer, jiffies + HZ); | 1307 | tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); |
1304 | if (x1->curlft.use_time) | 1308 | if (x1->curlft.use_time) |
1305 | xfrm_state_check_expire(x1); | 1309 | xfrm_state_check_expire(x1); |
1306 | 1310 | ||
@@ -1325,7 +1329,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
1325 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 1329 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
1326 | x->curlft.packets >= x->lft.hard_packet_limit) { | 1330 | x->curlft.packets >= x->lft.hard_packet_limit) { |
1327 | x->km.state = XFRM_STATE_EXPIRED; | 1331 | x->km.state = XFRM_STATE_EXPIRED; |
1328 | mod_timer(&x->timer, jiffies); | 1332 | tasklet_hrtimer_start(&x->mtimer, ktime_set(0,0), HRTIMER_MODE_REL); |
1329 | return -EINVAL; | 1333 | return -EINVAL; |
1330 | } | 1334 | } |
1331 | 1335 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index b95a2d64eb59..1ada6186933c 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -62,6 +62,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) | |||
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | 64 | ||
65 | static int verify_auth_trunc(struct nlattr **attrs) | ||
66 | { | ||
67 | struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC]; | ||
68 | struct xfrm_algo_auth *algp; | ||
69 | |||
70 | if (!rt) | ||
71 | return 0; | ||
72 | |||
73 | algp = nla_data(rt); | ||
74 | if (nla_len(rt) < xfrm_alg_auth_len(algp)) | ||
75 | return -EINVAL; | ||
76 | |||
77 | algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; | ||
78 | return 0; | ||
79 | } | ||
80 | |||
65 | static int verify_aead(struct nlattr **attrs) | 81 | static int verify_aead(struct nlattr **attrs) |
66 | { | 82 | { |
67 | struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; | 83 | struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; |
@@ -128,7 +144,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
128 | err = -EINVAL; | 144 | err = -EINVAL; |
129 | switch (p->id.proto) { | 145 | switch (p->id.proto) { |
130 | case IPPROTO_AH: | 146 | case IPPROTO_AH: |
131 | if (!attrs[XFRMA_ALG_AUTH] || | 147 | if ((!attrs[XFRMA_ALG_AUTH] && |
148 | !attrs[XFRMA_ALG_AUTH_TRUNC]) || | ||
132 | attrs[XFRMA_ALG_AEAD] || | 149 | attrs[XFRMA_ALG_AEAD] || |
133 | attrs[XFRMA_ALG_CRYPT] || | 150 | attrs[XFRMA_ALG_CRYPT] || |
134 | attrs[XFRMA_ALG_COMP]) | 151 | attrs[XFRMA_ALG_COMP]) |
@@ -139,10 +156,12 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
139 | if (attrs[XFRMA_ALG_COMP]) | 156 | if (attrs[XFRMA_ALG_COMP]) |
140 | goto out; | 157 | goto out; |
141 | if (!attrs[XFRMA_ALG_AUTH] && | 158 | if (!attrs[XFRMA_ALG_AUTH] && |
159 | !attrs[XFRMA_ALG_AUTH_TRUNC] && | ||
142 | !attrs[XFRMA_ALG_CRYPT] && | 160 | !attrs[XFRMA_ALG_CRYPT] && |
143 | !attrs[XFRMA_ALG_AEAD]) | 161 | !attrs[XFRMA_ALG_AEAD]) |
144 | goto out; | 162 | goto out; |
145 | if ((attrs[XFRMA_ALG_AUTH] || | 163 | if ((attrs[XFRMA_ALG_AUTH] || |
164 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
146 | attrs[XFRMA_ALG_CRYPT]) && | 165 | attrs[XFRMA_ALG_CRYPT]) && |
147 | attrs[XFRMA_ALG_AEAD]) | 166 | attrs[XFRMA_ALG_AEAD]) |
148 | goto out; | 167 | goto out; |
@@ -152,6 +171,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
152 | if (!attrs[XFRMA_ALG_COMP] || | 171 | if (!attrs[XFRMA_ALG_COMP] || |
153 | attrs[XFRMA_ALG_AEAD] || | 172 | attrs[XFRMA_ALG_AEAD] || |
154 | attrs[XFRMA_ALG_AUTH] || | 173 | attrs[XFRMA_ALG_AUTH] || |
174 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
155 | attrs[XFRMA_ALG_CRYPT]) | 175 | attrs[XFRMA_ALG_CRYPT]) |
156 | goto out; | 176 | goto out; |
157 | break; | 177 | break; |
@@ -161,6 +181,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
161 | case IPPROTO_ROUTING: | 181 | case IPPROTO_ROUTING: |
162 | if (attrs[XFRMA_ALG_COMP] || | 182 | if (attrs[XFRMA_ALG_COMP] || |
163 | attrs[XFRMA_ALG_AUTH] || | 183 | attrs[XFRMA_ALG_AUTH] || |
184 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
164 | attrs[XFRMA_ALG_AEAD] || | 185 | attrs[XFRMA_ALG_AEAD] || |
165 | attrs[XFRMA_ALG_CRYPT] || | 186 | attrs[XFRMA_ALG_CRYPT] || |
166 | attrs[XFRMA_ENCAP] || | 187 | attrs[XFRMA_ENCAP] || |
@@ -176,6 +197,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
176 | 197 | ||
177 | if ((err = verify_aead(attrs))) | 198 | if ((err = verify_aead(attrs))) |
178 | goto out; | 199 | goto out; |
200 | if ((err = verify_auth_trunc(attrs))) | ||
201 | goto out; | ||
179 | if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) | 202 | if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) |
180 | goto out; | 203 | goto out; |
181 | if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) | 204 | if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) |
@@ -229,6 +252,66 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, | |||
229 | return 0; | 252 | return 0; |
230 | } | 253 | } |
231 | 254 | ||
255 | static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props, | ||
256 | struct nlattr *rta) | ||
257 | { | ||
258 | struct xfrm_algo *ualg; | ||
259 | struct xfrm_algo_auth *p; | ||
260 | struct xfrm_algo_desc *algo; | ||
261 | |||
262 | if (!rta) | ||
263 | return 0; | ||
264 | |||
265 | ualg = nla_data(rta); | ||
266 | |||
267 | algo = xfrm_aalg_get_byname(ualg->alg_name, 1); | ||
268 | if (!algo) | ||
269 | return -ENOSYS; | ||
270 | *props = algo->desc.sadb_alg_id; | ||
271 | |||
272 | p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL); | ||
273 | if (!p) | ||
274 | return -ENOMEM; | ||
275 | |||
276 | strcpy(p->alg_name, algo->name); | ||
277 | p->alg_key_len = ualg->alg_key_len; | ||
278 | p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; | ||
279 | memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8); | ||
280 | |||
281 | *algpp = p; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props, | ||
286 | struct nlattr *rta) | ||
287 | { | ||
288 | struct xfrm_algo_auth *p, *ualg; | ||
289 | struct xfrm_algo_desc *algo; | ||
290 | |||
291 | if (!rta) | ||
292 | return 0; | ||
293 | |||
294 | ualg = nla_data(rta); | ||
295 | |||
296 | algo = xfrm_aalg_get_byname(ualg->alg_name, 1); | ||
297 | if (!algo) | ||
298 | return -ENOSYS; | ||
299 | if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits) | ||
300 | return -EINVAL; | ||
301 | *props = algo->desc.sadb_alg_id; | ||
302 | |||
303 | p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL); | ||
304 | if (!p) | ||
305 | return -ENOMEM; | ||
306 | |||
307 | strcpy(p->alg_name, algo->name); | ||
308 | if (!p->alg_trunc_len) | ||
309 | p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; | ||
310 | |||
311 | *algpp = p; | ||
312 | return 0; | ||
313 | } | ||
314 | |||
232 | static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, | 315 | static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, |
233 | struct nlattr *rta) | 316 | struct nlattr *rta) |
234 | { | 317 | { |
@@ -332,10 +415,14 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
332 | if ((err = attach_aead(&x->aead, &x->props.ealgo, | 415 | if ((err = attach_aead(&x->aead, &x->props.ealgo, |
333 | attrs[XFRMA_ALG_AEAD]))) | 416 | attrs[XFRMA_ALG_AEAD]))) |
334 | goto error; | 417 | goto error; |
335 | if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, | 418 | if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo, |
336 | xfrm_aalg_get_byname, | 419 | attrs[XFRMA_ALG_AUTH_TRUNC]))) |
337 | attrs[XFRMA_ALG_AUTH]))) | ||
338 | goto error; | 420 | goto error; |
421 | if (!x->props.aalgo) { | ||
422 | if ((err = attach_auth(&x->aalg, &x->props.aalgo, | ||
423 | attrs[XFRMA_ALG_AUTH]))) | ||
424 | goto error; | ||
425 | } | ||
339 | if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, | 426 | if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, |
340 | xfrm_ealg_get_byname, | 427 | xfrm_ealg_get_byname, |
341 | attrs[XFRMA_ALG_CRYPT]))) | 428 | attrs[XFRMA_ALG_CRYPT]))) |
@@ -548,6 +635,24 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) | |||
548 | return 0; | 635 | return 0; |
549 | } | 636 | } |
550 | 637 | ||
638 | static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb) | ||
639 | { | ||
640 | struct xfrm_algo *algo; | ||
641 | struct nlattr *nla; | ||
642 | |||
643 | nla = nla_reserve(skb, XFRMA_ALG_AUTH, | ||
644 | sizeof(*algo) + (auth->alg_key_len + 7) / 8); | ||
645 | if (!nla) | ||
646 | return -EMSGSIZE; | ||
647 | |||
648 | algo = nla_data(nla); | ||
649 | strcpy(algo->alg_name, auth->alg_name); | ||
650 | memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8); | ||
651 | algo->alg_key_len = auth->alg_key_len; | ||
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
551 | /* Don't change this without updating xfrm_sa_len! */ | 656 | /* Don't change this without updating xfrm_sa_len! */ |
552 | static int copy_to_user_state_extra(struct xfrm_state *x, | 657 | static int copy_to_user_state_extra(struct xfrm_state *x, |
553 | struct xfrm_usersa_info *p, | 658 | struct xfrm_usersa_info *p, |
@@ -563,8 +668,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
563 | 668 | ||
564 | if (x->aead) | 669 | if (x->aead) |
565 | NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); | 670 | NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); |
566 | if (x->aalg) | 671 | if (x->aalg) { |
567 | NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); | 672 | if (copy_to_user_auth(x->aalg, skb)) |
673 | goto nla_put_failure; | ||
674 | |||
675 | NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC, | ||
676 | xfrm_alg_auth_len(x->aalg), x->aalg); | ||
677 | } | ||
568 | if (x->ealg) | 678 | if (x->ealg) |
569 | NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); | 679 | NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); |
570 | if (x->calg) | 680 | if (x->calg) |
@@ -2117,8 +2227,11 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) | |||
2117 | size_t l = 0; | 2227 | size_t l = 0; |
2118 | if (x->aead) | 2228 | if (x->aead) |
2119 | l += nla_total_size(aead_len(x->aead)); | 2229 | l += nla_total_size(aead_len(x->aead)); |
2120 | if (x->aalg) | 2230 | if (x->aalg) { |
2121 | l += nla_total_size(xfrm_alg_len(x->aalg)); | 2231 | l += nla_total_size(sizeof(struct xfrm_algo) + |
2232 | (x->aalg->alg_key_len + 7) / 8); | ||
2233 | l += nla_total_size(xfrm_alg_auth_len(x->aalg)); | ||
2234 | } | ||
2122 | if (x->ealg) | 2235 | if (x->ealg) |
2123 | l += nla_total_size(xfrm_alg_len(x->ealg)); | 2236 | l += nla_total_size(xfrm_alg_len(x->ealg)); |
2124 | if (x->calg) | 2237 | if (x->calg) |
@@ -2608,22 +2721,24 @@ static int __net_init xfrm_user_net_init(struct net *net) | |||
2608 | xfrm_netlink_rcv, NULL, THIS_MODULE); | 2721 | xfrm_netlink_rcv, NULL, THIS_MODULE); |
2609 | if (nlsk == NULL) | 2722 | if (nlsk == NULL) |
2610 | return -ENOMEM; | 2723 | return -ENOMEM; |
2724 | net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */ | ||
2611 | rcu_assign_pointer(net->xfrm.nlsk, nlsk); | 2725 | rcu_assign_pointer(net->xfrm.nlsk, nlsk); |
2612 | return 0; | 2726 | return 0; |
2613 | } | 2727 | } |
2614 | 2728 | ||
2615 | static void __net_exit xfrm_user_net_exit(struct net *net) | 2729 | static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list) |
2616 | { | 2730 | { |
2617 | struct sock *nlsk = net->xfrm.nlsk; | 2731 | struct net *net; |
2618 | 2732 | list_for_each_entry(net, net_exit_list, exit_list) | |
2619 | rcu_assign_pointer(net->xfrm.nlsk, NULL); | 2733 | rcu_assign_pointer(net->xfrm.nlsk, NULL); |
2620 | synchronize_rcu(); | 2734 | synchronize_net(); |
2621 | netlink_kernel_release(nlsk); | 2735 | list_for_each_entry(net, net_exit_list, exit_list) |
2736 | netlink_kernel_release(net->xfrm.nlsk_stash); | ||
2622 | } | 2737 | } |
2623 | 2738 | ||
2624 | static struct pernet_operations xfrm_user_net_ops = { | 2739 | static struct pernet_operations xfrm_user_net_ops = { |
2625 | .init = xfrm_user_net_init, | 2740 | .init = xfrm_user_net_init, |
2626 | .exit = xfrm_user_net_exit, | 2741 | .exit_batch = xfrm_user_net_exit, |
2627 | }; | 2742 | }; |
2628 | 2743 | ||
2629 | static int __init xfrm_user_init(void) | 2744 | static int __init xfrm_user_init(void) |