diff --git a/drivers/net/wireless/celeno/cl8k/vif.c b/drivers/net/wireless/celeno/cl8k/vif.c
new file mode 100644
index 000000000000..7592f0d32e7a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vif.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/list.h>
+
+#include "hw.h"
+#include "mac_addr.h"
+#include "vif.h"
+
+void cl_vif_init(struct cl_hw *cl_hw)
+{
+	rwlock_init(&cl_hw->vif_db.lock);
+	INIT_LIST_HEAD(&cl_hw->vif_db.head);
+}
+
+void cl_vif_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+	struct cl_vif_db *vif_db = &cl_hw->vif_db;
+
+	write_lock_bh(&vif_db->lock);
+	list_add_tail(&cl_vif->list, &vif_db->head);
+
+	if (cl_vif->vif->type != NL80211_IFTYPE_STATION)
+		vif_db->num_iface_bcn++;
+
+	/* Multicast vif set */
+	cl_hw->mc_vif = cl_vif;
+
+	write_unlock_bh(&vif_db->lock);
+}
+
+void cl_vif_remove(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+	struct cl_vif_db *vif_db = &cl_hw->vif_db;
+
+	write_lock_bh(&vif_db->lock);
+	/* Multicast vif unset */
+	if (cl_hw->mc_vif == cl_vif)
+		cl_hw->mc_vif = cl_vif_get_next(cl_hw, cl_hw->mc_vif);
+
+	list_del(&cl_vif->list);
+
+	if (cl_vif->vif->type != NL80211_IFTYPE_STATION)
+		vif_db->num_iface_bcn--;
+	write_unlock_bh(&vif_db->lock);
+
+	cl_bcmc_cfm_poll_empty_per_vif(cl_hw, cl_vif);
+}
+
+struct cl_vif *cl_vif_get_next(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+	if (list_is_last(&cl_vif->list, &cl_hw->vif_db.head))
+		return list_first_entry_or_null(&cl_hw->vif_db.head,
+						struct cl_vif, list);
+	else
+		return list_next_entry(cl_vif, list);
+}
+
+struct cl_vif *cl_vif_get_by_dev(struct cl_hw *cl_hw, struct net_device *dev)
+{
+	struct cl_vif *cl_vif = NULL, *cl_vif_ret = NULL;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		if (cl_vif->dev == dev) {
+			cl_vif_ret = cl_vif;
+			goto unlock;
+		}
+
+unlock:
+	read_unlock_bh(&cl_hw->vif_db.lock);
+	return cl_vif_ret;
+}
+
+struct cl_vif *cl_vif_get_by_mac(struct cl_hw *cl_hw, u8 *mac_addr)
+{
+	struct cl_vif *cl_vif, *cl_vif_ret = NULL;
+
+	read_lock(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		if (cl_mac_addr_compare(cl_vif->vif->addr, mac_addr)) {
+			cl_vif_ret = cl_vif;
+			goto unlock;
+		}
+
+unlock:
+	read_unlock(&cl_hw->vif_db.lock);
+	return cl_vif_ret;
+}
+
+struct cl_vif *cl_vif_get_first(struct cl_hw *cl_hw)
+{
+	return list_first_entry_or_null(&cl_hw->vif_db.head, struct cl_vif, list);
+}
+
+struct cl_vif *cl_vif_get_first_ap(struct cl_hw *cl_hw)
+{
+	struct cl_vif *cl_vif, *cl_vif_ret = NULL;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		if (cl_vif->vif->type == NL80211_IFTYPE_AP ||
+		    cl_vif->vif->type == NL80211_IFTYPE_MESH_POINT ||
+		    cl_hw->conf->ce_listener_en) {
+			cl_vif_ret = cl_vif;
+			goto unlock;
+		}
+
+unlock:
+	read_unlock_bh(&cl_hw->vif_db.lock);
+	return cl_vif_ret;
+}
+
+struct net_device *cl_vif_get_first_net_device(struct cl_hw *cl_hw)
+{
+	struct cl_vif *cl_vif = NULL;
+	struct net_device *dev = NULL;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	cl_vif = list_first_entry_or_null(&cl_hw->vif_db.head, struct cl_vif, list);
+	if (cl_vif)
+		dev = cl_vif->dev;
+	read_unlock_bh(&cl_hw->vif_db.lock);
+
+	return dev;
+}
+
+struct net_device *cl_vif_get_dev_by_index(struct cl_hw *cl_hw, u8 index)
+{
+	struct cl_vif *cl_vif = NULL;
+	struct net_device *dev = NULL;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		if (cl_vif->vif_index == index) {
+			dev = cl_vif->dev;
+			goto unlock;
+		}
+
+unlock:
+	read_unlock_bh(&cl_hw->vif_db.lock);
+	return dev;
+}
+
+void cl_vif_ap_tx_enable(struct cl_hw *cl_hw, bool enable)
+{
+	struct cl_vif *cl_vif;
+	struct ieee80211_vif *vif;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+		vif = cl_vif->vif;
+
+		if (vif->type != NL80211_IFTYPE_AP)
+			continue;
+
+		cl_vif->tx_en = enable;
+		cl_dbg_verbose(cl_hw, "Set tx_en=%u for vif_index=%u\n",
+			       enable, cl_vif->vif_index);
+	}
+	read_unlock_bh(&cl_hw->vif_db.lock);
+}
