Пример #1
0
static int r92su_get_station(struct wiphy *wiphy, struct net_device *ndev,
			     const u8 *mac, struct station_info *sinfo)
{
	struct r92su *r92su = wiphy_priv(wiphy);
	struct r92su_sta *sta;
	int err = -ENOENT;

	mutex_lock(&r92su->lock);
	if (!r92su_is_connected(r92su)) {
		err = -ENODEV;
		goto out;
	}

	rcu_read_lock();
	sta = r92su_sta_get(r92su, mac);
	if (sta) {
		r92su_sta_set_sinfo(r92su, sta, sinfo);
		err = 0;
	}
	rcu_read_unlock();

out:
	mutex_unlock(&r92su->lock);
	return err;

}
Пример #2
0
static int r92su_set_default_key(struct wiphy *wiphy, struct net_device *ndev,
				 u8 idx, bool unicast, bool multicast)
{
	struct r92su *r92su = wiphy_priv(wiphy);
	struct cfg80211_bss *bss;
	struct r92su_bss_priv *bss_priv;
	int err = -EAGAIN;

	mutex_lock(&r92su->lock);
	if (!r92su_is_connected(r92su))
		goto out;

	rcu_read_lock();
	bss = rcu_dereference(r92su->connect_bss);
	if (!bss)
		goto out_rcu;

	bss_priv = r92su_get_bss_priv(bss);

	if (unicast)
		bss_priv->def_uni_key_idx = idx;

	if (multicast)
		bss_priv->def_multi_key_idx = idx;

	err = 0;
out_rcu:
	rcu_read_unlock();

out:
	mutex_unlock(&r92su->lock);
	return err;
}
Пример #3
0
static int r92su_stop(struct net_device *ndev)
{
	struct r92su *r92su = ndev->ml_priv;
	struct cfg80211_bss *tmp_bss;
	struct llist_node *node;
	int err = -EINVAL, i;

	mutex_lock(&r92su->lock);

	if (r92su_is_connected(r92su)) {
		err = __r92su_disconnect(r92su);
		WARN_ONCE(err, "disconnect failed");
	}

	r92su_set_power(r92su, false);

	if (r92su_is_initializing(r92su)) {
		err = r92su_hw_mac_deinit(r92su);
		WARN_ONCE(err, "failed to deinitilize MAC");
	}

	if (r92su_is_initializing(r92su))
		r92su_set_state(r92su, R92SU_STOP);

	if (r92su->scan_request)
		cfg80211_scan_done(r92su->scan_request, true);

	tmp_bss = r92su->want_connect_bss;
	r92su->want_connect_bss = NULL;
	r92su_bss_free(r92su, tmp_bss);

	r92su->scan_request = NULL;

	for (i = 0; i < MAX_STA; i++)
		r92su_sta_del(r92su, i);

	mutex_unlock(&r92su->lock);

	cancel_delayed_work_sync(&r92su->survey_done_work);
	cancel_delayed_work_sync(&r92su->service_work);
	cancel_work_sync(&r92su->add_bss_work);
	cancel_work_sync(&r92su->connect_bss_work);
	cancel_work_sync(&r92su->disconnect_work);

	node = llist_del_all(&r92su->add_bss_list);
	while (node) {
		struct r92su_add_bss *bss_priv =
			llist_entry(node, struct r92su_add_bss, head);
		node = ACCESS_ONCE(node->next);
		kfree(bss_priv);
	}

	/* wait for keys and stas to be freed */
	synchronize_rcu();
	rcu_barrier();

	return err;
}
Пример #4
0
static int __r92su_disconnect(struct r92su *r92su)
{
	int err = 0;
	if (r92su_is_connected(r92su))
		err = r92su_h2c_disconnect(r92su);

	/* always free the connected bss */
	r92su_bss_free_connected(r92su, true);
	return err;
}
Пример #5
0
static int r92su_add_key(struct wiphy *wiphy, struct net_device *ndev,
			 u8 idx, bool pairwise, const u8 *mac_addr,
			 struct key_params *params)
{
	struct r92su *r92su = wiphy_priv(wiphy);
	int err;
	struct cfg80211_bss *bss;

	mutex_lock(&r92su->lock);
	if (!r92su_is_connected(r92su)) {
		err = -EAGAIN;
		goto out_unlock;
	}
	bss = rcu_dereference_protected(r92su->connect_bss,
					lockdep_is_held(&r92su->lock));

