diff options
Diffstat (limited to 'net/mac80211/ibss.c')
| -rw-r--r-- | net/mac80211/ibss.c | 171 | 
1 files changed, 86 insertions, 85 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b2cc1fda6cf..c691780725a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -43,6 +43,8 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,  {  	u16 auth_alg, auth_transaction, status_code; +	lockdep_assert_held(&sdata->u.ibss.mtx); +  	if (len < 24 + 6)  		return; @@ -78,6 +80,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,  	u32 bss_change;  	u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; +	lockdep_assert_held(&ifibss->mtx); +  	/* Reset own TSF to allow time synchronization work. */  	drv_reset_tsf(local); @@ -172,11 +176,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,  	rcu_assign_pointer(ifibss->presp, skb);  	sdata->vif.bss_conf.beacon_int = beacon_int; +	sdata->vif.bss_conf.basic_rates = basic_rates;  	bss_change = BSS_CHANGED_BEACON_INT;  	bss_change |= ieee80211_reset_erp_info(sdata);  	bss_change |= BSS_CHANGED_BSSID;  	bss_change |= BSS_CHANGED_BEACON;  	bss_change |= BSS_CHANGED_BEACON_ENABLED; +	bss_change |= BSS_CHANGED_BASIC_RATES;  	bss_change |= BSS_CHANGED_IBSS;  	sdata->vif.bss_conf.ibss_joined = true;  	ieee80211_bss_info_change_notify(sdata, bss_change); @@ -203,6 +209,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,  	int i, j;  	u16 beacon_int = cbss->beacon_interval; +	lockdep_assert_held(&sdata->u.ibss.mtx); +  	if (beacon_int < 10)  		beacon_int = 10; @@ -447,6 +455,8 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)  	int active = 0;  	struct sta_info *sta; +	lockdep_assert_held(&sdata->u.ibss.mtx); +  	rcu_read_lock();  	list_for_each_entry_rcu(sta, &local->sta_list, list) { @@ -471,6 +481,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)  {  	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; +	lockdep_assert_held(&ifibss->mtx); +  	mod_timer(&ifibss->timer,  		  round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); @@ -503,6 +515,8 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)  	u16 capability;  	int i; +	lockdep_assert_held(&ifibss->mtx); +  	if (ifibss->fixed_bssid) {  		memcpy(bssid, ifibss->bssid, ETH_ALEN);  	} else { @@ -529,7 +543,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)  		sdata->drop_unencrypted = 0;  	__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, -				  ifibss->channel, 3, /* first two are basic */ +				  ifibss->channel, ifibss->basic_rates,  				  capability, 0);  } @@ -547,6 +561,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)  	int active_ibss;  	u16 capability; +	lockdep_assert_held(&ifibss->mtx); +  	active_ibss = ieee80211_sta_active_ibss(sdata);  #ifdef CONFIG_MAC80211_IBSS_DEBUG  	printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", @@ -635,6 +651,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,  	struct ieee80211_mgmt *resp;  	u8 *pos, *end; +	lockdep_assert_held(&ifibss->mtx); +  	if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||  	    len < 24 + 2 || !ifibss->presp)  		return; @@ -727,8 +745,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);  } -static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, -					  struct sk_buff *skb) +void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, +				   struct sk_buff *skb)  {  	struct ieee80211_rx_status *rx_status;  	struct ieee80211_mgmt *mgmt; @@ -738,6 +756,8 @@ static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,  	mgmt = (struct ieee80211_mgmt *) skb->data;  	fc = le16_to_cpu(mgmt->frame_control); +	mutex_lock(&sdata->u.ibss.mtx); +  	switch (fc & IEEE80211_FCTL_STYPE) {  	case IEEE80211_STYPE_PROBE_REQ:  		ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len); @@ -755,35 +775,22 @@ static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,  		break;  	} -	kfree_skb(skb); +	mutex_unlock(&sdata->u.ibss.mtx);  } -static void ieee80211_ibss_work(struct work_struct *work) +void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)  { -	struct ieee80211_sub_if_data *sdata = -		container_of(work, struct ieee80211_sub_if_data, u.ibss.work); -	struct ieee80211_local *local = sdata->local; -	struct ieee80211_if_ibss *ifibss; -	struct sk_buff *skb; - -	if (WARN_ON(local->suspended)) -		return; - -	if (!ieee80211_sdata_running(sdata)) -		return; - -	if (local->scanning) -		return; - -	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC)) -		return; -	ifibss = &sdata->u.ibss; +	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; -	while ((skb = skb_dequeue(&ifibss->skb_queue))) -		ieee80211_ibss_rx_queued_mgmt(sdata, skb); +	mutex_lock(&ifibss->mtx); -	if (!test_and_clear_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request)) -		return; +	/* +	 * Work could be scheduled after scan or similar +	 * when we aren't even joined (or trying) with a +	 * network. +	 */ +	if (!ifibss->ssid_len) +		goto out;  	switch (ifibss->state) {  	case IEEE80211_IBSS_MLME_SEARCH: @@ -796,6 +803,9 @@ static void ieee80211_ibss_work(struct work_struct *work)  		WARN_ON(1);  		break;  	} + + out: +	mutex_unlock(&ifibss->mtx);  }  static void ieee80211_ibss_timer(unsigned long data) @@ -810,8 +820,7 @@ static void ieee80211_ibss_timer(unsigned long data)  		return;  	} -	set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); -	ieee80211_queue_work(&local->hw, &ifibss->work); +	ieee80211_queue_work(&local->hw, &sdata->work);  }  #ifdef CONFIG_PM @@ -819,7 +828,6 @@ void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata)  {  	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; -	cancel_work_sync(&ifibss->work);  	if (del_timer_sync(&ifibss->timer))  		ifibss->timer_running = true;  } @@ -839,10 +847,9 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)  {  	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; -	INIT_WORK(&ifibss->work, ieee80211_ibss_work);  	setup_timer(&ifibss->timer, ieee80211_ibss_timer,  		    (unsigned long) sdata); -	skb_queue_head_init(&ifibss->skb_queue); +	mutex_init(&ifibss->mtx);  }  /* scan finished notification */ @@ -856,45 +863,28 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)  			continue;  		if (sdata->vif.type != NL80211_IFTYPE_ADHOC)  			continue; -		if (!sdata->u.ibss.ssid_len) -			continue;  		sdata->u.ibss.last_scan_completed = jiffies; -		mod_timer(&sdata->u.ibss.timer, 0); +		ieee80211_queue_work(&local->hw, &sdata->work);  	}  	mutex_unlock(&local->iflist_mtx);  } -ieee80211_rx_result -ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) -{ -	struct ieee80211_local *local = sdata->local; -	struct ieee80211_mgmt *mgmt; -	u16 fc; - -	if (skb->len < 24) -		return RX_DROP_MONITOR; - -	mgmt = (struct ieee80211_mgmt *) skb->data; -	fc = le16_to_cpu(mgmt->frame_control); - -	switch (fc & IEEE80211_FCTL_STYPE) { -	case IEEE80211_STYPE_PROBE_RESP: -	case IEEE80211_STYPE_BEACON: -	case IEEE80211_STYPE_PROBE_REQ: -	case IEEE80211_STYPE_AUTH: -		skb_queue_tail(&sdata->u.ibss.skb_queue, skb); -		ieee80211_queue_work(&local->hw, &sdata->u.ibss.work); -		return RX_QUEUED; -	} - -	return RX_DROP_MONITOR; -} -  int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,  			struct cfg80211_ibss_params *params)  {  	struct sk_buff *skb; +	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; + +	mutex_lock(&sdata->u.ibss.mtx); +  	if (params->bssid) {  		memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);  		sdata->u.ibss.fixed_bssid = true; @@ -902,6 +892,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,  		sdata->u.ibss.fixed_bssid = false;  	sdata->u.ibss.privacy = params->privacy; +	sdata->u.ibss.basic_rates = params->basic_rates;  	sdata->vif.bss_conf.beacon_int = params->beacon_interval; @@ -922,34 +913,18 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,  			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); +	ieee80211_queue_work(&sdata->local->hw, &sdata->work); + +	mutex_unlock(&sdata->u.ibss.mtx);  	return 0;  } @@ -957,11 +932,33 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,  int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)  {  	struct sk_buff *skb; +	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; +	struct ieee80211_local *local = sdata->local; +	struct cfg80211_bss *cbss; +	u16 capability; +	int active_ibss; -	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); +	mutex_lock(&sdata->u.ibss.mtx); + +	active_ibss = ieee80211_sta_active_ibss(sdata); + +	if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { +		capability = WLAN_CAPABILITY_IBSS; + +		if (ifibss->privacy) +			capability |= WLAN_CAPABILITY_PRIVACY; + +		cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->channel, +					ifibss->bssid, ifibss->ssid, +					ifibss->ssid_len, WLAN_CAPABILITY_IBSS | +					WLAN_CAPABILITY_PRIVACY, +					capability); + +		if (cbss) { +			cfg80211_unlink_bss(local->hw.wiphy, cbss); +			cfg80211_put_bss(cbss); +		} +	}  	sta_info_flush(sdata->local, sdata); @@ -975,10 +972,14 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)  	synchronize_rcu();  	kfree_skb(skb); -	skb_queue_purge(&sdata->u.ibss.skb_queue); +	skb_queue_purge(&sdata->skb_queue);  	memset(sdata->u.ibss.bssid, 0, ETH_ALEN);  	sdata->u.ibss.ssid_len = 0; +	del_timer_sync(&sdata->u.ibss.timer); + +	mutex_unlock(&sdata->u.ibss.mtx); +  	ieee80211_recalc_idle(sdata->local);  	return 0;  |