Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe9066ad authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'mac80211-for-davem-2015-05-26' of...

Merge tag 'mac80211-for-davem-2015-05-26' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211



Johannes Berg says:

====================
We have three more fixes:
 * AP_VLAN tailroom calculation fix, the bug leads to warnings
   along with dropped packets
 * NAPI context issue, calling napi_gro_receive() from a timer
   (obviously) can lead to crashes
 * remain-on-channel combining leads to dropped requests and not
   being able to finish certain operations, so remove it
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5f59102f f9dca80b
Loading
Loading
Loading
Loading
+11 −48
Original line number Diff line number Diff line
@@ -2495,54 +2495,25 @@ static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local,
					   struct ieee80211_roc_work *new_roc,
					   struct ieee80211_roc_work *cur_roc)
{
	unsigned long j = jiffies;
	unsigned long cur_roc_end = cur_roc->hw_start_time +
				    msecs_to_jiffies(cur_roc->duration);
	struct ieee80211_roc_work *next_roc;
	int new_dur;
	unsigned long now = jiffies;
	unsigned long remaining = cur_roc->hw_start_time +
				  msecs_to_jiffies(cur_roc->duration) -
				  now;

	if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun))
		return false;

	if (time_after(j + IEEE80211_ROC_MIN_LEFT, cur_roc_end))
	/* if it doesn't fit entirely, schedule a new one */
	if (new_roc->duration > jiffies_to_msecs(remaining))
		return false;

	ieee80211_handle_roc_started(new_roc);

	new_dur = new_roc->duration - jiffies_to_msecs(cur_roc_end - j);

	/* cur_roc is long enough - add new_roc to the dependents list. */
	if (new_dur <= 0) {
	/* add to dependents so we send the expired event properly */
	list_add_tail(&new_roc->list, &cur_roc->dependents);
	return true;
}

	new_roc->duration = new_dur;

	/*
	 * if cur_roc was already coalesced before, we might
	 * want to extend the next roc instead of adding
	 * a new one.
	 */
	next_roc = list_entry(cur_roc->list.next,
			      struct ieee80211_roc_work, list);
	if (&next_roc->list != &local->roc_list &&
	    next_roc->chan == new_roc->chan &&
	    next_roc->sdata == new_roc->sdata &&
	    !WARN_ON(next_roc->started)) {
		list_add_tail(&new_roc->list, &next_roc->dependents);
		next_roc->duration = max(next_roc->duration,
					 new_roc->duration);
		next_roc->type = max(next_roc->type, new_roc->type);
		return true;
	}

	/* add right after cur_roc */
	list_add(&new_roc->list, &cur_roc->list);

	return true;
}