	err = r92su_internal_add_key(r92su, bss, params->cipher, idx,
				     pairwise, mac_addr, params->key, false);
out_unlock:
	mutex_unlock(&r92su->lock);
	return err;
}
Пример #6
0
static void r92su_bss_free_connected(struct r92su *r92su,
				     bool locally_generated)
{
	struct cfg80211_bss *old_bss;

	if (r92su_is_connected(r92su))
		r92su_set_state(r92su, R92SU_OPEN);

	rcu_read_lock();
	old_bss = rcu_dereference(r92su->connect_bss);
	rcu_assign_pointer(r92su->connect_bss, NULL);
	if (old_bss) {
		switch (r92su->wdev.iftype) {
		case NL80211_IFTYPE_STATION:
			/* cfg80211 doesn't like it when cfg80211_disconnected
			 * is called without reason. So check if we were really
			 * connected.
			 */
			cfg80211_disconnected(r92su->wdev.netdev,
				      WLAN_STATUS_UNSPECIFIED_FAILURE, NULL, 0,
				      locally_generated, GFP_ATOMIC);
			break;

		case NL80211_IFTYPE_ADHOC:
			cfg80211_unlink_bss(r92su->wdev.wiphy, old_bss);
			break;

		default:
			WARN(1, "unsupported network type %d\n",
			     r92su->wdev.iftype);
			break;
		}
		r92su_bss_free(r92su, old_bss);
	}
	rcu_read_unlock();
}
Пример #7
0
static int r92su_del_key(struct wiphy *wiphy, struct net_device *ndev,
			 u8 idx, bool pairwise, const u8 *mac_addr)
{
	static const enum r92su_enc_alg no_key = NO_ENCRYPTION;
	struct r92su *r92su = wiphy_priv(wiphy);
	struct r92su_key *old_key = NULL;
	int err = -EAGAIN;

	mutex_lock(&r92su->lock);
	if (!r92su_is_connected(r92su))
		goto out;

	if (pairwise) {
		struct r92su_sta *sta;

		rcu_read_lock();
		sta = r92su_sta_get(r92su, mac_addr);
		if (sta) {
			old_key = rcu_dereference(sta->sta_key);
			/* check if key was uploaded ? */
			if (old_key && old_key->uploaded == false) {
				err = 0;
				goto out_free;
			}
		}
		rcu_read_unlock();

		err = r92su_h2c_set_sta_key(r92su, no_key, mac_addr,
					    NULL);
		if (err)
			goto out;

		rcu_read_lock();
		sta = r92su_sta_get(r92su, mac_addr);
		if (!sta)
			goto out_free;

		old_key = rcu_dereference(sta->sta_key);
		if (old_key) {
			WARN(!old_key->uploaded, "pairwise-key for station %pM was ninja-deleted",
			     mac_addr);
			old_key->uploaded = false;
		}
		rcu_assign_pointer(sta->sta_key, NULL);
	} else {
		struct cfg80211_bss *bss;
		struct r92su_bss_priv *bss_priv;

		rcu_read_lock();
		bss = rcu_dereference(r92su->connect_bss);
		if (bss) {
			bss_priv = r92su_get_bss_priv(bss);
			old_key = rcu_dereference(bss_priv->group_key[idx]);
			if (old_key && old_key->uploaded == false) {
				err = 0;
				goto out_free;
			}
		}
		rcu_read_unlock();

		err = r92su_h2c_set_key(r92su, no_key, idx, !pairwise,
					NULL);
		if (err)
			goto out;

		rcu_read_lock();
		bss = rcu_dereference(r92su->connect_bss);
		if (bss) {
			bss_priv = r92su_get_bss_priv(bss);
			old_key = rcu_dereference(bss_priv->group_key[idx]);
			if (old_key)
				old_key->uploaded = false;
			rcu_assign_pointer(bss_priv->group_key[idx], NULL);
		} else {
			/* BSS which held the key is already gone! */
		}
	}

out_free:
	r92su_key_free(old_key);
	rcu_read_unlock();

out:
	mutex_unlock(&r92su->lock);
	return err;
}
Пример #8
0
static void r92su_survey_done_work(struct work_struct *work)
{
	struct cfg80211_scan_request *req;
	struct r92su *r92su = container_of(work, struct r92su,
					   survey_done_work.work);

	mutex_lock(&r92su->lock);
	if (!r92su_is_open(r92su))
		goto out;

	req = r92su->scan_request;
	r92su->scan_request = NULL;

	if (req) {
		struct cfg80211_scan_info info = {
			.aborted = false,
		};
		cfg80211_scan_done(req, &info);
	}

	r92su->scanned = true;
	complete(&r92su->scan_done);
out:
	mutex_unlock(&r92su->lock);
}

