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 | ||
