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.c198
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
184int __xfrm_state_delete(struct xfrm_state *x); 184int __xfrm_state_delete(struct xfrm_state *x);
185 185
186static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
187static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
188
189int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 186int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
190void km_state_expired(struct xfrm_state *x, int hard, u32 pid); 187void 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
236static void xfrm_timer_handler(unsigned long data) 233static 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
528struct xfrm_state * 525struct xfrm_state *
529xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 526xfrm_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}
832EXPORT_SYMBOL(xfrm_state_add); 829EXPORT_SYMBOL(xfrm_state_add);
833 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
834int xfrm_state_update(struct xfrm_state *x) 985int 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,
970EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1121EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
971 1122
972struct xfrm_state * 1123struct xfrm_state *
973xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 1124xfrm_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}
1346EXPORT_SYMBOL(km_policy_expired); 1497EXPORT_SYMBOL(km_policy_expired);
1347 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
1348int 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)
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}
1459EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 1630EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1460 1631
1461static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) 1632struct 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
1473static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) 1644void 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
1649EXPORT_SYMBOL(xfrm_state_get_afinfo);
1650EXPORT_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 */
1479void xfrm_state_delete_tunnel(struct xfrm_state *x) 1653void xfrm_state_delete_tunnel(struct xfrm_state *x)
1480{ 1654{
@@ -1564,7 +1738,7 @@ error:
1564} 1738}
1565 1739
1566EXPORT_SYMBOL(xfrm_init_state); 1740EXPORT_SYMBOL(xfrm_init_state);
1567 1741
1568void __init xfrm_state_init(void) 1742void __init xfrm_state_init(void)
1569{ 1743{
1570 unsigned int sz; 1744 unsigned int sz;