本文主要介绍external/wpa_supplicant_8/src/p2p/p2p.c文件

先看下p2p_find 这个方法

P2P_find 主要用于 P2P(点对点)网络中查找其他对等方的功能。另外可以看到设置P2P模块的状态为 P2P_SEARCH
int p2p_find(struct p2p_data *p2p, unsigned int timeout, enum
p2p_discovery_type type, unsigned int num_req_dev_types, const u8
*req_dev_types, const u8 *dev_id, unsigned int search_delay, u8 seek_count,
const char **seek, int freq, bool include_6ghz) { int res; struct os_reltime
start; p2p_dbg(p2p, "Starting find (type=%d)", type); //确认P2P扫描已经可以使用 if
(p2p->p2p_scan_running) { p2p_dbg(p2p, "p2p_scan is already running"); }
p2p_free_req_dev_types(p2p); if (req_dev_types && num_req_dev_types) {
p2p->req_dev_types = os_memdup(req_dev_types, num_req_dev_types *
WPS_DEV_TYPE_LEN); if (p2p->req_dev_types == NULL) return -1;
p2p->num_req_dev_types = num_req_dev_types; } if (dev_id) {
os_memcpy(p2p->find_dev_id_buf, dev_id, ETH_ALEN); p2p->find_dev_id =
p2p->find_dev_id_buf; } else p2p->find_dev_id = NULL; p2p->include_6ghz =
p2p_wfd_enabled(p2p) && include_6ghz; if (seek_count == 0 || !seek) { /* Not an
ASP search */ p2p->p2ps_seek = 0; } else if (seek_count == 1 && seek &&
(!seek[0] || !seek[0][0])) { /* * An empty seek string means no hash values,
but still an ASP * search. */ p2p_dbg(p2p, "ASP search"); p2p->p2ps_seek_count
= 0; p2p->p2ps_seek = 1; } else if (seek && seek_count <= P2P_MAX_QUERY_HASH) {
u8 buf[P2PS_HASH_LEN]; int i, count = 0; for (i = 0; i < seek_count; i++) { if
(!p2ps_gen_hash(p2p, seek[i], buf)) continue; p2p_dbg(p2p, "Seek service %s
hash " MACSTR, seek[i], MAC2STR(buf)); os_memcpy(&p2p->p2ps_seek_hash[count *
P2PS_HASH_LEN], buf, P2PS_HASH_LEN); count++; } p2p->p2ps_seek_count = count;
p2p->p2ps_seek = 1; } else { p2p->p2ps_seek_count = 0; p2p->p2ps_seek = 1; } /*
Special case to perform wildcard search */ if (p2p->p2ps_seek_count == 0 &&
p2p->p2ps_seek) { p2p->p2ps_seek_count = 1; os_memcpy(&p2p->p2ps_seek_hash,
p2p->wild_card_hash, P2PS_HASH_LEN); }
//P2P_AFTER_SCAN_NOTHING表示P2P设备完成scan动作后,无需做其他动作 p2p->start_after_scan =
P2P_AFTER_SCAN_NOTHING; p2p_clear_timeout(p2p); if (p2p->pending_listen_freq) {
p2p_dbg(p2p, "Clear pending_listen_freq for p2p_find");
p2p->pending_listen_freq = 0; } //停止监听 p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p->find_pending_full = 0; p2p->find_type = type; if (freq != 2412 && freq !=
2437 && freq != 2462 && freq != 60480) p2p->find_specified_freq = freq; else
p2p->find_specified_freq = 0; p2p_device_clear_reported(p2p);
os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN); //设置P2P模块的状态为 P2P_SEARCH
p2p_set_state(p2p, P2P_SEARCH); p2p->search_delay = search_delay;
p2p->in_search_delay = 0; eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p->last_p2p_find_timeout = timeout; if (timeout) //注册一个扫描超时处理任务
eloop_register_timeout(timeout, 0, p2p_find_timeout, p2p, NULL);
os_get_reltime(&start); switch (type) { case P2P_FIND_START_WITH_FULL: if (freq
> 0) { /* * Start with the specified channel and then move to * scans for
social channels and this specific channel. */ res =
p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SPECIFIC, freq,
p2p->num_req_dev_types, p2p->req_dev_types, dev_id, DEV_PW_DEFAULT,
p2p->include_6ghz); break; } /* fall through */ case P2P_FIND_PROGRESSIVE:
//p2p_scan指向函数 wpas_p2p_scan res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,
P2P_SCAN_FULL, 0, p2p->num_req_dev_types, p2p->req_dev_types, dev_id,
DEV_PW_DEFAULT, p2p->include_6ghz); break; case P2P_FIND_ONLY_SOCIAL: res =
p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
p2p->num_req_dev_types, p2p->req_dev_types, dev_id, DEV_PW_DEFAULT,
p2p->include_6ghz); break; default: return -1; } if (!res) p2p->find_start =
start; if (res != 0 && p2p->p2p_scan_running) { p2p_dbg(p2p, "Failed to start
p2p_scan - another p2p_scan was already running"); /* wait for the previous
p2p_scan to complete */ if (type == P2P_FIND_PROGRESSIVE || (type ==
P2P_FIND_START_WITH_FULL && freq == 0)) p2p->find_pending_full = 1; res = 0; /*
do not report failure */ } else if (res != 0) { p2p_dbg(p2p, "Failed to start
p2p_scan"); p2p_set_state(p2p, P2P_IDLE);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); } return res; }

 接着看下P2P模块的状态为 P2P_SEARCH后如何进行进入listen状态

 也就是p2p_listen_in_find这个方法
static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc) { unsigned
int r, tu; int freq; struct wpabuf *ies; p2p_dbg(p2p, "Starting short listen
state (state=%s)", p2p_state_txt(p2p->state)); if (p2p->pending_listen_freq) {
/* We have a pending p2p_listen request */ p2p_dbg(p2p, "p2p_listen command
pending already"); return; } //根据
p2p_supplicant.conf中listen_channel等配置参数获取对应的频段 freq =
p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel); if (freq < 0) {
p2p_dbg(p2p, "Unknown regulatory class/channel"); return; } //计算需要在listen state
等待的时间 if (os_get_random((u8 *) &r, sizeof(r)) < 0) r = 0; tu = (r %
((p2p->max_disc_int - p2p->min_disc_int) + 1) + p2p->min_disc_int) * 100; if
(p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu) tu =
p2p->max_disc_tu; if (!dev_disc && tu < 100) tu = 100; /* Need to wait in
non-device discovery use cases */ if (p2p->cfg->max_listen && 1024 * tu / 1000
> p2p->cfg->max_listen) tu = p2p->cfg->max_listen * 1000 / 1024; if (tu == 0) {
p2p_dbg(p2p, "Skip listen state since duration was 0 TU"); p2p_set_timeout(p2p,
0, 0); return; } //构造P2P Probe Response帧,当我们在Listen state收到其他设备发来的Probe
Request帧后,wifi驱动将直接回复此处设置的 P2P Probe Response帧。 ies =
p2p_build_probe_resp_ies(p2p, NULL, 0); if (ies == NULL) return;
p2p->pending_listen_freq = freq; p2p->pending_listen_sec = 0;
p2p->pending_listen_usec = 1024 * tu; //start_listen指向 wpas_start_listen 函数 if
(p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000, ies) < 0) {
p2p_dbg(p2p, "Failed to start listen mode"); p2p->pending_listen_freq = 0; }
wpabuf_free(ies); }
在来看p2p_connect函数,其代码如下所示

这里面有3个重要的知识点

1、是
breaker值在每次发起P2P_CONNECT时都取反一次,这样做的目的是在双方的Intent值相同的情况下,多次协商时,双方都有机会做GO。并且在发送Request时才填入自己的breaker值,在回应Response时,是把对方的breaker值取反后作为breaker值发送。

2. 如果当前P2P还在扫描过程中,则设置start_after_scan为P2P_AFTER_SCAN_CONNECT标志,当scan结束后,在扫描结果处理流程中,该标志将通知P2P进入connect处理流程

3.   p2p_connect_send发送GON Request帧
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, enum p2p_wps_method
wps_method, int go_intent, const u8 *own_interface_addr, unsigned int
force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len,
int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id) { struct
p2p_device *dev; p2p_dbg(p2p, "Request to start group negotiation - peer="
MACSTR " GO Intent=%d Intended Interface Address=" MACSTR " wps_method=%d
persistent_group=%d pd_before_go_neg=%d " "oob_pw_id=%u allow_6ghz=%d",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr), wps_method,
persistent_group, pd_before_go_neg, oob_pw_id, p2p->allow_6ghz); //获取当前设备p2p
dev设备的信息 dev = p2p_get_device(p2p, peer_addr); if (dev == NULL || (dev->flags &
P2P_DEV_PROBE_REQ_ONLY)) { p2p_dbg(p2p, "Cannot connect to unknown P2P Device "
MACSTR, MAC2STR(peer_addr)); return -1; } // 如果指定了工作频段,则需要判断是否支持该工作频段,否则return
-1 if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent == 15) <
0) return -1; if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { if
(!(dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { p2p_dbg(p2p,
"Cannot connect to P2P Device " MACSTR " that is in a group and is not
discoverable", MAC2STR(peer_addr)); return -1; } if (dev->oper_freq <= 0) {
p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR " with incomplete
information", MAC2STR(peer_addr)); return -1; } /* * First, try to connect
directly. If the peer does not * acknowledge frames, assume it is sleeping and
use device * discoverability via the GO at that point. */ } p2p->ssid_set = 0;
if (force_ssid) { wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID", force_ssid,
force_ssid_len); os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
p2p->ssid_len = force_ssid_len; p2p->ssid_set = 1; } dev->flags &=
~P2P_DEV_NOT_YET_READY; dev->flags &= ~P2P_DEV_USER_REJECTED; dev->flags &=
~P2P_DEV_WAIT_GO_NEG_RESPONSE; dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM; if
(pd_before_go_neg) dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG; else { dev->flags &=
~P2P_DEV_PD_BEFORE_GO_NEG; /* * Assign dialog token and tie breaker here to use
the same * values in each retry within the same GO Negotiation exchange. */
dev->dialog_token++; if (dev->dialog_token == 0) dev->dialog_token = 1;
dev->tie_breaker = p2p->next_tie_breaker; p2p->next_tie_breaker =
!p2p->next_tie_breaker;//这里是对intent的值取反 } dev->connect_reqs = 0;
dev->go_neg_req_sent = 0; dev->go_state = UNKNOWN_GO;
p2p_set_dev_persistent(dev, persistent_group); p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); if (p2p->state !=
P2P_IDLE) p2p_stop_find(p2p); dev->wps_method = wps_method; dev->oob_pw_id =
oob_pw_id; dev->status = P2P_SC_SUCCESS; if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan running - delay connect send"); /*
如果当前P2P还在扫描过程中,则设置start_after_scan为P2P_AFTER_SCAN_CONNECT标志,
当scan结束后,在扫描结果处理流程中,该标志将通知P2P进入connect处理流程。 */ p2p->start_after_scan =
P2P_AFTER_SCAN_CONNECT; os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
return 0; } // 下面这个函数将发送GON Request帧 return p2p_connect_send(p2p, dev); }

p2p_set_state和p2p_set_timeout记录了P2P: State和Timeout
void p2p_set_state(struct p2p_data *p2p, int new_state) { p2p_dbg(p2p, "State
%s -> %s", p2p_state_txt(p2p->state), p2p_state_txt(new_state)); p2p->state =
new_state; if (new_state == P2P_IDLE && p2p->pending_channel) { p2p_dbg(p2p,
"Apply change in listen channel"); p2p->cfg->reg_class =
p2p->pending_reg_class; p2p->cfg->channel = p2p->pending_channel;
p2p->pending_reg_class = 0; p2p->pending_channel = 0; } } void
p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec) {
p2p_dbg(p2p, "Set timeout (state=%s): %u.%06u sec", p2p_state_txt(p2p->state),
sec, usec); eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL); }

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信