static int r92su_stop(struct net_device *ndev)
{
	struct r92su *r92su = ndev->ml_priv;
	struct cfg80211_bss *tmp_bss;
	struct llist_node *node;
	int err = -EINVAL, i;

	mutex_lock(&r92su->lock);

	if (r92su_is_connected(r92su)) {
		err = __r92su_disconnect(r92su);
		WARN_ONCE(err, "disconnect failed");
	}

	r92su_set_power(r92su, false);

	if (r92su_is_initializing(r92su)) {
		err = r92su_hw_mac_deinit(r92su);
		WARN_ONCE(err, "failed to deinitilize MAC");
	}

	if (r92su_is_initializing(r92su))
		r92su_set_state(r92su, R92SU_STOP);

	if (r92su->scan_request) {
		struct cfg80211_scan_info info = {
			.aborted = true,
		};
		cfg80211_scan_done(r92su->scan_request, &info);
	}

	tmp_bss = r92su->want_connect_bss;
	r92su->want_connect_bss = NULL;
	r92su_bss_free(r92su, tmp_bss);

	r92su->scan_request = NULL;

	for (i = 0; i < MAX_STA; i++)
		r92su_sta_del(r92su, i);

	mutex_unlock(&r92su->lock);

	cancel_delayed_work_sync(&r92su->survey_done_work);
	cancel_delayed_work_sync(&r92su->service_work);
	cancel_work_sync(&r92su->add_bss_work);
	cancel_work_sync(&r92su->connect_bss_work);
	cancel_work_sync(&r92su->disconnect_work);

	node = llist_del_all(&r92su->add_bss_list);
	while (node) {
		struct r92su_add_bss *bss_priv =
			llist_entry(node, struct r92su_add_bss, head);
		node = ACCESS_ONCE(node->next);
		kfree(bss_priv);
	}

	/* wait for keys and stas to be freed */
	synchronize_rcu();
	rcu_barrier();

	return err;
}

static netdev_tx_t r92su_start_xmit(struct sk_buff *skb,
				    struct net_device *ndev)
{
	struct r92su *r92su = ndev->ml_priv;

	switch (r92su->wdev.iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_ADHOC:
		if (skb->len >= ETH_ALEN + ETH_ALEN + 2)
			r92su_tx(r92su, skb, false);
		break;

	case NL80211_IFTYPE_MONITOR:
		r92su_tx_monitor(r92su, skb);
		break;

	default:
		dev_kfree_skb_any(skb);
		break;
	}
	return NETDEV_TX_OK;
}

static const struct net_device_ops r92su_netdevice_ops = {
	.ndo_open = r92su_open,
	.ndo_stop = r92su_stop,
	.ndo_start_xmit = r92su_start_xmit,
	.ndo_set_mac_address = eth_mac_addr,
	.ndo_set_rx_mode = r92su_set_rx_mode,
	.ndo_change_mtu = eth_change_mtu,
	.ndo_validate_addr = eth_validate_addr,
};

static void *devm_dup(struct device *dev, void *src, size_t len)
{
	void *tmp;

	tmp = devm_kzalloc(dev, len, GFP_KERNEL);
	if (tmp)
		memcpy(tmp, src, len);
	return tmp;
}

static int r92su_init_band(struct r92su *r92su)
{
	struct ieee80211_supported_band *band;

	band = &r92su->band_2GHZ;
	band->channels = devm_dup(&r92su->wdev.wiphy->dev,
		r92su_channeltable, sizeof(r92su_channeltable));
	if (!band->channels)
		return -ENOMEM;

	band->bitrates = devm_dup(&r92su->wdev.wiphy->dev,
		r92su_ratetable, sizeof(r92su_ratetable));
	if (!band->bitrates)
		return -ENOMEM;

	band->n_channels = ARRAY_SIZE(r92su_channeltable);
	band->n_bitrates = ARRAY_SIZE(r92su_ratetable);

	memcpy(&band->ht_cap, &r92su_ht_info, sizeof(r92su_ht_info));
	band->ht_cap.ht_supported = !r92su->disable_ht;

	switch (r92su->rf_type) {
	case R92SU_1T1R:
		/* nothing needs to be done. The default ht_cap
		 * contains all the necessary bits for just 1T1R
		 * devices */
		break;

	case R92SU_1T2R:
	case R92SU_2T2R:
		band->ht_cap.mcs.rx_mask[1] = 0xff;
		band->ht_cap.mcs.rx_highest = cpu_to_le16(300);
		break;
	}

	r92su->wdev.wiphy->bands[NL80211_BAND_2GHZ] = &r92su->band_2GHZ;

	return 0;
}

static const struct ieee80211_txrx_stypes
r92su_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
	[NL80211_IFTYPE_ADHOC] = {
		.tx = 0xffff,
		.rx = 0,
	},