call-barring: Conform to coding style item M4
[platform/upstream/ofono.git] / btio / btio.c
index 6d71b90..9781ec4 100644 (file)
 #include <bluetooth/l2cap.h>
 #include <bluetooth/rfcomm.h>
 #include <bluetooth/sco.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
 
 #include <glib.h>
 
 #include "btio.h"
 
+#ifndef BT_FLUSHABLE
+#define BT_FLUSHABLE   8
+#endif
+
 #define ERROR_FAILED(gerr, str, err) \
                g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
                                str ": %s (%d)", strerror(err), err)
@@ -60,6 +62,7 @@ struct set_opts {
        int master;
        uint8_t mode;
        int flushable;
+       uint32_t priority;
 };
 
 struct connect {
@@ -148,16 +151,18 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
                return FALSE;
 
        if (cond & G_IO_OUT) {
-               int err = 0, sock = g_io_channel_unix_get_fd(io);
-               socklen_t len = sizeof(err);
+               int err, sk_err = 0, sock = g_io_channel_unix_get_fd(io);
+               socklen_t len = sizeof(sk_err);
 
-               if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
-                       err = errno;
+               if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+                       err = -errno;
+               else
+                       err = -sk_err;
 
-               if (err)
+               if (err < 0)
                        g_set_error(&gerr, BT_IO_ERROR,
                                        BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
-                                       strerror(err), err);
+                                       strerror(-err), -err);
        } else if (cond & (G_IO_HUP | G_IO_ERR))
                g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
                                "HUP or ERR on socket");
@@ -267,8 +272,9 @@ static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm,
                addr.l2_psm = htobs(psm);
 
        if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               int error = -errno;
                ERROR_FAILED(err, "l2cap_bind", errno);
-               return -1;
+               return error;
        }
 
        return 0;
@@ -290,7 +296,7 @@ static int l2cap_connect(int sock, const bdaddr_t *dst,
 
        err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
-               return err;
+               return -errno;
 
        return 0;
 }
@@ -497,9 +503,32 @@ static int l2cap_set_flushable(int sock, gboolean flushable)
        return 0;
 }
 
+static int set_priority(int sock, uint32_t prio)
+{
+       if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0)
+               return -errno;
+
+       return 0;
+}
+
+static gboolean get_key_size(int sock, int *size, GError **err)
+{
+       struct bt_security sec;
+       socklen_t len;
+
+       memset(&sec, 0, sizeof(sec));
+       len = sizeof(sec);
+       if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) {
+               *size = sec.key_size;
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
 static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu,
                                uint16_t omtu, uint8_t mode, int master,
-                               int flushable, GError **err)
+                               int flushable, uint32_t priority, GError **err)
 {
        if (imtu || omtu || mode) {
                struct l2cap_options l2o;
@@ -537,6 +566,11 @@ static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu,
                return FALSE;
        }
 
+       if (priority > 0 && set_priority(sock, priority) < 0) {
+               ERROR_FAILED(err, "set_priority", errno);
+               return FALSE;
+       }
+
        if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
                return FALSE;
 
@@ -554,8 +588,9 @@ static int rfcomm_bind(int sock,
        addr.rc_channel = channel;
 
        if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               int error = -errno;
                ERROR_FAILED(err, "rfcomm_bind", errno);
-               return -1;
+               return error;
        }
 
        return 0;
@@ -573,7 +608,7 @@ static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
 
        err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
-               return err;
+               return -errno;
 
        return 0;
 }
@@ -600,8 +635,9 @@ static int sco_bind(int sock, const bdaddr_t *src, GError **err)
        bacpy(&addr.sco_bdaddr, src);
 
        if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               int error = -errno;
                ERROR_FAILED(err, "sco_bind", errno);
-               return -1;
+               return error;
        }
 
        return 0;
@@ -618,7 +654,7 @@ static int sco_connect(int sock, const bdaddr_t *dst)
 
        err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
-               return err;
+               return -errno;
 
        return 0;
 }
@@ -659,18 +695,15 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
        /* Set defaults */
        opts->defer = DEFAULT_DEFER_TIMEOUT;
        opts->master = -1;
-       opts->sec_level = BT_IO_SEC_MEDIUM;
        opts->mode = L2CAP_MODE_BASIC;
        opts->flushable = -1;
+       opts->priority = 0;
 
        while (opt != BT_IO_OPT_INVALID) {
                switch (opt) {
                case BT_IO_OPT_SOURCE:
                        str = va_arg(args, const char *);
-                       if (strncasecmp(str, "hci", 3) == 0)
-                               hci_devba(atoi(str + 3), &opts->src);
-                       else
-                               str2ba(str, &opts->src);
+                       str2ba(str, &opts->src);
                        break;
                case BT_IO_OPT_SOURCE_BDADDR:
                        bacpy(&opts->src, va_arg(args, const bdaddr_t *));
@@ -720,6 +753,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                case BT_IO_OPT_FLUSHABLE:
                        opts->flushable = va_arg(args, gboolean);
                        break;
+               case BT_IO_OPT_PRIORITY:
+                       opts->priority = va_arg(args, int);
+                       break;
                default:
                        g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
                                        "Unknown option %d", opt);
@@ -790,6 +826,17 @@ static int l2cap_get_flushable(int sock, gboolean *flushable)
        return 0;
 }
 
