18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __BEN_VLAN_802_1Q_INC__
38c2ecf20Sopenharmony_ci#define __BEN_VLAN_802_1Q_INC__
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
68c2ecf20Sopenharmony_ci#include <linux/u64_stats_sync.h>
78c2ecf20Sopenharmony_ci#include <linux/list.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci/* if this changes, algorithm will have to be reworked because this
108c2ecf20Sopenharmony_ci * depends on completely exhausting the VLAN identifier space.  Thus
118c2ecf20Sopenharmony_ci * it gives constant time look-up, but in many cases it wastes memory.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#define VLAN_GROUP_ARRAY_SPLIT_PARTS  8
148c2ecf20Sopenharmony_ci#define VLAN_GROUP_ARRAY_PART_LEN     (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS)
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cienum vlan_protos {
178c2ecf20Sopenharmony_ci	VLAN_PROTO_8021Q	= 0,
188c2ecf20Sopenharmony_ci	VLAN_PROTO_8021AD,
198c2ecf20Sopenharmony_ci	VLAN_PROTO_NUM,
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct vlan_group {
238c2ecf20Sopenharmony_ci	unsigned int		nr_vlan_devs;
248c2ecf20Sopenharmony_ci	struct hlist_node	hlist;	/* linked list */
258c2ecf20Sopenharmony_ci	struct net_device **vlan_devices_arrays[VLAN_PROTO_NUM]
268c2ecf20Sopenharmony_ci					       [VLAN_GROUP_ARRAY_SPLIT_PARTS];
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistruct vlan_info {
308c2ecf20Sopenharmony_ci	struct net_device	*real_dev; /* The ethernet(like) device
318c2ecf20Sopenharmony_ci					    * the vlan is attached to.
328c2ecf20Sopenharmony_ci					    */
338c2ecf20Sopenharmony_ci	struct vlan_group	grp;
348c2ecf20Sopenharmony_ci	struct list_head	vid_list;
358c2ecf20Sopenharmony_ci	unsigned int		nr_vids;
368c2ecf20Sopenharmony_ci	struct rcu_head		rcu;
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic inline int vlan_proto_idx(__be16 proto)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	switch (proto) {
428c2ecf20Sopenharmony_ci	case htons(ETH_P_8021Q):
438c2ecf20Sopenharmony_ci		return VLAN_PROTO_8021Q;
448c2ecf20Sopenharmony_ci	case htons(ETH_P_8021AD):
458c2ecf20Sopenharmony_ci		return VLAN_PROTO_8021AD;
468c2ecf20Sopenharmony_ci	default:
478c2ecf20Sopenharmony_ci		WARN(1, "invalid VLAN protocol: 0x%04x\n", ntohs(proto));
488c2ecf20Sopenharmony_ci		return -EINVAL;
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline struct net_device *__vlan_group_get_device(struct vlan_group *vg,
538c2ecf20Sopenharmony_ci							 unsigned int pidx,
548c2ecf20Sopenharmony_ci							 u16 vlan_id)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct net_device **array;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	array = vg->vlan_devices_arrays[pidx]
598c2ecf20Sopenharmony_ci				       [vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
608c2ecf20Sopenharmony_ci	return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
648c2ecf20Sopenharmony_ci						       __be16 vlan_proto,
658c2ecf20Sopenharmony_ci						       u16 vlan_id)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	int pidx = vlan_proto_idx(vlan_proto);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (pidx < 0)
708c2ecf20Sopenharmony_ci		return NULL;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return __vlan_group_get_device(vg, pidx, vlan_id);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic inline void vlan_group_set_device(struct vlan_group *vg,
768c2ecf20Sopenharmony_ci					 __be16 vlan_proto, u16 vlan_id,
778c2ecf20Sopenharmony_ci					 struct net_device *dev)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	int pidx = vlan_proto_idx(vlan_proto);
808c2ecf20Sopenharmony_ci	struct net_device **array;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (!vg || pidx < 0)
838c2ecf20Sopenharmony_ci		return;
848c2ecf20Sopenharmony_ci	array = vg->vlan_devices_arrays[pidx]
858c2ecf20Sopenharmony_ci				       [vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
868c2ecf20Sopenharmony_ci	array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/* Must be invoked with rcu_read_lock or with RTNL. */
908c2ecf20Sopenharmony_cistatic inline struct net_device *vlan_find_dev(struct net_device *real_dev,
918c2ecf20Sopenharmony_ci					       __be16 vlan_proto, u16 vlan_id)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (vlan_info)
968c2ecf20Sopenharmony_ci		return vlan_group_get_device(&vlan_info->grp,
978c2ecf20Sopenharmony_ci					     vlan_proto, vlan_id);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return NULL;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic inline netdev_features_t vlan_tnl_features(struct net_device *real_dev)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	netdev_features_t ret;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	ret = real_dev->hw_enc_features &
1078c2ecf20Sopenharmony_ci	      (NETIF_F_CSUM_MASK | NETIF_F_ALL_TSO | NETIF_F_GSO_ENCAP_ALL);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if ((ret & NETIF_F_GSO_ENCAP_ALL) && (ret & NETIF_F_CSUM_MASK))
1108c2ecf20Sopenharmony_ci		return (ret & ~NETIF_F_CSUM_MASK) | NETIF_F_HW_CSUM;
1118c2ecf20Sopenharmony_ci	return 0;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#define vlan_group_for_each_dev(grp, i, dev) \
1158c2ecf20Sopenharmony_ci	for ((i) = 0; i < VLAN_PROTO_NUM * VLAN_N_VID; i++) \
1168c2ecf20Sopenharmony_ci		if (((dev) = __vlan_group_get_device((grp), (i) / VLAN_N_VID, \
1178c2ecf20Sopenharmony_ci							    (i) % VLAN_N_VID)))
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ciint vlan_filter_push_vids(struct vlan_info *vlan_info, __be16 proto);
1208c2ecf20Sopenharmony_civoid vlan_filter_drop_vids(struct vlan_info *vlan_info, __be16 proto);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/* found in vlan_dev.c */
1238c2ecf20Sopenharmony_civoid vlan_dev_set_ingress_priority(const struct net_device *dev,
1248c2ecf20Sopenharmony_ci				   u32 skb_prio, u16 vlan_prio);
1258c2ecf20Sopenharmony_ciint vlan_dev_set_egress_priority(const struct net_device *dev,
1268c2ecf20Sopenharmony_ci				 u32 skb_prio, u16 vlan_prio);
1278c2ecf20Sopenharmony_ciint vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask);
1288c2ecf20Sopenharmony_civoid vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciint vlan_check_real_dev(struct net_device *real_dev,
1318c2ecf20Sopenharmony_ci			__be16 protocol, u16 vlan_id,
1328c2ecf20Sopenharmony_ci			struct netlink_ext_ack *extack);
1338c2ecf20Sopenharmony_civoid vlan_setup(struct net_device *dev);
1348c2ecf20Sopenharmony_ciint register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack);
1358c2ecf20Sopenharmony_civoid unregister_vlan_dev(struct net_device *dev, struct list_head *head);
1368c2ecf20Sopenharmony_civoid vlan_dev_uninit(struct net_device *dev);
1378c2ecf20Sopenharmony_cibool vlan_dev_inherit_address(struct net_device *dev,
1388c2ecf20Sopenharmony_ci			      struct net_device *real_dev);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic inline u32 vlan_get_ingress_priority(struct net_device *dev,
1418c2ecf20Sopenharmony_ci					    u16 vlan_tci)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct vlan_dev_priv *vip = vlan_dev_priv(dev);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return vip->ingress_priority_map[(vlan_tci >> VLAN_PRIO_SHIFT) & 0x7];
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#ifdef CONFIG_VLAN_8021Q_GVRP
1498c2ecf20Sopenharmony_ciint vlan_gvrp_request_join(const struct net_device *dev);
1508c2ecf20Sopenharmony_civoid vlan_gvrp_request_leave(const struct net_device *dev);
1518c2ecf20Sopenharmony_ciint vlan_gvrp_init_applicant(struct net_device *dev);
1528c2ecf20Sopenharmony_civoid vlan_gvrp_uninit_applicant(struct net_device *dev);
1538c2ecf20Sopenharmony_ciint vlan_gvrp_init(void);
1548c2ecf20Sopenharmony_civoid vlan_gvrp_uninit(void);
1558c2ecf20Sopenharmony_ci#else
1568c2ecf20Sopenharmony_cistatic inline int vlan_gvrp_request_join(const struct net_device *dev) { return 0; }
1578c2ecf20Sopenharmony_cistatic inline void vlan_gvrp_request_leave(const struct net_device *dev) {}
1588c2ecf20Sopenharmony_cistatic inline int vlan_gvrp_init_applicant(struct net_device *dev) { return 0; }
1598c2ecf20Sopenharmony_cistatic inline void vlan_gvrp_uninit_applicant(struct net_device *dev) {}
1608c2ecf20Sopenharmony_cistatic inline int vlan_gvrp_init(void) { return 0; }
1618c2ecf20Sopenharmony_cistatic inline void vlan_gvrp_uninit(void) {}
1628c2ecf20Sopenharmony_ci#endif
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci#ifdef CONFIG_VLAN_8021Q_MVRP
1658c2ecf20Sopenharmony_ciint vlan_mvrp_request_join(const struct net_device *dev);
1668c2ecf20Sopenharmony_civoid vlan_mvrp_request_leave(const struct net_device *dev);
1678c2ecf20Sopenharmony_ciint vlan_mvrp_init_applicant(struct net_device *dev);
1688c2ecf20Sopenharmony_civoid vlan_mvrp_uninit_applicant(struct net_device *dev);
1698c2ecf20Sopenharmony_ciint vlan_mvrp_init(void);
1708c2ecf20Sopenharmony_civoid vlan_mvrp_uninit(void);
1718c2ecf20Sopenharmony_ci#else
1728c2ecf20Sopenharmony_cistatic inline int vlan_mvrp_request_join(const struct net_device *dev) { return 0; }
1738c2ecf20Sopenharmony_cistatic inline void vlan_mvrp_request_leave(const struct net_device *dev) {}
1748c2ecf20Sopenharmony_cistatic inline int vlan_mvrp_init_applicant(struct net_device *dev) { return 0; }
1758c2ecf20Sopenharmony_cistatic inline void vlan_mvrp_uninit_applicant(struct net_device *dev) {}
1768c2ecf20Sopenharmony_cistatic inline int vlan_mvrp_init(void) { return 0; }
1778c2ecf20Sopenharmony_cistatic inline void vlan_mvrp_uninit(void) {}
1788c2ecf20Sopenharmony_ci#endif
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ciextern const char vlan_fullname[];
1818c2ecf20Sopenharmony_ciextern const char vlan_version[];
1828c2ecf20Sopenharmony_ciint vlan_netlink_init(void);
1838c2ecf20Sopenharmony_civoid vlan_netlink_fini(void);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ciextern struct rtnl_link_ops vlan_link_ops;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ciextern unsigned int vlan_net_id;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistruct proc_dir_entry;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistruct vlan_net {
1928c2ecf20Sopenharmony_ci	/* /proc/net/vlan */
1938c2ecf20Sopenharmony_ci	struct proc_dir_entry *proc_vlan_dir;
1948c2ecf20Sopenharmony_ci	/* /proc/net/vlan/config */
1958c2ecf20Sopenharmony_ci	struct proc_dir_entry *proc_vlan_conf;
1968c2ecf20Sopenharmony_ci	/* Determines interface naming scheme. */
1978c2ecf20Sopenharmony_ci	unsigned short name_type;
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci#endif /* !(__BEN_VLAN_802_1Q_INC__) */
201