diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-10-01 13:39:36 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-10-01 13:39:36 +0200 |
commit | e4d680c706284ca0413a84bd2a28fda76b360904 (patch) | |
tree | 6613396dafb5c7d1f2d946ea8e7f4f57a482bad6 /drivers/net/wireless/brcm80211/brcmfmac | |
parent | Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/lin... (diff) | |
parent | ath9k: Fix BTCOEX weight initialization (diff) | |
download | linux-e4d680c706284ca0413a84bd2a28fda76b360904.tar.xz linux-e4d680c706284ca0413a84bd2a28fda76b360904.zip |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 33 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/usb.c | 48 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 2416 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | 81 |
5 files changed, 1764 insertions, 860 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 55e489d2147d..17e7ae73e008 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -27,6 +27,7 @@ * IO codes that are interpreted by dongle firmware ******************************************************************************/ #define BRCMF_C_UP 2 +#define BRCMF_C_DOWN 3 #define BRCMF_C_SET_PROMISC 10 #define BRCMF_C_GET_RATE 12 #define BRCMF_C_GET_INFRA 19 @@ -50,7 +51,10 @@ #define BRCMF_C_REASSOC 53 #define BRCMF_C_SET_ROAM_TRIGGER 55 #define BRCMF_C_SET_ROAM_DELTA 57 +#define BRCMF_C_GET_BCNPRD 75 +#define BRCMF_C_SET_BCNPRD 76 #define BRCMF_C_GET_DTIMPRD 77 +#define BRCMF_C_SET_DTIMPRD 78 #define BRCMF_C_SET_COUNTRY 84 #define BRCMF_C_GET_PM 85 #define BRCMF_C_SET_PM 86 @@ -134,6 +138,9 @@ #define WLC_BSS_RSSI_ON_CHANNEL 0x0002 +#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ +#define BRCMF_STA_ASSOC 0x10 /* Associated */ + struct brcmf_event_msg { __be16 version; __be16 flags; @@ -566,6 +573,28 @@ struct brcmf_channel_info_le { __le32 scan_channel; }; +struct brcmf_sta_info_le { + __le16 ver; /* version of this struct */ + __le16 len; /* length in bytes of this structure */ + __le16 cap; /* sta's advertised capabilities */ + __le32 flags; /* flags defined below */ + __le32 idle; /* time since data pkt rx'd from sta */ + u8 ea[ETH_ALEN]; /* Station address */ + __le32 count; /* # rates in this set */ + u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */ + /* w/hi bit set if basic */ + __le32 in; /* seconds elapsed since associated */ + __le32 listen_interval_inms; /* Min Listen interval in ms for STA */ + __le32 tx_pkts; /* # of packets transmitted */ + __le32 tx_failures; /* # of packets failed */ + __le32 rx_ucast_pkts; /* # of unicast packets received */ + __le32 rx_mcast_pkts; /* # of multicast packets received */ + __le32 tx_rate; /* Rate of last successful tx frame */ + __le32 rx_rate; /* Rate of last successful rx frame */ + __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ + __le32 rx_decrypt_failures; /* # of packet decrypted failed */ +}; + /* Bus independent dongle command */ struct brcmf_dcmd { uint cmd; /* common dongle cmd definition */ @@ -585,7 +614,7 @@ struct brcmf_pub { /* Linkage ponters */ struct brcmf_bus *bus_if; struct brcmf_proto *prot; - struct brcmf_cfg80211_dev *config; + struct brcmf_cfg80211_info *config; struct device *dev; /* fullmac dongle device pointer */ /* Internal brcmf items */ @@ -658,6 +687,8 @@ extern const struct bcmevent_name bcmevent_names[]; extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); +extern uint brcmf_c_mkiovar_bsscfg(char *name, char *data, uint datalen, + char *buf, uint buflen, s32 bssidx); extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index aa4f719a51a9..15c5db5752d1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -88,6 +88,52 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) return len; } +uint +brcmf_c_mkiovar_bsscfg(char *name, char *data, uint datalen, + char *buf, uint buflen, s32 bssidx) +{ + const s8 *prefix = "bsscfg:"; + s8 *p; + u32 prefixlen; + u32 namelen; + u32 iolen; + __le32 bssidx_le; + + if (bssidx == 0) + return brcmf_c_mkiovar(name, data, datalen, buf, buflen); + + prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ + namelen = (u32) strlen(name) + 1; /* lengh of iovar name + null */ + iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen; + + if (buflen < 0 || iolen > (u32)buflen) { + brcmf_dbg(ERROR, "buffer is too short\n"); + return 0; + } + + p = buf; + + /* copy prefix, no null */ + memcpy(p, prefix, prefixlen); + p += prefixlen; + + /* copy iovar name including null */ + memcpy(p, name, namelen); + p += namelen; + + /* bss config index as first data */ + bssidx_le = cpu_to_le32(bssidx); + memcpy(p, &bssidx_le, sizeof(bssidx_le)); + p += sizeof(bssidx_le); + + /* parameter buffer follows */ + if (datalen) + memcpy(p, data, datalen); + + return iolen; + +} + bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, int prec) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 5fe6ec7f838e..a2b4b1e71017 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -160,40 +160,17 @@ static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev) return brcmf_usb_get_buspub(dev)->devinfo; } -static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo, - uint *condition, bool *pending) +static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo) { - DECLARE_WAITQUEUE(wait, current); - int timeout = IOCTL_RESP_TIMEOUT; - - /* Convert timeout in millsecond to jiffies */ - timeout = msecs_to_jiffies(timeout); - /* Wait until control frame is available */ - add_wait_queue(&devinfo->ioctl_resp_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - smp_mb(); - while (!(*condition) && (!signal_pending(current) && timeout)) { - timeout = schedule_timeout(timeout); - /* Wait until control frame is available */ - smp_mb(); - } - - if (signal_pending(current)) - *pending = true; - - set_current_state(TASK_RUNNING); - remove_wait_queue(&devinfo->ioctl_resp_wait, &wait); - - return timeout; + return wait_event_timeout(devinfo->ioctl_resp_wait, + devinfo->ctl_completed, + msecs_to_jiffies(IOCTL_RESP_TIMEOUT)); } -static int brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo) +static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo) { if (waitqueue_active(&devinfo->ioctl_resp_wait)) - wake_up_interruptible(&devinfo->ioctl_resp_wait); - - return 0; + wake_up(&devinfo->ioctl_resp_wait); } static void @@ -322,7 +299,6 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len) { int err = 0; int timeout = 0; - bool pending; struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { @@ -340,9 +316,7 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len) clear_bit(0, &devinfo->ctl_op); return err; } - - timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed, - &pending); + timeout = brcmf_usb_ioctl_resp_wait(devinfo); clear_bit(0, &devinfo->ctl_op); if (!timeout) { brcmf_dbg(ERROR, "Txctl wait timed out\n"); @@ -355,7 +329,6 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len) { int err = 0; int timeout = 0; - bool pending; struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { @@ -365,15 +338,14 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len) if (test_and_set_bit(0, &devinfo->ctl_op)) return -EIO; + devinfo->ctl_completed = false; err = brcmf_usb_recv_ctl(devinfo, buf, len); if (err) { brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); clear_bit(0, &devinfo->ctl_op); return err; } - devinfo->ctl_completed = false; - timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed, - &pending); + timeout = brcmf_usb_ioctl_resp_wait(devinfo); err = devinfo->ctl_urb_status; clear_bit(0, &devinfo->ctl_op); if (!timeout) { @@ -493,6 +465,8 @@ static void brcmf_usb_tx_complete(struct urb *urb) else devinfo->bus_pub.bus->dstats.tx_errors++; + brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); + brcmu_pkt_buf_free_skb(req->skb); req->skb = NULL; brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index af396e4ab977..c1abaa6db59e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -48,6 +48,46 @@ #define BRCMF_PNO_SCAN_COMPLETE 1 #define BRCMF_PNO_SCAN_INCOMPLETE 0 +#define TLV_LEN_OFF 1 /* length offset */ +#define TLV_HDR_LEN 2 /* header length */ +#define TLV_BODY_OFF 2 /* body offset */ +#define TLV_OUI_LEN 3 /* oui id length */ +#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ +#define WPA_OUI_TYPE 1 +#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */ +#define WME_OUI_TYPE 2 + +#define VS_IE_FIXED_HDR_LEN 6 +#define WPA_IE_VERSION_LEN 2 +#define WPA_IE_MIN_OUI_LEN 4 +#define WPA_IE_SUITE_COUNT_LEN 2 + +#define WPA_CIPHER_NONE 0 /* None */ +#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ +#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ +#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ +#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ + +#define RSN_AKM_NONE 0 /* None (IBSS) */ +#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ +#define RSN_AKM_PSK 2 /* Pre-shared Key */ +#define RSN_CAP_LEN 2 /* Length of RSN capabilities */ +#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C + +#define VNDR_IE_CMD_LEN 4 /* length of the set command + * string :"add", "del" (+ NUL) + */ +#define VNDR_IE_COUNT_OFFSET 4 +#define VNDR_IE_PKTFLAG_OFFSET 8 +#define VNDR_IE_VSIE_OFFSET 12 +#define VNDR_IE_HDR_SIZE 12 +#define VNDR_IE_BEACON_FLAG 0x1 +#define VNDR_IE_PRBRSP_FLAG 0x2 +#define MAX_VNDR_IE_NUMBER 5 + +#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */ +#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */ + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) @@ -55,33 +95,12 @@ static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; static u32 brcmf_dbg_level = WL_DBG_ERR; -static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data) -{ - dev->driver_data = data; -} - -static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev) -{ - void *data = NULL; - - if (dev) - data = dev->driver_data; - return data; -} - -static -struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev) -{ - struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg_dev); - return ci->cfg_priv; -} - static bool check_sys_up(struct wiphy *wiphy) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + if (!test_bit(WL_STATUS_READY, &cfg->status)) { WL_INFO("device is not ready : status (%d)\n", - (int)cfg_priv->status); + (int)cfg->status); return false; } return true; @@ -269,6 +288,25 @@ struct brcmf_tlv { u8 data[1]; }; +/* Vendor specific ie. id = 221, oui and type defines exact ie */ +struct brcmf_vs_tlv { + u8 id; + u8 len; + u8 oui[3]; + u8 oui_type; +}; + +struct parsed_vndr_ie_info { + u8 *ie_ptr; + u32 ie_len; /* total length including id & length field */ + struct brcmf_vs_tlv vndrie; +}; + +struct parsed_vndr_ies { + u32 count; + struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; +}; + /* Quarter dBm units to mW * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 * Table is offset so the last entry is largest mW value that fits in @@ -366,6 +404,44 @@ brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par) return err; } +static s32 +brcmf_dev_iovar_setbuf_bsscfg(struct net_device *ndev, s8 *name, + void *param, s32 paramlen, + void *buf, s32 buflen, s32 bssidx) +{ + s32 err = -ENOMEM; + u32 len; + + len = brcmf_c_mkiovar_bsscfg(name, param, paramlen, + buf, buflen, bssidx); + BUG_ON(!len); + if (len > 0) + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len); + if (err) + WL_ERR("error (%d)\n", err); + + return err; +} + +static s32 +brcmf_dev_iovar_getbuf_bsscfg(struct net_device *ndev, s8 *name, + void *param, s32 paramlen, + void *buf, s32 buflen, s32 bssidx) +{ + s32 err = -ENOMEM; + u32 len; + + len = brcmf_c_mkiovar_bsscfg(name, param, paramlen, + buf, buflen, bssidx); + BUG_ON(!len); + if (len > 0) + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, buf, len); + if (err) + WL_ERR("error (%d)\n", err); + + return err; +} + static void convert_key_from_CPU(struct brcmf_wsec_key *key, struct brcmf_wsec_key_le *key_le) { @@ -380,16 +456,22 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key, memcpy(key_le->ea, key->ea, sizeof(key->ea)); } -static int send_key_to_dongle(struct net_device *ndev, - struct brcmf_wsec_key *key) +static int +send_key_to_dongle(struct brcmf_cfg80211_info *cfg, s32 bssidx, + struct net_device *ndev, struct brcmf_wsec_key *key) { int err; struct brcmf_wsec_key_le key_le; convert_key_from_CPU(key, &key_le); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le)); + + err = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le, + sizeof(key_le), + cfg->extra_buf, + WL_EXTRA_BUF_MAX, bssidx); + if (err) - WL_ERR("WLC_SET_KEY error (%d)\n", err); + WL_ERR("wsec_key error (%d)\n", err); return err; } @@ -398,14 +480,12 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct wireless_dev *wdev; + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); s32 infra = 0; + s32 ap = 0; s32 err = 0; - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; + WL_TRACE("Enter, ndev=%p, type=%d\n", ndev, type); switch (type) { case NL80211_IFTYPE_MONITOR: @@ -414,29 +494,44 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, type); return -EOPNOTSUPP; case NL80211_IFTYPE_ADHOC: - cfg_priv->conf->mode = WL_MODE_IBSS; + cfg->conf->mode = WL_MODE_IBSS; infra = 0; break; case NL80211_IFTYPE_STATION: - cfg_priv->conf->mode = WL_MODE_BSS; + cfg->conf->mode = WL_MODE_BSS; infra = 1; break; + case NL80211_IFTYPE_AP: + cfg->conf->mode = WL_MODE_AP; + ap = 1; + break; default: err = -EINVAL; goto done; } - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); - if (err) { - WL_ERR("WLC_SET_INFRA error (%d)\n", err); - err = -EAGAIN; + if (ap) { + set_bit(WL_STATUS_AP_CREATING, &cfg->status); + if (!cfg->ap_info) + cfg->ap_info = kzalloc(sizeof(*cfg->ap_info), + GFP_KERNEL); + if (!cfg->ap_info) { + err = -ENOMEM; + goto done; + } + WL_INFO("IF Type = AP\n"); } else { - wdev = ndev->ieee80211_ptr; - wdev->iftype = type; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); + if (err) { + WL_ERR("WLC_SET_INFRA error (%d)\n", err); + err = -EAGAIN; + goto done; + } + WL_INFO("IF Type = %s\n", + (cfg->conf->mode == WL_MODE_IBSS) ? + "Adhoc" : "Infra"); } - - WL_INFO("IF Type = %s\n", - (cfg_priv->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra"); + ndev->ieee80211_ptr->iftype = type; done: WL_TRACE("Exit\n"); @@ -487,12 +582,55 @@ brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval) return err; } +static s32 +brcmf_dev_intvar_set_bsscfg(struct net_device *ndev, s8 *name, u32 val, + s32 bssidx) +{ + s8 buf[BRCMF_DCMD_SMLEN]; + __le32 val_le; + + val_le = cpu_to_le32(val); + + return brcmf_dev_iovar_setbuf_bsscfg(ndev, name, &val_le, + sizeof(val_le), buf, sizeof(buf), + bssidx); +} + +static s32 +brcmf_dev_intvar_get_bsscfg(struct net_device *ndev, s8 *name, s32 *val, + s32 bssidx) +{ + s8 buf[BRCMF_DCMD_SMLEN]; + s32 err; + __le32 val_le; + + memset(buf, 0, sizeof(buf)); + err = brcmf_dev_iovar_getbuf_bsscfg(ndev, name, val, sizeof(*val), buf, + sizeof(buf), bssidx); + if (err == 0) { + memcpy(&val_le, buf, sizeof(val_le)); + *val = le32_to_cpu(val_le); + } + return err; +} + + +/* + * For now brcmf_find_bssidx will return 0. Once p2p gets implemented this + * should return the ndev matching bssidx. + */ +static s32 +brcmf_find_bssidx(struct brcmf_cfg80211_info *cfg, struct net_device *ndev) +{ + return 0; +} + static void brcmf_set_mpc(struct net_device *ndev, int mpc) { s32 err = 0; - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { + if (test_bit(WL_STATUS_READY, &cfg->status)) { err = brcmf_dev_intvar_set(ndev, "mpc", mpc); if (err) { WL_ERR("fail to set mpc\n"); @@ -578,10 +716,10 @@ brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, return err; } -static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_do_iscan(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); + struct net_device *ndev = cfg_to_ndev(cfg); struct brcmf_ssid ssid; __le32 passive_scan; s32 err = 0; @@ -591,19 +729,19 @@ static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv) iscan->state = WL_ISCAN_STATE_SCANING; - passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1); - err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN, + passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); + err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_SET_PASSIVE_SCAN, &passive_scan, sizeof(passive_scan)); if (err) { WL_ERR("error (%d)\n", err); return err; } brcmf_set_mpc(ndev, 0); - cfg_priv->iscan_kickstart = true; + cfg->iscan_kickstart = true; err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START); if (err) { brcmf_set_mpc(ndev, 1); - cfg_priv->iscan_kickstart = false; + cfg->iscan_kickstart = false; return err; } mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); @@ -616,27 +754,27 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); struct cfg80211_ssid *ssids; - struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int; + struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int; __le32 passive_scan; bool iscan_req; bool spec_scan; s32 err = 0; u32 SSID_len; - if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { - WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); + if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { + WL_ERR("Scanning already : status (%lu)\n", cfg->status); return -EAGAIN; } - if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) { + if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) { WL_ERR("Scanning being aborted : status (%lu)\n", - cfg_priv->status); + cfg->status); return -EAGAIN; } - if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { + if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) { WL_ERR("Connecting : status (%lu)\n", - cfg_priv->status); + cfg->status); return -EAGAIN; } @@ -645,7 +783,7 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev, if (request) { /* scan bss */ ssids = request->ssids; - if (cfg_priv->iscan_on && (!ssids || !ssids->ssid_len)) + if (cfg->iscan_on && (!ssids || !ssids->ssid_len)) iscan_req = true; } else { /* scan in ibss */ @@ -653,10 +791,10 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev, ssids = this_ssid; } - cfg_priv->scan_request = request; - set_bit(WL_STATUS_SCANNING, &cfg_priv->status); + cfg->scan_request = request; + set_bit(WL_STATUS_SCANNING, &cfg->status); if (iscan_req) { - err = brcmf_do_iscan(cfg_priv); + err = brcmf_do_iscan(cfg); if (!err) return err; else @@ -675,7 +813,7 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev, WL_SCAN("Broadcast scan\n"); } - passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1); + passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, &passive_scan, sizeof(passive_scan)); if (err) { @@ -700,8 +838,8 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev, return 0; scan_out: - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); - cfg_priv->scan_request = NULL; + clear_bit(WL_STATUS_SCANNING, &cfg->status); + cfg->scan_request = NULL; return err; } @@ -806,7 +944,7 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, } static s32 -brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, bool aborted, bool fw_abort) { @@ -818,11 +956,11 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv, /* clear scan request, because the FW abort can cause a second call */ /* to this functon and might cause a double cfg80211_scan_done */ - scan_request = cfg_priv->scan_request; - cfg_priv->scan_request = NULL; + scan_request = cfg->scan_request; + cfg->scan_request = NULL; - if (timer_pending(&cfg_priv->escan_timeout)) - del_timer_sync(&cfg_priv->escan_timeout); + if (timer_pending(&cfg->escan_timeout)) + del_timer_sync(&cfg->escan_timeout); if (fw_abort) { /* Do a scan abort to stop the driver's scan engine */ @@ -848,11 +986,11 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv, * e-scan can be initiated by scheduled scan * which takes precedence. */ - if (cfg_priv->sched_escan) { + if (cfg->sched_escan) { WL_SCAN("scheduled scan completed\n"); - cfg_priv->sched_escan = false; + cfg->sched_escan = false; if (!aborted) - cfg80211_sched_scan_results(cfg_to_wiphy(cfg_priv)); + cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); brcmf_set_mpc(ndev, 1); } else if (scan_request) { WL_SCAN("ESCAN Completed scan: %s\n", @@ -860,7 +998,7 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv, cfg80211_scan_done(scan_request, aborted); brcmf_set_mpc(ndev, 1); } - if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { WL_ERR("Scan complete while device not scanning\n"); return -EPERM; } @@ -869,7 +1007,7 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv, } static s32 -brcmf_run_escan(struct brcmf_cfg80211_priv *cfg_priv, struct net_device *ndev, +brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, struct cfg80211_scan_request *request, u16 action) { s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + @@ -899,7 +1037,7 @@ brcmf_run_escan(struct brcmf_cfg80211_priv *cfg_priv, struct net_device *ndev, params->sync_id = cpu_to_le16(0x1234); err = brcmf_dev_iovar_setbuf(ndev, "escan", params, params_size, - cfg_priv->escan_ioctl_buf, BRCMF_DCMD_MEDLEN); + cfg->escan_ioctl_buf, BRCMF_DCMD_MEDLEN); if (err) { if (err == -EBUSY) WL_INFO("system busy : escan canceled\n"); @@ -913,7 +1051,7 @@ exit: } static s32 -brcmf_do_escan(struct brcmf_cfg80211_priv *cfg_priv, struct wiphy *wiphy, +brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request) { s32 err; @@ -921,10 +1059,10 @@ brcmf_do_escan(struct brcmf_cfg80211_priv *cfg_priv, struct wiphy *wiphy, struct brcmf_scan_results *results; WL_SCAN("Enter\n"); - cfg_priv->escan_info.ndev = ndev; - cfg_priv->escan_info.wiphy = wiphy; - cfg_priv->escan_info.escan_state = WL_ESCAN_STATE_SCANNING; - passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1); + cfg->escan_info.ndev = ndev; + cfg->escan_info.wiphy = wiphy; + cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING; + passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, &passive_scan, sizeof(passive_scan)); if (err) { @@ -932,12 +1070,12 @@ brcmf_do_escan(struct brcmf_cfg80211_priv *cfg_priv, struct wiphy *wiphy, return err; } brcmf_set_mpc(ndev, 0); - results = (struct brcmf_scan_results *)cfg_priv->escan_info.escan_buf; + results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf; results->version = 0; results->count = 0; results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE; - err = brcmf_run_escan(cfg_priv, ndev, request, WL_ESCAN_ACTION_START); + err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START); if (err) brcmf_set_mpc(ndev, 1); return err; @@ -948,9 +1086,9 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); struct cfg80211_ssid *ssids; - struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int; + struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int; __le32 passive_scan; bool escan_req; bool spec_scan; @@ -959,23 +1097,23 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, WL_SCAN("START ESCAN\n"); - if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { - WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); + if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { + WL_ERR("Scanning already : status (%lu)\n", cfg->status); return -EAGAIN; } - if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) { + if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) { WL_ERR("Scanning being aborted : status (%lu)\n", - cfg_priv->status); + cfg->status); return -EAGAIN; } - if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { + if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) { WL_ERR("Connecting : status (%lu)\n", - cfg_priv->status); + cfg->status); return -EAGAIN; } /* Arm scan timeout timer */ - mod_timer(&cfg_priv->escan_timeout, jiffies + + mod_timer(&cfg->escan_timeout, jiffies + WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); escan_req = false; @@ -989,10 +1127,10 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, ssids = this_ssid; } - cfg_priv->scan_request = request; - set_bit(WL_STATUS_SCANNING, &cfg_priv->status); + cfg->scan_request = request; + set_bit(WL_STATUS_SCANNING, &cfg->status); if (escan_req) { - err = brcmf_do_escan(cfg_priv, wiphy, ndev, request); + err = brcmf_do_escan(cfg, wiphy, ndev, request); if (!err) return err; else @@ -1011,7 +1149,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, } else WL_SCAN("Broadcast scan\n"); - passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1); + passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1); err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, &passive_scan, sizeof(passive_scan)); if (err) { @@ -1036,10 +1174,10 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, return 0; scan_out: - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); - if (timer_pending(&cfg_priv->escan_timeout)) - del_timer_sync(&cfg_priv->escan_timeout); - cfg_priv->scan_request = NULL; + clear_bit(WL_STATUS_SCANNING, &cfg->status); + if (timer_pending(&cfg->escan_timeout)) + del_timer_sync(&cfg->escan_timeout); + cfg->scan_request = NULL; return err; } @@ -1048,7 +1186,7 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct net_device *ndev = request->wdev->netdev; - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); s32 err = 0; WL_TRACE("Enter\n"); @@ -1056,9 +1194,9 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, if (!check_sys_up(wiphy)) return -EIO; - if (cfg_priv->iscan_on) + if (cfg->iscan_on) err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL); - else if (cfg_priv->escan_on) + else if (cfg->escan_on) err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL); if (err) @@ -1105,8 +1243,8 @@ static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l) static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg); s32 err = 0; WL_TRACE("Enter\n"); @@ -1114,30 +1252,30 @@ static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return -EIO; if (changed & WIPHY_PARAM_RTS_THRESHOLD && - (cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) { - cfg_priv->conf->rts_threshold = wiphy->rts_threshold; - err = brcmf_set_rts(ndev, cfg_priv->conf->rts_threshold); + (cfg->conf->rts_threshold != wiphy->rts_threshold)) { + cfg->conf->rts_threshold = wiphy->rts_threshold; + err = brcmf_set_rts(ndev, cfg->conf->rts_threshold); if (!err) goto done; } if (changed & WIPHY_PARAM_FRAG_THRESHOLD && - (cfg_priv->conf->frag_threshold != wiphy->frag_threshold)) { - cfg_priv->conf->frag_threshold = wiphy->frag_threshold; - err = brcmf_set_frag(ndev, cfg_priv->conf->frag_threshold); + (cfg->conf->frag_threshold != wiphy->frag_threshold)) { + cfg->conf->frag_threshold = wiphy->frag_threshold; + err = brcmf_set_frag(ndev, cfg->conf->frag_threshold); if (!err) goto done; } if (changed & WIPHY_PARAM_RETRY_LONG - && (cfg_priv->conf->retry_long != wiphy->retry_long)) { - cfg_priv->conf->retry_long = wiphy->retry_long; - err = brcmf_set_retry(ndev, cfg_priv->conf->retry_long, true); + && (cfg->conf->retry_long != wiphy->retry_long)) { + cfg->conf->retry_long = wiphy->retry_long; + err = brcmf_set_retry(ndev, cfg->conf->retry_long, true); if (!err) goto done; } if (changed & WIPHY_PARAM_RETRY_SHORT - && (cfg_priv->conf->retry_short != wiphy->retry_short)) { - cfg_priv->conf->retry_short = wiphy->retry_short; - err = brcmf_set_retry(ndev, cfg_priv->conf->retry_short, false); + && (cfg->conf->retry_short != wiphy->retry_short)) { + cfg->conf->retry_short = wiphy->retry_short; + err = brcmf_set_retry(ndev, cfg->conf->retry_short, false); if (!err) goto done; } @@ -1147,61 +1285,6 @@ done: return err; } -static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item) -{ - switch (item) { - case WL_PROF_SEC: - return &cfg_priv->profile->sec; - case WL_PROF_BSSID: - return &cfg_priv->profile->bssid; - case WL_PROF_SSID: - return &cfg_priv->profile->ssid; - } - WL_ERR("invalid item (%d)\n", item); - return NULL; -} - -static s32 -brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e, void *data, s32 item) -{ - s32 err = 0; - struct brcmf_ssid *ssid; - - switch (item) { - case WL_PROF_SSID: - ssid = (struct brcmf_ssid *) data; - memset(cfg_priv->profile->ssid.SSID, 0, - sizeof(cfg_priv->profile->ssid.SSID)); - memcpy(cfg_priv->profile->ssid.SSID, - ssid->SSID, ssid->SSID_len); - cfg_priv->profile->ssid.SSID_len = ssid->SSID_len; - break; - case WL_PROF_BSSID: - if (data) - memcpy(cfg_priv->profile->bssid, data, ETH_ALEN); - else - memset(cfg_priv->profile->bssid, 0, ETH_ALEN); - break; - case WL_PROF_SEC: - memcpy(&cfg_priv->profile->sec, data, - sizeof(cfg_priv->profile->sec)); - break; - case WL_PROF_BEACONINT: - cfg_priv->profile->beacon_interval = *(u16 *)data; - break; - case WL_PROF_DTIMPERIOD: - cfg_priv->profile->dtim_period = *(u8 *)data; - break; - default: - WL_ERR("unsupported item (%d)\n", item); - err = -EOPNOTSUPP; - break; - } - - return err; -} - static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) { memset(prof, 0, sizeof(*prof)); @@ -1234,20 +1317,20 @@ static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, } } -static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_link_down(struct brcmf_cfg80211_info *cfg) { struct net_device *ndev = NULL; s32 err = 0; WL_TRACE("Enter\n"); - if (cfg_priv->link_up) { - ndev = cfg_to_ndev(cfg_priv); + if (cfg->link_up) { + ndev = cfg_to_ndev(cfg); WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0); if (err) WL_ERR("WLC_DISASSOC failed (%d)\n", err); - cfg_priv->link_up = false; + cfg->link_up = false; } WL_TRACE("Exit\n"); } @@ -1256,13 +1339,13 @@ static s32 brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_join_params join_params; size_t join_params_size = 0; s32 err = 0; s32 wsec = 0; s32 bcnprd; - struct brcmf_ssid ssid; WL_TRACE("Enter\n"); if (!check_sys_up(wiphy)) @@ -1275,7 +1358,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, return -EOPNOTSUPP; } - set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + set_bit(WL_STATUS_CONNECTING, &cfg->status); if (params->bssid) WL_CONN("BSSID: %pM\n", params->bssid); @@ -1338,40 +1421,38 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, memset(&join_params, 0, sizeof(struct brcmf_join_params)); /* SSID */ - ssid.SSID_len = min_t(u32, params->ssid_len, 32); - memcpy(ssid.SSID, params->ssid, ssid.SSID_len); - memcpy(join_params.ssid_le.SSID, params->ssid, ssid.SSID_len); - join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); + profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32); + memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len); + memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len); + join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); join_params_size = sizeof(join_params.ssid_le); - brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID); /* BSSID */ if (params->bssid) { memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN); join_params_size = sizeof(join_params.ssid_le) + BRCMF_ASSOC_PARAMS_FIXED_SIZE; + memcpy(profile->bssid, params->bssid, ETH_ALEN); } else { memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); + memset(profile->bssid, 0, ETH_ALEN); } - brcmf_update_prof(cfg_priv, NULL, - &join_params.params_le.bssid, WL_PROF_BSSID); - /* Channel */ if (params->channel) { u32 target_channel; - cfg_priv->channel = + cfg->channel = ieee80211_frequency_to_channel( params->channel->center_freq); if (params->channel_fixed) { /* adding chanspec */ - brcmf_ch_to_chanspec(cfg_priv->channel, + brcmf_ch_to_chanspec(cfg->channel, &join_params, &join_params_size); } /* set channel for starter */ - target_channel = cfg_priv->channel; + target_channel = cfg->channel; err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL, &target_channel); if (err) { @@ -1379,9 +1460,9 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, goto done; } } else - cfg_priv->channel = 0; + cfg->channel = 0; - cfg_priv->ibss_starter = false; + cfg->ibss_starter = false; err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, @@ -1393,7 +1474,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, done: if (err) - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + clear_bit(WL_STATUS_CONNECTING, &cfg->status); WL_TRACE("Exit\n"); return err; } @@ -1401,14 +1482,14 @@ done: static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); s32 err = 0; WL_TRACE("Enter\n"); if (!check_sys_up(wiphy)) return -EIO; - brcmf_link_down(cfg_priv); + brcmf_link_down(cfg); WL_TRACE("Exit\n"); @@ -1418,7 +1499,8 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) static s32 brcmf_set_wpa_version(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_cfg80211_security *sec; s32 val = 0; s32 err = 0; @@ -1435,7 +1517,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, WL_ERR("set wpa_auth failed (%d)\n", err); return err; } - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec = &profile->sec; sec->wpa_versions = sme->crypto.wpa_versions; return err; } @@ -1443,7 +1525,8 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, static s32 brcmf_set_auth_type(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_cfg80211_security *sec; s32 val = 0; s32 err = 0; @@ -1474,7 +1557,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, WL_ERR("set auth failed (%d)\n", err); return err; } - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec = &profile->sec; sec->auth_type = sme->auth_type; return err; } @@ -1483,7 +1566,8 @@ static s32 brcmf_set_set_cipher(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_cfg80211_security *sec; s32 pval = 0; s32 gval = 0; @@ -1539,7 +1623,7 @@ brcmf_set_set_cipher(struct net_device *ndev, return err; } - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec = &profile->sec; sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; sec->cipher_group = sme->crypto.cipher_group; @@ -1549,7 +1633,8 @@ brcmf_set_set_cipher(struct net_device *ndev, static s32 brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_cfg80211_security *sec; s32 val = 0; s32 err = 0; @@ -1595,74 +1680,76 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) return err; } } - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec = &profile->sec; sec->wpa_auth = sme->crypto.akm_suites[0]; return err; } static s32 -brcmf_set_wep_sharedkey(struct net_device *ndev, - struct cfg80211_connect_params *sme) +brcmf_set_sharedkey(struct net_device *ndev, + struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_cfg80211_security *sec; struct brcmf_wsec_key key; s32 val; s32 err = 0; + s32 bssidx; WL_CONN("key len (%d)\n", sme->key_len); if (sme->key_len == 0) return 0; - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec = &profile->sec; WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n", sec->wpa_versions, sec->cipher_pairwise); if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) return 0; - if (sec->cipher_pairwise & - (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)) { - memset(&key, 0, sizeof(key)); - key.len = (u32) sme->key_len; - key.index = (u32) sme->key_idx; - if (key.len > sizeof(key.data)) { - WL_ERR("Too long key length (%u)\n", key.len); - return -EINVAL; - } - memcpy(key.data, sme->key, key.len); - key.flags = BRCMF_PRIMARY_KEY; - switch (sec->cipher_pairwise) { - case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - break; - default: - WL_ERR("Invalid algorithm (%d)\n", - sme->crypto.ciphers_pairwise[0]); - return -EINVAL; - } - /* Set the new key/index */ - WL_CONN("key length (%d) key index (%d) algo (%d)\n", - key.len, key.index, key.algo); - WL_CONN("key \"%s\"\n", key.data); - err = send_key_to_dongle(ndev, &key); - if (err) - return err; + if (!(sec->cipher_pairwise & + (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104))) + return 0; - if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { - WL_CONN("set auth_type to shared key\n"); - val = 1; /* shared key */ - err = brcmf_dev_intvar_set(ndev, "auth", val); - if (err) { - WL_ERR("set auth failed (%d)\n", err); - return err; - } - } + memset(&key, 0, sizeof(key)); + key.len = (u32) sme->key_len; + key.index = (u32) sme->key_idx; + if (key.len > sizeof(key.data)) { + WL_ERR("Too long key length (%u)\n", key.len); + return -EINVAL; + } + memcpy(key.data, sme->key, key.len); + key.flags = BRCMF_PRIMARY_KEY; + switch (sec->cipher_pairwise) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + break; + default: + WL_ERR("Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0]); + return -EINVAL; + } + /* Set the new key/index */ + WL_CONN("key length (%d) key index (%d) algo (%d)\n", + key.len, key.index, key.algo); + WL_CONN("key \"%s\"\n", key.data); + bssidx = brcmf_find_bssidx(cfg, ndev); + err = send_key_to_dongle(cfg, bssidx, ndev, &key); + if (err) + return err; + + if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { + WL_CONN("set auth_type to shared key\n"); + val = WL_AUTH_SHARED_KEY; /* shared key */ + err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", val, bssidx); + if (err) + WL_ERR("set auth failed (%d)\n", err); } return err; } @@ -1671,7 +1758,8 @@ static s32 brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct ieee80211_channel *chan = sme->channel; struct brcmf_join_params join_params; size_t join_params_size; @@ -1688,15 +1776,15 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, return -EOPNOTSUPP; } - set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + set_bit(WL_STATUS_CONNECTING, &cfg->status); if (chan) { - cfg_priv->channel = + cfg->channel = ieee80211_frequency_to_channel(chan->center_freq); WL_CONN("channel (%d), center_req (%d)\n", - cfg_priv->channel, chan->center_freq); + cfg->channel, chan->center_freq); } else - cfg_priv->channel = 0; + cfg->channel = 0; WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); @@ -1724,20 +1812,20 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } - err = brcmf_set_wep_sharedkey(ndev, sme); + err = brcmf_set_sharedkey(ndev, sme); if (err) { - WL_ERR("brcmf_set_wep_sharedkey failed (%d)\n", err); + WL_ERR("brcmf_set_sharedkey failed (%d)\n", err); goto done; } memset(&join_params, 0, sizeof(join_params)); join_params_size = sizeof(join_params.ssid_le); - ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), (u32)sme->ssid_len); - memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len); - memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len); - join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); - brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID); + profile->ssid.SSID_len = min_t(u32, + sizeof(ssid.SSID), (u32)sme->ssid_len); + memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len); + memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); + join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); @@ -1745,7 +1833,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, WL_CONN("ssid \"%s\", len (%d)\n", ssid.SSID, ssid.SSID_len); - brcmf_ch_to_chanspec(cfg_priv->channel, + brcmf_ch_to_chanspec(cfg->channel, &join_params, &join_params_size); err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, &join_params, join_params_size); @@ -1754,7 +1842,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, done: if (err) - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + clear_bit(WL_STATUS_CONNECTING, &cfg->status); WL_TRACE("Exit\n"); return err; } @@ -1763,7 +1851,8 @@ static s32 brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_scb_val_le scbval; s32 err = 0; @@ -1771,16 +1860,16 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, if (!check_sys_up(wiphy)) return -EIO; - clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + clear_bit(WL_STATUS_CONNECTED, &cfg->status); - memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN); + memcpy(&scbval.ea, &profile->bssid, ETH_ALEN); scbval.val = cpu_to_le32(reason_code); err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval, sizeof(struct brcmf_scb_val_le)); if (err) WL_ERR("error (%d)\n", err); - cfg_priv->link_up = false; + cfg->link_up = false; WL_TRACE("Exit\n"); return err; @@ -1791,8 +1880,8 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, s32 mbm) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg); u16 txpwrmw; s32 err = 0; s32 disable = 0; @@ -1828,7 +1917,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, (s32) (brcmf_mw_to_qdbm(txpwrmw))); if (err) WL_ERR("qtxpower error (%d)\n", err); - cfg_priv->conf->tx_power = dbm; + cfg->conf->tx_power = dbm; done: WL_TRACE("Exit\n"); @@ -1837,8 +1926,8 @@ done: static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg); s32 txpwrdbm; u8 result; s32 err = 0; @@ -1865,16 +1954,19 @@ static s32 brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool unicast, bool multicast) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); u32 index; u32 wsec; s32 err = 0; + s32 bssidx; WL_TRACE("Enter\n"); WL_CONN("key index (%d)\n", key_idx); if (!check_sys_up(wiphy)) return -EIO; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec); + bssidx = brcmf_find_bssidx(cfg, ndev); + err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); if (err) { WL_ERR("WLC_GET_WSEC error (%d)\n", err); goto done; @@ -1897,9 +1989,11 @@ static s32 brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, const u8 *mac_addr, struct key_params *params) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_wsec_key key; struct brcmf_wsec_key_le key_le; s32 err = 0; + s32 bssidx; memset(&key, 0, sizeof(key)); key.index = (u32) key_idx; @@ -1908,12 +2002,13 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, if (!is_multicast_ether_addr(mac_addr)) memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); key.len = (u32) params->key_len; + bssidx = brcmf_find_bssidx(cfg, ndev); /* check for key index change */ if (key.len == 0) { /* key delete */ - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(cfg, bssidx, ndev, &key); if (err) - return err; + WL_ERR("key delete error (%d)\n", err); } else { if (key.len > sizeof(key.data)) { WL_ERR("Invalid key length (%d)\n", key.len); @@ -1969,12 +2064,12 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, convert_key_from_CPU(&key, &key_le); brcmf_netdev_wait_pend8021x(ndev); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, - sizeof(key_le)); - if (err) { - WL_ERR("WLC_SET_KEY error (%d)\n", err); - return err; - } + err = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le, + sizeof(key_le), + cfg->extra_buf, + WL_EXTRA_BUF_MAX, bssidx); + if (err) + WL_ERR("wsec_key error (%d)\n", err); } return err; } @@ -1984,11 +2079,13 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_wsec_key key; s32 val; s32 wsec; s32 err = 0; u8 keybuf[8]; + s32 bssidx; WL_TRACE("Enter\n"); WL_CONN("key index (%d)\n", key_idx); @@ -2015,25 +2112,33 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: key.algo = CRYPTO_ALGO_WEP1; + val = WEP_ENABLED; WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); break; case WLAN_CIPHER_SUITE_WEP104: key.algo = CRYPTO_ALGO_WEP128; + val = WEP_ENABLED; WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: - memcpy(keybuf, &key.data[24], sizeof(keybuf)); - memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); - memcpy(&key.data[16], keybuf, sizeof(keybuf)); + if (cfg->conf->mode != WL_MODE_AP) { + WL_CONN("Swapping key\n"); + memcpy(keybuf, &key.data[24], sizeof(keybuf)); + memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); + memcpy(&key.data[16], keybuf, sizeof(keybuf)); + } key.algo = CRYPTO_ALGO_TKIP; + val = TKIP_ENABLED; WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); break; case WLAN_CIPHER_SUITE_AES_CMAC: key.algo = CRYPTO_ALGO_AES_CCM; + val = AES_ENABLED; WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); break; case WLAN_CIPHER_SUITE_CCMP: key.algo = CRYPTO_ALGO_AES_CCM; + val = AES_ENABLED; WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); break; default: @@ -2042,28 +2147,23 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, goto done; } - err = send_key_to_dongle(ndev, &key); /* Set the new key/index */ + bssidx = brcmf_find_bssidx(cfg, ndev); + err = send_key_to_dongle(cfg, bssidx, ndev, &key); if (err) goto done; - val = WEP_ENABLED; - err = brcmf_dev_intvar_get(ndev, "wsec", &wsec); + err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); if (err) { WL_ERR("get wsec error (%d)\n", err); goto done; } - wsec &= ~(WEP_ENABLED); wsec |= val; - err = brcmf_dev_intvar_set(ndev, "wsec", wsec); + err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx); if (err) { WL_ERR("set wsec error (%d)\n", err); goto done; } - val = 1; /* assume shared key. otherwise 0 */ - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val); - if (err) - WL_ERR("WLC_SET_AUTH error (%d)\n", err); done: WL_TRACE("Exit\n"); return err; @@ -2073,10 +2173,10 @@ static s32 brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool pairwise, const u8 *mac_addr) { + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_wsec_key key; s32 err = 0; - s32 val; - s32 wsec; + s32 bssidx; WL_TRACE("Enter\n"); if (!check_sys_up(wiphy)) @@ -2091,7 +2191,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, WL_CONN("key index (%d)\n", key_idx); /* Set the new key/index */ - err = send_key_to_dongle(ndev, &key); + bssidx = brcmf_find_bssidx(cfg, ndev); + err = send_key_to_dongle(cfg, bssidx, ndev, &key); if (err) { if (err == -EINVAL) { if (key.index >= DOT11_MAX_DEFAULT_KEYS) @@ -2100,35 +2201,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, } /* Ignore this error, may happen during DISASSOC */ err = -EAGAIN; - goto done; - } - - val = 0; - err = brcmf_dev_intvar_get(ndev, "wsec", &wsec); - if (err) { - WL_ERR("get wsec error (%d)\n", err); - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - goto done; - } - wsec &= ~(WEP_ENABLED); - wsec |= val; - err = brcmf_dev_intvar_set(ndev, "wsec", wsec); - if (err) { - WL_ERR("set wsec error (%d)\n", err); - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - goto done; } - val = 0; /* assume open key. otherwise 1 */ - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val); - if (err) { - WL_ERR("WLC_SET_AUTH error (%d)\n", err); - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - } -done: WL_TRACE("Exit\n"); return err; } @@ -2139,10 +2213,12 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, void (*callback) (void *cookie, struct key_params * params)) { struct key_params params; - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_cfg80211_security *sec; s32 wsec; s32 err = 0; + s32 bssidx; WL_TRACE("Enter\n"); WL_CONN("key index (%d)\n", key_idx); @@ -2151,16 +2227,17 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, memset(¶ms, 0, sizeof(params)); - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec); + bssidx = brcmf_find_bssidx(cfg, ndev); + err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx); if (err) { WL_ERR("WLC_GET_WSEC error (%d)\n", err); /* Ignore this error, may happen during DISASSOC */ err = -EAGAIN; goto done; } - switch (wsec) { + switch (wsec & ~SES_OW_ENABLED) { case WEP_ENABLED: - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec = &profile->sec; if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { params.cipher = WLAN_CIPHER_SUITE_WEP40; WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); @@ -2200,53 +2277,73 @@ brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, - u8 *mac, struct station_info *sinfo) + u8 *mac, struct station_info *sinfo) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_scb_val_le scb_val; int rssi; s32 rate; s32 err = 0; - u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID); + u8 *bssid = profile->bssid; + struct brcmf_sta_info_le *sta_info_le; - WL_TRACE("Enter\n"); + WL_TRACE("Enter, MAC %pM\n", mac); if (!check_sys_up(wiphy)) return -EIO; - if (memcmp(mac, bssid, ETH_ALEN)) { - WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X" - "wl_bssid-%X:%X:%X:%X:%X:%X\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - bssid[0], bssid[1], bssid[2], bssid[3], - bssid[4], bssid[5]); - err = -ENOENT; - goto done; - } - - /* Report the current tx rate */ - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate); - if (err) { - WL_ERR("Could not get rate (%d)\n", err); - } else { - sinfo->filled |= STATION_INFO_TX_BITRATE; - sinfo->txrate.legacy = rate * 5; - WL_CONN("Rate %d Mbps\n", rate / 2); - } + if (cfg->conf->mode == WL_MODE_AP) { + err = brcmf_dev_iovar_getbuf(ndev, "sta_info", mac, ETH_ALEN, + cfg->dcmd_buf, + WL_DCMD_LEN_MAX); + if (err < 0) { + WL_ERR("GET STA INFO failed, %d\n", err); + goto done; + } + sta_info_le = (struct brcmf_sta_info_le *)cfg->dcmd_buf; - if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) { - memset(&scb_val, 0, sizeof(scb_val)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, - sizeof(struct brcmf_scb_val_le)); + sinfo->filled = STATION_INFO_INACTIVE_TIME; + sinfo->inactive_time = le32_to_cpu(sta_info_le->idle) * 1000; + if (le32_to_cpu(sta_info_le->flags) & BRCMF_STA_ASSOC) { + sinfo->filled |= STATION_INFO_CONNECTED_TIME; + sinfo->connected_time = le32_to_cpu(sta_info_le->in); + } + WL_TRACE("STA idle time : %d ms, connected time :%d sec\n", + sinfo->inactive_time, sinfo->connected_time); + } else if (cfg->conf->mode == WL_MODE_BSS) { + if (memcmp(mac, bssid, ETH_ALEN)) { + WL_ERR("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", + mac, bssid); + err = -ENOENT; + goto done; + } + /* Report the current tx rate */ + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate); if (err) { - WL_ERR("Could not get rssi (%d)\n", err); + WL_ERR("Could not get rate (%d)\n", err); + goto done; } else { - rssi = le32_to_cpu(scb_val.val); - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = rssi; - WL_CONN("RSSI %d dBm\n", rssi); + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rate * 5; + WL_CONN("Rate %d Mbps\n", rate / 2); } - } + if (test_bit(WL_STATUS_CONNECTED, &cfg->status)) { + memset(&scb_val, 0, sizeof(scb_val)); + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, + sizeof(scb_val)); + if (err) { + WL_ERR("Could not get rssi (%d)\n", err); + goto done; + } else { + rssi = le32_to_cpu(scb_val.val); + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi; + WL_CONN("RSSI %d dBm\n", rssi); + } + } + } else + err = -EPERM; done: WL_TRACE("Exit\n"); return err; @@ -2258,7 +2355,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, { s32 pm; s32 err = 0; - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); WL_TRACE("Enter\n"); @@ -2266,14 +2363,13 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, * Powersave enable/disable request is coming from the * cfg80211 even before the interface is up. In that * scenario, driver will be storing the power save - * preference in cfg_priv struct to apply this to + * preference in cfg struct to apply this to * FW later while initializing the dongle */ - cfg_priv->pwr_save = enabled; - if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) { + cfg->pwr_save = enabled; + if (!test_bit(WL_STATUS_READY, &cfg->status)) { - WL_INFO("Device is not ready," - "storing the value in cfg_priv struct\n"); + WL_INFO("Device is not ready, storing the value in cfg_info struct\n"); goto done; } @@ -2351,10 +2447,10 @@ done: return err; } -static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, +static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, struct brcmf_bss_info_le *bi) { - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct wiphy *wiphy = cfg_to_wiphy(cfg); struct ieee80211_channel *notify_channel; struct cfg80211_bss *bss; struct ieee80211_supported_band *band; @@ -2418,14 +2514,14 @@ next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss) le32_to_cpu(bss->length)); } -static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg) { struct brcmf_scan_results *bss_list; struct brcmf_bss_info_le *bi = NULL; /* must be initialized */ s32 err = 0; int i; - bss_list = cfg_priv->bss_list; + bss_list = cfg->bss_list; if (bss_list->version != BRCMF_BSS_INFO_VERSION) { WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", bss_list->version); @@ -2434,17 +2530,17 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv) WL_SCAN("scanned AP count (%d)\n", bss_list->count); for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) { bi = next_bss_le(bss_list, bi); - err = brcmf_inform_single_bss(cfg_priv, bi); + err = brcmf_inform_single_bss(cfg, bi); if (err) break; } return err; } -static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, +static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const u8 *bssid) { - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct wiphy *wiphy = cfg_to_wiphy(cfg); struct ieee80211_channel *notify_channel; struct brcmf_bss_info_le *bi = NULL; struct ieee80211_supported_band *band; @@ -2519,9 +2615,9 @@ CleanUp: return err; } -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv) +static bool brcmf_is_ibssmode(struct brcmf_cfg80211_info *cfg) { - return cfg_priv->conf->mode == WL_MODE_IBSS; + return cfg->conf->mode == WL_MODE_IBSS; } /* @@ -2538,22 +2634,62 @@ static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) totlen = buflen; /* find tagged parameter */ - while (totlen >= 2) { + while (totlen >= TLV_HDR_LEN) { int len = elt->len; /* validate remaining totlen */ - if ((elt->id == key) && (totlen >= (len + 2))) + if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) return elt; - elt = (struct brcmf_tlv *) ((u8 *) elt + (len + 2)); - totlen -= (len + 2); + elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN)); + totlen -= (len + TLV_HDR_LEN); + } + + return NULL; +} + +/* Is any of the tlvs the expected entry? If + * not update the tlvs buffer pointer/length. + */ +static bool +brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, + u8 *oui, u32 oui_len, u8 type) +{ + /* If the contents match the OUI and the type */ + if (ie[TLV_LEN_OFF] >= oui_len + 1 && + !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && + type == ie[TLV_BODY_OFF + oui_len]) { + return true; } + if (tlvs == NULL) + return false; + /* point to the next ie */ + ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; + /* calculate the length of the rest of the buffer */ + *tlvs_len -= (int)(ie - *tlvs); + /* update the pointer to the start of the buffer */ + *tlvs = ie; + + return false; +} + +struct brcmf_vs_tlv * +brcmf_find_wpaie(u8 *parse, u32 len) +{ + struct brcmf_tlv *ie; + + while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_WPA))) { + if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, + WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) + return (struct brcmf_vs_tlv *)ie; + } return NULL; } -static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg) { + struct brcmf_cfg80211_profile *profile = cfg->profile; struct brcmf_bss_info_le *bi; struct brcmf_ssid *ssid; struct brcmf_tlv *tim; @@ -2564,21 +2700,21 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) s32 err = 0; WL_TRACE("Enter\n"); - if (brcmf_is_ibssmode(cfg_priv)) + if (brcmf_is_ibssmode(cfg)) return err; - ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID); + ssid = &profile->ssid; - *(__le32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); - err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO, - cfg_priv->extra_buf, WL_EXTRA_BUF_MAX); + *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); + err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_GET_BSS_INFO, + cfg->extra_buf, WL_EXTRA_BUF_MAX); if (err) { WL_ERR("Could not get bss info %d\n", err); goto update_bss_info_out; } - bi = (struct brcmf_bss_info_le *)(cfg_priv->extra_buf + 4); - err = brcmf_inform_single_bss(cfg_priv, bi); + bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4); + err = brcmf_inform_single_bss(cfg, bi); if (err) goto update_bss_info_out; @@ -2596,7 +2732,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) * so we speficially query dtim information to dongle. */ u32 var; - err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv), + err = brcmf_dev_intvar_get(cfg_to_ndev(cfg), "dtim_assoc", &var); if (err) { WL_ERR("wl dtim_assoc failed (%d)\n", err); @@ -2605,22 +2741,22 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) dtim_period = (u8)var; } - brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT); - brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD); + profile->beacon_interval = beacon_interval; + profile->dtim_period = dtim_period; update_bss_info_out: WL_TRACE("Exit"); return err; } -static void brcmf_abort_scanning(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - struct escan_info *escan = &cfg_priv->escan_info; + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); + struct escan_info *escan = &cfg->escan_info; struct brcmf_ssid ssid; - set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); - if (cfg_priv->iscan_on) { + set_bit(WL_STATUS_SCAN_ABORTING, &cfg->status); + if (cfg->iscan_on) { iscan->state = WL_ISCAN_STATE_IDLE; if (iscan->timer_on) { @@ -2634,39 +2770,39 @@ static void brcmf_abort_scanning(struct brcmf_cfg80211_priv *cfg_priv) memset(&ssid, 0, sizeof(ssid)); brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); - if (cfg_priv->scan_request) { + if (cfg->scan_request) { /* Indidate scan abort to cfg80211 layer */ WL_INFO("Terminating scan in progress\n"); - cfg80211_scan_done(cfg_priv->scan_request, true); - cfg_priv->scan_request = NULL; + cfg80211_scan_done(cfg->scan_request, true); + cfg->scan_request = NULL; } } - if (cfg_priv->escan_on && cfg_priv->scan_request) { + if (cfg->escan_on && cfg->scan_request) { escan->escan_state = WL_ESCAN_STATE_IDLE; - brcmf_notify_escan_complete(cfg_priv, escan->ndev, true, true); + brcmf_notify_escan_complete(cfg, escan->ndev, true, true); } - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); - clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); + clear_bit(WL_STATUS_SCANNING, &cfg->status); + clear_bit(WL_STATUS_SCAN_ABORTING, &cfg->status); } static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, bool aborted) { - struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); - struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan); + struct net_device *ndev = cfg_to_ndev(cfg); - if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { WL_ERR("Scan complete while device not scanning\n"); return; } - if (cfg_priv->scan_request) { + if (cfg->scan_request) { WL_SCAN("ISCAN Completed scan: %s\n", aborted ? "Aborted" : "Done"); - cfg80211_scan_done(cfg_priv->scan_request, aborted); + cfg80211_scan_done(cfg->scan_request, aborted); brcmf_set_mpc(ndev, 1); - cfg_priv->scan_request = NULL; + cfg->scan_request = NULL; } - cfg_priv->iscan_kickstart = false; + cfg->iscan_kickstart = false; } static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) @@ -2719,21 +2855,21 @@ brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, return err; } -static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_iscan_done(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; s32 err = 0; iscan->state = WL_ISCAN_STATE_IDLE; - brcmf_inform_bss(cfg_priv); + brcmf_inform_bss(cfg); brcmf_notify_iscan_complete(iscan, false); return err; } -static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_iscan_pending(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; s32 err = 0; /* Reschedule the timer */ @@ -2743,12 +2879,12 @@ static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv) return err; } -static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; s32 err = 0; - brcmf_inform_bss(cfg_priv); + brcmf_inform_bss(cfg); brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); /* Reschedule the timer */ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); @@ -2757,9 +2893,9 @@ static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv) return err; } -static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; s32 err = 0; iscan->state = WL_ISCAN_STATE_IDLE; @@ -2773,7 +2909,7 @@ static void brcmf_cfg80211_iscan_handler(struct work_struct *work) struct brcmf_cfg80211_iscan_ctrl *iscan = container_of(work, struct brcmf_cfg80211_iscan_ctrl, work); - struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); + struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan); struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; u32 status = BRCMF_SCAN_RESULTS_PARTIAL; @@ -2782,12 +2918,12 @@ static void brcmf_cfg80211_iscan_handler(struct work_struct *work) iscan->timer_on = 0; } - if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) { + if (brcmf_get_iscan_results(iscan, &status, &cfg->bss_list)) { status = BRCMF_SCAN_RESULTS_ABORTED; WL_ERR("Abort iscan\n"); } - el->handler[status](cfg_priv); + el->handler[status](cfg); } static void brcmf_iscan_timer(unsigned long data) @@ -2802,11 +2938,11 @@ static void brcmf_iscan_timer(unsigned long data) } } -static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); - if (cfg_priv->iscan_on) { + if (cfg->iscan_on) { iscan->state = WL_ISCAN_STATE_IDLE; INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler); } @@ -2824,21 +2960,21 @@ static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; } -static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_init_iscan(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); int err = 0; - if (cfg_priv->iscan_on) { - iscan->ndev = cfg_to_ndev(cfg_priv); + if (cfg->iscan_on) { + iscan->ndev = cfg_to_ndev(cfg); brcmf_init_iscan_eloop(&iscan->el); iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; init_timer(&iscan->timer); iscan->timer.data = (unsigned long) iscan; iscan->timer.function = brcmf_iscan_timer; - err = brcmf_invoke_iscan(cfg_priv); + err = brcmf_invoke_iscan(cfg); if (!err) - iscan->data = cfg_priv; + iscan->data = cfg; } return err; @@ -2846,23 +2982,23 @@ static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv) static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) { - struct brcmf_cfg80211_priv *cfg_priv = - container_of(work, struct brcmf_cfg80211_priv, + struct brcmf_cfg80211_info *cfg = + container_of(work, struct brcmf_cfg80211_info, escan_timeout_work); - brcmf_notify_escan_complete(cfg_priv, - cfg_priv->escan_info.ndev, true, true); + brcmf_notify_escan_complete(cfg, + cfg->escan_info.ndev, true, true); } static void brcmf_escan_timeout(unsigned long data) { - struct brcmf_cfg80211_priv *cfg_priv = - (struct brcmf_cfg80211_priv *)data; + struct brcmf_cfg80211_info *cfg = + (struct brcmf_cfg80211_info *)data; - if (cfg_priv->scan_request) { + if (cfg->scan_request) { WL_ERR("timer expired\n"); - if (cfg_priv->escan_on) - schedule_work(&cfg_priv->escan_timeout_work); + if (cfg->escan_on) + schedule_work(&cfg->escan_timeout_work); } } @@ -2899,7 +3035,7 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss, } static s32 -brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { @@ -2915,11 +3051,11 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, status = be32_to_cpu(e->status); - if (!ndev || !cfg_priv->escan_on || - !test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + if (!ndev || !cfg->escan_on || + !test_bit(WL_STATUS_SCANNING, &cfg->status)) { WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n", - ndev, cfg_priv->escan_on, - !test_bit(WL_STATUS_SCANNING, &cfg_priv->status)); + ndev, cfg->escan_on, + !test_bit(WL_STATUS_SCANNING, &cfg->status)); return -EPERM; } @@ -2930,7 +3066,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, WL_ERR("Invalid escan result (NULL pointer)\n"); goto exit; } - if (!cfg_priv->scan_request) { + if (!cfg->scan_request) { WL_SCAN("result without cfg80211 request\n"); goto exit; } @@ -2950,7 +3086,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, goto exit; } - if (!(cfg_to_wiphy(cfg_priv)->interface_modes & + if (!(cfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { if (le16_to_cpu(bss_info_le->capability) & WLAN_CAPABILITY_IBSS) { @@ -2960,7 +3096,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, } list = (struct brcmf_scan_results *) - cfg_priv->escan_info.escan_buf; + cfg->escan_info.escan_buf; if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) { WL_ERR("Buffer is too small: ignoring\n"); goto exit; @@ -2973,19 +3109,19 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, if (brcmf_compare_update_same_bss(bss, bss_info_le)) goto exit; } - memcpy(&(cfg_priv->escan_info.escan_buf[list->buflen]), + memcpy(&(cfg->escan_info.escan_buf[list->buflen]), bss_info_le, bi_length); list->version = le32_to_cpu(bss_info_le->version); list->buflen += bi_length; list->count++; } else { - cfg_priv->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (cfg_priv->scan_request) { - cfg_priv->bss_list = (struct brcmf_scan_results *) - cfg_priv->escan_info.escan_buf; - brcmf_inform_bss(cfg_priv); + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + if (cfg->scan_request) { + cfg->bss_list = (struct brcmf_scan_results *) + cfg->escan_info.escan_buf; + brcmf_inform_bss(cfg); aborted = status != BRCMF_E_STATUS_SUCCESS; - brcmf_notify_escan_complete(cfg_priv, ndev, aborted, + brcmf_notify_escan_complete(cfg, ndev, aborted, false); } else WL_ERR("Unexpected scan result 0x%x\n", status); @@ -2994,18 +3130,18 @@ exit: return err; } -static void brcmf_init_escan(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) { - if (cfg_priv->escan_on) { - cfg_priv->el.handler[BRCMF_E_ESCAN_RESULT] = + if (cfg->escan_on) { + cfg->el.handler[BRCMF_E_ESCAN_RESULT] = brcmf_cfg80211_escan_handler; - cfg_priv->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; /* Init scan_timeout timer */ - init_timer(&cfg_priv->escan_timeout); - cfg_priv->escan_timeout.data = (unsigned long) cfg_priv; - cfg_priv->escan_timeout.function = brcmf_escan_timeout; - INIT_WORK(&cfg_priv->escan_timeout_work, + init_timer(&cfg->escan_timeout); + cfg->escan_timeout.data = (unsigned long) cfg; + cfg->escan_timeout.function = brcmf_escan_timeout; + INIT_WORK(&cfg->escan_timeout_work, brcmf_cfg80211_escan_timeout_worker); } } @@ -3022,7 +3158,7 @@ static __always_inline void brcmf_delay(u32 ms) static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); /* * Check for WL_STATUS_READY before any function call which @@ -3031,7 +3167,7 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) */ WL_TRACE("Enter\n"); - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) + if (test_bit(WL_STATUS_READY, &cfg->status)) brcmf_invoke_iscan(wiphy_to_cfg(wiphy)); WL_TRACE("Exit\n"); @@ -3041,8 +3177,8 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg); WL_TRACE("Enter\n"); @@ -3056,12 +3192,12 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, * While going to suspend if associated with AP disassociate * from AP to save power while system is in suspended state */ - if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || - test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && - test_bit(WL_STATUS_READY, &cfg_priv->status)) { + if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) || + test_bit(WL_STATUS_CONNECTING, &cfg->status)) && + test_bit(WL_STATUS_READY, &cfg->status)) { WL_INFO("Disassociating from AP" " while entering suspend state\n"); - brcmf_link_down(cfg_priv); + brcmf_link_down(cfg); /* * Make sure WPA_Supplicant receives all the event @@ -3071,13 +3207,13 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, brcmf_delay(500); } - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) - brcmf_abort_scanning(cfg_priv); + if (test_bit(WL_STATUS_READY, &cfg->status)) + brcmf_abort_scanning(cfg); else - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); + clear_bit(WL_STATUS_SCANNING, &cfg->status); /* Turn off watchdog timer */ - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) + if (test_bit(WL_STATUS_READY, &cfg->status)) brcmf_set_mpc(ndev, 1); WL_TRACE("Exit\n"); @@ -3088,14 +3224,14 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, static __used s32 brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); u32 buflen; - buflen = brcmf_c_mkiovar(name, buf, len, cfg_priv->dcmd_buf, + buflen = brcmf_c_mkiovar(name, buf, len, cfg->dcmd_buf, WL_DCMD_LEN_MAX); BUG_ON(!buflen); - return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg_priv->dcmd_buf, + return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg->dcmd_buf, buflen); } @@ -3103,20 +3239,20 @@ static s32 brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf, s32 buf_len) { - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); u32 len; s32 err = 0; - len = brcmf_c_mkiovar(name, NULL, 0, cfg_priv->dcmd_buf, + len = brcmf_c_mkiovar(name, NULL, 0, cfg->dcmd_buf, WL_DCMD_LEN_MAX); BUG_ON(!len); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg_priv->dcmd_buf, + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg->dcmd_buf, WL_DCMD_LEN_MAX); if (err) { WL_ERR("error (%d)\n", err); return err; } - memcpy(buf, cfg_priv->dcmd_buf, buf_len); + memcpy(buf, cfg->dcmd_buf, buf_len); return err; } @@ -3149,8 +3285,8 @@ static s32 brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids; + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct pmkid_list *pmkids = &cfg->pmk_list->pmkids; s32 err = 0; int i; int pmkid_len; @@ -3178,7 +3314,7 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, for (i = 0; i < WLAN_PMKID_LEN; i++) WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]); - err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); + err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); WL_TRACE("Exit\n"); return err; @@ -3188,7 +3324,7 @@ static s32 brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct pmkid_list pmkid; s32 err = 0; int i, pmkid_len; @@ -3205,30 +3341,30 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, for (i = 0; i < WLAN_PMKID_LEN; i++) WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]); - pmkid_len = le32_to_cpu(cfg_priv->pmk_list->pmkids.npmkid); + pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid); for (i = 0; i < pmkid_len; i++) if (!memcmp - (pmksa->bssid, &cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, + (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, ETH_ALEN)) break; if ((pmkid_len > 0) && (i < pmkid_len)) { - memset(&cfg_priv->pmk_list->pmkids.pmkid[i], 0, + memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(struct pmkid)); for (; i < (pmkid_len - 1); i++) { - memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, - &cfg_priv->pmk_list->pmkids.pmkid[i + 1].BSSID, + memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, + &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID, ETH_ALEN); - memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].PMKID, - &cfg_priv->pmk_list->pmkids.pmkid[i + 1].PMKID, + memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, + &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID, WLAN_PMKID_LEN); } - cfg_priv->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1); + cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1); } else err = -EINVAL; - err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); + err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); WL_TRACE("Exit\n"); return err; @@ -3238,15 +3374,15 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, static s32 brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); s32 err = 0; WL_TRACE("Enter\n"); if (!check_sys_up(wiphy)) return -EIO; - memset(cfg_priv->pmk_list, 0, sizeof(*cfg_priv->pmk_list)); - err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); + memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list)); + err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); WL_TRACE("Exit\n"); return err; @@ -3262,7 +3398,7 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) * cfg80211_scan_request one out of the received PNO event. */ static s32 -brcmf_notify_sched_scan_results(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { @@ -3270,7 +3406,7 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_priv *cfg_priv, struct cfg80211_scan_request *request = NULL; struct cfg80211_ssid *ssid = NULL; struct ieee80211_channel *channel = NULL; - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct wiphy *wiphy = cfg_to_wiphy(cfg); int err = 0; int channel_req = 0; int band = 0; @@ -3299,8 +3435,8 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_priv *cfg_priv, int i; request = kzalloc(sizeof(*request), GFP_KERNEL); - ssid = kzalloc(sizeof(*ssid) * result_count, GFP_KERNEL); - channel = kzalloc(sizeof(*channel) * result_count, GFP_KERNEL); + ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL); + channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL); if (!request || !ssid || !channel) { err = -ENOMEM; goto out_err; @@ -3342,19 +3478,19 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_priv *cfg_priv, if (request->n_ssids) request->ssids = &ssid[0]; - if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { /* Abort any on-going scan */ - brcmf_abort_scanning(cfg_priv); + brcmf_abort_scanning(cfg); } - set_bit(WL_STATUS_SCANNING, &cfg_priv->status); - err = brcmf_do_escan(cfg_priv, wiphy, ndev, request); + set_bit(WL_STATUS_SCANNING, &cfg->status); + err = brcmf_do_escan(cfg, wiphy, ndev, request); if (err) { - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); + clear_bit(WL_STATUS_SCANNING, &cfg->status); goto out_err; } - cfg_priv->sched_escan = true; - cfg_priv->scan_request = request; + cfg->sched_escan = true; + cfg->scan_request = request; } else { WL_ERR("FALSE PNO Event. (pfn_count == 0)\n"); goto out_err; @@ -3419,15 +3555,15 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, struct cfg80211_sched_scan_request *request) { char iovbuf[128]; - struct brcmf_cfg80211_priv *cfg_priv = wiphy_priv(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct brcmf_pno_net_param_le pfn; int i; int ret = 0; WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n", request->n_match_sets, request->n_ssids); - if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { - WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); + if (test_bit(WL_STATUS_SCANNING, &cfg->status)) { + WL_ERR("Scanning already : status (%lu)\n", cfg->status); return -EAGAIN; } @@ -3506,12 +3642,12 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *ndev) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); WL_SCAN("enter\n"); brcmf_dev_pno_clean(ndev); - if (cfg_priv->sched_escan) - brcmf_notify_escan_complete(cfg_priv, ndev, true, true); + if (cfg->sched_escan) + brcmf_notify_escan_complete(cfg, ndev, true, true); return 0; } #endif /* CONFIG_BRCMISCAN */ @@ -3519,8 +3655,8 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, #ifdef CONFIG_NL80211_TESTMODE static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) { - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_priv->wdev->netdev; + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg->wdev->netdev; struct brcmf_dcmd *dcmd = data; struct sk_buff *reply; int ret; @@ -3535,6 +3671,682 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) } #endif +static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx) +{ + s32 err; + + /* set auth */ + err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", 0, bssidx); + if (err < 0) { + WL_ERR("auth error %d\n", err); + return err; + } + /* set wsec */ + err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", 0, bssidx); + if (err < 0) { + WL_ERR("wsec error %d\n", err); + return err; + } + /* set upper-layer auth */ + err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth", + WPA_AUTH_NONE, bssidx); + if (err < 0) { + WL_ERR("wpa_auth error %d\n", err); + return err; + } + + return 0; +} + +static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie) +{ + if (is_rsn_ie) + return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0); + + return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0); +} + +static s32 +brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, + bool is_rsn_ie, s32 bssidx) +{ + u32 auth = 0; /* d11 open authentication */ + u16 count; + s32 err = 0; + s32 len = 0; + u32 i; + u32 wsec; + u32 pval = 0; + u32 gval = 0; + u32 wpa_auth = 0; + u32 offset; + u8 *data; + u16 rsn_cap; + u32 wme_bss_disable; + + WL_TRACE("Enter\n"); + if (wpa_ie == NULL) + goto exit; + + len = wpa_ie->len + TLV_HDR_LEN; + data = (u8 *)wpa_ie; + offset = 0; + if (!is_rsn_ie) + offset += VS_IE_FIXED_HDR_LEN; + offset += WPA_IE_VERSION_LEN; + + /* check for multicast cipher suite */ + if (offset + WPA_IE_MIN_OUI_LEN > len) { + err = -EINVAL; + WL_ERR("no multicast cipher suite\n"); + goto exit; + } + + if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) { + err = -EINVAL; + WL_ERR("ivalid OUI\n"); + goto exit; + } + offset += TLV_OUI_LEN; + + /* pick up multicast cipher */ + switch (data[offset]) { + case WPA_CIPHER_NONE: + gval = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + gval = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + gval = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + gval = AES_ENABLED; + break; + default: + err = -EINVAL; + WL_ERR("Invalid multi cast cipher info\n"); + goto exit; + } + + offset++; + /* walk thru unicast cipher list and pick up what we recognize */ + count = data[offset] + (data[offset + 1] << 8); + offset += WPA_IE_SUITE_COUNT_LEN; + /* Check for unicast suite(s) */ + if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) { + err = -EINVAL; + WL_ERR("no unicast cipher suite\n"); + goto exit; + } + for (i = 0; i < count; i++) { + if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) { + err = -EINVAL; + WL_ERR("ivalid OUI\n"); + goto exit; + } + offset += TLV_OUI_LEN; + switch (data[offset]) { + case WPA_CIPHER_NONE: + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + pval |= WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + pval |= TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + pval |= AES_ENABLED; + break; + default: + WL_ERR("Ivalid unicast security info\n"); + } + offset++; + } + /* walk thru auth management suite list and pick up what we recognize */ + count = data[offset] + (data[offset + 1] << 8); + offset += WPA_IE_SUITE_COUNT_LEN; + /* Check for auth key management suite(s) */ + if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) { + err = -EINVAL; + WL_ERR("no auth key mgmt suite\n"); + goto exit; + } + for (i = 0; i < count; i++) { + if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) { + err = -EINVAL; + WL_ERR("ivalid OUI\n"); + goto exit; + } + offset += TLV_OUI_LEN; + switch (data[offset]) { + case RSN_AKM_NONE: + WL_TRACE("RSN_AKM_NONE\n"); + wpa_auth |= WPA_AUTH_NONE; + break; + case RSN_AKM_UNSPECIFIED: + WL_TRACE("RSN_AKM_UNSPECIFIED\n"); + is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) : + (wpa_auth |= WPA_AUTH_UNSPECIFIED); + break; + case RSN_AKM_PSK: + WL_TRACE("RSN_AKM_PSK\n"); + is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) : + (wpa_auth |= WPA_AUTH_PSK); + break; + default: + WL_ERR("Ivalid key mgmt info\n"); + } + offset++; + } + + if (is_rsn_ie) { + wme_bss_disable = 1; + if ((offset + RSN_CAP_LEN) <= len) { + rsn_cap = data[offset] + (data[offset + 1] << 8); + if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK) + wme_bss_disable = 0; + } + /* set wme_bss_disable to sync RSN Capabilities */ + err = brcmf_dev_intvar_set_bsscfg(ndev, "wme_bss_disable", + wme_bss_disable, bssidx); + if (err < 0) { + WL_ERR("wme_bss_disable error %d\n", err); + goto exit; + } + } + /* FOR WPS , set SES_OW_ENABLED */ + wsec = (pval | gval | SES_OW_ENABLED); + + /* set auth */ + err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", auth, bssidx); + if (err < 0) { + WL_ERR("auth error %d\n", err); + goto exit; + } + /* set wsec */ + err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx); + if (err < 0) { + WL_ERR("wsec error %d\n", err); + goto exit; + } + /* set upper-layer auth */ + err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth", wpa_auth, bssidx); + if (err < 0) { + WL_ERR("wpa_auth error %d\n", err); + goto exit; + } + +exit: + return err; +} + +static s32 +brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len, + struct parsed_vndr_ies *vndr_ies) +{ + s32 err = 0; + struct brcmf_vs_tlv *vndrie; + struct brcmf_tlv *ie; + struct parsed_vndr_ie_info *parsed_info; + s32 remaining_len; + + remaining_len = (s32)vndr_ie_len; + memset(vndr_ies, 0, sizeof(*vndr_ies)); + + ie = (struct brcmf_tlv *)vndr_ie_buf; + while (ie) { + if (ie->id != WLAN_EID_VENDOR_SPECIFIC) + goto next; + vndrie = (struct brcmf_vs_tlv *)ie; + /* len should be bigger than OUI length + one */ + if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) { + WL_ERR("invalid vndr ie. length is too small %d\n", + vndrie->len); + goto next; + } + /* if wpa or wme ie, do not add ie */ + if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) && + ((vndrie->oui_type == WPA_OUI_TYPE) || + (vndrie->oui_type == WME_OUI_TYPE))) { + WL_TRACE("Found WPA/WME oui. Do not add it\n"); + goto next; + } + + parsed_info = &vndr_ies->ie_info[vndr_ies->count]; + + /* save vndr ie information */ + parsed_info->ie_ptr = (char *)vndrie; + parsed_info->ie_len = vndrie->len + TLV_HDR_LEN; + memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie)); + + vndr_ies->count++; + + WL_TRACE("** OUI %02x %02x %02x, type 0x%02x\n", + parsed_info->vndrie.oui[0], + parsed_info->vndrie.oui[1], + parsed_info->vndrie.oui[2], + parsed_info->vndrie.oui_type); + + if (vndr_ies->count >= MAX_VNDR_IE_NUMBER) + break; +next: + remaining_len -= ie->len; + if (remaining_len <= 2) + ie = NULL; + else + ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len); + } + return err; +} + +static u32 +brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) +{ + + __le32 iecount_le; + __le32 pktflag_le; + + strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1); + iebuf[VNDR_IE_CMD_LEN - 1] = '\0'; + + iecount_le = cpu_to_le32(1); + memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le)); + + pktflag_le = cpu_to_le32(pktflag); + memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le)); + + memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len); + + return ie_len + VNDR_IE_HDR_SIZE; +} + +s32 +brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, + struct net_device *ndev, s32 bssidx, s32 pktflag, + u8 *vndr_ie_buf, u32 vndr_ie_len) +{ + s32 err = 0; + u8 *iovar_ie_buf; + u8 *curr_ie_buf; + u8 *mgmt_ie_buf = NULL; + u32 mgmt_ie_buf_len = 0; + u32 *mgmt_ie_len = 0; + u32 del_add_ie_buf_len = 0; + u32 total_ie_buf_len = 0; + u32 parsed_ie_buf_len = 0; + struct parsed_vndr_ies old_vndr_ies; + struct parsed_vndr_ies new_vndr_ies; + struct parsed_vndr_ie_info *vndrie_info; + s32 i; + u8 *ptr; + u32 remained_buf_len; + + WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag); + iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!iovar_ie_buf) + return -ENOMEM; + curr_ie_buf = iovar_ie_buf; + if (test_bit(WL_STATUS_AP_CREATING, &cfg->status) || + test_bit(WL_STATUS_AP_CREATED, &cfg->status)) { + switch (pktflag) { + case VNDR_IE_PRBRSP_FLAG: + mgmt_ie_buf = cfg->ap_info->probe_res_ie; + mgmt_ie_len = &cfg->ap_info->probe_res_ie_len; + mgmt_ie_buf_len = + sizeof(cfg->ap_info->probe_res_ie); + break; + case VNDR_IE_BEACON_FLAG: + mgmt_ie_buf = cfg->ap_info->beacon_ie; + mgmt_ie_len = &cfg->ap_info->beacon_ie_len; + mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie); + break; + default: + err = -EPERM; + WL_ERR("not suitable type\n"); + goto exit; + } + bssidx = 0; + } else { + err = -EPERM; + WL_ERR("not suitable type\n"); + goto exit; + } + + if (vndr_ie_len > mgmt_ie_buf_len) { + err = -ENOMEM; + WL_ERR("extra IE size too big\n"); + goto exit; + } + + /* parse and save new vndr_ie in curr_ie_buff before comparing it */ + if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) { + ptr = curr_ie_buf; + brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies); + for (i = 0; i < new_vndr_ies.count; i++) { + vndrie_info = &new_vndr_ies.ie_info[i]; + memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, + vndrie_info->ie_len); + parsed_ie_buf_len += vndrie_info->ie_len; + } + } + + if (mgmt_ie_buf != NULL) { + if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && + (memcmp(mgmt_ie_buf, curr_ie_buf, + parsed_ie_buf_len) == 0)) { + WL_TRACE("Previous mgmt IE is equals to current IE"); + goto exit; + } + + /* parse old vndr_ie */ + brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies); + + /* make a command to delete old ie */ + for (i = 0; i < old_vndr_ies.count; i++) { + vndrie_info = &old_vndr_ies.ie_info[i]; + + WL_TRACE("DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, + vndrie_info->vndrie.len, + vndrie_info->vndrie.oui[0], + vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2]); + + del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag, + vndrie_info->ie_ptr, + vndrie_info->ie_len, + "del"); + curr_ie_buf += del_add_ie_buf_len; + total_ie_buf_len += del_add_ie_buf_len; + } + } + + *mgmt_ie_len = 0; + /* Add if there is any extra IE */ + if (mgmt_ie_buf && parsed_ie_buf_len) { + ptr = mgmt_ie_buf; + + remained_buf_len = mgmt_ie_buf_len; + + /* make a command to add new ie */ + for (i = 0; i < new_vndr_ies.count; i++) { + vndrie_info = &new_vndr_ies.ie_info[i]; + + WL_TRACE("ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n", + vndrie_info->vndrie.id, + vndrie_info->vndrie.len, + vndrie_info->vndrie.oui[0], + vndrie_info->vndrie.oui[1], + vndrie_info->vndrie.oui[2]); + + del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag, + vndrie_info->ie_ptr, + vndrie_info->ie_len, + "add"); + /* verify remained buf size before copy data */ + remained_buf_len -= vndrie_info->ie_len; + if (remained_buf_len < 0) { + WL_ERR("no space in mgmt_ie_buf: len left %d", + remained_buf_len); + break; + } + + /* save the parsed IE in wl struct */ + memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, + vndrie_info->ie_len); + *mgmt_ie_len += vndrie_info->ie_len; + + curr_ie_buf += del_add_ie_buf_len; + total_ie_buf_len += del_add_ie_buf_len; + } + } + if (total_ie_buf_len) { + err = brcmf_dev_iovar_setbuf_bsscfg(ndev, "vndr_ie", + iovar_ie_buf, + total_ie_buf_len, + cfg->extra_buf, + WL_EXTRA_BUF_MAX, bssidx); + if (err) + WL_ERR("vndr ie set error : %d\n", err); + } + +exit: + kfree(iovar_ie_buf); + return err; +} + +static s32 +brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_ap_settings *settings) +{ + s32 ie_offset; + struct brcmf_tlv *ssid_ie; + struct brcmf_ssid_le ssid_le; + s32 ioctl_value; + s32 err = -EPERM; + struct brcmf_tlv *rsn_ie; + struct brcmf_vs_tlv *wpa_ie; + struct brcmf_join_params join_params; + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + s32 bssidx = 0; + + WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", + settings->channel_type, settings->beacon_interval, + settings->dtim_period); + WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n", + settings->ssid, settings->ssid_len, settings->auth_type, + settings->inactivity_timeout); + + if (!test_bit(WL_STATUS_AP_CREATING, &cfg->status)) { + WL_ERR("Not in AP creation mode\n"); + return -EPERM; + } + + memset(&ssid_le, 0, sizeof(ssid_le)); + if (settings->ssid == NULL || settings->ssid_len == 0) { + ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + ssid_ie = brcmf_parse_tlvs( + (u8 *)&settings->beacon.head[ie_offset], + settings->beacon.head_len - ie_offset, + WLAN_EID_SSID); + if (!ssid_ie) + return -EINVAL; + + memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len); + ssid_le.SSID_len = cpu_to_le32(ssid_ie->len); + WL_TRACE("SSID is (%s) in Head\n", ssid_le.SSID); + } else { + memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len); + ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len); + } + + brcmf_set_mpc(ndev, 0); + ioctl_value = 1; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_DOWN, &ioctl_value); + if (err < 0) { + WL_ERR("BRCMF_C_DOWN error %d\n", err); + goto exit; + } + ioctl_value = 1; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &ioctl_value); + if (err < 0) { + WL_ERR("SET INFRA error %d\n", err); + goto exit; + } + ioctl_value = 1; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value); + if (err < 0) { + WL_ERR("setting AP mode failed %d\n", err); + goto exit; + } + + /* find the RSN_IE */ + rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, + settings->beacon.tail_len, WLAN_EID_RSN); + + /* find the WPA_IE */ + wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail, + settings->beacon.tail_len); + + kfree(cfg->ap_info->rsn_ie); + cfg->ap_info->rsn_ie = NULL; + kfree(cfg->ap_info->wpa_ie); + cfg->ap_info->wpa_ie = NULL; + + if ((wpa_ie != NULL || rsn_ie != NULL)) { + WL_TRACE("WPA(2) IE is found\n"); + if (wpa_ie != NULL) { + /* WPA IE */ + err = brcmf_configure_wpaie(ndev, wpa_ie, false, + bssidx); + if (err < 0) + goto exit; + cfg->ap_info->wpa_ie = kmemdup(wpa_ie, + wpa_ie->len + + TLV_HDR_LEN, + GFP_KERNEL); + } else { + /* RSN IE */ + err = brcmf_configure_wpaie(ndev, + (struct brcmf_vs_tlv *)rsn_ie, true, bssidx); + if (err < 0) + goto exit; + cfg->ap_info->rsn_ie = kmemdup(rsn_ie, + rsn_ie->len + + TLV_HDR_LEN, + GFP_KERNEL); + } + cfg->ap_info->security_mode = true; + } else { + WL_TRACE("No WPA(2) IEs found\n"); + brcmf_configure_opensecurity(ndev, bssidx); + cfg->ap_info->security_mode = false; + } + /* Set Beacon IEs to FW */ + err = brcmf_set_management_ie(cfg, ndev, bssidx, + VNDR_IE_BEACON_FLAG, + (u8 *)settings->beacon.tail, + settings->beacon.tail_len); + if (err) + WL_ERR("Set Beacon IE Failed\n"); + else + WL_TRACE("Applied Vndr IEs for Beacon\n"); + + /* Set Probe Response IEs to FW */ + err = brcmf_set_management_ie(cfg, ndev, bssidx, + VNDR_IE_PRBRSP_FLAG, + (u8 *)settings->beacon.proberesp_ies, + settings->beacon.proberesp_ies_len); + if (err) + WL_ERR("Set Probe Resp IE Failed\n"); + else + WL_TRACE("Applied Vndr IEs for Probe Resp\n"); + + if (settings->beacon_interval) { + ioctl_value = settings->beacon_interval; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_BCNPRD, + &ioctl_value); + if (err < 0) { + WL_ERR("Beacon Interval Set Error, %d\n", err); + goto exit; + } + } + if (settings->dtim_period) { + ioctl_value = settings->dtim_period; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_DTIMPRD, + &ioctl_value); + if (err < 0) { + WL_ERR("DTIM Interval Set Error, %d\n", err); + goto exit; + } + } + ioctl_value = 1; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value); + if (err < 0) { + WL_ERR("BRCMF_C_UP error (%d)\n", err); + goto exit; + } + + memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ + memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); + /* create softap */ + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, &join_params, + sizeof(join_params)); + if (err < 0) { + WL_ERR("SET SSID error (%d)\n", err); + goto exit; + } + clear_bit(WL_STATUS_AP_CREATING, &cfg->status); + set_bit(WL_STATUS_AP_CREATED, &cfg->status); + +exit: + if (err) + brcmf_set_mpc(ndev, 1); + return err; +} + +static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + s32 ioctl_value; + s32 err = -EPERM; + + WL_TRACE("Enter\n"); + + if (cfg->conf->mode == WL_MODE_AP) { + /* Due to most likely deauths outstanding we sleep */ + /* first to make sure they get processed by fw. */ + msleep(400); + ioctl_value = 0; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value); + if (err < 0) { + WL_ERR("setting AP mode failed %d\n", err); + goto exit; + } + ioctl_value = 0; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value); + if (err < 0) { + WL_ERR("BRCMF_C_UP error %d\n", err); + goto exit; + } + brcmf_set_mpc(ndev, 1); + clear_bit(WL_STATUS_AP_CREATING, &cfg->status); + clear_bit(WL_STATUS_AP_CREATED, &cfg->status); + } +exit: + return err; +} + +static int +brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, + u8 *mac) +{ + struct brcmf_scb_val_le scbval; + s32 err; + + if (!mac) + return -EFAULT; + + WL_TRACE("Enter %pM\n", mac); + + if (!check_sys_up(wiphy)) + return -EIO; + + memcpy(&scbval.ea, mac, ETH_ALEN); + scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON, + &scbval, sizeof(scbval)); + if (err) + WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err); + + WL_TRACE("Exit\n"); + return err; +} + static struct cfg80211_ops wl_cfg80211_ops = { .change_virtual_intf = brcmf_cfg80211_change_iface, .scan = brcmf_cfg80211_scan, @@ -3558,6 +4370,9 @@ static struct cfg80211_ops wl_cfg80211_ops = { .set_pmksa = brcmf_cfg80211_set_pmksa, .del_pmksa = brcmf_cfg80211_del_pmksa, .flush_pmksa = brcmf_cfg80211_flush_pmksa, + .start_ap = brcmf_cfg80211_start_ap, + .stop_ap = brcmf_cfg80211_stop_ap, + .del_station = brcmf_cfg80211_del_station, #ifndef CONFIG_BRCMISCAN /* scheduled scan need e-scan, which is mutual exclusive with i-scan */ .sched_scan_start = brcmf_cfg80211_sched_scan_start, @@ -3595,8 +4410,7 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) #endif } -static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, - struct device *ndev) +static struct wireless_dev *brcmf_alloc_wdev(struct device *ndev) { struct wireless_dev *wdev; s32 err = 0; @@ -3605,9 +4419,8 @@ static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, if (!wdev) return ERR_PTR(-ENOMEM); - wdev->wiphy = - wiphy_new(&wl_cfg80211_ops, - sizeof(struct brcmf_cfg80211_priv) + sizeof_iface); + wdev->wiphy = wiphy_new(&wl_cfg80211_ops, + sizeof(struct brcmf_cfg80211_info)); if (!wdev->wiphy) { WL_ERR("Could not allocate wiphy device\n"); err = -ENOMEM; @@ -3616,8 +4429,9 @@ static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, set_wiphy_dev(wdev->wiphy, ndev); wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; - wdev->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set * it as 11a by default. @@ -3650,9 +4464,9 @@ wiphy_new_out: return ERR_PTR(err); } -static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_free_wdev(struct brcmf_cfg80211_info *cfg) { - struct wireless_dev *wdev = cfg_priv->wdev; + struct wireless_dev *wdev = cfg->wdev; if (!wdev) { WL_ERR("wdev is invalid\n"); @@ -3661,10 +4475,10 @@ static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv) wiphy_unregister(wdev->wiphy); wiphy_free(wdev->wiphy); kfree(wdev); - cfg_priv->wdev = NULL; + cfg->wdev = NULL; } -static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, +static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e) { u32 event = be32_to_cpu(e->event_type); @@ -3672,14 +4486,14 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { WL_CONN("Processing set ssid\n"); - cfg_priv->link_up = true; + cfg->link_up = true; return true; } return false; } -static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, +static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e) { u32 event = be32_to_cpu(e->event_type); @@ -3692,7 +4506,7 @@ static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, return false; } -static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, +static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e) { u32 event = be32_to_cpu(e->event_type); @@ -3713,9 +4527,9 @@ static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, return false; } -static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); kfree(conn_info->req_ie); conn_info->req_ie = NULL; @@ -3725,30 +4539,30 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) conn_info->resp_ie_len = 0; } -static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) { - struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct net_device *ndev = cfg_to_ndev(cfg); struct brcmf_cfg80211_assoc_ielen_le *assoc_info; - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); u32 req_len; u32 resp_len; s32 err = 0; - brcmf_clear_assoc_ies(cfg_priv); + brcmf_clear_assoc_ies(cfg); - err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg_priv->extra_buf, + err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg->extra_buf, WL_ASSOC_INFO_MAX); if (err) { WL_ERR("could not get assoc info (%d)\n", err); return err; } assoc_info = - (struct brcmf_cfg80211_assoc_ielen_le *)cfg_priv->extra_buf; + (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf; req_len = le32_to_cpu(assoc_info->req_len); resp_len = le32_to_cpu(assoc_info->resp_len); if (req_len) { err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies", - cfg_priv->extra_buf, + cfg->extra_buf, WL_ASSOC_INFO_MAX); if (err) { WL_ERR("could not get assoc req (%d)\n", err); @@ -3756,7 +4570,7 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) } conn_info->req_ie_len = req_len; conn_info->req_ie = - kmemdup(cfg_priv->extra_buf, conn_info->req_ie_len, + kmemdup(cfg->extra_buf, conn_info->req_ie_len, GFP_KERNEL); } else { conn_info->req_ie_len = 0; @@ -3764,7 +4578,7 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) } if (resp_len) { err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies", - cfg_priv->extra_buf, + cfg->extra_buf, WL_ASSOC_INFO_MAX); if (err) { WL_ERR("could not get assoc resp (%d)\n", err); @@ -3772,7 +4586,7 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) } conn_info->resp_ie_len = resp_len; conn_info->resp_ie = - kmemdup(cfg_priv->extra_buf, conn_info->resp_ie_len, + kmemdup(cfg->extra_buf, conn_info->resp_ie_len, GFP_KERNEL); } else { conn_info->resp_ie_len = 0; @@ -3785,12 +4599,13 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) } static s32 -brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e) { - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + struct wiphy *wiphy = cfg_to_wiphy(cfg); struct brcmf_channel_info_le channel_le; struct ieee80211_channel *notify_channel; struct ieee80211_supported_band *band; @@ -3800,9 +4615,9 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, WL_TRACE("Enter\n"); - brcmf_get_assoc_ies(cfg_priv); - brcmf_update_prof(cfg_priv, NULL, &e->addr, WL_PROF_BSSID); - brcmf_update_bss_info(cfg_priv); + brcmf_get_assoc_ies(cfg); + memcpy(profile->bssid, e->addr, ETH_ALEN); + brcmf_update_bss_info(cfg); brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le, sizeof(channel_le)); @@ -3818,37 +4633,35 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, freq = ieee80211_channel_to_frequency(target_channel, band->band); notify_channel = ieee80211_get_channel(wiphy, freq); - cfg80211_roamed(ndev, notify_channel, - (u8 *)brcmf_read_prof(cfg_priv, WL_PROF_BSSID), + cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid, conn_info->req_ie, conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); WL_CONN("Report roaming result\n"); - set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + set_bit(WL_STATUS_CONNECTED, &cfg->status); WL_TRACE("Exit\n"); return err; } static s32 -brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, bool completed) { - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); + struct brcmf_cfg80211_profile *profile = cfg->profile; + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); s32 err = 0; WL_TRACE("Enter\n"); - if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { + if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg->status)) { if (completed) { - brcmf_get_assoc_ies(cfg_priv); - brcmf_update_prof(cfg_priv, NULL, &e->addr, - WL_PROF_BSSID); - brcmf_update_bss_info(cfg_priv); + brcmf_get_assoc_ies(cfg); + memcpy(profile->bssid, e->addr, ETH_ALEN); + brcmf_update_bss_info(cfg); } cfg80211_connect_result(ndev, - (u8 *)brcmf_read_prof(cfg_priv, - WL_PROF_BSSID), + (u8 *)profile->bssid, conn_info->req_ie, conn_info->req_ie_len, conn_info->resp_ie, @@ -3857,7 +4670,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); if (completed) - set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + set_bit(WL_STATUS_CONNECTED, &cfg->status); WL_CONN("Report connect result - connection %s\n", completed ? "succeeded" : "failed"); } @@ -3866,52 +4679,93 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, } static s32 -brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, + struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + s32 err = 0; + u32 event = be32_to_cpu(e->event_type); + u32 reason = be32_to_cpu(e->reason); + u32 len = be32_to_cpu(e->datalen); + static int generation; + + struct station_info sinfo; + + WL_CONN("event %d, reason %d\n", event, reason); + memset(&sinfo, 0, sizeof(sinfo)); + + sinfo.filled = 0; + if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && + reason == BRCMF_E_STATUS_SUCCESS) { + sinfo.filled = STATION_INFO_ASSOC_REQ_IES; + if (!data) { + WL_ERR("No IEs present in ASSOC/REASSOC_IND"); + return -EINVAL; + } + sinfo.assoc_req_ies = data; + sinfo.assoc_req_ies_len = len; + generation++; + sinfo.generation = generation; + cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC); + } else if ((event == BRCMF_E_DISASSOC_IND) || + (event == BRCMF_E_DEAUTH_IND) || + (event == BRCMF_E_DEAUTH)) { + generation++; + sinfo.generation = generation; + cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC); + } + return err; +} + +static s32 +brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { + struct brcmf_cfg80211_profile *profile = cfg->profile; s32 err = 0; - if (brcmf_is_linkup(cfg_priv, e)) { + if (cfg->conf->mode == WL_MODE_AP) { + err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); + } else if (brcmf_is_linkup(cfg, e)) { WL_CONN("Linkup\n"); - if (brcmf_is_ibssmode(cfg_priv)) { - brcmf_update_prof(cfg_priv, NULL, (void *)e->addr, - WL_PROF_BSSID); - wl_inform_ibss(cfg_priv, ndev, e->addr); + if (brcmf_is_ibssmode(cfg)) { + memcpy(profile->bssid, e->addr, ETH_ALEN); + wl_inform_ibss(cfg, ndev, e->addr); cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + clear_bit(WL_STATUS_CONNECTING, &cfg->status); + set_bit(WL_STATUS_CONNECTED, &cfg->status); } else - brcmf_bss_connect_done(cfg_priv, ndev, e, true); - } else if (brcmf_is_linkdown(cfg_priv, e)) { + brcmf_bss_connect_done(cfg, ndev, e, true); + } else if (brcmf_is_linkdown(cfg, e)) { WL_CONN("Linkdown\n"); - if (brcmf_is_ibssmode(cfg_priv)) { - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + if (brcmf_is_ibssmode(cfg)) { + clear_bit(WL_STATUS_CONNECTING, &cfg->status); if (test_and_clear_bit(WL_STATUS_CONNECTED, - &cfg_priv->status)) - brcmf_link_down(cfg_priv); + &cfg->status)) + brcmf_link_down(cfg); } else { - brcmf_bss_connect_done(cfg_priv, ndev, e, false); + brcmf_bss_connect_done(cfg, ndev, e, false); if (test_and_clear_bit(WL_STATUS_CONNECTED, - &cfg_priv->status)) { + &cfg->status)) { cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - brcmf_link_down(cfg_priv); + brcmf_link_down(cfg); } } - brcmf_init_prof(cfg_priv->profile); - } else if (brcmf_is_nonetwork(cfg_priv, e)) { - if (brcmf_is_ibssmode(cfg_priv)) - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + brcmf_init_prof(cfg->profile); + } else if (brcmf_is_nonetwork(cfg, e)) { + if (brcmf_is_ibssmode(cfg)) + clear_bit(WL_STATUS_CONNECTING, &cfg->status); else - brcmf_bss_connect_done(cfg_priv, ndev, e, false); + brcmf_bss_connect_done(cfg, ndev, e, false); } return err; } static s32 -brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { @@ -3920,17 +4774,17 @@ brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, u32 status = be32_to_cpu(e->status); if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { - if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) - brcmf_bss_roaming_done(cfg_priv, ndev, e); + if (test_bit(WL_STATUS_CONNECTED, &cfg->status)) + brcmf_bss_roaming_done(cfg, ndev, e); else - brcmf_bss_connect_done(cfg_priv, ndev, e, true); + brcmf_bss_connect_done(cfg, ndev, e, true); } return err; } static s32 -brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { @@ -3949,7 +4803,7 @@ brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, } static s32 -brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, +brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { @@ -3962,12 +4816,12 @@ brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, WL_TRACE("Enter\n"); - if (cfg_priv->iscan_on && cfg_priv->iscan_kickstart) { + if (cfg->iscan_on && cfg->iscan_kickstart) { WL_TRACE("Exit\n"); - return brcmf_wakeup_iscan(cfg_to_iscan(cfg_priv)); + return brcmf_wakeup_iscan(cfg_to_iscan(cfg)); } - if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) { WL_ERR("Scan complete while device not scanning\n"); scan_abort = true; err = -EINVAL; @@ -3984,33 +4838,33 @@ brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, scan_channel = le32_to_cpu(channel_inform_le.scan_channel); if (scan_channel) WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel); - cfg_priv->bss_list = cfg_priv->scan_results; - bss_list_le = (struct brcmf_scan_results_le *) cfg_priv->bss_list; + cfg->bss_list = cfg->scan_results; + bss_list_le = (struct brcmf_scan_results_le *) cfg->bss_list; - memset(cfg_priv->scan_results, 0, len); + memset(cfg->scan_results, 0, len); bss_list_le->buflen = cpu_to_le32(len); err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS, - cfg_priv->scan_results, len); + cfg->scan_results, len); if (err) { WL_ERR("%s Scan_results error (%d)\n", ndev->name, err); err = -EINVAL; scan_abort = true; goto scan_done_out; } - cfg_priv->scan_results->buflen = le32_to_cpu(bss_list_le->buflen); - cfg_priv->scan_results->version = le32_to_cpu(bss_list_le->version); - cfg_priv->scan_results->count = le32_to_cpu(bss_list_le->count); + cfg->scan_results->buflen = le32_to_cpu(bss_list_le->buflen); + cfg->scan_results->version = le32_to_cpu(bss_list_le->version); + cfg->scan_results->count = le32_to_cpu(bss_list_le->count); - err = brcmf_inform_bss(cfg_priv); + err = brcmf_inform_bss(cfg); if (err) scan_abort = true; scan_done_out: - if (cfg_priv->scan_request) { + if (cfg->scan_request) { WL_SCAN("calling cfg80211_scan_done\n"); - cfg80211_scan_done(cfg_priv->scan_request, scan_abort); + cfg80211_scan_done(cfg->scan_request, scan_abort); brcmf_set_mpc(ndev, 1); - cfg_priv->scan_request = NULL; + cfg->scan_request = NULL; } WL_TRACE("Exit\n"); @@ -4033,74 +4887,85 @@ static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) memset(el, 0, sizeof(*el)); el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status; el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status; + el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status; + el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status; + el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status; + el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status; + el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status; el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results; } -static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) -{ - kfree(cfg_priv->scan_results); - cfg_priv->scan_results = NULL; - kfree(cfg_priv->bss_info); - cfg_priv->bss_info = NULL; - kfree(cfg_priv->conf); - cfg_priv->conf = NULL; - kfree(cfg_priv->profile); - cfg_priv->profile = NULL; - kfree(cfg_priv->scan_req_int); - cfg_priv->scan_req_int = NULL; - kfree(cfg_priv->escan_ioctl_buf); - cfg_priv->escan_ioctl_buf = NULL; - kfree(cfg_priv->dcmd_buf); - cfg_priv->dcmd_buf = NULL; - kfree(cfg_priv->extra_buf); - cfg_priv->extra_buf = NULL; - kfree(cfg_priv->iscan); - cfg_priv->iscan = NULL; - kfree(cfg_priv->pmk_list); - cfg_priv->pmk_list = NULL; -} - -static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) -{ - cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); - if (!cfg_priv->scan_results) +static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) +{ + kfree(cfg->scan_results); + cfg->scan_results = NULL; + kfree(cfg->bss_info); + cfg->bss_info = NULL; + kfree(cfg->conf); + cfg->conf = NULL; + kfree(cfg->profile); + cfg->profile = NULL; + kfree(cfg->scan_req_int); + cfg->scan_req_int = NULL; + kfree(cfg->escan_ioctl_buf); + cfg->escan_ioctl_buf = NULL; + kfree(cfg->dcmd_buf); + cfg->dcmd_buf = NULL; + kfree(cfg->extra_buf); + cfg->extra_buf = NULL; + kfree(cfg->iscan); + cfg->iscan = NULL; + kfree(cfg->pmk_list); + cfg->pmk_list = NULL; + if (cfg->ap_info) { + kfree(cfg->ap_info->wpa_ie); + kfree(cfg->ap_info->rsn_ie); + kfree(cfg->ap_info); + cfg->ap_info = NULL; + } +} + +static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) +{ + cfg->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); + if (!cfg->scan_results) goto init_priv_mem_out; - cfg_priv->conf = kzalloc(sizeof(*cfg_priv->conf), GFP_KERNEL); - if (!cfg_priv->conf) + cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL); + if (!cfg->conf) goto init_priv_mem_out; - cfg_priv->profile = kzalloc(sizeof(*cfg_priv->profile), GFP_KERNEL); - if (!cfg_priv->profile) + cfg->profile = kzalloc(sizeof(*cfg->profile), GFP_KERNEL); + if (!cfg->profile) goto init_priv_mem_out; - cfg_priv->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (!cfg_priv->bss_info) + cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (!cfg->bss_info) goto init_priv_mem_out; - cfg_priv->scan_req_int = kzalloc(sizeof(*cfg_priv->scan_req_int), + cfg->scan_req_int = kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL); - if (!cfg_priv->scan_req_int) + if (!cfg->scan_req_int) goto init_priv_mem_out; - cfg_priv->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); - if (!cfg_priv->escan_ioctl_buf) + cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); + if (!cfg->escan_ioctl_buf) goto init_priv_mem_out; - cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); - if (!cfg_priv->dcmd_buf) + cfg->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); + if (!cfg->dcmd_buf) goto init_priv_mem_out; - cfg_priv->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); - if (!cfg_priv->extra_buf) + cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!cfg->extra_buf) goto init_priv_mem_out; - cfg_priv->iscan = kzalloc(sizeof(*cfg_priv->iscan), GFP_KERNEL); - if (!cfg_priv->iscan) + cfg->iscan = kzalloc(sizeof(*cfg->iscan), GFP_KERNEL); + if (!cfg->iscan) goto init_priv_mem_out; - cfg_priv->pmk_list = kzalloc(sizeof(*cfg_priv->pmk_list), GFP_KERNEL); - if (!cfg_priv->pmk_list) + cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); + if (!cfg->pmk_list) goto init_priv_mem_out; return 0; init_priv_mem_out: - brcmf_deinit_priv_mem(cfg_priv); + brcmf_deinit_priv_mem(cfg); return -ENOMEM; } @@ -4110,17 +4975,17 @@ init_priv_mem_out: */ static struct brcmf_cfg80211_event_q *brcmf_deq_event( - struct brcmf_cfg80211_priv *cfg_priv) + struct brcmf_cfg80211_info *cfg) { struct brcmf_cfg80211_event_q *e = NULL; - spin_lock_irq(&cfg_priv->evt_q_lock); - if (!list_empty(&cfg_priv->evt_q_list)) { - e = list_first_entry(&cfg_priv->evt_q_list, + spin_lock_irq(&cfg->evt_q_lock); + if (!list_empty(&cfg->evt_q_list)) { + e = list_first_entry(&cfg->evt_q_list, struct brcmf_cfg80211_event_q, evt_q_list); list_del(&e->evt_q_list); } - spin_unlock_irq(&cfg_priv->evt_q_lock); + spin_unlock_irq(&cfg->evt_q_lock); return e; } @@ -4132,7 +4997,7 @@ static struct brcmf_cfg80211_event_q *brcmf_deq_event( */ static s32 -brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, +brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event, const struct brcmf_event_msg *msg, void *data) { struct brcmf_cfg80211_event_q *e; @@ -4156,9 +5021,9 @@ brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, if (data) memcpy(&e->edata, data, data_len); - spin_lock_irqsave(&cfg_priv->evt_q_lock, flags); - list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list); - spin_unlock_irqrestore(&cfg_priv->evt_q_lock, flags); + spin_lock_irqsave(&cfg->evt_q_lock, flags); + list_add_tail(&e->evt_q_list, &cfg->evt_q_list); + spin_unlock_irqrestore(&cfg->evt_q_lock, flags); return err; } @@ -4170,12 +5035,12 @@ static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) static void brcmf_cfg80211_event_handler(struct work_struct *work) { - struct brcmf_cfg80211_priv *cfg_priv = - container_of(work, struct brcmf_cfg80211_priv, + struct brcmf_cfg80211_info *cfg = + container_of(work, struct brcmf_cfg80211_info, event_work); struct brcmf_cfg80211_event_q *e; - e = brcmf_deq_event(cfg_priv); + e = brcmf_deq_event(cfg); if (unlikely(!e)) { WL_ERR("event queue empty...\n"); return; @@ -4183,147 +5048,131 @@ static void brcmf_cfg80211_event_handler(struct work_struct *work) do { WL_INFO("event type (%d)\n", e->etype); - if (cfg_priv->el.handler[e->etype]) - cfg_priv->el.handler[e->etype](cfg_priv, - cfg_to_ndev(cfg_priv), + if (cfg->el.handler[e->etype]) + cfg->el.handler[e->etype](cfg, + cfg_to_ndev(cfg), &e->emsg, e->edata); else WL_INFO("Unknown Event (%d): ignoring\n", e->etype); brcmf_put_event(e); - } while ((e = brcmf_deq_event(cfg_priv))); + } while ((e = brcmf_deq_event(cfg))); } -static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg) { - spin_lock_init(&cfg_priv->evt_q_lock); - INIT_LIST_HEAD(&cfg_priv->evt_q_list); + spin_lock_init(&cfg->evt_q_lock); + INIT_LIST_HEAD(&cfg->evt_q_list); } -static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg) { struct brcmf_cfg80211_event_q *e; - spin_lock_irq(&cfg_priv->evt_q_lock); - while (!list_empty(&cfg_priv->evt_q_list)) { - e = list_first_entry(&cfg_priv->evt_q_list, + spin_lock_irq(&cfg->evt_q_lock); + while (!list_empty(&cfg->evt_q_list)) { + e = list_first_entry(&cfg->evt_q_list, struct brcmf_cfg80211_event_q, evt_q_list); list_del(&e->evt_q_list); kfree(e); } - spin_unlock_irq(&cfg_priv->evt_q_lock); + spin_unlock_irq(&cfg->evt_q_lock); } -static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv) +static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) { s32 err = 0; - cfg_priv->scan_request = NULL; - cfg_priv->pwr_save = true; + cfg->scan_request = NULL; + cfg->pwr_save = true; #ifdef CONFIG_BRCMISCAN - cfg_priv->iscan_on = true; /* iscan on & off switch. + cfg->iscan_on = true; /* iscan on & off switch. we enable iscan per default */ - cfg_priv->escan_on = false; /* escan on & off switch. + cfg->escan_on = false; /* escan on & off switch. we disable escan per default */ #else - cfg_priv->iscan_on = false; /* iscan on & off switch. + cfg->iscan_on = false; /* iscan on & off switch. we disable iscan per default */ - cfg_priv->escan_on = true; /* escan on & off switch. + cfg->escan_on = true; /* escan on & off switch. we enable escan per default */ #endif - cfg_priv->roam_on = true; /* roam on & off switch. + cfg->roam_on = true; /* roam on & off switch. we enable roam per default */ - cfg_priv->iscan_kickstart = false; - cfg_priv->active_scan = true; /* we do active scan for + cfg->iscan_kickstart = false; + cfg->active_scan = true; /* we do active scan for specific scan per default */ - cfg_priv->dongle_up = false; /* dongle is not up yet */ - brcmf_init_eq(cfg_priv); - err = brcmf_init_priv_mem(cfg_priv); + cfg->dongle_up = false; /* dongle is not up yet */ + brcmf_init_eq(cfg); + err = brcmf_init_priv_mem(cfg); if (err) return err; - INIT_WORK(&cfg_priv->event_work, brcmf_cfg80211_event_handler); - brcmf_init_eloop_handler(&cfg_priv->el); - mutex_init(&cfg_priv->usr_sync); - err = brcmf_init_iscan(cfg_priv); + INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler); + brcmf_init_eloop_handler(&cfg->el); + mutex_init(&cfg->usr_sync); + err = brcmf_init_iscan(cfg); if (err) return err; - brcmf_init_escan(cfg_priv); - brcmf_init_conf(cfg_priv->conf); - brcmf_init_prof(cfg_priv->profile); - brcmf_link_down(cfg_priv); + brcmf_init_escan(cfg); + brcmf_init_conf(cfg->conf); + brcmf_init_prof(cfg->profile); + brcmf_link_down(cfg); return err; } -static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv) +static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) { - cancel_work_sync(&cfg_priv->event_work); - cfg_priv->dongle_up = false; /* dongle down */ - brcmf_flush_eq(cfg_priv); - brcmf_link_down(cfg_priv); - brcmf_abort_scanning(cfg_priv); - brcmf_deinit_priv_mem(cfg_priv); + cancel_work_sync(&cfg->event_work); + cfg->dongle_up = false; /* dongle down */ + brcmf_flush_eq(cfg); + brcmf_link_down(cfg); + brcmf_abort_scanning(cfg); + brcmf_deinit_priv_mem(cfg); } -struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, - struct device *busdev, - struct brcmf_pub *drvr) +struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev, + struct device *busdev, + struct brcmf_pub *drvr) { struct wireless_dev *wdev; - struct brcmf_cfg80211_priv *cfg_priv; - struct brcmf_cfg80211_iface *ci; - struct brcmf_cfg80211_dev *cfg_dev; + struct brcmf_cfg80211_info *cfg; s32 err = 0; if (!ndev) { WL_ERR("ndev is invalid\n"); return NULL; } - cfg_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL); - if (!cfg_dev) - return NULL; - wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), busdev); + wdev = brcmf_alloc_wdev(busdev); if (IS_ERR(wdev)) { - kfree(cfg_dev); return NULL; } wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); - cfg_priv = wdev_to_cfg(wdev); - cfg_priv->wdev = wdev; - cfg_priv->pub = drvr; - ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci; - ci->cfg_priv = cfg_priv; + cfg = wdev_to_cfg(wdev); + cfg->wdev = wdev; + cfg->pub = drvr; ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; - err = wl_init_priv(cfg_priv); + err = wl_init_priv(cfg); if (err) { WL_ERR("Failed to init iwm_priv (%d)\n", err); goto cfg80211_attach_out; } - brcmf_set_drvdata(cfg_dev, ci); - return cfg_dev; + return cfg; cfg80211_attach_out: - brcmf_free_wdev(cfg_priv); - kfree(cfg_dev); + brcmf_free_wdev(cfg); return NULL; } -void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev) +void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_priv *cfg_priv; - - cfg_priv = brcmf_priv_get(cfg_dev); - - wl_deinit_priv(cfg_priv); - brcmf_free_wdev(cfg_priv); - brcmf_set_drvdata(cfg_dev, NULL); - kfree(cfg_dev); + wl_deinit_priv(cfg); + brcmf_free_wdev(cfg); } void @@ -4331,10 +5180,10 @@ brcmf_cfg80211_event(struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { u32 event_type = be32_to_cpu(e->event_type); - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - if (!brcmf_enq_event(cfg_priv, event_type, e, data)) - schedule_work(&cfg_priv->event_work); + if (!brcmf_enq_event(cfg, event_type, e, data)) + schedule_work(&cfg->event_work); } static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) @@ -4355,6 +5204,9 @@ static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) case NL80211_IFTYPE_STATION: infra = 1; break; + case NL80211_IFTYPE_AP: + infra = 1; + break; default: err = -EINVAL; WL_ERR("invalid type (%d)\n", iftype); @@ -4527,14 +5379,14 @@ dongle_scantime_out: return err; } -static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) +static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg) { struct wiphy *wiphy; s32 phy_list; s8 phy; s32 err = 0; - err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST, + err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCM_GET_PHYLIST, &phy_list, sizeof(phy_list)); if (err) { WL_ERR("error (%d)\n", err); @@ -4544,29 +5396,29 @@ static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) phy = ((char *)&phy_list)[0]; WL_INFO("%c phy\n", phy); if (phy == 'n' || phy == 'a') { - wiphy = cfg_to_wiphy(cfg_priv); + wiphy = cfg_to_wiphy(cfg); wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; } return err; } -static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg) { - return wl_update_wiphybands(cfg_priv); + return wl_update_wiphybands(cfg); } -static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv) +static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) { struct net_device *ndev; struct wireless_dev *wdev; s32 power_mode; s32 err = 0; - if (cfg_priv->dongle_up) + if (cfg->dongle_up) return err; - ndev = cfg_to_ndev(cfg_priv); + ndev = cfg_to_ndev(cfg); wdev = ndev->ieee80211_ptr; brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, @@ -4576,21 +5428,21 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv) if (err) goto default_conf_out; - power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF; + power_mode = cfg->pwr_save ? PM_FAST : PM_OFF; err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode); if (err) goto default_conf_out; WL_INFO("power save set to %s\n", (power_mode ? "enabled" : "disabled")); - err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1), + err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT); if (err) goto default_conf_out; err = brcmf_dongle_mode(ndev, wdev->iftype); if (err && err != -EINPROGRESS) goto default_conf_out; - err = brcmf_dongle_probecap(cfg_priv); + err = brcmf_dongle_probecap(cfg); if (err) goto default_conf_out; @@ -4598,31 +5450,31 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv) default_conf_out: - cfg_priv->dongle_up = true; + cfg->dongle_up = true; return err; } -static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv) +static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_info *cfg) { char buf[10+IFNAMSIZ]; struct dentry *fd; s32 err = 0; - sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name); - cfg_priv->debugfsdir = debugfs_create_dir(buf, - cfg_to_wiphy(cfg_priv)->debugfsdir); + sprintf(buf, "netdev:%s", cfg_to_ndev(cfg)->name); + cfg->debugfsdir = debugfs_create_dir(buf, + cfg_to_wiphy(cfg)->debugfsdir); - fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir, - (u16 *)&cfg_priv->profile->beacon_interval); + fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg->debugfsdir, + (u16 *)&cfg->profile->beacon_interval); if (!fd) { err = -ENOMEM; goto err_out; } - fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir, - (u8 *)&cfg_priv->profile->dtim_period); + fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg->debugfsdir, + (u8 *)&cfg->profile->dtim_period); if (!fd) { err = -ENOMEM; goto err_out; @@ -4632,40 +5484,40 @@ err_out: return err; } -static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_info *cfg) { - debugfs_remove_recursive(cfg_priv->debugfsdir); - cfg_priv->debugfsdir = NULL; + debugfs_remove_recursive(cfg->debugfsdir); + cfg->debugfsdir = NULL; } -static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv) +static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) { s32 err = 0; - set_bit(WL_STATUS_READY, &cfg_priv->status); + set_bit(WL_STATUS_READY, &cfg->status); - brcmf_debugfs_add_netdev_params(cfg_priv); + brcmf_debugfs_add_netdev_params(cfg); - err = brcmf_config_dongle(cfg_priv); + err = brcmf_config_dongle(cfg); if (err) return err; - brcmf_invoke_iscan(cfg_priv); + brcmf_invoke_iscan(cfg); return err; } -static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv) +static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) { /* * While going down, if associated with AP disassociate * from AP to save power */ - if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || - test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && - test_bit(WL_STATUS_READY, &cfg_priv->status)) { + if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) || + test_bit(WL_STATUS_CONNECTING, &cfg->status)) && + test_bit(WL_STATUS_READY, &cfg->status)) { WL_INFO("Disassociating from AP"); - brcmf_link_down(cfg_priv); + brcmf_link_down(cfg); /* Make sure WPA_Supplicant receives all the event generated due to DISASSOC call to the fw to keep @@ -4674,36 +5526,32 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv) brcmf_delay(500); } - brcmf_abort_scanning(cfg_priv); - clear_bit(WL_STATUS_READY, &cfg_priv->status); + brcmf_abort_scanning(cfg); + clear_bit(WL_STATUS_READY, &cfg->status); - brcmf_debugfs_remove_netdev(cfg_priv); + brcmf_debugfs_remove_netdev(cfg); return 0; } -s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev) +s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_priv *cfg_priv; s32 err = 0; - cfg_priv = brcmf_priv_get(cfg_dev); - mutex_lock(&cfg_priv->usr_sync); - err = __brcmf_cfg80211_up(cfg_priv); - mutex_unlock(&cfg_priv->usr_sync); + mutex_lock(&cfg->usr_sync); + err = __brcmf_cfg80211_up(cfg); + mutex_unlock(&cfg->usr_sync); return err; } -s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev) +s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_priv *cfg_priv; s32 err = 0; - cfg_priv = brcmf_priv_get(cfg_dev); - mutex_lock(&cfg_priv->usr_sync); - err = __brcmf_cfg80211_down(cfg_priv); - mutex_unlock(&cfg_priv->usr_sync); + mutex_lock(&cfg->usr_sync); + err = __brcmf_cfg80211_down(cfg); + mutex_unlock(&cfg->usr_sync); return err; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 52e408ed6f41..71ced174748a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -17,12 +17,6 @@ #ifndef _wl_cfg80211_h_ #define _wl_cfg80211_h_ -struct brcmf_cfg80211_conf; -struct brcmf_cfg80211_iface; -struct brcmf_cfg80211_priv; -struct brcmf_cfg80211_security; -struct brcmf_cfg80211_ibss; - #define WL_DBG_NONE 0 #define WL_DBG_CONN (1 << 5) #define WL_DBG_SCAN (1 << 4) @@ -130,13 +124,18 @@ do { \ #define WL_ESCAN_ACTION_CONTINUE 2 #define WL_ESCAN_ACTION_ABORT 3 +#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ +#define IE_MAX_LEN 512 + /* dongle status */ enum wl_status { WL_STATUS_READY, WL_STATUS_SCANNING, WL_STATUS_SCAN_ABORTING, WL_STATUS_CONNECTING, - WL_STATUS_CONNECTED + WL_STATUS_CONNECTED, + WL_STATUS_AP_CREATING, + WL_STATUS_AP_CREATED }; /* wi-fi mode */ @@ -176,23 +175,17 @@ struct brcmf_cfg80211_conf { struct ieee80211_channel channel; }; +/* forward declaration */ +struct brcmf_cfg80211_info; + /* cfg80211 main event loop */ struct brcmf_cfg80211_event_loop { - s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_priv *cfg_priv, + s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data); }; -/* representing interface of cfg80211 plane */ -struct brcmf_cfg80211_iface { - struct brcmf_cfg80211_priv *cfg_priv; -}; - -struct brcmf_cfg80211_dev { - void *driver_data; /* to store cfg80211 object information */ -}; - /* basic structure of scan request */ struct brcmf_cfg80211_scan_req { struct brcmf_ssid_le ssid_le; @@ -245,7 +238,7 @@ struct brcmf_cfg80211_profile { /* dongle iscan event loop */ struct brcmf_cfg80211_iscan_eloop { s32 (*handler[WL_SCAN_ERSULTS_LAST]) - (struct brcmf_cfg80211_priv *cfg_priv); + (struct brcmf_cfg80211_info *cfg); }; /* dongle iscan controller */ @@ -295,6 +288,17 @@ struct escan_info { struct net_device *ndev; }; +/* Structure to hold WPS, WPA IEs for a AP */ +struct ap_info { + u8 probe_res_ie[IE_MAX_LEN]; + u8 beacon_ie[IE_MAX_LEN]; + u32 probe_res_ie_len; + u32 beacon_ie_len; + u8 *wpa_ie; + u8 *rsn_ie; + bool security_mode; +}; + /** * struct brcmf_pno_param_le - PNO scan configuration parameters * @@ -377,7 +381,7 @@ struct brcmf_pno_scanresults_le { }; /** - * struct brcmf_cfg80211_priv - dongle private data of cfg80211 interface + * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface * * @wdev: representing wl cfg80211 device. * @conf: dongle configuration. @@ -417,9 +421,10 @@ struct brcmf_pno_scanresults_le { * @escan_timeout: Timer for catch scan timeout. * @escan_timeout_work: scan timeout worker. * @escan_ioctl_buf: dongle command buffer for escan commands. + * @ap_info: host ap information. * @ci: used to link this structure to netdev private data. */ -struct brcmf_cfg80211_priv { +struct brcmf_cfg80211_info { struct wireless_dev *wdev; struct brcmf_cfg80211_conf *conf; struct cfg80211_scan_request *scan_request; @@ -458,52 +463,52 @@ struct brcmf_cfg80211_priv { struct timer_list escan_timeout; struct work_struct escan_timeout_work; u8 *escan_ioctl_buf; - u8 ci[0] __aligned(NETDEV_ALIGN); + struct ap_info *ap_info; }; -static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_priv *w) +static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *w) { return w->wdev->wiphy; } -static inline struct brcmf_cfg80211_priv *wiphy_to_cfg(struct wiphy *w) +static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w) { - return (struct brcmf_cfg80211_priv *)(wiphy_priv(w)); + return (struct brcmf_cfg80211_info *)(wiphy_priv(w)); } -static inline struct brcmf_cfg80211_priv *wdev_to_cfg(struct wireless_dev *wd) +static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd) { - return (struct brcmf_cfg80211_priv *)(wdev_priv(wd)); + return (struct brcmf_cfg80211_info *)(wdev_priv(wd)); } -static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_priv *cfg) +static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg) { return cfg->wdev->netdev; } -static inline struct brcmf_cfg80211_priv *ndev_to_cfg(struct net_device *ndev) +static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev) { return wdev_to_cfg(ndev->ieee80211_ptr); } -#define iscan_to_cfg(i) ((struct brcmf_cfg80211_priv *)(i->data)) +#define iscan_to_cfg(i) ((struct brcmf_cfg80211_info *)(i->data)) #define cfg_to_iscan(w) (w->iscan) static inline struct -brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg) +brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg) { return &cfg->conn_info; } -extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, - struct device *busdev, - struct brcmf_pub *drvr); -extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg); +struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev, + struct device *busdev, + struct brcmf_pub *drvr); +void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); /* event handler from dongle */ -extern void brcmf_cfg80211_event(struct net_device *ndev, - const struct brcmf_event_msg *e, void *data); -extern s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev); -extern s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev); +void brcmf_cfg80211_event(struct net_device *ndev, + const struct brcmf_event_msg *e, void *data); +s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg); +s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg); #endif /* _wl_cfg80211_h_ */ |