cfg80211: remove enum ieee80211_band
[cascardo/linux.git] / drivers / net / wireless / ath / wil6210 / cfg80211.c
index 11f1bb8..0fb3a79 100644 (file)
 #include "wil6210.h"
 #include "wmi.h"
 
+#define WIL_MAX_ROC_DURATION_MS 5000
+
 #define CHAN60G(_channel, _flags) {                            \
-       .band                   = IEEE80211_BAND_60GHZ,         \
+       .band                   = NL80211_BAND_60GHZ,           \
        .center_freq            = 56160 + (2160 * (_channel)),  \
        .hw_value               = (_channel),                   \
        .flags                  = (_flags),                     \
@@ -76,12 +78,24 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
                .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
                BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
        },
+       [NL80211_IFTYPE_P2P_DEVICE] = {
+               .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
 };
 
 static const u32 wil_cipher_suites[] = {
        WLAN_CIPHER_SUITE_GCMP,
 };
 
+static const char * const key_usage_str[] = {
+       [WMI_KEY_USE_PAIRWISE]  = "PTK",
+       [WMI_KEY_USE_RX_GROUP]  = "RX_GTK",
+       [WMI_KEY_USE_TX_GROUP]  = "TX_GTK",
+};
+
 int wil_iftype_nl2wmi(enum nl80211_iftype type)
 {
        static const struct {
@@ -113,7 +127,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
                .interval_usec = 0,
        };
        struct {
-               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_cmd_hdr wmi;
                struct wmi_notify_req_done_event evt;
        } __packed reply;
        struct wil_net_stats *stats = &wil->sta[cid].stats;
@@ -226,13 +240,82 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy,
        return rc;
 }
 
+static struct wireless_dev *
+wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
+                      unsigned char name_assign_type,
+                      enum nl80211_iftype type,
+                      u32 *flags, struct vif_params *params)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wireless_dev *p2p_wdev;
+
+       wil_dbg_misc(wil, "%s()\n", __func__);
+
+       if (type != NL80211_IFTYPE_P2P_DEVICE) {
+               wil_err(wil, "%s: unsupported iftype %d\n", __func__, type);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (wil->p2p_wdev) {
+               wil_err(wil, "%s: P2P_DEVICE interface already created\n",
+                       __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+       p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL);
+       if (!p2p_wdev)
+               return ERR_PTR(-ENOMEM);
+
+       p2p_wdev->iftype = type;
+       p2p_wdev->wiphy = wiphy;
+       /* use our primary ethernet address */
+       ether_addr_copy(p2p_wdev->address, ndev->perm_addr);
+
+       wil->p2p_wdev = p2p_wdev;
+
+       return p2p_wdev;
+}
+
+static int wil_cfg80211_del_iface(struct wiphy *wiphy,
+                                 struct wireless_dev *wdev)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+       wil_dbg_misc(wil, "%s()\n", __func__);
+
+       if (wdev != wil->p2p_wdev) {
+               wil_err(wil, "%s: delete of incorrect interface 0x%p\n",
+                       __func__, wdev);
+               return -EINVAL;
+       }
+
+       wil_p2p_wdev_free(wil);
+
+       return 0;
+}
+
 static int wil_cfg80211_change_iface(struct wiphy *wiphy,
                                     struct net_device *ndev,
                                     enum nl80211_iftype type, u32 *flags,
                                     struct vif_params *params)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-       struct wireless_dev *wdev = wil->wdev;
+       struct wireless_dev *wdev = wil_to_wdev(wil);
+       int rc;
+
+       wil_dbg_misc(wil, "%s() type=%d\n", __func__, type);
+
+       if (netif_running(wil_to_ndev(wil)) && !wil_is_recovery_blocked(wil)) {
+               wil_dbg_misc(wil, "interface is up. resetting...\n");
+               mutex_lock(&wil->mutex);
+               __wil_down(wil);
+               rc = __wil_up(wil);
+               mutex_unlock(&wil->mutex);
+
+               if (rc)
+                       return rc;
+       }
 
        switch (type) {
        case NL80211_IFTYPE_STATION:
@@ -260,7 +343,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
                             struct cfg80211_scan_request *request)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-       struct wireless_dev *wdev = wil->wdev;
