// SPDX-License-Identifier: GPL-2.0-or-later /* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "lib/bluetooth.h" #include "lib/hci.h" #include "lib/hci_lib.h" #include "lib/l2cap.h" #include "src/shared/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; } close(fd); 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"); close(fd); return false; } 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_PRIMARY) 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: free(dl); 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(); }