From 5ff58cb0e277fb4cb4613aa3d2a83e7237c59894 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 9 Feb 2004 10:08:18 +0000 Subject: Add device specific configuration --- hcid/hcid.h | 27 ++++++--- hcid/lexer.l | 21 +++++-- hcid/main.c | 178 ++++++++++++++++++++++++++++++++++++++++++++-------------- 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 -#include "glib-ectomy.h" - #include +#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 @@ -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 #include @@ -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 WORD PATH STRING LIST +%token WORD PATH STRING LIST HCI BDADDR %token NUM %type bool pkt_type link_mode link_policy sec_mode pair_mode -%type dev_name +%type 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; } -- cgit