diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 198 |
1 files changed, 186 insertions, 12 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index fdb08d9f34aa..a35f9e4ede26 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -183,9 +183,6 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock); | |||
183 | 183 | ||
184 | int __xfrm_state_delete(struct xfrm_state *x); | 184 | int __xfrm_state_delete(struct xfrm_state *x); |
185 | 185 | ||
186 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); | ||
187 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | ||
188 | |||
189 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 186 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
190 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); | 187 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); |
191 | 188 | ||
@@ -230,7 +227,7 @@ static inline unsigned long make_jiffies(long secs) | |||
230 | if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) | 227 | if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) |
231 | return MAX_SCHEDULE_TIMEOUT-1; | 228 | return MAX_SCHEDULE_TIMEOUT-1; |
232 | else | 229 | else |
233 | return secs*HZ; | 230 | return secs*HZ; |
234 | } | 231 | } |
235 | 232 | ||
236 | static void xfrm_timer_handler(unsigned long data) | 233 | static void xfrm_timer_handler(unsigned long data) |
@@ -526,7 +523,7 @@ static void xfrm_hash_grow_check(int have_hash_collision) | |||
526 | } | 523 | } |
527 | 524 | ||
528 | struct xfrm_state * | 525 | struct xfrm_state * |
529 | xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | 526 | xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, |
530 | struct flowi *fl, struct xfrm_tmpl *tmpl, | 527 | struct flowi *fl, struct xfrm_tmpl *tmpl, |
531 | struct xfrm_policy *pol, int *err, | 528 | struct xfrm_policy *pol, int *err, |
532 | unsigned short family) | 529 | unsigned short family) |
@@ -537,7 +534,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
537 | int acquire_in_progress = 0; | 534 | int acquire_in_progress = 0; |
538 | int error = 0; | 535 | int error = 0; |
539 | struct xfrm_state *best = NULL; | 536 | struct xfrm_state *best = NULL; |
540 | 537 | ||
541 | spin_lock_bh(&xfrm_state_lock); | 538 | spin_lock_bh(&xfrm_state_lock); |
542 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | 539 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { |
543 | if (x->props.family == family && | 540 | if (x->props.family == family && |
@@ -573,7 +570,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
573 | acquire_in_progress = 1; | 570 | acquire_in_progress = 1; |
574 | } else if (x->km.state == XFRM_STATE_ERROR || | 571 | } else if (x->km.state == XFRM_STATE_ERROR || |
575 | x->km.state == XFRM_STATE_EXPIRED) { | 572 | x->km.state == XFRM_STATE_EXPIRED) { |
576 | if (xfrm_selector_match(&x->sel, fl, family) && | 573 | if (xfrm_selector_match(&x->sel, fl, family) && |
577 | security_xfrm_state_pol_flow_match(x, pol, fl)) | 574 | security_xfrm_state_pol_flow_match(x, pol, fl)) |
578 | error = -ESRCH; | 575 | error = -ESRCH; |
579 | } | 576 | } |
@@ -831,6 +828,160 @@ out: | |||
831 | } | 828 | } |
832 | EXPORT_SYMBOL(xfrm_state_add); | 829 | EXPORT_SYMBOL(xfrm_state_add); |
833 | 830 | ||
831 | #ifdef CONFIG_XFRM_MIGRATE | ||
832 | struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | ||
833 | { | ||
834 | int err = -ENOMEM; | ||
835 | struct xfrm_state *x = xfrm_state_alloc(); | ||
836 | if (!x) | ||
837 | goto error; | ||
838 | |||
839 | memcpy(&x->id, &orig->id, sizeof(x->id)); | ||
840 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); | ||
841 | memcpy(&x->lft, &orig->lft, sizeof(x->lft)); | ||
842 | x->props.mode = orig->props.mode; | ||
843 | x->props.replay_window = orig->props.replay_window; | ||
844 | x->props.reqid = orig->props.reqid; | ||
845 | x->props.family = orig->props.family; | ||
846 | x->props.saddr = orig->props.saddr; | ||
847 | |||
848 | if (orig->aalg) { | ||
849 | x->aalg = xfrm_algo_clone(orig->aalg); | ||
850 | if (!x->aalg) | ||
851 | goto error; | ||
852 | } | ||
853 | x->props.aalgo = orig->props.aalgo; | ||
854 | |||
855 | if (orig->ealg) { | ||
856 | x->ealg = xfrm_algo_clone(orig->ealg); | ||
857 | if (!x->ealg) | ||
858 | goto error; | ||
859 | } | ||
860 | x->props.ealgo = orig->props.ealgo; | ||
861 | |||
862 | if (orig->calg) { | ||
863 | x->calg = xfrm_algo_clone(orig->calg); | ||
864 | if (!x->calg) | ||
865 | goto error; | ||
866 | } | ||
867 | x->props.calgo = orig->props.calgo; | ||
868 | |||
869 | if (orig->encap) { | ||
870 | x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); | ||
871 | if (!x->encap) | ||
872 | goto error; | ||
873 | } | ||
874 | |||
875 | if (orig->coaddr) { | ||
876 | x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), | ||
877 | GFP_KERNEL); | ||
878 | if (!x->coaddr) | ||
879 | goto error; | ||
880 | } | ||
881 | |||
882 | err = xfrm_init_state(x); | ||
883 | if (err) | ||
884 | goto error; | ||
885 | |||
886 | x->props.flags = orig->props.flags; | ||
887 | |||
888 | x->curlft.add_time = orig->curlft.add_time; | ||
889 | x->km.state = orig->km.state; | ||
890 | x->km.seq = orig->km.seq; | ||
891 | |||
892 | return x; | ||
893 | |||
894 | error: | ||
895 | if (errp) | ||
896 | *errp = err; | ||
897 | if (x) { | ||
898 | kfree(x->aalg); | ||
899 | kfree(x->ealg); | ||
900 | kfree(x->calg); | ||
901 | kfree(x->encap); | ||
902 | kfree(x->coaddr); | ||
903 | } | ||
904 | kfree(x); | ||
905 | return NULL; | ||
906 | } | ||
907 | EXPORT_SYMBOL(xfrm_state_clone); | ||
908 | |||
909 | /* xfrm_state_lock is held */ | ||
910 | struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) | ||
911 | { | ||
912 | unsigned int h; | ||
913 | struct xfrm_state *x; | ||
914 | struct hlist_node *entry; | ||
915 | |||
916 | if (m->reqid) { | ||
917 | h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, | ||
918 | m->reqid, m->old_family); | ||
919 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | ||
920 | if (x->props.mode != m->mode || | ||
921 | x->id.proto != m->proto) | ||
922 | continue; | ||
923 | if (m->reqid && x->props.reqid != m->reqid) | ||
924 | continue; | ||
925 | if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, | ||
926 | m->old_family) || | ||
927 | xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, | ||
928 | m->old_family)) | ||
929 | continue; | ||
930 | xfrm_state_hold(x); | ||
931 | return x; | ||
932 | } | ||
933 | } else { | ||
934 | h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, | ||
935 | m->old_family); | ||
936 | hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { | ||
937 | if (x->props.mode != m->mode || | ||
938 | x->id.proto != m->proto) | ||
939 | continue; | ||
940 | if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, | ||
941 | m->old_family) || | ||
942 | xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, | ||
943 | m->old_family)) | ||
944 | continue; | ||
945 | xfrm_state_hold(x); | ||
946 | return x; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | return NULL; | ||
951 | } | ||
952 | EXPORT_SYMBOL(xfrm_migrate_state_find); | ||
953 | |||
954 | struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, | ||
955 | struct xfrm_migrate *m) | ||
956 | { | ||
957 | struct xfrm_state *xc; | ||
958 | int err; | ||
959 | |||
960 | xc = xfrm_state_clone(x, &err); | ||
961 | if (!xc) | ||
962 | return NULL; | ||
963 | |||
964 | memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); | ||
965 | memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); | ||
966 | |||
967 | /* add state */ | ||
968 | if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { | ||
969 | /* a care is needed when the destination address of the | ||
970 | state is to be updated as it is a part of triplet */ | ||
971 | xfrm_state_insert(xc); | ||
972 | } else { | ||
973 | if ((err = xfrm_state_add(xc)) < 0) | ||
974 | goto error; | ||
975 | } | ||
976 | |||
977 | return xc; | ||
978 | error: | ||
979 | kfree(xc); | ||
980 | return NULL; | ||
981 | } | ||
982 | EXPORT_SYMBOL(xfrm_state_migrate); | ||
983 | #endif | ||
984 | |||
834 | int xfrm_state_update(struct xfrm_state *x) | 985 | int xfrm_state_update(struct xfrm_state *x) |
835 | { | 986 | { |
836 | struct xfrm_state *x1; | 987 | struct xfrm_state *x1; |
@@ -970,8 +1121,8 @@ xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
970 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | 1121 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); |
971 | 1122 | ||
972 | struct xfrm_state * | 1123 | struct xfrm_state * |
973 | xfrm_find_acq(u8 mode, u32 reqid, u8 proto, | 1124 | xfrm_find_acq(u8 mode, u32 reqid, u8 proto, |
974 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1125 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
975 | int create, unsigned short family) | 1126 | int create, unsigned short family) |
976 | { | 1127 | { |
977 | struct xfrm_state *x; | 1128 | struct xfrm_state *x; |
@@ -1345,6 +1496,26 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) | |||
1345 | } | 1496 | } |
1346 | EXPORT_SYMBOL(km_policy_expired); | 1497 | EXPORT_SYMBOL(km_policy_expired); |
1347 | 1498 | ||
1499 | int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | ||
1500 | struct xfrm_migrate *m, int num_migrate) | ||
1501 | { | ||
1502 | int err = -EINVAL; | ||
1503 | int ret; | ||
1504 | struct xfrm_mgr *km; | ||
1505 | |||
1506 | read_lock(&xfrm_km_lock); | ||
1507 | list_for_each_entry(km, &xfrm_km_list, list) { | ||
1508 | if (km->migrate) { | ||
1509 | ret = km->migrate(sel, dir, type, m, num_migrate); | ||
1510 | if (!ret) | ||
1511 | err = ret; | ||
1512 | } | ||
1513 | } | ||
1514 | read_unlock(&xfrm_km_lock); | ||
1515 | return err; | ||
1516 | } | ||
1517 | EXPORT_SYMBOL(km_migrate); | ||
1518 | |||
1348 | int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) | 1519 | int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) |
1349 | { | 1520 | { |
1350 | int err = -EINVAL; | 1521 | int err = -EINVAL; |
@@ -1458,7 +1629,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1458 | } | 1629 | } |
1459 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); | 1630 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); |
1460 | 1631 | ||
1461 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) | 1632 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) |
1462 | { | 1633 | { |
1463 | struct xfrm_state_afinfo *afinfo; | 1634 | struct xfrm_state_afinfo *afinfo; |
1464 | if (unlikely(family >= NPROTO)) | 1635 | if (unlikely(family >= NPROTO)) |
@@ -1470,11 +1641,14 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) | |||
1470 | return afinfo; | 1641 | return afinfo; |
1471 | } | 1642 | } |
1472 | 1643 | ||
1473 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) | 1644 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) |
1474 | { | 1645 | { |
1475 | read_unlock(&xfrm_state_afinfo_lock); | 1646 | read_unlock(&xfrm_state_afinfo_lock); |
1476 | } | 1647 | } |
1477 | 1648 | ||
1649 | EXPORT_SYMBOL(xfrm_state_get_afinfo); | ||
1650 | EXPORT_SYMBOL(xfrm_state_put_afinfo); | ||
1651 | |||
1478 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ | 1652 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ |
1479 | void xfrm_state_delete_tunnel(struct xfrm_state *x) | 1653 | void xfrm_state_delete_tunnel(struct xfrm_state *x) |
1480 | { | 1654 | { |
@@ -1564,7 +1738,7 @@ error: | |||
1564 | } | 1738 | } |
1565 | 1739 | ||
1566 | EXPORT_SYMBOL(xfrm_init_state); | 1740 | EXPORT_SYMBOL(xfrm_init_state); |
1567 | 1741 | ||
1568 | void __init xfrm_state_init(void) | 1742 | void __init xfrm_state_init(void) |
1569 | { | 1743 | { |
1570 | unsigned int sz; | 1744 | unsigned int sz; |