mac80211: add explicit IBSS driver operations
authorJohannes Berg <johannes.berg@intel.com>
Mon, 19 Aug 2013 16:48:41 +0000 (18:48 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 1 Oct 2013 10:17:45 +0000 (12:17 +0200)
This can be useful for drivers if they have any failure cases
when joining an IBSS. Also move setting the queue parameters
to before this new call, in case the new driver op needs them
already.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/driver-ops.h
net/mac80211/ibss.c
net/mac80211/trace.h

index 3411c59b636bb21754862d1bd86cdaac62d83c49..8cff800f7046573a8531161ae8f867d88461edaf 100644 (file)
@@ -2666,6 +2666,10 @@ enum ieee80211_roc_type {
  *     zero using ieee80211_csa_is_complete() after the beacon has been
  *     transmitted and then call ieee80211_csa_finish().
  *
+ * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
+ *     information in bss_conf is set up and the beacon can be retrieved. A
+ *     channel context is bound before this is called.
+ * @leave_ibss: Leave the IBSS again.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
@@ -2857,6 +2861,9 @@ struct ieee80211_ops {
        void (*channel_switch_beacon)(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif,
                                      struct cfg80211_chan_def *chandef);
+
+       int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+       void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 };
 
 /**
index b3ea11f3d526962ddd8190587f82d8d84134067c..5d03c47c0a4cb4fa60e861750956c64bb8c90337 100644 (file)
@@ -1085,4 +1085,31 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
        }
 }
 
+static inline int drv_join_ibss(struct ieee80211_local *local,
+                               struct ieee80211_sub_if_data *sdata)
+{
+       int ret = 0;
+
+       might_sleep();
+       check_sdata_in_driver(sdata);
+
+       trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf);
+       if (local->ops->join_ibss)
+               ret = local->ops->join_ibss(&local->hw, &sdata->vif);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
+static inline void drv_leave_ibss(struct ieee80211_local *local,
+                                 struct ieee80211_sub_if_data *sdata)
+{
+       might_sleep();
+       check_sdata_in_driver(sdata);
+
+       trace_drv_leave_ibss(local, sdata);
+       if (local->ops->leave_ibss)
+               local->ops->leave_ibss(&local->hw, &sdata->vif);
+       trace_drv_return_void(local);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
index 5ea9b3ae303e88b9ab44998f3af7edff16002f33..21a0b8835cb31d4a27dda9b2243038c2280b8f6a 100644 (file)
@@ -229,6 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        struct beacon_data *presp;
        enum nl80211_bss_scan_width scan_width;
        bool have_higher_than_11mbit;
+       int err;
 
        sdata_assert_lock(sdata);
 
@@ -247,6 +248,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                ieee80211_bss_info_change_notify(sdata,
                                                 BSS_CHANGED_IBSS |
                                                 BSS_CHANGED_BEACON_ENABLED);
+               drv_leave_ibss(local, sdata);
        }
 
        presp = rcu_dereference_protected(ifibss->presp,
@@ -329,11 +331,26 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
+       ieee80211_set_wmm_default(sdata, true);
+
        sdata->vif.bss_conf.ibss_joined = true;
        sdata->vif.bss_conf.ibss_creator = creator;
-       ieee80211_bss_info_change_notify(sdata, bss_change);
 
-       ieee80211_set_wmm_default(sdata, true);
+       err = drv_join_ibss(local, sdata);
+       if (err) {
+               sdata->vif.bss_conf.ibss_joined = false;
+               sdata->vif.bss_conf.ibss_creator = false;
+               sdata->vif.bss_conf.enable_beacon = false;
+               sdata->vif.bss_conf.ssid_len = 0;
+               RCU_INIT_POINTER(ifibss->presp, NULL);
+               kfree_rcu(presp, rcu_head);
+               ieee80211_vif_release_channel(sdata);
+               sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
+                          err);
+               return;
+       }
+
+       ieee80211_bss_info_change_notify(sdata, bss_change);
 
        ifibss->state = IEEE80211_IBSS_MLME_JOINED;
        mod_timer(&ifibss->timer,
@@ -761,6 +778,7 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
        clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
                                                BSS_CHANGED_IBSS);
+       drv_leave_ibss(local, sdata);
        ieee80211_vif_release_channel(sdata);
 }
 
index 1aba645882bd92abbf9e5a4cdd90f7544a173c4a..5d62c5804819e8e3faa3e696e16b166c5f431524 100644 (file)
@@ -1475,6 +1475,41 @@ DEFINE_EVENT(local_sdata_evt, drv_ipv6_addr_change,
 );
 #endif
 
+TRACE_EVENT(drv_join_ibss,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_bss_conf *info),
+
+       TP_ARGS(local, sdata, info),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u8, dtimper)
+               __field(u16, bcnint)
+               __dynamic_array(u8, ssid, info->ssid_len);
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->dtimper = info->dtim_period;
+               __entry->bcnint = info->beacon_int;
+               memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG
+       )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_leave_ibss,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */