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; } }
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; }
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; } }