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