Commit 5f3b9d36 authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-next-for-davem-2016-08-12' of...

Merge tag 'mac80211-next-for-davem-2016-08-12' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
Not much for -next so far, but here it goes:
 * send more nl80211 events for interfaces
 * remove useless network/transport offset mangling code
 * validate beacon intervals identically for all interface types
 * use driver rate estimates for mesh
 * fix a compiler type/signedness warning
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 70567833 ff9a71af
......@@ -1088,13 +1088,13 @@ static inline void drv_leave_ibss(struct ieee80211_local *local,
}
static inline u32 drv_get_expected_throughput(struct ieee80211_local *local,
struct ieee80211_sta *sta)
struct sta_info *sta)
{
u32 ret = 0;
trace_drv_get_expected_throughput(sta);
if (local->ops->get_expected_throughput)
ret = local->ops->get_expected_throughput(&local->hw, sta);
trace_drv_get_expected_throughput(&sta->sta);
if (local->ops->get_expected_throughput && sta->uploaded)
ret = local->ops->get_expected_throughput(&local->hw, &sta->sta);
trace_drv_return_u32(local, ret);
return ret;
......
......@@ -326,22 +326,33 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
u32 tx_time, estimated_retx;
u64 result;
if (sta->mesh->fail_avg >= 100)
return MAX_METRIC;
/* Try to get rate based on HW/SW RC algorithm.
* Rate is returned in units of Kbps, correct this
* to comply with airtime calculation units
* Round up in case we get rate < 100Kbps
*/
rate = DIV_ROUND_UP(sta_get_expected_throughput(sta), 100);
sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo);
rate = cfg80211_calculate_bitrate(&rinfo);
if (WARN_ON(!rate))
return MAX_METRIC;
if (rate) {
err = 0;
} else {
if (sta->mesh->fail_avg >= 100)
return MAX_METRIC;
err = (sta->mesh->fail_avg << ARITH_SHIFT) / 100;
sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo);
rate = cfg80211_calculate_bitrate(&rinfo);
if (WARN_ON(!rate))
return MAX_METRIC;
err = (sta->mesh->fail_avg << ARITH_SHIFT) / 100;
}
/* bitrate is in units of 100 Kbps, while we need rate in units of
* 1Mbps. This will be corrected on tx_time computation.
*/
tx_time = (device_constant + 10 * test_frame_len / rate);
estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT);
return (u32)result;
}
......
......@@ -2279,11 +2279,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
/* check if the driver has a SW RC implementation */
if (ref && ref->ops->get_expected_throughput)
thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
else
thr = drv_get_expected_throughput(local, &sta->sta);
thr = sta_get_expected_throughput(sta);
if (thr != 0) {
sinfo->filled |= BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
......@@ -2291,6 +2287,25 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
}
}
u32 sta_get_expected_throughput(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct rate_control_ref *ref = NULL;
u32 thr = 0;
if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
ref = local->rate_ctrl;
/* check if the driver has a SW RC implementation */
if (ref && ref->ops->get_expected_throughput)
thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
else
thr = drv_get_expected_throughput(local, sta);
return thr;
}
unsigned long ieee80211_sta_last_active(struct sta_info *sta)
{
struct ieee80211_sta_rx_stats *stats = sta_get_last_rx_stats(sta);
......
......@@ -712,6 +712,8 @@ void sta_set_rate_info_tx(struct sta_info *sta,
struct rate_info *rinfo);
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo);
u32 sta_get_expected_throughput(struct sta_info *sta);
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
unsigned long exp_time);
u8 sta_info_tx_streams(struct sta_info *sta);
......
......@@ -2334,7 +2334,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
struct mesh_path __maybe_unused *mppath = NULL, *mpath = NULL;
const u8 *encaps_data;
int encaps_len, skip_header_bytes;
int nh_pos, h_pos;
bool wme_sta = false, authorized = false;
bool tdls_peer;
bool multicast;
......@@ -2640,13 +2639,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
encaps_len = 0;
}
nh_pos = skb_network_header(skb) - skb->data;
h_pos = skb_transport_header(skb) - skb->data;
skb_pull(skb, skip_header_bytes);
nh_pos -= skip_header_bytes;
h_pos -= skip_header_bytes;
head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
/*
......@@ -2672,18 +2665,12 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
}
}
if (encaps_data) {
if (encaps_data)
memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
nh_pos += encaps_len;
h_pos += encaps_len;
}
#ifdef CONFIG_MAC80211_MESH
if (meshhdrlen > 0) {
if (meshhdrlen > 0)
memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
nh_pos += meshhdrlen;
h_pos += meshhdrlen;
}
#endif
if (ieee80211_is_data_qos(fc)) {
......@@ -2699,15 +2686,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
} else
memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
nh_pos += hdrlen;
h_pos += hdrlen;
/* Update skb pointers to various headers since this modified frame
* is going to go through Linux networking code that may potentially
* need things like pointer to IP header. */
skb_reset_mac_header(skb);
skb_set_network_header(skb, nh_pos);
skb_set_transport_header(skb, h_pos);
info = IEEE80211_SKB_CB(skb);
memset(info, 0, sizeof(*info));
......@@ -4390,9 +4369,6 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
int ac = ieee802_1d_to_ac[tid & 7];
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
skb_set_queue_mapping(skb, ac);
skb->priority = tid;
......
......@@ -906,6 +906,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
if (WARN_ON(wdev->netdev))
return;
nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE);
list_del_rcu(&wdev->list);
rdev->devlist_generation++;
......@@ -1079,6 +1081,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
dev->priv_flags |= IFF_DONT_BRIDGE;
nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
break;
case NETDEV_GOING_DOWN:
cfg80211_leave(rdev, wdev);
......@@ -1157,6 +1161,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
* remove and clean it up.
*/
if (!list_empty(&wdev->list)) {
nl80211_notify_iface(rdev, wdev,
NL80211_CMD_DEL_INTERFACE);
sysfs_remove_link(&dev->dev.kobj, "phy80211");
list_del_rcu(&wdev->list);
rdev->devlist_generation++;
......
......@@ -2751,7 +2751,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct vif_params params;
struct wireless_dev *wdev;
struct sk_buff *msg, *event;
struct sk_buff *msg;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
u32 flags;
......@@ -2855,20 +2855,15 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
return -ENOBUFS;
}
event = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (event) {
if (nl80211_send_iface(event, 0, 0, 0,
rdev, wdev, false) < 0) {
nlmsg_free(event);
goto out;
}
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
event, 0, NL80211_MCGRP_CONFIG,
GFP_KERNEL);
}
/*
* For wdevs which have no associated netdev object (e.g. of type
* NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
* For all other types, the event will be generated from the
* netdev notifier
*/
if (!wdev->netdev)
nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
out:
return genlmsg_reply(msg, info);
}
......@@ -2876,18 +2871,10 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev = info->user_ptr[1];
struct sk_buff *msg;
int status;
if (!rdev->ops->del_virtual_intf)
return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (msg && nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, true) < 0) {
nlmsg_free(msg);
msg = NULL;
}
/*
* If we remove a wireless device without a netdev then clear
* user_ptr[1] so that nl80211_post_doit won't dereference it
......@@ -2898,15 +2885,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
if (!wdev->netdev)
info->user_ptr[1] = NULL;
status = rdev_del_virtual_intf(rdev, wdev);
if (status >= 0 && msg)
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
msg, 0, NL80211_MCGRP_CONFIG,
GFP_KERNEL);
else
nlmsg_free(msg);
return status;
return rdev_del_virtual_intf(rdev, wdev);
}
static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
......@@ -5374,6 +5353,18 @@ static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *ou
return 0;
}
static int nl80211_check_power_mode(const struct nlattr *nla,
enum nl80211_mesh_power_mode min,
enum nl80211_mesh_power_mode max,
enum nl80211_mesh_power_mode *out)
{
u32 val = nla_get_u32(nla);
if (val < min || val > max)
return -EINVAL;
*out = val;
return 0;
}
static int nl80211_parse_mesh_config(struct genl_info *info,
struct mesh_config *cfg,
u32 *mask_out)
......@@ -5518,7 +5509,7 @@ do { \
NL80211_MESH_POWER_ACTIVE,
NL80211_MESH_POWER_MAX,
mask, NL80211_MESHCONF_POWER_MODE,
nl80211_check_u32);
nl80211_check_power_mode);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
0, 65535, mask,
NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
......@@ -7773,12 +7764,13 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.beacon_interval = 100;
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
ibss.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)
return -EINVAL;
}
err = cfg80211_validate_beacon_int(rdev, ibss.beacon_interval);
if (err)
return err;
if (!rdev->ops->join_ibss)
return -EOPNOTSUPP;
......@@ -9252,9 +9244,10 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
setup.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
if (setup.beacon_interval < 10 ||
setup.beacon_interval > 10000)
return -EINVAL;
err = cfg80211_validate_beacon_int(rdev, setup.beacon_interval);
if (err)
return err;
}
if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
......@@ -11847,6 +11840,29 @@ void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
NL80211_MCGRP_CONFIG, GFP_KERNEL);
}
void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_commands cmd)
{
struct sk_buff *msg;
WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
cmd != NL80211_CMD_DEL_INTERFACE);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return;
if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
nlmsg_free(msg);
return;
}
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_CONFIG, GFP_KERNEL);
}
static int nl80211_add_scan_req(struct sk_buff *msg,
struct cfg80211_registered_device *rdev)
{
......
......@@ -7,6 +7,9 @@ int nl80211_init(void);
void nl80211_exit(void);
void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
enum nl80211_commands cmd);
void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_commands cmd);
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
......
......@@ -1559,7 +1559,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev;
int res = 0;
if (!beacon_int)
if (beacon_int < 10 || beacon_int > 10000)
return -EINVAL;
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment