NULL);
if (!wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+ wpa_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report");
return;
}
return;
}
wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
- wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
- report[0]);
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+ report[0]);
wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
neighbor_rep);
wpa_s->rrm.notify_neighbor_rep = NULL;
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
/* Workaround different, undefined for Windows, error codes used here */
+#ifndef ENOTCONN
#define ENOTCONN -1
+#endif
+#ifndef EOPNOTSUPP
#define EOPNOTSUPP -1
+#endif
+#ifndef ECANCELED
#define ECANCELED -1
#endif
+#endif
/* Measurement Request element + Location Subject + Maximum Age subelement */
#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
const u8 *rrm_ie;
if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
- wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No connection, no RRM.");
return -ENOTCONN;
}
if (!wpa_s->rrm.rrm_used) {
- wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No RRM in current connection.");
return -EOPNOTSUPP;
}
WLAN_EID_RRM_ENABLED_CAPABILITIES);
if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
!(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
- wpa_printf(MSG_DEBUG,
- "RRM: No network support for Neighbor Report.");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: No network support for Neighbor Report.");
return -EOPNOTSUPP;
}
- if (!cb) {
- wpa_printf(MSG_DEBUG,
- "RRM: Neighbor Report request must provide a callback.");
- return -EINVAL;
- }
-
/* Refuse if there's a live request */
if (wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_DEBUG,
- "RRM: Currently handling previous Neighbor Report.");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Currently handling previous Neighbor Report.");
return -EBUSY;
}
(lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
(civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
if (buf == NULL) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to allocate Neighbor Report Request");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Failed to allocate Neighbor Report Request");
return -ENOMEM;
}
- wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
- (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
- wpa_s->rrm.next_neighbor_rep_token);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Neighbor report request (for %s), token=%d",
+ (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+ wpa_s->rrm.next_neighbor_rep_token);
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to send Neighbor Report Request");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Failed to send Neighbor Report Request");
wpabuf_free(buf);
return -ECANCELED;
}
}
-static int wpas_rrm_report_elem(struct wpabuf *buf, u8 token, u8 mode, u8 type,
+static int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type,
const u8 *data, size_t data_len)
{
- if (wpabuf_tailroom(buf) < 5 + data_len)
+ if (wpabuf_resize(buf, 5 + data_len))
return -1;
- wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
- wpabuf_put_u8(buf, 3 + data_len);
- wpabuf_put_u8(buf, token);
- wpabuf_put_u8(buf, mode);
- wpabuf_put_u8(buf, type);
+ wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(*buf, 3 + data_len);
+ wpabuf_put_u8(*buf, token);
+ wpabuf_put_u8(*buf, mode);
+ wpabuf_put_u8(*buf, type);
if (data_len)
- wpabuf_put_data(buf, data, data_len);
+ wpabuf_put_data(*buf, data, data_len);
return 0;
}
if (max_age != 0xffff && max_age < diff_l)
goto reject;
- if (wpabuf_resize(buf, 5 + wpabuf_len(wpa_s->lci)))
- return -1;
-
- if (wpas_rrm_report_elem(*buf, req->token,
+ if (wpas_rrm_report_elem(buf, req->token,
MEASUREMENT_REPORT_MODE_ACCEPT, req->type,
wpabuf_head_u8(wpa_s->lci),
wpabuf_len(wpa_s->lci)) < 0) {
return 0;
reject:
- if (wpabuf_resize(buf, sizeof(struct rrm_measurement_report_element))) {
- wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
- return -1;
- }
-
- if (wpas_rrm_report_elem(*buf, req->token,
+ if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
+ wpas_rrm_report_elem(buf, req->token,
MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
req->type, NULL, 0) < 0) {
wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
}
+static int wpas_rrm_beacon_rep_update_last_frame(u8 *pos, size_t len)
+{
+ struct rrm_measurement_report_element *msr_rep;
+ u8 *end = pos + len;
+ u8 *msr_rep_end;
+ struct rrm_measurement_beacon_report *rep = NULL;
+ u8 *subelem;
+
+ /* Find the last beacon report element */
+ while (end - pos >= (int) sizeof(*msr_rep)) {
+ msr_rep = (struct rrm_measurement_report_element *) pos;
+ msr_rep_end = pos + msr_rep->len + 2;
+
+ if (msr_rep->eid != WLAN_EID_MEASURE_REPORT ||
+ msr_rep_end > end) {
+ /* Should not happen. This indicates a bug. */
+ wpa_printf(MSG_ERROR,
+ "RRM: non-measurement report element in measurement report frame");
+ return -1;
+ }
+
+ if (msr_rep->type == MEASURE_TYPE_BEACON)
+ rep = (struct rrm_measurement_beacon_report *)
+ msr_rep->variable;
+
+ pos += pos[1] + 2;
+ }
+
+ if (!rep)
+ return 0;
+
+ subelem = rep->variable;
+ while (subelem + 2 < msr_rep_end &&
+ subelem[0] != WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION)
+ subelem += 2 + subelem[1];
+
+ if (subelem + 2 < msr_rep_end &&
+ subelem[0] == WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION &&
+ subelem[1] == 1 &&
+ subelem + BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN <= end)
+ subelem[2] = 1;
+
+ return 0;
+}
+
+
static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s,
struct wpabuf *buf)
{
int len = wpabuf_len(buf);
- const u8 *pos = wpabuf_head_u8(buf), *next = pos;
+ u8 *pos = wpabuf_mhead_u8(buf), *next = pos;
#define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3)
while (len) {
int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len;
+ if (send_len == len)
+ wpas_rrm_beacon_rep_update_last_frame(pos, len);
+
if (send_len == len ||
(send_len + next[1] + 2) > MPDU_REPORT_LEN) {
wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len);
pos = next;
}
- next += next[1] + 2;
+ if (len)
+ next += next[1] + 2;
}
#undef MPDU_REPORT_LEN
}
u8 primary_chan = chan - (2 * num_primary_channels - 2) + i * 4;
freqs[i] = ieee80211_chan_to_freq(NULL, op_class, primary_chan);
+ /* ieee80211_chan_to_freq() is not really meant for this
+ * conversion of 20 MHz primary channel numbers for wider VHT
+ * channels, so handle those as special cases here for now. */
+ if (freqs[i] < 0 &&
+ (op_class == 128 || op_class == 129 || op_class == 130))
+ freqs[i] = 5000 + 5 * primary_chan;
if (freqs[i] < 0) {
wpa_printf(MSG_DEBUG,
"Beacon Report: Invalid channel %u",
next_freq = freqs;
for (i = 0; i < num_chans; i++) {
u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
- enum chan_allowed res = verify_channel(mode, chan, op->bw);
+ enum chan_allowed res = verify_channel(mode, op->op_class, chan,
+ op->bw);
if (res == NOT_ALLOWED || (res == NO_IR && active))
continue;
pos++;
left--;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+ is_6ghz_op_class(op->op_class));
if (!mode)
continue;
return NULL;
}
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+ is_6ghz_op_class(op->op_class));
if (!mode)
return NULL;
if (ext_freqs) {
int_array_concat(&freqs, ext_freqs);
os_free(ext_freqs);
+ int_array_sort_unique(freqs);
}
return freqs;
}
-int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
- u8 *op_class, u8 *chan, u8 *phy_type)
+static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type)
{
const u8 *ie;
int sec_chan = 0, vht = 0;
seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx;
seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx;
if (seg1 && abs(seg1 - seg0) == 8)
- vht = VHT_CHANWIDTH_160MHZ;
+ vht = CHANWIDTH_160MHZ;
else if (seg1)
- vht = VHT_CHANWIDTH_80P80MHZ;
+ vht = CHANWIDTH_80P80MHZ;
else
- vht = VHT_CHANWIDTH_80MHZ;
+ vht = CHANWIDTH_80MHZ;
break;
case 2:
- vht = VHT_CHANWIDTH_160MHZ;
+ vht = CHANWIDTH_160MHZ;
break;
case 3:
- vht = VHT_CHANWIDTH_80P80MHZ;
+ vht = CHANWIDTH_80P80MHZ;
break;
default:
- vht = VHT_CHANWIDTH_USE_HT;
+ vht = CHANWIDTH_USE_HT;
break;
}
}
static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
enum beacon_report_detail detail,
struct wpa_bss *bss, u8 *buf,
- size_t buf_len)
+ size_t buf_len, u8 **ies_buf,
+ size_t *ie_len, int add_fixed)
{
- u8 *ies = (u8 *) (bss + 1);
- size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ u8 *ies = *ies_buf;
+ size_t ies_len = *ie_len;
u8 *pos = buf;
int rem_len;
rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) -
- sizeof(struct rrm_measurement_report_element) - 2;
+ sizeof(struct rrm_measurement_report_element) - 2 -
+ REPORTED_FRAME_BODY_SUBELEM_LEN;
if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
wpa_printf(MSG_DEBUG,
* Minimal frame body subelement size: EID(1) + length(1) + TSF(8) +
* beacon interval(2) + capabilities(2) = 14 bytes
*/
- if (buf_len < 14)
- return 0;
+ if (add_fixed && buf_len < 14)
+ return -1;
*pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY;
/* The length will be filled later */
pos++;
- WPA_PUT_LE64(pos, bss->tsf);
- pos += sizeof(bss->tsf);
- WPA_PUT_LE16(pos, bss->beacon_int);
- pos += 2;
- WPA_PUT_LE16(pos, bss->caps);
- pos += 2;
+
+ if (add_fixed) {
+ WPA_PUT_LE64(pos, bss->tsf);
+ pos += sizeof(bss->tsf);
+ WPA_PUT_LE16(pos, bss->beacon_int);
+ pos += 2;
+ WPA_PUT_LE16(pos, bss->caps);
+ pos += 2;
+ }
rem_len -= pos - buf;
while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) {
if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
(eids && bitfield_is_set(eids, ies[0]))) {
- u8 eid = ies[0], elen = ies[1];
-
- if ((eid == WLAN_EID_TIM || eid == WLAN_EID_RSN) &&
- elen > 4)
- elen = 4;
- /*
- * TODO: Truncate IBSS DFS element as described in
- * IEEE Std 802.11-2016, 9.4.2.22.7.
- */
+ u8 elen = ies[1];
if (2 + elen > buf + buf_len - pos ||
2 + elen > rem_len)
ies += 2 + ies[1];
}
+ *ie_len = ies_len;
+ *ies_buf = ies;
+
/* Now the length is known */
buf[1] = pos - buf - 2;
return pos - buf;
}
+static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
+ struct wpa_bss *bss,
+ struct wpabuf **wpa_buf,
+ struct rrm_measurement_beacon_report *rep,
+ u8 **ie, size_t *ie_len, u8 idx)
+{
+ int ret;
+ u8 *buf, *pos;
+ u32 subelems_len = REPORTED_FRAME_BODY_SUBELEM_LEN +
+ (data->last_indication ?
+ BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN : 0);
+
+ /* Maximum element length: Beacon Report element + Reported Frame Body
+ * subelement + all IEs of the reported Beacon frame + Reported Frame
+ * Body Fragment ID subelement */
+ buf = os_malloc(sizeof(*rep) + 14 + *ie_len + subelems_len);
+ if (!buf)
+ return -1;
+
+ os_memcpy(buf, rep, sizeof(*rep));
+
+ ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
+ bss, buf + sizeof(*rep),
+ 14 + *ie_len, ie, ie_len,
+ idx == 0);
+ if (ret < 0)
+ goto out;
+
+ pos = buf + ret + sizeof(*rep);
+ pos[0] = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID;
+ pos[1] = 2;
+
+ /*
+ * Only one Beacon Report Measurement is supported at a time, so
+ * the Beacon Report ID can always be set to 1.
+ */
+ pos[2] = 1;
+
+ /* Fragment ID Number (bits 0..6) and More Frame Body Fragments (bit 7)
+ */
+ pos[3] = idx;
+ if (data->report_detail != BEACON_REPORT_DETAIL_NONE && *ie_len)
+ pos[3] |= REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+ else
+ pos[3] &= ~REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+
+ pos += REPORTED_FRAME_BODY_SUBELEM_LEN;
+
+ if (data->last_indication) {
+ pos[0] = WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION;
+ pos[1] = 1;
+
+ /* This field will be updated later if this is the last frame */
+ pos[2] = 0;
+ }
+
+ ret = wpas_rrm_report_elem(wpa_buf, data->token,
+ MEASUREMENT_REPORT_MODE_ACCEPT,
+ MEASURE_TYPE_BEACON, buf,
+ ret + sizeof(*rep) + subelems_len);
+out:
+ os_free(buf);
+ return ret;
+}
+
+
static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
struct wpabuf **wpa_buf, struct wpa_bss *bss,
u64 start, u64 parent_tsf)
{
struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
- u8 *ie = (u8 *) (bss + 1);
- size_t ie_len = bss->ie_len + bss->beacon_ie_len;
- int ret;
- u8 buf[2000];
- struct rrm_measurement_beacon_report *rep;
+ u8 *ies = (u8 *) (bss + 1);
+ u8 *pos = ies;
+ size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ struct rrm_measurement_beacon_report rep;
+ u8 idx = 0;
if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 &&
os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0)
os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0))
return 0;
- rep = (struct rrm_measurement_beacon_report *) buf;
- if (wpas_get_op_chan_phy(bss->freq, ie, ie_len, &rep->op_class,
- &rep->channel, &rep->report_info) < 0)
+ if (wpas_get_op_chan_phy(bss->freq, ies, ies_len, &rep.op_class,
+ &rep.channel, &rep.report_info) < 0)
return 0;
- rep->start_time = host_to_le64(start);
- rep->duration = host_to_le16(data->scan_params.duration);
- rep->rcpi = rssi_to_rcpi(bss->level);
- rep->rsni = 255; /* 255 indicates that RSNI is not available */
- os_memcpy(rep->bssid, bss->bssid, ETH_ALEN);
- rep->antenna_id = 0; /* unknown */
- rep->parent_tsf = host_to_le32(parent_tsf);
+ rep.start_time = host_to_le64(start);
+ rep.duration = host_to_le16(data->scan_params.duration);
+ rep.rcpi = rssi_to_rcpi(bss->level);
+ rep.rsni = 255; /* 255 indicates that RSNI is not available */
+ os_memcpy(rep.bssid, bss->bssid, ETH_ALEN);
+ rep.antenna_id = 0; /* unknown */
+ rep.parent_tsf = host_to_le32(parent_tsf);
- ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
- bss, rep->variable,
- sizeof(buf) - sizeof(*rep));
- if (ret < 0)
- return -1;
+ do {
+ int ret;
- if (wpabuf_resize(wpa_buf,
- sizeof(struct rrm_measurement_report_element) +
- sizeof(*rep) + ret)) {
- wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
- return -1;
- }
+ ret = wpas_add_beacon_rep_elem(data, bss, wpa_buf, &rep,
+ &pos, &ies_len, idx++);
+ if (ret)
+ return ret;
+ } while (data->report_detail != BEACON_REPORT_DETAIL_NONE &&
+ ies_len >= 2);
- return wpas_rrm_report_elem(*wpa_buf, wpa_s->beacon_rep_data.token,
- MEASUREMENT_REPORT_MODE_ACCEPT,
- MEASURE_TYPE_BEACON, buf,
- ret + sizeof(*rep));
+ return 0;
}
static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s,
struct wpabuf **buf)
{
- if (wpabuf_resize(buf, 5)) {
- wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
- return -1;
- }
-
- return wpas_rrm_report_elem(*buf, wpa_s->beacon_rep_data.token,
+ return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
MEASUREMENT_REPORT_MODE_ACCEPT,
MEASURE_TYPE_BEACON, NULL, 0);
}
}
-static void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s)
+void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s)
{
- struct wpabuf *buf;
+ if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr)) {
+ struct wpabuf *buf = NULL;
+
+ if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token,
+ MEASUREMENT_REPORT_MODE_REJECT_REFUSED,
+ MEASURE_TYPE_BEACON, NULL, 0)) {
+ wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
+ wpabuf_free(buf);
+ return;
+ }
- buf = wpabuf_alloc(sizeof(struct rrm_measurement_beacon_report));
- if (!buf ||
- wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
- MEASUREMENT_REPORT_MODE_REJECT_REFUSED,
- MEASURE_TYPE_BEACON, NULL, 0)) {
- wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
+ wpas_rrm_send_msr_report(wpa_s, buf);
wpabuf_free(buf);
- return;
}
- wpas_rrm_send_msr_report(wpa_s, buf);
wpas_clear_beacon_rep_data(wpa_s);
- wpabuf_free(buf);
}
BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u",
subelem[0]);
- return 0;
+ return -1;
}
break;
case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL:
/* Skip - it will be processed when freqs are added */
break;
+ case WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION:
+ if (slen != 1) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: Invalid last indication request subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ data->last_indication = subelem[0];
+ break;
default:
wpa_printf(MSG_DEBUG,
"Beacon request: Unknown subelement id %u", sid);
u32 interval_usec;
u32 _rand;
int ret = 0, res;
+ u8 reject_mode;
if (len < sizeof(*req))
return -1;
elems_len = len - sizeof(*req);
rand_interval = le_to_host16(req->rand_interval);
+ os_free(params->freqs);
os_memset(params, 0, sizeof(*params));
data->token = elem_token;
res = wpas_rm_handle_beacon_req_subelem(
wpa_s, data, subelems[0], subelems[1], &subelems[2]);
- if (res != 1) {
+ if (res < 0) {
ret = res;
goto out;
+ } else if (!res) {
+ reject_mode = MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE;
+ goto out_reject;
}
elems_len -= 2 + subelems[1];
req->variable, len - sizeof(*req));
if (!params->freqs) {
wpa_printf(MSG_DEBUG, "Beacon request: No valid channels");
- goto out;
+ reject_mode = MEASUREMENT_REPORT_MODE_REJECT_REFUSED;
+ goto out_reject;
}
params->duration = le_to_host16(req->duration);
eloop_register_timeout(0, interval_usec, wpas_rrm_scan_timeout, wpa_s,
NULL);
return 1;
+out_reject:
+ if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
+ wpas_rrm_report_elem(buf, elem_token, reject_mode,
+ MEASURE_TYPE_BEACON, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+ ret = -1;
+ }
out:
wpas_clear_beacon_rep_data(wpa_s);
return ret;
}
reject:
- if (wpabuf_resize(buf, sizeof(struct rrm_measurement_report_element))) {
- wpa_printf(MSG_DEBUG, "RRM: Memory allocation failed");
- return -1;
- }
-
- if (wpas_rrm_report_elem(*buf, req->token,
+ if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
+ wpas_rrm_report_elem(buf, req->token,
MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
req->type, NULL, 0) < 0) {
wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
- const u8 *src,
+ const u8 *src, const u8 *dst,
const u8 *frame, size_t len)
{
struct wpabuf *report;
}
wpa_s->rrm.token = *frame;
+ os_memcpy(wpa_s->rrm.dst_addr, dst, ETH_ALEN);
/* Number of repetitions is not supported */
}
os_memset(&report, 0, sizeof(report));
+ report.dialog_token = req->dialog_token;
report.tpc.eid = WLAN_EID_TPC_REPORT;
report.tpc.len = 2;
+ /* Note: The driver is expected to update report.tpc.tx_power and
+ * report.tpc.link_margin subfields when sending out this frame.
+ * Similarly, the driver would need to update report.rx_ant_id and
+ * report.tx_ant_id subfields. */
report.rsni = 255; /* 255 indicates that RSNI is not available */
- report.dialog_token = req->dialog_token;
report.rcpi = rssi_to_rcpi(rssi);
/* action_category + action_code */
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
wpabuf_put_data(buf, &report, sizeof(report));
- wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
- wpabuf_head(buf), wpabuf_len(buf));
+ wpa_hexdump_buf(MSG_DEBUG, "RRM: Link measurement report", buf);
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
wpa_s->own_addr, wpa_s->bssid,
continue;
}
+ /*
+ * Don't report results that were not received during the
+ * current measurement.
+ */
if (!(wpa_s->drv_rrm_flags &
WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT)) {
struct os_reltime update_time, diff;
(unsigned int) diff.usec);
continue;
}
- }
-
- /*
- * Don't report results that were not received during the
- * current measurement.
- */
- if (info->scan_start_tsf > scan_res->res[i]->parent_tsf)
+ } else if (info->scan_start_tsf >
+ scan_res->res[i]->parent_tsf) {
continue;
+ }
if (wpas_add_beacon_rep(wpa_s, &buf, bss, info->scan_start_tsf,
scan_res->res[i]->parent_tsf) < 0)