Esempio n. 1
0
static int r92su_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
			  struct cfg80211_mgmt_tx_params *params, u64 *cookie)
{
	struct r92su *r92su = wiphy_priv(wiphy);
	struct sk_buff *skb;

	if (params->len < sizeof(struct ieee80211_hdr))
		return -EINVAL;

	skb = dev_alloc_skb(r92su->wdev.netdev->needed_headroom + params->len +
			    r92su->wdev.netdev->needed_tailroom);
	if (!skb)
		return -ENOMEM;

	skb_reserve(skb, r92su->wdev.netdev->needed_headroom);
	memcpy(skb_put(skb, params->len), params->buf, params->len);
	r92su_tx(r92su, skb, true);
	return 0;
}
Esempio n. 2
0
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;
}
Esempio n. 3
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,
	},