#include <bluetooth/l2cap.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sco.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
#include <glib.h>
int master;
uint8_t mode;
int flushable;
+ uint32_t priority;
};
struct connect {
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");
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;
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;
/* 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 *));
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);
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)
{
uint16_t handle;
socklen_t len;
gboolean flushable = FALSE;
+ uint32_t priority;
len = sizeof(l2o);
memset(&l2o, 0, len);
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;
}
*(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);
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);
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:
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:
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:
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: