+
+int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_ibss_params *params)
+{
+ struct sk_buff *skb;
+
+ if (params->bssid) {
+ memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
+ sdata->u.ibss.fixed_bssid = true;
+ } else
+ sdata->u.ibss.fixed_bssid = false;
+
+ sdata->u.ibss.privacy = params->privacy;
+
+ sdata->vif.bss_conf.beacon_int = params->beacon_interval;
+
+ sdata->u.ibss.channel = params->channel;
+ sdata->u.ibss.fixed_channel = params->channel_fixed;
+
+ if (params->ie) {
+ sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len,
+ GFP_KERNEL);
+ if (sdata->u.ibss.ie)
+ sdata->u.ibss.ie_len = params->ie_len;
+ }
+
+ skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
+ 36 /* bitrates */ +
+ 34 /* SSID */ +
+ 3 /* DS params */ +
+ 4 /* IBSS params */ +
+ params->ie_len);
+ if (!skb)
+ return -ENOMEM;
+
+ sdata->u.ibss.skb = skb;
+ sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
+ sdata->u.ibss.ibss_join_req = jiffies;
+
+ memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
+
+ /*
+ * The ssid_len setting below is used to see whether
+ * we are active, and we need all other settings
+ * before that may get visible.
+ */
+ mb();
+
+ sdata->u.ibss.ssid_len = params->ssid_len;
+
+ ieee80211_recalc_idle(sdata->local);
+
+ set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work);
+
+ return 0;
+}
+
+int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
+{
+ struct sk_buff *skb;
+
+ del_timer_sync(&sdata->u.ibss.timer);
+ clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
+ cancel_work_sync(&sdata->u.ibss.work);
+ clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
+
+ sta_info_flush(sdata->local, sdata);
+
+ /* remove beacon */
+ kfree(sdata->u.ibss.ie);
+ skb = sdata->u.ibss.presp;
+ rcu_assign_pointer(sdata->u.ibss.presp, NULL);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+ synchronize_rcu();
+ kfree_skb(skb);
+
+ skb_queue_purge(&sdata->u.ibss.skb_queue);
+ memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
+ sdata->u.ibss.ssid_len = 0;
+
+ ieee80211_recalc_idle(sdata->local);
+
+ return 0;
+}