OSDN Git Service

tools: Add simple test utility for L2CAP connectionless channels
authorMarcel Holtmann <marcel@holtmann.org>
Sun, 13 Oct 2013 20:17:19 +0000 (13:17 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Sun, 13 Oct 2013 20:17:19 +0000 (13:17 -0700)
.gitignore
Makefile.tools
tools/cltest.c [new file with mode: 0644]

index d2253e5..e492c3f 100644 (file)
@@ -52,6 +52,7 @@ tools/hid2hci
 tools/rfcomm
 tools/l2ping
 tools/l2test
+tools/cltest
 tools/rctest
 tools/scotest
 tools/amptest
index 76e7768..87bb62e 100644 (file)
@@ -174,7 +174,8 @@ noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
                        tools/scotest tools/amptest tools/hwdb \
                        tools/hcieventmask tools/hcisecfilter \
                        tools/btmgmt tools/btinfo tools/btattach \
-                       tools/btsnoop tools/btiotest tools/mpris-player
+                       tools/btsnoop tools/btiotest tools/cltest \
+                       tools/mpris-player
 
 tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
 tools_bdaddr_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
@@ -208,6 +209,9 @@ tools_btiotest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 tools_mpris_player_SOURCES = tools/mpris-player.c
 tools_mpris_player_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
 
+tools_cltest_SOURCES = tools/cltest.c monitor/mainloop.h monitor/mainloop.c
+tools_cltest_LDADD = lib/libbluetooth-internal.la
+
 EXTRA_DIST += tools/bdaddr.1
 endif
 
diff --git a/tools/cltest.c b/tools/cltest.c
new file mode 100644 (file)
index 0000000..16b7553
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; 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 <alloca.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+
+#include "monitor/mainloop.h"
+
+static bool send_message(const bdaddr_t *src, const bdaddr_t *dst,
+                                                       uint16_t psm)
+{
+       const unsigned char buf[] = { 0x42, 0x23 };
+       struct sockaddr_l2 addr;
+       ssize_t len;
+       int fd;
+
+       fd = socket(PF_BLUETOOTH, SOCK_DGRAM | SOCK_CLOEXEC, BTPROTO_L2CAP);
+       if (fd < 0) {
+               perror("Failed to create transmitter socket");
+               return false;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.l2_family = AF_BLUETOOTH;
+       bacpy(&addr.l2_bdaddr, src);
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind transmitter socket");
+               close(fd);
+               return false;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.l2_family = AF_BLUETOOTH;
+       bacpy(&addr.l2_bdaddr, dst);
+       addr.l2_psm = htobs(psm);
+
+       if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to connect transmitter socket");
+               close(fd);
+               return false;
+       }
+
+       len = send(fd, buf, sizeof(buf), 0);
+       if (len < 0) {
+               perror("Failed to send message");
+               close(fd);
+               return false;
+       }
+
+       return true;
+}
+
+static void receiver_callback(int fd, uint32_t events, void *user_data)
+{
+       unsigned char buf[512];
+       struct sockaddr_l2 addr;
+       socklen_t addrlen = sizeof(addr);
+       char str[18];
+       ssize_t len, i;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               close(fd);
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       len = recvfrom(fd, buf, sizeof(buf), 0,
+                               (struct sockaddr *) &addr, &addrlen);
+       if (len < 0) {
+               perror("Failed to receive data");
+               return;
+       }
+
+       if (addrlen > 0) {
+               ba2str(&addr.l2_bdaddr, str);
+               printf("RX Address: %s PSM: %d CID: %d\n", str,
+                               btohs(addr.l2_psm), btohs(addr.l2_cid));
+       }
+
+       printf("RX Data:");
+       for (i = 0; i < len; i++)
+               printf(" 0x%02x", buf[i]);
+       printf("\n");
+}
+
+static bool create_receiver(const bdaddr_t *bdaddr, uint16_t psm)
+{
+       struct sockaddr_l2 addr;
+       int fd;
+
+       fd = socket(PF_BLUETOOTH, SOCK_DGRAM | SOCK_CLOEXEC, BTPROTO_L2CAP);
+       if (fd < 0) {
+               perror("Failed to create receiver socket");
+               return false;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.l2_family = AF_BLUETOOTH;
+       bacpy(&addr.l2_bdaddr, bdaddr);
+       addr.l2_psm = htobs(psm);
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind receiver socket");
+               close(fd);
+               return false;
+       }
+
+       mainloop_add_fd(fd, EPOLLIN, receiver_callback, NULL, NULL);
+
+       return true;
+}
+
+static bool activate_controller(int fd, struct hci_dev_info *di)
+{
+       if (!hci_test_bit(HCI_UP, &di->flags)) {
+               char addr[18];
+
+               ba2str(&di->bdaddr, addr);
+               printf("Activating controller %s\n", addr);
+
+               if (ioctl(fd, HCIDEVUP, di->dev_id) < 0) {
+                       if (errno != EALREADY) {
+                               perror("Failed to bring up HCI device");
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+static bool enable_connections(int fd, struct hci_dev_info *di)
+{
+       if (!hci_test_bit(HCI_PSCAN, &di->flags)) {
+               struct hci_dev_req dr;
+               char addr[18];
+
+               ba2str(&di->bdaddr, addr);
+               printf("Enabling connections on %s\n", addr);
+
+               dr.dev_id  = di->dev_id;
+               dr.dev_opt = SCAN_PAGE;
+
+               if (ioctl(fd, HCISETSCAN, (unsigned long) &dr) < 0) {
+                       perror("Failed to enable connections");
+                       return false;
+               }
+       }
+       return true;
+}
+
+static bdaddr_t bdaddr_src;
+static bdaddr_t bdaddr_dst;
+
+static bool find_controllers(void)
+{
+       struct hci_dev_list_req *dl;
+       struct hci_dev_req *dr;
+       bool result;
+       int fd, i;
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0) {
+               perror("Failed to open raw HCI socket");
+               return false;
+       }
+
+       dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
+       if (!dl) {
+               perror("Failed allocate HCI device request memory");
+               result = false;
+               goto done;
+       }
+
+       dl->dev_num = HCI_MAX_DEV;
+       dr = dl->dev_req;
+
+       if (ioctl(fd, HCIGETDEVLIST, (void *) dl) < 0) {
+               perror("Failed to get HCI device list");
+               result = false;
+               goto done;
+       }
+
+       result = true;
+
+       for (i = 0; i< dl->dev_num && result; i++) {
+               struct hci_dev_info di;
+
+               di.dev_id = (dr + i)->dev_id;
+
+               if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0)
+                       continue;
+
+               if (((di.type & 0x30) >> 4) != HCI_BREDR)
+                       continue;
+
+               if (!bacmp(&bdaddr_src, BDADDR_ANY)) {
+                       bacpy(&bdaddr_src, &di.bdaddr);
+                       result = activate_controller(fd, &di);
+               } else if (!bacmp(&bdaddr_dst, BDADDR_ANY)) {
+                       bacpy(&bdaddr_dst, &di.bdaddr);
+                       result = activate_controller(fd, &di);
+                       if (result)
+                               result = enable_connections(fd, &di);
+               }
+       }
+
+done:
+       close(fd);
+       return result;
+}
+
+int main(int argc ,char *argv[])
+{
+       char addr_src[18], addr_dst[18];
+
+       bacpy(&bdaddr_src, BDADDR_ANY);
+       bacpy(&bdaddr_dst, BDADDR_ANY);
+
+       if (!find_controllers())
+               return EXIT_FAILURE;
+
+       if (!bacmp(&bdaddr_src, BDADDR_ANY) ||
+                               !bacmp(&bdaddr_dst, BDADDR_ANY)) {
+               fprintf(stderr, "Two controllers are required\n");
+               return EXIT_FAILURE;
+       }
+
+       ba2str(&bdaddr_src, addr_src);
+       ba2str(&bdaddr_dst, addr_dst);
+
+       printf("%s -> %s\n", addr_src, addr_dst);
+
+       mainloop_init();
+
+       create_receiver(&bdaddr_dst, 0x0021);
+       send_message(&bdaddr_src, &bdaddr_dst, 0x0021);
+
+       return mainloop_run();
+}