+       struct wireless_dev *wdev = request->wdev;
        struct {
                struct wmi_start_scan_cmd cmd;
                u16 chnl[4];
@@ -268,6 +351,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
        uint i, n;
        int rc;
 
+       wil_dbg_misc(wil, "%s(), wdev=0x%p iftype=%d\n",
+                    __func__, wdev, wdev->iftype);
+
        if (wil->scan_request) {
                wil_err(wil, "Already scanning\n");
                return -EAGAIN;
@@ -277,6 +363,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_P2P_DEVICE:
                break;
        default:
                return -EOPNOTSUPP;
@@ -288,6 +375,20 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
                return -EBUSY;
        }
 
+       /* scan on P2P_DEVICE is handled as p2p search */
+       if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+               wil->scan_request = request;
+               wil->radio_wdev = wdev;
+               rc = wil_p2p_search(wil, request);
+               if (rc) {
+                       wil->radio_wdev = wil_to_wdev(wil);
+                       wil->scan_request = NULL;
+               }
+               return rc;
+       }
+
+       (void)wil_p2p_stop_discovery(wil);
+
        wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
        wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);
 
@@ -313,6 +414,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
        mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
 
        memset(&cmd, 0, sizeof(cmd));
+       cmd.cmd.scan_type = WMI_ACTIVE_SCAN;
        cmd.cmd.num_channels = 0;
        n = min(request->n_channels, 4U);
        for (i = 0; i < n; i++) {
@@ -340,12 +442,19 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
        if (rc)
                goto out;
 
+       if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) {
+               cmd.cmd.discovery_mode = 1;
+               wil_dbg_misc(wil, "active scan with discovery_mode=1\n");
+       }
+
+       wil->radio_wdev = wdev;
        rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
                        cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
 
 out:
        if (rc) {
                del_timer_sync(&wil->scan_timer);
+               wil->radio_wdev = wil_to_wdev(wil);
                wil->scan_request = NULL;
        }
 
@@ -390,6 +499,7 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
                print_hex_dump(KERN_INFO, "  SSID: ", DUMP_PREFIX_OFFSET,
                               16, 1, sme->ssid, sme->ssid_len, true);
        wil_info(wil, "  Privacy: %s\n", sme->privacy ? "secure" : "open");
+       wil_info(wil, "  PBSS: %d\n", sme->pbss);
        wil_print_crypto(wil, &sme->crypto);
 }
 
@@ -404,7 +514,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
        const u8 *rsn_eid;
        int ch;
        int rc = 0;
+       enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
 
