diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2004-02-17 18:04:03 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2004-02-17 18:04:03 +0000 | 
| commit | f17bb94f47090f3397b60b5e264aa9f18dbf203d (patch) | |
| tree | cd475c5e55def20433d0ac0e83a0410e0606da91 | |
| parent | 5903cfe8fdfa5df4a0ce737219385d16da85e279 (diff) | |
Add D-Bus support for PIN request
| -rw-r--r-- | hcid/Makefile.am | 8 | ||||
| -rw-r--r-- | hcid/dbus.c | 206 | ||||
| -rw-r--r-- | hcid/glib-ectomy.c | 19 | ||||
| -rw-r--r-- | hcid/glib-ectomy.h | 2 | ||||
| -rw-r--r-- | hcid/hcid.h | 6 | ||||
| -rw-r--r-- | hcid/kword.c | 76 | ||||
| -rw-r--r-- | hcid/kword.h | 44 | ||||
| -rw-r--r-- | hcid/lexer.l | 5 | ||||
| -rw-r--r-- | hcid/lib.c | 4 | ||||
| -rw-r--r-- | hcid/main.c | 12 | ||||
| -rw-r--r-- | hcid/parser.y | 12 | ||||
| -rw-r--r-- | hcid/security.c | 21 | 
12 files changed, 347 insertions, 68 deletions
| diff --git a/hcid/Makefile.am b/hcid/Makefile.am index 378d3a35..14428722 100644 --- a/hcid/Makefile.am +++ b/hcid/Makefile.am @@ -4,7 +4,13 @@  sbin_PROGRAMS = hcid -hcid_SOURCES = main.c security.c hcid.h lib.c lib.h parser.h parser.y lexer.l kword.h kword.c glib-ectomy.h glib-ectomy.c +if ENABLE_DBUS +dbus_hcid_sources = dbus.c +else +dbus_hcid_sources = +endif + +hcid_SOURCES = main.c security.c hcid.h lib.c lib.h parser.h parser.y lexer.l kword.h kword.c glib-ectomy.h glib-ectomy.c $(dbus_hcid_sources)  hcid_CONFIG  = hcid.conf  YFLAGS   = -d diff --git a/hcid/dbus.c b/hcid/dbus.c new file mode 100644 index 00000000..4c2bb18d --- /dev/null +++ b/hcid/dbus.c @@ -0,0 +1,206 @@ +#include <stdio.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus.h> + +#include "hcid.h" +#include "glib-ectomy.h" + +static DBusConnection *connection; + +#define TIMEOUT (30 * 1000)		// 30 seconds + +#define SERVICE_NAME "org.handhelds.gpe.bluez" +#define INTERFACE_NAME SERVICE_NAME ".PinAgent" +#define REQUEST_NAME "PinRequest" +#define PATH_NAME "/org/handhelds/gpe/bluez/PinAgent" + +#define WRONG_ARGS_ERROR "org.handhelds.gpe.bluez.Error.WrongArgs" + +struct pin_request +{ +	int dev; +	bdaddr_t bda; +}; + +static void reply_handler_function(DBusPendingCall *call, void *user_data) +{ +	struct pin_request *req = (struct pin_request *) user_data; +	pin_code_reply_cp pr; +	DBusMessage *message; +	DBusMessageIter iter; +	int type; +	size_t len; +	char *pin; + +	message = dbus_pending_call_get_reply(call); + +	if (dbus_message_is_error(message, WRONG_ARGS_ERROR)) +		goto error; + +	dbus_message_iter_init(message, &iter); + +	type = dbus_message_iter_get_arg_type(&iter); +	if (type != DBUS_TYPE_STRING) +		goto error; + +	pin = dbus_message_iter_get_string(&iter); +	len = strlen(pin); + +	memset(&pr, 0, sizeof(pr)); +	bacpy(&pr.bdaddr, &req->bda); +	memcpy(pr.pin_code, pin, len); +	pr.pin_len = len; +	hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, +						PIN_CODE_REPLY_CP_SIZE, &pr); + +	return; + +error: +	hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, +							6, &req->bda); +} + + +static void free_pin_req(void *req) +{ +	free(req); +} + +void hcid_dbus_request_pin(int dev, struct hci_conn_info *ci) +{ +	DBusMessage *message; +	DBusMessageIter iter; +	DBusPendingCall *pending = NULL; +	struct pin_request *req; + +	message = dbus_message_new_method_call(SERVICE_NAME, PATH_NAME, +						INTERFACE_NAME, REQUEST_NAME); +	if (message == NULL) { +		syslog(LOG_ERR, "Couldn't allocate D-BUS message"); +		goto failed; +	} + +	req = malloc(sizeof(*req)); +	req->dev = dev; +	bacpy(&req->bda, &ci->bdaddr); + +	dbus_message_append_iter_init(message, &iter); + +	dbus_message_iter_append_boolean(&iter, ci->out); +	dbus_message_iter_append_byte_array(&iter, +			(unsigned char *) &ci->bdaddr, sizeof(ci->bdaddr)); + +	if (dbus_connection_send_with_reply(connection, message, +						&pending, TIMEOUT) == FALSE) { +		syslog(LOG_ERR, "D-BUS send failed"); +		goto failed; +	} + +	dbus_pending_call_set_notify(pending, reply_handler_function, +							req, free_pin_req); + +	dbus_connection_flush (connection); + +	dbus_message_unref (message); + +	return; + +failed: +	dbus_message_unref (message); +	hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, +							6, &ci->bdaddr); +} + +gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) +{ +	DBusWatch *watch = (DBusWatch *) data; +	int flags = 0; + +	if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE; +	if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE; +	if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP; +	if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR; + +	dbus_watch_handle(watch, flags); + +	dbus_connection_ref(connection); + +	/* Dispatch messages */ +	while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS); + +	dbus_connection_unref(connection); + +	return TRUE; +} + +dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ +	GIOCondition cond = G_IO_HUP | G_IO_ERR; +	GIOChannel *io; +	guint id; +	int fd, flags; + +	if (!dbus_watch_get_enabled(watch)) +		return TRUE; + +	fd = dbus_watch_get_fd(watch); +	io = g_io_channel_unix_new(fd); +	flags = dbus_watch_get_flags(watch); + +	if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN; +	if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT; + +	id = g_io_add_watch(io, cond, watch_func, watch); + +	dbus_watch_set_data(watch, (void *) id, NULL); + +	return TRUE; +} + +static void remove_watch(DBusWatch *watch, void *data) +{ +	guint id = (guint) dbus_watch_get_data(watch); + +	dbus_watch_set_data(watch, NULL, NULL); + +	if (id) +		g_io_remove_watch(id); +} + +static void watch_toggled(DBusWatch *watch, void *data) +{ +	/* Because we just exit on OOM, enable/disable is +	 * no different from add/remove +	 */ +	if (dbus_watch_get_enabled(watch)) +		add_watch(watch, data); +	else +		remove_watch(watch, data); +} + +gboolean hcid_dbus_init(void) +{ +	DBusError error; + +	dbus_error_init(&error); + +	connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); +	if (connection == NULL) { +		fprintf(stderr, "Failed to open connection to system message bus: %s\n", +			error.message); +		dbus_error_free(&error); +		return FALSE; +	} + +	dbus_connection_set_watch_functions(connection, +		add_watch, remove_watch, watch_toggled, NULL, NULL); + +	return TRUE; +} diff --git a/hcid/glib-ectomy.c b/hcid/glib-ectomy.c index 5b56855e..8489cd73 100644 --- a/hcid/glib-ectomy.c +++ b/hcid/glib-ectomy.c @@ -1,5 +1,3 @@ -#include "glib-ectomy.h" -  #include <stdio.h>  #include <string.h>  #include <stdlib.h> @@ -8,7 +6,7 @@  #include <fcntl.h>  #include <limits.h> -// static void remove_watch(int fd); +#include "glib-ectomy.h"  GIOError    g_io_channel_read   (GIOChannel    *channel,   			         gchar         *buf,  @@ -84,6 +82,21 @@ struct watch {  static struct watch watch_head = { .id = 0, .next = 0 }; +void  g_io_remove_watch (guint id) +{ +  struct watch *w, *p; + +  for (p = &watch_head, w = watch_head.next; w; w = w->next) +    { +      if (w->id == id) +	{ +	  p->next = w->next; +	  free (w); +	  return; +	} +    } +} +  guint     g_io_add_watch        (GIOChannel      *channel,  				 GIOCondition     condition,  				 GIOFunc          func, diff --git a/hcid/glib-ectomy.h b/hcid/glib-ectomy.h index b1ac263b..703ae54b 100644 --- a/hcid/glib-ectomy.h +++ b/hcid/glib-ectomy.h @@ -92,6 +92,8 @@ guint     g_io_add_watch        (GIOChannel      *channel,  				 GIOCondition     condition,  				 GIOFunc          func,  				 gpointer         user_data); +void  g_io_remove_watch (guint id); +  GMainLoop *g_main_loop_new        (GMainContext *context, diff --git a/hcid/hcid.h b/hcid/hcid.h index 3bd0ad46..f8233d70 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -76,6 +76,7 @@ struct hcid_opts {  	int     pin_len;  	char   *pin_helper;  	char   *pin_file; +	int     dbus_pin_helper;  	char   *key_file; @@ -102,3 +103,8 @@ void init_security_data(void);  void start_security_manager(int hdev);  void stop_security_manager(int hdev);  void toggle_pairing(int enable); + +#ifdef ENABLE_DBUS +void hcid_dbus_request_pin(int dev, struct hci_conn_info *ci); +gboolean hcid_dbus_init(void); +#endif diff --git a/hcid/kword.c b/hcid/kword.c index 0486f21b..09ad0573 100644 --- a/hcid/kword.c +++ b/hcid/kword.c @@ -26,58 +26,64 @@  #include <stdlib.h>  #include <string.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h>  #include "hcid.h"  #include "kword.h"  #include "parser.h"  struct kword cfg_keyword[] = { -   { "options",  K_OPTIONS	},  -   { "default",  K_DEVICE	},  -   { "device",   K_DEVICE	},  -   { "autoinit", K_AUTOINIT	},  -   { "security", K_SECURITY	},  -   { "pairing",  K_PAIRING	},  -   { "pkt_type", K_PTYPE	},  -   { "lm", 	 K_LM		},  -   { "lp", 	 K_LP		},  -   { "iscan", 	 K_ISCAN	},  -   { "pscan", 	 K_PSCAN	},  -   { "name",     K_NAME		},  -   { "class",    K_CLASS	},  -   { "auth",	 K_AUTH		}, -   { "encrypt",  K_ENCRYPT	}, -   { "pin_helper",  K_PINHELP	}, +	{ "options",		K_OPTIONS	}, +	{ "default",		K_DEVICE	}, +	{ "device",		K_DEVICE	}, +	{ "autoinit",		K_AUTOINIT	}, +	{ "security",		K_SECURITY	}, +	{ "pairing",		K_PAIRING	}, +	{ "pkt_type",		K_PTYPE		}, +	{ "lm", 		K_LM		}, +	{ "lp", 		K_LP		}, +	{ "iscan",		K_ISCAN		}, +	{ "pscan",		K_PSCAN		}, +	{ "name",		K_NAME		}, +	{ "class",		K_CLASS		}, +	{ "auth",		K_AUTH		}, +	{ "encrypt",		K_ENCRYPT	}, +	{ "pin_helper",		K_PINHELP	}, +	{ "dbus_pin_helper",	K_DBUSPINHELP	}, -   { "yes",      K_YES		}, -   { "no",       K_NO		}, -   { "enable",	 K_YES		}, -   { "disable",	 K_NO		}, -   { NULL , 0 } +	{ "yes",		K_YES		}, +	{ "no",			K_NO		}, +	{ "enable",		K_YES		}, +	{ "disable",		K_NO		}, +	{ NULL , 0 }  };  struct kword sec_param[] = { -   { "none",	 HCID_SEC_NONE	}, -   { "auto",	 HCID_SEC_AUTO	}, -   { "user",	 HCID_SEC_USER	}, -   { NULL , 0 } +	{ "none",		HCID_SEC_NONE	}, +	{ "auto",		HCID_SEC_AUTO	}, +	{ "user",		HCID_SEC_USER	}, +	{ NULL , 0 }  };  struct kword pair_param[] = { -   { "none",	 HCID_PAIRING_NONE	}, -   { "multi",	 HCID_PAIRING_MULTI	}, -   { "once",	 HCID_PAIRING_ONCE	}, -   { NULL , 0 } +	{ "none",	HCID_PAIRING_NONE	}, +	{ "multi",	HCID_PAIRING_MULTI	}, +	{ "once",	HCID_PAIRING_ONCE	}, +	{ NULL , 0 }  };  int lineno;  int find_keyword(struct kword *kw, char *str)  { -    while( kw->str ){ -	if( !strcmp(str,kw->str) ) -	   return kw->type; -	kw++; -    } -    return -1; +	while (kw->str) { +		if (!strcmp(str,kw->str)) +			return kw->type; +		kw++; +	} +	return -1;  } diff --git a/hcid/kword.h b/hcid/kword.h index 10c54493..67baaf13 100644 --- a/hcid/kword.h +++ b/hcid/kword.h @@ -1,32 +1,32 @@  /*  -	BlueZ - Bluetooth protocol stack for Linux -	Copyright (C) 2000-2001 Qualcomm Incorporated - -	Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> - -	This program is free software; you can redistribute it and/or modify -	it under the terms of the GNU General Public License version 2 as -	published by the Free Software Foundation; - -	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. -	IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, -	OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER -	RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -	NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE -	USE OR PERFORMANCE OF THIS SOFTWARE. - -	ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, -	TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. +   BlueZ - Bluetooth protocol stack for Linux +   Copyright (C) 2000-2001 Qualcomm Incorporated +    +   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> +    +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License version 2 as +   published by the Free Software Foundation; +    +   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, +   OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +   RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +   NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +   USE OR PERFORMANCE OF THIS SOFTWARE. +    +   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, +   TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED.  */  /*   * $Id$   */   struct kword { -   char *str; -   int  type; +	char *str; +	int  type;  };  extern int lineno; diff --git a/hcid/lexer.l b/hcid/lexer.l index 1947bcd4..3c9ed308 100644 --- a/hcid/lexer.l +++ b/hcid/lexer.l @@ -27,6 +27,11 @@   */  #include <string.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h>  #include "hcid.h"  #include "kword.h" @@ -32,6 +32,10 @@  #include <netdb.h>  #include <signal.h> +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +  #include "hcid.h"  #include "lib.h" diff --git a/hcid/main.c b/hcid/main.c index d5c52c9d..c3f4131d 100644 --- a/hcid/main.c +++ b/hcid/main.c @@ -541,6 +541,18 @@ int main(int argc, char *argv[], char *env[])  	if (read_config(hcid.config_file) < 0)  		syslog(LOG_ERR, "Config load failed"); +#ifdef ENABLE_DBUS +	if (hcid_dbus_init() == FALSE && hcid.dbus_pin_helper) { +		syslog(LOG_ERR, "Unable to get on D-BUS"); +		exit(1); +	} +#else +	if (hcid.dbus_pin_helper) { +		syslog(LOG_ERR, "D-BUS not configured in this build of hcid"); +		exit(1); +	} +#endif +  	init_security_data();  	/* Create event loop */ diff --git a/hcid/parser.y b/hcid/parser.y index e14ca200..1848bd04 100644 --- a/hcid/parser.y +++ b/hcid/parser.y @@ -58,7 +58,7 @@ int yyerror(char *s);  %token K_OPTIONS K_DEVICE  %token K_AUTOINIT K_SECURITY K_PAIRING  %token K_PTYPE K_NAME K_CLASS K_LM K_LP K_AUTH K_ENCRYPT K_ISCAN K_PSCAN -%token K_PINHELP +%token K_PINHELP K_DBUSPINHELP  %token K_YES K_NO  %token <str> WORD PATH STRING LIST HCI BDADDR @@ -112,10 +112,18 @@ hcid_opt:  				hcid.pairing = $2;  			} -  | K_PINHELP  PATH	{ +  | K_PINHELP PATH	{  				if (hcid.pin_helper)  					free(hcid.pin_helper);  				hcid.pin_helper = strdup($2); +				hcid.dbus_pin_helper = 0; +			} + +  | K_DBUSPINHELP	{ +				if (hcid.pin_helper) +					free(hcid.pin_helper); +				hcid.pin_helper = NULL; +				hcid.dbus_pin_helper = 1;  			}    | WORD		{ diff --git a/hcid/security.c b/hcid/security.c index 7aa9a7a4..189bc7d8 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -173,7 +173,7 @@ static void link_key_notify(int dev, bdaddr_t *sba, void *ptr)  	evt_link_key_notify *evt = ptr;  	bdaddr_t *dba = &evt->bdaddr;  	struct link_key key; -        char sa[18]; +	char sa[18];  	ba2str(sba, sa);  	syslog(LOG_INFO, "link_key_notify (sba=%s)\n", sa); @@ -291,6 +291,17 @@ reject:  	exit(0);  } +static void request_pin(int dev, struct hci_conn_info *ci) +{ +#ifdef ENABLE_DBUS +	if (hcid.dbus_pin_helper) { +		hcid_dbus_request_pin(dev, ci); +		return; +	} +#endif +	call_pin_helper(dev, ci); +} +  static void pin_code_request(int dev, bdaddr_t *sba, bdaddr_t *dba)  {  	struct hci_conn_info_req *cr; @@ -337,11 +348,11 @@ static void pin_code_request(int dev, bdaddr_t *sba, bdaddr_t *dba)  			/* Outgoing connection */  			/* Let PIN helper handle that */  -			call_pin_helper(dev, ci); +			request_pin(dev, ci);  		}  	} else {  		/* Let PIN helper handle that */  -		call_pin_helper(dev, ci); +		request_pin(dev, ci);  	}	  	free(cr);  	return; @@ -397,7 +408,7 @@ gboolean io_security_event(GIOChannel *chan, GIOCondition cond, gpointer data)  		link_key_notify(dev, &di->bdaddr, ptr);  		break;  	} -		 +  	return TRUE;  } @@ -410,7 +421,7 @@ void start_security_manager(int hdev)  	if (chan)  		return; -	 +  	syslog(LOG_INFO, "Starting security manager %d", hdev);  	if ((dev = hci_open_dev(hdev)) < 0) { | 
