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