/* P2P Service Discovery related */ #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 Comeback Request AF */ #define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comeback Response AF */
/* Mask for retry counter of custom dwell time */ #define CUSTOM_RETRY_MASK 0xff000000 /** * struct brcmf_p2p_disc_st_le - set discovery state in firmware. * * @state: requested discovery state (see enum brcmf_p2p_disc_state). * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state. * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state.
*/ struct brcmf_p2p_disc_st_le {
u8 state;
__le16 chspec;
__le16 dwell;
};
/** * enum brcmf_p2p_disc_state - P2P discovery state values * * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE. * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time. * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE.
*/ enum brcmf_p2p_disc_state {
WL_P2P_DISC_ST_SCAN,
WL_P2P_DISC_ST_LISTEN,
WL_P2P_DISC_ST_SEARCH
};
/** * struct brcmf_p2p_scan_le - P2P specific scan request. * * @type: type of scan method requested (values: 'E' or 'S'). * @reserved: reserved (ignored). * @eparams: parameters used for type 'E'. * @sparams: parameters used for type 'S'.
*/ struct brcmf_p2p_scan_le {
u8 type;
u8 reserved[3]; union { struct brcmf_escan_params_le eparams; struct brcmf_scan_params_le sparams;
};
};
/** * struct brcmf_config_af_params - Action Frame Parameters for tx. * * @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.
*/ struct brcmf_config_af_params {
s32 mpc_onoff; bool search_channel; bool extra_listen;
};
/** * brcmf_p2p_is_pub_action() - true if p2p public type frame. * * @frame: action frame data. * @frame_len: length of action frame data. * * Determine if action frame is p2p public action type
*/ staticbool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)
{ struct brcmf_p2p_pub_act_frame *pact_frm;
if (frame == NULL) returnfalse;
pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; if (frame_len < sizeof(*pact_frm)) returnfalse;
/** * brcmf_p2p_print_actframe() - debug print routine. * * @tx: Received or to be transmitted * @frame: action frame data. * @frame_len: length of action frame data. * * Print information about the p2p action frame
*/
/* In case of COB type, firmware has default mac address * After Initializing firmware, we have to set current mac address to * firmware for P2P device address. This must be done with discovery * disabled.
*/
brcmf_fil_iovar_int_set(ifp, "p2p_disc", 0);
ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac,
ETH_ALEN); if (ret)
bphy_err(drvr, "failed to update device address ret %d\n", ret);
return ret;
}
/** * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P. * * @p2p: P2P specific data. * @dev_addr: optional device address. * * P2P needs mac addresses for P2P device and interface. If no device * address it specified, these are derived from a random ethernet * address.
*/ staticvoid 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)) { /* 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.
*/ if (random_addr)
eth_random_addr(p2p->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->conn_int_addr, p2p->dev_addr, ETH_ALEN);
p2p->conn_int_addr[0] |= 0x02;
p2p->conn_int_addr[4] ^= 0x80;
/** * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan. * * @request: the scan request as received from cfg80211. * * returns true if one of the ssids in the request matches the * P2P wildcard ssid; otherwise returns false.
*/ staticbool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request)
{ struct cfg80211_ssid *ssids = request->ssids; int i;
for (i = 0; i < request->n_ssids; i++) { if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN) continue;
/** * brcmf_p2p_deinit_discovery() - disable P2P device discovery. * * @p2p: P2P specific data. * * Resets the discovery state and disables it in firmware.
*/ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
{ struct brcmf_cfg80211_vif *vif;
brcmf_dbg(TRACE, "enter\n");
/* Set the discovery state to SCAN */
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
(void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
/* Disable P2P discovery in the firmware */
vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
(void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0);
return 0;
}
/** * brcmf_p2p_enable_discovery() - initialize and configure discovery. * * @p2p: P2P specific data. * * Initializes the discovery device and configure the virtual interface.
*/ staticint 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) {
bphy_err(drvr, "P2P config device not available\n");
ret = -EPERM; gotoexit;
}
/* Re-initialize P2P Discovery in the firmware */
vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1); if (ret < 0) {
bphy_err(drvr, "set p2p_disc error\n"); gotoexit;
}
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) {
bphy_err(drvr, "unable to set WL_P2P_DISC_ST_SCAN\n"); gotoexit;
}
/* * Set wsec to any non-zero value in the discovery bsscfg * to ensure our P2P probe responses have the privacy bit * set in the 802.11 WPA IE. Some peer devices may not * initiate WPS with us if this bit is not set.
*/
ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED); if (ret < 0) {
bphy_err(drvr, "wsec error %d\n", ret); gotoexit;
}
vif = p2p->bss_idx[bss_type].vif; if (vif == NULL) {
bphy_err(drvr, "no vif for bss type %d\n", bss_type);
ret = -EINVAL; gotoexit;
}
p2p_params = (struct brcmf_p2p_scan_le *)memblk;
sparams = &p2p_params->eparams.params_le;
switch (search_state) { case WL_P2P_DISC_ST_SEARCH: /* * If we in SEARCH STATE, we don't need to set SSID explictly * because dongle use P2P WILDCARD internally by default, use * null ssid, which it is already due to kzalloc.
*/ break; case WL_P2P_DISC_ST_SCAN: /* * wpa_supplicant has p2p_find command with type social or * progressive. For progressive, we need to set the ssid to * P2P WILDCARD because we just do broadcast scan unless * setting SSID.
*/
sparams->ssid_le.SSID_len =
cpu_to_le32(BRCMF_P2P_WILDCARD_SSID_LEN);
memcpy(sparams->ssid_le.SSID, BRCMF_P2P_WILDCARD_SSID,
BRCMF_P2P_WILDCARD_SSID_LEN); break; default:
bphy_err(drvr, " invalid search state %d\n", search_state);
ret = -EINVAL; gotoexit;
}
/* * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan * supported by the supplicant.
*/ if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1))
active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS; elseif (num_chans == AF_PEER_SEARCH_CNT)
active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS; elseif (brcmf_get_vif_state_any(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))
active = -1; else
active = P2PAPI_SCAN_DWELL_TIME_MS;
/* Override scan params to find a peer for a connection */ if (num_chans == 1) {
active = WL_SCAN_CONNECT_DWELL_TIME_MS; /* WAR to sync with presence period of VSDB GO. * send probe request more frequently
*/
nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS;
} else {
nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS;
}
/** * brcmf_p2p_scan_prep() - prepare scan based on request. * * @wiphy: wiphy device. * @request: scan request from cfg80211. * @vif: vif on which scan request is to be executed. * * Prepare the scan appropriately for type of scan requested. Overrides the * escan .run() callback for peer-to-peer scanning.
*/ int brcmf_p2p_scan_prep(struct wiphy *wiphy, struct cfg80211_scan_request *request, struct brcmf_cfg80211_vif *vif)
{ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_p2p_info *p2p = &cfg->p2p; int err;
if (brcmf_p2p_scan_is_p2p_request(request)) { /* find my listen channel */
err = brcmf_p2p_find_listen_channel(request->ie,
request->ie_len); if (err < 0) return err;
p2p->afx_hdl.my_listen_chan = err;
clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
err = brcmf_p2p_enable_discovery(p2p); if (err) return err;
/** * brcmf_p2p_discover_listen() - set firmware to discover listen state. * * @p2p: p2p device. * @channel: channel nr for discover listen. * @duration: time in ms to stay on channel. *
*/ 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) {
bphy_err(drvr, "Discovery is not set, so we have nothing to do\n");
err = -EPERM; gotoexit;
}
if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) {
bphy_err(drvr, "Previous LISTEN is not completed yet\n"); /* WAR: prevent cookie mismatch in wpa_supplicant return OK */ gotoexit;
}
/** * brcmf_p2p_notify_listen_complete() - p2p listen has completed. * * @ifp: interfac control. * @e: event message. Not used, to make it usable for fweh event dispatcher. * @data: payload of message. Not used. *
*/ int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, conststruct brcmf_event_msg *e, void *data)
{ struct brcmf_cfg80211_info *cfg = ifp->drvr->config; struct brcmf_p2p_info *p2p = &cfg->p2p;
brcmf_dbg(TRACE, "Enter\n"); if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN,
&p2p->status)) { if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
&p2p->status)) {
clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
&p2p->status);
brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n");
complete(&p2p->wait_next_af);
}
/** * brcmf_p2p_act_frm_search() - search function for action frame. * * @p2p: p2p device. * @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;
u32 i; struct brcmu_chan ch;
brcmf_dbg(TRACE, "Enter\n");
if (channel)
channel_cnt = AF_PEER_SEARCH_CNT; else
channel_cnt = SOCIAL_CHAN_CNT;
default_chan_list = kcalloc(channel_cnt, sizeof(*default_chan_list),
GFP_KERNEL); if (default_chan_list == NULL) {
bphy_err(drvr, "channel list allocation failed\n");
err = -ENOMEM; gotoexit;
}
ch.bw = BRCMU_CHAN_BW_20; if (channel) {
ch.chnum = channel;
p2p->cfg->d11inf.encchspec(&ch); /* insert same channel to the chan_list */ for (i = 0; i < channel_cnt; i++)
default_chan_list[i] = ch.chspec;
} else {
ch.chnum = SOCIAL_CHAN_1;
p2p->cfg->d11inf.encchspec(&ch);
default_chan_list[0] = ch.chspec;
ch.chnum = SOCIAL_CHAN_2;
p2p->cfg->d11inf.encchspec(&ch);
default_chan_list[1] = ch.chspec;
ch.chnum = SOCIAL_CHAN_3;
p2p->cfg->d11inf.encchspec(&ch);
default_chan_list[2] = ch.chspec;
}
err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list,
WL_P2P_DISC_ST_SEARCH, P2PAPI_BSSCFG_DEVICE);
kfree(default_chan_list); exit: return err;
}
if (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);
}
}
/* Loop to wait until we find a peer's channel or the * pending action frame tx is cancelled.
*/
retry = 0; while ((retry < P2P_CHANNEL_SYNC_RETRY) &&
(afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) {
afx_hdl->is_listen = false;
brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n",
retry); /* search peer on peer's listen channel */
schedule_work(&afx_hdl->afx_work);
wait_for_completion_timeout(&afx_hdl->act_frm_scan,
P2P_AF_FRM_SCAN_MAX_WAIT); if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
(!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
&p2p->status))) break;
if (afx_hdl->my_listen_chan) {
brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n",
afx_hdl->my_listen_chan); /* listen on my listen channel */
afx_hdl->is_listen = true;
schedule_work(&afx_hdl->afx_work);
wait_for_completion_timeout(&afx_hdl->act_frm_scan,
P2P_AF_FRM_SCAN_MAX_WAIT);
} if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
(!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
&p2p->status))) break;
retry++;
/* if sta is connected or connecting, sleep for a while before * retry af tx or finding a peer
*/ if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) ||
test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state))
msleep(P2P_DEFAULT_SLEEP_TIME_VSDB);
}
/** * brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel * * @cfg: common configuration struct. * @bi: bss info struct, result from scan. *
*/ bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, struct brcmf_bss_info_le *bi)
if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
(test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) {
brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n"); /* if channel is not zero, "actfame" uses off channel scan. * So abort scan for off channel completion.
*/ 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);
}
} elseif (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
&p2p->status)) {
brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n"); /* So abort scan to cancel listen */
brcmf_notify_escan_complete(cfg, ifp, true, true);
}
}
/** * 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.
*/ staticbool
brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac)
{ struct brcmf_cfg80211_info *cfg = p2p->cfg; struct brcmf_if *ifp;
brcmf_dbg(TRACE, "Enter\n");
if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) ||
!p2p->gon_req_action) returnfalse;
brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n"); /* if sa(peer) addr is less than da(my) addr, then this device * process peer's gon request and block to send gon req. * if not (sa addr > da addr), * this device will process gon request and drop gon req of peer.
*/
ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) {
brcmf_dbg(INFO, "Block transmit gon req !!!\n");
p2p->block_gon_req_tx = true; /* if we are finding a common channel for sending af, * do not scan more to block to send current gon req
*/ if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
&p2p->status))
complete(&p2p->afx_hdl.act_frm_scan); if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
&p2p->status))
brcmf_p2p_stop_wait_next_action_frame(cfg); returnfalse;
}
/* drop gon request of peer to process gon request by this device. */
brcmf_dbg(INFO, "Drop received gon req !!!\n");
action = P2P_PAF_SUBTYPE_INVALID; if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) {
act_frm = (struct brcmf_p2p_pub_act_frame *)frame;
action = act_frm->subtype; if ((action == P2P_PAF_GON_REQ) &&
(brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) { if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
&p2p->status) &&
(ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {
afx_hdl->peer_chan = ch.control_ch_num;
brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",
afx_hdl->peer_chan);
complete(&afx_hdl->act_frm_scan);
} return 0;
} /* After complete GO Negotiation, roll back to mpc mode */ if ((action == P2P_PAF_GON_CONF) ||
(action == P2P_PAF_PROVDIS_RSP))
brcmf_set_mpc(ifp, 1); if (action == P2P_PAF_GON_CONF) {
brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
}
} elseif (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) {
sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
action = sd_act_frm->action;
}
if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
(p2p->next_af_subtype == action)) {
brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action);
clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
&p2p->status); /* Stop waiting for next AF. */
brcmf_p2p_stop_wait_next_action_frame(cfg);
}
if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status)) return 0;
if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) { if (e->status == BRCMF_E_STATUS_SUCCESS) {
set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
&p2p->status); if (!p2p->wait_for_offchan_complete)
complete(&p2p->send_af_done);
} else {
set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); /* If there is no ack, we don't need to wait for * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event
*/
brcmf_p2p_stop_wait_next_action_frame(cfg);
}
/** * 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. * * Send an action frame immediately without doing channel synchronization. * * This function waits for a completion event before returning. * 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_if *ifp, struct brcmf_p2p_info *p2p, struct brcmf_fil_af_params_le *af_params)
{ struct brcmf_pub *drvr = p2p->cfg->pub;
s32 err = 0;
/* Add the default dwell time. Dwell time to stay off-channel */ /* to wait for a response action frame after transmitting an */ /* GO Negotiation action frame */
af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME);
if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) { /* p2p public action frame process */ if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) { /* Just send unknown subtype frame with */ /* default parameters. */
bphy_err(drvr, "P2P Public action frame, unknown subtype.\n");
}
} elseif (brcmf_p2p_is_gas_action(action_frame->data,
action_frame_len)) { /* service discovery process */ if (action == P2PSD_ACTION_ID_GAS_IREQ ||
action == P2PSD_ACTION_ID_GAS_CREQ) { /* configure service discovery query frame */
config_af_params.search_channel = true;
/* save next af suptype to cancel */ /* remaining dwell time */
p2p->next_af_subtype = action + 1;
af_params->dwell_time =
cpu_to_le32(P2P_AF_MED_DWELL_TIME);
} elseif (action == P2PSD_ACTION_ID_GAS_IRESP ||
action == P2PSD_ACTION_ID_GAS_CRESP) { /* configure service discovery response frame */
af_params->dwell_time =
cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
} else {
bphy_err(drvr, "Unknown action type: %d\n", action); gotoexit;
}
} elseif (brcmf_p2p_is_p2p_action(action_frame->data,
action_frame_len)) { /* do not configure anything. it will be */ /* sent with a default configuration */
} else {
bphy_err(drvr, "Unknown Frame: category 0x%x, action 0x%x\n",
category, action); returnfalse;
}
/* if connecting on primary iface, sleep for a while before sending * af tx for VSDB
*/ if (test_bit(BRCMF_VIF_STATUS_CONNECTING,
&p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state))
msleep(50);
/* if scan is ongoing, abort current scan. */ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
brcmf_abort_scanning(cfg);
/* To make sure to send successfully action frame, turn off mpc */ if (config_af_params.mpc_onoff == 0)
brcmf_set_mpc(ifp, 0);
/* set status and destination address before sending af */ if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { /* set status to cancel the remained dwell time in rx process */
set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
}
/* Abort scan even for VSDB scenarios. Scan gets aborted in * firmware but after the check of piggyback algorithm. To take * care of current piggback algo, lets abort the scan here * itself.
*/
brcmf_notify_escan_complete(cfg, ifp, true, true);
/* WAR: sometimes dongle does not keep the dwell time of 'actframe'. * if we coundn't get the next action response frame and dongle does * not keep the dwell time, go to listen state again to get next action * response frame.
*/ if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx &&
test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
p2p->af_sent_channel == afx_hdl->my_listen_chan) {
delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies); if (le32_to_cpu(af_params->dwell_time) > delta_ms)
extra_listen_time = le32_to_cpu(af_params->dwell_time) -
delta_ms; else
extra_listen_time = 0; if (extra_listen_time > 50) {
set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
&p2p->status);
brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n",
le32_to_cpu(af_params->dwell_time),
extra_listen_time);
extra_listen_time += 100; if (!brcmf_p2p_discover_listen(p2p,
p2p->af_sent_channel,
extra_listen_time)) { unsignedlong duration;
if (p2p->block_gon_req_tx) { /* if ack is true, supplicant will wait more time(100ms). * so we will return it as a success to get more time .
*/
p2p->block_gon_req_tx = false;
ack = true;
}
clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status); /* if all done, turn mpc on again */ if (config_af_params.mpc_onoff == 1)
brcmf_set_mpc(ifp, 1);
/* Firmware sends us two proberesponses for each idx one. At the */ /* moment anything but bsscfgidx 0 is passed up to supplicant */ if (e->bsscfgidx == 0) return 0;
/* Filter any P2P probe reqs arriving during the GO-NEG Phase */ if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) {
brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n"); return 0;
}
/* Check if wpa_supplicant has registered for this frame */
brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4; if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) return 0;
vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; if (!vif) {
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) {
bphy_err(drvr, "vif for P2PAPI_BSSCFG_CONNECTION does not exist\n"); return -EPERM;
}
brcmf_set_mpc(vif->ifp, 0);
/* In concurrency case, STA may be already associated in a particular */ /* channel. so retrieve the current channel of primary interface and */ /* then start the virtual interface on that. */
brcmf_p2p_get_current_chanspec(p2p, &chanspec);
/* firmware requires unique mac address for p2pdev interface */ if (addr && ether_addr_equal(addr, pri_ifp->mac_addr)) {
bphy_err(drvr, "discovery vif must be different from primary interface\n");
err = -EINVAL; goto fail;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.