aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/key/af_key.c29
-rw-r--r--net/xfrm/xfrm_state.c26
-rw-r--r--net/xfrm/xfrm_user.c13
3 files changed, 36 insertions, 32 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c
index ff5c3d03005e..143d46f6329a 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1253,8 +1253,11 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
1253 struct sadb_x_sa2 *sa2; 1253 struct sadb_x_sa2 *sa2;
1254 struct sadb_address *saddr, *daddr; 1254 struct sadb_address *saddr, *daddr;
1255 struct sadb_msg *out_hdr; 1255 struct sadb_msg *out_hdr;
1256 struct sadb_spirange *range;
1256 struct xfrm_state *x = NULL; 1257 struct xfrm_state *x = NULL;
1257 int mode; 1258 int mode;
1259 int err;
1260 u32 min_spi, max_spi;
1258 u32 reqid; 1261 u32 reqid;
1259 u8 proto; 1262 u8 proto;
1260 unsigned short family; 1263 unsigned short family;
@@ -1309,25 +1312,17 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
1309 if (x == NULL) 1312 if (x == NULL)
1310 return -ENOENT; 1313 return -ENOENT;
1311 1314
1312 resp_skb = ERR_PTR(-ENOENT); 1315 min_spi = 0x100;
1313 1316 max_spi = 0x0fffffff;
1314 spin_lock_bh(&x->lock);
1315 if (x->km.state != XFRM_STATE_DEAD) {
1316 struct sadb_spirange *range = ext_hdrs[SADB_EXT_SPIRANGE-1];
1317 u32 min_spi, max_spi;
1318 1317
1319 if (range != NULL) { 1318 range = ext_hdrs[SADB_EXT_SPIRANGE-1];
1320 min_spi = range->sadb_spirange_min; 1319 if (range) {
1321 max_spi = range->sadb_spirange_max; 1320 min_spi = range->sadb_spirange_min;
1322 } else { 1321 max_spi = range->sadb_spirange_max;
1323 min_spi = 0x100;
1324 max_spi = 0x0fffffff;
1325 }
1326 xfrm_alloc_spi(x, htonl(min_spi), htonl(max_spi));
1327 if (x->id.spi)
1328 resp_skb = pfkey_xfrm_state2msg(x, 0, 3);
1329 } 1322 }
1330 spin_unlock_bh(&x->lock); 1323
1324 err = xfrm_alloc_spi(x, min_spi, max_spi);
1325 resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x, 0, 3);
1331 1326
1332 if (IS_ERR(resp_skb)) { 1327 if (IS_ERR(resp_skb)) {
1333 xfrm_state_put(x); 1328 xfrm_state_put(x);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 0d07f6b92d26..344f0a6abec5 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1275,26 +1275,33 @@ u32 xfrm_get_acqseq(void)
1275} 1275}
1276EXPORT_SYMBOL(xfrm_get_acqseq); 1276EXPORT_SYMBOL(xfrm_get_acqseq);
1277 1277
1278void 1278int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
1279xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi)
1280{ 1279{
1281 unsigned int h; 1280 unsigned int h;
1282 struct xfrm_state *x0; 1281 struct xfrm_state *x0;
1282 int err = -ENOENT;
1283 __be32 minspi = htonl(low);
1284 __be32 maxspi = htonl(high);
1285
1286 spin_lock_bh(&x->lock);
1287 if (x->km.state == XFRM_STATE_DEAD)
1288 goto unlock;
1283 1289
1290 err = 0;
1284 if (x->id.spi) 1291 if (x->id.spi)
1285 return; 1292 goto unlock;
1293
1294 err = -ENOENT;
1286 1295
1287 if (minspi == maxspi) { 1296 if (minspi == maxspi) {
1288 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); 1297 x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
1289 if (x0) { 1298 if (x0) {
1290 xfrm_state_put(x0); 1299 xfrm_state_put(x0);
1291 return; 1300 goto unlock;
1292 } 1301 }
1293 x->id.spi = minspi; 1302 x->id.spi = minspi;
1294 } else { 1303 } else {
1295 u32 spi = 0; 1304 u32 spi = 0;
1296 u32 low = ntohl(minspi);
1297 u32 high = ntohl(maxspi);
1298 for (h=0; h<high-low+1; h++) { 1305 for (h=0; h<high-low+1; h++) {
1299 spi = low + net_random()%(high-low+1); 1306 spi = low + net_random()%(high-low+1);
1300 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family); 1307 x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
@@ -1310,7 +1317,14 @@ xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi)
1310 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); 1317 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
1311 hlist_add_head(&x->byspi, xfrm_state_byspi+h); 1318 hlist_add_head(&x->byspi, xfrm_state_byspi+h);
1312 spin_unlock_bh(&xfrm_state_lock); 1319 spin_unlock_bh(&xfrm_state_lock);
1320
1321 err = 0;
1313 } 1322 }
1323
1324unlock:
1325 spin_unlock_bh(&x->lock);
1326
1327 return err;
1314} 1328}
1315EXPORT_SYMBOL(xfrm_alloc_spi); 1329EXPORT_SYMBOL(xfrm_alloc_spi);
1316 1330
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 8e10e9098a83..52c7fce54641 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -784,16 +784,11 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
784 if (x == NULL) 784 if (x == NULL)
785 goto out_noput; 785 goto out_noput;
786 786
787 resp_skb = ERR_PTR(-ENOENT); 787 err = xfrm_alloc_spi(x, p->min, p->max);
788 788 if (err)
789 spin_lock_bh(&x->lock); 789 goto out;
790 if (x->km.state != XFRM_STATE_DEAD) {
791 xfrm_alloc_spi(x, htonl(p->min), htonl(p->max));
792 if (x->id.spi)
793 resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
794 }
795 spin_unlock_bh(&x->lock);
796 790
791 resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
797 if (IS_ERR(resp_skb)) { 792 if (IS_ERR(resp_skb)) {
798 err = PTR_ERR(resp_skb); 793 err = PTR_ERR(resp_skb);
799 goto out; 794 goto out;