Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b05ee456 authored by Igor Mitsyanko's avatar Igor Mitsyanko Committed by Kalle Valo
Browse files

qtnfmac: add support for radar detection and CAC



Implement two parts of radar handling logic:
- cfg80211 .start_radar_detect callback to allow nl80211 to initiate CAC
- radar event to allow wlan device to advertize CAC and radar events

Signed-off-by: default avatarIgor Mitsyanko <igor.mitsyanko.os@quantenna.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 5bf374ab
Loading
Loading
Loading
Loading
+17 −1
Original line number Original line Diff line number Diff line
@@ -751,6 +751,21 @@ static int qtnf_channel_switch(struct wiphy *wiphy, struct net_device *dev,
	return ret;
	return ret;
}
}


static int qtnf_start_radar_detection(struct wiphy *wiphy,
				      struct net_device *ndev,
				      struct cfg80211_chan_def *chandef,
				      u32 cac_time_ms)
{
	struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
	int ret;

	ret = qtnf_cmd_start_cac(vif, chandef, cac_time_ms);
	if (ret)
		pr_err("%s: failed to start CAC ret=%d\n", ndev->name, ret);

	return ret;
}

static struct cfg80211_ops qtn_cfg80211_ops = {
static struct cfg80211_ops qtn_cfg80211_ops = {
	.add_virtual_intf	= qtnf_add_virtual_intf,
	.add_virtual_intf	= qtnf_add_virtual_intf,
	.change_virtual_intf	= qtnf_change_virtual_intf,
	.change_virtual_intf	= qtnf_change_virtual_intf,
@@ -774,7 +789,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
	.disconnect		= qtnf_disconnect,
	.disconnect		= qtnf_disconnect,
	.dump_survey		= qtnf_dump_survey,
	.dump_survey		= qtnf_dump_survey,
	.get_channel		= qtnf_get_channel,
	.get_channel		= qtnf_get_channel,
	.channel_switch		= qtnf_channel_switch
	.channel_switch		= qtnf_channel_switch,
	.start_radar_detection	= qtnf_start_radar_detection,
};
};


static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,
static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,
+38 −0
Original line number Original line Diff line number Diff line
@@ -2512,3 +2512,41 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)
	consume_skb(resp_skb);
	consume_skb(resp_skb);
	return ret;
	return ret;
}
}

int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
		       const struct cfg80211_chan_def *chdef,
		       u32 cac_time_ms)
{
	struct qtnf_bus *bus = vif->mac->bus;
	struct sk_buff *cmd_skb;
	struct qlink_cmd_start_cac *cmd;
	int ret;
	u16 res_code;

	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
					    QLINK_CMD_START_CAC,
					    sizeof(*cmd));
	if (unlikely(!cmd_skb))
		return -ENOMEM;

	cmd = (struct qlink_cmd_start_cac *)cmd_skb->data;
	cmd->cac_time_ms = cpu_to_le32(cac_time_ms);
	qlink_chandef_cfg2q(chdef, &cmd->chan);

	qtnf_bus_lock(bus);
	ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
	qtnf_bus_unlock(bus);

	if (ret)
		return ret;

	switch (res_code) {
	case QLINK_CMD_RESULT_OK:
		break;
	default:
		ret = -EOPNOTSUPP;
		break;
	}

	return ret;
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -76,5 +76,8 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,
int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,
int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,
			      struct cfg80211_csa_settings *params);
			      struct cfg80211_csa_settings *params);
int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef);
int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef);
int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
		       const struct cfg80211_chan_def *chdef,
		       u32 cac_time_ms);


#endif /* QLINK_COMMANDS_H_ */
#endif /* QLINK_COMMANDS_H_ */
+61 −0
Original line number Original line Diff line number Diff line
@@ -395,6 +395,63 @@ qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
	return 0;
	return 0;
}
}


