aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r--net/xfrm/xfrm_state.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 24f7bfd07af2..91b02687db52 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -828,6 +828,160 @@ out:
828} 828}
829EXPORT_SYMBOL(xfrm_state_add); 829EXPORT_SYMBOL(xfrm_state_add);
830 830
831#ifdef CONFIG_XFRM_MIGRATE
832struct 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}
907EXPORT_SYMBOL(xfrm_state_clone);
908
909/* xfrm_state_lock is held */
910struct 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}
952EXPORT_SYMBOL(xfrm_migrate_state_find);
953
954struct 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;
978error:
979 kfree(xc);
980 return NULL;
981}
982EXPORT_SYMBOL(xfrm_state_migrate);
983#endif
984
831int xfrm_state_update(struct xfrm_state *x) 985int xfrm_state_update(struct xfrm_state *x)
832{ 986{
833 struct xfrm_state *x1; 987 struct xfrm_state *x1;
@@ -1342,6 +1496,26 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
1342} 1496}
1343EXPORT_SYMBOL(km_policy_expired); 1497EXPORT_SYMBOL(km_policy_expired);
1344 1498
1499int 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}
1517EXPORT_SYMBOL(km_migrate);
1518
1345int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 1519int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
1346{ 1520{
1347 int err = -EINVAL; 1521 int err = -EINVAL;