diff options
Diffstat (limited to 'hidd')
-rw-r--r-- | hidd/Makefile.am | 22 | ||||
-rw-r--r-- | hidd/fakehid.c | 669 | ||||
-rw-r--r-- | hidd/fakehid.txt | 134 | ||||
-rw-r--r-- | hidd/hidd.1 | 41 | ||||
-rw-r--r-- | hidd/hidd.h | 34 | ||||
-rw-r--r-- | hidd/main.c | 860 | ||||
-rw-r--r-- | hidd/sdp.c | 352 |
7 files changed, 0 insertions, 2112 deletions
diff --git a/hidd/Makefile.am b/hidd/Makefile.am deleted file mode 100644 index 508372b4..00000000 --- a/hidd/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ - -if HIDD -bin_PROGRAMS = hidd - -hidd_SOURCES = main.c hidd.h sdp.c fakehid.c - -hidd_LDADD = @BLUEZ_LIBS@ -lm $(top_builddir)/common/libhelper.a -endif - -AM_CFLAGS = @BLUEZ_CFLAGS@ - -INCLUDES = -I$(top_srcdir)/common - -if HIDD -if MANPAGES -man_MANS = hidd.1 -endif -endif - -EXTRA_DIST = hidd.1 fakehid.txt - -MAINTAINERCLEANFILES = Makefile.in diff --git a/hidd/fakehid.c b/hidd/fakehid.c deleted file mode 100644 index feefe2a6..00000000 --- a/hidd/fakehid.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2003-2008 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 - -#define _GNU_SOURCE -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> -#include <signal.h> -#include <sys/poll.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <bluetooth/bluetooth.h> -#include <bluetooth/rfcomm.h> -#include <bluetooth/hidp.h> - -#include "hidd.h" -#include "uinput.h" - -#include <math.h> - -#ifdef NEED_PPOLL -#include "ppoll.h" -#endif - -static volatile sig_atomic_t __io_canceled = 0; - -static void sig_hup(int sig) -{ -} - -static void sig_term(int sig) -{ - __io_canceled = 1; -} - -static void send_event(int fd, uint16_t type, uint16_t code, int32_t value) -{ - struct uinput_event event; - int len; - - if (fd <= fileno(stderr)) - return; - - memset(&event, 0, sizeof(event)); - event.type = type; - event.code = code; - event.value = value; - - len = write(fd, &event, sizeof(event)); -} - -static int uinput_create(char *name, int keyboard, int mouse) -{ - struct uinput_dev dev; - int fd, aux; - - fd = open("/dev/uinput", O_RDWR); - if (fd < 0) { - fd = open("/dev/input/uinput", O_RDWR); - if (fd < 0) { - fd = open("/dev/misc/uinput", O_RDWR); - if (fd < 0) { - fprintf(stderr, "Can't open input device: %s (%d)\n", - strerror(errno), errno); - return -1; - } - } - } - - memset(&dev, 0, sizeof(dev)); - - if (name) - strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE); - - dev.id.bustype = BUS_BLUETOOTH; - dev.id.vendor = 0x0000; - dev.id.product = 0x0000; - dev.id.version = 0x0000; - - if (write(fd, &dev, sizeof(dev)) < 0) { - fprintf(stderr, "Can't write device information: %s (%d)\n", - strerror(errno), errno); - close(fd); - return -1; - } - - if (mouse) { - ioctl(fd, UI_SET_EVBIT, EV_REL); - - for (aux = REL_X; aux <= REL_MISC; aux++) - ioctl(fd, UI_SET_RELBIT, aux); - } - - if (keyboard) { - ioctl(fd, UI_SET_EVBIT, EV_KEY); - ioctl(fd, UI_SET_EVBIT, EV_LED); - ioctl(fd, UI_SET_EVBIT, EV_REP); - - for (aux = KEY_RESERVED; aux <= KEY_UNKNOWN; aux++) - ioctl(fd, UI_SET_KEYBIT, aux); - - //for (aux = LED_NUML; aux <= LED_MISC; aux++) - // ioctl(fd, UI_SET_LEDBIT, aux); - } - - if (mouse) { - ioctl(fd, UI_SET_EVBIT, EV_KEY); - - for (aux = BTN_LEFT; aux <= BTN_BACK; aux++) - ioctl(fd, UI_SET_KEYBIT, aux); - } - - ioctl(fd, UI_DEV_CREATE); - - return fd; -} - -static int rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) -{ - struct sockaddr_rc addr; - int sk; - - sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (sk < 0) { - fprintf(stderr, "Can't create socket: %s (%d)\n", - strerror(errno), errno); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, src); - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - fprintf(stderr, "Can't bind socket: %s (%d)\n", - strerror(errno), errno); - close(sk); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, dst); - addr.rc_channel = channel; - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - fprintf(stderr, "Can't connect: %s (%d)\n", - strerror(errno), errno); - close(sk); - return -1; - } - - return sk; -} - -static void func(int fd) -{ -} - -static void back(int fd) -{ -} - -static void next(int fd) -{ -} - -static void button(int fd, unsigned int button, int is_press) -{ - switch (button) { - case 1: - send_event(fd, EV_KEY, BTN_LEFT, is_press); - break; - case 3: - send_event(fd, EV_KEY, BTN_RIGHT, is_press); - break; - } - - send_event(fd, EV_SYN, SYN_REPORT, 0); -} - -static void move(int fd, unsigned int direction) -{ - double angle; - int32_t x, y; - - angle = (direction * 22.5) * 3.1415926 / 180; - x = (int) (sin(angle) * 8); - y = (int) (cos(angle) * -8); - - send_event(fd, EV_REL, REL_X, x); - send_event(fd, EV_REL, REL_Y, y); - - send_event(fd, EV_SYN, SYN_REPORT, 0); -} - -static inline void epox_decode(int fd, unsigned char event) -{ - switch (event) { - case 48: - func(fd); break; - case 55: - back(fd); break; - case 56: - next(fd); break; - case 53: - button(fd, 1, 1); break; - case 121: - button(fd, 1, 0); break; - case 113: - break; - case 54: - button(fd, 3, 1); break; - case 120: - button(fd, 3, 0); break; - case 112: - break; - case 51: - move(fd, 0); break; - case 97: - move(fd, 1); break; - case 65: - move(fd, 2); break; - case 98: - move(fd, 3); break; - case 50: - move(fd, 4); break; - case 99: - move(fd, 5); break; - case 67: - move(fd, 6); break; - case 101: - move(fd, 7); break; - case 52: - move(fd, 8); break; - case 100: - move(fd, 9); break; - case 66: - move(fd, 10); break; - case 102: - move(fd, 11); break; - case 49: - move(fd, 12); break; - case 103: - move(fd, 13); break; - case 57: - move(fd, 14); break; - case 104: - move(fd, 15); break; - case 69: - break; - default: - printf("Unknown event code %d\n", event); - break; - } -} - -int epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) -{ - unsigned char buf[16]; - struct sigaction sa; - struct pollfd p; - sigset_t sigs; - char addr[18]; - int i, fd, sk, len; - - sk = rfcomm_connect(src, dst, channel); - if (sk < 0) - return -1; - - fd = uinput_create("Bluetooth Presenter", 0, 1); - if (fd < 0) { - close(sk); - return -1; - } - - ba2str(dst, addr); - - printf("Connected to %s on channel %d\n", addr, channel); - printf("Press CTRL-C for hangup\n"); - - memset(&sa, 0, sizeof(sa)); - sa.sa_flags = SA_NOCLDSTOP; - sa.sa_handler = SIG_IGN; - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGPIPE, &sa, NULL); - - sa.sa_handler = sig_term; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - - sa.sa_handler = sig_hup; - sigaction(SIGHUP, &sa, NULL); - - sigfillset(&sigs); - sigdelset(&sigs, SIGCHLD); - sigdelset(&sigs, SIGPIPE); - sigdelset(&sigs, SIGTERM); - sigdelset(&sigs, SIGINT); - sigdelset(&sigs, SIGHUP); - - p.fd = sk; - p.events = POLLIN | POLLERR | POLLHUP; - - while (!__io_canceled) { - p.revents = 0; - if (ppoll(&p, 1, NULL, &sigs) < 1) - continue; - - len = read(sk, buf, sizeof(buf)); - if (len < 0) - break; - - for (i = 0; i < len; i++) - epox_decode(fd, buf[i]); - } - - printf("Disconnected\n"); - - ioctl(fd, UI_DEV_DESTROY); - - close(fd); - close(sk); - - return 0; -} - -int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) -{ - printf("Not implemented\n"); - return -1; -} - -/* The strange meta key close to Ctrl has been assigned to Esc, - Fn key to CtrlR and the left space to Alt*/ - -static unsigned char jthree_keycodes[63] = { - KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, - KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, - KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, - KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, - KEY_LEFTALT, KEY_TAB, KEY_CAPSLOCK, KEY_ESC, - KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, - KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, - KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, - KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_UP, - KEY_SPACE, KEY_COMPOSE, KEY_LEFT, KEY_DOWN, KEY_RIGHT, - KEY_LEFTCTRL, KEY_RIGHTSHIFT, KEY_LEFTSHIFT, KEY_DELETE, KEY_RIGHTCTRL, KEY_RIGHTALT, -}; - -static inline void jthree_decode(int fd, unsigned char event) -{ - if (event > 63) - send_event(fd, EV_KEY, jthree_keycodes[event & 0x3f], 0); - else - send_event(fd, EV_KEY, jthree_keycodes[event - 1], 1); -} - -int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) -{ - unsigned char buf[16]; - struct sigaction sa; - struct pollfd p; - sigset_t sigs; - char addr[18]; - int i, fd, sk, len; - - sk = rfcomm_connect(src, dst, channel); - if (sk < 0) - return -1; - - fd = uinput_create("J-Three Keyboard", 1, 0); - if (fd < 0) { - close(sk); - return -1; - } - - ba2str(dst, addr); - - printf("Connected to %s on channel %d\n", addr, channel); - printf("Press CTRL-C for hangup\n"); - - memset(&sa, 0, sizeof(sa)); - sa.sa_flags = SA_NOCLDSTOP; - sa.sa_handler = SIG_IGN; - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGPIPE, &sa, NULL); - - sa.sa_handler = sig_term; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - - sa.sa_handler = sig_hup; - sigaction(SIGHUP, &sa, NULL); - - sigfillset(&sigs); - sigdelset(&sigs, SIGCHLD); - sigdelset(&sigs, SIGPIPE); - sigdelset(&sigs, SIGTERM); - sigdelset(&sigs, SIGINT); - sigdelset(&sigs, SIGHUP); - - p.fd = sk; - p.events = POLLIN | POLLERR | POLLHUP; - - while (!__io_canceled) { - p.revents = 0; - if (ppoll(&p, 1, NULL, &sigs) < 1) - continue; - - len = read(sk, buf, sizeof(buf)); - if (len < 0) - break; - - for (i = 0; i < len; i++) - jthree_decode(fd, buf[i]); - } - - printf("Disconnected\n"); - - ioctl(fd, UI_DEV_DESTROY); - - close(fd); - close(sk); - - return 0; -} - -static const int celluon_xlate_num[10] = { - KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 -}; - -static const int celluon_xlate_char[26] = { - KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, - KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, - KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z -}; - -static int celluon_xlate(int c) -{ - if (c >= '0' && c <= '9') - return celluon_xlate_num[c - '0']; - - if (c >= 'A' && c <= 'Z') - return celluon_xlate_char[c - 'A']; - - switch (c) { - case 0x08: - return KEY_BACKSPACE; - case 0x09: - return KEY_TAB; - case 0x0d: - return KEY_ENTER; - case 0x11: - return KEY_LEFTCTRL; - case 0x14: - return KEY_CAPSLOCK; - case 0x20: - return KEY_SPACE; - case 0x25: - return KEY_LEFT; - case 0x26: - return KEY_UP; - case 0x27: - return KEY_RIGHT; - case 0x28: - return KEY_DOWN; - case 0x2e: - return KEY_DELETE; - case 0x5b: - return KEY_MENU; - case 0xa1: - return KEY_RIGHTSHIFT; - case 0xa0: - return KEY_LEFTSHIFT; - case 0xba: - return KEY_SEMICOLON; - case 0xbd: - return KEY_MINUS; - case 0xbc: - return KEY_COMMA; - case 0xbb: - return KEY_EQUAL; - case 0xbe: - return KEY_DOT; - case 0xbf: - return KEY_SLASH; - case 0xc0: - return KEY_GRAVE; - case 0xdb: - return KEY_LEFTBRACE; - case 0xdc: - return KEY_BACKSLASH; - case 0xdd: - return KEY_RIGHTBRACE; - case 0xde: - return KEY_APOSTROPHE; - case 0xff03: - return KEY_HOMEPAGE; - case 0xff04: - return KEY_TIME; - case 0xff06: - return KEY_OPEN; - case 0xff07: - return KEY_LIST; - case 0xff08: - return KEY_MAIL; - case 0xff30: - return KEY_CALC; - case 0xff1a: /* Map FN to ALT */ - return KEY_LEFTALT; - case 0xff2f: - return KEY_INFO; - default: - printf("Unknown key %x\n", c); - return c; - } -} - -struct celluon_state { - int len; /* Expected length of current packet */ - int count; /* Number of bytes received */ - int action; - int key; -}; - -static void celluon_decode(int fd, struct celluon_state *s, uint8_t c) -{ - if (s->count < 2 && c != 0xa5) { - /* Lost Sync */ - s->count = 0; - return; - } - - switch (s->count) { - case 0: - /* New packet - Reset state */ - s->len = 30; - s->key = 0; - break; - case 1: - break; - case 6: - s->action = c; - break; - case 28: - s->key = c; - if (c == 0xff) - s->len = 31; - break; - case 29: - case 30: - if (s->count == s->len - 1) { - /* TODO: Verify checksum */ - if (s->action < 2) { - send_event(fd, EV_KEY, celluon_xlate(s->key), - s->action); - } - s->count = -1; - } else { - s->key = (s->key << 8) | c; - } - break; - } - - s->count++; - - return; -} - -int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) -{ - unsigned char buf[16]; - struct sigaction sa; - struct pollfd p; - sigset_t sigs; - char addr[18]; - int i, fd, sk, len; - struct celluon_state s; - - sk = rfcomm_connect(src, dst, channel); - if (sk < 0) - return -1; - - fd = uinput_create("Celluon Keyboard", 1, 0); - if (fd < 0) { - close(sk); - return -1; - } - - ba2str(dst, addr); - - printf("Connected to %s on channel %d\n", addr, channel); - printf("Press CTRL-C for hangup\n"); - - memset(&sa, 0, sizeof(sa)); - sa.sa_flags = SA_NOCLDSTOP; - sa.sa_handler = SIG_IGN; - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGPIPE, &sa, NULL); - - sa.sa_handler = sig_term; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - - sa.sa_handler = sig_hup; - sigaction(SIGHUP, &sa, NULL); - - sigfillset(&sigs); - sigdelset(&sigs, SIGCHLD); - sigdelset(&sigs, SIGPIPE); - sigdelset(&sigs, SIGTERM); - sigdelset(&sigs, SIGINT); - sigdelset(&sigs, SIGHUP); - - p.fd = sk; - p.events = POLLIN | POLLERR | POLLHUP; - - memset(&s, 0, sizeof(s)); - - while (!__io_canceled) { - p.revents = 0; - if (ppoll(&p, 1, NULL, &sigs) < 1) - continue; - - len = read(sk, buf, sizeof(buf)); - if (len < 0) - break; - - for (i = 0; i < len; i++) - celluon_decode(fd, &s, buf[i]); - } - - printf("Disconnected\n"); - - ioctl(fd, UI_DEV_DESTROY); - - close(fd); - close(sk); - - return 0; -} diff --git a/hidd/fakehid.txt b/hidd/fakehid.txt deleted file mode 100644 index 000d0ee2..00000000 --- a/hidd/fakehid.txt +++ /dev/null @@ -1,134 +0,0 @@ -EPox Presenter -============== - -# hcitool inq -Inquiring ... - 00:04:61:aa:bb:cc clock offset: 0x1ded class: 0x004000 - -# hcitool info 00:04:61:aa:bb:cc -Requesting information ... - BD Address: 00:04:61:aa:bb:cc - OUI Company: EPOX Computer Co., Ltd. (00-04-61) - Device Name: EPox BT-PM01B aabbcc - LMP Version: 1.1 (0x1) LMP Subversion: 0xf78 - Manufacturer: Cambridge Silicon Radio (10) - Features: 0xff 0xff 0x0f 0x00 0x00 0x00 0x00 0x00 - <3-slot packets> <5-slot packets> <encryption> <slot offset> - <timing accuracy> <role switch> <hold mode> <sniff mode> - <park state> <RSSI> <channel quality> <SCO link> <HV2 packets> - <HV3 packets> <u-law log> <A-law log> <CVSD> <paging scheme> - <power control> <transparent SCO> - -# sdptool records --raw 00:04:61:aa:bb:cc -Sequence - Attribute 0x0000 - ServiceRecordHandle - UINT32 0x00010000 - Attribute 0x0001 - ServiceClassIDList - Sequence - UUID16 0x1101 - SerialPort - Attribute 0x0004 - ProtocolDescriptorList - Sequence - Sequence - UUID16 0x0100 - L2CAP - Sequence - UUID16 0x0003 - RFCOMM - UINT8 0x01 - Attribute 0x0100 - String Cable Replacement - - -J-Three Keyboard -================ - -# hcitool inq -Inquiring ... - 00:0A:3A:aa:bb:cc clock offset: 0x3039 class: 0x001f00 - -# hcitool info 00:0A:3A:aa:bb:cc -Password: -Requesting information ... - BD Address: 00:0A:3A:aa:bb:cc - OUI Company: J-THREE INTERNATIONAL Holding Co., Ltd. (00-0A-3A) - Device Name: KEYBOARD - LMP Version: 1.1 (0x1) LMP Subversion: 0x2c2 - Manufacturer: Cambridge Silicon Radio (10) - Features: 0xbc 0x06 0x07 0x00 0x00 0x00 0x00 0x00 - <encryption> <slot offset> <timing accuracy> <role switch> - <sniff mode> <RSSI> <channel quality> <CVSD> <paging scheme> - <power control> - -# sdptool records --raw 00:0A:3A:aa:bb:cc -Sequence - Attribute 0x0000 - ServiceRecordHandle - UINT32 0x00010000 - Attribute 0x0001 - ServiceClassIDList - Sequence - UUID16 0x1101 - SerialPort - Attribute 0x0004 - ProtocolDescriptorList - Sequence - Sequence - UUID16 0x0100 - L2CAP - Sequence - UUID16 0x0003 - RFCOMM - UINT8 0x01 - Attribute 0x0006 - LanguageBaseAttributeIDList - Sequence - UINT16 0x656e - UINT16 0x006a - UINT16 0x0100 - Attribute 0x0100 - String SPP slave - - -Celluon Laserkey Keyboard -========================= - -# hcitool inq -Inquiring ... - 00:0B:24:aa:bb:cc clock offset: 0x3ab6 class: 0x400210 - -# hcitool info 00:0B:24:aa:bb:cc -Requesting information ... - BD Address: 00:0B:24:aa:bb:cc - OUI Company: AirLogic (00-0B-24) - Device Name: CL800BT - LMP Version: 1.1 (0x1) LMP Subversion: 0x291 - Manufacturer: Cambridge Silicon Radio (10) - Features: 0xff 0xff 0x0f 0x00 0x00 0x00 0x00 0x00 - <3-slot packets> <5-slot packets> <encryption> <slot offset> - <timing accuracy> <role switch> <hold mode> <sniff mode> - <park state> <RSSI> <channel quality> <SCO link> <HV2 packets> - <HV3 packets> <u-law log> <A-law log> <CVSD> <paging scheme> - <power control> <transparent SCO> - -# sdptool records --raw 00:0B:24:aa:bb:cc -Sequence - Attribute 0x0000 - ServiceRecordHandle - UINT32 0x00010000 - Attribute 0x0001 - ServiceClassIDList - Sequence - UUID16 0x1101 - SerialPort - Attribute 0x0004 - ProtocolDescriptorList - Sequence - Sequence - UUID16 0x0100 - L2CAP - Sequence - UUID16 0x0003 - RFCOMM - UINT8 0x01 - Attribute 0x0100 - String Serial Port - -Packet format is as follows (all fields little-endian): - 0 uint16 magic # 0x5a5a - 2 uint32 unknown # ??? - 6 uint8 action # 0 = keyup, 1 = keydown, 2 = repeat - # 3, 4, 5, 6 = ??? (Mouse mode) - 7 uint8 unknown[9] # ??? - 16 uint8 action2 # ??? same as action - 17 uint16 x # Horizontal coordinate - 19 uint16 y # Vertical coordinate - 21 uint16 time # Some sort of timestamp - 23 uint8 unknown[5] # ??? - 28 uint8 key[] # single byte keycode or 0xff byte - # follwed by special keycode byte. - Each packet followed by a checksum byte. diff --git a/hidd/hidd.1 b/hidd/hidd.1 deleted file mode 100644 index b186ac24..00000000 --- a/hidd/hidd.1 +++ /dev/null @@ -1,41 +0,0 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.33. -.TH HIDD "1" "May 2004" "hidd - Bluetooth HID daemon" "User Commands" -.SH NAME -hidd \- Bluetooth HID daemon -.SH DESCRIPTION -hidd - Bluetooth HID daemon -.SS "Usage:" -.IP -hidd [options] [commands] -.SH OPTIONS -.TP -\fB\-i\fR <hciX|bdaddr> -Local HCI device or BD Address -.TP -\fB\-t\fR <timeout> -Set idle timeout (in minutes) -.TP -\fB\-n\fR, \fB\-\-nodaemon\fR -Don't fork daemon to background -.TP -\fB\-h\fR, \fB\-\-help\fR -Display help -.SS "Commands:" -.TP -\fB\-\-server\fR -Start HID server -.TP -\fB\-\-search\fR -Search for HID devices -.TP -\fB\-\-connect\fR <bdaddr> -Connect remote HID device -.TP -\fB\-\-kill\fR <bdaddr> -Terminate HID connection -.TP -\fB\-\-killall\fR -Terminate all connections -.TP -\fB\-\-show\fR -List current HID connections diff --git a/hidd/hidd.h b/hidd/hidd.h deleted file mode 100644 index 63e0cbbe..00000000 --- a/hidd/hidd.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2003-2008 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 - * - */ - -#define L2CAP_PSM_HIDP_CTRL 0x11 -#define L2CAP_PSM_HIDP_INTR 0x13 - -int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req); -int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req); -int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len); - -int epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel); -int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel); -int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel); -int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel); diff --git a/hidd/main.c b/hidd/main.c deleted file mode 100644 index d0883b36..00000000 --- a/hidd/main.c +++ /dev/null @@ -1,860 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2003-2008 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 - -#define _GNU_SOURCE -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <signal.h> -#include <getopt.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 <bluetooth/sdp.h> -#include <bluetooth/hidp.h> - -#include "hidd.h" - -#ifdef NEED_PPOLL -#include "ppoll.h" -#endif - -enum { - NONE, - SHOW, - SERVER, - SEARCH, - CONNECT, - KILL -}; - -static volatile sig_atomic_t __io_canceled = 0; - -static void sig_hup(int sig) -{ -} - -static void sig_term(int sig) -{ - __io_canceled = 1; -} - -static int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm) -{ - struct sockaddr_l2 addr; - struct l2cap_options opts; - int sk; - - if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, src); - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(sk); - return -1; - } - - memset(&opts, 0, sizeof(opts)); - opts.imtu = HIDP_DEFAULT_MTU; - opts.omtu = HIDP_DEFAULT_MTU; - opts.flush_to = 0xffff; - - setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)); - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, dst); - addr.l2_psm = htobs(psm); - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(sk); - return -1; - } - - return sk; -} - -static int l2cap_listen(const bdaddr_t *bdaddr, unsigned short psm, int lm, int backlog) -{ - struct sockaddr_l2 addr; - struct l2cap_options opts; - int sk; - - if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, bdaddr); - addr.l2_psm = htobs(psm); - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - close(sk); - return -1; - } - - setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)); - - memset(&opts, 0, sizeof(opts)); - opts.imtu = HIDP_DEFAULT_MTU; - opts.omtu = HIDP_DEFAULT_MTU; - opts.flush_to = 0xffff; - - setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)); - - if (listen(sk, backlog) < 0) { - close(sk); - return -1; - } - - return sk; -} - -static int l2cap_accept(int sk, bdaddr_t *bdaddr) -{ - struct sockaddr_l2 addr; - socklen_t addrlen; - int nsk; - - memset(&addr, 0, sizeof(addr)); - addrlen = sizeof(addr); - - if ((nsk = accept(sk, (struct sockaddr *) &addr, &addrlen)) < 0) - return -1; - - if (bdaddr) - bacpy(bdaddr, &addr.l2_bdaddr); - - return nsk; -} - -static int request_authentication(bdaddr_t *src, bdaddr_t *dst) -{ - struct hci_conn_info_req *cr; - char addr[18]; - int err, dd, dev_id; - - ba2str(src, addr); - dev_id = hci_devid(addr); - if (dev_id < 0) - return dev_id; - - dd = hci_open_dev(dev_id); - if (dd < 0) - return dd; - - cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); - if (!cr) - return -ENOMEM; - - bacpy(&cr->bdaddr, dst); - cr->type = ACL_LINK; - err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr); - if (err < 0) { - free(cr); - hci_close_dev(dd); - return err; - } - - err = hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000); - - free(cr); - hci_close_dev(dd); - - return err; -} - -static int request_encryption(bdaddr_t *src, bdaddr_t *dst) -{ - struct hci_conn_info_req *cr; - char addr[18]; - int err, dd, dev_id; - - ba2str(src, addr); - dev_id = hci_devid(addr); - if (dev_id < 0) - return dev_id; - - dd = hci_open_dev(dev_id); - if (dd < 0) - return dd; - - cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); - if (!cr) - return -ENOMEM; - - bacpy(&cr->bdaddr, dst); - cr->type = ACL_LINK; - err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr); - if (err < 0) { - free(cr); - hci_close_dev(dd); - return err; - } - - err = hci_encrypt_link(dd, htobs(cr->conn_info->handle), 1, 25000); - - free(cr); - hci_close_dev(dd); - - return err; -} - -static void enable_sixaxis(int csk) -{ - const unsigned char buf[] = { - 0x53 /*HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE*/, - 0xf4, 0x42, 0x03, 0x00, 0x00 }; - int err; - - err = write(csk, buf, sizeof(buf)); -} - -static int create_device(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout) -{ - struct hidp_connadd_req req; - struct sockaddr_l2 addr; - socklen_t addrlen; - bdaddr_t src, dst; - char bda[18]; - int err; - - memset(&addr, 0, sizeof(addr)); - addrlen = sizeof(addr); - - if (getsockname(csk, (struct sockaddr *) &addr, &addrlen) < 0) - return -1; - - bacpy(&src, &addr.l2_bdaddr); - - memset(&addr, 0, sizeof(addr)); - addrlen = sizeof(addr); - - if (getpeername(csk, (struct sockaddr *) &addr, &addrlen) < 0) - return -1; - - bacpy(&dst, &addr.l2_bdaddr); - - memset(&req, 0, sizeof(req)); - req.ctrl_sock = csk; - req.intr_sock = isk; - req.flags = 0; - req.idle_to = timeout * 60; - - err = get_stored_device_info(&src, &dst, &req); - if (!err) - goto create; - - if (!nocheck) { - ba2str(&dst, bda); - syslog(LOG_ERR, "Rejected connection from unknown device %s", bda); - /* Return no error to avoid run_server() complaining too */ - return 0; - } - - if (!nosdp) { - err = get_sdp_device_info(&src, &dst, &req); - if (err < 0) - goto error; - } else { - struct l2cap_conninfo conn; - socklen_t size; - uint8_t class[3]; - - memset(&conn, 0, sizeof(conn)); - size = sizeof(conn); - if (getsockopt(csk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &size) < 0) - memset(class, 0, 3); - else - memcpy(class, conn.dev_class, 3); - - if (class[1] == 0x25 && (class[2] == 0x00 || class[2] == 0x01)) - req.subclass = class[0]; - else - req.subclass = 0xc0; - } - -create: - if (subclass != 0x00) - req.subclass = subclass; - - ba2str(&dst, bda); - syslog(LOG_INFO, "New HID device %s (%s)", bda, req.name); - - if (encrypt && (req.subclass & 0x40)) { - err = request_authentication(&src, &dst); - if (err < 0) { - syslog(LOG_ERR, "Authentication for %s failed", bda); - goto error; - } - - err = request_encryption(&src, &dst); - if (err < 0) - syslog(LOG_ERR, "Encryption for %s failed", bda); - } - - if (bootonly) { - req.rd_size = 0; - req.flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); - } - - if (req.vendor == 0x054c && req.product == 0x0268) - enable_sixaxis(csk); - - err = ioctl(ctl, HIDPCONNADD, &req); - -error: - if (req.rd_data) - free(req.rd_data); - - return err; -} - -static void run_server(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout) -{ - struct pollfd p[2]; - sigset_t sigs; - short events; - int err, ncsk, nisk; - - sigfillset(&sigs); - sigdelset(&sigs, SIGCHLD); - sigdelset(&sigs, SIGPIPE); - sigdelset(&sigs, SIGTERM); - sigdelset(&sigs, SIGINT); - sigdelset(&sigs, SIGHUP); - - p[0].fd = csk; - p[0].events = POLLIN | POLLERR | POLLHUP; - - p[1].fd = isk; - p[1].events = POLLIN | POLLERR | POLLHUP; - - while (!__io_canceled) { - p[0].revents = 0; - p[1].revents = 0; - - if (ppoll(p, 2, NULL, &sigs) < 1) - continue; - - events = p[0].revents | p[1].revents; - - if (events & POLLIN) { - ncsk = l2cap_accept(csk, NULL); - nisk = l2cap_accept(isk, NULL); - - err = create_device(ctl, ncsk, nisk, subclass, nosdp, nocheck, bootonly, encrypt, timeout); - if (err < 0) - syslog(LOG_ERR, "HID create error %d (%s)", - errno, strerror(errno)); - - close(nisk); - sleep(1); - close(ncsk); - } - } -} - -static char *hidp_state[] = { - "unknown", - "connected", - "open", - "bound", - "listening", - "connecting", - "connecting", - "config", - "disconnecting", - "closed" -}; - -static char *hidp_flagstostr(uint32_t flags) -{ - static char str[100]; - str[0] = 0; - - strcat(str, "["); - - if (flags & (1 << HIDP_BOOT_PROTOCOL_MODE)) - strcat(str, "boot-protocol"); - - strcat(str, "]"); - - return str; -} - -static void do_show(int ctl) -{ - struct hidp_connlist_req req; - struct hidp_conninfo ci[16]; - char addr[18]; - int i; - - req.cnum = 16; - req.ci = ci; - - if (ioctl(ctl, HIDPGETCONNLIST, &req) < 0) { - perror("Can't get connection list"); - close(ctl); - exit(1); - } - - for (i = 0; i < req.cnum; i++) { - ba2str(&ci[i].bdaddr, addr); - printf("%s %s [%04x:%04x] %s %s\n", addr, ci[i].name, - ci[i].vendor, ci[i].product, hidp_state[ci[i].state], - ci[i].flags ? hidp_flagstostr(ci[i].flags) : ""); - } -} - -static void do_connect(int ctl, bdaddr_t *src, bdaddr_t *dst, uint8_t subclass, int fakehid, int bootonly, int encrypt, int timeout) -{ - struct hidp_connadd_req req; - uint16_t uuid = HID_SVCLASS_ID; - uint8_t channel = 0; - char name[256]; - int csk, isk, err; - - memset(&req, 0, sizeof(req)); - - err = get_sdp_device_info(src, dst, &req); - if (err < 0 && fakehid) - err = get_alternate_device_info(src, dst, - &uuid, &channel, name, sizeof(name) - 1); - - if (err < 0) { - perror("Can't get device information"); - close(ctl); - exit(1); - } - - switch (uuid) { - case HID_SVCLASS_ID: - goto connect; - - case SERIAL_PORT_SVCLASS_ID: - if (subclass == 0x40 || !strcmp(name, "Cable Replacement")) { - if (epox_presenter(src, dst, channel) < 0) { - close(ctl); - exit(1); - } - break; - } - if (subclass == 0x1f || !strcmp(name, "SPP slave")) { - if (jthree_keyboard(src, dst, channel) < 0) { - close(ctl); - exit(1); - } - break; - } - if (subclass == 0x02 || !strcmp(name, "Serial Port")) { - if (celluon_keyboard(src, dst, channel) < 0) { - close(ctl); - exit(1); - } - break; - } - break; - - case HEADSET_SVCLASS_ID: - case HANDSFREE_SVCLASS_ID: - if (headset_presenter(src, dst, channel) < 0) { - close(ctl); - exit(1); - } - break; - } - - return; - -connect: - csk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_CTRL); - if (csk < 0) { - perror("Can't create HID control channel"); - close(ctl); - exit(1); - } - - isk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_INTR); - if (isk < 0) { - perror("Can't create HID interrupt channel"); - close(csk); - close(ctl); - exit(1); - } - - err = create_device(ctl, csk, isk, subclass, 1, 1, bootonly, encrypt, timeout); - if (err < 0) { - fprintf(stderr, "HID create error %d (%s)\n", - errno, strerror(errno)); - close(isk); - sleep(1); - close(csk); - close(ctl); - exit(1); - } -} - -static void do_search(int ctl, bdaddr_t *bdaddr, uint8_t subclass, int fakehid, int bootonly, int encrypt, int timeout) -{ - inquiry_info *info = NULL; - bdaddr_t src, dst; - int i, dev_id, num_rsp, length, flags; - char addr[18]; - uint8_t class[3]; - - ba2str(bdaddr, addr); - dev_id = hci_devid(addr); - if (dev_id < 0) { - dev_id = hci_get_route(NULL); - hci_devba(dev_id, &src); - } else - bacpy(&src, bdaddr); - - length = 8; /* ~10 seconds */ - num_rsp = 0; - flags = IREQ_CACHE_FLUSH; - - printf("Searching ...\n"); - - num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags); - - for (i = 0; i < num_rsp; i++) { - memcpy(class, (info+i)->dev_class, 3); - if (class[1] == 0x25 && (class[2] == 0x00 || class[2] == 0x01)) { - bacpy(&dst, &(info+i)->bdaddr); - ba2str(&dst, addr); - - printf("\tConnecting to device %s\n", addr); - do_connect(ctl, &src, &dst, subclass, fakehid, bootonly, encrypt, timeout); - } - } - - if (!fakehid) - goto done; - - for (i = 0; i < num_rsp; i++) { - memcpy(class, (info+i)->dev_class, 3); - if ((class[0] == 0x00 && class[2] == 0x00 && - (class[1] == 0x40 || class[1] == 0x1f)) || - (class[0] == 0x10 && class[1] == 0x02 && class[2] == 0x40)) { - bacpy(&dst, &(info+i)->bdaddr); - ba2str(&dst, addr); - - printf("\tConnecting to device %s\n", addr); - do_connect(ctl, &src, &dst, subclass, 1, bootonly, 0, timeout); - } - } - -done: - bt_free(info); - - if (!num_rsp) { - fprintf(stderr, "\tNo devices in range or visible\n"); - close(ctl); - exit(1); - } -} - -static void do_kill(int ctl, bdaddr_t *bdaddr, uint32_t flags) -{ - struct hidp_conndel_req req; - struct hidp_connlist_req cl; - struct hidp_conninfo ci[16]; - int i; - - if (!bacmp(bdaddr, BDADDR_ALL)) { - cl.cnum = 16; - cl.ci = ci; - - if (ioctl(ctl, HIDPGETCONNLIST, &cl) < 0) { - perror("Can't get connection list"); - close(ctl); - exit(1); - } - - for (i = 0; i < cl.cnum; i++) { - bacpy(&req.bdaddr, &ci[i].bdaddr); - req.flags = flags; - - if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { - perror("Can't release connection"); - close(ctl); - exit(1); - } - } - - } else { - bacpy(&req.bdaddr, bdaddr); - req.flags = flags; - - if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { - perror("Can't release connection"); - close(ctl); - exit(1); - } - } -} - -static void usage(void) -{ - printf("hidd - Bluetooth HID daemon version %s\n\n", VERSION); - - printf("Usage:\n" - "\thidd [options] [commands]\n" - "\n"); - - printf("Options:\n" - "\t-i <hciX|bdaddr> Local HCI device or BD Address\n" - "\t-t <timeout> Set idle timeout (in minutes)\n" - "\t-b <subclass> Overwrite the boot mode subclass\n" - "\t-n, --nodaemon Don't fork daemon to background\n" - "\t-h, --help Display help\n" - "\n"); - - printf("Commands:\n" - "\t--server Start HID server\n" - "\t--search Search for HID devices\n" - "\t--connect <bdaddr> Connect remote HID device\n" - "\t--unplug <bdaddr> Unplug the HID connection\n" - "\t--kill <bdaddr> Terminate HID connection\n" - "\t--killall Terminate all connections\n" - "\t--show List current HID connections\n" - "\n"); -} - -static struct option main_options[] = { - { "help", 0, 0, 'h' }, - { "nodaemon", 0, 0, 'n' }, - { "subclass", 1, 0, 'b' }, - { "timeout", 1, 0, 't' }, - { "device", 1, 0, 'i' }, - { "master", 0, 0, 'M' }, - { "encrypt", 0, 0, 'E' }, - { "nosdp", 0, 0, 'D' }, - { "nocheck", 0, 0, 'Z' }, - { "bootonly", 0, 0, 'B' }, - { "hidonly", 0, 0, 'H' }, - { "show", 0, 0, 'l' }, - { "list", 0, 0, 'l' }, - { "server", 0, 0, 'd' }, - { "listen", 0, 0, 'd' }, - { "search", 0, 0, 's' }, - { "create", 1, 0, 'c' }, - { "connect", 1, 0, 'c' }, - { "disconnect", 1, 0, 'k' }, - { "terminate", 1, 0, 'k' }, - { "release", 1, 0, 'k' }, - { "kill", 1, 0, 'k' }, - { "killall", 0, 0, 'K' }, - { "unplug", 1, 0, 'u' }, - { 0, 0, 0, 0 } -}; - -int main(int argc, char *argv[]) -{ - struct sigaction sa; - bdaddr_t bdaddr, dev; - uint32_t flags = 0; - uint8_t subclass = 0x00; - char addr[18]; - int log_option = LOG_NDELAY | LOG_PID; - int opt, ctl, csk, isk; - int mode = SHOW, detach = 1, nosdp = 0, nocheck = 0, bootonly = 0; - int fakehid = 1, encrypt = 0, timeout = 30, lm = 0; - - bacpy(&bdaddr, BDADDR_ANY); - - while ((opt = getopt_long(argc, argv, "+i:nt:b:MEDZBHldsc:k:Ku:h", main_options, NULL)) != -1) { - switch(opt) { - case 'i': - if (!strncasecmp(optarg, "hci", 3)) - hci_devba(atoi(optarg + 3), &bdaddr); - else - str2ba(optarg, &bdaddr); - break; - case 'n': - detach = 0; - break; - case 't': - timeout = atoi(optarg); - break; - case 'b': - if (!strncasecmp(optarg, "0x", 2)) - subclass = (uint8_t) strtol(optarg, NULL, 16); - else - subclass = atoi(optarg); - break; - case 'M': - lm |= L2CAP_LM_MASTER; - break; - case 'E': - encrypt = 1; - break; - case 'D': - nosdp = 1; - break; - case 'Z': - nocheck = 1; - break; - case 'B': - bootonly = 1; - break; - case 'H': - fakehid = 0; - break; - case 'l': - mode = SHOW; - break; - case 'd': - mode = SERVER; - break; - case 's': - mode = SEARCH; - break; - case 'c': - str2ba(optarg, &dev); - mode = CONNECT; - break; - case 'k': - str2ba(optarg, &dev); - mode = KILL; - break; - case 'K': - bacpy(&dev, BDADDR_ALL); - mode = KILL; - break; - case 'u': - str2ba(optarg, &dev); - flags = (1 << HIDP_VIRTUAL_CABLE_UNPLUG); - mode = KILL; - break; - case 'h': - usage(); - exit(0); - default: - exit(0); - } - } - - ba2str(&bdaddr, addr); - - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) { - perror("Can't open HIDP control socket"); - exit(1); - } - - switch (mode) { - case SERVER: - csk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_CTRL, lm, 10); - if (csk < 0) { - perror("Can't listen on HID control channel"); - close(ctl); - exit(1); - } - - isk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_INTR, lm, 10); - if (isk < 0) { - perror("Can't listen on HID interrupt channel"); - close(ctl); - close(csk); - exit(1); - } - break; - - case SEARCH: - do_search(ctl, &bdaddr, subclass, fakehid, bootonly, encrypt, timeout); - close(ctl); - exit(0); - - case CONNECT: - do_connect(ctl, &bdaddr, &dev, subclass, fakehid, bootonly, encrypt, timeout); - close(ctl); - exit(0); - - case KILL: - do_kill(ctl, &dev, flags); - close(ctl); - exit(0); - - default: - do_show(ctl); - close(ctl); - exit(0); - } - - if (detach) { - if (daemon(0, 0)) { - perror("Can't start daemon"); - exit(1); - } - } else - log_option |= LOG_PERROR; - - openlog("hidd", log_option, LOG_DAEMON); - - if (bacmp(&bdaddr, BDADDR_ANY)) - syslog(LOG_INFO, "Bluetooth HID daemon (%s)", addr); - else - syslog(LOG_INFO, "Bluetooth HID daemon"); - - memset(&sa, 0, sizeof(sa)); - sa.sa_flags = SA_NOCLDSTOP; - - sa.sa_handler = sig_term; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sa.sa_handler = sig_hup; - sigaction(SIGHUP, &sa, NULL); - - sa.sa_handler = SIG_IGN; - sigaction(SIGCHLD, &sa, NULL); - sigaction(SIGPIPE, &sa, NULL); - - run_server(ctl, csk, isk, subclass, nosdp, nocheck, bootonly, encrypt, timeout); - - syslog(LOG_INFO, "Exit"); - - close(csk); - close(isk); - close(ctl); - - return 0; -} diff --git a/hidd/sdp.c b/hidd/sdp.c deleted file mode 100644 index eaf8c136..00000000 --- a/hidd/sdp.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2003-2008 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 <fcntl.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/param.h> -#include <sys/socket.h> - -#include <bluetooth/bluetooth.h> -#include <bluetooth/l2cap.h> -#include <bluetooth/sdp.h> -#include <bluetooth/sdp_lib.h> -#include <bluetooth/hidp.h> - -#include "textfile.h" -#include "hidd.h" - -static void epox_endian_quirk(unsigned char *data, int size) -{ - /* USAGE_PAGE (Keyboard) 05 07 - * USAGE_MINIMUM (0) 19 00 - * USAGE_MAXIMUM (65280) 2A 00 FF <= must be FF 00 - * LOGICAL_MINIMUM (0) 15 00 - * LOGICAL_MAXIMUM (65280) 26 00 FF <= must be FF 00 - */ - unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff, - 0x15, 0x00, 0x26, 0x00, 0xff }; - int i; - - if (!data) - return; - - for (i = 0; i < size - sizeof(pattern); i++) { - if (!memcmp(data + i, pattern, sizeof(pattern))) { - data[i + 5] = 0xff; - data[i + 6] = 0x00; - data[i + 10] = 0xff; - data[i + 11] = 0x00; - } - } -} - -static int store_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) -{ - char filename[PATH_MAX + 1], addr[18], *str, *desc; - int i, err, size; - - ba2str(src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); - - size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; - str = malloc(size); - if (!str) - return -ENOMEM; - - desc = malloc((req->rd_size * 2) + 1); - if (!desc) { - free(str); - return -ENOMEM; - } - - memset(desc, 0, (req->rd_size * 2) + 1); - for (i = 0; i < req->rd_size; i++) - sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]); - - snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s", - req->vendor, req->product, req->version, - req->subclass, req->country, req->parser, desc, - req->flags, req->name); - - free(desc); - - create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - ba2str(dst, addr); - err = textfile_put(filename, addr, str); - - free(str); - - return err; -} - -int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) -{ - char filename[PATH_MAX + 1], addr[18], tmp[3], *str, *desc; - unsigned int vendor, product, version, subclass, country, parser, pos; - int i; - - desc = malloc(4096); - if (!desc) - return -ENOMEM; - - memset(desc, 0, 4096); - - ba2str(src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); - - ba2str(dst, addr); - str = textfile_get(filename, addr); - if (!str) { - free(desc); - return -EIO; - } - - sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", - &vendor, &product, &version, &subclass, &country, - &parser, desc, &req->flags, &pos); - - free(str); - - req->vendor = vendor; - req->product = product; - req->version = version; - req->subclass = subclass; - req->country = country; - req->parser = parser; - - snprintf(req->name, 128, str + pos); - - req->rd_size = strlen(desc) / 2; - req->rd_data = malloc(req->rd_size); - if (!req->rd_data) { - free(desc); - return -ENOMEM; - } - - memset(tmp, 0, sizeof(tmp)); - for (i = 0; i < req->rd_size; i++) { - memcpy(tmp, desc + (i * 2), 2); - req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); - } - - free(desc); - - return 0; -} - -int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) -{ - struct sockaddr_l2 addr; - socklen_t addrlen; - bdaddr_t bdaddr; - uint32_t range = 0x0000ffff; - sdp_session_t *s; - sdp_list_t *search, *attrid, *pnp_rsp, *hid_rsp; - sdp_record_t *rec; - sdp_data_t *pdlist, *pdlist2; - uuid_t svclass; - int err; - - s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE); - if (!s) - return -1; - - sdp_uuid16_create(&svclass, PNP_INFO_SVCLASS_ID); - search = sdp_list_append(NULL, &svclass); - attrid = sdp_list_append(NULL, &range); - - err = sdp_service_search_attr_req(s, search, - SDP_ATTR_REQ_RANGE, attrid, &pnp_rsp); - - sdp_list_free(search, NULL); - sdp_list_free(attrid, NULL); - - sdp_uuid16_create(&svclass, HID_SVCLASS_ID); - search = sdp_list_append(NULL, &svclass); - attrid = sdp_list_append(NULL, &range); - - err = sdp_service_search_attr_req(s, search, - SDP_ATTR_REQ_RANGE, attrid, &hid_rsp); - - sdp_list_free(search, NULL); - sdp_list_free(attrid, NULL); - - memset(&addr, 0, sizeof(addr)); - addrlen = sizeof(addr); - - if (getsockname(s->sock, (struct sockaddr *) &addr, &addrlen) < 0) - bacpy(&bdaddr, src); - else - bacpy(&bdaddr, &addr.l2_bdaddr); - - sdp_close(s); - - if (err || !hid_rsp) - return -1; - - if (pnp_rsp) { - rec = (sdp_record_t *) pnp_rsp->data; - - pdlist = sdp_data_get(rec, 0x0201); - req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; - - pdlist = sdp_data_get(rec, 0x0202); - req->product = pdlist ? pdlist->val.uint16 : 0x0000; - - pdlist = sdp_data_get(rec, 0x0203); - req->version = pdlist ? pdlist->val.uint16 : 0x0000; - - sdp_record_free(rec); - } - - rec = (sdp_record_t *) hid_rsp->data; - - pdlist = sdp_data_get(rec, 0x0101); - pdlist2 = sdp_data_get(rec, 0x0102); - if (pdlist) { - if (pdlist2) { - if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) { - strncpy(req->name, pdlist2->val.str, sizeof(req->name) - 1); - strcat(req->name, " "); - } - strncat(req->name, pdlist->val.str, - sizeof(req->name) - strlen(req->name)); - } else - strncpy(req->name, pdlist->val.str, sizeof(req->name)); - } else { - pdlist2 = sdp_data_get(rec, 0x0100); - if (pdlist2) - strncpy(req->name, pdlist2->val.str, sizeof(req->name)); - } - - pdlist = sdp_data_get(rec, 0x0201); - req->parser = pdlist ? pdlist->val.uint16 : 0x0100; - - pdlist = sdp_data_get(rec, 0x0202); - req->subclass = pdlist ? pdlist->val.uint8 : 0; - - pdlist = sdp_data_get(rec, 0x0203); - req->country = pdlist ? pdlist->val.uint8 : 0; - - pdlist = sdp_data_get(rec, 0x0206); - if (pdlist) { - pdlist = pdlist->val.dataseq; - pdlist = pdlist->val.dataseq; - pdlist = pdlist->next; - - req->rd_data = malloc(pdlist->unitSize); - if (req->rd_data) { - memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); - req->rd_size = pdlist->unitSize; - epox_endian_quirk(req->rd_data, req->rd_size); - } - } - - sdp_record_free(rec); - - if (bacmp(&bdaddr, BDADDR_ANY)) - store_device_info(&bdaddr, dst, req); - - return 0; -} - -int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len) -{ - uint16_t attr1 = SDP_ATTR_PROTO_DESC_LIST; - uint16_t attr2 = SDP_ATTR_SVCNAME_PRIMARY; - sdp_session_t *s; - sdp_list_t *search, *attrid, *rsp; - uuid_t svclass; - int err; - - s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE); - if (!s) - return -1; - - sdp_uuid16_create(&svclass, HEADSET_SVCLASS_ID); - search = sdp_list_append(NULL, &svclass); - attrid = sdp_list_append(NULL, &attr1); - attrid = sdp_list_append(attrid, &attr2); - - err = sdp_service_search_attr_req(s, search, - SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp); - - sdp_list_free(search, NULL); - sdp_list_free(attrid, NULL); - - if (err <= 0) { - sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID); - search = sdp_list_append(NULL, &svclass); - attrid = sdp_list_append(NULL, &attr1); - attrid = sdp_list_append(attrid, &attr2); - - err = sdp_service_search_attr_req(s, search, - SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp); - - sdp_list_free(search, NULL); - sdp_list_free(attrid, NULL); - - if (err < 0) { - sdp_close(s); - return err; - } - - if (uuid) - *uuid = SERIAL_PORT_SVCLASS_ID; - } else { - if (uuid) - *uuid = HEADSET_SVCLASS_ID; - } - - sdp_close(s); - - for (; rsp; rsp = rsp->next) { - sdp_record_t *rec = (sdp_record_t *) rsp->data; - sdp_list_t *protos; - - sdp_get_service_name(rec, name, len); - - if (!sdp_get_access_protos(rec, &protos)) { - uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID); - if (ch > 0) { - if (channel) - *channel = ch; - return 0; - } - } - - sdp_record_free(rec); - } - - return -EIO; -} |