diff options
author | Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 2009-08-28 06:27:47 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-28 14:40:58 -0400 |
commit | 5c52323e8c44a06183052986dbd028ce15622166 (patch) | |
tree | df0cd094ba83e2b93f1a1753b1da12092af7e55c /drivers/net/wireless/rndis_wlan.c | |
parent | 9f77ccab57534f45b0289ceae3a6b85478d14182 (diff) |
rndis_wlan: add cfg80211 connect, disconnect, join_ibss and leave_ibss
Add cfg80211 connect functions for station and ad-hoc modes and
convert wext to use theim.
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.c | 669 |
1 files changed, 460 insertions, 209 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c5a674d8d1fb..c2af5be35d39 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -358,13 +358,6 @@ struct ndis_80211_assoc_info { | |||
358 | __le32 offset_resp_ies; | 358 | __le32 offset_resp_ies; |
359 | } __attribute__((packed)); | 359 | } __attribute__((packed)); |
360 | 360 | ||
361 | /* these have to match what is in wpa_supplicant */ | ||
362 | enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP }; | ||
363 | enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, | ||
364 | CIPHER_WEP104 }; | ||
365 | enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, | ||
366 | KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE }; | ||
367 | |||
368 | /* | 361 | /* |
369 | * private data | 362 | * private data |
370 | */ | 363 | */ |
@@ -379,6 +372,15 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, | |||
379 | #define WORK_LINK_DOWN (1<<1) | 372 | #define WORK_LINK_DOWN (1<<1) |
380 | #define WORK_SET_MULTICAST_LIST (1<<2) | 373 | #define WORK_SET_MULTICAST_LIST (1<<2) |
381 | 374 | ||
375 | #define RNDIS_WLAN_ALG_NONE 0 | ||
376 | #define RNDIS_WLAN_ALG_WEP (1<<0) | ||
377 | #define RNDIS_WLAN_ALG_TKIP (1<<1) | ||
378 | #define RNDIS_WLAN_ALG_CCMP (1<<2) | ||
379 | |||
380 | #define RNDIS_WLAN_KEY_MGMT_NONE 0 | ||
381 | #define RNDIS_WLAN_KEY_MGMT_802_1X (1<<0) | ||
382 | #define RNDIS_WLAN_KEY_MGMT_PSK (1<<1) | ||
383 | |||
382 | #define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) | 384 | #define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) |
383 | 385 | ||
384 | static const struct ieee80211_channel rndis_channels[] = { | 386 | static const struct ieee80211_channel rndis_channels[] = { |
@@ -469,15 +471,16 @@ struct rndis_wlan_private { | |||
469 | /* hardware state */ | 471 | /* hardware state */ |
470 | int radio_on; | 472 | int radio_on; |
471 | int infra_mode; | 473 | int infra_mode; |
474 | bool connected; | ||
472 | struct ndis_80211_ssid essid; | 475 | struct ndis_80211_ssid essid; |
473 | __le32 current_command_oid; | 476 | __le32 current_command_oid; |
474 | 477 | ||
475 | /* encryption stuff */ | 478 | /* encryption stuff */ |
476 | int encr_tx_key_index; | 479 | int encr_tx_key_index; |
477 | struct rndis_wlan_encr_key encr_keys[4]; | 480 | struct rndis_wlan_encr_key encr_keys[4]; |
481 | enum nl80211_auth_type wpa_auth_type; | ||
478 | int wpa_version; | 482 | int wpa_version; |
479 | int wpa_keymgmt; | 483 | int wpa_keymgmt; |
480 | int wpa_authalg; | ||
481 | int wpa_ie_len; | 484 | int wpa_ie_len; |
482 | u8 *wpa_ie; | 485 | u8 *wpa_ie; |
483 | int wpa_cipher_pair; | 486 | int wpa_cipher_pair; |
@@ -503,12 +506,27 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, | |||
503 | int dbm); | 506 | int dbm); |
504 | static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); | 507 | static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); |
505 | 508 | ||
509 | static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, | ||
510 | struct cfg80211_connect_params *sme); | ||
511 | |||
512 | static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, | ||
513 | u16 reason_code); | ||
514 | |||
515 | static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
516 | struct cfg80211_ibss_params *params); | ||
517 | |||
518 | static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); | ||
519 | |||
506 | static struct cfg80211_ops rndis_config_ops = { | 520 | static struct cfg80211_ops rndis_config_ops = { |
507 | .change_virtual_intf = rndis_change_virtual_intf, | 521 | .change_virtual_intf = rndis_change_virtual_intf, |
508 | .scan = rndis_scan, | 522 | .scan = rndis_scan, |
509 | .set_wiphy_params = rndis_set_wiphy_params, | 523 | .set_wiphy_params = rndis_set_wiphy_params, |
510 | .set_tx_power = rndis_set_tx_power, | 524 | .set_tx_power = rndis_set_tx_power, |
511 | .get_tx_power = rndis_get_tx_power, | 525 | .get_tx_power = rndis_get_tx_power, |
526 | .connect = rndis_connect, | ||
527 | .disconnect = rndis_disconnect, | ||
528 | .join_ibss = rndis_join_ibss, | ||
529 | .leave_ibss = rndis_leave_ibss, | ||
512 | }; | 530 | }; |
513 | 531 | ||
514 | static void *rndis_wiphy_privid = &rndis_wiphy_privid; | 532 | static void *rndis_wiphy_privid = &rndis_wiphy_privid; |
@@ -545,6 +563,34 @@ static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) | |||
545 | } | 563 | } |
546 | 564 | ||
547 | 565 | ||
566 | static int rndis_cipher_to_alg(u32 cipher) | ||
567 | { | ||
568 | switch (cipher) { | ||
569 | default: | ||
570 | return RNDIS_WLAN_ALG_NONE; | ||
571 | case WLAN_CIPHER_SUITE_WEP40: | ||
572 | case WLAN_CIPHER_SUITE_WEP104: | ||
573 | return RNDIS_WLAN_ALG_WEP; | ||
574 | case WLAN_CIPHER_SUITE_TKIP: | ||
575 | return RNDIS_WLAN_ALG_TKIP; | ||
576 | case WLAN_CIPHER_SUITE_CCMP: | ||
577 | return RNDIS_WLAN_ALG_CCMP; | ||
578 | } | ||
579 | } | ||
580 | |||
581 | static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) | ||
582 | { | ||
583 | switch (akm_suite) { | ||
584 | default: | ||
585 | return RNDIS_WLAN_KEY_MGMT_NONE; | ||
586 | case WLAN_AKM_SUITE_8021X: | ||
587 | return RNDIS_WLAN_KEY_MGMT_802_1X; | ||
588 | case WLAN_AKM_SUITE_PSK: | ||
589 | return RNDIS_WLAN_KEY_MGMT_PSK; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | |||
548 | #ifdef DEBUG | 594 | #ifdef DEBUG |
549 | static const char *oid_to_string(__le32 oid) | 595 | static const char *oid_to_string(__le32 oid) |
550 | { | 596 | { |
@@ -925,35 +971,16 @@ static int set_infra_mode(struct usbnet *usbdev, int mode); | |||
925 | static void restore_keys(struct usbnet *usbdev); | 971 | static void restore_keys(struct usbnet *usbdev); |
926 | static int rndis_check_bssid_list(struct usbnet *usbdev); | 972 | static int rndis_check_bssid_list(struct usbnet *usbdev); |
927 | 973 | ||
928 | static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) | ||
929 | { | ||
930 | int ret, len; | ||
931 | |||
932 | len = sizeof(*ssid); | ||
933 | ret = rndis_query_oid(usbdev, OID_802_11_SSID, ssid, &len); | ||
934 | |||
935 | if (ret != 0) | ||
936 | ssid->length = 0; | ||
937 | |||
938 | #ifdef DEBUG | ||
939 | { | ||
940 | unsigned char tmp[NDIS_802_11_LENGTH_SSID + 1]; | ||
941 | |||
942 | memcpy(tmp, ssid->essid, le32_to_cpu(ssid->length)); | ||
943 | tmp[le32_to_cpu(ssid->length)] = 0; | ||
944 | devdbg(usbdev, "get_essid: '%s', ret: %d", tmp, ret); | ||
945 | } | ||
946 | #endif | ||
947 | return ret; | ||
948 | } | ||
949 | |||
950 | |||
951 | static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) | 974 | static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) |
952 | { | 975 | { |
953 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 976 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
954 | int ret; | 977 | int ret; |
955 | 978 | ||
956 | ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); | 979 | ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); |
980 | if (ret < 0) { | ||
981 | devwarn(usbdev, "setting SSID failed (%08X)", ret); | ||
982 | return ret; | ||
983 | } | ||
957 | if (ret == 0) { | 984 | if (ret == 0) { |
958 | memcpy(&priv->essid, ssid, sizeof(priv->essid)); | 985 | memcpy(&priv->essid, ssid, sizeof(priv->essid)); |
959 | priv->radio_on = 1; | 986 | priv->radio_on = 1; |
@@ -963,6 +990,25 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) | |||
963 | return ret; | 990 | return ret; |
964 | } | 991 | } |
965 | 992 | ||
993 | static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) | ||
994 | { | ||
995 | int ret; | ||
996 | |||
997 | ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); | ||
998 | if (ret < 0) { | ||
999 | devwarn(usbdev, "setting BSSID[%pM] failed (%08X)", bssid, ret); | ||
1000 | return ret; | ||
1001 | } | ||
1002 | |||
1003 | return ret; | ||
1004 | } | ||
1005 | |||
1006 | static int clear_bssid(struct usbnet *usbdev) | ||
1007 | { | ||
1008 | u8 broadcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
1009 | |||
1010 | return set_bssid(usbdev, broadcast_mac); | ||
1011 | } | ||
966 | 1012 | ||
967 | static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) | 1013 | static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) |
968 | { | 1014 | { |
@@ -984,11 +1030,15 @@ static int get_association_info(struct usbnet *usbdev, | |||
984 | info, &len); | 1030 | info, &len); |
985 | } | 1031 | } |
986 | 1032 | ||
987 | static int is_associated(struct usbnet *usbdev) | 1033 | static bool is_associated(struct usbnet *usbdev) |
988 | { | 1034 | { |
1035 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
989 | u8 bssid[ETH_ALEN]; | 1036 | u8 bssid[ETH_ALEN]; |
990 | int ret; | 1037 | int ret; |
991 | 1038 | ||
1039 | if (!priv->radio_on) | ||
1040 | return false; | ||
1041 | |||
992 | ret = get_bssid(usbdev, bssid); | 1042 | ret = get_bssid(usbdev, bssid); |
993 | 1043 | ||
994 | return (ret == 0 && !is_zero_ether_addr(bssid)); | 1044 | return (ret == 0 && !is_zero_ether_addr(bssid)); |
@@ -1032,34 +1082,34 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) | |||
1032 | } | 1082 | } |
1033 | 1083 | ||
1034 | 1084 | ||
1035 | static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) | 1085 | static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, |
1086 | enum nl80211_auth_type auth_type, int keymgmt) | ||
1036 | { | 1087 | { |
1037 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 1088 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
1038 | __le32 tmp; | 1089 | __le32 tmp; |
1039 | int auth_mode, ret; | 1090 | int auth_mode, ret; |
1040 | 1091 | ||
1041 | devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x " | 1092 | devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x " |
1042 | "keymgmt=0x%x", wpa_version, authalg, priv->wpa_keymgmt); | 1093 | "keymgmt=0x%x", wpa_version, auth_type, keymgmt); |
1043 | 1094 | ||
1044 | if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { | 1095 | if (wpa_version & NL80211_WPA_VERSION_2) { |
1045 | if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) | 1096 | if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) |
1046 | auth_mode = NDIS_80211_AUTH_WPA2; | 1097 | auth_mode = NDIS_80211_AUTH_WPA2; |
1047 | else | 1098 | else |
1048 | auth_mode = NDIS_80211_AUTH_WPA2_PSK; | 1099 | auth_mode = NDIS_80211_AUTH_WPA2_PSK; |
1049 | } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { | 1100 | } else if (wpa_version & NL80211_WPA_VERSION_1) { |
1050 | if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) | 1101 | if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) |
1051 | auth_mode = NDIS_80211_AUTH_WPA; | 1102 | auth_mode = NDIS_80211_AUTH_WPA; |
1052 | else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK) | 1103 | else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK) |
1053 | auth_mode = NDIS_80211_AUTH_WPA_PSK; | 1104 | auth_mode = NDIS_80211_AUTH_WPA_PSK; |
1054 | else | 1105 | else |
1055 | auth_mode = NDIS_80211_AUTH_WPA_NONE; | 1106 | auth_mode = NDIS_80211_AUTH_WPA_NONE; |
1056 | } else if (authalg & IW_AUTH_ALG_SHARED_KEY) { | 1107 | } else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) |
1057 | if (authalg & IW_AUTH_ALG_OPEN_SYSTEM) | 1108 | auth_mode = NDIS_80211_AUTH_SHARED; |
1058 | auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; | 1109 | else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) |
1059 | else | ||
1060 | auth_mode = NDIS_80211_AUTH_SHARED; | ||
1061 | } else | ||
1062 | auth_mode = NDIS_80211_AUTH_OPEN; | 1110 | auth_mode = NDIS_80211_AUTH_OPEN; |
1111 | else | ||
1112 | return -ENOTSUPP; | ||
1063 | 1113 | ||
1064 | tmp = cpu_to_le32(auth_mode); | 1114 | tmp = cpu_to_le32(auth_mode); |
1065 | ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, | 1115 | ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, |
@@ -1070,7 +1120,9 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) | |||
1070 | } | 1120 | } |
1071 | 1121 | ||
1072 | priv->wpa_version = wpa_version; | 1122 | priv->wpa_version = wpa_version; |
1073 | priv->wpa_authalg = authalg; | 1123 | priv->wpa_auth_type = auth_type; |
1124 | priv->wpa_keymgmt = keymgmt; | ||
1125 | |||
1074 | return 0; | 1126 | return 0; |
1075 | } | 1127 | } |
1076 | 1128 | ||
@@ -1082,8 +1134,8 @@ static int set_priv_filter(struct usbnet *usbdev) | |||
1082 | 1134 | ||
1083 | devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); | 1135 | devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); |
1084 | 1136 | ||
1085 | if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 || | 1137 | if (priv->wpa_version & NL80211_WPA_VERSION_2 || |
1086 | priv->wpa_version & IW_AUTH_WPA_VERSION_WPA) | 1138 | priv->wpa_version & NL80211_WPA_VERSION_1) |
1087 | tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); | 1139 | tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); |
1088 | else | 1140 | else |
1089 | tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); | 1141 | tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); |
@@ -1100,19 +1152,17 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) | |||
1100 | int encr_mode, ret; | 1152 | int encr_mode, ret; |
1101 | 1153 | ||
1102 | devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x", | 1154 | devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x", |
1103 | pairwise, | 1155 | pairwise, groupwise); |
1104 | groupwise); | ||
1105 | 1156 | ||
1106 | if (pairwise & IW_AUTH_CIPHER_CCMP) | 1157 | if (pairwise & RNDIS_WLAN_ALG_CCMP) |
1107 | encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; | 1158 | encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; |
1108 | else if (pairwise & IW_AUTH_CIPHER_TKIP) | 1159 | else if (pairwise & RNDIS_WLAN_ALG_TKIP) |
1109 | encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; | 1160 | encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; |
1110 | else if (pairwise & | 1161 | else if (pairwise & RNDIS_WLAN_ALG_WEP) |
1111 | (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) | ||
1112 | encr_mode = NDIS_80211_ENCR_WEP_ENABLED; | 1162 | encr_mode = NDIS_80211_ENCR_WEP_ENABLED; |
1113 | else if (groupwise & IW_AUTH_CIPHER_CCMP) | 1163 | else if (groupwise & RNDIS_WLAN_ALG_CCMP) |
1114 | encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; | 1164 | encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; |
1115 | else if (groupwise & IW_AUTH_CIPHER_TKIP) | 1165 | else if (groupwise & RNDIS_WLAN_ALG_TKIP) |
1116 | encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; | 1166 | encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; |
1117 | else | 1167 | else |
1118 | encr_mode = NDIS_80211_ENCR_DISABLED; | 1168 | encr_mode = NDIS_80211_ENCR_DISABLED; |
@@ -1131,18 +1181,6 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) | |||
1131 | } | 1181 | } |
1132 | 1182 | ||
1133 | 1183 | ||
1134 | static int set_assoc_params(struct usbnet *usbdev) | ||
1135 | { | ||
1136 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
1137 | |||
1138 | set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg); | ||
1139 | set_priv_filter(usbdev); | ||
1140 | set_encr_mode(usbdev, priv->wpa_cipher_pair, priv->wpa_cipher_group); | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | |||
1146 | static int set_infra_mode(struct usbnet *usbdev, int mode) | 1184 | static int set_infra_mode(struct usbnet *usbdev, int mode) |
1147 | { | 1185 | { |
1148 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 1186 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
@@ -1201,16 +1239,11 @@ static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) | |||
1201 | 1239 | ||
1202 | static void set_default_iw_params(struct usbnet *usbdev) | 1240 | static void set_default_iw_params(struct usbnet *usbdev) |
1203 | { | 1241 | { |
1204 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
1205 | |||
1206 | priv->wpa_keymgmt = 0; | ||
1207 | priv->wpa_version = 0; | ||
1208 | |||
1209 | set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); | 1242 | set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); |
1210 | set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, | 1243 | set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, |
1211 | IW_AUTH_ALG_OPEN_SYSTEM); | 1244 | RNDIS_WLAN_KEY_MGMT_NONE); |
1212 | set_priv_filter(usbdev); | 1245 | set_priv_filter(usbdev); |
1213 | set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); | 1246 | set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); |
1214 | } | 1247 | } |
1215 | 1248 | ||
1216 | 1249 | ||
@@ -1224,8 +1257,40 @@ static int deauthenticate(struct usbnet *usbdev) | |||
1224 | } | 1257 | } |
1225 | 1258 | ||
1226 | 1259 | ||
1260 | static int set_channel(struct usbnet *usbdev, int channel) | ||
1261 | { | ||
1262 | struct ndis_80211_conf config; | ||
1263 | unsigned int dsconfig; | ||
1264 | int len, ret; | ||
1265 | |||
1266 | devdbg(usbdev, "set_channel(%d)", channel); | ||
1267 | |||
1268 | /* this OID is valid only when not associated */ | ||
1269 | if (is_associated(usbdev)) | ||
1270 | return 0; | ||
1271 | |||
1272 | dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000; | ||
1273 | |||
1274 | len = sizeof(config); | ||
1275 | ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); | ||
1276 | if (ret < 0) { | ||
1277 | devdbg(usbdev, "set_channel: querying configuration failed"); | ||
1278 | return ret; | ||
1279 | } | ||
1280 | |||
1281 | config.ds_config = cpu_to_le32(dsconfig); | ||
1282 | ret = rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config, | ||
1283 | sizeof(config)); | ||
1284 | |||
1285 | devdbg(usbdev, "set_channel: %d -> %d", channel, ret); | ||
1286 | |||
1287 | return ret; | ||
1288 | } | ||
1289 | |||
1290 | |||
1227 | /* index must be 0 - N, as per NDIS */ | 1291 | /* index must be 0 - N, as per NDIS */ |
1228 | static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) | 1292 | static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, |
1293 | int index) | ||
1229 | { | 1294 | { |
1230 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 1295 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
1231 | struct ndis_80211_wep_key ndis_key; | 1296 | struct ndis_80211_wep_key ndis_key; |
@@ -1248,8 +1313,8 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) | |||
1248 | 1313 | ||
1249 | if (index == priv->encr_tx_key_index) { | 1314 | if (index == priv->encr_tx_key_index) { |
1250 | ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; | 1315 | ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; |
1251 | ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, | 1316 | ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP, |
1252 | IW_AUTH_CIPHER_NONE); | 1317 | RNDIS_WLAN_ALG_NONE); |
1253 | if (ret) | 1318 | if (ret) |
1254 | devwarn(usbdev, "encryption couldn't be enabled (%08X)", | 1319 | devwarn(usbdev, "encryption couldn't be enabled (%08X)", |
1255 | ret); | 1320 | ret); |
@@ -1458,7 +1523,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) | |||
1458 | 1523 | ||
1459 | /* if it is transmit key, disable encryption */ | 1524 | /* if it is transmit key, disable encryption */ |
1460 | if (index == priv->encr_tx_key_index) | 1525 | if (index == priv->encr_tx_key_index) |
1461 | set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); | 1526 | set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); |
1462 | 1527 | ||
1463 | return 0; | 1528 | return 0; |
1464 | } | 1529 | } |
@@ -1765,6 +1830,243 @@ static void rndis_get_scan_results(struct work_struct *work) | |||
1765 | priv->scan_request = NULL; | 1830 | priv->scan_request = NULL; |
1766 | } | 1831 | } |
1767 | 1832 | ||
1833 | static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, | ||
1834 | struct cfg80211_connect_params *sme) | ||
1835 | { | ||
1836 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | ||
1837 | struct usbnet *usbdev = priv->usbdev; | ||
1838 | struct ieee80211_channel *channel = sme->channel; | ||
1839 | struct ndis_80211_ssid ssid; | ||
1840 | int pairwise = RNDIS_WLAN_ALG_NONE; | ||
1841 | int groupwise = RNDIS_WLAN_ALG_NONE; | ||
1842 | int keymgmt = RNDIS_WLAN_KEY_MGMT_NONE; | ||
1843 | int length, i, ret, chan = -1; | ||
1844 | |||
1845 | if (channel) | ||
1846 | chan = ieee80211_frequency_to_channel(channel->center_freq); | ||
1847 | |||
1848 | groupwise = rndis_cipher_to_alg(sme->crypto.cipher_group); | ||
1849 | for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) | ||
1850 | pairwise |= | ||
1851 | rndis_cipher_to_alg(sme->crypto.ciphers_pairwise[i]); | ||
1852 | |||
1853 | if (sme->crypto.n_ciphers_pairwise > 0 && | ||
1854 | pairwise == RNDIS_WLAN_ALG_NONE) { | ||
1855 | deverr(usbdev, "Unsupported pairwise cipher"); | ||
1856 | return -ENOTSUPP; | ||
1857 | } | ||
1858 | |||
1859 | for (i = 0; i < sme->crypto.n_akm_suites; i++) | ||
1860 | keymgmt |= | ||
1861 | rndis_akm_suite_to_key_mgmt(sme->crypto.akm_suites[i]); | ||
1862 | |||
1863 | if (sme->crypto.n_akm_suites > 0 && | ||
1864 | keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) { | ||
1865 | deverr(usbdev, "Invalid keymgmt"); | ||
1866 | return -ENOTSUPP; | ||
1867 | } | ||
1868 | |||
1869 | devdbg(usbdev, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:" | ||
1870 | "0x%x]:0x%x)", sme->ssid, sme->bssid, chan, | ||
1871 | sme->privacy, sme->crypto.wpa_versions, sme->auth_type, | ||
1872 | groupwise, pairwise, keymgmt); | ||
1873 | |||
1874 | if (is_associated(usbdev)) | ||
1875 | disassociate(usbdev, false); | ||
1876 | |||
1877 | ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); | ||
1878 | if (ret < 0) { | ||
1879 | devdbg(usbdev, "connect: set_infra_mode failed, %d", ret); | ||
1880 | goto err_turn_radio_on; | ||
1881 | } | ||
1882 | |||
1883 | ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type, | ||
1884 | keymgmt); | ||
1885 | if (ret < 0) { | ||
1886 | devdbg(usbdev, "connect: set_auth_mode failed, %d", ret); | ||
1887 | goto err_turn_radio_on; | ||
1888 | } | ||
1889 | |||
1890 | set_priv_filter(usbdev); | ||
1891 | |||
1892 | ret = set_encr_mode(usbdev, pairwise, groupwise); | ||
1893 | if (ret < 0) { | ||
1894 | devdbg(usbdev, "connect: set_encr_mode failed, %d", ret); | ||
1895 | goto err_turn_radio_on; | ||
1896 | } | ||
1897 | |||
1898 | if (channel) { | ||
1899 | ret = set_channel(usbdev, chan); | ||
1900 | if (ret < 0) { | ||
1901 | devdbg(usbdev, "connect: set_channel failed, %d", ret); | ||
1902 | goto err_turn_radio_on; | ||
1903 | } | ||
1904 | } | ||
1905 | |||
1906 | if (sme->key && ((groupwise | pairwise) & RNDIS_WLAN_ALG_WEP)) { | ||
1907 | priv->encr_tx_key_index = sme->key_idx; | ||
1908 | ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx); | ||
1909 | if (ret < 0) { | ||
1910 | devdbg(usbdev, "connect: add_wep_key failed, %d " | ||
1911 | "(%d, %d)", ret, sme->key_len, sme->key_idx); | ||
1912 | goto err_turn_radio_on; | ||
1913 | } | ||
1914 | } | ||
1915 | |||
1916 | if (sme->bssid && !is_zero_ether_addr(sme->bssid) && | ||
1917 | !is_broadcast_ether_addr(sme->bssid)) { | ||
1918 | ret = set_bssid(usbdev, sme->bssid); | ||
1919 | if (ret < 0) { | ||
1920 | devdbg(usbdev, "connect: set_bssid failed, %d", ret); | ||
1921 | goto err_turn_radio_on; | ||
1922 | } | ||
1923 | } else | ||
1924 | clear_bssid(usbdev); | ||
1925 | |||
1926 | length = sme->ssid_len; | ||
1927 | if (length > NDIS_802_11_LENGTH_SSID) | ||
1928 | length = NDIS_802_11_LENGTH_SSID; | ||
1929 | |||
1930 | memset(&ssid, 0, sizeof(ssid)); | ||
1931 | ssid.length = cpu_to_le32(length); | ||
1932 | memcpy(ssid.essid, sme->ssid, length); | ||
1933 | |||
1934 | /* Pause and purge rx queue, so we don't pass packets before | ||
1935 | * 'media connect'-indication. | ||
1936 | */ | ||
1937 | usbnet_pause_rx(usbdev); | ||
1938 | usbnet_purge_paused_rxq(usbdev); | ||
1939 | |||
1940 | ret = set_essid(usbdev, &ssid); | ||
1941 | if (ret < 0) | ||
1942 | devdbg(usbdev, "connect: set_essid failed, %d", ret); | ||
1943 | return ret; | ||
1944 | |||
1945 | err_turn_radio_on: | ||
1946 | disassociate(usbdev, 1); | ||
1947 | |||
1948 | return ret; | ||
1949 | } | ||
1950 | |||
1951 | static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, | ||
1952 | u16 reason_code) | ||
1953 | { | ||
1954 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | ||
1955 | struct usbnet *usbdev = priv->usbdev; | ||
1956 | |||
1957 | devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code); | ||
1958 | |||
1959 | priv->connected = false; | ||
1960 | |||
1961 | return deauthenticate(usbdev); | ||
1962 | } | ||
1963 | |||
1964 | static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
1965 | struct cfg80211_ibss_params *params) | ||
1966 | { | ||
1967 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | ||
1968 | struct usbnet *usbdev = priv->usbdev; | ||
1969 | struct ieee80211_channel *channel = params->channel; | ||
1970 | struct ndis_80211_ssid ssid; | ||
1971 | enum nl80211_auth_type auth_type; | ||
1972 | int ret, alg, length, chan = -1; | ||
1973 | |||
1974 | if (channel) | ||
1975 | chan = ieee80211_frequency_to_channel(channel->center_freq); | ||
1976 | |||
1977 | /* TODO: How to handle ad-hoc encryption? | ||
1978 | * connect() has *key, join_ibss() doesn't. RNDIS requires key to be | ||
1979 | * pre-shared for encryption (open/shared/wpa), is key set before | ||
1980 | * join_ibss? Which auth_type to use (not in params)? What about WPA? | ||
1981 | */ | ||
1982 | if (params->privacy) { | ||
1983 | auth_type = NL80211_AUTHTYPE_SHARED_KEY; | ||
1984 | alg = RNDIS_WLAN_ALG_WEP; | ||
1985 | } else { | ||
1986 | auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
1987 | alg = RNDIS_WLAN_ALG_NONE; | ||
1988 | } | ||
1989 | |||
1990 | devdbg(usbdev, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)", params->ssid, | ||
1991 | params->bssid, chan, params->privacy); | ||
1992 | |||
1993 | if (is_associated(usbdev)) | ||
1994 | disassociate(usbdev, false); | ||
1995 | |||
1996 | ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC); | ||
1997 | if (ret < 0) { | ||
1998 | devdbg(usbdev, "join_ibss: set_infra_mode failed, %d", ret); | ||
1999 | goto err_turn_radio_on; | ||
2000 | } | ||
2001 | |||
2002 | ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE); | ||
2003 | if (ret < 0) { | ||
2004 | devdbg(usbdev, "join_ibss: set_auth_mode failed, %d", ret); | ||
2005 | goto err_turn_radio_on; | ||
2006 | } | ||
2007 | |||
2008 | set_priv_filter(usbdev); | ||
2009 | |||
2010 | ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE); | ||
2011 | if (ret < 0) { | ||
2012 | devdbg(usbdev, "join_ibss: set_encr_mode failed, %d", ret); | ||
2013 | goto err_turn_radio_on; | ||
2014 | } | ||
2015 | |||
2016 | if (channel) { | ||
2017 | ret = set_channel(usbdev, chan); | ||
2018 | if (ret < 0) { | ||
2019 | devdbg(usbdev, "join_ibss: set_channel failed, %d", | ||
2020 | ret); | ||
2021 | goto err_turn_radio_on; | ||
2022 | } | ||
2023 | } | ||
2024 | |||
2025 | if (params->bssid && !is_zero_ether_addr(params->bssid) && | ||
2026 | !is_broadcast_ether_addr(params->bssid)) { | ||
2027 | ret = set_bssid(usbdev, params->bssid); | ||
2028 | if (ret < 0) { | ||
2029 | devdbg(usbdev, "join_ibss: set_bssid failed, %d", ret); | ||
2030 | goto err_turn_radio_on; | ||
2031 | } | ||
2032 | } else | ||
2033 | clear_bssid(usbdev); | ||
2034 | |||
2035 | length = params->ssid_len; | ||
2036 | if (length > NDIS_802_11_LENGTH_SSID) | ||
2037 | length = NDIS_802_11_LENGTH_SSID; | ||
2038 | |||
2039 | memset(&ssid, 0, sizeof(ssid)); | ||
2040 | ssid.length = cpu_to_le32(length); | ||
2041 | memcpy(ssid.essid, params->ssid, length); | ||
2042 | |||
2043 | /* Don't need to pause rx queue for ad-hoc. */ | ||
2044 | usbnet_purge_paused_rxq(usbdev); | ||
2045 | usbnet_resume_rx(usbdev); | ||
2046 | |||
2047 | ret = set_essid(usbdev, &ssid); | ||
2048 | if (ret < 0) | ||
2049 | devdbg(usbdev, "join_ibss: set_essid failed, %d", ret); | ||
2050 | return ret; | ||
2051 | |||
2052 | err_turn_radio_on: | ||
2053 | disassociate(usbdev, 1); | ||
2054 | |||
2055 | return ret; | ||
2056 | } | ||
2057 | |||
2058 | static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | ||
2059 | { | ||
2060 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | ||
2061 | struct usbnet *usbdev = priv->usbdev; | ||
2062 | |||
2063 | devdbg(usbdev, "cfg80211.leave_ibss()"); | ||
2064 | |||
2065 | priv->connected = false; | ||
2066 | |||
2067 | return deauthenticate(usbdev); | ||
2068 | } | ||
2069 | |||
1768 | 2070 | ||
1769 | /* | 2071 | /* |
1770 | * wireless extension handlers | 2072 | * wireless extension handlers |
@@ -1777,7 +2079,10 @@ static int rndis_iw_commit(struct net_device *dev, | |||
1777 | return 0; | 2079 | return 0; |
1778 | } | 2080 | } |
1779 | 2081 | ||
1780 | 2082 | #if 0 | |
2083 | /* Commented code out instead of removing to have more sane patch for review. | ||
2084 | * Will be removed later in the set. | ||
2085 | */ | ||
1781 | static int rndis_iw_set_essid(struct net_device *dev, | 2086 | static int rndis_iw_set_essid(struct net_device *dev, |
1782 | struct iw_request_info *info, union iwreq_data *wrqu, char *essid) | 2087 | struct iw_request_info *info, union iwreq_data *wrqu, char *essid) |
1783 | { | 2088 | { |
@@ -1990,6 +2295,7 @@ static int rndis_iw_get_auth(struct net_device *dev, | |||
1990 | } | 2295 | } |
1991 | return 0; | 2296 | return 0; |
1992 | } | 2297 | } |
2298 | #endif | ||
1993 | 2299 | ||
1994 | 2300 | ||
1995 | static int rndis_iw_set_encode(struct net_device *dev, | 2301 | static int rndis_iw_set_encode(struct net_device *dev, |
@@ -2024,11 +2330,11 @@ static int rndis_iw_set_encode(struct net_device *dev, | |||
2024 | 2330 | ||
2025 | /* global encryption state (for all keys) */ | 2331 | /* global encryption state (for all keys) */ |
2026 | if (wrqu->data.flags & IW_ENCODE_OPEN) | 2332 | if (wrqu->data.flags & IW_ENCODE_OPEN) |
2027 | ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, | 2333 | ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, |
2028 | IW_AUTH_ALG_OPEN_SYSTEM); | 2334 | RNDIS_WLAN_KEY_MGMT_NONE); |
2029 | else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/ | 2335 | else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/ |
2030 | ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, | 2336 | ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_SHARED_KEY, |
2031 | IW_AUTH_ALG_SHARED_KEY); | 2337 | RNDIS_WLAN_KEY_MGMT_NONE); |
2032 | if (ret != 0) | 2338 | if (ret != 0) |
2033 | return ret; | 2339 | return ret; |
2034 | 2340 | ||
@@ -2077,7 +2383,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, | |||
2077 | return -EINVAL; | 2383 | return -EINVAL; |
2078 | } | 2384 | } |
2079 | 2385 | ||
2080 | if (ext->alg == WPA_ALG_WEP) { | 2386 | if (ext->alg == IW_ENCODE_ALG_WEP) { |
2081 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) | 2387 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) |
2082 | priv->encr_tx_key_index = keyidx; | 2388 | priv->encr_tx_key_index = keyidx; |
2083 | return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); | 2389 | return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); |
@@ -2110,63 +2416,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, | |||
2110 | } | 2416 | } |
2111 | 2417 | ||
2112 | 2418 | ||
2113 | static int rndis_iw_set_genie(struct net_device *dev, | ||
2114 | struct iw_request_info *info, union iwreq_data *wrqu, char *extra) | ||
2115 | { | ||
2116 | struct usbnet *usbdev = netdev_priv(dev); | ||
2117 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
2118 | int ret = 0; | ||
2119 | |||
2120 | #ifdef DEBUG | ||
2121 | int j; | ||
2122 | u8 *gie = extra; | ||
2123 | for (j = 0; j < wrqu->data.length; j += 8) | ||
2124 | devdbg(usbdev, | ||
2125 | "SIOCSIWGENIE %04x - " | ||
2126 | "%02x %02x %02x %02x %02x %02x %02x %02x", j, | ||
2127 | gie[j + 0], gie[j + 1], gie[j + 2], gie[j + 3], | ||
2128 | gie[j + 4], gie[j + 5], gie[j + 6], gie[j + 7]); | ||
2129 | #endif | ||
2130 | /* clear existing IEs */ | ||
2131 | if (priv->wpa_ie_len) { | ||
2132 | kfree(priv->wpa_ie); | ||
2133 | priv->wpa_ie_len = 0; | ||
2134 | } | ||
2135 | |||
2136 | /* set new IEs */ | ||
2137 | priv->wpa_ie = kmalloc(wrqu->data.length, GFP_KERNEL); | ||
2138 | if (priv->wpa_ie) { | ||
2139 | priv->wpa_ie_len = wrqu->data.length; | ||
2140 | memcpy(priv->wpa_ie, extra, priv->wpa_ie_len); | ||
2141 | } else | ||
2142 | ret = -ENOMEM; | ||
2143 | return ret; | ||
2144 | } | ||
2145 | |||
2146 | |||
2147 | static int rndis_iw_get_genie(struct net_device *dev, | ||
2148 | struct iw_request_info *info, union iwreq_data *wrqu, char *extra) | ||
2149 | { | ||
2150 | struct usbnet *usbdev = netdev_priv(dev); | ||
2151 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
2152 | |||
2153 | devdbg(usbdev, "SIOCGIWGENIE"); | ||
2154 | |||
2155 | if (priv->wpa_ie_len == 0 || priv->wpa_ie == NULL) { | ||
2156 | wrqu->data.length = 0; | ||
2157 | return 0; | ||
2158 | } | ||
2159 | |||
2160 | if (wrqu->data.length < priv->wpa_ie_len) | ||
2161 | return -E2BIG; | ||
2162 | |||
2163 | wrqu->data.length = priv->wpa_ie_len; | ||
2164 | memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); | ||
2165 | |||
2166 | return 0; | ||
2167 | } | ||
2168 | |||
2169 | |||
2170 | static int rndis_iw_set_freq(struct net_device *dev, | 2419 | static int rndis_iw_set_freq(struct net_device *dev, |
2171 | struct iw_request_info *info, union iwreq_data *wrqu, char *extra) | 2420 | struct iw_request_info *info, union iwreq_data *wrqu, char *extra) |
2172 | { | 2421 | { |
@@ -2233,32 +2482,6 @@ static int rndis_iw_get_rate(struct net_device *dev, | |||
2233 | } | 2482 | } |
2234 | 2483 | ||
2235 | 2484 | ||
2236 | static int rndis_iw_set_mlme(struct net_device *dev, | ||
2237 | struct iw_request_info *info, union iwreq_data *wrqu, char *extra) | ||
2238 | { | ||
2239 | struct usbnet *usbdev = netdev_priv(dev); | ||
2240 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
2241 | struct iw_mlme *mlme = (struct iw_mlme *)extra; | ||
2242 | unsigned char bssid[ETH_ALEN]; | ||
2243 | |||
2244 | get_bssid(usbdev, bssid); | ||
2245 | |||
2246 | if (memcmp(bssid, mlme->addr.sa_data, ETH_ALEN)) | ||
2247 | return -EINVAL; | ||
2248 | |||
2249 | switch (mlme->cmd) { | ||
2250 | case IW_MLME_DEAUTH: | ||
2251 | return deauthenticate(usbdev); | ||
2252 | case IW_MLME_DISASSOC: | ||
2253 | return disassociate(usbdev, priv->radio_on); | ||
2254 | default: | ||
2255 | return -EOPNOTSUPP; | ||
2256 | } | ||
2257 | |||
2258 | return 0; | ||
2259 | } | ||
2260 | |||
2261 | |||
2262 | static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) | 2485 | static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) |
2263 | { | 2486 | { |
2264 | struct usbnet *usbdev = netdev_priv(dev); | 2487 | struct usbnet *usbdev = netdev_priv(dev); |
@@ -2283,12 +2506,12 @@ static const iw_handler rndis_iw_handler[] = | |||
2283 | IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, | 2506 | IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, |
2284 | IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, | 2507 | IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, |
2285 | IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, | 2508 | IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, |
2286 | IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid, | 2509 | IW_IOCTL(SIOCSIWAP) = (iw_handler) cfg80211_wext_siwap, |
2287 | IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid, | 2510 | IW_IOCTL(SIOCGIWAP) = (iw_handler) cfg80211_wext_giwap, |
2288 | IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, | 2511 | IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, |
2289 | IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, | 2512 | IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, |
2290 | IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid, | 2513 | IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, |
2291 | IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid, | 2514 | IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, |
2292 | IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, | 2515 | IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, |
2293 | IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, | 2516 | IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, |
2294 | IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, | 2517 | IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, |
@@ -2298,11 +2521,10 @@ static const iw_handler rndis_iw_handler[] = | |||
2298 | IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, | 2521 | IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, |
2299 | IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, | 2522 | IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, |
2300 | IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext, | 2523 | IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext, |
2301 | IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth, | 2524 | IW_IOCTL(SIOCSIWAUTH) = (iw_handler) cfg80211_wext_siwauth, |
2302 | IW_IOCTL(SIOCGIWAUTH) = rndis_iw_get_auth, | 2525 | IW_IOCTL(SIOCGIWAUTH) = (iw_handler) cfg80211_wext_giwauth, |
2303 | IW_IOCTL(SIOCSIWGENIE) = rndis_iw_set_genie, | 2526 | IW_IOCTL(SIOCSIWGENIE) = (iw_handler) cfg80211_wext_siwgenie, |
2304 | IW_IOCTL(SIOCGIWGENIE) = rndis_iw_get_genie, | 2527 | IW_IOCTL(SIOCSIWMLME) = (iw_handler) cfg80211_wext_siwmlme, |
2305 | IW_IOCTL(SIOCSIWMLME) = rndis_iw_set_mlme, | ||
2306 | }; | 2528 | }; |
2307 | 2529 | ||
2308 | static const iw_handler rndis_wlan_private_handler[] = { | 2530 | static const iw_handler rndis_wlan_private_handler[] = { |
@@ -2325,49 +2547,78 @@ static const struct iw_handler_def rndis_iw_handlers = { | |||
2325 | 2547 | ||
2326 | static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) | 2548 | static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) |
2327 | { | 2549 | { |
2550 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
2328 | struct ndis_80211_assoc_info *info; | 2551 | struct ndis_80211_assoc_info *info; |
2329 | union iwreq_data evt; | ||
2330 | u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32]; | 2552 | u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32]; |
2331 | u8 bssid[ETH_ALEN]; | 2553 | u8 bssid[ETH_ALEN]; |
2554 | int resp_ie_len, req_ie_len; | ||
2555 | u8 *req_ie, *resp_ie; | ||
2332 | int ret, offset; | 2556 | int ret, offset; |
2557 | bool roamed = false; | ||
2558 | |||
2559 | if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { | ||
2560 | /* received media connect indication while connected, either | ||
2561 | * device reassociated with same AP or roamed to new. */ | ||
2562 | roamed = true; | ||
2563 | } | ||
2564 | |||
2565 | req_ie_len = 0; | ||
2566 | resp_ie_len = 0; | ||
2567 | req_ie = NULL; | ||
2568 | resp_ie = NULL; | ||
2569 | |||
2570 | if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { | ||
2571 | memset(assoc_buf, 0, sizeof(assoc_buf)); | ||
2572 | info = (void *)assoc_buf; | ||
2573 | |||
2574 | /* Get association info IEs from device and send them back to | ||
2575 | * userspace. */ | ||
2576 | ret = get_association_info(usbdev, info, sizeof(assoc_buf)); | ||
2577 | if (!ret) { | ||
2578 | req_ie_len = le32_to_cpu(info->req_ie_length); | ||
2579 | if (req_ie_len > 0) { | ||
2580 | offset = le32_to_cpu(info->offset_req_ies); | ||
2581 | req_ie = (u8 *)info + offset; | ||
2582 | } | ||
2333 | 2583 | ||
2334 | memset(assoc_buf, 0, sizeof(assoc_buf)); | 2584 | resp_ie_len = le32_to_cpu(info->resp_ie_length); |
2335 | info = (void *)assoc_buf; | 2585 | if (resp_ie_len > 0) { |
2586 | offset = le32_to_cpu(info->offset_resp_ies); | ||
2587 | resp_ie = (u8 *)info + offset; | ||
2588 | } | ||
2589 | } | ||
2590 | } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) | ||
2591 | return; | ||
2336 | 2592 | ||
2337 | netif_carrier_on(usbdev->net); | 2593 | ret = get_bssid(usbdev, bssid); |
2594 | if (ret < 0) | ||
2595 | memset(bssid, 0, sizeof(bssid)); | ||
2338 | 2596 | ||
2339 | /* Get association info IEs from device and send them back to | 2597 | devdbg(usbdev, "link up work: [%pM] %s", bssid, roamed ? "roamed" : ""); |
2340 | * userspace. */ | ||
2341 | ret = get_association_info(usbdev, info, sizeof(assoc_buf)); | ||
2342 | if (!ret) { | ||
2343 | evt.data.length = le32_to_cpu(info->req_ie_length); | ||
2344 | if (evt.data.length > 0) { | ||
2345 | offset = le32_to_cpu(info->offset_req_ies); | ||
2346 | wireless_send_event(usbdev->net, | ||
2347 | IWEVASSOCREQIE, &evt, | ||
2348 | (char *)info + offset); | ||
2349 | } | ||
2350 | 2598 | ||
2351 | evt.data.length = le32_to_cpu(info->resp_ie_length); | 2599 | /* Internal bss list in device always contains at least the currently |
2352 | if (evt.data.length > 0) { | 2600 | * connected bss and we can get it to cfg80211 with |
2353 | offset = le32_to_cpu(info->offset_resp_ies); | 2601 | * rndis_check_bssid_list(). |
2354 | wireless_send_event(usbdev->net, | 2602 | * NOTE: This is true for Broadcom chip, but not mentioned in RNDIS |
2355 | IWEVASSOCRESPIE, &evt, | 2603 | * spec. |
2356 | (char *)info + offset); | 2604 | */ |
2357 | } | 2605 | rndis_check_bssid_list(usbdev); |
2358 | 2606 | ||
2359 | usbnet_resume_rx(usbdev); | 2607 | if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { |
2360 | } | 2608 | if (!roamed) |
2609 | cfg80211_connect_result(usbdev->net, bssid, req_ie, | ||
2610 | req_ie_len, resp_ie, | ||
2611 | resp_ie_len, 0, GFP_KERNEL); | ||
2612 | else | ||
2613 | cfg80211_roamed(usbdev->net, bssid, req_ie, req_ie_len, | ||
2614 | resp_ie, resp_ie_len, GFP_KERNEL); | ||
2615 | } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) | ||
2616 | cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); | ||
2361 | 2617 | ||
2362 | ret = get_bssid(usbdev, bssid); | 2618 | priv->connected = true; |
2363 | if (!ret) { | ||
2364 | evt.data.flags = 0; | ||
2365 | evt.data.length = 0; | ||
2366 | memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); | ||
2367 | wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); | ||
2368 | } | ||
2369 | 2619 | ||
2370 | usbnet_resume_rx(usbdev); | 2620 | usbnet_resume_rx(usbdev); |
2621 | netif_carrier_on(usbdev->net); | ||
2371 | } | 2622 | } |
2372 | 2623 | ||
2373 | static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) | 2624 | static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) |