diff options
author | Arik Nemtsov <arik@wizery.com> | 2010-10-16 12:08:58 -0400 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2011-01-24 15:11:47 -0500 |
commit | 98bdaabbbced007c7eb89cd373f9cb1640635b46 (patch) | |
tree | aa073697f83ff89a2fd64cffa44df84bffac8aff /drivers/net/wireless/wl12xx/cmd.c | |
parent | 203c903cbfbdf23bbb3020b9344dd1ffabcfcb53 (diff) |
wl12xx: AP-mode high level commands
Add commands to start/stop BSS, add/remove STA and configure encryption
keys. Split the encryption commands "set key" and "set default key" into
AP and STA specific versions.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Reviewed-by: Luciano Coelho <coelho@ti.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/cmd.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/cmd.c | 276 |
1 files changed, 272 insertions, 4 deletions
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 3b7b8f0a200b..f9c5ce91cb12 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "wl12xx_80211.h" | 36 | #include "wl12xx_80211.h" |
37 | #include "cmd.h" | 37 | #include "cmd.h" |
38 | #include "event.h" | 38 | #include "event.h" |
39 | #include "tx.h" | ||
39 | 40 | ||
40 | #define WL1271_CMD_FAST_POLL_COUNT 50 | 41 | #define WL1271_CMD_FAST_POLL_COUNT 50 |
41 | 42 | ||
@@ -702,9 +703,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) | |||
702 | wl->basic_rate); | 703 | wl->basic_rate); |
703 | } | 704 | } |
704 | 705 | ||
705 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) | 706 | int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id) |
706 | { | 707 | { |
707 | struct wl1271_cmd_set_keys *cmd; | 708 | struct wl1271_cmd_set_sta_keys *cmd; |
708 | int ret = 0; | 709 | int ret = 0; |
709 | 710 | ||
710 | wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); | 711 | wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); |
@@ -731,11 +732,42 @@ out: | |||
731 | return ret; | 732 | return ret; |
732 | } | 733 | } |
733 | 734 | ||
734 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | 735 | int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id) |
736 | { | ||
737 | struct wl1271_cmd_set_ap_keys *cmd; | ||
738 | int ret = 0; | ||
739 | |||
740 | wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id); | ||
741 | |||
742 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
743 | if (!cmd) { | ||
744 | ret = -ENOMEM; | ||
745 | goto out; | ||
746 | } | ||
747 | |||
748 | cmd->hlid = WL1271_AP_BROADCAST_HLID; | ||
749 | cmd->key_id = id; | ||
750 | cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; | ||
751 | cmd->key_action = cpu_to_le16(KEY_SET_ID); | ||
752 | cmd->key_type = KEY_WEP; | ||
753 | |||
754 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); | ||
755 | if (ret < 0) { | ||
756 | wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret); | ||
757 | goto out; | ||
758 | } | ||
759 | |||
760 | out: | ||
761 | kfree(cmd); | ||
762 | |||
763 | return ret; | ||
764 | } | ||
765 | |||
766 | int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | ||
735 | u8 key_size, const u8 *key, const u8 *addr, | 767 | u8 key_size, const u8 *key, const u8 *addr, |
736 | u32 tx_seq_32, u16 tx_seq_16) | 768 | u32 tx_seq_32, u16 tx_seq_16) |
737 | { | 769 | { |
738 | struct wl1271_cmd_set_keys *cmd; | 770 | struct wl1271_cmd_set_sta_keys *cmd; |
739 | int ret = 0; | 771 | int ret = 0; |
740 | 772 | ||
741 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 773 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
@@ -788,6 +820,67 @@ out: | |||
788 | return ret; | 820 | return ret; |
789 | } | 821 | } |
790 | 822 | ||
823 | int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | ||
824 | u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, | ||
825 | u16 tx_seq_16) | ||
826 | { | ||
827 | struct wl1271_cmd_set_ap_keys *cmd; | ||
828 | int ret = 0; | ||
829 | u8 lid_type; | ||
830 | |||
831 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
832 | if (!cmd) | ||
833 | return -ENOMEM; | ||
834 | |||
835 | if (hlid == WL1271_AP_BROADCAST_HLID) { | ||
836 | if (key_type == KEY_WEP) | ||
837 | lid_type = WEP_DEFAULT_LID_TYPE; | ||
838 | else | ||
839 | lid_type = BROADCAST_LID_TYPE; | ||
840 | } else { | ||
841 | lid_type = UNICAST_LID_TYPE; | ||
842 | } | ||
843 | |||
844 | wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" | ||
845 | " hlid: %d", (int)action, (int)id, (int)lid_type, | ||
846 | (int)key_type, (int)hlid); | ||
847 | |||
848 | cmd->lid_key_type = lid_type; | ||
849 | cmd->hlid = hlid; | ||
850 | cmd->key_action = cpu_to_le16(action); | ||
851 | cmd->key_size = key_size; | ||
852 | cmd->key_type = key_type; | ||
853 | cmd->key_id = id; | ||
854 | cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); | ||
855 | cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); | ||
856 | |||
857 | if (key_type == KEY_TKIP) { | ||
858 | /* | ||
859 | * We get the key in the following form: | ||
860 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
861 | * but the target is expecting: | ||
862 | * TKIP - RX MIC - TX MIC | ||
863 | */ | ||
864 | memcpy(cmd->key, key, 16); | ||
865 | memcpy(cmd->key + 16, key + 24, 8); | ||
866 | memcpy(cmd->key + 24, key + 16, 8); | ||
867 | } else { | ||
868 | memcpy(cmd->key, key, key_size); | ||
869 | } | ||
870 | |||
871 | wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); | ||
872 | |||
873 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); | ||
874 | if (ret < 0) { | ||
875 | wl1271_warning("could not set ap keys"); | ||
876 | goto out; | ||
877 | } | ||
878 | |||
879 | out: | ||
880 | kfree(cmd); | ||
881 | return ret; | ||
882 | } | ||
883 | |||
791 | int wl1271_cmd_disconnect(struct wl1271 *wl) | 884 | int wl1271_cmd_disconnect(struct wl1271 *wl) |
792 | { | 885 | { |
793 | struct wl1271_cmd_disconnect *cmd; | 886 | struct wl1271_cmd_disconnect *cmd; |
@@ -850,3 +943,178 @@ out_free: | |||
850 | out: | 943 | out: |
851 | return ret; | 944 | return ret; |
852 | } | 945 | } |
946 | |||
947 | int wl1271_cmd_start_bss(struct wl1271 *wl) | ||
948 | { | ||
949 | struct wl1271_cmd_bss_start *cmd; | ||
950 | struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; | ||
951 | int ret; | ||
952 | |||
953 | wl1271_debug(DEBUG_CMD, "cmd start bss"); | ||
954 | |||
955 | /* | ||
956 | * FIXME: We currently do not support hidden SSID. The real SSID | ||
957 | * should be fetched from mac80211 first. | ||
958 | */ | ||
959 | if (wl->ssid_len == 0) { | ||
960 | wl1271_warning("Hidden SSID currently not supported for AP"); | ||
961 | ret = -EINVAL; | ||
962 | goto out; | ||
963 | } | ||
964 | |||
965 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
966 | if (!cmd) { | ||
967 | ret = -ENOMEM; | ||
968 | goto out; | ||
969 | } | ||
970 | |||
971 | memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); | ||
972 | |||
973 | cmd->aging_period = WL1271_AP_DEF_INACTIV_SEC; | ||
974 | cmd->bss_index = WL1271_AP_BSS_INDEX; | ||
975 | cmd->global_hlid = WL1271_AP_GLOBAL_HLID; | ||
976 | cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; | ||
977 | cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set); | ||
978 | cmd->beacon_interval = cpu_to_le16(wl->beacon_int); | ||
979 | cmd->dtim_interval = bss_conf->dtim_period; | ||
980 | cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP; | ||
981 | cmd->channel = wl->channel; | ||
982 | cmd->ssid_len = wl->ssid_len; | ||
983 | cmd->ssid_type = SSID_TYPE_PUBLIC; | ||
984 | memcpy(cmd->ssid, wl->ssid, wl->ssid_len); | ||
985 | |||
986 | switch (wl->band) { | ||
987 | case IEEE80211_BAND_2GHZ: | ||
988 | cmd->band = RADIO_BAND_2_4GHZ; | ||
989 | break; | ||
990 | case IEEE80211_BAND_5GHZ: | ||
991 | cmd->band = RADIO_BAND_5GHZ; | ||
992 | break; | ||
993 | default: | ||
994 | wl1271_warning("bss start - unknown band: %d", (int)wl->band); | ||
995 | cmd->band = RADIO_BAND_2_4GHZ; | ||
996 | break; | ||
997 | } | ||
998 | |||
999 | ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0); | ||
1000 | if (ret < 0) { | ||
1001 | wl1271_error("failed to initiate cmd start bss"); | ||
1002 | goto out_free; | ||
1003 | } | ||
1004 | |||
1005 | out_free: | ||
1006 | kfree(cmd); | ||
1007 | |||
1008 | out: | ||
1009 | return ret; | ||
1010 | } | ||
1011 | |||
1012 | int wl1271_cmd_stop_bss(struct wl1271 *wl) | ||
1013 | { | ||
1014 | struct wl1271_cmd_bss_start *cmd; | ||
1015 | int ret; | ||
1016 | |||
1017 | wl1271_debug(DEBUG_CMD, "cmd stop bss"); | ||
1018 | |||
1019 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1020 | if (!cmd) { | ||
1021 | ret = -ENOMEM; | ||
1022 | goto out; | ||
1023 | } | ||
1024 | |||
1025 | cmd->bss_index = WL1271_AP_BSS_INDEX; | ||
1026 | |||
1027 | ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0); | ||
1028 | if (ret < 0) { | ||
1029 | wl1271_error("failed to initiate cmd stop bss"); | ||
1030 | goto out_free; | ||
1031 | } | ||
1032 | |||
1033 | out_free: | ||
1034 | kfree(cmd); | ||
1035 | |||
1036 | out: | ||
1037 | return ret; | ||
1038 | } | ||
1039 | |||
1040 | int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) | ||
1041 | { | ||
1042 | struct wl1271_cmd_add_sta *cmd; | ||
1043 | int ret; | ||
1044 | |||
1045 | wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid); | ||
1046 | |||
1047 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1048 | if (!cmd) { | ||
1049 | ret = -ENOMEM; | ||
1050 | goto out; | ||
1051 | } | ||
1052 | |||
1053 | /* currently we don't support UAPSD */ | ||
1054 | cmd->sp_len = 0; | ||
1055 | |||
1056 | memcpy(cmd->addr, sta->addr, ETH_ALEN); | ||
1057 | cmd->bss_index = WL1271_AP_BSS_INDEX; | ||
1058 | cmd->aid = sta->aid; | ||
1059 | cmd->hlid = hlid; | ||
1060 | |||
1061 | /* | ||
1062 | * FIXME: Does STA support QOS? We need to propagate this info from | ||
1063 | * hostapd. Currently not that important since this is only used for | ||
1064 | * sending the correct flavor of null-data packet in response to a | ||
1065 | * trigger. | ||
1066 | */ | ||
1067 | cmd->wmm = 0; | ||
1068 | |||
1069 | cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, | ||
1070 | sta->supp_rates[wl->band])); | ||
1071 | |||
1072 | wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates); | ||
1073 | |||
1074 | ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0); | ||
1075 | if (ret < 0) { | ||
1076 | wl1271_error("failed to initiate cmd add sta"); | ||
1077 | goto out_free; | ||
1078 | } | ||
1079 | |||
1080 | out_free: | ||
1081 | kfree(cmd); | ||
1082 | |||
1083 | out: | ||
1084 | return ret; | ||
1085 | } | ||
1086 | |||
1087 | int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) | ||
1088 | { | ||
1089 | struct wl1271_cmd_remove_sta *cmd; | ||
1090 | int ret; | ||
1091 | |||
1092 | wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid); | ||
1093 | |||
1094 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1095 | if (!cmd) { | ||
1096 | ret = -ENOMEM; | ||
1097 | goto out; | ||
1098 | } | ||
1099 | |||
1100 | cmd->hlid = hlid; | ||
1101 | /* We never send a deauth, mac80211 is in charge of this */ | ||
1102 | cmd->reason_opcode = 0; | ||
1103 | cmd->send_deauth_flag = 0; | ||
1104 | |||
1105 | ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0); | ||
1106 | if (ret < 0) { | ||
1107 | wl1271_error("failed to initiate cmd remove sta"); | ||
1108 | goto out_free; | ||
1109 | } | ||
1110 | |||
1111 | ret = wl1271_cmd_wait_for_event(wl, STA_REMOVE_COMPLETE_EVENT_ID); | ||
1112 | if (ret < 0) | ||
1113 | wl1271_error("cmd remove sta event completion error"); | ||
1114 | |||
1115 | out_free: | ||
1116 | kfree(cmd); | ||
1117 | |||
1118 | out: | ||
1119 | return ret; | ||
1120 | } | ||