+static int hostapd_ctrl_iface_log_level(struct hostapd_data *hapd, char *cmd,
+ char *buf, size_t buflen)
+{
+ char *pos, *end, *stamp;
+ int ret;
+
+ /* cmd: "LOG_LEVEL [<level>]" */
+ if (*cmd == '\0') {
+ pos = buf;
+ end = buf + buflen;
+ ret = os_snprintf(pos, end - pos, "Current level: %s\n"
+ "Timestamp: %d\n",
+ debug_level_str(wpa_debug_level),
+ wpa_debug_timestamp);
+ if (os_snprintf_error(end - pos, ret))
+ ret = 0;
+
+ return ret;
+ }
+
+ while (*cmd == ' ')
+ cmd++;
+
+ stamp = os_strchr(cmd, ' ');
+ if (stamp) {
+ *stamp++ = '\0';
+ while (*stamp == ' ') {
+ stamp++;
+ }
+ }
+
+ if (os_strlen(cmd)) {
+ int level = str_to_debug_level(cmd);
+ if (level < 0)
+ return -1;
+ wpa_debug_level = level;
+ }
+
+ if (stamp && os_strlen(stamp))
+ wpa_debug_timestamp = atoi(stamp);
+
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+}
+
+
+#ifdef NEED_AP_MLME
+static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ char *pos, *end;
+ struct hostapd_sta_info *info;
+ struct os_reltime now;
+
+ if (!iface->num_sta_seen)
+ return 0;
+
+ sta_track_expire(iface, 0);
+
+ pos = buf;
+ end = buf + buflen;
+
+ os_get_reltime(&now);
+ dl_list_for_each_reverse(info, &iface->sta_seen,
+ struct hostapd_sta_info, list) {
+ struct os_reltime age;
+ int ret;
+
+ os_reltime_sub(&now, &info->last_seen, &age);
+ ret = os_snprintf(pos, end - pos, MACSTR " %u\n",
+ MAC2STR(info->addr), (unsigned int) age.sec);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+#endif /* NEED_AP_MLME */
+
+
+static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
+ return -1;
+ }
+
+ return hostapd_send_lci_req(hapd, addr);
+}
+
+
+static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ char *token, *context = NULL;
+ int random_interval, min_ap;
+ u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
+ unsigned int n_responders;
+
+ token = str_token(cmd, " ", &context);
+ if (!token || hwaddr_aton(token, addr)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE - Bad destination address");
+ return -1;
+ }
+
+ token = str_token(cmd, " ", &context);
+ if (!token)
+ return -1;
+
+ random_interval = atoi(token);
+ if (random_interval < 0 || random_interval > 0xffff)
+ return -1;
+
+ token = str_token(cmd, " ", &context);
+ if (!token)
+ return -1;
+
+ min_ap = atoi(token);
+ if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
+ return -1;
+
+ n_responders = 0;
+ while ((token = str_token(cmd, " ", &context))) {
+ if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE: Too many responders");
+ return -1;
+ }
+
+ if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE: Bad responder address");
+ return -1;
+ }
+
+ n_responders++;
+ }
+
+ if (!n_responders) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE - No FTM responder address");
+ return -1;
+ }
+
+ return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
+ responders, n_responders);
+}
+
+
+static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ struct wpabuf *nr, *lci = NULL, *civic = NULL;
+ char *tmp;
+ int ret;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
+ return -1;
+ }
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad or missing SSID");
+ return -1;
+ }
+ buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
+ if (!buf)
+ return -1;
+
+ tmp = os_strstr(buf, "nr=");
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
+ return -1;
+ }
+
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+
+ nr = wpabuf_parse_bin(tmp + 3);
+ if (!nr) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
+ return -1;
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "lci=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ lci = wpabuf_parse_bin(tmp + 4);
+ if (!lci) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad LCI subelement");
+ wpabuf_free(nr);
+ return -1;
+ }
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "civic=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ civic = wpabuf_parse_bin(tmp + 6);
+ if (!civic) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad civic subelement");
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ return -1;
+ }
+ }
+
+set:
+ ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic);
+
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ wpabuf_free(civic);
+
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
+ char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ char *tmp;
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
+ return -1;
+ }
+
+ return hostapd_neighbor_remove(hapd, bssid, &ssid);
+}
+
+
+static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
+ size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) iface->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (iface->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+