NetBSD/lib/libbluetooth/parser.y

613 lines
12 KiB
Plaintext

/* $NetBSD: parser.y,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
%{
/*-
* Copyright (c) 2006 Itronix Inc.
* 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.
* 3. The name of Itronix Inc. may not be used to endorse
* or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
*/
/*
* parser.y
*
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.1 2006/06/19 15:44:36 gdamore Exp $
* $FreeBSD: src/usr.sbin/bluetooth/hcsecd/parser.y,v 1.4 2004/09/14 20:04:33 emax Exp $
*/
#include <bluetooth.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <dev/bluetooth/btdev.h>
struct bt_handle {
FILE *fp;
};
int _btyyparse (void);
int _btyylex (void);
void _btyyerror (const char *);
static int hexcpy (uint8_t *, const char *, int);
extern int _btyylineno;
extern FILE *_btyyin;
static void *arg;
static const bdaddr_t *bdaddr;
static int count;
static bt_cfgentry_t *found;
static void (*func)(bt_cfgentry_t *, void *);
static bt_cfgentry_t *entry;
static uint8_t hid_buffer[1024];
static int hid_length;
%}
%union {
char *string;
bdaddr_t bdaddr;
int value;
}
%token <string> T_STRING T_HEXSTRING
%token <bdaddr> T_BDADDRSTRING
%token <value> T_VALUE
%token T_DEVICE
%token T_BDADDR
%token T_NAME
%token T_KEY
%token T_PIN
%token T_TYPE
%token T_HID
%token T_HSET
%token T_CONTROL_PSM
%token T_CONTROL_CHANNEL
%token T_INTERRUPT_PSM
%token T_RECONNECT_INITIATE
%token T_BATTERY_POWER
%token T_NORMALLY_CONNECTABLE
%token T_HID_DESCRIPTOR
%token T_TRUE
%token T_FALSE
%token T_ERROR
%%
config:
line
| config line
;
line:
T_DEVICE
{
entry = malloc(sizeof(bt_cfgentry_t));
if (entry == NULL)
YYABORT;
memset(entry, 0, sizeof(bt_cfgentry_t));
}
'{' options '}'
{
if (bdaddr != NULL) {
if (bdaddr_same(&entry->bdaddr, bdaddr)) {
bt_freeconfig(found);
found = entry;
} else
bt_freeconfig(entry);
}
if (func != NULL) {
(*func)(entry, arg);
bt_freeconfig(entry);
}
entry = NULL;
count++;
}
;
options:
option ';'
| options option ';'
;
option:
bdaddr
| type
| name
| key
| pin
| control_psm
| control_channel
| interrupt_psm
| reconnect_initiate
| battery_power
| normally_connectable
| hid_descriptor
| parser_error
;
bdaddr:
T_BDADDR T_BDADDRSTRING
{
bdaddr_copy(&entry->bdaddr, &$2);
}
;
type:
T_TYPE T_HID
{
entry->type = BTDEV_HID;
}
| T_TYPE T_HSET
{
entry->type = BTDEV_HSET;
}
;
name:
T_NAME T_STRING
{
if (entry->name != NULL)
free(entry->name);
entry->name = strdup($2);
if (entry->name == NULL)
YYABORT;
}
;
key:
T_KEY T_HEXSTRING
{
if (entry->key == NULL) {
entry->key = malloc(HCI_KEY_SIZE);
if (entry->key == NULL)
YYABORT;
}
memset(entry->key, 0, HCI_KEY_SIZE);
hexcpy(entry->key, $2, HCI_KEY_SIZE);
}
;
pin:
T_PIN T_STRING
{
if (entry->pin == NULL) {
entry->pin = malloc(HCI_PIN_SIZE);
if (entry->pin == NULL)
YYABORT;
}
strncpy((char *)entry->pin, $2, HCI_PIN_SIZE);
}
| T_PIN T_HEXSTRING
{
if (entry->pin == NULL) {
entry->pin = malloc(HCI_PIN_SIZE);
if (entry->pin == NULL)
YYABORT;
}
memset(entry->pin, 0, HCI_PIN_SIZE);
hexcpy(entry->pin, $2, HCI_PIN_SIZE);
}
;
control_psm:
T_CONTROL_PSM T_HEXSTRING
{
if (strlen($2) > sizeof(entry->control_psm) * 2) {
errno = EINVAL;
YYABORT;
}
entry->control_psm = (uint16_t)strtoul($2, NULL, 16);
}
;
control_channel:
T_CONTROL_CHANNEL T_VALUE
{
entry->control_channel = (uint8_t)$2;
}
;
interrupt_psm:
T_INTERRUPT_PSM T_HEXSTRING
{
if (strlen($2) > sizeof(entry->interrupt_psm) * 2) {
errno = EINVAL;
YYABORT;
}
entry->interrupt_psm = (uint16_t)strtoul($2, NULL, 16);
}
;
reconnect_initiate:
T_RECONNECT_INITIATE T_TRUE
{
entry->reconnect_initiate = 1;
}
| T_RECONNECT_INITIATE T_FALSE
{
entry->reconnect_initiate = 0;
}
;
battery_power:
T_BATTERY_POWER T_TRUE
{
entry->battery_power = 1;
}
| T_BATTERY_POWER T_FALSE
{
entry->battery_power = 0;
}
;
normally_connectable:
T_NORMALLY_CONNECTABLE T_TRUE
{
entry->normally_connectable = 1;
}
| T_NORMALLY_CONNECTABLE T_FALSE
{
entry->normally_connectable = 0;
}
;
hid_descriptor:
T_HID_DESCRIPTOR
{
hid_length = 0;
}
'{' hid_descriptor_bytes '}'
{
if (entry->hid_descriptor != NULL)
free(entry->hid_descriptor);
entry->hid_descriptor = malloc(hid_length);
if (entry->hid_descriptor == NULL)
YYABORT;
memcpy(entry->hid_descriptor, hid_buffer, hid_length);
entry->hid_length = hid_length;
}
;
hid_descriptor_bytes:
hid_descriptor_byte
| hid_descriptor_bytes hid_descriptor_byte
;
hid_descriptor_byte:
T_HEXSTRING
{
if (hid_length >= sizeof(hid_buffer)) {
errno = ENOBUFS;
YYABORT;
}
if (strlen($1) != 2) {
errno = EINVAL;
YYABORT;
}
hid_buffer[hid_length++] = (uint8_t)strtoul($1, NULL, 16);
}
;
parser_error:
T_ERROR
{
errno = EINVAL;
YYABORT;
}
%%
/* Display parser error message */
void
_btyyerror(const char *message)
{
/* fprintf(stderr, "%s in line %d", message, _btyylineno); */
count = -1;
}
/* Convert hex ASCII to int4 */
static int
hexa2int4(char a)
{
if ('0' <= a && a <= '9')
return (a - '0');
if ('A' <= a && a <= 'F')
return (a - 'A' + 0xa);
if ('a' <= a && a <= 'f')
return (a - 'a' + 0xa);
/* NOTREACHED */
return 0;
}
/* Convert ASCII hex string to uint8 array */
static int
hexcpy(uint8_t *dest, const char *src, int len)
{
int n;
for (n = 0 ; n < len && *src != '\0' ; n++) {
*dest++ = (hexa2int4(src[0]) << 4) | hexa2int4(src[1]);
src += 2;
}
return n;
}
/* Open config file */
bt_handle_t
bt_openconfig(const char *name)
{
bt_handle_t handle;
handle = malloc(sizeof(bt_handle_t));
if (handle == NULL)
return NULL;
memset(handle, 0, sizeof(bt_handle_t));
if (name == NULL)
name = "/etc/bluetooth/bluetooth.conf";
handle->fp = fopen(name, "r");
if (handle->fp == NULL) {
free(handle);
return NULL;
}
return handle;
}
/* Find config entry for device */
bt_cfgentry_t *
bt_getconfig(bt_handle_t handle, const bdaddr_t *device)
{
if (handle == NULL || handle->fp == NULL) {
errno = EBADF;
return NULL;
}
arg = NULL;
bdaddr = device;
count = 0;
found = NULL;
func = NULL;
_btyyin = handle->fp;
rewind(_btyyin);
_btyyparse();
_btyyin = NULL;
if (found == NULL)
errno = ENOENT;
return found;
}
/* Call function for each config entry */
int
bt_eachconfig(bt_handle_t handle, void (*f)(bt_cfgentry_t *, void *), void *a)
{
if (handle == NULL || handle->fp == NULL) {
errno = EBADF;
return -1;
}
arg = a;
bdaddr = NULL;
count = 0;
found = NULL;
func = f;
_btyyin = handle->fp;
rewind(_btyyin);
_btyyparse();
_btyyin = NULL;
return count;
}
/* Free config entry */
void
bt_freeconfig(bt_cfgentry_t *cfg)
{
if (cfg == NULL)
return;
if (cfg->name)
free(cfg->name);
if (cfg->pin)
free(cfg->pin);
if (cfg->key)
free(cfg->key);
if (cfg->hid_descriptor)
free(cfg->hid_descriptor);
free(cfg);
}
/* Close config file */
int
bt_closeconfig(bt_handle_t handle)
{
int rv;
if (handle == NULL) {
errno = EBADF;
return -1;
}
rv = fclose(handle->fp);
handle->fp = NULL;
free(handle);
return rv;
}
#define OPT "\t%-23s "
#define Q "\""
#define HEX "0x%4.4x"
#define DEC "%d"
#define KEY "0x%s"
#define STR "%s"
#define SLEN "%.*s"
#define EOL ";\n"
/* Print config entry */
int
bt_printconfig(FILE *fp, bt_cfgentry_t *cfg)
{
int i, n;
if (cfg == NULL || fp == NULL)
return -1;
fprintf(fp, "device {\n");
fprintf(fp, OPT STR EOL, "bdaddr", bt_ntoa(&cfg->bdaddr, NULL));
if (cfg->type != 0) {
const char *type;
switch (cfg->type) {
case BTDEV_HID:
type = "hid";
break;
case BTDEV_HSET:
type = "hset";
break;
default:
type = "unknown";
break;
}
fprintf(fp, OPT STR EOL, "type", type);
}
if (cfg->name != NULL)
fprintf(fp, OPT Q STR Q EOL, "name", cfg->name);
if (cfg->pin != NULL)
fprintf(fp, OPT Q SLEN Q EOL, "pin", HCI_PIN_SIZE, cfg->pin);
if (cfg->key != NULL) {
fprintf(fp, OPT STR, "key", "0x");
n = HCI_KEY_SIZE - 1;
while (n > 1 && cfg->key[n] == 0)
n--;
for (i = 0 ; i <= n ; i++)
fprintf(fp, "%2.2x", cfg->key[i]);
fprintf(fp, EOL);
}
if (cfg->control_psm != 0)
fprintf(fp, OPT HEX EOL, "control_psm", cfg->control_psm);
if (cfg->interrupt_psm != 0)
fprintf(fp, OPT HEX EOL, "interrupt_psm", cfg->interrupt_psm);
if (cfg->control_channel != 0)
fprintf(fp, OPT DEC EOL, "control_channel", cfg->control_channel);
if (cfg->reconnect_initiate != 0)
fprintf(fp, OPT STR EOL, "reconnect_initiate", "true");
if (cfg->battery_power != 0)
fprintf(fp, OPT STR EOL, "battery_power", "true");
if (cfg->normally_connectable != 0)
fprintf(fp, OPT STR EOL, "normally_connectable", "true");
if (cfg->hid_descriptor != NULL) {
fprintf(fp, OPT "{", "hid_descriptor");
for (i = 0 ; i < cfg->hid_length ; i++)
fprintf(fp, "%s0x%2.2x",
((i % 8) ? " " : "\n\t\t"),
cfg->hid_descriptor[i]);
fprintf(fp, "\n\t}" EOL);
}
fprintf(fp, "}\n");
return 0;
}