diff options
-rw-r--r-- | network/server.c | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/network/server.c b/network/server.c index 427bff8b..1a02bb50 100644 --- a/network/server.c +++ b/network/server.c @@ -25,11 +25,14 @@ #include <config.h> #endif +#include <unistd.h> #include <stdlib.h> #include <errno.h> +#include <sys/socket.h> #include <bluetooth/bluetooth.h> #include <bluetooth/bnep.h> +#include <bluetooth/l2cap.h> #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> @@ -51,6 +54,7 @@ struct network_server { dbus_bool_t secure; uint32_t record_id; /* Service record id */ uint16_t id; /* Service class identifier */ + GIOChannel *io; /* GIOChannel when listening */ }; void add_lang_attr(sdp_record_t *r) @@ -183,6 +187,86 @@ static int create_server_record(sdp_buf_t *buf, uint16_t id) return ret; } +static gboolean connect_event(GIOChannel *chan, + GIOCondition cond, gpointer data) +{ + info("FIXME: Connect event"); + return FALSE; +} + +static int l2cap_listen(struct network_server *ns) +{ + struct l2cap_options l2o; + struct sockaddr_l2 l2a; + socklen_t olen; + int sk, lm, err; + + /* Create L2CAP socket and bind it to PSM BNEP */ + sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (sk < 0) { + err = errno; + error("Cannot create L2CAP socket. %s(%d)", + strerror(err), err); + return -err; + } + + memset(&l2a, 0, sizeof(l2a)); + l2a.l2_family = AF_BLUETOOTH; + bacpy(&l2a.l2_bdaddr, BDADDR_ANY); + l2a.l2_psm = htobs(BNEP_PSM); + + if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a))) { + err = errno; + error("Bind failed. %s(%d)", strerror(err), err); + goto fail; + } + + /* Setup L2CAP options according to BNEP spec */ + memset(&l2o, 0, sizeof(l2o)); + olen = sizeof(l2o); + if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen) < 0) { + err = errno; + error("Failed to get L2CAP options. %s(%d)", + strerror(err), err); + goto fail; + } + + l2o.imtu = l2o.omtu = BNEP_MTU; + if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) { + err = errno; + error("Failed to set L2CAP options. %s(%d)", + strerror(err), err); + goto fail; + } + + /* Set link mode */ + lm = (ns->secure ? L2CAP_LM_SECURE : 0); + if (lm && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) < 0) { + err = errno; + error("Failed to set link mode. %s(%d)", + strerror(err), err); + goto fail; + } + + if (listen(sk, 10) < 0) { + err = errno; + error("Listen failed. %s(%d)", strerror(err), err); + goto fail; + } + + ns->io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(ns->io, TRUE); + + g_io_add_watch(ns->io, G_IO_IN, connect_event, NULL); + + return 0; +fail: + + close(sk); + errno = err; + return -err; +} + static uint32_t add_server_record(DBusConnection *conn, uint16_t id) { DBusMessage *msg, *reply; @@ -259,6 +343,7 @@ static DBusHandlerResult enable(DBusConnection *conn, { struct network_server *ns = data; DBusMessage *reply; + int err; reply = dbus_message_new_method_return(msg); if (!reply) @@ -273,7 +358,9 @@ static DBusHandlerResult enable(DBusConnection *conn, /* FIXME: Check security */ - /* FIXME: Start listen */ + err = l2cap_listen(ns); + if (err < 0) + return err_failed(conn, msg, strerror(-err)); return send_message_and_unref(conn, reply); } |