parser.y revision 330449
11573Srgrimes%{ 23070Spst/* 31573Srgrimes * parser.y 41573Srgrimes */ 51573Srgrimes 61573Srgrimes/*- 71573Srgrimes * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 81573Srgrimes * 91573Srgrimes * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com> 101573Srgrimes * All rights reserved. 111573Srgrimes * 121573Srgrimes * Redistribution and use in source and binary forms, with or without 133070Spst * modification, are permitted provided that the following conditions 141573Srgrimes * are met: 151573Srgrimes * 1. Redistributions of source code must retain the above copyright 161573Srgrimes * notice, this list of conditions and the following disclaimer. 171573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 181573Srgrimes * notice, this list of conditions and the following disclaimer in the 191573Srgrimes * documentation and/or other materials provided with the distribution. 201573Srgrimes * 211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2692986Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2792986Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29113977Snectar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30145633Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311573Srgrimes * SUCH DAMAGE. 321573Srgrimes * 331573Srgrimes * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $ 341573Srgrimes * $FreeBSD: stable/11/usr.sbin/bluetooth/bthidd/parser.y 330449 2018-03-05 07:26:05Z eadler $ 351573Srgrimes */ 361573Srgrimes 371573Srgrimes#include <sys/queue.h> 38145512Sume#define L2CAP_SOCKET_CHECKED 39145633Sume#include <bluetooth.h> 401573Srgrimes#include <dev/usb/usb.h> 4165532Snectar#include <dev/usb/usbhid.h> 4265532Snectar#include <errno.h> 4317903Speter#include <limits.h> 4417903Speter#include <stdio.h> 45113977Snectar#include <stdlib.h> 46145602Sume#include <string.h> 47158115Sume#include <unistd.h> 48158115Sume#include <usbhid.h> 49158115Sume 501573Srgrimes#ifndef BTHIDCONTROL 5165532Snectar#include <stdarg.h> 5265532Snectar#include <syslog.h> 5365532Snectar#define SYSLOG syslog 5465532Snectar#define LOGCRIT LOG_CRIT 5565532Snectar#define LOGERR LOG_ERR 5665532Snectar#define LOGWARNING LOG_WARNING 571991Swollman#define EOL 58157779Sume#else 59157779Sume#define SYSLOG fprintf 60145512Sume#define LOGCRIT stderr 6165532Snectar#define LOGERR stderr 62145512Sume#define LOGWARNING stderr 6365532Snectar#define EOL "\n" 6465532Snectar#endif /* ndef BTHIDCONTROL */ 6565532Snectar 661991Swollman#include "bthid_config.h" 67158115Sume 68158115Sume int yylex (void); 69158115Sume void yyerror (char const *); 70158115Sumestatic int32_t check_hid_device(hid_device_p hid_device); 71158115Sumestatic void free_hid_device (hid_device_p hid_device); 721991Swollman 73157779Sumeextern FILE *yyin; 74157779Sumeextern int yylineno; 75157779Sume char const *config_file = BTHIDD_CONFFILE; 76145633Sume char const *hids_file = BTHIDD_HIDSFILE; 77145633Sume 78157779Sumestatic char buffer[1024]; 791991Swollmanstatic int32_t hid_descriptor_size; 80157779Sumestatic hid_device_t *hid_device = NULL; 81157779Sumestatic LIST_HEAD(, hid_device) hid_devices; 8217903Speter 83157779Sume%} 84157779Sume 85157779Sume%union { 86157779Sume bdaddr_t bdaddr; 87157779Sume int32_t num; 88157779Sume} 89145633Sume 90157779Sume%token <bdaddr> T_BDADDRSTRING 91157779Sume%token <num> T_HEXBYTE 92157779Sume%token T_DEVICE T_BDADDR T_CONTROL_PSM T_INTERRUPT_PSM T_RECONNECT_INITIATE 93145633Sume%token T_BATTERY_POWER T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR 94145633Sume%token T_TRUE T_FALSE T_ERROR 95145633Sume 96157779Sume%% 97145633Sume 98157779Sumeconfig: line 99145633Sume | config line 100145633Sume ; 101157779Sume 102157779Sumeline: T_DEVICE 103157779Sume { 104145633Sume hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device)); 105157779Sume if (hid_device == NULL) { 106157779Sume SYSLOG(LOGCRIT, "Could not allocate new " \ 107157779Sume "config entry" EOL); 108157779Sume YYABORT; 109145633Sume } 110157779Sume 111157779Sume hid_device->new_device = 1; 112157779Sume } 113157779Sume '{' options '}' 114157779Sume { 115157779Sume if (check_hid_device(hid_device)) 116157779Sume LIST_INSERT_HEAD(&hid_devices,hid_device,next); 117157779Sume else 118157779Sume free_hid_device(hid_device); 119157779Sume 120157779Sume hid_device = NULL; 121157779Sume } 122157779Sume ; 123157779Sume 124157779Sumeoptions: option ';' 125157779Sume | options option ';' 126157779Sume ; 127157779Sume 128157779Sumeoption: bdaddr 129157779Sume | control_psm 130157779Sume | interrupt_psm 131157779Sume | reconnect_initiate 132157779Sume | battery_power 133157779Sume | normally_connectable 134157779Sume | hid_descriptor 135157779Sume | parser_error 136157779Sume ; 137157779Sume 138157779Sumebdaddr: T_BDADDR T_BDADDRSTRING 139157779Sume { 140157779Sume memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr)); 141157779Sume } 142157779Sume ; 143157779Sume 144157779Sumecontrol_psm: T_CONTROL_PSM T_HEXBYTE 145157779Sume { 146157779Sume hid_device->control_psm = $2; 147157779Sume } 148157779Sume ; 149157779Sume 150157779Sumeinterrupt_psm: T_INTERRUPT_PSM T_HEXBYTE 151157779Sume { 152157779Sume hid_device->interrupt_psm = $2; 153157779Sume } 154157779Sume ; 155157779Sume 156157779Sumereconnect_initiate: T_RECONNECT_INITIATE T_TRUE 157157779Sume { 158157779Sume hid_device->reconnect_initiate = 1; 159157779Sume } 160157779Sume | T_RECONNECT_INITIATE T_FALSE 161145633Sume { 162145633Sume hid_device->reconnect_initiate = 0; 163158115Sume } 164157779Sume ; 165158115Sume 166158115Sumebattery_power: T_BATTERY_POWER T_TRUE 167158115Sume { 168158115Sume hid_device->battery_power = 1; 169158115Sume } 170158115Sume | T_BATTERY_POWER T_FALSE 171158115Sume { 172158791Sume hid_device->battery_power = 0; 173158791Sume } 174158791Sume ; 175158115Sume 176158115Sumenormally_connectable: T_NORMALLY_CONNECTABLE T_TRUE 177158115Sume { 178158115Sume hid_device->normally_connectable = 1; 179158115Sume } 180158115Sume | T_NORMALLY_CONNECTABLE T_FALSE 181158115Sume { 182158115Sume hid_device->normally_connectable = 0; 183158115Sume } 184158115Sume ; 185158115Sume 186158115Sumehid_descriptor: T_HID_DESCRIPTOR 187158115Sume { 188158115Sume hid_descriptor_size = 0; 189158115Sume } 190158115Sume '{' hid_descriptor_bytes '}' 191158115Sume { 192158115Sume if (hid_device->desc != NULL) 193158115Sume hid_dispose_report_desc(hid_device->desc); 194158115Sume 195158115Sume hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size); 196158115Sume if (hid_device->desc == NULL) { 197158115Sume SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL); 198158115Sume YYABORT; 199158115Sume } 200158115Sume } 201158115Sume ; 202158115Sume 203158115Sumehid_descriptor_bytes: hid_descriptor_byte 204158115Sume | hid_descriptor_bytes hid_descriptor_byte 205158115Sume ; 206158115Sume 207158115Sumehid_descriptor_byte: T_HEXBYTE 208158115Sume { 209158115Sume if (hid_descriptor_size >= (int32_t) sizeof(buffer)) { 210158115Sume SYSLOG(LOGCRIT, "HID descriptor is too big" EOL); 211158115Sume YYABORT; 212158115Sume } 213158115Sume 214158115Sume buffer[hid_descriptor_size ++] = $1; 215158115Sume } 216158115Sume ; 217158115Sume 218158115Sumeparser_error: T_ERROR 219158791Sume { 220158791Sume YYABORT; 221158115Sume } 222158115Sume 223158115Sume%% 224158791Sume 225158791Sume/* Display parser error message */ 226158115Sumevoid 227158115Sumeyyerror(char const *message) 228158115Sume{ 229158115Sume SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno); 230158115Sume} 231158115Sume 232158115Sume/* Re-read config file */ 233158115Sumeint32_t 234158115Sumeread_config_file(void) 235158115Sume{ 236158115Sume int32_t e; 237158115Sume 238158115Sume if (config_file == NULL) { 239158115Sume SYSLOG(LOGERR, "Unknown config file name!" EOL); 240158115Sume return (-1); 241158115Sume } 242158115Sume 243158115Sume if ((yyin = fopen(config_file, "r")) == NULL) { 244158115Sume SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL, 245158791Sume config_file, strerror(errno), errno); 246158791Sume return (-1); 247158115Sume } 248158791Sume 249158115Sume clean_config(); 250158115Sume if (yyparse() < 0) { 251158115Sume SYSLOG(LOGERR, "Could not parse config file '%s'" EOL, 252158115Sume config_file); 253158115Sume e = -1; 254158115Sume } else 255158115Sume e = 0; 256158115Sume 257158115Sume fclose(yyin); 258158115Sume yyin = NULL; 259158115Sume 260158115Sume return (e); 261158115Sume} 262158115Sume 263158115Sume/* Clean config */ 264158115Sumevoid 265158115Sumeclean_config(void) 266158115Sume{ 267158791Sume while (!LIST_EMPTY(&hid_devices)) { 268158791Sume hid_device_p d = LIST_FIRST(&hid_devices); 269158791Sume 270158115Sume LIST_REMOVE(d, next); 271158115Sume free_hid_device(d); 272158115Sume } 273158115Sume} 274158115Sume 275158115Sume/* Lookup config entry */ 276158115Sumehid_device_p 277158115Sumeget_hid_device(bdaddr_p bdaddr) 278158115Sume{ 279158115Sume hid_device_p d; 280158115Sume 281158115Sume LIST_FOREACH(d, &hid_devices, next) 282158791Sume if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0) 283158791Sume break; 284158115Sume 285158115Sume return (d); 286158115Sume} 287158115Sume 288158115Sume/* Get next config entry */ 289158115Sumehid_device_p 290158115Sumeget_next_hid_device(hid_device_p d) 291158115Sume{ 292158115Sume return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next)); 293158115Sume} 294158115Sume 295158115Sume/* Print config entry */ 296158115Sumevoid 297158115Sumeprint_hid_device(hid_device_p d, FILE *f) 298158115Sume{ 299158115Sume /* XXX FIXME hack! */ 300158115Sume struct report_desc { 301158115Sume unsigned int size; 302158115Sume unsigned char data[1]; 303158115Sume }; 304158115Sume /* XXX FIXME hack! */ 305158115Sume 306158115Sume struct report_desc *desc = (struct report_desc *) d->desc; 307158115Sume uint32_t i; 308158115Sume 309158115Sume fprintf(f, 310158115Sume"device {\n" \ 311158115Sume" bdaddr %s;\n" \ 312158115Sume" control_psm 0x%x;\n" \ 313158115Sume" interrupt_psm 0x%x;\n" \ 314158115Sume" reconnect_initiate %s;\n" \ 315158115Sume" battery_power %s;\n" \ 316158115Sume" normally_connectable %s;\n" \ 317158115Sume" hid_descriptor {", 318158115Sume bt_ntoa(&d->bdaddr, NULL), 319158115Sume d->control_psm, d->interrupt_psm, 320158115Sume d->reconnect_initiate? "true" : "false", 321158115Sume d->battery_power? "true" : "false", 322158115Sume d->normally_connectable? "true" : "false"); 323158115Sume 324158115Sume for (i = 0; i < desc->size; i ++) { 325158115Sume if ((i % 8) == 0) 326158115Sume fprintf(f, "\n "); 327158115Sume 328158115Sume fprintf(f, "0x%2.2x ", desc->data[i]); 329158115Sume } 330158115Sume 331158115Sume fprintf(f, 332158115Sume"\n" \ 333158115Sume" };\n" \ 334158115Sume"}\n"); 335158115Sume} 336158115Sume 337158115Sume/* Check config entry */ 338158115Sumestatic int32_t 339158115Sumecheck_hid_device(hid_device_p d) 340158115Sume{ 341158115Sume hid_data_t hd; 342158115Sume hid_item_t hi; 343158115Sume int32_t page; 344158115Sume 345158115Sume if (get_hid_device(&d->bdaddr) != NULL) { 346158115Sume SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL, 347158115Sume bt_ntoa(&d->bdaddr, NULL)); 348158115Sume return (0); 349158115Sume } 350158115Sume 351158115Sume if (d->control_psm == 0) { 352158115Sume SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL); 353158115Sume return (0); 354158115Sume } 355158115Sume 356158115Sume if (d->interrupt_psm == 0) { 357158115Sume SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL); 358158115Sume return (0); 359158115Sume } 360158115Sume 361158115Sume if (d->desc == NULL) { 362158115Sume SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL); 363158115Sume return (0); 364158115Sume } 365158115Sume 366158115Sume /* XXX somehow need to make sure descriptor is valid */ 367158115Sume for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) { 368158115Sume switch (hi.kind) { 369158115Sume case hid_collection: 370158115Sume case hid_endcollection: 371158115Sume case hid_output: 372158115Sume case hid_feature: 373158791Sume break; 374158791Sume 375158791Sume case hid_input: 376158115Sume /* Check if the device may send keystrokes */ 377158115Sume page = HID_PAGE(hi.usage); 378158115Sume if (page == HUP_KEYBOARD) 379158115Sume d->keyboard = 1; 380158115Sume break; 381158115Sume } 382158115Sume } 383158115Sume hid_end_parse(hd); 384158115Sume 385158115Sume return (1); 386158115Sume} 387158115Sume 388158115Sume/* Free config entry */ 389158791Sumestatic void 390158791Sumefree_hid_device(hid_device_p d) 391158115Sume{ 392158115Sume if (d->desc != NULL) 393158115Sume hid_dispose_report_desc(d->desc); 394158115Sume 395158115Sume memset(d, 0, sizeof(*d)); 396158115Sume free(d); 397158115Sume} 398158115Sume 399158115Sume/* Re-read hids file */ 400158115Sumeint32_t 401158115Sumeread_hids_file(void) 402158115Sume{ 403158115Sume FILE *f; 404158115Sume hid_device_t *d; 405158115Sume char *line; 406158115Sume bdaddr_t bdaddr; 407158115Sume int32_t lineno; 408158115Sume 409158115Sume if (hids_file == NULL) { 410158115Sume SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 411158115Sume return (-1); 412158115Sume } 413158115Sume 414158115Sume if ((f = fopen(hids_file, "r")) == NULL) { 415158115Sume if (errno == ENOENT) 416158115Sume return (0); 417158115Sume 418158115Sume SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 419158115Sume hids_file, strerror(errno), errno); 420158115Sume return (-1); 421158115Sume } 422158115Sume 423158115Sume for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) { 424158115Sume if ((line = strtok(buffer, "\r\n\t ")) == NULL) 425158115Sume continue; /* ignore empty lines */ 426158115Sume 427158115Sume if (!bt_aton(line, &bdaddr)) { 428158115Sume SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \ 429158115Sume "%s:%d" EOL, hids_file, lineno); 430158115Sume continue; 431158115Sume } 432158115Sume 433158115Sume if ((d = get_hid_device(&bdaddr)) != NULL) 434158115Sume d->new_device = 0; 435158115Sume } 436158115Sume 437158115Sume fclose(f); 438158115Sume 439157779Sume return (0); 440158115Sume} 441157779Sume 442157779Sume/* Write hids file */ 443157779Sumeint32_t 444157779Sumewrite_hids_file(void) 445157779Sume{ 446157779Sume char path[PATH_MAX]; 447157779Sume FILE *f; 448157779Sume hid_device_t *d; 449157779Sume 450157779Sume if (hids_file == NULL) { 451157779Sume SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 452157779Sume return (-1); 453157779Sume } 454157779Sume 455157779Sume snprintf(path, sizeof(path), "%s.new", hids_file); 456157779Sume 457157779Sume if ((f = fopen(path, "w")) == NULL) { 458157779Sume SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 459157779Sume path, strerror(errno), errno); 460157779Sume return (-1); 461157779Sume } 462157779Sume 463157779Sume LIST_FOREACH(d, &hid_devices, next) 464157779Sume if (!d->new_device) 465157779Sume fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL)); 466157779Sume 467157779Sume fclose(f); 468157779Sume 469157779Sume if (rename(path, hids_file) < 0) { 470157779Sume SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \ 471157779Sume "%s (%d)" EOL, path, hids_file, strerror(errno), errno); 472157779Sume unlink(path); 473157779Sume return (-1); 474157779Sume } 475157779Sume 476157779Sume return (0); 477157779Sume} 478157779Sume 479157779Sume