Commit 3eacf866 authored by Arend van Spriel's avatar Arend van Spriel Committed by John W. Linville

brcmfmac: introduce brcmf_cfg80211_vif structure

This patch introduces the brcmf_cfg80211_vif structure which is
used to keep track of multiple virtual interfaces in the driver.
Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarFranky Lin <frankyl@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ec6de0ed
...@@ -682,10 +682,14 @@ struct brcmf_if_event { ...@@ -682,10 +682,14 @@ struct brcmf_if_event {
u8 bssidx; u8 bssidx;
}; };
/* forward declaration */
struct brcmf_cfg80211_vif;
/** /**
* struct brcmf_if - interface control information. * struct brcmf_if - interface control information.
* *
* @drvr: points to device related information. * @drvr: points to device related information.
* @vif: points to cfg80211 specific interface information.
* @ndev: associated network device. * @ndev: associated network device.
* @stats: interface specific network statistics. * @stats: interface specific network statistics.
* @idx: interface index in device firmware. * @idx: interface index in device firmware.
...@@ -694,6 +698,7 @@ struct brcmf_if_event { ...@@ -694,6 +698,7 @@ struct brcmf_if_event {
*/ */
struct brcmf_if { struct brcmf_if {
struct brcmf_pub *drvr; struct brcmf_pub *drvr;
struct brcmf_cfg80211_vif *vif;
struct net_device *ndev; struct net_device *ndev;
struct net_device_stats stats; struct net_device_stats stats;
int idx; int idx;
......
...@@ -49,6 +49,8 @@ ...@@ -49,6 +49,8 @@
#define BRCMF_PNO_SCAN_COMPLETE 1 #define BRCMF_PNO_SCAN_COMPLETE 1
#define BRCMF_PNO_SCAN_INCOMPLETE 0 #define BRCMF_PNO_SCAN_INCOMPLETE 0
#define BRCMF_IFACE_MAX_CNT 2
#define TLV_LEN_OFF 1 /* length offset */ #define TLV_LEN_OFF 1 /* length offset */
#define TLV_HDR_LEN 2 /* header length */ #define TLV_HDR_LEN 2 /* header length */
#define TLV_BODY_OFF 2 /* body offset */ #define TLV_BODY_OFF 2 /* body offset */
...@@ -3441,7 +3443,7 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, ...@@ -3441,7 +3443,7 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = cfg->wdev->netdev; struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_dcmd *dcmd = data; struct brcmf_dcmd *dcmd = data;
struct sk_buff *reply; struct sk_buff *reply;
int ret; int ret;
...@@ -4194,72 +4196,95 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) ...@@ -4194,72 +4196,95 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
#endif #endif
} }
static struct wireless_dev *brcmf_alloc_wdev(struct device *ndev) static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
{ {
struct wireless_dev *wdev; struct wiphy *wiphy;
s32 err = 0; s32 err = 0;
wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
if (!wdev) if (!wiphy) {
return ERR_PTR(-ENOMEM);
wdev->wiphy = wiphy_new(&wl_cfg80211_ops,
sizeof(struct brcmf_cfg80211_info));
if (!wdev->wiphy) {
WL_ERR("Could not allocate wiphy device\n"); WL_ERR("Could not allocate wiphy device\n");
err = -ENOMEM; return ERR_PTR(-ENOMEM);
goto wiphy_new_out;
} }
set_wiphy_dev(wdev->wiphy, ndev); set_wiphy_dev(wiphy, phydev);
wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP); BIT(NL80211_IFTYPE_AP);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
* it as 11a by default. * it as 11a by default.
* This will be updated with * This will be updated with
* 11n phy tables in * 11n phy tables in
* "ifconfig up" * "ifconfig up"
* if phy has 11n capability * if phy has 11n capability
*/ */
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wdev->wiphy->cipher_suites = __wl_cipher_suites; wiphy->cipher_suites = __wl_cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
* save mode * save mode
* by default * by default
*/ */
brcmf_wiphy_pno_params(wdev->wiphy); brcmf_wiphy_pno_params(wiphy);
err = wiphy_register(wdev->wiphy); err = wiphy_register(wiphy);
if (err < 0) { if (err < 0) {
WL_ERR("Could not register wiphy device (%d)\n", err); WL_ERR("Could not register wiphy device (%d)\n", err);
goto wiphy_register_out; wiphy_free(wiphy);
return ERR_PTR(err);
} }
return wdev; return wiphy;
}
wiphy_register_out: static
wiphy_free(wdev->wiphy); struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
struct net_device *netdev,
s32 mode, bool pm_block)
{
struct brcmf_cfg80211_vif *vif;
wiphy_new_out: if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
kfree(wdev); return ERR_PTR(-ENOSPC);
return ERR_PTR(err); vif = kzalloc(sizeof(*vif), GFP_KERNEL);
if (!vif)
return ERR_PTR(-ENOMEM);
vif->wdev.wiphy = cfg->wiphy;
vif->wdev.netdev = netdev;
vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
if (netdev) {
vif->ifp = netdev_priv(netdev);
netdev->ieee80211_ptr = &vif->wdev;
SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
}
vif->mode = mode;
vif->pm_block = pm_block;
vif->roam_off = -1;
list_add_tail(&vif->list, &cfg->vif_list);
cfg->vif_cnt++;
return vif;
} }
static void brcmf_free_wdev(struct brcmf_cfg80211_info *cfg) static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
{ {
struct wireless_dev *wdev = cfg->wdev; struct brcmf_cfg80211_info *cfg;
struct wiphy *wiphy;
if (!wdev) { wiphy = vif->wdev.wiphy;
WL_ERR("wdev is invalid\n"); cfg = wiphy_priv(wiphy);
return; list_del(&vif->list);
cfg->vif_cnt--;
kfree(vif);
if (!cfg->vif_cnt) {
wiphy_unregister(wiphy);
wiphy_free(wiphy);
} }
wiphy_unregister(wdev->wiphy);
wiphy_free(wdev->wiphy);
kfree(wdev);
cfg->wdev = NULL;
} }
static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
...@@ -4935,8 +4960,10 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr) ...@@ -4935,8 +4960,10 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)
{ {
struct net_device *ndev = drvr->iflist[0]->ndev; struct net_device *ndev = drvr->iflist[0]->ndev;
struct device *busdev = drvr->dev; struct device *busdev = drvr->dev;
struct wireless_dev *wdev;
struct brcmf_cfg80211_info *cfg; struct brcmf_cfg80211_info *cfg;
struct wiphy *wiphy;
struct brcmf_cfg80211_vif *vif;
struct brcmf_if *ifp;
s32 err = 0; s32 err = 0;
if (!ndev) { if (!ndev) {
...@@ -4944,35 +4971,45 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr) ...@@ -4944,35 +4971,45 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)
return NULL; return NULL;
} }
wdev = brcmf_alloc_wdev(busdev); ifp = netdev_priv(ndev);
if (IS_ERR(wdev)) { wiphy = brcmf_setup_wiphy(busdev);
if (IS_ERR(wiphy))
return NULL; return NULL;
}
wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); cfg = wiphy_priv(wiphy);
cfg = wdev_to_cfg(wdev); cfg->wiphy = wiphy;
cfg->wdev = wdev;
cfg->pub = drvr; cfg->pub = drvr;
ndev->ieee80211_ptr = wdev; INIT_LIST_HEAD(&cfg->vif_list);
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev; vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
if (IS_ERR(vif)) {
wiphy_free(wiphy);
return NULL;
}
err = wl_init_priv(cfg); err = wl_init_priv(cfg);
if (err) { if (err) {
WL_ERR("Failed to init iwm_priv (%d)\n", err); WL_ERR("Failed to init iwm_priv (%d)\n", err);
goto cfg80211_attach_out; goto cfg80211_attach_out;
} }
ifp->vif = vif;
return cfg; return cfg;
cfg80211_attach_out: cfg80211_attach_out:
brcmf_free_wdev(cfg); brcmf_free_vif(vif);
return NULL; return NULL;
} }
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
{ {
struct brcmf_cfg80211_vif *vif;
struct brcmf_cfg80211_vif *tmp;
wl_deinit_priv(cfg); wl_deinit_priv(cfg);
brcmf_free_wdev(cfg); list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
brcmf_free_vif(vif);
}
} }
void void
......
...@@ -235,6 +235,25 @@ struct brcmf_cfg80211_profile { ...@@ -235,6 +235,25 @@ struct brcmf_cfg80211_profile {
s32 band; s32 band;
}; };
/**
* struct brcmf_cfg80211_vif - virtual interface specific information.
*
* @ifp: lower layer interface pointer
* @wdev: wireless device.
* @mode: operating mode.
* @roam_off: roaming state.
* @pm_block: power-management blocked.
* @list: linked list.
*/
struct brcmf_cfg80211_vif {
struct brcmf_if *ifp;
struct wireless_dev wdev;
s32 mode;
s32 roam_off;
bool pm_block;
struct list_head list;
};
/* dongle iscan event loop */ /* dongle iscan event loop */
struct brcmf_cfg80211_iscan_eloop { struct brcmf_cfg80211_iscan_eloop {
s32 (*handler[WL_SCAN_ERSULTS_LAST]) s32 (*handler[WL_SCAN_ERSULTS_LAST])
...@@ -383,7 +402,7 @@ struct brcmf_pno_scanresults_le { ...@@ -383,7 +402,7 @@ struct brcmf_pno_scanresults_le {
/** /**
* struct brcmf_cfg80211_info - dongle private data of cfg80211 interface * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
* *
* @wdev: representing wl cfg80211 device. * @wiphy: wiphy object for cfg80211 interface.
* @conf: dongle configuration. * @conf: dongle configuration.
* @scan_request: cfg80211 scan request object. * @scan_request: cfg80211 scan request object.
* @el: main event loop. * @el: main event loop.
...@@ -422,10 +441,11 @@ struct brcmf_pno_scanresults_le { ...@@ -422,10 +441,11 @@ struct brcmf_pno_scanresults_le {
* @escan_timeout_work: scan timeout worker. * @escan_timeout_work: scan timeout worker.
* @escan_ioctl_buf: dongle command buffer for escan commands. * @escan_ioctl_buf: dongle command buffer for escan commands.
* @ap_info: host ap information. * @ap_info: host ap information.
* @ci: used to link this structure to netdev private data. * @vif_list: linked list of vif instances.
* @vif_cnt: number of vif instances.
*/ */
struct brcmf_cfg80211_info { struct brcmf_cfg80211_info {
struct wireless_dev *wdev; struct wiphy *wiphy;
struct brcmf_cfg80211_conf *conf; struct brcmf_cfg80211_conf *conf;
struct cfg80211_scan_request *scan_request; struct cfg80211_scan_request *scan_request;
struct brcmf_cfg80211_event_loop el; struct brcmf_cfg80211_event_loop el;
...@@ -464,11 +484,13 @@ struct brcmf_cfg80211_info { ...@@ -464,11 +484,13 @@ struct brcmf_cfg80211_info {
struct work_struct escan_timeout_work; struct work_struct escan_timeout_work;
u8 *escan_ioctl_buf; u8 *escan_ioctl_buf;
struct ap_info *ap_info; struct ap_info *ap_info;
struct list_head vif_list;
u8 vif_cnt;
}; };
static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *w) static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
{ {
return w->wdev->wiphy; return cfg->wiphy;
} }
static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w) static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w)
...@@ -481,9 +503,12 @@ static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd) ...@@ -481,9 +503,12 @@ static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd)
return (struct brcmf_cfg80211_info *)(wdev_priv(wd)); return (struct brcmf_cfg80211_info *)(wdev_priv(wd));
} }
static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg) static inline
struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)
{ {
return cfg->wdev->netdev; struct brcmf_cfg80211_vif *vif;
vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list);
return vif->wdev.netdev;
} }
static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev) static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment