aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/assoc.c
diff options
context:
space:
mode:
authorHolger Schurig <hs4233@mail.mn-solutions.de>2008-04-02 10:27:10 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-08 16:44:40 -0400
commit697900ac14528e985b66f471ecb81082fc00baa9 (patch)
treeafcfac67c1ce47c2005d35eb84249a4fb1a19736 /drivers/net/wireless/libertas/assoc.c
parent53f36d70f072403d9aef68b332b72eb8c559b4ae (diff)
libertas: move association code from join.c into scan.c
Besides code moving, I did the following changes: * made some functions static * removed some unneeded #include's * made patch checkpatch.pl clean Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/assoc.c')
-rw-r--r--drivers/net/wireless/libertas/assoc.c862
1 files changed, 858 insertions, 4 deletions
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index 95d98203eb4e..e794e93a2297 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -1,13 +1,9 @@
1/* Copyright (C) 2006, Red Hat, Inc. */ 1/* Copyright (C) 2006, Red Hat, Inc. */
2 2
3#include <linux/bitops.h>
4#include <net/ieee80211.h>
5#include <linux/etherdevice.h> 3#include <linux/etherdevice.h>
6 4
7#include "assoc.h" 5#include "assoc.h"
8#include "join.h"
9#include "decl.h" 6#include "decl.h"
10#include "hostcmd.h"
11#include "host.h" 7#include "host.h"
12#include "cmd.h" 8#include "cmd.h"
13 9
@@ -17,6 +13,162 @@ static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) =
17static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = 13static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
18 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 14 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
19 15
16/* The firmware needs certain bits masked out of the beacon-derviced capability
17 * field when associating/joining to BSSs.
18 */
19#define CAPINFO_MASK (~(0xda00))
20
21
22
23/**
24 * @brief Associate to a specific BSS discovered in a scan
25 *
26 * @param priv A pointer to struct lbs_private structure
27 * @param pbssdesc Pointer to the BSS descriptor to associate with.
28 *
29 * @return 0-success, otherwise fail
30 */
31static int lbs_associate(struct lbs_private *priv,
32 struct assoc_request *assoc_req)
33{
34 int ret;
35
36 lbs_deb_enter(LBS_DEB_ASSOC);
37
38 ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
39 0, CMD_OPTION_WAITFORRSP,
40 0, assoc_req->bss.bssid);
41
42 if (ret)
43 goto done;
44
45 /* set preamble to firmware */
46 if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
47 (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
48 priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
49 else
50 priv->preamble = CMD_TYPE_LONG_PREAMBLE;
51
52 lbs_set_radio_control(priv);
53
54 ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
55 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
56
57done:
58 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
59 return ret;
60}
61
62/**
63 * @brief Join an adhoc network found in a previous scan
64 *
65 * @param priv A pointer to struct lbs_private structure
66 * @param pbssdesc Pointer to a BSS descriptor found in a previous scan
67 * to attempt to join
68 *
69 * @return 0--success, -1--fail
70 */
71static int lbs_join_adhoc_network(struct lbs_private *priv,
72 struct assoc_request *assoc_req)
73{
74 struct bss_descriptor *bss = &assoc_req->bss;
75 int ret = 0;
76
77 lbs_deb_join("current SSID '%s', ssid length %u\n",
78 escape_essid(priv->curbssparams.ssid,
79 priv->curbssparams.ssid_len),
80 priv->curbssparams.ssid_len);
81 lbs_deb_join("requested ssid '%s', ssid length %u\n",
82 escape_essid(bss->ssid, bss->ssid_len),
83 bss->ssid_len);
84
85 /* check if the requested SSID is already joined */
86 if (priv->curbssparams.ssid_len &&
87 !lbs_ssid_cmp(priv->curbssparams.ssid,
88 priv->curbssparams.ssid_len,
89 bss->ssid, bss->ssid_len) &&
90 (priv->mode == IW_MODE_ADHOC) &&
91 (priv->connect_status == LBS_CONNECTED)) {
92 union iwreq_data wrqu;
93
94 lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
95 "current, not attempting to re-join");
96
97 /* Send the re-association event though, because the association
98 * request really was successful, even if just a null-op.
99 */
100 memset(&wrqu, 0, sizeof(wrqu));
101 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
102 ETH_ALEN);
103 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
104 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
105 goto out;
106 }
107
108 /* Use shortpreamble only when both creator and card supports
109 short preamble */
110 if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ||
111 !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
112 lbs_deb_join("AdhocJoin: Long preamble\n");
113 priv->preamble = CMD_TYPE_LONG_PREAMBLE;
114 } else {
115 lbs_deb_join("AdhocJoin: Short preamble\n");
116 priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
117 }
118
119 lbs_set_radio_control(priv);
120
121 lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
122 lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
123
124 priv->adhoccreate = 0;
125
126 ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
127 0, CMD_OPTION_WAITFORRSP,
128 OID_802_11_SSID, assoc_req);
129
130out:
131 return ret;
132}
133
134/**
135 * @brief Start an Adhoc Network
136 *
137 * @param priv A pointer to struct lbs_private structure
138 * @param adhocssid The ssid of the Adhoc Network
139 * @return 0--success, -1--fail
140 */
141static int lbs_start_adhoc_network(struct lbs_private *priv,
142 struct assoc_request *assoc_req)
143{
144 int ret = 0;
145
146 priv->adhoccreate = 1;
147
148 if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
149 lbs_deb_join("AdhocStart: Short preamble\n");
150 priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
151 } else {
152 lbs_deb_join("AdhocStart: Long preamble\n");
153 priv->preamble = CMD_TYPE_LONG_PREAMBLE;
154 }
155
156 lbs_set_radio_control(priv);
157
158 lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
159 lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
160
161 ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
162 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
163
164 return ret;
165}
166
167int lbs_stop_adhoc_network(struct lbs_private *priv)
168{
169 return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
170 0, CMD_OPTION_WAITFORRSP, 0, NULL);
171}
20 172
21static int assoc_helper_essid(struct lbs_private *priv, 173static int assoc_helper_essid(struct lbs_private *priv,
22 struct assoc_request * assoc_req) 174 struct assoc_request * assoc_req)
@@ -722,3 +874,705 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
722 lbs_deb_leave(LBS_DEB_ASSOC); 874 lbs_deb_leave(LBS_DEB_ASSOC);
723 return assoc_req; 875 return assoc_req;
724} 876}
877
878
879/**
880 * @brief This function finds common rates between rate1 and card rates.
881 *
882 * It will fill common rates in rate1 as output if found.
883 *
884 * NOTE: Setting the MSB of the basic rates need to be taken
885 * care, either before or after calling this function
886 *
887 * @param priv A pointer to struct lbs_private structure
888 * @param rate1 the buffer which keeps input and output
889 * @param rate1_size the size of rate1 buffer; new size of buffer on return
890 *
891 * @return 0 or -1
892 */
893static int get_common_rates(struct lbs_private *priv,
894 u8 *rates,
895 u16 *rates_size)
896{
897 u8 *card_rates = lbs_bg_rates;
898 size_t num_card_rates = sizeof(lbs_bg_rates);
899 int ret = 0, i, j;
900 u8 tmp[30];
901 size_t tmp_size = 0;
902
903 /* For each rate in card_rates that exists in rate1, copy to tmp */
904 for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
905 for (j = 0; rates[j] && (j < *rates_size); j++) {
906 if (rates[j] == card_rates[i])
907 tmp[tmp_size++] = card_rates[i];
908 }
909 }
910
911 lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
912 lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
913 lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
914 lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
915
916 if (!priv->auto_rate) {
917 for (i = 0; i < tmp_size; i++) {
918 if (tmp[i] == priv->cur_rate)
919 goto done;
920 }
921 lbs_pr_alert("Previously set fixed data rate %#x isn't "
922 "compatible with the network.\n", priv->cur_rate);
923 ret = -1;
924 goto done;
925 }
926 ret = 0;
927
928done:
929 memset(rates, 0, *rates_size);
930 *rates_size = min_t(int, tmp_size, *rates_size);
931 memcpy(rates, tmp, *rates_size);
932 return ret;
933}
934
935
936/**
937 * @brief Sets the MSB on basic rates as the firmware requires
938 *
939 * Scan through an array and set the MSB for basic data rates.
940 *
941 * @param rates buffer of data rates
942 * @param len size of buffer
943 */
944static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
945{
946 int i;
947
948 for (i = 0; i < len; i++) {
949 if (rates[i] == 0x02 || rates[i] == 0x04 ||
950 rates[i] == 0x0b || rates[i] == 0x16)
951 rates[i] |= 0x80;
952 }
953}
954
955/**
956 * @brief Send Deauthentication Request
957 *
958 * @param priv A pointer to struct lbs_private structure
959 * @return 0--success, -1--fail
960 */
961int lbs_send_deauthentication(struct lbs_private *priv)
962{
963 return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
964 0, CMD_OPTION_WAITFORRSP, 0, NULL);
965}
966
967/**
968 * @brief This function prepares command of authenticate.
969 *
970 * @param priv A pointer to struct lbs_private structure
971 * @param cmd A pointer to cmd_ds_command structure
972 * @param pdata_buf Void cast of pointer to a BSSID to authenticate with
973 *
974 * @return 0 or -1
975 */
976int lbs_cmd_80211_authenticate(struct lbs_private *priv,
977 struct cmd_ds_command *cmd,
978 void *pdata_buf)
979{
980 struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
981 int ret = -1;
982 u8 *bssid = pdata_buf;
983 DECLARE_MAC_BUF(mac);
984
985 lbs_deb_enter(LBS_DEB_JOIN);
986
987 cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
988 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
989 + S_DS_GEN);
990
991 /* translate auth mode to 802.11 defined wire value */
992 switch (priv->secinfo.auth_mode) {
993 case IW_AUTH_ALG_OPEN_SYSTEM:
994 pauthenticate->authtype = 0x00;
995 break;
996 case IW_AUTH_ALG_SHARED_KEY:
997 pauthenticate->authtype = 0x01;
998 break;
999 case IW_AUTH_ALG_LEAP:
1000 pauthenticate->authtype = 0x80;
1001 break;
1002 default:
1003 lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
1004 priv->secinfo.auth_mode);
1005 goto out;
1006 }
1007
1008 memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
1009
1010 lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
1011 print_mac(mac, bssid), pauthenticate->authtype);
1012 ret = 0;
1013
1014out:
1015 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
1016 return ret;
1017}
1018
1019int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
1020 struct cmd_ds_command *cmd)
1021{
1022 struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
1023
1024 lbs_deb_enter(LBS_DEB_JOIN);
1025
1026 cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
1027 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
1028 S_DS_GEN);
1029
1030 /* set AP MAC address */
1031 memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN);
1032
1033 /* Reason code 3 = Station is leaving */
1034#define REASON_CODE_STA_LEAVING 3
1035 dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
1036
1037 lbs_deb_leave(LBS_DEB_JOIN);
1038 return 0;
1039}
1040
1041int lbs_cmd_80211_associate(struct lbs_private *priv,
1042 struct cmd_ds_command *cmd, void *pdata_buf)
1043{
1044 struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
1045 int ret = 0;
1046 struct assoc_request *assoc_req = pdata_buf;
1047 struct bss_descriptor *bss = &assoc_req->bss;
1048 u8 *pos;
1049 u16 tmpcap, tmplen;
1050 struct mrvlietypes_ssidparamset *ssid;
1051 struct mrvlietypes_phyparamset *phy;
1052 struct mrvlietypes_ssparamset *ss;
1053 struct mrvlietypes_ratesparamset *rates;
1054 struct mrvlietypes_rsnparamset *rsn;
1055
1056 lbs_deb_enter(LBS_DEB_ASSOC);
1057
1058 pos = (u8 *) passo;
1059
1060 if (!priv) {
1061 ret = -1;
1062 goto done;
1063 }
1064
1065 cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
1066
1067 memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
1068 pos += sizeof(passo->peerstaaddr);
1069
1070 /* set the listen interval */
1071 passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
1072
1073 pos += sizeof(passo->capability);
1074 pos += sizeof(passo->listeninterval);
1075 pos += sizeof(passo->bcnperiod);
1076 pos += sizeof(passo->dtimperiod);
1077
1078 ssid = (struct mrvlietypes_ssidparamset *) pos;
1079 ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
1080 tmplen = bss->ssid_len;
1081 ssid->header.len = cpu_to_le16(tmplen);
1082 memcpy(ssid->ssid, bss->ssid, tmplen);
1083 pos += sizeof(ssid->header) + tmplen;
1084
1085 phy = (struct mrvlietypes_phyparamset *) pos;
1086 phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
1087 tmplen = sizeof(phy->fh_ds.dsparamset);
1088 phy->header.len = cpu_to_le16(tmplen);
1089 memcpy(&phy->fh_ds.dsparamset,
1090 &bss->phyparamset.dsparamset.currentchan,
1091 tmplen);
1092 pos += sizeof(phy->header) + tmplen;
1093
1094 ss = (struct mrvlietypes_ssparamset *) pos;
1095 ss->header.type = cpu_to_le16(TLV_TYPE_CF);
1096 tmplen = sizeof(ss->cf_ibss.cfparamset);
1097 ss->header.len = cpu_to_le16(tmplen);
1098 pos += sizeof(ss->header) + tmplen;
1099
1100 rates = (struct mrvlietypes_ratesparamset *) pos;
1101 rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
1102 memcpy(&rates->rates, &bss->rates, MAX_RATES);
1103 tmplen = MAX_RATES;
1104 if (get_common_rates(priv, rates->rates, &tmplen)) {
1105 ret = -1;
1106 goto done;
1107 }
1108 pos += sizeof(rates->header) + tmplen;
1109 rates->header.len = cpu_to_le16(tmplen);
1110 lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
1111
1112 /* Copy the infra. association rates into Current BSS state structure */
1113 memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
1114 memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
1115
1116 /* Set MSB on basic rates as the firmware requires, but _after_
1117 * copying to current bss rates.
1118 */
1119 lbs_set_basic_rate_flags(rates->rates, tmplen);
1120
1121 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
1122 rsn = (struct mrvlietypes_rsnparamset *) pos;
1123 /* WPA_IE or WPA2_IE */
1124 rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
1125 tmplen = (u16) assoc_req->wpa_ie[1];
1126 rsn->header.len = cpu_to_le16(tmplen);
1127 memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
1128 lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
1129 sizeof(rsn->header) + tmplen);
1130 pos += sizeof(rsn->header) + tmplen;
1131 }
1132
1133 /* update curbssparams */
1134 priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
1135
1136 if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
1137 ret = -1;
1138 goto done;
1139 }
1140
1141 cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
1142
1143 /* set the capability info */
1144 tmpcap = (bss->capability & CAPINFO_MASK);
1145 if (bss->mode == IW_MODE_INFRA)
1146 tmpcap |= WLAN_CAPABILITY_ESS;
1147 passo->capability = cpu_to_le16(tmpcap);
1148 lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
1149
1150done:
1151 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1152 return ret;
1153}
1154
1155int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
1156 struct cmd_ds_command *cmd, void *pdata_buf)
1157{
1158 struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
1159 int ret = 0;
1160 int cmdappendsize = 0;
1161 struct assoc_request *assoc_req = pdata_buf;
1162 u16 tmpcap = 0;
1163 size_t ratesize = 0;
1164
1165 lbs_deb_enter(LBS_DEB_JOIN);
1166
1167 if (!priv) {
1168 ret = -1;
1169 goto done;
1170 }
1171
1172 cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
1173
1174 /*
1175 * Fill in the parameters for 2 data structures:
1176 * 1. cmd_ds_802_11_ad_hoc_start command
1177 * 2. priv->scantable[i]
1178 *
1179 * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
1180 * probe delay, and cap info.
1181 *
1182 * Firmware will fill up beacon period, DTIM, Basic rates
1183 * and operational rates.
1184 */
1185
1186 memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
1187 memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
1188
1189 lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
1190 escape_essid(assoc_req->ssid, assoc_req->ssid_len),
1191 assoc_req->ssid_len);
1192
1193 /* set the BSS type */
1194 adhs->bsstype = CMD_BSS_TYPE_IBSS;
1195 priv->mode = IW_MODE_ADHOC;
1196 if (priv->beacon_period == 0)
1197 priv->beacon_period = MRVDRV_BEACON_INTERVAL;
1198 adhs->beaconperiod = cpu_to_le16(priv->beacon_period);
1199
1200 /* set Physical param set */
1201#define DS_PARA_IE_ID 3
1202#define DS_PARA_IE_LEN 1
1203
1204 adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
1205 adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
1206
1207 WARN_ON(!assoc_req->channel);
1208
1209 lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
1210 assoc_req->channel);
1211
1212 adhs->phyparamset.dsparamset.currentchan = assoc_req->channel;
1213
1214 /* set IBSS param set */
1215#define IBSS_PARA_IE_ID 6
1216#define IBSS_PARA_IE_LEN 2
1217
1218 adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
1219 adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
1220 adhs->ssparamset.ibssparamset.atimwindow = 0;
1221
1222 /* set capability info */
1223 tmpcap = WLAN_CAPABILITY_IBSS;
1224 if (assoc_req->secinfo.wep_enabled) {
1225 lbs_deb_join("ADHOC_S_CMD: WEP enabled, "
1226 "setting privacy on\n");
1227 tmpcap |= WLAN_CAPABILITY_PRIVACY;
1228 } else {
1229 lbs_deb_join("ADHOC_S_CMD: WEP disabled, "
1230 "setting privacy off\n");
1231 }
1232 adhs->capability = cpu_to_le16(tmpcap);
1233
1234 /* probedelay */
1235 adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
1236
1237 memset(adhs->rates, 0, sizeof(adhs->rates));
1238 ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates));
1239 memcpy(adhs->rates, lbs_bg_rates, ratesize);
1240
1241 /* Copy the ad-hoc creating rates into Current BSS state structure */
1242 memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
1243 memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize);
1244
1245 /* Set MSB on basic rates as the firmware requires, but _after_
1246 * copying to current bss rates.
1247 */
1248 lbs_set_basic_rate_flags(adhs->rates, ratesize);
1249
1250 lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
1251 adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
1252
1253 lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
1254
1255 if (lbs_create_dnld_countryinfo_11d(priv)) {
1256 lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
1257 ret = -1;
1258 goto done;
1259 }
1260
1261 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) +
1262 S_DS_GEN + cmdappendsize);
1263
1264 ret = 0;
1265done:
1266 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
1267 return ret;
1268}
1269
1270int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd)
1271{
1272 cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
1273 cmd->size = cpu_to_le16(S_DS_GEN);
1274
1275 return 0;
1276}
1277
1278int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
1279 struct cmd_ds_command *cmd, void *pdata_buf)
1280{
1281 struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
1282 struct assoc_request *assoc_req = pdata_buf;
1283 struct bss_descriptor *bss = &assoc_req->bss;
1284 int cmdappendsize = 0;
1285 int ret = 0;
1286 u16 ratesize = 0;
1287 DECLARE_MAC_BUF(mac);
1288
1289 lbs_deb_enter(LBS_DEB_JOIN);
1290
1291 cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
1292
1293 join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
1294 join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
1295
1296 memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
1297 memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
1298
1299 memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
1300 sizeof(union ieeetypes_phyparamset));
1301
1302 memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
1303 sizeof(union IEEEtypes_ssparamset));
1304
1305 join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
1306 lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
1307 bss->capability, CAPINFO_MASK);
1308
1309 /* information on BSSID descriptor passed to FW */
1310 lbs_deb_join(
1311 "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
1312 print_mac(mac, join_cmd->bss.bssid),
1313 join_cmd->bss.ssid);
1314
1315 /* failtimeout */
1316 join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
1317
1318 /* probedelay */
1319 join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
1320
1321 priv->curbssparams.channel = bss->channel;
1322
1323 /* Copy Data rates from the rates recorded in scan response */
1324 memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
1325 ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
1326 memcpy(join_cmd->bss.rates, bss->rates, ratesize);
1327 if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) {
1328 lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
1329 ret = -1;
1330 goto done;
1331 }
1332
1333 /* Copy the ad-hoc creating rates into Current BSS state structure */
1334 memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
1335 memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize);
1336
1337 /* Set MSB on basic rates as the firmware requires, but _after_
1338 * copying to current bss rates.
1339 */
1340 lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
1341
1342 join_cmd->bss.ssparamset.ibssparamset.atimwindow =
1343 cpu_to_le16(bss->atimwindow);
1344
1345 if (assoc_req->secinfo.wep_enabled) {
1346 u16 tmp = le16_to_cpu(join_cmd->bss.capability);
1347 tmp |= WLAN_CAPABILITY_PRIVACY;
1348 join_cmd->bss.capability = cpu_to_le16(tmp);
1349 }
1350
1351 if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
1352 /* wake up first */
1353 __le32 Localpsmode;
1354
1355 Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
1356 ret = lbs_prepare_and_send_command(priv,
1357 CMD_802_11_PS_MODE,
1358 CMD_ACT_SET,
1359 0, 0, &Localpsmode);
1360
1361 if (ret) {
1362 ret = -1;
1363 goto done;
1364 }
1365 }
1366
1367 if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
1368 ret = -1;
1369 goto done;
1370 }
1371
1372 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) +
1373 S_DS_GEN + cmdappendsize);
1374
1375done:
1376 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
1377 return ret;
1378}
1379
1380int lbs_ret_80211_associate(struct lbs_private *priv,
1381 struct cmd_ds_command *resp)
1382{
1383 int ret = 0;
1384 union iwreq_data wrqu;
1385 struct ieeetypes_assocrsp *passocrsp;
1386 struct bss_descriptor *bss;
1387 u16 status_code;
1388
1389 lbs_deb_enter(LBS_DEB_ASSOC);
1390
1391 if (!priv->in_progress_assoc_req) {
1392 lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
1393 ret = -1;
1394 goto done;
1395 }
1396 bss = &priv->in_progress_assoc_req->bss;
1397
1398 passocrsp = (struct ieeetypes_assocrsp *) &resp->params;
1399
1400 /*
1401 * Older FW versions map the IEEE 802.11 Status Code in the association
1402 * response to the following values returned in passocrsp->statuscode:
1403 *
1404 * IEEE Status Code Marvell Status Code
1405 * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
1406 * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
1407 * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
1408 * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
1409 * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
1410 * others -> 0x0003 ASSOC_RESULT_REFUSED
1411 *
1412 * Other response codes:
1413 * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
1414 * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
1415 * association response from the AP)
1416 */
1417
1418 status_code = le16_to_cpu(passocrsp->statuscode);
1419 switch (status_code) {
1420 case 0x00:
1421 break;
1422 case 0x01:
1423 lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
1424 break;
1425 case 0x02:
1426 lbs_deb_assoc("ASSOC_RESP: internal timer "
1427 "expired while waiting for the AP\n");
1428 break;
1429 case 0x03:
1430 lbs_deb_assoc("ASSOC_RESP: association "
1431 "refused by AP\n");
1432 break;
1433 case 0x04:
1434 lbs_deb_assoc("ASSOC_RESP: authentication "
1435 "refused by AP\n");
1436 break;
1437 default:
1438 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
1439 " unknown\n", status_code);
1440 break;
1441 }
1442
1443 if (status_code) {
1444 lbs_mac_event_disconnected(priv);
1445 ret = -1;
1446 goto done;
1447 }
1448
1449 lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
1450 le16_to_cpu(resp->size) - S_DS_GEN);
1451
1452 /* Send a Media Connected event, according to the Spec */
1453 priv->connect_status = LBS_CONNECTED;
1454
1455 /* Update current SSID and BSSID */
1456 memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
1457 priv->curbssparams.ssid_len = bss->ssid_len;
1458 memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
1459
1460 priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
1461 priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
1462
1463 memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
1464 memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
1465 priv->nextSNRNF = 0;
1466 priv->numSNRNF = 0;
1467
1468 netif_carrier_on(priv->dev);
1469 if (!priv->tx_pending_len)
1470 netif_wake_queue(priv->dev);
1471
1472 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
1473 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1474 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
1475
1476done:
1477 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1478 return ret;
1479}
1480
1481int lbs_ret_80211_disassociate(struct lbs_private *priv)
1482{
1483 lbs_deb_enter(LBS_DEB_JOIN);
1484
1485 lbs_mac_event_disconnected(priv);
1486
1487 lbs_deb_leave(LBS_DEB_JOIN);
1488 return 0;
1489}
1490
1491int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
1492 struct cmd_ds_command *resp)
1493{
1494 int ret = 0;
1495 u16 command = le16_to_cpu(resp->command);
1496 u16 result = le16_to_cpu(resp->result);
1497 struct cmd_ds_802_11_ad_hoc_result *padhocresult;
1498 union iwreq_data wrqu;
1499 struct bss_descriptor *bss;
1500 DECLARE_MAC_BUF(mac);
1501
1502 lbs_deb_enter(LBS_DEB_JOIN);
1503
1504 padhocresult = &resp->params.result;
1505
1506 lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size));
1507 lbs_deb_join("ADHOC_RESP: command = %x\n", command);
1508 lbs_deb_join("ADHOC_RESP: result = %x\n", result);
1509
1510 if (!priv->in_progress_assoc_req) {
1511 lbs_deb_join("ADHOC_RESP: no in-progress association "
1512 "request\n");
1513 ret = -1;
1514 goto done;
1515 }
1516 bss = &priv->in_progress_assoc_req->bss;
1517
1518 /*
1519 * Join result code 0 --> SUCCESS
1520 */
1521 if (result) {
1522 lbs_deb_join("ADHOC_RESP: failed\n");
1523 if (priv->connect_status == LBS_CONNECTED)
1524 lbs_mac_event_disconnected(priv);
1525 ret = -1;
1526 goto done;
1527 }
1528
1529 /*
1530 * Now the join cmd should be successful
1531 * If BSSID has changed use SSID to compare instead of BSSID
1532 */
1533 lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
1534 escape_essid(bss->ssid, bss->ssid_len));
1535
1536 /* Send a Media Connected event, according to the Spec */
1537 priv->connect_status = LBS_CONNECTED;
1538
1539 if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
1540 /* Update the created network descriptor with the new BSSID */
1541 memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
1542 }
1543
1544 /* Set the BSSID from the joined/started descriptor */
1545 memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
1546
1547 /* Set the new SSID to current SSID */
1548 memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
1549 priv->curbssparams.ssid_len = bss->ssid_len;
1550
1551 netif_carrier_on(priv->dev);
1552 if (!priv->tx_pending_len)
1553 netif_wake_queue(priv->dev);
1554
1555 memset(&wrqu, 0, sizeof(wrqu));
1556 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
1557 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1558 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
1559
1560 lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
1561 lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel);
1562 lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
1563 print_mac(mac, padhocresult->bssid));
1564
1565done:
1566 lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
1567 return ret;
1568}
1569
1570int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv)
1571{
1572 lbs_deb_enter(LBS_DEB_JOIN);
1573
1574 lbs_mac_event_disconnected(priv);
1575
1576 lbs_deb_leave(LBS_DEB_JOIN);
1577 return 0;
1578}