示例#1
0
文件: main.c 项目: UNwS/rtl8192su
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;
}
示例#2
0
文件: main.c 项目: chunkeey/rtl8192su
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();
}
示例#3
0
文件: main.c 项目: chunkeey/rtl8192su
static void r92su_bss_connect_work(struct work_struct *work)
{
	struct r92su *r92su;
	struct c2h_join_bss_event *join_bss = NULL;
	struct cfg80211_bss *cfg_bss = NULL;
	struct r92su_bss_priv *bss_priv;
	u8 *resp_ie = NULL;
	unsigned int resp_ie_len = 0;
	u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE;

	r92su = container_of(work, struct r92su, connect_bss_work);

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

	cfg_bss = r92su->want_connect_bss;
	join_bss = r92su->connect_result;

	if (!cfg_bss || !join_bss)
		goto out;

	bss_priv = r92su_get_bss_priv(cfg_bss);
	r92su->connect_result = NULL;

	if (le32_to_cpu(join_bss->bss.ie_length) < 12)
		goto report_cfg80211;

	if (join_bss->join_result) {
		struct r92su_bss_priv *bss_priv = r92su_get_bss_priv(cfg_bss);
		struct r92su_sta *sta;

		sta = r92su_sta_alloc(r92su, join_bss->bss.bssid,
			BSS_MACID,
			le32_to_cpu(join_bss->aid), GFP_KERNEL);
		if (!sta)
			goto report_cfg80211;

		resp_ie = join_bss->bss.ies.ie;
		resp_ie_len = le32_to_cpu(join_bss->bss.ie_length) - 12;

		sta->enc_sta = le32_to_cpu(join_bss->bss.privacy) ?
			       true : false;

		sta->qos_sta = r92su_parse_wmm_cap_ie(r92su, resp_ie,
						      resp_ie_len);

		/* The 802.11-2012 spec says that a HT STA has to be QoS STA
		 * as well. So in theory we should do instead:
		 *	sta->qos_sta |= sta->ht_sta;
		 * However, the QoS parameters are needed for legacy STAs as
		 * well. Therefore, there's no excuse for a HT STA to forget
		 * the WMM IE!
		 */
		if (sta->qos_sta)
			sta->ht_sta = r92su_parse_ht_cap_ie(r92su, resp_ie,
							    resp_ie_len);
		status = WLAN_STATUS_SUCCESS;

		bss_priv->sta = sta;
		rcu_assign_pointer(r92su->connect_bss, cfg_bss);
		r92su->want_connect_bss = NULL;
		r92su_set_state(r92su, R92SU_CONNECTED);
	}

report_cfg80211:
	switch (r92su->wdev.iftype) {
	case NL80211_IFTYPE_STATION:
		cfg80211_connect_result(r92su->wdev.netdev,
			join_bss->bss.bssid, bss_priv->assoc_ie,
			bss_priv->assoc_ie_len, resp_ie, resp_ie_len,
			status, GFP_KERNEL);
		if (status == WLAN_STATUS_SUCCESS)
			r92su_set_power(r92su, true);
		break;
	case NL80211_IFTYPE_ADHOC:
		if (status == WLAN_STATUS_SUCCESS) {
			cfg80211_ibss_joined(r92su->wdev.netdev,
					     join_bss->bss.bssid,
					     cfg_bss->channel, GFP_KERNEL);
		}
		break;

	default:
		WARN(1, "unsupported network type %d\n", r92su->wdev.iftype);
		break;
	}

	kfree(bss_priv->assoc_ie);
	bss_priv->assoc_ie = NULL;

out:
	mutex_unlock(&r92su->lock);
	kfree(join_bss);

	if (status == WLAN_STATUS_SUCCESS) {
		netif_tx_start_all_queues(r92su->wdev.netdev);
		netif_carrier_on(r92su->wdev.netdev);
	} else {
		r92su_bss_free(r92su, cfg_bss);
	}
}
示例#4
0
文件: main.c 项目: chunkeey/rtl8192su
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,
	},