parser.y revision 281210
11556Srgrimes%{ 21556Srgrimes/* 31556Srgrimes * parser.y 41556Srgrimes */ 51556Srgrimes 61556Srgrimes/*- 71556Srgrimes * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com> 81556Srgrimes * All rights reserved. 91556Srgrimes * 101556Srgrimes * Redistribution and use in source and binary forms, with or without 111556Srgrimes * modification, are permitted provided that the following conditions 121556Srgrimes * are met: 131556Srgrimes * 1. Redistributions of source code must retain the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer. 151556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161556Srgrimes * notice, this list of conditions and the following disclaimer in the 171556Srgrimes * documentation and/or other materials provided with the distribution. 181556Srgrimes * 191556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 201556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 211556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 221556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 231556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 241556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 251556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 261556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 271556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 281556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 291556Srgrimes * SUCH DAMAGE. 301556Srgrimes * 311556Srgrimes * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $ 321556Srgrimes * $FreeBSD: head/usr.sbin/bluetooth/bthidd/parser.y 281210 2015-04-07 16:48:23Z takawata $ 331556Srgrimes */ 3436150Scharnier 3536150Scharnier#include <sys/queue.h> 3636150Scharnier#define L2CAP_SOCKET_CHECKED 371556Srgrimes#include <bluetooth.h> 3899110Sobrien#include <dev/usb/usb.h> 3999110Sobrien#include <dev/usb/usbhid.h> 401556Srgrimes#include <errno.h> 411556Srgrimes#include <limits.h> 4246684Skris#include <stdio.h> 431556Srgrimes#include <stdlib.h> 441556Srgrimes#include <string.h> 4517987Speter#include <unistd.h> 4617987Speter#include <usbhid.h> 4717987Speter 4817987Speter#ifndef BTHIDCONTROL 4917987Speter#include <stdarg.h> 5018016Speter#include <syslog.h> 51104282Smux#define SYSLOG syslog 5218018Speter#define LOGCRIT LOG_CRIT 5338536Scracauer#define LOGERR LOG_ERR 5417987Speter#define LOGWARNING LOG_WARNING 551556Srgrimes#define EOL 561556Srgrimes#else 571556Srgrimes#define SYSLOG fprintf 581556Srgrimes#define LOGCRIT stderr 591556Srgrimes#define LOGERR stderr 601556Srgrimes#define LOGWARNING stderr 611556Srgrimes#define EOL "\n" 62246167Sjilles#endif /* ndef BTHIDCONTROL */ 63250214Sjilles 641556Srgrimes#include "bthid_config.h" 651556Srgrimes 661556Srgrimes int yylex (void); 67359077Shrs void yyerror (char const *); 68359077Shrsstatic int32_t check_hid_device(hid_device_p hid_device); 69359077Shrsstatic void free_hid_device (hid_device_p hid_device); 70359077Shrs 71359077Shrsextern FILE *yyin; 72359077Shrsextern int yylineno; 73359077Shrs char const *config_file = BTHIDD_CONFFILE; 74359077Shrs char const *hids_file = BTHIDD_HIDSFILE; 75359077Shrs 76359077Shrsstatic char buffer[1024]; 77359077Shrsstatic int32_t hid_descriptor_size; 78359077Shrsstatic hid_device_t *hid_device = NULL; 79149018Sstefanfstatic LIST_HEAD(, hid_device) hid_devices; 80149018Sstefanf 81149018Sstefanf%} 82149018Sstefanf 83359077Shrs%union { 84359077Shrs bdaddr_t bdaddr; 85359077Shrs int32_t num; 86359077Shrs} 87359077Shrs 88359077Shrs%token <bdaddr> T_BDADDRSTRING 89359077Shrs%token <num> T_HEXBYTE 90359077Shrs%token T_DEVICE T_BDADDR T_CONTROL_PSM T_INTERRUPT_PSM T_RECONNECT_INITIATE 91359077Shrs%token T_BATTERY_POWER T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR 92359077Shrs%token T_TRUE T_FALSE T_ERROR 93359077Shrs 94359077Shrs%% 95359077Shrs 96359077Shrsconfig: line 97359077Shrs | config line 98359077Shrs ; 99359077Shrs 100359077Shrsline: T_DEVICE 101359077Shrs { 102359077Shrs hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device)); 103359077Shrs if (hid_device == NULL) { 104359077Shrs SYSLOG(LOGCRIT, "Could not allocate new " \ 105359077Shrs "config entry" EOL); 106359077Shrs YYABORT; 107359077Shrs } 108359077Shrs 109359077Shrs hid_device->new_device = 1; 110359077Shrs } 111359077Shrs '{' options '}' 112359077Shrs { 113359077Shrs if (check_hid_device(hid_device)) 114359077Shrs LIST_INSERT_HEAD(&hid_devices,hid_device,next); 115359077Shrs else 116359077Shrs free_hid_device(hid_device); 117359077Shrs 118359077Shrs hid_device = NULL; 119359077Shrs } 120359077Shrs ; 121359077Shrs 122359077Shrsoptions: option ';' 123359077Shrs | options option ';' 124359077Shrs ; 125359077Shrs 126359077Shrsoption: bdaddr 127359077Shrs | control_psm 128359077Shrs | interrupt_psm 129359077Shrs | reconnect_initiate 130359077Shrs | battery_power 131359077Shrs | normally_connectable 132359077Shrs | hid_descriptor 133359077Shrs | parser_error 134359077Shrs ; 135359077Shrs 136359077Shrsbdaddr: T_BDADDR T_BDADDRSTRING 137359077Shrs { 138359077Shrs memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr)); 139359077Shrs } 1401556Srgrimes ; 14150394Stg 14250394Stgcontrol_psm: T_CONTROL_PSM T_HEXBYTE 1431556Srgrimes { 1441556Srgrimes hid_device->control_psm = $2; 145190295Sstefanf } 146190295Sstefanf ; 147190295Sstefanf 148190295Sstefanfinterrupt_psm: T_INTERRUPT_PSM T_HEXBYTE 149190295Sstefanf { 150190295Sstefanf hid_device->interrupt_psm = $2; 151190295Sstefanf } 152190295Sstefanf ; 153190295Sstefanf 154190295Sstefanfreconnect_initiate: T_RECONNECT_INITIATE T_TRUE 1551556Srgrimes { 1561556Srgrimes hid_device->reconnect_initiate = 1; 15717987Speter } 15890111Simp | T_RECONNECT_INITIATE T_FALSE 15917987Speter { 1601556Srgrimes hid_device->reconnect_initiate = 0; 1611556Srgrimes } 1621556Srgrimes ; 16350394Stg 1641556Srgrimesbattery_power: T_BATTERY_POWER T_TRUE 165201053Sjilles { 1661556Srgrimes hid_device->battery_power = 1; 1671556Srgrimes } 1681556Srgrimes | T_BATTERY_POWER T_FALSE 1691556Srgrimes { 170190295Sstefanf hid_device->battery_power = 0; 171190295Sstefanf } 172287308Sjilles ; 17329983Smsmith 17429983Smsmithnormally_connectable: T_NORMALLY_CONNECTABLE T_TRUE 17529983Smsmith { 176250214Sjilles hid_device->normally_connectable = 1; 177250214Sjilles } 178359077Shrs | T_NORMALLY_CONNECTABLE T_FALSE 1791556Srgrimes { 18050394Stg hid_device->normally_connectable = 0; 1811556Srgrimes } 18229983Smsmith ; 18329983Smsmith 18450394Stghid_descriptor: T_HID_DESCRIPTOR 18529983Smsmith { 18629983Smsmith hid_descriptor_size = 0; 18759436Scracauer } 18829983Smsmith '{' hid_descriptor_bytes '}' 18929983Smsmith { 19029983Smsmith if (hid_device->desc != NULL) 19150394Stg hid_dispose_report_desc(hid_device->desc); 19250394Stg 19350394Stg hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size); 19429983Smsmith if (hid_device->desc == NULL) { 19559436Scracauer SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL); 19659436Scracauer YYABORT; 19729983Smsmith } 19829983Smsmith } 19929983Smsmith ; 20029983Smsmith 20129983Smsmithhid_descriptor_bytes: hid_descriptor_byte 20229983Smsmith | hid_descriptor_bytes hid_descriptor_byte 20329983Smsmith ; 20429983Smsmith 20529983Smsmithhid_descriptor_byte: T_HEXBYTE 20629983Smsmith { 20729983Smsmith if (hid_descriptor_size >= (int32_t) sizeof(buffer)) { 20829983Smsmith SYSLOG(LOGCRIT, "HID descriptor is too big" EOL); 20929983Smsmith YYABORT; 21029983Smsmith } 21129983Smsmith 21229983Smsmith buffer[hid_descriptor_size ++] = $1; 2131556Srgrimes } 2141556Srgrimes ; 2151556Srgrimes 2161556Srgrimesparser_error: T_ERROR 2171556Srgrimes { 2181556Srgrimes YYABORT; 2191556Srgrimes } 2201556Srgrimes 221190298Sstefanf%% 22229983Smsmith 22329983Smsmith/* Display parser error message */ 22429983Smsmithvoid 22529983Smsmithyyerror(char const *message) 22629983Smsmith{ 22729983Smsmith SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno); 22829983Smsmith} 22929983Smsmith 23029983Smsmith/* Re-read config file */ 23129983Smsmithint32_t 23229983Smsmithread_config_file(void) 233250214Sjilles{ 234250214Sjilles int32_t e; 235250214Sjilles 236250214Sjilles if (config_file == NULL) { 23729983Smsmith SYSLOG(LOGERR, "Unknown config file name!" EOL); 23829983Smsmith return (-1); 2391556Srgrimes } 240190295Sstefanf 2411556Srgrimes if ((yyin = fopen(config_file, "r")) == NULL) { 2421556Srgrimes SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL, 243287308Sjilles config_file, strerror(errno), errno); 244359077Shrs return (-1); 2451556Srgrimes } 246359077Shrs 247250214Sjilles clean_config(); 248250214Sjilles if (yyparse() < 0) { 249250214Sjilles SYSLOG(LOGERR, "Could not parse config file '%s'" EOL, 250250214Sjilles config_file); 251250214Sjilles e = -1; 252250214Sjilles } else 253250214Sjilles e = 0; 254250214Sjilles 255250214Sjilles fclose(yyin); 256250214Sjilles yyin = NULL; 257250214Sjilles 258250214Sjilles return (e); 2591556Srgrimes} 2601556Srgrimes 2611556Srgrimes/* Clean config */ 2621556Srgrimesvoid 2631556Srgrimesclean_config(void) 264215783Sjilles{ 2651556Srgrimes while (!LIST_EMPTY(&hid_devices)) { 2661556Srgrimes hid_device_p d = LIST_FIRST(&hid_devices); 267286826Sjilles 268286826Sjilles LIST_REMOVE(d, next); 269287308Sjilles free_hid_device(d); 270215783Sjilles } 271286826Sjilles} 2721556Srgrimes 2731556Srgrimes/* Lookup config entry */ 27450394Stghid_device_p 2751556Srgrimesget_hid_device(bdaddr_p bdaddr) 2761556Srgrimes{ 2771556Srgrimes hid_device_p d; 2781556Srgrimes 2791556Srgrimes LIST_FOREACH(d, &hid_devices, next) 280190295Sstefanf if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0) 281190295Sstefanf break; 282190295Sstefanf 283190295Sstefanf return (d); 284190295Sstefanf} 285190295Sstefanf 286190295Sstefanf/* Get next config entry */ 287190295Sstefanfhid_device_p 288190295Sstefanfget_next_hid_device(hid_device_p d) 289215783Sjilles{ 290190295Sstefanf return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next)); 291190295Sstefanf} 292190295Sstefanf 293190295Sstefanf/* Print config entry */ 294190295Sstefanfvoid 295287308Sjillesprint_hid_device(hid_device_p d, FILE *f) 296287308Sjilles{ 297215783Sjilles /* XXX FIXME hack! */ 298287308Sjilles struct report_desc { 299190295Sstefanf unsigned int size; 300190295Sstefanf unsigned char data[1]; 301190295Sstefanf }; 302190295Sstefanf /* XXX FIXME hack! */ 303190295Sstefanf 304190295Sstefanf struct report_desc *desc = (struct report_desc *) d->desc; 305190295Sstefanf uint32_t i; 306190295Sstefanf 307190295Sstefanf fprintf(f, 308190295Sstefanf"device {\n" \ 309287308Sjilles" bdaddr %s;\n" \ 310215783Sjilles" control_psm 0x%x;\n" \ 3111556Srgrimes" interrupt_psm 0x%x;\n" \ 3121556Srgrimes" reconnect_initiate %s;\n" \ 313190295Sstefanf" battery_power %s;\n" \ 314190295Sstefanf" normally_connectable %s;\n" \ 315190295Sstefanf" hid_descriptor {", 316190295Sstefanf bt_ntoa(&d->bdaddr, NULL), 317190295Sstefanf d->control_psm, d->interrupt_psm, 318190295Sstefanf d->reconnect_initiate? "true" : "false", 319190295Sstefanf d->battery_power? "true" : "false", 320287308Sjilles d->normally_connectable? "true" : "false"); 321287308Sjilles 322215783Sjilles for (i = 0; i < desc->size; i ++) { 323190295Sstefanf if ((i % 8) == 0) 3241556Srgrimes fprintf(f, "\n "); 325190295Sstefanf 326190295Sstefanf fprintf(f, "0x%2.2x ", desc->data[i]); 327190295Sstefanf } 328190295Sstefanf 329190295Sstefanf fprintf(f, 330287308Sjilles"\n" \ 3311556Srgrimes" };\n" \ 332359077Shrs"}\n"); 3331556Srgrimes} 334190295Sstefanf 335287308Sjilles/* Check config entry */ 336287308Sjillesstatic int32_t 337287308Sjillescheck_hid_device(hid_device_p d) 338287308Sjilles{ 339287308Sjilles hid_data_t hd; 340287308Sjilles hid_item_t hi; 341287308Sjilles int32_t page; 3421556Srgrimes 343190295Sstefanf if (get_hid_device(&d->bdaddr) != NULL) { 344190295Sstefanf SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL, 3451556Srgrimes bt_ntoa(&d->bdaddr, NULL)); 346278820Sjilles return (0); 3471556Srgrimes } 3481556Srgrimes 3491556Srgrimes if (d->control_psm == 0) { 3501556Srgrimes SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL); 3511556Srgrimes return (0); 35217987Speter } 353201053Sjilles 35417987Speter if (d->interrupt_psm == 0) { 35517987Speter SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL); 3561556Srgrimes return (0); 3571556Srgrimes } 35817987Speter 3591556Srgrimes if (d->desc == NULL) { 36017987Speter SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL); 36117987Speter return (0); 3621556Srgrimes } 36311571Sjoerg 36417987Speter /* XXX somehow need to make sure descriptor is valid */ 36517987Speter for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) { 36617987Speter switch (hi.kind) { 36717987Speter case hid_collection: 36811571Sjoerg case hid_endcollection: 36917987Speter case hid_output: 37017987Speter case hid_feature: 37117987Speter break; 37211571Sjoerg 37317987Speter case hid_input: 37417987Speter /* Check if the device may send keystrokes */ 37517987Speter page = HID_PAGE(hi.usage); 37617987Speter if (page == HUP_KEYBOARD) 37717987Speter d->keyboard = 1; 37817987Speter break; 37917987Speter } 38017987Speter } 38111571Sjoerg hid_end_parse(hd); 38217987Speter 38317987Speter return (1); 38417987Speter} 38517987Speter 38617987Speter/* Free config entry */ 38717987Speterstatic void 38817987Speterfree_hid_device(hid_device_p d) 38917987Speter{ 39011571Sjoerg if (d->desc != NULL) 39117987Speter hid_dispose_report_desc(d->desc); 39217987Speter 39317987Speter memset(d, 0, sizeof(*d)); 39417987Speter free(d); 39517987Speter} 39617987Speter 39717987Speter/* Re-read hids file */ 39817987Speterint32_t 39911571Sjoergread_hids_file(void) 40017987Speter{ 40117987Speter FILE *f; 40217987Speter hid_device_t *d; 40317987Speter char *line; 40417987Speter bdaddr_t bdaddr; 405246167Sjilles int32_t lineno; 40617987Speter 40717987Speter if (hids_file == NULL) { 40817987Speter SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 409149918Sstefanf return (-1); 41017987Speter } 41117987Speter 41217987Speter if ((f = fopen(hids_file, "r")) == NULL) { 41317987Speter if (errno == ENOENT) 41420425Ssteve return (0); 415151795Sstefanf 416297761Spfg SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 41741844Simp hids_file, strerror(errno), errno); 41811571Sjoerg return (-1); 41917987Speter } 42017987Speter 42141844Simp for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) { 422151795Sstefanf if ((line = strtok(buffer, "\r\n\t ")) == NULL) 42317987Speter continue; /* ignore empty lines */ 42417987Speter 42511571Sjoerg if (!bt_aton(line, &bdaddr)) { 42611571Sjoerg SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \ 42711571Sjoerg "%s:%d" EOL, hids_file, lineno); 42817987Speter continue; 42917987Speter } 43017987Speter 43117987Speter if ((d = get_hid_device(&bdaddr)) != NULL) 43217987Speter d->new_device = 0; 43317987Speter } 43417987Speter 43517987Speter fclose(f); 43617987Speter 43711571Sjoerg return (0); 43817987Speter} 43917987Speter 44018016Speter/* Write hids file */ 44117987Speterint32_t 44217987Speterwrite_hids_file(void) 44317987Speter{ 44417987Speter char path[PATH_MAX]; 44511571Sjoerg FILE *f; 44617987Speter hid_device_t *d; 44717987Speter 44818016Speter if (hids_file == NULL) { 44917987Speter SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 45017987Speter return (-1); 45118016Speter } 45217987Speter 45317987Speter snprintf(path, sizeof(path), "%s.new", hids_file); 45418016Speter 45517987Speter if ((f = fopen(path, "w")) == NULL) { 45617987Speter SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 45718016Speter path, strerror(errno), errno); 45817987Speter return (-1); 45917987Speter } 46018016Speter 46117987Speter LIST_FOREACH(d, &hid_devices, next) 46217987Speter if (!d->new_device) 46318016Speter fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL)); 46417987Speter 46517987Speter fclose(f); 46618016Speter 46717987Speter if (rename(path, hids_file) < 0) { 46817987Speter SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \ 46918016Speter "%s (%d)" EOL, path, hids_file, strerror(errno), errno); 47017987Speter unlink(path); 47117987Speter return (-1); 47218016Speter } 47317987Speter 47417987Speter return (0); 47518016Speter} 47617987Speter 47717987Speter