1 /* Copyright (C) 2006, Red Hat, Inc. */
3 #include <linux/bitops.h>
4 #include <net/ieee80211.h>
5 #include <linux/etherdevice.h>
14 static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
15 static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
18 static int assoc_helper_essid(lbs_private *priv,
19 struct assoc_request * assoc_req)
21 lbs_adapter *adapter = priv->adapter;
23 struct bss_descriptor * bss;
26 lbs_deb_enter(LBS_DEB_ASSOC);
28 /* FIXME: take channel into account when picking SSIDs if a channel
32 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
33 channel = assoc_req->channel;
35 lbs_deb_assoc("SSID '%s' requested\n",
36 escape_essid(assoc_req->ssid, assoc_req->ssid_len));
37 if (assoc_req->mode == IW_MODE_INFRA) {
38 lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
39 assoc_req->ssid_len, 0);
41 bss = lbs_find_ssid_in_list(adapter, assoc_req->ssid,
42 assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
44 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
45 ret = lbs_associate(priv, assoc_req);
47 lbs_deb_assoc("SSID not found; cannot associate\n");
49 } else if (assoc_req->mode == IW_MODE_ADHOC) {
50 /* Scan for the network, do not save previous results. Stale
51 * scan data will cause us to join a non-existant adhoc network
53 lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
54 assoc_req->ssid_len, 1);
56 /* Search for the requested SSID in the scan table */
57 bss = lbs_find_ssid_in_list(adapter, assoc_req->ssid,
58 assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
60 lbs_deb_assoc("SSID found, will join\n");
61 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
62 lbs_join_adhoc_network(priv, assoc_req);
64 /* else send START command */
65 lbs_deb_assoc("SSID not found, creating adhoc network\n");
66 memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
68 assoc_req->bss.ssid_len = assoc_req->ssid_len;
69 lbs_start_adhoc_network(priv, assoc_req);
73 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
78 static int assoc_helper_bssid(lbs_private *priv,
79 struct assoc_request * assoc_req)
81 lbs_adapter *adapter = priv->adapter;
83 struct bss_descriptor * bss;
86 lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
87 print_mac(mac, assoc_req->bssid));
89 /* Search for index position in list for requested MAC */
90 bss = lbs_find_bssid_in_list(adapter, assoc_req->bssid,
93 lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
94 "cannot associate.\n", print_mac(mac, assoc_req->bssid));
98 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
99 if (assoc_req->mode == IW_MODE_INFRA) {
100 ret = lbs_associate(priv, assoc_req);
101 lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
102 } else if (assoc_req->mode == IW_MODE_ADHOC) {
103 lbs_join_adhoc_network(priv, assoc_req);
107 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
112 static int assoc_helper_associate(lbs_private *priv,
113 struct assoc_request * assoc_req)
115 int ret = 0, done = 0;
117 lbs_deb_enter(LBS_DEB_ASSOC);
119 /* If we're given and 'any' BSSID, try associating based on SSID */
121 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
122 if (compare_ether_addr(bssid_any, assoc_req->bssid)
123 && compare_ether_addr(bssid_off, assoc_req->bssid)) {
124 ret = assoc_helper_bssid(priv, assoc_req);
129 if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
130 ret = assoc_helper_essid(priv, assoc_req);
133 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
138 static int assoc_helper_mode(lbs_private *priv,
139 struct assoc_request * assoc_req)
141 lbs_adapter *adapter = priv->adapter;
144 lbs_deb_enter(LBS_DEB_ASSOC);
146 if (assoc_req->mode == adapter->mode)
149 if (assoc_req->mode == IW_MODE_INFRA) {
150 if (adapter->psstate != PS_STATE_FULL_POWER)
151 lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
152 adapter->psmode = LBS802_11POWERMODECAM;
155 adapter->mode = assoc_req->mode;
156 ret = lbs_prepare_and_send_command(priv,
158 0, CMD_OPTION_WAITFORRSP,
159 OID_802_11_INFRASTRUCTURE_MODE,
160 /* Shoot me now */ (void *) (size_t) assoc_req->mode);
163 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
168 static int update_channel(lbs_private * priv)
171 /* the channel in f/w could be out of sync, get the current channel */
172 lbs_deb_enter(LBS_DEB_ASSOC);
173 ret = lbs_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
174 CMD_OPT_802_11_RF_CHANNEL_GET,
175 CMD_OPTION_WAITFORRSP, 0, NULL);
176 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
180 void lbs_sync_channel(struct work_struct *work)
182 lbs_private *priv = container_of(work, lbs_private, sync_channel);
184 lbs_deb_enter(LBS_DEB_ASSOC);
185 if (update_channel(priv) != 0)
186 lbs_pr_info("Channel synchronization failed.");
187 lbs_deb_leave(LBS_DEB_ASSOC);
190 static int assoc_helper_channel(lbs_private *priv,
191 struct assoc_request * assoc_req)
193 lbs_adapter *adapter = priv->adapter;
196 lbs_deb_enter(LBS_DEB_ASSOC);
198 ret = update_channel(priv);
200 lbs_deb_assoc("ASSOC: channel: error getting channel.");
203 if (assoc_req->channel == adapter->curbssparams.channel)
206 lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
207 adapter->curbssparams.channel, assoc_req->channel);
209 ret = lbs_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
210 CMD_OPT_802_11_RF_CHANNEL_SET,
211 CMD_OPTION_WAITFORRSP, 0, &assoc_req->channel);
213 lbs_deb_assoc("ASSOC: channel: error setting channel.");
216 ret = update_channel(priv);
218 lbs_deb_assoc("ASSOC: channel: error getting channel.");
221 if (assoc_req->channel != adapter->curbssparams.channel) {
222 lbs_deb_assoc("ASSOC: channel: failed to update channel to %d",
227 if ( assoc_req->secinfo.wep_enabled
228 && (assoc_req->wep_keys[0].len
229 || assoc_req->wep_keys[1].len
230 || assoc_req->wep_keys[2].len
231 || assoc_req->wep_keys[3].len)) {
232 /* Make sure WEP keys are re-sent to firmware */
233 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
236 /* Must restart/rejoin adhoc networks after channel change */
237 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
240 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
245 static int assoc_helper_wep_keys(lbs_private *priv,
246 struct assoc_request * assoc_req)
248 lbs_adapter *adapter = priv->adapter;
252 lbs_deb_enter(LBS_DEB_ASSOC);
254 /* Set or remove WEP keys */
255 if ( assoc_req->wep_keys[0].len
256 || assoc_req->wep_keys[1].len
257 || assoc_req->wep_keys[2].len
258 || assoc_req->wep_keys[3].len) {
259 ret = lbs_prepare_and_send_command(priv,
262 CMD_OPTION_WAITFORRSP,
265 ret = lbs_prepare_and_send_command(priv,
268 CMD_OPTION_WAITFORRSP,
275 /* enable/disable the MAC's WEP packet filter */
276 if (assoc_req->secinfo.wep_enabled)
277 adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
279 adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
280 ret = lbs_set_mac_packet_filter(priv);
284 mutex_lock(&adapter->lock);
286 /* Copy WEP keys into adapter wep key fields */
287 for (i = 0; i < 4; i++) {
288 memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
289 sizeof(struct enc_key));
291 adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
293 mutex_unlock(&adapter->lock);
296 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
300 static int assoc_helper_secinfo(lbs_private *priv,
301 struct assoc_request * assoc_req)
303 lbs_adapter *adapter = priv->adapter;
308 lbs_deb_enter(LBS_DEB_ASSOC);
310 memcpy(&adapter->secinfo, &assoc_req->secinfo,
311 sizeof(struct lbs_802_11_security));
313 ret = lbs_set_mac_packet_filter(priv);
317 /* If RSN is already enabled, don't try to enable it again, since
318 * ENABLE_RSN resets internal state machines and will clobber the
319 * 4-way WPA handshake.
322 /* Get RSN enabled/disabled */
323 ret = lbs_prepare_and_send_command(priv,
324 CMD_802_11_ENABLE_RSN,
326 CMD_OPTION_WAITFORRSP,
329 lbs_deb_assoc("Failed to get RSN status: %d", ret);
333 /* Don't re-enable RSN if it's already enabled */
334 do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled);
338 /* Set RSN enabled/disabled */
340 ret = lbs_prepare_and_send_command(priv,
341 CMD_802_11_ENABLE_RSN,
343 CMD_OPTION_WAITFORRSP,
347 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
352 static int assoc_helper_wpa_keys(lbs_private *priv,
353 struct assoc_request * assoc_req)
356 unsigned int flags = assoc_req->flags;
358 lbs_deb_enter(LBS_DEB_ASSOC);
360 /* Work around older firmware bug where WPA unicast and multicast
361 * keys must be set independently. Seen in SDIO parts with firmware
365 if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
366 clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
367 ret = lbs_prepare_and_send_command(priv,
368 CMD_802_11_KEY_MATERIAL,
370 CMD_OPTION_WAITFORRSP,
372 assoc_req->flags = flags;
378 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
379 clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
381 ret = lbs_prepare_and_send_command(priv,
382 CMD_802_11_KEY_MATERIAL,
384 CMD_OPTION_WAITFORRSP,
386 assoc_req->flags = flags;
390 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
395 static int assoc_helper_wpa_ie(lbs_private *priv,
396 struct assoc_request * assoc_req)
398 lbs_adapter *adapter = priv->adapter;
401 lbs_deb_enter(LBS_DEB_ASSOC);
403 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
404 memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
405 adapter->wpa_ie_len = assoc_req->wpa_ie_len;
407 memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
408 adapter->wpa_ie_len = 0;
411 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
416 static int should_deauth_infrastructure(lbs_adapter *adapter,
417 struct assoc_request * assoc_req)
421 lbs_deb_enter(LBS_DEB_ASSOC);
423 if (adapter->connect_status != LBS_CONNECTED)
426 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
427 lbs_deb_assoc("Deauthenticating due to new SSID\n");
432 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
433 if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
434 lbs_deb_assoc("Deauthenticating due to new security\n");
440 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
441 lbs_deb_assoc("Deauthenticating due to new BSSID\n");
446 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
447 lbs_deb_assoc("Deauthenticating due to channel switch\n");
452 /* FIXME: deal with 'auto' mode somehow */
453 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
454 if (assoc_req->mode != IW_MODE_INFRA) {
455 lbs_deb_assoc("Deauthenticating due to leaving "
463 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
468 static int should_stop_adhoc(lbs_adapter *adapter,
469 struct assoc_request * assoc_req)
471 lbs_deb_enter(LBS_DEB_ASSOC);
473 if (adapter->connect_status != LBS_CONNECTED)
476 if (lbs_ssid_cmp(adapter->curbssparams.ssid,
477 adapter->curbssparams.ssid_len,
478 assoc_req->ssid, assoc_req->ssid_len) != 0)
481 /* FIXME: deal with 'auto' mode somehow */
482 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
483 if (assoc_req->mode != IW_MODE_ADHOC)
487 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
488 if (assoc_req->channel != adapter->curbssparams.channel)
492 lbs_deb_leave(LBS_DEB_ASSOC);
497 void lbs_association_worker(struct work_struct *work)
499 lbs_private *priv = container_of(work, lbs_private, assoc_work.work);
500 lbs_adapter *adapter = priv->adapter;
501 struct assoc_request * assoc_req = NULL;
503 int find_any_ssid = 0;
504 DECLARE_MAC_BUF(mac);
506 lbs_deb_enter(LBS_DEB_ASSOC);
508 mutex_lock(&adapter->lock);
509 assoc_req = adapter->pending_assoc_req;
510 adapter->pending_assoc_req = NULL;
511 adapter->in_progress_assoc_req = assoc_req;
512 mutex_unlock(&adapter->lock);
518 "Association Request:\n"
528 escape_essid(assoc_req->ssid, assoc_req->ssid_len),
529 assoc_req->channel, assoc_req->band, assoc_req->mode,
530 print_mac(mac, assoc_req->bssid),
531 assoc_req->secinfo.WPAenabled ? " WPA" : "",
532 assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
533 assoc_req->secinfo.wep_enabled ? " WEP" : "",
534 assoc_req->secinfo.auth_mode);
536 /* If 'any' SSID was specified, find an SSID to associate with */
537 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
538 && !assoc_req->ssid_len)
541 /* But don't use 'any' SSID if there's a valid locked BSSID to use */
542 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
543 if (compare_ether_addr(assoc_req->bssid, bssid_any)
544 && compare_ether_addr(assoc_req->bssid, bssid_off))
551 ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
552 &assoc_req->ssid_len, assoc_req->mode, &new_mode);
554 lbs_deb_assoc("Could not find best network\n");
559 /* Ensure we switch to the mode of the AP */
560 if (assoc_req->mode == IW_MODE_AUTO) {
561 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
562 assoc_req->mode = new_mode;
567 * Check if the attributes being changing require deauthentication
568 * from the currently associated infrastructure access point.
570 if (adapter->mode == IW_MODE_INFRA) {
571 if (should_deauth_infrastructure(adapter, assoc_req)) {
572 ret = lbs_send_deauthentication(priv);
574 lbs_deb_assoc("Deauthentication due to new "
575 "configuration request failed: %d\n",
579 } else if (adapter->mode == IW_MODE_ADHOC) {
580 if (should_stop_adhoc(adapter, assoc_req)) {
581 ret = lbs_stop_adhoc_network(priv);
583 lbs_deb_assoc("Teardown of AdHoc network due to "
584 "new configuration request failed: %d\n",
591 /* Send the various configuration bits to the firmware */
592 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
593 ret = assoc_helper_mode(priv, assoc_req);
598 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
599 ret = assoc_helper_channel(priv, assoc_req);
604 if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
605 || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
606 ret = assoc_helper_wep_keys(priv, assoc_req);
611 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
612 ret = assoc_helper_secinfo(priv, assoc_req);
617 if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
618 ret = assoc_helper_wpa_ie(priv, assoc_req);
623 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
624 || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
625 ret = assoc_helper_wpa_keys(priv, assoc_req);
630 /* SSID/BSSID should be the _last_ config option set, because they
631 * trigger the association attempt.
633 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
634 || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
637 ret = assoc_helper_associate(priv, assoc_req);
639 lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
644 if (adapter->connect_status != LBS_CONNECTED) {
645 lbs_deb_assoc("ASSOC: association attempt unsuccessful, "
651 lbs_deb_assoc("ASSOC: association attempt successful. "
652 "Associated to '%s' (%s)\n",
653 escape_essid(adapter->curbssparams.ssid,
654 adapter->curbssparams.ssid_len),
655 print_mac(mac, adapter->curbssparams.bssid));
656 lbs_prepare_and_send_command(priv,
658 0, CMD_OPTION_WAITFORRSP, 0, NULL);
660 lbs_prepare_and_send_command(priv,
662 0, CMD_OPTION_WAITFORRSP, 0, NULL);
670 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
674 mutex_lock(&adapter->lock);
675 adapter->in_progress_assoc_req = NULL;
676 mutex_unlock(&adapter->lock);
680 lbs_deb_leave(LBS_DEB_ASSOC);
685 * Caller MUST hold any necessary locks
687 struct assoc_request *lbs_get_association_request(lbs_adapter *adapter)
689 struct assoc_request * assoc_req;
691 lbs_deb_enter(LBS_DEB_ASSOC);
692 if (!adapter->pending_assoc_req) {
693 adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
695 if (!adapter->pending_assoc_req) {
696 lbs_pr_info("Not enough memory to allocate association"
702 /* Copy current configuration attributes to the association request,
703 * but don't overwrite any that are already set.
705 assoc_req = adapter->pending_assoc_req;
706 if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
707 memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
709 assoc_req->ssid_len = adapter->curbssparams.ssid_len;
712 if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
713 assoc_req->channel = adapter->curbssparams.channel;
715 if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
716 assoc_req->band = adapter->curbssparams.band;
718 if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
719 assoc_req->mode = adapter->mode;
721 if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
722 memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
726 if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
728 for (i = 0; i < 4; i++) {
729 memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
730 sizeof(struct enc_key));
734 if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
735 assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
737 if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
738 memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
739 sizeof(struct enc_key));
742 if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
743 memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
744 sizeof(struct enc_key));
747 if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
748 memcpy(&assoc_req->secinfo, &adapter->secinfo,
749 sizeof(struct lbs_802_11_security));
752 if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
753 memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
755 assoc_req->wpa_ie_len = adapter->wpa_ie_len;
758 lbs_deb_leave(LBS_DEB_ASSOC);