diff options
| -rw-r--r-- | hcid/hcid.h | 27 | ||||
| -rw-r--r-- | hcid/lexer.l | 21 | ||||
| -rw-r--r-- | hcid/main.c | 178 | ||||
| -rw-r--r-- | hcid/parser.y | 95 | 
4 files changed, 233 insertions, 88 deletions
| diff --git a/hcid/hcid.h b/hcid/hcid.h index 55ef0ab0..3bd0ad46 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -20,23 +20,24 @@     ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS,     TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED.  */ +  /*   * $Id$   */  #include <sys/types.h> -#include "glib-ectomy.h" -  #include <bluetooth/bluetooth.h> +#include "glib-ectomy.h" +  #define HCID_CONFIG_FILE "/etc/bluetooth/hcid.conf"  #define HCID_PIN_FILE    "/etc/bluetooth/pin"  #define HCID_KEY_FILE    "/etc/bluetooth/link_key"  #define HCID_PIN_HELPER  "/bin/bluepin"  struct device_opts { -	char  *name; +	char    *name;  	uint32_t class;  	uint16_t pkt_type;  	uint16_t scan; @@ -44,15 +45,23 @@ struct device_opts {  	uint16_t link_policy;  	uint16_t auth;  	uint16_t encrypt; -};    -extern struct device_opts devi; +}; + +extern struct device_opts default_device; +extern struct device_opts *parser_device; + +struct device_list { +	char *ref;			/* HCI device or Bluetooth address */ +	struct device_list *next; +	struct device_opts opts; +};  struct link_key {  	bdaddr_t sba;  	bdaddr_t dba; -	uint8_t	 key[16]; -	uint8_t	 type; -	time_t	 time; +	uint8_t  key[16]; +	uint8_t  type; +	time_t   time;  };  struct hcid_opts { @@ -84,6 +93,8 @@ extern struct hcid_opts hcid;  int read_config(char *file); +struct device_opts *alloc_device_opts(char *addr); +  gboolean io_stack_event(GIOChannel *chan, GIOCondition cond, gpointer data);  gboolean io_security_event(GIOChannel *chan, GIOCondition cond, gpointer data); diff --git a/hcid/lexer.l b/hcid/lexer.l index 85cd5780..1947bcd4 100644 --- a/hcid/lexer.l +++ b/hcid/lexer.l @@ -24,7 +24,7 @@  /*   * $Id$ - */  + */  #include <string.h> @@ -44,16 +44,19 @@ int yyerror(char *str);  hex		0x[0-9a-zA-Z]+  num		[0-9]+ -kword		[A-Za-z0-9\_\-]+	 +kword		[A-Za-z0-9\_\-]+  word		[A-Za-z0-9\-\_+=\!\$\#\%\&\*\^\@@\\\~\.]+  wordnm		{word}:{num}  list		({word}\,*)+  comment		\#.*\n -fname		[A-Za-z0-9\_\.\-]+	 +fname		[A-Za-z0-9\_\.\-]+  path		(\/{fname})+  string		\".*\" +hci		hci[0-9]+ +hextuple	[0-9a-zA-Z][0-9a-zA-Z] +bdaddr		{hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple} -%x OPTION PARAM   +%x OPTION PARAM  %%  [ \t] { @@ -70,6 +73,16 @@ string		\".*\"  	lineno++;  } +{hci} { +	yylval.str = yytext; +	return HCI; +} + +{bdaddr} { +	yylval.str = yytext; +	return BDADDR; +} +  {hex} {  	yylval.num = strtol(yytext, NULL, 16);  	return NUM; diff --git a/hcid/main.c b/hcid/main.c index 85534fdf..d5c52c9d 100644 --- a/hcid/main.c +++ b/hcid/main.c @@ -20,6 +20,7 @@     ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS,     TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED.  */ +  /*   * $Id$   */ @@ -50,7 +51,9 @@  #include "lib.h"  struct hcid_opts hcid; -struct device_opts devi; +struct device_opts default_device; +struct device_opts *parser_device; +static struct device_list *device_list = NULL;  static GMainLoop *event_loop; @@ -64,8 +67,93 @@ static void usage(void)  	printf("\thcid [-n not_daemon] [-f config file]\n");  } +static inline void init_device_defaults(struct device_opts *device_opts) +{ +	memset(device_opts, 0, sizeof(*device_opts)); +	device_opts->scan = SCAN_PAGE | SCAN_INQUIRY; +} + +struct device_opts *alloc_device_opts(char *ref) +{ +	struct device_list *device; + +	device = malloc(sizeof(struct device_list)); +	if (!device) { +		syslog(LOG_INFO, "Can't allocate devlist opts buffer. %s(%d)",  +			strerror(errno), errno); +		exit(1); +	} + +	device->ref = ref; +	device->next = device_list; +	device_list = device; + +	init_device_defaults(&device->opts); + +	return &device->opts; +} + +static void free_device_opts(void) +{ +	struct device_list *device, *next; + +	if (default_device.name) { +		free(default_device.name); +		default_device.name = NULL; +	} + +	for (device = device_list; device; device = next) { +		free(device->ref); +		if (device->opts.name) +			free(device->opts.name); +		next = device->next; +		free(device); +	} + +	device_list = NULL; +} + +static inline struct device_opts *find_device_opts(char *ref) +{ +	struct device_list *device; + +	for (device = device_list; device; device = device->next) +		if (!strcmp(ref, device->ref)) +			return &device->opts; + +	return NULL; +} + +static struct device_opts *get_device_opts(int sock, int hdev) +{ +	struct device_opts *device_opts = NULL; +	struct hci_dev_info di; + +	/* First try to get BD_ADDR based settings ... */ +	di.dev_id = hdev; +	if (!ioctl(sock, HCIGETDEVINFO, (void *) &di)) { +		char addr[18]; +		ba2str(&di.bdaddr, addr); +		device_opts = find_device_opts(addr); +	} + +	/* ... then try HCI based settings ... */ +	if (!device_opts) { +		char ref[8]; +		snprintf(ref, sizeof(ref) - 1, "hci%d", hdev); +		device_opts = find_device_opts(ref); +	} + +	/* ... and last use the default settings. */ +	if (!device_opts) +		device_opts = &default_device; + +	return device_opts; +} +  static void configure_device(int hdev)  { +	struct device_opts *device_opts;  	struct hci_dev_req dr;  	int s; @@ -87,51 +175,52 @@ static void configure_device(int hdev)  		exit(1);  	} -	dr.dev_id  = hdev; +	dr.dev_id   = hdev; +	device_opts = get_device_opts(s, hdev);  	/* Set scan mode */ -	dr.dev_opt = devi.scan; -	if (ioctl(s, HCISETSCAN, (unsigned long)&dr) < 0) { +	dr.dev_opt = device_opts->scan; +	if (ioctl(s, HCISETSCAN, (unsigned long) &dr) < 0) {  		syslog(LOG_ERR, "Can't set scan mode on hci%d. %s(%d)\n",   				hdev, strerror(errno), errno);  	}  	/* Set authentication */ -	if (devi.auth) +	if (device_opts->auth)  		dr.dev_opt = AUTH_ENABLED;  	else  		dr.dev_opt = AUTH_DISABLED; -	if (ioctl(s, HCISETAUTH, (unsigned long)&dr) < 0) { +	if (ioctl(s, HCISETAUTH, (unsigned long) &dr) < 0) {  		syslog(LOG_ERR, "Can't set auth on hci%d. %s(%d)\n",   				hdev, strerror(errno), errno);  	}  	/* Set encryption */ -	if (devi.encrypt) +	if (device_opts->encrypt)  		dr.dev_opt = ENCRYPT_P2P;  	else  		dr.dev_opt = ENCRYPT_DISABLED; -	if (ioctl(s, HCISETENCRYPT, (unsigned long)&dr) < 0) { +	if (ioctl(s, HCISETENCRYPT, (unsigned long) &dr) < 0) {  		syslog(LOG_ERR, "Can't set encrypt on hci%d. %s(%d)\n",   				hdev, strerror(errno), errno);  	} -        /* Set device class */ -	if (devi.class) { -		uint32_t class = htobl(devi.class); +	/* Set device class */ +	if (device_opts->class) { +		uint32_t class = htobl(device_opts->class);  		write_class_of_dev_cp cp; -                 +  		memcpy(cp.dev_class, &class, 3);  		hci_send_cmd(s, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,  			WRITE_CLASS_OF_DEV_CP_SIZE, (void *) &cp);  	}  	/* Set device name */ -	if (devi.name) { +	if (device_opts->name) {  		change_local_name_cp cp; -		expand_name(cp.name, devi.name, hdev); +		expand_name(cp.name, device_opts->name, hdev);  		hci_send_cmd(s, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,  			CHANGE_LOCAL_NAME_CP_SIZE, (void *) &cp); @@ -142,6 +231,7 @@ static void configure_device(int hdev)  static void init_device(int hdev)  { +	struct device_opts *device_opts;  	struct hci_dev_req dr;  	int s; @@ -170,30 +260,31 @@ static void init_device(int hdev)  		exit(1);  	} -	dr.dev_id  = hdev; +	dr.dev_id   = hdev; +	device_opts = get_device_opts(s, hdev);  	/* Set packet type */ -	if (devi.pkt_type) { -		dr.dev_opt = devi.pkt_type; -		if (ioctl(s, HCISETPTYPE, (unsigned long)&dr) < 0) { +	if (device_opts->pkt_type) { +		dr.dev_opt = device_opts->pkt_type; +		if (ioctl(s, HCISETPTYPE, (unsigned long) &dr) < 0) {  			syslog(LOG_ERR, "Can't set packet type on hci%d. %s(%d)\n",   				hdev, strerror(errno), errno);  		}  	}  	/* Set link mode */ -	if (devi.link_mode) { -		dr.dev_opt = devi.link_mode; -		if (ioctl(s, HCISETLINKMODE, (unsigned long)&dr) < 0) { +	if (device_opts->link_mode) { +		dr.dev_opt = device_opts->link_mode; +		if (ioctl(s, HCISETLINKMODE, (unsigned long) &dr) < 0) {  			syslog(LOG_ERR, "Can't set link mode on hci%d. %s(%d)\n",   				hdev, strerror(errno), errno);  		}  	}  	/* Set link policy */ -	if (devi.link_policy) { -		dr.dev_opt = devi.link_policy; -		if (ioctl(s, HCISETLINKPOL, (unsigned long)&dr) < 0) { +	if (device_opts->link_policy) { +		dr.dev_opt = device_opts->link_policy; +		if (ioctl(s, HCISETLINKPOL, (unsigned long) &dr) < 0) {  			syslog(LOG_ERR, "Can't set link policy on hci%d. %s(%d)\n",   				hdev, strerror(errno), errno);  		} @@ -216,13 +307,13 @@ static void init_all_devices(int ctl)  	dl->dev_num = HCI_MAX_DEV;  	dr = dl->dev_req; -	if (ioctl(ctl, HCIGETDEVLIST, (void*)dl)) { +	if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {  		syslog(LOG_INFO, "Can't get device list. %s(%d)",  			strerror(errno), errno);  		exit(1);  	} -	for (i=0; i < dl->dev_num; i++, dr++) { +	for (i = 0; i < dl->dev_num; i++, dr++) {  		if (hcid.auto_init)  			init_device(dr->dev_id); @@ -232,7 +323,7 @@ static void init_all_devices(int ctl)  		if (hcid.security && hci_test_bit(HCI_UP, &dr->dev_opt))  			start_security_manager(dr->dev_id);  	} -	 +  	free(dl);  } @@ -241,10 +332,7 @@ static void init_defaults(void)  	hcid.auto_init = 0;  	hcid.security  = 0; -	devi.pkt_type = 0; -	devi.scan = SCAN_PAGE | SCAN_INQUIRY; -	devi.auth = 0; -	devi.encrypt = 0; +	init_device_defaults(&default_device);  }  static void sig_usr1(int sig) @@ -265,7 +353,9 @@ static void sig_term(int sig)  static void sig_hup(int sig)  {  	syslog(LOG_INFO, "Reloading config file"); +  	init_defaults(); +  	if (read_config(hcid.config_file) < 0)  		syslog(LOG_ERR, "Config reload failed"); @@ -346,7 +436,7 @@ gboolean io_stack_event(GIOChannel *chan, GIOCondition cond, gpointer data)  	return TRUE;  } -extern int optind,opterr,optopt; +extern int optind, opterr, optopt;  extern char *optarg;  int main(int argc, char *argv[], char *env[]) @@ -361,18 +451,18 @@ int main(int argc, char *argv[], char *env[])  	/* Default HCId settings */  	hcid.config_file = HCID_CONFIG_FILE; -	hcid.host_name = get_host_name(); -	hcid.security  = HCID_SEC_AUTO; -	hcid.pairing   = HCID_PAIRING_MULTI; +	hcid.host_name   = get_host_name(); +	hcid.security    = HCID_SEC_AUTO; +	hcid.pairing     = HCID_PAIRING_MULTI; -	hcid.pin_file   = strdup(HCID_PIN_FILE); -	hcid.pin_helper = strdup(HCID_PIN_HELPER); -	hcid.key_file   = strdup(HCID_KEY_FILE); +	hcid.pin_file    = strdup(HCID_PIN_FILE); +	hcid.pin_helper  = strdup(HCID_PIN_HELPER); +	hcid.key_file    = strdup(HCID_KEY_FILE);  	init_defaults(); -	while ((opt=getopt(argc,argv,"f:n")) != EOF) { -		switch(opt) { +	while ((opt = getopt(argc, argv, "f:n")) != EOF) { +		switch (opt) {  		case 'n':  			daemon = 0;  			break; @@ -402,8 +492,8 @@ int main(int argc, char *argv[], char *env[])  	}  	umask(0077); -	 -        init_title(argc, argv, env, "hcid: "); + +	init_title(argc, argv, env, "hcid: ");  	set_title("initializing");  	/* Start logging to syslog and stderr */ @@ -443,7 +533,7 @@ int main(int argc, char *argv[], char *env[])  	addr.hci_family = AF_BLUETOOTH;  	addr.hci_dev = HCI_DEV_NONE; -	if (bind(hcid.sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { +	if (bind(hcid.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {  		syslog(LOG_ERR, "Can't bind HCI socket. %s(%d)\n", strerror(errno), errno);  		exit(1);  	} @@ -467,6 +557,8 @@ int main(int argc, char *argv[], char *env[])  	/* Start event processor */  	g_main_run(event_loop); +	free_device_opts(); +  	syslog(LOG_INFO, "Exit.");  	return 0;  } diff --git a/hcid/parser.y b/hcid/parser.y index f0aafbd3..e14ca200 100644 --- a/hcid/parser.y +++ b/hcid/parser.y @@ -24,7 +24,7 @@  /*   * $Id$ - */  + */  #include <stdio.h>  #include <stdlib.h> @@ -45,7 +45,7 @@  int cfg_error(const char *fmt, ...);  int yyparse(void); -int yylex(void);	 +int yylex(void);  int yyerror(char *s);   %} @@ -61,27 +61,42 @@ int yyerror(char *s);  %token K_PINHELP  %token K_YES K_NO -%token <str> WORD PATH STRING LIST +%token <str> WORD PATH STRING LIST HCI BDADDR  %token <num> NUM  %type  <num> bool pkt_type link_mode link_policy sec_mode pair_mode -%type  <str> dev_name +%type  <str> dev_name hci bdaddr  %%  config: statement | config statement;  statement:     K_OPTIONS hcid_options -  -  | K_DEVICE device_options + +  | device device_options    | WORD	{  			cfg_error("Invalid statement '%s'", $1);  		} +    | error	{  			yyclearin; yyerrok;  		}    ; +device: +  K_DEVICE		{ +				parser_device = &default_device; +			} + +  | K_DEVICE hci	{ +				parser_device = alloc_device_opts($2); +			} + +  | K_DEVICE bdaddr	{ +				parser_device = alloc_device_opts($2); +			} +  ; +  hcid_options: '{' hcid_opts '}';  hcid_opts: | hcid_opt ';' | error ';' | hcid_opts hcid_opt ';';  hcid_opt:  @@ -109,7 +124,7 @@ hcid_opt:    ;  sec_mode: -   WORD		{	 +  WORD		{  			int opt = find_keyword(sec_param, $1);  			if (opt < 0) {  				cfg_error("Unknown security mode '%s'", $1); @@ -118,11 +133,13 @@ sec_mode:  				$$ = opt;  		} -  | K_NO	{ 	$$ = HCID_SEC_NONE; 	} +  | K_NO	{ +			$$ = HCID_SEC_NONE; +		}    ;  pair_mode: -   WORD		{	 +  WORD		{  			int opt = find_keyword(pair_param, $1);  			if (opt < 0) {  				cfg_error("Unknown pairing mode '%s'", $1); @@ -137,47 +154,47 @@ device_options: '{' device_opts '}';  device_opts: | device_opt ';' | error ';' | device_opts device_opt ';';  device_opt:    K_PTYPE pkt_type	{ -				devi.pkt_type = $2; +				parser_device->pkt_type = $2;  			}    | K_LM link_mode	{ -				devi.link_mode = $2; +				parser_device->link_mode = $2;  			}    | K_LP link_policy	{ -				devi.link_policy = $2; +				parser_device->link_policy = $2;  			} -  | K_NAME dev_name	{   -				if (devi.name) -					free(devi.name); -				devi.name = $2; +  | K_NAME dev_name	{ +				if (parser_device->name) +					free(parser_device->name); +				parser_device->name = $2;  			}    | K_CLASS NUM		{ -				devi.class = $2; +				parser_device->class = $2;  			}    | K_AUTH bool		{ -				devi.auth = $2; +				parser_device->auth = $2;  			}    | K_ENCRYPT bool	{ -				devi.encrypt = $2; +				 parser_device->encrypt = $2;  			}    | K_ISCAN bool	{  				if ($2) -					devi.scan |=  SCAN_INQUIRY; +					parser_device->scan |=  SCAN_INQUIRY;  				else -					devi.scan &= ~SCAN_INQUIRY; +					parser_device->scan &= ~SCAN_INQUIRY;  			}    | K_PSCAN bool	{  				if ($2) -					devi.scan |=  SCAN_PAGE; +					parser_device->scan |=  SCAN_PAGE;  				else -					devi.scan &= ~SCAN_PAGE; +					parser_device->scan &= ~SCAN_PAGE;  			}    | WORD		{ @@ -187,7 +204,7 @@ device_opt:    ;  dev_name: -  WORD		{   +  WORD		{  			$$ = strdup($1);  		} @@ -196,8 +213,20 @@ dev_name:  		}    ; +hci: +  HCI		{ +			$$ = strdup($1); +		} +  ; + +bdaddr: +  BDADDR	{ +			$$ = strdup($1); +		} +  ; +  pkt_type: -  WORD 	 	{ +  WORD		{  			int opt;  			if (!hci_strtoptype($1, &opt))  				cfg_error("Unknown packet type '%s'", $1); @@ -209,11 +238,11 @@ pkt_type:  			if (!hci_strtoptype($1, &opt))  				cfg_error("Unknown packet type '%s'", $1);  			$$ = opt; -  		} +		}    ;  link_mode: -  WORD 	 	{ +  WORD		{  			int opt;  			if (!hci_strtolm($1, &opt))  				cfg_error("Unknown link mode '%s'", $1); @@ -225,11 +254,11 @@ link_mode:  			if (!hci_strtolm($1, &opt))  				cfg_error("Unknown link mode '%s'", $1);  			$$ = opt; -  		} +		}    ;  link_policy: -  WORD 	 	{ +  WORD		{  			int opt;  			if (!hci_strtolp($1, &opt))  				cfg_error("Unknown link policy '%s'", $1); @@ -241,7 +270,7 @@ link_policy:  			if (!hci_strtolp($1, &opt))  				cfg_error("Unknown link policy '%s'", $1);  			$$ = opt; -  		} +		}    ;  bool: K_YES { $$ = 1; } | K_NO  { $$ = 0; }; @@ -276,13 +305,13 @@ int read_config(char *file)  	if( !(yyin = fopen(file,"r")) ){  		syslog(LOG_ERR,"Can not open %s", file); -		return -1;       +		return -1;  	}  	lineno = 1;  	yyparse();  	fclose(yyin); -   -	return 0;      + +	return 0;  } | 
