diff options
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 231 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.h | 3 |
3 files changed, 193 insertions, 44 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index fed7b8077f5e..e676cfccedfe 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -1723,32 +1723,14 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) | |||
1723 | return 0; | 1723 | return 0; |
1724 | } | 1724 | } |
1725 | 1725 | ||
1726 | static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | 1726 | static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif, |
1727 | struct cfg80211_wowlan *wow, u32 *filter) | ||
1727 | { | 1728 | { |
1728 | struct in_device *in_dev; | 1729 | int ret, pos; |
1729 | struct in_ifaddr *ifa; | 1730 | u8 mask[WOW_MASK_SIZE]; |
1730 | struct ath6kl_vif *vif; | ||
1731 | int ret, pos, left; | ||
1732 | u32 filter = 0; | ||
1733 | u16 i; | 1731 | u16 i; |
1734 | u8 mask[WOW_MASK_SIZE], index = 0; | ||
1735 | __be32 ips[MAX_IP_ADDRS]; | ||
1736 | |||
1737 | vif = ath6kl_vif_first(ar); | ||
1738 | if (!vif) | ||
1739 | return -EIO; | ||
1740 | |||
1741 | if (!ath6kl_cfg80211_ready(vif)) | ||
1742 | return -EIO; | ||
1743 | |||
1744 | if (!test_bit(CONNECTED, &vif->flags)) | ||
1745 | return -EINVAL; | ||
1746 | 1732 | ||
1747 | /* Clear existing WOW patterns */ | 1733 | /* Configure the patterns that we received from the user. */ |
1748 | for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) | ||
1749 | ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, | ||
1750 | WOW_LIST_ID, i); | ||
1751 | /* Configure new WOW patterns */ | ||
1752 | for (i = 0; i < wow->n_patterns; i++) { | 1734 | for (i = 0; i < wow->n_patterns; i++) { |
1753 | 1735 | ||
1754 | /* | 1736 | /* |
@@ -1771,14 +1753,194 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
1771 | * matched from the first byte of received pkt in the firmware. | 1753 | * matched from the first byte of received pkt in the firmware. |
1772 | */ | 1754 | */ |
1773 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | 1755 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, |
1774 | vif->fw_vif_idx, WOW_LIST_ID, | 1756 | vif->fw_vif_idx, WOW_LIST_ID, |
1775 | wow->patterns[i].pattern_len, | 1757 | wow->patterns[i].pattern_len, |
1776 | 0 /* pattern offset */, | 1758 | 0 /* pattern offset */, |
1777 | wow->patterns[i].pattern, mask); | 1759 | wow->patterns[i].pattern, mask); |
1778 | if (ret) | 1760 | if (ret) |
1779 | return ret; | 1761 | return ret; |
1780 | } | 1762 | } |
1781 | 1763 | ||
1764 | if (wow->disconnect) | ||
1765 | *filter |= WOW_FILTER_OPTION_NWK_DISASSOC; | ||
1766 | |||
1767 | if (wow->magic_pkt) | ||
1768 | *filter |= WOW_FILTER_OPTION_MAGIC_PACKET; | ||
1769 | |||
1770 | if (wow->gtk_rekey_failure) | ||
1771 | *filter |= WOW_FILTER_OPTION_GTK_ERROR; | ||
1772 | |||
1773 | if (wow->eap_identity_req) | ||
1774 | *filter |= WOW_FILTER_OPTION_EAP_REQ; | ||
1775 | |||
1776 | if (wow->four_way_handshake) | ||
1777 | *filter |= WOW_FILTER_OPTION_8021X_4WAYHS; | ||
1778 | |||
1779 | return 0; | ||
1780 | } | ||
1781 | |||
1782 | static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif) | ||
1783 | { | ||
1784 | static const u8 unicst_pattern[] = { 0x00, 0x00, 0x00, | ||
1785 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1786 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1787 | 0x00, 0x08 }; | ||
1788 | static const u8 unicst_mask[] = { 0x01, 0x00, 0x00, | ||
1789 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1790 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1791 | 0x00, 0x7f }; | ||
1792 | u8 unicst_offset = 0; | ||
1793 | static const u8 arp_pattern[] = { 0x08, 0x06 }; | ||
1794 | static const u8 arp_mask[] = { 0xff, 0xff }; | ||
1795 | u8 arp_offset = 20; | ||
1796 | static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 }; | ||
1797 | static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 }; | ||
1798 | u8 discvr_offset = 38; | ||
1799 | static const u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff, | ||
1800 | 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1801 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, | ||
1802 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1803 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1804 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 /* port 67 */ }; | ||
1805 | static const u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff, | ||
1806 | 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1807 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, | ||
1808 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1809 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1810 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xff /* port 67 */ }; | ||
1811 | u8 dhcp_offset = 0; | ||
1812 | int ret; | ||
1813 | |||
1814 | /* Setup unicast IP, EAPOL-like and ARP pkt pattern */ | ||
1815 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1816 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1817 | sizeof(unicst_pattern), unicst_offset, | ||
1818 | unicst_pattern, unicst_mask); | ||
1819 | if (ret) { | ||
1820 | ath6kl_err("failed to add WOW unicast IP pattern\n"); | ||
1821 | return ret; | ||
1822 | } | ||
1823 | |||
1824 | /* Setup all ARP pkt pattern */ | ||
1825 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1826 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1827 | sizeof(arp_pattern), arp_offset, | ||
1828 | arp_pattern, arp_mask); | ||
1829 | if (ret) { | ||
1830 | ath6kl_err("failed to add WOW ARP pattern\n"); | ||
1831 | return ret; | ||
1832 | } | ||
1833 | |||
1834 | /* | ||
1835 | * Setup multicast pattern for mDNS 224.0.0.251, | ||
1836 | * SSDP 239.255.255.250 and LLMNR 224.0.0.252 | ||
1837 | */ | ||
1838 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1839 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1840 | sizeof(discvr_pattern), discvr_offset, | ||
1841 | discvr_pattern, discvr_mask); | ||
1842 | if (ret) { | ||
1843 | ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n"); | ||
1844 | return ret; | ||
1845 | } | ||
1846 | |||
1847 | /* Setup all DHCP broadcast pkt pattern */ | ||
1848 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1849 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1850 | sizeof(dhcp_pattern), dhcp_offset, | ||
1851 | dhcp_pattern, dhcp_mask); | ||
1852 | if (ret) { | ||
1853 | ath6kl_err("failed to add WOW DHCP broadcast pattern\n"); | ||
1854 | return ret; | ||
1855 | } | ||
1856 | |||
1857 | return 0; | ||
1858 | } | ||
1859 | |||
1860 | static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) | ||
1861 | { | ||
1862 | struct net_device *ndev = vif->ndev; | ||
1863 | static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 }; | ||
1864 | static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 }; | ||
1865 | u8 discvr_offset = 38; | ||
1866 | u8 mac_mask[ETH_ALEN]; | ||
1867 | int ret; | ||
1868 | |||
1869 | /* Setup unicast pkt pattern */ | ||
1870 | memset(mac_mask, 0xff, ETH_ALEN); | ||
1871 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1872 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1873 | ETH_ALEN, 0, ndev->dev_addr, | ||
1874 | mac_mask); | ||
1875 | if (ret) { | ||
1876 | ath6kl_err("failed to add WOW unicast pattern\n"); | ||
1877 | return ret; | ||
1878 | } | ||
1879 | |||
1880 | /* | ||
1881 | * Setup multicast pattern for mDNS 224.0.0.251, | ||
1882 | * SSDP 239.255.255.250 and LLMNR 224.0.0.252 | ||
1883 | */ | ||
1884 | if ((ndev->flags & IFF_ALLMULTI) || | ||
1885 | (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) { | ||
1886 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1887 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1888 | sizeof(discvr_pattern), discvr_offset, | ||
1889 | discvr_pattern, discvr_mask); | ||
1890 | if (ret) { | ||
1891 | ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR " | ||
1892 | "pattern\n"); | ||
1893 | return ret; | ||
1894 | } | ||
1895 | } | ||
1896 | |||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | ||
1901 | { | ||
1902 | struct in_device *in_dev; | ||
1903 | struct in_ifaddr *ifa; | ||
1904 | struct ath6kl_vif *vif; | ||
1905 | int ret, left; | ||
1906 | u32 filter = 0; | ||
1907 | u16 i; | ||
1908 | u8 index = 0; | ||
1909 | __be32 ips[MAX_IP_ADDRS]; | ||
1910 | |||
1911 | vif = ath6kl_vif_first(ar); | ||
1912 | if (!vif) | ||
1913 | return -EIO; | ||
1914 | |||
1915 | if (!ath6kl_cfg80211_ready(vif)) | ||
1916 | return -EIO; | ||
1917 | |||
1918 | if (!test_bit(CONNECTED, &vif->flags)) | ||
1919 | return -EINVAL; | ||
1920 | |||
1921 | if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) | ||
1922 | return -EINVAL; | ||
1923 | |||
1924 | /* Clear existing WOW patterns */ | ||
1925 | for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) | ||
1926 | ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, | ||
1927 | WOW_LIST_ID, i); | ||
1928 | |||
1929 | /* | ||
1930 | * Skip the default WOW pattern configuration | ||
1931 | * if the driver receives any WOW patterns from | ||
1932 | * the user. | ||
1933 | */ | ||
1934 | if (wow) | ||
1935 | ret = ath6kl_wow_usr(ar, vif, wow, &filter); | ||
1936 | else if (vif->nw_type == AP_NETWORK) | ||
1937 | ret = ath6kl_wow_ap(ar, vif); | ||
1938 | else | ||
1939 | ret = ath6kl_wow_sta(ar, vif); | ||
1940 | |||
1941 | if (ret) | ||
1942 | return ret; | ||
1943 | |||
1782 | /* Setup own IP addr for ARP agent. */ | 1944 | /* Setup own IP addr for ARP agent. */ |
1783 | in_dev = __in_dev_get_rtnl(vif->ndev); | 1945 | in_dev = __in_dev_get_rtnl(vif->ndev); |
1784 | if (!in_dev) | 1946 | if (!in_dev) |
@@ -1806,21 +1968,6 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
1806 | } | 1968 | } |
1807 | 1969 | ||
1808 | skip_arp: | 1970 | skip_arp: |
1809 | if (wow->disconnect) | ||
1810 | filter |= WOW_FILTER_OPTION_NWK_DISASSOC; | ||
1811 | |||
1812 | if (wow->magic_pkt) | ||
1813 | filter |= WOW_FILTER_OPTION_MAGIC_PACKET; | ||
1814 | |||
1815 | if (wow->gtk_rekey_failure) | ||
1816 | filter |= WOW_FILTER_OPTION_GTK_ERROR; | ||
1817 | |||
1818 | if (wow->eap_identity_req) | ||
1819 | filter |= WOW_FILTER_OPTION_EAP_REQ; | ||
1820 | |||
1821 | if (wow->four_way_handshake) | ||
1822 | filter |= WOW_FILTER_OPTION_8021X_4WAYHS; | ||
1823 | |||
1824 | ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, | 1971 | ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, |
1825 | ATH6KL_WOW_MODE_ENABLE, | 1972 | ATH6KL_WOW_MODE_ENABLE, |
1826 | filter, | 1973 | filter, |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 5d678bf372d3..9c8e4dfbfa0c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -2620,7 +2620,8 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, | |||
2620 | 2620 | ||
2621 | int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | 2621 | int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, |
2622 | u8 list_id, u8 filter_size, | 2622 | u8 list_id, u8 filter_size, |
2623 | u8 filter_offset, u8 *filter, u8 *mask) | 2623 | u8 filter_offset, const u8 *filter, |
2624 | const u8 *mask) | ||
2624 | { | 2625 | { |
2625 | struct sk_buff *skb; | 2626 | struct sk_buff *skb; |
2626 | struct wmi_add_wow_pattern_cmd *cmd; | 2627 | struct wmi_add_wow_pattern_cmd *cmd; |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 48e9d2641d69..85698ef2dd88 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -2461,7 +2461,8 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, | |||
2461 | u32 filter, u16 host_req_delay); | 2461 | u32 filter, u16 host_req_delay); |
2462 | int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | 2462 | int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, |
2463 | u8 list_id, u8 filter_size, | 2463 | u8 list_id, u8 filter_size, |
2464 | u8 filter_offset, u8 *filter, u8 *mask); | 2464 | u8 filter_offset, const u8 *filter, |
2465 | const u8 *mask); | ||
2465 | int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | 2466 | int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, |
2466 | u16 list_id, u16 filter_id); | 2467 | u16 list_id, u16 filter_id); |
2467 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); | 2468 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); |