summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2004-02-17 18:04:03 +0000
committerMarcel Holtmann <marcel@holtmann.org>2004-02-17 18:04:03 +0000
commitf17bb94f47090f3397b60b5e264aa9f18dbf203d (patch)
treecd475c5e55def20433d0ac0e83a0410e0606da91
parent5903cfe8fdfa5df4a0ce737219385d16da85e279 (diff)
Add D-Bus support for PIN request
-rw-r--r--hcid/Makefile.am8
-rw-r--r--hcid/dbus.c206
-rw-r--r--hcid/glib-ectomy.c19
-rw-r--r--hcid/glib-ectomy.h2
-rw-r--r--hcid/hcid.h6
-rw-r--r--hcid/kword.c76
-rw-r--r--hcid/kword.h44
-rw-r--r--hcid/lexer.l5
-rw-r--r--hcid/lib.c4
-rw-r--r--hcid/main.c12
-rw-r--r--hcid/parser.y12
-rw-r--r--hcid/security.c21
12 files changed, 347 insertions, 68 deletions
diff --git a/hcid/Makefile.am b/hcid/Makefile.am
index 378d3a353..144287221 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 000000000..4c2bb18d4
--- /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 5b56855e2..8489cd73c 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 b1ac263b1..703ae54be 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 3bd0ad465..f8233d70e 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 0486f21b3..09ad05734 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 10c54493e..67baaf13c 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 1947bcd41..3c9ed3081 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"
diff --git a/hcid/lib.c b/hcid/lib.c
index 2e3100121..bb85feb4d 100644
--- a/hcid/lib.c
+++ b/hcid/lib.c
@@ -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 d5c52c9d6..c3f4131dc 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 e14ca2003..1848bd041 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 7aa9a7a48..189bc7d88 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) {