mirror of https://gitee.com/openkylin/linux.git
qtnfmac: track broadcast domain of each interface
If firmware reports that it supports hardware switch capabilities, driver needs to track and notify device whenever broadcast domain of a particular network device changes (ie. whenever it's upper master device changes). Firmware needs a unique ID to tell broadcast domains from each other which is an opaque number otherwise. For that purpose we can use netspace:ifidx pair to uniquely identify each broadcast domain: - if netdev is not part of a bridge, then use it's own ifidx as a broadcast domain ID - if netdev is part of a bridge, then use bridge netdev ifidx as broadcast domain ID Firmware makes sure that packets are only forwarded between interfaces marked with the same broadcast domain ID. Signed-off-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
4502822342
commit
decfc5c70d
|
@ -54,6 +54,7 @@ struct qtnf_bus {
|
|||
struct work_struct event_work;
|
||||
struct mutex bus_lock; /* lock during command/event processing */
|
||||
struct dentry *dbg_dir;
|
||||
struct notifier_block netdev_nb;
|
||||
/* bus private data */
|
||||
char bus_priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
|
|
|
@ -248,6 +248,15 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
|
|||
goto error_del_vif;
|
||||
}
|
||||
|
||||
if (mac->bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) {
|
||||
ret = qtnf_cmd_netdev_changeupper(vif, vif->netdev->ifindex);
|
||||
if (ret) {
|
||||
unregister_netdevice(vif->netdev);
|
||||
vif->netdev = NULL;
|
||||
goto error_del_vif;
|
||||
}
|
||||
}
|
||||
|
||||
vif->wdev.netdev = vif->netdev;
|
||||
return &vif->wdev;
|
||||
|
||||
|
|
|
@ -2756,3 +2756,35 @@ int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif,
|
|||
qtnf_bus_unlock(bus);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain)
|
||||
{
|
||||
struct qtnf_bus *bus = vif->mac->bus;
|
||||
struct sk_buff *cmd_skb;
|
||||
struct qlink_cmd_ndev_changeupper *cmd;
|
||||
int ret;
|
||||
|
||||
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
|
||||
QLINK_CMD_NDEV_EVENT,
|
||||
sizeof(*cmd));
|
||||
if (!cmd_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
pr_debug("[VIF%u.%u] set broadcast domain to %d\n",
|
||||
vif->mac->macid, vif->vifid, br_domain);
|
||||
|
||||
cmd = (struct qlink_cmd_ndev_changeupper *)cmd_skb->data;
|
||||
cmd->nehdr.event = cpu_to_le16(QLINK_NDEV_EVENT_CHANGEUPPER);
|
||||
cmd->upper_type = QLINK_NDEV_UPPER_TYPE_BRIDGE;
|
||||
cmd->br_domain = cpu_to_le32(br_domain);
|
||||
|
||||
qtnf_bus_lock(bus);
|
||||
ret = qtnf_cmd_send(bus, cmd_skb);
|
||||
qtnf_bus_unlock(bus);
|
||||
|
||||
if (ret)
|
||||
pr_err("[VIF%u.%u] failed to set broadcast domain\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -75,5 +75,6 @@ int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif,
|
|||
enum nl80211_tx_power_setting type, int mbm);
|
||||
int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif,
|
||||
const struct cfg80211_wowlan *wowl);
|
||||
int qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain);
|
||||
|
||||
#endif /* QLINK_COMMANDS_H_ */
|
||||
|
|
|
@ -613,6 +613,12 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid)
|
|||
goto error_del_vif;
|
||||
}
|
||||
|
||||
if (bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) {
|
||||
ret = qtnf_cmd_netdev_changeupper(vif, vif->netdev->ifindex);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
pr_debug("MAC%u initialized\n", macid);
|
||||
|
||||
return 0;
|
||||
|
@ -625,6 +631,54 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool qtnf_netdev_is_qtn(const struct net_device *ndev)
|
||||
{
|
||||
return ndev->netdev_ops == &qtnf_netdev_ops;
|
||||
}
|
||||
|
||||
static int qtnf_core_netdevice_event(struct notifier_block *nb,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
|
||||
const struct netdev_notifier_changeupper_info *info;
|
||||
struct qtnf_vif *vif;
|
||||
int br_domain;
|
||||
int ret = 0;
|
||||
|
||||
if (!qtnf_netdev_is_qtn(ndev))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (!net_eq(dev_net(ndev), &init_net))
|
||||
return NOTIFY_OK;
|
||||
|
||||
vif = qtnf_netdev_get_priv(ndev);
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_CHANGEUPPER:
|
||||
info = ptr;
|
||||
|
||||
if (!netif_is_bridge_master(info->upper_dev))
|
||||
break;
|
||||
|
||||
pr_debug("[VIF%u.%u] change bridge: %s %s\n",
|
||||
vif->mac->macid, vif->vifid,
|
||||
netdev_name(info->upper_dev),
|
||||
info->linking ? "add" : "del");
|
||||
|
||||
if (info->linking)
|
||||
br_domain = info->upper_dev->ifindex;
|
||||
else
|
||||
br_domain = ndev->ifindex;
|
||||
|
||||
ret = qtnf_cmd_netdev_changeupper(vif, br_domain);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return notifier_from_errno(ret);
|
||||
}
|
||||
|
||||
int qtnf_core_attach(struct qtnf_bus *bus)
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -685,6 +739,15 @@ int qtnf_core_attach(struct qtnf_bus *bus)
|
|||
}
|
||||
}
|
||||
|
||||
if (bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) {
|
||||
bus->netdev_nb.notifier_call = qtnf_core_netdevice_event;
|
||||
ret = register_netdevice_notifier(&bus->netdev_nb);
|
||||
if (ret) {
|
||||
pr_err("failed to register netdev notifier: %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
bus->fw_state = QTNF_FW_STATE_RUNNING;
|
||||
return 0;
|
||||
|
||||
|
@ -698,6 +761,7 @@ void qtnf_core_detach(struct qtnf_bus *bus)
|
|||
{
|
||||
unsigned int macid;
|
||||
|
||||
unregister_netdevice_notifier(&bus->netdev_nb);
|
||||
qtnf_bus_data_rx_stop(bus);
|
||||
|
||||
for (macid = 0; macid < QTNF_MAX_MAC; macid++)
|
||||
|
|
|
@ -153,6 +153,7 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev);
|
|||
void qtnf_netdev_updown(struct net_device *ndev, bool up);
|
||||
void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted);
|
||||
struct dentry *qtnf_get_debugfs_dir(void);
|
||||
bool qtnf_netdev_is_qtn(const struct net_device *ndev);
|
||||
|
||||
static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev)
|
||||
{
|
||||
|
|
|
@ -59,6 +59,7 @@ struct qlink_msg_header {
|
|||
* @QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR: device supports MAC Address
|
||||
* Randomization in probe requests.
|
||||
* @QLINK_HW_CAPAB_OBSS_SCAN: device can perform OBSS scanning.
|
||||
* @QLINK_HW_CAPAB_HW_BRIDGE: device has hardware switch capabilities.
|
||||
*/
|
||||
enum qlink_hw_capab {
|
||||
QLINK_HW_CAPAB_REG_UPDATE = BIT(0),
|
||||
|
@ -69,6 +70,7 @@ enum qlink_hw_capab {
|
|||
QLINK_HW_CAPAB_OBSS_SCAN = BIT(5),
|
||||
QLINK_HW_CAPAB_SCAN_DWELL = BIT(6),
|
||||
QLINK_HW_CAPAB_SAE = BIT(8),
|
||||
QLINK_HW_CAPAB_HW_BRIDGE = BIT(9),
|
||||
};
|
||||
|
||||
enum qlink_iface_type {
|
||||
|
@ -219,6 +221,8 @@ struct qlink_sta_info_state {
|
|||
* @QLINK_CMD_START_CAC: start radar detection procedure on a specified channel.
|
||||
* @QLINK_CMD_TXPWR: get or set current channel transmit power for
|
||||
* the specified MAC.
|
||||
* @QLINK_CMD_NDEV_EVENT: signalizes changes made with a corresponding network
|
||||
* device.
|
||||
*/
|
||||
enum qlink_cmd_type {
|
||||
QLINK_CMD_FW_INIT = 0x0001,
|
||||
|
@ -251,6 +255,7 @@ enum qlink_cmd_type {
|
|||
QLINK_CMD_DEL_STA = 0x0052,
|
||||
QLINK_CMD_SCAN = 0x0053,
|
||||
QLINK_CMD_CHAN_STATS = 0x0054,
|
||||
QLINK_CMD_NDEV_EVENT = 0x0055,
|
||||
QLINK_CMD_CONNECT = 0x0060,
|
||||
QLINK_CMD_DISCONNECT = 0x0061,
|
||||
QLINK_CMD_PM_SET = 0x0062,
|
||||
|
@ -771,6 +776,42 @@ struct qlink_cmd_wowlan_set {
|
|||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
enum qlink_ndev_event_type {
|
||||
QLINK_NDEV_EVENT_CHANGEUPPER,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_ndev_event - data for QLINK_CMD_NDEV_EVENT command
|
||||
*
|
||||
* @event: type of event, one of &enum qlink_ndev_event_type
|
||||
*/
|
||||
struct qlink_cmd_ndev_event {
|
||||
struct qlink_cmd chdr;
|
||||
__le16 event;
|
||||
u8 rsvd[2];
|
||||
} __packed;
|
||||
|
||||
enum qlink_ndev_upper_type {
|
||||
QLINK_NDEV_UPPER_TYPE_NONE,
|
||||
QLINK_NDEV_UPPER_TYPE_BRIDGE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_ndev_changeupper - data for QLINK_NDEV_EVENT_CHANGEUPPER
|
||||
*
|
||||
* @br_domain: layer 2 broadcast domain ID that ndev is a member of
|
||||
* @upper_type: type of upper device, one of &enum qlink_ndev_upper_type
|
||||
*/
|
||||
struct qlink_cmd_ndev_changeupper {
|
||||
struct qlink_cmd_ndev_event nehdr;
|
||||
__le64 flags;
|
||||
__le32 br_domain;
|
||||
__le32 netspace_id;
|
||||
__le16 vlanid;
|
||||
u8 upper_type;
|
||||
u8 rsvd[1];
|
||||
} __packed;
|
||||
|
||||
/* QLINK Command Responses messages related definitions
|
||||
*/
|
||||
|
||||
|
|
Loading…
Reference in New Issue