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

Commit f1398fd2 authored by Vasily Ulyanov's avatar Vasily Ulyanov Committed by Kalle Valo
Browse files

qtnfmac: support MAC address based access control



This allows a running AP to blacklist STAs by their MAC addresses
respecting the configured policy (either accept or deny unless listed).
It can be setup on .start_ap or with .set_mac_acl commands.

Signed-off-by: default avatarVasily Ulyanov <vulyanov@quantenna.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 7a4d3a3b
Loading
Loading
Loading
Loading
+16 −0
Original line number Original line Diff line number Diff line
@@ -778,6 +778,20 @@ static int qtnf_start_radar_detection(struct wiphy *wiphy,
	return ret;
	return ret;
}
}


static int qtnf_set_mac_acl(struct wiphy *wiphy,
			    struct net_device *dev,
			    const struct cfg80211_acl_data *params)
{
	struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
	int ret;

	ret = qtnf_cmd_set_mac_acl(vif, params);
	if (ret)
		pr_err("%s: failed to set mac ACL ret=%d\n", dev->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,
@@ -803,6 +817,7 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
	.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,
	.start_radar_detection	= qtnf_start_radar_detection,
	.set_mac_acl		= qtnf_set_mac_acl,
};
};


static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,
static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,
@@ -918,6 +933,7 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
	wiphy->max_scan_ie_len = QTNF_MAX_VSIE_LEN;
	wiphy->max_scan_ie_len = QTNF_MAX_VSIE_LEN;
	wiphy->mgmt_stypes = qtnf_mgmt_stypes;
	wiphy->mgmt_stypes = qtnf_mgmt_stypes;
	wiphy->max_remain_on_channel_duration = 5000;
	wiphy->max_remain_on_channel_duration = 5000;
	wiphy->max_acl_mac_addrs = mac->macinfo.max_acl_mac_addrs;


	wiphy->iface_combinations = iface_comb;
	wiphy->iface_combinations = iface_comb;
	wiphy->n_iface_combinations = 1;
	wiphy->n_iface_combinations = 1;
+62 −0
Original line number Original line Diff line number Diff line
@@ -162,6 +162,14 @@ static void qtnf_cmd_tlv_ie_set_add(struct sk_buff *cmd_skb, u8 frame_type,
		memcpy(tlv->ie_data, buf, len);
		memcpy(tlv->ie_data, buf, len);
}
}


static inline size_t qtnf_cmd_acl_data_size(const struct cfg80211_acl_data *acl)
{
	size_t size = sizeof(struct qlink_acl_data) +
		      acl->n_acl_entries * sizeof(struct qlink_mac_address);

	return size;
}

static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
				      const struct cfg80211_ap_settings *s)
				      const struct cfg80211_ap_settings *s)
{
{
@@ -178,6 +186,9 @@ static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
	if (cfg80211_chandef_valid(&s->chandef))
	if (cfg80211_chandef_valid(&s->chandef))
		len += sizeof(struct qlink_tlv_chandef);
		len += sizeof(struct qlink_tlv_chandef);


	if (s->acl)
		len += qtnf_cmd_acl_data_size(s->acl);

	if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) {
	if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) {
		pr_err("VIF%u.%u: can not fit AP settings: %u\n",
		pr_err("VIF%u.%u: can not fit AP settings: %u\n",
		       vif->mac->macid, vif->vifid, len);
		       vif->mac->macid, vif->vifid, len);
@@ -283,6 +294,16 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
		memcpy(tlv->val, s->vht_cap, sizeof(*s->vht_cap));
		memcpy(tlv->val, s->vht_cap, sizeof(*s->vht_cap));
	}
	}


	if (s->acl) {
		size_t acl_size = qtnf_cmd_acl_data_size(s->acl);
		struct qlink_tlv_hdr *tlv =
			skb_put(cmd_skb, sizeof(*tlv) + acl_size);

		tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA);
		tlv->len = cpu_to_le16(acl_size);
		qlink_acl_data_cfg2q(s->acl, (struct qlink_acl_data *)tlv->val);
	}

	qtnf_bus_lock(vif->mac->bus);
	qtnf_bus_lock(vif->mac->bus);


	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
@@ -1206,6 +1227,7 @@ qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac,
	mac_info->radar_detect_widths =
	mac_info->radar_detect_widths =
			qlink_chan_width_mask_to_nl(le16_to_cpu(
			qlink_chan_width_mask_to_nl(le16_to_cpu(
					resp_info->radar_detect_widths));
					resp_info->radar_detect_widths));
	mac_info->max_acl_mac_addrs = le32_to_cpu(resp_info->max_acl_mac_addrs);


	memcpy(&mac_info->ht_cap_mod_mask, &resp_info->ht_cap_mod_mask,
	memcpy(&mac_info->ht_cap_mod_mask, &resp_info->ht_cap_mod_mask,
	       sizeof(mac_info->ht_cap_mod_mask));
	       sizeof(mac_info->ht_cap_mod_mask));
@@ -2609,3 +2631,43 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif,


	return ret;
	return ret;
}
}