static int qtnf_event_handle_radar(struct qtnf_vif *vif,
				   const struct qlink_event_radar *ev,
				   u16 len)
{
	struct wiphy *wiphy = priv_to_wiphy(vif->mac);
	struct cfg80211_chan_def chandef;

	if (len < sizeof(*ev)) {
		pr_err("MAC%u: payload is too short\n", vif->mac->macid);
		return -EINVAL;
	}

	if (!wiphy->registered || !vif->netdev)
		return 0;

	qlink_chandef_q2cfg(wiphy, &ev->chan, &chandef);

	if (!cfg80211_chandef_valid(&chandef)) {
		pr_err("MAC%u: bad channel f1=%u f2=%u bw=%u\n",
		       vif->mac->macid,
		       chandef.center_freq1, chandef.center_freq2,
		       chandef.width);
		return -EINVAL;
	}

	pr_info("%s: radar event=%u f1=%u f2=%u bw=%u\n",
		vif->netdev->name, ev->event,
		chandef.center_freq1, chandef.center_freq2,
		chandef.width);

	switch (ev->event) {
	case QLINK_RADAR_DETECTED:
		cfg80211_radar_event(wiphy, &chandef, GFP_KERNEL);
		break;
	case QLINK_RADAR_CAC_FINISHED:
		if (!vif->wdev.cac_started)
			break;

		cfg80211_cac_event(vif->netdev, &chandef,
				   NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
		break;
	case QLINK_RADAR_CAC_ABORTED:
		if (!vif->wdev.cac_started)
			break;

		cfg80211_cac_event(vif->netdev, &chandef,
				   NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
		break;
	default:
		pr_warn("%s: unhandled radar event %u\n",
			vif->netdev->name, ev->event);
		break;
	}

	return 0;
}

static int qtnf_event_parse(struct qtnf_wmac *mac,
static int qtnf_event_parse(struct qtnf_wmac *mac,
			    const struct sk_buff *event_skb)
			    const struct sk_buff *event_skb)
{
{
@@ -449,6 +506,10 @@ static int qtnf_event_parse(struct qtnf_wmac *mac,
		ret = qtnf_event_handle_freq_change(mac, (const void *)event,
		ret = qtnf_event_handle_freq_change(mac, (const void *)event,
						    event_len);
						    event_len);
		break;
		break;
	case QLINK_EVENT_RADAR:
		ret = qtnf_event_handle_radar(vif, (const void *)event,
					      event_len);
		break;
	default:
	default:
		pr_warn("unknown event type: %x\n", event_id);
		pr_warn("unknown event type: %x\n", event_id);
		break;
		break;
+36 −0
Original line number Original line Diff line number Diff line
@@ -205,6 +205,7 @@ struct qlink_auth_encr {
 * @QLINK_CMD_REG_NOTIFY: notify device about regulatory domain change. This
 * @QLINK_CMD_REG_NOTIFY: notify device about regulatory domain change. This
 *	command is supported only if device reports QLINK_HW_SUPPORTS_REG_UPDATE
 *	command is supported only if device reports QLINK_HW_SUPPORTS_REG_UPDATE
 *	capability.
 *	capability.
 * @QLINK_CMD_START_CAC: start radar detection procedure on a specified channel.
 */
 */
enum qlink_cmd_type {
enum qlink_cmd_type {
	QLINK_CMD_FW_INIT		= 0x0001,
	QLINK_CMD_FW_INIT		= 0x0001,
@@ -224,6 +225,7 @@ enum qlink_cmd_type {
	QLINK_CMD_BAND_INFO_GET		= 0x001A,
	QLINK_CMD_BAND_INFO_GET		= 0x001A,
	QLINK_CMD_CHAN_SWITCH		= 0x001B,
	QLINK_CMD_CHAN_SWITCH		= 0x001B,
	QLINK_CMD_CHAN_GET		= 0x001C,
	QLINK_CMD_CHAN_GET		= 0x001C,
	QLINK_CMD_START_CAC		= 0x001D,
	QLINK_CMD_START_AP		= 0x0021,
	QLINK_CMD_START_AP		= 0x0021,
	QLINK_CMD_STOP_AP		= 0x0022,
	QLINK_CMD_STOP_AP		= 0x0022,
	QLINK_CMD_GET_STA_INFO		= 0x0030,
	QLINK_CMD_GET_STA_INFO		= 0x0030,
@@ -617,6 +619,18 @@ struct qlink_cmd_start_ap {
	u8 info[0];
	u8 info[0];
} __packed;
} __packed;


/**
 * struct qlink_cmd_start_cac - data for QLINK_CMD_START_CAC command
 *
 * @chan: a channel to start a radar detection procedure on.
 * @cac_time_ms: CAC time.
 */
struct qlink_cmd_start_cac {
	struct qlink_cmd chdr;
	struct qlink_chandef chan;
	__le32 cac_time_ms;
} __packed;

/* QLINK Command Responses messages related definitions
/* QLINK Command Responses messages related definitions
 */
 */


@@ -814,6 +828,7 @@ enum qlink_event_type {
	QLINK_EVENT_BSS_JOIN		= 0x0026,
	QLINK_EVENT_BSS_JOIN		= 0x0026,
	QLINK_EVENT_BSS_LEAVE		= 0x0027,
	QLINK_EVENT_BSS_LEAVE		= 0x0027,
	QLINK_EVENT_FREQ_CHANGE		= 0x0028,
	QLINK_EVENT_FREQ_CHANGE		= 0x0028,
	QLINK_EVENT_RADAR		= 0x0029,
};
};


/**
/**
@@ -963,6 +978,27 @@ struct qlink_event_scan_complete {
	__le32 flags;
	__le32 flags;
} __packed;
} __packed;


enum qlink_radar_event {
	QLINK_RADAR_DETECTED,
	QLINK_RADAR_CAC_FINISHED,
	QLINK_RADAR_CAC_ABORTED,
	QLINK_RADAR_NOP_FINISHED,
	QLINK_RADAR_PRE_CAC_EXPIRED,
};

/**
 * struct qlink_event_radar - data for QLINK_EVENT_RADAR event
 *
 * @chan: channel on which radar event happened.
 * @event: radar event type, one of &enum qlink_radar_event.
 */
struct qlink_event_radar {
	struct qlink_event ehdr;
	struct qlink_chandef chan;
	u8 event;
	u8 rsvd[3];
} __packed;

/* QLINK TLVs (Type-Length Values) definitions
/* QLINK TLVs (Type-Length Values) definitions
 */
 */