aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-10-09 16:29:52 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:55:01 -0400
commit658b219e9379d75fbdc578b9630b598098471258 (patch)
treefe802c4e1ee6468a9c2558a5e529b2380845a003
parent75ba28c633952f7994a7117c98ae6515b58f8d30 (diff)
[IPSEC]: Move common code into xfrm_alloc_spi
This patch moves some common code that conceptually belongs to the xfrm core from af_key/xfrm_user into xfrm_alloc_spi. In particular, the spin lock on the state is now taken inside xfrm_alloc_spi. Previously it also protected the construction of the response PF_KEY/XFRM messages to user-space. This is inconsistent as other identical constructions are not protected by the state lock. This is bad because they in fact should be protected but only in certain spots (so as not to hold the lock for too long which may cause packet drops). The SPI byte order conversion has also been moved. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/xfrm.h2
-rw-r--r--net/key/af_key.c29
-rw-r--r--net/xfrm/xfrm_state.c26
-rw-r--r--net/xfrm/xfrm_user.c13
4 files changed, 37 insertions, 33 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 064a4ca63476..1c116dc03e0e 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1084,7 +1084,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
1084struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete, int *err); 1084struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete, int *err);
1085int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); 1085int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
1086u32 xfrm_get_acqseq(void); 1086u32 xfrm_get_acqseq(void);
1087void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi); 1087extern int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
1088struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 1088struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
1089 xfrm_address_t *daddr, xfrm_address_t *saddr, 1089 xfrm_address_t *daddr, xfrm_address_t *saddr,
1090 int create, unsigned short family); 1090 int create, unsigned short family);
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;