static int ieee80211_start_roc_work(struct ieee80211_local *local,
				    struct ieee80211_sub_if_data *sdata,
				    struct ieee80211_channel *channel,
@@ -2652,17 +2623,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
			 * In the offloaded ROC case, if it hasn't begun, add
			 * this new one to the dependent list to be handled
			 * when the master one begins. If it has begun,
			 * check that there's still a minimum time left and
			 * if so, start this one, transmitting the frame, but
			 * add it to the list directly after this one with
			 * a reduced time so we'll ask the driver to execute
			 * it right after finishing the previous one, in the
			 * hope that it'll also be executed right afterwards,
			 * effectively extending the old one.
			 * If there's no minimum time left, just add it to the
			 * normal list.
			 * TODO: the ROC type is ignored here, assuming that it
			 * is better to immediately use the current ROC.
			 * check if it fits entirely within the existing one,
			 * in which case it will just be dependent as well.
			 * Otherwise, schedule it by itself.
			 */
			if (!tmp->hw_begun) {
				list_add_tail(&roc->list, &tmp->dependents);
+3 −6
Original line number Diff line number Diff line
@@ -205,6 +205,8 @@ enum ieee80211_packet_rx_flags {
 * @IEEE80211_RX_CMNTR: received on cooked monitor already
 * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported
 *	to cfg80211_report_obss_beacon().
 * @IEEE80211_RX_REORDER_TIMER: this frame is released by the
 *	reorder buffer timeout timer, not the normal RX path
 *
 * These flags are used across handling multiple interfaces
 * for a single frame.
@@ -212,6 +214,7 @@ enum ieee80211_packet_rx_flags {
enum ieee80211_rx_flags {
	IEEE80211_RX_CMNTR		= BIT(0),
	IEEE80211_RX_BEACON_REPORTED	= BIT(1),
	IEEE80211_RX_REORDER_TIMER	= BIT(2),
};

struct ieee80211_rx_data {
@@ -325,12 +328,6 @@ struct mesh_preq_queue {
	u8 flags;
};

#if HZ/100 == 0
#define IEEE80211_ROC_MIN_LEFT	1
#else
#define IEEE80211_ROC_MIN_LEFT	(HZ/100)
#endif

struct ieee80211_roc_work {
	struct list_head list;
	struct list_head dependents;
+6 −0
Original line number Diff line number Diff line
@@ -522,6 +522,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
		memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
		       sizeof(sdata->vif.hw_queue));
		sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;

		mutex_lock(&local->key_mtx);
		sdata->crypto_tx_tailroom_needed_cnt +=
			master->crypto_tx_tailroom_needed_cnt;
		mutex_unlock(&local->key_mtx);

		break;
		}
	case NL80211_IFTYPE_AP:
+73 −9
Original line number Diff line number Diff line
@@ -58,6 +58,22 @@ static void assert_key_lock(struct ieee80211_local *local)
	lockdep_assert_held(&local->key_mtx);
}

static void
update_vlan_tailroom_need_count(struct ieee80211_sub_if_data *sdata, int delta)
{
	struct ieee80211_sub_if_data *vlan;

	if (sdata->vif.type != NL80211_IFTYPE_AP)
		return;

	mutex_lock(&sdata->local->mtx);

	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
		vlan->crypto_tx_tailroom_needed_cnt += delta;

	mutex_unlock(&sdata->local->mtx);
}

static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
{
	/*
@@ -79,6 +95,8 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
	 * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
	 */

	update_vlan_tailroom_need_count(sdata, 1);

	if (!sdata->crypto_tx_tailroom_needed_cnt++) {
		/*
		 * Flush all XMIT packets currently using HW encryption or no
@@ -88,6 +106,15 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
	}
}

static void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
					 int delta)
{
	WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt < delta);

	update_vlan_tailroom_need_count(sdata, -delta);
	sdata->crypto_tx_tailroom_needed_cnt -= delta;
}

static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
{
	struct ieee80211_sub_if_data *sdata;
@@ -144,7 +171,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)

		if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
		      (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
			sdata->crypto_tx_tailroom_needed_cnt--;
			decrease_tailroom_need_count(sdata, 1);

		WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
			(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
@@ -541,7 +568,7 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key,
			schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
					      HZ/2);
		} else {
			sdata->crypto_tx_tailroom_needed_cnt--;
			decrease_tailroom_need_count(sdata, 1);
		}
	}

@@ -631,6 +658,7 @@ void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
{
	struct ieee80211_key *key;
	struct ieee80211_sub_if_data *vlan;

	ASSERT_RTNL();

@@ -639,7 +667,14 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)

	mutex_lock(&sdata->local->key_mtx);

	sdata->crypto_tx_tailroom_needed_cnt = 0;
	WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
		     sdata->crypto_tx_tailroom_pending_dec);

	if (sdata->vif.type == NL80211_IFTYPE_AP) {
		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
			WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
				     vlan->crypto_tx_tailroom_pending_dec);
	}

	list_for_each_entry(key, &sdata->key_list, list) {
		increment_tailroom_need_count(sdata);
@@ -649,6 +684,22 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
	mutex_unlock(&sdata->local->key_mtx);
}

void ieee80211_reset_crypto_tx_tailroom(struct ieee80211_sub_if_data *sdata)
{
	struct ieee80211_sub_if_data *vlan;

	mutex_lock(&sdata->local->key_mtx);

	sdata->crypto_tx_tailroom_needed_cnt = 0;

	if (sdata->vif.type == NL80211_IFTYPE_AP) {
		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
			vlan->crypto_tx_tailroom_needed_cnt = 0;
	}

	mutex_unlock(&sdata->local->key_mtx);
}

void ieee80211_iter_keys(struct ieee80211_hw *hw,
			 struct ieee80211_vif *vif,
			 void (*iter)(struct ieee80211_hw *hw,
@@ -688,8 +739,8 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
{
	struct ieee80211_key *key, *tmp;

	sdata->crypto_tx_tailroom_needed_cnt -=
		sdata->crypto_tx_tailroom_pending_dec;
	decrease_tailroom_need_count(sdata,
				     sdata->crypto_tx_tailroom_pending_dec);
	sdata->crypto_tx_tailroom_pending_dec = 0;

	ieee80211_debugfs_key_remove_mgmt_default(sdata);
@@ -709,6 +760,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
{
	struct ieee80211_local *local = sdata->local;
	struct ieee80211_sub_if_data *vlan;
	struct ieee80211_sub_if_data *master;
	struct ieee80211_key *key, *tmp;
	LIST_HEAD(keys);

@@ -728,8 +780,20 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
	list_for_each_entry_safe(key, tmp, &keys, list)
		__ieee80211_key_destroy(key, false);

	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
		if (sdata->bss) {
			master = container_of(sdata->bss,
					      struct ieee80211_sub_if_data,
					      u.ap);

			WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt !=
				     master->crypto_tx_tailroom_needed_cnt);
		}
	} else {
		WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
			     sdata->crypto_tx_tailroom_pending_dec);
	}

	if (sdata->vif.type == NL80211_IFTYPE_AP) {
		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
			WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
@@ -793,8 +857,8 @@ void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
	 */

	mutex_lock(&sdata->local->key_mtx);
	sdata->crypto_tx_tailroom_needed_cnt -=
		sdata->crypto_tx_tailroom_pending_dec;
	decrease_tailroom_need_count(sdata,
				     sdata->crypto_tx_tailroom_pending_dec);
	sdata->crypto_tx_tailroom_pending_dec = 0;
	mutex_unlock(&sdata->local->key_mtx);
}
+1 −0
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
void ieee80211_free_sta_keys(struct ieee80211_local *local,
			     struct sta_info *sta);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_reset_crypto_tx_tailroom(struct ieee80211_sub_if_data *sdata);

#define key_mtx_dereference(local, ref) \
	rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
Loading