diff options
Diffstat (limited to 'net/mac80211/work.c')
| -rw-r--r-- | net/mac80211/work.c | 45 | 
1 files changed, 44 insertions, 1 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index b025dc7bb0f..81d4ad64184 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -560,6 +560,22 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)  	return WORK_ACT_TIMEOUT;  } +static enum work_action __must_check +ieee80211_assoc_beacon_wait(struct ieee80211_work *wk) +{ +	if (wk->started) +		return WORK_ACT_TIMEOUT; + +	/* +	 * Wait up to one beacon interval ... +	 * should this be more if we miss one? +	 */ +	printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", +	       wk->sdata->name, wk->filter_ta); +	wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval); +	return WORK_ACT_NONE; +} +  static void ieee80211_auth_challenge(struct ieee80211_work *wk,  				     struct ieee80211_mgmt *mgmt,  				     size_t len) @@ -709,6 +725,25 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,  	return WORK_ACT_DONE;  } +static enum work_action __must_check +ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk, +			 struct ieee80211_mgmt *mgmt, size_t len) +{ +	struct ieee80211_sub_if_data *sdata = wk->sdata; +	struct ieee80211_local *local = sdata->local; + +	ASSERT_WORK_MTX(local); + +	if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) +		return WORK_ACT_MISMATCH; + +	if (len < 24 + 12) +		return WORK_ACT_NONE; + +	printk(KERN_DEBUG "%s: beacon received\n", sdata->name); +	return WORK_ACT_DONE; +} +  static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,  					  struct sk_buff *skb)  { @@ -731,6 +766,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,  		case IEEE80211_WORK_DIRECT_PROBE:  		case IEEE80211_WORK_AUTH:  		case IEEE80211_WORK_ASSOC: +		case IEEE80211_WORK_ASSOC_BEACON_WAIT:  			bssid = wk->filter_ta;  			break;  		default: @@ -745,6 +781,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,  			continue;  		switch (fc & IEEE80211_FCTL_STYPE) { +		case IEEE80211_STYPE_BEACON: +			rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len); +			break;  		case IEEE80211_STYPE_PROBE_RESP:  			rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,  							   rx_status); @@ -840,7 +879,7 @@ static void ieee80211_work_work(struct work_struct *work)  	/*  	 * ieee80211_queue_work() should have picked up most cases, -	 * here we'll pick the the rest. +	 * here we'll pick the rest.  	 */  	if (WARN(local->suspended, "work scheduled while going to suspend\n"))  		return; @@ -916,6 +955,9 @@ static void ieee80211_work_work(struct work_struct *work)  		case IEEE80211_WORK_REMAIN_ON_CHANNEL:  			rma = ieee80211_remain_on_channel_timeout(wk);  			break; +		case IEEE80211_WORK_ASSOC_BEACON_WAIT: +			rma = ieee80211_assoc_beacon_wait(wk); +			break;  		}  		wk->started = started; @@ -1065,6 +1107,7 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,  		case IEEE80211_STYPE_PROBE_RESP:  		case IEEE80211_STYPE_ASSOC_RESP:  		case IEEE80211_STYPE_REASSOC_RESP: +		case IEEE80211_STYPE_BEACON:  			skb_queue_tail(&local->work_skb_queue, skb);  			ieee80211_queue_work(&local->hw, &local->work_work);  			return RX_QUEUED;  |