blob: cd8e043b16f47a6ea671fd74661958e0b13730be [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/* Copyright (C) 2006, Red Hat, Inc. */
2
3#include <linux/bitops.h>
4#include <net/ieee80211.h>
Dan Williams3cf209312007-05-25 17:28:30 -04005#include <linux/etherdevice.h>
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02006
7#include "assoc.h"
8#include "join.h"
9#include "decl.h"
10#include "hostcmd.h"
11#include "host.h"
Dan Williams2dd4b262007-12-11 16:54:15 -050012#include "cmd.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020013
14
15static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
16static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
17
Dan Williamse76850d2007-05-25 17:09:41 -040018
Holger Schurig69f90322007-11-23 15:43:44 +010019static int assoc_helper_essid(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020020 struct assoc_request * assoc_req)
21{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020022 int ret = 0;
Dan Williamsfcdb53d2007-05-25 16:15:56 -040023 struct bss_descriptor * bss;
Dan Williamsaeea0ab2007-05-25 22:30:48 -040024 int channel = -1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020025
Holger Schurig9012b282007-05-25 11:27:16 -040026 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020027
Dan Williamsef9a2642007-05-25 16:46:33 -040028 /* FIXME: take channel into account when picking SSIDs if a channel
29 * is set.
30 */
31
Dan Williamsaeea0ab2007-05-25 22:30:48 -040032 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
33 channel = assoc_req->channel;
34
Holger Schurig0765af42007-10-15 12:55:56 +020035 lbs_deb_assoc("SSID '%s' requested\n",
Dan Williamsd8efea22007-05-28 23:54:55 -040036 escape_essid(assoc_req->ssid, assoc_req->ssid_len));
Dan Williams0dc5a292007-05-10 22:58:02 -040037 if (assoc_req->mode == IW_MODE_INFRA) {
Holger Schurig10078322007-11-15 18:05:47 -050038 lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
Holger Schurig6e22a852007-08-02 13:05:32 -040039 assoc_req->ssid_len, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020040
David Woodhouseaa21c002007-12-08 20:04:36 +000041 bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
Dan Williamsd8efea22007-05-28 23:54:55 -040042 assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
Dan Williamsfcdb53d2007-05-25 16:15:56 -040043 if (bss != NULL) {
Dan Williamse76850d2007-05-25 17:09:41 -040044 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
Holger Schurig10078322007-11-15 18:05:47 -050045 ret = lbs_associate(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020046 } else {
Dan Williamsd8efea22007-05-28 23:54:55 -040047 lbs_deb_assoc("SSID not found; cannot associate\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020048 }
Dan Williams0dc5a292007-05-10 22:58:02 -040049 } else if (assoc_req->mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020050 /* Scan for the network, do not save previous results. Stale
51 * scan data will cause us to join a non-existant adhoc network
52 */
Holger Schurig10078322007-11-15 18:05:47 -050053 lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
Dan Williamsd8efea22007-05-28 23:54:55 -040054 assoc_req->ssid_len, 1);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020055
56 /* Search for the requested SSID in the scan table */
David Woodhouseaa21c002007-12-08 20:04:36 +000057 bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
Dan Williamsd8efea22007-05-28 23:54:55 -040058 assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
Dan Williamsfcdb53d2007-05-25 16:15:56 -040059 if (bss != NULL) {
Dan Williamsd8efea22007-05-28 23:54:55 -040060 lbs_deb_assoc("SSID found, will join\n");
Dan Williamse76850d2007-05-25 17:09:41 -040061 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
Holger Schurig10078322007-11-15 18:05:47 -050062 lbs_join_adhoc_network(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020063 } else {
64 /* else send START command */
Dan Williamsd8efea22007-05-28 23:54:55 -040065 lbs_deb_assoc("SSID not found, creating adhoc network\n");
Dan Williamse76850d2007-05-25 17:09:41 -040066 memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
Dan Williamsd8efea22007-05-28 23:54:55 -040067 IW_ESSID_MAX_SIZE);
68 assoc_req->bss.ssid_len = assoc_req->ssid_len;
Holger Schurig10078322007-11-15 18:05:47 -050069 lbs_start_adhoc_network(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020070 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020071 }
72
Holger Schurig9012b282007-05-25 11:27:16 -040073 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020074 return ret;
75}
76
77
Holger Schurig69f90322007-11-23 15:43:44 +010078static int assoc_helper_bssid(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020079 struct assoc_request * assoc_req)
80{
Dan Williamsfcdb53d2007-05-25 16:15:56 -040081 int ret = 0;
82 struct bss_descriptor * bss;
Joe Perches0795af52007-10-03 17:59:30 -070083 DECLARE_MAC_BUF(mac);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020084
Joe Perches0795af52007-10-03 17:59:30 -070085 lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
86 print_mac(mac, assoc_req->bssid));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020087
88 /* Search for index position in list for requested MAC */
David Woodhouseaa21c002007-12-08 20:04:36 +000089 bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020090 assoc_req->mode);
Dan Williamsfcdb53d2007-05-25 16:15:56 -040091 if (bss == NULL) {
Joe Perches0795af52007-10-03 17:59:30 -070092 lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
93 "cannot associate.\n", print_mac(mac, assoc_req->bssid));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020094 goto out;
95 }
96
Dan Williamse76850d2007-05-25 17:09:41 -040097 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
Dan Williams0dc5a292007-05-10 22:58:02 -040098 if (assoc_req->mode == IW_MODE_INFRA) {
Holger Schurig10078322007-11-15 18:05:47 -050099 ret = lbs_associate(priv, assoc_req);
100 lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
Dan Williams0dc5a292007-05-10 22:58:02 -0400101 } else if (assoc_req->mode == IW_MODE_ADHOC) {
Holger Schurig10078322007-11-15 18:05:47 -0500102 lbs_join_adhoc_network(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200103 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200104
105out:
Holger Schurig9012b282007-05-25 11:27:16 -0400106 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200107 return ret;
108}
109
110
Holger Schurig69f90322007-11-23 15:43:44 +0100111static int assoc_helper_associate(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200112 struct assoc_request * assoc_req)
113{
114 int ret = 0, done = 0;
115
Holger Schurig0765af42007-10-15 12:55:56 +0200116 lbs_deb_enter(LBS_DEB_ASSOC);
117
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200118 /* If we're given and 'any' BSSID, try associating based on SSID */
119
120 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
Dan Williams3cf209312007-05-25 17:28:30 -0400121 if (compare_ether_addr(bssid_any, assoc_req->bssid)
122 && compare_ether_addr(bssid_off, assoc_req->bssid)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200123 ret = assoc_helper_bssid(priv, assoc_req);
124 done = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200125 }
126 }
127
128 if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
129 ret = assoc_helper_essid(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200130 }
131
Holger Schurig0765af42007-10-15 12:55:56 +0200132 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200133 return ret;
134}
135
136
Holger Schurig69f90322007-11-23 15:43:44 +0100137static int assoc_helper_mode(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200138 struct assoc_request * assoc_req)
139{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200140 int ret = 0;
141
Holger Schurig9012b282007-05-25 11:27:16 -0400142 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200143
David Woodhouseaa21c002007-12-08 20:04:36 +0000144 if (assoc_req->mode == priv->mode)
Holger Schurig9012b282007-05-25 11:27:16 -0400145 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200146
Dan Williams0dc5a292007-05-10 22:58:02 -0400147 if (assoc_req->mode == IW_MODE_INFRA) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000148 if (priv->psstate != PS_STATE_FULL_POWER)
Holger Schurig10078322007-11-15 18:05:47 -0500149 lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
David Woodhouseaa21c002007-12-08 20:04:36 +0000150 priv->psmode = LBS802_11POWERMODECAM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200151 }
152
David Woodhouseaa21c002007-12-08 20:04:36 +0000153 priv->mode = assoc_req->mode;
Holger Schurig10078322007-11-15 18:05:47 -0500154 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400155 CMD_802_11_SNMP_MIB,
156 0, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200157 OID_802_11_INFRASTRUCTURE_MODE,
David Woodhouse981f1872007-05-25 23:36:54 -0400158 /* Shoot me now */ (void *) (size_t) assoc_req->mode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200159
Holger Schurig9012b282007-05-25 11:27:16 -0400160done:
161 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200162 return ret;
163}
164
165
David Woodhouse9f462572007-12-12 22:50:21 -0500166int lbs_update_channel(struct lbs_private *priv)
Dan Williamsef9a2642007-05-25 16:46:33 -0400167{
Holger Schurig0765af42007-10-15 12:55:56 +0200168 int ret;
Dan Williams2dd4b262007-12-11 16:54:15 -0500169
Dan Williamsef9a2642007-05-25 16:46:33 -0400170 /* the channel in f/w could be out of sync, get the current channel */
Holger Schurig0765af42007-10-15 12:55:56 +0200171 lbs_deb_enter(LBS_DEB_ASSOC);
Dan Williams2dd4b262007-12-11 16:54:15 -0500172
173 ret = lbs_get_channel(priv);
174 if (ret > 0)
175 priv->curbssparams.channel = (u8) ret;
176
Holger Schurig0765af42007-10-15 12:55:56 +0200177 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
178 return ret;
Dan Williamsef9a2642007-05-25 16:46:33 -0400179}
180
Holger Schurig10078322007-11-15 18:05:47 -0500181void lbs_sync_channel(struct work_struct *work)
Luis Carlos Cobo Rusb8bedef2007-05-30 12:14:34 -0400182{
Holger Schurig69f90322007-11-23 15:43:44 +0100183 struct lbs_private *priv = container_of(work, struct lbs_private,
184 sync_channel);
Luis Carlos Cobo Rusb8bedef2007-05-30 12:14:34 -0400185
Holger Schurig0765af42007-10-15 12:55:56 +0200186 lbs_deb_enter(LBS_DEB_ASSOC);
David Woodhouse9f462572007-12-12 22:50:21 -0500187 if (lbs_update_channel(priv))
Luis Carlos Cobo Rusb8bedef2007-05-30 12:14:34 -0400188 lbs_pr_info("Channel synchronization failed.");
Holger Schurig0765af42007-10-15 12:55:56 +0200189 lbs_deb_leave(LBS_DEB_ASSOC);
Luis Carlos Cobo Rusb8bedef2007-05-30 12:14:34 -0400190}
191
Holger Schurig69f90322007-11-23 15:43:44 +0100192static int assoc_helper_channel(struct lbs_private *priv,
Dan Williamsef9a2642007-05-25 16:46:33 -0400193 struct assoc_request * assoc_req)
194{
Dan Williamsef9a2642007-05-25 16:46:33 -0400195 int ret = 0;
196
197 lbs_deb_enter(LBS_DEB_ASSOC);
198
David Woodhouse9f462572007-12-12 22:50:21 -0500199 ret = lbs_update_channel(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400200 if (ret < 0) {
David Woodhouse23d36ee2007-12-12 00:14:21 -0500201 lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
Dan Williamsef9a2642007-05-25 16:46:33 -0400202 }
203
David Woodhouseaa21c002007-12-08 20:04:36 +0000204 if (assoc_req->channel == priv->curbssparams.channel)
Dan Williamsef9a2642007-05-25 16:46:33 -0400205 goto done;
206
David Woodhouse8642f1f2007-12-11 20:03:01 -0500207 if (priv->mesh_dev) {
David Woodhouse86062132007-12-13 00:32:36 -0500208 /* Change mesh channel first; 21.p21 firmware won't let
209 you change channel otherwise (even though it'll return
210 an error to this */
211 lbs_mesh_config(priv, 0, assoc_req->channel);
David Woodhouse8642f1f2007-12-11 20:03:01 -0500212 }
213
Dan Williamsef9a2642007-05-25 16:46:33 -0400214 lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
David Woodhouse86062132007-12-13 00:32:36 -0500215 priv->curbssparams.channel, assoc_req->channel);
Dan Williamsef9a2642007-05-25 16:46:33 -0400216
Dan Williams2dd4b262007-12-11 16:54:15 -0500217 ret = lbs_set_channel(priv, assoc_req->channel);
218 if (ret < 0)
David Woodhouse23d36ee2007-12-12 00:14:21 -0500219 lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
Dan Williamsef9a2642007-05-25 16:46:33 -0400220
Dan Williams2dd4b262007-12-11 16:54:15 -0500221 /* FIXME: shouldn't need to grab the channel _again_ after setting
222 * it since the firmware is supposed to return the new channel, but
223 * whatever... */
David Woodhouse9f462572007-12-12 22:50:21 -0500224 ret = lbs_update_channel(priv);
Dan Williams2dd4b262007-12-11 16:54:15 -0500225 if (ret < 0)
David Woodhouse23d36ee2007-12-12 00:14:21 -0500226 lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
Dan Williamsef9a2642007-05-25 16:46:33 -0400227
David Woodhouseaa21c002007-12-08 20:04:36 +0000228 if (assoc_req->channel != priv->curbssparams.channel) {
David Woodhouse88ae2912007-12-11 19:57:05 -0500229 lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
Dan Williamsef9a2642007-05-25 16:46:33 -0400230 assoc_req->channel);
David Woodhouse8642f1f2007-12-11 20:03:01 -0500231 goto restore_mesh;
Dan Williamsef9a2642007-05-25 16:46:33 -0400232 }
233
234 if ( assoc_req->secinfo.wep_enabled
235 && (assoc_req->wep_keys[0].len
236 || assoc_req->wep_keys[1].len
237 || assoc_req->wep_keys[2].len
238 || assoc_req->wep_keys[3].len)) {
239 /* Make sure WEP keys are re-sent to firmware */
240 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
241 }
242
243 /* Must restart/rejoin adhoc networks after channel change */
David Woodhouse23d36ee2007-12-12 00:14:21 -0500244 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
Dan Williamsef9a2642007-05-25 16:46:33 -0400245
David Woodhouse8642f1f2007-12-11 20:03:01 -0500246 restore_mesh:
247 if (priv->mesh_dev)
David Woodhouse86062132007-12-13 00:32:36 -0500248 lbs_mesh_config(priv, 1, priv->curbssparams.channel);
David Woodhouse8642f1f2007-12-11 20:03:01 -0500249
250 done:
Dan Williamsef9a2642007-05-25 16:46:33 -0400251 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
252 return ret;
253}
254
255
Holger Schurig69f90322007-11-23 15:43:44 +0100256static int assoc_helper_wep_keys(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200257 struct assoc_request * assoc_req)
258{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200259 int i;
260 int ret = 0;
261
Holger Schurig9012b282007-05-25 11:27:16 -0400262 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200263
264 /* Set or remove WEP keys */
265 if ( assoc_req->wep_keys[0].len
266 || assoc_req->wep_keys[1].len
267 || assoc_req->wep_keys[2].len
268 || assoc_req->wep_keys[3].len) {
Holger Schurig10078322007-11-15 18:05:47 -0500269 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400270 CMD_802_11_SET_WEP,
271 CMD_ACT_ADD,
272 CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200273 0, assoc_req);
274 } else {
Holger Schurig10078322007-11-15 18:05:47 -0500275 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400276 CMD_802_11_SET_WEP,
277 CMD_ACT_REMOVE,
278 CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200279 0, NULL);
280 }
281
282 if (ret)
283 goto out;
284
285 /* enable/disable the MAC's WEP packet filter */
Dan Williams889c05b2007-05-10 22:57:23 -0400286 if (assoc_req->secinfo.wep_enabled)
David Woodhouseaa21c002007-12-08 20:04:36 +0000287 priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200288 else
David Woodhouseaa21c002007-12-08 20:04:36 +0000289 priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
Holger Schurig10078322007-11-15 18:05:47 -0500290 ret = lbs_set_mac_packet_filter(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200291 if (ret)
292 goto out;
293
David Woodhouseaa21c002007-12-08 20:04:36 +0000294 mutex_lock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200295
David Woodhouseaa21c002007-12-08 20:04:36 +0000296 /* Copy WEP keys into priv wep key fields */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200297 for (i = 0; i < 4; i++) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000298 memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
Dan Williams1443b652007-08-02 10:45:55 -0400299 sizeof(struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200300 }
David Woodhouseaa21c002007-12-08 20:04:36 +0000301 priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200302
David Woodhouseaa21c002007-12-08 20:04:36 +0000303 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200304
305out:
Holger Schurig9012b282007-05-25 11:27:16 -0400306 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200307 return ret;
308}
309
Holger Schurig69f90322007-11-23 15:43:44 +0100310static int assoc_helper_secinfo(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200311 struct assoc_request * assoc_req)
312{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200313 int ret = 0;
Dan Williams18c96c342007-06-18 12:01:12 -0400314 u32 do_wpa;
315 u32 rsn = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200316
Holger Schurig9012b282007-05-25 11:27:16 -0400317 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200318
David Woodhouseaa21c002007-12-08 20:04:36 +0000319 memcpy(&priv->secinfo, &assoc_req->secinfo,
Holger Schurig10078322007-11-15 18:05:47 -0500320 sizeof(struct lbs_802_11_security));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200321
Holger Schurig10078322007-11-15 18:05:47 -0500322 ret = lbs_set_mac_packet_filter(priv);
Dan Williams90a42212007-05-25 23:01:24 -0400323 if (ret)
324 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200325
Dan Williams18c96c342007-06-18 12:01:12 -0400326 /* If RSN is already enabled, don't try to enable it again, since
327 * ENABLE_RSN resets internal state machines and will clobber the
328 * 4-way WPA handshake.
329 */
330
331 /* Get RSN enabled/disabled */
Holger Schurig10078322007-11-15 18:05:47 -0500332 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400333 CMD_802_11_ENABLE_RSN,
334 CMD_ACT_GET,
335 CMD_OPTION_WAITFORRSP,
Dan Williams18c96c342007-06-18 12:01:12 -0400336 0, &rsn);
337 if (ret) {
David Woodhouse23d36ee2007-12-12 00:14:21 -0500338 lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
Dan Williams18c96c342007-06-18 12:01:12 -0400339 goto out;
340 }
341
342 /* Don't re-enable RSN if it's already enabled */
343 do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled);
344 if (do_wpa == rsn)
345 goto out;
346
347 /* Set RSN enabled/disabled */
348 rsn = do_wpa;
Holger Schurig10078322007-11-15 18:05:47 -0500349 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400350 CMD_802_11_ENABLE_RSN,
351 CMD_ACT_SET,
352 CMD_OPTION_WAITFORRSP,
Dan Williams18c96c342007-06-18 12:01:12 -0400353 0, &rsn);
Dan Williams90a42212007-05-25 23:01:24 -0400354
355out:
Holger Schurig9012b282007-05-25 11:27:16 -0400356 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200357 return ret;
358}
359
360
Holger Schurig69f90322007-11-23 15:43:44 +0100361static int assoc_helper_wpa_keys(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200362 struct assoc_request * assoc_req)
363{
364 int ret = 0;
Dan Williams2bcde512007-10-03 10:37:45 -0400365 unsigned int flags = assoc_req->flags;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200366
Holger Schurig9012b282007-05-25 11:27:16 -0400367 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200368
Dan Williams2bcde512007-10-03 10:37:45 -0400369 /* Work around older firmware bug where WPA unicast and multicast
370 * keys must be set independently. Seen in SDIO parts with firmware
371 * version 5.0.11p0.
372 */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200373
Dan Williams2bcde512007-10-03 10:37:45 -0400374 if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
375 clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -0500376 ret = lbs_prepare_and_send_command(priv,
Dan Williams2bcde512007-10-03 10:37:45 -0400377 CMD_802_11_KEY_MATERIAL,
378 CMD_ACT_SET,
379 CMD_OPTION_WAITFORRSP,
380 0, assoc_req);
381 assoc_req->flags = flags;
382 }
383
384 if (ret)
385 goto out;
386
387 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
388 clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
389
Holger Schurig10078322007-11-15 18:05:47 -0500390 ret = lbs_prepare_and_send_command(priv,
Dan Williams2bcde512007-10-03 10:37:45 -0400391 CMD_802_11_KEY_MATERIAL,
392 CMD_ACT_SET,
393 CMD_OPTION_WAITFORRSP,
394 0, assoc_req);
395 assoc_req->flags = flags;
396 }
397
398out:
Holger Schurig9012b282007-05-25 11:27:16 -0400399 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200400 return ret;
401}
402
403
Holger Schurig69f90322007-11-23 15:43:44 +0100404static int assoc_helper_wpa_ie(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200405 struct assoc_request * assoc_req)
406{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200407 int ret = 0;
408
Holger Schurig9012b282007-05-25 11:27:16 -0400409 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200410
411 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000412 memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
413 priv->wpa_ie_len = assoc_req->wpa_ie_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200414 } else {
David Woodhouseaa21c002007-12-08 20:04:36 +0000415 memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
416 priv->wpa_ie_len = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200417 }
418
Holger Schurig9012b282007-05-25 11:27:16 -0400419 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200420 return ret;
421}
422
423
David Woodhouseaa21c002007-12-08 20:04:36 +0000424static int should_deauth_infrastructure(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200425 struct assoc_request * assoc_req)
426{
Holger Schurig0765af42007-10-15 12:55:56 +0200427 int ret = 0;
428
429 lbs_deb_enter(LBS_DEB_ASSOC);
430
David Woodhouseaa21c002007-12-08 20:04:36 +0000431 if (priv->connect_status != LBS_CONNECTED)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200432 return 0;
433
434 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
Holger Schurig0765af42007-10-15 12:55:56 +0200435 lbs_deb_assoc("Deauthenticating due to new SSID\n");
436 ret = 1;
437 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200438 }
439
440 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000441 if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
Holger Schurig0765af42007-10-15 12:55:56 +0200442 lbs_deb_assoc("Deauthenticating due to new security\n");
443 ret = 1;
444 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200445 }
446 }
447
448 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
Holger Schurig0765af42007-10-15 12:55:56 +0200449 lbs_deb_assoc("Deauthenticating due to new BSSID\n");
450 ret = 1;
451 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200452 }
453
Luis Carlos Cobo Rusfff47f12007-05-30 12:16:13 -0400454 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
Holger Schurig0765af42007-10-15 12:55:56 +0200455 lbs_deb_assoc("Deauthenticating due to channel switch\n");
456 ret = 1;
457 goto out;
Luis Carlos Cobo Rusfff47f12007-05-30 12:16:13 -0400458 }
459
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200460 /* FIXME: deal with 'auto' mode somehow */
461 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
Holger Schurig0765af42007-10-15 12:55:56 +0200462 if (assoc_req->mode != IW_MODE_INFRA) {
463 lbs_deb_assoc("Deauthenticating due to leaving "
464 "infra mode\n");
465 ret = 1;
466 goto out;
467 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200468 }
469
Holger Schurig0765af42007-10-15 12:55:56 +0200470out:
471 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200472 return 0;
473}
474
475
David Woodhouseaa21c002007-12-08 20:04:36 +0000476static int should_stop_adhoc(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200477 struct assoc_request * assoc_req)
478{
Holger Schurig0765af42007-10-15 12:55:56 +0200479 lbs_deb_enter(LBS_DEB_ASSOC);
480
David Woodhouseaa21c002007-12-08 20:04:36 +0000481 if (priv->connect_status != LBS_CONNECTED)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200482 return 0;
483
David Woodhouseaa21c002007-12-08 20:04:36 +0000484 if (lbs_ssid_cmp(priv->curbssparams.ssid,
485 priv->curbssparams.ssid_len,
Dan Williamsd8efea22007-05-28 23:54:55 -0400486 assoc_req->ssid, assoc_req->ssid_len) != 0)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200487 return 1;
488
489 /* FIXME: deal with 'auto' mode somehow */
490 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400491 if (assoc_req->mode != IW_MODE_ADHOC)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200492 return 1;
493 }
494
Dan Williamsef9a2642007-05-25 16:46:33 -0400495 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000496 if (assoc_req->channel != priv->curbssparams.channel)
Dan Williamsef9a2642007-05-25 16:46:33 -0400497 return 1;
498 }
499
Holger Schurig0765af42007-10-15 12:55:56 +0200500 lbs_deb_leave(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200501 return 0;
502}
503
504
Holger Schurig10078322007-11-15 18:05:47 -0500505void lbs_association_worker(struct work_struct *work)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200506{
Holger Schurig69f90322007-11-23 15:43:44 +0100507 struct lbs_private *priv = container_of(work, struct lbs_private,
508 assoc_work.work);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200509 struct assoc_request * assoc_req = NULL;
510 int ret = 0;
511 int find_any_ssid = 0;
Joe Perches0795af52007-10-03 17:59:30 -0700512 DECLARE_MAC_BUF(mac);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200513
Holger Schurig9012b282007-05-25 11:27:16 -0400514 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200515
David Woodhouseaa21c002007-12-08 20:04:36 +0000516 mutex_lock(&priv->lock);
517 assoc_req = priv->pending_assoc_req;
518 priv->pending_assoc_req = NULL;
519 priv->in_progress_assoc_req = assoc_req;
520 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200521
Holger Schurig9012b282007-05-25 11:27:16 -0400522 if (!assoc_req)
523 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200524
Holger Schurig0765af42007-10-15 12:55:56 +0200525 lbs_deb_assoc(
526 "Association Request:\n"
527 " flags: 0x%08lx\n"
528 " SSID: '%s'\n"
529 " chann: %d\n"
530 " band: %d\n"
531 " mode: %d\n"
532 " BSSID: %s\n"
533 " secinfo: %s%s%s\n"
534 " auth_mode: %d\n",
535 assoc_req->flags,
536 escape_essid(assoc_req->ssid, assoc_req->ssid_len),
537 assoc_req->channel, assoc_req->band, assoc_req->mode,
538 print_mac(mac, assoc_req->bssid),
539 assoc_req->secinfo.WPAenabled ? " WPA" : "",
540 assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
541 assoc_req->secinfo.wep_enabled ? " WEP" : "",
542 assoc_req->secinfo.auth_mode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200543
544 /* If 'any' SSID was specified, find an SSID to associate with */
545 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
Dan Williamsd8efea22007-05-28 23:54:55 -0400546 && !assoc_req->ssid_len)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200547 find_any_ssid = 1;
548
549 /* But don't use 'any' SSID if there's a valid locked BSSID to use */
550 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
Dan Williams3cf209312007-05-25 17:28:30 -0400551 if (compare_ether_addr(assoc_req->bssid, bssid_any)
552 && compare_ether_addr(assoc_req->bssid, bssid_off))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200553 find_any_ssid = 0;
554 }
555
556 if (find_any_ssid) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400557 u8 new_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200558
Holger Schurig10078322007-11-15 18:05:47 -0500559 ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
Dan Williamsd8efea22007-05-28 23:54:55 -0400560 &assoc_req->ssid_len, assoc_req->mode, &new_mode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200561 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400562 lbs_deb_assoc("Could not find best network\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200563 ret = -ENETUNREACH;
564 goto out;
565 }
566
567 /* Ensure we switch to the mode of the AP */
Dan Williams0dc5a292007-05-10 22:58:02 -0400568 if (assoc_req->mode == IW_MODE_AUTO) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200569 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
570 assoc_req->mode = new_mode;
571 }
572 }
573
574 /*
575 * Check if the attributes being changing require deauthentication
576 * from the currently associated infrastructure access point.
577 */
David Woodhouseaa21c002007-12-08 20:04:36 +0000578 if (priv->mode == IW_MODE_INFRA) {
579 if (should_deauth_infrastructure(priv, assoc_req)) {
Holger Schurig10078322007-11-15 18:05:47 -0500580 ret = lbs_send_deauthentication(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200581 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400582 lbs_deb_assoc("Deauthentication due to new "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200583 "configuration request failed: %d\n",
584 ret);
585 }
586 }
David Woodhouseaa21c002007-12-08 20:04:36 +0000587 } else if (priv->mode == IW_MODE_ADHOC) {
588 if (should_stop_adhoc(priv, assoc_req)) {
Holger Schurig10078322007-11-15 18:05:47 -0500589 ret = lbs_stop_adhoc_network(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200590 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400591 lbs_deb_assoc("Teardown of AdHoc network due to "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200592 "new configuration request failed: %d\n",
593 ret);
594 }
595
596 }
597 }
598
599 /* Send the various configuration bits to the firmware */
600 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
601 ret = assoc_helper_mode(priv, assoc_req);
Holger Schurig0765af42007-10-15 12:55:56 +0200602 if (ret)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200603 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200604 }
605
Dan Williamsef9a2642007-05-25 16:46:33 -0400606 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
607 ret = assoc_helper_channel(priv, assoc_req);
Holger Schurig0765af42007-10-15 12:55:56 +0200608 if (ret)
Dan Williamsef9a2642007-05-25 16:46:33 -0400609 goto out;
Dan Williamsef9a2642007-05-25 16:46:33 -0400610 }
611
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200612 if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
613 || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
614 ret = assoc_helper_wep_keys(priv, assoc_req);
Holger Schurig0765af42007-10-15 12:55:56 +0200615 if (ret)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200616 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200617 }
618
619 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
620 ret = assoc_helper_secinfo(priv, assoc_req);
Holger Schurig0765af42007-10-15 12:55:56 +0200621 if (ret)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200622 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200623 }
624
625 if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
626 ret = assoc_helper_wpa_ie(priv, assoc_req);
Holger Schurig0765af42007-10-15 12:55:56 +0200627 if (ret)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200628 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200629 }
630
631 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
632 || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
633 ret = assoc_helper_wpa_keys(priv, assoc_req);
Holger Schurig0765af42007-10-15 12:55:56 +0200634 if (ret)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200635 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200636 }
637
638 /* SSID/BSSID should be the _last_ config option set, because they
639 * trigger the association attempt.
640 */
641 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
642 || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
643 int success = 1;
644
645 ret = assoc_helper_associate(priv, assoc_req);
646 if (ret) {
Holger Schurig91843462007-11-28 14:05:02 +0100647 lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200648 ret);
649 success = 0;
650 }
651
David Woodhouseaa21c002007-12-08 20:04:36 +0000652 if (priv->connect_status != LBS_CONNECTED) {
Holger Schurig91843462007-11-28 14:05:02 +0100653 lbs_deb_assoc("ASSOC: association unsuccessful, "
654 "not connected\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200655 success = 0;
656 }
657
658 if (success) {
Holger Schurig91843462007-11-28 14:05:02 +0100659 lbs_deb_assoc("ASSOC: associated to '%s', %s\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000660 escape_essid(priv->curbssparams.ssid,
661 priv->curbssparams.ssid_len),
662 print_mac(mac, priv->curbssparams.bssid));
Holger Schurig10078322007-11-15 18:05:47 -0500663 lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400664 CMD_802_11_RSSI,
665 0, CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200666
Holger Schurig10078322007-11-15 18:05:47 -0500667 lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400668 CMD_802_11_GET_LOG,
669 0, CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200670 } else {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200671 ret = -1;
672 }
673 }
674
675out:
676 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400677 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200678 ret);
679 }
Dan Williamse76850d2007-05-25 17:09:41 -0400680
David Woodhouseaa21c002007-12-08 20:04:36 +0000681 mutex_lock(&priv->lock);
682 priv->in_progress_assoc_req = NULL;
683 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200684 kfree(assoc_req);
Holger Schurig9012b282007-05-25 11:27:16 -0400685
686done:
687 lbs_deb_leave(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200688}
689
690
691/*
692 * Caller MUST hold any necessary locks
693 */
David Woodhouseaa21c002007-12-08 20:04:36 +0000694struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200695{
696 struct assoc_request * assoc_req;
697
Holger Schurig0765af42007-10-15 12:55:56 +0200698 lbs_deb_enter(LBS_DEB_ASSOC);
David Woodhouseaa21c002007-12-08 20:04:36 +0000699 if (!priv->pending_assoc_req) {
700 priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
Dan Williamse76850d2007-05-25 17:09:41 -0400701 GFP_KERNEL);
David Woodhouseaa21c002007-12-08 20:04:36 +0000702 if (!priv->pending_assoc_req) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200703 lbs_pr_info("Not enough memory to allocate association"
704 " request!\n");
705 return NULL;
706 }
707 }
708
709 /* Copy current configuration attributes to the association request,
710 * but don't overwrite any that are already set.
711 */
David Woodhouseaa21c002007-12-08 20:04:36 +0000712 assoc_req = priv->pending_assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200713 if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000714 memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
Dan Williamsd8efea22007-05-28 23:54:55 -0400715 IW_ESSID_MAX_SIZE);
David Woodhouseaa21c002007-12-08 20:04:36 +0000716 assoc_req->ssid_len = priv->curbssparams.ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200717 }
718
719 if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
David Woodhouseaa21c002007-12-08 20:04:36 +0000720 assoc_req->channel = priv->curbssparams.channel;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200721
Dan Williamse76850d2007-05-25 17:09:41 -0400722 if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
David Woodhouseaa21c002007-12-08 20:04:36 +0000723 assoc_req->band = priv->curbssparams.band;
Dan Williamse76850d2007-05-25 17:09:41 -0400724
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200725 if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
David Woodhouseaa21c002007-12-08 20:04:36 +0000726 assoc_req->mode = priv->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200727
728 if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000729 memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200730 ETH_ALEN);
731 }
732
733 if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
734 int i;
735 for (i = 0; i < 4; i++) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000736 memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
Dan Williams1443b652007-08-02 10:45:55 -0400737 sizeof(struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200738 }
739 }
740
741 if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
David Woodhouseaa21c002007-12-08 20:04:36 +0000742 assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200743
744 if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000745 memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
Dan Williams1443b652007-08-02 10:45:55 -0400746 sizeof(struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200747 }
748
749 if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000750 memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
Dan Williams1443b652007-08-02 10:45:55 -0400751 sizeof(struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200752 }
753
754 if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000755 memcpy(&assoc_req->secinfo, &priv->secinfo,
Holger Schurig10078322007-11-15 18:05:47 -0500756 sizeof(struct lbs_802_11_security));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200757 }
758
759 if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000760 memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200761 MAX_WPA_IE_LEN);
David Woodhouseaa21c002007-12-08 20:04:36 +0000762 assoc_req->wpa_ie_len = priv->wpa_ie_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200763 }
764
Holger Schurig0765af42007-10-15 12:55:56 +0200765 lbs_deb_leave(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200766 return assoc_req;
767}