diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 9 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 108 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 397 |
3 files changed, 481 insertions, 33 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index ae62054a9fc4..f5eae9febd26 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -26,8 +26,8 @@ | |||
26 | #include <net/xfrm.h> | 26 | #include <net/xfrm.h> |
27 | #include <net/ip.h> | 27 | #include <net/ip.h> |
28 | 28 | ||
29 | DECLARE_MUTEX(xfrm_cfg_sem); | 29 | DEFINE_MUTEX(xfrm_cfg_mutex); |
30 | EXPORT_SYMBOL(xfrm_cfg_sem); | 30 | EXPORT_SYMBOL(xfrm_cfg_mutex); |
31 | 31 | ||
32 | static DEFINE_RWLOCK(xfrm_policy_lock); | 32 | static DEFINE_RWLOCK(xfrm_policy_lock); |
33 | 33 | ||
@@ -203,7 +203,7 @@ static void xfrm_policy_timer(unsigned long data) | |||
203 | } | 203 | } |
204 | 204 | ||
205 | if (warn) | 205 | if (warn) |
206 | km_policy_expired(xp, dir, 0); | 206 | km_policy_expired(xp, dir, 0, 0); |
207 | if (next != LONG_MAX && | 207 | if (next != LONG_MAX && |
208 | !mod_timer(&xp->timer, jiffies + make_jiffies(next))) | 208 | !mod_timer(&xp->timer, jiffies + make_jiffies(next))) |
209 | xfrm_pol_hold(xp); | 209 | xfrm_pol_hold(xp); |
@@ -216,7 +216,7 @@ out: | |||
216 | expired: | 216 | expired: |
217 | read_unlock(&xp->lock); | 217 | read_unlock(&xp->lock); |
218 | if (!xfrm_policy_delete(xp, dir)) | 218 | if (!xfrm_policy_delete(xp, dir)) |
219 | km_policy_expired(xp, dir, 1); | 219 | km_policy_expired(xp, dir, 1, 0); |
220 | xfrm_pol_put(xp); | 220 | xfrm_pol_put(xp); |
221 | } | 221 | } |
222 | 222 | ||
@@ -621,6 +621,7 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir) | |||
621 | } | 621 | } |
622 | return -ENOENT; | 622 | return -ENOENT; |
623 | } | 623 | } |
624 | EXPORT_SYMBOL(xfrm_policy_delete); | ||
624 | 625 | ||
625 | int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | 626 | int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) |
626 | { | 627 | { |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index c656cbaf35e8..a8e14dc1b04e 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -20,6 +20,15 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | 22 | ||
23 | struct sock *xfrm_nl; | ||
24 | EXPORT_SYMBOL(xfrm_nl); | ||
25 | |||
26 | u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME; | ||
27 | EXPORT_SYMBOL(sysctl_xfrm_aevent_etime); | ||
28 | |||
29 | u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE; | ||
30 | EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth); | ||
31 | |||
23 | /* Each xfrm_state may be linked to two tables: | 32 | /* Each xfrm_state may be linked to two tables: |
24 | 33 | ||
25 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) | 34 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) |
@@ -50,18 +59,20 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock); | |||
50 | 59 | ||
51 | static int xfrm_state_gc_flush_bundles; | 60 | static int xfrm_state_gc_flush_bundles; |
52 | 61 | ||
53 | static int __xfrm_state_delete(struct xfrm_state *x); | 62 | int __xfrm_state_delete(struct xfrm_state *x); |
54 | 63 | ||
55 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); | 64 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); |
56 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 65 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
57 | 66 | ||
58 | static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 67 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
59 | static void km_state_expired(struct xfrm_state *x, int hard); | 68 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); |
60 | 69 | ||
61 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 70 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
62 | { | 71 | { |
63 | if (del_timer(&x->timer)) | 72 | if (del_timer(&x->timer)) |
64 | BUG(); | 73 | BUG(); |
74 | if (del_timer(&x->rtimer)) | ||
75 | BUG(); | ||
65 | kfree(x->aalg); | 76 | kfree(x->aalg); |
66 | kfree(x->ealg); | 77 | kfree(x->ealg); |
67 | kfree(x->calg); | 78 | kfree(x->calg); |
@@ -153,7 +164,7 @@ static void xfrm_timer_handler(unsigned long data) | |||
153 | 164 | ||
154 | x->km.dying = warn; | 165 | x->km.dying = warn; |
155 | if (warn) | 166 | if (warn) |
156 | km_state_expired(x, 0); | 167 | km_state_expired(x, 0, 0); |
157 | resched: | 168 | resched: |
158 | if (next != LONG_MAX && | 169 | if (next != LONG_MAX && |
159 | !mod_timer(&x->timer, jiffies + make_jiffies(next))) | 170 | !mod_timer(&x->timer, jiffies + make_jiffies(next))) |
@@ -168,13 +179,15 @@ expired: | |||
168 | goto resched; | 179 | goto resched; |
169 | } | 180 | } |
170 | if (!__xfrm_state_delete(x) && x->id.spi) | 181 | if (!__xfrm_state_delete(x) && x->id.spi) |
171 | km_state_expired(x, 1); | 182 | km_state_expired(x, 1, 0); |
172 | 183 | ||
173 | out: | 184 | out: |
174 | spin_unlock(&x->lock); | 185 | spin_unlock(&x->lock); |
175 | xfrm_state_put(x); | 186 | xfrm_state_put(x); |
176 | } | 187 | } |
177 | 188 | ||
189 | static void xfrm_replay_timer_handler(unsigned long data); | ||
190 | |||
178 | struct xfrm_state *xfrm_state_alloc(void) | 191 | struct xfrm_state *xfrm_state_alloc(void) |
179 | { | 192 | { |
180 | struct xfrm_state *x; | 193 | struct xfrm_state *x; |
@@ -190,11 +203,16 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
190 | init_timer(&x->timer); | 203 | init_timer(&x->timer); |
191 | x->timer.function = xfrm_timer_handler; | 204 | x->timer.function = xfrm_timer_handler; |
192 | x->timer.data = (unsigned long)x; | 205 | x->timer.data = (unsigned long)x; |
206 | init_timer(&x->rtimer); | ||
207 | x->rtimer.function = xfrm_replay_timer_handler; | ||
208 | x->rtimer.data = (unsigned long)x; | ||
193 | x->curlft.add_time = (unsigned long)xtime.tv_sec; | 209 | x->curlft.add_time = (unsigned long)xtime.tv_sec; |
194 | x->lft.soft_byte_limit = XFRM_INF; | 210 | x->lft.soft_byte_limit = XFRM_INF; |
195 | x->lft.soft_packet_limit = XFRM_INF; | 211 | x->lft.soft_packet_limit = XFRM_INF; |
196 | x->lft.hard_byte_limit = XFRM_INF; | 212 | x->lft.hard_byte_limit = XFRM_INF; |
197 | x->lft.hard_packet_limit = XFRM_INF; | 213 | x->lft.hard_packet_limit = XFRM_INF; |
214 | x->replay_maxage = 0; | ||
215 | x->replay_maxdiff = 0; | ||
198 | spin_lock_init(&x->lock); | 216 | spin_lock_init(&x->lock); |
199 | } | 217 | } |
200 | return x; | 218 | return x; |
@@ -212,7 +230,7 @@ void __xfrm_state_destroy(struct xfrm_state *x) | |||
212 | } | 230 | } |
213 | EXPORT_SYMBOL(__xfrm_state_destroy); | 231 | EXPORT_SYMBOL(__xfrm_state_destroy); |
214 | 232 | ||
215 | static int __xfrm_state_delete(struct xfrm_state *x) | 233 | int __xfrm_state_delete(struct xfrm_state *x) |
216 | { | 234 | { |
217 | int err = -ESRCH; | 235 | int err = -ESRCH; |
218 | 236 | ||
@@ -228,6 +246,8 @@ static int __xfrm_state_delete(struct xfrm_state *x) | |||
228 | spin_unlock(&xfrm_state_lock); | 246 | spin_unlock(&xfrm_state_lock); |
229 | if (del_timer(&x->timer)) | 247 | if (del_timer(&x->timer)) |
230 | __xfrm_state_put(x); | 248 | __xfrm_state_put(x); |
249 | if (del_timer(&x->rtimer)) | ||
250 | __xfrm_state_put(x); | ||
231 | 251 | ||
232 | /* The number two in this test is the reference | 252 | /* The number two in this test is the reference |
233 | * mentioned in the comment below plus the reference | 253 | * mentioned in the comment below plus the reference |
@@ -249,6 +269,7 @@ static int __xfrm_state_delete(struct xfrm_state *x) | |||
249 | 269 | ||
250 | return err; | 270 | return err; |
251 | } | 271 | } |
272 | EXPORT_SYMBOL(__xfrm_state_delete); | ||
252 | 273 | ||
253 | int xfrm_state_delete(struct xfrm_state *x) | 274 | int xfrm_state_delete(struct xfrm_state *x) |
254 | { | 275 | { |
@@ -426,6 +447,10 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
426 | if (!mod_timer(&x->timer, jiffies + HZ)) | 447 | if (!mod_timer(&x->timer, jiffies + HZ)) |
427 | xfrm_state_hold(x); | 448 | xfrm_state_hold(x); |
428 | 449 | ||
450 | if (x->replay_maxage && | ||
451 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | ||
452 | xfrm_state_hold(x); | ||
453 | |||
429 | wake_up(&km_waitq); | 454 | wake_up(&km_waitq); |
430 | } | 455 | } |
431 | 456 | ||
@@ -580,7 +605,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
580 | (x->curlft.bytes >= x->lft.soft_byte_limit || | 605 | (x->curlft.bytes >= x->lft.soft_byte_limit || |
581 | x->curlft.packets >= x->lft.soft_packet_limit)) { | 606 | x->curlft.packets >= x->lft.soft_packet_limit)) { |
582 | x->km.dying = 1; | 607 | x->km.dying = 1; |
583 | km_state_expired(x, 0); | 608 | km_state_expired(x, 0, 0); |
584 | } | 609 | } |
585 | return 0; | 610 | return 0; |
586 | } | 611 | } |
@@ -762,6 +787,61 @@ out: | |||
762 | } | 787 | } |
763 | EXPORT_SYMBOL(xfrm_state_walk); | 788 | EXPORT_SYMBOL(xfrm_state_walk); |
764 | 789 | ||
790 | |||
791 | void xfrm_replay_notify(struct xfrm_state *x, int event) | ||
792 | { | ||
793 | struct km_event c; | ||
794 | /* we send notify messages in case | ||
795 | * 1. we updated on of the sequence numbers, and the seqno difference | ||
796 | * is at least x->replay_maxdiff, in this case we also update the | ||
797 | * timeout of our timer function | ||
798 | * 2. if x->replay_maxage has elapsed since last update, | ||
799 | * and there were changes | ||
800 | * | ||
801 | * The state structure must be locked! | ||
802 | */ | ||
803 | |||
804 | switch (event) { | ||
805 | case XFRM_REPLAY_UPDATE: | ||
806 | if (x->replay_maxdiff && | ||
807 | (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && | ||
808 | (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) | ||
809 | return; | ||
810 | |||
811 | break; | ||
812 | |||
813 | case XFRM_REPLAY_TIMEOUT: | ||
814 | if ((x->replay.seq == x->preplay.seq) && | ||
815 | (x->replay.bitmap == x->preplay.bitmap) && | ||
816 | (x->replay.oseq == x->preplay.oseq)) | ||
817 | return; | ||
818 | |||
819 | break; | ||
820 | } | ||
821 | |||
822 | memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); | ||
823 | c.event = XFRM_MSG_NEWAE; | ||
824 | c.data.aevent = event; | ||
825 | km_state_notify(x, &c); | ||
826 | |||
827 | if (x->replay_maxage && | ||
828 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | ||
829 | xfrm_state_hold(x); | ||
830 | } | ||
831 | EXPORT_SYMBOL(xfrm_replay_notify); | ||
832 | |||
833 | static void xfrm_replay_timer_handler(unsigned long data) | ||
834 | { | ||
835 | struct xfrm_state *x = (struct xfrm_state*)data; | ||
836 | |||
837 | spin_lock(&x->lock); | ||
838 | |||
839 | if (xfrm_aevent_is_on() && x->km.state == XFRM_STATE_VALID) | ||
840 | xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); | ||
841 | |||
842 | spin_unlock(&x->lock); | ||
843 | } | ||
844 | |||
765 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) | 845 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) |
766 | { | 846 | { |
767 | u32 diff; | 847 | u32 diff; |
@@ -805,6 +885,9 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq) | |||
805 | diff = x->replay.seq - seq; | 885 | diff = x->replay.seq - seq; |
806 | x->replay.bitmap |= (1U << diff); | 886 | x->replay.bitmap |= (1U << diff); |
807 | } | 887 | } |
888 | |||
889 | if (xfrm_aevent_is_on()) | ||
890 | xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); | ||
808 | } | 891 | } |
809 | EXPORT_SYMBOL(xfrm_replay_advance); | 892 | EXPORT_SYMBOL(xfrm_replay_advance); |
810 | 893 | ||
@@ -835,11 +918,12 @@ void km_state_notify(struct xfrm_state *x, struct km_event *c) | |||
835 | EXPORT_SYMBOL(km_policy_notify); | 918 | EXPORT_SYMBOL(km_policy_notify); |
836 | EXPORT_SYMBOL(km_state_notify); | 919 | EXPORT_SYMBOL(km_state_notify); |
837 | 920 | ||
838 | static void km_state_expired(struct xfrm_state *x, int hard) | 921 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid) |
839 | { | 922 | { |
840 | struct km_event c; | 923 | struct km_event c; |
841 | 924 | ||
842 | c.data.hard = hard; | 925 | c.data.hard = hard; |
926 | c.pid = pid; | ||
843 | c.event = XFRM_MSG_EXPIRE; | 927 | c.event = XFRM_MSG_EXPIRE; |
844 | km_state_notify(x, &c); | 928 | km_state_notify(x, &c); |
845 | 929 | ||
@@ -847,11 +931,12 @@ static void km_state_expired(struct xfrm_state *x, int hard) | |||
847 | wake_up(&km_waitq); | 931 | wake_up(&km_waitq); |
848 | } | 932 | } |
849 | 933 | ||
934 | EXPORT_SYMBOL(km_state_expired); | ||
850 | /* | 935 | /* |
851 | * We send to all registered managers regardless of failure | 936 | * We send to all registered managers regardless of failure |
852 | * We are happy with one success | 937 | * We are happy with one success |
853 | */ | 938 | */ |
854 | static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) | 939 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) |
855 | { | 940 | { |
856 | int err = -EINVAL, acqret; | 941 | int err = -EINVAL, acqret; |
857 | struct xfrm_mgr *km; | 942 | struct xfrm_mgr *km; |
@@ -865,6 +950,7 @@ static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_polic | |||
865 | read_unlock(&xfrm_km_lock); | 950 | read_unlock(&xfrm_km_lock); |
866 | return err; | 951 | return err; |
867 | } | 952 | } |
953 | EXPORT_SYMBOL(km_query); | ||
868 | 954 | ||
869 | int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport) | 955 | int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport) |
870 | { | 956 | { |
@@ -883,17 +969,19 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport) | |||
883 | } | 969 | } |
884 | EXPORT_SYMBOL(km_new_mapping); | 970 | EXPORT_SYMBOL(km_new_mapping); |
885 | 971 | ||
886 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard) | 972 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) |
887 | { | 973 | { |
888 | struct km_event c; | 974 | struct km_event c; |
889 | 975 | ||
890 | c.data.hard = hard; | 976 | c.data.hard = hard; |
977 | c.pid = pid; | ||
891 | c.event = XFRM_MSG_POLEXPIRE; | 978 | c.event = XFRM_MSG_POLEXPIRE; |
892 | km_policy_notify(pol, dir, &c); | 979 | km_policy_notify(pol, dir, &c); |
893 | 980 | ||
894 | if (hard) | 981 | if (hard) |
895 | wake_up(&km_waitq); | 982 | wake_up(&km_waitq); |
896 | } | 983 | } |
984 | EXPORT_SYMBOL(km_policy_expired); | ||
897 | 985 | ||
898 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) | 986 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) |
899 | { | 987 | { |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7de17559249a..81d1005830f4 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -28,8 +28,6 @@ | |||
28 | #include <net/netlink.h> | 28 | #include <net/netlink.h> |
29 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | 30 | ||
31 | static struct sock *xfrm_nl; | ||
32 | |||
33 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) | 31 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) |
34 | { | 32 | { |
35 | struct rtattr *rt = xfrma[type - 1]; | 33 | struct rtattr *rt = xfrma[type - 1]; |
@@ -103,9 +101,6 @@ static inline int verify_sec_ctx_len(struct rtattr **xfrma) | |||
103 | 101 | ||
104 | uctx = RTA_DATA(rt); | 102 | uctx = RTA_DATA(rt); |
105 | 103 | ||
106 | if (uctx->ctx_len > PAGE_SIZE) | ||
107 | return -EINVAL; | ||
108 | |||
109 | len += sizeof(struct xfrm_user_sec_ctx); | 104 | len += sizeof(struct xfrm_user_sec_ctx); |
110 | len += uctx->ctx_len; | 105 | len += uctx->ctx_len; |
111 | 106 | ||
@@ -276,6 +271,56 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * | |||
276 | x->props.flags = p->flags; | 271 | x->props.flags = p->flags; |
277 | } | 272 | } |
278 | 273 | ||
274 | /* | ||
275 | * someday when pfkey also has support, we could have the code | ||
276 | * somehow made shareable and move it to xfrm_state.c - JHS | ||
277 | * | ||
278 | */ | ||
279 | static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) | ||
280 | { | ||
281 | int err = - EINVAL; | ||
282 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; | ||
283 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; | ||
284 | struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; | ||
285 | struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1]; | ||
286 | |||
287 | if (rp) { | ||
288 | struct xfrm_replay_state *replay; | ||
289 | if (RTA_PAYLOAD(rp) < sizeof(*replay)) | ||
290 | goto error; | ||
291 | replay = RTA_DATA(rp); | ||
292 | memcpy(&x->replay, replay, sizeof(*replay)); | ||
293 | memcpy(&x->preplay, replay, sizeof(*replay)); | ||
294 | } | ||
295 | |||
296 | if (lt) { | ||
297 | struct xfrm_lifetime_cur *ltime; | ||
298 | if (RTA_PAYLOAD(lt) < sizeof(*ltime)) | ||
299 | goto error; | ||
300 | ltime = RTA_DATA(lt); | ||
301 | x->curlft.bytes = ltime->bytes; | ||
302 | x->curlft.packets = ltime->packets; | ||
303 | x->curlft.add_time = ltime->add_time; | ||
304 | x->curlft.use_time = ltime->use_time; | ||
305 | } | ||
306 | |||
307 | if (et) { | ||
308 | if (RTA_PAYLOAD(et) < sizeof(u32)) | ||
309 | goto error; | ||
310 | x->replay_maxage = *(u32*)RTA_DATA(et); | ||
311 | } | ||
312 | |||
313 | if (rt) { | ||
314 | if (RTA_PAYLOAD(rt) < sizeof(u32)) | ||
315 | goto error; | ||
316 | x->replay_maxdiff = *(u32*)RTA_DATA(rt); | ||
317 | } | ||
318 | |||
319 | return 0; | ||
320 | error: | ||
321 | return err; | ||
322 | } | ||
323 | |||
279 | static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | 324 | static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, |
280 | struct rtattr **xfrma, | 325 | struct rtattr **xfrma, |
281 | int *errp) | 326 | int *errp) |
@@ -311,6 +356,18 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
311 | goto error; | 356 | goto error; |
312 | 357 | ||
313 | x->km.seq = p->seq; | 358 | x->km.seq = p->seq; |
359 | x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; | ||
360 | /* sysctl_xfrm_aevent_etime is in 100ms units */ | ||
361 | x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; | ||
362 | x->preplay.bitmap = 0; | ||
363 | x->preplay.seq = x->replay.seq+x->replay_maxdiff; | ||
364 | x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; | ||
365 | |||
366 | /* override default values from above */ | ||
367 | |||
368 | err = xfrm_update_ae_params(x, (struct rtattr **)xfrma); | ||
369 | if (err < 0) | ||
370 | goto error; | ||
314 | 371 | ||
315 | return x; | 372 | return x; |
316 | 373 | ||
@@ -1025,9 +1082,142 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma | |||
1025 | return 0; | 1082 | return 0; |
1026 | } | 1083 | } |
1027 | 1084 | ||
1028 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1085 | |
1086 | static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) | ||
1087 | { | ||
1088 | struct xfrm_aevent_id *id; | ||
1089 | struct nlmsghdr *nlh; | ||
1090 | struct xfrm_lifetime_cur ltime; | ||
1091 | unsigned char *b = skb->tail; | ||
1092 | |||
1093 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); | ||
1094 | id = NLMSG_DATA(nlh); | ||
1095 | nlh->nlmsg_flags = 0; | ||
1096 | |||
1097 | id->sa_id.daddr = x->id.daddr; | ||
1098 | id->sa_id.spi = x->id.spi; | ||
1099 | id->sa_id.family = x->props.family; | ||
1100 | id->sa_id.proto = x->id.proto; | ||
1101 | id->flags = c->data.aevent; | ||
1102 | |||
1103 | RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); | ||
1104 | |||
1105 | ltime.bytes = x->curlft.bytes; | ||
1106 | ltime.packets = x->curlft.packets; | ||
1107 | ltime.add_time = x->curlft.add_time; | ||
1108 | ltime.use_time = x->curlft.use_time; | ||
1109 | |||
1110 | RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime); | ||
1111 | |||
1112 | if (id->flags&XFRM_AE_RTHR) { | ||
1113 | RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff); | ||
1114 | } | ||
1115 | |||
1116 | if (id->flags&XFRM_AE_ETHR) { | ||
1117 | u32 etimer = x->replay_maxage*10/HZ; | ||
1118 | RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); | ||
1119 | } | ||
1120 | |||
1121 | nlh->nlmsg_len = skb->tail - b; | ||
1122 | return skb->len; | ||
1123 | |||
1124 | rtattr_failure: | ||
1125 | nlmsg_failure: | ||
1126 | skb_trim(skb, b - skb->data); | ||
1127 | return -1; | ||
1128 | } | ||
1129 | |||
1130 | static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1131 | { | ||
1132 | struct xfrm_state *x; | ||
1133 | struct sk_buff *r_skb; | ||
1134 | int err; | ||
1135 | struct km_event c; | ||
1136 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); | ||
1137 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | ||
1138 | struct xfrm_usersa_id *id = &p->sa_id; | ||
1139 | |||
1140 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); | ||
1141 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); | ||
1142 | |||
1143 | if (p->flags&XFRM_AE_RTHR) | ||
1144 | len+=RTA_SPACE(sizeof(u32)); | ||
1145 | |||
1146 | if (p->flags&XFRM_AE_ETHR) | ||
1147 | len+=RTA_SPACE(sizeof(u32)); | ||
1148 | |||
1149 | r_skb = alloc_skb(len, GFP_ATOMIC); | ||
1150 | if (r_skb == NULL) | ||
1151 | return -ENOMEM; | ||
1152 | |||
1153 | x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); | ||
1154 | if (x == NULL) { | ||
1155 | kfree(r_skb); | ||
1156 | return -ESRCH; | ||
1157 | } | ||
1158 | |||
1159 | /* | ||
1160 | * XXX: is this lock really needed - none of the other | ||
1161 | * gets lock (the concern is things getting updated | ||
1162 | * while we are still reading) - jhs | ||
1163 | */ | ||
1164 | spin_lock_bh(&x->lock); | ||
1165 | c.data.aevent = p->flags; | ||
1166 | c.seq = nlh->nlmsg_seq; | ||
1167 | c.pid = nlh->nlmsg_pid; | ||
1168 | |||
1169 | if (build_aevent(r_skb, x, &c) < 0) | ||
1170 | BUG(); | ||
1171 | err = netlink_unicast(xfrm_nl, r_skb, | ||
1172 | NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
1173 | spin_unlock_bh(&x->lock); | ||
1174 | xfrm_state_put(x); | ||
1175 | return err; | ||
1176 | } | ||
1177 | |||
1178 | static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1029 | { | 1179 | { |
1180 | struct xfrm_state *x; | ||
1030 | struct km_event c; | 1181 | struct km_event c; |
1182 | int err = - EINVAL; | ||
1183 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); | ||
1184 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; | ||
1185 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; | ||
1186 | |||
1187 | if (!lt && !rp) | ||
1188 | return err; | ||
1189 | |||
1190 | /* pedantic mode - thou shalt sayeth replaceth */ | ||
1191 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) | ||
1192 | return err; | ||
1193 | |||
1194 | x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | ||
1195 | if (x == NULL) | ||
1196 | return -ESRCH; | ||
1197 | |||
1198 | if (x->km.state != XFRM_STATE_VALID) | ||
1199 | goto out; | ||
1200 | |||
1201 | spin_lock_bh(&x->lock); | ||
1202 | err = xfrm_update_ae_params(x,(struct rtattr **)xfrma); | ||
1203 | spin_unlock_bh(&x->lock); | ||
1204 | if (err < 0) | ||
1205 | goto out; | ||
1206 | |||
1207 | c.event = nlh->nlmsg_type; | ||
1208 | c.seq = nlh->nlmsg_seq; | ||
1209 | c.pid = nlh->nlmsg_pid; | ||
1210 | c.data.aevent = XFRM_AE_CU; | ||
1211 | km_state_notify(x, &c); | ||
1212 | err = 0; | ||
1213 | out: | ||
1214 | xfrm_state_put(x); | ||
1215 | return err; | ||
1216 | } | ||
1217 | |||
1218 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1219 | { | ||
1220 | struct km_event c; | ||
1031 | 1221 | ||
1032 | xfrm_policy_flush(); | 1222 | xfrm_policy_flush(); |
1033 | c.event = nlh->nlmsg_type; | 1223 | c.event = nlh->nlmsg_type; |
@@ -1037,6 +1227,139 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **x | |||
1037 | return 0; | 1227 | return 0; |
1038 | } | 1228 | } |
1039 | 1229 | ||
1230 | static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1231 | { | ||
1232 | struct xfrm_policy *xp; | ||
1233 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | ||
1234 | struct xfrm_userpolicy_info *p = &up->pol; | ||
1235 | int err = -ENOENT; | ||
1236 | |||
1237 | if (p->index) | ||
1238 | xp = xfrm_policy_byid(p->dir, p->index, 0); | ||
1239 | else { | ||
1240 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | ||
1241 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | ||
1242 | struct xfrm_policy tmp; | ||
1243 | |||
1244 | err = verify_sec_ctx_len(rtattrs); | ||
1245 | if (err) | ||
1246 | return err; | ||
1247 | |||
1248 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
1249 | if (rt) { | ||
1250 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
1251 | |||
1252 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | ||
1253 | return err; | ||
1254 | } | ||
1255 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0); | ||
1256 | security_xfrm_policy_free(&tmp); | ||
1257 | } | ||
1258 | |||
1259 | if (xp == NULL) | ||
1260 | return err; | ||
1261 | read_lock(&xp->lock); | ||
1262 | if (xp->dead) { | ||
1263 | read_unlock(&xp->lock); | ||
1264 | goto out; | ||
1265 | } | ||
1266 | |||
1267 | read_unlock(&xp->lock); | ||
1268 | err = 0; | ||
1269 | if (up->hard) { | ||
1270 | xfrm_policy_delete(xp, p->dir); | ||
1271 | } else { | ||
1272 | // reset the timers here? | ||
1273 | printk("Dont know what to do with soft policy expire\n"); | ||
1274 | } | ||
1275 | km_policy_expired(xp, p->dir, up->hard, current->pid); | ||
1276 | |||
1277 | out: | ||
1278 | xfrm_pol_put(xp); | ||
1279 | return err; | ||
1280 | } | ||
1281 | |||
1282 | static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1283 | { | ||
1284 | struct xfrm_state *x; | ||
1285 | int err; | ||
1286 | struct xfrm_user_expire *ue = NLMSG_DATA(nlh); | ||
1287 | struct xfrm_usersa_info *p = &ue->state; | ||
1288 | |||
1289 | x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); | ||
1290 | err = -ENOENT; | ||
1291 | |||
1292 | if (x == NULL) | ||
1293 | return err; | ||
1294 | |||
1295 | err = -EINVAL; | ||
1296 | |||
1297 | spin_lock_bh(&x->lock); | ||
1298 | if (x->km.state != XFRM_STATE_VALID) | ||
1299 | goto out; | ||
1300 | km_state_expired(x, ue->hard, current->pid); | ||
1301 | |||
1302 | if (ue->hard) | ||
1303 | __xfrm_state_delete(x); | ||
1304 | out: | ||
1305 | spin_unlock_bh(&x->lock); | ||
1306 | xfrm_state_put(x); | ||
1307 | return err; | ||
1308 | } | ||
1309 | |||
1310 | static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1311 | { | ||
1312 | struct xfrm_policy *xp; | ||
1313 | struct xfrm_user_tmpl *ut; | ||
1314 | int i; | ||
1315 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; | ||
1316 | |||
1317 | struct xfrm_user_acquire *ua = NLMSG_DATA(nlh); | ||
1318 | struct xfrm_state *x = xfrm_state_alloc(); | ||
1319 | int err = -ENOMEM; | ||
1320 | |||
1321 | if (!x) | ||
1322 | return err; | ||
1323 | |||
1324 | err = verify_newpolicy_info(&ua->policy); | ||
1325 | if (err) { | ||
1326 | printk("BAD policy passed\n"); | ||
1327 | kfree(x); | ||
1328 | return err; | ||
1329 | } | ||
1330 | |||
1331 | /* build an XP */ | ||
1332 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { | ||
1333 | kfree(x); | ||
1334 | return err; | ||
1335 | } | ||
1336 | |||
1337 | memcpy(&x->id, &ua->id, sizeof(ua->id)); | ||
1338 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); | ||
1339 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); | ||
1340 | |||
1341 | ut = RTA_DATA(rt); | ||
1342 | /* extract the templates and for each call km_key */ | ||
1343 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { | ||
1344 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; | ||
1345 | memcpy(&x->id, &t->id, sizeof(x->id)); | ||
1346 | x->props.mode = t->mode; | ||
1347 | x->props.reqid = t->reqid; | ||
1348 | x->props.family = ut->family; | ||
1349 | t->aalgos = ua->aalgos; | ||
1350 | t->ealgos = ua->ealgos; | ||
1351 | t->calgos = ua->calgos; | ||
1352 | err = km_query(x, t, xp); | ||
1353 | |||
1354 | } | ||
1355 | |||
1356 | kfree(x); | ||
1357 | kfree(xp); | ||
1358 | |||
1359 | return 0; | ||
1360 | } | ||
1361 | |||
1362 | |||
1040 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) | 1363 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) |
1041 | 1364 | ||
1042 | static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | 1365 | static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { |
@@ -1054,6 +1377,8 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1054 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), | 1377 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), |
1055 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), | 1378 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), |
1056 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), | 1379 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), |
1380 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | ||
1381 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | ||
1057 | }; | 1382 | }; |
1058 | 1383 | ||
1059 | #undef XMSGSIZE | 1384 | #undef XMSGSIZE |
@@ -1071,10 +1396,15 @@ static struct xfrm_link { | |||
1071 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, | 1396 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, |
1072 | .dump = xfrm_dump_policy }, | 1397 | .dump = xfrm_dump_policy }, |
1073 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, | 1398 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, |
1399 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, | ||
1400 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, | ||
1074 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, | 1401 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, |
1075 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, | 1402 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, |
1403 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, | ||
1076 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, | 1404 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, |
1077 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, | 1405 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, |
1406 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, | ||
1407 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, | ||
1078 | }; | 1408 | }; |
1079 | 1409 | ||
1080 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | 1410 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) |
@@ -1156,26 +1486,26 @@ static void xfrm_netlink_rcv(struct sock *sk, int len) | |||
1156 | unsigned int qlen = 0; | 1486 | unsigned int qlen = 0; |
1157 | 1487 | ||
1158 | do { | 1488 | do { |
1159 | down(&xfrm_cfg_sem); | 1489 | mutex_lock(&xfrm_cfg_mutex); |
1160 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); | 1490 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); |
1161 | up(&xfrm_cfg_sem); | 1491 | mutex_unlock(&xfrm_cfg_mutex); |
1162 | 1492 | ||
1163 | } while (qlen); | 1493 | } while (qlen); |
1164 | } | 1494 | } |
1165 | 1495 | ||
1166 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) | 1496 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) |
1167 | { | 1497 | { |
1168 | struct xfrm_user_expire *ue; | 1498 | struct xfrm_user_expire *ue; |
1169 | struct nlmsghdr *nlh; | 1499 | struct nlmsghdr *nlh; |
1170 | unsigned char *b = skb->tail; | 1500 | unsigned char *b = skb->tail; |
1171 | 1501 | ||
1172 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE, | 1502 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, |
1173 | sizeof(*ue)); | 1503 | sizeof(*ue)); |
1174 | ue = NLMSG_DATA(nlh); | 1504 | ue = NLMSG_DATA(nlh); |
1175 | nlh->nlmsg_flags = 0; | 1505 | nlh->nlmsg_flags = 0; |
1176 | 1506 | ||
1177 | copy_to_user_state(x, &ue->state); | 1507 | copy_to_user_state(x, &ue->state); |
1178 | ue->hard = (hard != 0) ? 1 : 0; | 1508 | ue->hard = (c->data.hard != 0) ? 1 : 0; |
1179 | 1509 | ||
1180 | nlh->nlmsg_len = skb->tail - b; | 1510 | nlh->nlmsg_len = skb->tail - b; |
1181 | return skb->len; | 1511 | return skb->len; |
@@ -1194,13 +1524,31 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | |||
1194 | if (skb == NULL) | 1524 | if (skb == NULL) |
1195 | return -ENOMEM; | 1525 | return -ENOMEM; |
1196 | 1526 | ||
1197 | if (build_expire(skb, x, c->data.hard) < 0) | 1527 | if (build_expire(skb, x, c) < 0) |
1198 | BUG(); | 1528 | BUG(); |
1199 | 1529 | ||
1200 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; | 1530 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; |
1201 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 1531 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); |
1202 | } | 1532 | } |
1203 | 1533 | ||
1534 | static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) | ||
1535 | { | ||
1536 | struct sk_buff *skb; | ||
1537 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | ||
1538 | |||
1539 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); | ||
1540 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); | ||
1541 | skb = alloc_skb(len, GFP_ATOMIC); | ||
1542 | if (skb == NULL) | ||
1543 | return -ENOMEM; | ||
1544 | |||
1545 | if (build_aevent(skb, x, c) < 0) | ||
1546 | BUG(); | ||
1547 | |||
1548 | NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS; | ||
1549 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); | ||
1550 | } | ||
1551 | |||
1204 | static int xfrm_notify_sa_flush(struct km_event *c) | 1552 | static int xfrm_notify_sa_flush(struct km_event *c) |
1205 | { | 1553 | { |
1206 | struct xfrm_usersa_flush *p; | 1554 | struct xfrm_usersa_flush *p; |
@@ -1313,6 +1661,8 @@ static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) | |||
1313 | switch (c->event) { | 1661 | switch (c->event) { |
1314 | case XFRM_MSG_EXPIRE: | 1662 | case XFRM_MSG_EXPIRE: |
1315 | return xfrm_exp_state_notify(x, c); | 1663 | return xfrm_exp_state_notify(x, c); |
1664 | case XFRM_MSG_NEWAE: | ||
1665 | return xfrm_aevent_state_notify(x, c); | ||
1316 | case XFRM_MSG_DELSA: | 1666 | case XFRM_MSG_DELSA: |
1317 | case XFRM_MSG_UPDSA: | 1667 | case XFRM_MSG_UPDSA: |
1318 | case XFRM_MSG_NEWSA: | 1668 | case XFRM_MSG_NEWSA: |
@@ -1443,13 +1793,14 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1443 | } | 1793 | } |
1444 | 1794 | ||
1445 | static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | 1795 | static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, |
1446 | int dir, int hard) | 1796 | int dir, struct km_event *c) |
1447 | { | 1797 | { |
1448 | struct xfrm_user_polexpire *upe; | 1798 | struct xfrm_user_polexpire *upe; |
1449 | struct nlmsghdr *nlh; | 1799 | struct nlmsghdr *nlh; |
1800 | int hard = c->data.hard; | ||
1450 | unsigned char *b = skb->tail; | 1801 | unsigned char *b = skb->tail; |
1451 | 1802 | ||
1452 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); | 1803 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); |
1453 | upe = NLMSG_DATA(nlh); | 1804 | upe = NLMSG_DATA(nlh); |
1454 | nlh->nlmsg_flags = 0; | 1805 | nlh->nlmsg_flags = 0; |
1455 | 1806 | ||
@@ -1480,7 +1831,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve | |||
1480 | if (skb == NULL) | 1831 | if (skb == NULL) |
1481 | return -ENOMEM; | 1832 | return -ENOMEM; |
1482 | 1833 | ||
1483 | if (build_polexpire(skb, xp, dir, c->data.hard) < 0) | 1834 | if (build_polexpire(skb, xp, dir, c) < 0) |
1484 | BUG(); | 1835 | BUG(); |
1485 | 1836 | ||
1486 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; | 1837 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; |
@@ -1596,12 +1947,15 @@ static struct xfrm_mgr netlink_mgr = { | |||
1596 | 1947 | ||
1597 | static int __init xfrm_user_init(void) | 1948 | static int __init xfrm_user_init(void) |
1598 | { | 1949 | { |
1950 | struct sock *nlsk; | ||
1951 | |||
1599 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); | 1952 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); |
1600 | 1953 | ||
1601 | xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, | 1954 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, |
1602 | xfrm_netlink_rcv, THIS_MODULE); | 1955 | xfrm_netlink_rcv, THIS_MODULE); |
1603 | if (xfrm_nl == NULL) | 1956 | if (nlsk == NULL) |
1604 | return -ENOMEM; | 1957 | return -ENOMEM; |
1958 | rcu_assign_pointer(xfrm_nl, nlsk); | ||
1605 | 1959 | ||
1606 | xfrm_register_km(&netlink_mgr); | 1960 | xfrm_register_km(&netlink_mgr); |
1607 | 1961 | ||
@@ -1610,11 +1964,16 @@ static int __init xfrm_user_init(void) | |||
1610 | 1964 | ||
1611 | static void __exit xfrm_user_exit(void) | 1965 | static void __exit xfrm_user_exit(void) |
1612 | { | 1966 | { |
1967 | struct sock *nlsk = xfrm_nl; | ||
1968 | |||
1613 | xfrm_unregister_km(&netlink_mgr); | 1969 | xfrm_unregister_km(&netlink_mgr); |
1614 | sock_release(xfrm_nl->sk_socket); | 1970 | rcu_assign_pointer(xfrm_nl, NULL); |
1971 | synchronize_rcu(); | ||
1972 | sock_release(nlsk->sk_socket); | ||
1615 | } | 1973 | } |
1616 | 1974 | ||
1617 | module_init(xfrm_user_init); | 1975 | module_init(xfrm_user_init); |
1618 | module_exit(xfrm_user_exit); | 1976 | module_exit(xfrm_user_exit); |
1619 | MODULE_LICENSE("GPL"); | 1977 | MODULE_LICENSE("GPL"); |
1620 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); | 1978 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); |
1979 | |||