+       wil_dbg_misc(wil, "%s()\n", __func__);
        wil_print_connect_params(wil, sme);
 
        if (test_bit(wil_status_fwconnecting, wil->status) ||
@@ -422,14 +534,12 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
        if (sme->privacy && !rsn_eid)
                wil_info(wil, "WSC connection\n");
 
-       if (sme->pbss) {
-               wil_err(wil, "connect - PBSS not yet supported\n");
-               return -EOPNOTSUPP;
-       }
+       if (sme->pbss)
+               bss_type = IEEE80211_BSS_TYPE_PBSS;
 
        bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
                               sme->ssid, sme->ssid_len,
-                              IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
+                              bss_type, IEEE80211_PRIVACY_ANY);
        if (!bss) {
                wil_err(wil, "Unable to find BSS\n");
                return -ENOENT;
@@ -568,10 +678,20 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
        struct ieee80211_mgmt *mgmt_frame = (void *)buf;
        struct wmi_sw_tx_req_cmd *cmd;
        struct {
-               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_cmd_hdr wmi;
                struct wmi_sw_tx_complete_event evt;
        } __packed evt;
 
+       /* Note, currently we do not support the "wait" parameter, user-space
+        * must call remain_on_channel before mgmt_tx or listen on a channel
+        * another way (AP/PCP or connected station)
+        * in addition we need to check if specified "chan" argument is
+        * different from currently "listened" channel and fail if it is.
+        */
+
+       wil_dbg_misc(wil, "%s()\n", __func__);
+       print_hex_dump_bytes("mgmt tx frame ", DUMP_PREFIX_OFFSET, buf, len);
+
        cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
        if (!cmd) {
                rc = -ENOMEM;
@@ -598,7 +718,7 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
                                    struct cfg80211_chan_def *chandef)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-       struct wireless_dev *wdev = wil->wdev;
+       struct wireless_dev *wdev = wil_to_wdev(wil);
 
        wdev->preset_chandef = *chandef;
 
@@ -608,22 +728,19 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
 static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
                                               bool pairwise)
 {
-       struct wireless_dev *wdev = wil->wdev;
+       struct wireless_dev *wdev = wil_to_wdev(wil);
        enum wmi_key_usage rc;
-       static const char * const key_usage_str[] = {
-               [WMI_KEY_USE_PAIRWISE]  = "WMI_KEY_USE_PAIRWISE",
-               [WMI_KEY_USE_RX_GROUP]  = "WMI_KEY_USE_RX_GROUP",
-               [WMI_KEY_USE_TX_GROUP]  = "WMI_KEY_USE_TX_GROUP",
-       };
 
        if (pairwise) {
                rc = WMI_KEY_USE_PAIRWISE;
        } else {
                switch (wdev->iftype) {
                case NL80211_IFTYPE_STATION:
+               case NL80211_IFTYPE_P2P_CLIENT:
                        rc = WMI_KEY_USE_RX_GROUP;
                        break;
                case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_P2P_GO:
                        rc = WMI_KEY_USE_TX_GROUP;
                        break;
                default:
@@ -638,20 +755,86 @@ static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
        return rc;
 }
 
+static struct wil_tid_crypto_rx_single *
+wil_find_crypto_ctx(struct wil6210_priv *wil, u8 key_index,
+                   enum wmi_key_usage key_usage, const u8 *mac_addr)
+{
+       int cid = -EINVAL;
+       int tid = 0;
+       struct wil_sta_info *s;
+       struct wil_tid_crypto_rx *c;
+
+       if (key_usage == WMI_KEY_USE_TX_GROUP)
+               return NULL; /* not needed */
+
+       /* supplicant provides Rx group key in STA mode with NULL MAC address */
+       if (mac_addr)
+               cid = wil_find_cid(wil, mac_addr);
+       else if (key_usage == WMI_KEY_USE_RX_GROUP)
+               cid = wil_find_cid_by_idx(wil, 0);
+       if (cid < 0) {
+               wil_err(wil, "No CID for %pM %s[%d]\n", mac_addr,
+                       key_usage_str[key_usage], key_index);
+               return ERR_PTR(cid);
+       }
+
+       s = &wil->sta[cid];
+       if (key_usage == WMI_KEY_USE_PAIRWISE)
+               c = &s->tid_crypto_rx[tid];
+       else
+               c = &s->group_crypto_rx;
+
+       return &c->key_id[key_index];
+}
+
 static int wil_cfg80211_add_key(struct wiphy *wiphy,
                                struct net_device *ndev,
                                u8 key_index, bool pairwise,
                                const u8 *mac_addr,
                                struct key_params *params)
 {
+       int rc;
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
        enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
+       struct wil_tid_crypto_rx_single *cc = wil_find_crypto_ctx(wil,
+                                                                 key_index,
+                                                                 key_usage,
+                                                                 mac_addr);
+
+       wil_dbg_misc(wil, "%s(%pM %s[%d] PN %*phN)\n", __func__,
+                    mac_addr, key_usage_str[key_usage], key_index,
+                    params->seq_len, params->seq);
+
+       if (IS_ERR(cc)) {
+               wil_err(wil, "Not connected, %s(%pM %s[%d] PN %*phN)\n",
+                       __func__, mac_addr, key_usage_str[key_usage], key_index,
+                       params->seq_len, params->seq);
+               return -EINVAL;
+       }
 
-       wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
-                    pairwise ? "PTK" : "GTK");
+       if (cc)
+               cc->key_set = false;
+
+       if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
+               wil_err(wil,
+                       "Wrong PN len %d, %s(%pM %s[%d] PN %*phN)\n",
+                       params->seq_len, __func__, mac_addr,
+                       key_usage_str[key_usage], key_index,
+                       params->seq_len, params->seq);
+               return -EINVAL;
+       }
+
+       rc = wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
+                               params->key, key_usage);
+       if ((rc == 0) && cc) {
+               if (params->seq)
+                       memcpy(cc->pn, params->seq, IEEE80211_GCMP_PN_LEN);
+               else
+                       memset(cc->pn, 0, IEEE80211_GCMP_PN_LEN);
+               cc->key_set = true;
+       }
 
