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 | { |
