DECLARE_BITMAP(removed_channels, IEEE80211_NAN_MAX_CHANNELS);
};
+/**
+ * struct ieee80211_if_nan_data - NAN data path state
+ *
+ * @nmi: pointer to the NAN management interface sdata. Used for data path,
+ * hence RCU.
+ */
+struct ieee80211_if_nan_data {
+ struct ieee80211_sub_if_data __rcu *nmi;
+};
+
struct ieee80211_link_data_managed {
u8 bssid[ETH_ALEN] __aligned(2);
struct ieee80211_if_ocb ocb;
struct ieee80211_if_mntr mntr;
struct ieee80211_if_nan nan;
+ struct ieee80211_if_nan_data nan_data;
} u;
struct ieee80211_link_data deflink;
nsdata->vif.type == NL80211_IFTYPE_OCB))
return -EBUSY;
+ /*
+ * A NAN DATA interface is correlated to the NAN
+ * (management) one
+ */
+ if (iftype == NL80211_IFTYPE_NAN_DATA &&
+ nsdata->vif.type == NL80211_IFTYPE_NAN) {
+ if (!nsdata->u.nan.started)
+ return -EINVAL;
+ rcu_assign_pointer(sdata->u.nan_data.nmi, nsdata);
+ }
+
/*
* Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down)
{
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_sub_if_data *iter;
unsigned long flags;
struct sk_buff_head freeq;
struct sk_buff *skb, *tmp;
}
break;
case NL80211_IFTYPE_NAN:
+ /* Check if any open NAN_DATA interfaces */
+ list_for_each_entry(iter, &local->interfaces, list) {
+ WARN_ON(iter->vif.type == NL80211_IFTYPE_NAN_DATA &&
+ ieee80211_sdata_running(iter));
+ }
+
/* clean all the functions */
if (!(local->hw.wiphy->nan_capa.flags &
WIPHY_NAN_FLAGS_USERSPACE_DE)) {
spin_unlock_bh(&sdata->u.nan.de.func_lock);
}
break;
+ case NL80211_IFTYPE_NAN_DATA:
+ RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
+ fallthrough;
default:
wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
/*
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_NAN:
- case NL80211_IFTYPE_NAN_DATA:
/* no special treatment */
break;
+ case NL80211_IFTYPE_NAN_DATA:
+ if (WARN_ON(!rcu_access_pointer(sdata->u.nan_data.nmi)))
+ return -ENOLINK;
+ break;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
res = drv_start(local);
if (res) {
/*
- * no need to worry about AP_VLAN cleanup since in that
- * case we can't have open_count == 0
+ * no need to worry about AP_VLAN/NAN_DATA cleanup since
+ * in that case we can't have open_count == 0
*/
return res;
}
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
+ case NL80211_IFTYPE_NAN_DATA:
netif_carrier_off(dev);
break;
case NL80211_IFTYPE_P2P_DEVICE:
err_stop:
if (!local->open_count)
drv_stop(local, false);
+ if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
+ RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
list_del(&sdata->u.vlan.list);
/* Might not be initialized yet, but it is harmless */