diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-12-03 03:20:44 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-06 16:01:29 -0500 |
commit | 29cbe68c516a48a9a88b3226878570c6cbd83c02 (patch) | |
tree | 4774f8a3a244236234a521baa4d1ae5b3e1494ba /net/wireless/nl80211.c | |
parent | bd90fdcc5fbd99a2a778999610420cf793bd1be2 (diff) |
cfg80211/mac80211: add mesh join/leave commands
Instead of tying mesh activity to interface up,
add join and leave commands for mesh. Since we
must be backward compatible, let cfg80211 handle
joining a mesh if a mesh ID was pre-configured
when the device goes up.
Note that this therefore must modify mac80211 as
well since mac80211 needs to lose the logic to
start the mesh on interface up.
We now allow querying mesh parameters before the
mesh is connected, which simply returns defaults.
Setting them (internally renamed to "update") is
only allowed while connected. Specify them with
the new mesh join command instead where needed.
In mac80211, beaconing must now also follow the
mesh enabled/not enabled state, which is done
by testing the mesh ID.
Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 137 |
1 files changed, 116 insertions, 21 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c8d4d53fc450..56508d40c740 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 | ||
2545 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2564 | static 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 | ||
2708 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2738 | static 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 | ||
2727 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 2771 | static 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 | ||
4552 | static 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 | |||
4579 | static 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 | ||
4992 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5087 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |