diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 108 |
1 files changed, 98 insertions, 10 deletions
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 | { |