diff options
author | Dan Williams <dcbw@redhat.com> | 2006-01-10 00:56:11 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-12 16:34:24 -0500 |
commit | 9a6301c114aaab1df6de6fad9899bb89852a7592 (patch) | |
tree | 7889afd49f5d4a97434c4bac5995e1828192c96d | |
parent | c213460fd4781c04832c81416532d64ae2bfa88b (diff) |
[PATCH] wireless/atmel: add IWENCODEEXT, IWAUTH, and association event support
This patch allows the Atmel driver to work correctly with wpa_supplicant
and other programs that require some conformance with WEXT-18. It
should not affect current behavior of the driver. The patch does four
things:
1) Implements SIOCSIWENCODEEXT, SIOCGIWENCODEEXT, SIOCSIWAUTH, and
SIOCGIWAUTH calls for unencrypted and WEP operation
2) Accepts zero-filled addresses for SIOCSIWAP, which are legal and
should turn off any previous forced WAP address
3) Sends association and de-association events to userspace at most of
the appropriate times
4) Fixes erroneous order of CIPHER_SUITE_WEP_* arguments in one location
which are actually unused anyway
Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | drivers/net/wireless/atmel.c | 227 |
1 files changed, 223 insertions, 4 deletions
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index e4729ddf29fd..f0ccfef66445 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c | |||
@@ -1407,6 +1407,17 @@ static int atmel_close(struct net_device *dev) | |||
1407 | { | 1407 | { |
1408 | struct atmel_private *priv = netdev_priv(dev); | 1408 | struct atmel_private *priv = netdev_priv(dev); |
1409 | 1409 | ||
1410 | /* Send event to userspace that we are disassociating */ | ||
1411 | if (priv->station_state == STATION_STATE_READY) { | ||
1412 | union iwreq_data wrqu; | ||
1413 | |||
1414 | wrqu.data.length = 0; | ||
1415 | wrqu.data.flags = 0; | ||
1416 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
1417 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
1418 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
1419 | } | ||
1420 | |||
1410 | atmel_enter_state(priv, STATION_STATE_DOWN); | 1421 | atmel_enter_state(priv, STATION_STATE_DOWN); |
1411 | 1422 | ||
1412 | if (priv->bus_type == BUS_TYPE_PCCARD) | 1423 | if (priv->bus_type == BUS_TYPE_PCCARD) |
@@ -1780,10 +1791,10 @@ static int atmel_set_encode(struct net_device *dev, | |||
1780 | priv->wep_is_on = 1; | 1791 | priv->wep_is_on = 1; |
1781 | priv->exclude_unencrypted = 1; | 1792 | priv->exclude_unencrypted = 1; |
1782 | if (priv->wep_key_len[index] > 5) { | 1793 | if (priv->wep_key_len[index] > 5) { |
1783 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | 1794 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; |
1784 | priv->encryption_level = 2; | 1795 | priv->encryption_level = 2; |
1785 | } else { | 1796 | } else { |
1786 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | 1797 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; |
1787 | priv->encryption_level = 1; | 1798 | priv->encryption_level = 1; |
1788 | } | 1799 | } |
1789 | } | 1800 | } |
@@ -1853,6 +1864,181 @@ static int atmel_get_encode(struct net_device *dev, | |||
1853 | return 0; | 1864 | return 0; |
1854 | } | 1865 | } |
1855 | 1866 | ||
1867 | static int atmel_set_encodeext(struct net_device *dev, | ||
1868 | struct iw_request_info *info, | ||
1869 | union iwreq_data *wrqu, | ||
1870 | char *extra) | ||
1871 | { | ||
1872 | struct atmel_private *priv = netdev_priv(dev); | ||
1873 | struct iw_point *encoding = &wrqu->encoding; | ||
1874 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
1875 | int idx, key_len; | ||
1876 | |||
1877 | /* Determine and validate the key index */ | ||
1878 | idx = encoding->flags & IW_ENCODE_INDEX; | ||
1879 | if (idx) { | ||
1880 | if (idx < 1 || idx > WEP_KEYS) | ||
1881 | return -EINVAL; | ||
1882 | idx--; | ||
1883 | } else | ||
1884 | idx = priv->default_key; | ||
1885 | |||
1886 | if ((encoding->flags & IW_ENCODE_DISABLED) || | ||
1887 | ext->alg == IW_ENCODE_ALG_NONE) { | ||
1888 | priv->wep_is_on = 0; | ||
1889 | priv->encryption_level = 0; | ||
1890 | priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | ||
1891 | } | ||
1892 | |||
1893 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) | ||
1894 | priv->default_key = idx; | ||
1895 | |||
1896 | /* Set the requested key */ | ||
1897 | switch (ext->alg) { | ||
1898 | case IW_ENCODE_ALG_NONE: | ||
1899 | break; | ||
1900 | case IW_ENCODE_ALG_WEP: | ||
1901 | if (ext->key_len > 5) { | ||
1902 | priv->wep_key_len[idx] = 13; | ||
1903 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | ||
1904 | priv->encryption_level = 2; | ||
1905 | } else if (ext->key_len > 0) { | ||
1906 | priv->wep_key_len[idx] = 5; | ||
1907 | priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | ||
1908 | priv->encryption_level = 1; | ||
1909 | } else { | ||
1910 | return -EINVAL; | ||
1911 | } | ||
1912 | priv->wep_is_on = 1; | ||
1913 | memset(priv->wep_keys[idx], 0, 13); | ||
1914 | key_len = min ((int)ext->key_len, priv->wep_key_len[idx]); | ||
1915 | memcpy(priv->wep_keys[idx], ext->key, key_len); | ||
1916 | break; | ||
1917 | default: | ||
1918 | return -EINVAL; | ||
1919 | } | ||
1920 | |||
1921 | return -EINPROGRESS; | ||
1922 | } | ||
1923 | |||
1924 | static int atmel_get_encodeext(struct net_device *dev, | ||
1925 | struct iw_request_info *info, | ||
1926 | union iwreq_data *wrqu, | ||
1927 | char *extra) | ||
1928 | { | ||
1929 | struct atmel_private *priv = netdev_priv(dev); | ||
1930 | struct iw_point *encoding = &wrqu->encoding; | ||
1931 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
1932 | int idx, max_key_len; | ||
1933 | |||
1934 | max_key_len = encoding->length - sizeof(*ext); | ||
1935 | if (max_key_len < 0) | ||
1936 | return -EINVAL; | ||
1937 | |||
1938 | idx = encoding->flags & IW_ENCODE_INDEX; | ||
1939 | if (idx) { | ||
1940 | if (idx < 1 || idx > WEP_KEYS) | ||
1941 | return -EINVAL; | ||
1942 | idx--; | ||
1943 | } else | ||
1944 | idx = priv->default_key; | ||
1945 | |||
1946 | encoding->flags = idx + 1; | ||
1947 | memset(ext, 0, sizeof(*ext)); | ||
1948 | |||
1949 | if (!priv->wep_is_on) { | ||
1950 | ext->alg = IW_ENCODE_ALG_NONE; | ||
1951 | ext->key_len = 0; | ||
1952 | encoding->flags |= IW_ENCODE_DISABLED; | ||
1953 | } else { | ||
1954 | if (priv->encryption_level > 0) | ||
1955 | ext->alg = IW_ENCODE_ALG_WEP; | ||
1956 | else | ||
1957 | return -EINVAL; | ||
1958 | |||
1959 | ext->key_len = priv->wep_key_len[idx]; | ||
1960 | memcpy(ext->key, priv->wep_keys[idx], ext->key_len); | ||
1961 | encoding->flags |= IW_ENCODE_ENABLED; | ||
1962 | } | ||
1963 | |||
1964 | return 0; | ||
1965 | } | ||
1966 | |||
1967 | static int atmel_set_auth(struct net_device *dev, | ||
1968 | struct iw_request_info *info, | ||
1969 | union iwreq_data *wrqu, char *extra) | ||
1970 | { | ||
1971 | struct atmel_private *priv = netdev_priv(dev); | ||
1972 | struct iw_param *param = &wrqu->param; | ||
1973 | |||
1974 | switch (param->flags & IW_AUTH_INDEX) { | ||
1975 | case IW_AUTH_WPA_VERSION: | ||
1976 | case IW_AUTH_CIPHER_PAIRWISE: | ||
1977 | case IW_AUTH_CIPHER_GROUP: | ||
1978 | case IW_AUTH_KEY_MGMT: | ||
1979 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
1980 | case IW_AUTH_PRIVACY_INVOKED: | ||
1981 | /* | ||
1982 | * atmel does not use these parameters | ||
1983 | */ | ||
1984 | break; | ||
1985 | |||
1986 | case IW_AUTH_DROP_UNENCRYPTED: | ||
1987 | priv->exclude_unencrypted = param->value ? 1 : 0; | ||
1988 | break; | ||
1989 | |||
1990 | case IW_AUTH_80211_AUTH_ALG: { | ||
1991 | if (param->value & IW_AUTH_ALG_SHARED_KEY) { | ||
1992 | priv->exclude_unencrypted = 1; | ||
1993 | } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { | ||
1994 | priv->exclude_unencrypted = 0; | ||
1995 | } else | ||
1996 | return -EINVAL; | ||
1997 | break; | ||
1998 | } | ||
1999 | |||
2000 | case IW_AUTH_WPA_ENABLED: | ||
2001 | /* Silently accept disable of WPA */ | ||
2002 | if (param->value > 0) | ||
2003 | return -EOPNOTSUPP; | ||
2004 | break; | ||
2005 | |||
2006 | default: | ||
2007 | return -EOPNOTSUPP; | ||
2008 | } | ||
2009 | return -EINPROGRESS; | ||
2010 | } | ||
2011 | |||
2012 | static int atmel_get_auth(struct net_device *dev, | ||
2013 | struct iw_request_info *info, | ||
2014 | union iwreq_data *wrqu, char *extra) | ||
2015 | { | ||
2016 | struct atmel_private *priv = netdev_priv(dev); | ||
2017 | struct iw_param *param = &wrqu->param; | ||
2018 | |||
2019 | switch (param->flags & IW_AUTH_INDEX) { | ||
2020 | case IW_AUTH_DROP_UNENCRYPTED: | ||
2021 | param->value = priv->exclude_unencrypted; | ||
2022 | break; | ||
2023 | |||
2024 | case IW_AUTH_80211_AUTH_ALG: | ||
2025 | if (priv->exclude_unencrypted == 1) | ||
2026 | param->value = IW_AUTH_ALG_SHARED_KEY; | ||
2027 | else | ||
2028 | param->value = IW_AUTH_ALG_OPEN_SYSTEM; | ||
2029 | break; | ||
2030 | |||
2031 | case IW_AUTH_WPA_ENABLED: | ||
2032 | param->value = 0; | ||
2033 | break; | ||
2034 | |||
2035 | default: | ||
2036 | return -EOPNOTSUPP; | ||
2037 | } | ||
2038 | return 0; | ||
2039 | } | ||
2040 | |||
2041 | |||
1856 | static int atmel_get_name(struct net_device *dev, | 2042 | static int atmel_get_name(struct net_device *dev, |
1857 | struct iw_request_info *info, | 2043 | struct iw_request_info *info, |
1858 | char *cwrq, | 2044 | char *cwrq, |
@@ -2289,13 +2475,15 @@ static int atmel_set_wap(struct net_device *dev, | |||
2289 | { | 2475 | { |
2290 | struct atmel_private *priv = netdev_priv(dev); | 2476 | struct atmel_private *priv = netdev_priv(dev); |
2291 | int i; | 2477 | int i; |
2292 | static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 }; | 2478 | static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
2479 | static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
2293 | unsigned long flags; | 2480 | unsigned long flags; |
2294 | 2481 | ||
2295 | if (awrq->sa_family != ARPHRD_ETHER) | 2482 | if (awrq->sa_family != ARPHRD_ETHER) |
2296 | return -EINVAL; | 2483 | return -EINVAL; |
2297 | 2484 | ||
2298 | if (memcmp(bcast, awrq->sa_data, 6) == 0) { | 2485 | if (!memcmp(any, awrq->sa_data, 6) || |
2486 | !memcmp(off, awrq->sa_data, 6)) { | ||
2299 | del_timer_sync(&priv->management_timer); | 2487 | del_timer_sync(&priv->management_timer); |
2300 | spin_lock_irqsave(&priv->irqlock, flags); | 2488 | spin_lock_irqsave(&priv->irqlock, flags); |
2301 | atmel_scan(priv, 1); | 2489 | atmel_scan(priv, 1); |
@@ -2378,6 +2566,15 @@ static const iw_handler atmel_handler[] = | |||
2378 | (iw_handler) atmel_get_encode, /* SIOCGIWENCODE */ | 2566 | (iw_handler) atmel_get_encode, /* SIOCGIWENCODE */ |
2379 | (iw_handler) atmel_set_power, /* SIOCSIWPOWER */ | 2567 | (iw_handler) atmel_set_power, /* SIOCSIWPOWER */ |
2380 | (iw_handler) atmel_get_power, /* SIOCGIWPOWER */ | 2568 | (iw_handler) atmel_get_power, /* SIOCGIWPOWER */ |
2569 | (iw_handler) NULL, /* -- hole -- */ | ||
2570 | (iw_handler) NULL, /* -- hole -- */ | ||
2571 | (iw_handler) NULL, /* SIOCSIWGENIE */ | ||
2572 | (iw_handler) NULL, /* SIOCGIWGENIE */ | ||
2573 | (iw_handler) atmel_set_auth, /* SIOCSIWAUTH */ | ||
2574 | (iw_handler) atmel_get_auth, /* SIOCGIWAUTH */ | ||
2575 | (iw_handler) atmel_set_encodeext, /* SIOCSIWENCODEEXT */ | ||
2576 | (iw_handler) atmel_get_encodeext, /* SIOCGIWENCODEEXT */ | ||
2577 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | ||
2381 | }; | 2578 | }; |
2382 | 2579 | ||
2383 | static const iw_handler atmel_private_handler[] = | 2580 | static const iw_handler atmel_private_handler[] = |
@@ -2924,6 +3121,8 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) | |||
2924 | u16 ass_id = le16_to_cpu(ass_resp->ass_id); | 3121 | u16 ass_id = le16_to_cpu(ass_resp->ass_id); |
2925 | u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; | 3122 | u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; |
2926 | 3123 | ||
3124 | union iwreq_data wrqu; | ||
3125 | |||
2927 | if (frame_len < 8 + rates_len) | 3126 | if (frame_len < 8 + rates_len) |
2928 | return; | 3127 | return; |
2929 | 3128 | ||
@@ -2954,6 +3153,14 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) | |||
2954 | priv->station_is_associated = 1; | 3153 | priv->station_is_associated = 1; |
2955 | priv->station_was_associated = 1; | 3154 | priv->station_was_associated = 1; |
2956 | atmel_enter_state(priv, STATION_STATE_READY); | 3155 | atmel_enter_state(priv, STATION_STATE_READY); |
3156 | |||
3157 | /* Send association event to userspace */ | ||
3158 | wrqu.data.length = 0; | ||
3159 | wrqu.data.flags = 0; | ||
3160 | memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN); | ||
3161 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
3162 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
3163 | |||
2957 | return; | 3164 | return; |
2958 | } | 3165 | } |
2959 | 3166 | ||
@@ -3632,6 +3839,7 @@ static int reset_atmel_card(struct net_device *dev) | |||
3632 | 3839 | ||
3633 | struct atmel_private *priv = netdev_priv(dev); | 3840 | struct atmel_private *priv = netdev_priv(dev); |
3634 | u8 configuration; | 3841 | u8 configuration; |
3842 | int old_state = priv->station_state; | ||
3635 | 3843 | ||
3636 | /* data to add to the firmware names, in priority order | 3844 | /* data to add to the firmware names, in priority order |
3637 | this implemenents firmware versioning */ | 3845 | this implemenents firmware versioning */ |
@@ -3792,6 +4000,17 @@ static int reset_atmel_card(struct net_device *dev) | |||
3792 | else | 4000 | else |
3793 | build_wep_mib(priv); | 4001 | build_wep_mib(priv); |
3794 | 4002 | ||
4003 | if (old_state == STATION_STATE_READY) | ||
4004 | { | ||
4005 | union iwreq_data wrqu; | ||
4006 | |||
4007 | wrqu.data.length = 0; | ||
4008 | wrqu.data.flags = 0; | ||
4009 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
4010 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
4011 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
4012 | } | ||
4013 | |||
3795 | return 1; | 4014 | return 1; |
3796 | } | 4015 | } |
3797 | 4016 | ||