Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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);
}