* [PATCH 3/4] Bluetooth: Use common SOCK_STREAM receive code in RFCOMM
From: Mat Martineau @ 2010-09-08 17:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, rshaffer, linux-arm-msm, Mat Martineau
In-Reply-To: <1283965529-17068-1-git-send-email-mathewm@codeaurora.org>
To reduce code duplication, have rfcomm_sock_recvmsg() call
bt_sock_stream_recvmsg(). The common bt_sock_stream_recvmsg()
code is nearly identical, with the RFCOMM-specific functionality
for deferred setup and connection unthrottling left in
rfcomm_sock_recvmsg().
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/rfcomm/sock.c | 104 +++----------------------------------------
1 files changed, 6 insertions(+), 98 deletions(-)
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 44a6232..4396f47 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -617,121 +617,29 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
return sent;
}
-static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(sk_sleep(sk), &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (!skb_queue_empty(&sk->sk_receive_queue) ||
- sk->sk_err ||
- (sk->sk_shutdown & RCV_SHUTDOWN) ||
- signal_pending(current) ||
- !timeo)
- break;
-
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- }
-
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
- return timeo;
-}
-
static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
- int err = 0;
- size_t target, copied = 0;
- long timeo;
+ int len;
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
rfcomm_dlc_accept(d);
return 0;
}
- if (flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- msg->msg_namelen = 0;
-
- BT_DBG("sk %p size %zu", sk, size);
+ len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags);
lock_sock(sk);
+ if (!(flags & MSG_PEEK) && len > 0)
+ atomic_sub(len, &sk->sk_rmem_alloc);
- target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
- timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-
- do {
- struct sk_buff *skb;
- int chunk;
-
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (!skb) {
- if (copied >= target)
- break;
-
- if ((err = sock_error(sk)) != 0)
- break;
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- break;
-
- err = -EAGAIN;
- if (!timeo)
- break;
-
- timeo = rfcomm_sock_data_wait(sk, timeo);
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- goto out;
- }
- continue;
- }
-
- chunk = min_t(unsigned int, skb->len, size);
- if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- if (!copied)
- copied = -EFAULT;
- break;
- }
- copied += chunk;
- size -= chunk;
-
- sock_recv_ts_and_drops(msg, sk, skb);
-
- if (!(flags & MSG_PEEK)) {
- atomic_sub(chunk, &sk->sk_rmem_alloc);
-
- skb_pull(skb, chunk);
- if (skb->len) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- kfree_skb(skb);
-
- } else {
- /* put message back and return */
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- } while (size);
-
-out:
if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
-
release_sock(sk);
- return copied ? : err;
+
+ return len;
}
static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
--
1.7.1
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply related
* [PATCH 4/4] Bluetooth: Use a stream-oriented recvmsg with SOCK_STREAM L2CAP sockets.
From: Mat Martineau @ 2010-09-08 17:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, rshaffer, linux-arm-msm, Mat Martineau
In-Reply-To: <1283965529-17068-1-git-send-email-mathewm@codeaurora.org>
L2CAP ERTM sockets can be opened with the SOCK_STREAM socket type,
which is a mandatory request for ERTM mode.
However, these sockets still have SOCK_SEQPACKET read semantics when
bt_sock_recvmsg() is used to pull data from the receive queue. If the
application is only reading part of a frame, then the unread portion
of the frame is discarded. If the application requests more bytes
than are in the current frame, only the current frame's data is
returned.
This patch utilizes common code derived from RFCOMM's recvmsg()
function to make L2CAP SOCK_STREAM reads behave like RFCOMM reads (and
other SOCK_STREAM sockets in general). The application may read one
byte at a time from the input stream and not lose any data, and may
also read across L2CAP frame boundaries.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
net/bluetooth/l2cap.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index b5eff42..38aa78c 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1961,6 +1961,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
release_sock(sk);
+ if (sock->type == SOCK_STREAM)
+ return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
+
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
}
--
1.7.1
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply related
* [PATCH v3] Bluetooth: Add socket option definitions for AMP
From: Mat Martineau @ 2010-09-08 17:16 UTC (permalink / raw)
To: linux-bluetooth
Cc: marcel, gustavo, rshaffer, haijun.liu, linux-arm-msm,
Mat Martineau
This adds a new BT_AMP socket option to control the use of AMP channels.
It is for use with the SOL_BLUETOOTH option level on L2CAP sockets.
Available option values are defined as:
BT_AMP_REQUIRE_BR_EDR
* Default
* AMP controllers cannot be used
* Channel move requests from the remote device are denied
* If the L2CAP channel is currently using AMP, move the channel to
BR/EDR
BT_AMP_PREFER_AMP
* Allow use of AMP controllers
* If the L2CAP channel is currently on BR/EDR and AMP controller
resources are available, initiate a channel move to AMP
* Channel move requests from the remote device are allowed
* If the L2CAP socket has not been connected yet, try to create
and configure the channel directly on an AMP controller rather
than BR/EDR
BT_AMP_PREFER_BR_EDR
* Allow use of AMP controllers
* If the L2CAP channel is currently on AMP, move it to BR/EDR
* Channel move requests from the remote device are allowed
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
include/net/bluetooth/bluetooth.h | 28 ++++++++++++++++++++++++++++
1 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 27a902d..d2c62dc 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -64,6 +64,34 @@ struct bt_security {
#define BT_DEFER_SETUP 7
+
+#define BT_AMP_POLICY 8
+
+/* Require BR/EDR (default policy)
+ * AMP controllers cannot be used
+ * Channel move requests from the remote device are denied
+ * If the L2CAP channel is currently using AMP, move the channel to BR/EDR
+ */
+#define BT_AMP_POLICY_REQUIRE_BR_EDR 0
+
+/* Prefer AMP
+ * Allow use of AMP controllers
+ * If the L2CAP channel is currently on BR/EDR and AMP controller
+ * resources are available, initiate a channel move to AMP
+ * Channel move requests from the remote device are allowed
+ * If the L2CAP socket has not been connected yet, try to create
+ * and configure the channel directly on an AMP controller rather
+ * than BR/EDR
+ */
+#define BT_AMP_POLICY_PREFER_AMP 1
+
+/* Prefer BR/EDR
+ * Allow use of AMP controllers
+ * If the L2CAP channel is currently on AMP, move it to BR/EDR
+ * Channel move requests from the remote device are allowed
+ */
+#define BT_AMP_POLICY_PREFER_BR_EDR 2
+
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
--
1.7.1
^ permalink raw reply related
* [bluetooth-next-2.6 v3 2/2] Bluetooth: Initial move of L2CAP socket to l2cap_sock.c
From: Gustavo F. Padovan @ 2010-09-08 18:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1283970347-23477-1-git-send-email-padovan@profusion.mobi>
This patch tries to do the minimal to move l2cap_sock_create() and its
dependencies to l2cap_sock.c. It create a API to initialize and cleanup
the L2CAP sockets from l2cap_core.c through l2cap_init_sockets() and
l2cap_cleanup_sockets().
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 12 +++
net/bluetooth/Makefile | 2 +-
net/bluetooth/l2cap_core.c | 172 ++---------------------------------
net/bluetooth/l2cap_sock.c | 201 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 222 insertions(+), 165 deletions(-)
create mode 100644 net/bluetooth/l2cap_sock.c
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 6c24144..0bc0329 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -423,6 +423,18 @@ static inline int l2cap_tx_window_full(struct sock *sk)
#define __is_sframe(ctrl) (ctrl) & L2CAP_CTRL_FRAME_TYPE
#define __is_sar_start(ctrl) ((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START
+extern int disable_ertm;
+extern const struct proto_ops l2cap_sock_ops;
+extern struct bt_sock_list l2cap_sk_list;
+
+int l2cap_init_sockets(void);
+void l2cap_cleanup_sockets(void);
+
+void __l2cap_sock_close(struct sock *sk, int reason);
+void l2cap_sock_kill(struct sock *sk);
+void l2cap_sock_init(struct sock *sk, struct sock *parent);
+struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
+
void l2cap_load(void);
#endif /* __L2CAP_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 94e1f57..6d1b1a3 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -12,4 +12,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o
-l2cap-objs := l2cap_core.o
+l2cap-objs := l2cap_core.o l2cap_sock.o
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 44a8fb0..ec6fc96 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -57,24 +57,20 @@
#define VERSION "2.15"
-static int disable_ertm = 0;
+int disable_ertm = 0;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, };
-static const struct proto_ops l2cap_sock_ops;
-
static struct workqueue_struct *_busy_wq;
-static struct bt_sock_list l2cap_sk_list = {
+struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
};
static void l2cap_busy_work(struct work_struct *work);
-static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
-static void l2cap_sock_kill(struct sock *sk);
static int l2cap_build_conf_req(struct sock *sk, void *data);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
@@ -83,31 +79,6 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
/* ---- L2CAP timers ---- */
-static void l2cap_sock_timeout(unsigned long arg)
-{
- struct sock *sk = (struct sock *) arg;
- int reason;
-
- BT_DBG("sock %p state %d", sk, sk->sk_state);
-
- bh_lock_sock(sk);
-
- if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
- reason = ECONNREFUSED;
- else if (sk->sk_state == BT_CONNECT &&
- l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
- reason = ECONNREFUSED;
- else
- reason = ETIMEDOUT;
-
- __l2cap_sock_close(sk, reason);
-
- bh_unlock_sock(sk);
-
- l2cap_sock_kill(sk);
- sock_put(sk);
-}
-
static void l2cap_sock_set_timer(struct sock *sk, long timeout)
{
BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
@@ -778,14 +749,6 @@ static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t
return s;
}
-static void l2cap_sock_destruct(struct sock *sk)
-{
- BT_DBG("sk %p", sk);
-
- skb_queue_purge(&sk->sk_receive_queue);
- skb_queue_purge(&sk->sk_write_queue);
-}
-
static void l2cap_sock_cleanup_listen(struct sock *parent)
{
struct sock *sk;
@@ -803,7 +766,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
/* Kill socket (only if zapped and orphan)
* Must be called on unlocked socket.
*/
-static void l2cap_sock_kill(struct sock *sk)
+void l2cap_sock_kill(struct sock *sk)
{
if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
return;
@@ -816,7 +779,7 @@ static void l2cap_sock_kill(struct sock *sk)
sock_put(sk);
}
-static void __l2cap_sock_close(struct sock *sk, int reason)
+void __l2cap_sock_close(struct sock *sk, int reason)
{
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
@@ -880,109 +843,6 @@ static void l2cap_sock_close(struct sock *sk)
l2cap_sock_kill(sk);
}
-static void l2cap_sock_init(struct sock *sk, struct sock *parent)
-{
- struct l2cap_pinfo *pi = l2cap_pi(sk);
-
- BT_DBG("sk %p", sk);
-
- if (parent) {
- sk->sk_type = parent->sk_type;
- bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
-
- pi->imtu = l2cap_pi(parent)->imtu;
- pi->omtu = l2cap_pi(parent)->omtu;
- pi->conf_state = l2cap_pi(parent)->conf_state;
- pi->mode = l2cap_pi(parent)->mode;
- pi->fcs = l2cap_pi(parent)->fcs;
- pi->max_tx = l2cap_pi(parent)->max_tx;
- pi->tx_win = l2cap_pi(parent)->tx_win;
- pi->sec_level = l2cap_pi(parent)->sec_level;
- pi->role_switch = l2cap_pi(parent)->role_switch;
- pi->force_reliable = l2cap_pi(parent)->force_reliable;
- } else {
- pi->imtu = L2CAP_DEFAULT_MTU;
- pi->omtu = 0;
- if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
- pi->mode = L2CAP_MODE_ERTM;
- pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
- } else {
- pi->mode = L2CAP_MODE_BASIC;
- }
- pi->max_tx = L2CAP_DEFAULT_MAX_TX;
- pi->fcs = L2CAP_FCS_CRC16;
- pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
- pi->sec_level = BT_SECURITY_LOW;
- pi->role_switch = 0;
- pi->force_reliable = 0;
- }
-
- /* Default config options */
- pi->conf_len = 0;
- pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
- skb_queue_head_init(TX_QUEUE(sk));
- skb_queue_head_init(SREJ_QUEUE(sk));
- skb_queue_head_init(BUSY_QUEUE(sk));
- INIT_LIST_HEAD(SREJ_LIST(sk));
-}
-
-static struct proto l2cap_proto = {
- .name = "L2CAP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct l2cap_pinfo)
-};
-
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
-{
- struct sock *sk;
-
- sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
- if (!sk)
- return NULL;
-
- sock_init_data(sock, sk);
- INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
-
- sk->sk_destruct = l2cap_sock_destruct;
- sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = proto;
- sk->sk_state = BT_OPEN;
-
- setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
-
- bt_sock_link(&l2cap_sk_list, sk);
- return sk;
-}
-
-static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- sock->state = SS_UNCONNECTED;
-
- if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
- sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
- return -EPERM;
-
- sock->ops = &l2cap_sock_ops;
-
- sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC);
- if (!sk)
- return -ENOMEM;
-
- l2cap_sock_init(sk, NULL);
- return 0;
-}
-
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
struct sock *sk = sock->sk;
@@ -4752,7 +4612,7 @@ static const struct file_operations l2cap_debugfs_fops = {
static struct dentry *l2cap_debugfs;
-static const struct proto_ops l2cap_sock_ops = {
+const struct proto_ops l2cap_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = l2cap_sock_release,
@@ -4772,12 +4632,6 @@ static const struct proto_ops l2cap_sock_ops = {
.getsockopt = l2cap_sock_getsockopt
};
-static const struct net_proto_family l2cap_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = l2cap_sock_create,
-};
-
static struct hci_proto l2cap_hci_proto = {
.name = "L2CAP",
.id = HCI_PROTO_L2CAP,
@@ -4793,7 +4647,7 @@ static int __init l2cap_init(void)
{
int err;
- err = proto_register(&l2cap_proto, 0);
+ err = l2cap_init_sockets();
if (err < 0)
return err;
@@ -4801,16 +4655,9 @@ static int __init l2cap_init(void)
if (!_busy_wq)
goto error;
- err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
- if (err < 0) {
- BT_ERR("L2CAP socket registration failed");
- goto error;
- }
-
err = hci_register_proto(&l2cap_hci_proto);
if (err < 0) {
BT_ERR("L2CAP protocol registration failed");
- bt_sock_unregister(BTPROTO_L2CAP);
goto error;
}
@@ -4827,7 +4674,7 @@ static int __init l2cap_init(void)
return 0;
error:
- proto_unregister(&l2cap_proto);
+ l2cap_cleanup_sockets();
return err;
}
@@ -4838,13 +4685,10 @@ static void __exit l2cap_exit(void)
flush_workqueue(_busy_wq);
destroy_workqueue(_busy_wq);
- if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
- BT_ERR("L2CAP socket unregistration failed");
-
if (hci_unregister_proto(&l2cap_hci_proto) < 0)
BT_ERR("L2CAP protocol unregistration failed");
- proto_unregister(&l2cap_proto);
+ l2cap_cleanup_sockets();
}
void l2cap_load(void)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
new file mode 100644
index 0000000..463fb11
--- /dev/null
+++ b/net/bluetooth/l2cap_sock.c
@@ -0,0 +1,201 @@
+/*
+ BlueZ - Bluetooth protocol stack for Linux
+ Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
+
+ 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.
+*/
+
+/* Bluetooth L2CAP sockets. */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/l2cap.h>
+
+static void l2cap_sock_timeout(unsigned long arg)
+{
+ struct sock *sk = (struct sock *) arg;
+ int reason;
+
+ BT_DBG("sock %p state %d", sk, sk->sk_state);
+
+ bh_lock_sock(sk);
+
+ if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
+ reason = ECONNREFUSED;
+ else if (sk->sk_state == BT_CONNECT &&
+ l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
+ reason = ECONNREFUSED;
+ else
+ reason = ETIMEDOUT;
+
+ __l2cap_sock_close(sk, reason);
+
+ bh_unlock_sock(sk);
+
+ l2cap_sock_kill(sk);
+ sock_put(sk);
+}
+
+static void l2cap_sock_destruct(struct sock *sk)
+{
+ BT_DBG("sk %p", sk);
+
+ skb_queue_purge(&sk->sk_receive_queue);
+ skb_queue_purge(&sk->sk_write_queue);
+}
+
+void l2cap_sock_init(struct sock *sk, struct sock *parent)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+
+ BT_DBG("sk %p", sk);
+
+ if (parent) {
+ sk->sk_type = parent->sk_type;
+ bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
+
+ pi->imtu = l2cap_pi(parent)->imtu;
+ pi->omtu = l2cap_pi(parent)->omtu;
+ pi->conf_state = l2cap_pi(parent)->conf_state;
+ pi->mode = l2cap_pi(parent)->mode;
+ pi->fcs = l2cap_pi(parent)->fcs;
+ pi->max_tx = l2cap_pi(parent)->max_tx;
+ pi->tx_win = l2cap_pi(parent)->tx_win;
+ pi->sec_level = l2cap_pi(parent)->sec_level;
+ pi->role_switch = l2cap_pi(parent)->role_switch;
+ pi->force_reliable = l2cap_pi(parent)->force_reliable;
+ } else {
+ pi->imtu = L2CAP_DEFAULT_MTU;
+ pi->omtu = 0;
+ if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
+ pi->mode = L2CAP_MODE_ERTM;
+ pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+ } else {
+ pi->mode = L2CAP_MODE_BASIC;
+ }
+ pi->max_tx = L2CAP_DEFAULT_MAX_TX;
+ pi->fcs = L2CAP_FCS_CRC16;
+ pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+ pi->sec_level = BT_SECURITY_LOW;
+ pi->role_switch = 0;
+ pi->force_reliable = 0;
+ }
+
+ /* Default config options */
+ pi->conf_len = 0;
+ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ skb_queue_head_init(TX_QUEUE(sk));
+ skb_queue_head_init(SREJ_QUEUE(sk));
+ skb_queue_head_init(BUSY_QUEUE(sk));
+ INIT_LIST_HEAD(SREJ_LIST(sk));
+}
+
+static struct proto l2cap_proto = {
+ .name = "L2CAP",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct l2cap_pinfo)
+};
+
+struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
+{
+ struct sock *sk;
+
+ sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
+ if (!sk)
+ return NULL;
+
+ sock_init_data(sock, sk);
+ INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+
+ sk->sk_destruct = l2cap_sock_destruct;
+ sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
+
+ sock_reset_flag(sk, SOCK_ZAPPED);
+
+ sk->sk_protocol = proto;
+ sk->sk_state = BT_OPEN;
+
+ setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
+
+ bt_sock_link(&l2cap_sk_list, sk);
+ return sk;
+}
+
+static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
+ int kern)
+{
+ struct sock *sk;
+
+ BT_DBG("sock %p", sock);
+
+ sock->state = SS_UNCONNECTED;
+
+ if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
+ sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
+ return -ESOCKTNOSUPPORT;
+
+ if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
+ return -EPERM;
+
+ sock->ops = &l2cap_sock_ops;
+
+ sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC);
+ if (!sk)
+ return -ENOMEM;
+
+ l2cap_sock_init(sk, NULL);
+ return 0;
+}
+
+static const struct net_proto_family l2cap_sock_family_ops = {
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .create = l2cap_sock_create,
+};
+
+int __init l2cap_init_sockets(void)
+{
+ int err;
+
+ err = proto_register(&l2cap_proto, 0);
+ if (err < 0)
+ return err;
+
+ err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
+ if (err < 0)
+ goto error;
+
+ BT_INFO("L2CAP socket layer initialized");
+
+ return 0;
+
+error:
+ BT_ERR("L2CAP socket registration failed");
+ proto_unregister(&l2cap_proto);
+ return err;
+}
+
+void l2cap_cleanup_sockets(void)
+{
+ if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
+ BT_ERR("L2CAP socket unregistration failed");
+
+ proto_unregister(&l2cap_proto);
+}
--
1.7.2.2
^ permalink raw reply related
* Re: [PATCH 1/4] Bluetooth: Validate PSM values in calls to connect() and bind()
From: Gustavo F. Padovan @ 2010-09-08 19:45 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, marcel, gustavo, rshaffer, linux-arm-msm
In-Reply-To: <1283965529-17068-2-git-send-email-mathewm@codeaurora.org>
* Mat Martineau <mathewm@codeaurora.org> [2010-09-08 10:05:26 -0700]:
> Valid L2CAP PSMs are odd numbers, and the least significant bit of the
> most significant byte must be 0.
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> net/bluetooth/l2cap.c | 25 +++++++++++++++++++++----
> 1 files changed, 21 insertions(+), 4 deletions(-)
Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
* Re: [PATCH 2/4] Bluetooth: Add common code for stream-oriented recvmsg()
From: Gustavo F. Padovan @ 2010-09-08 19:46 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, marcel, gustavo, rshaffer, linux-arm-msm
In-Reply-To: <1283965529-17068-3-git-send-email-mathewm@codeaurora.org>
* Mat Martineau <mathewm@codeaurora.org> [2010-09-08 10:05:27 -0700]:
> This commit adds a bt_sock_stream_recvmsg() function for use by any
> Bluetooth code that uses SOCK_STREAM sockets. This code is copied
> from rfcomm_sock_recvmsg() with minimal modifications to remove
> RFCOMM-specific functionality and improve readability.
>
> L2CAP (with the SOCK_STREAM socket type) and RFCOMM have common needs
> when it comes to reading data. Proper stream read semantics require
> that applications can read from a stream one byte at a time and not
> lose any data. The RFCOMM code already operated on and pulled data
> from the underlying L2CAP socket, so very few changes were required to
> make the code more generic for use with non-RFCOMM data over L2CAP.
>
> Applications that need more awareness of L2CAP frame boundaries are
> still free to use SOCK_SEQPACKET sockets, and may verify that they
> connection did not fall back to basic mode by calling getsockopt().
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> include/net/bluetooth/bluetooth.h | 2 +
> net/bluetooth/af_bluetooth.c | 109 +++++++++++++++++++++++++++++++++++++
> 2 files changed, 111 insertions(+), 0 deletions(-)
Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
* Re: [PATCH 3/4] Bluetooth: Use common SOCK_STREAM receive code in RFCOMM
From: Gustavo F. Padovan @ 2010-09-08 19:47 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, marcel, gustavo, rshaffer, linux-arm-msm
In-Reply-To: <1283965529-17068-4-git-send-email-mathewm@codeaurora.org>
* Mat Martineau <mathewm@codeaurora.org> [2010-09-08 10:05:28 -0700]:
> To reduce code duplication, have rfcomm_sock_recvmsg() call
> bt_sock_stream_recvmsg(). The common bt_sock_stream_recvmsg()
> code is nearly identical, with the RFCOMM-specific functionality
> for deferred setup and connection unthrottling left in
> rfcomm_sock_recvmsg().
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> net/bluetooth/rfcomm/sock.c | 104 +++----------------------------------------
> 1 files changed, 6 insertions(+), 98 deletions(-)
Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
* Re: [PATCH 4/4] Bluetooth: Use a stream-oriented recvmsg with SOCK_STREAM L2CAP sockets.
From: Gustavo F. Padovan @ 2010-09-08 19:47 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, marcel, gustavo, rshaffer, linux-arm-msm
In-Reply-To: <1283965529-17068-5-git-send-email-mathewm@codeaurora.org>
* Mat Martineau <mathewm@codeaurora.org> [2010-09-08 10:05:29 -0700]:
> L2CAP ERTM sockets can be opened with the SOCK_STREAM socket type,
> which is a mandatory request for ERTM mode.
>
> However, these sockets still have SOCK_SEQPACKET read semantics when
> bt_sock_recvmsg() is used to pull data from the receive queue. If the
> application is only reading part of a frame, then the unread portion
> of the frame is discarded. If the application requests more bytes
> than are in the current frame, only the current frame's data is
> returned.
>
> This patch utilizes common code derived from RFCOMM's recvmsg()
> function to make L2CAP SOCK_STREAM reads behave like RFCOMM reads (and
> other SOCK_STREAM sockets in general). The application may read one
> byte at a time from the input stream and not lose any data, and may
> also read across L2CAP frame boundaries.
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> net/bluetooth/l2cap.c | 3 +++
> 1 files changed, 3 insertions(+), 0 deletions(-)
Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
* Re: [PATCH 1/2] Bluetooth: Implement LE Set Advertise Enable cmd
From: Gustavo F. Padovan @ 2010-09-08 21:43 UTC (permalink / raw)
To: Anderson Briglia; +Cc: linux-bluetooth
In-Reply-To: <1282591815-26934-1-git-send-email-anderson.briglia@openbossa.org>
Hi Anderson,
* Anderson Briglia <anderson.briglia@openbossa.org> [2010-08-23 15:30:14 -0400]:
> This patch implements LE Set Advertise Enable command for dual mode and
> Low Energy hci controllers. It also adds new HCI flags in order to
> indicate the Advertising state for userland applications and kernel
> itself.
>
> Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
> ---
> include/net/bluetooth/hci.h | 6 ++++++
> net/bluetooth/hci_event.c | 27 +++++++++++++++++++++++++++
> 2 files changed, 33 insertions(+), 0 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index bcbdd6d..cae1816 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -76,6 +76,7 @@ enum {
> HCI_INQUIRY,
>
> HCI_RAW,
Skip a line here and then add the new LE commands
> + HCI_LE_ADV,
> };
>
> /* HCI ioctl defines */
> @@ -593,6 +594,11 @@ struct hci_rp_read_bd_addr {
> bdaddr_t bdaddr;
> } __packed;
>
> +/* --- HCI LE Commands --- */
> +#define HCI_OP_LE_SET_ADVERTISE_ENABLE 0x200a
> + #define ADVERTISE_ENABLED 0x01
> + #define ADVERTISE_DISABLED 0x00
> +
> /* ---- HCI Events ---- */
> #define HCI_EV_INQUIRY_COMPLETE 0x01
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index bfef5ba..c86c655 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -822,6 +822,29 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
> hci_dev_unlock(hdev);
> }
>
> +static void hci_cc_le_set_advertise(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> + __u8 status = *((__u8 *) skb->data);
> + void *sent;
> +
> + BT_DBG("%s status 0x%x", hdev->name, status);
> +
> + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADVERTISE_ENABLE);
> + if (!sent)
> + return;
> +
> + if (!status) {
> + __u8 param = *((__u8 *) sent);
> +
> + clear_bit(HCI_LE_ADV, &hdev->flags);
> +
> + if (param & ADVERTISE_ENABLED)
> + set_bit(HCI_LE_ADV, &hdev->flags);
We could do that this way:
if (param == ADVERTISE_ENABLED)
set_bit(HCI_LE_ADV, &hdev->flags);
else
clear_bit(HCI_LE_ADV, &hdev->flags);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
* Re: [PATCH 2/2] Bluetooth: Implement LE Set Scan Enable cmd
From: Gustavo F. Padovan @ 2010-09-08 22:05 UTC (permalink / raw)
To: Anderson Briglia; +Cc: linux-bluetooth
In-Reply-To: <1282591815-26934-2-git-send-email-anderson.briglia@openbossa.org>
Hi Anderson,
* Anderson Briglia <anderson.briglia@openbossa.org> [2010-08-23 15:30:15 -0400]:
> This patch implements LE Set Scan Enable command for dual
> mode and Low Energy hci controllers. It also adds new HCI flags
> in order to indicate the LE Scanning state for userland applications
> and kernel itself.
>
> Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
> ---
> include/net/bluetooth/hci.h | 5 +++++
> net/bluetooth/hci_event.c | 25 +++++++++++++++++++++++++
> 2 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index cae1816..268aa94 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -77,6 +77,7 @@ enum {
>
> HCI_RAW,
> HCI_LE_ADV,
> + HCI_LE_SCAN,
> };
>
> /* HCI ioctl defines */
> @@ -599,6 +600,10 @@ struct hci_rp_read_bd_addr {
> #define ADVERTISE_ENABLED 0x01
> #define ADVERTISE_DISABLED 0x00
>
> +#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
> + #define LESCAN_ENABLED 0x01
> + #define LESCAN_DISABLED 0x00
Make these LE_SCAN_ENABLED and LE_SCAN_DISABLED.
> /* ---- HCI Events ---- */
> #define HCI_EV_INQUIRY_COMPLETE 0x01
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index c86c655..f483801 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -845,6 +845,27 @@ static void hci_cc_le_set_advertise(struct hci_dev *hdev, struct sk_buff *skb)
> hci_req_complete(hdev, status);
> }
>
> +static void hci_cc_le_set_scan(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> + __u8 status = *((__u8 *) skb->data);
> + void *sent;
> +
> + BT_DBG("%s status 0x%x", hdev->name, status);
> +
> + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
> + if (!sent)
> + return;
> +
> + clear_bit(HCI_LE_SCAN, &hdev->flags);
Why do you have this clear_bit() outside of the if below? if
status != 0, i.e, the command has failed we can say for sure that
scanning is disabled.
> + if (!status) {
> + __u8 param = *((__u8 *) sent);
> + if (param & LESCAN_ENABLED)
> + set_bit(HCI_LE_SCAN, &hdev->flags);
> + }
> +
> + hci_req_complete(hdev, status);
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
* Re: [PATCH 1/2] Bluetooth: Implement LE Set Advertise Enable cmd
From: Gustavo F. Padovan @ 2010-09-08 22:06 UTC (permalink / raw)
To: Anderson Briglia; +Cc: linux-bluetooth
In-Reply-To: <20100908214359.GM16973@vigoh>
* Gustavo F. Padovan <padovan@profusion.mobi> [2010-09-08 18:43:59 -0300]:
> Hi Anderson,
>
> * Anderson Briglia <anderson.briglia@openbossa.org> [2010-08-23 15:30:14 -0400]:
>
> > This patch implements LE Set Advertise Enable command for dual mode and
> > Low Energy hci controllers. It also adds new HCI flags in order to
> > indicate the Advertising state for userland applications and kernel
> > itself.
> >
> > Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
> > ---
> > include/net/bluetooth/hci.h | 6 ++++++
> > net/bluetooth/hci_event.c | 27 +++++++++++++++++++++++++++
> > 2 files changed, 33 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> > index bcbdd6d..cae1816 100644
> > --- a/include/net/bluetooth/hci.h
> > +++ b/include/net/bluetooth/hci.h
> > @@ -76,6 +76,7 @@ enum {
> > HCI_INQUIRY,
> >
> > HCI_RAW,
>
> Skip a line here and then add the new LE commands
>
> > + HCI_LE_ADV,
> > };
> >
> > /* HCI ioctl defines */
> > @@ -593,6 +594,11 @@ struct hci_rp_read_bd_addr {
> > bdaddr_t bdaddr;
> > } __packed;
> >
> > +/* --- HCI LE Commands --- */
> > +#define HCI_OP_LE_SET_ADVERTISE_ENABLE 0x200a
> > + #define ADVERTISE_ENABLED 0x01
> > + #define ADVERTISE_DISABLED 0x00
And make these LE_ADVERTISE...
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
^ permalink raw reply
* Possible regression with skb_clone() in 2.6.36
From: Gustavo F. Padovan @ 2010-09-08 23:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: netdev, linux-kernel, marcel, davem
I've been experiencing some problems when running the L2CAP Streaming mode in
2.6.36. The system quickly runs in an Out Of Memory condition and crash. That
wasn't happening before, so I think we may have a regression here (I didn't
find where yet). The crash log is below.
The following patch does not fix the regression, but shows that removing the
skb_clone() call from l2cap_streaming_send() we workaround the problem. The
patch is good anyway because it saves memory and time.
By now I have no idea on how to fix this.
[ 5066.137533] Bluetooth: L2CAP ver 2.15
[ 5066.137873] Bluetooth: L2CAP socket layer initialized
[ 5066.545179] Bluetooth: RFCOMM TTY layer initialized
[ 5066.545879] Bluetooth: RFCOMM socket layer initialized
[ 5066.546582] Bluetooth: RFCOMM ver 1.11
[ 5092.268021] l2test invoked oom-killer: gfp_mask=0x4d0, order=0, oom_adj=0, oom_sc
ore_adj=0
[ 5092.268872] Pid: 3897, comm: l2test Not tainted 2.6.36-rc3 #5
[ 5092.269863] Call Trace:
[ 5092.270265] [<ffffffff8138b6a6>] ? _raw_spin_unlock+0x26/0x30
[ 5092.270878] [<ffffffff810c0827>] T.427+0x77/0x1e0
[ 5092.271874] [<ffffffff811b85e7>] ? security_real_capable_noaudit+0x37/0x60
[ 5092.272956] [<ffffffff810c0e3a>] out_of_memory+0x2ca/0x2f0
[ 5092.273894] [<ffffffff810c3d43>] __alloc_pages_nodemask+0x693/0x6b0
[ 5092.274871] [<ffffffff810ea3e6>] cache_alloc_refill+0x2d6/0x5c0
[ 5092.275864] [<ffffffff810ea805>] __kmalloc+0x135/0x150
[ 5092.276876] [<ffffffff8130f2ae>] __alloc_skb+0x6e/0x150
[ 5092.277865] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.278652] [<ffffffff8130ace2>] sock_alloc_send_pskb+0x1c2/0x320
[ 5092.278927] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.279864] [<ffffffff81312add>] ? memcpy_fromiovec+0x6d/0x90
[ 5092.280864] [<ffffffff8130ae50>] sock_alloc_send_skb+0x10/0x20
[ 5092.281867] [<ffffffffa00e600f>] l2cap_create_iframe_pdu+0x9f/0x2c0 [l2cap]
[ 5092.282865] [<ffffffffa00e84b9>] l2cap_sock_sendmsg+0x5d9/0x910 [l2cap]
[ 5092.283932] [<ffffffff8138ba3c>] ? restore_args+0x0/0x30
[ 5092.284865] [<ffffffff8130725b>] sock_sendmsg+0xdb/0x100
[ 5092.285652] [<ffffffff8138ba3c>] ? restore_args+0x0/0x30
[ 5092.285864] [<ffffffff8138ba3c>] ? restore_args+0x0/0x30
[ 5092.286864] [<ffffffff813073c0>] sys_sendto+0xf0/0x130
[ 5092.287864] [<ffffffff8138b60b>] ? _raw_spin_unlock_irq+0x2b/0x40
[ 5092.288872] [<ffffffff81093cfd>] ? trace_hardirqs_on_caller+0x13d/0x180
[ 5092.289927] [<ffffffff81093d4d>] ? trace_hardirqs_on+0xd/0x10
[ 5092.290864] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.291649] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.291864] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.292864] [<ffffffff8130740f>] sys_send+0xf/0x20
[ 5092.293870] [<ffffffff8132ccd6>] compat_sys_socketcall+0x146/0x1f0
[ 5092.294875] [<ffffffff81053ee4>] sysenter_dispatch+0x7/0x30
[ 5092.295673] Mem-Info:
[ 5092.295863] DMA per-cpu:
[ 5092.296214] CPU 0: hi: 0, btch: 1 usd: 0
[ 5092.296925] DMA32 per-cpu:
[ 5092.297298] CPU 0: hi: 90, btch: 15 usd: 85
[ 5092.297864] active_anon:504 inactive_anon:543 isolated_anon:0
[ 5092.297865] active_file:14 inactive_file:3 isolated_file:0
[ 5092.297866] unevictable:0 dirty:0 writeback:3 unstable:0
[ 5092.297866] free:728 slab_reclaimable:559 slab_unreclaimable:39895
[ 5092.297867] mapped:12 shmem:35 pagetables:84 bounce:0
[ 5092.299944] DMA free:1064kB min:124kB low:152kB high:184kB active_anon:0kB inacti
ve_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB iso
lated(file):0kB present:15768kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem
:0kB slab_reclaimable:0kB slab_unreclaimable:14916kB kernel_stack:0kB pagetables:0kB
unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes
[ 5092.301862] lowmem_reserve[]: 0 236 236 236
[ 5092.303134] DMA32 free:1848kB min:1904kB low:2380kB high:2856kB active_anon:2016k
B inactive_anon:2172kB active_file:56kB inactive_file:12kB unevictable:0kB isolated(
anon):0kB isolated(file):0kB present:242380kB mlocked:0kB dirty:0kB writeback:12kB m
apped:48kB shmem:140kB slab_reclaimable:2236kB slab_unreclaimable:144664kB kernel_st
ack:456kB pagetables:336kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:1
03 all_unreclaimable? yes
[ 5092.304962] lowmem_reserve[]: 0 0 0 0
[ 5092.306066] DMA: 0*4kB 1*8kB 0*16kB 1*32kB 0*64kB 0*128kB 0*256kB 0*512kB 1*1024k
B 0*2048kB 0*4096kB = 1064kB
[ 5092.307862] DMA32: 10*4kB 2*8kB 0*16kB 0*32kB 0*64kB 0*128kB 1*256kB 1*512kB 1*10
24kB 0*2048kB 0*4096kB = 1848kB
[ 5092.309467] 52 total pagecache pages
[ 5092.309862] 0 pages in swap cache
[ 5092.310317] Swap cache stats: add 0, delete 0, find 0/0
[ 5092.310862] Free swap = 0kB
[ 5092.311260] Total swap = 0kB
[ 5092.313796] 65530 pages RAM
[ 5092.313868] 22603 pages reserved
[ 5092.314324] 206 pages shared
[ 5092.314862] 39353 pages non-shared
[ 5092.315348] [ pid ] uid tgid total_vm rss cpu oom_adj oom_score_adj name
[ 5092.315867] [ 1] 0 1 438 19 0 0 0 init
[ 5092.316871] [ 1018] 0 1018 537 75 0 -17 -1000 udevd
[ 5092.318867] [ 2217] 101 2217 606 39 0 0 0 dbus-
daemon
[ 5092.319865] [ 2825] 0 2825 481 29 0 0 0 dhcpc
d
[ 5092.320865] [ 3497] 0 3497 1091 83 0 0 0 sshd
[ 5092.321969] [ 3535] 0 3535 477 31 0 0 0 agett
y
[ 5092.322864] [ 3536] 0 3536 477 30 0 0 0 agett
y
[ 5092.323864] [ 3537] 0 3537 477 29 0 0 0 agett
y
[ 5092.325937] [ 3538] 0 3538 477 31 0 0 0 agett
y
[ 5092.326865] [ 3539] 0 3539 477 31 0 0 0 agett
y
[ 5092.327864] [ 3540] 0 3540 477 31 0 0 0 agett
y
[ 5092.328864] [ 3541] 0 3541 1738 105 0 0 0 sshd
[ 5092.329865] [ 3545] 0 3545 745 72 0 0 0 bash
[ 5092.330864] [ 3550] 0 3550 706 43 0 0 0 scree
n
[ 5092.331866] [ 3551] 0 3551 772 124 0 0 0 scree
n
[ 5092.332965] [ 3552] 0 3552 745 77 0 0 0 bash
[ 5092.333865] [ 3557] 0 3557 745 77 0 0 0 bash
[ 5092.334867] [ 3562] 0 3562 536 75 0 -17 -1000 udevd
[ 5092.336865] [ 3567] 0 3567 536 75 0 -17 -1000 udevd
[ 5092.337865] [ 3887] 0 3887 935 54 0 0 0 bluet
oothd
[ 5092.338864] [ 3896] 0 3896 458 24 0 0 0 l2tes
t
[ 5092.339864] [ 3897] 0 3897 458 24 0 0 0 l2tes
t
[ 5092.340933] [ 3942] 0 3942 458 29 0 0 0 l2tes
t
[ 5092.341863] Kernel panic - not syncing: Out of memory and no killable processes..
.
[ 5092.341864]
[ 5092.342864] Pid: 3897, comm: l2test Not tainted 2.6.36-rc3 #5
[ 5092.343862] Call Trace:
[ 5092.344934] [<ffffffff813884d9>] panic+0x8c/0x199
[ 5092.345621] [<ffffffff810c0e54>] out_of_memory+0x2e4/0x2f0
[ 5092.345864] [<ffffffff810c3d43>] __alloc_pages_nodemask+0x693/0x6b0
[ 5092.346894] [<ffffffff810ea3e6>] cache_alloc_refill+0x2d6/0x5c0
[ 5092.347864] [<ffffffff810ea805>] __kmalloc+0x135/0x150
[ 5092.348871] [<ffffffff8130f2ae>] __alloc_skb+0x6e/0x150
[ 5092.349865] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.350628] [<ffffffff8130ace2>] sock_alloc_send_pskb+0x1c2/0x320
[ 5092.350935] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.351864] [<ffffffff81312add>] ? memcpy_fromiovec+0x6d/0x90
[ 5092.352864] [<ffffffff8130ae50>] sock_alloc_send_skb+0x10/0x20
[ 5092.353867] [<ffffffffa00e600f>] l2cap_create_iframe_pdu+0x9f/0x2c0 [l2cap]
[ 5092.354865] [<ffffffffa00e84b9>] l2cap_sock_sendmsg+0x5d9/0x910 [l2cap]
[ 5092.355864] [<ffffffff8138ba3c>] ? restore_args+0x0/0x30
[ 5092.356864] [<ffffffff8130725b>] sock_sendmsg+0xdb/0x100
[ 5092.357612] [<ffffffff8138ba3c>] ? restore_args+0x0/0x30
[ 5092.357931] [<ffffffff8138ba3c>] ? restore_args+0x0/0x30
[ 5092.358864] [<ffffffff813073c0>] sys_sendto+0xf0/0x130
[ 5092.359864] [<ffffffff8138b60b>] ? _raw_spin_unlock_irq+0x2b/0x40
[ 5092.360929] [<ffffffff81093cfd>] ? trace_hardirqs_on_caller+0x13d/0x180
[ 5092.361866] [<ffffffff81093d4d>] ? trace_hardirqs_on+0xd/0x10
[ 5092.362864] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.363653] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.364868] [<ffffffff810d3a00>] ? might_fault+0x40/0x90
[ 5092.365865] [<ffffffff8130740f>] sys_send+0xf/0x20
[ 5092.366945] [<ffffffff8132ccd6>] compat_sys_socketcall+0x146/0x1f0
[ 5092.367865] [<ffffffff81053ee4>] sysenter_dispatch+0x7/0x30
Gustavo F. Padovan (1):
Bluetooth: Simplify L2CAP Streaming mode sending
^ permalink raw reply
* [PATCH] Bluetooth: Simplify L2CAP Streaming mode sending
From: Gustavo F. Padovan @ 2010-09-08 23:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: netdev, linux-kernel, marcel, davem
In-Reply-To: <1283988727-1456-1-git-send-email-padovan@profusion.mobi>
As we don't have any error control on the Streaming mode, i.e., we don't
need to keep a copy of the skb for later resending we don't need to
call skb_clone() on it.
Then we can go one further here, and dequeue the skb before sending it,
that also means we don't need to look to sk->sk_send_head anymore.
The patch saves memory and time when sending Streaming mode data, so
it is good to mainline.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
net/bluetooth/l2cap.c | 24 +++++++-----------------
1 files changed, 7 insertions(+), 17 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 9fad312..f2062aa 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1441,33 +1441,23 @@ static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
static void l2cap_streaming_send(struct sock *sk)
{
- struct sk_buff *skb, *tx_skb;
+ struct sk_buff *skb;
struct l2cap_pinfo *pi = l2cap_pi(sk);
u16 control, fcs;
- while ((skb = sk->sk_send_head)) {
- tx_skb = skb_clone(skb, GFP_ATOMIC);
-
- control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+ while ((skb = skb_dequeue(TX_QUEUE(sk)))) {
+ control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
- put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+ put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
if (pi->fcs == L2CAP_FCS_CRC16) {
- fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
- put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
+ fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
+ put_unaligned_le16(fcs, skb->data + skb->len - 2);
}
- l2cap_do_send(sk, tx_skb);
+ l2cap_do_send(sk, skb);
pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
-
- if (skb_queue_is_last(TX_QUEUE(sk), skb))
- sk->sk_send_head = NULL;
- else
- sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
-
- skb = skb_dequeue(TX_QUEUE(sk));
- kfree_skb(skb);
}
}
--
1.7.2.2
^ permalink raw reply related
* [PATCH] Bluetooth: Don't clear the blacklist when closing the HCI device
From: johan.hedberg @ 2010-09-09 7:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Johan Hedberg
From: Johan Hedberg <johan.hedberg@nokia.com>
Clearing the blacklist in hci_dev_do_close() would mean that user space
needs to do extra work to re-block devices after a DEVDOWN-DEVUP cycle.
This patch removes the clearing of the blacklist in this case and
thereby saves user space from the extra work.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
net/bluetooth/hci_core.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c52f091..bc2a052 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -562,7 +562,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_lock_bh(hdev);
inquiry_cache_flush(hdev);
hci_conn_hash_flush(hdev);
- hci_blacklist_clear(hdev);
hci_dev_unlock_bh(hdev);
hci_notify(hdev, HCI_DEV_DOWN);
--
1.7.0.4
^ permalink raw reply related
* [PATCHv3 0/3] Bluetooth: L2CAP robustness fixes
From: Emeltchenko Andrei @ 2010-09-09 7:42 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
Fixes increase L2CAP robustness to DOS attacks to BT stack.
Andrei Emeltchenko (3):
Bluetooth: fix MTU L2CAP configuration parameter
Bluetooth: check for l2cap header in start fragment
Bluetooth: check L2CAP length in first ACL fragment
net/bluetooth/l2cap.c | 26 ++++++++++++++++++++++----
1 files changed, 22 insertions(+), 4 deletions(-)
^ permalink raw reply
* [PATCHv3 1/3] Bluetooth: fix MTU L2CAP configuration parameter
From: Emeltchenko Andrei @ 2010-09-09 7:42 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1284018181-29928-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
When receiving L2CAP negative configuration response with respect
to MTU parameter we modify wrong field. MTU here means proposed
value of MTU that the remote device intends to transmit. So for local
L2CAP socket it is pi->imtu.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
Acked-by: Ville Tervo <ville.tervo@nokia.com>
Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
net/bluetooth/l2cap.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index c784703..9fad312 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2771,10 +2771,10 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
case L2CAP_CONF_MTU:
if (val < L2CAP_DEFAULT_MIN_MTU) {
*result = L2CAP_CONF_UNACCEPT;
- pi->omtu = L2CAP_DEFAULT_MIN_MTU;
+ pi->imtu = L2CAP_DEFAULT_MIN_MTU;
} else
- pi->omtu = val;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+ pi->imtu = val;
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
break;
case L2CAP_CONF_FLUSH_TO:
--
1.7.0.4
^ permalink raw reply related
* [PATCHv3 2/3] Bluetooth: check for l2cap header in start fragment
From: Emeltchenko Andrei @ 2010-09-09 7:43 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1284018181-29928-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
BLUETOOTH SPECIFICATION Version 4.0 [Vol 3] page 36 mentioned
"Note: Start Fragments always begin with the Basic L2CAP header
of a PDU."
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
---
net/bluetooth/l2cap.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 9fad312..ce8f5e4 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -4664,7 +4664,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
l2cap_conn_unreliable(conn, ECOMM);
}
- if (skb->len < 2) {
+ /* Start fragment always begin with Basic L2CAP header */
+ if (skb->len < L2CAP_HDR_SIZE) {
BT_ERR("Frame is too short (len %d)", skb->len);
l2cap_conn_unreliable(conn, ECOMM);
goto drop;
--
1.7.0.4
^ permalink raw reply related
* [PATCHv3 3/3] Bluetooth: check L2CAP length in first ACL fragment
From: Emeltchenko Andrei @ 2010-09-09 7:43 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1284018181-29928-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
Current Bluetooth code assembles fragments of big L2CAP packets
in l2cap_recv_acldata and then checks allowed L2CAP size in
assemled L2CAP packet (pi->imtu < skb->len).
The patch moves allowed L2CAP size check to the early stage when
we receive the first fragment of L2CAP packet. We do not need to
reserve and keep L2CAP fragments for bad packets.
Updated version after comments from Mat Martineau <mathewm@codeaurora.org>
Trace below is received when using stress tools sending big
fragmented L2CAP packets.
...
[ 1712.798492] swapper: page allocation failure. order:4, mode:0x4020
[ 1712.804809] [<c0031870>] (unwind_backtrace+0x0/0xdc) from [<c00a1f70>]
(__alloc_pages_nodemask+0x4)
[ 1712.814666] [<c00a1f70>] (__alloc_pages_nodemask+0x47c/0x4d4) from
[<c00a1fd8>] (__get_free_pages+)
[ 1712.824645] [<c00a1fd8>] (__get_free_pages+0x10/0x3c) from [<c026eb5c>]
(__alloc_skb+0x4c/0xfc)
[ 1712.833465] [<c026eb5c>] (__alloc_skb+0x4c/0xfc) from [<bf28c738>]
(l2cap_recv_acldata+0xf0/0x1f8 )
[ 1712.843322] [<bf28c738>] (l2cap_recv_acldata+0xf0/0x1f8 [l2cap]) from
[<bf0094ac>] (hci_rx_task+0x)
...
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
---
net/bluetooth/l2cap.c | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index ce8f5e4..c95fbd8 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -4654,6 +4654,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
if (flags & ACL_START) {
struct l2cap_hdr *hdr;
+ struct sock *sk;
+ u16 cid;
int len;
if (conn->rx_len) {
@@ -4673,6 +4675,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
hdr = (struct l2cap_hdr *) skb->data;
len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
+ cid = __le16_to_cpu(hdr->cid);
if (len == skb->len) {
/* Complete frame received */
@@ -4689,6 +4692,20 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
goto drop;
}
+ sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
+
+ if (sk && l2cap_pi(sk)->imtu < len) {
+ BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)",
+ len, l2cap_pi(sk)->imtu);
+ conn->rx_len = 0; /* needed? */
+ bh_unlock_sock(sk);
+ l2cap_conn_unreliable(conn, ECOMM);
+ goto drop;
+ }
+
+ if (sk)
+ bh_unlock_sock(sk);
+
/* Allocate skb for the complete frame (with header) */
conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!conn->rx_skb)
--
1.7.0.4
^ permalink raw reply related
* Bluez 4.70 Compiling issues
From: steven bluez @ 2010-09-09 9:33 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Marcel Holtmann, Gustavo F. Padovan"
In-Reply-To: <AANLkTik3Lr0NqDyn1Rpi=X3dvGTGcVuUbYnr7_+weaBD@mail.gmail.com>
Hi all ,
=A0=A0=A0=A0=A0=A0=A0 While I compile Bluez4.70 in my lucidlynx (ubuntu 10.=
04
&10.10). I am facing issues please do suggest on how to compile the
same & i have attached the logs
>
> =A0 CC=A0=A0=A0=A0 src/manager.o
> =A0 CC=A0=A0=A0=A0 src/adapter.o
> =A0 CC=A0=A0=A0=A0 src/device.o
> =A0 CC=A0=A0=A0=A0 src/dbus-common.o
> =A0 CC=A0=A0=A0=A0 src/dbus-hci.o
> =A0 GEN=A0=A0=A0 audio/telephony.c
> =A0 CC=A0=A0=A0=A0 audio/telephony.o
> =A0 GEN=A0=A0=A0 src/bluetooth.exp
> =A0 GEN=A0=A0=A0 src/bluetooth.ver
> =A0 CCLD=A0=A0 src/bluetoothd
> src/attrib-server.o: In function `send_notification':
> attrib-server.c:(.text+0x21d): undefined reference to `enc_notification'
> attrib-server.c:(.text+0x272): undefined reference to `g_attrib_send'
> src/attrib-server.o: In function `connect_event':
> attrib-server.c:(.text+0x9bc): undefined reference to `g_attrib_new'
> attrib-server.c:(.text+0x9e7): undefined reference to `g_attrib_register'
> src/attrib-server.o: In function `channel_destroy':
> attrib-server.c:(.text+0xa31): undefined reference to `g_attrib_unregiste=
r_all'
> attrib-server.c:(.text+0xa3c): undefined reference to `g_attrib_unref'
> src/attrib-server.o: In function `.L59':
> attrib-server.c:(.text+0xaf4): undefined reference to `dec_read_by_grp_re=
q'
> attrib-server.c:(.text+0xb2e): undefined reference to `enc_error_resp'
> attrib-server.c:(.text+0xb6d): undefined reference to `g_attrib_send'
> src/attrib-server.o: In function `.L58':
> attrib-server.c:(.text+0xb9e): undefined reference to `dec_read_req'
> attrib-server.c:(.text+0xc05): undefined reference to `enc_read_resp'
> src/attrib-server.o: In function `.L57':
> attrib-server.c:(.text+0xc3c): undefined reference to `dec_read_by_type_r=
eq'
> attrib-server.c:(.text+0xe09): undefined reference to `enc_read_by_type_r=
esp'
> attrib-server.c:(.text+0xe1d): undefined reference to `att_data_list_free=
'
> src/attrib-server.o: In function `.L56':
> attrib-server.c:(.text+0xe5f): undefined reference to `dec_find_info_req'
> attrib-server.c:(.text+0x102a): undefined reference to `enc_find_info_res=
p'
> attrib-server.c:(.text+0x1038): undefined reference to `att_data_list_fre=
e'
> attrib-server.c:(.text+0x12da): undefined reference to `enc_error_resp'
> attrib-server.c:(.text+0x1314): undefined reference to `enc_error_resp'
> attrib-server.c:(.text+0x134c): undefined reference to `enc_error_resp'
> attrib-server.c:(.text+0x1382): undefined reference to `enc_error_resp'
> attrib-server.c:(.text+0x13b5): undefined reference to `enc_error_resp'
> attrib-server.c:(.text+0x13dc): undefined reference to `enc_read_by_grp_r=
esp'
> attrib-server.c:(.text+0x13f0): undefined reference to `att_data_list_fre=
e'
> attrib-server.c:(.text+0x145a): undefined reference to `enc_error_resp'
> attrib-server.c:(.text+0x148f): undefined reference to `enc_error_resp'
> collect2: ld returned 1 exit status
> make[1]: *** [src/bluetoothd] Error 1
> make: *** [all] Error 2
Regards,
Steven
^ permalink raw reply
* obex: isolate btio.[ch] as a library and do some cleanup
From: Zhenhua Zhang @ 2010-09-09 9:41 UTC (permalink / raw)
To: linux-bluetooth
Hi,
These patches move obexd/src/btio.[ch] out from source directory and make it identical with bluez's btio.[ch]. So we can freely copy them among bluez, obex and ofono.
Regards,
Zhenhua
^ permalink raw reply
* [PATCH 1/4] btio: Remove blank line at EOF
From: Zhenhua Zhang @ 2010-09-09 9:41 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1284025283-3773-1-git-send-email-zhenhua.zhang@intel.com>
---
src/btio.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/src/btio.c b/src/btio.c
index 485eec6..42a3bcd 100644
--- a/src/btio.c
+++ b/src/btio.c
@@ -1297,4 +1297,3 @@ GQuark bt_io_error_quark(void)
{
return g_quark_from_static_string("bt-io-error-quark");
}
-
--
1.7.0.4
^ permalink raw reply related
* [PATCH 2/4] btio: Seperate btio.[ch] into btio directory
From: Zhenhua Zhang @ 2010-09-09 9:41 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1284025283-3773-1-git-send-email-zhenhua.zhang@intel.com>
Seperate btio.[ch] from src directory to btio sub-folder.
---
Makefile.am | 19 +-
btio/btio.c | 1299 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
btio/btio.h | 97 +++++
src/btio.c | 1299 -----------------------------------------------------------
src/btio.h | 97 -----
5 files changed, 1406 insertions(+), 1405 deletions(-)
create mode 100644 btio/btio.c
create mode 100644 btio/btio.h
delete mode 100644 src/btio.c
delete mode 100644 src/btio.h
diff --git a/Makefile.am b/Makefile.am
index 07fc27d..961a375 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,6 +18,8 @@ gwobex_sources = gwobex/gw-obex.h gwobex/gw-obex.c \
gwobex/obex-xfer.h gwobex/obex-xfer.c \
gwobex/utils.h gwobex/utils.c gwobex/log.h
+btio_sources = btio/btio.h btio/btio.c
+
libexec_PROGRAMS =
if SERVER
@@ -65,11 +67,10 @@ builtin_nodist += plugins/phonebook.c
libexec_PROGRAMS += src/obexd
-src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) \
+src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) $(btio_sources) \
src/main.c src/obexd.h src/plugin.h src/plugin.c \
- src/log.h src/log.c src/btio.h src/btio.c \
- src/dbus.h src/manager.c src/obex.h src/obex.c \
- src/obex-priv.h \
+ src/log.h src/log.c src/dbus.h src/manager.c \
+ src/obex.h src/obex.c src/obex-priv.h \
src/mimetype.h src/mimetype.c \
src/service.h src/service.c \
src/transport.h src/transport.c \
@@ -107,13 +108,12 @@ service_in_files += client/obex-client.service.in
libexec_PROGRAMS += client/obex-client
-client_obex_client_SOURCES = $(gdbus_sources) $(gwobex_sources) client/main.c \
- client/session.h client/session.c \
+client_obex_client_SOURCES = $(gdbus_sources) $(gwobex_sources) $(btio_sources) \
+ client/main.c client/session.h client/session.c \
src/log.h src/log.c \
client/pbap.h client/pbap.c \
client/sync.h client/sync.c \
- client/transfer.h client/transfer.c \
- src/btio.c src/btio.h
+ client/transfer.h client/transfer.c
client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @OPENOBEX_LIBS@ @BLUEZ_LIBS@
endif
@@ -126,7 +126,8 @@ AM_CFLAGS = @OPENOBEX_CFLAGS@ @BLUEZ_CFLAGS@ @EBOOK_CFLAGS@ \
-DOBEX_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
INCLUDES = -I$(builddir)/src -I$(srcdir)/src -I$(srcdir)/plugins \
- -I$(srcdir)/gdbus -I$(srcdir)/gwobex
+ -I$(srcdir)/gdbus -I$(srcdir)/gwobex \
+ -I$(srcdir)/btio
CLEANFILES = $(service_DATA) $(builtin_files)
diff --git a/btio/btio.c b/btio/btio.c
new file mode 100644
index 0000000..42a3bcd
--- /dev/null
+++ b/btio/btio.c
@@ -0,0 +1,1299 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#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"
+
+#define ERROR_FAILED(gerr, str, err) \
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+ str ": %s (%d)", strerror(err), err)
+
+#define DEFAULT_DEFER_TIMEOUT 30
+
+struct set_opts {
+ bdaddr_t src;
+ bdaddr_t dst;
+ int defer;
+ int sec_level;
+ uint8_t channel;
+ uint16_t psm;
+ uint16_t mtu;
+ uint16_t imtu;
+ uint16_t omtu;
+ int master;
+ uint8_t mode;
+};
+
+struct connect {
+ BtIOConnect connect;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+struct accept {
+ BtIOConnect connect;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+struct server {
+ BtIOConnect connect;
+ BtIOConfirm confirm;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+static void server_remove(struct server *server)
+{
+ if (server->destroy)
+ server->destroy(server->user_data);
+ g_free(server);
+}
+
+static void connect_remove(struct connect *conn)
+{
+ if (conn->destroy)
+ conn->destroy(conn->user_data);
+ g_free(conn);
+}
+
+static void accept_remove(struct accept *accept)
+{
+ if (accept->destroy)
+ accept->destroy(accept->user_data);
+ g_free(accept);
+}
+
+static gboolean check_nval(GIOChannel *io)
+{
+ struct pollfd fds;
+
+ memset(&fds, 0, sizeof(fds));
+ fds.fd = g_io_channel_unix_get_fd(io);
+ fds.events = POLLNVAL;
+
+ if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLNVAL))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct accept *accept = user_data;
+ GError *err = NULL;
+
+ /* If the user aborted this accept attempt */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
+ "HUP or ERR on socket");
+
+ accept->connect(io, err, accept->user_data);
+
+ g_clear_error(&err);
+
+ return FALSE;
+}
+
+static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct connect *conn = user_data;
+ GError *gerr = NULL;
+
+ /* If the user aborted this connect attempt */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ if (cond & G_IO_OUT) {
+ int err = 0, sock = g_io_channel_unix_get_fd(io);
+ socklen_t len = sizeof(err);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
+ err = errno;
+
+ if (err)
+ g_set_error(&gerr, BT_IO_ERROR,
+ BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
+ 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");
+
+ conn->connect(io, gerr, conn->user_data);
+
+ if (gerr)
+ g_error_free(gerr);
+
+ return FALSE;
+}
+
+static gboolean server_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct server *server = user_data;
+ int srv_sock, cli_sock;
+ GIOChannel *cli_io;
+
+ /* If the user closed the server */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ srv_sock = g_io_channel_unix_get_fd(io);
+
+ cli_sock = accept(srv_sock, NULL, NULL);
+ if (cli_sock < 0)
+ return TRUE;
+
+ cli_io = g_io_channel_unix_new(cli_sock);
+
+ g_io_channel_set_close_on_unref(cli_io, TRUE);
+ g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL);
+
+ if (server->confirm)
+ server->confirm(cli_io, server->user_data);
+ else
+ server->connect(cli_io, NULL, server->user_data);
+
+ g_io_channel_unref(cli_io);
+
+ return TRUE;
+}
+
+static void server_add(GIOChannel *io, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy)
+{
+ struct server *server;
+ GIOCondition cond;
+
+ server = g_new0(struct server, 1);
+ server->connect = connect;
+ server->confirm = confirm;
+ server->user_data = user_data;
+ server->destroy = destroy;
+
+ cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server,
+ (GDestroyNotify) server_remove);
+}
+
+static void connect_add(GIOChannel *io, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy)
+{
+ struct connect *conn;
+ GIOCondition cond;
+
+ conn = g_new0(struct connect, 1);
+ conn->connect = connect;
+ conn->user_data = user_data;
+ conn->destroy = destroy;
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, connect_cb, conn,
+ (GDestroyNotify) connect_remove);
+}
+
+static void accept_add(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy)
+{
+ struct accept *accept;
+ GIOCondition cond;
+
+ accept = g_new0(struct accept, 1);
+ accept->connect = connect;
+ accept->user_data = user_data;
+ accept->destroy = destroy;
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept,
+ (GDestroyNotify) accept_remove);
+}
+
+static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, GError **err)
+{
+ struct sockaddr_l2 addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+ addr.l2_psm = htobs(psm);
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "l2cap_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int l2cap_connect(int sock, const bdaddr_t *dst, uint16_t psm)
+{
+ int err;
+ struct sockaddr_l2 addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(psm);
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static int l2cap_set_master(int sock, int master)
+{
+ int flags;
+ socklen_t len;
+
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len) < 0)
+ return -errno;
+
+ if (master) {
+ if (flags & L2CAP_LM_MASTER)
+ return 0;
+ flags |= L2CAP_LM_MASTER;
+ } else {
+ if (!(flags & L2CAP_LM_MASTER))
+ return 0;
+ flags &= ~L2CAP_LM_MASTER;
+ }
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, sizeof(flags)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int rfcomm_set_master(int sock, int master)
+{
+ int flags;
+ socklen_t len;
+
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, &len) < 0)
+ return -errno;
+
+ if (master) {
+ if (flags & RFCOMM_LM_MASTER)
+ return 0;
+ flags |= RFCOMM_LM_MASTER;
+ } else {
+ if (!(flags & RFCOMM_LM_MASTER))
+ return 0;
+ flags &= ~RFCOMM_LM_MASTER;
+ }
+
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, sizeof(flags)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int l2cap_set_lm(int sock, int level)
+{
+ int lm_map[] = {
+ 0,
+ L2CAP_LM_AUTH,
+ L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT,
+ L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE,
+ }, opt = lm_map[level];
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int rfcomm_set_lm(int sock, int level)
+{
+ int lm_map[] = {
+ 0,
+ RFCOMM_LM_AUTH,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE,
+ }, opt = lm_map[level];
+
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
+{
+ struct bt_security sec;
+ int ret;
+
+ if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Valid security level range is %d-%d",
+ BT_SECURITY_LOW, BT_SECURITY_HIGH);
+ return FALSE;
+ }
+
+ memset(&sec, 0, sizeof(sec));
+ sec.level = level;
+
+ if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec,
+ sizeof(sec)) == 0)
+ return TRUE;
+
+ if (errno != ENOPROTOOPT) {
+ ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno);
+ return FALSE;
+ }
+
+ if (type == BT_IO_L2CAP)
+ ret = l2cap_set_lm(sock, level);
+ else
+ ret = rfcomm_set_lm(sock, level);
+
+ if (ret < 0) {
+ ERROR_FAILED(err, "setsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int l2cap_get_lm(int sock, int *sec_level)
+{
+ int opt;
+ socklen_t len;
+
+ len = sizeof(opt);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, &len) < 0)
+ return -errno;
+
+ *sec_level = 0;
+
+ if (opt & L2CAP_LM_AUTH)
+ *sec_level = BT_SECURITY_LOW;
+ if (opt & L2CAP_LM_ENCRYPT)
+ *sec_level = BT_SECURITY_MEDIUM;
+ if (opt & L2CAP_LM_SECURE)
+ *sec_level = BT_SECURITY_HIGH;
+
+ return 0;
+}
+
+static int rfcomm_get_lm(int sock, int *sec_level)
+{
+ int opt;
+ socklen_t len;
+
+ len = sizeof(opt);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, &len) < 0)
+ return -errno;
+
+ *sec_level = 0;
+
+ if (opt & RFCOMM_LM_AUTH)
+ *sec_level = BT_SECURITY_LOW;
+ if (opt & RFCOMM_LM_ENCRYPT)
+ *sec_level = BT_SECURITY_MEDIUM;
+ if (opt & RFCOMM_LM_SECURE)
+ *sec_level = BT_SECURITY_HIGH;
+
+ return 0;
+}
+
+static gboolean get_sec_level(int sock, BtIOType type, int *level,
+ GError **err)
+{
+ struct bt_security sec;
+ socklen_t len;
+ int ret;
+
+ memset(&sec, 0, sizeof(sec));
+ len = sizeof(sec);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) {
+ *level = sec.level;
+ return TRUE;
+ }
+
+ if (errno != ENOPROTOOPT) {
+ ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno);
+ return FALSE;
+ }
+
+ if (type == BT_IO_L2CAP)
+ ret = l2cap_get_lm(sock, level);
+ else
+ ret = rfcomm_get_lm(sock, level);
+
+ if (ret < 0) {
+ ERROR_FAILED(err, "getsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu,
+ uint8_t mode, int master, GError **err)
+{
+ if (imtu || omtu || mode) {
+ struct l2cap_options l2o;
+ socklen_t len;
+
+ memset(&l2o, 0, sizeof(l2o));
+ len = sizeof(l2o);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (imtu)
+ l2o.imtu = imtu;
+ if (omtu)
+ l2o.omtu = omtu;
+ if (mode)
+ l2o.mode = mode;
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
+ sizeof(l2o)) < 0) {
+ ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+ }
+
+ if (master >= 0 && l2cap_set_master(sock, master) < 0) {
+ ERROR_FAILED(err, "l2cap_set_master", errno);
+ return FALSE;
+ }
+
+ if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
+ return FALSE;
+
+ return TRUE;
+}
+
+static int rfcomm_bind(int sock,
+ const bdaddr_t *src, uint8_t channel, GError **err)
+{
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = channel;
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "rfcomm_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
+{
+ int err;
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, dst);
+ addr.rc_channel = channel;
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err)
+{
+ if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err))
+ return FALSE;
+
+ if (master >= 0 && rfcomm_set_master(sock, master) < 0) {
+ ERROR_FAILED(err, "rfcomm_set_master", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int sco_bind(int sock, const bdaddr_t *src, GError **err)
+{
+ struct sockaddr_sco addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, src);
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "sco_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sco_connect(int sock, const bdaddr_t *dst)
+{
+ struct sockaddr_sco addr;
+ int err;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, dst);
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static gboolean sco_set(int sock, uint16_t mtu, GError **err)
+{
+ struct sco_options sco_opt;
+ socklen_t len;
+
+ if (!mtu)
+ return TRUE;
+
+ len = sizeof(sco_opt);
+ memset(&sco_opt, 0, len);
+ if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ sco_opt.mtu = mtu;
+ if (setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt,
+ sizeof(sco_opt)) < 0) {
+ ERROR_FAILED(err, "setsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean parse_set_opts(struct set_opts *opts, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+ const char *str;
+
+ memset(opts, 0, sizeof(*opts));
+
+ /* Set defaults */
+ opts->defer = DEFAULT_DEFER_TIMEOUT;
+ opts->master = -1;
+ opts->sec_level = BT_IO_SEC_MEDIUM;
+ opts->mode = L2CAP_MODE_BASIC;
+
+ 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);
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(&opts->src, va_arg(args, const bdaddr_t *));
+ break;
+ case BT_IO_OPT_DEST:
+ str2ba(va_arg(args, const char *), &opts->dst);
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ opts->defer = va_arg(args, int);
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ opts->sec_level = va_arg(args, int);
+ break;
+ case BT_IO_OPT_CHANNEL:
+ opts->channel = va_arg(args, int);
+ break;
+ case BT_IO_OPT_PSM:
+ opts->psm = va_arg(args, int);
+ break;
+ case BT_IO_OPT_MTU:
+ opts->mtu = va_arg(args, int);
+ opts->imtu = opts->mtu;
+ opts->omtu = opts->mtu;
+ break;
+ case BT_IO_OPT_OMTU:
+ opts->omtu = va_arg(args, int);
+ if (!opts->mtu)
+ opts->mtu = opts->omtu;
+ break;
+ case BT_IO_OPT_IMTU:
+ opts->imtu = va_arg(args, int);
+ if (!opts->mtu)
+ opts->mtu = opts->imtu;
+ break;
+ case BT_IO_OPT_MASTER:
+ opts->master = va_arg(args, gboolean);
+ break;
+ case BT_IO_OPT_MODE:
+ opts->mode = va_arg(args, int);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst,
+ socklen_t len, GError **err)
+{
+ socklen_t olen;
+
+ memset(src, 0, len);
+ olen = len;
+ if (getsockname(sock, src, &olen) < 0) {
+ ERROR_FAILED(err, "getsockname", errno);
+ return FALSE;
+ }
+
+ memset(dst, 0, len);
+ olen = len;
+ if (getpeername(sock, dst, &olen) < 0) {
+ ERROR_FAILED(err, "getpeername", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int l2cap_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct l2cap_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_l2 src, dst;
+ struct l2cap_options l2o;
+ int flags;
+ uint8_t dev_class[3];
+ uint16_t handle;
+ socklen_t len;
+
+ len = sizeof(l2o);
+ memset(&l2o, 0, len);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.l2_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.l2_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.l2_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ len = sizeof(int);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
+ va_arg(args, int *), &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
+ errno);
+ return FALSE;
+ }
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ if (!get_sec_level(sock, BT_IO_L2CAP,
+ 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;
+ break;
+ case BT_IO_OPT_OMTU:
+ *(va_arg(args, uint16_t *)) = l2o.omtu;
+ break;
+ case BT_IO_OPT_IMTU:
+ *(va_arg(args, uint16_t *)) = l2o.imtu;
+ break;
+ case BT_IO_OPT_MASTER:
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_LM)",
+ errno);
+ return FALSE;
+ }
+ *(va_arg(args, gboolean *)) =
+ (flags & L2CAP_LM_MASTER) ? TRUE : FALSE;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (l2cap_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (l2cap_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static int rfcomm_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct rfcomm_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_rc src, dst;
+ int flags;
+ socklen_t len;
+ uint8_t dev_class[3];
+ uint16_t handle;
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.rc_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.rc_bdaddr);
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ len = sizeof(int);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
+ va_arg(args, int *), &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
+ errno);
+ return FALSE;
+ }
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ if (!get_sec_level(sock, BT_IO_RFCOMM,
+ va_arg(args, int *), err))
+ return FALSE;
+ break;
+ case BT_IO_OPT_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel ?
+ src.rc_channel : dst.rc_channel;
+ break;
+ case BT_IO_OPT_SOURCE_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel;
+ break;
+ case BT_IO_OPT_DEST_CHANNEL:
+ *(va_arg(args, uint8_t *)) = dst.rc_channel;
+ break;
+ case BT_IO_OPT_MASTER:
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(RFCOMM_LM)",
+ errno);
+ return FALSE;
+ }
+ *(va_arg(args, gboolean *)) =
+ (flags & RFCOMM_LM_MASTER) ? TRUE : FALSE;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static int sco_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct sco_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_SCO, SCO_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_sco src, dst;
+ struct sco_options sco_opt;
+ socklen_t len;
+ uint8_t dev_class[3];
+ uint16_t handle;
+
+ len = sizeof(sco_opt);
+ memset(&sco_opt, 0, len);
+ if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.sco_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.sco_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.sco_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.sco_bdaddr);
+ break;
+ case BT_IO_OPT_MTU:
+ case BT_IO_OPT_IMTU:
+ case BT_IO_OPT_OMTU:
+ *(va_arg(args, uint16_t *)) = sco_opt.mtu;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (sco_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (sco_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ int sock;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ case BT_IO_L2CAP:
+ return l2cap_get(sock, err, opt1, args);
+ case BT_IO_RFCOMM:
+ return rfcomm_get(sock, err, opt1, args);
+ case BT_IO_SCO:
+ return sco_get(sock, err, opt1, args);
+ }
+
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+}
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy, GError **err)
+{
+ int sock;
+ char c;
+ struct pollfd pfd;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLOUT;
+
+ if (poll(&pfd, 1, 0) < 0) {
+ ERROR_FAILED(err, "poll", errno);
+ return FALSE;
+ }
+
+ if (!(pfd.revents & POLLOUT)) {
+ int ret;
+ ret = read(sock, &c, 1);
+ }
+
+ accept_add(io, connect, user_data, destroy);
+
+ return TRUE;
+}
+
+gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...)
+{
+ va_list args;
+ gboolean ret;
+ struct set_opts opts;
+ int sock;
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, err, opt1, args);
+ va_end(args);
+
+ if (!ret)
+ return ret;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ case BT_IO_L2CAP:
+ return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
+ opts.mode, opts.master, err);
+ case BT_IO_RFCOMM:
+ return rfcomm_set(sock, opts.sec_level, opts.master, err);
+ case BT_IO_SCO:
+ return sco_set(sock, opts.mtu, err);
+ }
+
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+}
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...)
+{
+ va_list args;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = get_valist(io, type, err, opt1, args);
+ va_end(args);
+
+ return ret;
+}
+
+static GIOChannel *create_io(BtIOType type, gboolean server,
+ struct set_opts *opts, GError **err)
+{
+ int sock;
+ GIOChannel *io;
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
+ return NULL;
+ }
+ if (l2cap_bind(sock, &opts->src,
+ server ? opts->psm : 0, err) < 0)
+ goto failed;
+ if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
+ goto failed;
+ break;
+ case BT_IO_L2CAP:
+ sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
+ return NULL;
+ }
+ if (l2cap_bind(sock, &opts->src,
+ server ? opts->psm : 0, err) < 0)
+ goto failed;
+ if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
+ opts->mode, opts->master, err))
+ goto failed;
+ break;
+ case BT_IO_RFCOMM:
+ sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);
+ return NULL;
+ }
+ if (rfcomm_bind(sock, &opts->src,
+ server ? opts->channel : 0, err) < 0)
+ goto failed;
+ if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
+ goto failed;
+ break;
+ case BT_IO_SCO:
+ sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);
+ return NULL;
+ }
+ if (sco_bind(sock, &opts->src, err) < 0)
+ goto failed;
+ if (!sco_set(sock, opts->mtu, err))
+ goto failed;
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return NULL;
+ }
+
+ io = g_io_channel_unix_new(sock);
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+ g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+
+ return io;
+
+failed:
+ close(sock);
+
+ return NULL;
+}
+
+GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy,
+ GError **gerr, BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int err, sock;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, gerr, opt1, args);
+ va_end(args);
+
+ if (ret == FALSE)
+ return NULL;
+
+ io = create_io(type, FALSE, &opts, gerr);
+ if (io == NULL)
+ return NULL;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ err = l2cap_connect(sock, &opts.dst, 0);
+ break;
+ case BT_IO_L2CAP:
+ err = l2cap_connect(sock, &opts.dst, opts.psm);
+ break;
+ case BT_IO_RFCOMM:
+ err = rfcomm_connect(sock, &opts.dst, opts.channel);
+ break;
+ case BT_IO_SCO:
+ err = sco_connect(sock, &opts.dst);
+ break;
+ default:
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return NULL;
+ }
+
+ if (err < 0) {
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
+ "connect: %s (%d)", strerror(-err), -err);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ connect_add(io, connect, user_data, destroy);
+
+ return io;
+}
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int sock;
+ gboolean ret;
+
+ if (type == BT_IO_L2RAW) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Server L2CAP RAW sockets not supported");
+ return NULL;
+ }
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, err, opt1, args);
+ va_end(args);
+
+ if (ret == FALSE)
+ return NULL;
+
+ io = create_io(type, TRUE, &opts, err);
+ if (io == NULL)
+ return NULL;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ if (confirm)
+ setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
+ sizeof(opts.defer));
+
+ if (listen(sock, 5) < 0) {
+ ERROR_FAILED(err, "listen", errno);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ server_add(io, connect, confirm, user_data, destroy);
+
+ return io;
+}
+
+GQuark bt_io_error_quark(void)
+{
+ return g_quark_from_static_string("bt-io-error-quark");
+}
diff --git a/btio/btio.h b/btio/btio.h
new file mode 100644
index 0000000..e9dcc9f
--- /dev/null
+++ b/btio/btio.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifndef BT_IO_H
+#define BT_IO_H
+
+#include <glib.h>
+
+typedef enum {
+ BT_IO_ERROR_DISCONNECTED,
+ BT_IO_ERROR_CONNECT_FAILED,
+ BT_IO_ERROR_FAILED,
+ BT_IO_ERROR_INVALID_ARGS,
+} BtIOError;
+
+#define BT_IO_ERROR bt_io_error_quark()
+
+GQuark bt_io_error_quark(void);
+
+typedef enum {
+ BT_IO_L2RAW,
+ BT_IO_L2CAP,
+ BT_IO_RFCOMM,
+ BT_IO_SCO,
+} BtIOType;
+
+typedef enum {
+ BT_IO_OPT_INVALID = 0,
+ BT_IO_OPT_SOURCE,
+ BT_IO_OPT_SOURCE_BDADDR,
+ BT_IO_OPT_DEST,
+ BT_IO_OPT_DEST_BDADDR,
+ BT_IO_OPT_DEFER_TIMEOUT,
+ BT_IO_OPT_SEC_LEVEL,
+ BT_IO_OPT_CHANNEL,
+ BT_IO_OPT_SOURCE_CHANNEL,
+ BT_IO_OPT_DEST_CHANNEL,
+ BT_IO_OPT_PSM,
+ BT_IO_OPT_MTU,
+ BT_IO_OPT_OMTU,
+ BT_IO_OPT_IMTU,
+ BT_IO_OPT_MASTER,
+ BT_IO_OPT_HANDLE,
+ BT_IO_OPT_CLASS,
+ BT_IO_OPT_MODE,
+} BtIOOption;
+
+typedef enum {
+ BT_IO_SEC_SDP = 0,
+ BT_IO_SEC_LOW,
+ BT_IO_SEC_MEDIUM,
+ BT_IO_SEC_HIGH,
+} BtIOSecLevel;
+
+typedef void (*BtIOConfirm)(GIOChannel *io, void *user_data);
+
+typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy, GError **err);
+
+gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...);
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...);
+
+GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy,
+ GError **err, BtIOOption opt1, ...);
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...);
+
+#endif
diff --git a/src/btio.c b/src/btio.c
deleted file mode 100644
index 42a3bcd..0000000
--- a/src/btio.c
+++ /dev/null
@@ -1,1299 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#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"
-
-#define ERROR_FAILED(gerr, str, err) \
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
- str ": %s (%d)", strerror(err), err)
-
-#define DEFAULT_DEFER_TIMEOUT 30
-
-struct set_opts {
- bdaddr_t src;
- bdaddr_t dst;
- int defer;
- int sec_level;
- uint8_t channel;
- uint16_t psm;
- uint16_t mtu;
- uint16_t imtu;
- uint16_t omtu;
- int master;
- uint8_t mode;
-};
-
-struct connect {
- BtIOConnect connect;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-struct accept {
- BtIOConnect connect;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-struct server {
- BtIOConnect connect;
- BtIOConfirm confirm;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-static void server_remove(struct server *server)
-{
- if (server->destroy)
- server->destroy(server->user_data);
- g_free(server);
-}
-
-static void connect_remove(struct connect *conn)
-{
- if (conn->destroy)
- conn->destroy(conn->user_data);
- g_free(conn);
-}
-
-static void accept_remove(struct accept *accept)
-{
- if (accept->destroy)
- accept->destroy(accept->user_data);
- g_free(accept);
-}
-
-static gboolean check_nval(GIOChannel *io)
-{
- struct pollfd fds;
-
- memset(&fds, 0, sizeof(fds));
- fds.fd = g_io_channel_unix_get_fd(io);
- fds.events = POLLNVAL;
-
- if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLNVAL))
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct accept *accept = user_data;
- GError *err = NULL;
-
- /* If the user aborted this accept attempt */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR))
- g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
- "HUP or ERR on socket");
-
- accept->connect(io, err, accept->user_data);
-
- g_clear_error(&err);
-
- return FALSE;
-}
-
-static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct connect *conn = user_data;
- GError *gerr = NULL;
-
- /* If the user aborted this connect attempt */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- if (cond & G_IO_OUT) {
- int err = 0, sock = g_io_channel_unix_get_fd(io);
- socklen_t len = sizeof(err);
-
- if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
- err = errno;
-
- if (err)
- g_set_error(&gerr, BT_IO_ERROR,
- BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
- 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");
-
- conn->connect(io, gerr, conn->user_data);
-
- if (gerr)
- g_error_free(gerr);
-
- return FALSE;
-}
-
-static gboolean server_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct server *server = user_data;
- int srv_sock, cli_sock;
- GIOChannel *cli_io;
-
- /* If the user closed the server */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- srv_sock = g_io_channel_unix_get_fd(io);
-
- cli_sock = accept(srv_sock, NULL, NULL);
- if (cli_sock < 0)
- return TRUE;
-
- cli_io = g_io_channel_unix_new(cli_sock);
-
- g_io_channel_set_close_on_unref(cli_io, TRUE);
- g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL);
-
- if (server->confirm)
- server->confirm(cli_io, server->user_data);
- else
- server->connect(cli_io, NULL, server->user_data);
-
- g_io_channel_unref(cli_io);
-
- return TRUE;
-}
-
-static void server_add(GIOChannel *io, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy)
-{
- struct server *server;
- GIOCondition cond;
-
- server = g_new0(struct server, 1);
- server->connect = connect;
- server->confirm = confirm;
- server->user_data = user_data;
- server->destroy = destroy;
-
- cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server,
- (GDestroyNotify) server_remove);
-}
-
-static void connect_add(GIOChannel *io, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy)
-{
- struct connect *conn;
- GIOCondition cond;
-
- conn = g_new0(struct connect, 1);
- conn->connect = connect;
- conn->user_data = user_data;
- conn->destroy = destroy;
-
- cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, connect_cb, conn,
- (GDestroyNotify) connect_remove);
-}
-
-static void accept_add(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy)
-{
- struct accept *accept;
- GIOCondition cond;
-
- accept = g_new0(struct accept, 1);
- accept->connect = connect;
- accept->user_data = user_data;
- accept->destroy = destroy;
-
- cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept,
- (GDestroyNotify) accept_remove);
-}
-
-static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, GError **err)
-{
- struct sockaddr_l2 addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, src);
- addr.l2_psm = htobs(psm);
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "l2cap_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int l2cap_connect(int sock, const bdaddr_t *dst, uint16_t psm)
-{
- int err;
- struct sockaddr_l2 addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, dst);
- addr.l2_psm = htobs(psm);
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static int l2cap_set_master(int sock, int master)
-{
- int flags;
- socklen_t len;
-
- len = sizeof(flags);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len) < 0)
- return -errno;
-
- if (master) {
- if (flags & L2CAP_LM_MASTER)
- return 0;
- flags |= L2CAP_LM_MASTER;
- } else {
- if (!(flags & L2CAP_LM_MASTER))
- return 0;
- flags &= ~L2CAP_LM_MASTER;
- }
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, sizeof(flags)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int rfcomm_set_master(int sock, int master)
-{
- int flags;
- socklen_t len;
-
- len = sizeof(flags);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, &len) < 0)
- return -errno;
-
- if (master) {
- if (flags & RFCOMM_LM_MASTER)
- return 0;
- flags |= RFCOMM_LM_MASTER;
- } else {
- if (!(flags & RFCOMM_LM_MASTER))
- return 0;
- flags &= ~RFCOMM_LM_MASTER;
- }
-
- if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, sizeof(flags)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int l2cap_set_lm(int sock, int level)
-{
- int lm_map[] = {
- 0,
- L2CAP_LM_AUTH,
- L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT,
- L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE,
- }, opt = lm_map[level];
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int rfcomm_set_lm(int sock, int level)
-{
- int lm_map[] = {
- 0,
- RFCOMM_LM_AUTH,
- RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT,
- RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE,
- }, opt = lm_map[level];
-
- if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0)
- return -errno;
-
- return 0;
-}
-
-static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
-{
- struct bt_security sec;
- int ret;
-
- if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Valid security level range is %d-%d",
- BT_SECURITY_LOW, BT_SECURITY_HIGH);
- return FALSE;
- }
-
- memset(&sec, 0, sizeof(sec));
- sec.level = level;
-
- if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec,
- sizeof(sec)) == 0)
- return TRUE;
-
- if (errno != ENOPROTOOPT) {
- ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno);
- return FALSE;
- }
-
- if (type == BT_IO_L2CAP)
- ret = l2cap_set_lm(sock, level);
- else
- ret = rfcomm_set_lm(sock, level);
-
- if (ret < 0) {
- ERROR_FAILED(err, "setsockopt(LM)", -ret);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int l2cap_get_lm(int sock, int *sec_level)
-{
- int opt;
- socklen_t len;
-
- len = sizeof(opt);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, &len) < 0)
- return -errno;
-
- *sec_level = 0;
-
- if (opt & L2CAP_LM_AUTH)
- *sec_level = BT_SECURITY_LOW;
- if (opt & L2CAP_LM_ENCRYPT)
- *sec_level = BT_SECURITY_MEDIUM;
- if (opt & L2CAP_LM_SECURE)
- *sec_level = BT_SECURITY_HIGH;
-
- return 0;
-}
-
-static int rfcomm_get_lm(int sock, int *sec_level)
-{
- int opt;
- socklen_t len;
-
- len = sizeof(opt);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, &len) < 0)
- return -errno;
-
- *sec_level = 0;
-
- if (opt & RFCOMM_LM_AUTH)
- *sec_level = BT_SECURITY_LOW;
- if (opt & RFCOMM_LM_ENCRYPT)
- *sec_level = BT_SECURITY_MEDIUM;
- if (opt & RFCOMM_LM_SECURE)
- *sec_level = BT_SECURITY_HIGH;
-
- return 0;
-}
-
-static gboolean get_sec_level(int sock, BtIOType type, int *level,
- GError **err)
-{
- struct bt_security sec;
- socklen_t len;
- int ret;
-
- memset(&sec, 0, sizeof(sec));
- len = sizeof(sec);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) {
- *level = sec.level;
- return TRUE;
- }
-
- if (errno != ENOPROTOOPT) {
- ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno);
- return FALSE;
- }
-
- if (type == BT_IO_L2CAP)
- ret = l2cap_get_lm(sock, level);
- else
- ret = rfcomm_get_lm(sock, level);
-
- if (ret < 0) {
- ERROR_FAILED(err, "getsockopt(LM)", -ret);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu,
- uint8_t mode, int master, GError **err)
-{
- if (imtu || omtu || mode) {
- struct l2cap_options l2o;
- socklen_t len;
-
- memset(&l2o, 0, sizeof(l2o));
- len = sizeof(l2o);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
-
- if (imtu)
- l2o.imtu = imtu;
- if (omtu)
- l2o.omtu = omtu;
- if (mode)
- l2o.mode = mode;
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
- sizeof(l2o)) < 0) {
- ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
- }
-
- if (master >= 0 && l2cap_set_master(sock, master) < 0) {
- ERROR_FAILED(err, "l2cap_set_master", errno);
- return FALSE;
- }
-
- if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
- return FALSE;
-
- return TRUE;
-}
-
-static int rfcomm_bind(int sock,
- const bdaddr_t *src, uint8_t channel, GError **err)
-{
- struct sockaddr_rc addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, src);
- addr.rc_channel = channel;
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "rfcomm_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
-{
- int err;
- struct sockaddr_rc addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, dst);
- addr.rc_channel = channel;
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err)
-{
- if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err))
- return FALSE;
-
- if (master >= 0 && rfcomm_set_master(sock, master) < 0) {
- ERROR_FAILED(err, "rfcomm_set_master", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int sco_bind(int sock, const bdaddr_t *src, GError **err)
-{
- struct sockaddr_sco addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, src);
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "sco_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int sco_connect(int sock, const bdaddr_t *dst)
-{
- struct sockaddr_sco addr;
- int err;
-
- memset(&addr, 0, sizeof(addr));
- addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, dst);
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static gboolean sco_set(int sock, uint16_t mtu, GError **err)
-{
- struct sco_options sco_opt;
- socklen_t len;
-
- if (!mtu)
- return TRUE;
-
- len = sizeof(sco_opt);
- memset(&sco_opt, 0, len);
- if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- sco_opt.mtu = mtu;
- if (setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt,
- sizeof(sco_opt)) < 0) {
- ERROR_FAILED(err, "setsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean parse_set_opts(struct set_opts *opts, GError **err,
- BtIOOption opt1, va_list args)
-{
- BtIOOption opt = opt1;
- const char *str;
-
- memset(opts, 0, sizeof(*opts));
-
- /* Set defaults */
- opts->defer = DEFAULT_DEFER_TIMEOUT;
- opts->master = -1;
- opts->sec_level = BT_IO_SEC_MEDIUM;
- opts->mode = L2CAP_MODE_BASIC;
-
- 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);
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(&opts->src, va_arg(args, const bdaddr_t *));
- break;
- case BT_IO_OPT_DEST:
- str2ba(va_arg(args, const char *), &opts->dst);
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- opts->defer = va_arg(args, int);
- break;
- case BT_IO_OPT_SEC_LEVEL:
- opts->sec_level = va_arg(args, int);
- break;
- case BT_IO_OPT_CHANNEL:
- opts->channel = va_arg(args, int);
- break;
- case BT_IO_OPT_PSM:
- opts->psm = va_arg(args, int);
- break;
- case BT_IO_OPT_MTU:
- opts->mtu = va_arg(args, int);
- opts->imtu = opts->mtu;
- opts->omtu = opts->mtu;
- break;
- case BT_IO_OPT_OMTU:
- opts->omtu = va_arg(args, int);
- if (!opts->mtu)
- opts->mtu = opts->omtu;
- break;
- case BT_IO_OPT_IMTU:
- opts->imtu = va_arg(args, int);
- if (!opts->mtu)
- opts->mtu = opts->imtu;
- break;
- case BT_IO_OPT_MASTER:
- opts->master = va_arg(args, gboolean);
- break;
- case BT_IO_OPT_MODE:
- opts->mode = va_arg(args, int);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst,
- socklen_t len, GError **err)
-{
- socklen_t olen;
-
- memset(src, 0, len);
- olen = len;
- if (getsockname(sock, src, &olen) < 0) {
- ERROR_FAILED(err, "getsockname", errno);
- return FALSE;
- }
-
- memset(dst, 0, len);
- olen = len;
- if (getpeername(sock, dst, &olen) < 0) {
- ERROR_FAILED(err, "getpeername", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int l2cap_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct l2cap_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
- va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_l2 src, dst;
- struct l2cap_options l2o;
- int flags;
- uint8_t dev_class[3];
- uint16_t handle;
- socklen_t len;
-
- len = sizeof(l2o);
- memset(&l2o, 0, len);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.l2_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.l2_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.l2_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- len = sizeof(int);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
- va_arg(args, int *), &len) < 0) {
- ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
- errno);
- return FALSE;
- }
- break;
- case BT_IO_OPT_SEC_LEVEL:
- if (!get_sec_level(sock, BT_IO_L2CAP,
- 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;
- break;
- case BT_IO_OPT_OMTU:
- *(va_arg(args, uint16_t *)) = l2o.omtu;
- break;
- case BT_IO_OPT_IMTU:
- *(va_arg(args, uint16_t *)) = l2o.imtu;
- break;
- case BT_IO_OPT_MASTER:
- len = sizeof(flags);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_LM)",
- errno);
- return FALSE;
- }
- *(va_arg(args, gboolean *)) =
- (flags & L2CAP_LM_MASTER) ? TRUE : FALSE;
- break;
- case BT_IO_OPT_HANDLE:
- if (l2cap_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (l2cap_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static int rfcomm_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct rfcomm_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
- va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_rc src, dst;
- int flags;
- socklen_t len;
- uint8_t dev_class[3];
- uint16_t handle;
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.rc_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.rc_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.rc_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.rc_bdaddr);
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- len = sizeof(int);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
- va_arg(args, int *), &len) < 0) {
- ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
- errno);
- return FALSE;
- }
- break;
- case BT_IO_OPT_SEC_LEVEL:
- if (!get_sec_level(sock, BT_IO_RFCOMM,
- va_arg(args, int *), err))
- return FALSE;
- break;
- case BT_IO_OPT_CHANNEL:
- *(va_arg(args, uint8_t *)) = src.rc_channel ?
- src.rc_channel : dst.rc_channel;
- break;
- case BT_IO_OPT_SOURCE_CHANNEL:
- *(va_arg(args, uint8_t *)) = src.rc_channel;
- break;
- case BT_IO_OPT_DEST_CHANNEL:
- *(va_arg(args, uint8_t *)) = dst.rc_channel;
- break;
- case BT_IO_OPT_MASTER:
- len = sizeof(flags);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(RFCOMM_LM)",
- errno);
- return FALSE;
- }
- *(va_arg(args, gboolean *)) =
- (flags & RFCOMM_LM_MASTER) ? TRUE : FALSE;
- break;
- case BT_IO_OPT_HANDLE:
- if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static int sco_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct sco_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_SCO, SCO_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_sco src, dst;
- struct sco_options sco_opt;
- socklen_t len;
- uint8_t dev_class[3];
- uint16_t handle;
-
- len = sizeof(sco_opt);
- memset(&sco_opt, 0, len);
- if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.sco_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.sco_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.sco_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.sco_bdaddr);
- break;
- case BT_IO_OPT_MTU:
- case BT_IO_OPT_IMTU:
- case BT_IO_OPT_OMTU:
- *(va_arg(args, uint16_t *)) = sco_opt.mtu;
- break;
- case BT_IO_OPT_HANDLE:
- if (sco_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (sco_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, va_list args)
-{
- int sock;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- case BT_IO_L2CAP:
- return l2cap_get(sock, err, opt1, args);
- case BT_IO_RFCOMM:
- return rfcomm_get(sock, err, opt1, args);
- case BT_IO_SCO:
- return sco_get(sock, err, opt1, args);
- }
-
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return FALSE;
-}
-
-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy, GError **err)
-{
- int sock;
- char c;
- struct pollfd pfd;
-
- sock = g_io_channel_unix_get_fd(io);
-
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = sock;
- pfd.events = POLLOUT;
-
- if (poll(&pfd, 1, 0) < 0) {
- ERROR_FAILED(err, "poll", errno);
- return FALSE;
- }
-
- if (!(pfd.revents & POLLOUT)) {
- int ret;
- ret = read(sock, &c, 1);
- }
-
- accept_add(io, connect, user_data, destroy);
-
- return TRUE;
-}
-
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...)
-{
- va_list args;
- gboolean ret;
- struct set_opts opts;
- int sock;
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, err, opt1, args);
- va_end(args);
-
- if (!ret)
- return ret;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- case BT_IO_L2CAP:
- return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
- opts.mode, opts.master, err);
- case BT_IO_RFCOMM:
- return rfcomm_set(sock, opts.sec_level, opts.master, err);
- case BT_IO_SCO:
- return sco_set(sock, opts.mtu, err);
- }
-
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return FALSE;
-}
-
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...)
-{
- va_list args;
- gboolean ret;
-
- va_start(args, opt1);
- ret = get_valist(io, type, err, opt1, args);
- va_end(args);
-
- return ret;
-}
-
-static GIOChannel *create_io(BtIOType type, gboolean server,
- struct set_opts *opts, GError **err)
-{
- int sock;
- GIOChannel *io;
-
- switch (type) {
- case BT_IO_L2RAW:
- sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
- return NULL;
- }
- if (l2cap_bind(sock, &opts->src,
- server ? opts->psm : 0, err) < 0)
- goto failed;
- if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
- goto failed;
- break;
- case BT_IO_L2CAP:
- sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
- return NULL;
- }
- if (l2cap_bind(sock, &opts->src,
- server ? opts->psm : 0, err) < 0)
- goto failed;
- if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
- opts->mode, opts->master, err))
- goto failed;
- break;
- case BT_IO_RFCOMM:
- sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);
- return NULL;
- }
- if (rfcomm_bind(sock, &opts->src,
- server ? opts->channel : 0, err) < 0)
- goto failed;
- if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
- goto failed;
- break;
- case BT_IO_SCO:
- sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);
- return NULL;
- }
- if (sco_bind(sock, &opts->src, err) < 0)
- goto failed;
- if (!sco_set(sock, opts->mtu, err))
- goto failed;
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return NULL;
- }
-
- io = g_io_channel_unix_new(sock);
-
- g_io_channel_set_close_on_unref(io, TRUE);
- g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
-
- return io;
-
-failed:
- close(sock);
-
- return NULL;
-}
-
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
- GError **gerr, BtIOOption opt1, ...)
-{
- GIOChannel *io;
- va_list args;
- struct set_opts opts;
- int err, sock;
- gboolean ret;
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, gerr, opt1, args);
- va_end(args);
-
- if (ret == FALSE)
- return NULL;
-
- io = create_io(type, FALSE, &opts, gerr);
- if (io == NULL)
- return NULL;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- err = l2cap_connect(sock, &opts.dst, 0);
- break;
- case BT_IO_L2CAP:
- err = l2cap_connect(sock, &opts.dst, opts.psm);
- break;
- case BT_IO_RFCOMM:
- err = rfcomm_connect(sock, &opts.dst, opts.channel);
- break;
- case BT_IO_SCO:
- err = sco_connect(sock, &opts.dst);
- break;
- default:
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return NULL;
- }
-
- if (err < 0) {
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
- "connect: %s (%d)", strerror(-err), -err);
- g_io_channel_unref(io);
- return NULL;
- }
-
- connect_add(io, connect, user_data, destroy);
-
- return io;
-}
-
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy, GError **err,
- BtIOOption opt1, ...)
-{
- GIOChannel *io;
- va_list args;
- struct set_opts opts;
- int sock;
- gboolean ret;
-
- if (type == BT_IO_L2RAW) {
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Server L2CAP RAW sockets not supported");
- return NULL;
- }
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, err, opt1, args);
- va_end(args);
-
- if (ret == FALSE)
- return NULL;
-
- io = create_io(type, TRUE, &opts, err);
- if (io == NULL)
- return NULL;
-
- sock = g_io_channel_unix_get_fd(io);
-
- if (confirm)
- setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
- sizeof(opts.defer));
-
- if (listen(sock, 5) < 0) {
- ERROR_FAILED(err, "listen", errno);
- g_io_channel_unref(io);
- return NULL;
- }
-
- server_add(io, connect, confirm, user_data, destroy);
-
- return io;
-}
-
-GQuark bt_io_error_quark(void)
-{
- return g_quark_from_static_string("bt-io-error-quark");
-}
diff --git a/src/btio.h b/src/btio.h
deleted file mode 100644
index e9dcc9f..0000000
--- a/src/btio.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-#ifndef BT_IO_H
-#define BT_IO_H
-
-#include <glib.h>
-
-typedef enum {
- BT_IO_ERROR_DISCONNECTED,
- BT_IO_ERROR_CONNECT_FAILED,
- BT_IO_ERROR_FAILED,
- BT_IO_ERROR_INVALID_ARGS,
-} BtIOError;
-
-#define BT_IO_ERROR bt_io_error_quark()
-
-GQuark bt_io_error_quark(void);
-
-typedef enum {
- BT_IO_L2RAW,
- BT_IO_L2CAP,
- BT_IO_RFCOMM,
- BT_IO_SCO,
-} BtIOType;
-
-typedef enum {
- BT_IO_OPT_INVALID = 0,
- BT_IO_OPT_SOURCE,
- BT_IO_OPT_SOURCE_BDADDR,
- BT_IO_OPT_DEST,
- BT_IO_OPT_DEST_BDADDR,
- BT_IO_OPT_DEFER_TIMEOUT,
- BT_IO_OPT_SEC_LEVEL,
- BT_IO_OPT_CHANNEL,
- BT_IO_OPT_SOURCE_CHANNEL,
- BT_IO_OPT_DEST_CHANNEL,
- BT_IO_OPT_PSM,
- BT_IO_OPT_MTU,
- BT_IO_OPT_OMTU,
- BT_IO_OPT_IMTU,
- BT_IO_OPT_MASTER,
- BT_IO_OPT_HANDLE,
- BT_IO_OPT_CLASS,
- BT_IO_OPT_MODE,
-} BtIOOption;
-
-typedef enum {
- BT_IO_SEC_SDP = 0,
- BT_IO_SEC_LOW,
- BT_IO_SEC_MEDIUM,
- BT_IO_SEC_HIGH,
-} BtIOSecLevel;
-
-typedef void (*BtIOConfirm)(GIOChannel *io, void *user_data);
-
-typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
-
-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy, GError **err);
-
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...);
-
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...);
-
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
- GError **err, BtIOOption opt1, ...);
-
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy, GError **err,
- BtIOOption opt1, ...);
-
-#endif
--
1.7.0.4
^ permalink raw reply related
* [PATCH 3/4] btio: Remove unused bt_io_set function
From: Zhenhua Zhang @ 2010-09-09 9:41 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1284025283-3773-1-git-send-email-zhenhua.zhang@intel.com>
It is not used by either obex or bluez.
---
btio/btio.c | 33 ---------------------------------
btio/btio.h | 3 ---
2 files changed, 0 insertions(+), 36 deletions(-)
diff --git a/btio/btio.c b/btio/btio.c
index 42a3bcd..d4969e5 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -1074,39 +1074,6 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
return TRUE;
}
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...)
-{
- va_list args;
- gboolean ret;
- struct set_opts opts;
- int sock;
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, err, opt1, args);
- va_end(args);
-
- if (!ret)
- return ret;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- case BT_IO_L2CAP:
- return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
- opts.mode, opts.master, err);
- case BT_IO_RFCOMM:
- return rfcomm_set(sock, opts.sec_level, opts.master, err);
- case BT_IO_SCO:
- return sco_set(sock, opts.mtu, err);
- }
-
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return FALSE;
-}
-
gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
BtIOOption opt1, ...)
{
diff --git a/btio/btio.h b/btio/btio.h
index e9dcc9f..3c5db2a 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -79,9 +79,6 @@ typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
GDestroyNotify destroy, GError **err);
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...);
-
gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
BtIOOption opt1, ...);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 4/4] btio: Replace void * with gpointer
From: Zhenhua Zhang @ 2010-09-09 9:41 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1284025283-3773-1-git-send-email-zhenhua.zhang@intel.com>
TO make it consistent with bluez btio.c.
---
btio/btio.c | 24 ++++++++++++------------
btio/btio.h | 10 +++++-----
2 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/btio/btio.c b/btio/btio.c
index d4969e5..41b698f 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -62,20 +62,20 @@ struct set_opts {
struct connect {
BtIOConnect connect;
- void *user_data;
+ gpointer user_data;
GDestroyNotify destroy;
};
struct accept {
BtIOConnect connect;
- void *user_data;
+ gpointer user_data;
GDestroyNotify destroy;
};
struct server {
BtIOConnect connect;
BtIOConfirm confirm;
- void *user_data;
+ gpointer user_data;
GDestroyNotify destroy;
};
@@ -115,7 +115,7 @@ static gboolean check_nval(GIOChannel *io)
}
static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
+ gpointer user_data)
{
struct accept *accept = user_data;
GError *err = NULL;
@@ -136,7 +136,7 @@ static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
}
static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
+ gpointer user_data)
{
struct connect *conn = user_data;
GError *gerr = NULL;
@@ -169,7 +169,7 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
}
static gboolean server_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
+ gpointer user_data)
{
struct server *server = user_data;
int srv_sock, cli_sock;
@@ -201,7 +201,7 @@ static gboolean server_cb(GIOChannel *io, GIOCondition cond,
}
static void server_add(GIOChannel *io, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
+ BtIOConfirm confirm, gpointer user_data,
GDestroyNotify destroy)
{
struct server *server;
@@ -219,7 +219,7 @@ static void server_add(GIOChannel *io, BtIOConnect connect,
}
static void connect_add(GIOChannel *io, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy)
+ gpointer user_data, GDestroyNotify destroy)
{
struct connect *conn;
GIOCondition cond;
@@ -234,7 +234,7 @@ static void connect_add(GIOChannel *io, BtIOConnect connect,
(GDestroyNotify) connect_remove);
}
-static void accept_add(GIOChannel *io, BtIOConnect connect, void *user_data,
+static void accept_add(GIOChannel *io, BtIOConnect connect, gpointer user_data,
GDestroyNotify destroy)
{
struct accept *accept;
@@ -1046,7 +1046,7 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
return FALSE;
}
-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
GDestroyNotify destroy, GError **err)
{
int sock;
@@ -1162,7 +1162,7 @@ failed:
}
GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
+ gpointer user_data, GDestroyNotify destroy,
GError **gerr, BtIOOption opt1, ...)
{
GIOChannel *io;
@@ -1216,7 +1216,7 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
}
GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
+ BtIOConfirm confirm, gpointer user_data,
GDestroyNotify destroy, GError **err,
BtIOOption opt1, ...)
{
diff --git a/btio/btio.h b/btio/btio.h
index 3c5db2a..5f2911a 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -72,22 +72,22 @@ typedef enum {
BT_IO_SEC_HIGH,
} BtIOSecLevel;
-typedef void (*BtIOConfirm)(GIOChannel *io, void *user_data);
+typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data);
-typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
+typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);
-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
GDestroyNotify destroy, GError **err);
gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
BtIOOption opt1, ...);
GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
+ gpointer user_data, GDestroyNotify destroy,
GError **err, BtIOOption opt1, ...);
GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
+ BtIOConfirm confirm, gpointer user_data,
GDestroyNotify destroy, GError **err,
BtIOOption opt1, ...);
--
1.7.0.4
^ permalink raw reply related
* bluez: isolate btio.[ch] as a library and do cleanup
From: Zhenhua Zhang @ 2010-09-09 9:43 UTC (permalink / raw)
To: linux-bluetooth
Hi,
These patches move bluez/src/btio.[ch] out from source directory and make it identical with obex's btio.[ch]. So we can freely copy them among bluez, obex and ofono.
Regards,
Zhenhua
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox