aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c122
1 files changed, 76 insertions, 46 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index bd1ef84..9f32756 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -188,11 +188,22 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
return -ENOLINK;
break;
- case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_AP_VLAN: {
+ struct ieee80211_sub_if_data *master;
+
if (!sdata->bss)
return -ENOLINK;
+
list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
+
+ master = container_of(sdata->bss,
+ struct ieee80211_sub_if_data, u.ap);
+ sdata->control_port_protocol =
+ master->control_port_protocol;
+ sdata->control_port_no_encrypt =
+ master->control_port_no_encrypt;
break;
+ }
case NL80211_IFTYPE_AP:
sdata->bss = &sdata->u.ap;
break;
@@ -265,7 +276,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
break;
default:
if (coming_up) {
- res = drv_add_interface(local, &sdata->vif);
+ res = drv_add_interface(local, sdata);
if (res)
goto err_stop;
}
@@ -282,10 +293,18 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
changed |= ieee80211_reset_erp_info(sdata);
ieee80211_bss_info_change_notify(sdata, changed);
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC)
netif_carrier_off(dev);
else
netif_carrier_on(dev);
+
+ /*
+ * set default queue parameters so drivers don't
+ * need to initialise the hardware if the hardware
+ * doesn't start up with sane defaults
+ */
+ ieee80211_set_wmm_default(sdata, true);
}
set_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -299,8 +318,9 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
goto err_del_interface;
}
- /* no locking required since STA is not live yet */
- sta->flags |= WLAN_STA_AUTHORIZED;
+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+ sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
res = sta_info_insert(sta);
if (res) {
@@ -329,15 +349,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
if (coming_up)
local->open_count++;
- if (hw_reconf_flags) {
+ if (hw_reconf_flags)
ieee80211_hw_config(local, hw_reconf_flags);
- /*
- * set default queue parameters so drivers don't
- * need to initialise the hardware if the hardware
- * doesn't start up with sane defaults
- */
- ieee80211_set_wmm_default(sdata);
- }
ieee80211_recalc_ps(local, -1);
@@ -345,7 +358,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
return 0;
err_del_interface:
- drv_remove_interface(local, &sdata->vif);
+ drv_remove_interface(local, sdata);
err_stop:
if (!local->open_count)
drv_stop(local);
@@ -363,8 +376,7 @@ static int ieee80211_open(struct net_device *dev)
int err;
/* fail early if user set an invalid address */
- if (!is_zero_ether_addr(dev->dev_addr) &&
- !is_valid_ether_addr(dev->dev_addr))
+ if (!is_valid_ether_addr(dev->dev_addr))
return -EADDRNOTAVAIL;
err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
@@ -383,10 +395,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
u32 hw_reconf_flags = 0;
int i;
enum nl80211_channel_type orig_ct;
+ bool cancel_scan;
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
- if (local->scan_sdata == sdata)
+ cancel_scan = local->scan_sdata == sdata;
+ if (cancel_scan)
ieee80211_scan_cancel(local);
/*
@@ -451,27 +465,31 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *vlan, *tmpsdata;
struct beacon_data *old_beacon =
rtnl_dereference(sdata->u.ap.beacon);
+ struct sk_buff *old_probe_resp =
+ rtnl_dereference(sdata->u.ap.probe_resp);
/* sdata_running will return false, so this will disable */
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED);
- /* remove beacon */
- rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+ /* remove beacon and probe response */
+ RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
+ RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
synchronize_rcu();
kfree(old_beacon);
-
- /* free all potentially still buffered bcast frames */
- while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
- local->total_ps_buffered--;
- dev_kfree_skb(skb);
- }
+ kfree_skb(old_probe_resp);
/* down all dependent devices, that is VLANs */
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
WARN_ON(!list_empty(&sdata->u.ap.vlans));
+
+ /* free all potentially still buffered bcast frames */
+ local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps_bc_buf);
+ skb_queue_purge(&sdata->u.ap.ps_bc_buf);
+ } else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ ieee80211_mgd_stop(sdata);
}
if (going_down)
@@ -535,7 +553,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
ieee80211_free_keys(sdata);
if (going_down)
- drv_remove_interface(local, &sdata->vif);
+ drv_remove_interface(local, sdata);
}
sdata->bss = NULL;
@@ -546,6 +564,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_ps(local, -1);
+ if (cancel_scan)
+ flush_delayed_work(&local->scan_work);
+
if (local->open_count == 0) {
if (local->ops->napi_poll)
napi_disable(&local->napi);
@@ -658,7 +679,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
.ndo_stop = ieee80211_stop,
.ndo_uninit = ieee80211_teardown_sdata,
.ndo_start_xmit = ieee80211_subif_start_xmit,
- .ndo_set_multicast_list = ieee80211_set_multicast_list,
+ .ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_netdev_select_queue,
@@ -671,7 +692,6 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
struct ieee80211_local *local = sdata->local;
struct ieee80211_hdr *hdr;
struct ieee80211_radiotap_header *rtap = (void *)skb->data;
- u8 *p;
if (local->hw.queues < 4)
return 0;
@@ -682,19 +702,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len));
- if (!ieee80211_is_data(hdr->frame_control)) {
- skb->priority = 7;
- return ieee802_1d_to_ac[skb->priority];
- }
- if (!ieee80211_is_data_qos(hdr->frame_control)) {
- skb->priority = 0;
- return ieee802_1d_to_ac[skb->priority];
- }
-
- p = ieee80211_get_qos_ctl(hdr);
- skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
-
- return ieee80211_downgrade_queue(local, skb);
+ return ieee80211_select_queue_80211(local, skb, hdr);
}
static const struct net_device_ops ieee80211_monitorif_ops = {
@@ -702,7 +710,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
.ndo_stop = ieee80211_stop,
.ndo_uninit = ieee80211_teardown_sdata,
.ndo_start_xmit = ieee80211_monitor_start_xmit,
- .ndo_set_multicast_list = ieee80211_set_multicast_list,
+ .ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_select_queue = ieee80211_monitor_select_queue,
@@ -865,6 +873,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
sdata->control_port_no_encrypt = false;
+ sdata->noack_map = 0;
+
/* only monitor differs */
sdata->dev->type = ARPHRD_ETHER;
@@ -1143,8 +1153,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ASSERT_RTNL();
- ndev = alloc_netdev_mq(sizeof(*sdata) + local->hw.vif_data_size,
- name, ieee80211_if_setup, local->hw.queues);
+ ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size,
+ name, ieee80211_if_setup, local->hw.queues, 1);
if (!ndev)
return -ENOMEM;
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
@@ -1190,6 +1200,13 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sband = local->hw.wiphy->bands[i];
sdata->rc_rateidx_mask[i] =
sband ? (1 << sband->n_bitrates) - 1 : 0;
+ if (sband)
+ memcpy(sdata->rc_rateidx_mcs_mask[i],
+ sband->ht_cap.mcs.rx_mask,
+ sizeof(sdata->rc_rateidx_mcs_mask[i]));
+ else
+ memset(sdata->rc_rateidx_mcs_mask[i], 0,
+ sizeof(sdata->rc_rateidx_mcs_mask[i]));
}
/* setup type-dependent data */
@@ -1227,6 +1244,9 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_path_flush_by_iface(sdata);
+
synchronize_rcu();
unregister_netdevice(sdata->dev);
}
@@ -1255,6 +1275,9 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
list_del(&sdata->list);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_path_flush_by_iface(sdata);
+
unregister_netdevice_queue(sdata->dev, &unreg_list);
}
mutex_unlock(&local->iflist_mtx);
@@ -1315,7 +1338,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
/* do not count disabled managed interfaces */
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
- !sdata->u.mgd.associated) {
+ !sdata->u.mgd.associated &&
+ !sdata->u.mgd.auth_data &&
+ !sdata->u.mgd.assoc_data) {
sdata->vif.bss_conf.idle = true;
continue;
}
@@ -1326,6 +1351,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
continue;
}
/* count everything else */
+ sdata->vif.bss_conf.idle = false;
count++;
}
@@ -1334,7 +1360,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
wk->sdata->vif.bss_conf.idle = false;
}
- if (local->scan_sdata) {
+ if (local->scan_sdata &&
+ !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
scanning = true;
local->scan_sdata->vif.bss_conf.idle = false;
}
@@ -1343,6 +1370,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
hw_roc = true;
list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ continue;
if (sdata->old_idle == sdata->vif.bss_conf.idle)
continue;
if (!ieee80211_sdata_running(sdata))