/** * DOC: Interface list locking * * The interface list in each struct ieee80211_local is protected * three-fold: * * (1) modifications may only be done under the RTNL *and* wiphy mutex * *and* iflist_mtx * (2) modifications are done in an RCU manner so atomic readers * can traverse the list in RCU-safe blocks. * * As a consequence, reads (traversals) of the list can be protected * by either the RTNL, the wiphy mutex, the iflist_mtx or RCU.
*/
if ((new & ~mask) != (tmp & ~mask)) {
ret = -EINVAL; break;
}
}
return ret;
}
staticint ieee80211_can_powered_addr_change(struct ieee80211_sub_if_data *sdata)
{ struct ieee80211_roc_work *roc; struct ieee80211_local *local = sdata->local; struct ieee80211_sub_if_data *scan_sdata; int ret = 0;
lockdep_assert_wiphy(local->hw.wiphy);
/* To be the most flexible here we want to only limit changing the * address if the specific interface is doing offchannel work or * scanning.
*/ if (netif_carrier_ok(sdata->dev)) return -EBUSY;
/* if any stations are set known (so they know this vif too), reject */ if (sta_info_get_by_idx(sdata, 0)) return -EBUSY;
/* First check no ROC work is happening on this iface */
list_for_each_entry(roc, &local->roc_list, list) { if (roc->sdata != sdata) continue;
if (roc->started) {
ret = -EBUSY; goto unlock;
}
}
/* And if this iface is scanning */ if (local->scanning) {
scan_sdata = rcu_dereference_protected(local->scan_sdata,
lockdep_is_held(&local->hw.wiphy->mtx)); if (sdata == scan_sdata)
ret = -EBUSY;
}
/* * More interface types could be added here but changing the * address while powered makes the most sense in client modes.
*/ switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: /* refuse while connecting */ if (sdata->u.mgd.auth_data || sdata->u.mgd.assoc_data) return -EBUSY; break; default:
ret = -EOPNOTSUPP;
}
/* Regardless of eth_mac_addr() return we still want to add the * interface back. This should not fail...
*/ if (live)
WARN_ON(drv_add_interface(local, sdata));
/* * This happens during unregistration if there's a bond device * active (maybe other cases?) and we must get removed from it. * But we really don't care anymore if it's not registered now.
*/ if (!dev->ieee80211_ptr->registered) return 0;
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(nsdata, &local->interfaces, list) { if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { /* * Only OCB and monitor mode may coexist
*/ if ((sdata->vif.type == NL80211_IFTYPE_OCB &&
nsdata->vif.type != NL80211_IFTYPE_MONITOR) ||
(sdata->vif.type != NL80211_IFTYPE_MONITOR &&
nsdata->vif.type == NL80211_IFTYPE_OCB)) return -EBUSY;
/* * Allow only a single IBSS interface to be up at any * time. This is restricted because beacon distribution * cannot work properly if both are in the same IBSS. * * To remove this restriction we'd have to disallow them * from setting the same SSID on different IBSS interfaces * belonging to the same hardware. Then, however, we're * faced with having to adopt two different TSF timers...
*/ if (iftype == NL80211_IFTYPE_ADHOC &&
nsdata->vif.type == NL80211_IFTYPE_ADHOC) return -EBUSY; /* * will not add another interface while any channel * switch is active.
*/ if (nsdata->vif.bss_conf.csa_active) return -EBUSY;
/* * The remaining checks are only performed for interfaces * with the same MAC address.
*/ if (!ether_addr_equal(sdata->vif.addr,
nsdata->vif.addr)) continue;
/* * check whether it may have the same address
*/ if (!identical_mac_addr_allowed(iftype,
nsdata->vif.type)) return -ENOTUNIQ;
/* No support for VLAN with MLO yet */ if (iftype == NL80211_IFTYPE_AP_VLAN &&
sdata->wdev.use_4addr &&
nsdata->vif.type == NL80211_IFTYPE_AP &&
nsdata->vif.valid_links) return -EOPNOTSUPP;
/* * can only add VLANs to enabled APs
*/ if (iftype == NL80211_IFTYPE_AP_VLAN &&
nsdata->vif.type == NL80211_IFTYPE_AP)
sdata->bss = &nsdata->u.ap;
}
}
staticint ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype iftype)
{ int n_queues = sdata->local->hw.queues; int i;
if (iftype == NL80211_IFTYPE_NAN) return 0;
if (iftype != NL80211_IFTYPE_P2P_DEVICE) { for (i = 0; i < IEEE80211_NUM_ACS; i++) { if (WARN_ON_ONCE(sdata->vif.hw_queue[i] ==
IEEE80211_INVAL_HW_QUEUE)) return -EINVAL; if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >=
n_queues)) return -EINVAL;
}
}
cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; if (cancel_scan)
ieee80211_scan_cancel(local);
ieee80211_roc_purge(local, sdata);
switch (sdata->vif.type) { case NL80211_IFTYPE_STATION:
ieee80211_mgd_stop(sdata); break; case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_stop(sdata); break; case NL80211_IFTYPE_MONITOR:
list_del_rcu(&sdata->u.mntr.list); break; case NL80211_IFTYPE_AP_VLAN:
ieee80211_apvlan_link_clear(sdata); 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!) * * 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, -1);
WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN && flushed > 0);
/* don't count this interface for allmulti while it is down */ if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
atomic_dec(&local->iff_allmultis);
if (sdata->vif.type == NL80211_IFTYPE_AP) {
WARN_ON(!list_empty(&sdata->u.ap.vlans));
} elseif (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { /* remove all packets in parent bc_buf pointing to this dev */
ps = &sdata->bss->ps;
switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN:
list_del(&sdata->u.vlan.list);
RCU_INIT_POINTER(sdata->vif.bss_conf.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:
local->monitors--;
if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
spin_unlock_bh(&sdata->u.nan.func_lock); break; default:
wiphy_work_cancel(sdata->local->hw.wiphy, &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) * * 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);
skb_queue_purge(&sdata->status_queue);
}
/* * Since ieee80211_free_txskb() may issue __dev_queue_xmit() * which should be called with interrupts enabled, reclamation * is done in two phases:
*/
__skb_queue_head_init(&freeq);
/* unlink from local queues... */
spin_lock_irqsave(&local->queue_stop_reason_lock, flags); for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
skb_queue_walk_safe(&local->pending[i], skb, tmp) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (info->control.vif == &sdata->vif) {
__skb_unlink(skb, &local->pending[i]);
__skb_queue_tail(&freeq, skb);
}
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
/* ... and perform actual reclamation with interrupts enabled. */
skb_queue_walk_safe(&freeq, skb, tmp) {
__skb_unlink(skb, &freeq);
ieee80211_free_txskb(&local->hw, skb);
}
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ieee80211_txq_remove_vlan(local, sdata);
if (sdata->vif.txq)
ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq));
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 * 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(rcu_access_pointer(local->monitor_sdata)); return;
}
switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: break; case NL80211_IFTYPE_MONITOR: if (local->virt_monitors == 0)
ieee80211_del_virtual_monitor(local);
/* Check if any of the links of current sdata is an MBSSID. */
for_each_vif_active_link(&sdata->vif, link_conf, link_id) {
tx_bss_conf = sdata_dereference(link_conf->tx_bss_conf, sdata); if (!tx_bss_conf) continue;
/* If we are not tx sdata reset tx sdata's tx_bss_conf to avoid recusrion * while closing tx sdata at the end of outer loop below.
*/ if (sdata != tx_sdata) {
tx_link = sdata_dereference(tx_sdata->link[tx_bss_conf->link_id],
tx_sdata); if (!tx_link) continue;
/* loop through sdatas to find if any of their links * belong to same MBSSID set as the one getting deleted.
*/
for_each_sdata_link(tx_sdata->local, link) { struct ieee80211_sub_if_data *link_sdata = link->sdata;
/* Remove all links of matching MLD until dynamic link * removal can be supported.
*/
cfg80211_stop_iface(link_sdata->wdev.wiphy, &link_sdata->wdev,
GFP_KERNEL);
}
/* If we are not tx sdata, remove links of tx sdata and proceed */ if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata))
cfg80211_stop_iface(tx_sdata->wdev.wiphy,
&tx_sdata->wdev, GFP_KERNEL);
}
}
/* Close the dependent MBSSID interfaces with wiphy lock as we may be * terminating its partner links too in case of MLD.
*/ if (sdata->vif.type == NL80211_IFTYPE_AP)
ieee80211_stop_mbssid(sdata);
/* * Called when the netdev is removed or, by the code below, before * the interface type changes.
*/ staticvoid ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
{ if (WARN_ON(!list_empty(&sdata->work.entry)))
wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
/* free extra data */
ieee80211_free_keys(sdata, false);
ieee80211_debugfs_remove_netdev(sdata);
ieee80211_destroy_frag_cache(&sdata->frags);
if (ieee80211_vif_is_mesh(&sdata->vif))
ieee80211_mesh_teardown_sdata(sdata);
sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev);
local = sdata->local;
if (!local->ops->net_fill_forward_path) return -EOPNOTSUPP;
rcu_read_lock(); switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN:
sta = rcu_dereference(sdata->u.vlan.sta); if (sta) break; if (sdata->wdev.use_4addr) goto out; if (is_multicast_ether_addr(ctx->daddr)) goto out;
sta = sta_info_get_bss(sdata, ctx->daddr); break; case NL80211_IFTYPE_AP: if (is_multicast_ether_addr(ctx->daddr)) goto out;
sta = sta_info_get(sdata, ctx->daddr); break; case NL80211_IFTYPE_STATION: if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
sta = sta_info_get(sdata, ctx->daddr); if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) goto out;
break;
}
}
sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid); break; default: goto out;
}
if (!sta) goto out;
ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path);
out:
rcu_read_unlock();
staticbool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)
{ switch (iftype) { /* P2P GO and client are mapped to AP/STATION types */ case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: returntrue; default: returnfalse;
}
}
/* * Initialize the default link, so we can use link_id 0 for non-MLD, * and that continues to work for non-MLD-aware drivers that use just * vif.bss_conf instead of vif.link_conf. * * Note that we never change this, so if link ID 0 isn't used in an * MLD connection, we get a separate allocation for it.
*/
ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf);
}
int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
{ struct ieee80211_sub_if_data *sdata; int ret;
if (local->monitor_sdata ||
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) return 0;
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); if (!sdata) return -ENOMEM;
/* set up data */
sdata->vif.type = NL80211_IFTYPE_MONITOR;
snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
wiphy_name(local->hw.wiphy));
sdata->wdev.iftype = NL80211_IFTYPE_MONITOR;
sdata->wdev.wiphy = local->hw.wiphy;
ieee80211_sdata_init(local, sdata);
ieee80211_set_default_queues(sdata);
if (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
ret = drv_add_interface(local, sdata); if (WARN_ON(ret)) { /* ok .. stupid driver, it asked for this! */
kfree(sdata); return ret;
}
}
set_bit(SDATA_STATE_RUNNING, &sdata->state);
ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); if (ret) {
kfree(sdata); return ret;
}
/* * NOTE: Be very careful when changing this function, it must NOT return * an error on interface type changes that have been pre-checked, so most * checks should be in ieee80211_check_concurrent_iface.
*/ 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;
u64 changed = 0; int res;
u32 hw_reconf_flags = 0;
lockdep_assert_wiphy(local->hw.wiphy);
switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: { struct ieee80211_sub_if_data *master;
break;
} case NL80211_IFTYPE_AP:
sdata->bss = &sdata->u.ap; 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_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: case NL80211_IFTYPE_WDS: /* cannot happen */
WARN_ON(1); break;
}
if (local->open_count == 0) { /* here we can consider everything in good order (again) */
local->reconfig_failure = false;
res = drv_start(local); if (res) goto err_del_bss;
ieee80211_led_radio(local, true);
ieee80211_mod_tpt_led_trig(local,
IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
}
/* * Copy the hopefully now-present MAC address to * this interface, if it has the special null one.
*/ if (dev && is_zero_ether_addr(dev->dev_addr)) {
eth_hw_addr_set(dev, local->hw.wiphy->perm_addr);
memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
if (!is_valid_ether_addr(dev->dev_addr)) {
res = -EADDRNOTAVAIL; goto err_stop;
}
}
sdata->vif.addr_valid = sdata->vif.type != NL80211_IFTYPE_MONITOR ||
(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE); switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: /* no need to tell driver, but set carrier and chanctx */ if (sdata->bss->active) { struct ieee80211_link_data *link;
netif_carrier_on(dev);
ieee80211_set_vif_encap_ops(sdata);
} else {
netif_carrier_off(dev);
} break; case NL80211_IFTYPE_MONITOR: if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
res = drv_add_interface(local, sdata); if (res) goto err_stop;
} else { if (local->virt_monitors == 0 && local->open_count == 0) {
res = ieee80211_add_virtual_monitor(local); if (res) goto err_stop;
}
local->virt_monitors++;
/* must be before the call to ieee80211_configure_filter */ if (local->virt_monitors == 1) {
local->hw.conf.flags |= IEEE80211_CONF_MONITOR;
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
}
}
switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: 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_P2P_DEVICE: case NL80211_IFTYPE_NAN: break; default: /* not reached */
WARN_ON(1);
}
/* * Set default queue parameters so drivers don't * need to initialise the hardware if the hardware * doesn't start up with sane defaults. * Enable QoS for anything but station interfaces.
*/
ieee80211_set_wmm_default(&sdata->deflink, true,
sdata->vif.type != NL80211_IFTYPE_STATION);
}
/* * set_multicast_list will be invoked by the networking core * which will check whether any increments here were done in * 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)
local->open_count++;
if (local->open_count == 1)
ieee80211_hw_conf_init(local); elseif (hw_reconf_flags)
ieee80211_hw_config(local, -1, hw_reconf_flags);
ieee80211_recalc_ps(local);
set_bit(SDATA_STATE_RUNNING, &sdata->state);
return 0;
err_del_interface:
drv_remove_interface(local, sdata);
err_stop: if (!local->open_count)
drv_stop(local, false);
err_del_bss:
sdata->bss = NULL; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
list_del(&sdata->u.vlan.list); /* might already be clear but that doesn't matter */
clear_bit(SDATA_STATE_RUNNING, &sdata->state); return res;
}
/* * So the frame isn't mgmt, but frame_control * is at the right place anyway, of course, so * the if statement is correct. * * Warn if we have other data frame types here, * they must not get here.
*/
WARN_ON(hdr->frame_control &
cpu_to_le16(IEEE80211_STYPE_NULLFUNC));
WARN_ON(!(hdr->seq_ctrl &
cpu_to_le16(IEEE80211_SCTL_FRAG))); /* * This was a fragment of a frame, received while * a block-ack session was active. That cannot be * right, so terminate the session.
*/
sta = sta_info_get_bss(sdata, mgmt->sa); if (sta) {
u16 tid = ieee80211_get_tid(hdr);
__ieee80211_stop_rx_ba_session(
sta, tid, WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_REQUIRE_SETUP, true);
}
} elseswitch (sdata->vif.type) { case NL80211_IFTYPE_STATION:
ieee80211_sta_rx_queued_mgmt(sdata, skb); break; case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_rx_queued_mgmt(sdata, skb); break; case NL80211_IFTYPE_MESH_POINT: if (!ieee80211_vif_is_mesh(&sdata->vif)) break;
ieee80211_mesh_rx_queued_mgmt(sdata, skb); break; default:
WARN(1, "frame for unexpected interface type"); break;
}
}
/* then other type-dependent work */ switch (sdata->vif.type) { case NL80211_IFTYPE_STATION:
ieee80211_sta_work(sdata); break; case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_work(sdata); break; case NL80211_IFTYPE_MESH_POINT: if (!ieee80211_vif_is_mesh(&sdata->vif)) break;
ieee80211_mesh_work(sdata); break; case NL80211_IFTYPE_OCB:
ieee80211_ocb_work(sdata); break; default: break;
}
}
/* for now, don't support changing while links exist */ if (ieee80211_vif_is_mld(&sdata->vif)) return -EBUSY;
switch (sdata->vif.type) { case NL80211_IFTYPE_AP: if (!list_empty(&sdata->u.ap.vlans)) return -EBUSY; break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_OCB: /* * Could maybe also all others here? * Just not sure how that interacts * with the RX/config path e.g. for * mesh.
*/ break; default: return -EBUSY;
}
switch (type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_OCB: /* * Could probably support everything * but here.
*/ break; case NL80211_IFTYPE_P2P_CLIENT:
p2p = true;
internal_type = NL80211_IFTYPE_STATION; break; case NL80211_IFTYPE_P2P_GO:
p2p = true;
internal_type = NL80211_IFTYPE_AP; break; default: return -EBUSY;
}
ret = ieee80211_check_concurrent_iface(sdata, internal_type); if (ret) return ret;
ieee80211_stop_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE); /* do_stop will synchronize_rcu() first thing */
ieee80211_do_stop(sdata, false);
ieee80211_teardown_sdata(sdata);
ieee80211_set_sdata_offload_flags(sdata);
ret = drv_change_interface(local, sdata, internal_type, p2p); if (ret)
type = ieee80211_vif_type_p2p(&sdata->vif);
/* * Ignore return value here, there's not much we can do since * the driver changed the interface type internally already. * The warnings will hopefully make driver authors fix it :-)
*/
ieee80211_check_queues(sdata, type);
/* default ... something at least */
memcpy(perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
if (is_zero_ether_addr(local->hw.wiphy->addr_mask) &&
local->hw.wiphy->n_addresses <= 1) return;
switch (type) { case NL80211_IFTYPE_MONITOR: /* doesn't matter */ break; case NL80211_IFTYPE_AP_VLAN: /* match up with an AP interface */
list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_AP) continue;
memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); break;
} /* keep default if no AP interface present */ break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: if (ieee80211_hw_check(&local->hw, P2P_DEV_ADDR_FOR_INTF)) {
list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) continue; if (!ieee80211_sdata_running(sdata)) continue;
memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); return;
}
}
fallthrough; default: /* assign a new address if possible -- try n_addresses first */ for (i = 0; i < local->hw.wiphy->n_addresses; i++) { bool used = false;
list_for_each_entry(sdata, &local->interfaces, list) { if (ether_addr_equal(local->hw.wiphy->addresses[i].addr,
sdata->vif.addr)) {
used = true; break;
}
}
if (!used) {
memcpy(perm_addr,
local->hw.wiphy->addresses[i].addr,
ETH_ALEN); break;
}
}
/* try mask if available */ if (is_zero_ether_addr(local->hw.wiphy->addr_mask)) break;
/* MTU range is normally 256 - 2304, where the upper limit is * the maximum MSDU size. Monitor interfaces send and receive * MPDU and A-MSDU frames which may be much larger so we do * not impose an upper limit in that case.
*/
ndev->min_mtu = 256; if (type == NL80211_IFTYPE_MONITOR)
ndev->max_mtu = 0; else
ndev->max_mtu = local->hw.max_mtu;
ret = cfg80211_register_netdevice(ndev); if (ret) {
free_netdev(ndev); return ret;
}
}
/* Before destroying the interfaces, make sure they're all stopped so * that the hardware is stopped. Otherwise, the driver might still be * iterating the interfaces during the shutdown, e.g. from a worker * or from RX processing or similar, and if it does so (using atomic * iteration) while we're manipulating the list, the iteration will * crash. * * After this, the hardware should be stopped and the driver should * have stopped all of its activities, so that we can do RCU-unaware * manipulations of the interface list below.
*/
cfg80211_shutdown_all_interfaces(local->hw.wiphy);
guard(wiphy)(local->hw.wiphy);
WARN(local->open_count, "%s: open count remains %d\n",
wiphy_name(local->hw.wiphy), local->open_count);
/* * Remove IP addresses explicitly, since the notifier will * skip the callbacks if wdev->registered is false, since * we can't acquire the wiphy_lock() again there if already * inside this locked section.
*/
sdata->vif.cfg.arp_addr_cnt = 0; if (sdata->vif.type == NL80211_IFTYPE_STATION &&
sdata->u.mgd.associated)
ieee80211_vif_cfg_change_notify(sdata,
BSS_CHANGED_ARP_FILTER);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.