diff options
author | David S. Miller <davem@davemloft.net> | 2010-03-22 21:15:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-22 21:15:15 -0400 |
commit | 33e2bf6aa16061bae1253514e7c32af27d2b4b31 (patch) | |
tree | 652d13b4feea9a8f562186e7badae72d2e22fe1f /drivers/net/wireless/rndis_wlan.c | |
parent | e880eb6c5c9d98e389ffc0d8947f75d70785361a (diff) | |
parent | 819bfecc4fc6b6e5a793f719a45b7146ce423b79 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts:
Documentation/feature-removal-schedule.txt
drivers/net/wireless/ath/ath5k/phy.c
Diffstat (limited to 'drivers/net/wireless/rndis_wlan.c')
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 364 |
1 files changed, 344 insertions, 20 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2887047069f2..aceb95ef7274 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -117,6 +117,7 @@ MODULE_PARM_DESC(workaround_interval, | |||
117 | #define OID_802_11_ADD_KEY cpu_to_le32(0x0d01011d) | 117 | #define OID_802_11_ADD_KEY cpu_to_le32(0x0d01011d) |
118 | #define OID_802_11_REMOVE_KEY cpu_to_le32(0x0d01011e) | 118 | #define OID_802_11_REMOVE_KEY cpu_to_le32(0x0d01011e) |
119 | #define OID_802_11_ASSOCIATION_INFORMATION cpu_to_le32(0x0d01011f) | 119 | #define OID_802_11_ASSOCIATION_INFORMATION cpu_to_le32(0x0d01011f) |
120 | #define OID_802_11_CAPABILITY cpu_to_le32(0x0d010122) | ||
120 | #define OID_802_11_PMKID cpu_to_le32(0x0d010123) | 121 | #define OID_802_11_PMKID cpu_to_le32(0x0d010123) |
121 | #define OID_802_11_NETWORK_TYPES_SUPPORTED cpu_to_le32(0x0d010203) | 122 | #define OID_802_11_NETWORK_TYPES_SUPPORTED cpu_to_le32(0x0d010203) |
122 | #define OID_802_11_NETWORK_TYPE_IN_USE cpu_to_le32(0x0d010204) | 123 | #define OID_802_11_NETWORK_TYPE_IN_USE cpu_to_le32(0x0d010204) |
@@ -358,6 +359,30 @@ struct ndis_80211_assoc_info { | |||
358 | __le32 offset_resp_ies; | 359 | __le32 offset_resp_ies; |
359 | } __attribute__((packed)); | 360 | } __attribute__((packed)); |
360 | 361 | ||
362 | struct ndis_80211_auth_encr_pair { | ||
363 | __le32 auth_mode; | ||
364 | __le32 encr_mode; | ||
365 | } __attribute__((packed)); | ||
366 | |||
367 | struct ndis_80211_capability { | ||
368 | __le32 length; | ||
369 | __le32 version; | ||
370 | __le32 num_pmkids; | ||
371 | __le32 num_auth_encr_pair; | ||
372 | struct ndis_80211_auth_encr_pair auth_encr_pair[0]; | ||
373 | } __attribute__((packed)); | ||
374 | |||
375 | struct ndis_80211_bssid_info { | ||
376 | u8 bssid[6]; | ||
377 | u8 pmkid[16]; | ||
378 | }; | ||
379 | |||
380 | struct ndis_80211_pmkid { | ||
381 | __le32 length; | ||
382 | __le32 bssid_info_count; | ||
383 | struct ndis_80211_bssid_info bssid_info[0]; | ||
384 | }; | ||
385 | |||
361 | /* | 386 | /* |
362 | * private data | 387 | * private data |
363 | */ | 388 | */ |
@@ -476,13 +501,7 @@ struct rndis_wlan_private { | |||
476 | /* encryption stuff */ | 501 | /* encryption stuff */ |
477 | int encr_tx_key_index; | 502 | int encr_tx_key_index; |
478 | struct rndis_wlan_encr_key encr_keys[4]; | 503 | struct rndis_wlan_encr_key encr_keys[4]; |
479 | enum nl80211_auth_type wpa_auth_type; | ||
480 | int wpa_version; | 504 | int wpa_version; |
481 | int wpa_keymgmt; | ||
482 | int wpa_ie_len; | ||
483 | u8 *wpa_ie; | ||
484 | int wpa_cipher_pair; | ||
485 | int wpa_cipher_group; | ||
486 | 505 | ||
487 | u8 command_buffer[COMMAND_BUFFER_SIZE]; | 506 | u8 command_buffer[COMMAND_BUFFER_SIZE]; |
488 | }; | 507 | }; |
@@ -534,6 +553,14 @@ static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
534 | static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, | 553 | static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, |
535 | int idx, u8 *mac, struct station_info *sinfo); | 554 | int idx, u8 *mac, struct station_info *sinfo); |
536 | 555 | ||
556 | static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, | ||
557 | struct cfg80211_pmksa *pmksa); | ||
558 | |||
559 | static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, | ||
560 | struct cfg80211_pmksa *pmksa); | ||
561 | |||
562 | static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev); | ||
563 | |||
537 | static struct cfg80211_ops rndis_config_ops = { | 564 | static struct cfg80211_ops rndis_config_ops = { |
538 | .change_virtual_intf = rndis_change_virtual_intf, | 565 | .change_virtual_intf = rndis_change_virtual_intf, |
539 | .scan = rndis_scan, | 566 | .scan = rndis_scan, |
@@ -550,6 +577,9 @@ static struct cfg80211_ops rndis_config_ops = { | |||
550 | .set_default_key = rndis_set_default_key, | 577 | .set_default_key = rndis_set_default_key, |
551 | .get_station = rndis_get_station, | 578 | .get_station = rndis_get_station, |
552 | .dump_station = rndis_dump_station, | 579 | .dump_station = rndis_dump_station, |
580 | .set_pmksa = rndis_set_pmksa, | ||
581 | .del_pmksa = rndis_del_pmksa, | ||
582 | .flush_pmksa = rndis_flush_pmksa, | ||
553 | }; | 583 | }; |
554 | 584 | ||
555 | static void *rndis_wiphy_privid = &rndis_wiphy_privid; | 585 | static void *rndis_wiphy_privid = &rndis_wiphy_privid; |
@@ -704,6 +734,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) | |||
704 | struct rndis_query_c *get_c; | 734 | struct rndis_query_c *get_c; |
705 | } u; | 735 | } u; |
706 | int ret, buflen; | 736 | int ret, buflen; |
737 | int resplen, respoffs, copylen; | ||
707 | 738 | ||
708 | buflen = *len + sizeof(*u.get); | 739 | buflen = *len + sizeof(*u.get); |
709 | if (buflen < CONTROL_BUFFER_SIZE) | 740 | if (buflen < CONTROL_BUFFER_SIZE) |
@@ -733,11 +764,34 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) | |||
733 | le32_to_cpu(u.get_c->status)); | 764 | le32_to_cpu(u.get_c->status)); |
734 | 765 | ||
735 | if (ret == 0) { | 766 | if (ret == 0) { |
736 | memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); | 767 | resplen = le32_to_cpu(u.get_c->len); |
768 | respoffs = le32_to_cpu(u.get_c->offset) + 8; | ||
737 | 769 | ||
738 | ret = le32_to_cpu(u.get_c->len); | 770 | if (respoffs > buflen) { |
739 | if (ret > *len) | 771 | /* Device returned data offset outside buffer, error. */ |
740 | *len = ret; | 772 | netdev_dbg(dev->net, "%s(%s): received invalid " |
773 | "data offset: %d > %d\n", __func__, | ||
774 | oid_to_string(oid), respoffs, buflen); | ||
775 | |||
776 | ret = -EINVAL; | ||
777 | goto exit_unlock; | ||
778 | } | ||
779 | |||
780 | if ((resplen + respoffs) > buflen) { | ||
781 | /* Device would have returned more data if buffer would | ||
782 | * have been big enough. Copy just the bits that we got. | ||
783 | */ | ||
784 | copylen = buflen - respoffs; | ||
785 | } else { | ||
786 | copylen = resplen; | ||
787 | } | ||
788 | |||
789 | if (copylen > *len) | ||
790 | copylen = *len; | ||
791 | |||
792 | memcpy(data, u.buf + respoffs, copylen); | ||
793 | |||
794 | *len = resplen; | ||
741 | 795 | ||
742 | ret = rndis_error_status(u.get_c->status); | 796 | ret = rndis_error_status(u.get_c->status); |
743 | if (ret < 0) | 797 | if (ret < 0) |
@@ -746,6 +800,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) | |||
746 | le32_to_cpu(u.get_c->status), ret); | 800 | le32_to_cpu(u.get_c->status), ret); |
747 | } | 801 | } |
748 | 802 | ||
803 | exit_unlock: | ||
749 | mutex_unlock(&priv->command_lock); | 804 | mutex_unlock(&priv->command_lock); |
750 | 805 | ||
751 | if (u.buf != priv->command_buffer) | 806 | if (u.buf != priv->command_buffer) |
@@ -1091,8 +1146,6 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, | |||
1091 | } | 1146 | } |
1092 | 1147 | ||
1093 | priv->wpa_version = wpa_version; | 1148 | priv->wpa_version = wpa_version; |
1094 | priv->wpa_auth_type = auth_type; | ||
1095 | priv->wpa_keymgmt = keymgmt; | ||
1096 | 1149 | ||
1097 | return 0; | 1150 | return 0; |
1098 | } | 1151 | } |
@@ -1117,7 +1170,6 @@ static int set_priv_filter(struct usbnet *usbdev) | |||
1117 | 1170 | ||
1118 | static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) | 1171 | static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) |
1119 | { | 1172 | { |
1120 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
1121 | __le32 tmp; | 1173 | __le32 tmp; |
1122 | int encr_mode, ret; | 1174 | int encr_mode, ret; |
1123 | 1175 | ||
@@ -1146,8 +1198,6 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) | |||
1146 | return ret; | 1198 | return ret; |
1147 | } | 1199 | } |
1148 | 1200 | ||
1149 | priv->wpa_cipher_pair = pairwise; | ||
1150 | priv->wpa_cipher_group = groupwise; | ||
1151 | return 0; | 1201 | return 0; |
1152 | } | 1202 | } |
1153 | 1203 | ||
@@ -1568,6 +1618,194 @@ set_filter: | |||
1568 | le32_to_cpu(filter), ret); | 1618 | le32_to_cpu(filter), ret); |
1569 | } | 1619 | } |
1570 | 1620 | ||
1621 | #ifdef DEBUG | ||
1622 | static void debug_print_pmkids(struct usbnet *usbdev, | ||
1623 | struct ndis_80211_pmkid *pmkids, | ||
1624 | const char *func_str) | ||
1625 | { | ||
1626 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
1627 | int i, len, count, max_pmkids, entry_len; | ||
1628 | |||
1629 | max_pmkids = priv->wdev.wiphy->max_num_pmkids; | ||
1630 | len = le32_to_cpu(pmkids->length); | ||
1631 | count = le32_to_cpu(pmkids->bssid_info_count); | ||
1632 | |||
1633 | entry_len = (count > 0) ? (len - sizeof(*pmkids)) / count : -1; | ||
1634 | |||
1635 | netdev_dbg(usbdev->net, "%s(): %d PMKIDs (data len: %d, entry len: " | ||
1636 | "%d)\n", func_str, count, len, entry_len); | ||
1637 | |||
1638 | if (count > max_pmkids) | ||
1639 | count = max_pmkids; | ||
1640 | |||
1641 | for (i = 0; i < count; i++) { | ||
1642 | u32 *tmp = (u32 *)pmkids->bssid_info[i].pmkid; | ||
1643 | |||
1644 | netdev_dbg(usbdev->net, "%s(): bssid: %pM, " | ||
1645 | "pmkid: %08X:%08X:%08X:%08X\n", | ||
1646 | func_str, pmkids->bssid_info[i].bssid, | ||
1647 | cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), | ||
1648 | cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); | ||
1649 | } | ||
1650 | } | ||
1651 | #else | ||
1652 | static void debug_print_pmkids(struct usbnet *usbdev, | ||
1653 | struct ndis_80211_pmkid *pmkids, | ||
1654 | const char *func_str) | ||
1655 | { | ||
1656 | return; | ||
1657 | } | ||
1658 | #endif | ||
1659 | |||
1660 | static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev) | ||
1661 | { | ||
1662 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
1663 | struct ndis_80211_pmkid *pmkids; | ||
1664 | int len, ret, max_pmkids; | ||
1665 | |||
1666 | max_pmkids = priv->wdev.wiphy->max_num_pmkids; | ||
1667 | len = sizeof(*pmkids) + max_pmkids * sizeof(pmkids->bssid_info[0]); | ||
1668 | |||
1669 | pmkids = kzalloc(len, GFP_KERNEL); | ||
1670 | if (!pmkids) | ||
1671 | return ERR_PTR(-ENOMEM); | ||
1672 | |||
1673 | pmkids->length = cpu_to_le32(len); | ||
1674 | pmkids->bssid_info_count = cpu_to_le32(max_pmkids); | ||
1675 | |||
1676 | ret = rndis_query_oid(usbdev, OID_802_11_PMKID, pmkids, &len); | ||
1677 | if (ret < 0) { | ||
1678 | netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d)" | ||
1679 | " -> %d\n", __func__, len, max_pmkids, ret); | ||
1680 | |||
1681 | kfree(pmkids); | ||
1682 | return ERR_PTR(ret); | ||
1683 | } | ||
1684 | |||
1685 | if (le32_to_cpu(pmkids->bssid_info_count) > max_pmkids) | ||
1686 | pmkids->bssid_info_count = cpu_to_le32(max_pmkids); | ||
1687 | |||
1688 | debug_print_pmkids(usbdev, pmkids, __func__); | ||
1689 | |||
1690 | return pmkids; | ||
1691 | } | ||
1692 | |||
1693 | static int set_device_pmkids(struct usbnet *usbdev, | ||
1694 | struct ndis_80211_pmkid *pmkids) | ||
1695 | { | ||
1696 | int ret, len, num_pmkids; | ||
1697 | |||
1698 | num_pmkids = le32_to_cpu(pmkids->bssid_info_count); | ||
1699 | len = sizeof(*pmkids) + num_pmkids * sizeof(pmkids->bssid_info[0]); | ||
1700 | pmkids->length = cpu_to_le32(len); | ||
1701 | |||
1702 | debug_print_pmkids(usbdev, pmkids, __func__); | ||
1703 | |||
1704 | ret = rndis_set_oid(usbdev, OID_802_11_PMKID, pmkids, | ||
1705 | le32_to_cpu(pmkids->length)); | ||
1706 | if (ret < 0) { | ||
1707 | netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d) -> %d" | ||
1708 | "\n", __func__, len, num_pmkids, ret); | ||
1709 | } | ||
1710 | |||
1711 | kfree(pmkids); | ||
1712 | return ret; | ||
1713 | } | ||
1714 | |||
1715 | static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev, | ||
1716 | struct ndis_80211_pmkid *pmkids, | ||
1717 | struct cfg80211_pmksa *pmksa, | ||
1718 | int max_pmkids) | ||
1719 | { | ||
1720 | int i, len, count, newlen, err; | ||
1721 | |||
1722 | len = le32_to_cpu(pmkids->length); | ||
1723 | count = le32_to_cpu(pmkids->bssid_info_count); | ||
1724 | |||
1725 | if (count > max_pmkids) | ||
1726 | count = max_pmkids; | ||
1727 | |||
1728 | for (i = 0; i < count; i++) | ||
1729 | if (!compare_ether_addr(pmkids->bssid_info[i].bssid, | ||
1730 | pmksa->bssid)) | ||
1731 | break; | ||
1732 | |||
1733 | /* pmkid not found */ | ||
1734 | if (i == count) { | ||
1735 | netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n", | ||
1736 | __func__, pmksa->bssid); | ||
1737 | err = -ENOENT; | ||
1738 | goto error; | ||
1739 | } | ||
1740 | |||
1741 | for (; i + 1 < count; i++) | ||
1742 | pmkids->bssid_info[i] = pmkids->bssid_info[i + 1]; | ||
1743 | |||
1744 | count--; | ||
1745 | newlen = sizeof(*pmkids) + count * sizeof(pmkids->bssid_info[0]); | ||
1746 | |||
1747 | pmkids->length = cpu_to_le32(newlen); | ||
1748 | pmkids->bssid_info_count = cpu_to_le32(count); | ||
1749 | |||
1750 | return pmkids; | ||
1751 | error: | ||
1752 | kfree(pmkids); | ||
1753 | return ERR_PTR(err); | ||
1754 | } | ||
1755 | |||
1756 | static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev, | ||
1757 | struct ndis_80211_pmkid *pmkids, | ||
1758 | struct cfg80211_pmksa *pmksa, | ||
1759 | int max_pmkids) | ||
1760 | { | ||
1761 | int i, err, len, count, newlen; | ||
1762 | |||
1763 | len = le32_to_cpu(pmkids->length); | ||
1764 | count = le32_to_cpu(pmkids->bssid_info_count); | ||
1765 | |||
1766 | if (count > max_pmkids) | ||
1767 | count = max_pmkids; | ||
1768 | |||
1769 | /* update with new pmkid */ | ||
1770 | for (i = 0; i < count; i++) { | ||
1771 | if (compare_ether_addr(pmkids->bssid_info[i].bssid, | ||
1772 | pmksa->bssid)) | ||
1773 | continue; | ||
1774 | |||
1775 | memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid, | ||
1776 | WLAN_PMKID_LEN); | ||
1777 | |||
1778 | return pmkids; | ||
1779 | } | ||
1780 | |||
1781 | /* out of space, return error */ | ||
1782 | if (i == max_pmkids) { | ||
1783 | netdev_dbg(usbdev->net, "%s(): out of space\n", __func__); | ||
1784 | err = -ENOSPC; | ||
1785 | goto error; | ||
1786 | } | ||
1787 | |||
1788 | /* add new pmkid */ | ||
1789 | newlen = sizeof(*pmkids) + (count + 1) * sizeof(pmkids->bssid_info[0]); | ||
1790 | |||
1791 | pmkids = krealloc(pmkids, newlen, GFP_KERNEL); | ||
1792 | if (!pmkids) { | ||
1793 | err = -ENOMEM; | ||
1794 | goto error; | ||
1795 | } | ||
1796 | |||
1797 | pmkids->length = cpu_to_le32(newlen); | ||
1798 | pmkids->bssid_info_count = cpu_to_le32(count + 1); | ||
1799 | |||
1800 | memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN); | ||
1801 | memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); | ||
1802 | |||
1803 | return pmkids; | ||
1804 | error: | ||
1805 | kfree(pmkids); | ||
1806 | return ERR_PTR(err); | ||
1807 | } | ||
1808 | |||
1571 | /* | 1809 | /* |
1572 | * cfg80211 ops | 1810 | * cfg80211 ops |
1573 | */ | 1811 | */ |
@@ -2178,6 +2416,78 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, | |||
2178 | return 0; | 2416 | return 0; |
2179 | } | 2417 | } |
2180 | 2418 | ||
2419 | static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, | ||
2420 | struct cfg80211_pmksa *pmksa) | ||
2421 | { | ||
2422 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | ||
2423 | struct usbnet *usbdev = priv->usbdev; | ||
2424 | struct ndis_80211_pmkid *pmkids; | ||
2425 | u32 *tmp = (u32 *)pmksa->pmkid; | ||
2426 | |||
2427 | netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, | ||
2428 | pmksa->bssid, | ||
2429 | cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), | ||
2430 | cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); | ||
2431 | |||
2432 | pmkids = get_device_pmkids(usbdev); | ||
2433 | if (IS_ERR(pmkids)) { | ||
2434 | /* couldn't read PMKID cache from device */ | ||
2435 | return PTR_ERR(pmkids); | ||
2436 | } | ||
2437 | |||
2438 | pmkids = update_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); | ||
2439 | if (IS_ERR(pmkids)) { | ||
2440 | /* not found, list full, etc */ | ||
2441 | return PTR_ERR(pmkids); | ||
2442 | } | ||
2443 | |||
2444 | return set_device_pmkids(usbdev, pmkids); | ||
2445 | } | ||
2446 | |||
2447 | static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, | ||
2448 | struct cfg80211_pmksa *pmksa) | ||
2449 | { | ||
2450 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | ||
2451 | struct usbnet *usbdev = priv->usbdev; | ||
2452 | struct ndis_80211_pmkid *pmkids; | ||
2453 | u32 *tmp = (u32 *)pmksa->pmkid; | ||
2454 | |||
2455 | netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__, | ||
2456 | pmksa->bssid, | ||
2457 | cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]), | ||
2458 | cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3])); | ||
2459 | |||
2460 | pmkids = get_device_pmkids(usbdev); | ||
2461 | if (IS_ERR(pmkids)) { | ||
2462 | /* Couldn't read PMKID cache from device */ | ||
2463 | return PTR_ERR(pmkids); | ||
2464 | } | ||
2465 | |||
2466 | pmkids = remove_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids); | ||
2467 | if (IS_ERR(pmkids)) { | ||
2468 | /* not found, etc */ | ||
2469 | return PTR_ERR(pmkids); | ||
2470 | } | ||
2471 | |||
2472 | return set_device_pmkids(usbdev, pmkids); | ||
2473 | } | ||
2474 | |||
2475 | static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) | ||
2476 | { | ||
2477 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | ||
2478 | struct usbnet *usbdev = priv->usbdev; | ||
2479 | struct ndis_80211_pmkid pmkid; | ||
2480 | |||
2481 | netdev_dbg(usbdev->net, "%s()\n", __func__); | ||
2482 | |||
2483 | memset(&pmkid, 0, sizeof(pmkid)); | ||
2484 | |||
2485 | pmkid.length = cpu_to_le32(sizeof(pmkid)); | ||
2486 | pmkid.bssid_info_count = cpu_to_le32(0); | ||
2487 | |||
2488 | return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid)); | ||
2489 | } | ||
2490 | |||
2181 | /* | 2491 | /* |
2182 | * workers, indication handlers, device poller | 2492 | * workers, indication handlers, device poller |
2183 | */ | 2493 | */ |
@@ -2522,12 +2832,14 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) | |||
2522 | } | 2832 | } |
2523 | } | 2833 | } |
2524 | 2834 | ||
2525 | static int rndis_wlan_get_caps(struct usbnet *usbdev) | 2835 | static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) |
2526 | { | 2836 | { |
2527 | struct { | 2837 | struct { |
2528 | __le32 num_items; | 2838 | __le32 num_items; |
2529 | __le32 items[8]; | 2839 | __le32 items[8]; |
2530 | } networks_supported; | 2840 | } networks_supported; |
2841 | struct ndis_80211_capability *caps; | ||
2842 | u8 caps_buf[sizeof(*caps) + sizeof(caps->auth_encr_pair) * 16]; | ||
2531 | int len, retval, i, n; | 2843 | int len, retval, i, n; |
2532 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 2844 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
2533 | 2845 | ||
@@ -2555,6 +2867,21 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev) | |||
2555 | } | 2867 | } |
2556 | } | 2868 | } |
2557 | 2869 | ||
2870 | /* get device 802.11 capabilities, number of PMKIDs */ | ||
2871 | caps = (struct ndis_80211_capability *)caps_buf; | ||
2872 | len = sizeof(caps_buf); | ||
2873 | retval = rndis_query_oid(usbdev, OID_802_11_CAPABILITY, caps, &len); | ||
2874 | if (retval >= 0) { | ||
2875 | netdev_dbg(usbdev->net, "OID_802_11_CAPABILITY -> len %d, " | ||
2876 | "ver %d, pmkids %d, auth-encr-pairs %d\n", | ||
2877 | le32_to_cpu(caps->length), | ||
2878 | le32_to_cpu(caps->version), | ||
2879 | le32_to_cpu(caps->num_pmkids), | ||
2880 | le32_to_cpu(caps->num_auth_encr_pair)); | ||
2881 | wiphy->max_num_pmkids = le32_to_cpu(caps->num_pmkids); | ||
2882 | } else | ||
2883 | wiphy->max_num_pmkids = 0; | ||
2884 | |||
2558 | return retval; | 2885 | return retval; |
2559 | } | 2886 | } |
2560 | 2887 | ||
@@ -2802,7 +3129,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) | |||
2802 | wiphy->max_scan_ssids = 1; | 3129 | wiphy->max_scan_ssids = 1; |
2803 | 3130 | ||
2804 | /* TODO: fill-out band/encr information based on priv->caps */ | 3131 | /* TODO: fill-out band/encr information based on priv->caps */ |
2805 | rndis_wlan_get_caps(usbdev); | 3132 | rndis_wlan_get_caps(usbdev, wiphy); |
2806 | 3133 | ||
2807 | memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); | 3134 | memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); |
2808 | memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); | 3135 | memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); |
@@ -2862,9 +3189,6 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) | |||
2862 | flush_workqueue(priv->workqueue); | 3189 | flush_workqueue(priv->workqueue); |
2863 | destroy_workqueue(priv->workqueue); | 3190 | destroy_workqueue(priv->workqueue); |
2864 | 3191 | ||
2865 | if (priv && priv->wpa_ie_len) | ||
2866 | kfree(priv->wpa_ie); | ||
2867 | |||
2868 | rndis_unbind(usbdev, intf); | 3192 | rndis_unbind(usbdev, intf); |
2869 | 3193 | ||
2870 | wiphy_unregister(priv->wdev.wiphy); | 3194 | wiphy_unregister(priv->wdev.wiphy); |