Re: [PATCHv3 RESEND 09/11] mac80211: Implement add_nan_func and rm_nan_func

2016-04-06 Thread Johannes Berg
On Tue, 2016-03-29 at 12:35 +0300, Emmanuel Grumbach wrote:

> + * @rm_nan_func: Remove a nan function. The driver must call
> + * ieee80211_nan_func_terminated() with
> + * NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon
> removal.

bad indentation.

Also here: nan -> NAN.

> + /* Only set max_nan_de_entries as available to honor the
> device's
> +  * limitations
> +  */
> + bitmap_set(sdata->u.nan.func_ids, 1,
> +    sdata->local->hw.max_nan_de_entries);

That doesn't make a lot of sense to me. What are you trying to do?

> + inst_id = find_first_bit(sdata->u.nan.func_ids,
> +  IEEE80211_MAX_NAN_INSTANCE_ID + 1);
> + if (inst_id == IEEE80211_MAX_NAN_INSTANCE_ID + 1)
> + return -ENOBUFS;

Wouldn't you use max_nan_de_entries here instead of
MAX_NAN_INSTANCE_ID, after validating that the former is actually
smaller than or equal to the latter?

Also, the logic says that the variable should be called
"available_func_ids", although I'd prefer "used_func_ids" after
adjusting the logic according to the comments above.

> + cfg80211_clone_nan_func_members(&func->func, nan_func);

This is quite obviously missing error checking, but see the discussion
in the patch that introduced it.

> + spin_lock_bh(&sdata->u.nan.func_lock);
> + clear_bit(inst_id, sdata->u.nan.func_ids);
> + list_add(&func->list, &sdata->u.nan.functions_list);
> + spin_unlock_bh(&sdata->u.nan.func_lock);
> +
> + ret = drv_add_nan_func(sdata->local, sdata, nan_func);
> + if (ret) {
> + spin_lock_bh(&sdata->u.nan.func_lock);
> + set_bit(inst_id, sdata->u.nan.func_ids);
> + list_del(&func->list);
> + spin_unlock_bh(&sdata->u.nan.func_lock);
> +
> + cfg80211_free_nan_func_members(&func->func);
> + kfree(func);
> + }
> +
> + return ret;
> +}

> +static struct ieee80211_nan_func *
> +ieee80211_find_nan_func(struct ieee80211_sub_if_data *sdata, u8
> instance_id)
> +{
> + struct ieee80211_nan_func *func;
> +
> + lockdep_assert_held(&sdata->u.nan.func_lock);
> +
> + list_for_each_entry(func, &sdata->u.nan.functions_list,
> list) {
> + if (func->func.instance_id == instance_id)
> + return func;
> + }
> +
> + return NULL;
> +}

Arguably though, this whole thing just screams "idr" [1] and then you
don't even need the list_head in the cfg80211 struct.

[1] include/linux/idr.h

> +static struct ieee80211_nan_func *
> +ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data
> *sdata,
> +   u64 cookie)
> +{
> + struct ieee80211_nan_func *func;
> +
> + lockdep_assert_held(&sdata->u.nan.func_lock);
> +
> + list_for_each_entry(func, &sdata->u.nan.functions_list,
> list) {
> + if (func->func.cookie == cookie)
> + return func;
> + }
> +
> + return NULL;
> +}

Although this might be more difficult then, but you always
have idr_for_each_entry().

> + case NL80211_IFTYPE_NAN:
> + /* clean all the functions */
> + spin_lock_bh(&sdata->u.nan.func_lock);
> + list_for_each_entry_safe(func, tmp_func,
> +  &sdata-
> >u.nan.functions_list, list) {
> + list_del(&func->list);
> + cfg80211_free_nan_func_members(&func->func);
> + kfree(func);
> + }
> + spin_unlock_bh(&sdata->u.nan.func_lock);
> + break;
>   case NL80211_IFTYPE_P2P_DEVICE:
>   /* relies on synchronize_rcu() below */
>   RCU_INIT_POINTER(local->p2p_sdata, NULL);
>   /* fall through */
> - case NL80211_IFTYPE_NAN:

any particular reason you're moving the case label?

>   default:
>   cancel_work_sync(&sdata->work);
>   /*
> @@ -1453,9 +1464,15 @@ static void ieee80211_setup_sdata(struct
> ieee80211_sub_if_data *sdata,
>   case NL80211_IFTYPE_WDS:
>   sdata->vif.bss_conf.bssid = NULL;
>   break;
> + case NL80211_IFTYPE_NAN:
> + bitmap_zero(sdata->u.nan.func_ids,
> + IEEE80211_MAX_NAN_INSTANCE_ID + 1);
> + INIT_LIST_HEAD(&sdata->u.nan.functions_list);
> + spin_lock_init(&sdata->u.nan.func_lock);
> + sdata->vif.bss_conf.bssid = sdata->vif.addr;
> + break;
>   case NL80211_IFTYPE_AP_VLAN:
>   case NL80211_IFTYPE_P2P_DEVICE:
> - case NL80211_IFTYPE_NAN:

also here?

> + if (!local->hw.max_nan_de_entries)
> + local->hw.max_nan_de_entries =
> IEEE80211_MAX_NAN_INSTANCE_ID;

Need a max check also, I guess?

> +/* TODO: record more fields */

