diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen index cf6075593..1989eea03 100644 --- a/doc/dbus.doxygen +++ b/doc/dbus.doxygen @@ -455,6 +455,58 @@ fi.w1.wpa_supplicant1.CreateInterface.
Add Vendor Elements to corresponding frame ID.
+Get Vendor Elements of corresponding frame ID.
+Remove Vendor Elements of corresponding frame ID.
+Save configuration to the configuration file.
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 7b45a3a71..1f4630f3d 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7844,61 +7844,6 @@ static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd) #endif /* CONFIG_TESTING_OPTIONS */ -static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s) -{ - unsigned int i; - char buf[30]; - - wpa_printf(MSG_DEBUG, "Update vendor elements"); - - for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) { - if (wpa_s->vendor_elem[i]) { - int res; - - res = os_snprintf(buf, sizeof(buf), "frame[%u]", i); - if (!os_snprintf_error(sizeof(buf), res)) { - wpa_hexdump_buf(MSG_DEBUG, buf, - wpa_s->vendor_elem[i]); - } - } - } - -#ifdef CONFIG_P2P - if (wpa_s->parent == wpa_s && - wpa_s->global->p2p && - !wpa_s->global->p2p_disabled) - p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem); -#endif /* CONFIG_P2P */ -} - - -static struct wpa_supplicant * -wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s, - enum wpa_vendor_elem_frame frame) -{ - switch (frame) { -#ifdef CONFIG_P2P - case VENDOR_ELEM_PROBE_REQ_P2P: - case VENDOR_ELEM_PROBE_RESP_P2P: - case VENDOR_ELEM_PROBE_RESP_P2P_GO: - case VENDOR_ELEM_BEACON_P2P_GO: - case VENDOR_ELEM_P2P_PD_REQ: - case VENDOR_ELEM_P2P_PD_RESP: - case VENDOR_ELEM_P2P_GO_NEG_REQ: - case VENDOR_ELEM_P2P_GO_NEG_RESP: - case VENDOR_ELEM_P2P_GO_NEG_CONF: - case VENDOR_ELEM_P2P_INV_REQ: - case VENDOR_ELEM_P2P_INV_RESP: - case VENDOR_ELEM_P2P_ASSOC_REQ: - case VENDOR_ELEM_P2P_ASSOC_RESP: - return wpa_s->parent; -#endif /* CONFIG_P2P */ - default: - return wpa_s; - } -} - - static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) { char *pos = cmd; @@ -7910,7 +7855,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) frame = atoi(pos); if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); pos = os_strchr(pos, ' '); if (pos == NULL) @@ -7941,7 +7886,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) if (wpa_s->vendor_elem[frame] == NULL) { wpa_s->vendor_elem[frame] = buf; - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -7952,7 +7897,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) wpabuf_put_buf(wpa_s->vendor_elem[frame], buf); wpabuf_free(buf); - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -7965,7 +7910,7 @@ static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd, if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); if (wpa_s->vendor_elem[frame] == NULL) return 0; @@ -7983,12 +7928,12 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) size_t len; u8 *buf; struct ieee802_11_elems elems; - u8 *ie, *end; + int res; frame = atoi(pos); if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); pos = os_strchr(pos, ' '); if (pos == NULL) @@ -7998,7 +7943,7 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) if (*pos == '*') { wpabuf_free(wpa_s->vendor_elem[frame]); wpa_s->vendor_elem[frame] = NULL; - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -8026,31 +7971,9 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) return -1; } - ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]); - end = ie + wpabuf_len(wpa_s->vendor_elem[frame]); - - for (; ie + 1 < end; ie += 2 + ie[1]) { - if (ie + len > end) - break; - if (os_memcmp(ie, buf, len) != 0) - continue; - - if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) { - wpabuf_free(wpa_s->vendor_elem[frame]); - wpa_s->vendor_elem[frame] = NULL; - } else { - os_memmove(ie, ie + len, - end - (ie + len)); - wpa_s->vendor_elem[frame]->used -= len; - } - os_free(buf); - wpas_ctrl_vendor_elem_update(wpa_s); - return 0; - } - + res = wpas_vendor_elem_remove(wpa_s, frame, buf, len); os_free(buf); - - return -1; + return res; } diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 440b8cfc7..91a1511a3 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -3070,6 +3070,30 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { } }, #endif /* CONFIG_TDLS */ + { "VendorElemAdd", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_add, + { + { "frame_id", "i", ARG_IN }, + { "ielems", "ay", ARG_IN }, + END_ARGS + } + }, + { "VendorElemGet", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_get, + { + { "frame_id", "i", ARG_IN }, + { "ielems", "ay", ARG_OUT }, + END_ARGS + } + }, + { "VendorElemRem", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_remove, + { + { "frame_id", "i", ARG_IN }, + { "ielems", "ay", ARG_IN }, + END_ARGS + } + }, #ifndef CONFIG_NO_CONFIG_WRITE { "SaveConfig", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_save_config, diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index fbfcdc9a9..6b77008a5 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -4363,3 +4363,147 @@ out: } #endif /* CONFIG_AP */ + + +DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 *ielems; + int len; + struct ieee802_11_elems elems; + dbus_int32_t frame_id; + DBusMessageIter iter, array; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &array); + dbus_message_iter_get_fixed_array(&array, &ielems, &len); + if (!ielems || len == 0) { + return dbus_message_new_error( + message, DBUS_ERROR_INVALID_ARGS, "Invalid value"); + } + + if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Parse error"); + } + + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + if (!wpa_s->vendor_elem[frame_id]) { + wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len); + wpas_vendor_elem_update(wpa_s); + return NULL; + } + + if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Resize error"); + } + + wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len); + wpas_vendor_elem_update(wpa_s); + return NULL; +} + + +DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply; + DBusMessageIter iter, array_iter; + dbus_int32_t frame_id; + const u8 *elem; + size_t elem_len; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } + + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + if (!wpa_s->vendor_elem[frame_id]) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "ID value does not exist"); + } + + reply = dbus_message_new_method_return(message); + if (!reply) + return wpas_dbus_error_no_memory(message); + + dbus_message_iter_init_append(reply, &iter); + + elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]); + elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &array_iter) || + !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, + &elem, elem_len) || + !dbus_message_iter_close_container(&iter, &array_iter)) { + dbus_message_unref(reply); + reply = wpas_dbus_error_no_memory(message); + } + + return reply; +} + + +DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + u8 *ielems; + int len; + struct ieee802_11_elems elems; + DBusMessageIter iter, array; + dbus_int32_t frame_id; + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &frame_id); + if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid ID"); + } + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &array); + dbus_message_iter_get_fixed_array(&array, &ielems, &len); + if (!ielems || len == 0) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Invalid value"); + } + + wpa_s = wpas_vendor_elem(wpa_s, frame_id); + + if (len == 1 && *ielems == '*') { + wpabuf_free(wpa_s->vendor_elem[frame_id]); + wpa_s->vendor_elem[frame_id] = NULL; + wpas_vendor_elem_update(wpa_s); + return NULL; + } + + if (!wpa_s->vendor_elem[frame_id]) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "ID value does not exist"); + } + + if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) { + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Parse error"); + } + + if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0) + return NULL; + + return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, + "Not found"); +} diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index 86c835977..31b92d195 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -194,6 +194,13 @@ DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message, DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message, + struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message, + struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_vendor_elem_remove( + DBusMessage *message, struct wpa_supplicant *wpa_s); + DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message, struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 7e5c07ade..580fbe8a1 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -6143,3 +6143,86 @@ void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, } wpabuf_free(buf); } + + +struct wpa_supplicant * +wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame) +{ + switch (frame) { +#ifdef CONFIG_P2P + case VENDOR_ELEM_PROBE_REQ_P2P: + case VENDOR_ELEM_PROBE_RESP_P2P: + case VENDOR_ELEM_PROBE_RESP_P2P_GO: + case VENDOR_ELEM_BEACON_P2P_GO: + case VENDOR_ELEM_P2P_PD_REQ: + case VENDOR_ELEM_P2P_PD_RESP: + case VENDOR_ELEM_P2P_GO_NEG_REQ: + case VENDOR_ELEM_P2P_GO_NEG_RESP: + case VENDOR_ELEM_P2P_GO_NEG_CONF: + case VENDOR_ELEM_P2P_INV_REQ: + case VENDOR_ELEM_P2P_INV_RESP: + case VENDOR_ELEM_P2P_ASSOC_REQ: + case VENDOR_ELEM_P2P_ASSOC_RESP: + return wpa_s->parent; +#endif /* CONFIG_P2P */ + default: + return wpa_s; + } +} + + +void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s) +{ + unsigned int i; + char buf[30]; + + wpa_printf(MSG_DEBUG, "Update vendor elements"); + + for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) { + if (wpa_s->vendor_elem[i]) { + int res; + + res = os_snprintf(buf, sizeof(buf), "frame[%u]", i); + if (!os_snprintf_error(sizeof(buf), res)) { + wpa_hexdump_buf(MSG_DEBUG, buf, + wpa_s->vendor_elem[i]); + } + } + } + +#ifdef CONFIG_P2P + if (wpa_s->parent == wpa_s && + wpa_s->global->p2p && + !wpa_s->global->p2p_disabled) + p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem); +#endif /* CONFIG_P2P */ +} + + +int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame, + const u8 *elem, size_t len) +{ + u8 *ie, *end; + + ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]); + end = ie + wpabuf_len(wpa_s->vendor_elem[frame]); + + for (; ie + 1 < end; ie += 2 + ie[1]) { + if (ie + len > end) + break; + if (os_memcmp(ie, elem, len) != 0) + continue; + + if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) { + wpabuf_free(wpa_s->vendor_elem[frame]); + wpa_s->vendor_elem[frame] = NULL; + } else { + os_memmove(ie, ie + len, end - (ie + len)); + wpa_s->vendor_elem[frame]->used -= len; + } + wpas_vendor_elem_update(wpa_s); + return 0; + } + + return -1; +} diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index a8b273bc0..05a1bc669 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1179,6 +1179,12 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx); +void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s); +struct wpa_supplicant * wpas_vendor_elem(struct wpa_supplicant *wpa_s, + enum wpa_vendor_elem_frame frame); +int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame, + const u8 *elem, size_t len); + #ifdef CONFIG_FST struct fst_wpa_obj;