Index: head/usr.sbin/bluetooth/bthidd/parser.y =================================================================== --- head/usr.sbin/bluetooth/bthidd/parser.y (revision 162528) +++ head/usr.sbin/bluetooth/bthidd/parser.y (revision 162529) @@ -1,475 +1,475 @@ %{ /* * parser.y */ /*- * Copyright (c) 2006 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #ifndef BTHIDCONTROL #include #include #define SYSLOG syslog #define LOGCRIT LOG_CRIT #define LOGERR LOG_ERR #define LOGWARNING LOG_WARNING #define EOL #else #define SYSLOG fprintf #define LOGCRIT stderr #define LOGERR stderr #define LOGWARNING stderr #define EOL "\n" #endif /* ndef BTHIDCONTROL */ #include "bthid_config.h" int yyparse (void); int yylex (void); void yyerror (char const *); static int32_t check_hid_device(hid_device_p hid_device); static void free_hid_device (hid_device_p hid_device); extern FILE *yyin; extern int yylineno; char const *config_file = BTHIDD_CONFFILE; char const *hids_file = BTHIDD_HIDSFILE; static char buffer[1024]; static int32_t hid_descriptor_size; static hid_device_t *hid_device = NULL; static LIST_HEAD(, hid_device) hid_devices; %} %union { bdaddr_t bdaddr; int32_t num; } %token T_BDADDRSTRING %token T_HEXBYTE %token T_DEVICE T_BDADDR T_CONTROL_PSM T_INTERRUPT_PSM T_RECONNECT_INITIATE %token T_BATTERY_POWER T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR %token T_TRUE T_FALSE T_ERROR %% config: line | config line ; line: T_DEVICE { hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device)); if (hid_device == NULL) { SYSLOG(LOGCRIT, "Could not allocate new " \ "config entry" EOL); YYABORT; } hid_device->new_device = 1; } '{' options '}' { if (check_hid_device(hid_device)) LIST_INSERT_HEAD(&hid_devices,hid_device,next); else free_hid_device(hid_device); hid_device = NULL; } ; options: option ';' | options option ';' ; option: bdaddr | control_psm | interrupt_psm | reconnect_initiate | battery_power | normally_connectable | hid_descriptor | parser_error ; bdaddr: T_BDADDR T_BDADDRSTRING { memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr)); } ; control_psm: T_CONTROL_PSM T_HEXBYTE { hid_device->control_psm = $2; } ; interrupt_psm: T_INTERRUPT_PSM T_HEXBYTE { hid_device->interrupt_psm = $2; } ; reconnect_initiate: T_RECONNECT_INITIATE T_TRUE { hid_device->reconnect_initiate = 1; } | T_RECONNECT_INITIATE T_FALSE { hid_device->reconnect_initiate = 0; } ; battery_power: T_BATTERY_POWER T_TRUE { hid_device->battery_power = 1; } | T_BATTERY_POWER T_FALSE { hid_device->battery_power = 0; } ; normally_connectable: T_NORMALLY_CONNECTABLE T_TRUE { hid_device->normally_connectable = 1; } | T_NORMALLY_CONNECTABLE T_FALSE { hid_device->normally_connectable = 0; } ; hid_descriptor: T_HID_DESCRIPTOR { hid_descriptor_size = 0; } '{' hid_descriptor_bytes '}' { if (hid_device->desc != NULL) hid_dispose_report_desc(hid_device->desc); - hid_device->desc = hid_use_report_desc(buffer, hid_descriptor_size); + hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size); if (hid_device->desc == NULL) { SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL); YYABORT; } } ; hid_descriptor_bytes: hid_descriptor_byte | hid_descriptor_bytes hid_descriptor_byte ; hid_descriptor_byte: T_HEXBYTE { if (hid_descriptor_size >= (int32_t) sizeof(buffer)) { SYSLOG(LOGCRIT, "HID descriptor is too big" EOL); YYABORT; } buffer[hid_descriptor_size ++] = $1; } ; parser_error: T_ERROR { YYABORT; } %% /* Display parser error message */ void yyerror(char const *message) { SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno); } /* Re-read config file */ int32_t read_config_file(void) { int32_t e; if (config_file == NULL) { SYSLOG(LOGERR, "Unknown config file name!" EOL); return (-1); } if ((yyin = fopen(config_file, "r")) == NULL) { SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL, config_file, strerror(errno), errno); return (-1); } clean_config(); if (yyparse() < 0) { SYSLOG(LOGERR, "Could not parse config file '%s'" EOL, config_file); e = -1; } else e = 0; fclose(yyin); yyin = NULL; return (e); } /* Clean config */ void clean_config(void) { while (!LIST_EMPTY(&hid_devices)) { hid_device_p d = LIST_FIRST(&hid_devices); LIST_REMOVE(d, next); free_hid_device(d); } } /* Lookup config entry */ hid_device_p get_hid_device(bdaddr_p bdaddr) { hid_device_p d; LIST_FOREACH(d, &hid_devices, next) if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0) break; return (d); } /* Get next config entry */ hid_device_p get_next_hid_device(hid_device_p d) { return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next)); } /* Print config entry */ void print_hid_device(hid_device_p d, FILE *f) { /* XXX FIXME hack! */ struct report_desc { unsigned int size; unsigned char data[1]; }; /* XXX FIXME hack! */ struct report_desc *desc = (struct report_desc *) d->desc; uint32_t i; fprintf(f, "device {\n" \ " bdaddr %s;\n" \ " control_psm 0x%x;\n" \ " interrupt_psm 0x%x;\n" \ " reconnect_initiate %s;\n" \ " battery_power %s;\n" \ " normally_connectable %s;\n" \ " hid_descriptor {", bt_ntoa(&d->bdaddr, NULL), d->control_psm, d->interrupt_psm, d->reconnect_initiate? "true" : "false", d->battery_power? "true" : "false", d->normally_connectable? "true" : "false"); for (i = 0; i < desc->size; i ++) { if ((i % 8) == 0) fprintf(f, "\n "); fprintf(f, "0x%2.2x ", desc->data[i]); } fprintf(f, "\n" \ " };\n" \ "}\n"); } /* Check config entry */ static int32_t check_hid_device(hid_device_p d) { hid_data_t hd; hid_item_t hi; int32_t page; if (get_hid_device(&d->bdaddr) != NULL) { SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL, bt_ntoa(&d->bdaddr, NULL)); return (0); } if (d->control_psm == 0) { SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL); return (0); } if (d->interrupt_psm == 0) { SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL); return (0); } if (d->desc == NULL) { SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL); return (0); } /* XXX somehow need to make sure descriptor is valid */ for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) { switch (hi.kind) { case hid_collection: case hid_endcollection: case hid_output: case hid_feature: break; case hid_input: /* Check if the device may send keystrokes */ page = HID_PAGE(hi.usage); if (page == HUP_KEYBOARD || page == HUP_CONSUMER) d->keyboard = 1; break; } } hid_end_parse(hd); return (1); } /* Free config entry */ static void free_hid_device(hid_device_p d) { if (d->desc != NULL) hid_dispose_report_desc(d->desc); memset(d, 0, sizeof(*d)); free(d); } /* Re-read hids file */ int32_t read_hids_file(void) { FILE *f; hid_device_t *d; char *line; bdaddr_t bdaddr; int32_t lineno; if (hids_file == NULL) { SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); return (-1); } if ((f = fopen(hids_file, "r")) == NULL) { if (errno == ENOENT) return (0); SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, hids_file, strerror(errno), errno); return (-1); } for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) { if ((line = strtok(buffer, "\r\n\t ")) == NULL) continue; /* ignore empty lines */ if (!bt_aton(line, &bdaddr)) { SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \ "%s:%d" EOL, hids_file, lineno); continue; } if ((d = get_hid_device(&bdaddr)) != NULL) d->new_device = 0; } fclose(f); return (0); } /* Write hids file */ int32_t write_hids_file(void) { char path[PATH_MAX]; FILE *f; hid_device_t *d; if (hids_file == NULL) { SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); return (-1); } snprintf(path, sizeof(path), "%s.new", hids_file); if ((f = fopen(path, "w")) == NULL) { SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, path, strerror(errno), errno); return (-1); } LIST_FOREACH(d, &hid_devices, next) if (!d->new_device) fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL)); fclose(f); if (rename(path, hids_file) < 0) { SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \ "%s (%d)" EOL, path, hids_file, strerror(errno), errno); unlink(path); return (-1); } return (0); } Index: head/usr.sbin/bluetooth/hccontrol/link_control.c =================================================================== --- head/usr.sbin/bluetooth/hccontrol/link_control.c (revision 162528) +++ head/usr.sbin/bluetooth/hccontrol/link_control.c (revision 162529) @@ -1,960 +1,960 @@ /* * link_control.c * * Copyright (c) 2001-2002 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: link_control.c,v 1.4 2003/08/18 19:19:54 max Exp $ * $FreeBSD$ */ #include #include #include #include #include "hccontrol.h" static void hci_inquiry_response (int n, uint8_t **b); /* Send Inquiry command to the unit */ static int hci_inquiry(int s, int argc, char **argv) { int n0, n1, n2, timo; - uint8_t b[512]; + char b[512]; ng_hci_inquiry_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; /* set defaults */ cp.lap[2] = 0x9e; cp.lap[1] = 0x8b; cp.lap[0] = 0x33; cp.inquiry_length = 5; cp.num_responses = 8; /* parse command parameters */ switch (argc) { case 3: /* number of responses, range 0x00 - 0xff */ if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 0xff) return (USAGE); cp.num_responses = (n0 & 0xff); case 2: /* inquiry length (N * 1.28) sec, range 0x01 - 0x30 */ if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x1 || n0 > 0x30) return (USAGE); cp.inquiry_length = (n0 & 0xff); case 1: /* LAP */ if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3) return (USAGE); cp.lap[0] = (n0 & 0xff); cp.lap[1] = (n1 & 0xff); cp.lap[2] = (n2 & 0xff); case 0: /* use defaults */ break; default: return (USAGE); } /* send request and expect status back */ n0 = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_INQUIRY), (char const *) &cp, sizeof(cp), b, &n0) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); timo = timeout; timeout = cp.inquiry_length * 1.28 + 1; wait_for_more: /* wait for inquiry events */ n0 = sizeof(b); if (hci_recv(s, b, &n0) == ERROR) { timeout = timo; return (ERROR); } if (n0 < sizeof(*e)) { timeout = timo; errno = EIO; return (ERROR); } switch (e->event) { case NG_HCI_EVENT_INQUIRY_RESULT: { ng_hci_inquiry_result_ep *ir = (ng_hci_inquiry_result_ep *)(e + 1); uint8_t *r = (uint8_t *)(ir + 1); fprintf(stdout, "Inquiry result, num_responses=%d\n", ir->num_responses); for (n0 = 0; n0 < ir->num_responses; n0++) hci_inquiry_response(n0, &r); goto wait_for_more; } case NG_HCI_EVENT_INQUIRY_COMPL: fprintf(stdout, "Inquiry complete. Status: %s [%#02x]\n", hci_status2str(*(b + sizeof(*e))), *(b + sizeof(*e))); break; default: goto wait_for_more; } timeout = timo; return (OK); } /* hci_inquiry */ /* Print Inquiry_Result event */ static void hci_inquiry_response(int n, uint8_t **b) { ng_hci_inquiry_response *ir = (ng_hci_inquiry_response *)(*b); fprintf(stdout, "Inquiry result #%d\n", n); fprintf(stdout, "\tBD_ADDR: %s\n", hci_bdaddr2str(&ir->bdaddr)); fprintf(stdout, "\tPage Scan Rep. Mode: %#02x\n", ir->page_scan_rep_mode); fprintf(stdout, "\tPage Scan Period Mode: %#02x\n", ir->page_scan_period_mode); fprintf(stdout, "\tPage Scan Mode: %#02x\n", ir->page_scan_mode); fprintf(stdout, "\tClass: %02x:%02x:%02x\n", ir->uclass[2], ir->uclass[1], ir->uclass[0]); fprintf(stdout, "\tClock offset: %#04x\n", le16toh(ir->clock_offset)); *b += sizeof(*ir); } /* hci_inquiry_response */ /* Send Create_Connection command to the unit */ static int hci_create_connection(int s, int argc, char **argv) { int n0; char b[512]; ng_hci_create_con_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; /* Set defaults */ memset(&cp, 0, sizeof(cp)); cp.pkt_type = htole16( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 | NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 | NG_HCI_PKT_DM5); cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0; cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE; cp.clock_offset = 0; cp.accept_role_switch = 1; /* parse command parameters */ switch (argc) { case 6: /* accept role switch */ if (sscanf(argv[5], "%d", &n0) != 1) return (USAGE); cp.accept_role_switch = n0 ? 1 : 0; case 5: /* clock offset */ if (sscanf(argv[4], "%d", &n0) != 1) return (USAGE); cp.clock_offset = (n0 & 0xffff); cp.clock_offset = htole16(cp.clock_offset); case 4: /* page scan mode */ if (sscanf(argv[3], "%d", &n0) != 1 || n0 < 0 || n0 > 3) return (USAGE); cp.page_scan_mode = (n0 & 0xff); case 3: /* page scan rep mode */ if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 2) return (USAGE); cp.page_scan_rep_mode = (n0 & 0xff); case 2: /* packet type */ if (sscanf(argv[1], "%x", &n0) != 1) return (USAGE); n0 &= ( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 | NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 | NG_HCI_PKT_DM5); if (n0 == 0) return (USAGE); cp.pkt_type = (n0 & 0xffff); cp.pkt_type = htole16(cp.pkt_type); case 1: /* BD_ADDR */ if (!bt_aton(argv[0], &cp.bdaddr)) { struct hostent *he = NULL; if ((he = bt_gethostbyname(argv[0])) == NULL) return (USAGE); memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr)); } break; default: return (USAGE); } /* send request and expect status response */ n0 = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_CREATE_CON), (char const *) &cp, sizeof(cp), b, &n0) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); /* wait for event */ again: n0 = sizeof(b); if (hci_recv(s, b, &n0) == ERROR) return (ERROR); if (n0 < sizeof(*e)) { errno = EIO; return (ERROR); } if (e->event == NG_HCI_EVENT_CON_COMPL) { ng_hci_con_compl_ep *ep = (ng_hci_con_compl_ep *)(e + 1); if (ep->status != 0x00) { fprintf(stdout, "Status: %s [%#02x]\n", hci_status2str(ep->status), ep->status); return (FAILED); } fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr)); fprintf(stdout, "Connection handle: %d\n", le16toh(ep->con_handle)); fprintf(stdout, "Encryption mode: %s [%d]\n", hci_encrypt2str(ep->encryption_mode, 0), ep->encryption_mode); } else goto again; return (OK); } /* hci_create_connection */ /* Send Disconnect command to the unit */ static int hci_disconnect(int s, int argc, char **argv) { int n; char b[512]; ng_hci_discon_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; /* Set defaults */ memset(&cp, 0, sizeof(cp)); cp.reason = 0x13; /* parse command parameters */ switch (argc) { case 2: /* reason */ if (sscanf(argv[1], "%d", &n) != 1 || n <= 0x00 || n > 0xff) return (USAGE); cp.reason = (uint8_t) (n & 0xff); case 1: /* connection handle */ if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) return (USAGE); cp.con_handle = (uint16_t) (n & 0x0fff); cp.con_handle = htole16(cp.con_handle); break; default: return (USAGE); } /* send request and expect status response */ n = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_DISCON), (char const *) &cp, sizeof(cp), b, &n) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); /* wait for event */ again: n = sizeof(b); if (hci_recv(s, b, &n) == ERROR) return (ERROR); if (n < sizeof(*e)) { errno = EIO; return (ERROR); } if (e->event == NG_HCI_EVENT_DISCON_COMPL) { ng_hci_discon_compl_ep *ep = (ng_hci_discon_compl_ep *)(e + 1); if (ep->status != 0x00) { fprintf(stdout, "Status: %s [%#02x]\n", hci_status2str(ep->status), ep->status); return (FAILED); } fprintf(stdout, "Connection handle: %d\n", le16toh(ep->con_handle)); fprintf(stdout, "Reason: %s [%#02x]\n", hci_status2str(ep->reason), ep->reason); } else goto again; return (OK); } /* hci_diconnect */ /* Send Add_SCO_Connection command to the unit */ static int hci_add_sco_connection(int s, int argc, char **argv) { int n; char b[512]; ng_hci_add_sco_con_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; /* Set defaults */ memset(&cp, 0, sizeof(cp)); cp.pkt_type = htole16(NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3); /* parse command parameters */ switch (argc) { case 2: /* packet type */ if (sscanf(argv[1], "%x", &n) != 1) return (USAGE); n &= (NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3); if (n == 0) return (USAGE); cp.pkt_type = (uint16_t) (n & 0x0fff); cp.pkt_type = htole16(cp.pkt_type); case 1: /* acl connection handle */ if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) return (USAGE); cp.con_handle = (uint16_t) (n & 0x0fff); cp.con_handle = htole16(cp.con_handle); break; default: return (USAGE); } /* send request and expect status response */ n = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_ADD_SCO_CON), (char const *) &cp, sizeof(cp), b, &n) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); /* wait for event */ again: n = sizeof(b); if (hci_recv(s, b, &n) == ERROR) return (ERROR); if (n < sizeof(*e)) { errno = EIO; return (ERROR); } if (e->event == NG_HCI_EVENT_CON_COMPL) { ng_hci_con_compl_ep *ep = (ng_hci_con_compl_ep *)(e + 1); if (ep->status != 0x00) { fprintf(stdout, "Status: %s [%#02x]\n", hci_status2str(ep->status), ep->status); return (FAILED); } fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr)); fprintf(stdout, "Connection handle: %d\n", le16toh(ep->con_handle)); fprintf(stdout, "Encryption mode: %s [%d]\n", hci_encrypt2str(ep->encryption_mode, 0), ep->encryption_mode); } else goto again; return (OK); } /* Add_SCO_Connection */ /* Send Change_Connection_Packet_Type command to the unit */ static int hci_change_connection_packet_type(int s, int argc, char **argv) { int n; char b[512]; ng_hci_change_con_pkt_type_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; switch (argc) { case 2: /* connection handle */ if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) return (USAGE); cp.con_handle = (uint16_t) (n & 0x0fff); cp.con_handle = htole16(cp.con_handle); /* packet type */ if (sscanf(argv[1], "%x", &n) != 1) return (USAGE); cp.pkt_type = (uint16_t) (n & 0xffff); cp.pkt_type = htole16(cp.pkt_type); break; default: return (USAGE); } /* send request and expect status response */ n = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_CHANGE_CON_PKT_TYPE), (char const *) &cp, sizeof(cp), b, &n) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); /* wait for event */ again: n = sizeof(b); if (hci_recv(s, b, &n) == ERROR) return (ERROR); if (n < sizeof(*e)) { errno = EIO; return (ERROR); } if (e->event == NG_HCI_EVENT_CON_PKT_TYPE_CHANGED) { ng_hci_con_pkt_type_changed_ep *ep = (ng_hci_con_pkt_type_changed_ep *)(e + 1); if (ep->status != 0x00) { fprintf(stdout, "Status: %s [%#02x]\n", hci_status2str(ep->status), ep->status); return (FAILED); } fprintf(stdout, "Connection handle: %d\n", le16toh(ep->con_handle)); fprintf(stdout, "Packet type: %#04x\n", le16toh(ep->pkt_type)); } else goto again; return (OK); } /* hci_change_connection_packet_type */ /* Send Remote_Name_Request command to the unit */ static int hci_remote_name_request(int s, int argc, char **argv) { int n0; char b[512]; ng_hci_remote_name_req_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; memset(&cp, 0, sizeof(cp)); cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0; cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE; /* parse command parameters */ switch (argc) { case 4: /* clock_offset */ if (sscanf(argv[3], "%x", &n0) != 1) return (USAGE); cp.clock_offset = (n0 & 0xffff); cp.clock_offset = htole16(cp.clock_offset); case 3: /* page_scan_mode */ if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x03) return (USAGE); cp.page_scan_mode = (n0 & 0xff); case 2: /* page_scan_rep_mode */ if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x02) return (USAGE); cp.page_scan_rep_mode = (n0 & 0xff); case 1: /* BD_ADDR */ if (!bt_aton(argv[0], &cp.bdaddr)) { struct hostent *he = NULL; if ((he = bt_gethostbyname(argv[0])) == NULL) return (USAGE); memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr)); } break; default: return (USAGE); } /* send request and expect status response */ n0 = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_REMOTE_NAME_REQ), (char const *) &cp, sizeof(cp), b, &n0) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); /* wait for event */ again: n0 = sizeof(b); if (hci_recv(s, b, &n0) == ERROR) return (ERROR); if (n0 < sizeof(*e)) { errno = EIO; return (ERROR); } if (e->event == NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL) { ng_hci_remote_name_req_compl_ep *ep = (ng_hci_remote_name_req_compl_ep *)(e + 1); if (ep->status != 0x00) { fprintf(stdout, "Status: %s [%#02x]\n", hci_status2str(ep->status), ep->status); return (FAILED); } fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr)); fprintf(stdout, "Name: %s\n", ep->name); } else goto again; return (OK); } /* hci_remote_name_request */ /* Send Read_Remote_Supported_Features command to the unit */ static int hci_read_remote_supported_features(int s, int argc, char **argv) { int n; char b[512]; ng_hci_read_remote_features_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; char buffer[1024]; /* parse command parameters */ switch (argc) { case 1: /* connecton handle */ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff) return (USAGE); cp.con_handle = (n & 0x0fff); cp.con_handle = htole16(cp.con_handle); break; default: return (USAGE); } /* send request and expect status response */ n = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_READ_REMOTE_FEATURES), (char const *) &cp, sizeof(cp), b, &n) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); /* wait for event */ again: n = sizeof(b); if (hci_recv(s, b, &n) == ERROR) return (ERROR); if (n < sizeof(*e)) { errno = EIO; return (ERROR); } if (e->event == NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL) { ng_hci_read_remote_features_compl_ep *ep = (ng_hci_read_remote_features_compl_ep *)(e + 1); if (ep->status != 0x00) { fprintf(stdout, "Status: %s [%#02x]\n", hci_status2str(ep->status), ep->status); return (FAILED); } fprintf(stdout, "Connection handle: %d\n", le16toh(ep->con_handle)); fprintf(stdout, "Features: "); for (n = 0; n < sizeof(ep->features); n++) fprintf(stdout, "%#02x ", ep->features[n]); fprintf(stdout, "\n%s\n", hci_features2str(ep->features, buffer, sizeof(buffer))); } else goto again; return (OK); } /* hci_read_remote_supported_features */ /* Send Read_Remote_Version_Information command to the unit */ static int hci_read_remote_version_information(int s, int argc, char **argv) { int n; char b[512]; ng_hci_read_remote_ver_info_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; /* parse command parameters */ switch (argc) { case 1: /* connecton handle */ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff) return (USAGE); cp.con_handle = (n & 0x0fff); cp.con_handle = htole16(cp.con_handle); break; default: return (USAGE); } /* send request and expect status response */ n = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_READ_REMOTE_VER_INFO), (char const *) &cp, sizeof(cp), b, &n) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); /* wait for event */ again: n = sizeof(b); if (hci_recv(s, b, &n) == ERROR) return (ERROR); if (n < sizeof(*e)) { errno = EIO; return (ERROR); } if (e->event == NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL) { ng_hci_read_remote_ver_info_compl_ep *ep = (ng_hci_read_remote_ver_info_compl_ep *)(e + 1); if (ep->status != 0x00) { fprintf(stdout, "Status: %s [%#02x]\n", hci_status2str(ep->status), ep->status); return (FAILED); } ep->manufacturer = le16toh(ep->manufacturer); fprintf(stdout, "Connection handle: %d\n", le16toh(ep->con_handle)); fprintf(stdout, "LMP version: %s [%#02x]\n", hci_lmpver2str(ep->lmp_version), ep->lmp_version); fprintf(stdout, "LMP sub-version: %#04x\n", le16toh(ep->lmp_subversion)); fprintf(stdout, "Manufacturer: %s [%#04x]\n", hci_manufacturer2str(ep->manufacturer), ep->manufacturer); } else goto again; return (OK); } /* hci_read_remote_version_information */ /* Send Read_Clock_Offset command to the unit */ static int hci_read_clock_offset(int s, int argc, char **argv) { int n; char b[512]; ng_hci_read_clock_offset_cp cp; ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; /* parse command parameters */ switch (argc) { case 1: /* connecton handle */ if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff) return (USAGE); cp.con_handle = (n & 0x0fff); cp.con_handle = htole16(cp.con_handle); break; default: return (USAGE); } /* send request and expect status response */ n = sizeof(b); if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_READ_CLOCK_OFFSET), (char const *) &cp, sizeof(cp), b, &n) == ERROR) return (ERROR); if (*b != 0x00) return (FAILED); /* wait for event */ again: n = sizeof(b); if (hci_recv(s, b, &n) == ERROR) return (ERROR); if (n < sizeof(*e)) { errno = EIO; return (ERROR); } if (e->event == NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL) { ng_hci_read_clock_offset_compl_ep *ep = (ng_hci_read_clock_offset_compl_ep *)(e + 1); if (ep->status != 0x00) { fprintf(stdout, "Status: %s [%#02x]\n", hci_status2str(ep->status), ep->status); return (FAILED); } fprintf(stdout, "Connection handle: %d\n", le16toh(ep->con_handle)); fprintf(stdout, "Clock offset: %#04x\n", le16toh(ep->clock_offset)); } else goto again; return (OK); } /* hci_read_clock_offset */ struct hci_command link_control_commands[] = { { "inquiry ", "\nThis command will cause the Bluetooth unit to enter Inquiry Mode.\n" \ "Inquiry Mode is used to discover other nearby Bluetooth units. The LAP\n" \ "input parameter contains the LAP from which the inquiry access code shall\n" \ "be derived when the inquiry procedure is made. The Inquiry_Length parameter\n"\ "specifies the total duration of the Inquiry Mode and, when this time\n" \ "expires, Inquiry will be halted. The Num_Responses parameter specifies the\n" \ "number of responses that can be received before the Inquiry is halted.\n\n" \ "\t - xx:xx:xx; 9e:8b:33 (GIAC), 93:8b:00 (LDIAC)\n" \ "\t - dd; total length == dd * 1.28 sec\n" \ "\t - dd", &hci_inquiry }, { "create_connection ", "" \ "\t - xx:xx:xx:xx:xx:xx BD_ADDR or name\n\n" \ "\t - xxxx; packet type\n" \ "" \ "\t\tACL packets\n" \ "\t\t-----------\n" \ "\t\t0x0008 DM1\n" \ "\t\t0x0010 DH1\n" \ "\t\t0x0400 DM3\n" \ "\t\t0x0800 DH3\n" \ "\t\t0x4000 DM5\n" \ "\t\t0x8000 DH5\n\n" \ "" \ "\trep_mode - d; page scan repetition mode\n" \ "" \ "\t\tPage scan repetition modes\n" \ "\t\t--------------------------\n" \ "\t\t0 Page scan repetition mode 0\n" \ "\t\t1 Page scan repetition mode 1\n" \ "\t\t2 Page scan repetition mode 2\n" \ "\n" \ "\tps_mode - d; Page scan mode\n" \ "" \ "\t\tPage scan modes\n" \ "\t\t---------------\n" \ "\t\t0 Mandatory page scan mode\n" \ "\t\t1 Optional page scan mode1\n" \ "\t\t2 Optional page scan mode2\n" \ "\t\t3 Optional page scan mode3\n" \ "\n" \ "\tclck_off - dddd; clock offset. Use 0 if unknown\n\n" \ "\trole_sw - d; allow (1) or deny role switch\n", &hci_create_connection }, { "disconnect ", "\nThe Disconnection command is used to terminate an existing connection.\n" \ "The connection handle command parameter indicates which connection is to\n" \ "be disconnected. The Reason command parameter indicates the reason for\n" \ "ending the connection.\n\n" \ "\t - dddd; connection handle\n" \ "\t - dd; reason; usually 19 (0x13) - user ended;\n" \ "\t also 0x05, 0x13-0x15, 0x1A, 0x29", &hci_disconnect }, { "add_sco_connection ", "This command will cause the link manager to create a SCO connection using\n" \ "the ACL connection specified by the connection handle command parameter.\n" \ "The Link Manager will determine how the new connection is established. This\n"\ "connection is determined by the current state of the device, its piconet,\n" \ "and the state of the device to be connected. The packet type command parameter\n" \ "specifies which packet types the Link Manager should use for the connection.\n"\ "The Link Manager must only use the packet type(s) specified by the packet\n" \ "type command parameter for sending HCI SCO data packets. Multiple packet\n" \ "types may be specified for the packet type command parameter by performing\n" \ "a bitwise OR operation of the different packet types. Note: An SCO connection\n" \ "can only be created when an ACL connection already exists and when it is\n" \ "not put in park mode.\n\n" \ "\t - dddd; ACL connection handle\n" \ "\t - xxxx; packet type\n" \ "" \ "\t\tSCO packets\n" \ "\t\t-----------\n" \ "\t\t0x0020 HV1\n" \ "\t\t0x0040 HV2\n" \ "\t\t0x0080 HV3\n", &hci_add_sco_connection }, { "change_connection_packet_type ", "The Change_Connection_Packet_Type command is used to change which packet\n" \ "types can be used for a connection that is currently established. This\n" \ "allows current connections to be dynamically modified to support different\n" \ "types of user data. The Packet_Type command parameter specifies which\n" \ "packet types the Link Manager can use for the connection. Multiple packet\n" \ "types may be specified for the Packet_Type command parameter by bitwise OR\n" \ "operation of the different packet types.\n\n" \ "\t - dddd; connection handle\n" \ "\t - xxxx; packet type mask\n" \ "" \ "\t\tACL packets\n" \ "\t\t-----------\n" \ "\t\t0x0008 DM1\n" \ "\t\t0x0010 DH1\n" \ "\t\t0x0400 DM3\n" \ "\t\t0x0800 DH3\n" \ "\t\t0x4000 DM5\n" \ "\t\t0x8000 DH5\n\n" \ "" \ "\t\tSCO packets\n" \ "\t\t-----------\n" \ "\t\t0x0020 HV1\n" \ "\t\t0x0040 HV2\n" \ "\t\t0x0080 HV3\n" \ "", &hci_change_connection_packet_type }, { "remote_name_request ", "\nThe Remote_Name_Request command is used to obtain the user-friendly\n" \ "name of another Bluetooth unit.\n\n" \ "\t - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \ "\t - dd; page scan repetition mode [0-2]\n" \ "\t - dd; page scan mode [0-3]\n" \ "\t - xxxx; clock offset [0 - 0xffff]", &hci_remote_name_request }, { "read_remote_supported_features ", "\nThis command requests a list of the supported features for the remote\n" \ "unit identified by the connection handle parameter. The connection handle\n" \ "must be a connection handle for an ACL connection.\n\n" \ "\t - dddd; connection handle", &hci_read_remote_supported_features }, { "read_remote_version_information ", "\nThis command will obtain the values for the version information for the\n" \ "remote Bluetooth unit identified by the connection handle parameter. The\n" \ "connection handle must be a connection handle for an ACL connection.\n\n" \ "\t - dddd; connection handle", &hci_read_remote_version_information }, { "read_clock_offset ", "\nThis command allows the Host to read the clock offset from the remote unit.\n" \ "\t - dddd; connection handle", &hci_read_clock_offset }, { NULL, }}; Index: head/usr.sbin/bluetooth/hcsecd/hcsecd.c =================================================================== --- head/usr.sbin/bluetooth/hcsecd/hcsecd.c (revision 162528) +++ head/usr.sbin/bluetooth/hcsecd/hcsecd.c (revision 162529) @@ -1,447 +1,447 @@ /* * hcsecd.c * * Copyright (c) 2001-2002 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: hcsecd.c,v 1.6 2003/08/18 19:19:55 max Exp $ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include "hcsecd.h" static int done = 0; static int process_pin_code_request_event (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr); static int process_link_key_request_event (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr); static int send_pin_code_reply (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, char const *pin); static int send_link_key_reply (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, uint8_t *key); static int process_link_key_notification_event (int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep); static void sighup (int s); static void sigint (int s); static void usage (void); /* Main */ int main(int argc, char *argv[]) { int n, detach, sock; socklen_t size; struct sigaction sa; struct sockaddr_hci addr; struct ng_btsocket_hci_raw_filter filter; char buffer[HCSECD_BUFFER_SIZE]; ng_hci_event_pkt_t *event = NULL; detach = 1; while ((n = getopt(argc, argv, "df:h")) != -1) { switch (n) { case 'd': detach = 0; break; case 'f': config_file = optarg; break; case 'h': default: usage(); /* NOT REACHED */ } } if (config_file == NULL) usage(); /* NOT REACHED */ if (getuid() != 0) errx(1, "** ERROR: You should run %s as privileged user!", HCSECD_IDENT); /* Set signal handlers */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigint; sa.sa_flags = SA_NOCLDWAIT; if (sigaction(SIGINT, &sa, NULL) < 0) err(1, "Could not sigaction(SIGINT)"); if (sigaction(SIGTERM, &sa, NULL) < 0) err(1, "Could not sigaction(SIGINT)"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sighup; if (sigaction(SIGHUP, &sa, NULL) < 0) err(1, "Could not sigaction(SIGHUP)"); /* Open socket and set filter */ sock = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); if (sock < 0) err(1, "Could not create HCI socket"); memset(&filter, 0, sizeof(filter)); bit_set(filter.event_mask, NG_HCI_EVENT_PIN_CODE_REQ - 1); bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_REQ - 1); bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1); if (setsockopt(sock, SOL_HCI_RAW, SO_HCI_RAW_FILTER, (void * const) &filter, sizeof(filter)) < 0) err(1, "Could not set HCI socket filter"); if (detach) if (daemon(0, 0) < 0) err(1, "Could not daemon()ize"); openlog(HCSECD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON); read_config_file(); read_keys_file(); if (detach) { FILE *pid = NULL; if ((pid = fopen(HCSECD_PIDFILE, "w")) == NULL) { syslog(LOG_ERR, "Could not create PID file %s. %s (%d)", HCSECD_PIDFILE, strerror(errno), errno); exit(1); } fprintf(pid, "%d", getpid()); fclose(pid); } event = (ng_hci_event_pkt_t *) buffer; while (!done) { size = sizeof(addr); n = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &addr, &size); if (n < 0) { if (errno == EINTR) continue; syslog(LOG_ERR, "Could not receive from HCI socket. " \ "%s (%d)", strerror(errno), errno); exit(1); } if (event->type != NG_HCI_EVENT_PKT) { syslog(LOG_ERR, "Received unexpected HCI packet, " \ "type=%#x", event->type); continue; } switch (event->event) { case NG_HCI_EVENT_PIN_CODE_REQ: process_pin_code_request_event(sock, &addr, (bdaddr_p)(event + 1)); break; case NG_HCI_EVENT_LINK_KEY_REQ: process_link_key_request_event(sock, &addr, (bdaddr_p)(event + 1)); break; case NG_HCI_EVENT_LINK_KEY_NOTIFICATION: process_link_key_notification_event(sock, &addr, (ng_hci_link_key_notification_ep *)(event + 1)); break; default: syslog(LOG_ERR, "Received unexpected HCI event, " \ "event=%#x", event->event); break; } } if (detach) if (remove(HCSECD_PIDFILE) < 0) syslog(LOG_ERR, "Could not remove PID file %s. %s (%d)", HCSECD_PIDFILE, strerror(errno), errno); dump_keys_file(); clean_config(); closelog(); close(sock); return (0); } /* Process PIN_Code_Request event */ static int process_pin_code_request_event(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr) { link_key_p key = NULL; syslog(LOG_DEBUG, "Got PIN_Code_Request event from '%s', " \ "remote bdaddr %s", addr->hci_node, bt_ntoa(bdaddr, NULL)); if ((key = get_key(bdaddr, 0)) != NULL) { syslog(LOG_DEBUG, "Found matching entry, " \ "remote bdaddr %s, name '%s', PIN code %s", bt_ntoa(&key->bdaddr, NULL), (key->name != NULL)? key->name : "No name", (key->pin != NULL)? "exists" : "doesn't exist"); return (send_pin_code_reply(sock, addr, bdaddr, key->pin)); } syslog(LOG_DEBUG, "Could not PIN code for remote bdaddr %s", bt_ntoa(bdaddr, NULL)); return (send_pin_code_reply(sock, addr, bdaddr, NULL)); } /* Process Link_Key_Request event */ static int process_link_key_request_event(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr) { link_key_p key = NULL; syslog(LOG_DEBUG, "Got Link_Key_Request event from '%s', " \ "remote bdaddr %s", addr->hci_node, bt_ntoa(bdaddr, NULL)); if ((key = get_key(bdaddr, 0)) != NULL) { syslog(LOG_DEBUG, "Found matching entry, " \ "remote bdaddr %s, name '%s', link key %s", bt_ntoa(&key->bdaddr, NULL), (key->name != NULL)? key->name : "No name", (key->key != NULL)? "exists" : "doesn't exist"); return (send_link_key_reply(sock, addr, bdaddr, key->key)); } syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s", bt_ntoa(bdaddr, NULL)); return (send_link_key_reply(sock, addr, bdaddr, NULL)); } /* Send PIN_Code_[Negative]_Reply */ static int send_pin_code_reply(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, char const *pin) { uint8_t buffer[HCSECD_BUFFER_SIZE]; ng_hci_cmd_pkt_t *cmd = NULL; memset(buffer, 0, sizeof(buffer)); cmd = (ng_hci_cmd_pkt_t *) buffer; cmd->type = NG_HCI_CMD_PKT; if (pin != NULL) { ng_hci_pin_code_rep_cp *cp = NULL; cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_PIN_CODE_REP)); cmd->length = sizeof(*cp); cp = (ng_hci_pin_code_rep_cp *)(cmd + 1); memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr)); - strncpy(cp->pin, pin, sizeof(cp->pin)); - cp->pin_size = strlen(cp->pin); + strncpy((char *) cp->pin, pin, sizeof(cp->pin)); + cp->pin_size = strlen((char const *) cp->pin); syslog(LOG_DEBUG, "Sending PIN_Code_Reply to '%s' " \ "for remote bdaddr %s", addr->hci_node, bt_ntoa(bdaddr, NULL)); } else { ng_hci_pin_code_neg_rep_cp *cp = NULL; cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_PIN_CODE_NEG_REP)); cmd->length = sizeof(*cp); cp = (ng_hci_pin_code_neg_rep_cp *)(cmd + 1); memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr)); syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to '%s' " \ "for remote bdaddr %s", addr->hci_node, bt_ntoa(bdaddr, NULL)); } again: if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, (struct sockaddr *) addr, sizeof(*addr)) < 0) { if (errno == EINTR) goto again; syslog(LOG_ERR, "Could not send PIN code reply to '%s' " \ "for remote bdaddr %s. %s (%d)", addr->hci_node, bt_ntoa(bdaddr, NULL), strerror(errno), errno); return (-1); } return (0); } /* Send Link_Key_[Negative]_Reply */ static int send_link_key_reply(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, uint8_t *key) { uint8_t buffer[HCSECD_BUFFER_SIZE]; ng_hci_cmd_pkt_t *cmd = NULL; memset(buffer, 0, sizeof(buffer)); cmd = (ng_hci_cmd_pkt_t *) buffer; cmd->type = NG_HCI_CMD_PKT; if (key != NULL) { ng_hci_link_key_rep_cp *cp = NULL; cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_LINK_KEY_REP)); cmd->length = sizeof(*cp); cp = (ng_hci_link_key_rep_cp *)(cmd + 1); memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr)); memcpy(&cp->key, key, sizeof(cp->key)); syslog(LOG_DEBUG, "Sending Link_Key_Reply to '%s' " \ "for remote bdaddr %s", addr->hci_node, bt_ntoa(bdaddr, NULL)); } else { ng_hci_link_key_neg_rep_cp *cp = NULL; cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_LINK_KEY_NEG_REP)); cmd->length = sizeof(*cp); cp = (ng_hci_link_key_neg_rep_cp *)(cmd + 1); memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr)); syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to '%s' " \ "for remote bdaddr %s", addr->hci_node, bt_ntoa(bdaddr, NULL)); } again: if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, (struct sockaddr *) addr, sizeof(*addr)) < 0) { if (errno == EINTR) goto again; syslog(LOG_ERR, "Could not send link key reply to '%s' " \ "for remote bdaddr %s. %s (%d)", addr->hci_node, bt_ntoa(bdaddr, NULL), strerror(errno), errno); return (-1); } return (0); } /* Process Link_Key_Notification event */ static int process_link_key_notification_event(int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep) { link_key_p key = NULL; syslog(LOG_DEBUG, "Got Link_Key_Notification event from '%s', " \ "remote bdaddr %s", addr->hci_node, bt_ntoa(&ep->bdaddr, NULL)); if ((key = get_key(&ep->bdaddr, 1)) == NULL) { syslog(LOG_ERR, "Could not find entry for remote bdaddr %s", bt_ntoa(&ep->bdaddr, NULL)); return (-1); } syslog(LOG_DEBUG, "Updating link key for the entry, " \ "remote bdaddr %s, name '%s', link key %s", bt_ntoa(&key->bdaddr, NULL), (key->name != NULL)? key->name : "No name", (key->key != NULL)? "exists" : "doesn't exist"); if (key->key == NULL) { key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE); if (key->key == NULL) { syslog(LOG_ERR, "Could not allocate link key"); exit(1); } } memcpy(key->key, &ep->key, NG_HCI_KEY_SIZE); return (0); } /* Signal handlers */ static void sighup(int s) { syslog(LOG_DEBUG, "Got SIGHUP (%d)", s); dump_keys_file(); read_config_file(); read_keys_file(); } static void sigint(int s) { syslog(LOG_DEBUG, "Got signal %d, total number of signals %d", s, ++ done); } /* Display usage and exit */ static void usage(void) { fprintf(stderr, "Usage: %s [-d] -f config_file [-h]\n" \ "Where:\n" \ "\t-d do not detach from terminal\n" \ "\t-f config_file use \n" \ "\t-h display this message\n", HCSECD_IDENT); exit(255); }