+ return pmkids;
+}
+
+static int set_device_pmkids(struct usbnet *usbdev,
+ struct ndis_80211_pmkid *pmkids)
+{
+ int ret, len, num_pmkids;
+
+ num_pmkids = le32_to_cpu(pmkids->bssid_info_count);
+ len = sizeof(*pmkids) + num_pmkids * sizeof(pmkids->bssid_info[0]);
+ pmkids->length = cpu_to_le32(len);
+
+ debug_print_pmkids(usbdev, pmkids, __func__);
+
+ ret = rndis_set_oid(usbdev, OID_802_11_PMKID, pmkids,
+ le32_to_cpu(pmkids->length));
+ if (ret < 0) {
+ netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d) -> %d"
+ "\n", __func__, len, num_pmkids, ret);
+ }
+
+ kfree(pmkids);
+ return ret;
+}
+
+static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev,
+ struct ndis_80211_pmkid *pmkids,
+ struct cfg80211_pmksa *pmksa,
+ int max_pmkids)
+{
+ int i, len, count, newlen, err;
+
+ len = le32_to_cpu(pmkids->length);
+ count = le32_to_cpu(pmkids->bssid_info_count);
+
+ if (count > max_pmkids)
+ count = max_pmkids;
+
+ for (i = 0; i < count; i++)
+ if (!compare_ether_addr(pmkids->bssid_info[i].bssid,
+ pmksa->bssid))
+ break;
+
+ /* pmkid not found */
+ if (i == count) {
+ netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n",
+ __func__, pmksa->bssid);
+ err = -ENOENT;
+ goto error;
+ }
+
+ for (; i + 1 < count; i++)
+ pmkids->bssid_info[i] = pmkids->bssid_info[i + 1];
+
+ count--;
+ newlen = sizeof(*pmkids) + count * sizeof(pmkids->bssid_info[0]);
+
+ pmkids->length = cpu_to_le32(newlen);
+ pmkids->bssid_info_count = cpu_to_le32(count);
+
+ return pmkids;
+error:
+ kfree(pmkids);
+ return ERR_PTR(err);
+}
+
+static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
+ struct ndis_80211_pmkid *pmkids,
+ struct cfg80211_pmksa *pmksa,
+ int max_pmkids)
+{
+ int i, err, len, count, newlen;
+
+ len = le32_to_cpu(pmkids->length);
+ count = le32_to_cpu(pmkids->bssid_info_count);
+
+ if (count > max_pmkids)
+ count = max_pmkids;
+
+ /* update with new pmkid */
+ for (i = 0; i < count; i++) {
+ if (compare_ether_addr(pmkids->bssid_info[i].bssid,
+ pmksa->bssid))
+ continue;
+
+ memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid,
+ WLAN_PMKID_LEN);
+
+ return pmkids;
+ }
+
+ /* out of space, return error */
+ if (i == max_pmkids) {
+ netdev_dbg(usbdev->net, "%s(): out of space\n", __func__);
+ err = -ENOSPC;
+ goto error;
+ }
+
+ /* add new pmkid */
+ newlen = sizeof(*pmkids) + (count + 1) * sizeof(pmkids->bssid_info[0]);
+
+ pmkids = krealloc(pmkids, newlen, GFP_KERNEL);
+ if (!pmkids) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ pmkids->length = cpu_to_le32(newlen);
+ pmkids->bssid_info_count = cpu_to_le32(count + 1);
+
+ memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN);
+ memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
+
+ return pmkids;
+error:
+ kfree(pmkids);
+ return ERR_PTR(err);
+}
+
+/*
+ * cfg80211 ops
+ */
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)