int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,
			 const struct cfg80211_acl_data *params)
{
	struct qtnf_bus *bus = vif->mac->bus;
	struct sk_buff *cmd_skb;
	struct qlink_cmd_set_mac_acl *cmd;
	u16 res_code;
	int ret;

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

	cmd = (struct qlink_cmd_set_mac_acl *)cmd_skb->data;
	qlink_acl_data_cfg2q(params, &cmd->acl);

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

	if (unlikely(ret))
		return ret;

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

	return ret;
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -79,5 +79,7 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef);
int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
		       const struct cfg80211_chan_def *chdef,
		       const struct cfg80211_chan_def *chdef,
		       u32 cac_time_ms);
		       u32 cac_time_ms);
int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,
			 const struct cfg80211_acl_data *params);


#endif /* QLINK_COMMANDS_H_ */
#endif /* QLINK_COMMANDS_H_ */
+1 −0
Original line number Original line Diff line number Diff line
@@ -103,6 +103,7 @@ struct qtnf_mac_info {
	u8 sretry_limit;
	u8 sretry_limit;
	u8 coverage_class;
	u8 coverage_class;
	u8 radar_detect_widths;
	u8 radar_detect_widths;
	u32 max_acl_mac_addrs;
	struct ieee80211_ht_cap ht_cap_mod_mask;
	struct ieee80211_ht_cap ht_cap_mod_mask;
	struct ieee80211_vht_cap vht_cap_mod_mask;
	struct ieee80211_vht_cap vht_cap_mod_mask;
	struct ieee80211_iface_limit *limits;
	struct ieee80211_iface_limit *limits;
+36 −1
Original line number Original line Diff line number Diff line
@@ -19,7 +19,7 @@


#include <linux/ieee80211.h>
#include <linux/ieee80211.h>


#define QLINK_PROTO_VER		9
#define QLINK_PROTO_VER		10


#define QLINK_MACID_RSVD		0xFF
#define QLINK_MACID_RSVD		0xFF
#define QLINK_VIFID_RSVD		0xFF
#define QLINK_VIFID_RSVD		0xFF
@@ -239,6 +239,7 @@ enum qlink_cmd_type {
	QLINK_CMD_START_CAC		= 0x001D,
	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_SET_MAC_ACL		= 0x0023,
	QLINK_CMD_GET_STA_INFO		= 0x0030,
	QLINK_CMD_GET_STA_INFO		= 0x0030,
	QLINK_CMD_ADD_KEY		= 0x0040,
	QLINK_CMD_ADD_KEY		= 0x0040,
	QLINK_CMD_DEL_KEY		= 0x0041,
	QLINK_CMD_DEL_KEY		= 0x0041,
@@ -640,6 +641,38 @@ struct qlink_cmd_start_cac {
	__le32 cac_time_ms;
	__le32 cac_time_ms;
} __packed;
} __packed;


enum qlink_acl_policy {
	QLINK_ACL_POLICY_ACCEPT_UNLESS_LISTED,
	QLINK_ACL_POLICY_DENY_UNLESS_LISTED,
};

struct qlink_mac_address {
	u8 addr[ETH_ALEN];
} __packed;

/**
 * struct qlink_acl_data - ACL data
 *
 * @policy: filter policy, one of &enum qlink_acl_policy.
 * @num_entries: number of MAC addresses in array.
 * @mac_address: MAC addresses array.
 */
struct qlink_acl_data {
	__le32 policy;
	__le32 num_entries;
	struct qlink_mac_address mac_addrs[0];
} __packed;

/**
 * struct qlink_cmd_set_mac_acl - data for QLINK_CMD_SET_MAC_ACL command
 *
 * @acl: ACL data.
 */
struct qlink_cmd_set_mac_acl {
	struct qlink_cmd chdr;
	struct qlink_acl_data acl;
} __packed;

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


@@ -701,6 +734,7 @@ struct qlink_resp_get_mac_info {
	struct ieee80211_ht_cap ht_cap_mod_mask;
	struct ieee80211_ht_cap ht_cap_mod_mask;
	__le16 max_ap_assoc_sta;
	__le16 max_ap_assoc_sta;
	__le16 radar_detect_widths;
	__le16 radar_detect_widths;
	__le32 max_acl_mac_addrs;
	u8 bands_cap;
	u8 bands_cap;
	u8 rsvd[1];
	u8 rsvd[1];
	u8 var_info[0];
	u8 var_info[0];
@@ -1049,6 +1083,7 @@ enum qlink_tlv_id {
	QTN_TLV_ID_SEQ			= 0x0303,
	QTN_TLV_ID_SEQ			= 0x0303,
	QTN_TLV_ID_IE_SET		= 0x0305,
	QTN_TLV_ID_IE_SET		= 0x0305,
	QTN_TLV_ID_EXT_CAPABILITY_MASK	= 0x0306,
	QTN_TLV_ID_EXT_CAPABILITY_MASK	= 0x0306,
	QTN_TLV_ID_ACL_DATA		= 0x0307,
};
};


struct qlink_tlv_hdr {
struct qlink_tlv_hdr {
Loading