diff options
Diffstat (limited to 'drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c')
| -rw-r--r-- | drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 355 |
1 files changed, 238 insertions, 117 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 456a1bf008b3..e1752a513c73 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/slab.h> #include <linux/netdevice.h> @@ -28,6 +17,7 @@ #include "fwil_types.h" #include "p2p.h" #include "cfg80211.h" +#include "feature.h" /* parameters used for p2p escan */ #define P2PAPI_SCAN_NPROBES 1 @@ -70,12 +60,13 @@ #define P2P_AF_MIN_DWELL_TIME 100 #define P2P_AF_MED_DWELL_TIME 400 #define P2P_AF_LONG_DWELL_TIME 1000 -#define P2P_AF_TX_MAX_RETRY 1 +#define P2P_AF_TX_MAX_RETRY 5 #define P2P_AF_MAX_WAIT_TIME msecs_to_jiffies(2000) #define P2P_INVALID_CHANNEL -1 #define P2P_CHANNEL_SYNC_RETRY 5 #define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(450) #define P2P_DEFAULT_SLEEP_TIME_VSDB 200 +#define P2P_AF_RETRY_DELAY_TIME 40 /* WiFi P2P Public Action Frame OUI Subtypes */ #define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ @@ -99,10 +90,13 @@ #define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */ #define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */ #define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */ -#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */ -#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */ +#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comeback Request AF */ +#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comeback Response AF */ #define BRCMF_P2P_DISABLE_TIMEOUT msecs_to_jiffies(500) + +/* Mask for retry counter of custom dwell time */ +#define CUSTOM_RETRY_MASK 0xff000000 /** * struct brcmf_p2p_disc_st_le - set discovery state in firmware. * @@ -151,11 +145,11 @@ struct brcmf_p2p_scan_le { * * @category: P2P_PUB_AF_CATEGORY * @action: P2P_PUB_AF_ACTION - * @oui[3]: P2P_OUI + * @oui: P2P_OUI * @oui_type: OUI type - P2P_VER * @subtype: OUI subtype - P2P_TYPE_* * @dialog_token: nonzero, identifies req/rsp transaction - * @elts[1]: Variable length information elements. + * @elts: Variable length information elements. */ struct brcmf_p2p_pub_act_frame { u8 category; @@ -164,18 +158,18 @@ struct brcmf_p2p_pub_act_frame { u8 oui_type; u8 subtype; u8 dialog_token; - u8 elts[1]; + u8 elts[]; }; /** * struct brcmf_p2p_action_frame - WiFi P2P Action Frame * * @category: P2P_AF_CATEGORY - * @OUI[3]: OUI - P2P_OUI + * @oui: OUI - P2P_OUI * @type: OUI Type - P2P_VER * @subtype: OUI Subtype - P2P_AF_* * @dialog_token: nonzero, identifies req/resp tranaction - * @elts[1]: Variable length information elements. + * @elts: Variable length information elements. */ struct brcmf_p2p_action_frame { u8 category; @@ -183,7 +177,7 @@ struct brcmf_p2p_action_frame { u8 type; u8 subtype; u8 dialog_token; - u8 elts[1]; + u8 elts[]; }; /** @@ -192,13 +186,13 @@ struct brcmf_p2p_action_frame { * @category: 0x04 Public Action Frame * @action: 0x6c Advertisement Protocol * @dialog_token: nonzero, identifies req/rsp transaction - * @query_data[1]: Query Data. SD gas ireq SD gas iresp + * @query_data: Query Data. SD gas ireq SD gas iresp */ struct brcmf_p2psd_gas_pub_act_frame { u8 category; u8 action; u8 dialog_token; - u8 query_data[1]; + u8 query_data[]; }; /** @@ -207,7 +201,7 @@ struct brcmf_p2psd_gas_pub_act_frame { * @mpc_onoff: To make sure to send successfully action frame, we have to * turn off mpc 0: off, 1: on, (-1): do nothing * @search_channel: 1: search peer's channel to send af - * extra_listen: keep the dwell time to get af response frame. + * @extra_listen: keep the dwell time to get af response frame. */ struct brcmf_config_af_params { s32 mpc_onoff; @@ -231,7 +225,7 @@ static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len) return false; pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; - if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1) + if (frame_len < sizeof(*pact_frm)) return false; if (pact_frm->category == P2P_PUB_AF_CATEGORY && @@ -259,7 +253,7 @@ static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len) return false; act_frm = (struct brcmf_p2p_action_frame *)frame; - if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1) + if (frame_len < sizeof(*act_frm)) return false; if (act_frm->category == P2P_AF_CATEGORY && @@ -286,7 +280,7 @@ static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len) return false; sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; - if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1) + if (frame_len < sizeof(*sd_act_frm)) return false; if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) @@ -402,11 +396,11 @@ static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) (tx) ? "TX" : "RX"); break; case P2PSD_ACTION_ID_GAS_CREQ: - brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n", + brcmf_dbg(TRACE, "%s P2P GAS Comeback Request\n", (tx) ? "TX" : "RX"); break; case P2PSD_ACTION_ID_GAS_CRESP: - brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n", + brcmf_dbg(TRACE, "%s P2P GAS Comeback Response\n", (tx) ? "TX" : "RX"); break; default: @@ -434,6 +428,7 @@ static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) */ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) { + struct brcmf_pub *drvr = ifp->drvr; s32 ret = 0; brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); @@ -450,7 +445,7 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac, ETH_ALEN); if (ret) - brcmf_err("failed to update device address ret %d\n", ret); + bphy_err(drvr, "failed to update device address ret %d\n", ret); return ret; } @@ -467,10 +462,21 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) */ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr) { + struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; bool random_addr = false; + bool local_admin = false; - if (!dev_addr || is_zero_ether_addr(dev_addr)) - random_addr = true; + if (!dev_addr || is_zero_ether_addr(dev_addr)) { + /* If the primary interface address is already locally + * administered, create a new random address. + */ + if (pri_ifp->mac_addr[0] & 0x02) { + random_addr = true; + } else { + dev_addr = pri_ifp->mac_addr; + local_admin = true; + } + } /* Generate the P2P Device Address obtaining a random ethernet * address with the locally administered bit set. @@ -480,13 +486,20 @@ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr) else memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); + if (local_admin) + p2p->dev_addr[0] |= 0x02; + /* Generate the P2P Interface Address. If the discovery and connection * BSSCFGs need to simultaneously co-exist, then this address must be * different from the P2P Device Address, but also locally administered. */ - memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN); - p2p->int_addr[0] |= 0x02; - p2p->int_addr[4] ^= 0x80; + memcpy(p2p->conn_int_addr, p2p->dev_addr, ETH_ALEN); + p2p->conn_int_addr[0] |= 0x02; + p2p->conn_int_addr[4] ^= 0x80; + + memcpy(p2p->conn2_int_addr, p2p->dev_addr, ETH_ALEN); + p2p->conn2_int_addr[0] |= 0x02; + p2p->conn2_int_addr[4] ^= 0x90; } /** @@ -570,13 +583,14 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p) */ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p) { + struct brcmf_pub *drvr = p2p->cfg->pub; struct brcmf_cfg80211_vif *vif; s32 ret = 0; brcmf_dbg(TRACE, "enter\n"); vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; if (!vif) { - brcmf_err("P2P config device not available\n"); + bphy_err(drvr, "P2P config device not available\n"); ret = -EPERM; goto exit; } @@ -590,13 +604,13 @@ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p) vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1); if (ret < 0) { - brcmf_err("set p2p_disc error\n"); + bphy_err(drvr, "set p2p_disc error\n"); goto exit; } vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); if (ret < 0) { - brcmf_err("unable to set WL_P2P_DISC_ST_SCAN\n"); + bphy_err(drvr, "unable to set WL_P2P_DISC_ST_SCAN\n"); goto exit; } @@ -608,7 +622,7 @@ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p) */ ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED); if (ret < 0) { - brcmf_err("wsec error %d\n", ret); + bphy_err(drvr, "wsec error %d\n", ret); goto exit; } @@ -630,6 +644,7 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans, u16 chanspecs[], s32 search_state, enum p2p_bss_type bss_type) { + struct brcmf_pub *drvr = p2p->cfg->pub; s32 ret = 0; s32 memsize = offsetof(struct brcmf_p2p_scan_le, eparams.params_le.channel_list); @@ -648,7 +663,7 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans, vif = p2p->bss_idx[bss_type].vif; if (vif == NULL) { - brcmf_err("no vif for bss type %d\n", bss_type); + bphy_err(drvr, "no vif for bss type %d\n", bss_type); ret = -EINVAL; goto exit; } @@ -676,7 +691,7 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans, BRCMF_P2P_WILDCARD_SSID_LEN); break; default: - brcmf_err(" invalid search state %d\n", search_state); + bphy_err(drvr, " invalid search state %d\n", search_state); ret = -EINVAL; goto exit; } @@ -748,9 +763,8 @@ exit: * brcmf_p2p_run_escan() - escan callback for peer-to-peer. * * @cfg: driver private data for cfg80211 interface. - * @ndev: net device for which scan is requested. + * @ifp: interface control. * @request: scan request from cfg80211. - * @action: scan action. * * Determines the P2P discovery state based to scan request parameters and * validates the channels in the request. @@ -760,6 +774,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, struct cfg80211_scan_request *request) { struct brcmf_p2p_info *p2p = &cfg->p2p; + struct brcmf_pub *drvr = cfg->pub; s32 err = 0; s32 search_state = WL_P2P_DISC_ST_SCAN; struct brcmf_cfg80211_vif *vif; @@ -822,7 +837,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, } exit: if (err) - brcmf_err("error (%d)\n", err); + bphy_err(drvr, "error (%d)\n", err); return err; } @@ -897,8 +912,6 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy, if (err) return err; - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - /* override .run_escan() callback. */ cfg->escan_info.run = brcmf_p2p_run_escan; } @@ -917,19 +930,20 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy, static s32 brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration) { + struct brcmf_pub *drvr = p2p->cfg->pub; struct brcmf_cfg80211_vif *vif; struct brcmu_chan ch; s32 err = 0; vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; if (!vif) { - brcmf_err("Discovery is not set, so we have nothing to do\n"); + bphy_err(drvr, "Discovery is not set, so we have nothing to do\n"); err = -EPERM; goto exit; } if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) { - brcmf_err("Previous LISTEN is not completed yet\n"); + bphy_err(drvr, "Previous LISTEN is not completed yet\n"); /* WAR: prevent cookie mismatch in wpa_supplicant return OK */ goto exit; } @@ -952,9 +966,10 @@ exit: * brcmf_p2p_remain_on_channel() - put device on channel and stay there. * * @wiphy: wiphy device. + * @wdev: wireless device. * @channel: channel to stay on. * @duration: time in ms to remain on channel. - * + * @cookie: cookie. */ int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *channel, @@ -1039,13 +1054,14 @@ void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp) * brcmf_p2p_act_frm_search() - search function for action frame. * * @p2p: p2p device. - * channel: channel on which action frame is to be trasmitted. + * @channel: channel on which action frame is to be trasmitted. * * search function to reach at common channel to send action frame. When * channel is 0 then all social channels will be used to send af */ static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel) { + struct brcmf_pub *drvr = p2p->cfg->pub; s32 err; u32 channel_cnt; u16 *default_chan_list; @@ -1061,7 +1077,7 @@ static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel) default_chan_list = kcalloc(channel_cnt, sizeof(*default_chan_list), GFP_KERNEL); if (default_chan_list == NULL) { - brcmf_err("channel list allocation failed\n"); + bphy_err(drvr, "channel list allocation failed\n"); err = -ENOMEM; goto exit; } @@ -1103,6 +1119,7 @@ static void brcmf_p2p_afx_handler(struct work_struct *work) struct brcmf_p2p_info *p2p = container_of(afx_hdl, struct brcmf_p2p_info, afx_hdl); + struct brcmf_pub *drvr = p2p->cfg->pub; s32 err; if (!afx_hdl->is_active) @@ -1111,12 +1128,12 @@ static void brcmf_p2p_afx_handler(struct work_struct *work) if (afx_hdl->is_listen && afx_hdl->my_listen_chan) /* 100ms ~ 300ms */ err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan, - 100 * (1 + prandom_u32() % 3)); + 100 * get_random_u32_inclusive(1, 3)); else err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan); if (err) { - brcmf_err("ERROR occurred! value is (%d)\n", err); + bphy_err(drvr, "ERROR occurred! value is (%d)\n", err); if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status)) complete(&afx_hdl->act_frm_scan); @@ -1249,6 +1266,30 @@ bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, } /** + * brcmf_p2p_abort_action_frame() - abort action frame. + * + * @cfg: common configuration struct. + * + */ +static s32 brcmf_p2p_abort_action_frame(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_p2p_info *p2p = &cfg->p2p; + struct brcmf_cfg80211_vif *vif; + s32 err; + s32 int_val = 1; + + brcmf_dbg(TRACE, "Enter\n"); + + vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; + err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe_abort", &int_val, + sizeof(s32)); + if (err) + brcmf_err(" aborting action frame has failed (%d)\n", err); + + return err; +} + +/** * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete. * * @cfg: common configuration struct. @@ -1259,6 +1300,7 @@ brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) { struct brcmf_p2p_info *p2p = &cfg->p2p; struct brcmf_if *ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; + s32 err; if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) && (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) || @@ -1267,8 +1309,13 @@ brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) /* if channel is not zero, "actfame" uses off channel scan. * So abort scan for off channel completion. */ - if (p2p->af_sent_channel) - brcmf_notify_escan_complete(cfg, ifp, true, true); + if (p2p->af_sent_channel) { + /* abort actframe using actframe_abort or abort scan */ + err = brcmf_p2p_abort_action_frame(cfg); + if (err) + brcmf_notify_escan_complete(cfg, ifp, true, + true); + } } else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, &p2p->status)) { brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n"); @@ -1282,6 +1329,7 @@ brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) * brcmf_p2p_gon_req_collision() - Check if go negotiaton collission * * @p2p: p2p device info struct. + * @mac: MAC address. * * return true if recevied action frame is to be dropped. */ @@ -1338,7 +1386,8 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_cfg80211_info *cfg = drvr->config; struct brcmf_p2p_info *p2p = &cfg->p2p; struct afx_hdl *afx_hdl = &p2p->afx_hdl; struct wireless_dev *wdev; @@ -1354,7 +1403,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, u8 action; if (e->datalen < sizeof(*rxframe)) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } @@ -1409,7 +1458,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) + mgmt_frame_len, GFP_KERNEL); if (!mgmt_frame) { - brcmf_err("No memory available for action frame\n"); + bphy_err(drvr, "No memory available for action frame\n"); return -ENOMEM; } memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN); @@ -1417,8 +1466,8 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, ETH_ALEN); memcpy(mgmt_frame->sa, e->addr, ETH_ALEN); mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); - memcpy(&mgmt_frame->u, frame, mgmt_frame_len); - mgmt_frame_len += offsetof(struct ieee80211_mgmt, u); + memcpy(mgmt_frame->u.body, frame, mgmt_frame_len); + mgmt_frame_len += offsetof(struct ieee80211_mgmt, u.body); freq = ieee80211_channel_to_frequency(ch.control_ch_num, ch.band == BRCMU_CHAN_BAND_2G ? @@ -1480,6 +1529,7 @@ int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, /** * brcmf_p2p_tx_action_frame() - send action frame over fil. * + * @ifp: interface to transmit on. * @p2p: p2p info struct for vif. * @af_params: action frame data/info. * @@ -1489,12 +1539,12 @@ int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action * frame is transmitted. */ -static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, +static s32 brcmf_p2p_tx_action_frame(struct brcmf_if *ifp, + struct brcmf_p2p_info *p2p, struct brcmf_fil_af_params_le *af_params) { - struct brcmf_cfg80211_vif *vif; + struct brcmf_pub *drvr = p2p->cfg->pub; s32 err = 0; - s32 timeout = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -1502,11 +1552,10 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params, + err = brcmf_fil_bsscfg_data_set(ifp, "actframe", af_params, sizeof(*af_params)); if (err) { - brcmf_err(" sending action frame has failed\n"); + bphy_err(drvr, " sending action frame has failed\n"); goto exit; } @@ -1524,8 +1573,7 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, (p2p->wait_for_offchan_complete) ? "off-channel" : "on-channel"); - timeout = wait_for_completion_timeout(&p2p->send_af_done, - P2P_AF_MAX_WAIT_TIME); + wait_for_completion_timeout(&p2p->send_af_done, P2P_AF_MAX_WAIT_TIME); if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) { brcmf_dbg(TRACE, "TX action frame operation is success\n"); @@ -1556,6 +1604,7 @@ static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg, struct brcmf_config_af_params *config_af_params) { struct brcmf_p2p_info *p2p = &cfg->p2p; + struct brcmf_pub *drvr = cfg->pub; struct brcmf_fil_action_frame_le *action_frame; struct brcmf_p2p_pub_act_frame *act_frm; s32 err = 0; @@ -1634,29 +1683,39 @@ static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg, config_af_params->extra_listen = false; break; default: - brcmf_err("Unknown p2p pub act frame subtype: %d\n", - act_frm->subtype); + bphy_err(drvr, "Unknown p2p pub act frame subtype: %d\n", + act_frm->subtype); err = -EINVAL; } return err; } +static bool brcmf_p2p_check_dwell_overflow(u32 requested_dwell, + unsigned long dwell_jiffies) +{ + if ((requested_dwell & CUSTOM_RETRY_MASK) && + (jiffies_to_msecs(jiffies - dwell_jiffies) > + (requested_dwell & ~CUSTOM_RETRY_MASK))) { + brcmf_err("Action frame TX retry time over dwell time!\n"); + return true; + } + return false; +} /** * brcmf_p2p_send_action_frame() - send action frame . * - * @cfg: driver private data for cfg80211 interface. - * @ndev: net device to transmit on. + * @ifp: interface to transmit on. * @af_params: configuration data for action frame. */ -bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +bool brcmf_p2p_send_action_frame(struct brcmf_if *ifp, struct brcmf_fil_af_params_le *af_params) { + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; struct brcmf_p2p_info *p2p = &cfg->p2p; - struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_fil_action_frame_le *action_frame; struct brcmf_config_af_params config_af_params; struct afx_hdl *afx_hdl = &p2p->afx_hdl; + struct brcmf_pub *drvr = cfg->pub; u16 action_frame_len; bool ack = false; u8 category; @@ -1664,7 +1723,10 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, s32 tx_retry; s32 extra_listen_time; uint delta_ms; + unsigned long dwell_jiffies = 0; + bool dwell_overflow = false; + u32 requested_dwell = le32_to_cpu(af_params->dwell_time); action_frame = &af_params->action_frame; action_frame_len = le16_to_cpu(action_frame->len); @@ -1692,7 +1754,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) { /* Just send unknown subtype frame with */ /* default parameters. */ - brcmf_err("P2P Public action frame, unknown subtype.\n"); + bphy_err(drvr, "P2P Public action frame, unknown subtype.\n"); } } else if (brcmf_p2p_is_gas_action(action_frame->data, action_frame_len)) { @@ -1714,7 +1776,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); } else { - brcmf_err("Unknown action type: %d\n", action); + bphy_err(drvr, "Unknown action type: %d\n", action); goto exit; } } else if (brcmf_p2p_is_p2p_action(action_frame->data, @@ -1722,8 +1784,8 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, /* do not configure anything. it will be */ /* sent with a default configuration */ } else { - brcmf_err("Unknown Frame: category 0x%x, action 0x%x\n", - category, action); + bphy_err(drvr, "Unknown Frame: category 0x%x, action 0x%x\n", + category, action); return false; } @@ -1761,7 +1823,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, if (brcmf_p2p_af_searching_channel(p2p) == P2P_INVALID_CHANNEL) { - brcmf_err("Couldn't find peer's channel.\n"); + bphy_err(drvr, "Couldn't find peer's channel.\n"); goto exit; } @@ -1775,15 +1837,25 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, /* update channel */ af_params->channel = cpu_to_le32(afx_hdl->peer_chan); } + dwell_jiffies = jiffies; + dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell, + dwell_jiffies); tx_retry = 0; while (!p2p->block_gon_req_tx && - (ack == false) && (tx_retry < P2P_AF_TX_MAX_RETRY)) { - ack = !brcmf_p2p_tx_action_frame(p2p, af_params); + (!ack) && (tx_retry < P2P_AF_TX_MAX_RETRY) && + !dwell_overflow) { + if (af_params->channel) + msleep(P2P_AF_RETRY_DELAY_TIME); + + ack = !brcmf_p2p_tx_action_frame(ifp, p2p, af_params); tx_retry++; + dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell, + dwell_jiffies); } - if (ack == false) { - brcmf_err("Failed to send Action Frame(retry %d)\n", tx_retry); + if (!ack) { + bphy_err(drvr, "Failed to send Action Frame(retry %d)\n", + tx_retry); clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); } @@ -1868,7 +1940,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, e->reason); if (e->datalen < sizeof(*rxframe)) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } @@ -1956,15 +2028,16 @@ static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p, } /** - * Change a P2P Role. - * Parameters: - * @mac: MAC address of the BSS to change a role + * brcmf_p2p_ifchange - Change a P2P Role. + * @cfg: driver private data for cfg80211 interface. + * @if_type: interface type. * Returns 0 if success. */ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, enum brcmf_fil_p2p_if_types if_type) { struct brcmf_p2p_info *p2p = &cfg->p2p; + struct brcmf_pub *drvr = cfg->pub; struct brcmf_cfg80211_vif *vif; struct brcmf_fil_p2p_if_le if_request; s32 err; @@ -1974,13 +2047,13 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; if (!vif) { - brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n"); + bphy_err(drvr, "vif for P2PAPI_BSSCFG_PRIMARY does not exist\n"); return -EPERM; } brcmf_notify_escan_complete(cfg, vif->ifp, true, true); vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif; if (!vif) { - brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n"); + bphy_err(drvr, "vif for P2PAPI_BSSCFG_CONNECTION does not exist\n"); return -EPERM; } brcmf_set_mpc(vif->ifp, 0); @@ -1992,13 +2065,13 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, if_request.type = cpu_to_le16((u16)if_type); if_request.chspec = cpu_to_le16(chanspec); - memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr)); + memcpy(if_request.addr, p2p->conn_int_addr, sizeof(if_request.addr)); brcmf_cfg80211_arm_vif_event(cfg, vif); err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request, sizeof(if_request)); if (err) { - brcmf_err("p2p_ifupd FAILED, err=%d\n", err); + bphy_err(drvr, "p2p_ifupd FAILED, err=%d\n", err); brcmf_cfg80211_arm_vif_event(cfg, NULL); return err; } @@ -2006,7 +2079,7 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, BRCMF_VIF_EVENT_TIMEOUT); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (!err) { - brcmf_err("No BRCMF_E_IF_CHANGE event received\n"); + bphy_err(drvr, "No BRCMF_E_IF_CHANGE event received\n"); return -EIO; } @@ -2043,7 +2116,7 @@ static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif) struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); struct net_device *pri_ndev = cfg_to_ndev(cfg); struct brcmf_if *ifp = netdev_priv(pri_ndev); - u8 *addr = vif->wdev.netdev->dev_addr; + const u8 *addr = vif->wdev.netdev->dev_addr; return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN); } @@ -2053,7 +2126,7 @@ static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif) struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); struct net_device *pri_ndev = cfg_to_ndev(cfg); struct brcmf_if *ifp = netdev_priv(pri_ndev); - u8 *addr = vif->wdev.netdev->dev_addr; + const u8 *addr = vif->wdev.netdev->dev_addr; return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN); } @@ -2069,6 +2142,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, struct wiphy *wiphy, u8 *addr) { + struct brcmf_pub *drvr = p2p->cfg->pub; struct brcmf_cfg80211_vif *p2p_vif; struct brcmf_if *p2p_ifp; struct brcmf_if *pri_ifp; @@ -2080,7 +2154,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE); if (IS_ERR(p2p_vif)) { - brcmf_err("could not create discovery vif\n"); + bphy_err(drvr, "could not create discovery vif\n"); return (struct wireless_dev *)p2p_vif; } @@ -2088,8 +2162,9 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, /* firmware requires unique mac address for p2pdev interface */ if (addr && ether_addr_equal(addr, pri_ifp->mac_addr)) { - brcmf_err("discovery vif must be different from primary interface\n"); - return ERR_PTR(-EINVAL); + bphy_err(drvr, "discovery vif must be different from primary interface\n"); + err = -EINVAL; + goto fail; } brcmf_p2p_generate_bss_mac(p2p, addr); @@ -2101,7 +2176,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, /* Initialize P2P Discovery in the firmware */ err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); if (err < 0) { - brcmf_err("set p2p_disc error\n"); + bphy_err(drvr, "set p2p_disc error\n"); brcmf_fweh_p2pdev_setup(pri_ifp, false); brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL); goto fail; @@ -2113,7 +2188,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL); brcmf_fweh_p2pdev_setup(pri_ifp, false); if (!err) { - brcmf_err("timeout occurred\n"); + bphy_err(drvr, "timeout occurred\n"); err = -EIO; goto fail; } @@ -2127,13 +2202,12 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, /* verify bsscfg index for P2P discovery */ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bsscfgidx); if (err < 0) { - brcmf_err("retrieving discover bsscfg index failed\n"); + bphy_err(drvr, "retrieving discover bsscfg index failed\n"); goto fail; } WARN_ON(p2p_ifp->bsscfgidx != bsscfgidx); - init_completion(&p2p->send_af_done); INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler); init_completion(&p2p->afx_hdl.act_frm_scan); init_completion(&p2p->wait_next_af); @@ -2145,6 +2219,27 @@ fail: return ERR_PTR(err); } +static int brcmf_p2p_get_conn_idx(struct brcmf_cfg80211_info *cfg) +{ + int i; + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + + if (!ifp) + return -ENODEV; + + for (i = P2PAPI_BSSCFG_CONNECTION; i < P2PAPI_BSSCFG_MAX; i++) { + if (!cfg->p2p.bss_idx[i].vif) { + if (i == P2PAPI_BSSCFG_CONNECTION2 && + !(brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) { + brcmf_err("Multi p2p not supported"); + return -EIO; + } + return i; + } + } + return -EIO; +} + /** * brcmf_p2p_add_vif() - create a new P2P virtual interface. * @@ -2161,9 +2256,12 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_pub *drvr = cfg->pub; struct brcmf_cfg80211_vif *vif; enum brcmf_fil_p2p_if_types iftype; - int err; + int err = 0; + int connidx; + u8 *p2p_intf_addr; if (brcmf_cfg80211_vif_event_armed(cfg)) return ERR_PTR(-EBUSY); @@ -2189,9 +2287,21 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, return (struct wireless_dev *)vif; brcmf_cfg80211_arm_vif_event(cfg, vif); - err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr, - iftype); + connidx = brcmf_p2p_get_conn_idx(cfg); + + if (connidx == P2PAPI_BSSCFG_CONNECTION) + p2p_intf_addr = cfg->p2p.conn_int_addr; + else if (connidx == P2PAPI_BSSCFG_CONNECTION2) + p2p_intf_addr = cfg->p2p.conn2_int_addr; + else + err = -EINVAL; + + if (!err) + err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, + p2p_intf_addr, iftype); + if (err) { + brcmf_err("request p2p interface failed\n"); brcmf_cfg80211_arm_vif_event(cfg, NULL); goto fail; } @@ -2201,7 +2311,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, BRCMF_VIF_EVENT_TIMEOUT); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (!err) { - brcmf_err("timeout occurred\n"); + bphy_err(drvr, "timeout occurred\n"); err = -EIO; goto fail; } @@ -2209,21 +2319,21 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, /* interface created in firmware */ ifp = vif->ifp; if (!ifp) { - brcmf_err("no if pointer provided\n"); + bphy_err(drvr, "no if pointer provided\n"); err = -ENOENT; goto fail; } - strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); ifp->ndev->name_assign_type = name_assign_type; err = brcmf_net_attach(ifp, true); if (err) { - brcmf_err("Registering netdevice failed\n"); + bphy_err(drvr, "Registering netdevice failed\n"); free_netdev(ifp->ndev); goto fail; } - cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif; + cfg->p2p.bss_idx[connidx].vif = vif; /* Disable firmware roaming for P2P interface */ brcmf_fil_iovar_int_set(ifp, "roam_off", 1); if (iftype == BRCMF_FIL_P2P_IF_GO) { @@ -2304,13 +2414,17 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) brcmf_remove_interface(vif->ifp, true); brcmf_cfg80211_arm_vif_event(cfg, NULL); - if (iftype != NL80211_IFTYPE_P2P_DEVICE) - p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; + if (iftype != NL80211_IFTYPE_P2P_DEVICE) { + if (vif == p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif) + p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; + if (vif == p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION2].vif) + p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION2].vif = NULL; + } return err; } -void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool rtnl_locked) +void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool locked) { struct brcmf_cfg80211_info *cfg; struct brcmf_cfg80211_vif *vif; @@ -2319,11 +2433,15 @@ void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool rtnl_locked) vif = ifp->vif; cfg = wdev_to_cfg(&vif->wdev); cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; - if (!rtnl_locked) + if (!locked) { rtnl_lock(); - cfg80211_unregister_wdev(&vif->wdev); - if (!rtnl_locked) + wiphy_lock(cfg->wiphy); + cfg80211_unregister_wdev(&vif->wdev); + wiphy_unlock(cfg->wiphy); rtnl_unlock(); + } else { + cfg80211_unregister_wdev(&vif->wdev); + } brcmf_free_vif(vif); } @@ -2373,6 +2491,7 @@ void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev) */ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced) { + struct brcmf_pub *drvr = cfg->pub; struct brcmf_p2p_info *p2p; struct brcmf_if *pri_ifp; s32 err = 0; @@ -2384,10 +2503,12 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced) pri_ifp = brcmf_get_ifp(cfg->pub, 0); p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif; + init_completion(&p2p->send_af_done); + if (p2pdev_forced) { err_ptr = brcmf_p2p_create_p2pdev(p2p, NULL, NULL); if (IS_ERR(err_ptr)) { - brcmf_err("P2P device creation failed.\n"); + bphy_err(drvr, "P2P device creation failed.\n"); err = PTR_ERR(err_ptr); } } else { |