-       return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
-                                 params->key, key_usage);
+       return rc;
 }
 
 static int wil_cfg80211_del_key(struct wiphy *wiphy,
@@ -661,9 +844,20 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
        enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
+       struct wil_tid_crypto_rx_single *cc = wil_find_crypto_ctx(wil,
+                                                                 key_index,
+                                                                 key_usage,
+                                                                 mac_addr);
+
+       wil_dbg_misc(wil, "%s(%pM %s[%d])\n", __func__, mac_addr,
+                    key_usage_str[key_usage], key_index);
+
+       if (IS_ERR(cc))
+               wil_info(wil, "Not connected, %s(%pM %s[%d])\n", __func__,
+                        mac_addr, key_usage_str[key_usage], key_index);
 
-       wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
-                    pairwise ? "PTK" : "GTK");
+       if (!IS_ERR_OR_NULL(cc))
+               cc->key_set = false;
 
        return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
 }
@@ -674,6 +868,9 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
                                        u8 key_index, bool unicast,
                                        bool multicast)
 {
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+       wil_dbg_misc(wil, "%s: entered\n", __func__);
        return 0;
 }
 
@@ -686,16 +883,19 @@ static int wil_remain_on_channel(struct wiphy *wiphy,
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
        int rc;
 
-       /* TODO: handle duration */
-       wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration);
+       wil_dbg_misc(wil, "%s() center_freq=%d, duration=%d iftype=%d\n",
+                    __func__, chan->center_freq, duration, wdev->iftype);
 
-       rc = wmi_set_channel(wil, chan->hw_value);
+       rc = wil_p2p_listen(wil, duration, chan, cookie);
        if (rc)
                return rc;
 
-       rc = wmi_rxon(wil, true);
+       wil->radio_wdev = wdev;
 
-       return rc;
+       cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
+                                 GFP_KERNEL);
+
+       return 0;
 }
 
 static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
@@ -703,13 +903,10 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
                                        u64 cookie)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-       int rc;
-
-       wil_info(wil, "%s()\n", __func__);
 
-       rc = wmi_rxon(wil, false);
+       wil_dbg_misc(wil, "%s()\n", __func__);
 
-       return rc;
+       return wil_p2p_cancel_listen(wil, cookie);
 }
 
 /**
@@ -852,12 +1049,22 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
                                  const u8 *ssid, size_t ssid_len, u32 privacy,
                                  int bi, u8 chan,
                                  struct cfg80211_beacon_data *bcon,
-                                 u8 hidden_ssid)
+                                 u8 hidden_ssid, u32 pbss)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
        int rc;
        struct wireless_dev *wdev = ndev->ieee80211_ptr;
        u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
+       u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
+
+       if (pbss)
+               wmi_nettype = WMI_NETTYPE_P2P;
+
+       wil_dbg_misc(wil, "%s: is_go=%d\n", __func__, is_go);
+       if (is_go && !pbss) {
+               wil_err(wil, "%s: P2P GO must be in PBSS\n", __func__);
+               return -ENOTSUPP;
+       }
 
        wil_set_recovery_state(wil, fw_recovery_idle);
 
@@ -879,10 +1086,11 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
        wil->privacy = privacy;
        wil->channel = chan;
        wil->hidden_ssid = hidden_ssid;
+       wil->pbss = pbss;
 
        netif_carrier_on(ndev);
 
-       rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid);
+       rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid, is_go);
        if (rc)
                goto err_pcp_start;
 
@@ -928,7 +1136,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
                                            wdev->ssid_len, privacy,
                                            wdev->beacon_interval,
                                            wil->channel, bcon,
-                                           wil->hidden_ssid);
+                                           wil->hidden_ssid,
+                                           wil->pbss);
        } else {
                rc = _wil_cfg80211_set_ies(wiphy, bcon);
        }
@@ -954,11 +1163,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
                return -EINVAL;
        }
 
-       if (info->pbss) {
-               wil_err(wil, "AP: PBSS not yet supported\n");
-               return -EOPNOTSUPP;
-       }
-
        switch (info->hidden_ssid) {
        case NL80211_HIDDEN_SSID_NOT_IN_USE:
                hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
@@ -984,6 +1188,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
                     info->hidden_ssid);
        wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
                     info->dtim_period);
+       wil_dbg_misc(wil, "PBSS %d\n", info->pbss);
        print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
                             info->ssid, info->ssid_len);
        wil_print_bcon_data(bcon);
@@ -992,7 +1197,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
        rc = _wil_cfg80211_start_ap(wiphy, ndev,
                                    info->ssid, info->ssid_len, info->privacy,
                                    info->beacon_interval, channel->hw_value,
-                                   bcon, hidden_ssid);
+                                   bcon, hidden_ssid, info->pbss);
 
        return rc;
 }
@@ -1139,7 +1344,26 @@ static int wil_cfg80211_change_bss(struct wiphy *wiphy,
        return 0;
 }
 
+static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
+                                        struct wireless_dev *wdev)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+       wil_dbg_misc(wil, "%s: entered\n", __func__);
+       return 0;
+}
+
+static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
+                                        struct wireless_dev *wdev)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+       wil_dbg_misc(wil, "%s: entered\n", __func__);
+}
+
 static struct cfg80211_ops wil_cfg80211_ops = {
+       .add_virtual_intf = wil_cfg80211_add_iface,
+       .del_virtual_intf = wil_cfg80211_del_iface,
        .scan = wil_cfg80211_scan,
        .connect = wil_cfg80211_connect,
        .disconnect = wil_cfg80211_disconnect,
@@ -1160,20 +1384,25 @@ static struct cfg80211_ops wil_cfg80211_ops = {
        .del_station = wil_cfg80211_del_station,
        .probe_client = wil_cfg80211_probe_client,
        .change_bss = wil_cfg80211_change_bss,
+       /* P2P device */
+       .start_p2p_device = wil_cfg80211_start_p2p_device,
+       .stop_p2p_device = wil_cfg80211_stop_p2p_device,
 };
 
 static void wil_wiphy_init(struct wiphy *wiphy)
 {
        wiphy->max_scan_ssids = 1;
        wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
+       wiphy->max_remain_on_channel_duration = WIL_MAX_ROC_DURATION_MS;
        wiphy->max_num_pmkids = 0 /* TODO: */;
        wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                 BIT(NL80211_IFTYPE_AP) |
+                                BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                                BIT(NL80211_IFTYPE_P2P_GO) |
+                                BIT(NL80211_IFTYPE_P2P_DEVICE) |
                                 BIT(NL80211_IFTYPE_MONITOR);
-       /* TODO: enable P2P when integrated with supplicant:
-        * BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)
-        */
        wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
+                       WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
                        WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
        dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
                __func__, wiphy->flags);
@@ -1182,7 +1411,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
                NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
                NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
 
-       wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
+       wiphy->bands[NL80211_BAND_60GHZ] = &wil_band_60ghz;
 
        /* TODO: figure this out */
        wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
@@ -1241,3 +1470,18 @@ void wil_wdev_free(struct wil6210_priv *wil)
        wiphy_free(wdev->wiphy);
        kfree(wdev);
 }
+
+void wil_p2p_wdev_free(struct wil6210_priv *wil)
+{
+       struct wireless_dev *p2p_wdev;
+
+       mutex_lock(&wil->p2p_wdev_mutex);
+       p2p_wdev = wil->p2p_wdev;
+       if (p2p_wdev) {
+               wil->p2p_wdev = NULL;
+               wil->radio_wdev = wil_to_wdev(wil);
+               cfg80211_unregister_wdev(p2p_wdev);
+               kfree(p2p_wdev);
+       }
+       mutex_unlock(&wil->p2p_wdev_mutex);
+}