diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 58 |
1 files changed, 34 insertions, 24 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 9fa3322b2a7d..9f8530356b86 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -669,7 +669,7 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
669 | return 0; | 669 | return 0; |
670 | } | 670 | } |
671 | 671 | ||
672 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) | 672 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) |
673 | { | 673 | { |
674 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); | 674 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); |
675 | struct xfrm_state *x; | 675 | struct xfrm_state *x; |
@@ -689,7 +689,7 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
689 | return NULL; | 689 | return NULL; |
690 | } | 690 | } |
691 | 691 | ||
692 | static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) | 692 | static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) |
693 | { | 693 | { |
694 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); | 694 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); |
695 | struct xfrm_state *x; | 695 | struct xfrm_state *x; |
@@ -713,12 +713,14 @@ static inline struct xfrm_state * | |||
713 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) | 713 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) |
714 | { | 714 | { |
715 | struct net *net = xs_net(x); | 715 | struct net *net = xs_net(x); |
716 | u32 mark = x->mark.v & x->mark.m; | ||
716 | 717 | ||
717 | if (use_spi) | 718 | if (use_spi) |
718 | return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi, | 719 | return __xfrm_state_lookup(net, mark, &x->id.daddr, |
719 | x->id.proto, family); | 720 | x->id.spi, x->id.proto, family); |
720 | else | 721 | else |
721 | return __xfrm_state_lookup_byaddr(net, &x->id.daddr, | 722 | return __xfrm_state_lookup_byaddr(net, mark, |
723 | &x->id.daddr, | ||
722 | &x->props.saddr, | 724 | &x->props.saddr, |
723 | x->id.proto, family); | 725 | x->id.proto, family); |
724 | } | 726 | } |
@@ -783,6 +785,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
783 | int acquire_in_progress = 0; | 785 | int acquire_in_progress = 0; |
784 | int error = 0; | 786 | int error = 0; |
785 | struct xfrm_state *best = NULL; | 787 | struct xfrm_state *best = NULL; |
788 | u32 mark = pol->mark.v & pol->mark.m; | ||
786 | 789 | ||
787 | to_put = NULL; | 790 | to_put = NULL; |
788 | 791 | ||
@@ -819,7 +822,7 @@ found: | |||
819 | x = best; | 822 | x = best; |
820 | if (!x && !error && !acquire_in_progress) { | 823 | if (!x && !error && !acquire_in_progress) { |
821 | if (tmpl->id.spi && | 824 | if (tmpl->id.spi && |
822 | (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi, | 825 | (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, |
823 | tmpl->id.proto, family)) != NULL) { | 826 | tmpl->id.proto, family)) != NULL) { |
824 | to_put = x0; | 827 | to_put = x0; |
825 | error = -EEXIST; | 828 | error = -EEXIST; |
@@ -833,6 +836,7 @@ found: | |||
833 | /* Initialize temporary selector matching only | 836 | /* Initialize temporary selector matching only |
834 | * to current session. */ | 837 | * to current session. */ |
835 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); | 838 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); |
839 | memcpy(&x->mark, &pol->mark, sizeof(x->mark)); | ||
836 | 840 | ||
837 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); | 841 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); |
838 | if (error) { | 842 | if (error) { |
@@ -875,7 +879,7 @@ out: | |||
875 | } | 879 | } |
876 | 880 | ||
877 | struct xfrm_state * | 881 | struct xfrm_state * |
878 | xfrm_stateonly_find(struct net *net, | 882 | xfrm_stateonly_find(struct net *net, u32 mark, |
879 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 883 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
880 | unsigned short family, u8 mode, u8 proto, u32 reqid) | 884 | unsigned short family, u8 mode, u8 proto, u32 reqid) |
881 | { | 885 | { |
@@ -971,7 +975,7 @@ void xfrm_state_insert(struct xfrm_state *x) | |||
971 | EXPORT_SYMBOL(xfrm_state_insert); | 975 | EXPORT_SYMBOL(xfrm_state_insert); |
972 | 976 | ||
973 | /* xfrm_state_lock is held */ | 977 | /* xfrm_state_lock is held */ |
974 | static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) | 978 | static struct xfrm_state *__find_acq_core(struct net *net, struct xfrm_mark *m, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) |
975 | { | 979 | { |
976 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); | 980 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); |
977 | struct hlist_node *entry; | 981 | struct hlist_node *entry; |
@@ -1026,6 +1030,8 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
1026 | x->props.family = family; | 1030 | x->props.family = family; |
1027 | x->props.mode = mode; | 1031 | x->props.mode = mode; |
1028 | x->props.reqid = reqid; | 1032 | x->props.reqid = reqid; |
1033 | x->mark.v = m->v; | ||
1034 | x->mark.m = m->m; | ||
1029 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 1035 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
1030 | xfrm_state_hold(x); | 1036 | xfrm_state_hold(x); |
1031 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); | 1037 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
@@ -1042,7 +1048,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
1042 | return x; | 1048 | return x; |
1043 | } | 1049 | } |
1044 | 1050 | ||
1045 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq); | 1051 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); |
1046 | 1052 | ||
1047 | int xfrm_state_add(struct xfrm_state *x) | 1053 | int xfrm_state_add(struct xfrm_state *x) |
1048 | { | 1054 | { |
@@ -1050,6 +1056,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1050 | struct xfrm_state *x1, *to_put; | 1056 | struct xfrm_state *x1, *to_put; |
1051 | int family; | 1057 | int family; |
1052 | int err; | 1058 | int err; |
1059 | u32 mark = x->mark.v & x->mark.m; | ||
1053 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | 1060 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); |
1054 | 1061 | ||
1055 | family = x->props.family; | 1062 | family = x->props.family; |
@@ -1067,7 +1074,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1067 | } | 1074 | } |
1068 | 1075 | ||
1069 | if (use_spi && x->km.seq) { | 1076 | if (use_spi && x->km.seq) { |
1070 | x1 = __xfrm_find_acq_byseq(net, x->km.seq); | 1077 | x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); |
1071 | if (x1 && ((x1->id.proto != x->id.proto) || | 1078 | if (x1 && ((x1->id.proto != x->id.proto) || |
1072 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { | 1079 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { |
1073 | to_put = x1; | 1080 | to_put = x1; |
@@ -1076,8 +1083,8 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1076 | } | 1083 | } |
1077 | 1084 | ||
1078 | if (use_spi && !x1) | 1085 | if (use_spi && !x1) |
1079 | x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid, | 1086 | x1 = __find_acq_core(net, &x->mark, family, x->props.mode, |
1080 | x->id.proto, | 1087 | x->props.reqid, x->id.proto, |
1081 | &x->id.daddr, &x->props.saddr, 0); | 1088 | &x->id.daddr, &x->props.saddr, 0); |
1082 | 1089 | ||
1083 | __xfrm_state_bump_genids(x); | 1090 | __xfrm_state_bump_genids(x); |
@@ -1151,6 +1158,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1151 | goto error; | 1158 | goto error; |
1152 | } | 1159 | } |
1153 | 1160 | ||
1161 | memcpy(&x->mark, &orig->mark, sizeof(x->mark)); | ||
1162 | |||
1154 | err = xfrm_init_state(x); | 1163 | err = xfrm_init_state(x); |
1155 | if (err) | 1164 | if (err) |
1156 | goto error; | 1165 | goto error; |
@@ -1342,41 +1351,41 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
1342 | EXPORT_SYMBOL(xfrm_state_check_expire); | 1351 | EXPORT_SYMBOL(xfrm_state_check_expire); |
1343 | 1352 | ||
1344 | struct xfrm_state * | 1353 | struct xfrm_state * |
1345 | xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, | 1354 | xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, |
1346 | unsigned short family) | 1355 | u8 proto, unsigned short family) |
1347 | { | 1356 | { |
1348 | struct xfrm_state *x; | 1357 | struct xfrm_state *x; |
1349 | 1358 | ||
1350 | spin_lock_bh(&xfrm_state_lock); | 1359 | spin_lock_bh(&xfrm_state_lock); |
1351 | x = __xfrm_state_lookup(net, daddr, spi, proto, family); | 1360 | x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); |
1352 | spin_unlock_bh(&xfrm_state_lock); | 1361 | spin_unlock_bh(&xfrm_state_lock); |
1353 | return x; | 1362 | return x; |
1354 | } | 1363 | } |
1355 | EXPORT_SYMBOL(xfrm_state_lookup); | 1364 | EXPORT_SYMBOL(xfrm_state_lookup); |
1356 | 1365 | ||
1357 | struct xfrm_state * | 1366 | struct xfrm_state * |
1358 | xfrm_state_lookup_byaddr(struct net *net, | 1367 | xfrm_state_lookup_byaddr(struct net *net, u32 mark, |
1359 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1368 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
1360 | u8 proto, unsigned short family) | 1369 | u8 proto, unsigned short family) |
1361 | { | 1370 | { |
1362 | struct xfrm_state *x; | 1371 | struct xfrm_state *x; |
1363 | 1372 | ||
1364 | spin_lock_bh(&xfrm_state_lock); | 1373 | spin_lock_bh(&xfrm_state_lock); |
1365 | x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family); | 1374 | x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); |
1366 | spin_unlock_bh(&xfrm_state_lock); | 1375 | spin_unlock_bh(&xfrm_state_lock); |
1367 | return x; | 1376 | return x; |
1368 | } | 1377 | } |
1369 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | 1378 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); |
1370 | 1379 | ||
1371 | struct xfrm_state * | 1380 | struct xfrm_state * |
1372 | xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto, | 1381 | xfrm_find_acq(struct net *net, struct xfrm_mark *mark, u8 mode, u32 reqid, u8 proto, |
1373 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1382 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
1374 | int create, unsigned short family) | 1383 | int create, unsigned short family) |
1375 | { | 1384 | { |
1376 | struct xfrm_state *x; | 1385 | struct xfrm_state *x; |
1377 | 1386 | ||
1378 | spin_lock_bh(&xfrm_state_lock); | 1387 | spin_lock_bh(&xfrm_state_lock); |
1379 | x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create); | 1388 | x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); |
1380 | spin_unlock_bh(&xfrm_state_lock); | 1389 | spin_unlock_bh(&xfrm_state_lock); |
1381 | 1390 | ||
1382 | return x; | 1391 | return x; |
@@ -1423,7 +1432,7 @@ EXPORT_SYMBOL(xfrm_state_sort); | |||
1423 | 1432 | ||
1424 | /* Silly enough, but I'm lazy to build resolution list */ | 1433 | /* Silly enough, but I'm lazy to build resolution list */ |
1425 | 1434 | ||
1426 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | 1435 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
1427 | { | 1436 | { |
1428 | int i; | 1437 | int i; |
1429 | 1438 | ||
@@ -1442,12 +1451,12 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
1442 | return NULL; | 1451 | return NULL; |
1443 | } | 1452 | } |
1444 | 1453 | ||
1445 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq) | 1454 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
1446 | { | 1455 | { |
1447 | struct xfrm_state *x; | 1456 | struct xfrm_state *x; |
1448 | 1457 | ||
1449 | spin_lock_bh(&xfrm_state_lock); | 1458 | spin_lock_bh(&xfrm_state_lock); |
1450 | x = __xfrm_find_acq_byseq(net, seq); | 1459 | x = __xfrm_find_acq_byseq(net, mark, seq); |
1451 | spin_unlock_bh(&xfrm_state_lock); | 1460 | spin_unlock_bh(&xfrm_state_lock); |
1452 | return x; | 1461 | return x; |
1453 | } | 1462 | } |
@@ -1474,6 +1483,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1474 | int err = -ENOENT; | 1483 | int err = -ENOENT; |
1475 | __be32 minspi = htonl(low); | 1484 | __be32 minspi = htonl(low); |
1476 | __be32 maxspi = htonl(high); | 1485 | __be32 maxspi = htonl(high); |
1486 | u32 mark = x->mark.v & x->mark.m; | ||
1477 | 1487 | ||
1478 | spin_lock_bh(&x->lock); | 1488 | spin_lock_bh(&x->lock); |
1479 | if (x->km.state == XFRM_STATE_DEAD) | 1489 | if (x->km.state == XFRM_STATE_DEAD) |
@@ -1486,7 +1496,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1486 | err = -ENOENT; | 1496 | err = -ENOENT; |
1487 | 1497 | ||
1488 | if (minspi == maxspi) { | 1498 | if (minspi == maxspi) { |
1489 | x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family); | 1499 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); |
1490 | if (x0) { | 1500 | if (x0) { |
1491 | xfrm_state_put(x0); | 1501 | xfrm_state_put(x0); |
1492 | goto unlock; | 1502 | goto unlock; |
@@ -1496,7 +1506,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1496 | u32 spi = 0; | 1506 | u32 spi = 0; |
1497 | for (h=0; h<high-low+1; h++) { | 1507 | for (h=0; h<high-low+1; h++) { |
1498 | spi = low + net_random()%(high-low+1); | 1508 | spi = low + net_random()%(high-low+1); |
1499 | x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); | 1509 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); |
1500 | if (x0 == NULL) { | 1510 | if (x0 == NULL) { |
1501 | x->id.spi = htonl(spi); | 1511 | x->id.spi = htonl(spi); |
1502 | break; | 1512 | break; |