This refactor code for message processing for future feature addition. nokia.com:bt and EIR processing is now separated from performing actions based on received data. --- plugins/neard.c | 308 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 157 insertions(+), 151 deletions(-) diff --git a/plugins/neard.c b/plugins/neard.c index 6272144..7df4544 100644 --- a/plugins/neard.c +++ b/plugins/neard.c @@ -55,6 +55,26 @@ static gboolean agent_register_postpone = FALSE; /* For NFC mimetype limits max OOB EIR size */ #define NFC_OOB_EIR_MAX UINT8_MAX +struct oob_params { + bdaddr_t address; + uint32_t class; + char *name; + GSList *services; + uint8_t *hash; + uint8_t *randomizer; + uint8_t *pin; + int pin_len; +}; + +static void free_oob_params(struct oob_params *params) +{ + g_slist_free_full(params->services, g_free); + g_free(params->name); + g_free(params->hash); + g_free(params->randomizer); + g_free(params->pin); +} + static DBusMessage *error_reply(DBusMessage *msg, int error) { const char *name; @@ -268,14 +288,9 @@ static int check_device(struct btd_device *device) return 0; } -/* returns 1 if action (pairing or reading local data) is not needed */ -static int process_eir(struct btd_adapter *adapter, uint8_t *eir, size_t size, - bdaddr_t *remote) +static int process_eir(uint8_t *eir, size_t size, struct oob_params *remote) { struct eir_data eir_data; - char remote_address[18]; - struct btd_device *device; - int err; DBG("size %zu", size); @@ -284,48 +299,25 @@ static int process_eir(struct btd_adapter *adapter, uint8_t *eir, size_t size, if (eir_parse_oob(&eir_data, eir, size) < 0) return -EINVAL; - ba2str(&eir_data.addr, remote_address); - - DBG("hci%u remote:%s", btd_adapter_get_index(adapter), remote_address); - - device = adapter_get_device(adapter, &eir_data.addr, BDADDR_BREDR); - - err = check_device(device); - if (err < 0) { - eir_data_free(&eir_data); - return err; - } + bacpy(&remote->address, &eir_data.addr); - /* store OOB data */ - if (eir_data.class != 0) - device_set_class(device, eir_data.class); + remote->class = eir_data.class; - /* TODO handle incomplete name? */ - if (eir_data.name) { - adapter_store_cached_name(adapter_get_address(adapter), - &eir_data.addr, eir_data.name); - device_set_name(device, eir_data.name); - } + remote->name = eir_data.name; + eir_data.name = NULL; - if (eir_data.hash) - btd_adapter_add_remote_oob_data(adapter, &eir_data.addr, - eir_data.hash, eir_data.randomizer); + remote->services = eir_data.services; + eir_data.services = NULL; - /* TODO handle UUIDs? */ + remote->hash = eir_data.hash; + eir_data.hash = NULL; - if (remote) - bacpy(remote, &eir_data.addr); - - /* - * In RequestOOB reply append local hash and randomizer only if - * received EIR also contained it. - */ - if (!remote && !eir_data.hash) - err = -EALREADY; + remote->randomizer = eir_data.randomizer; + eir_data.randomizer = NULL; eir_data_free(&eir_data); - return err; + return 0; } /* @@ -350,16 +342,8 @@ static int process_eir(struct btd_adapter *adapter, uint8_t *eir, size_t size, * N bytes - name */ -struct nokia_com_bt { - bdaddr_t address; - uint32_t cod; - uint8_t pin[16]; - int pin_len; - char *name; -}; - static int process_nokia_long (void *data, size_t size, uint8_t marker, - struct nokia_com_bt *nokia) + struct oob_params *remote) { struct { bdaddr_t address; @@ -373,26 +357,26 @@ static int process_nokia_long (void *data, size_t size, uint8_t marker, return -EINVAL; /* address is not reverted */ - baswap(&nokia->address, &n->address); + baswap(&remote->address, &n->address); - nokia->cod = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16); + remote->class = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16); if (n->name_len > 0) - nokia->name = g_strndup((char *)n->name, n->name_len); + remote->name = g_strndup((char *)n->name, n->name_len); if (marker == 0x01) { - memcpy(nokia->pin, n->authentication, 4); - nokia->pin_len = 4; + remote->pin = g_memdup(n->authentication, 4); + remote->pin_len = 4; } else if (marker == 0x02) { - memcpy(nokia->pin, n->authentication, 16); - nokia->pin_len = 16; + remote->pin = g_memdup(n->authentication, 16); + remote->pin_len = 16; } return 0; } static int process_nokia_short (void *data, size_t size, - struct nokia_com_bt *nokia) + struct oob_params *remote) { struct { bdaddr_t address; @@ -406,21 +390,21 @@ static int process_nokia_short (void *data, size_t size, return -EINVAL; /* address is not reverted */ - baswap(&nokia->address, &n->address); + baswap(&remote->address, &n->address); - nokia->cod = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16); + remote->class = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16); if (n->name_len > 0) - nokia->name = g_strndup((char *)n->name, n->name_len); + remote->name = g_strndup((char *)n->name, n->name_len); - memcpy(nokia->pin, n->authentication, 4); - nokia->pin_len = 4; + remote->pin = g_memdup(n->authentication, 4); + remote->pin_len = 4; return 0; } static int process_nokia_extra_short (void *data, size_t size, - struct nokia_com_bt *nokia) + struct oob_params *remote) { struct { bdaddr_t address; @@ -432,95 +416,42 @@ static int process_nokia_extra_short (void *data, size_t size, if (size != sizeof(*n) + n->name_len) return -EINVAL; - bacpy(&nokia->address, &n->address); + bacpy(&remote->address, &n->address); - nokia->cod = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16); + remote->class = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16); if (n->name_len > 0) - nokia->name = g_strndup((char *)n->name, n->name_len); + remote->name = g_strndup((char *)n->name, n->name_len); return 0; } -/* returns 1 if pairing is not needed */ -static int process_nokia_com_bt(struct btd_adapter *adapter, void *data, - size_t size, bdaddr_t *remote) +static int process_nokia_com_bt(uint8_t *data, size_t size, + struct oob_params *remote) { - uint8_t *marker; - struct nokia_com_bt nokia; - struct btd_device *device; - int ret; - char remote_address[18]; - - /* Support this only for PushOOB */ - if (!remote) - return -EOPNOTSUPP; + uint8_t marker; - marker = data++; - size --; + marker = *data++; + size--; - DBG("marker: 0x%.2x size: %zu", *marker, size); + DBG("marker: 0x%.2x size: %zu", marker, size); - memset(&nokia, 0, sizeof(nokia)); - - switch (*marker) { + switch (marker) { case 0x00: case 0x01: case 0x02: - ret = process_nokia_long(data, size, *marker, &nokia); - break; + return process_nokia_long(data, size, marker, remote); case 0x10: - ret = process_nokia_extra_short(data, size, &nokia); - break; + return process_nokia_extra_short(data, size, remote); case 0x24: - ret = process_nokia_short(data, size, &nokia); - break; + return process_nokia_short(data, size, remote); default: - info("Not supported Nokia NFC extension (0x%.2x)", *marker); - ret = -EPROTONOSUPPORT; - break; - } - - if (ret < 0) - return ret; - - ba2str(&nokia.address, remote_address); - DBG("hci%u remote:%s", btd_adapter_get_index(adapter), remote_address); - - device = adapter_get_device(adapter, &nokia.address, BDADDR_BREDR); - - ret = check_device(device); - if (ret != 0) { - g_free(nokia.name); - return ret; - } - - DBG("hci%u remote:%s", btd_adapter_get_index(adapter), remote_address); - - if (nokia.name) { - adapter_store_cached_name(adapter_get_address(adapter), remote, - nokia.name); - device_set_name(device, nokia.name); - g_free(nokia.name); + info("Not supported Nokia NFC extension (0x%.2x)", marker); + return -EPROTONOSUPPORT; } - - if (nokia.cod != 0) - device_set_class(device, nokia.cod); - - if (nokia.pin_len > 0) { - /* TODO - * Handle PIN, for now only discovery mode and 'common' PINs - * that might be provided by agent will work correctly. - */ - } - - bacpy(remote, &nokia.address); - - return 0; } -static int process_params(DBusMessage *msg, struct btd_adapter *adapter, - bdaddr_t *remote) +static int process_message(DBusMessage *msg, struct oob_params *remote) { DBusMessageIter iter; DBusMessageIter dict; @@ -538,8 +469,8 @@ static int process_params(DBusMessage *msg, struct btd_adapter *adapter, type = dbus_message_iter_get_arg_type(&dict); if (type != DBUS_TYPE_DICT_ENTRY) { - if (!remote && type == DBUS_TYPE_INVALID) - return -EALREADY; + if (type == DBUS_TYPE_INVALID) + return -ENOENT; return -EINVAL; } @@ -566,7 +497,7 @@ static int process_params(DBusMessage *msg, struct btd_adapter *adapter, dbus_message_iter_recurse(&value, &array); dbus_message_iter_get_fixed_array(&array, &eir, &size); - return process_eir(adapter, eir, size, remote); + return process_eir(eir, size, remote); } else if (strcasecmp(key, "nokia.com:bt") == 0) { DBusMessageIter array; uint8_t *data; @@ -575,7 +506,7 @@ static int process_params(DBusMessage *msg, struct btd_adapter *adapter, dbus_message_iter_recurse(&value, &array); dbus_message_iter_get_fixed_array(&array, &data, &size); - return process_nokia_com_bt(adapter, data, size, remote); + return process_nokia_com_bt(data, size, remote); } return -EINVAL; @@ -598,12 +529,39 @@ static int check_adapter(struct btd_adapter *adapter) return 0; } +static void store_params(struct btd_adapter *adapter, struct btd_device *device, + struct oob_params *params) +{ + if (params->class != 0) + device_set_class(device, params->class); + + if (params->name) { + adapter_store_cached_name(adapter_get_address(adapter), + ¶ms->address, params->name); + device_set_name(device, params->name); + } + + /* TODO handle UUIDs? */ + + if (params->hash) { + btd_adapter_add_remote_oob_data(adapter, ¶ms->address, + params->hash, + params->randomizer); + } else if (params->pin_len) { + /* TODO + * Handle PIN, for now only discovery mode and 'common' PINs + * that might be provided by agent will work correctly. + */ + } +} + static DBusMessage *push_oob(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter; struct agent *agent; struct oob_handler *handler; - bdaddr_t remote; + struct oob_params remote; + struct btd_device *device; uint8_t io_cap; int err; @@ -615,15 +573,6 @@ static DBusMessage *push_oob(DBusConnection *conn, DBusMessage *msg, void *data) if (err < 0) return error_reply(msg, -err); - err = process_params(msg, adapter, &remote); - - /* already paired, reply immediately */ - if (err == -EALREADY) - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); - - if (err < 0) - return error_reply(msg, -err); - agent = adapter_get_agent(adapter); if (!agent) return error_reply(msg, ENONET); @@ -631,13 +580,43 @@ static DBusMessage *push_oob(DBusConnection *conn, DBusMessage *msg, void *data) io_cap = agent_get_io_capability(agent); agent_unref(agent); - err = adapter_create_bonding(adapter, &remote, BDADDR_BREDR, io_cap); + memset(&remote, 0, sizeof(remote)); + + err = process_message(msg, &remote); + if (err < 0) + return error_reply(msg, -err); + + if (bacmp(&remote.address, BDADDR_ANY) == 0) { + free_oob_params(&remote); + + return error_reply(msg, EINVAL); + } + + device = adapter_get_device(adapter, &remote.address, BDADDR_BREDR); + + err = check_device(device); + if (err < 0) { + free_oob_params(&remote); + + /* already paired, reply immediately */ + if (err == -EALREADY) + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + + return error_reply(msg, -err); + } + + store_params(adapter, device, &remote); + + free_oob_params(&remote); + + err = adapter_create_bonding(adapter, device_get_address(device), + BDADDR_BREDR, io_cap); if (err < 0) return error_reply(msg, -err); handler = g_new0(struct oob_handler, 1); handler->bonding_cb = bonding_complete; - bacpy(&handler->remote_addr, &remote); + bacpy(&handler->remote_addr, device_get_address(device)); handler->user_data = dbus_message_ref(msg); btd_adapter_set_oob_handler(adapter, handler); @@ -650,6 +629,8 @@ static DBusMessage *request_oob(DBusConnection *conn, DBusMessage *msg, { struct btd_adapter *adapter; struct oob_handler *handler; + struct oob_params remote; + struct btd_device *device; int err; DBG(""); @@ -660,13 +641,38 @@ static DBusMessage *request_oob(DBusConnection *conn, DBusMessage *msg, if (err < 0) return error_reply(msg, -err); - err = process_params(msg, adapter, NULL); - if (err == -EALREADY) - return create_request_oob_reply(adapter, NULL, NULL, msg); + memset(&remote, 0, sizeof(remote)); + err = process_message(msg, &remote); if (err < 0) return error_reply(msg, -err); + if (bacmp(&remote.address, BDADDR_ANY) == 0) + goto read_local; + + device = adapter_get_device(adapter, &remote.address, BDADDR_BREDR); + + err = check_device(device); + if (err < 0) { + free_oob_params(&remote); + + if (err == -EALREADY) + return create_request_oob_reply(adapter, NULL, NULL, + msg); + + return error_reply(msg, -err); + } + + store_params(adapter, device, &remote); + + if (!remote.hash) { + free_oob_params(&remote); + return create_request_oob_reply(adapter, NULL, NULL, msg); + } + +read_local: + free_oob_params(&remote); + err = btd_adapter_read_local_oob_data(adapter); if (err < 0) return error_reply(msg, -err); -- 1.8.1.1 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html