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: Vasily Ulyanov <vulyanov@quantenna.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
7a4d3a3bc8
commit
f1398fd2dd
|
@ -778,6 +778,20 @@ static int qtnf_start_radar_detection(struct wiphy *wiphy,
|
|||
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 = {
|
||||
.add_virtual_intf = qtnf_add_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,
|
||||
.channel_switch = qtnf_channel_switch,
|
||||
.start_radar_detection = qtnf_start_radar_detection,
|
||||
.set_mac_acl = qtnf_set_mac_acl,
|
||||
};
|
||||
|
||||
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->mgmt_stypes = qtnf_mgmt_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
wiphy->max_acl_mac_addrs = mac->macinfo.max_acl_mac_addrs;
|
||||
|
||||
wiphy->iface_combinations = iface_comb;
|
||||
wiphy->n_iface_combinations = 1;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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,
|
||||
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))
|
||||
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)) {
|
||||
pr_err("VIF%u.%u: can not fit AP settings: %u\n",
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 =
|
||||
qlink_chan_width_mask_to_nl(le16_to_cpu(
|
||||
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,
|
||||
sizeof(mac_info->ht_cap_mod_mask));
|
||||
|
@ -2609,3 +2631,43 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
const struct cfg80211_chan_def *chdef,
|
||||
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_ */
|
||||
|
|
|
@ -103,6 +103,7 @@ struct qtnf_mac_info {
|
|||
u8 sretry_limit;
|
||||
u8 coverage_class;
|
||||
u8 radar_detect_widths;
|
||||
u32 max_acl_mac_addrs;
|
||||
struct ieee80211_ht_cap ht_cap_mod_mask;
|
||||
struct ieee80211_vht_cap vht_cap_mod_mask;
|
||||
struct ieee80211_iface_limit *limits;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
#define QLINK_PROTO_VER 9
|
||||
#define QLINK_PROTO_VER 10
|
||||
|
||||
#define QLINK_MACID_RSVD 0xFF
|
||||
#define QLINK_VIFID_RSVD 0xFF
|
||||
|
@ -239,6 +239,7 @@ enum qlink_cmd_type {
|
|||
QLINK_CMD_START_CAC = 0x001D,
|
||||
QLINK_CMD_START_AP = 0x0021,
|
||||
QLINK_CMD_STOP_AP = 0x0022,
|
||||
QLINK_CMD_SET_MAC_ACL = 0x0023,
|
||||
QLINK_CMD_GET_STA_INFO = 0x0030,
|
||||
QLINK_CMD_ADD_KEY = 0x0040,
|
||||
QLINK_CMD_DEL_KEY = 0x0041,
|
||||
|
@ -640,6 +641,38 @@ struct qlink_cmd_start_cac {
|
|||
__le32 cac_time_ms;
|
||||
} __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
|
||||
*/
|
||||
|
||||
|
@ -701,6 +734,7 @@ struct qlink_resp_get_mac_info {
|
|||
struct ieee80211_ht_cap ht_cap_mod_mask;
|
||||
__le16 max_ap_assoc_sta;
|
||||
__le16 radar_detect_widths;
|
||||
__le32 max_acl_mac_addrs;
|
||||
u8 bands_cap;
|
||||
u8 rsvd[1];
|
||||
u8 var_info[0];
|
||||
|
@ -1049,6 +1083,7 @@ enum qlink_tlv_id {
|
|||
QTN_TLV_ID_SEQ = 0x0303,
|
||||
QTN_TLV_ID_IE_SET = 0x0305,
|
||||
QTN_TLV_ID_EXT_CAPABILITY_MASK = 0x0306,
|
||||
QTN_TLV_ID_ACL_DATA = 0x0307,
|
||||
};
|
||||
|
||||
struct qlink_tlv_hdr {
|
||||
|
|
|
@ -176,3 +176,21 @@ bool qtnf_utils_is_bit_set(const u8 *arr, unsigned int bit,
|
|||
|
||||
return arr[idx] & mask;
|
||||
}
|
||||
|
||||
void qlink_acl_data_cfg2q(const struct cfg80211_acl_data *acl,
|
||||
struct qlink_acl_data *qacl)
|
||||
{
|
||||
switch (acl->acl_policy) {
|
||||
case NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED:
|
||||
qacl->policy =
|
||||
cpu_to_le32(QLINK_ACL_POLICY_ACCEPT_UNLESS_LISTED);
|
||||
break;
|
||||
case NL80211_ACL_POLICY_DENY_UNLESS_LISTED:
|
||||
qacl->policy = cpu_to_le32(QLINK_ACL_POLICY_DENY_UNLESS_LISTED);
|
||||
break;
|
||||
}
|
||||
|
||||
qacl->num_entries = cpu_to_le32(acl->n_acl_entries);
|
||||
memcpy(qacl->mac_addrs, acl->mac_addrs,
|
||||
acl->n_acl_entries * sizeof(*qacl->mac_addrs));
|
||||
}
|
||||
|
|
|
@ -71,5 +71,7 @@ void qlink_chandef_cfg2q(const struct cfg80211_chan_def *chdef,
|
|||
enum qlink_hidden_ssid qlink_hidden_ssid_nl2q(enum nl80211_hidden_ssid nl_val);
|
||||
bool qtnf_utils_is_bit_set(const u8 *arr, unsigned int bit,
|
||||
unsigned int arr_max_len);
|
||||
void qlink_acl_data_cfg2q(const struct cfg80211_acl_data *acl,
|
||||
struct qlink_acl_data *qacl);
|
||||
|
||||
#endif /* _QTN_FMAC_QLINK_UTIL_H_ */
|
||||
|
|
Loading…
Reference in New Issue