P2P: Allow P2P listen being offloaded to the driver/firmware
This allows P2P Listen to be offloaded to device to enhance power saving. To start P2P listen offload, from wpa_cli interface, issue the command: p2p_lo_start <freq> <period> <interval> <count> To stop P2P listen offload, issue the command: p2p_lo_stop Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
35d6655755
commit
a6f5b1937a
15 changed files with 436 additions and 43 deletions
|
@ -271,6 +271,9 @@ extern "C" {
|
||||||
|
|
||||||
#define AP_CSA_FINISHED "AP-CSA-FINISHED "
|
#define AP_CSA_FINISHED "AP-CSA-FINISHED "
|
||||||
|
|
||||||
|
#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED "
|
||||||
|
#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON "
|
||||||
|
|
||||||
/* BSS Transition Management Response frame received */
|
/* BSS Transition Management Response frame received */
|
||||||
#define BSS_TM_RESP "BSS-TM-RESP "
|
#define BSS_TM_RESP "BSS-TM-RESP "
|
||||||
|
|
||||||
|
|
|
@ -1278,6 +1278,8 @@ struct wpa_driver_capa {
|
||||||
#define WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS 0x0000008000000000ULL
|
#define WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS 0x0000008000000000ULL
|
||||||
/** Driver supports full AP client state */
|
/** Driver supports full AP client state */
|
||||||
#define WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE 0x0000010000000000ULL
|
#define WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE 0x0000010000000000ULL
|
||||||
|
/** Driver supports P2P Listen offload */
|
||||||
|
#define WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD 0x0000020000000000ULL
|
||||||
u64 flags;
|
u64 flags;
|
||||||
|
|
||||||
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
|
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
|
||||||
|
@ -3573,6 +3575,32 @@ struct wpa_driver_ops {
|
||||||
int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type,
|
int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type,
|
||||||
const u8 **ext_capab, const u8 **ext_capab_mask,
|
const u8 **ext_capab, const u8 **ext_capab_mask,
|
||||||
unsigned int *ext_capab_len);
|
unsigned int *ext_capab_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* p2p_lo_start - Start offloading P2P listen to device
|
||||||
|
* @priv: Private driver interface data
|
||||||
|
* @freq: Listening frequency (MHz) for P2P listen
|
||||||
|
* @period: Length of the listen operation in milliseconds
|
||||||
|
* @interval: Interval for running the listen operation in milliseconds
|
||||||
|
* @count: Number of times to run the listen operation
|
||||||
|
* @device_types: Device primary and secondary types
|
||||||
|
* @dev_types_len: Number of bytes for device_types
|
||||||
|
* @ies: P2P IE and WSC IE for Probe Response frames
|
||||||
|
* @ies_len: Length of ies in bytes
|
||||||
|
* Returns: 0 on success or -1 on failure
|
||||||
|
*/
|
||||||
|
int (*p2p_lo_start)(void *priv, unsigned int freq,
|
||||||
|
unsigned int period, unsigned int interval,
|
||||||
|
unsigned int count,
|
||||||
|
const u8 *device_types, size_t dev_types_len,
|
||||||
|
const u8 *ies, size_t ies_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* p2p_lo_stop - Stop P2P listen offload
|
||||||
|
* @priv: Private driver interface data
|
||||||
|
* Returns: 0 on success or -1 on failure
|
||||||
|
*/
|
||||||
|
int (*p2p_lo_stop)(void *priv);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -4057,6 +4085,11 @@ enum wpa_event_type {
|
||||||
* on a DFS frequency by a driver that supports DFS Offload.
|
* on a DFS frequency by a driver that supports DFS Offload.
|
||||||
*/
|
*/
|
||||||
EVENT_DFS_CAC_STARTED,
|
EVENT_DFS_CAC_STARTED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EVENT_P2P_LO_STOP - Notify that P2P listen offload is stopped
|
||||||
|
*/
|
||||||
|
EVENT_P2P_LO_STOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -4782,6 +4815,27 @@ union wpa_event_data {
|
||||||
u16 ch_width;
|
u16 ch_width;
|
||||||
enum hostapd_hw_mode hw_mode;
|
enum hostapd_hw_mode hw_mode;
|
||||||
} acs_selected_channels;
|
} acs_selected_channels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct p2p_lo_stop - Reason code for P2P Listen offload stop event
|
||||||
|
* @reason_code: Reason for stopping offload
|
||||||
|
* P2P_LO_STOPPED_REASON_COMPLETE: Listen offload finished as
|
||||||
|
* scheduled.
|
||||||
|
* P2P_LO_STOPPED_REASON_RECV_STOP_CMD: Host requested offload to
|
||||||
|
* be stopped.
|
||||||
|
* P2P_LO_STOPPED_REASON_INVALID_PARAM: Invalid listen offload
|
||||||
|
* parameters.
|
||||||
|
* P2P_LO_STOPPED_REASON_NOT_SUPPORTED: Listen offload not
|
||||||
|
* supported by device.
|
||||||
|
*/
|
||||||
|
struct p2p_lo_stop {
|
||||||
|
enum {
|
||||||
|
P2P_LO_STOPPED_REASON_COMPLETE = 0,
|
||||||
|
P2P_LO_STOPPED_REASON_RECV_STOP_CMD,
|
||||||
|
P2P_LO_STOPPED_REASON_INVALID_PARAM,
|
||||||
|
P2P_LO_STOPPED_REASON_NOT_SUPPORTED,
|
||||||
|
} reason_code;
|
||||||
|
} p2p_lo_stop;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -80,6 +80,7 @@ const char * event_to_string(enum wpa_event_type event)
|
||||||
E2S(NEW_PEER_CANDIDATE);
|
E2S(NEW_PEER_CANDIDATE);
|
||||||
E2S(ACS_CHANNEL_SELECTED);
|
E2S(ACS_CHANNEL_SELECTED);
|
||||||
E2S(DFS_CAC_STARTED);
|
E2S(DFS_CAC_STARTED);
|
||||||
|
E2S(P2P_LO_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
|
|
|
@ -9117,6 +9117,89 @@ static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
|
||||||
|
unsigned int period, unsigned int interval,
|
||||||
|
unsigned int count, const u8 *device_types,
|
||||||
|
size_t dev_types_len,
|
||||||
|
const u8 *ies, size_t ies_len)
|
||||||
|
{
|
||||||
|
struct i802_bss *bss = priv;
|
||||||
|
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||||
|
struct nl_msg *msg;
|
||||||
|
struct nlattr *container;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
|
||||||
|
freq, period, interval, count);
|
||||||
|
|
||||||
|
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
|
||||||
|
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
|
||||||
|
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
|
||||||
|
QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
|
||||||
|
if (!container)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
|
||||||
|
freq) ||
|
||||||
|
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
|
||||||
|
period) ||
|
||||||
|
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
|
||||||
|
interval) ||
|
||||||
|
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
|
||||||
|
count) ||
|
||||||
|
nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
|
||||||
|
dev_types_len, device_types) ||
|
||||||
|
nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
|
||||||
|
ies_len, ies))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
nla_nest_end(msg, container);
|
||||||
|
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
||||||
|
msg = NULL;
|
||||||
|
if (ret) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"nl80211: Failed to send P2P Listen offload vendor command");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
nlmsg_free(msg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int nl80211_p2p_lo_stop(void *priv)
|
||||||
|
{
|
||||||
|
struct i802_bss *bss = priv;
|
||||||
|
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||||
|
struct nl_msg *msg;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
|
||||||
|
|
||||||
|
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
|
||||||
|
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
|
||||||
|
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
|
||||||
|
QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP)) {
|
||||||
|
nlmsg_free(msg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return send_and_recv_msgs(drv, msg, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
||||||
|
|
||||||
|
|
||||||
|
@ -9357,6 +9440,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
.set_band = nl80211_set_band,
|
.set_band = nl80211_set_band,
|
||||||
.get_pref_freq_list = nl80211_get_pref_freq_list,
|
.get_pref_freq_list = nl80211_get_pref_freq_list,
|
||||||
.set_prob_oper_freq = nl80211_set_prob_oper_freq,
|
.set_prob_oper_freq = nl80211_set_prob_oper_freq,
|
||||||
|
.p2p_lo_start = nl80211_p2p_lo_start,
|
||||||
|
.p2p_lo_stop = nl80211_p2p_lo_stop,
|
||||||
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
||||||
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
|
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
|
||||||
.get_ext_capab = nl80211_get_ext_capab,
|
.get_ext_capab = nl80211_get_ext_capab,
|
||||||
|
|
|
@ -972,6 +972,8 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
|
||||||
if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS,
|
if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS,
|
||||||
&info))
|
&info))
|
||||||
drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
|
drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
|
||||||
|
if (check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD, &info))
|
||||||
|
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD;
|
||||||
os_free(info.flags);
|
os_free(info.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1876,6 +1876,31 @@ static void qca_nl80211_scan_done_event(struct wpa_driver_nl80211_data *drv,
|
||||||
external_scan);
|
external_scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv,
|
||||||
|
u8 *data, size_t len)
|
||||||
|
{
|
||||||
|
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1];
|
||||||
|
union wpa_event_data event;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"nl80211: P2P listen offload stop vendor event received");
|
||||||
|
|
||||||
|
if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX,
|
||||||
|
(struct nlattr *) data, len, NULL) ||
|
||||||
|
!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON])
|
||||||
|
return;
|
||||||
|
|
||||||
|
os_memset(&event, 0, sizeof(event));
|
||||||
|
event.p2p_lo_stop.reason_code =
|
||||||
|
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"nl80211: P2P Listen offload stop reason: %d",
|
||||||
|
event.p2p_lo_stop.reason_code);
|
||||||
|
wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
||||||
|
|
||||||
|
|
||||||
|
@ -1909,6 +1934,9 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
|
||||||
case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE:
|
case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE:
|
||||||
qca_nl80211_scan_done_event(drv, data, len);
|
qca_nl80211_scan_done_event(drv, data, len);
|
||||||
break;
|
break;
|
||||||
|
case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP:
|
||||||
|
qca_nl80211_p2p_lo_stop_event(drv, data, len);
|
||||||
|
break;
|
||||||
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
||||||
default:
|
default:
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
|
|
132
src/p2p/p2p.c
132
src/p2p/p2p.c
|
@ -2234,6 +2234,58 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int p2p_build_probe_resp_buf(struct p2p_data *p2p, struct wpabuf *buf,
|
||||||
|
struct wpabuf *ies,
|
||||||
|
const u8 *addr, int rx_freq)
|
||||||
|
{
|
||||||
|
struct ieee80211_mgmt *resp;
|
||||||
|
u8 channel, op_class;
|
||||||
|
|
||||||
|
resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
|
||||||
|
u.probe_resp.variable));
|
||||||
|
|
||||||
|
resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
|
||||||
|
(WLAN_FC_STYPE_PROBE_RESP << 4));
|
||||||
|
os_memcpy(resp->da, addr, ETH_ALEN);
|
||||||
|
os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
|
||||||
|
os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
|
||||||
|
resp->u.probe_resp.beacon_int = host_to_le16(100);
|
||||||
|
/* hardware or low-level driver will setup seq_ctrl and timestamp */
|
||||||
|
resp->u.probe_resp.capab_info =
|
||||||
|
host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
|
||||||
|
WLAN_CAPABILITY_PRIVACY |
|
||||||
|
WLAN_CAPABILITY_SHORT_SLOT_TIME);
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, WLAN_EID_SSID);
|
||||||
|
wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
|
||||||
|
wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
|
||||||
|
wpabuf_put_u8(buf, 8);
|
||||||
|
wpabuf_put_u8(buf, (60 / 5) | 0x80);
|
||||||
|
wpabuf_put_u8(buf, 90 / 5);
|
||||||
|
wpabuf_put_u8(buf, (120 / 5) | 0x80);
|
||||||
|
wpabuf_put_u8(buf, 180 / 5);
|
||||||
|
wpabuf_put_u8(buf, (240 / 5) | 0x80);
|
||||||
|
wpabuf_put_u8(buf, 360 / 5);
|
||||||
|
wpabuf_put_u8(buf, 480 / 5);
|
||||||
|
wpabuf_put_u8(buf, 540 / 5);
|
||||||
|
|
||||||
|
if (!rx_freq) {
|
||||||
|
channel = p2p->cfg->channel;
|
||||||
|
} else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
|
||||||
|
p2p_err(p2p, "Failed to convert freq to channel");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
|
||||||
|
wpabuf_put_u8(buf, 1);
|
||||||
|
wpabuf_put_u8(buf, channel);
|
||||||
|
|
||||||
|
wpabuf_put_buf(buf, ies);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
|
static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
|
||||||
{
|
{
|
||||||
|
@ -2267,10 +2319,8 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
{
|
{
|
||||||
struct ieee802_11_elems elems;
|
struct ieee802_11_elems elems;
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
struct ieee80211_mgmt *resp;
|
|
||||||
struct p2p_message msg;
|
struct p2p_message msg;
|
||||||
struct wpabuf *ies;
|
struct wpabuf *ies;
|
||||||
u8 channel, op_class;
|
|
||||||
|
|
||||||
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
|
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
|
||||||
ParseFailed) {
|
ParseFailed) {
|
||||||
|
@ -2414,49 +2464,12 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
return P2P_PREQ_NOT_PROCESSED;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
|
if (p2p_build_probe_resp_buf(p2p, buf, ies, addr, rx_freq)) {
|
||||||
u.probe_resp.variable));
|
|
||||||
|
|
||||||
resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
|
|
||||||
(WLAN_FC_STYPE_PROBE_RESP << 4));
|
|
||||||
os_memcpy(resp->da, addr, ETH_ALEN);
|
|
||||||
os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
|
|
||||||
os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
|
|
||||||
resp->u.probe_resp.beacon_int = host_to_le16(100);
|
|
||||||
/* hardware or low-level driver will setup seq_ctrl and timestamp */
|
|
||||||
resp->u.probe_resp.capab_info =
|
|
||||||
host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
|
|
||||||
WLAN_CAPABILITY_PRIVACY |
|
|
||||||
WLAN_CAPABILITY_SHORT_SLOT_TIME);
|
|
||||||
|
|
||||||
wpabuf_put_u8(buf, WLAN_EID_SSID);
|
|
||||||
wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
|
|
||||||
wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
|
|
||||||
|
|
||||||
wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
|
|
||||||
wpabuf_put_u8(buf, 8);
|
|
||||||
wpabuf_put_u8(buf, (60 / 5) | 0x80);
|
|
||||||
wpabuf_put_u8(buf, 90 / 5);
|
|
||||||
wpabuf_put_u8(buf, (120 / 5) | 0x80);
|
|
||||||
wpabuf_put_u8(buf, 180 / 5);
|
|
||||||
wpabuf_put_u8(buf, (240 / 5) | 0x80);
|
|
||||||
wpabuf_put_u8(buf, 360 / 5);
|
|
||||||
wpabuf_put_u8(buf, 480 / 5);
|
|
||||||
wpabuf_put_u8(buf, 540 / 5);
|
|
||||||
|
|
||||||
if (!rx_freq) {
|
|
||||||
channel = p2p->cfg->channel;
|
|
||||||
} else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
|
|
||||||
wpabuf_free(ies);
|
wpabuf_free(ies);
|
||||||
wpabuf_free(buf);
|
wpabuf_free(buf);
|
||||||
return P2P_PREQ_NOT_PROCESSED;
|
return P2P_PREQ_NOT_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
|
|
||||||
wpabuf_put_u8(buf, 1);
|
|
||||||
wpabuf_put_u8(buf, channel);
|
|
||||||
|
|
||||||
wpabuf_put_buf(buf, ies);
|
|
||||||
wpabuf_free(ies);
|
wpabuf_free(ies);
|
||||||
|
|
||||||
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
|
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
|
||||||
|
@ -2470,12 +2483,18 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
enum p2p_probe_req_status
|
enum p2p_probe_req_status
|
||||||
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
const u8 *bssid, const u8 *ie, size_t ie_len,
|
const u8 *bssid, const u8 *ie, size_t ie_len,
|
||||||
unsigned int rx_freq)
|
unsigned int rx_freq, int p2p_lo_started)
|
||||||
{
|
{
|
||||||
enum p2p_probe_req_status res;
|
enum p2p_probe_req_status res;
|
||||||
|
|
||||||
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
|
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
|
||||||
|
|
||||||
|
if (p2p_lo_started) {
|
||||||
|
p2p_dbg(p2p,
|
||||||
|
"Probe Response is offloaded, do not reply Probe Request");
|
||||||
|
return P2P_PREQ_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
|
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
|
||||||
if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
|
if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
|
||||||
return res;
|
return res;
|
||||||
|
@ -5490,3 +5509,34 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
|
||||||
i, p2p->pref_freq_list[i]);
|
i, p2p->pref_freq_list[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
|
||||||
|
unsigned int freq)
|
||||||
|
{
|
||||||
|
struct wpabuf *ies, *buf;
|
||||||
|
u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
|
||||||
|
if (!ies) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"CTRL: Failed to build Probe Response IEs");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(200 + wpabuf_len(ies));
|
||||||
|
if (!buf) {
|
||||||
|
wpabuf_free(ies);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = p2p_build_probe_resp_buf(p2p, buf, ies, addr, freq);
|
||||||
|
wpabuf_free(ies);
|
||||||
|
if (ret) {
|
||||||
|
wpabuf_free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
|
@ -1555,12 +1555,13 @@ enum p2p_probe_req_status {
|
||||||
* @ie: Information elements from the Probe Request frame body
|
* @ie: Information elements from the Probe Request frame body
|
||||||
* @ie_len: Length of ie buffer in octets
|
* @ie_len: Length of ie buffer in octets
|
||||||
* @rx_freq: Probe Request frame RX frequency
|
* @rx_freq: Probe Request frame RX frequency
|
||||||
|
* @p2p_lo_started: Whether P2P Listen Offload is started
|
||||||
* Returns: value indicating the type and status of the probe request
|
* Returns: value indicating the type and status of the probe request
|
||||||
*/
|
*/
|
||||||
enum p2p_probe_req_status
|
enum p2p_probe_req_status
|
||||||
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
|
||||||
const u8 *bssid, const u8 *ie, size_t ie_len,
|
const u8 *bssid, const u8 *ie, size_t ie_len,
|
||||||
unsigned int rx_freq);
|
unsigned int rx_freq, int p2p_lo_started);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* p2p_rx_action - Report received Action frame
|
* p2p_rx_action - Report received Action frame
|
||||||
|
@ -2383,4 +2384,7 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
|
||||||
int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
|
int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
|
||||||
unsigned int *num);
|
unsigned int *num);
|
||||||
|
|
||||||
|
struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
|
||||||
|
unsigned int freq);
|
||||||
|
|
||||||
#endif /* P2P_H */
|
#endif /* P2P_H */
|
||||||
|
|
|
@ -6283,6 +6283,21 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
|
||||||
|
{
|
||||||
|
int freq = 0, period = 0, interval = 0, count = 0;
|
||||||
|
|
||||||
|
if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
|
|
||||||
|
@ -8968,6 +8983,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
||||||
} else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
|
} else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
|
||||||
if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
|
if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
|
} else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
|
||||||
|
if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
|
||||||
|
reply_len = -1;
|
||||||
|
} else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
|
||||||
|
if (wpas_p2p_lo_stop(wpa_s))
|
||||||
|
reply_len = -1;
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
#ifdef CONFIG_WIFI_DISPLAY
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
|
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
|
||||||
|
|
|
@ -946,4 +946,27 @@ static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s,
|
||||||
&wpa_s->extended_capa_len);
|
&wpa_s->extended_capa_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s,
|
||||||
|
unsigned int channel,
|
||||||
|
unsigned int period,
|
||||||
|
unsigned int interval,
|
||||||
|
unsigned int count,
|
||||||
|
const u8 *device_types,
|
||||||
|
size_t dev_types_len,
|
||||||
|
const u8 *ies, size_t ies_len)
|
||||||
|
{
|
||||||
|
if (!wpa_s->driver->p2p_lo_start)
|
||||||
|
return -1;
|
||||||
|
return wpa_s->driver->p2p_lo_start(wpa_s->drv_priv, channel, period,
|
||||||
|
interval, count, device_types,
|
||||||
|
dev_types_len, ies, ies_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
if (!wpa_s->driver->p2p_lo_stop)
|
||||||
|
return -1;
|
||||||
|
return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* DRIVER_I_H */
|
#endif /* DRIVER_I_H */
|
||||||
|
|
|
@ -4067,6 +4067,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
&data->acs_selected_channels);
|
&data->acs_selected_channels);
|
||||||
#endif /* CONFIG_ACS */
|
#endif /* CONFIG_ACS */
|
||||||
break;
|
break;
|
||||||
|
case EVENT_P2P_LO_STOP:
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
|
wpa_s->p2p_lo_started = 0;
|
||||||
|
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_LISTEN_OFFLOAD_STOP
|
||||||
|
P2P_LISTEN_OFFLOAD_STOP_REASON "reason=%d",
|
||||||
|
data->p2p_lo_stop.reason_code);
|
||||||
|
#endif /* CONFIG_P2P */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
|
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -6632,6 +6632,12 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
|
||||||
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
|
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (wpa_s->p2p_lo_started) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"P2P: Cannot start P2P listen, it is offloaded");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_supplicant_cancel_sched_scan(wpa_s);
|
wpa_supplicant_cancel_sched_scan(wpa_s);
|
||||||
wpas_p2p_clear_pending_action_tx(wpa_s);
|
wpas_p2p_clear_pending_action_tx(wpa_s);
|
||||||
|
|
||||||
|
@ -6705,7 +6711,7 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
|
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
|
||||||
ie, ie_len, rx_freq)) {
|
ie, ie_len, rx_freq, wpa_s->p2p_lo_started)) {
|
||||||
case P2P_PREQ_NOT_P2P:
|
case P2P_PREQ_NOT_P2P:
|
||||||
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
|
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
|
||||||
ssi_signal);
|
ssi_signal);
|
||||||
|
@ -9206,3 +9212,86 @@ void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
|
||||||
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
|
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
|
||||||
wpas_p2p_group_deinit(wpa_s);
|
wpas_p2p_group_deinit(wpa_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
|
||||||
|
unsigned int period, unsigned int interval,
|
||||||
|
unsigned int count)
|
||||||
|
{
|
||||||
|
struct p2p_data *p2p = wpa_s->global->p2p;
|
||||||
|
u8 *device_types;
|
||||||
|
size_t dev_types_len;
|
||||||
|
struct wpabuf *buf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (wpa_s->p2p_lo_started) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
|
"P2P Listen offload is already started");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wpa_s->global->p2p == NULL ||
|
||||||
|
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "P2P: Listen offload not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
|
||||||
|
wpa_printf(MSG_ERROR, "P2P: Input channel not supported: %u",
|
||||||
|
freq);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get device type */
|
||||||
|
dev_types_len = (wpa_s->conf->num_sec_device_types + 1) *
|
||||||
|
WPS_DEV_TYPE_LEN;
|
||||||
|
device_types = os_malloc(dev_types_len);
|
||||||
|
if (!device_types)
|
||||||
|
return -1;
|
||||||
|
os_memcpy(device_types, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN);
|
||||||
|
os_memcpy(&device_types[WPS_DEV_TYPE_LEN], wpa_s->conf->sec_device_type,
|
||||||
|
wpa_s->conf->num_sec_device_types * WPS_DEV_TYPE_LEN);
|
||||||
|
|
||||||
|
/* Get Probe Response IE(s) */
|
||||||
|
buf = p2p_build_probe_resp_template(p2p, freq);
|
||||||
|
if (!buf) {
|
||||||
|
os_free(device_types);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wpa_drv_p2p_lo_start(wpa_s, freq, period, interval, count,
|
||||||
|
device_types, dev_types_len,
|
||||||
|
wpabuf_mhead_u8(buf), wpabuf_len(buf));
|
||||||
|
if (ret < 0)
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
|
"P2P: Failed to start P2P listen offload");
|
||||||
|
|
||||||
|
os_free(device_types);
|
||||||
|
wpabuf_free(buf);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
wpa_s->p2p_lo_started = 1;
|
||||||
|
|
||||||
|
/* Stop current P2P listen if any */
|
||||||
|
wpas_stop_listen(wpa_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!wpa_s->p2p_lo_started)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = wpa_drv_p2p_lo_stop(wpa_s);
|
||||||
|
if (ret < 0)
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
|
"P2P: Failed to stop P2P listen offload");
|
||||||
|
|
||||||
|
wpa_s->p2p_lo_started = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -207,6 +207,10 @@ int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
|
||||||
void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
|
void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
|
||||||
struct wps_event_fail *fail);
|
struct wps_event_fail *fail);
|
||||||
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
|
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
|
||||||
|
int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
|
||||||
|
unsigned int period, unsigned int interval,
|
||||||
|
unsigned int count);
|
||||||
|
int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
|
||||||
|
|
||||||
#else /* CONFIG_P2P */
|
#else /* CONFIG_P2P */
|
||||||
|
|
||||||
|
|
|
@ -2892,6 +2892,20 @@ static int wpa_cli_cmd_get_pref_freq_list(struct wpa_ctrl *ctrl, int argc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum wpa_cli_cmd_flags {
|
enum wpa_cli_cmd_flags {
|
||||||
cli_cmd_flag_none = 0x00,
|
cli_cmd_flag_none = 0x00,
|
||||||
cli_cmd_flag_sensitive = 0x01
|
cli_cmd_flag_sensitive = 0x01
|
||||||
|
@ -3477,6 +3491,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
|
||||||
{ "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL,
|
{ "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL,
|
||||||
cli_cmd_flag_none,
|
cli_cmd_flag_none,
|
||||||
"<interface type> = retrieve preferred freq list for the specified interface type" },
|
"<interface type> = retrieve preferred freq list for the specified interface type" },
|
||||||
|
{ "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL,
|
||||||
|
cli_cmd_flag_none,
|
||||||
|
"<freq> <period> <interval> <count> = start P2P listen offload" },
|
||||||
|
{ "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL,
|
||||||
|
cli_cmd_flag_none,
|
||||||
|
"= stop P2P listen offload" },
|
||||||
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
|
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -893,6 +893,7 @@ struct wpa_supplicant {
|
||||||
|
|
||||||
unsigned int p2p_go_max_oper_chwidth;
|
unsigned int p2p_go_max_oper_chwidth;
|
||||||
unsigned int p2p_go_vht_center_freq2;
|
unsigned int p2p_go_vht_center_freq2;
|
||||||
|
int p2p_lo_started;
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
struct wpa_ssid *bgscan_ssid;
|
struct wpa_ssid *bgscan_ssid;
|
||||||
|
|
Loading…
Reference in a new issue