Exemplo n.º 1
0
static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
{
	int cid = -ENOENT;
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;

	might_sleep();
	if (bssid) {
		cid = wil_find_cid(wil, bssid);
		wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
	} else {
		wil_dbg_misc(wil, "%s(all)\n", __func__);
	}

	if (cid >= 0) /* disconnect 1 peer */
		wil_disconnect_cid(wil, cid);
	else /* disconnect all */
		for (cid = 0; cid < WIL6210_MAX_CID; cid++)
			wil_disconnect_cid(wil, cid);

	/* link state */
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
		wil_link_off(wil);
		if (test_bit(wil_status_fwconnected, &wil->status)) {
			clear_bit(wil_status_fwconnected, &wil->status);
			cfg80211_disconnected(ndev,
					      WLAN_STATUS_UNSPECIFIED_FAILURE,
					      NULL, 0, GFP_KERNEL);
		} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
						WLAN_STATUS_UNSPECIFIED_FAILURE,
						GFP_KERNEL);
		}
		clear_bit(wil_status_fwconnecting, &wil->status);
		break;
	default:
		break;
	}
}
Exemplo n.º 2
0
static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
                              struct station_info *sinfo)
{
    struct wmi_notify_req_cmd cmd = {
        .cid = cid,
        .interval_usec = 0,
    };
    struct {
        struct wil6210_mbox_hdr_wmi wmi;
        struct wmi_notify_req_done_event evt;
    } __packed reply;
    struct wil_net_stats *stats = &wil->sta[cid].stats;
    int rc;

    rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
                  WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
    if (rc)
        return rc;

    wil_dbg_wmi(wil, "Link status for CID %d: {\n"
                "  MCS %d TSF 0x%016llx\n"
                "  BF status 0x%08x SNR 0x%08x SQI %d%%\n"
                "  Tx Tpt %d goodput %d Rx goodput %d\n"
                "  Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
                cid, le16_to_cpu(reply.evt.bf_mcs),
                le64_to_cpu(reply.evt.tsf), reply.evt.status,
                le32_to_cpu(reply.evt.snr_val),
                reply.evt.sqi,
                le32_to_cpu(reply.evt.tx_tpt),
                le32_to_cpu(reply.evt.tx_goodput),
                le32_to_cpu(reply.evt.rx_goodput),
                le16_to_cpu(reply.evt.my_rx_sector),
                le16_to_cpu(reply.evt.my_tx_sector),
                le16_to_cpu(reply.evt.other_rx_sector),
                le16_to_cpu(reply.evt.other_tx_sector));

    sinfo->generation = wil->sinfo_gen;

    sinfo->filled = STATION_INFO_RX_BYTES |
                    STATION_INFO_TX_BYTES |
                    STATION_INFO_RX_PACKETS |
                    STATION_INFO_TX_PACKETS |
                    STATION_INFO_RX_BITRATE |
                    STATION_INFO_TX_BITRATE |
                    STATION_INFO_RX_DROP_MISC |
                    STATION_INFO_TX_FAILED;

    sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
    sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
    sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
    sinfo->rxrate.mcs = stats->last_mcs_rx;
    sinfo->rx_bytes = stats->rx_bytes;
    sinfo->rx_packets = stats->rx_packets;
    sinfo->rx_dropped_misc = stats->rx_dropped;
    sinfo->tx_bytes = stats->tx_bytes;
    sinfo->tx_packets = stats->tx_packets;
    sinfo->tx_failed = stats->tx_errors;

    if (test_bit(wil_status_fwconnected, &wil->status)) {
        sinfo->filled |= STATION_INFO_SIGNAL;
        sinfo->signal = reply.evt.sqi;
    }

    return rc;
}

static int wil_cfg80211_get_station(struct wiphy *wiphy,
                                    struct net_device *ndev,
                                    u8 *mac, struct station_info *sinfo)
{
    struct wil6210_priv *wil = wiphy_to_wil(wiphy);
    int rc;

    int cid = wil_find_cid(wil, mac);

    wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
    if (cid < 0)
        return cid;

    rc = wil_cid_fill_sinfo(wil, cid, sinfo);

    return rc;
}

/*
 * Find @idx-th active STA for station dump.
 */
static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx)
{
    int i;

    for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
        if (wil->sta[i].status == wil_sta_unused)
            continue;
        if (idx == 0)
            return i;
        idx--;
    }

    return -ENOENT;
}
Exemplo n.º 3
0
static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
{
	int cid = -ENOENT;
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;

	might_sleep();
	if (bssid) {
		cid = wil_find_cid(wil, bssid);
		wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
	} else {
		wil_dbg_misc(wil, "%s(all)\n", __func__);
	}

	if (cid >= 0) /* disconnect 1 peer */
		wil_disconnect_cid(wil, cid);
	else {/* disconnect all */

		/*
		 * BUG FIX: Disconnect single sta only
		 *          We may get to here few times 
		 *          with BSSID address
		*/
		if(ndev->dev_addr && bssid) {	
			if(ether_addr_equal(ndev->dev_addr, bssid) ) {
				for (cid = 0; cid < WIL6210_MAX_CID; cid++)
					wil_disconnect_cid(wil, cid);
				}
		}
	}
	/* link state */
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
		wil_link_off(wil);
		clear_bit(wil_status_fwconnected, &wil->status);

		switch (wdev->sme_state) {
		case CFG80211_SME_CONNECTED:
			cfg80211_disconnected(ndev,
					      WLAN_STATUS_UNSPECIFIED_FAILURE,
					      NULL, 0, GFP_KERNEL);
			break;
		case CFG80211_SME_CONNECTING:
			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
						WLAN_STATUS_UNSPECIFIED_FAILURE,
						GFP_KERNEL);
			break;
		default:
			break;
		}

		wil_dbg_misc(wil, "clear_bit(wil_status_dontscan)\n");
		clear_bit(wil_status_dontscan, &wil->status);
		break;
	default:
		/* AP-like interface and monitor:
		 * never scan, always connected
		 */
		if (bssid)
			cfg80211_del_sta(ndev, bssid, GFP_KERNEL);
		break;
	}
}