aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rndis_wlan.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@mbnet.fi>2010-03-04 11:27:36 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-03-10 17:44:28 -0500
commit5a7d05830de1ecfdaf0a9fb43e4aa08abbdbfe9f (patch)
tree88fd43490767cd215d232e94c0edc5a4c605a5be /drivers/net/wireless/rndis_wlan.c
parent0308383f9591c991b3eb865c4f5ea2a87242afac (diff)
rndis_wlan: Implement cfg80211 PMKSA API
Add support for cfg80211 set_pmksa/del_pmksa/flush_pmksa. Updating PMKID entry list is done on driver side since NDIS API requires full list update. v2: - fixed to use new netdev_dbg/warn/etc instead of old devdbg/warn/etc - fixed false padding from struct ndis_80211_bssid_info Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rndis_wlan.c')
-rw-r--r--drivers/net/wireless/rndis_wlan.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 3433461995a7..267afd714c74 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -372,6 +372,17 @@ struct ndis_80211_capability {
372 struct ndis_80211_auth_encr_pair auth_encr_pair[0]; 372 struct ndis_80211_auth_encr_pair auth_encr_pair[0];
373} __attribute__((packed)); 373} __attribute__((packed));
374 374
375struct ndis_80211_bssid_info {
376 u8 bssid[6];
377 u8 pmkid[16];
378};
379
380struct ndis_80211_pmkid {
381 __le32 length;
382 __le32 bssid_info_count;
383 struct ndis_80211_bssid_info bssid_info[0];
384};
385
375/* 386/*
376 * private data 387 * private data
377 */ 388 */
@@ -542,6 +553,14 @@ static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
542static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, 553static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
543 int idx, u8 *mac, struct station_info *sinfo); 554 int idx, u8 *mac, struct station_info *sinfo);
544 555
556static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
557 struct cfg80211_pmksa *pmksa);
558
559static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
560 struct cfg80211_pmksa *pmksa);
561
562static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev);
563
545static struct cfg80211_ops rndis_config_ops = { 564static struct cfg80211_ops rndis_config_ops = {
546 .change_virtual_intf = rndis_change_virtual_intf, 565 .change_virtual_intf = rndis_change_virtual_intf,
547 .scan = rndis_scan, 566 .scan = rndis_scan,
@@ -558,6 +577,9 @@ static struct cfg80211_ops rndis_config_ops = {
558 .set_default_key = rndis_set_default_key, 577 .set_default_key = rndis_set_default_key,
559 .get_station = rndis_get_station, 578 .get_station = rndis_get_station,
560 .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,
561}; 583};
562 584
563static void *rndis_wiphy_privid = &rndis_wiphy_privid; 585static void *rndis_wiphy_privid = &rndis_wiphy_privid;
@@ -1580,6 +1602,194 @@ static void set_multicast_list(struct usbnet *usbdev)
1580 le32_to_cpu(filter), ret); 1602 le32_to_cpu(filter), ret);
1581} 1603}
1582 1604
1605#ifdef DEBUG
1606static void debug_print_pmkids(struct usbnet *usbdev,
1607 struct ndis_80211_pmkid *pmkids,
1608 const char *func_str)
1609{
1610 struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
1611 int i, len, count, max_pmkids, entry_len;
1612
1613 max_pmkids = priv->wdev.wiphy->max_num_pmkids;
1614 len = le32_to_cpu(pmkids->length);
1615 count = le32_to_cpu(pmkids->bssid_info_count);
1616
1617 entry_len = (count > 0) ? (len - sizeof(*pmkids)) / count : -1;
1618
1619 netdev_dbg(usbdev->net, "%s(): %d PMKIDs (data len: %d, entry len: "
1620 "%d)\n", func_str, count, len, entry_len);
1621
1622 if (count > max_pmkids)
1623 count = max_pmkids;
1624
1625 for (i = 0; i < count; i++) {
1626 u32 *tmp = (u32 *)pmkids->bssid_info[i].pmkid;
1627
1628 netdev_dbg(usbdev->net, "%s(): bssid: %pM, "
1629 "pmkid: %08X:%08X:%08X:%08X\n",
1630 func_str, pmkids->bssid_info[i].bssid,
1631 cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
1632 cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
1633 }
1634}
1635#else
1636static void debug_print_pmkids(struct usbnet *usbdev,
1637 struct ndis_80211_pmkid *pmkids,
1638 const char *func_str)
1639{
1640 return;
1641}
1642#endif
1643
1644static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev)
1645{
1646 struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
1647 struct ndis_80211_pmkid *pmkids;
1648 int len, ret, max_pmkids;
1649
1650 max_pmkids = priv->wdev.wiphy->max_num_pmkids;
1651 len = sizeof(*pmkids) + max_pmkids * sizeof(pmkids->bssid_info[0]);
1652
1653 pmkids = kzalloc(len, GFP_KERNEL);
1654 if (!pmkids)
1655 return ERR_PTR(-ENOMEM);
1656
1657 pmkids->length = cpu_to_le32(len);
1658 pmkids->bssid_info_count = cpu_to_le32(max_pmkids);
1659
1660 ret = rndis_query_oid(usbdev, OID_802_11_PMKID, pmkids, &len);
1661 if (ret < 0) {
1662 netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d)"
1663 " -> %d\n", __func__, len, max_pmkids, ret);
1664
1665 kfree(pmkids);
1666 return ERR_PTR(ret);
1667 }
1668
1669 if (le32_to_cpu(pmkids->bssid_info_count) > max_pmkids)
1670 pmkids->bssid_info_count = cpu_to_le32(max_pmkids);
1671
1672 debug_print_pmkids(usbdev, pmkids, __func__);
1673
1674 return pmkids;
1675}
1676
1677static int set_device_pmkids(struct usbnet *usbdev,
1678 struct ndis_80211_pmkid *pmkids)
1679{
1680 int ret, len, num_pmkids;
1681
1682 num_pmkids = le32_to_cpu(pmkids->bssid_info_count);
1683 len = sizeof(*pmkids) + num_pmkids * sizeof(pmkids->bssid_info[0]);
1684 pmkids->length = cpu_to_le32(len);
1685
1686 debug_print_pmkids(usbdev, pmkids, __func__);
1687
1688 ret = rndis_set_oid(usbdev, OID_802_11_PMKID, pmkids,
1689 le32_to_cpu(pmkids->length));
1690 if (ret < 0) {
1691 netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d) -> %d"
1692 "\n", __func__, len, num_pmkids, ret);
1693 }
1694
1695 kfree(pmkids);
1696 return ret;
1697}
1698
1699static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev,
1700 struct ndis_80211_pmkid *pmkids,
1701 struct cfg80211_pmksa *pmksa,
1702 int max_pmkids)
1703{
1704 int i, len, count, newlen, err;
1705
1706 len = le32_to_cpu(pmkids->length);
1707 count = le32_to_cpu(pmkids->bssid_info_count);
1708
1709 if (count > max_pmkids)
1710 count = max_pmkids;
1711
1712 for (i = 0; i < count; i++)
1713 if (!compare_ether_addr(pmkids->bssid_info[i].bssid,
1714 pmksa->bssid))
1715 break;
1716
1717 /* pmkid not found */
1718 if (i == count) {
1719 netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n",
1720 __func__, pmksa->bssid);
1721 err = -ENOENT;
1722 goto error;
1723 }
1724
1725 for (; i + 1 < count; i++)
1726 pmkids->bssid_info[i] = pmkids->bssid_info[i + 1];
1727
1728 count--;
1729 newlen = sizeof(*pmkids) + count * sizeof(pmkids->bssid_info[0]);
1730
1731 pmkids->length = cpu_to_le32(newlen);
1732 pmkids->bssid_info_count = cpu_to_le32(count);
1733
1734 return pmkids;
1735error:
1736 kfree(pmkids);
1737 return ERR_PTR(err);
1738}
1739
1740static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
1741 struct ndis_80211_pmkid *pmkids,
1742 struct cfg80211_pmksa *pmksa,
1743 int max_pmkids)
1744{
1745 int i, err, len, count, newlen;
1746
1747 len = le32_to_cpu(pmkids->length);
1748 count = le32_to_cpu(pmkids->bssid_info_count);
1749
1750 if (count > max_pmkids)
1751 count = max_pmkids;
1752
1753 /* update with new pmkid */
1754 for (i = 0; i < count; i++) {
1755 if (compare_ether_addr(pmkids->bssid_info[i].bssid,
1756 pmksa->bssid))
1757 continue;
1758
1759 memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid,
1760 WLAN_PMKID_LEN);
1761
1762 return pmkids;
1763 }
1764
1765 /* out of space, return error */
1766 if (i == max_pmkids) {
1767 netdev_dbg(usbdev->net, "%s(): out of space\n", __func__);
1768 err = -ENOSPC;
1769 goto error;
1770 }
1771
1772 /* add new pmkid */
1773 newlen = sizeof(*pmkids) + (count + 1) * sizeof(pmkids->bssid_info[0]);
1774
1775 pmkids = krealloc(pmkids, newlen, GFP_KERNEL);
1776 if (!pmkids) {
1777 err = -ENOMEM;
1778 goto error;
1779 }
1780
1781 pmkids->length = cpu_to_le32(newlen);
1782 pmkids->bssid_info_count = cpu_to_le32(count + 1);
1783
1784 memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN);
1785 memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
1786
1787 return pmkids;
1788error:
1789 kfree(pmkids);
1790 return ERR_PTR(err);
1791}
1792
1583/* 1793/*
1584 * cfg80211 ops 1794 * cfg80211 ops
1585 */ 1795 */
@@ -2190,6 +2400,78 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
2190 return 0; 2400 return 0;
2191} 2401}
2192 2402
2403static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
2404 struct cfg80211_pmksa *pmksa)
2405{
2406 struct rndis_wlan_private *priv = wiphy_priv(wiphy);
2407 struct usbnet *usbdev = priv->usbdev;
2408 struct ndis_80211_pmkid *pmkids;
2409 u32 *tmp = (u32 *)pmksa->pmkid;
2410
2411 netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__,
2412 pmksa->bssid,
2413 cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
2414 cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
2415
2416 pmkids = get_device_pmkids(usbdev);
2417 if (IS_ERR(pmkids)) {
2418 /* couldn't read PMKID cache from device */
2419 return PTR_ERR(pmkids);
2420 }
2421
2422 pmkids = update_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids);
2423 if (IS_ERR(pmkids)) {
2424 /* not found, list full, etc */
2425 return PTR_ERR(pmkids);
2426 }
2427
2428 return set_device_pmkids(usbdev, pmkids);
2429}
2430
2431static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
2432 struct cfg80211_pmksa *pmksa)
2433{
2434 struct rndis_wlan_private *priv = wiphy_priv(wiphy);
2435 struct usbnet *usbdev = priv->usbdev;
2436 struct ndis_80211_pmkid *pmkids;
2437 u32 *tmp = (u32 *)pmksa->pmkid;
2438
2439 netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__,
2440 pmksa->bssid,
2441 cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
2442 cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
2443
2444 pmkids = get_device_pmkids(usbdev);
2445 if (IS_ERR(pmkids)) {
2446 /* Couldn't read PMKID cache from device */
2447 return PTR_ERR(pmkids);
2448 }
2449
2450 pmkids = remove_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids);
2451 if (IS_ERR(pmkids)) {
2452 /* not found, etc */
2453 return PTR_ERR(pmkids);
2454 }
2455
2456 return set_device_pmkids(usbdev, pmkids);
2457}
2458
2459static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
2460{
2461 struct rndis_wlan_private *priv = wiphy_priv(wiphy);
2462 struct usbnet *usbdev = priv->usbdev;
2463 struct ndis_80211_pmkid pmkid;
2464
2465 netdev_dbg(usbdev->net, "%s()\n", __func__);
2466
2467 memset(&pmkid, 0, sizeof(pmkid));
2468
2469 pmkid.length = cpu_to_le32(sizeof(pmkid));
2470 pmkid.bssid_info_count = cpu_to_le32(0);
2471
2472 return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid));
2473}
2474
2193/* 2475/*
2194 * workers, indication handlers, device poller 2476 * workers, indication handlers, device poller
2195 */ 2477 */