...
but isn't cfg80211 recording them anyway?

> +static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data
> *sdata)
> +{
> + struct ieee80211_nan_func *func, *ftmp;
> 

[PATCHv3 RESEND 09/11] mac80211: Implement add_nan_func and rm_nan_func

2016-03-29 Thread Emmanuel Grumbach
From: Andrei Otcheretianski 

Implement add/rm_nan_func functions and handle nan function
termination notifications. Handle instance_id allocation for
nan functions and implement the reconfig flow.

Signed-off-by: Andrei Otcheretianski 
Signed-off-by: Emmanuel Grumbach 
---
 include/net/mac80211.h |  31 ++
 net/mac80211/cfg.c | 147 +
 net/mac80211/driver-ops.h  |  32 ++
 net/mac80211/ieee80211_i.h |  15 +
 net/mac80211/iface.c   |  21 ++-
 net/mac80211/main.c|   3 +
 net/mac80211/trace.h   |  53 
 net/mac80211/util.c|  55 -
 8 files changed, 354 insertions(+), 3 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 011f979..a3cc08f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2116,6 +2116,8 @@ enum ieee80211_hw_flags {
  *
  * @txq_ac_max_pending: maximum number of frames per AC pending in all txq
  * entries for a vif.
+ * @max_nan_de_entries: maximum number of NAN DE functions supported by the
+ * device.
  */
 struct ieee80211_hw {
struct ieee80211_conf conf;
@@ -2146,6 +2148,7 @@ struct ieee80211_hw {
u8 n_cipher_schemes;
const struct ieee80211_cipher_scheme *cipher_schemes;
int txq_ac_max_pending;
+   u8 max_nan_de_entries;
 };
 
 static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
@@ -3364,6 +3367,12 @@ enum ieee80211_reconfig_type {
  * @nan_change_conf: change nan configuration. The data in cfg80211_nan_conf
  * contains full new configuration and changes specify which parameters
  * are changed with respect to the last nan config.
+ * @add_nan_func: Add a nan function. Returns 0 on success. The data in
+ * cfg80211_nan_func must not be referenced outside the scope of
+ * this call.
+ * @rm_nan_func: Remove a nan function. The driver must call
+ * ieee80211_nan_func_terminated() with
+ * NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal.
  */
 struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -3611,6 +3620,12 @@ struct ieee80211_ops {
int (*nan_change_conf)(struct ieee80211_hw *hw,
   struct ieee80211_vif *vif,
   struct cfg80211_nan_conf *conf, u8 changes);
+   int (*add_nan_func)(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   const struct cfg80211_nan_func *nan_func);
+   void (*rm_nan_func)(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   u8 instance_id);
 };
 
 /**
@@ -5655,4 +5670,20 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw 
*hw,
 void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
 unsigned long *frame_cnt,
 unsigned long *byte_cnt);
+
+/*
+ * ieee80211_nan_func_terminated - notify about NAN function termination.
+ *
+ * This function is used to notify mac80211 about nan function termination.
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @inst_id: the local instance id
+ * @reason: termination reason (one of the NL80211_NAN_FUNC_TERM_REASON_*)
+ * @gfp: allocation flags
+ */
+void ieee80211_nan_func_terminated(struct ieee80211_vif *vif,
+  u8 inst_id,
+  enum nl80211_nan_func_term_reason reason,
+  gfp_t gfp);
+
 #endif /* MAC80211_H */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 9215232..67b0d8a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3,6 +3,7 @@
  *
  * Copyright 2006-2010 Johannes Berg 
  * Copyright 2013-2015  Intel Mobile Communications GmbH
+ * Copyright (C) 2015-2016 Intel Deutschland GmbH
  *
  * This file is GPLv2 as found in COPYING.
  */
@@ -152,6 +153,12 @@ static int ieee80211_start_nan(struct wiphy *wiphy,
 
memcpy(&sdata->u.nan.nan_conf, conf, sizeof(sdata->u.nan.nan_conf));
 
+   /* Only set max_nan_de_entries as available to honor the device's
+* limitations
+*/
+   bitmap_set(sdata->u.nan.func_ids, 1,
+  sdata->local->hw.max_nan_de_entries);
+
return ret;
 }
 
@@ -194,6 +201,107 @@ static int ieee80211_nan_change_conf(struct wiphy *wiphy,
return ret;
 }
 
+static int ieee80211_add_nan_func(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_func *nan_func)
+{
+   struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+   struct ieee80211_nan_func *func;
+   int ret;
+   int inst_id;
+
+   if (sdata->vif.type != NL80211_IFTYPE_NAN)
+   return -EOPNOTSUPP;
+
+   if (!ieee80211_sdata_running(sdata))
+   return -ENETDOWN;
+
+   inst_id = find_first