/* 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 */
/* In case of COB type, firmware has default mac address *AfterInitializingfirmware,wehavetosetcurrentmacaddressto *firmwareforP2Pdeviceaddress.Thismustbedonewithdiscovery *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);
if (!dev_addr || is_zero_ether_addr(dev_addr)) { /* If the primary interface address is already locally *administered,createanewrandomaddress.
*/ 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 *addresswiththelocallyadministeredbitset.
*/ 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 *BSSCFGsneedtosimultaneouslyco-exist,thenthisaddressmustbe *differentfromtheP2PDeviceAddress,butalsolocallyadministered.
*/
memcpy(p2p->conn_int_addr, p2p->dev_addr, ETH_ALEN);
p2p->conn_int_addr[0] |= 0x02;
p2p->conn_int_addr[4] ^= 0x80;
/* 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);
/* *SOCIAL_CHAN_CNT+1takescareoftheProgressivescan *supportedbythesupplicant.
*/ 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. *sendproberequestmorefrequently
*/
nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS;
} else {
nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS;
}
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_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);
}
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 *pendingactionframetxiscancelled.
*/
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 *retryaftxorfindingapeer
*/ 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);
}
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. *Soabortscanforoffchannelcompletion.
*/ 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);
}
}
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 *processpeer'sgonrequestandblocktosendgonreq. *ifnot(saaddr>daaddr), *thisdevicewillprocessgonrequestanddropgonreqofpeer.
*/
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, *donotscanmoretoblocktosendcurrentgonreq
*/ 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);
} return0;
} /* 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)) return0;
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_COMPLETEevent
*/
brcmf_p2p_stop_wait_next_action_frame(cfg);
}
/* 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");
}
} else if (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);
} else if (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);
goto exit;
}
} else if (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);
return false;
}
/* 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)) {
unsigned long 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;
}
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.
*
* @wiphy: wiphy device of new interface.
* @name: name of the new interface.
* @name_assign_type: origin of the interface name
* @type: nl80211 interface type.
* @params: contains mac address for P2P device.
*/
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
unsigned char name_assign_type,
enum nl80211_iftype type,
struct vif_params *params)
{
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 = 0;
int connidx;
u8 *p2p_intf_addr;
if (brcmf_cfg80211_vif_event_armed(cfg))
return ERR_PTR(-EBUSY);
iftype = vif->wdev.iftype;
brcmf_cfg80211_arm_vif_event(cfg, vif);
switch (iftype) {
case NL80211_IFTYPE_P2P_CLIENT:
if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
wait_for_disable = true;
break;
case NL80211_IFTYPE_P2P_GO:
if (!brcmf_p2p_disable_p2p_if(vif))
wait_for_disable = true;
break;
case NL80211_IFTYPE_P2P_DEVICE:
if (!p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
return 0;
brcmf_p2p_cancel_remain_on_channel(vif->ifp);
brcmf_p2p_deinit_discovery(p2p);
break;
default:
return -ENOTSUPP;
}
clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
if (wait_for_disable)
wait_for_completion_timeout(&cfg->vif_disabled,
BRCMF_P2P_DISABLE_TIMEOUT);
err = 0;
if (iftype != NL80211_IFTYPE_P2P_DEVICE) {
brcmf_vif_clear_mgmt_ies(vif);
err = brcmf_p2p_release_p2p_if(vif);
}
if (!err) {
/* wait for firmware event */
err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
BRCMF_VIF_EVENT_TIMEOUT);
if (!err)
err = -EIO;
else
err = 0;
}
brcmf_remove_interface(vif->ifp, true);
brcmf_cfg80211_arm_vif_event(cfg, 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;
}
vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
/* This call can be result of the unregister_wdev call. In that case
* we dont want to do anything anymore. Just return. The config vif
* will have been cleared at this point.
*/
if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == vif) {
mutex_lock(&cfg->usr_sync);
/* Set the discovery state to SCAN */
(void)brcmf_p2p_set_discover_state(vif->ifp,
WL_P2P_DISC_ST_SCAN, 0, 0);
brcmf_abort_scanning(cfg);
clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
mutex_unlock(&cfg->usr_sync);
}
}
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
if (vif != NULL) {
brcmf_p2p_cancel_remain_on_channel(vif->ifp);
brcmf_p2p_deinit_discovery(p2p);
brcmf_remove_interface(vif->ifp, false);
}
/* just set it all to zero */
memset(p2p, 0, sizeof(*p2p));
}
Messung V0.5 in Prozent
¤ 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.0.154Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-12)
¤
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.