Commit 4b7afb52 authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg

mac80211: reorganize code to remove a forward declaration

Remove the newly added ieee80211_set_vif_encap_ops declaration.
No further code changes.
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Link: https://lore.kernel.org/r/20200908123702.88454-15-nbd@nbd.nameSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f02dff93
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
*/ */
static void ieee80211_iface_work(struct work_struct *work); static void ieee80211_iface_work(struct work_struct *work);
static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata);
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
{ {
...@@ -349,968 +348,993 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, ...@@ -349,968 +348,993 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
return 0; return 0;
} }
static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype) static int ieee80211_open(struct net_device *dev)
{ {
switch (iftype) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
/* P2P GO and client are mapped to AP/STATION types */ int err;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION: /* fail early if user set an invalid address */
return true; if (!is_valid_ether_addr(dev->dev_addr))
default: return -EADDRNOTAVAIL;
return false;
} err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
if (err)
return err;
return ieee80211_do_open(&sdata->wdev, true);
} }
static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdata) static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
bool going_down)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
u32 flags; unsigned long flags;
struct sk_buff *skb, *tmp;
flags = sdata->vif.offload_flags; u32 hw_reconf_flags = 0;
int i, flushed;
struct ps_data *ps;
struct cfg80211_chan_def chandef;
bool cancel_scan;
struct cfg80211_nan_func *func;
if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) && clear_bit(SDATA_STATE_RUNNING, &sdata->state);
ieee80211_iftype_supports_encap_offload(sdata->vif.type)) {
flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED;
if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) && cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
local->hw.wiphy->frag_threshold != (u32)-1) if (cancel_scan)
flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ieee80211_scan_cancel(local);
if (local->monitors) /*
flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; * Stop TX on this interface first.
} else { */
flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; if (sdata->dev)
} netif_tx_stop_all_queues(sdata->dev);
if (sdata->vif.offload_flags == flags) ieee80211_roc_purge(local, sdata);
return false;
sdata->vif.offload_flags = flags; switch (sdata->vif.type) {
return true; case NL80211_IFTYPE_STATION:
} ieee80211_mgd_stop(sdata);
break;
case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_stop(sdata);
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
break;
list_del_rcu(&sdata->u.mntr.list);
break;
default:
break;
}
/*
* Remove all stations associated with this interface.
*
* This must be done before calling ops->remove_interface()
* because otherwise we can later invoke ops->sta_notify()
* whenever the STAs are removed, and that invalidates driver
* assumptions about always getting a vif pointer that is valid
* (because if we remove a STA after ops->remove_interface()
* the driver will have removed the vif info already!)
*
* In WDS mode a station must exist here and be flushed, for
* AP_VLANs stations may exist since there's nothing else that
* would have removed them, but in other modes there shouldn't
* be any stations.
*/
flushed = sta_info_flush(sdata);
WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
(sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)));
static void ieee80211_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata) /* don't count this interface for allmulti while it is down */
{ if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
struct ieee80211_local *local = sdata->local; atomic_dec(&local->iff_allmultis);
struct ieee80211_sub_if_data *vsdata;
if (ieee80211_set_sdata_offload_flags(sdata)) { if (sdata->vif.type == NL80211_IFTYPE_AP) {
drv_update_vif_offload(local, sdata); local->fif_pspoll--;
ieee80211_set_vif_encap_ops(sdata); local->fif_probe_req--;
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
local->fif_probe_req--;
} }
list_for_each_entry(vsdata, &local->interfaces, list) { if (sdata->dev) {
if (vsdata->vif.type != NL80211_IFTYPE_AP_VLAN || netif_addr_lock_bh(sdata->dev);
vsdata->bss != &sdata->u.ap) spin_lock_bh(&local->filter_lock);
continue; __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
sdata->dev->addr_len);
ieee80211_set_vif_encap_ops(vsdata); spin_unlock_bh(&local->filter_lock);
netif_addr_unlock_bh(sdata->dev);
} }
}
void ieee80211_recalc_offload(struct ieee80211_local *local) del_timer_sync(&local->dynamic_ps_timer);
{ cancel_work_sync(&local->dynamic_ps_enable_work);
struct ieee80211_sub_if_data *sdata;
if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD)) cancel_work_sync(&sdata->recalc_smps);
return; sdata_lock(sdata);
mutex_lock(&local->mtx);
sdata->vif.csa_active = false;
if (sdata->vif.type == NL80211_IFTYPE_STATION)
sdata->u.mgd.csa_waiting_bcn = false;
if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);
sdata->csa_block_tx = false;
}
mutex_unlock(&local->mtx);
sdata_unlock(sdata);
mutex_lock(&local->iflist_mtx); cancel_work_sync(&sdata->csa_finalize_work);
list_for_each_entry(sdata, &local->interfaces, list) { cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
if (!ieee80211_sdata_running(sdata))
continue;
ieee80211_recalc_sdata_offload(sdata); if (sdata->wdev.cac_started) {
chandef = sdata->vif.bss_conf.chandef;
WARN_ON(local->suspended);
mutex_lock(&local->mtx);
ieee80211_vif_release_channel(sdata);
mutex_unlock(&local->mtx);
cfg80211_cac_event(sdata->dev, &chandef,
NL80211_RADAR_CAC_ABORTED,
GFP_KERNEL);
} }
mutex_unlock(&local->iflist_mtx); /* APs need special treatment */
} if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
const int offset)
{
struct ieee80211_local *local = sdata->local;
u32 flags = sdata->u.mntr.flags;
#define ADJUST(_f, _s) do { \
if (flags & MONITOR_FLAG_##_f) \
local->fif_##_s += offset; \
} while (0)
ADJUST(FCSFAIL, fcsfail); /* down all dependent devices, that is VLANs */
ADJUST(PLCPFAIL, plcpfail); list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
ADJUST(CONTROL, control); u.vlan.list)
ADJUST(CONTROL, pspoll); dev_close(vlan->dev);
ADJUST(OTHER_BSS, other_bss); WARN_ON(!list_empty(&sdata->u.ap.vlans));
} else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
/* remove all packets in parent bc_buf pointing to this dev */
ps = &sdata->bss->ps;
#undef ADJUST spin_lock_irqsave(&ps->bc_buf.lock, flags);
} skb_queue_walk_safe(&ps->bc_buf, skb, tmp) {
if (skb->dev == sdata->dev) {
__skb_unlink(skb, &ps->bc_buf);
local->total_ps_buffered--;
ieee80211_free_txskb(&local->hw, skb);
}
}
spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
}
static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) if (going_down)
{ local->open_count--;
struct ieee80211_local *local = sdata->local;
int i;
for (i = 0; i < IEEE80211_NUM_ACS; i++) { switch (sdata->vif.type) {
if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) case NL80211_IFTYPE_AP_VLAN:
sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE; mutex_lock(&local->mtx);
else if (local->hw.queues >= IEEE80211_NUM_ACS) list_del(&sdata->u.vlan.list);
sdata->vif.hw_queue[i] = i; mutex_unlock(&local->mtx);
else RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL);
sdata->vif.hw_queue[i] = 0; /* see comment in the default case below */
ieee80211_free_keys(sdata, true);
/* no need to tell driver */
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) {
local->cooked_mntrs--;
break;
} }
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
}
int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
int ret;
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) local->monitors--;
return 0; if (local->monitors == 0) {
local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
}
ASSERT_RTNL(); ieee80211_adjust_monitor_flags(sdata, -1);
break;
case NL80211_IFTYPE_NAN:
/* clean all the functions */
spin_lock_bh(&sdata->u.nan.func_lock);
if (local->monitor_sdata) idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) {
return 0; idr_remove(&sdata->u.nan.function_inst_ids, i);
cfg80211_free_nan_func(func);
}
idr_destroy(&sdata->u.nan.function_inst_ids);
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); spin_unlock_bh(&sdata->u.nan.func_lock);
if (!sdata) break;
return -ENOMEM; case NL80211_IFTYPE_P2P_DEVICE:
/* relies on synchronize_rcu() below */
RCU_INIT_POINTER(local->p2p_sdata, NULL);
fallthrough;
default:
cancel_work_sync(&sdata->work);
/*
* When we get here, the interface is marked down.
* Free the remaining keys, if there are any
* (which can happen in AP mode if userspace sets
* keys before the interface is operating, and maybe
* also in WDS mode)
*
* Force the key freeing to always synchronize_net()
* to wait for the RX path in case it is using this
* interface enqueuing frames at this very time on
* another CPU.
*/
ieee80211_free_keys(sdata, true);
skb_queue_purge(&sdata->skb_queue);
}
/* set up data */ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
sdata->local = local; for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
sdata->vif.type = NL80211_IFTYPE_MONITOR; skb_queue_walk_safe(&local->pending[i], skb, tmp) {
snprintf(sdata->name, IFNAMSIZ, "%s-monitor", struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
wiphy_name(local->hw.wiphy)); if (info->control.vif == &sdata->vif) {
sdata->wdev.iftype = NL80211_IFTYPE_MONITOR; __skb_unlink(skb, &local->pending[i]);
ieee80211_free_txskb(&local->hw, skb);
}
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ieee80211_txq_remove_vlan(local, sdata);
ieee80211_set_default_queues(sdata); sdata->bss = NULL;
ret = drv_add_interface(local, sdata); if (local->open_count == 0)
if (WARN_ON(ret)) { ieee80211_clear_tx_pending(local);
/* ok .. stupid driver, it asked for this! */
kfree(sdata);
return ret;
}
ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); sdata->vif.bss_conf.beacon_int = 0;
if (ret) {
kfree(sdata); /*
return ret; * If the interface goes down while suspended, presumably because
* the device was unplugged and that happens before our resume,
* then the driver is already unconfigured and the remainder of
* this function isn't needed.
* XXX: what about WoWLAN? If the device has software state, e.g.
* memory allocated, it might expect teardown commands from
* mac80211 here?
*/
if (local->suspended) {
WARN_ON(local->wowlan);
WARN_ON(rtnl_dereference(local->monitor_sdata));
return;
} }
mutex_lock(&local->iflist_mtx); switch (sdata->vif.type) {
rcu_assign_pointer(local->monitor_sdata, sdata); case NL80211_IFTYPE_AP_VLAN:
mutex_unlock(&local->iflist_mtx); break;
case NL80211_IFTYPE_MONITOR:
if (local->monitors == 0)
ieee80211_del_virtual_monitor(local);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, ieee80211_recalc_idle(local);
IEEE80211_CHANCTX_EXCLUSIVE);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
if (ret) {
mutex_lock(&local->iflist_mtx); if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
RCU_INIT_POINTER(local->monitor_sdata, NULL); break;
mutex_unlock(&local->iflist_mtx);
synchronize_net(); fallthrough;
default:
if (going_down)
drv_remove_interface(local, sdata); drv_remove_interface(local, sdata);
kfree(sdata);
return ret;
} }
skb_queue_head_init(&sdata->skb_queue); ieee80211_recalc_ps(local);
INIT_WORK(&sdata->work, ieee80211_iface_work);
return 0; if (cancel_scan)
} flush_delayed_work(&local->scan_work);
void ieee80211_del_virtual_monitor(struct ieee80211_local *local) if (local->open_count == 0) {
{ ieee80211_stop_device(local);
struct ieee80211_sub_if_data *sdata;
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) /* no reconfiguring after stop! */
return; return;
}
ASSERT_RTNL(); /* do after stop to avoid reconfiguring when we stop anyway */
ieee80211_configure_filter(local);
ieee80211_hw_config(local, hw_reconf_flags);
mutex_lock(&local->iflist_mtx); if (local->monitors == local->open_count)
ieee80211_add_virtual_monitor(local);
}
sdata = rcu_dereference_protected(local->monitor_sdata, static int ieee80211_stop(struct net_device *dev)
lockdep_is_held(&local->iflist_mtx)); {
if (!sdata) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
mutex_unlock(&local->iflist_mtx);
return;
}
RCU_INIT_POINTER(local->monitor_sdata, NULL); ieee80211_do_stop(sdata, true);
mutex_unlock(&local->iflist_mtx);
synchronize_net(); return 0;
}
mutex_lock(&local->mtx); static void ieee80211_set_multicast_list(struct net_device *dev)
ieee80211_vif_release_channel(sdata); {
mutex_unlock(&local->mtx); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
int allmulti, sdata_allmulti;
drv_remove_interface(local, sdata); allmulti = !!(dev->flags & IFF_ALLMULTI);
sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
kfree(sdata); if (allmulti != sdata_allmulti) {
if (dev->flags & IFF_ALLMULTI)
atomic_inc(&local->iff_allmultis);
else
atomic_dec(&local->iff_allmultis);
sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
}
spin_lock_bh(&local->filter_lock);
__hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
spin_unlock_bh(&local->filter_lock);
ieee80211_queue_work(&local->hw, &local->reconfig_filter);
} }
/* /*
* NOTE: Be very careful when changing this function, it must NOT return * Called when the netdev is removed or, by the code below, before
* an error on interface type changes that have been pre-checked, so most * the interface type changes.
* checks should be in ieee80211_check_concurrent_iface.
*/ */
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); int i;
struct net_device *dev = wdev->netdev;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
u32 changed = 0;
int res;
u32 hw_reconf_flags = 0;
switch (sdata->vif.type) { /* free extra data */
case NL80211_IFTYPE_WDS: ieee80211_free_keys(sdata, false);
if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
return -ENOLINK;
break;
case NL80211_IFTYPE_AP_VLAN: {
struct ieee80211_sub_if_data *master;
if (!sdata->bss) ieee80211_debugfs_remove_netdev(sdata);
return -ENOLINK;
mutex_lock(&local->mtx); for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
list_add(&sdata->u.vlan.list, &sdata->bss->vlans); __skb_queue_purge(&sdata->fragments[i].skb_list);
mutex_unlock(&local->mtx); sdata->fragment_next = 0;
master = container_of(sdata->bss, if (ieee80211_vif_is_mesh(&sdata->vif))
struct ieee80211_sub_if_data, u.ap); ieee80211_mesh_teardown_sdata(sdata);
sdata->control_port_protocol = }
master->control_port_protocol;
sdata->control_port_no_encrypt =
master->control_port_no_encrypt;
sdata->control_port_over_nl80211 =
master->control_port_over_nl80211;
sdata->control_port_no_preauth =
master->control_port_no_preauth;
sdata->vif.cab_queue = master->vif.cab_queue;
memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
sizeof(sdata->vif.hw_queue));
sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;
mutex_lock(&local->key_mtx); static void ieee80211_uninit(struct net_device *dev)
sdata->crypto_tx_tailroom_needed_cnt += {
master->crypto_tx_tailroom_needed_cnt; ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
mutex_unlock(&local->key_mtx); }
break; static u16 ieee80211_netdev_select_queue(struct net_device *dev,
} struct sk_buff *skb,
case NL80211_IFTYPE_AP: struct net_device *sb_dev)
sdata->bss = &sdata->u.ap; {
break; return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
case NL80211_IFTYPE_MESH_POINT: }
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_NAN:
/* no special treatment */
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
/* cannot happen */
WARN_ON(1);
break;
}
if (local->open_count == 0) { static void
res = drv_start(local); ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
if (res) {
goto err_del_bss; int i;
/* we're brought up, everything changes */
hw_reconf_flags = ~0;
ieee80211_led_radio(local, true);
ieee80211_mod_tpt_led_trig(local,
IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
}
/* for_each_possible_cpu(i) {
* Copy the hopefully now-present MAC address to const struct pcpu_sw_netstats *tstats;
* this interface, if it has the special null one. u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
*/ unsigned int start;
if (dev && is_zero_ether_addr(dev->dev_addr)) {
memcpy(dev->dev_addr,
local->hw.wiphy->perm_addr,
ETH_ALEN);
memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
if (!is_valid_ether_addr(dev->dev_addr)) { tstats = per_cpu_ptr(dev->tstats, i);
res = -EADDRNOTAVAIL;
goto err_stop;
}
}
switch (sdata->vif.type) { do {
case NL80211_IFTYPE_AP_VLAN: start = u64_stats_fetch_begin_irq(&tstats->syncp);
/* no need to tell driver, but set carrier and chanctx */ rx_packets = tstats->rx_packets;
if (rtnl_dereference(sdata->bss->beacon)) { tx_packets = tstats->tx_packets;
ieee80211_vif_vlan_copy_chanctx(sdata); rx_bytes = tstats->rx_bytes;
netif_carrier_on(dev); tx_bytes = tstats->tx_bytes;
ieee80211_set_vif_encap_ops(sdata); } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
} else {
netif_carrier_off(dev);
}
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) {
local->cooked_mntrs++;
break;
}
if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) { stats->rx_packets += rx_packets;
res = drv_add_interface(local, sdata); stats->tx_packets += tx_packets;
if (res) stats->rx_bytes += rx_bytes;
goto err_stop; stats->tx_bytes += tx_bytes;
} else if (local->monitors == 0 && local->open_count == 0) {
res = ieee80211_add_virtual_monitor(local);
if (res)
goto err_stop;
} }
}
/* must be before the call to ieee80211_configure_filter */ static const struct net_device_ops ieee80211_dataif_ops = {
local->monitors++; .ndo_open = ieee80211_open,
if (local->monitors == 1) { .ndo_stop = ieee80211_stop,
local->hw.conf.flags |= IEEE80211_CONF_MONITOR; .ndo_uninit = ieee80211_uninit,
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; .ndo_start_xmit = ieee80211_subif_start_xmit,
} .ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_netdev_select_queue,
.ndo_get_stats64 = ieee80211_get_stats64,
};
ieee80211_adjust_monitor_flags(sdata, 1); static u16 ieee80211_monitor_select_queue(struct net_device *dev,
ieee80211_configure_filter(local); struct sk_buff *skb,
ieee80211_recalc_offload(local); struct net_device *sb_dev)
mutex_lock(&local->mtx); {
ieee80211_recalc_idle(local); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
mutex_unlock(&local->mtx); struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
int len_rthdr;
netif_carrier_on(dev); if (local->hw.queues < IEEE80211_NUM_ACS)
break; return 0;
default:
if (coming_up) {
ieee80211_del_virtual_monitor(local);
ieee80211_set_sdata_offload_flags(sdata);
res = drv_add_interface(local, sdata); /* reset flags and info before parsing radiotap header */
if (res) memset(info, 0, sizeof(*info));
goto err_stop;
ieee80211_set_vif_encap_ops(sdata); if (!ieee80211_parse_tx_radiotap(skb, dev))
res = ieee80211_check_queues(sdata, return 0; /* doesn't matter, frame will be dropped */
ieee80211_vif_type_p2p(&sdata->vif));
if (res)
goto err_del_interface;
}
if (sdata->vif.type == NL80211_IFTYPE_AP) { len_rthdr = ieee80211_get_radiotap_len(skb->data);
local->fif_pspoll++; hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
local->fif_probe_req++; if (skb->len < len_rthdr + 2 ||
skb->len < len_rthdr + ieee80211_hdrlen(hdr->frame_control))
return 0; /* doesn't matter, frame will be dropped */
ieee80211_configure_filter(local); return ieee80211_select_queue_80211(sdata, skb, hdr);
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { }
local->fif_probe_req++;
}
if (sdata->vif.probe_req_reg) static const struct net_device_ops ieee80211_monitorif_ops = {
drv_config_iface_filter(local, sdata, .ndo_open = ieee80211_open,
FIF_PROBE_REQ, .ndo_stop = ieee80211_stop,
FIF_PROBE_REQ); .ndo_uninit = ieee80211_uninit,
.ndo_start_xmit = ieee80211_monitor_start_xmit,
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_monitor_select_queue,
.ndo_get_stats64 = ieee80211_get_stats64,
};
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && static const struct net_device_ops ieee80211_dataif_8023_ops = {
sdata->vif.type != NL80211_IFTYPE_NAN) .ndo_open = ieee80211_open,
changed |= ieee80211_reset_erp_info(sdata); .ndo_stop = ieee80211_stop,
ieee80211_bss_info_change_notify(sdata, changed); .ndo_uninit = ieee80211_uninit,
.ndo_start_xmit = ieee80211_subif_start_xmit_8023,
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_netdev_select_queue,
.ndo_get_stats64 = ieee80211_get_stats64,
};
switch (sdata->vif.type) { static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
case NL80211_IFTYPE_STATION: {
case NL80211_IFTYPE_ADHOC: switch (iftype) {
/* P2P GO and client are mapped to AP/STATION types */
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_OCB: return true;
netif_carrier_off(dev);
break;
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_NAN:
break;
default: default:
/* not reached */ return false;
WARN_ON(1);
} }
}
/* static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdata)
* Set default queue parameters so drivers don't {
* need to initialise the hardware if the hardware struct ieee80211_local *local = sdata->local;
* doesn't start up with sane defaults. u32 flags;
* Enable QoS for anything but station interfaces.
*/
ieee80211_set_wmm_default(sdata, true,
sdata->vif.type != NL80211_IFTYPE_STATION);
}
set_bit(SDATA_STATE_RUNNING, &sdata->state); flags = sdata->vif.offload_flags;
switch (sdata->vif.type) { if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) &&
case NL80211_IFTYPE_WDS: ieee80211_iftype_supports_encap_offload(sdata->vif.type)) {
/* Create STA entry for the WDS peer */ flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED;
sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
GFP_KERNEL);
if (!sta) {
res = -ENOMEM;
goto err_del_interface;
}
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); local->hw.wiphy->frag_threshold != (u32)-1)
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
res = sta_info_insert(sta); if (local->monitors)
if (res) { flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
/* STA has been freed */ } else {
goto err_del_interface; flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
} }
rate_control_rate_init(sta); if (sdata->vif.offload_flags == flags)
netif_carrier_on(dev); return false;
break;
case NL80211_IFTYPE_P2P_DEVICE: sdata->vif.offload_flags = flags;
rcu_assign_pointer(local->p2p_sdata, sdata); return true;
break; }
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata)
break; {
list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list); struct ieee80211_local *local = sdata->local;
break; struct ieee80211_sub_if_data *bss = sdata;
default: bool enabled;
break;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
if (!sdata->bss)
return;
bss = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
} }
/* if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) ||
* set_multicast_list will be invoked by the networking core !ieee80211_iftype_supports_encap_offload(bss->vif.type))
* which will check whether any increments here were done in return;
* error and sync them down to the hardware as filter flags.
*/
if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
atomic_inc(&local->iff_allmultis);
if (coming_up) enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED;
local->open_count++; if (sdata->wdev.use_4addr &&
!(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR))
enabled = false;
if (hw_reconf_flags) sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops :
ieee80211_hw_config(local, hw_reconf_flags); &ieee80211_dataif_ops;
}
ieee80211_recalc_ps(local); static void ieee80211_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *vsdata;
if (sdata->vif.type == NL80211_IFTYPE_MONITOR || if (ieee80211_set_sdata_offload_flags(sdata)) {
sdata->vif.type == NL80211_IFTYPE_AP_VLAN || drv_update_vif_offload(local, sdata);
local->ops->wake_tx_queue) { ieee80211_set_vif_encap_ops(sdata);
/* XXX: for AP_VLAN, actually track AP queues */ }
if (dev)
netif_tx_start_all_queues(dev);
} else if (dev) {
unsigned long flags;
int n_acs = IEEE80211_NUM_ACS;
int ac;
if (local->hw.queues < IEEE80211_NUM_ACS) list_for_each_entry(vsdata, &local->interfaces, list) {
n_acs = 1; if (vsdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
vsdata->bss != &sdata->u.ap)
continue;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags); ieee80211_set_vif_encap_ops(vsdata);
if (sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE || }
(local->queue_stop_reasons[sdata->vif.cab_queue] == 0 && }
skb_queue_empty(&local->pending[sdata->vif.cab_queue]))) {
for (ac = 0; ac < n_acs; ac++) { void ieee80211_recalc_offload(struct ieee80211_local *local)
int ac_queue = sdata->vif.hw_queue[ac]; {
struct ieee80211_sub_if_data *sdata;
if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD))
return;
if (local->queue_stop_reasons[ac_queue] == 0 && mutex_lock(&local->iflist_mtx);
skb_queue_empty(&local->pending[ac_queue]))
netif_start_subqueue(dev, ac);
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
return 0; list_for_each_entry(sdata, &local->interfaces, list) {
err_del_interface: if (!ieee80211_sdata_running(sdata))
drv_remove_interface(local, sdata); continue;
err_stop:
if (!local->open_count) ieee80211_recalc_sdata_offload(sdata);
drv_stop(local);
err_del_bss:
sdata->bss = NULL;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
mutex_lock(&local->mtx);
list_del(&sdata->u.vlan.list);
mutex_unlock(&local->mtx);
} }
/* might already be clear but that doesn't matter */
clear_bit(SDATA_STATE_RUNNING, &sdata->state); mutex_unlock(&local->iflist_mtx);
return res;
} }
static int ieee80211_open(struct net_device *dev) void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
const int offset)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local;
int err; u32 flags = sdata->u.mntr.flags;
/* fail early if user set an invalid address */ #define ADJUST(_f, _s) do { \
if (!is_valid_ether_addr(dev->dev_addr)) if (flags & MONITOR_FLAG_##_f) \
return -EADDRNOTAVAIL; local->fif_##_s += offset; \
} while (0)
err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type); ADJUST(FCSFAIL, fcsfail);
if (err) ADJUST(PLCPFAIL, plcpfail);
return err; ADJUST(CONTROL, control);
ADJUST(CONTROL, pspoll);
ADJUST(OTHER_BSS, other_bss);
return ieee80211_do_open(&sdata->wdev, true); #undef ADJUST
} }
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
bool going_down)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
unsigned long flags; int i;
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
int i, flushed;
struct ps_data *ps;
struct cfg80211_chan_def chandef;
bool cancel_scan;
struct cfg80211_nan_func *func;
clear_bit(SDATA_STATE_RUNNING, &sdata->state); for (i = 0; i < IEEE80211_NUM_ACS; i++) {
if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE;
else if (local->hw.queues >= IEEE80211_NUM_ACS)
sdata->vif.hw_queue[i] = i;
else
sdata->vif.hw_queue[i] = 0;
}
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
}
cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
if (cancel_scan) {
ieee80211_scan_cancel(local); struct ieee80211_sub_if_data *sdata;
int ret;
/* if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
* Stop TX on this interface first. return 0;
*/
if (sdata->dev)
netif_tx_stop_all_queues(sdata->dev);
ieee80211_roc_purge(local, sdata); ASSERT_RTNL();
switch (sdata->vif.type) { if (local->monitor_sdata)
case NL80211_IFTYPE_STATION: return 0;
ieee80211_mgd_stop(sdata);
break;
case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_stop(sdata);
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
break;
list_del_rcu(&sdata->u.mntr.list);
break;
default:
break;
}
/* sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
* Remove all stations associated with this interface. if (!sdata)
* return -ENOMEM;
* This must be done before calling ops->remove_interface()
* because otherwise we can later invoke ops->sta_notify()
* whenever the STAs are removed, and that invalidates driver
* assumptions about always getting a vif pointer that is valid
* (because if we remove a STA after ops->remove_interface()
* the driver will have removed the vif info already!)
*
* In WDS mode a station must exist here and be flushed, for
* AP_VLANs stations may exist since there's nothing else that
* would have removed them, but in other modes there shouldn't
* be any stations.
*/
flushed = sta_info_flush(sdata);
WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
(sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)));
/* don't count this interface for allmulti while it is down */ /* set up data */
if (sdata->flags & IEEE80211_SDATA_ALLMULTI) sdata->local = local;
atomic_dec(&local->iff_allmultis); sdata->vif.type = NL80211_IFTYPE_MONITOR;
snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
wiphy_name(local->hw.wiphy));
sdata->wdev.iftype = NL80211_IFTYPE_MONITOR;
if (sdata->vif.type == NL80211_IFTYPE_AP) { sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
local->fif_pspoll--;
local->fif_probe_req--; ieee80211_set_default_queues(sdata);
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
local->fif_probe_req--; ret = drv_add_interface(local, sdata);
if (WARN_ON(ret)) {
/* ok .. stupid driver, it asked for this! */
kfree(sdata);
return ret;
} }
if (sdata->dev) { ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR);
netif_addr_lock_bh(sdata->dev); if (ret) {
spin_lock_bh(&local->filter_lock); kfree(sdata);
__hw_addr_unsync(&local->mc_list, &sdata->dev->mc, return ret;
sdata->dev->addr_len);
spin_unlock_bh(&local->filter_lock);
netif_addr_unlock_bh(sdata->dev);
} }
del_timer_sync(&local->dynamic_ps_timer); mutex_lock(&local->iflist_mtx);
cancel_work_sync(&local->dynamic_ps_enable_work); rcu_assign_pointer(local->monitor_sdata, sdata);
mutex_unlock(&local->iflist_mtx);
cancel_work_sync(&sdata->recalc_smps);
sdata_lock(sdata);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
sdata->vif.csa_active = false; ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
if (sdata->vif.type == NL80211_IFTYPE_STATION) IEEE80211_CHANCTX_EXCLUSIVE);
sdata->u.mgd.csa_waiting_bcn = false;
if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);
sdata->csa_block_tx = false;
}
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
sdata_unlock(sdata); if (ret) {
mutex_lock(&local->iflist_mtx);
RCU_INIT_POINTER(local->monitor_sdata, NULL);
mutex_unlock(&local->iflist_mtx);
synchronize_net();
drv_remove_interface(local, sdata);
kfree(sdata);
return ret;
}
cancel_work_sync(&sdata->csa_finalize_work); skb_queue_head_init(&sdata->skb_queue);
INIT_WORK(&sdata->work, ieee80211_iface_work);
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); return 0;
}
void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
return;
ASSERT_RTNL();
mutex_lock(&local->iflist_mtx);
sdata = rcu_dereference_protected(local->monitor_sdata,
lockdep_is_held(&local->iflist_mtx));
if (!sdata) {
mutex_unlock(&local->iflist_mtx);
return;
}
RCU_INIT_POINTER(local->monitor_sdata, NULL);
mutex_unlock(&local->iflist_mtx);
synchronize_net();
if (sdata->wdev.cac_started) {
chandef = sdata->vif.bss_conf.chandef;
WARN_ON(local->suspended);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
ieee80211_vif_release_channel(sdata); ieee80211_vif_release_channel(sdata);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
cfg80211_cac_event(sdata->dev, &chandef,
NL80211_RADAR_CAC_ABORTED,
GFP_KERNEL);
}
/* APs need special treatment */ drv_remove_interface(local, sdata);
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;
/* down all dependent devices, that is VLANs */ kfree(sdata);
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)); * NOTE: Be very careful when changing this function, it must NOT return
} else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { * an error on interface type changes that have been pre-checked, so most
/* remove all packets in parent bc_buf pointing to this dev */ * checks should be in ieee80211_check_concurrent_iface.
ps = &sdata->bss->ps; */
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct net_device *dev = wdev->netdev;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
u32 changed = 0;
int res;
u32 hw_reconf_flags = 0;
spin_lock_irqsave(&ps->bc_buf.lock, flags); switch (sdata->vif.type) {
skb_queue_walk_safe(&ps->bc_buf, skb, tmp) { case NL80211_IFTYPE_WDS:
if (skb->dev == sdata->dev) { if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
__skb_unlink(skb, &ps->bc_buf); return -ENOLINK;
local->total_ps_buffered--; break;
ieee80211_free_txskb(&local->hw, skb); case NL80211_IFTYPE_AP_VLAN: {
} struct ieee80211_sub_if_data *master;
}
spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
}
if (going_down) if (!sdata->bss)
local->open_count--; return -ENOLINK;
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
list_del(&sdata->u.vlan.list); list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL);
/* see comment in the default case below */
ieee80211_free_keys(sdata, true);
/* no need to tell driver */
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) {
local->cooked_mntrs--;
break;
}
local->monitors--; master = container_of(sdata->bss,
if (local->monitors == 0) { struct ieee80211_sub_if_data, u.ap);
local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; sdata->control_port_protocol =
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; master->control_port_protocol;
} sdata->control_port_no_encrypt =
master->control_port_no_encrypt;
sdata->control_port_over_nl80211 =
master->control_port_over_nl80211;
sdata->control_port_no_preauth =
master->control_port_no_preauth;
sdata->vif.cab_queue = master->vif.cab_queue;
memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
sizeof(sdata->vif.hw_queue));
sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;
ieee80211_adjust_monitor_flags(sdata, -1); mutex_lock(&local->key_mtx);
break; sdata->crypto_tx_tailroom_needed_cnt +=
case NL80211_IFTYPE_NAN: master->crypto_tx_tailroom_needed_cnt;
/* clean all the functions */ mutex_unlock(&local->key_mtx);
spin_lock_bh(&sdata->u.nan.func_lock);
idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) { break;
idr_remove(&sdata->u.nan.function_inst_ids, i);
cfg80211_free_nan_func(func);
} }
idr_destroy(&sdata->u.nan.function_inst_ids); case NL80211_IFTYPE_AP:
sdata->bss = &sdata->u.ap;
spin_unlock_bh(&sdata->u.nan.func_lock);
break; break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_P2P_DEVICE:
/* relies on synchronize_rcu() below */ case NL80211_IFTYPE_OCB:
RCU_INIT_POINTER(local->p2p_sdata, NULL); case NL80211_IFTYPE_NAN:
fallthrough; /* no special treatment */
default: break;
cancel_work_sync(&sdata->work); case NL80211_IFTYPE_UNSPECIFIED:
/* case NUM_NL80211_IFTYPES:
* When we get here, the interface is marked down. case NL80211_IFTYPE_P2P_CLIENT:
* Free the remaining keys, if there are any case NL80211_IFTYPE_P2P_GO:
* (which can happen in AP mode if userspace sets /* cannot happen */
* keys before the interface is operating, and maybe WARN_ON(1);
* also in WDS mode) break;
*
* Force the key freeing to always synchronize_net()
* to wait for the RX path in case it is using this
* interface enqueuing frames at this very time on
* another CPU.
*/
ieee80211_free_keys(sdata, true);
skb_queue_purge(&sdata->skb_queue);
} }
spin_lock_irqsave(&local->queue_stop_reason_lock, flags); if (local->open_count == 0) {
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { res = drv_start(local);
skb_queue_walk_safe(&local->pending[i], skb, tmp) { if (res)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); goto err_del_bss;
if (info->control.vif == &sdata->vif) { /* we're brought up, everything changes */
__skb_unlink(skb, &local->pending[i]); hw_reconf_flags = ~0;
ieee80211_free_txskb(&local->hw, skb); ieee80211_led_radio(local, true);
} ieee80211_mod_tpt_led_trig(local,
} IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
} }
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ieee80211_txq_remove_vlan(local, sdata);
sdata->bss = NULL;
if (local->open_count == 0)
ieee80211_clear_tx_pending(local);
sdata->vif.bss_conf.beacon_int = 0;
/* /*
* If the interface goes down while suspended, presumably because * Copy the hopefully now-present MAC address to
* the device was unplugged and that happens before our resume, * this interface, if it has the special null one.
* then the driver is already unconfigured and the remainder of
* this function isn't needed.
* XXX: what about WoWLAN? If the device has software state, e.g.
* memory allocated, it might expect teardown commands from
* mac80211 here?
*/ */
if (local->suspended) { if (dev && is_zero_ether_addr(dev->dev_addr)) {
WARN_ON(local->wowlan); memcpy(dev->dev_addr,
WARN_ON(rtnl_dereference(local->monitor_sdata)); local->hw.wiphy->perm_addr,
return; ETH_ALEN);
memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
if (!is_valid_ether_addr(dev->dev_addr)) {
res = -EADDRNOTAVAIL;
goto err_stop;
}
} }
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP_VLAN:
/* no need to tell driver, but set carrier and chanctx */
if (rtnl_dereference(sdata->bss->beacon)) {
ieee80211_vif_vlan_copy_chanctx(sdata);
netif_carrier_on(dev);
ieee80211_set_vif_encap_ops(sdata);
} else {
netif_carrier_off(dev);
}
break; break;
case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MONITOR:
if (local->monitors == 0) if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) {
ieee80211_del_virtual_monitor(local); local->cooked_mntrs++;
mutex_lock(&local->mtx);
ieee80211_recalc_idle(local);
mutex_unlock(&local->mtx);
if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
break; break;
fallthrough;
default:
if (going_down)
drv_remove_interface(local, sdata);
} }
ieee80211_recalc_ps(local); if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
res = drv_add_interface(local, sdata);
if (cancel_scan) if (res)
flush_delayed_work(&local->scan_work); goto err_stop;
} else if (local->monitors == 0 && local->open_count == 0) {
if (local->open_count == 0) { res = ieee80211_add_virtual_monitor(local);
ieee80211_stop_device(local); if (res)
goto err_stop;
}
/* no reconfiguring after stop! */ /* must be before the call to ieee80211_configure_filter */
return; local->monitors++;
if (local->monitors == 1) {
local->hw.conf.flags |= IEEE80211_CONF_MONITOR;
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
} }
/* do after stop to avoid reconfiguring when we stop anyway */ ieee80211_adjust_monitor_flags(sdata, 1);
ieee80211_configure_filter(local); ieee80211_configure_filter(local);
ieee80211_hw_config(local, hw_reconf_flags); ieee80211_recalc_offload(local);
mutex_lock(&local->mtx);
if (local->monitors == local->open_count) ieee80211_recalc_idle(local);
ieee80211_add_virtual_monitor(local); mutex_unlock(&local->mtx);
}
static int ieee80211_stop(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_do_stop(sdata, true);
return 0;
}
static void ieee80211_set_multicast_list(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
int allmulti, sdata_allmulti;
allmulti = !!(dev->flags & IFF_ALLMULTI);
sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
if (allmulti != sdata_allmulti) { netif_carrier_on(dev);
if (dev->flags & IFF_ALLMULTI) break;
atomic_inc(&local->iff_allmultis); default:
else if (coming_up) {
atomic_dec(&local->iff_allmultis); ieee80211_del_virtual_monitor(local);
sdata->flags ^= IEEE80211_SDATA_ALLMULTI; ieee80211_set_sdata_offload_flags(sdata);
}
spin_lock_bh(&local->filter_lock); res = drv_add_interface(local, sdata);
__hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); if (res)
spin_unlock_bh(&local->filter_lock); goto err_stop;
ieee80211_queue_work(&local->hw, &local->reconfig_filter);
}
/* ieee80211_set_vif_encap_ops(sdata);
* Called when the netdev is removed or, by the code below, before res = ieee80211_check_queues(sdata,
* the interface type changes. ieee80211_vif_type_p2p(&sdata->vif));
*/ if (res)
static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) goto err_del_interface;
{ }
int i;
/* free extra data */ if (sdata->vif.type == NL80211_IFTYPE_AP) {
ieee80211_free_keys(sdata, false); local->fif_pspoll++;
local->fif_probe_req++;
ieee80211_debugfs_remove_netdev(sdata); ieee80211_configure_filter(local);
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
local->fif_probe_req++;
}
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) if (sdata->vif.probe_req_reg)
__skb_queue_purge(&sdata->fragments[i].skb_list); drv_config_iface_filter(local, sdata,
sdata->fragment_next = 0; FIF_PROBE_REQ,
FIF_PROBE_REQ);
if (ieee80211_vif_is_mesh(&sdata->vif)) if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
ieee80211_mesh_teardown_sdata(sdata); sdata->vif.type != NL80211_IFTYPE_NAN)
} changed |= ieee80211_reset_erp_info(sdata);
ieee80211_bss_info_change_notify(sdata, changed);
static void ieee80211_uninit(struct net_device *dev) switch (sdata->vif.type) {
{ case NL80211_IFTYPE_STATION:
ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev)); case NL80211_IFTYPE_ADHOC:
} case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
netif_carrier_off(dev);
break;
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_NAN:
break;
default:
/* not reached */
WARN_ON(1);
}
static u16 ieee80211_netdev_select_queue(struct net_device *dev, /*
struct sk_buff *skb, * Set default queue parameters so drivers don't
struct net_device *sb_dev) * need to initialise the hardware if the hardware
{ * doesn't start up with sane defaults.
return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb); * Enable QoS for anything but station interfaces.
} */
ieee80211_set_wmm_default(sdata, true,
sdata->vif.type != NL80211_IFTYPE_STATION);
}
static void set_bit(SDATA_STATE_RUNNING, &sdata->state);
ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
int i;
for_each_possible_cpu(i) { switch (sdata->vif.type) {
const struct pcpu_sw_netstats *tstats; case NL80211_IFTYPE_WDS:
u64 rx_packets, rx_bytes, tx_packets, tx_bytes; /* Create STA entry for the WDS peer */
unsigned int start; sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
GFP_KERNEL);
if (!sta) {
res = -ENOMEM;
goto err_del_interface;
}
tstats = per_cpu_ptr(dev->tstats, i); 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);
do { res = sta_info_insert(sta);
start = u64_stats_fetch_begin_irq(&tstats->syncp); if (res) {
rx_packets = tstats->rx_packets; /* STA has been freed */
tx_packets = tstats->tx_packets; goto err_del_interface;
rx_bytes = tstats->rx_bytes; }
tx_bytes = tstats->tx_bytes;
} while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
stats->rx_packets += rx_packets; rate_control_rate_init(sta);
stats->tx_packets += tx_packets; netif_carrier_on(dev);
stats->rx_bytes += rx_bytes; break;
stats->tx_bytes += tx_bytes; case NL80211_IFTYPE_P2P_DEVICE:
rcu_assign_pointer(local->p2p_sdata, sdata);
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
break;
list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list);
break;
default:
break;
} }
}
static const struct net_device_ops ieee80211_dataif_ops = { /*
.ndo_open = ieee80211_open, * set_multicast_list will be invoked by the networking core
.ndo_stop = ieee80211_stop, * which will check whether any increments here were done in
.ndo_uninit = ieee80211_uninit, * error and sync them down to the hardware as filter flags.
.ndo_start_xmit = ieee80211_subif_start_xmit, */
.ndo_set_rx_mode = ieee80211_set_multicast_list, if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
.ndo_set_mac_address = ieee80211_change_mac, atomic_inc(&local->iff_allmultis);
.ndo_select_queue = ieee80211_netdev_select_queue,
.ndo_get_stats64 = ieee80211_get_stats64,
};
static u16 ieee80211_monitor_select_queue(struct net_device *dev, if (coming_up)
struct sk_buff *skb, local->open_count++;
struct net_device *sb_dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
int len_rthdr;
if (local->hw.queues < IEEE80211_NUM_ACS) if (hw_reconf_flags)
return 0; ieee80211_hw_config(local, hw_reconf_flags);
/* reset flags and info before parsing radiotap header */ ieee80211_recalc_ps(local);
memset(info, 0, sizeof(*info));
if (!ieee80211_parse_tx_radiotap(skb, dev)) if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
return 0; /* doesn't matter, frame will be dropped */ sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
local->ops->wake_tx_queue) {
/* XXX: for AP_VLAN, actually track AP queues */
if (dev)
netif_tx_start_all_queues(dev);
} else if (dev) {
unsigned long flags;
int n_acs = IEEE80211_NUM_ACS;
int ac;
len_rthdr = ieee80211_get_radiotap_len(skb->data); if (local->hw.queues < IEEE80211_NUM_ACS)
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); n_acs = 1;
if (skb->len < len_rthdr + 2 ||
skb->len < len_rthdr + ieee80211_hdrlen(hdr->frame_control))
return 0; /* doesn't matter, frame will be dropped */
return ieee80211_select_queue_80211(sdata, skb, hdr); spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
} if (sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE ||
(local->queue_stop_reasons[sdata->vif.cab_queue] == 0 &&
skb_queue_empty(&local->pending[sdata->vif.cab_queue]))) {
for (ac = 0; ac < n_acs; ac++) {
int ac_queue = sdata->vif.hw_queue[ac];
static const struct net_device_ops ieee80211_monitorif_ops = { if (local->queue_stop_reasons[ac_queue] == 0 &&
.ndo_open = ieee80211_open, skb_queue_empty(&local->pending[ac_queue]))
.ndo_stop = ieee80211_stop, netif_start_subqueue(dev, ac);
.ndo_uninit = ieee80211_uninit, }
.ndo_start_xmit = ieee80211_monitor_start_xmit, }
.ndo_set_rx_mode = ieee80211_set_multicast_list, spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
.ndo_set_mac_address = ieee80211_change_mac, }
.ndo_select_queue = ieee80211_monitor_select_queue,
.ndo_get_stats64 = ieee80211_get_stats64,
};
static const struct net_device_ops ieee80211_dataif_8023_ops = { return 0;
.ndo_open = ieee80211_open, err_del_interface:
.ndo_stop = ieee80211_stop, drv_remove_interface(local, sdata);
.ndo_uninit = ieee80211_uninit, err_stop:
.ndo_start_xmit = ieee80211_subif_start_xmit_8023, if (!local->open_count)
.ndo_set_rx_mode = ieee80211_set_multicast_list, drv_stop(local);
.ndo_set_mac_address = ieee80211_change_mac, err_del_bss:
.ndo_select_queue = ieee80211_netdev_select_queue, sdata->bss = NULL;
.ndo_get_stats64 = ieee80211_get_stats64, if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
}; mutex_lock(&local->mtx);
list_del(&sdata->u.vlan.list);
mutex_unlock(&local->mtx);
}
/* might already be clear but that doesn't matter */
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
return res;
}
static void ieee80211_if_free(struct net_device *dev) static void ieee80211_if_free(struct net_device *dev)
{ {
...@@ -1332,32 +1356,6 @@ static void ieee80211_if_setup_no_queue(struct net_device *dev) ...@@ -1332,32 +1356,6 @@ static void ieee80211_if_setup_no_queue(struct net_device *dev)
dev->priv_flags |= IFF_NO_QUEUE; dev->priv_flags |= IFF_NO_QUEUE;
} }
static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *bss = sdata;
bool enabled;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
if (!sdata->bss)
return;
bss = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
}
if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) ||
!ieee80211_iftype_supports_encap_offload(bss->vif.type))
return;
enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED;
if (sdata->wdev.use_4addr &&
!(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR))
enabled = false;
sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops :
&ieee80211_dataif_ops;
}
static void ieee80211_iface_work(struct work_struct *work) static void ieee80211_iface_work(struct work_struct *work)
{ {
struct ieee80211_sub_if_data *sdata = struct ieee80211_sub_if_data *sdata =
......
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