diff options
author | Raja Mani <rmani@qca.qualcomm.com> | 2012-01-30 06:43:10 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2012-01-30 14:22:55 -0500 |
commit | d91e8eee046e0d4ae7a8a585616b5ce800f54568 (patch) | |
tree | f46dbb45d0b8d8e7f837e48c0926ffb470d381e0 /drivers | |
parent | e390af779dc671551800514d391928f5a798089a (diff) |
ath6kl: Configure WOW patterns while going to wow_suspend
First preference is given to the user configured WOW patterns.
If the user doesn't configure any patterns (for ex, via iw command),
the default patterns will be configured based on the current mode
(vif->nw_type) while going to WOW suspend.
Summary of changes:
* ath6kl_wow_ap() is added to configure the below default
patterns when the system enters into WOW suspend in AP mode.
+ Unicast IP, EAPOL-like and ARP packet pattern
+ ARP packet pattern
+ mDNS/SSDP/LLMNR pattern
+ DHCP broadcast pattern
* ath6kl_wow_sta() is added to configure the below default
patterns when the system enters into WOW suspend in STA mode.
+ Unicast packet pattern
+ mDNS/SSDP/LLMNR pattern
* Move the user provided WOW patterns configuration code
from ath6kl_wow_suspend() to a separate function called
ath6kl_wow_usr().
* Two argument variable's ('filter' and 'mask) data type in
ath6kl_wmi_add_wow_pattern_cmd() are changed from 'u8 *' to
'const u8 *'. This is needed to make all pattern and mask
arrays to be 'static const u8' in the caller function.
* New conditional check is added to make sure user
configured pattern count is within the limit (WOW_MAX_FILTERS_PER_LIST).
Signed-off-by: Raja Mani <rmani@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers')
-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); |