X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=wpa_supplicant%2Fctrl_iface.c;h=6c7b561503fdf1ae117f32eb59893f972ca1bafd;hb=545cc6af2593b3174ae7813d2fd658074ff44e23;hp=9c849cbf57b9bd681c6d29724bc4ff4aecb13232;hpb=53587ec1836cc9532d33c872875e1bad422ab5ad;p=libeap.git diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 9c849cb..6c7b561 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -31,6 +31,8 @@ #include "wps_supplicant.h" #include "ibss_rsn.h" #include "ap.h" +#include "p2p_supplicant.h" +#include "p2p/p2p.h" #include "notify.h" #include "bss.h" #include "scan.h" @@ -80,8 +82,37 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value))) ret = -1; - } else - ret = -1; + } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) { + wpa_s->wps_fragment_size = atoi(value); +#ifdef CONFIG_WPS_TESTING + } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { + long int val; + val = strtol(value, NULL, 0); + if (val < 0 || val > 0xff) { + ret = -1; + wpa_printf(MSG_DEBUG, "WPS: Invalid " + "wps_version_number %ld", val); + } else { + wps_version_number = val; + wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " + "version %u.%u", + (wps_version_number & 0xf0) >> 4, + wps_version_number & 0x0f); + } + } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { + wps_testing_dummy_cred = atoi(value); + wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", + wps_testing_dummy_cred); +#endif /* CONFIG_WPS_TESTING */ + } else if (os_strcasecmp(cmd, "ampdu") == 0) { + if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) + ret = -1; + } else { + value[-1] = '='; + ret = wpa_config_process_global(wpa_s->conf, cmd, -1); + if (ret == 0) + wpa_supplicant_update_config(wpa_s); + } return ret; } @@ -177,7 +208,7 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid); #endif /* CONFIG_AP */ - return wpas_wps_start_pbc(wpa_s, _bssid); + return wpas_wps_start_pbc(wpa_s, _bssid, 0); } @@ -208,7 +239,8 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, #endif /* CONFIG_AP */ if (pin) { - ret = wpas_wps_start_pin(wpa_s, _bssid, pin); + ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0, + DEV_PW_DEFAULT); if (ret < 0) return -1; ret = os_snprintf(buf, buflen, "%s", pin); @@ -217,7 +249,7 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, return ret; } - ret = wpas_wps_start_pin(wpa_s, _bssid, NULL); + ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT); if (ret < 0) return -1; @@ -229,6 +261,51 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, } +static int wpa_supplicant_ctrl_iface_wps_check_pin( + struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) +{ + char pin[9]; + size_t len; + char *pos; + int ret; + + wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", + (u8 *) cmd, os_strlen(cmd)); + for (pos = cmd, len = 0; *pos != '\0'; pos++) { + if (*pos < '0' || *pos > '9') + continue; + pin[len++] = *pos; + if (len == 9) { + wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); + return -1; + } + } + if (len != 4 && len != 8) { + wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); + return -1; + } + pin[len] = '\0'; + + if (len == 8) { + unsigned int pin_val; + pin_val = atoi(pin); + if (!wps_pin_valid(pin_val)) { + wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); + ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } + } + + ret = os_snprintf(buf, buflen, "%s", pin); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + + return ret; +} + + #ifdef CONFIG_WPS_OOB static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s, char *cmd) @@ -548,6 +625,15 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, ret = os_snprintf(pos, end - pos, "mode=AP\n"); break; + case WPAS_MODE_P2P_GO: + ret = os_snprintf(pos, end - pos, + "mode=P2P GO\n"); + break; + case WPAS_MODE_P2P_GROUP_FORMATION: + ret = os_snprintf(pos, end - pos, + "mode=P2P GO - group " + "formation\n"); + break; default: ret = 0; break; @@ -580,6 +666,22 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, pos += ret; } +#ifdef CONFIG_P2P + if (wpa_s->global->p2p) { + ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR + "\n", MAC2STR(wpa_s->global->p2p_dev_addr)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n", + MAC2STR(wpa_s->own_addr)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; +#endif /* CONFIG_P2P */ + if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, @@ -662,10 +764,12 @@ static int wpa_supplicant_ctrl_iface_list_networks( if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; - ret = os_snprintf(pos, end - pos, "\t%s%s", + ret = os_snprintf(pos, end - pos, "\t%s%s%s", ssid == wpa_s->current_ssid ? "[CURRENT]" : "", - ssid->disabled ? "[DISABLED]" : ""); + ssid->disabled ? "[DISABLED]" : "", + ssid->disabled == 2 ? "[P2P-PERSISTENT]" : + ""); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; @@ -875,7 +979,13 @@ static int wpa_supplicant_ctrl_iface_scan_result( { char *pos, *end; int ret; - const u8 *ie, *ie2; + const u8 *ie, *ie2, *p2p; + + p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); + if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN && + os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == + 0) + return 0; /* Do not show P2P listen discovery results here */ pos = buf; end = buf + buflen; @@ -910,6 +1020,12 @@ static int wpa_supplicant_ctrl_iface_scan_result( return pos - buf; pos += ret; } + if (p2p) { + ret = os_snprintf(pos, end - pos, "[P2P]"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } ret = os_snprintf(pos, end - pos, "\t%s", wpa_ssid_txt(bss->ssid, bss->ssid_len)); @@ -973,6 +1089,11 @@ static int wpa_supplicant_ctrl_iface_select_network( "network id=%d", id); return -1; } + if (ssid->disabled == 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " + "SELECT_NETWORK with persistent P2P group"); + return -1; + } } wpa_supplicant_select_network(wpa_s, ssid); @@ -1001,6 +1122,11 @@ static int wpa_supplicant_ctrl_iface_enable_network( "network id=%d", id); return -1; } + if (ssid->disabled == 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " + "ENABLE_NETWORK with persistent P2P group"); + return -1; + } } wpa_supplicant_enable_network(wpa_s, ssid); @@ -1028,6 +1154,12 @@ static int wpa_supplicant_ctrl_iface_disable_network( "network id=%d", id); return -1; } + if (ssid->disabled == 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " + "DISABLE_NETWORK with persistent P2P " + "group"); + return -1; + } } wpa_supplicant_disable_network(wpa_s, ssid); @@ -1613,6 +1745,12 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, return pos - buf; pos += ret; } + if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) { + ret = os_snprintf(pos, end - pos, "[P2P]"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) @@ -1669,6 +1807,14 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, pos += ret; #endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + ie = (const u8 *) (bss + 1); + ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; +#endif /* CONFIG_P2P */ + return pos - buf; } @@ -1746,11 +1892,790 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_P2P +static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) +{ + unsigned int timeout = atoi(cmd); + enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL; + + if (os_strstr(cmd, "type=social")) + type = P2P_FIND_ONLY_SOCIAL; + else if (os_strstr(cmd, "type=progressive")) + type = P2P_FIND_PROGRESSIVE; + + wpas_p2p_find(wpa_s, timeout, type); + return 0; +} + + +static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + u8 addr[ETH_ALEN]; + char *pos, *pos2; + char *pin = NULL; + enum p2p_wps_method wps_method; + int new_pin; + int ret; + int persistent_group; + int join; + int auth; + int go_intent = -1; + int freq = 0; + + /* <"pbc" | "pin" | PIN> [label|display|keypad] [persistent] + * [join] [auth] [go_intent=<0..15>] [freq=] */ + + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = cmd + 17; + if (*pos != ' ') + return -1; + pos++; + + persistent_group = os_strstr(pos, " persistent") != NULL; + join = os_strstr(pos, " join") != NULL; + auth = os_strstr(pos, " auth") != NULL; + + pos2 = os_strstr(pos, " go_intent="); + if (pos2) { + pos2 += 11; + go_intent = atoi(pos2); + if (go_intent < 0 || go_intent > 15) + return -1; + } + + pos2 = os_strstr(pos, " freq="); + if (pos2) { + pos2 += 6; + freq = atoi(pos2); + if (freq <= 0) + return -1; + } + + if (os_strncmp(pos, "pin", 3) == 0) { + /* Request random PIN (to be displayed) and enable the PIN */ + wps_method = WPS_PIN_DISPLAY; + } else if (os_strncmp(pos, "pbc", 3) == 0) { + wps_method = WPS_PBC; + } else { + pin = pos; + pos = os_strchr(pin, ' '); + wps_method = WPS_PIN_KEYPAD; + if (pos) { + *pos++ = '\0'; + if (os_strncmp(pos, "label", 5) == 0) + wps_method = WPS_PIN_LABEL; + else if (os_strncmp(pos, "display", 7) == 0) + wps_method = WPS_PIN_DISPLAY; + } + } + + new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, + persistent_group, join, auth, go_intent, + freq); + if (new_pin == -2) { + os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); + return 25; + } + if (new_pin == -3) { + os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25); + return 25; + } + if (new_pin < 0) + return -1; + if (wps_method == WPS_PIN_DISPLAY && pin == NULL) { + ret = os_snprintf(buf, buflen, "%08d", new_pin); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } + + os_memcpy(buf, "OK\n", 3); + return 3; +} + + +static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd) +{ + unsigned int timeout = atoi(cmd); + return wpas_p2p_listen(wpa_s, timeout); +} + + +static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + char *pos; + + /* */ + + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = cmd + 17; + if (*pos != ' ') + return -1; + pos++; + + return wpas_p2p_prov_disc(wpa_s, addr, pos); +} + + +static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf, + size_t buflen) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || + ssid->passphrase == NULL) + return -1; + + os_strlcpy(buf, ssid->passphrase, buflen); + return os_strlen(buf); +} + + +static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + u64 ref; + int res; + u8 dst_buf[ETH_ALEN], *dst; + struct wpabuf *tlvs; + char *pos; + size_t len; + + if (hwaddr_aton(cmd, dst_buf)) + return -1; + dst = dst_buf; + if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && + dst[3] == 0 && dst[4] == 0 && dst[5] == 0) + dst = NULL; + pos = cmd + 17; + if (*pos != ' ') + return -1; + pos++; + + if (os_strncmp(pos, "upnp ", 5) == 0) { + u8 version; + pos += 5; + if (hexstr2bin(pos, &version, 1) < 0) + return -1; + pos += 2; + if (*pos != ' ') + return -1; + pos++; + ref = (u64) wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos); + } else { + len = os_strlen(pos); + if (len & 1) + return -1; + len /= 2; + tlvs = wpabuf_alloc(len); + if (tlvs == NULL) + return -1; + if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) { + wpabuf_free(tlvs); + return -1; + } + + ref = (u64) wpas_p2p_sd_request(wpa_s, dst, tlvs); + wpabuf_free(tlvs); + } + res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref); + if (res < 0 || (unsigned) res >= buflen) + return -1; + return res; +} + + +static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s, + char *cmd) +{ + long long unsigned val; + u64 req; + if (sscanf(cmd, "%llx", &val) != 1) + return -1; + req = val; + return wpas_p2p_sd_cancel_request(wpa_s, (void *) req); +} + + +static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd) +{ + int freq; + u8 dst_buf[ETH_ALEN], *dst; + u8 dialog_token; + struct wpabuf *resp_tlvs; + char *pos, *pos2; + size_t len; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + freq = atoi(cmd); + if (freq == 0) + return -1; + + if (hwaddr_aton(pos, dst_buf)) + return -1; + dst = dst_buf; + if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && + dst[3] == 0 && dst[4] == 0 && dst[5] == 0) + dst = NULL; + pos += 17; + if (*pos != ' ') + return -1; + pos++; + + pos2 = os_strchr(pos, ' '); + if (pos2 == NULL) + return -1; + *pos2++ = '\0'; + dialog_token = atoi(pos); + + len = os_strlen(pos2); + if (len & 1) + return -1; + len /= 2; + resp_tlvs = wpabuf_alloc(len); + if (resp_tlvs == NULL) + return -1; + if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) { + wpabuf_free(resp_tlvs); + return -1; + } + + wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs); + wpabuf_free(resp_tlvs); + return 0; +} + + +static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s, + char *cmd) +{ + wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd); + return 0; +} + + +static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *pos; + size_t len; + struct wpabuf *query, *resp; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + query = wpabuf_alloc(len); + if (query == NULL) + return -1; + if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { + wpabuf_free(query); + return -1; + } + + len = os_strlen(pos); + if (len & 1) { + wpabuf_free(query); + return -1; + } + len /= 2; + resp = wpabuf_alloc(len); + if (resp == NULL) { + wpabuf_free(query); + return -1; + } + if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) { + wpabuf_free(query); + wpabuf_free(resp); + return -1; + } + + if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) { + wpabuf_free(query); + wpabuf_free(resp); + return -1; + } + return 0; +} + + +static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + u8 version; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (hexstr2bin(cmd, &version, 1) < 0) + return -1; + + return wpas_p2p_service_add_upnp(wpa_s, version, pos); +} + + +static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (os_strcmp(cmd, "bonjour") == 0) + return p2p_ctrl_service_add_bonjour(wpa_s, pos); + if (os_strcmp(cmd, "upnp") == 0) + return p2p_ctrl_service_add_upnp(wpa_s, pos); + wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); + return -1; +} + + +static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s, + char *cmd) +{ + size_t len; + struct wpabuf *query; + int ret; + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + query = wpabuf_alloc(len); + if (query == NULL) + return -1; + if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { + wpabuf_free(query); + return -1; + } + + ret = wpas_p2p_service_del_bonjour(wpa_s, query); + wpabuf_free(query); + return ret; +} + + +static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + u8 version; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (hexstr2bin(cmd, &version, 1) < 0) + return -1; + + return wpas_p2p_service_del_upnp(wpa_s, version, pos); +} + + +static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (os_strcmp(cmd, "bonjour") == 0) + return p2p_ctrl_service_del_bonjour(wpa_s, pos); + if (os_strcmp(cmd, "upnp") == 0) + return p2p_ctrl_service_del_upnp(wpa_s, pos); + wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); + return -1; +} + + +static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + + /* */ + + if (hwaddr_aton(cmd, addr)) + return -1; + + return wpas_p2p_reject(wpa_s, addr); +} + + +static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + int id; + struct wpa_ssid *ssid; + u8 peer[ETH_ALEN]; + + id = atoi(cmd); + pos = os_strstr(cmd, " peer="); + if (pos) { + pos += 6; + if (hwaddr_aton(pos, peer)) + return -1; + } + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL || ssid->disabled != 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " + "for persistent P2P group", + id); + return -1; + } + + return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL); +} + + +static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL; + + pos = os_strstr(cmd, " peer="); + if (!pos) + return -1; + + *pos = '\0'; + pos += 6; + if (hwaddr_aton(pos, peer)) { + wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos); + return -1; + } + + pos = os_strstr(pos, " go_dev_addr="); + if (pos) { + pos += 13; + if (hwaddr_aton(pos, go_dev_addr)) { + wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", + pos); + return -1; + } + go_dev = go_dev_addr; + } + + return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev); +} + + +static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) +{ + if (os_strncmp(cmd, "persistent=", 11) == 0) + return p2p_ctrl_invite_persistent(wpa_s, cmd + 11); + if (os_strncmp(cmd, "group=", 6) == 0) + return p2p_ctrl_invite_group(wpa_s, cmd + 6); + + return -1; +} + + +static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, + char *cmd, int freq) +{ + int id; + struct wpa_ssid *ssid; + + id = atoi(cmd); + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL || ssid->disabled != 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " + "for persistent P2P group", + id); + return -1; + } + + return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq); +} + + +static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) +{ + int freq = 0; + char *pos; + + pos = os_strstr(cmd, "freq="); + if (pos) + freq = atoi(pos + 5); + + if (os_strncmp(cmd, "persistent=", 11) == 0) + return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq); + if (os_strcmp(cmd, "persistent") == 0 || + os_strncmp(cmd, "persistent ", 11) == 0) + return wpas_p2p_group_add(wpa_s, 1, freq); + if (os_strncmp(cmd, "freq=", 5) == 0) + return wpas_p2p_group_add(wpa_s, 0, freq); + + wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'", + cmd); + return -1; +} + + +static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + u8 addr[ETH_ALEN], *addr_ptr; + int next; + + if (!wpa_s->global->p2p) + return -1; + + if (os_strcmp(cmd, "FIRST") == 0) { + addr_ptr = NULL; + next = 0; + } else if (os_strncmp(cmd, "NEXT-", 5) == 0) { + if (hwaddr_aton(cmd + 5, addr) < 0) + return -1; + addr_ptr = addr; + next = 1; + } else { + if (hwaddr_aton(cmd, addr) < 0) + return -1; + addr_ptr = addr; + next = 0; + } + + return p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next, + buf, buflen); +} + + +static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *param; + + if (wpa_s->global->p2p == NULL) + return -1; + + param = os_strchr(cmd, ' '); + if (param == NULL) + return -1; + *param++ = '\0'; + + if (os_strcmp(cmd, "discoverability") == 0) { + p2p_set_client_discoverability(wpa_s->global->p2p, + atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "managed") == 0) { + p2p_set_managed_oper(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "listen_channel") == 0) { + return p2p_set_listen_channel(wpa_s->global->p2p, 81, + atoi(param)); + } + + if (os_strcmp(cmd, "ssid_postfix") == 0) { + return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param, + os_strlen(param)); + } + + if (os_strcmp(cmd, "noa") == 0) { + char *pos; + int count, start, duration; + /* GO NoA parameters: count,start_offset(ms),duration(ms) */ + count = atoi(param); + pos = os_strchr(param, ','); + if (pos == NULL) + return -1; + pos++; + start = atoi(pos); + pos = os_strchr(pos, ','); + if (pos == NULL) + return -1; + pos++; + duration = atoi(pos); + if (count < 0 || count > 255 || start < 0 || duration < 0) + return -1; + if (count == 0 && duration > 0) + return -1; + wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d " + "start=%d duration=%d", count, start, duration); + return wpas_p2p_set_noa(wpa_s, count, start, duration); + } + + if (os_strcmp(cmd, "ps") == 0) + return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1); + + if (os_strcmp(cmd, "oppps") == 0) + return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1); + + if (os_strcmp(cmd, "ctwindow") == 0) + return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param)); + + if (os_strcmp(cmd, "disabled") == 0) { + wpa_s->global->p2p_disabled = atoi(param); + wpa_printf(MSG_DEBUG, "P2P functionality %s", + wpa_s->global->p2p_disabled ? + "disabled" : "enabled"); + if (wpa_s->global->p2p_disabled) { + wpas_p2p_stop_find(wpa_s); + os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); + p2p_flush(wpa_s->global->p2p); + } + return 0; + } + + if (os_strcmp(cmd, "force_long_sd") == 0) { + wpa_s->force_long_sd = atoi(param); + return 0; + } + + if (os_strcmp(cmd, "peer_filter") == 0) { + u8 addr[ETH_ALEN]; + if (hwaddr_aton(param, addr)) + return -1; + p2p_set_peer_filter(wpa_s->global->p2p, addr); + return 0; + } + + if (os_strcmp(cmd, "cross_connect") == 0) + return wpas_p2p_set_cross_connect(wpa_s, atoi(param)); + + if (os_strcmp(cmd, "go_apsd") == 0) { + if (os_strcmp(param, "disable") == 0) + wpa_s->set_ap_uapsd = 0; + else { + wpa_s->set_ap_uapsd = 1; + wpa_s->ap_uapsd = atoi(param); + } + return 0; + } + + if (os_strcmp(cmd, "client_apsd") == 0) { + if (os_strcmp(param, "disable") == 0) + wpa_s->set_sta_uapsd = 0; + else { + int be, bk, vi, vo; + char *pos; + /* format: BE,BK,VI,VO;max SP Length */ + be = atoi(param); + pos = os_strchr(param, ','); + if (pos == NULL) + return -1; + pos++; + bk = atoi(pos); + pos = os_strchr(pos, ','); + if (pos == NULL) + return -1; + pos++; + vi = atoi(pos); + pos = os_strchr(pos, ','); + if (pos == NULL) + return -1; + pos++; + vo = atoi(pos); + /* ignore max SP Length for now */ + + wpa_s->set_sta_uapsd = 1; + wpa_s->sta_uapsd = 0; + if (be) + wpa_s->sta_uapsd |= BIT(0); + if (bk) + wpa_s->sta_uapsd |= BIT(1); + if (vi) + wpa_s->sta_uapsd |= BIT(2); + if (vo) + wpa_s->sta_uapsd |= BIT(3); + } + return 0; + } + + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", + cmd); + + return -1; +} + + +static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos, *pos2; + unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; + + if (cmd[0]) { + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + dur1 = atoi(cmd); + + pos2 = os_strchr(pos, ' '); + if (pos2) + *pos2++ = '\0'; + int1 = atoi(pos); + } else + pos2 = NULL; + + if (pos2) { + pos = os_strchr(pos2, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + dur2 = atoi(pos2); + int2 = atoi(pos); + } + + return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2); +} + + +static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + unsigned int period = 0, interval = 0; + + if (cmd[0]) { + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + period = atoi(cmd); + interval = atoi(pos); + } + + return wpas_p2p_ext_listen(wpa_s, period, interval); +} + +#endif /* CONFIG_P2P */ + + +static int wpa_supplicant_ctrl_iface_sta_autoconnect( + struct wpa_supplicant *wpa_s, char *cmd) +{ + wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0; + return 0; +} + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { char *reply; - const int reply_size = 2048; + const int reply_size = 4096; int ctrl_rsp = 0; int reply_len; @@ -1759,7 +2684,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", (const u8 *) buf, os_strlen(buf)); } else { - wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", + int level = MSG_DEBUG; + if (os_strcmp(buf, "PING") == 0) + level = MSG_EXCESSIVE; + wpa_hexdump_ascii(level, "RX ctrl_iface", (const u8 *) buf, os_strlen(buf)); } @@ -1843,6 +2771,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8, reply, reply_size); + } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { + reply_len = wpa_supplicant_ctrl_iface_wps_check_pin( + wpa_s, buf + 14, reply, reply_size); + } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { + if (wpas_wps_cancel(wpa_s)) + reply_len = -1; #ifdef CONFIG_WPS_OOB } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) { if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8)) @@ -1880,6 +2814,89 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9)) reply_len = -1; #endif /* CONFIG_IBSS_RSN */ +#ifdef CONFIG_P2P + } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { + if (p2p_ctrl_find(wpa_s, buf + 9)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_FIND") == 0) { + if (p2p_ctrl_find(wpa_s, "")) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) { + wpas_p2p_stop_find(wpa_s); + } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) { + reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply, + reply_size); + } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) { + if (p2p_ctrl_listen(wpa_s, buf + 11)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_LISTEN") == 0) { + if (p2p_ctrl_listen(wpa_s, "")) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) { + if (wpas_p2p_group_remove(wpa_s, buf + 17)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) { + if (wpas_p2p_group_add(wpa_s, 0, 0)) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) { + if (p2p_ctrl_group_add(wpa_s, buf + 14)) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) { + if (p2p_ctrl_prov_disc(wpa_s, buf + 14)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) { + reply_len = p2p_get_passphrase(wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) { + reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply, + reply_size); + } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) { + if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) { + if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) { + wpas_p2p_sd_service_update(wpa_s); + } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) { + if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) { + wpas_p2p_service_flush(wpa_s); + } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) { + if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) { + if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) { + if (p2p_ctrl_reject(wpa_s, buf + 11) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) { + if (p2p_ctrl_invite(wpa_s, buf + 11) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) { + reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply, + reply_size); + } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) { + if (p2p_ctrl_set(wpa_s, buf + 8) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_FLUSH") == 0) { + os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); + wpa_s->force_long_sd = 0; + p2p_flush(wpa_s->global->p2p); + } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) { + if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) { + if (p2p_ctrl_presence_req(wpa_s, "") < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) { + if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) { + if (p2p_ctrl_ext_listen(wpa_s, "") < 0) + reply_len = -1; +#endif /* CONFIG_P2P */ } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) { if (wpa_supplicant_ctrl_iface_ctrl_rsp( @@ -1973,6 +2990,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "ROAM ", 5) == 0) { if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5)) reply_len = -1; + } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) { + if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16)) + reply_len = -1; } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16;