mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
Hosts that support 802.1X authentication are able to authenticate themselves by exchanging EAPOL frames with an authenticator (Ethernet bridge, in this case) and an authentication server. Access to the network is only granted by the authenticator to successfully authenticated hosts. The above is implemented in the bridge using the "locked" bridge port option. When enabled, link-local frames (e.g., EAPOL) can be locally received by the bridge, but all other frames are dropped unless the host is authenticated. That is, unless the user space control plane installed an FDB entry according to which the source address of the frame is located behind the locked ingress port. The entry can be dynamic, in which case learning needs to be enabled so that the entry will be refreshed by incoming traffic. There are deployments in which not all the devices connected to the authenticator (the bridge) support 802.1X. Such devices can include printers and cameras. One option to support such deployments is to unlock the bridge ports connecting these devices, but a slightly more secure option is to use MAB. When MAB is enabled, the MAC address of the connected device is used as the user name and password for the authentication. For MAB to work, the user space control plane needs to be notified about MAC addresses that are trying to gain access so that they will be compared against an allow list. This can be implemented via the regular learning process with the sole difference that learned FDB entries are installed with a new "locked" flag indicating that the entry cannot be used to authenticate the device. The flag cannot be set by user space, but user space can clear the flag by replacing the entry, thereby authenticating the device. Locked FDB entries implement the following semantics with regards to roaming, aging and forwarding: 1. Roaming: Locked FDB entries can roam to unlocked (authorized) ports, in which case the "locked" flag is cleared. FDB entries cannot roam to locked ports regardless of MAB being enabled or not. Therefore, locked FDB entries are only created if an FDB entry with the given {MAC, VID} does not already exist. This behavior prevents unauthenticated devices from disrupting traffic destined to already authenticated devices. 2. Aging: Locked FDB entries age and refresh by incoming traffic like regular entries. 3. Forwarding: Locked FDB entries forward traffic like regular entries. If user space detects an unauthorized MAC behind a locked port and wishes to prevent traffic with this MAC DA from reaching the host, it can do so using tc or a different mechanism. Enable the above behavior using a new bridge port option called "mab". It can only be enabled on a bridge port that is both locked and has learning enabled. Locked FDB entries are flushed from the port once MAB is disabled. A new option is added because there are pure 802.1X deployments that are not interested in notifications about locked FDB entries. Signed-off-by: Hans J. Schultz <netdev@kapio-technology.com> Signed-off-by: Ido Schimmel <idosch@nvidia.com> Acked-by: Nikolay Aleksandrov <razor@blackwall.org> Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
214 lines
5.5 KiB
C
214 lines
5.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Linux ethernet bridge
|
|
*
|
|
* Authors:
|
|
* Lennert Buytenhek <buytenh@gnu.org>
|
|
*/
|
|
#ifndef _LINUX_IF_BRIDGE_H
|
|
#define _LINUX_IF_BRIDGE_H
|
|
|
|
|
|
#include <linux/netdevice.h>
|
|
#include <uapi/linux/if_bridge.h>
|
|
#include <linux/bitops.h>
|
|
|
|
struct br_ip {
|
|
union {
|
|
__be32 ip4;
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
struct in6_addr ip6;
|
|
#endif
|
|
} src;
|
|
union {
|
|
__be32 ip4;
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
struct in6_addr ip6;
|
|
#endif
|
|
unsigned char mac_addr[ETH_ALEN];
|
|
} dst;
|
|
__be16 proto;
|
|
__u16 vid;
|
|
};
|
|
|
|
struct br_ip_list {
|
|
struct list_head list;
|
|
struct br_ip addr;
|
|
};
|
|
|
|
#define BR_HAIRPIN_MODE BIT(0)
|
|
#define BR_BPDU_GUARD BIT(1)
|
|
#define BR_ROOT_BLOCK BIT(2)
|
|
#define BR_MULTICAST_FAST_LEAVE BIT(3)
|
|
#define BR_ADMIN_COST BIT(4)
|
|
#define BR_LEARNING BIT(5)
|
|
#define BR_FLOOD BIT(6)
|
|
#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
|
|
#define BR_PROMISC BIT(7)
|
|
#define BR_PROXYARP BIT(8)
|
|
#define BR_LEARNING_SYNC BIT(9)
|
|
#define BR_PROXYARP_WIFI BIT(10)
|
|
#define BR_MCAST_FLOOD BIT(11)
|
|
#define BR_MULTICAST_TO_UNICAST BIT(12)
|
|
#define BR_VLAN_TUNNEL BIT(13)
|
|
#define BR_BCAST_FLOOD BIT(14)
|
|
#define BR_NEIGH_SUPPRESS BIT(15)
|
|
#define BR_ISOLATED BIT(16)
|
|
#define BR_MRP_AWARE BIT(17)
|
|
#define BR_MRP_LOST_CONT BIT(18)
|
|
#define BR_MRP_LOST_IN_CONT BIT(19)
|
|
#define BR_TX_FWD_OFFLOAD BIT(20)
|
|
#define BR_PORT_LOCKED BIT(21)
|
|
#define BR_PORT_MAB BIT(22)
|
|
|
|
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
|
|
|
|
struct net_bridge;
|
|
void brioctl_set(int (*hook)(struct net *net, struct net_bridge *br,
|
|
unsigned int cmd, struct ifreq *ifr,
|
|
void __user *uarg));
|
|
int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd,
|
|
struct ifreq *ifr, void __user *uarg);
|
|
|
|
#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
|
|
int br_multicast_list_adjacent(struct net_device *dev,
|
|
struct list_head *br_ip_list);
|
|
bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto);
|
|
bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto);
|
|
bool br_multicast_has_router_adjacent(struct net_device *dev, int proto);
|
|
bool br_multicast_enabled(const struct net_device *dev);
|
|
bool br_multicast_router(const struct net_device *dev);
|
|
#else
|
|
static inline int br_multicast_list_adjacent(struct net_device *dev,
|
|
struct list_head *br_ip_list)
|
|
{
|
|
return 0;
|
|
}
|
|
static inline bool br_multicast_has_querier_anywhere(struct net_device *dev,
|
|
int proto)
|
|
{
|
|
return false;
|
|
}
|
|
static inline bool br_multicast_has_querier_adjacent(struct net_device *dev,
|
|
int proto)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline bool br_multicast_has_router_adjacent(struct net_device *dev,
|
|
int proto)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
static inline bool br_multicast_enabled(const struct net_device *dev)
|
|
{
|
|
return false;
|
|
}
|
|
static inline bool br_multicast_router(const struct net_device *dev)
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_VLAN_FILTERING)
|
|
bool br_vlan_enabled(const struct net_device *dev);
|
|
int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid);
|
|
int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid);
|
|
int br_vlan_get_proto(const struct net_device *dev, u16 *p_proto);
|
|
int br_vlan_get_info(const struct net_device *dev, u16 vid,
|
|
struct bridge_vlan_info *p_vinfo);
|
|
int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
|
|
struct bridge_vlan_info *p_vinfo);
|
|
bool br_mst_enabled(const struct net_device *dev);
|
|
int br_mst_get_info(const struct net_device *dev, u16 msti, unsigned long *vids);
|
|
int br_mst_get_state(const struct net_device *dev, u16 msti, u8 *state);
|
|
#else
|
|
static inline bool br_vlan_enabled(const struct net_device *dev)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline int br_vlan_get_proto(const struct net_device *dev, u16 *p_proto)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline int br_vlan_get_info(const struct net_device *dev, u16 vid,
|
|
struct bridge_vlan_info *p_vinfo)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
|
|
struct bridge_vlan_info *p_vinfo)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline bool br_mst_enabled(const struct net_device *dev)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline int br_mst_get_info(const struct net_device *dev, u16 msti,
|
|
unsigned long *vids)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
static inline int br_mst_get_state(const struct net_device *dev, u16 msti,
|
|
u8 *state)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_BRIDGE)
|
|
struct net_device *br_fdb_find_port(const struct net_device *br_dev,
|
|
const unsigned char *addr,
|
|
__u16 vid);
|
|
void br_fdb_clear_offload(const struct net_device *dev, u16 vid);
|
|
bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag);
|
|
u8 br_port_get_stp_state(const struct net_device *dev);
|
|
clock_t br_get_ageing_time(const struct net_device *br_dev);
|
|
#else
|
|
static inline struct net_device *
|
|
br_fdb_find_port(const struct net_device *br_dev,
|
|
const unsigned char *addr,
|
|
__u16 vid)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static inline void br_fdb_clear_offload(const struct net_device *dev, u16 vid)
|
|
{
|
|
}
|
|
|
|
static inline bool
|
|
br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline u8 br_port_get_stp_state(const struct net_device *dev)
|
|
{
|
|
return BR_STATE_DISABLED;
|
|
}
|
|
|
|
static inline clock_t br_get_ageing_time(const struct net_device *br_dev)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#endif
|