diff options
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 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 | ||
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 = { |