aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c137
1 files changed, 116 insertions, 21 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c8d4d53fc45..56508d40c74 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -661,13 +661,14 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
661 CMD(add_beacon, NEW_BEACON); 661 CMD(add_beacon, NEW_BEACON);
662 CMD(add_station, NEW_STATION); 662 CMD(add_station, NEW_STATION);
663 CMD(add_mpath, NEW_MPATH); 663 CMD(add_mpath, NEW_MPATH);
664 CMD(set_mesh_params, SET_MESH_PARAMS); 664 CMD(update_mesh_params, SET_MESH_PARAMS);
665 CMD(change_bss, SET_BSS); 665 CMD(change_bss, SET_BSS);
666 CMD(auth, AUTHENTICATE); 666 CMD(auth, AUTHENTICATE);
667 CMD(assoc, ASSOCIATE); 667 CMD(assoc, ASSOCIATE);
668 CMD(deauth, DEAUTHENTICATE); 668 CMD(deauth, DEAUTHENTICATE);
669 CMD(disassoc, DISASSOCIATE); 669 CMD(disassoc, DISASSOCIATE);
670 CMD(join_ibss, JOIN_IBSS); 670 CMD(join_ibss, JOIN_IBSS);
671 CMD(join_mesh, JOIN_MESH);
671 CMD(set_pmksa, SET_PMKSA); 672 CMD(set_pmksa, SET_PMKSA);
672 CMD(del_pmksa, DEL_PMKSA); 673 CMD(del_pmksa, DEL_PMKSA);
673 CMD(flush_pmksa, FLUSH_PMKSA); 674 CMD(flush_pmksa, FLUSH_PMKSA);
@@ -1324,11 +1325,21 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
1324 } 1325 }
1325 1326
1326 if (info->attrs[NL80211_ATTR_MESH_ID]) { 1327 if (info->attrs[NL80211_ATTR_MESH_ID]) {
1328 struct wireless_dev *wdev = dev->ieee80211_ptr;
1329
1327 if (ntype != NL80211_IFTYPE_MESH_POINT) 1330 if (ntype != NL80211_IFTYPE_MESH_POINT)
1328 return -EINVAL; 1331 return -EINVAL;
1329 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); 1332 if (netif_running(dev))
1330 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 1333 return -EBUSY;
1331 change = true; 1334
1335 wdev_lock(wdev);
1336 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
1337 IEEE80211_MAX_MESH_ID_LEN);
1338 wdev->mesh_id_up_len =
1339 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1340 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
1341 wdev->mesh_id_up_len);
1342 wdev_unlock(wdev);
1332 } 1343 }
1333 1344
1334 if (info->attrs[NL80211_ATTR_4ADDR]) { 1345 if (info->attrs[NL80211_ATTR_4ADDR]) {
@@ -1388,12 +1399,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1388 !(rdev->wiphy.interface_modes & (1 << type))) 1399 !(rdev->wiphy.interface_modes & (1 << type)))
1389 return -EOPNOTSUPP; 1400 return -EOPNOTSUPP;
1390 1401
1391 if (type == NL80211_IFTYPE_MESH_POINT &&
1392 info->attrs[NL80211_ATTR_MESH_ID]) {
1393 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
1394 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1395 }
1396
1397 if (info->attrs[NL80211_ATTR_4ADDR]) { 1402 if (info->attrs[NL80211_ATTR_4ADDR]) {
1398 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1403 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1399 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); 1404 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
@@ -1410,6 +1415,20 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1410 if (IS_ERR(dev)) 1415 if (IS_ERR(dev))
1411 return PTR_ERR(dev); 1416 return PTR_ERR(dev);
1412 1417
1418 if (type == NL80211_IFTYPE_MESH_POINT &&
1419 info->attrs[NL80211_ATTR_MESH_ID]) {
1420 struct wireless_dev *wdev = dev->ieee80211_ptr;
1421
1422 wdev_lock(wdev);
1423 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
1424 IEEE80211_MAX_MESH_ID_LEN);
1425 wdev->mesh_id_up_len =
1426 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1427 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
1428 wdev->mesh_id_up_len);
1429 wdev_unlock(wdev);
1430 }
1431
1413 return 0; 1432 return 0;
1414} 1433}
1415 1434
@@ -2543,21 +2562,32 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
2543} 2562}
2544 2563
2545static int nl80211_get_mesh_params(struct sk_buff *skb, 2564static int nl80211_get_mesh_params(struct sk_buff *skb,
2546 struct genl_info *info) 2565 struct genl_info *info)
2547{ 2566{
2548 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 2567 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2549 struct mesh_config cur_params;
2550 int err;
2551 struct net_device *dev = info->user_ptr[1]; 2568 struct net_device *dev = info->user_ptr[1];
2569 struct wireless_dev *wdev = dev->ieee80211_ptr;
2570 struct mesh_config cur_params;
2571 int err = 0;
2552 void *hdr; 2572 void *hdr;
2553 struct nlattr *pinfoattr; 2573 struct nlattr *pinfoattr;
2554 struct sk_buff *msg; 2574 struct sk_buff *msg;
2555 2575
2576 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
2577 return -EOPNOTSUPP;
2578
2556 if (!rdev->ops->get_mesh_params) 2579 if (!rdev->ops->get_mesh_params)
2557 return -EOPNOTSUPP; 2580 return -EOPNOTSUPP;
2558 2581
2559 /* Get the mesh params */ 2582 wdev_lock(wdev);
2560 err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); 2583 /* If not connected, get default parameters */
2584 if (!wdev->mesh_id_len)
2585 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
2586 else
2587 err = rdev->ops->get_mesh_params(&rdev->wiphy, dev,
2588 &cur_params);
2589 wdev_unlock(wdev);
2590
2561 if (err) 2591 if (err)
2562 return err; 2592 return err;
2563 2593
@@ -2705,23 +2735,37 @@ do {\
2705#undef FILL_IN_MESH_PARAM_IF_SET 2735#undef FILL_IN_MESH_PARAM_IF_SET
2706} 2736}
2707 2737
2708static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) 2738static int nl80211_update_mesh_params(struct sk_buff *skb,
2739 struct genl_info *info)
2709{ 2740{
2710 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 2741 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2711 struct net_device *dev = info->user_ptr[1]; 2742 struct net_device *dev = info->user_ptr[1];
2743 struct wireless_dev *wdev = dev->ieee80211_ptr;
2712 struct mesh_config cfg; 2744 struct mesh_config cfg;
2713 u32 mask; 2745 u32 mask;
2714 int err; 2746 int err;
2715 2747
2716 if (!rdev->ops->set_mesh_params) 2748 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
2749 return -EOPNOTSUPP;
2750
2751 if (!rdev->ops->update_mesh_params)
2717 return -EOPNOTSUPP; 2752 return -EOPNOTSUPP;
2718 2753
2719 err = nl80211_parse_mesh_params(info, &cfg, &mask); 2754 err = nl80211_parse_mesh_params(info, &cfg, &mask);
2720 if (err) 2755 if (err)
2721 return err; 2756 return err;
2722 2757
2723 /* Apply changes */ 2758 wdev_lock(wdev);
2724 return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); 2759 if (!wdev->mesh_id_len)
2760 err = -ENOLINK;
2761
2762 if (!err)
2763 err = rdev->ops->update_mesh_params(&rdev->wiphy, dev,
2764 mask, &cfg);
2765
2766 wdev_unlock(wdev);
2767
2768 return err;
2725} 2769}
2726 2770
2727static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) 2771static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
@@ -4505,6 +4549,41 @@ out:
4505 return err; 4549 return err;
4506} 4550}
4507 4551
4552static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
4553{
4554 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4555 struct net_device *dev = info->user_ptr[1];
4556 struct mesh_config cfg;
4557 int err;
4558
4559 /* start with default */
4560 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
4561
4562 if (info->attrs[NL80211_ATTR_MESH_PARAMS]) {
4563 /* and parse parameters if given */
4564 err = nl80211_parse_mesh_params(info, &cfg, NULL);
4565 if (err)
4566 return err;
4567 }
4568
4569 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
4570 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
4571 return -EINVAL;
4572
4573 return cfg80211_join_mesh(rdev, dev,
4574 nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
4575 nla_len(info->attrs[NL80211_ATTR_MESH_ID]),
4576 &cfg);
4577}
4578
4579static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
4580{
4581 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4582 struct net_device *dev = info->user_ptr[1];
4583
4584 return cfg80211_leave_mesh(rdev, dev);
4585}
4586
4508#define NL80211_FLAG_NEED_WIPHY 0x01 4587#define NL80211_FLAG_NEED_WIPHY 0x01
4509#define NL80211_FLAG_NEED_NETDEV 0x02 4588#define NL80211_FLAG_NEED_NETDEV 0x02
4510#define NL80211_FLAG_NEED_RTNL 0x04 4589#define NL80211_FLAG_NEED_RTNL 0x04
@@ -4769,10 +4848,10 @@ static struct genl_ops nl80211_ops[] = {
4769 }, 4848 },
4770 { 4849 {
4771 .cmd = NL80211_CMD_SET_MESH_PARAMS, 4850 .cmd = NL80211_CMD_SET_MESH_PARAMS,
4772 .doit = nl80211_set_mesh_params, 4851 .doit = nl80211_update_mesh_params,
4773 .policy = nl80211_policy, 4852 .policy = nl80211_policy,
4774 .flags = GENL_ADMIN_PERM, 4853 .flags = GENL_ADMIN_PERM,
4775 .internal_flags = NL80211_FLAG_NEED_NETDEV | 4854 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
4776 NL80211_FLAG_NEED_RTNL, 4855 NL80211_FLAG_NEED_RTNL,
4777 }, 4856 },
4778 { 4857 {
@@ -4987,6 +5066,22 @@ static struct genl_ops nl80211_ops[] = {
4987 .internal_flags = NL80211_FLAG_NEED_NETDEV | 5066 .internal_flags = NL80211_FLAG_NEED_NETDEV |
4988 NL80211_FLAG_NEED_RTNL, 5067 NL80211_FLAG_NEED_RTNL,
4989 }, 5068 },
5069 {
5070 .cmd = NL80211_CMD_JOIN_MESH,
5071 .doit = nl80211_join_mesh,
5072 .policy = nl80211_policy,
5073 .flags = GENL_ADMIN_PERM,
5074 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
5075 NL80211_FLAG_NEED_RTNL,
5076 },
5077 {
5078 .cmd = NL80211_CMD_LEAVE_MESH,
5079 .doit = nl80211_leave_mesh,
5080 .policy = nl80211_policy,
5081 .flags = GENL_ADMIN_PERM,
5082 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
5083 NL80211_FLAG_NEED_RTNL,
5084 },
4990}; 5085};
4991 5086
4992static struct genl_multicast_group nl80211_mlme_mcgrp = { 5087static struct genl_multicast_group nl80211_mlme_mcgrp = {