aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-08 08:22:54 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-24 15:05:09 -0400
commitfffd0934b9390f34bec45762192b7edd3b12b4b5 (patch)
treed9779803763261f5795fe39a402d79c4220a3a22 /net/wireless/nl80211.c
parentb9454e83cac42fcdc90bfbfba479132bd6629455 (diff)
cfg80211: rework key operation
This reworks the key operation in cfg80211, and now only allows, from userspace, configuring keys (via nl80211) after the connection has been established (in managed mode), the IBSS been joined (in IBSS mode), at any time (in AP[_VLAN] modes) or never for all the other modes. In order to do shared key authentication correctly, it is now possible to give a WEP key to the AUTH command. To configure static WEP keys, these are given to the CONNECT or IBSS_JOIN command directly, for a userspace SME it is assumed it will configure it properly after the connection has been established. Since mac80211 used to check the default key in IBSS mode to see whether or not the network is protected, it needs an update in that area, as well as an update to make use of the WEP key passed to auth() for shared key authentication. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c170
1 files changed, 151 insertions, 19 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 50cf5931629..45c5f9c8e51 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -138,8 +138,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
138/* policy for the attributes */ 138/* policy for the attributes */
139static struct nla_policy 139static struct nla_policy
140nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { 140nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
141 [NL80211_KEY_DATA] = { .type = NLA_BINARY, 141 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
142 .len = WLAN_MAX_KEY_LEN },
143 [NL80211_KEY_IDX] = { .type = NLA_U8 }, 142 [NL80211_KEY_IDX] = { .type = NLA_U8 },
144 [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, 143 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
145 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, 144 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
@@ -305,6 +304,83 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
305 return 0; 304 return 0;
306} 305}
307 306
307static struct cfg80211_cached_keys *
308nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
309 struct nlattr *keys)
310{
311 struct key_parse parse;
312 struct nlattr *key;
313 struct cfg80211_cached_keys *result;
314 int rem, err, def = 0;
315
316 result = kzalloc(sizeof(*result), GFP_KERNEL);
317 if (!result)
318 return ERR_PTR(-ENOMEM);
319
320 result->def = -1;
321 result->defmgmt = -1;
322
323 nla_for_each_nested(key, keys, rem) {
324 memset(&parse, 0, sizeof(parse));
325 parse.idx = -1;
326
327 err = nl80211_parse_key_new(key, &parse);
328 if (err)
329 goto error;
330 err = -EINVAL;
331 if (!parse.p.key)
332 goto error;
333 if (parse.idx < 0 || parse.idx > 4)
334 goto error;
335 if (parse.def) {
336 if (def)
337 goto error;
338 def = 1;
339 result->def = parse.idx;
340 } else if (parse.defmgmt)
341 goto error;
342 err = cfg80211_validate_key_settings(rdev, &parse.p,
343 parse.idx, NULL);
344 if (err)
345 goto error;
346 result->params[parse.idx].cipher = parse.p.cipher;
347 result->params[parse.idx].key_len = parse.p.key_len;
348 result->params[parse.idx].key = result->data[parse.idx];
349 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
350 }
351
352 return result;
353 error:
354 kfree(result);
355 return ERR_PTR(err);
356}
357
358static int nl80211_key_allowed(struct wireless_dev *wdev)
359{
360 ASSERT_WDEV_LOCK(wdev);
361
362 if (!netif_running(wdev->netdev))
363 return -ENETDOWN;
364
365 switch (wdev->iftype) {
366 case NL80211_IFTYPE_AP:
367 case NL80211_IFTYPE_AP_VLAN:
368 break;
369 case NL80211_IFTYPE_ADHOC:
370 if (!wdev->current_bss)
371 return -ENOLINK;
372 break;
373 case NL80211_IFTYPE_STATION:
374 if (wdev->sme_state != CFG80211_SME_CONNECTED)
375 return -ENOLINK;
376 break;
377 default:
378 return -EINVAL;
379 }
380
381 return 0;
382}
383
308static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, 384static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
309 struct cfg80211_registered_device *dev) 385 struct cfg80211_registered_device *dev)
310{ 386{
@@ -1212,7 +1288,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1212 goto out; 1288 goto out;
1213 } 1289 }
1214 1290
1215 err = func(&rdev->wiphy, dev, key.idx); 1291 wdev_lock(dev->ieee80211_ptr);
1292 err = nl80211_key_allowed(dev->ieee80211_ptr);
1293 if (!err)
1294 err = func(&rdev->wiphy, dev, key.idx);
1295
1216#ifdef CONFIG_WIRELESS_EXT 1296#ifdef CONFIG_WIRELESS_EXT
1217 if (!err) { 1297 if (!err) {
1218 if (func == rdev->ops->set_default_key) 1298 if (func == rdev->ops->set_default_key)
@@ -1221,6 +1301,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1221 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; 1301 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
1222 } 1302 }
1223#endif 1303#endif
1304 wdev_unlock(dev->ieee80211_ptr);
1224 1305
1225 out: 1306 out:
1226 cfg80211_unlock_rdev(rdev); 1307 cfg80211_unlock_rdev(rdev);
@@ -1235,7 +1316,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1235static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) 1316static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
1236{ 1317{
1237 struct cfg80211_registered_device *rdev; 1318 struct cfg80211_registered_device *rdev;
1238 int err, i; 1319 int err;
1239 struct net_device *dev; 1320 struct net_device *dev;
1240 struct key_parse key; 1321 struct key_parse key;
1241 u8 *mac_addr = NULL; 1322 u8 *mac_addr = NULL;
@@ -1250,29 +1331,28 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
1250 if (info->attrs[NL80211_ATTR_MAC]) 1331 if (info->attrs[NL80211_ATTR_MAC])
1251 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 1332 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1252 1333
1253 if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr))
1254 return -EINVAL;
1255
1256 rtnl_lock(); 1334 rtnl_lock();
1257 1335
1258 err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); 1336 err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
1259 if (err) 1337 if (err)
1260 goto unlock_rtnl; 1338 goto unlock_rtnl;
1261 1339
1262 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) 1340 if (!rdev->ops->add_key) {
1263 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) 1341 err = -EOPNOTSUPP;
1264 break;
1265 if (i == rdev->wiphy.n_cipher_suites) {
1266 err = -EINVAL;
1267 goto out; 1342 goto out;
1268 } 1343 }
1269 1344
1270 if (!rdev->ops->add_key) { 1345 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
1271 err = -EOPNOTSUPP; 1346 err = -EINVAL;
1272 goto out; 1347 goto out;
1273 } 1348 }
1274 1349
1275 err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p); 1350 wdev_lock(dev->ieee80211_ptr);
1351 err = nl80211_key_allowed(dev->ieee80211_ptr);
1352 if (!err)
1353 err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
1354 mac_addr, &key.p);
1355 wdev_unlock(dev->ieee80211_ptr);
1276 1356
1277 out: 1357 out:
1278 cfg80211_unlock_rdev(rdev); 1358 cfg80211_unlock_rdev(rdev);
@@ -1309,7 +1389,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
1309 goto out; 1389 goto out;
1310 } 1390 }
1311 1391
1312 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); 1392 wdev_lock(dev->ieee80211_ptr);
1393 err = nl80211_key_allowed(dev->ieee80211_ptr);
1394 if (!err)
1395 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
1313 1396
1314#ifdef CONFIG_WIRELESS_EXT 1397#ifdef CONFIG_WIRELESS_EXT
1315 if (!err) { 1398 if (!err) {
@@ -1319,6 +1402,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
1319 dev->ieee80211_ptr->wext.default_mgmt_key = -1; 1402 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
1320 } 1403 }
1321#endif 1404#endif
1405 wdev_unlock(dev->ieee80211_ptr);
1322 1406
1323 out: 1407 out:
1324 cfg80211_unlock_rdev(rdev); 1408 cfg80211_unlock_rdev(rdev);
@@ -3159,6 +3243,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3159 const u8 *bssid, *ssid, *ie = NULL; 3243 const u8 *bssid, *ssid, *ie = NULL;
3160 int err, ssid_len, ie_len = 0; 3244 int err, ssid_len, ie_len = 0;
3161 enum nl80211_auth_type auth_type; 3245 enum nl80211_auth_type auth_type;
3246 struct key_parse key;
3162 3247
3163 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3248 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3164 return -EINVAL; 3249 return -EINVAL;
@@ -3175,6 +3260,25 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3175 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) 3260 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
3176 return -EINVAL; 3261 return -EINVAL;
3177 3262
3263 err = nl80211_parse_key(info, &key);
3264 if (err)
3265 return err;
3266
3267 if (key.idx >= 0) {
3268 if (!key.p.key || !key.p.key_len)
3269 return -EINVAL;
3270 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
3271 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
3272 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
3273 key.p.key_len != WLAN_KEY_LEN_WEP104))
3274 return -EINVAL;
3275 if (key.idx > 4)
3276 return -EINVAL;
3277 } else {
3278 key.p.key_len = 0;
3279 key.p.key = NULL;
3280 }
3281
3178 rtnl_lock(); 3282 rtnl_lock();
3179 3283
3180 err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); 3284 err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
@@ -3219,7 +3323,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3219 } 3323 }
3220 3324
3221 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 3325 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
3222 ssid, ssid_len, ie, ie_len); 3326 ssid, ssid_len, ie, ie_len,
3327 key.p.key, key.p.key_len, key.idx);
3223 3328
3224out: 3329out:
3225 cfg80211_unlock_rdev(rdev); 3330 cfg80211_unlock_rdev(rdev);
@@ -3506,6 +3611,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
3506 struct net_device *dev; 3611 struct net_device *dev;
3507 struct cfg80211_ibss_params ibss; 3612 struct cfg80211_ibss_params ibss;
3508 struct wiphy *wiphy; 3613 struct wiphy *wiphy;
3614 struct cfg80211_cached_keys *connkeys = NULL;
3509 int err; 3615 int err;
3510 3616
3511 memset(&ibss, 0, sizeof(ibss)); 3617 memset(&ibss, 0, sizeof(ibss));
@@ -3570,13 +3676,26 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
3570 } 3676 }
3571 3677
3572 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; 3678 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
3679 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
3680
3681 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
3682 connkeys = nl80211_parse_connkeys(rdev,
3683 info->attrs[NL80211_ATTR_KEYS]);
3684 if (IS_ERR(connkeys)) {
3685 err = PTR_ERR(connkeys);
3686 connkeys = NULL;
3687 goto out;
3688 }
3689 }
3573 3690
3574 err = cfg80211_join_ibss(rdev, dev, &ibss); 3691 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
3575 3692
3576out: 3693out:
3577 cfg80211_unlock_rdev(rdev); 3694 cfg80211_unlock_rdev(rdev);
3578 dev_put(dev); 3695 dev_put(dev);
3579unlock_rtnl: 3696unlock_rtnl:
3697 if (err)
3698 kfree(connkeys);
3580 rtnl_unlock(); 3699 rtnl_unlock();
3581 return err; 3700 return err;
3582} 3701}
@@ -3746,6 +3865,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
3746 struct net_device *dev; 3865 struct net_device *dev;
3747 struct cfg80211_connect_params connect; 3866 struct cfg80211_connect_params connect;
3748 struct wiphy *wiphy; 3867 struct wiphy *wiphy;
3868 struct cfg80211_cached_keys *connkeys = NULL;
3749 int err; 3869 int err;
3750 3870
3751 memset(&connect, 0, sizeof(connect)); 3871 memset(&connect, 0, sizeof(connect));
@@ -3810,12 +3930,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
3810 } 3930 }
3811 } 3931 }
3812 3932
3813 err = cfg80211_connect(rdev, dev, &connect); 3933 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
3934 connkeys = nl80211_parse_connkeys(rdev,
3935 info->attrs[NL80211_ATTR_KEYS]);
3936 if (IS_ERR(connkeys)) {
3937 err = PTR_ERR(connkeys);
3938 connkeys = NULL;
3939 goto out;
3940 }
3941 }
3942
3943 err = cfg80211_connect(rdev, dev, &connect, connkeys);
3814 3944
3815out: 3945out:
3816 cfg80211_unlock_rdev(rdev); 3946 cfg80211_unlock_rdev(rdev);
3817 dev_put(dev); 3947 dev_put(dev);
3818unlock_rtnl: 3948unlock_rtnl:
3949 if (err)
3950 kfree(connkeys);
3819 rtnl_unlock(); 3951 rtnl_unlock();
3820 return err; 3952 return err;
3821} 3953}