+static int get_priority(int sock, uint32_t *prio)
+{
+       socklen_t len;
+
+       len = sizeof(*prio);
+       if (getsockopt(sock, SOL_SOCKET, SO_PRIORITY, prio, &len) < 0)
+               return -errno;
+
+       return 0;
+}
+
 static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                                                                va_list args)
 {
@@ -800,7 +847,8 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
        uint8_t dev_class[3];
        uint16_t handle;
        socklen_t len;
-       gboolean flushable;
+       gboolean flushable = FALSE;
+       uint32_t priority;
 
        len = sizeof(l2o);
        memset(&l2o, 0, len);
@@ -841,13 +889,17 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                                                va_arg(args, int *), err))
                                return FALSE;
                        break;
+               case BT_IO_OPT_KEY_SIZE:
+                       if (!get_key_size(sock, va_arg(args, int *), err))
+                               return FALSE;
+                       break;
                case BT_IO_OPT_PSM:
                        *(va_arg(args, uint16_t *)) = src.l2_psm ?
-                                               src.l2_psm : dst.l2_psm;
+                                       btohs(src.l2_psm) : btohs(dst.l2_psm);
                        break;
                case BT_IO_OPT_CID:
                        *(va_arg(args, uint16_t *)) = src.l2_cid ?
-                                               src.l2_cid : dst.l2_cid;
+                                       btohs(src.l2_cid) : btohs(dst.l2_cid);
                        break;
                case BT_IO_OPT_OMTU:
                        *(va_arg(args, uint16_t *)) = l2o.omtu;
@@ -890,6 +942,13 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                        }
                        *(va_arg(args, gboolean *)) = flushable;
                        break;
+               case BT_IO_OPT_PRIORITY:
+                       if (get_priority(sock, &priority) < 0) {
+                               ERROR_FAILED(err, "get_priority", errno);
+                               return FALSE;
+                       }
+                       *(va_arg(args, uint32_t *)) = priority;
+                       break;
                default:
                        g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
                                        "Unknown option %d", opt);
@@ -1102,6 +1161,7 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
        switch (type) {
        case BT_IO_L2RAW:
        case BT_IO_L2CAP:
+       case BT_IO_L2ERTM:
                return l2cap_get(sock, err, opt1, args);
        case BT_IO_RFCOMM:
                return rfcomm_get(sock, err, opt1, args);
@@ -1133,8 +1193,10 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
        }
 
        if (!(pfd.revents & POLLOUT)) {
-               int ret;
-               ret = read(sock, &c, 1);
+               if (read(sock, &c, 1) < 0) {
+                       ERROR_FAILED(err, "read", errno);
+                       return FALSE;
+               }
        }
 
        accept_add(io, connect, user_data, destroy);
@@ -1162,8 +1224,10 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
        switch (type) {
        case BT_IO_L2RAW:
        case BT_IO_L2CAP:
+       case BT_IO_L2ERTM:
                return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
-                               opts.mode, opts.master, opts.flushable, err);
+                               opts.mode, opts.master, opts.flushable,
+                               opts.priority, err);
        case BT_IO_RFCOMM:
                return rfcomm_set(sock, opts.sec_level, opts.master, err);
        case BT_IO_SCO:
@@ -1204,7 +1268,7 @@ static GIOChannel *create_io(BtIOType type, gboolean server,
                if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
                                                        opts->cid, err) < 0)
                        goto failed;
-               if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, -1, err))
+               if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, -1, 0, err))
                        goto failed;
                break;
        case BT_IO_L2CAP:
@@ -1217,7 +1281,22 @@ static GIOChannel *create_io(BtIOType type, gboolean server,
                                                        opts->cid, err) < 0)
                        goto failed;
                if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
-                               opts->mode, opts->master, opts->flushable, err))
+                               opts->mode, opts->master, opts->flushable,
+                               opts->priority, err))
+                       goto failed;
+               break;
+       case BT_IO_L2ERTM:
+               sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
+               if (sock < 0) {
+                       ERROR_FAILED(err, "socket(STREAM, L2CAP)", errno);
+                       return NULL;
+               }
+               if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
+                                                       opts->cid, err) < 0)
+                       goto failed;
+               if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
+                               opts->mode, opts->master, opts->flushable,
+                               opts->priority, err))
                        goto failed;
                break;
        case BT_IO_RFCOMM:
@@ -1290,6 +1369,7 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
                err = l2cap_connect(sock, &opts.dst, 0, opts.cid);
                break;
        case BT_IO_L2CAP:
+       case BT_IO_L2ERTM:
                err = l2cap_connect(sock, &opts.dst, opts.psm, opts.cid);
                break;
        case BT_IO_RFCOMM: