diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 81 |
1 files changed, 56 insertions, 25 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index d11747c2a763..2537f26f097c 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -50,7 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock); | |||
50 | 50 | ||
51 | static int xfrm_state_gc_flush_bundles; | 51 | static int xfrm_state_gc_flush_bundles; |
52 | 52 | ||
53 | static void __xfrm_state_delete(struct xfrm_state *x); | 53 | static int __xfrm_state_delete(struct xfrm_state *x); |
54 | 54 | ||
55 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); | 55 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); |
56 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 56 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
@@ -154,6 +154,7 @@ static void xfrm_timer_handler(unsigned long data) | |||
154 | next = tmo; | 154 | next = tmo; |
155 | } | 155 | } |
156 | 156 | ||
157 | x->km.dying = warn; | ||
157 | if (warn) | 158 | if (warn) |
158 | km_state_expired(x, 0); | 159 | km_state_expired(x, 0); |
159 | resched: | 160 | resched: |
@@ -169,9 +170,8 @@ expired: | |||
169 | next = 2; | 170 | next = 2; |
170 | goto resched; | 171 | goto resched; |
171 | } | 172 | } |
172 | if (x->id.spi != 0) | 173 | if (!__xfrm_state_delete(x) && x->id.spi) |
173 | km_state_expired(x, 1); | 174 | km_state_expired(x, 1); |
174 | __xfrm_state_delete(x); | ||
175 | 175 | ||
176 | out: | 176 | out: |
177 | spin_unlock(&x->lock); | 177 | spin_unlock(&x->lock); |
@@ -215,8 +215,10 @@ void __xfrm_state_destroy(struct xfrm_state *x) | |||
215 | } | 215 | } |
216 | EXPORT_SYMBOL(__xfrm_state_destroy); | 216 | EXPORT_SYMBOL(__xfrm_state_destroy); |
217 | 217 | ||
218 | static void __xfrm_state_delete(struct xfrm_state *x) | 218 | static int __xfrm_state_delete(struct xfrm_state *x) |
219 | { | 219 | { |
220 | int err = -ESRCH; | ||
221 | |||
220 | if (x->km.state != XFRM_STATE_DEAD) { | 222 | if (x->km.state != XFRM_STATE_DEAD) { |
221 | x->km.state = XFRM_STATE_DEAD; | 223 | x->km.state = XFRM_STATE_DEAD; |
222 | spin_lock(&xfrm_state_lock); | 224 | spin_lock(&xfrm_state_lock); |
@@ -245,14 +247,21 @@ static void __xfrm_state_delete(struct xfrm_state *x) | |||
245 | * is what we are dropping here. | 247 | * is what we are dropping here. |
246 | */ | 248 | */ |
247 | atomic_dec(&x->refcnt); | 249 | atomic_dec(&x->refcnt); |
250 | err = 0; | ||
248 | } | 251 | } |
252 | |||
253 | return err; | ||
249 | } | 254 | } |
250 | 255 | ||
251 | void xfrm_state_delete(struct xfrm_state *x) | 256 | int xfrm_state_delete(struct xfrm_state *x) |
252 | { | 257 | { |
258 | int err; | ||
259 | |||
253 | spin_lock_bh(&x->lock); | 260 | spin_lock_bh(&x->lock); |
254 | __xfrm_state_delete(x); | 261 | err = __xfrm_state_delete(x); |
255 | spin_unlock_bh(&x->lock); | 262 | spin_unlock_bh(&x->lock); |
263 | |||
264 | return err; | ||
256 | } | 265 | } |
257 | EXPORT_SYMBOL(xfrm_state_delete); | 266 | EXPORT_SYMBOL(xfrm_state_delete); |
258 | 267 | ||
@@ -557,16 +566,18 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
557 | 566 | ||
558 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 567 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
559 | x->curlft.packets >= x->lft.hard_packet_limit) { | 568 | x->curlft.packets >= x->lft.hard_packet_limit) { |
560 | km_state_expired(x, 1); | 569 | x->km.state = XFRM_STATE_EXPIRED; |
561 | if (!mod_timer(&x->timer, jiffies + XFRM_ACQ_EXPIRES*HZ)) | 570 | if (!mod_timer(&x->timer, jiffies)) |
562 | xfrm_state_hold(x); | 571 | xfrm_state_hold(x); |
563 | return -EINVAL; | 572 | return -EINVAL; |
564 | } | 573 | } |
565 | 574 | ||
566 | if (!x->km.dying && | 575 | if (!x->km.dying && |
567 | (x->curlft.bytes >= x->lft.soft_byte_limit || | 576 | (x->curlft.bytes >= x->lft.soft_byte_limit || |
568 | x->curlft.packets >= x->lft.soft_packet_limit)) | 577 | x->curlft.packets >= x->lft.soft_packet_limit)) { |
578 | x->km.dying = 1; | ||
569 | km_state_expired(x, 0); | 579 | km_state_expired(x, 0); |
580 | } | ||
570 | return 0; | 581 | return 0; |
571 | } | 582 | } |
572 | EXPORT_SYMBOL(xfrm_state_check_expire); | 583 | EXPORT_SYMBOL(xfrm_state_check_expire); |
@@ -796,34 +807,56 @@ EXPORT_SYMBOL(xfrm_replay_advance); | |||
796 | static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list); | 807 | static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list); |
797 | static DEFINE_RWLOCK(xfrm_km_lock); | 808 | static DEFINE_RWLOCK(xfrm_km_lock); |
798 | 809 | ||
799 | static void km_state_expired(struct xfrm_state *x, int hard) | 810 | void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) |
800 | { | 811 | { |
801 | struct xfrm_mgr *km; | 812 | struct xfrm_mgr *km; |
802 | 813 | ||
803 | if (hard) | 814 | read_lock(&xfrm_km_lock); |
804 | x->km.state = XFRM_STATE_EXPIRED; | 815 | list_for_each_entry(km, &xfrm_km_list, list) |
805 | else | 816 | if (km->notify_policy) |
806 | x->km.dying = 1; | 817 | km->notify_policy(xp, dir, c); |
818 | read_unlock(&xfrm_km_lock); | ||
819 | } | ||
807 | 820 | ||
821 | void km_state_notify(struct xfrm_state *x, struct km_event *c) | ||
822 | { | ||
823 | struct xfrm_mgr *km; | ||
808 | read_lock(&xfrm_km_lock); | 824 | read_lock(&xfrm_km_lock); |
809 | list_for_each_entry(km, &xfrm_km_list, list) | 825 | list_for_each_entry(km, &xfrm_km_list, list) |
810 | km->notify(x, hard); | 826 | if (km->notify) |
827 | km->notify(x, c); | ||
811 | read_unlock(&xfrm_km_lock); | 828 | read_unlock(&xfrm_km_lock); |
829 | } | ||
830 | |||
831 | EXPORT_SYMBOL(km_policy_notify); | ||
832 | EXPORT_SYMBOL(km_state_notify); | ||
833 | |||
834 | static void km_state_expired(struct xfrm_state *x, int hard) | ||
835 | { | ||
836 | struct km_event c; | ||
837 | |||
838 | c.data.hard = hard; | ||
839 | c.event = XFRM_MSG_EXPIRE; | ||
840 | km_state_notify(x, &c); | ||
812 | 841 | ||
813 | if (hard) | 842 | if (hard) |
814 | wake_up(&km_waitq); | 843 | wake_up(&km_waitq); |
815 | } | 844 | } |
816 | 845 | ||
846 | /* | ||
847 | * We send to all registered managers regardless of failure | ||
848 | * We are happy with one success | ||
849 | */ | ||
817 | static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) | 850 | static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) |
818 | { | 851 | { |
819 | int err = -EINVAL; | 852 | int err = -EINVAL, acqret; |
820 | struct xfrm_mgr *km; | 853 | struct xfrm_mgr *km; |
821 | 854 | ||
822 | read_lock(&xfrm_km_lock); | 855 | read_lock(&xfrm_km_lock); |
823 | list_for_each_entry(km, &xfrm_km_list, list) { | 856 | list_for_each_entry(km, &xfrm_km_list, list) { |
824 | err = km->acquire(x, t, pol, XFRM_POLICY_OUT); | 857 | acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT); |
825 | if (!err) | 858 | if (!acqret) |
826 | break; | 859 | err = acqret; |
827 | } | 860 | } |
828 | read_unlock(&xfrm_km_lock); | 861 | read_unlock(&xfrm_km_lock); |
829 | return err; | 862 | return err; |
@@ -848,13 +881,11 @@ EXPORT_SYMBOL(km_new_mapping); | |||
848 | 881 | ||
849 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard) | 882 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard) |
850 | { | 883 | { |
851 | struct xfrm_mgr *km; | 884 | struct km_event c; |
852 | 885 | ||
853 | read_lock(&xfrm_km_lock); | 886 | c.data.hard = hard; |
854 | list_for_each_entry(km, &xfrm_km_list, list) | 887 | c.event = XFRM_MSG_POLEXPIRE; |
855 | if (km->notify_policy) | 888 | km_policy_notify(pol, dir, &c); |
856 | km->notify_policy(pol, dir, hard); | ||
857 | read_unlock(&xfrm_km_lock); | ||
858 | 889 | ||
859 | if (hard) | 890 | if (hard) |
860 | wake_up(&km_waitq); | 891 | wake_up(&km_waitq); |