1128080Semax%{ 2128080Semax/* 3128080Semax * parser.y 4162128Semax */ 5162128Semax 6162128Semax/*- 7330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 8330449Seadler * 9162128Semax * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com> 10128080Semax * All rights reserved. 11128080Semax * 12128080Semax * Redistribution and use in source and binary forms, with or without 13128080Semax * modification, are permitted provided that the following conditions 14128080Semax * are met: 15128080Semax * 1. Redistributions of source code must retain the above copyright 16128080Semax * notice, this list of conditions and the following disclaimer. 17128080Semax * 2. Redistributions in binary form must reproduce the above copyright 18128080Semax * notice, this list of conditions and the following disclaimer in the 19128080Semax * documentation and/or other materials provided with the distribution. 20128080Semax * 21128080Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22128080Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23128080Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24128080Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25128080Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26128080Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27128080Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28128080Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29128080Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30128080Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31128080Semax * SUCH DAMAGE. 32128080Semax * 33162128Semax * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $ 34128080Semax * $FreeBSD: stable/11/usr.sbin/bluetooth/bthidd/parser.y 330449 2018-03-05 07:26:05Z eadler $ 35128080Semax */ 36128080Semax 37128080Semax#include <sys/queue.h> 38281210Stakawata#define L2CAP_SOCKET_CHECKED 39128080Semax#include <bluetooth.h> 40162128Semax#include <dev/usb/usb.h> 41162128Semax#include <dev/usb/usbhid.h> 42128080Semax#include <errno.h> 43128080Semax#include <limits.h> 44128080Semax#include <stdio.h> 45235789Sbapt#include <stdlib.h> 46128080Semax#include <string.h> 47128080Semax#include <unistd.h> 48137868Semax#include <usbhid.h> 49128080Semax 50128080Semax#ifndef BTHIDCONTROL 51128080Semax#include <stdarg.h> 52128080Semax#include <syslog.h> 53128080Semax#define SYSLOG syslog 54128080Semax#define LOGCRIT LOG_CRIT 55128080Semax#define LOGERR LOG_ERR 56128080Semax#define LOGWARNING LOG_WARNING 57128080Semax#define EOL 58128080Semax#else 59128080Semax#define SYSLOG fprintf 60128080Semax#define LOGCRIT stderr 61128080Semax#define LOGERR stderr 62128080Semax#define LOGWARNING stderr 63137868Semax#define EOL "\n" 64128080Semax#endif /* ndef BTHIDCONTROL */ 65128080Semax 66128080Semax#include "bthid_config.h" 67128080Semax 68128080Semax int yylex (void); 69162128Semax void yyerror (char const *); 70162128Semaxstatic int32_t check_hid_device(hid_device_p hid_device); 71128080Semaxstatic void free_hid_device (hid_device_p hid_device); 72128080Semax 73162128Semaxextern FILE *yyin; 74128080Semaxextern int yylineno; 75162128Semax char const *config_file = BTHIDD_CONFFILE; 76162128Semax char const *hids_file = BTHIDD_HIDSFILE; 77128080Semax 78128080Semaxstatic char buffer[1024]; 79162128Semaxstatic int32_t hid_descriptor_size; 80128080Semaxstatic hid_device_t *hid_device = NULL; 81128080Semaxstatic LIST_HEAD(, hid_device) hid_devices; 82128080Semax 83128080Semax%} 84128080Semax 85128080Semax%union { 86128080Semax bdaddr_t bdaddr; 87162128Semax int32_t num; 88128080Semax} 89128080Semax 90128080Semax%token <bdaddr> T_BDADDRSTRING 91128080Semax%token <num> T_HEXBYTE 92128080Semax%token T_DEVICE T_BDADDR T_CONTROL_PSM T_INTERRUPT_PSM T_RECONNECT_INITIATE 93128080Semax%token T_BATTERY_POWER T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR 94128080Semax%token T_TRUE T_FALSE T_ERROR 95128080Semax 96128080Semax%% 97128080Semax 98128080Semaxconfig: line 99128080Semax | config line 100128080Semax ; 101128080Semax 102128080Semaxline: T_DEVICE 103128080Semax { 104128080Semax hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device)); 105128080Semax if (hid_device == NULL) { 106128080Semax SYSLOG(LOGCRIT, "Could not allocate new " \ 107128080Semax "config entry" EOL); 108128080Semax YYABORT; 109128080Semax } 110128080Semax 111128080Semax hid_device->new_device = 1; 112128080Semax } 113128080Semax '{' options '}' 114128080Semax { 115128080Semax if (check_hid_device(hid_device)) 116128080Semax LIST_INSERT_HEAD(&hid_devices,hid_device,next); 117128080Semax else 118128080Semax free_hid_device(hid_device); 119128080Semax 120128080Semax hid_device = NULL; 121128080Semax } 122128080Semax ; 123128080Semax 124128080Semaxoptions: option ';' 125128080Semax | options option ';' 126128080Semax ; 127128080Semax 128128080Semaxoption: bdaddr 129128080Semax | control_psm 130128080Semax | interrupt_psm 131128080Semax | reconnect_initiate 132128080Semax | battery_power 133128080Semax | normally_connectable 134128080Semax | hid_descriptor 135128080Semax | parser_error 136128080Semax ; 137128080Semax 138128080Semaxbdaddr: T_BDADDR T_BDADDRSTRING 139128080Semax { 140128080Semax memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr)); 141128080Semax } 142128080Semax ; 143128080Semax 144128080Semaxcontrol_psm: T_CONTROL_PSM T_HEXBYTE 145128080Semax { 146128080Semax hid_device->control_psm = $2; 147128080Semax } 148128080Semax ; 149128080Semax 150128080Semaxinterrupt_psm: T_INTERRUPT_PSM T_HEXBYTE 151128080Semax { 152128080Semax hid_device->interrupt_psm = $2; 153128080Semax } 154128080Semax ; 155128080Semax 156128080Semaxreconnect_initiate: T_RECONNECT_INITIATE T_TRUE 157128080Semax { 158128080Semax hid_device->reconnect_initiate = 1; 159128080Semax } 160128080Semax | T_RECONNECT_INITIATE T_FALSE 161128080Semax { 162128080Semax hid_device->reconnect_initiate = 0; 163128080Semax } 164128080Semax ; 165128080Semax 166128080Semaxbattery_power: T_BATTERY_POWER T_TRUE 167128080Semax { 168128080Semax hid_device->battery_power = 1; 169128080Semax } 170128080Semax | T_BATTERY_POWER T_FALSE 171128080Semax { 172128080Semax hid_device->battery_power = 0; 173128080Semax } 174128080Semax ; 175128080Semax 176128080Semaxnormally_connectable: T_NORMALLY_CONNECTABLE T_TRUE 177128080Semax { 178128080Semax hid_device->normally_connectable = 1; 179128080Semax } 180128080Semax | T_NORMALLY_CONNECTABLE T_FALSE 181128080Semax { 182128080Semax hid_device->normally_connectable = 0; 183128080Semax } 184128080Semax ; 185128080Semax 186128080Semaxhid_descriptor: T_HID_DESCRIPTOR 187128080Semax { 188128080Semax hid_descriptor_size = 0; 189128080Semax } 190128080Semax '{' hid_descriptor_bytes '}' 191128080Semax { 192128080Semax if (hid_device->desc != NULL) 193128080Semax hid_dispose_report_desc(hid_device->desc); 194128080Semax 195162529Semax hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size); 196128080Semax if (hid_device->desc == NULL) { 197128080Semax SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL); 198128080Semax YYABORT; 199128080Semax } 200128080Semax } 201128080Semax ; 202128080Semax 203128080Semaxhid_descriptor_bytes: hid_descriptor_byte 204128080Semax | hid_descriptor_bytes hid_descriptor_byte 205128080Semax ; 206128080Semax 207128080Semaxhid_descriptor_byte: T_HEXBYTE 208128080Semax { 209162128Semax if (hid_descriptor_size >= (int32_t) sizeof(buffer)) { 210128080Semax SYSLOG(LOGCRIT, "HID descriptor is too big" EOL); 211128080Semax YYABORT; 212128080Semax } 213128080Semax 214128080Semax buffer[hid_descriptor_size ++] = $1; 215128080Semax } 216128080Semax ; 217128080Semax 218128080Semaxparser_error: T_ERROR 219128080Semax { 220128080Semax YYABORT; 221128080Semax } 222128080Semax 223128080Semax%% 224128080Semax 225128080Semax/* Display parser error message */ 226128080Semaxvoid 227128080Semaxyyerror(char const *message) 228128080Semax{ 229128080Semax SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno); 230128080Semax} 231128080Semax 232128080Semax/* Re-read config file */ 233162128Semaxint32_t 234128080Semaxread_config_file(void) 235128080Semax{ 236162128Semax int32_t e; 237128080Semax 238128080Semax if (config_file == NULL) { 239128080Semax SYSLOG(LOGERR, "Unknown config file name!" EOL); 240128080Semax return (-1); 241128080Semax } 242128080Semax 243128080Semax if ((yyin = fopen(config_file, "r")) == NULL) { 244128080Semax SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL, 245128080Semax config_file, strerror(errno), errno); 246128080Semax return (-1); 247128080Semax } 248128080Semax 249128080Semax clean_config(); 250128080Semax if (yyparse() < 0) { 251128080Semax SYSLOG(LOGERR, "Could not parse config file '%s'" EOL, 252128080Semax config_file); 253128080Semax e = -1; 254128080Semax } else 255128080Semax e = 0; 256128080Semax 257128080Semax fclose(yyin); 258128080Semax yyin = NULL; 259128080Semax 260128080Semax return (e); 261128080Semax} 262128080Semax 263128080Semax/* Clean config */ 264128080Semaxvoid 265128080Semaxclean_config(void) 266128080Semax{ 267128080Semax while (!LIST_EMPTY(&hid_devices)) { 268162128Semax hid_device_p d = LIST_FIRST(&hid_devices); 269128080Semax 270162128Semax LIST_REMOVE(d, next); 271162128Semax free_hid_device(d); 272128080Semax } 273128080Semax} 274128080Semax 275128080Semax/* Lookup config entry */ 276128080Semaxhid_device_p 277128080Semaxget_hid_device(bdaddr_p bdaddr) 278128080Semax{ 279162128Semax hid_device_p d; 280128080Semax 281162128Semax LIST_FOREACH(d, &hid_devices, next) 282162128Semax if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0) 283128080Semax break; 284128080Semax 285162128Semax return (d); 286128080Semax} 287128080Semax 288128080Semax/* Get next config entry */ 289128080Semaxhid_device_p 290128080Semaxget_next_hid_device(hid_device_p d) 291128080Semax{ 292128080Semax return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next)); 293128080Semax} 294128080Semax 295128080Semax/* Print config entry */ 296128080Semaxvoid 297162128Semaxprint_hid_device(hid_device_p d, FILE *f) 298128080Semax{ 299128080Semax /* XXX FIXME hack! */ 300128080Semax struct report_desc { 301128080Semax unsigned int size; 302128080Semax unsigned char data[1]; 303128080Semax }; 304128080Semax /* XXX FIXME hack! */ 305128080Semax 306162128Semax struct report_desc *desc = (struct report_desc *) d->desc; 307162128Semax uint32_t i; 308128080Semax 309128080Semax fprintf(f, 310128080Semax"device {\n" \ 311128080Semax" bdaddr %s;\n" \ 312128080Semax" control_psm 0x%x;\n" \ 313140130Semax" interrupt_psm 0x%x;\n" \ 314128080Semax" reconnect_initiate %s;\n" \ 315128080Semax" battery_power %s;\n" \ 316128080Semax" normally_connectable %s;\n" \ 317128080Semax" hid_descriptor {", 318162128Semax bt_ntoa(&d->bdaddr, NULL), 319162128Semax d->control_psm, d->interrupt_psm, 320162128Semax d->reconnect_initiate? "true" : "false", 321162128Semax d->battery_power? "true" : "false", 322162128Semax d->normally_connectable? "true" : "false"); 323128080Semax 324128080Semax for (i = 0; i < desc->size; i ++) { 325128080Semax if ((i % 8) == 0) 326146357Semax fprintf(f, "\n "); 327128080Semax 328128080Semax fprintf(f, "0x%2.2x ", desc->data[i]); 329128080Semax } 330128080Semax 331146357Semax fprintf(f, 332128080Semax"\n" \ 333128080Semax" };\n" \ 334128080Semax"}\n"); 335128080Semax} 336128080Semax 337128080Semax/* Check config entry */ 338162128Semaxstatic int32_t 339162128Semaxcheck_hid_device(hid_device_p d) 340128080Semax{ 341162128Semax hid_data_t hd; 342162128Semax hid_item_t hi; 343162128Semax int32_t page; 344162128Semax 345162128Semax if (get_hid_device(&d->bdaddr) != NULL) { 346128080Semax SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL, 347162128Semax bt_ntoa(&d->bdaddr, NULL)); 348128080Semax return (0); 349128080Semax } 350128080Semax 351162128Semax if (d->control_psm == 0) { 352128080Semax SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL); 353128080Semax return (0); 354128080Semax } 355128080Semax 356162128Semax if (d->interrupt_psm == 0) { 357128080Semax SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL); 358128080Semax return (0); 359128080Semax } 360128080Semax 361162128Semax if (d->desc == NULL) { 362128080Semax SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL); 363128080Semax return (0); 364128080Semax } 365128080Semax 366162128Semax /* XXX somehow need to make sure descriptor is valid */ 367162128Semax for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) { 368162128Semax switch (hi.kind) { 369162128Semax case hid_collection: 370162128Semax case hid_endcollection: 371162128Semax case hid_output: 372162128Semax case hid_feature: 373162128Semax break; 374162128Semax 375162128Semax case hid_input: 376162128Semax /* Check if the device may send keystrokes */ 377162128Semax page = HID_PAGE(hi.usage); 378164700Semax if (page == HUP_KEYBOARD) 379162128Semax d->keyboard = 1; 380162128Semax break; 381162128Semax } 382162128Semax } 383162128Semax hid_end_parse(hd); 384162128Semax 385128080Semax return (1); 386128080Semax} 387128080Semax 388128080Semax/* Free config entry */ 389128080Semaxstatic void 390162128Semaxfree_hid_device(hid_device_p d) 391128080Semax{ 392162128Semax if (d->desc != NULL) 393162128Semax hid_dispose_report_desc(d->desc); 394128080Semax 395162128Semax memset(d, 0, sizeof(*d)); 396162128Semax free(d); 397128080Semax} 398128080Semax 399128080Semax/* Re-read hids file */ 400162128Semaxint32_t 401128080Semaxread_hids_file(void) 402128080Semax{ 403162128Semax FILE *f; 404162128Semax hid_device_t *d; 405162128Semax char *line; 406128080Semax bdaddr_t bdaddr; 407162128Semax int32_t lineno; 408128080Semax 409128080Semax if (hids_file == NULL) { 410128080Semax SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 411128080Semax return (-1); 412128080Semax } 413128080Semax 414128080Semax if ((f = fopen(hids_file, "r")) == NULL) { 415128080Semax if (errno == ENOENT) 416128080Semax return (0); 417128080Semax 418128080Semax SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 419128080Semax hids_file, strerror(errno), errno); 420128080Semax return (-1); 421128080Semax } 422128080Semax 423128080Semax for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) { 424128080Semax if ((line = strtok(buffer, "\r\n\t ")) == NULL) 425128080Semax continue; /* ignore empty lines */ 426128080Semax 427128080Semax if (!bt_aton(line, &bdaddr)) { 428128080Semax SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \ 429128080Semax "%s:%d" EOL, hids_file, lineno); 430128080Semax continue; 431128080Semax } 432128080Semax 433162128Semax if ((d = get_hid_device(&bdaddr)) != NULL) 434162128Semax d->new_device = 0; 435128080Semax } 436128080Semax 437128080Semax fclose(f); 438128080Semax 439128080Semax return (0); 440128080Semax} 441128080Semax 442128080Semax/* Write hids file */ 443162128Semaxint32_t 444128080Semaxwrite_hids_file(void) 445128080Semax{ 446128080Semax char path[PATH_MAX]; 447162128Semax FILE *f; 448162128Semax hid_device_t *d; 449128080Semax 450128080Semax if (hids_file == NULL) { 451128080Semax SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 452128080Semax return (-1); 453128080Semax } 454128080Semax 455128080Semax snprintf(path, sizeof(path), "%s.new", hids_file); 456128080Semax 457128080Semax if ((f = fopen(path, "w")) == NULL) { 458128080Semax SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 459128080Semax path, strerror(errno), errno); 460128080Semax return (-1); 461128080Semax } 462128080Semax 463162128Semax LIST_FOREACH(d, &hid_devices, next) 464162128Semax if (!d->new_device) 465162128Semax fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL)); 466128080Semax 467128080Semax fclose(f); 468128080Semax 469128080Semax if (rename(path, hids_file) < 0) { 470128080Semax SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \ 471128080Semax "%s (%d)" EOL, path, hids_file, strerror(errno), errno); 472128080Semax unlink(path); 473128080Semax return (-1); 474128080Semax } 475128080Semax 476128080Semax return (0); 477128080Semax} 478128080Semax 479