static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret = 0; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_WANT_SKB, }; /* If there isn't a scan actively going on in the hardware * then we are in between scan bands and not actually * actively scanning, so don't send the abort command */ if (!test_bit(STATUS_SCAN_HW, &priv->status)) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return 0; } ret = iwl_send_cmd_sync(priv, &cmd); if (ret) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return ret; } pkt = (struct iwl_rx_packet *)cmd.reply_page; if (pkt->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status); clear_bit(STATUS_SCAN_ABORTING, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status); } iwl_free_pages(priv, cmd.reply_page); return ret; }
static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_WANT_SKB, }; /* Exit instantly with error when device is not ready * to receive scan abort command or it does not perform * hardware scan currently */ if (!test_bit(STATUS_READY, &priv->status) || !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || !test_bit(STATUS_SCAN_HW, &priv->status) || test_bit(STATUS_FW_ERROR, &priv->status) || test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EIO; ret = iwl_send_cmd_sync(priv, &cmd); if (ret) return ret; pkt = (struct iwl_rx_packet *)cmd.reply_page; if (pkt->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status); ret = -EIO; } iwl_free_pages(priv, cmd.reply_page); return ret; }
int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { struct iwl_rx_packet *pkt = NULL; int ret = 0; u8 data[sizeof(*sta)]; struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, .flags = flags, .data = data, }; u8 sta_id __maybe_unused = sta->sta.sta_id; IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); if (flags & CMD_ASYNC) cmd.callback = iwl_add_sta_callback; else { cmd.flags |= CMD_WANT_SKB; might_sleep(); } cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); ret = iwl_send_cmd(priv, &cmd); if (ret || (flags & CMD_ASYNC)) return ret; if (ret == 0) { pkt = (struct iwl_rx_packet *)cmd.reply_page; ret = iwl_process_add_sta_resp(priv, sta, pkt, true); } iwl_free_pages(priv, cmd.reply_page); return ret; }
int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { int ret = 0; u8 data[sizeof(*sta)]; struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, .flags = flags, .data = { data, }, }; u8 sta_id __maybe_unused = sta->sta.sta_id; IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); if (!(flags & CMD_ASYNC)) { cmd.flags |= CMD_WANT_SKB; might_sleep(); } cmd.len[0] = iwlagn_build_addsta_hcmd(sta, data); ret = iwl_trans_send_cmd(trans(priv), &cmd); if (ret || (flags & CMD_ASYNC)) return ret; /*else the command was successfully sent in SYNC mode, need to free * the reply page */ iwl_free_pages(priv->shrd, cmd.reply_page); if (cmd.handler_status) IWL_ERR(priv, "%s - error in the CMD response %d", __func__, cmd.handler_status); return cmd.handler_status; }
int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { int cmd_idx; int ret; if (WARN_ON(cmd->flags & CMD_ASYNC)) return -EINVAL; /* A synchronous command can not have a callback set. */ if (WARN_ON(cmd->callback)) return -EINVAL; IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", get_cmd_string(cmd->id)); cmd_idx = iwl_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; clear_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } ret = wait_event_timeout(priv->wait_command_queue, !test_bit(STATUS_HCMD_ACTIVE, &priv->status), HOST_COMPLETE_TIMEOUT); if (!ret) { if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { IWL_ERR(priv, "Error sending %s: time out after %dms.\n", get_cmd_string(cmd->id), jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); clear_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n", get_cmd_string(cmd->id)); ret = -ETIMEDOUT; goto cancel; } } if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n", get_cmd_string(cmd->id)); ret = -ECANCELED; goto fail; } if (test_bit(STATUS_FW_ERROR, &priv->status)) { IWL_ERR(priv, "Command %s failed: FW Error\n", get_cmd_string(cmd->id)); ret = -EIO; goto fail; } if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) { IWL_ERR(priv, "Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); ret = -EIO; goto cancel; } return 0; cancel: if (cmd->flags & CMD_WANT_SKB) { /* * Cancel the CMD_WANT_SKB flag for the cmd in the * TX cmd queue. Otherwise in case the cmd comes * in later, it will possibly set an invalid * address (cmd->meta.source). */ priv->txq[priv->cmd_queue].meta[cmd_idx].flags &= ~CMD_WANT_SKB; } fail: if (cmd->reply_page) { iwl_free_pages(priv, cmd->reply_page); cmd->reply_page = 0; } return ret; }
static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_SYNC | CMD_WANT_SKB, }; /* Exit instantly with error when device is not ready * to receive scan abort command or it does not perform * hardware scan currently */ if (!test_bit(STATUS_READY, &priv->shrd->status) || !test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status) || !test_bit(STATUS_SCAN_HW, &priv->shrd->status) || test_bit(STATUS_FW_ERROR, &priv->shrd->status) || test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return -EIO; ret = iwl_trans_send_cmd(trans(priv), &cmd); if (ret) return ret; pkt = (struct iwl_rx_packet *)cmd.reply_page; if (pkt->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status); ret = -EIO; } iwl_free_pages(priv->shrd, cmd.reply_page); return ret; } static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) { /* check if scan was requested from mac80211 */ if (priv->scan_request) { IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); ieee80211_scan_completed(priv->hw, aborted); } if (priv->scan_type == IWL_SCAN_ROC) { ieee80211_remain_on_channel_expired(priv->hw); priv->hw_roc_channel = NULL; schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); } priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; } static void iwl_process_scan_complete(struct iwl_priv *priv) { bool aborted; lockdep_assert_held(&priv->shrd->mutex); if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status)) return; IWL_DEBUG_SCAN(priv, "Completed scan.\n"); cancel_delayed_work(&priv->scan_check); aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status); if (aborted) IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n"); if (!test_and_clear_bit(STATUS_SCANNING, &priv->shrd->status)) { IWL_DEBUG_SCAN(priv, "Scan already completed.\n"); goto out_settings; } if (priv->scan_type == IWL_SCAN_ROC) { ieee80211_remain_on_channel_expired(priv->hw); priv->hw_roc_channel = NULL; schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); } if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { int err; /* Check if mac80211 requested scan during our internal scan */ if (priv->scan_request == NULL) goto out_complete; /* If so request a new scan */ err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, priv->scan_request->channels[0]->band); if (err) { IWL_DEBUG_SCAN(priv, "failed to initiate pending scan: %d\n", err); aborted = true; goto out_complete; } return; } out_complete: iwl_complete_scan(priv, aborted); out_settings: /* Can we still talk to firmware ? */ if (!iwl_is_ready_rf(priv->shrd)) return; iwlagn_post_scan(priv); }
static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, int sta_id, bool temporary) { struct iwl_rx_packet *pkt; int ret; unsigned long flags_spin; struct iwl_rem_sta_cmd rm_sta_cmd; struct iwl_host_cmd cmd = { .id = REPLY_REMOVE_STA, .len = sizeof(struct iwl_rem_sta_cmd), .flags = CMD_SYNC, .data = &rm_sta_cmd, }; memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); rm_sta_cmd.num_sta = 1; memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN); cmd.flags |= CMD_WANT_SKB; ret = iwl_send_cmd(priv, &cmd); if (ret) return ret; pkt = (struct iwl_rx_packet *)cmd.reply_page; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", pkt->hdr.flags); ret = -EIO; } if (!ret) { switch (pkt->u.rem_sta.status) { case REM_STA_SUCCESS_MSK: if (!temporary) { spin_lock_irqsave(&priv->sta_lock, flags_spin); iwl_sta_ucode_deactivate(priv, sta_id); spin_unlock_irqrestore(&priv->sta_lock, flags_spin); } IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); break; default: ret = -EIO; IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); break; } } iwl_free_pages(priv, cmd.reply_page); return ret; } /** * iwl_remove_station - Remove driver's knowledge of station. */ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, const u8 *addr) { unsigned long flags; if (!iwl_is_ready(priv)) { IWL_DEBUG_INFO(priv, "Unable to remove station %pM, device not ready.\n", addr); /* * It is typical for stations to be removed when we are * going down. Return success since device will be down * soon anyway */ return 0; } IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n", sta_id, addr); if (WARN_ON(sta_id == IWL_INVALID_STATION)) return -EINVAL; spin_lock_irqsave(&priv->sta_lock, flags); if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n", addr); goto out_err; } if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n", addr); goto out_err; } if (priv->stations[sta_id].used & IWL_STA_LOCAL) { kfree(priv->stations[sta_id].lq); priv->stations[sta_id].lq = NULL; } priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; priv->num_stations--; BUG_ON(priv->num_stations < 0); spin_unlock_irqrestore(&priv->sta_lock, flags); return iwl_send_remove_station(priv, addr, sta_id, false); out_err: spin_unlock_irqrestore(&priv->sta_lock, flags); return -EINVAL; }
static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_SYNC | CMD_WANT_SKB, }; /* Exit instantly with error when device is not ready * to receive scan abort command or it does not perform * hardware scan currently */ if (!test_bit(STATUS_READY, &priv->status) || !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || !test_bit(STATUS_SCAN_HW, &priv->status) || test_bit(STATUS_FW_ERROR, &priv->status) || test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EIO; ret = trans_send_cmd(&priv->trans, &cmd); if (ret) return ret; pkt = (struct iwl_rx_packet *)cmd.reply_page; if (pkt->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status); ret = -EIO; } iwl_free_pages(priv, cmd.reply_page); return ret; } static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) { /* check if scan was requested from mac80211 */ if (priv->scan_request) { IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); ieee80211_scan_completed(priv->hw, aborted); } priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; } void iwl_force_scan_end(struct iwl_priv *priv) { lockdep_assert_held(&priv->mutex); if (!test_bit(STATUS_SCANNING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n"); return; } IWL_DEBUG_SCAN(priv, "Forcing scan end\n"); clear_bit(STATUS_SCANNING, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status); clear_bit(STATUS_SCAN_ABORTING, &priv->status); iwl_complete_scan(priv, true); }