From c108f0b48b4888e2f400dbdc8cf4a3e482eb3a80 Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Thu, 29 Aug 2019 19:03:51 +0200 Subject: [PATCH] sockaddr: properly decode sockaddr_hci addresses without hci_channel Before Linux commit v2.6.38-rc1~476^2~14^2~3^2~43^2~9, struct sockaddr_hci did not contain hci_channel field. * configure.ac (AC_CHECK_HEADERS([bluetooth/bluetooth.h])): Add check for struct sockaddr_hci.hci_channel. * sockaddr.c (print_sockaddr_data_bt): Decode struct sockaddr_hci without hci_channel field. * tests/net-sockaddr.c (check_hci): Add check for struct sockaddr_hci decoding without hci_channel field; guard hci_channel with #ifdef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL. (check_raw): Remove "len++", as 4-byte AF_BLUETOOTH socket addresses are interpreted as struct sockaddr_hci without hci_channel field. --- configure.ac | 3 +++ sockaddr.c | 16 +++++++++++++--- tests/net-sockaddr.c | 18 ++++++++++++++---- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 0bd49b6b..a7938e5c 100644 --- a/configure.ac +++ b/configure.ac @@ -479,6 +479,9 @@ AC_CHECK_HEADERS([linux/bpf.h], [ ]) AC_CHECK_HEADERS([bluetooth/bluetooth.h], [ + AC_CHECK_MEMBERS([struct sockaddr_hci.hci_channel],,, + [#include + #include ]) AC_CHECK_MEMBERS([struct sockaddr_l2.l2_bdaddr_type],,, [#include #include ]) diff --git a/sockaddr.c b/sockaddr.c index dbf3856c..c67d60e9 100644 --- a/sockaddr.c +++ b/sockaddr.c @@ -599,11 +599,21 @@ print_sockaddr_data_bt(const void *const buf, const int addrlen) }; switch (addrlen) { + case offsetofend(struct sockaddr_hci, hci_dev): case sizeof(struct sockaddr_hci): { const struct sockaddr_hci *const hci = buf; - tprintf("hci_dev=htobs(%hu), hci_channel=", - btohs(hci->hci_dev)); - printxval(hci_channels, hci->hci_channel, "HCI_CHANNEL_???"); + tprintf("hci_dev=htobs(%hu)", btohs(hci->hci_dev)); + + /* + * hci_channel field has been introduced + * Linux commit in v2.6.38-rc1~476^2~14^2~3^2~43^2~9. + */ + if (addrlen == sizeof(struct sockaddr_hci)) { + tprints(", hci_channel="); + printxval(hci_channels, hci->hci_channel, + "HCI_CHANNEL_???"); + } + break; } case sizeof(struct sockaddr_sco): { diff --git a/tests/net-sockaddr.c b/tests/net-sockaddr.c index cd973922..8aa738d1 100644 --- a/tests/net-sockaddr.c +++ b/tests/net-sockaddr.c @@ -543,11 +543,22 @@ check_hci(void) TAIL_ALLOC_OBJECT_VAR_PTR(struct sockaddr_hci, hci); hci->hci_family = AF_BLUETOOTH; hci->hci_dev = htobs(h_port); +# ifdef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL hci->hci_channel = HCI_CHANNEL_RAW; +# endif unsigned int len = sizeof(*hci); - int ret = connect(-1, (void *) hci, len); + + int ret = connect(-1, (void *) hci, 4); + printf("connect(-1, {sa_family=AF_BLUETOOTH, hci_dev=htobs(%hu)" + "}, 4) = %d EBADF (%m)\n", + h_port, ret); + + ret = connect(-1, (void *) hci, len); printf("connect(-1, {sa_family=AF_BLUETOOTH, hci_dev=htobs(%hu)" - ", hci_channel=HCI_CHANNEL_RAW}, %u) = %d EBADF (%m)\n", +# ifdef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL + ", hci_channel=HCI_CHANNEL_RAW" +# endif + "}, %u) = %d EBADF (%m)\n", h_port, len, ret); } @@ -700,9 +711,8 @@ check_raw(void) " = %d EBADF (%m)\n", len, ret); u.sa->sa_family = AF_BLUETOOTH; - ++len; ret = connect(-1, (void *) u.st, len); - printf("connect(-1, {sa_family=AF_BLUETOOTH, sa_data=\"00\"}, %u)" + printf("connect(-1, {sa_family=AF_BLUETOOTH, sa_data=\"0\"}, %u)" " = %d EBADF (%m)\n", len, ret); } -- 2.40.0