diff options
author | Pyun DoHyun <dh79.pyun@samsung.com> | 2018-05-18 03:01:11 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@review.ap-northeast-2.compute.internal> | 2018-05-18 03:01:11 +0000 |
commit | fd8e51badb18555cc2ff5980844af5cef087e43c (patch) | |
tree | 675d3baff345d8a0b3929d6f2e8fc288d805d506 | |
parent | 709dda0ace16b10d164c84899c7489986e42b454 (diff) | |
parent | c5f8c8712d47efc3903ba2a04af2299388ccf46e (diff) | |
download | bluez-fd8e51badb18555cc2ff5980844af5cef087e43c.tar.gz bluez-fd8e51badb18555cc2ff5980844af5cef087e43c.tar.bz2 bluez-fd8e51badb18555cc2ff5980844af5cef087e43c.zip |
Merge "Import meshctl & bt-shell related apis and fixes" into tizen
-rwxr-xr-x | Makefile.am | 9 | ||||
-rwxr-xr-x | Makefile.tools | 32 | ||||
-rw-r--r-- | client/advertising.c | 164 | ||||
-rwxr-xr-x | client/advertising.h | 8 | ||||
-rwxr-xr-x | client/gatt.c | 57 | ||||
-rw-r--r-- | client/main.c | 88 | ||||
-rwxr-xr-x | gdbus/client.c | 177 | ||||
-rwxr-xr-x | gdbus/gdbus.h | 13 | ||||
-rw-r--r-- | mesh/config-client.c | 547 | ||||
-rw-r--r-- | mesh/config-server.c | 3 | ||||
-rw-r--r-- | mesh/gatt.c | 16 | ||||
-rw-r--r-- | mesh/main.c | 246 | ||||
-rw-r--r-- | mesh/node.c | 24 | ||||
-rw-r--r-- | mesh/node.h | 2 | ||||
-rw-r--r-- | mesh/onoff-model.c | 30 | ||||
-rw-r--r-- | mesh/prov-db.c | 89 | ||||
-rw-r--r-- | mesh/prov-db.h | 2 | ||||
-rw-r--r-- | src/adapter.c | 6 | ||||
-rw-r--r-- | src/device.c | 25 | ||||
-rwxr-xr-x | src/shared/ecc.c | 101 | ||||
-rwxr-xr-x | src/shared/ecc.h | 27 | ||||
-rw-r--r-- | src/shared/mainloop-glib.c | 117 | ||||
-rwxr-xr-x | src/shared/mainloop.c | 4 | ||||
-rwxr-xr-x | src/shared/queue.c | 5 | ||||
-rw-r--r-- | src/shared/shell.c | 530 | ||||
-rw-r--r-- | src/shared/shell.h | 9 | ||||
-rwxr-xr-x | src/shared/util.c | 45 | ||||
-rwxr-xr-x | src/shared/util.h | 3 | ||||
-rwxr-xr-x | tools/bluetooth-player.c | 98 | ||||
-rwxr-xr-x | tools/btmgmt.c | 1532 | ||||
-rwxr-xr-x | tools/obexctl.c | 212 | ||||
-rwxr-xr-x | unit/test-ecc.c | 39 |
32 files changed, 2413 insertions, 1847 deletions
diff --git a/Makefile.am b/Makefile.am index b2c6b87b..f07ef83b 100755 --- a/Makefile.am +++ b/Makefile.am @@ -119,11 +119,16 @@ shared_sources = src/shared/io.h src/shared/timeout.h \ src/shared/gatt-server.h src/shared/gatt-server.c \ src/shared/gatt-db.h src/shared/gatt-db.c \ src/shared/gap.h src/shared/gap.c \ - src/shared/tty.h src/shared/shell.c src/shared/shell.h + src/shared/tty.h + +if READLINE +shared_sources += src/shared/shell.c src/shared/shell.h +endif src_libshared_glib_la_SOURCES = $(shared_sources) \ src/shared/io-glib.c \ - src/shared/timeout-glib.c + src/shared/timeout-glib.c \ + src/shared/mainloop-glib.c src_libshared_mainloop_la_SOURCES = $(shared_sources) \ src/shared/io-mainloop.c \ diff --git a/Makefile.tools b/Makefile.tools index ae448d2b..08e1efaf 100755 --- a/Makefile.tools +++ b/Makefile.tools @@ -17,24 +17,26 @@ if MESH bin_PROGRAMS += mesh/meshctl mesh_meshctl_SOURCES = mesh/main.c \ - mesh/mesh-net.h \ - mesh/node.h mesh/node.c \ - mesh/gatt.h mesh/gatt.c \ - mesh/crypto.h mesh/crypto.c \ - mesh/keys.h \ - mesh/net.h mesh/net.c \ - mesh/prov.h mesh/prov.c \ - mesh/util.h mesh/util.c \ - mesh/agent.h mesh/agent.c \ - mesh/prov-db.h mesh/prov-db.c \ - mesh/config-model.h mesh/config-client.c \ - mesh/config-server.c \ - mesh/onoff-model.h mesh/onoff-model.c + mesh/mesh-net.h \ + mesh/node.h mesh/node.c \ + mesh/gatt.h mesh/gatt.c \ + mesh/crypto.h mesh/crypto.c \ + mesh/keys.h \ + mesh/net.h mesh/net.c \ + mesh/prov.h mesh/prov.c \ + mesh/util.h mesh/util.c \ + mesh/agent.h mesh/agent.c \ + mesh/prov-db.h mesh/prov-db.c \ + mesh/config-model.h mesh/config-client.c \ + mesh/config-server.c \ + mesh/onoff-model.h mesh/onoff-model.c mesh_meshctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ - lib/libbluetooth-internal.la \ - @GLIB_LIBS@ @DBUS_LIBS@ -ljson-c -lreadline + lib/libbluetooth-internal.la \ + @GLIB_LIBS@ @DBUS_LIBS@ -ljson-c -lreadline endif +EXTRA_DIST += mesh/local_node.json mesh/prov_db.json + if MONITOR bin_PROGRAMS += monitor/btmon diff --git a/client/advertising.c b/client/advertising.c index 5ca45998..9b1df12d 100644 --- a/client/advertising.c +++ b/client/advertising.c @@ -32,6 +32,7 @@ #include <string.h> #include "gdbus/gdbus.h" +#include "src/shared/util.h" #include "src/shared/shell.h" #include "advertising.h" @@ -107,6 +108,77 @@ static void register_setup(DBusMessageIter *iter, void *user_data) dbus_message_iter_close_container(iter, &dict); } +static void print_uuid(const char *uuid) +{ + const char *text; + + text = bt_uuidstr_to_str(uuid); + if (text) { + char str[26]; + unsigned int n; + + str[sizeof(str) - 1] = '\0'; + + n = snprintf(str, sizeof(str), "%s", text); + if (n > sizeof(str) - 1) { + str[sizeof(str) - 2] = '.'; + str[sizeof(str) - 3] = '.'; + if (str[sizeof(str) - 4] == ' ') + str[sizeof(str) - 4] = '.'; + + n = sizeof(str) - 1; + } + + bt_shell_printf("UUID: %s(%s)\n", str, uuid); + } else + bt_shell_printf("UUID: (%s)\n", uuid); +} + +static void print_ad_uuids(void) +{ + char **uuid; + + for (uuid = ad.uuids; uuid && *uuid; uuid++) + print_uuid(*uuid); +} + +static void print_ad(void) +{ + print_ad_uuids(); + + if (ad.service.uuid) { + print_uuid(ad.service.uuid); + bt_shell_hexdump(ad.service.data.data, ad.service.data.len); + } + + if (ad.manufacturer.data.len) { + bt_shell_printf("Manufacturer: %u\n", ad.manufacturer.id); + bt_shell_hexdump(ad.manufacturer.data.data, + ad.manufacturer.data.len); + } + + bt_shell_printf("Tx Power: %s\n", ad.tx_power ? "on" : "off"); + + if (ad.local_name) + bt_shell_printf("LocalName: %s\n", ad.local_name); + else + bt_shell_printf("Name: %s\n", ad.name ? "on" : "off"); + + if (ad.local_appearance != UINT16_MAX) + bt_shell_printf("Appearance: %s (0x%04x)\n", + bt_appear_to_str(ad.local_appearance), + ad.local_appearance); + else + bt_shell_printf("Apperance: %s\n", + ad.appearance ? "on" : "off"); + + if (ad.duration) + bt_shell_printf("Duration: %u sec\n", ad.duration); + + if (ad.timeout) + bt_shell_printf("Timeout: %u sec\n", ad.timeout); +} + static void register_reply(DBusMessage *message, void *user_data) { DBusConnection *conn = user_data; @@ -117,6 +189,7 @@ static void register_reply(DBusMessage *message, void *user_data) if (dbus_set_error_from_message(&error, message) == FALSE) { ad.registered = true; bt_shell_printf("Advertising object registered\n"); + print_ad(); } else { bt_shell_printf("Failed to register advertisement: %s\n", error.name); dbus_error_free(&error); @@ -436,13 +509,15 @@ void ad_unregister(DBusConnection *conn, GDBusProxy *manager) void ad_advertise_uuids(DBusConnection *conn, int argc, char *argv[]) { + if (argc < 2 || !strlen(argv[1])) { + print_ad_uuids(); + return; + } + g_strfreev(ad.uuids); ad.uuids = NULL; ad.uuids_len = 0; - if (argc < 2 || !strlen(argv[1])) - return; - ad.uuids = g_strdupv(&argv[1]); if (!ad.uuids) { bt_shell_printf("Failed to parse input\n"); @@ -465,15 +540,16 @@ void ad_advertise_service(DBusConnection *conn, int argc, char *argv[]) unsigned int i; struct ad_data *data; - ad_clear_service(); - - if (argc < 2) + if (argc < 2 || !strlen(argv[1])) { + print_uuid(ad.service.uuid); + bt_shell_hexdump(ad.service.data.data, ad.service.data.len); return; + } ad.service.uuid = g_strdup(argv[1]); data = &ad.service.data; - for (i = 1; i < (unsigned int) argc; i++) { + for (i = 2; i < (unsigned int) argc; i++) { long int val; char *endptr = NULL; @@ -509,10 +585,18 @@ void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[]) long int val; struct ad_data *data; - ad_clear_manufacturer(); + if (argc < 2 || !strlen(argv[1])) { + if (ad.manufacturer.data.len) { + bt_shell_printf("Manufacturer: %u\n", + ad.manufacturer.id); + bt_shell_hexdump(ad.manufacturer.data.data, + ad.manufacturer.data.len); + } - if (argc < 2) return; + } + + ad_clear_manufacturer(); val = strtol(argv[1], &endptr, 0); if (!endptr || *endptr != '\0' || val > UINT16_MAX) { @@ -545,12 +629,17 @@ void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[]) "ManufacturerData"); } -void ad_advertise_tx_power(DBusConnection *conn, bool value) +void ad_advertise_tx_power(DBusConnection *conn, dbus_bool_t *value) { - if (ad.tx_power == value) + if (!value) { + bt_shell_printf("Tx Power: %s\n", ad.tx_power ? "on" : "off"); + return; + } + + if (ad.tx_power == *value) return; - ad.tx_power = value; + ad.tx_power = *value; g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes"); } @@ -572,6 +661,15 @@ void ad_advertise_name(DBusConnection *conn, bool value) void ad_advertise_local_name(DBusConnection *conn, const char *name) { + if (!name) { + if (ad.local_name) + bt_shell_printf("LocalName: %s\n", ad.local_name); + else + bt_shell_printf("Name: %s\n", ad.name ? "on" : "off"); + + return; + } + if (ad.local_name && !strcmp(name, ad.local_name)) return; @@ -594,32 +692,56 @@ void ad_advertise_appearance(DBusConnection *conn, bool value) g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes"); } -void ad_advertise_local_appearance(DBusConnection *conn, uint16_t value) +void ad_advertise_local_appearance(DBusConnection *conn, long int *value) { - if (ad.local_appearance == value) + if (!value) { + if (ad.local_appearance != UINT16_MAX) + bt_shell_printf("Appearance: %s (0x%04x)\n", + bt_appear_to_str(ad.local_appearance), + ad.local_appearance); + else + bt_shell_printf("Apperance: %s\n", + ad.appearance ? "on" : "off"); + return; + } - ad.local_appearance = value; + if (ad.local_appearance == *value) + return; + + ad.local_appearance = *value; g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Appearance"); } -void ad_advertise_duration(DBusConnection *conn, uint16_t value) +void ad_advertise_duration(DBusConnection *conn, long int *value) { - if (ad.duration == value) + if (!value) { + if (ad.duration) + bt_shell_printf("Duration: %u sec\n", ad.duration); + return; + } + + if (ad.duration == *value) return; - ad.duration = value; + ad.duration = *value; g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Duration"); } -void ad_advertise_timeout(DBusConnection *conn, uint16_t value) +void ad_advertise_timeout(DBusConnection *conn, long int *value) { - if (ad.timeout == value) + if (!value) { + if (ad.timeout) + bt_shell_printf("Timeout: %u sec\n", ad.timeout); + return; + } + + if (ad.timeout == *value) return; - ad.timeout = value; + ad.timeout = *value; g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Timeout"); } diff --git a/client/advertising.h b/client/advertising.h index d7472e1a..13e07643 100755 --- a/client/advertising.h +++ b/client/advertising.h @@ -27,10 +27,10 @@ void ad_unregister(DBusConnection *conn, GDBusProxy *manager); void ad_advertise_uuids(DBusConnection *conn, int argc, char *argv[]); void ad_advertise_service(DBusConnection *conn, int argc, char *argv[]); void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[]); -void ad_advertise_tx_power(DBusConnection *conn, bool value); +void ad_advertise_tx_power(DBusConnection *conn, dbus_bool_t *value); void ad_advertise_name(DBusConnection *conn, bool value); void ad_advertise_appearance(DBusConnection *conn, bool value); void ad_advertise_local_name(DBusConnection *conn, const char *name); -void ad_advertise_local_appearance(DBusConnection *conn, uint16_t value); -void ad_advertise_duration(DBusConnection *conn, uint16_t value); -void ad_advertise_timeout(DBusConnection *conn, uint16_t value); +void ad_advertise_local_appearance(DBusConnection *conn, long int *value); +void ad_advertise_duration(DBusConnection *conn, long int *value); +void ad_advertise_timeout(DBusConnection *conn, long int *value); diff --git a/client/gatt.c b/client/gatt.c index 224a78a1..4d51e053 100755 --- a/client/gatt.c +++ b/client/gatt.c @@ -206,25 +206,16 @@ static void print_characteristic(GDBusProxy *proxy, const char *description) static gboolean chrc_is_child(GDBusProxy *characteristic) { - GList *l; DBusMessageIter iter; - const char *service, *path; + const char *service; if (!g_dbus_proxy_get_property(characteristic, "Service", &iter)) return FALSE; dbus_message_iter_get_basic(&iter, &service); - for (l = services; l; l = g_list_next(l)) { - GDBusProxy *proxy = l->data; - - path = g_dbus_proxy_get_path(proxy); - - if (!strcmp(path, service)) - return TRUE; - } - - return FALSE; + return g_dbus_proxy_lookup(services, NULL, service, + "org.bluez.GattService1") != NULL; } void gatt_add_characteristic(GDBusProxy *proxy) @@ -378,33 +369,22 @@ void gatt_list_attributes(const char *path) list_attributes(path, services); } -static GDBusProxy *select_proxy(const char *path, GList *source) -{ - GList *l; - - for (l = source; l; l = g_list_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - static GDBusProxy *select_attribute(const char *path) { GDBusProxy *proxy; - proxy = select_proxy(path, services); + proxy = g_dbus_proxy_lookup(services, NULL, path, + "org.bluez.GattService1"); if (proxy) return proxy; - proxy = select_proxy(path, characteristics); + proxy = g_dbus_proxy_lookup(characteristics, NULL, path, + "org.bluez.GattCharacteristic1"); if (proxy) return proxy; - return select_proxy(path, descriptors); + return g_dbus_proxy_lookup(descriptors, NULL, path, + "org.bluez.GattDescriptor1"); } static GDBusProxy *select_proxy_by_uuid(GDBusProxy *parent, const char *uuid, @@ -465,28 +445,13 @@ GDBusProxy *gatt_select_attribute(GDBusProxy *parent, const char *arg) static char *attribute_generator(const char *text, int state, GList *source) { - static int index, len; - GList *list; + static int index; if (!state) { index = 0; - len = strlen(text); } - for (list = g_list_nth(source, index); list; - list = g_list_next(list)) { - GDBusProxy *proxy = list->data; - const char *path; - - index++; - - path = g_dbus_proxy_get_path(proxy); - - if (!strncmp(path, text, len)) - return strdup(path); - } - - return NULL; + return g_dbus_proxy_path_lookup(source, &index, text); } char *gatt_attribute_generator(const char *text, int state) diff --git a/client/main.c b/client/main.c index 17a92fda..1a0a7c1e 100644 --- a/client/main.c +++ b/client/main.c @@ -392,9 +392,8 @@ static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master) static gboolean service_is_child(GDBusProxy *service) { - GList *l; DBusMessageIter iter; - const char *device, *path; + const char *device; if (g_dbus_proxy_get_property(service, "Device", &iter) == FALSE) return FALSE; @@ -404,16 +403,8 @@ static gboolean service_is_child(GDBusProxy *service) if (!default_ctrl) return FALSE; - for (l = default_ctrl->devices; l; l = g_list_next(l)) { - struct GDBusProxy *proxy = l->data; - - path = g_dbus_proxy_get_path(proxy); - - if (!strcmp(path, device)) - return TRUE; - } - - return FALSE; + return g_dbus_proxy_lookup(default_ctrl->devices, NULL, device, + "org.bluez.Device1") != NULL; } static struct adapter *find_parent(GDBusProxy *device) @@ -2206,33 +2197,43 @@ static char *ad_generator(const char *text, int state) return argument_generator(text, state, ad_arguments); } -static void cmd_set_advertise_uuids(int argc, char *argv[]) +static void cmd_advertise_uuids(int argc, char *argv[]) { ad_advertise_uuids(dbus_conn, argc, argv); } -static void cmd_set_advertise_service(int argc, char *argv[]) +static void cmd_advertise_service(int argc, char *argv[]) { ad_advertise_service(dbus_conn, argc, argv); } -static void cmd_set_advertise_manufacturer(int argc, char *argv[]) +static void cmd_advertise_manufacturer(int argc, char *argv[]) { ad_advertise_manufacturer(dbus_conn, argc, argv); } -static void cmd_set_advertise_tx_power(int argc, char *argv[]) +static void cmd_advertise_tx_power(int argc, char *argv[]) { dbus_bool_t powered; + if (argc < 2) { + ad_advertise_tx_power(dbus_conn, NULL); + return; + } + if (!parse_argument(argc, argv, NULL, NULL, &powered, NULL)) return; - ad_advertise_tx_power(dbus_conn, powered); + ad_advertise_tx_power(dbus_conn, &powered); } -static void cmd_set_advertise_name(int argc, char *argv[]) +static void cmd_advertise_name(int argc, char *argv[]) { + if (argc < 2) { + ad_advertise_local_name(dbus_conn, NULL); + return; + } + if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "yes") == 0) { ad_advertise_name(dbus_conn, true); return; @@ -2246,11 +2247,16 @@ static void cmd_set_advertise_name(int argc, char *argv[]) ad_advertise_local_name(dbus_conn, argv[1]); } -static void cmd_set_advertise_appearance(int argc, char *argv[]) +static void cmd_advertise_appearance(int argc, char *argv[]) { long int value; char *endptr = NULL; + if (argc < 2) { + ad_advertise_local_appearance(dbus_conn, NULL); + return; + } + if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "yes") == 0) { ad_advertise_appearance(dbus_conn, true); return; @@ -2267,59 +2273,69 @@ static void cmd_set_advertise_appearance(int argc, char *argv[]) return; } - ad_advertise_local_appearance(dbus_conn, value); + ad_advertise_local_appearance(dbus_conn, &value); } -static void cmd_set_advertise_duration(int argc, char *argv[]) +static void cmd_advertise_duration(int argc, char *argv[]) { long int value; char *endptr = NULL; + if (argc < 2) { + ad_advertise_duration(dbus_conn, NULL); + return; + } + value = strtol(argv[1], &endptr, 0); if (!endptr || *endptr != '\0' || value > UINT16_MAX) { bt_shell_printf("Invalid argument\n"); return; } - ad_advertise_duration(dbus_conn, value); + ad_advertise_duration(dbus_conn, &value); } -static void cmd_set_advertise_timeout(int argc, char *argv[]) +static void cmd_advertise_timeout(int argc, char *argv[]) { long int value; char *endptr = NULL; + if (argc < 2) { + ad_advertise_timeout(dbus_conn, NULL); + return; + } + value = strtol(argv[1], &endptr, 0); if (!endptr || *endptr != '\0' || value > UINT16_MAX) { bt_shell_printf("Invalid argument\n"); return; } - ad_advertise_timeout(dbus_conn, value); + ad_advertise_timeout(dbus_conn, &value); } static const struct bt_shell_menu advertise_menu = { .name = "advertise", .desc = "Advertise Options Submenu", .entries = { - { "set-uuids", "[uuid1 uuid2 ...]", - cmd_set_advertise_uuids, "Set advertise uuids" }, - { "set-service", "[uuid] [data=xx xx ...]", cmd_set_advertise_service, + { "uuids", "[uuid1 uuid2 ...]", cmd_advertise_uuids, + "Set advertise uuids" }, + { "service", "[uuid] [data=xx xx ...]", cmd_advertise_service, "Set advertise service data" }, - { "set-manufacturer", "[id] [data=xx xx ...]", - cmd_set_advertise_manufacturer, + { "manufacturer", "[id] [data=xx xx ...]", + cmd_advertise_manufacturer, "Set advertise manufacturer data" }, - { "set-tx-power", "<on/off>", cmd_set_advertise_tx_power, + { "tx-power", "[on/off]", cmd_advertise_tx_power, "Enable/disable TX power to be advertised", mode_generator }, - { "set-name", "<on/off/name>", cmd_set_advertise_name, + { "name", "[on/off/name]", cmd_advertise_name, "Enable/disable local name to be advertised" }, - { "set-appearance", "<value>", cmd_set_advertise_appearance, + { "appearance", "[value]", cmd_advertise_appearance, "Set custom appearance to be advertised" }, - { "set-duration", "<seconds>", cmd_set_advertise_duration, - "Set advertise duration" }, - { "set-timeout", "<seconds>", cmd_set_advertise_timeout, - "Set advertise timeout" }, + { "duration", "[seconds]", cmd_advertise_duration, + "Set/Get advertise duration" }, + { "timeout", "[seconds]", cmd_advertise_timeout, + "Set/Get advertise timeout" }, { } }, }; diff --git a/gdbus/client.c b/gdbus/client.c index ab405969..dd5d2eb5 100755 --- a/gdbus/client.c +++ b/gdbus/client.c @@ -26,6 +26,7 @@ #endif #include <stdio.h> +#include <string.h> #include <glib.h> #include <dbus/dbus.h> @@ -126,6 +127,99 @@ static gboolean modify_match(DBusConnection *conn, const char *member, return TRUE; } +static void append_variant(DBusMessageIter *iter, int type, const void *val) +{ + DBusMessageIter value; + char sig[2] = { type, '\0' }; + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value); + + dbus_message_iter_append_basic(&value, type, val); + + dbus_message_iter_close_container(iter, &value); +} + +static void append_array_variant(DBusMessageIter *iter, int type, void *val, + int n_elements) +{ + DBusMessageIter variant, array; + char type_sig[2] = { type, '\0' }; + char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' }; + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + array_sig, &variant); + + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, + type_sig, &array); + + if (dbus_type_is_fixed(type) == TRUE) { + dbus_message_iter_append_fixed_array(&array, type, val, + n_elements); + } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) { + const char ***str_array = val; + int i; + + for (i = 0; i < n_elements; i++) + dbus_message_iter_append_basic(&array, type, + &((*str_array)[i])); + } + + dbus_message_iter_close_container(&variant, &array); + + dbus_message_iter_close_container(iter, &variant); +} + +static void dict_append_basic(DBusMessageIter *dict, int key_type, + const void *key, int type, void *val) +{ + DBusMessageIter entry; + + if (type == DBUS_TYPE_STRING) { + const char *str = *((const char **) val); + if (str == NULL) + return; + } + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, key_type, key); + + append_variant(&entry, type, val); + + dbus_message_iter_close_container(dict, &entry); +} + +void g_dbus_dict_append_entry(DBusMessageIter *dict, + const char *key, int type, void *val) +{ + dict_append_basic(dict, DBUS_TYPE_STRING, &key, type, val); +} + +void g_dbus_dict_append_basic_array(DBusMessageIter *dict, int key_type, + const void *key, int type, void *val, + int n_elements) +{ + DBusMessageIter entry; + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, key_type, key); + + append_array_variant(&entry, type, val, n_elements); + + dbus_message_iter_close_container(dict, &entry); +} + +void g_dbus_dict_append_array(DBusMessageIter *dict, + const char *key, int type, void *val, + int n_elements) +{ + g_dbus_dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val, + n_elements); +} + static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter) { int type; @@ -352,22 +446,49 @@ static void get_all_properties(GDBusProxy *proxy) dbus_message_unref(msg); } -static GDBusProxy *proxy_lookup(GList *list, const char *path, +GDBusProxy *g_dbus_proxy_lookup(GList *list, int *index, const char *path, const char *interface) { GList *l; - for (l = g_list_first(list); l; l = g_list_next(l)) { + if (!interface) + return NULL; + + for (l = g_list_nth(list, index ? *index : 0); l; l = g_list_next(l)) { GDBusProxy *proxy = l->data; + const char *proxy_iface = g_dbus_proxy_get_interface(proxy); + const char *proxy_path = g_dbus_proxy_get_path(proxy); - if (g_str_equal(proxy->interface, interface) == TRUE && - g_str_equal(proxy->obj_path, path) == TRUE) + if (index) + (*index)++; + + if (g_str_equal(proxy_iface, interface) == TRUE && + g_str_equal(proxy_path, path) == TRUE) return proxy; } return NULL; } +char *g_dbus_proxy_path_lookup(GList *list, int *index, const char *path) +{ + int len = strlen(path); + GList *l; + + for (l = g_list_nth(list, index ? *index : 0); l; l = g_list_next(l)) { + GDBusProxy *proxy = l->data; + const char *proxy_path = g_dbus_proxy_get_path(proxy); + + if (index) + (*index)++; + + if (!strncasecmp(proxy_path, path, len)) + return strdup(proxy_path); + } + + return NULL; +} + static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg, void *user_data) { @@ -519,7 +640,8 @@ GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path, if (client == NULL) return NULL; - proxy = proxy_lookup(client->proxy_list, path, interface); + proxy = g_dbus_proxy_lookup(client->proxy_list, NULL, + path, interface); if (proxy) return g_dbus_proxy_ref(proxy); @@ -725,9 +847,8 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy, struct set_property_data *data; GDBusClient *client; DBusMessage *msg; - DBusMessageIter iter, variant; + DBusMessageIter iter; DBusPendingCall *call; - char type_as_str[2]; if (proxy == NULL || name == NULL || value == NULL) return FALSE; @@ -754,18 +875,12 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy, return FALSE; } - type_as_str[0] = (char) type; - type_as_str[1] = '\0'; - dbus_message_iter_init_append(msg, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &proxy->interface); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); - dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, - type_as_str, &variant); - dbus_message_iter_append_basic(&variant, type, value); - dbus_message_iter_close_container(&iter, &variant); + append_variant(&iter, type, value); if (g_dbus_send_message_with_reply(client->dbus_conn, msg, &call, -1) == FALSE) { @@ -790,10 +905,8 @@ gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, struct set_property_data *data; GDBusClient *client; DBusMessage *msg; - DBusMessageIter iter, variant, array; + DBusMessageIter iter; DBusPendingCall *call; - char array_sig[3]; - char type_sig[2]; if (!proxy || !name || !value) return FALSE; @@ -822,37 +935,12 @@ gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, return FALSE; } - array_sig[0] = DBUS_TYPE_ARRAY; - array_sig[1] = (char) type; - array_sig[2] = '\0'; - - type_sig[0] = (char) type; - type_sig[1] = '\0'; - dbus_message_iter_init_append(msg, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &proxy->interface); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); - dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, - array_sig, &variant); - - dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, - type_sig, &array); - - if (dbus_type_is_fixed(type)) - dbus_message_iter_append_fixed_array(&array, type, &value, - size); - else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) { - const char **str = (const char **) value; - size_t i; - - for (i = 0; i < size; i++) - dbus_message_iter_append_basic(&array, type, &str[i]); - } - - dbus_message_iter_close_container(&variant, &array); - dbus_message_iter_close_container(&iter, &variant); + append_array_variant(&iter, type, &value, size); if (g_dbus_send_message_with_reply(client->dbus_conn, msg, &call, -1) == FALSE) { @@ -992,7 +1080,8 @@ static void parse_properties(GDBusClient *client, const char *path, if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) return; - proxy = proxy_lookup(client->proxy_list, path, interface); + proxy = g_dbus_proxy_lookup(client->proxy_list, NULL, + path, interface); if (proxy && !proxy->pending) { update_properties(proxy, iter, FALSE); return; diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h index e40dd44b..df66e794 100755 --- a/gdbus/gdbus.h +++ b/gdbus/gdbus.h @@ -345,6 +345,10 @@ const char *g_dbus_proxy_get_interface(GDBusProxy *proxy); gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name, DBusMessageIter *iter); +GDBusProxy *g_dbus_proxy_lookup(GList *list, int *index, const char *path, + const char *interface); +char *g_dbus_proxy_path_lookup(GList *list, int *index, const char *path); + gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name); typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data); @@ -359,6 +363,15 @@ gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, size_t size, GDBusResultFunction function, void *user_data, GDBusDestroyFunction destroy); +void g_dbus_dict_append_entry(DBusMessageIter *dict, + const char *key, int type, void *val); +void g_dbus_dict_append_basic_array(DBusMessageIter *dict, int key_type, + const void *key, int type, void *val, + int n_elements); +void g_dbus_dict_append_array(DBusMessageIter *dict, + const char *key, int type, void *val, + int n_elements); + typedef void (* GDBusSetupFunction) (DBusMessageIter *iter, void *user_data); typedef void (* GDBusReturnFunction) (DBusMessage *message, void *user_data); diff --git a/mesh/config-client.c b/mesh/config-client.c index f280441c..b6b02ef9 100644 --- a/mesh/config-client.c +++ b/mesh/config-client.c @@ -49,6 +49,23 @@ #define MIN_COMPOSITION_LEN 16 +static uint32_t print_mod_id(uint8_t *data, bool vid) +{ + uint32_t mod_id; + + if (!vid) { + mod_id = get_le16(data); + bt_shell_printf("Model Id\t%4.4x\n", mod_id); + mod_id = 0xffff0000 | mod_id; + } else { + mod_id = get_le16(data + 2); + bt_shell_printf("Model Id\t%4.4x %4.4x\n", + get_le16(data), mod_id); + mod_id = get_le16(data) << 16 | mod_id; + } + return mod_id; +} + static bool client_msg_recvd(uint16_t src, uint8_t *data, uint16_t len, void *user_data) { @@ -101,12 +118,13 @@ static bool client_msg_recvd(uint16_t src, uint8_t *data, if (len != 4) break; - bt_shell_printf("Node %4.4x AppKey Status %s\n", src, + bt_shell_printf("Node %4.4x AppKey status %s\n", src, mesh_status_str(data[0])); net_idx = get_le16(data + 1) & 0xfff; app_idx = get_le16(data + 2) >> 4; - bt_shell_printf("\tNetKey %3.3x, AppKey %3.3x\n", net_idx, app_idx); + bt_shell_printf("NetKey\t%3.3x\n", net_idx); + bt_shell_printf("AppKey\t%3.3x\n", app_idx); if (data[0] != MESH_STATUS_SUCCESS && data[0] != MESH_STATUS_IDX_ALREADY_STORED && @@ -119,7 +137,7 @@ static bool client_msg_recvd(uint16_t src, uint8_t *data, if (len != 3) break; - bt_shell_printf("Node %4.4x NetKey Status %s\n", src, + bt_shell_printf("Node %4.4x NetKey status %s\n", src, mesh_status_str(data[0])); net_idx = get_le16(data + 1) & 0xfff; @@ -136,23 +154,16 @@ static bool client_msg_recvd(uint16_t src, uint8_t *data, if (len != 7 && len != 9) break; - bt_shell_printf("Node %4.4x Model App Status %s\n", src, + bt_shell_printf("Node %4.4x Model App status %s\n", src, mesh_status_str(data[0])); addr = get_le16(data + 1); app_idx = get_le16(data + 3); - bt_shell_printf("\tElement %4.4x AppIdx %3.3x\n ", addr, app_idx); - - if (len == 7) { - mod_id = get_le16(data + 5); - bt_shell_printf("ModelId %4.4x\n", mod_id); - mod_id = 0xffff0000 | mod_id; - } else { - mod_id = get_le16(data + 7); - bt_shell_printf("ModelId %4.4x %4.4x\n", get_le16(data + 5), - mod_id); - mod_id = get_le16(data + 5) << 16 | mod_id; - } + bt_shell_printf("Element Addr\t%4.4x\n", addr); + + mod_id = print_mod_id(data + 5, (len == 9) ? true : false); + + bt_shell_printf("AppIdx\t\t%3.3x\n ", app_idx); if (data[0] == MESH_STATUS_SUCCESS && node_add_binding(node, addr - src, mod_id, app_idx)) @@ -162,24 +173,31 @@ static bool client_msg_recvd(uint16_t src, uint8_t *data, case OP_NODE_IDENTITY_STATUS: if (len != 4) return true; - bt_shell_printf("Network index 0x%04x has " - "Node Identity state 0x%02x %s\n", + bt_shell_printf("Network index 0x%04x " + "Node Identity state 0x%02x status %s\n", get_le16(data + 1), data[3], mesh_status_str(data[0])); break; + case OP_CONFIG_BEACON_STATUS: + if (len != 1) + return true; + bt_shell_printf("Node %4.4x Config Beacon Status 0x%02x\n", + src, data[0]); + break; + case OP_CONFIG_RELAY_STATUS: if (len != 2) return true; - bt_shell_printf("Node %4.4x Relay state: 0x%02x" - " count: %d steps: %d\n", + bt_shell_printf("Node %4.4x Relay state 0x%02x" + " count %d steps %d\n", src, data[0], data[1]>>5, data[1] & 0x1f); break; case OP_CONFIG_PROXY_STATUS: if (len != 1) return true; - bt_shell_printf("Node %4.4x Proxy state: 0x%02x\n", + bt_shell_printf("Node %4.4x Proxy state 0x%02x\n", src, data[0]); break; @@ -195,45 +213,42 @@ static bool client_msg_recvd(uint16_t src, uint8_t *data, if (len != 12 && len != 14) return true; - bt_shell_printf("\nSet publication for node %4.4x status: %s\n", - src, data[0] == MESH_STATUS_SUCCESS ? - "Success" : mesh_status_str(data[0])); + bt_shell_printf("\nNode %4.4x Publication status %s\n", + src, mesh_status_str(data[0])); if (data[0] != MESH_STATUS_SUCCESS) return true; ele_addr = get_le16(data + 1); - mod_id = get_le16(data + 10); - if (len == 14) - mod_id = (mod_id << 16) | get_le16(data + 12); - else - mod_id |= 0xffff0000; + + bt_shell_printf("Element Addr\t%04x\n", ele_addr); + + mod_id = print_mod_id(data + 10, (len == 14) ? true : false); pub.u.addr16 = get_le16(data + 3); pub.app_idx = get_le16(data + 5); pub.ttl = data[7]; pub.period = data[8]; n = (data[8] & 0x3f); - bt_shell_printf("Publication address: 0x%04x\n", pub.u.addr16); + bt_shell_printf("Pub Addr\t%04x\n", pub.u.addr16); switch (data[8] >> 6) { case 0: - bt_shell_printf("Period: %d ms\n", n * 100); + bt_shell_printf("Period\t\t%d ms\n", n * 100); break; case 2: n *= 10; /* fall through */ case 1: - bt_shell_printf("Period: %d sec\n", n); + bt_shell_printf("Period\t\t%d sec\n", n); break; case 3: - bt_shell_printf("Period: %d min\n", n * 10); + bt_shell_printf("Period\t\t%d min\n", n * 10); break; } pub.retransmit = data[9]; - bt_shell_printf("Retransmit count: %d\n", data[9] >> 5); - bt_shell_printf("Retransmit Interval Steps: %d\n", - data[9] & 0x1f); + bt_shell_printf("Rexmit count\t%d\n", data[9] >> 5); + bt_shell_printf("Rexmit steps\t%d\n", data[9] & 0x1f); ele_idx = ele_addr - node_get_primary(node); @@ -248,75 +263,102 @@ static bool client_msg_recvd(uint16_t src, uint8_t *data, /* Per Mesh Profile 4.3.2.19 */ case OP_CONFIG_MODEL_SUB_STATUS: - bt_shell_printf("\nSubscription changed" - " for node %4.4x status: %s\n", src, - data[0] == MESH_STATUS_SUCCESS ? "Success" : - mesh_status_str(data[0])); + bt_shell_printf("\nNode %4.4x Subscription status %s\n", + src, mesh_status_str(data[0])); if (data[0] != MESH_STATUS_SUCCESS) return true; - bt_shell_printf("Element Addr:\t%4.4x\n", get_le16(data + 1)); - bt_shell_printf("Subscr Addr:\t%4.4x\n", get_le16(data + 3)); - bt_shell_printf("Model ID:\t%4.4x\n", get_le16(data + 5)); - break; + ele_addr = get_le16(data + 1); + addr = get_le16(data + 3); + ele_idx = ele_addr - node_get_primary(node); + + bt_shell_printf("Element Addr\t%4.4x\n", ele_addr); + + mod_id = print_mod_id(data + 5, (len == 9) ? true : false); - /* TODO */ - /* Save subscription info in database */ + bt_shell_printf("Subscr Addr\t%4.4x\n", addr); + + /* Save subscriptions in node and database */ + if (node_add_subscription(node, ele_idx, mod_id, addr)) + prov_db_add_subscription(node, ele_idx, mod_id, addr); + break; /* Per Mesh Profile 4.3.2.27 */ case OP_CONFIG_MODEL_SUB_LIST: - bt_shell_printf("\nSubscription list for node %4.4x " - "length: %u status: %s\n", src, len, - data[0] == MESH_STATUS_SUCCESS ? "Success" : - mesh_status_str(data[0])); + bt_shell_printf("\nNode %4.4x Subscription List status %s\n", + src, mesh_status_str(data[0])); if (data[0] != MESH_STATUS_SUCCESS) return true; - bt_shell_printf("Element Addr:\t%4.4x\n", get_le16(data + 1)); - bt_shell_printf("Model ID:\t%4.4x\n", get_le16(data + 3)); + bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1)); + bt_shell_printf("Model ID\t%4.4x\n", get_le16(data + 3)); for (i = 5; i < len; i += 2) - bt_shell_printf("Subscr Addr:\t%4.4x\n", + bt_shell_printf("Subscr Addr\t%4.4x\n", get_le16(data + i)); break; /* Per Mesh Profile 4.3.2.50 */ case OP_MODEL_APP_LIST: - bt_shell_printf("\nModel App Key list for node %4.4x " - "length: %u status: %s\n", src, len, - data[0] == MESH_STATUS_SUCCESS ? "Success" : - mesh_status_str(data[0])); + bt_shell_printf("\nNode %4.4x Model AppIdx " + "status %s\n", src, + mesh_status_str(data[0])); if (data[0] != MESH_STATUS_SUCCESS) return true; - bt_shell_printf("Element Addr:\t%4.4x\n", get_le16(data + 1)); - bt_shell_printf("Model ID:\t%4.4x\n", get_le16(data + 3)); + bt_shell_printf("Element Addr\t%4.4x\n", get_le16(data + 1)); + bt_shell_printf("Model ID\t%4.4x\n", get_le16(data + 3)); for (i = 5; i < len; i += 2) - bt_shell_printf("Model App Key:\t%4.4x\n", + bt_shell_printf("Model AppIdx\t%4.4x\n", get_le16(data + i)); break; /* Per Mesh Profile 4.3.2.63 */ case OP_CONFIG_HEARTBEAT_PUB_STATUS: - bt_shell_printf("\nSet heartbeat for node %4.4x status: %s\n", - src, - data[0] == MESH_STATUS_SUCCESS ? "Success" : - mesh_status_str(data[0])); + bt_shell_printf("\nNode %4.4x Heartbeat publish status %s\n", + src, mesh_status_str(data[0])); + + if (data[0] != MESH_STATUS_SUCCESS) + return true; + + bt_shell_printf("Destination\t%4.4x\n", get_le16(data + 1)); + bt_shell_printf("Count\t\t%2.2x\n", data[3]); + bt_shell_printf("Period\t\t%2.2x\n", data[4]); + bt_shell_printf("TTL\t\t%2.2x\n", data[5]); + bt_shell_printf("Features\t%4.4x\n", get_le16(data + 6)); + bt_shell_printf("Net_Idx\t%4.4x\n", get_le16(data + 8)); + break; + + /* Per Mesh Profile 4.3.2.66 */ + case OP_CONFIG_HEARTBEAT_SUB_STATUS: + bt_shell_printf("\nNode %4.4x Heartbeat subscribe status %s\n", + src, mesh_status_str(data[0])); if (data[0] != MESH_STATUS_SUCCESS) return true; - bt_shell_printf("Destination:\t%4.4x\n", get_le16(data + 1)); - bt_shell_printf("Count:\t\t%2.2x\n", data[3]); - bt_shell_printf("Period:\t\t%2.2x\n", data[4]); - bt_shell_printf("TTL:\t\t%2.2x\n", data[5]); - bt_shell_printf("Features:\t%4.4x\n", get_le16(data + 6)); - bt_shell_printf("Net_Idx:\t%4.4x\n", get_le16(data + 8)); + bt_shell_printf("Source\t\t%4.4x\n", get_le16(data + 1)); + bt_shell_printf("Destination\t%4.4x\n", get_le16(data + 3)); + bt_shell_printf("Period\t\t%2.2x\n", data[5]); + bt_shell_printf("Count\t\t%2.2x\n", data[6]); + bt_shell_printf("Min Hops\t%2.2x\n", data[7]); + bt_shell_printf("Max Hops\t%2.2x\n", data[8]); + break; + + /* Per Mesh Profile 4.3.2.54 */ + case OP_NODE_RESET_STATUS: + bt_shell_printf("Node %4.4x reset status %s\n", + src, mesh_status_str(data[0])); + + net_release_address(node_get_primary(node), + (node_get_num_elements(node))); + /* TODO: Remove node info from database */ + node_free(node); break; } @@ -351,7 +393,7 @@ static uint32_t read_input_parameters(int argc, char *argv[]) return i; } -static void cmd_set_node(int argc, char *argv[]) +static void cmd_node_set(int argc, char *argv[]) { uint32_t dst; char *end; @@ -361,10 +403,12 @@ static void cmd_set_node(int argc, char *argv[]) bt_shell_printf("Bad unicast address %s: " "expected format 4 digit hex\n", argv[1]); target = UNASSIGNED_ADDRESS; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } else { bt_shell_printf("Configuring node %4.4x\n", dst); target = dst; set_menu_prompt("config", argv[1]); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } } @@ -395,17 +439,21 @@ static void cmd_default(uint32_t opcode) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(opcode, msg); - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send command (opcode 0x%x)\n", opcode); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_get_composition(int argc, char *argv[]) +static void cmd_composition_get(int argc, char *argv[]) { uint16_t n; uint8_t msg[32]; @@ -413,21 +461,25 @@ static void cmd_get_composition(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } node = node_find_by_addr(target); if (!node) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); n = mesh_opcode_set(OP_DEV_COMP_GET, msg); /* By default, use page 0 */ msg[n++] = (read_input_parameters(argc, argv) == 1) ? parms[0] : 0; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"GET NODE COMPOSITION\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_net_key(int argc, char *argv[], uint32_t opcode) @@ -440,20 +492,20 @@ static void cmd_net_key(int argc, char *argv[], uint32_t opcode) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(opcode, msg); if (read_input_parameters(argc, argv) != 1) { bt_shell_printf("Bad arguments %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } node = node_find_by_addr(target); if (!node) { bt_shell_printf("Node %4.4x\n not found", target); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } net_idx = parms[0]; @@ -462,9 +514,9 @@ static void cmd_net_key(int argc, char *argv[], uint32_t opcode) key = keys_net_key_get(net_idx, true); if (!key) { - bt_shell_printf("Network key with index %4.4x not found\n", + bt_shell_printf("NetKey with index %4.4x not found\n", net_idx); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } put_le16(net_idx, &msg[n]); @@ -477,7 +529,7 @@ static void cmd_net_key(int argc, char *argv[], uint32_t opcode) if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"%s NET KEY\"\n", opcode == OP_NETKEY_ADD ? "ADD" : "DEL"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (opcode != OP_NETKEY_DELETE) { @@ -490,14 +542,15 @@ static void cmd_net_key(int argc, char *argv[], uint32_t opcode) "netKeys"); } + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_add_net_key(int argc, char *argv[]) +static void cmd_netkey_add(int argc, char *argv[]) { cmd_net_key(argc, argv, OP_NETKEY_ADD); } -static void cmd_del_net_key(int argc, char *argv[]) +static void cmd_netkey_del(int argc, char *argv[]) { cmd_net_key(argc, argv, OP_NETKEY_DELETE); } @@ -513,18 +566,18 @@ static void cmd_app_key(int argc, char *argv[], uint32_t opcode) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (read_input_parameters(argc, argv) != 1) { bt_shell_printf("Bad arguments %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } node = node_find_by_addr(target); if (!node) { bt_shell_printf("Node %4.4x\n not found", target); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(opcode, msg); @@ -532,8 +585,8 @@ static void cmd_app_key(int argc, char *argv[], uint32_t opcode) app_idx = parms[0]; net_idx = keys_app_key_get_bound(app_idx); if (net_idx == NET_IDX_INVALID) { - bt_shell_printf("App key with index %4.4x not found\n", app_idx); - return; + bt_shell_printf("AppKey with index %4.4x not found\n", app_idx); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } msg[n++] = net_idx & 0xf; @@ -544,7 +597,7 @@ static void cmd_app_key(int argc, char *argv[], uint32_t opcode) if (opcode != OP_APPKEY_DELETE) { key = keys_app_key_get(app_idx, true); if (!key) { - bt_shell_printf("App key %4.4x not found\n", net_idx); + bt_shell_printf("AppKey %4.4x not found\n", net_idx); return; } @@ -555,7 +608,7 @@ static void cmd_app_key(int argc, char *argv[], uint32_t opcode) if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"ADD %s KEY\"\n", opcode == OP_APPKEY_ADD ? "ADD" : "DEL"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (opcode != OP_APPKEY_DELETE) { @@ -567,14 +620,16 @@ static void cmd_app_key(int argc, char *argv[], uint32_t opcode) prov_db_node_keys(node, node_get_app_keys(node), "appKeys"); } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_add_app_key(int argc, char *argv[]) +static void cmd_appkey_add(int argc, char *argv[]) { cmd_app_key(argc, argv, OP_APPKEY_ADD); } -static void cmd_del_app_key(int argc, char *argv[]) +static void cmd_appkey_del(int argc, char *argv[]) { cmd_app_key(argc, argv, OP_APPKEY_DELETE); } @@ -590,7 +645,8 @@ static bool verify_config_target(uint32_t dst) node = node_find_by_addr(dst); if (!node) { - bt_shell_printf("Node with unicast address %4.4x unknown\n", dst); + bt_shell_printf("Node with unicast address %4.4x unknown\n", + dst); return false; } @@ -609,12 +665,12 @@ static void cmd_bind(int argc, char *argv[]) int parm_cnt; if (!verify_config_target(target)) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 3 && parm_cnt != 4) { bt_shell_printf("Bad arguments\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(OP_MODEL_APP_BIND, msg); @@ -632,118 +688,169 @@ static void cmd_bind(int argc, char *argv[]) n += 2; } - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"MODEL APP BIND\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_set_ident(int argc, char *argv[]) +static void cmd_beacon_set(int argc, char *argv[]) { uint16_t n; - uint8_t msg[2 + 3 + 4]; + uint8_t msg[2 + 1]; int parm_cnt; if (!verify_config_target(target)) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + n = mesh_opcode_set(OP_CONFIG_BEACON_SET, msg); + + parm_cnt = read_input_parameters(argc, argv); + if (parm_cnt != 1) { + bt_shell_printf("bad arguments\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + msg[n++] = parms[0]; + + if (!config_send(msg, n)) { + bt_shell_printf("Failed to send \"SET BEACON\"\n"); return; + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_beacon_get(int argc, char *argv[]) +{ + cmd_default(OP_CONFIG_BEACON_GET); +} + +static void cmd_ident_set(int argc, char *argv[]) +{ + uint16_t n; + uint8_t msg[2 + 3 + 4]; + int parm_cnt; + + if (!verify_config_target(target)) + return bt_shell_noninteractive_quit(EXIT_FAILURE); n = mesh_opcode_set(OP_NODE_IDENTITY_SET, msg); parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 2) { bt_shell_printf("bad arguments\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } put_le16(parms[0], msg + n); n += 2; msg[n++] = parms[1]; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"SET IDENTITY\"\n"); + return; + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_get_ident(int argc, char *argv[]) +static void cmd_ident_get(int argc, char *argv[]) { uint16_t n; uint8_t msg[2 + 2 + 4]; int parm_cnt; if (!verify_config_target(target)) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); n = mesh_opcode_set(OP_NODE_IDENTITY_GET, msg); parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 1) { bt_shell_printf("bad arguments\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } put_le16(parms[0], msg + n); n += 2; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"GET IDENTITY\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_set_proxy(int argc, char *argv[]) +static void cmd_proxy_set(int argc, char *argv[]) { uint16_t n; - uint8_t msg[2 + 1 + 4]; + uint8_t msg[2 + 1]; int parm_cnt; if (!verify_config_target(target)) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); n = mesh_opcode_set(OP_CONFIG_PROXY_SET, msg); parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 1) { bt_shell_printf("bad arguments"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } msg[n++] = parms[0]; - msg[n++] = parms[1]; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"SET PROXY\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_get_proxy(int argc, char *argv[]) +static void cmd_proxy_get(int argc, char *argv[]) { cmd_default(OP_CONFIG_PROXY_GET); } -static void cmd_set_relay(int argc, char *argv[]) +static void cmd_relay_set(int argc, char *argv[]) { uint16_t n; uint8_t msg[2 + 2 + 4]; int parm_cnt; if (!verify_config_target(target)) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); n = mesh_opcode_set(OP_CONFIG_RELAY_SET, msg); parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 3) { bt_shell_printf("bad arguments\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } msg[n++] = parms[0]; msg[n++] = (parms[1] << 5) | parms[2]; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"SET RELAY\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_get_relay(int argc, char *argv[]) +static void cmd_relay_get(int argc, char *argv[]) { cmd_default(OP_CONFIG_RELAY_GET); } -static void cmd_set_ttl(int argc, char *argv[]) +static void cmd_ttl_set(int argc, char *argv[]) { uint16_t n; uint8_t msg[32]; @@ -752,7 +859,7 @@ static void cmd_set_ttl(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_SET, msg); @@ -765,25 +872,29 @@ static void cmd_set_ttl(int argc, char *argv[]) msg[n++] = ttl; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"SET_DEFAULT TTL\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_set_pub(int argc, char *argv[]) +static void cmd_pub_set(int argc, char *argv[]) { uint16_t n; uint8_t msg[32]; int parm_cnt; if (!verify_config_target(target)) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_SET, msg); parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 6 && parm_cnt != 7) { bt_shell_printf("Bad arguments\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } put_le16(parms[0], msg + n); @@ -791,7 +902,7 @@ static void cmd_set_pub(int argc, char *argv[]) /* Publish address */ put_le16(parms[1], msg + n); n += 2; - /* App key index + credential (set to 0) */ + /* AppKey index + credential (set to 0) */ put_le16(parms[2], msg + n); n += 2; /* TTL */ @@ -810,11 +921,15 @@ static void cmd_set_pub(int argc, char *argv[]) n += 2; } - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"SET MODEL PUBLICATION\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_get_pub(int argc, char *argv[]) +static void cmd_pub_get(int argc, char *argv[]) { uint16_t n; uint8_t msg[32]; @@ -822,7 +937,7 @@ static void cmd_get_pub(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_GET, msg); @@ -830,7 +945,7 @@ static void cmd_get_pub(int argc, char *argv[]) parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 2 && parm_cnt != 3) { bt_shell_printf("Bad arguments: %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } /* Element Address */ @@ -846,8 +961,12 @@ static void cmd_get_pub(int argc, char *argv[]) n += 2; } - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"GET MODEL PUBLICATION\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_sub_add(int argc, char *argv[]) @@ -858,7 +977,7 @@ static void cmd_sub_add(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(OP_CONFIG_MODEL_SUB_ADD, msg); @@ -866,7 +985,7 @@ static void cmd_sub_add(int argc, char *argv[]) parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 3) { bt_shell_printf("Bad arguments: %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } /* Per Mesh Profile 4.3.2.19 */ @@ -880,8 +999,12 @@ static void cmd_sub_add(int argc, char *argv[]) put_le16(parms[2], msg + n); n += 2; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"ADD SUBSCRIPTION\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_sub_get(int argc, char *argv[]) @@ -892,7 +1015,7 @@ static void cmd_sub_get(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(OP_CONFIG_MODEL_SUB_GET, msg); @@ -900,7 +1023,7 @@ static void cmd_sub_get(int argc, char *argv[]) parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 2) { bt_shell_printf("Bad arguments: %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } /* Per Mesh Profile 4.3.2.27 */ @@ -911,11 +1034,15 @@ static void cmd_sub_get(int argc, char *argv[]) put_le16(parms[1], msg + n); n += 2; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"GET SUB GET\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_get_app(int argc, char *argv[]) +static void cmd_mod_appidx_get(int argc, char *argv[]) { uint16_t n; uint8_t msg[32]; @@ -923,7 +1050,7 @@ static void cmd_get_app(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(OP_MODEL_APP_GET, msg); @@ -931,7 +1058,7 @@ static void cmd_get_app(int argc, char *argv[]) parm_cnt = read_input_parameters(argc, argv); if (parm_cnt != 2) { bt_shell_printf("Bad arguments: %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } /* Per Mesh Profile 4.3.2.49 */ @@ -942,11 +1069,15 @@ static void cmd_get_app(int argc, char *argv[]) put_le16(parms[1], msg + n); n += 2; - if (!config_send(msg, n)) + if (!config_send(msg, n)) { bt_shell_printf("Failed to send \"GET APP GET\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_set_hb(int argc, char *argv[]) +static void cmd_hb_pub_set(int argc, char *argv[]) { uint16_t n; uint8_t msg[32]; @@ -954,15 +1085,15 @@ static void cmd_set_hb(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(OP_CONFIG_HEARTBEAT_PUB_SET, msg); parm_cnt = read_input_parameters(argc, argv); - if (parm_cnt != 5) { + if (parm_cnt != 6) { bt_shell_printf("Bad arguments: %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } /* Per Mesh Profile 4.3.2.62 */ @@ -974,72 +1105,140 @@ static void cmd_set_hb(int argc, char *argv[]) /* Period Log */ msg[n++] = parms[2]; /* Heartbeat TTL */ - msg[n++] = DEFAULT_TTL; + msg[n++] = parms[3]; /* Features */ - put_le16(parms[3], msg + n); + put_le16(parms[4], msg + n); n += 2; /* NetKey Index */ - put_le16(parms[4], msg + n); + put_le16(parms[5], msg + n); n += 2; - if (!config_send(msg, n)) - bt_shell_printf("Failed to send \"SET HEARTBEAT PUBLICATION\"\n"); + if (!config_send(msg, n)) { + bt_shell_printf("Failed to send \"SET HEARTBEAT PUBLISH\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_hb_pub_get(int argc, char *argv[]) +{ + cmd_default(OP_CONFIG_HEARTBEAT_PUB_GET); } -static void cmd_get_ttl(int argc, char *argv[]) +static void cmd_hb_sub_set(int argc, char *argv[]) +{ + uint16_t n; + uint8_t msg[32]; + int parm_cnt; + + if (IS_UNASSIGNED(target)) { + bt_shell_printf("Destination not set\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + n = mesh_opcode_set(OP_CONFIG_HEARTBEAT_SUB_SET, msg); + + parm_cnt = read_input_parameters(argc, argv); + if (parm_cnt != 3) { + bt_shell_printf("Bad arguments: %s\n", argv[1]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + /* Per Mesh Profile 4.3.2.65 */ + /* Source address */ + put_le16(parms[0], msg + n); + n += 2; + /* Destination address */ + put_le16(parms[1], msg + n); + n += 2; + /* Period log */ + msg[n++] = parms[2]; + + if (!config_send(msg, n)) { + bt_shell_printf("Failed to send \"SET HEARTBEAT SUBSCRIBE\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_hb_sub_get(int argc, char *argv[]) +{ + cmd_default(OP_CONFIG_HEARTBEAT_SUB_GET); +} + +static void cmd_ttl_get(int argc, char *argv[]) { cmd_default(OP_CONFIG_DEFAULT_TTL_GET); } +static void cmd_node_reset(int argc, char *argv[]) +{ + cmd_default(OP_NODE_RESET); +} + static const struct bt_shell_menu cfg_menu = { .name = "config", .desc = "Configuration Model Submenu", .entries = { - {"target", "<unicast>", cmd_set_node, + {"target", "<unicast>", cmd_node_set, "Set target node to configure"}, - {"composition-get", "[page_num]", cmd_get_composition, - "Get Composition Data"}, - {"netkey-add", "<net_idx>", cmd_add_net_key, + {"composition-get", "[page_num]", cmd_composition_get, + "Get composition data"}, + {"netkey-add", "<net_idx>", cmd_netkey_add, "Add network key"}, - {"netkey-del", "<net_idx>", cmd_del_net_key, + {"netkey-del", "<net_idx>", cmd_netkey_del, "Delete network key"}, - {"appkey-add", "<app_idx>", cmd_add_app_key, + {"appkey-add", "<app_idx>", cmd_appkey_add, "Add application key"}, - {"appkey-del", "<app_idx>", cmd_del_app_key, + {"appkey-del", "<app_idx>", cmd_appkey_del, "Delete application key"}, {"bind", "<ele_idx> <app_idx> <mod_id> [cid]", cmd_bind, "Bind app key to a model"}, - {"ttl-set", "<ttl>", cmd_set_ttl, + {"mod-appidx-get", "<ele_addr> <model id>", + cmd_mod_appidx_get, "Get model app_idx"}, + {"ttl-set", "<ttl>", cmd_ttl_set, "Set default TTL"}, - {"ttl-get", NULL, cmd_get_ttl, + {"ttl-get", NULL, cmd_ttl_get, "Get default TTL"}, {"pub-set", "<ele_addr> <pub_addr> <app_idx> " "<per (step|res)> <re-xmt (cnt|per)> <mod id> " "[cid]", - cmd_set_pub, "\n\t\t\t\t\t\t Set publication"}, - {"pub-get", "<ele_addr> <model>", cmd_get_pub, + cmd_pub_set, "\n\t\t\t\t\t\t Set publication"}, + {"pub-get", "<ele_addr> <model>", cmd_pub_get, "Get publication"}, - {"proxy-set", "<proxy>", cmd_set_proxy, + {"proxy-set", "<proxy>", cmd_proxy_set, "Set proxy state"}, - {"proxy-get", NULL, cmd_get_proxy, + {"proxy-get", NULL, cmd_proxy_get, "Get proxy state"}, - {"ident-set", "<net_idx> <state>", cmd_set_ident, + {"ident-set", "<net_idx> <state>", cmd_ident_set, "Set node identity state"}, - {"ident-get", "<net_idx>", cmd_get_ident, + {"ident-get", "<net_idx>", cmd_ident_get, "Get node identity state"}, + {"beacon-set", "<state>", cmd_beacon_set, + "Set node identity state"}, + {"beacon-get", NULL, cmd_beacon_get, + "Get node beacon state"}, {"relay-set", "<relay> <rexmt count> <rexmt steps>", - cmd_set_relay, + cmd_relay_set, "Set relay"}, - {"relay-get", NULL, cmd_get_relay, + {"relay-get", NULL, cmd_relay_get, "Get relay"}, - {"hb-pub-set", "<pub_addr> <count> <period> <features> <net_idx>", - cmd_set_hb, "Set heartbeati publish"}, + {"hb-pub-set", "<pub_addr> <count> <period> <ttl> <features> <net_idx>", + cmd_hb_pub_set, "Set heartbeat publish"}, + {"hb-pub-get", NULL, cmd_hb_pub_get, + "Get heartbeat publish"}, + {"hb-sub-set", "<src_addr> <dst_addr> <period>", + cmd_hb_sub_set, "Set heartbeat subscribe"}, + {"hb-sub-get", NULL, cmd_hb_sub_get, + "Get heartbeat subscribe"}, {"sub-add", "<ele_addr> <sub_addr> <model id>", - cmd_sub_add, "Subscription add"}, + cmd_sub_add, "Add subscription"}, {"sub-get", "<ele_addr> <model id>", - cmd_sub_get, "Subscription get"}, - {"app-get", "<ele_addr> <model id>", - cmd_get_app, "Get App Keys"}, + cmd_sub_get, "Get subscription"}, + {"node-reset", NULL, cmd_node_reset, + "Reset a node and remove it from network"}, {} }, }; @@ -1048,7 +1247,7 @@ void config_client_get_composition(uint32_t dst) uint32_t tmp = target; target = dst; - cmd_get_composition(0, NULL); + cmd_composition_get(0, NULL); target = tmp; } diff --git a/mesh/config-server.c b/mesh/config-server.c index 10fead6e..2d657637 100644 --- a/mesh/config-server.c +++ b/mesh/config-server.c @@ -129,7 +129,8 @@ static bool server_msg_recvd(uint16_t src, uint8_t *data, pub.retransmit = data[8]; bt_shell_printf("Retransmit count: %d\n", data[8] >> 5); - bt_shell_printf("Retransmit Interval Steps: %d\n", data[8] & 0x1f); + bt_shell_printf("Retransmit Interval Steps: %d\n", + data[8] & 0x1f); ele_idx = ele_addr - node_get_primary(node); diff --git a/mesh/gatt.c b/mesh/gatt.c index 9116a9de..693577a3 100644 --- a/mesh/gatt.c +++ b/mesh/gatt.c @@ -383,7 +383,7 @@ static bool pipe_read(struct io *io, bool prov, void *user_data) uint8_t buf[512]; uint8_t *res; int fd = io_get_fd(io); - ssize_t len; + ssize_t len, len_sar; if (io != notify_io) return true; @@ -393,14 +393,14 @@ static bool pipe_read(struct io *io, bool prov, void *user_data) break; res = buf; - mesh_gatt_sar(&res, len); - - if (prov) - prov_data_ready(node, res, len); - else - net_data_ready(res, len); + len_sar = mesh_gatt_sar(&res, len); + if (len_sar) { + if (prov) + prov_data_ready(node, res, len_sar); + else + net_data_ready(res, len_sar); + } } - return true; } diff --git a/mesh/main.c b/mesh/main.c index b5ec4bcd..3e1484f6 100644 --- a/mesh/main.c +++ b/mesh/main.c @@ -637,12 +637,14 @@ static void connect_reply(DBusMessage *message, void *user_data) bt_shell_printf("Failed to connect: %s\n", error.name); dbus_error_free(&error); set_connected_device(NULL); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } bt_shell_printf("Connection successful\n"); set_connected_device(proxy); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void update_device_info(GDBusProxy *proxy) @@ -921,8 +923,10 @@ static GDBusProxy *get_characteristic(GDBusProxy *device, const char *char_uuid) for (l = char_list; l; l = l->next) { if (mesh_gatt_is_child(l->data, service, "Service") && char_is_mesh(l->data, char_uuid)) { - bt_shell_printf("Found matching char: path %s, uuid %s\n", - g_dbus_proxy_get_path(l->data), char_uuid); + bt_shell_printf("Found matching char: path %s," + " uuid %s\n", + g_dbus_proxy_get_path(l->data), + char_uuid); return l->data; } } @@ -945,7 +949,6 @@ static void mesh_session_setup(GDBusProxy *proxy) data_out_notify(connection.data_out, true, notify_prov_out_cb); } else if (connection.type != CONN_TYPE_INVALID){ - connection.data_in = get_characteristic(proxy, MESH_PROXY_DATA_IN_UUID_STR); if (!connection.data_in) @@ -982,13 +985,15 @@ static void proxy_added(GDBusProxy *proxy, void *user_data) } else if (!strcmp(interface, "org.bluez.GattService1") && service_is_mesh(proxy, NULL)) { - bt_shell_printf("Service added %s\n", g_dbus_proxy_get_path(proxy)); + bt_shell_printf("Service added %s\n", + g_dbus_proxy_get_path(proxy)); service_list = g_list_append(service_list, proxy); } else if (!strcmp(interface, "org.bluez.GattCharacteristic1") && char_is_mesh(proxy, NULL)) { - bt_shell_printf("Char added %s:\n", g_dbus_proxy_get_path(proxy)); + bt_shell_printf("Char added %s:\n", + g_dbus_proxy_get_path(proxy)); char_list = g_list_append(char_list, proxy); } @@ -1005,10 +1010,13 @@ static void start_discovery_reply(DBusMessage *message, void *user_data) bt_shell_printf("Failed to %s discovery: %s\n", enable == TRUE ? "start" : "stop", error.name); dbus_error_free(&error); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } - bt_shell_printf("Discovery %s\n", enable == TRUE ? "started" : "stopped"); + bt_shell_printf("Discovery %s\n", + enable == TRUE ? "started" : "stopped"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct mesh_device *find_device_by_proxy(GList *source, @@ -1193,8 +1201,10 @@ static void property_changed(GDBusProxy *proxy, const char *name, if (connected && connection.device == NULL) set_connected_device(proxy); else if (!connected && - connection.device == proxy) + connection.device == proxy) { + net_session_close(connection.data_in); set_connected_device(NULL); + } } else if ((strcmp(name, "Alias") == 0) && connection.device == proxy) { /* Re-generate prompt */ @@ -1206,8 +1216,8 @@ static void property_changed(GDBusProxy *proxy, const char *name, dbus_message_iter_get_basic(iter, &resolved); - bt_shell_printf("Services resolved %s\n", resolved ? - "yes" : "no"); + bt_shell_printf("Services resolved %s\n", + resolved ? "yes" : "no"); if (resolved) mesh_session_setup(connection.device); @@ -1306,6 +1316,8 @@ static void cmd_list(int argc, char *argv[]) struct adapter *adapter = list->data; print_adapter(adapter->proxy, NULL); } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_show(int argc, char *argv[]) @@ -1318,7 +1330,7 @@ static void cmd_show(int argc, char *argv[]) if (argc < 2 || !strlen(argv[1])) { if (check_default_ctrl() == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); proxy = default_ctrl->proxy; } else { @@ -1326,13 +1338,13 @@ static void cmd_show(int argc, char *argv[]) if (!adapter) { bt_shell_printf("Controller %s not available\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } proxy = adapter->proxy; } if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); dbus_message_iter_get_basic(&iter, &address); bt_shell_printf("Controller %s\n", address); @@ -1345,6 +1357,8 @@ static void cmd_show(int argc, char *argv[]) print_uuids(proxy); print_property(proxy, "Modalias"); print_property(proxy, "Discovering"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_select(int argc, char *argv[]) @@ -1354,26 +1368,31 @@ static void cmd_select(int argc, char *argv[]) adapter = find_ctrl_by_address(ctrl_list, argv[1]); if (!adapter) { bt_shell_printf("Controller %s not available\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (default_ctrl && default_ctrl->proxy == adapter->proxy) - return; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); forget_mesh_devices(); default_ctrl = adapter; print_adapter(adapter->proxy, NULL); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void generic_callback(const DBusError *error, void *user_data) { char *str = user_data; - if (dbus_error_is_set(error)) + if (dbus_error_is_set(error)) { bt_shell_printf("Failed to set %s: %s\n", str, error->name); - else + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } else { bt_shell_printf("Changing %s succeeded\n", str); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } } static void cmd_power(int argc, char *argv[]) @@ -1382,10 +1401,10 @@ static void cmd_power(int argc, char *argv[]) char *str; if (parse_argument_on_off(argc, argv, &powered) == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); if (check_default_ctrl() == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off"); @@ -1395,93 +1414,8 @@ static void cmd_power(int argc, char *argv[]) return; g_free(str); -} - -static void append_variant(DBusMessageIter *iter, int type, void *val) -{ - DBusMessageIter value; - char sig[2] = { type, '\0' }; - dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value); - - dbus_message_iter_append_basic(&value, type, val); - - dbus_message_iter_close_container(iter, &value); -} - -static void append_array_variant(DBusMessageIter *iter, int type, void *val, - int n_elements) -{ - DBusMessageIter variant, array; - char type_sig[2] = { type, '\0' }; - char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' }; - - dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, - array_sig, &variant); - - dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, - type_sig, &array); - - if (dbus_type_is_fixed(type) == TRUE) { - dbus_message_iter_append_fixed_array(&array, type, val, - n_elements); - } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) { - const char ***str_array = val; - int i; - - for (i = 0; i < n_elements; i++) - dbus_message_iter_append_basic(&array, type, - &((*str_array)[i])); - } - - dbus_message_iter_close_container(&variant, &array); - - dbus_message_iter_close_container(iter, &variant); -} - -static void dict_append_entry(DBusMessageIter *dict, const char *key, - int type, void *val) -{ - DBusMessageIter entry; - - if (type == DBUS_TYPE_STRING) { - const char *str = *((const char **) val); - - if (str == NULL) - return; - } - - dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, - NULL, &entry); - - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); - - append_variant(&entry, type, val); - - dbus_message_iter_close_container(dict, &entry); -} - -static void dict_append_basic_array(DBusMessageIter *dict, int key_type, - const void *key, int type, void *val, - int n_elements) -{ - DBusMessageIter entry; - - dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, - NULL, &entry); - - dbus_message_iter_append_basic(&entry, key_type, key); - - append_array_variant(&entry, type, val, n_elements); - - dbus_message_iter_close_container(dict, &entry); -} - -static void dict_append_array(DBusMessageIter *dict, const char *key, int type, - void *val, int n_elements) -{ - dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val, - n_elements); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } #define DISTANCE_VAL_INVALID 0x7FFF @@ -1506,21 +1440,24 @@ static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data) DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &args->uuids, + g_dbus_dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, + &args->uuids, args->uuids_len); if (args->pathloss != DISTANCE_VAL_INVALID) - dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16, + g_dbus_dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16, &args->pathloss); if (args->rssi != DISTANCE_VAL_INVALID) - dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16, &args->rssi); + g_dbus_dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16, + &args->rssi); if (args->transport != NULL) - dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING, + g_dbus_dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING, &args->transport); if (args->duplicate) - dict_append_entry(&dict, "DuplicateData", DBUS_TYPE_BOOLEAN, + g_dbus_dict_append_entry(&dict, "DuplicateData", + DBUS_TYPE_BOOLEAN, &args->duplicate); dbus_message_iter_close_container(iter, &dict); @@ -1535,10 +1472,12 @@ static void set_discovery_filter_reply(DBusMessage *message, void *user_data) if (dbus_set_error_from_message(&error, message) == TRUE) { bt_shell_printf("SetDiscoveryFilter failed: %s\n", error.name); dbus_error_free(&error); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } bt_shell_printf("SetDiscoveryFilter success\n"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static gint filtered_scan_rssi = DISTANCE_VAL_INVALID; @@ -1559,13 +1498,13 @@ static void set_scan_filter_commit(void) args.duplicate = TRUE; if (check_default_ctrl() == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter", set_discovery_filter_setup, set_discovery_filter_reply, &args, NULL) == FALSE) { bt_shell_printf("Failed to set discovery filter\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1581,7 +1520,7 @@ static void set_scan_filter_uuids(char *filters[]) filtered_scan_uuids = g_strdupv(filters); if (!filtered_scan_uuids) { bt_shell_printf("Failed to parse input\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } filtered_scan_uuids_len = g_strv_length(filtered_scan_uuids); @@ -1597,10 +1536,10 @@ static void cmd_scan_unprovisioned(int argc, char *argv[]) const char *method; if (parse_argument_on_off(argc, argv, &enable) == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); if (check_default_ctrl() == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); if (enable == TRUE) { discover_mesh = false; @@ -1615,6 +1554,7 @@ static void cmd_scan_unprovisioned(int argc, char *argv[]) GUINT_TO_POINTER(enable), NULL) == FALSE) { bt_shell_printf("Failed to %s discovery\n", enable == TRUE ? "start" : "stop"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1626,10 +1566,10 @@ static void cmd_info(int argc, char *argv[]) proxy = connection.device; if (!proxy) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); dbus_message_iter_get_basic(&iter, &address); bt_shell_printf("Device %s\n", address); @@ -1648,6 +1588,8 @@ static void cmd_info(int argc, char *argv[]) print_property(proxy, "ServiceData"); print_property(proxy, "RSSI"); print_property(proxy, "TxPower"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static const char *security2str(uint8_t level) @@ -1675,13 +1617,15 @@ static void cmd_security(int argc, char *argv[]) level = strtol(argv[1], &end, 10); if (end == argv[1] || !prov_set_sec_level(level)) { bt_shell_printf("Invalid security level %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } done: bt_shell_printf("Provision Security Level set to %u (%s)\n", prov_get_sec_level(), security2str(prov_get_sec_level())); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_connect(int argc, char *argv[]) @@ -1689,7 +1633,7 @@ static void cmd_connect(int argc, char *argv[]) char *filters[] = { MESH_PROXY_SVC_UUID, NULL }; if (check_default_ctrl() == FALSE) - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); memset(&connection, 0, sizeof(connection)); @@ -1701,7 +1645,7 @@ static void cmd_connect(int argc, char *argv[]) if (end == argv[1]) { connection.net_idx = NET_IDX_INVALID; bt_shell_printf("Invalid network index %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (argc > 2) @@ -1728,8 +1672,10 @@ static void cmd_connect(int argc, char *argv[]) if (g_dbus_proxy_method_call(default_ctrl->proxy, "StartDiscovery", NULL, start_discovery_reply, - GUINT_TO_POINTER(TRUE), NULL) == FALSE) + GUINT_TO_POINTER(TRUE), NULL) == FALSE) { bt_shell_printf("Failed to start mesh proxy discovery\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } g_dbus_proxy_method_call(default_ctrl->proxy, "StartDiscovery", NULL, NULL, NULL, NULL); @@ -1747,7 +1693,7 @@ static void prov_disconn_reply(DBusMessage *message, void *user_data) if (dbus_set_error_from_message(&error, message) == TRUE) { bt_shell_printf("Failed to disconnect: %s\n", error.name); dbus_error_free(&error); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } set_connected_device(NULL); @@ -1762,8 +1708,10 @@ static void prov_disconn_reply(DBusMessage *message, void *user_data) if (g_dbus_proxy_method_call(default_ctrl->proxy, "StartDiscovery", NULL, start_discovery_reply, - GUINT_TO_POINTER(TRUE), NULL) == FALSE) + GUINT_TO_POINTER(TRUE), NULL) == FALSE) { bt_shell_printf("Failed to start mesh proxy discovery\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } } @@ -1777,15 +1725,17 @@ static void disconn_reply(DBusMessage *message, void *user_data) if (dbus_set_error_from_message(&error, message) == TRUE) { bt_shell_printf("Failed to disconnect: %s\n", error.name); dbus_error_free(&error); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } bt_shell_printf("Successfully disconnected\n"); if (proxy != connection.device) - return; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); set_connected_device(NULL); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_disconn(int argc, char *argv[]) @@ -1797,6 +1747,8 @@ static void cmd_disconn(int argc, char *argv[]) } disconnect_device(disconn_reply, connection.device); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void mesh_prov_done(void *user_data, int status) @@ -1841,14 +1793,14 @@ static void cmd_start_prov(int argc, char *argv[]) bt_shell_printf("Device with UUID %s not found.\n", argv[1]); bt_shell_printf("Stale services? Remove device and " "re-discover\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } /* TODO: add command to remove a node from mesh, i.e., "unprovision" */ if (node_is_provisioned(node)) { bt_shell_printf("Already provisioned with unicast %4.4x\n", node_get_primary(node)); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } dev = find_device_by_uuid(default_ctrl->mesh_devices, @@ -1856,7 +1808,7 @@ static void cmd_start_prov(int argc, char *argv[]) if (!dev || !dev->proxy) { bt_shell_printf("Could not find device proxy\n"); memset(connection.dev_uuid, 0, 16); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } proxy = dev->proxy; @@ -1871,7 +1823,7 @@ static void cmd_start_prov(int argc, char *argv[]) proxy, NULL) == FALSE) { bt_shell_printf("Failed to connect "); print_device(proxy, NULL); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } else { bt_shell_printf("Trying to connect "); print_device(proxy, NULL); @@ -1881,15 +1833,22 @@ static void cmd_start_prov(int argc, char *argv[]) static void cmd_print_mesh(int argc, char *argv[]) { - if (!prov_db_show(mesh_prov_db_filename)) + if (!prov_db_show(mesh_prov_db_filename)) { bt_shell_printf("Unavailable\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_print_local(int argc, char *argv[]) { - if (!prov_db_show(mesh_local_config_filename)) + if (!prov_db_show(mesh_local_config_filename)) { bt_shell_printf("Unavailable\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static const struct bt_shell_menu main_menu = { @@ -1945,6 +1904,7 @@ static void client_ready(GDBusClient *client, void *user_data) int main(int argc, char *argv[]) { GDBusClient *client; + int status; int len; int extra; @@ -1956,8 +1916,8 @@ int main(int argc, char *argv[]) bt_shell_printf("Local config directory not provided.\n"); mesh_config_dir = ""; } else { - bt_shell_printf("Reading prov_db.json and local_node.json from %s\n", - mesh_config_dir); + bt_shell_printf("Reading prov_db.json and local_node.json from" + " %s\n", mesh_config_dir); } len = strlen(mesh_config_dir); @@ -1971,11 +1931,11 @@ int main(int argc, char *argv[]) mesh_local_config_filename = g_malloc(len + strlen("local_node.json") + 2); if (!mesh_local_config_filename) - exit(1); + goto fail; mesh_prov_db_filename = g_malloc(len + strlen("prov_db.json") + 2); if (!mesh_prov_db_filename) { - exit(1); + goto fail; } sprintf(mesh_local_config_filename, "%s", mesh_config_dir); @@ -1991,7 +1951,7 @@ int main(int argc, char *argv[]) if (!prov_db_read_local_node(mesh_local_config_filename, true)) { g_printerr("Failed to parse local node configuration file %s\n", mesh_local_config_filename); - exit(1); + goto fail; } sprintf(mesh_prov_db_filename, "%s", mesh_config_dir); @@ -2006,7 +1966,7 @@ int main(int argc, char *argv[]) if (!prov_db_read(mesh_prov_db_filename)) { g_printerr("Failed to parse provisioning database file %s\n", mesh_prov_db_filename); - exit(1); + goto fail; } dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL); @@ -2030,7 +1990,7 @@ int main(int argc, char *argv[]) if (!onoff_client_init(PRIMARY_ELEMENT_IDX)) g_printerr("Failed to initialize mesh generic On/Off client\n"); - bt_shell_run(); + status = bt_shell_run(); g_dbus_client_unref(client); @@ -2042,5 +2002,9 @@ int main(int argc, char *argv[]) g_list_free(service_list); g_list_free_full(ctrl_list, proxy_leak); - return 0; + return status; + +fail: + bt_shell_cleanup(); + return EXIT_FAILURE; } diff --git a/mesh/node.c b/mesh/node.c index 0a60e792..9ff74196 100644 --- a/mesh/node.c +++ b/mesh/node.c @@ -417,7 +417,7 @@ bool node_parse_composition(struct mesh_node *node, uint8_t *data, uint16_t len) m = *data++; v = *data++; - len -= 4; + len -= 2; while (len >= 2 && m--) { mod_id = get_le16(data); @@ -691,7 +691,7 @@ bool node_set_model(struct mesh_node *node, uint8_t ele_idx, uint32_t id) l = g_list_find_custom(ele->models, GUINT_TO_POINTER(id), match_model_id); if (l) - return false; + return true; model = g_malloc0(sizeof(struct mesh_model)); if (!model) @@ -757,7 +757,7 @@ bool node_add_binding(struct mesh_node *node, uint8_t ele_idx, GList *l; model = get_model(node, ele_idx, model_id); - if(!model) + if (!model) return false; l = g_list_find(model->bindings, GUINT_TO_POINTER(app_idx)); @@ -771,7 +771,25 @@ bool node_add_binding(struct mesh_node *node, uint8_t ele_idx, model->bindings = g_list_append(model->bindings, GUINT_TO_POINTER(app_idx)); + return true; +} + +bool node_add_subscription(struct mesh_node *node, uint8_t ele_idx, + uint32_t model_id, uint16_t addr) +{ + struct mesh_model *model; + GList *l; + + model = get_model(node, ele_idx, model_id); + if (!model) + return false; + + l = g_list_find(model->subscriptions, GUINT_TO_POINTER(addr)); + if (l) + return false; + model->subscriptions = g_list_append(model->subscriptions, + GUINT_TO_POINTER(addr)); return true; } diff --git a/mesh/node.h b/mesh/node.h index 1fab80a1..a5b5c752 100644 --- a/mesh/node.h +++ b/mesh/node.h @@ -111,6 +111,8 @@ bool node_set_composition(struct mesh_node *node, struct mesh_node_composition *comp); bool node_add_binding(struct mesh_node *node, uint8_t ele_idx, uint32_t model_id, uint16_t app_idx); +bool node_add_subscription(struct mesh_node *node, uint8_t ele_idx, + uint32_t model_id, uint16_t addr); uint8_t node_get_default_ttl(struct mesh_node *node); bool node_set_default_ttl(struct mesh_node *node, uint8_t ttl); bool node_set_sequence_number(struct mesh_node *node, uint32_t seq); diff --git a/mesh/onoff-model.c b/mesh/onoff-model.c index dbbe6970..49be089a 100644 --- a/mesh/onoff-model.c +++ b/mesh/onoff-model.c @@ -58,8 +58,8 @@ static int client_bind(uint16_t app_idx, int action) return MESH_STATUS_INSUFF_RESOURCES; } else { onoff_app_idx = app_idx; - bt_shell_printf("On/Off client model: new binding %4.4x\n", - app_idx); + bt_shell_printf("On/Off client model: new binding" + " %4.4x\n", app_idx); } } else { if (onoff_app_idx == app_idx) @@ -101,8 +101,8 @@ static void print_remaining_time(uint8_t remaining_time) break; } - bt_shell_printf("\n\t\tRemaining time: %d hrs %d mins %d secs %d msecs\n", - hours, minutes, secs, msecs); + bt_shell_printf("\n\t\tRemaining time: %d hrs %d mins %d secs %d" + " msecs\n", hours, minutes, secs, msecs); } @@ -134,7 +134,8 @@ static bool client_msg_recvd(uint16_t src, uint8_t *data, src, data[0] ? "ON" : "OFF"); if (len == 3) { - bt_shell_printf(", target = %s", data[1] ? "ON" : "OFF"); + bt_shell_printf(", target = %s", + data[1] ? "ON" : "OFF"); print_remaining_time(data[2]); } else bt_shell_printf("\n"); @@ -183,10 +184,12 @@ static void cmd_set_node(int argc, char *argv[]) bt_shell_printf("Bad unicast address %s: " "expected format 4 digit hex\n", argv[1]); target = UNASSIGNED_ADDRESS; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } else { bt_shell_printf("Controlling ON/OFF for node %4.4x\n", dst); target = dst; set_menu_prompt("on/off", argv[1]); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } } @@ -212,7 +215,7 @@ static void cmd_get_status(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } node = node_find_by_addr(target); @@ -222,8 +225,12 @@ static void cmd_get_status(int argc, char *argv[]) n = mesh_opcode_set(OP_GENERIC_ONOFF_GET, msg); - if (!send_cmd(msg, n)) + if (!send_cmd(msg, n)) { bt_shell_printf("Failed to send \"GENERIC ON/OFF GET\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_set(int argc, char *argv[]) @@ -234,7 +241,7 @@ static void cmd_set(int argc, char *argv[]) if (IS_UNASSIGNED(target)) { bt_shell_printf("Destination not set\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } node = node_find_by_addr(target); @@ -245,16 +252,19 @@ static void cmd_set(int argc, char *argv[]) if ((read_input_parameters(argc, argv) != 1) && parms[0] != 0 && parms[0] != 1) { bt_shell_printf("Bad arguments: Expecting \"0\" or \"1\"\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } n = mesh_opcode_set(OP_GENERIC_ONOFF_SET, msg); msg[n++] = parms[0]; msg[n++] = trans_id++; - if (!send_cmd(msg, n)) + if (!send_cmd(msg, n)) { bt_shell_printf("Failed to send \"GENERIC ON/OFF SET\"\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static const struct bt_shell_menu onoff_menu = { diff --git a/mesh/prov-db.c b/mesh/prov-db.c index 8a7b47f6..019b4e17 100644 --- a/mesh/prov-db.c +++ b/mesh/prov-db.c @@ -409,6 +409,36 @@ static json_object* find_configured_model(struct mesh_node *node, int ele_idx, return NULL; } +static bool parse_subscriptions(struct mesh_node *node, int ele_idx, + uint32_t model_id, json_object *jsubscriptions) + +{ + int cnt; + int i; + int addr; + + cnt = json_object_array_length(jsubscriptions); + + for (i = 0; i < cnt; ++i) { + char *str; + json_object *jsubscription; + + jsubscription = json_object_array_get_idx(jsubscriptions, i); + if (!jsubscription) + return false; + + str = (char *)json_object_get_string(jsubscription); + + if (sscanf(str, "%04x", &addr) != 1) + return false; + + if (!node_add_subscription(node, ele_idx, model_id, addr)) + return false; + } + + return true; +} + static bool parse_configuration_models(struct mesh_node *node, int ele_idx, json_object *jmodels) { @@ -441,11 +471,15 @@ static bool parse_configuration_models(struct mesh_node *node, int ele_idx, model_id += 0xffff0000; json_object_object_get_ex(jmodel, "bind", &jarray); + if (jarray && !parse_bindings(node, ele_idx, model_id, jarray)) return false; - json_object_object_get_ex(jmodel, "publish", &jvalue); + json_object_object_get_ex(jmodel, "subscribe", &jarray); + if (jarray && !parse_subscriptions(node, ele_idx, model_id, jarray)) + return false; + json_object_object_get_ex(jmodel, "publish", &jvalue); if (jvalue && !parse_model_pub(node, ele_idx, model_id, jvalue)) return false; } @@ -653,7 +687,7 @@ bool prov_db_add_node_composition(struct mesh_node *node, uint8_t *data, put_uint16(jcomp, "cid", comp->cid); put_uint16(jcomp, "pid", comp->pid); - put_uint16(jcomp, "vid", comp->pid); + put_uint16(jcomp, "vid", comp->vid); put_uint16(jcomp, "crpl", comp->crpl); jfeatures = json_object_new_object(); @@ -1070,14 +1104,13 @@ done: bool prov_db_add_binding(struct mesh_node *node, uint8_t ele_idx, uint32_t model_id, uint16_t app_idx) { - json_object *jmain; + bool local = (node == node_get_local_node()); + json_object *jbindings = NULL; json_object *jmodel; json_object *jvalue; - json_object *jbindings = NULL; - bool local = (node == node_get_local_node()); + json_object *jmain; jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain); - if (!jmodel) return false; @@ -1098,6 +1131,34 @@ bool prov_db_add_binding(struct mesh_node *node, uint8_t ele_idx, return true; } +bool prov_db_add_subscription(struct mesh_node *node, uint8_t ele_idx, + uint32_t model_id, uint16_t addr) +{ + bool local = (node == node_get_local_node()); + json_object *jsubscriptions = NULL; + json_object *jmodel; + json_object *jmain; + + jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain); + if (!jmodel) + return false; + + json_object_object_get_ex(jmodel, "subscribe", &jsubscriptions); + + if (!jsubscriptions) { + jsubscriptions = json_object_new_array(); + json_object_object_add(jmodel, "subscribe", jsubscriptions); + } + + put_uint16_array_entry(jsubscriptions, addr); + + prov_file_write(jmain, local); + + json_object_put(jmain); + + return true; +} + bool prov_db_node_set_model_pub(struct mesh_node *node, uint8_t ele_idx, uint32_t model_id, struct mesh_publication *pub) @@ -1225,6 +1286,7 @@ static bool parse_node_composition(struct mesh_node *node, json_object *jcomp) { json_object *jvalue; json_object *jelements; + json_object *jfeatures; json_bool enable; char *str; struct mesh_node_composition comp; @@ -1244,7 +1306,7 @@ static bool parse_node_composition(struct mesh_node *node, json_object *jcomp) str = (char *)json_object_get_string(jvalue); - if (sscanf(str, "%04hx", &comp.vid) != 1) + if (sscanf(str, "%04hx", &comp.pid) != 1) return false; json_object_object_get_ex(jcomp, "vid", &jvalue); @@ -1266,19 +1328,24 @@ static bool parse_node_composition(struct mesh_node *node, json_object *jcomp) return false; /* Extract features */ - json_object_object_get_ex(jcomp, "relay", &jvalue); + + json_object_object_get_ex(jcomp, "features", &jfeatures); + if (!jfeatures) + return false; + + json_object_object_get_ex(jfeatures, "relay", &jvalue); enable = json_object_get_boolean(jvalue); comp.relay = (enable) ? true : false; - json_object_object_get_ex(jcomp, "proxy", &jvalue); + json_object_object_get_ex(jfeatures, "proxy", &jvalue); enable = json_object_get_boolean(jvalue); comp.proxy = (enable) ? true : false; - json_object_object_get_ex(jcomp, "friend", &jvalue); + json_object_object_get_ex(jfeatures, "friend", &jvalue); enable = json_object_get_boolean(jvalue); comp.friend = (enable) ? true : false; - json_object_object_get_ex(jcomp, "lowPower", &jvalue); + json_object_object_get_ex(jfeatures, "lowPower", &jvalue); enable = json_object_get_boolean(jvalue); comp.lpn = (enable) ? true : false; diff --git a/mesh/prov-db.h b/mesh/prov-db.h index b1e4c629..b8584a8c 100644 --- a/mesh/prov-db.h +++ b/mesh/prov-db.h @@ -30,6 +30,8 @@ bool prov_db_add_node_composition(struct mesh_node *node, uint8_t *data, bool prov_db_node_keys(struct mesh_node *node, GList *idxs, const char *desc); bool prov_db_add_binding(struct mesh_node *node, uint8_t ele_idx, uint32_t model_id, uint16_t app_idx); +bool prov_db_add_subscription(struct mesh_node *node, uint8_t ele_idx, + uint32_t model_id, uint16_t addr); bool prov_db_node_set_ttl(struct mesh_node *node, uint8_t ttl); bool prov_db_node_set_iv_seq(struct mesh_node *node, uint32_t iv, uint32_t seq); bool prov_db_local_set_iv_index(uint32_t iv_index, bool update, bool prov); diff --git a/src/adapter.c b/src/adapter.c index a01f33c4..9c91a4fe 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -1913,7 +1913,7 @@ static void start_discovery_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { struct btd_adapter *adapter = user_data; - struct watch_client *client = adapter->discovery_list->data; + struct watch_client *client; const struct mgmt_cp_start_discovery *rp = param; DBusMessage *reply; @@ -1922,7 +1922,7 @@ static void start_discovery_complete(uint8_t status, uint16_t length, /* Is there are no clients the discovery must have been stopped while * discovery command was pending. */ - if (!client) { + if (!adapter->discovery_list) { struct mgmt_cp_stop_discovery cp; if (status != MGMT_STATUS_SUCCESS) @@ -1936,6 +1936,8 @@ static void start_discovery_complete(uint8_t status, uint16_t length, return; } + client = adapter->discovery_list->data; + if (length < sizeof(*rp)) { btd_error(adapter->dev_id, "Wrong size of start discovery return parameters"); diff --git a/src/device.c b/src/device.c index 08a02348..544b06d1 100644 --- a/src/device.c +++ b/src/device.c @@ -2871,6 +2871,7 @@ static void browse_request_complete(struct browse_req *req, uint8_t type, { struct btd_device *dev = req->device; DBusMessage *reply = NULL; + DBusMessage *msg; if (req->type != type) return; @@ -2907,19 +2908,31 @@ static void browse_request_complete(struct browse_req *req, uint8_t type, goto done; } - if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "Connect")) - reply = dev_connect(dbus_conn, req->msg, dev); - else if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, + /* if successfully resolved services we need to free browsing request + * before passing message back to connect functions, otherwise + * device->browse is set and "InProgress" error is returned instead + * of actually connecting services + */ + msg = dbus_message_ref(req->msg); + browse_request_free(req); + req = NULL; + + if (dbus_message_is_method_call(msg, DEVICE_INTERFACE, "Connect")) + reply = dev_connect(dbus_conn, msg, dev); + else if (dbus_message_is_method_call(msg, DEVICE_INTERFACE, "ConnectProfile")) - reply = connect_profile(dbus_conn, req->msg, dev); + reply = connect_profile(dbus_conn, msg, dev); else - reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID); + reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + + dbus_message_unref(msg); done: if (reply) g_dbus_send_message(dbus_conn, reply); - browse_request_free(req); + if (req) + browse_request_free(req); } static void device_set_svc_refreshed(struct btd_device *device, bool value) diff --git a/src/shared/ecc.c b/src/shared/ecc.c index 41be02b7..15f6b8a9 100755 --- a/src/shared/ecc.c +++ b/src/shared/ecc.c @@ -66,9 +66,13 @@ typedef struct { #define CURVE_N_32 { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull } +#define CURVE_B_32 { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, \ + 0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull } + static uint64_t curve_p[NUM_ECC_DIGITS] = CURVE_P_32; static struct ecc_point curve_g = CURVE_G_32; static uint64_t curve_n[NUM_ECC_DIGITS] = CURVE_N_32; +static uint64_t curve_b[NUM_ECC_DIGITS] = CURVE_B_32; static bool get_random_number(uint64_t *vli) { @@ -183,6 +187,19 @@ static int vli_cmp(const uint64_t *left, const uint64_t *right) return 0; } +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns one if left == right, zero otherwise. */ +static bool vli_equal(const uint64_t *left, const uint64_t *right) +{ + uint64_t diff = 0; + int i; + + for (i = NUM_ECC_DIGITS - 1; i >= 0; --i) + diff |= (left[i] ^ right[i]); + + return (diff == 0); +} + /* Computes result = in << c, returning carry. Can modify in place * (if result == in). 0 < shift < 64. */ @@ -770,6 +787,34 @@ static void ecc_point_mult(struct ecc_point *result, vli_set(result->y, ry[0]); } +static bool ecc_valid_point(const struct ecc_point *point) +{ + uint64_t tmp1[NUM_ECC_DIGITS]; + uint64_t tmp2[NUM_ECC_DIGITS]; + uint64_t _3[NUM_ECC_DIGITS] = { 3 }; /* -a = 3 */ + + /* The point at infinity is invalid. */ + if (ecc_point_is_zero(point)) + return false; + + /* x and y must be smaller than p. */ + if (vli_cmp(curve_p, point->x) != 1 || + vli_cmp(curve_p, point->y) != 1) + return false; + + /* Computes result = y^2. */ + vli_mod_square_fast(tmp1, point->y); + + /* Computes result = x^3 + ax + b. result must not overlap x. */ + vli_mod_square_fast(tmp2, point->x); /* r = x^2 */ + vli_mod_sub(tmp2, tmp2, _3, curve_p); /* r = x^2 - 3 */ + vli_mod_mult_fast(tmp2, tmp2, point->x); /* r = x^3 - 3x */ + vli_mod_add(tmp2, tmp2, curve_b, curve_p); /* r = x^3 - 3x + b */ + + /* Make sure that y^2 == x^3 + ax + b */ + return vli_equal(tmp1, tmp2); +} + /* Little endian byte-array to native conversion */ static void ecc_bytes2native(const uint8_t bytes[ECC_BYTES], uint64_t native[NUM_ECC_DIGITS]) @@ -811,33 +856,59 @@ static void ecc_native2bytes(const uint64_t native[NUM_ECC_DIGITS], } } -bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]) +bool ecc_make_public_key(const uint8_t private_key[32], uint8_t public_key[64]) { struct ecc_point pk; uint64_t priv[NUM_ECC_DIGITS]; - unsigned tries = 0; - do { - if (!get_random_number(priv) || (tries++ >= MAX_TRIES)) - return false; + ecc_bytes2native(private_key, priv); - if (vli_is_zero(priv)) - continue; + if (vli_is_zero(priv)) + return false; - /* Make sure the private key is in the range [1, n-1]. */ - if (vli_cmp(curve_n, priv) != 1) - continue; + /* Make sure the private key is in the range [1, n-1]. */ + if (vli_cmp(curve_n, priv) != 1) + return false; - ecc_point_mult(&pk, &curve_g, priv, NULL, vli_num_bits(priv)); - } while (ecc_point_is_zero(&pk)); + ecc_point_mult(&pk, &curve_g, priv, NULL, vli_num_bits(priv)); + + if (ecc_point_is_zero(&pk)) + return false; - ecc_native2bytes(priv, private_key); ecc_native2bytes(pk.x, public_key); ecc_native2bytes(pk.y, &public_key[32]); return true; } +bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]) +{ + uint64_t priv[NUM_ECC_DIGITS]; + unsigned int tries = 0; + bool result = false; + + for (tries = 0; !result && tries < MAX_TRIES; tries++) { + if (!get_random_number(priv)) + continue; + + ecc_native2bytes(priv, private_key); + + result = ecc_make_public_key(private_key, public_key); + } + + return result; +} + +bool ecc_valid_public_key(const uint8_t public_key[64]) +{ + struct ecc_point pk; + + ecc_bytes2native(public_key, pk.x); + ecc_bytes2native(&public_key[32], pk.y); + + return ecc_valid_point(&pk); +} + bool ecdh_shared_secret(const uint8_t public_key[64], const uint8_t private_key[32], uint8_t secret[32]) @@ -851,6 +922,10 @@ bool ecdh_shared_secret(const uint8_t public_key[64], ecc_bytes2native(public_key, pk.x); ecc_bytes2native(&public_key[32], pk.y); + + if (!ecc_valid_point(&pk)) + return false; + ecc_bytes2native(private_key, priv); ecc_point_mult(&product, &pk, priv, rand, vli_num_bits(priv)); diff --git a/src/shared/ecc.h b/src/shared/ecc.h index e971375a..a88e735c 100755 --- a/src/shared/ecc.h +++ b/src/shared/ecc.h @@ -27,16 +27,37 @@ #include <stdbool.h> #include <stdint.h> +/* Create a public key from a private key. + * + * Outputs: + * private_key - Const private key + * public_key - Will be filled in with the public key. + * + * Returns true if the public key was generated successfully, false + * if an error occurred. The keys are with the LSB first. + */ +bool ecc_make_public_key(const uint8_t private_key[32], uint8_t public_key[64]); + /* Create a public/private key pair. + * * Outputs: * public_key - Will be filled in with the public key. - * private_Key - Will be filled in with the private key. + * private_key - Will be filled in with the private key. * * Returns true if the key pair was generated successfully, false - * if an error occurred. They keys are with the LSB first. + * if an error occurred. The keys are with the LSB first. */ bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]); +/* Check to see if a public key is valid. + * + * Inputs: + * public_key - The public key to check. + * + * Returns true if the public key is valid, false if it is invalid. +*/ +bool ecc_valid_public_key(const uint8_t public_key[64]); + /* Compute a shared secret given your secret key and someone else's * public key. * Note: It is recommended that you hash the result of ecdh_shared_secret @@ -44,7 +65,7 @@ bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]); * * Inputs: * public_key - The public key of the remote party. - * private_Key - Your private key. + * private_key - Your private key. * * Outputs: * secret - Will be filled in with the shared secret value. diff --git a/src/shared/mainloop-glib.c b/src/shared/mainloop-glib.c new file mode 100644 index 00000000..8436969b --- /dev/null +++ b/src/shared/mainloop-glib.c @@ -0,0 +1,117 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2018 Intel Corporation + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <signal.h> +#include <sys/signalfd.h> + +#include <glib.h> + +#include "mainloop.h" + +static GMainLoop *main_loop; +static int exit_status; + +void mainloop_init(void) +{ + main_loop = g_main_loop_new(NULL, FALSE); +} + +void mainloop_quit(void) +{ + if (!main_loop) + return; + + g_main_loop_quit(main_loop); +} + +void mainloop_exit_success(void) +{ + exit_status = EXIT_SUCCESS; + mainloop_quit(); +} + +void mainloop_exit_failure(void) +{ + exit_status = EXIT_FAILURE; + mainloop_quit(); +} + +int mainloop_run(void) +{ + if (!main_loop) + return -EINVAL; + + g_main_loop_run(main_loop); + + g_main_loop_unref(main_loop); + main_loop = NULL; + + return exit_status; +} + +int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback, + void *user_data, mainloop_destroy_func destroy) +{ + return -ENOSYS; +} + +int mainloop_modify_fd(int fd, uint32_t events) +{ + return -ENOSYS; +} + +int mainloop_remove_fd(int fd) +{ + return -ENOSYS; +} + +int mainloop_add_timeout(unsigned int msec, mainloop_timeout_func callback, + void *user_data, mainloop_destroy_func destroy) +{ + return -ENOSYS; +} + +int mainloop_modify_timeout(int fd, unsigned int msec) +{ + return -ENOSYS; +} + +int mainloop_remove_timeout(int id) +{ + return -ENOSYS; +} + +int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback, + void *user_data, mainloop_destroy_func destroy) +{ + return -ENOSYS; +} diff --git a/src/shared/mainloop.c b/src/shared/mainloop.c index 09c46a79..e6ab9c43 100755 --- a/src/shared/mainloop.c +++ b/src/shared/mainloop.c @@ -42,7 +42,7 @@ static int epoll_fd; static int epoll_terminate; -static int exit_status; +static int exit_status = EXIT_SUCCESS; struct mainloop_data { int fd; @@ -141,8 +141,6 @@ int mainloop_run(void) } } - exit_status = EXIT_SUCCESS; - while (!epoll_terminate) { struct epoll_event events[MAX_EPOLL_EVENTS]; int n, nfds; diff --git a/src/shared/queue.c b/src/shared/queue.c index 5ddb8326..60df1114 100755 --- a/src/shared/queue.c +++ b/src/shared/queue.c @@ -280,9 +280,12 @@ void *queue_remove_if(struct queue *queue, queue_match_func_t function, { struct queue_entry *entry, *prev = NULL; - if (!queue || !function) + if (!queue) return NULL; + if (!function) + function = direct_match; + entry = queue->head; while (entry) { diff --git a/src/shared/shell.c b/src/shared/shell.c index 6cdea1c7..e7f17e02 100644 --- a/src/shared/shell.c +++ b/src/shared/shell.c @@ -29,6 +29,7 @@ #include <errno.h> #include <unistd.h> #include <stdlib.h> +#include <stdarg.h> #include <stdbool.h> #include <signal.h> #include <sys/signalfd.h> @@ -37,8 +38,9 @@ #include <readline/readline.h> #include <readline/history.h> -#include <glib.h> +#include "src/shared/mainloop.h" +#include "src/shared/timeout.h" #include "src/shared/io.h" #include "src/shared/util.h" #include "src/shared/queue.h" @@ -54,9 +56,17 @@ printf(COLOR_BLUE "%s %-*s " COLOR_OFF "%s\n", \ cmd, (int)(CMD_LENGTH - strlen(cmd)), "", desc) -static GMainLoop *main_loop; +struct bt_shell_env { + char *name; + void *value; +}; static struct { + bool init; + int argc; + char **argv; + bool mode; + int timeout; struct io *input; bool saved_prompt; @@ -66,6 +76,9 @@ static struct { const struct bt_shell_menu *menu; const struct bt_shell_menu *main; struct queue *submenus; + const struct bt_shell_menu_entry *exec; + + struct queue *envs; } data; static void shell_print_menu(void); @@ -73,19 +86,23 @@ static void shell_print_menu(void); static void cmd_version(int argc, char *argv[]) { bt_shell_printf("Version %s\n", VERSION); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_quit(int argc, char *argv[]) { - g_main_loop_quit(main_loop); + mainloop_quit(); } static void cmd_help(int argc, char *argv[]) { shell_print_menu(); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static const struct bt_shell_menu *find_menu(const char *name) +static const struct bt_shell_menu *find_menu(const char *name, size_t len) { const struct queue_entry *entry; @@ -93,8 +110,10 @@ static const struct bt_shell_menu *find_menu(const char *name) entry = entry->next) { struct bt_shell_menu *menu = entry->data; - if (!strcmp(menu->name, name)) + if (!strncmp(menu->name, name, len)) return menu; + + } return NULL; @@ -131,18 +150,20 @@ static void cmd_menu(int argc, char *argv[]) if (argc < 2 || !strlen(argv[1])) { bt_shell_printf("Missing name argument\n"); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } - menu = find_menu(argv[1]); + menu = find_menu(argv[1], strlen(argv[1])); if (!menu) { bt_shell_printf("Unable find menu with name: %s\n", argv[1]); - return; + return bt_shell_noninteractive_quit(EXIT_FAILURE); } bt_shell_set_menu(menu); shell_print_menu(); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static bool cmd_menu_exists(const struct bt_shell_menu *menu) @@ -177,6 +198,17 @@ static bool cmd_back_exists(const struct bt_shell_menu *menu) return true; } +static void cmd_export(int argc, char *argv[]) +{ + const struct queue_entry *entry; + + for (entry = queue_get_entries(data.envs); entry; entry = entry->next) { + struct bt_shell_env *env = entry->data; + + print_text(COLOR_HIGHLIGHT, "%s=%p", env->name, env->value); + } +} + static const struct bt_shell_menu_entry default_menu[] = { { "back", NULL, cmd_back, "Return to main menu", NULL, NULL, cmd_back_exists }, @@ -188,9 +220,20 @@ static const struct bt_shell_menu_entry default_menu[] = { { "exit", NULL, cmd_quit, "Quit program" }, { "help", NULL, cmd_help, "Display help about this program" }, + { "export", NULL, cmd_export, + "Print evironment variables" }, { } }; +static void shell_print_help(void) +{ + print_text(COLOR_HIGHLIGHT, + "\n" + "Use \"help\" for a list of available commands in a menu.\n" + "Use \"menu <submenu>\" if you want to enter any submenu.\n" + "Use \"back\" if you want to return to menu main."); +} + static void shell_print_menu(void) { const struct bt_shell_menu_entry *entry; @@ -229,18 +272,18 @@ static int parse_args(char *arg, wordexp_t *w, char *del, int flags) { char *str; - str = g_strdelimit(arg, del, '"'); + str = strdelimit(arg, del, '"'); if (wordexp(str, w, flags)) { - g_free(str); + free(str); return -EINVAL; } - /* If argument ends with ,,, set we_offs bypass strict checks */ - if (w->we_wordc && g_str_has_suffix(w->we_wordv[w->we_wordc -1], "...")) + /* If argument ends with ... set we_offs bypass strict checks */ + if (w->we_wordc && !strsuffix(w->we_wordv[w->we_wordc -1], "...")) w->we_offs = 1; - g_free(str); + free(str); return 0; } @@ -269,16 +312,30 @@ static int cmd_exec(const struct bt_shell_menu_entry *entry, } len = man - entry->arg; - man = strndup(entry->arg, len + 1); + if (entry->arg[0] == '<') + man = strndup(entry->arg, len + 1); + else { + /* Find where mandatory arguments start */ + opt = strrchr(entry->arg, '<'); + /* Skip if mandatory arguments are not in the right format */ + if (!opt || opt > man) { + opt = strdup(entry->arg); + goto optional; + } + man = strndup(opt, man - opt + 1); + } if (parse_args(man, &w, "<>", flags) < 0) { print_text(COLOR_HIGHLIGHT, - "Unable to parse mandatory command arguments"); + "Unable to parse mandatory command arguments: %s", man ); + free(man); return -EINVAL; } + free(man); + /* Check if there are enough arguments */ - if ((unsigned) argc - 1 < w.we_wordc && !w.we_offs) { + if ((unsigned) argc - 1 < w.we_wordc) { print_text(COLOR_HIGHLIGHT, "Missing %s argument", w.we_wordv[argc - 1]); goto fail; @@ -290,10 +347,13 @@ static int cmd_exec(const struct bt_shell_menu_entry *entry, optional: if (parse_args(opt, &w, "[]", flags) < 0) { print_text(COLOR_HIGHLIGHT, - "Unable to parse optional command arguments"); + "Unable to parse optional command arguments: %s", opt); + free(opt); return -EINVAL; } + free(opt); + /* Check if there are too many arguments */ if ((unsigned) argc - 1 > w.we_wordc && !w.we_offs) { print_text(COLOR_HIGHLIGHT, "Too many arguments: %d > %zu", @@ -301,15 +361,21 @@ optional: goto fail; } + w.we_offs = 0; wordfree(&w); exec: + data.exec = entry; + if (entry->func) entry->func(argc, argv); + data.exec = NULL; + return 0; fail: + w.we_offs = 0; wordfree(&w); return -EINVAL; } @@ -335,15 +401,56 @@ static int menu_exec(const struct bt_shell_menu_entry *entry, return -ENOENT; } -static void shell_exec(int argc, char *argv[]) +static int submenu_exec(int argc, char *argv[]) { + char *name; + int len, tlen; + const struct bt_shell_menu *submenu; + + if (data.menu != data.main) + return -ENOENT; + + name = strchr(argv[0], '.'); + if (!name) + return -ENOENT; + + tlen = strlen(argv[0]); + len = name - argv[0]; + name[0] = '\0'; + + submenu = find_menu(argv[0], strlen(argv[0])); + if (!submenu) + return -ENOENT; + + /* Replace submenu.command with command */ + memmove(argv[0], argv[0] + len + 1, tlen - len - 1); + memset(argv[0] + tlen - len - 1, 0, len + 1); + + return menu_exec(submenu->entries, argc, argv); +} + +static int shell_exec(int argc, char *argv[]) +{ + int err; + if (!data.menu || !argv[0]) - return; + return -EINVAL; - if (menu_exec(default_menu, argc, argv) == -ENOENT) { - if (menu_exec(data.menu->entries, argc, argv) == -ENOENT) - print_text(COLOR_HIGHLIGHT, "Invalid command"); + err = menu_exec(default_menu, argc, argv); + if (err == -ENOENT) { + err = menu_exec(data.menu->entries, argc, argv); + if (err == -ENOENT) { + err = submenu_exec(argc, argv); + if (err == -ENOENT) { + print_text(COLOR_HIGHLIGHT, + "Invalid command in menu %s: %s", + data.menu->name , argv[0]); + shell_print_help(); + } + } } + + return err; } void bt_shell_printf(const char *fmt, ...) @@ -353,16 +460,25 @@ void bt_shell_printf(const char *fmt, ...) char *saved_line; int saved_point; + if (!data.input) + return; + + if (data.mode) { + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + return; + } + save_input = !RL_ISSTATE(RL_STATE_DONE); if (save_input) { saved_point = rl_point; saved_line = rl_copy_text(0, rl_end); - if (!data.saved_prompt) { + if (!data.saved_prompt) rl_save_prompt(); - rl_replace_line("", 0); - rl_redisplay(); - } + rl_replace_line("", 0); + rl_redisplay(); } va_start(args, fmt); @@ -379,61 +495,42 @@ void bt_shell_printf(const char *fmt, ...) } } +static void print_string(const char *str, void *user_data) +{ + bt_shell_printf("%s\n", str); +} + void bt_shell_hexdump(const unsigned char *buf, size_t len) { - static const char hexdigits[] = "0123456789abcdef"; - char str[68]; - size_t i; + util_hexdump(' ', buf, len, print_string, NULL); +} - if (!len) +void bt_shell_usage() +{ + if (!data.exec) return; - str[0] = ' '; - - for (i = 0; i < len; i++) { - str[((i % 16) * 3) + 1] = ' '; - str[((i % 16) * 3) + 2] = hexdigits[buf[i] >> 4]; - str[((i % 16) * 3) + 3] = hexdigits[buf[i] & 0xf]; - str[(i % 16) + 51] = isprint(buf[i]) ? buf[i] : '.'; - - if ((i + 1) % 16 == 0) { - str[49] = ' '; - str[50] = ' '; - str[67] = '\0'; - bt_shell_printf("%s\n", str); - str[0] = ' '; - } - } - - if (i % 16 > 0) { - size_t j; - for (j = (i % 16); j < 16; j++) { - str[(j * 3) + 1] = ' '; - str[(j * 3) + 2] = ' '; - str[(j * 3) + 3] = ' '; - str[j + 51] = ' '; - } - str[49] = ' '; - str[50] = ' '; - str[67] = '\0'; - bt_shell_printf("%s\n", str); - } + bt_shell_printf("Usage: %s %s\n", data.exec->cmd, + data.exec->arg ? data.exec->arg : ""); } void bt_shell_prompt_input(const char *label, const char *msg, bt_shell_prompt_input_func func, void *user_data) { + if (!data.init || data.mode) + return; + /* Normal use should not prompt for user input to the value a second * time before it releases the prompt, but we take a safe action. */ if (data.saved_prompt) return; - rl_save_prompt(); - rl_message(COLOR_RED "[%s]" COLOR_OFF " %s ", label, msg); - data.saved_prompt = true; data.saved_func = func; data.saved_user_data = user_data; + + rl_save_prompt(); + bt_shell_printf(COLOR_RED "[%s]" COLOR_OFF " %s ", label, msg); } int bt_shell_release_prompt(const char *input) @@ -467,7 +564,7 @@ static void rl_handler(char *input) rl_insert_text("quit"); rl_redisplay(); rl_crlf(); - g_main_loop_quit(main_loop); + mainloop_quit(); return; } @@ -521,12 +618,15 @@ static char *find_cmd(const char *text, static char *cmd_generator(const char *text, int state) { static int index; - static bool default_menu_enabled; + static bool default_menu_enabled, submenu_enabled; + static const struct bt_shell_menu *menu; char *cmd; if (!state) { index = 0; + menu = NULL; default_menu_enabled = true; + submenu_enabled = false; } if (default_menu_enabled) { @@ -535,15 +635,124 @@ static char *cmd_generator(const char *text, int state) return cmd; } else { index = 0; + menu = data.menu; default_menu_enabled = false; } } - return find_cmd(text, data.menu->entries, &index); + if (!submenu_enabled) { + cmd = find_cmd(text, menu->entries, &index); + if (cmd || menu != data.main) + return cmd; + + cmd = strrchr(text, '.'); + if (!cmd) + return NULL; + + menu = find_menu(text, cmd - text); + if (!menu) + return NULL; + + index = 0; + submenu_enabled = true; + } + + cmd = find_cmd(text + strlen(menu->name) + 1, menu->entries, &index); + if (cmd) { + int err; + char *tmp; + + err = asprintf(&tmp, "%s.%s", menu->name, cmd); + + free(cmd); + + if (err < 0) + return NULL; + + cmd = tmp; + } + + return cmd; +} + +static wordexp_t args; + +static char *arg_generator(const char *text, int state) +{ + static unsigned int index, len; + const char *arg; + + if (!state) { + index = 0; + len = strlen(text); + } + + while (index < args.we_wordc) { + arg = args.we_wordv[index]; + index++; + + if (!strncmp(arg, text, len)) + return strdup(arg); + } + + return NULL; +} + +static char **args_completion(const struct bt_shell_menu_entry *entry, int argc, + const char *text) +{ + char **matches = NULL; + char *str; + int index; + + index = text[0] == '\0' ? argc - 1 : argc - 2; + if (index < 0) + return NULL; + + if (!entry->arg) + goto end; + + str = strdup(entry->arg); + + if (parse_args(str, &args, "<>[]", WRDE_NOCMD)) + goto done; + + /* Check if argument is valid */ + if ((unsigned) index > args.we_wordc - 1) + goto done; + + /* Check if there are multiple values */ + if (!strrchr(entry->arg, '/')) + goto done; + + free(str); + + /* Split values separated by / */ + str = strdelimit(args.we_wordv[index], "/", ' '); + + args.we_offs = 0; + wordfree(&args); + + if (wordexp(str, &args, WRDE_NOCMD)) + goto done; + + rl_completion_display_matches_hook = NULL; + matches = rl_completion_matches(text, arg_generator); + +done: + free(str); +end: + if (!matches && text[0] == '\0') + bt_shell_printf("Usage: %s %s\n", entry->cmd, + entry->arg ? entry->arg : ""); + + args.we_offs = 0; + wordfree(&args); + return matches; } static char **menu_completion(const struct bt_shell_menu_entry *entry, - const char *text, char *input_cmd) + const char *text, int argc, char *input_cmd) { char **matches = NULL; @@ -552,9 +761,7 @@ static char **menu_completion(const struct bt_shell_menu_entry *entry, continue; if (!entry->gen) { - if (text[0] == '\0') - bt_shell_printf("Usage: %s %s\n", entry->cmd, - entry->arg ? entry->arg : ""); + matches = args_completion(entry, argc, text); break; } @@ -579,9 +786,11 @@ static char **shell_completion(const char *text, int start, int end) if (wordexp(rl_line_buffer, &w, WRDE_NOCMD)) return NULL; - matches = menu_completion(default_menu, text, w.we_wordv[0]); + matches = menu_completion(default_menu, text, w.we_wordc, + w.we_wordv[0]); if (!matches) matches = menu_completion(data.menu->entries, text, + w.we_wordc, w.we_wordv[0]); wordfree(&w); @@ -598,7 +807,7 @@ static char **shell_completion(const char *text, int start, int end) static bool io_hup(struct io *io, void *user_data) { - g_main_loop_quit(main_loop); + mainloop_quit(); return false; } @@ -618,12 +827,12 @@ static bool signal_read(struct io *io, void *user_data) switch (si.ssi_signo) { case SIGINT: - if (data.input) { + if (data.input && !data.mode) { rl_replace_line("", 0); rl_crlf(); rl_on_new_line(); rl_redisplay(); - break; + return true; } /* @@ -636,9 +845,11 @@ static bool signal_read(struct io *io, void *user_data) /* fall through */ case SIGTERM: if (!terminated) { - rl_replace_line("", 0); - rl_crlf(); - g_main_loop_quit(main_loop); + if (!data.mode) { + rl_replace_line("", 0); + rl_crlf(); + } + mainloop_quit(); } terminated = true; @@ -680,6 +891,9 @@ static struct io *setup_signalfd(void) static void rl_init(void) { + if (data.mode) + return; + setlinebuf(stdout); rl_attempted_completion_function = shell_completion; @@ -690,6 +904,7 @@ static void rl_init(void) static const struct option main_options[] = { { "version", no_argument, 0, 'v' }, { "help", no_argument, 0, 'h' }, + { "timeout", required_argument, 0, 't' }, }; static void usage(int argc, char **argv, const struct bt_shell_opt *opt) @@ -705,13 +920,14 @@ static void usage(int argc, char **argv, const struct bt_shell_opt *opt) for (i = 0; opt && opt->options[i].name; i++) printf("\t--%s \t%s\n", opt->options[i].name, opt->help[i]); - printf("\t--version \tDisplay version\n" + printf("\t--timeout \tTimeout in seconds for non-interactive mode\n" + "\t--version \tDisplay version\n" "\t--help \t\tDisplay help\n"); } void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt) { - int c, index = 0; + int c, index = -1; struct option options[256]; char optstr[256]; size_t offset; @@ -723,9 +939,9 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt) if (opt) { memcpy(options + offset, opt->options, sizeof(struct option) * opt->optno); - snprintf(optstr, sizeof(optstr), "+hv%s", opt->optstr); + snprintf(optstr, sizeof(optstr), "+hvt:%s", opt->optstr); } else - snprintf(optstr, sizeof(optstr), "+hv"); + snprintf(optstr, sizeof(optstr), "+hvt:"); while ((c = getopt_long(argc, argv, optstr, options, &index)) != -1) { switch (c) { @@ -737,7 +953,17 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt) usage(argc, argv, opt); exit(EXIT_SUCCESS); return; + case 't': + data.timeout = atoi(optarg); + break; default: + if (index < 0) { + for (index = 0; options[index].val; index++) { + if (c == options[index].val) + break; + } + } + if (c != opt->options[index - offset].val) { usage(argc, argv, opt); exit(EXIT_SUCCESS); @@ -746,36 +972,87 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt) *opt->optarg[index - offset] = optarg; } + + index = -1; } - main_loop = g_main_loop_new(NULL, FALSE); + data.argc = argc - optind; + data.argv = argv + optind; + optind = 0; + data.mode = (data.argc > 0); + + if (data.mode) + bt_shell_set_env("NON_INTERACTIVE", &data.mode); + + mainloop_init(); rl_init(); + + data.init = true; } static void rl_cleanup(void) { + if (data.mode) + return; + rl_message(""); rl_callback_handler_remove(); } -void bt_shell_run(void) +static void env_destroy(void *data) +{ + struct bt_shell_env *env = data; + + free(env->name); + free(env); +} + +int bt_shell_run(void) { struct io *signal; + int status; signal = setup_signalfd(); - g_main_loop_run(main_loop); + status = mainloop_run(); + + io_destroy(signal); + + bt_shell_cleanup(); + return status; +} + +void bt_shell_cleanup(void) +{ bt_shell_release_prompt(""); bt_shell_detach(); - io_destroy(signal); - - g_main_loop_unref(main_loop); - main_loop = NULL; + if (data.envs) { + queue_destroy(data.envs, env_destroy); + data.envs = NULL; + } rl_cleanup(); + + data.init = false; +} + +void bt_shell_quit(int status) +{ + if (status == EXIT_SUCCESS) + mainloop_exit_success(); + else + mainloop_exit_failure(); +} + +void bt_shell_noninteractive_quit(int status) +{ + if (!data.mode || data.timeout) + return; + + bt_shell_quit(status); } bool bt_shell_set_menu(const struct bt_shell_menu *menu) @@ -806,13 +1083,11 @@ bool bt_shell_add_submenu(const struct bt_shell_menu *menu) void bt_shell_set_prompt(const char *string) { - if (!main_loop) + if (!data.init || data.mode) return; rl_set_prompt(string); - printf("\r"); - rl_on_new_line(); - rl_redisplay(); + bt_shell_printf("\r"); } static bool input_read(struct io *io, void *user_data) @@ -821,6 +1096,13 @@ static bool input_read(struct io *io, void *user_data) return true; } +static bool shell_quit(void *data) +{ + mainloop_quit(); + + return false; +} + bool bt_shell_attach(int fd) { struct io *io; @@ -831,11 +1113,24 @@ bool bt_shell_attach(int fd) io = io_new(fd); - io_set_read_handler(io, input_read, NULL, NULL); + if (!data.mode) + io_set_read_handler(io, input_read, NULL, NULL); + io_set_disconnect_handler(io, io_hup, NULL, NULL); data.input = io; + if (data.mode) { + if (shell_exec(data.argc, data.argv) < 0) { + bt_shell_noninteractive_quit(EXIT_FAILURE); + return true; + } + + if (data.timeout) + timeout_add(data.timeout * 1000, shell_quit, NULL, + NULL); + } + return true; } @@ -849,3 +1144,52 @@ bool bt_shell_detach(void) return true; } + +static bool match_env(const void *data, const void *user_data) +{ + const struct bt_shell_env *env = data; + const char *name = user_data; + + return !strcmp(env->name, name); +} + +void bt_shell_set_env(const char *name, void *value) +{ + struct bt_shell_env *env; + + if (!data.envs) { + if (!value) + return; + data.envs = queue_new(); + goto done; + } + + env = queue_remove_if(data.envs, match_env, (void *) name); + if (env) + env_destroy(env); + + /* Don't create an env if value is not set */ + if (!value) + return; + +done: + env = new0(struct bt_shell_env, 1); + env->name = strdup(name); + env->value = value; + + queue_push_tail(data.envs, env); +} + +void *bt_shell_get_env(const char *name) +{ + const struct bt_shell_env *env; + + if (!data.envs) + return NULL; + + env = queue_find(data.envs, match_env, name); + if (!env) + return NULL; + + return env->value; +} diff --git a/src/shared/shell.h b/src/shared/shell.h index 8b8b1f63..8b7cb7f3 100644 --- a/src/shared/shell.h +++ b/src/shared/shell.h @@ -66,7 +66,10 @@ struct bt_shell_opt { void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt); -void bt_shell_run(void); +int bt_shell_run(void); + +void bt_shell_quit(int status); +void bt_shell_noninteractive_quit(int status); bool bt_shell_set_menu(const struct bt_shell_menu *menu); @@ -79,6 +82,7 @@ void bt_shell_set_prompt(const char *string); void bt_shell_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void bt_shell_hexdump(const unsigned char *buf, size_t len); +void bt_shell_usage(void); void bt_shell_prompt_input(const char *label, const char *msg, bt_shell_prompt_input_func func, void *user_data); @@ -87,4 +91,7 @@ int bt_shell_release_prompt(const char *input); bool bt_shell_attach(int fd); bool bt_shell_detach(void); +void bt_shell_set_env(const char *name, void *value); +void *bt_shell_get_env(const char *name); + void bt_shell_cleanup(void); diff --git a/src/shared/util.c b/src/shared/util.c index f6f265e5..43a81afa 100755 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -980,3 +980,48 @@ const char *bt_appear_to_str(uint16_t appearance) return str; } + +char *strdelimit(char *str, char *del, char c) +{ + char *dup; + + if (!str) + return NULL; + + dup = strdup(str); + if (dup[0] == '\0') + return dup; + + while (del[0] != '\0') { + char *rep = dup; + + while ((rep = strchr(rep, del[0]))) + rep[0] = c; + + del++; + } + + return dup; +} + +int strsuffix(const char *str, const char *suffix) +{ + int len; + int suffix_len; + + if (!str || !suffix) + return -1; + + if (str[0] == '\0' && suffix[0] != '\0') + return -1; + + if (suffix[0] == '\0' && str[0] != '\0') + return -1; + + len = strlen(str); + suffix_len = strlen(suffix); + if (len < suffix_len) + return -1; + + return strncmp(str + len - suffix_len, suffix, suffix_len); +} diff --git a/src/shared/util.h b/src/shared/util.h index 3f5f6dfb..604dc3be 100755 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -92,6 +92,9 @@ do { \ #define newa(t, n) ((t*) alloca(sizeof(t)*(n))) #define malloc0(n) (calloc((n), 1)) +char *strdelimit(char *str, char *del, char c); +int strsuffix(const char *str, const char *suffix); + void *btd_malloc(size_t size); typedef void (*util_debug_func_t)(const char *str, void *user_data); diff --git a/tools/bluetooth-player.c b/tools/bluetooth-player.c index b22de277..0ab8cab3 100755 --- a/tools/bluetooth-player.c +++ b/tools/bluetooth-player.c @@ -51,9 +51,9 @@ static DBusConnection *dbus_conn; static GDBusProxy *default_player; -static GSList *players = NULL; -static GSList *folders = NULL; -static GSList *items = NULL; +static GList *players = NULL; +static GList *folders = NULL; +static GList *items = NULL; static void connect_handler(DBusConnection *connection, void *user_data) { @@ -90,25 +90,12 @@ static void play_reply(DBusMessage *message, void *user_data) bt_shell_printf("Play successful\n"); } -static GDBusProxy *find_item(const char *path) -{ - GSList *l; - - for (l = items; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - static void cmd_play_item(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_item(argv[1]); + proxy = g_dbus_proxy_lookup(items, NULL, argv[1], + BLUEZ_MEDIA_ITEM_INTERFACE); if (proxy == NULL) { bt_shell_printf("Item %s not available\n", argv[1]); return; @@ -460,28 +447,14 @@ static void print_player(GDBusProxy *proxy, const char *description) static void cmd_list(int argc, char *arg[]) { - GSList *l; + GList *l; - for (l = players; l; l = g_slist_next(l)) { + for (l = players; l; l = g_list_next(l)) { GDBusProxy *proxy = l->data; print_player(proxy, NULL); } } -static GDBusProxy *find_player(const char *path) -{ - GSList *l; - - for (l = players; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - static void print_iter(const char *label, const char *name, DBusMessageIter *iter) { @@ -557,25 +530,12 @@ static void print_property(GDBusProxy *proxy, const char *name) print_iter("\t", name, &iter); } -static GDBusProxy *find_folder(const char *path) -{ - GSList *l; - - for (l = folders; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - static void cmd_show_item(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_item(argv[1]); + proxy = g_dbus_proxy_lookup(items, NULL, argv[1], + BLUEZ_MEDIA_ITEM_INTERFACE); if (!proxy) { bt_shell_printf("Item %s not available\n", argv[1]); return; @@ -605,7 +565,8 @@ static void cmd_show(int argc, char *argv[]) proxy = default_player; } else { - proxy = find_player(argv[1]); + proxy = g_dbus_proxy_lookup(players, NULL, argv[1], + BLUEZ_MEDIA_PLAYER_INTERFACE); if (!proxy) { bt_shell_printf("Player %s not available\n", argv[1]); return; @@ -623,7 +584,9 @@ static void cmd_show(int argc, char *argv[]) print_property(proxy, "Position"); print_property(proxy, "Track"); - folder = find_folder(g_dbus_proxy_get_path(proxy)); + folder = g_dbus_proxy_lookup(folders, NULL, + g_dbus_proxy_get_path(proxy), + BLUEZ_MEDIA_FOLDER_INTERFACE); if (folder == NULL) return; @@ -637,7 +600,8 @@ static void cmd_show(int argc, char *argv[]) dbus_message_iter_get_basic(&iter, &path); - item = find_item(path); + item = g_dbus_proxy_lookup(items, NULL, path, + BLUEZ_MEDIA_ITEM_INTERFACE); if (item == NULL) return; @@ -650,7 +614,8 @@ static void cmd_select(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_player(argv[1]); + proxy = g_dbus_proxy_lookup(players, NULL, argv[1], + BLUEZ_MEDIA_PLAYER_INTERFACE); if (proxy == NULL) { bt_shell_printf("Player %s not available\n", argv[1]); return; @@ -697,7 +662,9 @@ static void cmd_change_folder(int argc, char *argv[]) if (check_default_player() == FALSE) return; - proxy = find_folder(g_dbus_proxy_get_path(default_player)); + proxy = g_dbus_proxy_lookup(folders, NULL, + g_dbus_proxy_get_path(default_player), + BLUEZ_MEDIA_FOLDER_INTERFACE); if (proxy == NULL) { bt_shell_printf("Operation not supported\n"); return; @@ -799,7 +766,9 @@ static void cmd_list_items(int argc, char *argv[]) if (check_default_player() == FALSE) return; - proxy = find_folder(g_dbus_proxy_get_path(default_player)); + proxy = g_dbus_proxy_lookup(folders, NULL, + g_dbus_proxy_get_path(default_player), + BLUEZ_MEDIA_FOLDER_INTERFACE); if (proxy == NULL) { bt_shell_printf("Operation not supported\n"); return; @@ -882,7 +851,9 @@ static void cmd_search(int argc, char *argv[]) if (check_default_player() == FALSE) return; - proxy = find_folder(g_dbus_proxy_get_path(default_player)); + proxy = g_dbus_proxy_lookup(folders, NULL, + g_dbus_proxy_get_path(default_player), + BLUEZ_MEDIA_FOLDER_INTERFACE); if (proxy == NULL) { bt_shell_printf("Operation not supported\n"); return; @@ -919,7 +890,8 @@ static void cmd_queue(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_item(argv[1]); + proxy = g_dbus_proxy_lookup(items, NULL, argv[1], + BLUEZ_MEDIA_ITEM_INTERFACE); if (proxy == NULL) { bt_shell_printf("Item %s not available\n", argv[1]); return; @@ -970,7 +942,7 @@ static const struct bt_shell_menu main_menu = { static void player_added(GDBusProxy *proxy) { - players = g_slist_append(players, proxy); + players = g_list_append(players, proxy); if (default_player == NULL) default_player = proxy; @@ -992,7 +964,7 @@ static void print_folder(GDBusProxy *proxy, const char *description) static void folder_added(GDBusProxy *proxy) { - folders = g_slist_append(folders, proxy); + folders = g_list_append(folders, proxy); print_folder(proxy, COLORED_NEW); } @@ -1017,7 +989,7 @@ static void print_item(GDBusProxy *proxy, const char *description) static void item_added(GDBusProxy *proxy) { - items = g_slist_append(items, proxy); + items = g_list_append(items, proxy); print_item(proxy, COLORED_NEW); } @@ -1043,19 +1015,19 @@ static void player_removed(GDBusProxy *proxy) if (default_player == proxy) default_player = NULL; - players = g_slist_remove(players, proxy); + players = g_list_remove(players, proxy); } static void folder_removed(GDBusProxy *proxy) { - folders = g_slist_remove(folders, proxy); + folders = g_list_remove(folders, proxy); print_folder(proxy, COLORED_DEL); } static void item_removed(GDBusProxy *proxy) { - items = g_slist_remove(items, proxy); + items = g_list_remove(items, proxy); print_item(proxy, COLORED_DEL); } diff --git a/tools/btmgmt.c b/tools/btmgmt.c index 3911ba26..122c46d0 100755 --- a/tools/btmgmt.c +++ b/tools/btmgmt.c @@ -40,9 +40,6 @@ #include <wordexp.h> #include <ctype.h> -#include <readline/readline.h> -#include <readline/history.h> - #include "lib/bluetooth.h" #include "lib/hci.h" #include "lib/hci_lib.h" @@ -52,11 +49,11 @@ #include "src/uuid-helper.h" #include "lib/mgmt.h" -#include "client/display.h" #include "src/shared/mainloop.h" #include "src/shared/io.h" #include "src/shared/util.h" #include "src/shared/mgmt.h" +#include "src/shared/shell.h" #define SCAN_TYPE_BREDR (1 << BDADDR_BREDR) #define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM)) @@ -67,10 +64,6 @@ static uint16_t mgmt_index = MGMT_INDEX_NONE; static bool discovery = false; static bool resolve_names = true; -static bool interactive = false; - -static char *saved_prompt = NULL; -static int saved_point = 0; static struct { uint16_t index; @@ -80,6 +73,7 @@ static struct { .index = MGMT_INDEX_NONE, }; + static int pending_index = 0; #ifndef MIN @@ -88,7 +82,7 @@ static int pending_index = 0; #define PROMPT_ON COLOR_BLUE "[mgmt]" COLOR_OFF "# " -static void set_index(char *arg) +static void set_index(const char *arg) { if (!arg || !strcmp(arg, "none") || !strcmp(arg, "any") || !strcmp(arg, "all")) @@ -110,38 +104,15 @@ static void update_prompt(uint16_t index) snprintf(str, sizeof(str), COLOR_BLUE "[hci%u]" COLOR_OFF "# ", index); - if (saved_prompt) { - free(saved_prompt); - saved_prompt = strdup(str); - return; - } - - rl_set_prompt(str); -} - -static void noninteractive_quit(int status) -{ - if (interactive) - return; - - if (status == EXIT_SUCCESS) - mainloop_exit_success(); - else - mainloop_exit_failure(); + bt_shell_set_prompt(str); } #define print(fmt, arg...) do { \ - if (interactive) \ - rl_printf(fmt "\n", ## arg); \ - else \ - printf(fmt "\n", ## arg); \ + bt_shell_printf(fmt "\n", ## arg); \ } while (0) #define error(fmt, arg...) do { \ - if (interactive) \ - rl_printf(COLOR_RED fmt "\n" COLOR_OFF, ## arg); \ - else \ - fprintf(stderr, fmt "\n", ## arg); \ + bt_shell_printf(COLOR_RED fmt "\n" COLOR_OFF, ## arg); \ } while (0) static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen) @@ -428,7 +399,7 @@ static void discovering(uint16_t index, uint16_t len, const void *param, ev->discovering ? "on" : "off"); if (ev->discovering == 0 && discovery) - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void new_link_key(uint16_t index, uint16_t len, const void *param, @@ -481,29 +452,6 @@ static void connected(uint16_t index, uint16_t len, const void *param, typestr(ev->addr.type), eir_len); } -static void release_prompt(void) -{ - if (!interactive) - return; - - memset(&prompt, 0, sizeof(prompt)); - prompt.index = MGMT_INDEX_NONE; - - if (!saved_prompt) - return; - - /* This will cause rl_expand_prompt to re-run over the last prompt, - * but our prompt doesn't expand anyway. - */ - rl_set_prompt(saved_prompt); - rl_replace_line("", 0); - rl_point = saved_point; - rl_redisplay(); - - free(saved_prompt); - saved_prompt = NULL; -} - static void disconnected(uint16_t index, uint16_t len, const void *param, void *user_data) { @@ -516,9 +464,6 @@ static void disconnected(uint16_t index, uint16_t len, const void *param, return; } - if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr))) - release_prompt(); - if (len < sizeof(*ev)) reason = MGMT_DEV_DISCONN_UNKNOWN; else @@ -557,9 +502,6 @@ static void auth_failed(uint16_t index, uint16_t len, const void *param, return; } - if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr))) - release_prompt(); - ba2str(&ev->addr.bdaddr, addr); print("hci%u %s auth failed with status 0x%02x (%s)", index, addr, ev->status, mgmt_errstr(ev->status)); @@ -739,14 +681,13 @@ static void pin_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("PIN Code reply failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("PIN Reply successful"); } -static int mgmt_pin_reply(struct mgmt *mgmt, uint16_t index, - const struct mgmt_addr_info *addr, +static int mgmt_pin_reply(uint16_t index, const struct mgmt_addr_info *addr, const char *pin, size_t len) { struct mgmt_cp_pin_code_reply cp; @@ -756,8 +697,8 @@ static int mgmt_pin_reply(struct mgmt *mgmt, uint16_t index, cp.pin_len = len; memcpy(cp.pin_code, pin, len); - return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, sizeof(cp), &cp, - pin_rsp, NULL, NULL); + return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, + sizeof(cp), &cp, pin_rsp, NULL, NULL); } static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param, @@ -766,14 +707,13 @@ static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("PIN Neg reply failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("PIN Negative Reply successful"); } -static int mgmt_pin_neg_reply(struct mgmt *mgmt, uint16_t index, - const struct mgmt_addr_info *addr) +static int mgmt_pin_neg_reply(uint16_t index, const struct mgmt_addr_info *addr) { struct mgmt_cp_pin_code_neg_reply cp; @@ -790,14 +730,13 @@ static void confirm_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("User Confirm reply failed. status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("User Confirm Reply successful"); } -static int mgmt_confirm_reply(struct mgmt *mgmt, uint16_t index, - const struct mgmt_addr_info *addr) +static int mgmt_confirm_reply(uint16_t index, const struct mgmt_addr_info *addr) { struct mgmt_cp_user_confirm_reply cp; @@ -814,13 +753,13 @@ static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Confirm Neg reply failed. status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("User Confirm Negative Reply successful"); } -static int mgmt_confirm_neg_reply(struct mgmt *mgmt, uint16_t index, +static int mgmt_confirm_neg_reply(uint16_t index, const struct mgmt_addr_info *addr) { struct mgmt_cp_user_confirm_reply cp; @@ -838,15 +777,14 @@ static void passkey_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("User Passkey reply failed. status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("User Passkey Reply successful"); } -static int mgmt_passkey_reply(struct mgmt *mgmt, uint16_t index, - const struct mgmt_addr_info *addr, - uint32_t passkey) +static int mgmt_passkey_reply(uint16_t index, const struct mgmt_addr_info *addr, + uint32_t passkey) { struct mgmt_cp_user_passkey_reply cp; @@ -864,13 +802,13 @@ static void passkey_neg_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Passkey Neg reply failed. status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("User Passkey Negative Reply successful"); } -static int mgmt_passkey_neg_reply(struct mgmt *mgmt, uint16_t index, +static int mgmt_passkey_neg_reply(uint16_t index, const struct mgmt_addr_info *addr) { struct mgmt_cp_user_passkey_reply cp; @@ -882,85 +820,40 @@ static int mgmt_passkey_neg_reply(struct mgmt *mgmt, uint16_t index, sizeof(cp), &cp, passkey_neg_rsp, NULL, NULL); } -static bool prompt_input(const char *input) +static void prompt_input(const char *input, void *user_data) { size_t len; - if (!prompt.req) - return false; - len = strlen(input); switch (prompt.req) { case MGMT_EV_PIN_CODE_REQUEST: if (len) - mgmt_pin_reply(mgmt, prompt.index, &prompt.addr, - input, len); + mgmt_pin_reply(prompt.index, &prompt.addr, input, len); else - mgmt_pin_neg_reply(mgmt, prompt.index, &prompt.addr); + mgmt_pin_neg_reply(prompt.index, &prompt.addr); break; case MGMT_EV_USER_PASSKEY_REQUEST: if (strlen(input) > 0) - mgmt_passkey_reply(mgmt, prompt.index, &prompt.addr, + mgmt_passkey_reply(prompt.index, &prompt.addr, atoi(input)); else - mgmt_passkey_neg_reply(mgmt, prompt.index, + mgmt_passkey_neg_reply(prompt.index, &prompt.addr); break; case MGMT_EV_USER_CONFIRM_REQUEST: if (input[0] == 'y' || input[0] == 'Y') - mgmt_confirm_reply(mgmt, prompt.index, &prompt.addr); + mgmt_confirm_reply(prompt.index, &prompt.addr); else - mgmt_confirm_neg_reply(mgmt, prompt.index, - &prompt.addr); + mgmt_confirm_neg_reply(prompt.index, &prompt.addr); break; } - - release_prompt(); - - return true; -} - -static void interactive_prompt(const char *msg) -{ - if (saved_prompt) - return; - - saved_prompt = strdup(rl_prompt); - if (!saved_prompt) - return; - - saved_point = rl_point; - - rl_set_prompt(""); - rl_redisplay(); - - rl_set_prompt(msg); - - rl_replace_line("", 0); - rl_redisplay(); -} - -static size_t get_input(char *buf, size_t buf_len) -{ - size_t len; - - if (!fgets(buf, buf_len, stdin)) - return 0; - - len = strlen(buf); - - /* Remove trailing white-space */ - while (len && isspace(buf[len - 1])) - buf[--len] = '\0'; - - return len; } static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr, const char *fmt, ...) { - char msg[256], buf[18]; + char msg[256]; va_list ap; int off; @@ -975,18 +868,7 @@ static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr, snprintf(msg + off, sizeof(msg) - off, " %s ", COLOR_BOLDGRAY ">>" COLOR_OFF); - if (interactive) { - interactive_prompt(msg); - va_end(ap); - return; - } - - printf("%s", msg); - fflush(stdout); - - memset(buf, 0, sizeof(buf)); - get_input(buf, sizeof(buf)); - prompt_input(buf); + bt_shell_prompt_input("", msg, prompt_input, NULL); } static void request_pin(uint16_t index, uint16_t len, const void *param, @@ -1137,18 +1019,15 @@ static void version_rsp(uint8_t status, uint16_t len, const void *param, get_le16(&rp->revision)); done: - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_usage(char *cmd); - -static void cmd_version(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_version(int argc, char **argv) { if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL, version_rsp, NULL, NULL) == 0) { error("Unable to send read_version cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1199,16 +1078,16 @@ static void commands_rsp(uint8_t status, uint16_t len, const void *param, } done: - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_commands(struct mgmt *mgmt, uint16_t index, int argc, +static void cmd_commands(int argc, char **argv) { if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, 0, NULL, commands_rsp, NULL, NULL) == 0) { error("Unable to send read_commands cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1246,7 +1125,7 @@ done: if (pending_index > 0) return; - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param, @@ -1259,12 +1138,12 @@ static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Reading index list failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Too small index list reply (%u bytes)", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } count = le16_to_cpu(rp->num_controllers); @@ -1272,7 +1151,7 @@ static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param, if (len < sizeof(*rp) + count * sizeof(uint16_t)) { error("Index count (%u) doesn't match reply length (%u)", count, len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("Unconfigured index list with %u item%s", @@ -1284,33 +1163,33 @@ static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param, if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL, config_info_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send read_config_info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } pending_index++; } if (!count) - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_config(int argc, char **argv) { - if (index == MGMT_INDEX_NONE) { + if (mgmt_index == MGMT_INDEX_NONE) { if (!mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, unconf_index_rsp, mgmt, NULL)) { error("Unable to send unconf_index_list cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } return; } - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL, + if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, mgmt_index, 0, NULL, config_info_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send read_config_info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1346,7 +1225,7 @@ done: if (pending_index > 0) return; - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void info_rsp(uint8_t status, uint16_t len, const void *param, @@ -1400,7 +1279,7 @@ done: if (pending_index > 0) return; - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void ext_info_rsp(uint8_t status, uint16_t len, const void *param, @@ -1450,7 +1329,7 @@ done: if (pending_index > 0) return; - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void index_rsp(uint8_t status, uint16_t len, const void *param, @@ -1464,12 +1343,12 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Reading index list failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Too small index list reply (%u bytes)", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } count = le16_to_cpu(rp->num_controllers); @@ -1477,7 +1356,7 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param, if (len < sizeof(*rp) + count * sizeof(uint16_t)) { error("Index count (%u) doesn't match reply length (%u)", count, len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("Index list with %u item%s", count, count != 1 ? "s" : ""); @@ -1488,33 +1367,33 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param, if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send read_info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } pending_index++; } if (!count) - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_info(int argc, char **argv) { - if (index == MGMT_INDEX_NONE) { + if (mgmt_index == MGMT_INDEX_NONE) { if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, index_rsp, mgmt, NULL)) { error("Unable to send index_list cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } return; } - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp, - UINT_TO_PTR(index), NULL)) { + if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, mgmt_index, 0, NULL, info_rsp, + UINT_TO_PTR(mgmt_index), NULL)) { error("Unable to send read_info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1528,12 +1407,12 @@ static void ext_index_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Reading ext index list failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Too small ext index list reply (%u bytes)", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } count = get_le16(&rp->num_controllers); @@ -1541,7 +1420,7 @@ static void ext_index_rsp(uint8_t status, uint16_t len, const void *param, if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { error("Index count (%u) doesn't match reply length (%u)", count, len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("Extended index list with %u item%s", @@ -1561,7 +1440,7 @@ static void ext_index_rsp(uint8_t status, uint16_t len, const void *param, index, 0, NULL, ext_info_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send read_ext_info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } pending_index++; break; @@ -1572,7 +1451,7 @@ static void ext_index_rsp(uint8_t status, uint16_t len, const void *param, index, 0, NULL, config_info_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send read_config cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } pending_index++; break; @@ -1589,17 +1468,17 @@ static void ext_index_rsp(uint8_t status, uint16_t len, const void *param, print(""); if (!count) - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_extinfo(struct mgmt *mgmt, uint16_t index, +static void cmd_extinfo( int argc, char **argv) { if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, ext_index_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send ext_index_list cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1610,7 +1489,7 @@ static void auto_power_enable_rsp(uint8_t status, uint16_t len, print("Successfully enabled controller with index %u", index); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void auto_power_info_rsp(uint8_t status, uint16_t len, @@ -1624,7 +1503,7 @@ static void auto_power_info_rsp(uint8_t status, uint16_t len, if (status) { error("Reading info failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } supported_settings = le32_to_cpu(rp->supported_settings); @@ -1653,13 +1532,13 @@ static void auto_power_info_rsp(uint8_t status, uint16_t len, NULL, NULL, NULL); if (current_settings & MGMT_SETTING_POWERED) - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); if (!mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, sizeof(val), &val, auto_power_enable_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send set powerd cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1677,7 +1556,7 @@ static void auto_power_index_evt(uint16_t index, uint16_t len, auto_power_info_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send read info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1692,7 +1571,7 @@ static void auto_power_index_rsp(uint8_t status, uint16_t len, if (status) { error("Reading index list failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } count = le16_to_cpu(rp->num_controllers); @@ -1716,13 +1595,15 @@ static void auto_power_index_rsp(uint8_t status, uint16_t len, auto_power_info_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send read info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_auto_power(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_auto_power(int argc, char **argv) { + int index; + + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -1730,7 +1611,7 @@ static void cmd_auto_power(struct mgmt *mgmt, uint16_t index, auto_power_index_rsp, UINT_TO_PTR(index), NULL)) { error("Unable to send read index list cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1795,16 +1676,11 @@ static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, settings2str(get_le32(rp))); done: - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static bool parse_setting(int argc, char **argv, uint8_t *val) { - if (argc < 2) { - cmd_usage(argv[0]); - return false; - } - if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) *val = 1; else if (strcasecmp(argv[1], "off") == 0) @@ -1814,37 +1690,33 @@ static bool parse_setting(int argc, char **argv, uint8_t *val) return true; } -static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op, - int argc, char **argv) +static void cmd_setting(uint16_t op, int argc, char **argv) { + int index; uint8_t val; if (parse_setting(argc, argv, &val) == false) - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) { error("Unable to send %s cmd", mgmt_opstr(op)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_power(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_power(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_POWERED, argc, argv); + cmd_setting(MGMT_OP_SET_POWERED, argc, argv); } -static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_discov(int argc, char **argv) { struct mgmt_cp_set_discoverable cp; - - if (argc < 2) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } + uint16_t index; memset(&cp, 0, sizeof(cp)); @@ -1860,53 +1732,46 @@ static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc, if (argc > 2) cp.timeout = htobs(atoi(argv[2])); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp, setting_rsp) == 0) { error("Unable to send set_discoverable cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_connectable(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_connectable(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_CONNECTABLE, argc, argv); + cmd_setting(MGMT_OP_SET_CONNECTABLE, argc, argv); } -static void cmd_fast_conn(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_fast_conn(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_FAST_CONNECTABLE, argc, argv); + cmd_setting(MGMT_OP_SET_FAST_CONNECTABLE, argc, argv); } -static void cmd_bondable(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_bondable(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_BONDABLE, argc, argv); + cmd_setting(MGMT_OP_SET_BONDABLE, argc, argv); } -static void cmd_linksec(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_linksec(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_LINK_SECURITY, argc, argv); + cmd_setting(MGMT_OP_SET_LINK_SECURITY, argc, argv); } -static void cmd_ssp(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_ssp(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_SSP, argc, argv); + cmd_setting(MGMT_OP_SET_SSP, argc, argv); } -static void cmd_sc(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_sc(int argc, char **argv) { uint8_t val; - - if (argc < 2) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } + uint16_t index; if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) val = 1; @@ -1917,45 +1782,46 @@ static void cmd_sc(struct mgmt *mgmt, uint16_t index, int argc, char **argv) else val = atoi(argv[1]); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (send_cmd(mgmt, MGMT_OP_SET_SECURE_CONN, index, sizeof(val), &val, setting_rsp) == 0) { error("Unable to send set_secure_conn cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_hs(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_hs(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_HS, argc, argv); + cmd_setting(MGMT_OP_SET_HS, argc, argv); } -static void cmd_le(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_le(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_LE, argc, argv); + cmd_setting(MGMT_OP_SET_LE, argc, argv); } -static void cmd_advertising(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_advertising(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_ADVERTISING, argc, argv); + cmd_setting(MGMT_OP_SET_ADVERTISING, argc, argv); } -static void cmd_bredr(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_bredr(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_BREDR, argc, argv); + cmd_setting(MGMT_OP_SET_BREDR, argc, argv); } -static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_privacy(int argc, char **argv) { struct mgmt_cp_set_privacy cp; + uint16_t index; if (parse_setting(argc, argv, &cp.privacy) == false) - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -1963,7 +1829,7 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc, if (hex2bin(argv[2], cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) { error("Invalid key format"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } else { int fd; @@ -1971,13 +1837,13 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc, fd = open("/dev/urandom", O_RDONLY); if (fd < 0) { error("open(/dev/urandom): %s", strerror(errno)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) { error("Reading from urandom failed"); close(fd); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } close(fd); @@ -1986,7 +1852,7 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc, if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp, setting_rsp) == 0) { error("Unable to send Set Privacy command"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -1998,39 +1864,36 @@ static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, if (len == 0 && status != 0) { error("%s failed, status 0x%02x (%s)", mgmt_opstr(op), status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len != sizeof(*rp)) { error("Unexpected %s len %u", mgmt_opstr(op), len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op), rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_class(int argc, char **argv) { uint8_t class[2]; - - if (argc < 3) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } + uint16_t index; class[0] = atoi(argv[1]); class[1] = atoi(argv[2]); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class, class_rsp) == 0) { error("Unable to send set_dev_class cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2043,12 +1906,12 @@ static void disconnect_rsp(uint8_t status, uint16_t len, const void *param, if (len == 0 && status != 0) { error("Disconnect failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len != sizeof(*rp)) { error("Invalid disconnect response length (%u)", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } ba2str(&rp->addr.bdaddr, addr); @@ -2059,7 +1922,7 @@ static void disconnect_rsp(uint8_t status, uint16_t len, const void *param, error("Disconnecting %s failed with status 0x%02x (%s)", addr, status, mgmt_errstr(status)); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option disconnect_options[] = { @@ -2068,13 +1931,12 @@ static struct option disconnect_options[] = { { 0, 0, 0, 0 } }; -static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_disconnect(int argc, char **argv) { struct mgmt_cp_disconnect cp; uint8_t type = BDADDR_BREDR; int opt; - char *cmd = argv[0]; + uint16_t index; while ((opt = getopt_long(argc, argv, "+t:h", disconnect_options, NULL)) != -1) { @@ -2083,13 +1945,13 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc, type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2097,11 +1959,7 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc, argv += optind; optind = 0; - if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); - } - + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2112,7 +1970,7 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc, if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp, disconnect_rsp, NULL, NULL) == 0) { error("Unable to send disconnect cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2124,14 +1982,14 @@ static void con_rsp(uint8_t status, uint16_t len, const void *param, if (len < sizeof(*rp)) { error("Too small (%u bytes) get_connections rsp", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } count = get_le16(&rp->conn_count); if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) { error("Invalid get_connections length (count=%u, len=%u)", count, len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } for (i = 0; i < count; i++) { @@ -2142,18 +2000,21 @@ static void con_rsp(uint8_t status, uint16_t len, const void *param, print("%s type %s", addr, typestr(rp->addr[i].type)); } - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_con(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_con(int argc, char **argv) { + uint16_t index; + + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL, con_rsp, NULL, NULL) == 0) { error("Unable to send get_connections cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2163,7 +2024,7 @@ static void find_service_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Start Service Discovery failed: status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("Service discovery started"); @@ -2191,8 +2052,7 @@ static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid) #define MAX_UUIDS 4 -static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_find_service(int argc, char **argv) { struct mgmt_cp_start_service_discovery *cp; uint8_t buf[sizeof(*cp) + 16 * MAX_UUIDS]; @@ -2203,19 +2063,15 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc, int8_t rssi; uint16_t count; int opt; - char *cmd = argv[0]; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; rssi = 127; count = 0; - if (argc == 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); - } - while ((opt = getopt_long(argc, argv, "+lbu:r:h", find_service_options, NULL)) != -1) { switch (opt) { @@ -2231,13 +2087,13 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc, if (count == MAX_UUIDS) { print("Max %u UUIDs supported", MAX_UUIDS); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (bt_string2uuid(&uuid, optarg) < 0) { print("Invalid UUID: %s", optarg); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } cp = (void *) buf; uuid_to_uuid128(&uuid128, &uuid); @@ -2249,13 +2105,13 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc, rssi = atoi(optarg); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2263,11 +2119,6 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc, argv += optind; optind = 0; - if (argc > 0) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); - } - cp = (void *) buf; cp->type = type; cp->rssi = rssi; @@ -2277,7 +2128,7 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc, sizeof(*cp) + count * 16, cp, find_service_rsp, NULL, NULL) == 0) { error("Unable to send start_service_discovery cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2287,7 +2138,7 @@ static void find_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Unable to start discovery. status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("Discovery started"); @@ -2302,14 +2153,15 @@ static struct option find_options[] = { { 0, 0, 0, 0 } }; -static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_find(int argc, char **argv) { struct mgmt_cp_start_discovery cp; uint8_t op = MGMT_OP_START_DISCOVERY; uint8_t type = SCAN_TYPE_DUAL; int opt; - char *cmd = argv[0]; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2328,13 +2180,13 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv) op = MGMT_OP_START_LIMITED_DISCOVERY; break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2348,7 +2200,7 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (mgmt_send(mgmt, op, index, sizeof(cp), &cp, find_rsp, NULL, NULL) == 0) { error("Unable to send start_discovery cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2358,13 +2210,13 @@ static void stop_find_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Stop Discovery failed: status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } print("Discovery stopped"); discovery = false; - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option stop_find_options[] = { @@ -2374,14 +2226,14 @@ static struct option stop_find_options[] = { { 0, 0, 0, 0 } }; -static void cmd_stop_find(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_stop_find(int argc, char **argv) { struct mgmt_cp_stop_discovery cp; uint8_t type = SCAN_TYPE_DUAL; int opt; - char *cmd = argv[0]; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2398,9 +2250,9 @@ static void cmd_stop_find(struct mgmt *mgmt, uint16_t index, int argc, break; case 'h': default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } } @@ -2414,7 +2266,7 @@ static void cmd_stop_find(struct mgmt *mgmt, uint16_t index, int argc, if (mgmt_send(mgmt, MGMT_OP_STOP_DISCOVERY, index, sizeof(cp), &cp, stop_find_rsp, NULL, NULL) == 0) { error("Unable to send stop_discovery cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2425,18 +2277,15 @@ static void name_rsp(uint8_t status, uint16_t len, const void *param, error("Unable to set local name with status 0x%02x (%s)", status, mgmt_errstr(status)); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_name(int argc, char **argv) { struct mgmt_cp_set_local_name cp; + uint16_t index; - if (argc < 2) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } - + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2449,7 +2298,7 @@ static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp, name_rsp, NULL, NULL) == 0) { error("Unable to send set_name cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2462,17 +2311,14 @@ static void pair_rsp(uint8_t status, uint16_t len, const void *param, if (len == 0 && status != 0) { error("Pairing failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len != sizeof(*rp)) { error("Unexpected pair_rsp len %u", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } - if (!memcmp(&rp->addr, &prompt.addr, sizeof(rp->addr))) - release_prompt(); - ba2str(&rp->addr.bdaddr, addr); if (status) @@ -2482,7 +2328,7 @@ static void pair_rsp(uint8_t status, uint16_t len, const void *param, else print("Paired with %s (%s)", addr, typestr(rp->addr.type)); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option pair_options[] = { @@ -2492,14 +2338,14 @@ static struct option pair_options[] = { { 0, 0, 0, 0 } }; -static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_pair(int argc, char **argv) { struct mgmt_cp_pair_device cp; uint8_t cap = 0x01; uint8_t type = BDADDR_BREDR; char addr[18]; int opt; - char *cmd = argv[0]; + uint16_t index; while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options, NULL)) != -1) { @@ -2511,13 +2357,13 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv) type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2526,10 +2372,11 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv) optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2544,7 +2391,7 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp, pair_rsp, NULL, NULL) == 0) { error("Unable to send pair_device cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2557,12 +2404,12 @@ static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param, if (len == 0 && status != 0) { error("Cancel Pairing failed with 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len != sizeof(*rp)) { error("Unexpected cancel_pair_rsp len %u", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } ba2str(&rp->bdaddr, addr); @@ -2574,7 +2421,7 @@ static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param, else print("Pairing Cancelled with %s", addr); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option cancel_pair_options[] = { @@ -2583,13 +2430,12 @@ static struct option cancel_pair_options[] = { { 0, 0, 0, 0 } }; -static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_cancel_pair(int argc, char **argv) { struct mgmt_addr_info cp; uint8_t type = BDADDR_BREDR; int opt; - char *cmd = argv[0]; + uint16_t index; while ((opt = getopt_long(argc, argv, "+t:h", cancel_pair_options, NULL)) != -1) { @@ -2598,13 +2444,13 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc, type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2613,10 +2459,11 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc, optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2627,7 +2474,7 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc, if (mgmt_reply(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp, cancel_pair_rsp, NULL, NULL) == 0) { error("Unable to send cancel_pair_device cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2640,12 +2487,12 @@ static void unpair_rsp(uint8_t status, uint16_t len, const void *param, if (len == 0 && status != 0) { error("Unpair device failed. status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len != sizeof(*rp)) { error("Unexpected unpair_device_rsp len %u", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } ba2str(&rp->addr.bdaddr, addr); @@ -2656,7 +2503,7 @@ static void unpair_rsp(uint8_t status, uint16_t len, const void *param, else print("%s unpaired", addr); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option unpair_options[] = { @@ -2665,13 +2512,12 @@ static struct option unpair_options[] = { { 0, 0, 0, 0 } }; -static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_unpair(int argc, char **argv) { struct mgmt_cp_unpair_device cp; uint8_t type = BDADDR_BREDR; int opt; - char *cmd = argv[0]; + uint16_t index = mgmt_index; while ((opt = getopt_long(argc, argv, "+t:h", unpair_options, NULL)) != -1) { @@ -2680,13 +2526,13 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc, type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2695,10 +2541,11 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc, optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2710,7 +2557,7 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc, if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp, unpair_rsp, NULL, NULL) == 0) { error("Unable to send unpair_device cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2723,13 +2570,15 @@ static void keys_rsp(uint8_t status, uint16_t len, const void *param, else print("Keys successfully loaded"); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_keys(int argc, char **argv) { struct mgmt_cp_load_link_keys cp; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2738,7 +2587,7 @@ static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp, keys_rsp, NULL, NULL) == 0) { error("Unable to send load_keys cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2751,13 +2600,15 @@ static void ltks_rsp(uint8_t status, uint16_t len, const void *param, else print("Long term keys successfully loaded"); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_ltks(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_ltks(int argc, char **argv) { struct mgmt_cp_load_long_term_keys cp; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2766,7 +2617,7 @@ static void cmd_ltks(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp, ltks_rsp, NULL, NULL) == 0) { error("Unable to send load_ltks cmd"); - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } } @@ -2779,7 +2630,7 @@ static void irks_rsp(uint8_t status, uint16_t len, const void *param, else print("Identity Resolving Keys successfully loaded"); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option irks_options[] = { @@ -2791,15 +2642,16 @@ static struct option irks_options[] = { #define MAX_IRKS 4 -static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_irks(int argc, char **argv) { struct mgmt_cp_load_irks *cp; uint8_t buf[sizeof(*cp) + 23 * MAX_IRKS]; uint16_t count, local_index; char path[PATH_MAX]; int opt; - char *cmd = argv[0]; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2813,7 +2665,7 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (count >= MAX_IRKS) { error("Number of IRKs exceeded"); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (strlen(optarg) > 3 && strncasecmp(optarg, "hci", 3) == 0) @@ -2826,7 +2678,7 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (!load_identity(path, &cp->irks[count])) { error("Unable to load identity"); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } count++; break; @@ -2834,23 +2686,23 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (count >= MAX_IRKS) { error("Number of IRKs exceeded"); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (!load_identity(optarg, &cp->irks[count])) { error("Unable to load identities"); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } count++; break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2858,18 +2710,13 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv) argv += optind; optind = 0; - if (argc > 0) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); - } - cp->irk_count = cpu_to_le16(count); if (mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index, sizeof(*cp) + count * 23, cp, irks_rsp, NULL, NULL) == 0) { error("Unable to send load_irks cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2882,12 +2729,12 @@ static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, if (len == 0 && status != 0) { error("%s failed, status 0x%02x (%s)", mgmt_opstr(op), status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len != sizeof(*rp)) { error("Unexpected %s len %u", mgmt_opstr(op), len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } ba2str(&rp->bdaddr, addr); @@ -2899,7 +2746,7 @@ static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, else print("%s %s succeeded", mgmt_opstr(op), addr); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option block_options[] = { @@ -2908,12 +2755,12 @@ static struct option block_options[] = { { 0, 0, 0, 0 } }; -static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_block(int argc, char **argv) { struct mgmt_cp_block_device cp; uint8_t type = BDADDR_BREDR; int opt; - char *cmd = argv[0]; + uint16_t index; while ((opt = getopt_long(argc, argv, "+t:h", block_options, NULL)) != -1) { @@ -2922,13 +2769,13 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv) type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2937,10 +2784,11 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv) optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2951,17 +2799,16 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp, block_rsp) == 0) { error("Unable to send block_device cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_unblock(int argc, char **argv) { struct mgmt_cp_unblock_device cp; uint8_t type = BDADDR_BREDR; int opt; - char *cmd = argv[0]; + uint16_t index; while ((opt = getopt_long(argc, argv, "+t:h", block_options, NULL)) != -1) { @@ -2970,13 +2817,13 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc, type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -2985,10 +2832,11 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc, optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -2999,28 +2847,29 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc, if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp, block_rsp) == 0) { error("Unable to send unblock_device cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_add_uuid(int argc, char **argv) { struct mgmt_cp_add_uuid cp; uint128_t uint128; uuid_t uuid, uuid128; + uint16_t index; if (argc < 3) { print("UUID and service hint needed"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (bt_string2uuid(&uuid, argv[1]) < 0) { print("Invalid UUID: %s", argv[1]); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } memset(&cp, 0, sizeof(cp)); @@ -3034,28 +2883,29 @@ static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc, if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp, class_rsp) == 0) { error("Unable to send add_uuid cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_remove_uuid(int argc, char **argv) { struct mgmt_cp_remove_uuid cp; uint128_t uint128; uuid_t uuid, uuid128; + uint16_t index; if (argc < 2) { print("UUID needed"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (bt_string2uuid(&uuid, argv[1]) < 0) { print("Invalid UUID: %s", argv[1]); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } memset(&cp, 0, sizeof(cp)); @@ -3067,17 +2917,16 @@ static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc, if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp, class_rsp) == 0) { error("Unable to send remove_uuid cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_clr_uuids(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_clr_uuids(int argc, char **argv) { char *uuid_any = "00000000-0000-0000-0000-000000000000"; char *rm_argv[] = { "rm-uuid", uuid_any, NULL }; - cmd_remove_uuid(mgmt, index, 2, rm_argv); + cmd_remove_uuid(2, rm_argv); } static void local_oob_rsp(uint8_t status, uint16_t len, const void *param, @@ -3089,12 +2938,12 @@ static void local_oob_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Read Local OOB Data failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Too small (%u bytes) read_local_oob rsp", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } bin2hex(rp->hash192, 16, str, sizeof(str)); @@ -3104,7 +2953,7 @@ static void local_oob_rsp(uint8_t status, uint16_t len, const void *param, print("Randomizer R with P-192: %s", str); if (len < sizeof(*rp)) - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); bin2hex(rp->hash256, 16, str, sizeof(str)); print("Hash C from P-256: %s", str); @@ -3112,19 +2961,21 @@ static void local_oob_rsp(uint8_t status, uint16_t len, const void *param, bin2hex(rp->rand256, 16, str, sizeof(str)); print("Randomizer R with P-256: %s", str); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_local_oob(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_local_oob(int argc, char **argv) { + uint16_t index; + + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL, local_oob_rsp, NULL, NULL) == 0) { error("Unable to send read_local_oob cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3155,12 +3006,11 @@ static struct option remote_oob_opt[] = { { 0, 0, 0, 0 } }; -static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_remote_oob(int argc, char **argv) { struct mgmt_cp_add_remote_oob_data cp; int opt; - char *cmd = argv[0]; + uint16_t index; memset(&cp, 0, sizeof(cp)); cp.addr.type = BDADDR_BREDR; @@ -3184,9 +3034,9 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index, hex2bin(optarg, cp.hash256, 16); break; default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3195,10 +3045,11 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index, optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3210,7 +3061,7 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index, sizeof(cp), &cp, remote_oob_rsp, NULL, NULL) == 0) { error("Unable to send add_remote_oob cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3223,25 +3074,15 @@ static void did_rsp(uint8_t status, uint16_t len, const void *param, else print("Device ID successfully set"); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void did_usage(void) -{ - cmd_usage("did"); - print(" possible source values: bluetooth, usb"); -} - -static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_did(int argc, char **argv) { struct mgmt_cp_set_device_id cp; uint16_t vendor, product, version , source; int result; - - if (argc < 2) { - did_usage(); - return noninteractive_quit(EXIT_FAILURE); - } + uint16_t index; result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product, &version); @@ -3257,10 +3098,9 @@ static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv) goto done; } - did_usage(); - return noninteractive_quit(EXIT_FAILURE); - + return; done: + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3272,7 +3112,7 @@ done: if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp, did_rsp, NULL, NULL) == 0) { error("Unable to send set_device_id cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3285,19 +3125,15 @@ static void static_addr_rsp(uint8_t status, uint16_t len, const void *param, else print("Static address successfully set"); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_static_addr(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_static_addr(int argc, char **argv) { struct mgmt_cp_set_static_address cp; + uint16_t index; - if (argc < 2) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } - + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3306,7 +3142,7 @@ static void cmd_static_addr(struct mgmt *mgmt, uint16_t index, if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp, static_addr_rsp, NULL, NULL) == 0) { error("Unable to send set_static_address cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3318,31 +3154,27 @@ static void options_rsp(uint16_t op, uint16_t id, uint8_t status, if (status != 0) { error("%s for hci%u failed with status 0x%02x (%s)", mgmt_opstr(op), id, status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Too small %s response (%u bytes)", mgmt_opstr(op), len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("hci%u %s complete, options: %s", id, mgmt_opstr(op), options2str(get_le32(rp))); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_public_addr(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_public_addr(int argc, char **argv) { struct mgmt_cp_set_public_address cp; + uint16_t index; - if (argc < 2) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } - + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3351,32 +3183,32 @@ static void cmd_public_addr(struct mgmt *mgmt, uint16_t index, if (send_cmd(mgmt, MGMT_OP_SET_PUBLIC_ADDRESS, index, sizeof(cp), &cp, options_rsp) == 0) { error("Unable to send Set Public Address cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_ext_config(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_ext_config(int argc, char **argv) { struct mgmt_cp_set_external_config cp; + uint16_t index; if (parse_setting(argc, argv, &cp.config) == false) - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (send_cmd(mgmt, MGMT_OP_SET_EXTERNAL_CONFIG, index, sizeof(cp), &cp, options_rsp) == 0) { error("Unable to send Set External Config cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_debug_keys(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_debug_keys(int argc, char **argv) { - cmd_setting(mgmt, index, MGMT_OP_SET_DEBUG_KEYS, argc, argv); + cmd_setting(MGMT_OP_SET_DEBUG_KEYS, argc, argv); } static void conn_info_rsp(uint8_t status, uint16_t len, const void *param, @@ -3387,12 +3219,12 @@ static void conn_info_rsp(uint8_t status, uint16_t len, const void *param, if (len == 0 && status != 0) { error("Get Conn Info failed, status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Unexpected Get Conn Info len %u", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } ba2str(&rp->addr.bdaddr, addr); @@ -3408,22 +3240,21 @@ static void conn_info_rsp(uint8_t status, uint16_t len, const void *param, rp->rssi, rp->tx_power, rp->max_tx_power); } - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option conn_info_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, { 0, 0, 0, 0 } }; -static void cmd_conn_info(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_conn_info(int argc, char **argv) { struct mgmt_cp_get_conn_info cp; uint8_t type = BDADDR_BREDR; int opt; - char *cmd = argv[0]; + uint16_t index; while ((opt = getopt_long(argc, argv, "+t:h", conn_info_options, NULL)) != -1) { @@ -3432,13 +3263,13 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index, type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3447,10 +3278,11 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index, optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3461,7 +3293,7 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index, if (mgmt_send(mgmt, MGMT_OP_GET_CONN_INFO, index, sizeof(cp), &cp, conn_info_rsp, NULL, NULL) == 0) { error("Unable to send get_conn_info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3474,20 +3306,16 @@ static void io_cap_rsp(uint8_t status, uint16_t len, const void *param, else print("IO Capabilities successfully set"); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_io_cap(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_io_cap(int argc, char **argv) { struct mgmt_cp_set_io_capability cp; uint8_t cap; + uint16_t index; - if (argc < 2) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } - + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3498,7 +3326,7 @@ static void cmd_io_cap(struct mgmt *mgmt, uint16_t index, if (mgmt_send(mgmt, MGMT_OP_SET_IO_CAPABILITY, index, sizeof(cp), &cp, io_cap_rsp, NULL, NULL) == 0) { error("Unable to send set-io-cap cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3511,19 +3339,15 @@ static void scan_params_rsp(uint8_t status, uint16_t len, const void *param, else print("Scan parameters successfully set"); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_scan_params(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_scan_params(int argc, char **argv) { struct mgmt_cp_set_scan_params cp; + uint16_t index; - if (argc < 3) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } - + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3533,7 +3357,7 @@ static void cmd_scan_params(struct mgmt *mgmt, uint16_t index, if (mgmt_send(mgmt, MGMT_OP_SET_SCAN_PARAMS, index, sizeof(cp), &cp, scan_params_rsp, NULL, NULL) == 0) { error("Unable to send set_scan_params cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3544,27 +3368,28 @@ static void clock_info_rsp(uint8_t status, uint16_t len, const void *param, if (len < sizeof(*rp)) { error("Unexpected Get Clock Info len %u", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (status) { error("Get Clock Info failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("Local Clock: %u", le32_to_cpu(rp->local_clock)); print("Piconet Clock: %u", le32_to_cpu(rp->piconet_clock)); print("Accurary: %u", le16_to_cpu(rp->accuracy)); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_clock_info(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_clock_info(int argc, char **argv) { struct mgmt_cp_get_clock_info cp; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3576,7 +3401,7 @@ static void cmd_clock_info(struct mgmt *mgmt, uint16_t index, if (mgmt_send(mgmt, MGMT_OP_GET_CLOCK_INFO, index, sizeof(cp), &cp, clock_info_rsp, NULL, NULL) == 0) { error("Unable to send get_clock_info cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3586,7 +3411,7 @@ static void add_device_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) error("Add device failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option add_device_options[] = { @@ -3596,15 +3421,14 @@ static struct option add_device_options[] = { { 0, 0, 0, 0 } }; -static void cmd_add_device(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_add_device(int argc, char **argv) { struct mgmt_cp_add_device cp; uint8_t action = 0x00; uint8_t type = BDADDR_BREDR; char addr[18]; int opt; - char *cmd = argv[0]; + uint16_t index; while ((opt = getopt_long(argc, argv, "+a:t:h", add_device_options, NULL)) != -1) { @@ -3616,13 +3440,13 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index, type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3631,10 +3455,11 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index, optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3649,7 +3474,7 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index, if (mgmt_send(mgmt, MGMT_OP_ADD_DEVICE, index, sizeof(cp), &cp, add_device_rsp, NULL, NULL) == 0) { error("Unable to send add device command"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3659,7 +3484,7 @@ static void remove_device_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) error("Remove device failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct option del_device_options[] = { @@ -3668,14 +3493,13 @@ static struct option del_device_options[] = { { 0, 0, 0, 0 } }; -static void cmd_del_device(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_del_device(int argc, char **argv) { struct mgmt_cp_remove_device cp; uint8_t type = BDADDR_BREDR; char addr[18]; int opt; - char *cmd = argv[0]; + uint16_t index; while ((opt = getopt_long(argc, argv, "+t:h", del_device_options, NULL)) != -1) { @@ -3684,13 +3508,13 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index, type = strtol(optarg, NULL, 0); break; case 'h': - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); default: - cmd_usage(cmd); + bt_shell_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3699,10 +3523,12 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index, optind = 0; if (argc < 1) { - cmd_usage(cmd); - return noninteractive_quit(EXIT_FAILURE); + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } + + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3716,17 +3542,16 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index, if (mgmt_send(mgmt, MGMT_OP_REMOVE_DEVICE, index, sizeof(cp), &cp, remove_device_rsp, NULL, NULL) == 0) { error("Unable to send remove device command"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_clr_devices(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_clr_devices(int argc, char **argv) { char *bdaddr_any = "00:00:00:00:00:00"; char *rm_argv[] = { "del-device", bdaddr_any, NULL }; - cmd_del_device(mgmt, index, 2, rm_argv); + cmd_del_device(2, rm_argv); } static void local_oob_ext_rsp(uint8_t status, uint16_t len, const void *param, @@ -3738,31 +3563,32 @@ static void local_oob_ext_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Read Local OOB Ext Data failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Too small (%u bytes) read_local_oob_ext rsp", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } eir_len = le16_to_cpu(rp->eir_len); if (len != sizeof(*rp) + eir_len) { error("local_oob_ext: expected %zu bytes, got %u bytes", sizeof(*rp) + eir_len, len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print_eir(rp->eir, eir_len); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_bredr_oob(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_bredr_oob(int argc, char **argv) { struct mgmt_cp_read_local_oob_ext_data cp; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3772,15 +3598,16 @@ static void cmd_bredr_oob(struct mgmt *mgmt, uint16_t index, index, sizeof(cp), &cp, local_oob_ext_rsp, NULL, NULL)) { error("Unable to send read_local_oob_ext cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_le_oob(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_le_oob(int argc, char **argv) { struct mgmt_cp_read_local_oob_ext_data cp; + uint16_t index; + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3790,7 +3617,7 @@ static void cmd_le_oob(struct mgmt *mgmt, uint16_t index, index, sizeof(cp), &cp, local_oob_ext_rsp, NULL, NULL)) { error("Unable to send read_local_oob_ext cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3831,18 +3658,18 @@ static void adv_features_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Reading adv features failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Too small adv features reply (%u bytes)", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp) + rp->num_instances * sizeof(uint8_t)) { error("Instances count (%u) doesn't match reply length (%u)", rp->num_instances, len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } supported_flags = le32_to_cpu(rp->supported_flags); @@ -3854,19 +3681,21 @@ static void adv_features_rsp(uint8_t status, uint16_t len, const void *param, print("Instances list with %u item%s", rp->num_instances, rp->num_instances != 1 ? "s" : ""); - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_advinfo(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_advinfo(int argc, char **argv) { + uint16_t index; + + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_FEATURES, index, 0, NULL, adv_features_rsp, NULL, NULL)) { error("Unable to send advertising features command"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3879,12 +3708,12 @@ static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Reading adv size info failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len < sizeof(*rp)) { error("Too small adv size info reply (%u bytes)", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } flags = le32_to_cpu(rp->flags); @@ -3893,19 +3722,19 @@ static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param, print("Max advertising data len: %u", rp->max_adv_data_len); print("Max scan response data len: %u", rp->max_scan_rsp_len); - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void advsize_usage(void) { - cmd_usage("advsize"); + bt_shell_usage(); print("Options:\n" "\t -c, --connectable \"connectable\" flag\n" "\t -g, --general-discov \"general-discoverable\" flag\n" "\t -l, --limited-discov \"limited-discoverable\" flag\n" "\t -m, --managed-flags \"managed-flags\" flag\n" - "\t -p, --tx-power \"tx-power\" flag\n"\ - "\t -a, --appearance \"appearance\" flag\n"\ + "\t -p, --tx-power \"tx-power\" flag\n" + "\t -a, --appearance \"appearance\" flag\n" "\t -n, --local-name \"local-name\" flag"); } @@ -3921,13 +3750,13 @@ static struct option advsize_options[] = { { 0, 0, 0, 0} }; -static void cmd_advsize(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_advsize(int argc, char **argv) { struct mgmt_cp_get_adv_size_info cp; uint8_t instance; uint32_t flags = 0; int opt; + uint16_t index; while ((opt = getopt_long(argc, argv, "+cglmphna", advsize_options, NULL)) != -1) { @@ -3956,7 +3785,7 @@ static void cmd_advsize(struct mgmt *mgmt, uint16_t index, default: advsize_usage(); optind = 0; - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3966,11 +3795,12 @@ static void cmd_advsize(struct mgmt *mgmt, uint16_t index, if (argc != 1) { advsize_usage(); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } instance = strtol(argv[0], NULL, 0); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -3982,7 +3812,7 @@ static void cmd_advsize(struct mgmt *mgmt, uint16_t index, if (!mgmt_send(mgmt, MGMT_OP_GET_ADV_SIZE_INFO, index, sizeof(cp), &cp, adv_size_info_rsp, NULL, NULL)) { error("Unable to send advertising size info command"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -3994,22 +3824,22 @@ static void add_adv_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Add Advertising failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len != sizeof(*rp)) { error("Invalid Add Advertising response length (%u)", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("Instance added: %u", rp->instance); - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void add_adv_usage(void) { - cmd_usage("add-adv"); + bt_shell_usage(); print("Options:\n" "\t -u, --uuid <uuid> Service UUID\n" "\t -d, --adv-data <data> Advertising Data bytes\n" @@ -4084,8 +3914,7 @@ static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len) #define MAX_AD_UUID_BYTES 32 -static void cmd_add_adv(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) +static void cmd_add_adv(int argc, char **argv) { struct mgmt_cp_add_advertising *cp = NULL; int opt; @@ -4101,6 +3930,7 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index, bool success = false; bool quit = true; uint32_t flags = 0; + uint16_t index; while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:cglmphna", add_adv_options, NULL)) != -1) { @@ -4211,6 +4041,7 @@ static void cmd_add_adv(struct mgmt *mgmt, uint16_t index, instance = strtol(argv[0], NULL, 0); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -4249,7 +4080,7 @@ done: free(cp); if (quit) - noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); + bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); } static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param, @@ -4260,31 +4091,28 @@ static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param, if (status != 0) { error("Remove Advertising failed with status 0x%02x (%s)", status, mgmt_errstr(status)); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } if (len != sizeof(*rp)) { error("Invalid Remove Advertising response length (%u)", len); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } print("Instance removed: %u", rp->instance); - return noninteractive_quit(EXIT_SUCCESS); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_rm_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_rm_adv(int argc, char **argv) { struct mgmt_cp_remove_advertising cp; uint8_t instance; - - if (argc != 2) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } + uint16_t index; instance = strtol(argv[1], NULL, 0); + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -4295,16 +4123,16 @@ static void cmd_rm_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv) if (!mgmt_send(mgmt, MGMT_OP_REMOVE_ADVERTISING, index, sizeof(cp), &cp, rm_adv_rsp, NULL, NULL)) { error("Unable to send \"Remove Advertising\" command"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -static void cmd_clr_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv) +static void cmd_clr_adv(int argc, char **argv) { char *all_instances = "0"; char *rm_argv[] = { "rm-adv", all_instances, NULL }; - cmd_rm_adv(mgmt, index, 2, rm_argv); + cmd_rm_adv(2, rm_argv); } static void appearance_rsp(uint8_t status, uint16_t len, const void *param, @@ -4316,19 +4144,15 @@ static void appearance_rsp(uint8_t status, uint16_t len, const void *param, else print("Appearance successfully set"); - noninteractive_quit(EXIT_SUCCESS); + bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_appearance(struct mgmt *mgmt, uint16_t index, int argc, - char **argv) +static void cmd_appearance(int argc, char **argv) { struct mgmt_cp_set_appearance cp; + uint16_t index; - if (argc < 2) { - cmd_usage(argv[0]); - return noninteractive_quit(EXIT_FAILURE); - } - + index = mgmt_index; if (index == MGMT_INDEX_NONE) index = 0; @@ -4337,20 +4161,83 @@ static void cmd_appearance(struct mgmt *mgmt, uint16_t index, int argc, if (mgmt_send(mgmt, MGMT_OP_SET_APPEARANCE, index, sizeof(cp), &cp, appearance_rsp, NULL, NULL) == 0) { error("Unable to send appearance cmd"); - return noninteractive_quit(EXIT_FAILURE); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } } -struct cmd_info { - char *cmd; - const char *arg; - void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv); - char *doc; - char * (*gen) (const char *text, int state); - void (*disp) (char **matches, int num_matches, int max_length); -}; +static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index) +{ + mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED, index, + class_of_dev_changed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index, + local_name_changed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found, + mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin, + mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm, + mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index, + request_passkey, mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index, + passkey_notify, mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index, + unconf_index_added, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index, + unconf_index_removed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index, + new_config_options, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, index, + ext_index_added, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, index, + ext_index_removed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index, + local_oob_data_updated, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index, + advertising_added, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index, + advertising_removed, NULL, NULL); +} + +static void cmd_select(int argc, char **argv) +{ + mgmt_cancel_all(mgmt); + mgmt_unregister_all(mgmt); -static struct cmd_info all_cmd[] = { + set_index(argv[1]); + + register_mgmt_callbacks(mgmt, mgmt_index); + + print("Selected index %u", mgmt_index); + + update_prompt(mgmt_index); +} + +static const struct bt_shell_menu main_menu = { + .name = "main", + .entries = { + { "select", "<index>", + cmd_select, "Select a different index" }, { "version", NULL, cmd_version, "Get the MGMT Version" }, { "commands", NULL, @@ -4473,363 +4360,45 @@ static struct cmd_info all_cmd[] = { cmd_clr_adv, "Clear advertising instances" }, { "appearance", "<appearance>", cmd_appearance, "Set appearance" }, + {} }, }; -static void cmd_quit(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) -{ - mainloop_exit_success(); -} - -static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index) -{ - mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED, index, - class_of_dev_changed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index, - local_name_changed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index, - request_passkey, mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index, - passkey_notify, mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index, - unconf_index_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index, - unconf_index_removed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index, - new_config_options, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, index, - ext_index_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, index, - ext_index_removed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index, - local_oob_data_updated, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index, - advertising_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index, - advertising_removed, NULL, NULL); -} - -static void cmd_select(struct mgmt *mgmt, uint16_t index, - int argc, char **argv) -{ - if (argc != 2) { - cmd_usage(argv[0]); - return; - } - - mgmt_cancel_all(mgmt); - mgmt_unregister_all(mgmt); - - set_index(argv[1]); - - register_mgmt_callbacks(mgmt, mgmt_index); - - print("Selected index %u", mgmt_index); - - update_prompt(mgmt_index); -} - -static struct cmd_info interactive_cmd[] = { - { "select", "<index>", - cmd_select, "Select a different index" }, - { "quit", NULL, - cmd_quit, "Exit program" }, - { "exit", NULL, - cmd_quit, "Exit program" }, - { "help", NULL, - NULL, "List supported commands" }, -}; - -static char *cmd_generator(const char *text, int state) -{ - static size_t i, j, len; - const char *cmd; - - if (!state) { - i = 0; - j = 0; - len = strlen(text); - } - - while (i < NELEM(all_cmd)) { - cmd = all_cmd[i++].cmd; - - if (!strncmp(cmd, text, len)) - return strdup(cmd); - } - - while (j < NELEM(interactive_cmd)) { - cmd = interactive_cmd[j++].cmd; - - if (!strncmp(cmd, text, len)) - return strdup(cmd); - } - - return NULL; -} - -static char **cmd_completion(const char *text, int start, int end) -{ - char **matches = NULL; - - if (start > 0) { - unsigned int i; - - for (i = 0; i < NELEM(all_cmd); i++) { - struct cmd_info *c = &all_cmd[i]; - - if (strncmp(c->cmd, rl_line_buffer, start - 1)) - continue; - - if (!c->gen) - continue; - - rl_completion_display_matches_hook = c->disp; - matches = rl_completion_matches(text, c->gen); - break; - } - } else { - rl_completion_display_matches_hook = NULL; - matches = rl_completion_matches(text, cmd_generator); - } - - if (!matches) - rl_attempted_completion_over = 1; - - return matches; -} - -static struct cmd_info *find_cmd(const char *cmd, struct cmd_info table[], - size_t cmd_count) -{ - size_t i; - - for (i = 0; i < cmd_count; i++) { - if (!strcmp(table[i].cmd, cmd)) - return &table[i]; - } - - return NULL; -} - -static void cmd_usage(char *cmd) -{ - struct cmd_info *c; - - if (!cmd) - return; - - c = find_cmd(cmd, all_cmd, NELEM(all_cmd)); - if (!c && interactive) { - c = find_cmd(cmd, interactive_cmd, NELEM(interactive_cmd)); - if (!c) - return; - error("Usage: %s %s", cmd, c->arg ? : ""); - return; - } - - if (!c) - return; - - print("Usage: %s %s", cmd, c->arg ? : ""); - -} - -static void rl_handler(char *input) +static void mgmt_debug(const char *str, void *user_data) { - struct cmd_info *c; - wordexp_t w; - char *cmd, **argv; - size_t argc, i; - - if (!input) { - rl_insert_text("quit"); - rl_redisplay(); - rl_crlf(); - mainloop_quit(); - return; - } - - if (!strlen(input)) - goto done; - - if (prompt_input(input)) - goto done; - - if (history_search(input, -1)) - add_history(input); - - if (wordexp(input, &w, WRDE_NOCMD)) - goto done; - - if (w.we_wordc == 0) - goto free_we; - - cmd = w.we_wordv[0]; - argv = w.we_wordv; - argc = w.we_wordc; - - c = find_cmd(cmd, all_cmd, NELEM(all_cmd)); - if (!c && interactive) - c = find_cmd(cmd, interactive_cmd, NELEM(interactive_cmd)); - - if (c && c->func) { - c->func(mgmt, mgmt_index, argc, argv); - goto free_we; - } - - if (strcmp(cmd, "help")) { - print("Invalid command"); - goto free_we; - } - - print("Available commands:"); - - for (i = 0; i < NELEM(all_cmd); i++) { - c = &all_cmd[i]; - if ((int)strlen(c->arg ? : "") <= - (int)(25 - strlen(c->cmd))) - printf(" %s %-*s %s\n", c->cmd, - (int)(25 - strlen(c->cmd)), - c->arg ? : "", - c->doc ? : ""); - else - printf(" %s %-s\n" " %s %-25s %s\n", - c->cmd, - c->arg ? : "", - "", "", - c->doc ? : ""); - } - - if (!interactive) - goto free_we; - - for (i = 0; i < NELEM(interactive_cmd); i++) { - c = &interactive_cmd[i]; - if ((int)strlen(c->arg ? : "") <= - (int)(25 - strlen(c->cmd))) - printf(" %s %-*s %s\n", c->cmd, - (int)(25 - strlen(c->cmd)), - c->arg ? : "", - c->doc ? : ""); - else - printf(" %s %-s\n" " %s %-25s %s\n", - c->cmd, - c->arg ? : "", - "", "", - c->doc ? : ""); - } + const char *prefix = user_data; -free_we: - wordfree(&w); -done: - free(input); + print("%s%s", prefix, str); } -static void usage(void) -{ - unsigned int i; - - printf("btmgmt ver %s\n", VERSION); - printf("Usage:\n" - "\tbtmgmt [options] <command> [command parameters]\n"); - - printf("Options:\n" - "\t--index <id>\tSpecify adapter index\n" - "\t--verbose\tEnable extra logging\n" - "\t--help\tDisplay help\n"); - - printf("Commands:\n"); - for (i = 0; i < NELEM(all_cmd); i++) - printf("\t%-15s\t%s\n", all_cmd[i].cmd, all_cmd[i].doc); - - printf("\n" - "For more information on the usage of each command use:\n" - "\tbtmgmt <command> --help\n" ); -} +static const char *index_option; static struct option main_options[] = { { "index", 1, 0, 'i' }, - { "verbose", 0, 0, 'v' }, - { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; -static bool prompt_read(struct io *io, void *user_data) -{ - rl_callback_read_char(); - return true; -} - -static struct io *setup_stdin(void) -{ - struct io *io; - - io = io_new(STDIN_FILENO); - if (!io) - return io; - - io_set_read_handler(io, prompt_read, NULL, NULL); - - return io; -} +static const char **optargs[] = { + &index_option +}; -static void mgmt_debug(const char *str, void *user_data) -{ - const char *prefix = user_data; +static const char *help[] = { + "Specify adapter index\n" +}; - print("%s%s", prefix, str); -} +static const struct bt_shell_opt opt = { + .options = main_options, + .optno = sizeof(main_options) / sizeof(struct option), + .optstr = "i:V", + .optarg = optargs, + .help = help, +}; int main(int argc, char *argv[]) { - struct io *input; - int status, opt; - - while ((opt = getopt_long(argc, argv, "+hi:", - main_options, NULL)) != -1) { - switch (opt) { - case 'i': - set_index(optarg); - break; - case 'h': - default: - usage(); - return 0; - } - } + int status; - argc -= optind; - argv += optind; - optind = 0; - - mainloop_init(); + bt_shell_init(argc, argv, &opt); + bt_shell_set_menu(&main_menu); mgmt = mgmt_new_default(); if (!mgmt) { @@ -4840,47 +4409,14 @@ int main(int argc, char *argv[]) if (getenv("MGMT_DEBUG")) mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL); - if (argc > 0) { - struct cmd_info *c; - - c = find_cmd(argv[0], all_cmd, NELEM(all_cmd)); - if (!c) { - fprintf(stderr, "Unknown command: %s\n", argv[0]); - mgmt_unref(mgmt); - return EXIT_FAILURE; - } - - c->func(mgmt, mgmt_index, argc, argv); - } + if (index_option) + set_index(index_option); register_mgmt_callbacks(mgmt, mgmt_index); - /* Interactive mode */ - if (!argc) - input = setup_stdin(); - else - input = NULL; - - if (input) { - interactive = true; - - rl_attempted_completion_function = cmd_completion; - - rl_erase_empty_line = 1; - rl_callback_handler_install(NULL, rl_handler); - - update_prompt(mgmt_index); - rl_redisplay(); - } - - status = mainloop_run(); - - if (input) { - io_destroy(input); - - rl_message(""); - rl_callback_handler_remove(); - } + bt_shell_attach(fileno(stdin)); + update_prompt(mgmt_index); + bt_shell_run(); mgmt_cancel_all(mgmt); mgmt_unregister_all(mgmt); diff --git a/tools/obexctl.c b/tools/obexctl.c index 209442c0..d72f33e0 100755 --- a/tools/obexctl.c +++ b/tools/obexctl.c @@ -59,13 +59,13 @@ static DBusConnection *dbus_conn; static GDBusProxy *default_session; -static GSList *sessions = NULL; -static GSList *opps = NULL; -static GSList *ftps = NULL; -static GSList *pbaps = NULL; -static GSList *maps = NULL; -static GSList *msgs = NULL; -static GSList *transfers = NULL; +static GList *sessions = NULL; +static GList *opps = NULL; +static GList *ftps = NULL; +static GList *pbaps = NULL; +static GList *maps = NULL; +static GList *msgs = NULL; +static GList *transfers = NULL; static GDBusProxy *client = NULL; struct transfer_data { @@ -219,26 +219,13 @@ static void disconnect_setup(DBusMessageIter *iter, void *user_data) dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); } -static GDBusProxy *find_session(const char *path) -{ - GSList *l; - - for (l = sessions; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - static void cmd_disconnect(int argc, char *argv[]) { GDBusProxy *proxy; if (argc > 1) - proxy = find_session(argv[1]); + proxy = g_dbus_proxy_lookup(sessions, NULL, argv[1], + OBEX_SESSION_INTERFACE); else proxy = default_session; @@ -285,9 +272,9 @@ static void print_proxy(GDBusProxy *proxy, const char *title, static void cmd_list(int argc, char *arg[]) { - GSList *l; + GList *l; - for (l = sessions; l; l = g_slist_next(l)) { + for (l = sessions; l; l = g_list_next(l)) { GDBusProxy *proxy = l->data; print_proxy(proxy, "Session", NULL); } @@ -393,7 +380,8 @@ static void cmd_show(int argc, char *argv[]) proxy = default_session; } else { - proxy = find_session(argv[1]); + proxy = g_dbus_proxy_lookup(sessions, NULL, argv[1], + OBEX_SESSION_INTERFACE); if (!proxy) { bt_shell_printf("Session %s not available\n", argv[1]); return; @@ -430,7 +418,8 @@ static void cmd_select(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_session(argv[1]); + proxy = g_dbus_proxy_lookup(sessions, NULL, argv[1], + OBEX_SESSION_INTERFACE); if (proxy == NULL) { bt_shell_printf("Session %s not available\n", argv[1]); return; @@ -444,34 +433,6 @@ static void cmd_select(int argc, char *argv[]) print_proxy(proxy, "Session", NULL); } -static GDBusProxy *find_transfer(const char *path) -{ - GSList *l; - - for (l = transfers; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - -static GDBusProxy *find_message(const char *path) -{ - GSList *l; - - for (l = msgs; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - static void transfer_info(GDBusProxy *proxy, int argc, char *argv[]) { bt_shell_printf("Transfer %s\n", g_dbus_proxy_get_path(proxy)); @@ -512,13 +473,14 @@ static void cmd_info(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_transfer(argv[1]); + proxy = g_dbus_proxy_lookup(transfers, NULL, argv[1], + OBEX_TRANSFER_INTERFACE); if (proxy) { transfer_info(proxy, argc, argv); return; } - proxy = find_message(argv[1]); + proxy = g_dbus_proxy_lookup(msgs, NULL, argv[1], OBEX_MSG_INTERFACE); if (proxy) { message_info(proxy, argc, argv); return; @@ -546,7 +508,8 @@ static void cmd_cancel(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_transfer(argv[1]); + proxy = g_dbus_proxy_lookup(transfers, NULL, argv[1], + OBEX_TRANSFER_INTERFACE); if (!proxy) { bt_shell_printf("Transfer %s not available\n", argv[1]); return; @@ -581,7 +544,8 @@ static void cmd_suspend(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_transfer(argv[1]); + proxy = g_dbus_proxy_lookup(transfers, NULL, argv[1], + OBEX_TRANSFER_INTERFACE); if (!proxy) { bt_shell_printf("Transfer %s not available\n", argv[1]); return; @@ -616,7 +580,8 @@ static void cmd_resume(int argc, char *argv[]) { GDBusProxy *proxy; - proxy = find_transfer(argv[1]); + proxy = g_dbus_proxy_lookup(transfers, NULL, argv[1], + OBEX_TRANSFER_INTERFACE); if (!proxy) { bt_shell_printf("Transfer %s not available\n", argv[1]); return; @@ -632,34 +597,6 @@ static void cmd_resume(int argc, char *argv[]) g_dbus_proxy_get_path(proxy)); } -static GDBusProxy *find_opp(const char *path) -{ - GSList *l; - - for (l = opps; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - -static GDBusProxy *find_map(const char *path) -{ - GSList *l; - - for (l = maps; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - static void print_dict_iter(DBusMessageIter *iter) { DBusMessageIter dict; @@ -806,18 +743,19 @@ static void map_send(GDBusProxy *proxy, int argc, char *argv[]) static void cmd_send(int argc, char *argv[]) { + const char *path = g_dbus_proxy_get_path(default_session); GDBusProxy *proxy; if (!check_default_session()) return; - proxy = find_opp(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(opps, NULL, path, OBEX_OPP_INTERFACE); if (proxy) { opp_send(proxy, argc, argv); return; } - proxy = find_map(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(maps, NULL, path, OBEX_MAP_INTERFACE); if (proxy) { map_send(proxy, argc, argv); return; @@ -828,12 +766,13 @@ static void cmd_send(int argc, char *argv[]) static void cmd_pull(int argc, char *argv[]) { + const char *path = g_dbus_proxy_get_path(default_session); GDBusProxy *proxy; if (!check_default_session()) return; - proxy = find_opp(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(opps, NULL, path, OBEX_OPP_INTERFACE); if (proxy) { opp_pull(proxy, argc, argv); return; @@ -913,34 +852,6 @@ static void setfolder_setup(DBusMessageIter *iter, void *user_data) dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder); } -static GDBusProxy *find_ftp(const char *path) -{ - GSList *l; - - for (l = ftps; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - -static GDBusProxy *find_pbap(const char *path) -{ - GSList *l; - - for (l = pbaps; l; l = g_slist_next(l)) { - GDBusProxy *proxy = l->data; - - if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) - return proxy; - } - - return NULL; -} - static void ftp_cd(GDBusProxy *proxy, int argc, char *argv[]) { if (g_dbus_proxy_method_call(proxy, "ChangeFolder", change_folder_setup, @@ -979,24 +890,25 @@ static void map_cd(GDBusProxy *proxy, int argc, char *argv[]) static void cmd_cd(int argc, char *argv[]) { + const char *path = g_dbus_proxy_get_path(default_session); GDBusProxy *proxy; if (!check_default_session()) return; - proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(ftps, NULL, path, OBEX_FTP_INTERFACE); if (proxy) { ftp_cd(proxy, argc, argv); return; } - proxy = find_pbap(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(pbaps, NULL, path, OBEX_PBAP_INTERFACE); if (proxy) { pbap_cd(proxy, argc, argv); return; } - proxy = find_map(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(maps, NULL, path, OBEX_MAP_INTERFACE); if (proxy) { map_cd(proxy, argc, argv); return; @@ -1326,24 +1238,25 @@ static void map_ls(GDBusProxy *proxy, int argc, char *argv[]) static void cmd_ls(int argc, char *argv[]) { + const char *path = g_dbus_proxy_get_path(default_session); GDBusProxy *proxy; if (!check_default_session()) return; - proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(ftps, NULL, path, OBEX_FTP_INTERFACE); if (proxy) { ftp_ls(proxy, argc, argv); return; } - proxy = find_pbap(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(pbaps, NULL, path, OBEX_PBAP_INTERFACE); if (proxy) { pbap_ls(proxy, argc, argv); return; } - proxy = find_map(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(maps, NULL, path, OBEX_MAP_INTERFACE); if (proxy) { map_ls(proxy, argc, argv); return; @@ -1652,7 +1565,7 @@ static void map_cp(GDBusProxy *proxy, int argc, char *argv[]) { GDBusProxy *obj; - obj = find_message(argv[1]); + obj = g_dbus_proxy_lookup(msgs, NULL, argv[1], OBEX_MSG_INTERFACE); if (obj == NULL) { bt_shell_printf("Invalid message argument\n"); return; @@ -1669,25 +1582,25 @@ static void map_cp(GDBusProxy *proxy, int argc, char *argv[]) static void cmd_cp(int argc, char *argv[]) { - + const char *path = g_dbus_proxy_get_path(default_session); GDBusProxy *proxy; if (!check_default_session()) return; - proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(ftps, NULL, path, OBEX_FTP_INTERFACE); if (proxy) { ftp_cp(proxy, argc, argv); return; } - proxy = find_pbap(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(pbaps, NULL, path, OBEX_PBAP_INTERFACE); if (proxy) { pbap_cp(proxy, argc, argv); return; } - proxy = find_map(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(maps, NULL, path, OBEX_MAP_INTERFACE); if (proxy) { map_cp(proxy, argc, argv); return; @@ -1713,13 +1626,14 @@ static void move_file_reply(DBusMessage *message, void *user_data) static void cmd_mv(int argc, char *argv[]) { + const char *path = g_dbus_proxy_get_path(default_session); GDBusProxy *proxy; struct cp_args *args; if (!check_default_session()) return; - proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(ftps, NULL, path, OBEX_FTP_INTERFACE); if (proxy == NULL) { bt_shell_printf("Command not supported\n"); return; @@ -1783,7 +1697,7 @@ static void map_rm(GDBusProxy *proxy, int argc, char *argv[]) GDBusProxy *msg; dbus_bool_t value = TRUE; - msg = find_message(argv[1]); + msg = g_dbus_proxy_lookup(msgs, NULL, argv[1], OBEX_MSG_INTERFACE); if (msg == NULL) { bt_shell_printf("Invalid message argument\n"); return; @@ -1801,18 +1715,19 @@ static void map_rm(GDBusProxy *proxy, int argc, char *argv[]) static void cmd_rm(int argc, char *argv[]) { + const char *path = g_dbus_proxy_get_path(default_session); GDBusProxy *proxy; if (!check_default_session()) return; - proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(ftps, NULL, path, OBEX_FTP_INTERFACE); if (proxy) { ftp_rm(proxy, argc, argv); return; } - proxy = find_map(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(maps, NULL, path, OBEX_MAP_INTERFACE); if (proxy) { map_rm(proxy, argc, argv); return; @@ -1845,12 +1760,13 @@ static void create_folder_setup(DBusMessageIter *iter, void *user_data) static void cmd_mkdir(int argc, char *argv[]) { + const char *path = g_dbus_proxy_get_path(default_session); GDBusProxy *proxy; if (!check_default_session()) return; - proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + proxy = g_dbus_proxy_lookup(ftps, NULL, path, OBEX_FTP_INTERFACE); if (proxy == NULL) { bt_shell_printf("Command not supported\n"); return; @@ -1902,7 +1818,7 @@ static void client_added(GDBusProxy *proxy) static void session_added(GDBusProxy *proxy) { - sessions = g_slist_append(sessions, proxy); + sessions = g_list_append(sessions, proxy); if (default_session == NULL) set_default_session(proxy); @@ -1969,7 +1885,7 @@ static void transfer_added(GDBusProxy *proxy) struct transfer_data *data; DBusMessageIter iter; - transfers = g_slist_append(transfers, proxy); + transfers = g_list_append(transfers, proxy); print_proxy(proxy, "Transfer", COLORED_NEW); @@ -1987,35 +1903,35 @@ static void transfer_added(GDBusProxy *proxy) static void opp_added(GDBusProxy *proxy) { - opps = g_slist_append(opps, proxy); + opps = g_list_append(opps, proxy); print_proxy(proxy, "ObjectPush", COLORED_NEW); } static void ftp_added(GDBusProxy *proxy) { - ftps = g_slist_append(ftps, proxy); + ftps = g_list_append(ftps, proxy); print_proxy(proxy, "FileTransfer", COLORED_NEW); } static void pbap_added(GDBusProxy *proxy) { - pbaps = g_slist_append(pbaps, proxy); + pbaps = g_list_append(pbaps, proxy); print_proxy(proxy, "PhonebookAccess", COLORED_NEW); } static void map_added(GDBusProxy *proxy) { - maps = g_slist_append(maps, proxy); + maps = g_list_append(maps, proxy); print_proxy(proxy, "MessageAccess", COLORED_NEW); } static void msg_added(GDBusProxy *proxy) { - msgs = g_slist_append(msgs, proxy); + msgs = g_list_append(msgs, proxy); print_proxy(proxy, "Message", COLORED_NEW); } @@ -2059,49 +1975,49 @@ static void session_removed(GDBusProxy *proxy) if (default_session == proxy) set_default_session(NULL); - sessions = g_slist_remove(sessions, proxy); + sessions = g_list_remove(sessions, proxy); } static void transfer_removed(GDBusProxy *proxy) { print_proxy(proxy, "Transfer", COLORED_DEL); - transfers = g_slist_remove(transfers, proxy); + transfers = g_list_remove(transfers, proxy); } static void opp_removed(GDBusProxy *proxy) { print_proxy(proxy, "ObjectPush", COLORED_DEL); - opps = g_slist_remove(opps, proxy); + opps = g_list_remove(opps, proxy); } static void ftp_removed(GDBusProxy *proxy) { print_proxy(proxy, "FileTransfer", COLORED_DEL); - ftps = g_slist_remove(ftps, proxy); + ftps = g_list_remove(ftps, proxy); } static void pbap_removed(GDBusProxy *proxy) { print_proxy(proxy, "PhonebookAccess", COLORED_DEL); - pbaps = g_slist_remove(pbaps, proxy); + pbaps = g_list_remove(pbaps, proxy); } static void map_removed(GDBusProxy *proxy) { print_proxy(proxy, "MessageAccess", COLORED_DEL); - maps = g_slist_remove(maps, proxy); + maps = g_list_remove(maps, proxy); } static void msg_removed(GDBusProxy *proxy) { print_proxy(proxy, "Message", COLORED_DEL); - msgs = g_slist_remove(msgs, proxy); + msgs = g_list_remove(msgs, proxy); } static void proxy_removed(GDBusProxy *proxy, void *user_data) diff --git a/unit/test-ecc.c b/unit/test-ecc.c index 9b48d0b3..d9136814 100755 --- a/unit/test-ecc.c +++ b/unit/test-ecc.c @@ -94,7 +94,10 @@ static int test_sample(uint8_t priv_a[32], uint8_t priv_b[32], uint8_t dhkey_a[32], dhkey_b[32]; int fails = 0; + memset(dhkey_a, 0, sizeof(dhkey_a)); ecdh_shared_secret(pub_b, priv_a, dhkey_a); + + memset(dhkey_b, 0, sizeof(dhkey_b)); ecdh_shared_secret(pub_a, priv_b, dhkey_b); if (g_test_verbose()) { @@ -110,6 +113,7 @@ static int test_sample(uint8_t priv_a[32], uint8_t priv_b[32], tester_debug("DHKey A matches :)"); } + if (memcmp(dhkey_b, dhkey, 32)) { tester_debug("DHKey B doesn't match!"); fails++; @@ -243,6 +247,39 @@ static void test_sample_3(const void *data) tester_test_passed(); } +static void test_invalid_pub(const void *data) +{ + uint8_t priv_a[32] = { 0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58, + 0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a, + 0x50, 0x3f, 0x10, 0xd2, 0xe3, 0xb3, 0xc9, 0x74, + 0x38, 0x5f, 0xc5, 0xa3, 0xd4, 0xf6, 0x49, 0x3f, + }; + uint8_t pub_a[64] = { 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, + 0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef, + 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, + 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20, + + 0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74, + 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76, + 0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63, + 0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc, + }; + uint8_t dhkey[32] = { 0x2d, 0xab, 0x00, 0x48, 0xcb, 0xb3, 0x7b, 0xda, + 0x55, 0x7b, 0x8b, 0x72, 0xa8, 0x57, 0x87, 0xc3, + 0x87, 0x27, 0x99, 0x32, 0xfc, 0x79, 0x5f, 0xae, + 0x7c, 0x1c, 0xf9, 0x49, 0xe6, 0xd7, 0xaa, 0x70, + }; + int fails; + + memset(pub_a + 32, 0x42, 32); + + fails = test_sample(priv_a, priv_a, pub_a, pub_a, dhkey); + + g_assert(fails >= 1); + + tester_test_passed(); +} + int main(int argc, char *argv[]) { tester_init(&argc, &argv); @@ -253,5 +290,7 @@ int main(int argc, char *argv[]) tester_add("/ecdh/sample/2", NULL, NULL, test_sample_2, NULL); tester_add("/ecdh/sample/3", NULL, NULL, test_sample_3, NULL); + tester_add("/ecdh/invalid", NULL, NULL, test_invalid_pub, NULL); + return tester_run(); } |