Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55055976 authored by Vasanthakumar Thiagarajan's avatar Vasanthakumar Thiagarajan Committed by Kalle Valo
Browse files

ath6kl: Implement add_virtual_intf() and del_virtual_intf()

parent 7b85832d
Loading
Loading
Loading
Loading
+121 −2
Original line number Diff line number Diff line
@@ -293,6 +293,57 @@ static int ath6kl_set_assoc_req_ies(struct ath6kl_vif *vif, const u8 *ies,
	return ret;
}

static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
{
	switch (type) {
	case NL80211_IFTYPE_STATION:
		*nw_type = INFRA_NETWORK;
		break;
	case NL80211_IFTYPE_ADHOC:
		*nw_type = ADHOC_NETWORK;
		break;
	case NL80211_IFTYPE_AP:
		*nw_type = AP_NETWORK;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
		*nw_type = INFRA_NETWORK;
		break;
	case NL80211_IFTYPE_P2P_GO:
		*nw_type = AP_NETWORK;
		break;
	default:
		ath6kl_err("invalid interface type %u\n", type);
		return -ENOTSUPP;
	}

	return 0;
}

static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
				   u8 *if_idx, u8 *nw_type)
{
	int i;

	if (ath6kl_nliftype_to_drv_iftype(type, nw_type))
		return false;

	if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
	    ar->num_vif))
		return false;

	if (type == NL80211_IFTYPE_STATION ||
	    type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
		for (i = 0; i < MAX_NUM_VIF; i++) {
			if ((ar->avail_idx_map >> i) & BIT(0)) {
				*if_idx = i;
				return true;
			}
		}
	}

	return false;
}

static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
				   struct cfg80211_connect_params *sme)
{
@@ -1206,6 +1257,52 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
	return 0;
}

static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
						    char *name,
						    enum nl80211_iftype type,
						    u32 *flags,
						    struct vif_params *params)
{
	struct ath6kl *ar = wiphy_priv(wiphy);
	struct net_device *ndev;
	u8 if_idx, nw_type;

	if (ar->num_vif == MAX_NUM_VIF) {
		ath6kl_err("Reached maximum number of supported vif\n");
		return ERR_PTR(-EINVAL);
	}

	if (!ath6kl_is_valid_iftype(ar, type, &if_idx, &nw_type)) {
		ath6kl_err("Not a supported interface type\n");
		return ERR_PTR(-EINVAL);
	}

	ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
	if (!ndev)
		return ERR_PTR(-ENOMEM);

	ar->num_vif++;

	return ndev;
}

static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
				     struct net_device *ndev)
{
	struct ath6kl *ar = wiphy_priv(wiphy);
	struct ath6kl_vif *vif = netdev_priv(ndev);

	spin_lock(&ar->list_lock);
	list_del(&vif->list);
	spin_unlock(&ar->list_lock);

	ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));

	ath6kl_deinit_if_data(vif);

	return 0;
}

static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
					struct net_device *ndev,
					enum nl80211_iftype type, u32 *flags,
@@ -1947,6 +2044,8 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
};

static struct cfg80211_ops ath6kl_cfg80211_ops = {
	.add_virtual_intf = ath6kl_cfg80211_add_iface,
	.del_virtual_intf = ath6kl_cfg80211_del_iface,
	.change_virtual_intf = ath6kl_cfg80211_change_iface,
	.scan = ath6kl_cfg80211_scan,
	.connect = ath6kl_cfg80211_connect,
@@ -2097,18 +2196,28 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)

void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
{
	struct ath6kl *ar = vif->ar;

	aggr_module_destroy(vif->aggr_cntxt);

	ar->avail_idx_map |= BIT(vif->fw_vif_idx);

	if (vif->nw_type == ADHOC_NETWORK)
		ar->ibss_if_active = false;

	unregister_netdevice(vif->ndev);

	ar->num_vif--;
}

struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
					enum nl80211_iftype type, u8 fw_vif_idx)
					enum nl80211_iftype type, u8 fw_vif_idx,
					u8 nw_type)
{
	struct net_device *ndev;
	struct ath6kl_vif *vif;

	ndev = alloc_netdev(sizeof(*vif), "wlan%d", ether_setup);
	ndev = alloc_netdev(sizeof(*vif), name, ether_setup);
	if (!ndev)
		return NULL;

@@ -2121,8 +2230,14 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
	vif->wdev.netdev = ndev;
	vif->wdev.iftype = type;
	vif->fw_vif_idx = fw_vif_idx;
	vif->nw_type = vif->next_mode = nw_type;
	ar->wdev = &vif->wdev;

	memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
	if (fw_vif_idx != 0)
		ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
				     0x2;

	init_netdev(ndev);

	ath6kl_init_control_info(vif);
@@ -2134,11 +2249,15 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
	if (register_netdevice(ndev))
		goto err;

	ar->avail_idx_map &= ~BIT(fw_vif_idx);
	vif->sme_state = SME_DISCONNECTED;
	set_bit(WLAN_ENABLED, &vif->flags);
	ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
	set_bit(NETDEV_REGISTERED, &vif->flags);

	if (type == NL80211_IFTYPE_ADHOC)
		ar->ibss_if_active = true;

	spin_lock(&ar->list_lock);
	list_add_tail(&vif->list, &ar->vif_list);
	spin_unlock(&ar->list_lock);
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
					enum nl80211_iftype type,
					u8 fw_vif_idx);
					u8 fw_vif_idx, u8 nw_type);
int ath6kl_register_ieee80211_hw(struct ath6kl *ar);
struct ath6kl *ath6kl_core_alloc(struct device *dev);
void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar);
+4 −0
Original line number Diff line number Diff line
@@ -460,6 +460,8 @@ struct ath6kl {
	struct list_head vif_list;
	/* Lock to avoid race in vif_list entries among add/del/traverse */
	spinlock_t list_lock;
	u8 num_vif;
	u8 avail_idx_map;
	spinlock_t lock;
	struct semaphore sem;
	u16 listen_intvl_b;
@@ -470,6 +472,7 @@ struct ath6kl {
	u8 tx_pwr;
	struct ath6kl_node_mapping node_map[MAX_NODE_NUM];
	u8 ibss_ps_enable;
	bool ibss_if_active;
	u8 node_num;
	u8 next_ep_id;
	struct ath6kl_cookie *cookie_list;
@@ -666,4 +669,5 @@ void ath6kl_init_control_info(struct ath6kl_vif *vif);
void ath6kl_deinit_if_data(struct ath6kl_vif *vif);
void ath6kl_core_free(struct ath6kl *ar);
struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready);
#endif /* CORE_H */
+7 −3
Original line number Diff line number Diff line
@@ -88,7 +88,6 @@ void ath6kl_init_profile_info(struct ath6kl_vif *vif)
	memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
	memset(vif->bssid, 0, sizeof(vif->bssid));
	vif->bss_ch = 0;
	vif->nw_type = vif->next_mode = INFRA_NETWORK;
}

static int ath6kl_set_host_app_area(struct ath6kl *ar)
@@ -1414,6 +1413,7 @@ static int ath6kl_init(struct ath6kl *ar)
	int status = 0;
	s32 timeleft;
	struct net_device *ndev;
	int i;

	if (!ar)
		return -EIO;
@@ -1445,10 +1445,14 @@ static int ath6kl_init(struct ath6kl *ar)
		goto err_node_cleanup;
	}

	for (i = 0; i < MAX_NUM_VIF; i++)
		ar->avail_idx_map |= BIT(i);

	rtnl_lock();

	/* Add an initial station interface */
	ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0);
	ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
				    INFRA_NETWORK);

	rtnl_unlock();

@@ -1632,7 +1636,7 @@ err_wq:
	return ret;
}

static void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
{
	static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
	bool discon_issued;