diff options
-rw-r--r-- | include/linux/sysctl.h | 2 | ||||
-rw-r--r-- | include/linux/xfrm.h | 30 | ||||
-rw-r--r-- | include/net/xfrm.h | 44 | ||||
-rw-r--r-- | net/core/sysctl_net_core.c | 23 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 76 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 4 |
6 files changed, 176 insertions, 3 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 6e8880ea49e7..b686548f32e0 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
@@ -261,6 +261,8 @@ enum | |||
261 | NET_CORE_DEV_WEIGHT=17, | 261 | NET_CORE_DEV_WEIGHT=17, |
262 | NET_CORE_SOMAXCONN=18, | 262 | NET_CORE_SOMAXCONN=18, |
263 | NET_CORE_BUDGET=19, | 263 | NET_CORE_BUDGET=19, |
264 | NET_CORE_AEVENT_ETIME=20, | ||
265 | NET_CORE_AEVENT_RSEQTH=21, | ||
264 | }; | 266 | }; |
265 | 267 | ||
266 | /* /proc/sys/net/ethernet */ | 268 | /* /proc/sys/net/ethernet */ |
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 82fbb758e28f..b54a12940ef6 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
@@ -156,6 +156,10 @@ enum { | |||
156 | XFRM_MSG_FLUSHPOLICY, | 156 | XFRM_MSG_FLUSHPOLICY, |
157 | #define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY | 157 | #define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY |
158 | 158 | ||
159 | XFRM_MSG_NEWAE, | ||
160 | #define XFRM_MSG_NEWAE XFRM_MSG_NEWAE | ||
161 | XFRM_MSG_GETAE, | ||
162 | #define XFRM_MSG_GETAE XFRM_MSG_GETAE | ||
159 | __XFRM_MSG_MAX | 163 | __XFRM_MSG_MAX |
160 | }; | 164 | }; |
161 | #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) | 165 | #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) |
@@ -194,6 +198,21 @@ struct xfrm_encap_tmpl { | |||
194 | xfrm_address_t encap_oa; | 198 | xfrm_address_t encap_oa; |
195 | }; | 199 | }; |
196 | 200 | ||
201 | /* AEVENT flags */ | ||
202 | enum xfrm_ae_ftype_t { | ||
203 | XFRM_AE_UNSPEC, | ||
204 | XFRM_AE_RTHR=1, /* replay threshold*/ | ||
205 | XFRM_AE_RVAL=2, /* replay value */ | ||
206 | XFRM_AE_LVAL=4, /* lifetime value */ | ||
207 | XFRM_AE_ETHR=8, /* expiry timer threshold */ | ||
208 | XFRM_AE_CR=16, /* Event cause is replay update */ | ||
209 | XFRM_AE_CE=32, /* Event cause is timer expiry */ | ||
210 | XFRM_AE_CU=64, /* Event cause is policy update */ | ||
211 | __XFRM_AE_MAX | ||
212 | |||
213 | #define XFRM_AE_MAX (__XFRM_AE_MAX - 1) | ||
214 | }; | ||
215 | |||
197 | /* Netlink message attributes. */ | 216 | /* Netlink message attributes. */ |
198 | enum xfrm_attr_type_t { | 217 | enum xfrm_attr_type_t { |
199 | XFRMA_UNSPEC, | 218 | XFRMA_UNSPEC, |
@@ -205,6 +224,10 @@ enum xfrm_attr_type_t { | |||
205 | XFRMA_SA, | 224 | XFRMA_SA, |
206 | XFRMA_POLICY, | 225 | XFRMA_POLICY, |
207 | XFRMA_SEC_CTX, /* struct xfrm_sec_ctx */ | 226 | XFRMA_SEC_CTX, /* struct xfrm_sec_ctx */ |
227 | XFRMA_LTIME_VAL, | ||
228 | XFRMA_REPLAY_VAL, | ||
229 | XFRMA_REPLAY_THRESH, | ||
230 | XFRMA_ETIMER_THRESH, | ||
208 | __XFRMA_MAX | 231 | __XFRMA_MAX |
209 | 232 | ||
210 | #define XFRMA_MAX (__XFRMA_MAX - 1) | 233 | #define XFRMA_MAX (__XFRMA_MAX - 1) |
@@ -235,6 +258,11 @@ struct xfrm_usersa_id { | |||
235 | __u8 proto; | 258 | __u8 proto; |
236 | }; | 259 | }; |
237 | 260 | ||
261 | struct xfrm_aevent_id { | ||
262 | __u32 flags; | ||
263 | struct xfrm_usersa_id sa_id; | ||
264 | }; | ||
265 | |||
238 | struct xfrm_userspi_info { | 266 | struct xfrm_userspi_info { |
239 | struct xfrm_usersa_info info; | 267 | struct xfrm_usersa_info info; |
240 | __u32 min; | 268 | __u32 min; |
@@ -306,6 +334,8 @@ enum xfrm_nlgroups { | |||
306 | #define XFRMNLGRP_SA XFRMNLGRP_SA | 334 | #define XFRMNLGRP_SA XFRMNLGRP_SA |
307 | XFRMNLGRP_POLICY, | 335 | XFRMNLGRP_POLICY, |
308 | #define XFRMNLGRP_POLICY XFRMNLGRP_POLICY | 336 | #define XFRMNLGRP_POLICY XFRMNLGRP_POLICY |
337 | XFRMNLGRP_AEVENTS, | ||
338 | #define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS | ||
309 | __XFRMNLGRP_MAX | 339 | __XFRMNLGRP_MAX |
310 | }; | 340 | }; |
311 | #define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1) | 341 | #define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1) |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 8d362c49b8a9..bc005e62e434 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -20,6 +20,10 @@ | |||
20 | 20 | ||
21 | #define XFRM_ALIGN8(len) (((len) + 7) & ~7) | 21 | #define XFRM_ALIGN8(len) (((len) + 7) & ~7) |
22 | 22 | ||
23 | extern struct sock *xfrm_nl; | ||
24 | extern u32 sysctl_xfrm_aevent_etime; | ||
25 | extern u32 sysctl_xfrm_aevent_rseqth; | ||
26 | |||
23 | extern struct semaphore xfrm_cfg_sem; | 27 | extern struct semaphore xfrm_cfg_sem; |
24 | 28 | ||
25 | /* Organization of SPD aka "XFRM rules" | 29 | /* Organization of SPD aka "XFRM rules" |
@@ -135,6 +139,16 @@ struct xfrm_state | |||
135 | /* State for replay detection */ | 139 | /* State for replay detection */ |
136 | struct xfrm_replay_state replay; | 140 | struct xfrm_replay_state replay; |
137 | 141 | ||
142 | /* Replay detection state at the time we sent the last notification */ | ||
143 | struct xfrm_replay_state preplay; | ||
144 | |||
145 | /* Replay detection notification settings */ | ||
146 | u32 replay_maxage; | ||
147 | u32 replay_maxdiff; | ||
148 | |||
149 | /* Replay detection notification timer */ | ||
150 | struct timer_list rtimer; | ||
151 | |||
138 | /* Statistics */ | 152 | /* Statistics */ |
139 | struct xfrm_stats stats; | 153 | struct xfrm_stats stats; |
140 | 154 | ||
@@ -169,6 +183,7 @@ struct km_event | |||
169 | u32 hard; | 183 | u32 hard; |
170 | u32 proto; | 184 | u32 proto; |
171 | u32 byid; | 185 | u32 byid; |
186 | u32 aevent; | ||
172 | } data; | 187 | } data; |
173 | 188 | ||
174 | u32 seq; | 189 | u32 seq; |
@@ -305,7 +320,21 @@ struct xfrm_policy | |||
305 | struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; | 320 | struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; |
306 | }; | 321 | }; |
307 | 322 | ||
308 | #define XFRM_KM_TIMEOUT 30 | 323 | #define XFRM_KM_TIMEOUT 30 |
324 | /* which seqno */ | ||
325 | #define XFRM_REPLAY_SEQ 1 | ||
326 | #define XFRM_REPLAY_OSEQ 2 | ||
327 | #define XFRM_REPLAY_SEQ_MASK 3 | ||
328 | /* what happened */ | ||
329 | #define XFRM_REPLAY_UPDATE XFRM_AE_CR | ||
330 | #define XFRM_REPLAY_TIMEOUT XFRM_AE_CE | ||
331 | |||
332 | /* default aevent timeout in units of 100ms */ | ||
333 | #define XFRM_AE_ETIME 10 | ||
334 | /* Async Event timer multiplier */ | ||
335 | #define XFRM_AE_ETH_M 10 | ||
336 | /* default seq threshold size */ | ||
337 | #define XFRM_AE_SEQT_SIZE 2 | ||
309 | 338 | ||
310 | struct xfrm_mgr | 339 | struct xfrm_mgr |
311 | { | 340 | { |
@@ -865,6 +894,7 @@ extern int xfrm_state_delete(struct xfrm_state *x); | |||
865 | extern void xfrm_state_flush(u8 proto); | 894 | extern void xfrm_state_flush(u8 proto); |
866 | extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); | 895 | extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); |
867 | extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); | 896 | extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); |
897 | extern void xfrm_replay_notify(struct xfrm_state *x, int event); | ||
868 | extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb); | 898 | extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb); |
869 | extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); | 899 | extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); |
870 | extern int xfrm_init_state(struct xfrm_state *x); | 900 | extern int xfrm_init_state(struct xfrm_state *x); |
@@ -965,4 +995,16 @@ static inline int xfrm_policy_id2dir(u32 index) | |||
965 | return index & 7; | 995 | return index & 7; |
966 | } | 996 | } |
967 | 997 | ||
998 | static inline int xfrm_aevent_is_on(void) | ||
999 | { | ||
1000 | return netlink_has_listeners(xfrm_nl,XFRMNLGRP_AEVENTS); | ||
1001 | } | ||
1002 | |||
1003 | static inline void xfrm_aevent_doreplay(struct xfrm_state *x) | ||
1004 | { | ||
1005 | if (xfrm_aevent_is_on()) | ||
1006 | xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); | ||
1007 | } | ||
1008 | |||
1009 | |||
968 | #endif /* _NET_XFRM_H */ | 1010 | #endif /* _NET_XFRM_H */ |
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 2f278c8e4743..710453656721 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
@@ -26,6 +26,11 @@ extern int sysctl_core_destroy_delay; | |||
26 | extern char sysctl_divert_version[]; | 26 | extern char sysctl_divert_version[]; |
27 | #endif /* CONFIG_NET_DIVERT */ | 27 | #endif /* CONFIG_NET_DIVERT */ |
28 | 28 | ||
29 | #ifdef CONFIG_XFRM | ||
30 | extern u32 sysctl_xfrm_aevent_etime; | ||
31 | extern u32 sysctl_xfrm_aevent_rseqth; | ||
32 | #endif | ||
33 | |||
29 | ctl_table core_table[] = { | 34 | ctl_table core_table[] = { |
30 | #ifdef CONFIG_NET | 35 | #ifdef CONFIG_NET |
31 | { | 36 | { |
@@ -111,6 +116,24 @@ ctl_table core_table[] = { | |||
111 | .proc_handler = &proc_dostring | 116 | .proc_handler = &proc_dostring |
112 | }, | 117 | }, |
113 | #endif /* CONFIG_NET_DIVERT */ | 118 | #endif /* CONFIG_NET_DIVERT */ |
119 | #ifdef CONFIG_XFRM | ||
120 | { | ||
121 | .ctl_name = NET_CORE_AEVENT_ETIME, | ||
122 | .procname = "xfrm_aevent_etime", | ||
123 | .data = &sysctl_xfrm_aevent_etime, | ||
124 | .maxlen = sizeof(u32), | ||
125 | .mode = 0644, | ||
126 | .proc_handler = &proc_dointvec | ||
127 | }, | ||
128 | { | ||
129 | .ctl_name = NET_CORE_AEVENT_RSEQTH, | ||
130 | .procname = "xfrm_aevent_rseqth", | ||
131 | .data = &sysctl_xfrm_aevent_rseqth, | ||
132 | .maxlen = sizeof(u32), | ||
133 | .mode = 0644, | ||
134 | .proc_handler = &proc_dointvec | ||
135 | }, | ||
136 | #endif /* CONFIG_XFRM */ | ||
114 | #endif /* CONFIG_NET */ | 137 | #endif /* CONFIG_NET */ |
115 | { | 138 | { |
116 | .ctl_name = NET_CORE_SOMAXCONN, | 139 | .ctl_name = NET_CORE_SOMAXCONN, |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index c656cbaf35e8..8eaee499cad5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | 22 | ||
23 | u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME; | ||
24 | u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE; | ||
23 | /* Each xfrm_state may be linked to two tables: | 25 | /* Each xfrm_state may be linked to two tables: |
24 | 26 | ||
25 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) | 27 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) |
@@ -62,6 +64,8 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
62 | { | 64 | { |
63 | if (del_timer(&x->timer)) | 65 | if (del_timer(&x->timer)) |
64 | BUG(); | 66 | BUG(); |
67 | if (del_timer(&x->rtimer)) | ||
68 | BUG(); | ||
65 | kfree(x->aalg); | 69 | kfree(x->aalg); |
66 | kfree(x->ealg); | 70 | kfree(x->ealg); |
67 | kfree(x->calg); | 71 | kfree(x->calg); |
@@ -190,11 +194,16 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
190 | init_timer(&x->timer); | 194 | init_timer(&x->timer); |
191 | x->timer.function = xfrm_timer_handler; | 195 | x->timer.function = xfrm_timer_handler; |
192 | x->timer.data = (unsigned long)x; | 196 | x->timer.data = (unsigned long)x; |
197 | init_timer(&x->rtimer); | ||
198 | x->rtimer.function = xfrm_replay_timer_handler; | ||
199 | x->rtimer.data = (unsigned long)x; | ||
193 | x->curlft.add_time = (unsigned long)xtime.tv_sec; | 200 | x->curlft.add_time = (unsigned long)xtime.tv_sec; |
194 | x->lft.soft_byte_limit = XFRM_INF; | 201 | x->lft.soft_byte_limit = XFRM_INF; |
195 | x->lft.soft_packet_limit = XFRM_INF; | 202 | x->lft.soft_packet_limit = XFRM_INF; |
196 | x->lft.hard_byte_limit = XFRM_INF; | 203 | x->lft.hard_byte_limit = XFRM_INF; |
197 | x->lft.hard_packet_limit = XFRM_INF; | 204 | x->lft.hard_packet_limit = XFRM_INF; |
205 | x->replay_maxage = 0; | ||
206 | x->replay_maxdiff = 0; | ||
198 | spin_lock_init(&x->lock); | 207 | spin_lock_init(&x->lock); |
199 | } | 208 | } |
200 | return x; | 209 | return x; |
@@ -228,6 +237,8 @@ static int __xfrm_state_delete(struct xfrm_state *x) | |||
228 | spin_unlock(&xfrm_state_lock); | 237 | spin_unlock(&xfrm_state_lock); |
229 | if (del_timer(&x->timer)) | 238 | if (del_timer(&x->timer)) |
230 | __xfrm_state_put(x); | 239 | __xfrm_state_put(x); |
240 | if (del_timer(&x->rtimer)) | ||
241 | __xfrm_state_put(x); | ||
231 | 242 | ||
232 | /* The number two in this test is the reference | 243 | /* The number two in this test is the reference |
233 | * mentioned in the comment below plus the reference | 244 | * mentioned in the comment below plus the reference |
@@ -426,6 +437,10 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
426 | if (!mod_timer(&x->timer, jiffies + HZ)) | 437 | if (!mod_timer(&x->timer, jiffies + HZ)) |
427 | xfrm_state_hold(x); | 438 | xfrm_state_hold(x); |
428 | 439 | ||
440 | if (x->replay_maxage && | ||
441 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | ||
442 | xfrm_state_hold(x); | ||
443 | |||
429 | wake_up(&km_waitq); | 444 | wake_up(&km_waitq); |
430 | } | 445 | } |
431 | 446 | ||
@@ -762,6 +777,62 @@ out: | |||
762 | } | 777 | } |
763 | EXPORT_SYMBOL(xfrm_state_walk); | 778 | EXPORT_SYMBOL(xfrm_state_walk); |
764 | 779 | ||
780 | |||
781 | void xfrm_replay_notify(struct xfrm_state *x, int event) | ||
782 | { | ||
783 | struct km_event c; | ||
784 | /* we send notify messages in case | ||
785 | * 1. we updated on of the sequence numbers, and the seqno difference | ||
786 | * is at least x->replay_maxdiff, in this case we also update the | ||
787 | * timeout of our timer function | ||
788 | * 2. if x->replay_maxage has elapsed since last update, | ||
789 | * and there were changes | ||
790 | * | ||
791 | * The state structure must be locked! | ||
792 | */ | ||
793 | |||
794 | switch (event) { | ||
795 | case XFRM_REPLAY_UPDATE: | ||
796 | if (x->replay_maxdiff && | ||
797 | (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && | ||
798 | (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) | ||
799 | return; | ||
800 | |||
801 | break; | ||
802 | |||
803 | case XFRM_REPLAY_TIMEOUT: | ||
804 | if ((x->replay.seq == x->preplay.seq) && | ||
805 | (x->replay.bitmap == x->preplay.bitmap) && | ||
806 | (x->replay.oseq == x->preplay.oseq)) | ||
807 | return; | ||
808 | |||
809 | break; | ||
810 | } | ||
811 | |||
812 | memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); | ||
813 | c.event = XFRM_MSG_NEWAE; | ||
814 | c.data.aevent = event; | ||
815 | km_state_notify(x, &c); | ||
816 | |||
817 | resched: | ||
818 | if (x->replay_maxage && | ||
819 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | ||
820 | xfrm_state_hold(x); | ||
821 | |||
822 | } | ||
823 | |||
824 | static void xfrm_replay_timer_handler(unsigned long data) | ||
825 | { | ||
826 | struct xfrm_state *x = (struct xfrm_state*)data; | ||
827 | |||
828 | spin_lock(&x->lock); | ||
829 | |||
830 | if (xfrm_aevent_is_on() && x->km.state == XFRM_STATE_VALID) | ||
831 | xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); | ||
832 | |||
833 | spin_unlock(&x->lock); | ||
834 | } | ||
835 | |||
765 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) | 836 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) |
766 | { | 837 | { |
767 | u32 diff; | 838 | u32 diff; |
@@ -805,6 +876,9 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq) | |||
805 | diff = x->replay.seq - seq; | 876 | diff = x->replay.seq - seq; |
806 | x->replay.bitmap |= (1U << diff); | 877 | x->replay.bitmap |= (1U << diff); |
807 | } | 878 | } |
879 | |||
880 | if (xfrm_aevent_is_on()) | ||
881 | xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); | ||
808 | } | 882 | } |
809 | EXPORT_SYMBOL(xfrm_replay_advance); | 883 | EXPORT_SYMBOL(xfrm_replay_advance); |
810 | 884 | ||
@@ -835,7 +909,7 @@ void km_state_notify(struct xfrm_state *x, struct km_event *c) | |||
835 | EXPORT_SYMBOL(km_policy_notify); | 909 | EXPORT_SYMBOL(km_policy_notify); |
836 | EXPORT_SYMBOL(km_state_notify); | 910 | EXPORT_SYMBOL(km_state_notify); |
837 | 911 | ||
838 | static void km_state_expired(struct xfrm_state *x, int hard) | 912 | void km_state_expired(struct xfrm_state *x, int hard) |
839 | { | 913 | { |
840 | struct km_event c; | 914 | struct km_event c; |
841 | 915 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7de17559249a..6f643e58e044 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -28,7 +28,7 @@ | |||
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; | 31 | struct sock *xfrm_nl; |
32 | 32 | ||
33 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) | 33 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) |
34 | { | 34 | { |
@@ -1618,3 +1618,5 @@ module_init(xfrm_user_init); | |||
1618 | module_exit(xfrm_user_exit); | 1618 | module_exit(xfrm_user_exit); |
1619 | MODULE_LICENSE("GPL"); | 1619 | MODULE_LICENSE("GPL"); |
1620 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); | 1620 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); |
1621 | EXPORT_SYMBOL(xfrm_nl); | ||
1622 | |||