* [PATCH_v3 2/4] android/pan: Listen for incoming connections and accept in NAP role
From: Ravi kumar Veeramally @ 2014-01-07 12:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389097880-14783-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Listen for incoming connections and accept it. Create bnep interface
add it to bridge and notify control and connection state information
through HAL. Remove the device on disconnect request. If android
settings UI does not have bluetooth tethering enabled it immediately
sends disconnect signal.
---
android/pan.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 190 insertions(+), 2 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 93078ba..0eef284 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -63,12 +63,17 @@ struct pan_device {
uint8_t role;
GIOChannel *io;
struct bnep *session;
+ guint watch;
};
static struct {
uint32_t record_id;
+ guint watch;
+ GIOChannel *io;
} nap_dev = {
.record_id = 0,
+ .watch = 0,
+ .io = NULL,
};
static int device_cmp(gconstpointer s, gconstpointer user_data)
@@ -81,13 +86,21 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
static void pan_device_free(struct pan_device *dev)
{
+ if (dev->watch > 0) {
+ bnep_server_delete(BNEP_BRIDGE, dev->iface, &dev->dst);
+ g_source_remove(dev->watch);
+ dev->watch = 0;
+ }
+
if (dev->io) {
g_io_channel_shutdown(dev->io, FALSE, NULL);
g_io_channel_unref(dev->io);
dev->io = NULL;
}
- bnep_free(dev->session);
+ if (dev->session)
+ bnep_free(dev->session);
+
devices = g_slist_remove(devices, dev);
g_free(dev);
@@ -298,7 +311,7 @@ static void bt_pan_disconnect(const void *buf, uint16_t len)
dev = l->data;
- if (dev->conn_state == HAL_PAN_STATE_CONNECTED)
+ if (dev->conn_state == HAL_PAN_STATE_CONNECTED && dev->session)
bnep_disconnect(dev->session);
bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
@@ -308,6 +321,154 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
}
+static gboolean nap_watchdog_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+
+ DBG("disconnected");
+
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+
+ return FALSE;
+}
+static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+ uint8_t packet[BNEP_MTU];
+ struct bnep_setup_conn_req *req = (void *) packet;
+ uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
+ int sk, n;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ error("Hangup or error or inval on BNEP socket");
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
+ n = read(sk, packet, sizeof(packet));
+ if (n < 0) {
+ error("read(): %s(%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ /* Highest known control command id BNEP_FILTER_MULT_ADDR_RSP 0x06 */
+ if (req->type == BNEP_CONTROL &&
+ req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
+ error("cmd not understood");
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_CMD_NOT_UNDERSTOOD,
+ req->ctrl);
+ goto failed;
+ }
+
+ if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) {
+ error("cmd is not BNEP_SETUP_CONN_REQ %02X %02X", req->type,
+ req->ctrl);
+ goto failed;
+ }
+
+ rsp = bnep_setup_decode(req, &dst_role, &src_role);
+ if (rsp) {
+ error("bnep_setup_decode failed");
+ goto failed;
+ }
+
+ rsp = bnep_setup_chk(dst_role, src_role);
+ if (rsp) {
+ error("benp_setup_chk failed");
+ goto failed;
+ }
+
+ if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
+ &dev->dst) < 0) {
+ error("server_connadd failed");
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto failed;
+ }
+
+ rsp = BNEP_SUCCESS;
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+
+ dev->watch = g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ nap_watchdog_cb, dev);
+ g_io_channel_unref(dev->io);
+ dev->io = NULL;
+
+ bt_pan_notify_ctrl_state(dev, HAL_PAN_CTRL_ENABLED);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTED);
+
+ return FALSE;
+
+failed:
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+ pan_device_free(dev);
+
+ return FALSE;
+}
+
+static void nap_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+
+ DBG("");
+
+ if (err) {
+ error("%s", err->message);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+ return;
+ }
+
+ g_io_channel_set_close_on_unref(chan, TRUE);
+ dev->watch = g_io_add_watch(chan,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ nap_setup_cb, dev);
+}
+
+static void nap_confirm_cb(GIOChannel *chan, gpointer data)
+{
+ struct pan_device *dev = NULL;
+ bdaddr_t dst;
+ char address[18];
+ GError *err = NULL;
+
+ DBG("");
+
+ bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ DBG("incoming connect request from %s", address);
+ dev = g_new0(struct pan_device, 1);
+ bacpy(&dev->dst, &dst);
+ local_role = HAL_PAN_ROLE_NAP;
+ dev->role = HAL_PAN_ROLE_PANU;
+
+ dev->io = g_io_channel_ref(chan);
+ g_io_channel_set_close_on_unref(dev->io, TRUE);
+
+ if (!bt_io_accept(dev->io, nap_connect_cb, dev, NULL, &err)) {
+ error("bt_io_accept: %s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ devices = g_slist_append(devices, dev);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTING);
+
+ return;
+
+failed:
+ g_free(dev);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
static int set_forward_delay(void)
{
int fd, ret;
@@ -378,10 +539,22 @@ static void destroy_nap_device(void)
nap_remove_bridge();
nap_dev.record_id = 0;
+
+ if (nap_dev.watch > 0) {
+ g_source_remove(nap_dev.watch);
+ nap_dev.watch = 0;
+ }
+
+ if (nap_dev.io) {
+ g_io_channel_shutdown(nap_dev.io, FALSE, NULL);
+ g_io_channel_unref(nap_dev.io);
+ nap_dev.io = NULL;
+ }
}
static int register_nap_server(void)
{
+ GError *gerr;
int err;
DBG("");
@@ -390,6 +563,21 @@ static int register_nap_server(void)
if (err < 0)
return err;
+ nap_dev.io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_PSM, BNEP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_OMTU, BNEP_MTU,
+ BT_IO_OPT_IMTU, BNEP_MTU,
+ BT_IO_OPT_INVALID);
+
+ if (!nap_dev.io) {
+ destroy_nap_device();
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return -EINVAL;
+ }
+
return 0;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v3 1/4] android/pan: Register Network Access Point
From: Ravi kumar Veeramally @ 2014-01-07 12:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389097880-14783-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Register NAP server and adds bnep bridge. Removes bridge
on destroy call. Bridge mechanism is needed when device acting
as a server and listen for incoming connections.
---
android/pan.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 108 insertions(+), 4 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 38e353d..93078ba 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -28,6 +28,11 @@
#include <unistd.h>
#include <fcntl.h>
#include <glib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <net/if.h>
+#include <linux/sockios.h>
#include "btio/btio.h"
#include "lib/bluetooth.h"
@@ -45,11 +50,11 @@
#include "bluetooth.h"
#define SVC_HINT_NETWORKING 0x02
+#define BNEP_BRIDGE "bnep"
static bdaddr_t adapter_addr;
GSList *devices = NULL;
uint8_t local_role = HAL_PAN_ROLE_NONE;
-static uint32_t record_id = 0;
struct pan_device {
char iface[16];
@@ -60,6 +65,12 @@ struct pan_device {
struct bnep *session;
};
+static struct {
+ uint32_t record_id;
+} nap_dev = {
+ .record_id = 0,
+};
+
static int device_cmp(gconstpointer s, gconstpointer user_data)
{
const struct pan_device *dev = s;
@@ -297,6 +308,91 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
}
+static int set_forward_delay(void)
+{
+ int fd, ret;
+ char path[41];
+
+ sprintf(path, "/sys/class/net/%s/bridge/forward_delay", BNEP_BRIDGE);
+
+ fd = open(path, O_RDWR);
+ if (fd < 0)
+ return -errno;
+
+ ret = write(fd, "0", sizeof("0"));
+ close(fd);
+
+ return ret;
+}
+
+static int nap_create_bridge(void)
+{
+ int sk, err;
+
+ DBG("%s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) < 0) {
+ err = -errno;
+ if (err != -EEXIST) {
+ close(sk);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ err = set_forward_delay();
+ if (err < 0)
+ ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+
+ close(sk);
+
+ return err;
+}
+
+static int nap_remove_bridge(void)
+{
+ int sk, err;
+
+ DBG("%s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ err = ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+ close(sk);
+
+ if (err < 0)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static void destroy_nap_device(void)
+{
+ DBG("");
+
+ nap_remove_bridge();
+
+ nap_dev.record_id = 0;
+}
+
+static int register_nap_server(void)
+{
+ int err;
+
+ DBG("");
+
+ err = nap_create_bridge();
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
static void bt_pan_enable(const void *buf, uint16_t len)
{
const struct hal_cmd_pan_enable *cmd = buf;
@@ -441,7 +537,15 @@ bool bt_pan_register(const bdaddr_t *addr)
return false;
}
- record_id = rec->handle;
+ err = register_nap_server();
+ if (err < 0) {
+ bt_adapter_remove_record(rec->handle);
+ sdp_record_free(rec);
+ bnep_cleanup();
+ return false;
+ }
+
+ nap_dev.record_id = rec->handle;
ipc_register(HAL_SERVICE_ID_PAN, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
@@ -455,6 +559,6 @@ void bt_pan_unregister(void)
bnep_cleanup();
ipc_unregister(HAL_SERVICE_ID_PAN);
- bt_adapter_remove_record(record_id);
- record_id = 0;
+ bt_adapter_remove_record(nap_dev.record_id);
+ destroy_nap_device();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v3 0/4] Add support for NAP role
From: Ravi kumar Veeramally @ 2014-01-07 12:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
v3: Fixed Johan's comments (removed fopen, fprintf and used open and write).
v2: Fixed Johan's comments.
v1: This patch set add support for NAP role. It register NAP server and create
bnep bridge and listen for incoming connections from client devices.
On incoming connection request it accepts connection, creates bnep interface
and notifies control state and connection state infromation. Removes device
on disconnect request. Android related changes are required to enable this
role. Patches sent to respective ML.
Ravi kumar Veeramally (4):
android/pan: Register Network Access Point
android/pan: Listen for incoming connections and accept in NAP role
android/pan: Implement PAN enable HAL api at daemon side
android/pan: Remove connected PAN devices on profile unregister call
android/pan.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 334 insertions(+), 12 deletions(-)
--
1.8.3.2
^ permalink raw reply
* Re: [PATCH] Bluetooth: hidp: make sure input buffers are big enough
From: Jiri Kosina @ 2014-01-07 12:11 UTC (permalink / raw)
To: David Herrmann
Cc: Marcel Holtmann, open list:HID CORE LAYER,
linux-bluetooth@vger.kernel.org development, Gustavo F. Padovan
In-Reply-To: <CANq1E4TOHvb3--H6SoRhB09sUwuYkrvSAXCNN2Y0PaVSOEte=w@mail.gmail.com>
On Fri, 27 Dec 2013, David Herrmann wrote:
> >> I also haven't figured out a nice way to make HID-core honor the
> >> "size" parameter. hid-input depends on getting the whole
> >> input-report.
> >
> > I think this needs clearly fixing.
>
> And we have a volunteer, yippie! ;)
>
> I think hid_input_report() in hid-core.c is the only place that relies
> on this. Maybe it really is easier to fix it. But I am not even
> slightly familiar with that code. So if no-one of the HID core
> developers steps up to fix it, we should take the transport-driver
> fixes instead. As nearly all transport-drivers are affected by this,
> maybe we should even move this buffer into hid_device and provide
> hid_input_truncated_report() which does this.
>
> Anyhow, waiting for Jiri's comments on this.
Hmm, this is really unfortunate situation.
I am now looking into making hid_input_report() honor 'size' properly, but
no matter how it'll be done in the end, it'll absolutely not be a simple
'fix'. So definitely can be done for 3.15 or so, but not as a fix for
current kernels.
So doing kzalloc(rsize, GFP_ATOMIC) in the HID-core for now, and copying
the buffer around, seems like only viable solution for now, with the
outlook of removing this ugliness once hid-core honors 'size' properly.
I will keep looking into this and maybe some easy way how to hack this
together will materialize, but I don't currently see it.
Hmm ...
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* [PATCH 2/2] Bluetooth: Fix 6loWPAN peer lookup
From: Claudio Takahasi @ 2014-01-07 12:07 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1389096468-2917-1-git-send-email-claudio.takahasi@openbossa.org>
This patch fixes peer address lookup for 6loWPAN over Bluetooth Low
Energy links.
ADDR_LE_DEV_PUBLIC, and ADDR_LE_DEV_RANDOM are the values allowed for
"dst_type" field in the hci_conn struct for LE links.
Signed-off-by: Claudio Takahasi <claudio.takahasi@openbossa.org>
---
net/bluetooth/6lowpan.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index ab4e771..adb3ea0 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -439,9 +439,9 @@ static void get_dest_bdaddr(struct in6_addr *ip6_daddr,
/* Set universal/local bit to 0 */
if (addr->b[5] & 1) {
addr->b[5] &= ~1;
- *addr_type = BDADDR_LE_PUBLIC;
+ *addr_type = ADDR_LE_DEV_PUBLIC;
} else {
- *addr_type = BDADDR_LE_RANDOM;
+ *addr_type = ADDR_LE_DEV_RANDOM;
}
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH 1/2] Bluetooth: Fix setting Universal/Local bit
From: Claudio Takahasi @ 2014-01-07 12:07 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
This patch fixes the Bluetooth Low Energy Address type checking when
setting Universal/Local bit for the 6loWPAN network device or for the
peer device connection.
ADDR_LE_DEV_PUBLIC or ADDR_LE_DEV_RANDOM are the values allowed for
"src_type" and "dst_type" in the hci_conn struct. The Bluetooth link
type can be obtainned reading the "type" field in the same struct.
Signed-off-by: Claudio Takahasi <claudio.takahasi@openbossa.org>
---
net/bluetooth/6lowpan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 5f0b11d..ab4e771 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -623,7 +623,7 @@ static void set_addr(u8 *eui, u8 *addr, u8 addr_type)
eui[0] ^= 2;
/* Universal/local bit set, RFC 4291 */
- if (addr_type == BDADDR_LE_PUBLIC)
+ if (addr_type == ADDR_LE_DEV_PUBLIC)
eui[0] |= 1;
else
eui[0] &= ~1;
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH_v2 1/4] android/pan: Register Network Access Point
From: Ravi kumar Veeramally @ 2014-01-07 12:04 UTC (permalink / raw)
To: linux-bluetooth, johan.hedberg
In-Reply-To: <20140107115539.GA2107@x220.p-661hnu-f1>
Hi Johan,
On 01/07/2014 01:55 PM, Johan Hedberg wrote:
> Hi Ravi,
>
> On Tue, Jan 07, 2014, Ravi kumar Veeramally wrote:
>> +static int set_forward_delay(void)
>> +{
>> + FILE *f;
>> + char *path;
>> +
>> + path = g_strdup_printf("/sys/class/net/%s/bridge/forward_delay",
>> + BNEP_BRIDGE);
>> + if (!path)
>> + return -ENOMEM;
>> +
>> + f = fopen(path, "r+");
>> + g_free(path);
>> + if (!f)
>> + return -errno;
> The above is not safe since g_free() might modify the value of errno.
>
> In general, we're not really in the habit of using the f* variants of
> file access functions. Could you convert the above to use a stack
> variable for path (there's a PATH_MAX variable you can use for its
> size) together with sprintf and use open + write instead of fopen +
> fprintf?
Ok, I will change it.
>> +static int nap_create_bridge(void)
>> +{
>> + int sk, err;
>> +
>> + DBG(" %s", BNEP_BRIDGE);
> Why the extra space before %s?
I will remove it.
>
>> + if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) == -1) {
> We usually check for this kind of errors with < 0 instead of == -1.
Ok.
>
>> + DBG(" %s", BNEP_BRIDGE);
> Same thing here with the seemingly unnecessary space.
Ok, I will remove it.
Regards,
Ravi.
^ permalink raw reply
* Re: [PATCH_v2 1/4] android/pan: Register Network Access Point
From: Johan Hedberg @ 2014-01-07 11:55 UTC (permalink / raw)
To: Ravi kumar Veeramally; +Cc: linux-bluetooth
In-Reply-To: <1389093533-13210-2-git-send-email-ravikumar.veeramally@linux.intel.com>
Hi Ravi,
On Tue, Jan 07, 2014, Ravi kumar Veeramally wrote:
> +static int set_forward_delay(void)
> +{
> + FILE *f;
> + char *path;
> +
> + path = g_strdup_printf("/sys/class/net/%s/bridge/forward_delay",
> + BNEP_BRIDGE);
> + if (!path)
> + return -ENOMEM;
> +
> + f = fopen(path, "r+");
> + g_free(path);
> + if (!f)
> + return -errno;
The above is not safe since g_free() might modify the value of errno.
In general, we're not really in the habit of using the f* variants of
file access functions. Could you convert the above to use a stack
variable for path (there's a PATH_MAX variable you can use for its
size) together with sprintf and use open + write instead of fopen +
fprintf?
> +static int nap_create_bridge(void)
> +{
> + int sk, err;
> +
> + DBG(" %s", BNEP_BRIDGE);
Why the extra space before %s?
> + if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) == -1) {
We usually check for this kind of errors with < 0 instead of == -1.
> + DBG(" %s", BNEP_BRIDGE);
Same thing here with the seemingly unnecessary space.
Johan
^ permalink raw reply
* [PATCH BlueZ v3 10/10] android/A2DP: Add stream suspend command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds the definitions to stream suspend command and response.
---
android/a2dp.c | 9 +++++++++
android/audio-msg.h | 5 +++++
2 files changed, 14 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 5d540f3..b59c53d 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -389,6 +389,13 @@ static void bt_stream_resume(const void *buf, uint16_t len)
audio_ipc_send_rsp(AUDIO_OP_RESUME_STREAM, AUDIO_STATUS_FAILED);
}
+static void bt_stream_suspend(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_OP_SUSPEND_STREAM, AUDIO_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
@@ -400,6 +407,8 @@ static const struct ipc_handler audio_handlers[] = {
{ bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
/* AUDIO_OP_RESUME_STREAM */
{ bt_stream_resume, false, sizeof(struct audio_cmd_resume_stream) },
+ /* AUDIO_OP_SUSPEND_STREAM */
+ { bt_stream_suspend, false, sizeof(struct audio_cmd_suspend_stream) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 8f92413..438bc18 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -77,3 +77,8 @@ struct audio_cmd_close_stream {
struct audio_cmd_resume_stream {
uint8_t id;
} __attribute__((packed));
+
+#define AUDIO_OP_SUSPEND_STREAM 0x06
+struct audio_cmd_suspend_stream {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 09/10] android/A2DP: Add stream resume command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds the definitions to stream resume command and response.
---
android/a2dp.c | 9 +++++++++
android/audio-msg.h | 5 +++++
2 files changed, 14 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 7c49bc9..5d540f3 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -382,6 +382,13 @@ static void bt_stream_close(const void *buf, uint16_t len)
audio_ipc_send_rsp(AUDIO_OP_CLOSE_STREAM, AUDIO_STATUS_FAILED);
}
+static void bt_stream_resume(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_OP_RESUME_STREAM, AUDIO_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
@@ -391,6 +398,8 @@ static const struct ipc_handler audio_handlers[] = {
{ bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
/* AUDIO_OP_CLOSE_STREAM */
{ bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
+ /* AUDIO_OP_RESUME_STREAM */
+ { bt_stream_resume, false, sizeof(struct audio_cmd_resume_stream) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 4dfa8cf..8f92413 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -72,3 +72,8 @@ struct audio_rsp_open_stream {
struct audio_cmd_close_stream {
uint8_t id;
} __attribute__((packed));
+
+#define AUDIO_OP_RESUME_STREAM 0x05
+struct audio_cmd_resume_stream {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 08/10] android/A2DP: Add stream close command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds the definitions to stream close command and response.
---
android/a2dp.c | 9 +++++++++
android/audio-msg.h | 5 +++++
2 files changed, 14 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 09a65e1..7c49bc9 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -375,6 +375,13 @@ static void bt_stream_open(const void *buf, uint16_t len)
audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, AUDIO_STATUS_FAILED);
}
+static void bt_stream_close(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_OP_CLOSE_STREAM, AUDIO_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
@@ -382,6 +389,8 @@ static const struct ipc_handler audio_handlers[] = {
{ bt_audio_close, false, sizeof(struct audio_cmd_close) },
/* AUDIO_OP_OPEN_STREAM */
{ bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
+ /* AUDIO_OP_CLOSE_STREAM */
+ { bt_stream_close, false, sizeof(struct audio_cmd_close_stream) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 0f0309a..4dfa8cf 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -67,3 +67,8 @@ struct audio_rsp_open_stream {
uint8_t len;
uint8_t data[0];
} __attribute__((packed));
+
+#define AUDIO_OP_CLOSE_STREAM 0x04
+struct audio_cmd_close_stream {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 07/10] android/A2DP: Add stream open command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds the definitions to stream open command and response.
---
android/a2dp.c | 9 +++++++++
android/audio-msg.h | 10 ++++++++++
2 files changed, 19 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 97e2778..09a65e1 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -368,11 +368,20 @@ static void bt_audio_close(const void *buf, uint16_t len)
audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
}
+static void bt_stream_open(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, AUDIO_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
/* AUDIO_OP_CLOSE */
{ bt_audio_close, false, sizeof(struct audio_cmd_close) },
+ /* AUDIO_OP_OPEN_STREAM */
+ { bt_stream_open, false, sizeof(struct audio_cmd_open_stream) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 6ac1fff..0f0309a 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -57,3 +57,13 @@ struct audio_rsp_open {
struct audio_cmd_close {
uint8_t id;
} __attribute__((packed));
+
+#define AUDIO_OP_OPEN_STREAM 0x03
+struct audio_cmd_open_stream {
+ uint8_t id;
+} __attribute__((packed));
+
+struct audio_rsp_open_stream {
+ uint8_t len;
+ uint8_t data[0];
+} __attribute__((packed));
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 06/10] android/A2DP: Add audio close command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds the definitions to audio close command and response.
---
android/a2dp.c | 9 +++++++++
android/audio-msg.h | 5 +++++
2 files changed, 14 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 38384f6..97e2778 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -361,9 +361,18 @@ static void bt_audio_open(const void *buf, uint16_t len)
audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
}
+static void bt_audio_close(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
/* AUDIO_OP_OPEN */
{ bt_audio_open, true, sizeof(struct audio_cmd_open) },
+ /* AUDIO_OP_CLOSE */
+ { bt_audio_close, false, sizeof(struct audio_cmd_close) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 158a2ab..6ac1fff 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -52,3 +52,8 @@ struct audio_cmd_open {
struct audio_rsp_open {
uint8_t id;
} __attribute__((packed));
+
+#define AUDIO_OP_CLOSE 0x02
+struct audio_cmd_close {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 05/10] android/A2DP: Add audio open command/response struct
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds the definitions to audio open command and response.
---
android/a2dp.c | 9 +++++++++
android/audio-ipc-api.txt | 2 +-
android/audio-msg.h | 18 ++++++++++++++++++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index c12d8f1..38384f6 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -354,7 +354,16 @@ static sdp_record_t *a2dp_record(void)
return record;
}
+static void bt_audio_open(const void *buf, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
+}
+
static const struct ipc_handler audio_handlers[] = {
+ /* AUDIO_OP_OPEN */
+ { bt_audio_open, true, sizeof(struct audio_cmd_open) },
};
bool bt_a2dp_register(const bdaddr_t *addr)
diff --git a/android/audio-ipc-api.txt b/android/audio-ipc-api.txt
index 1c42800..37a1569 100644
--- a/android/audio-ipc-api.txt
+++ b/android/audio-ipc-api.txt
@@ -49,9 +49,9 @@ Identifier: "audio" (BT_AUDIO_ID)
Command parameters: Service UUID (16 octets)
Codec ID (1 octet)
+ Number of codec presets (1 octet)
Codec capabilities length (1 octet)
Codec capabilities (variable)
- Number of codec presets (1 octet)
Codec preset # length (1 octet)
Codec preset # configuration (variable)
...
diff --git a/android/audio-msg.h b/android/audio-msg.h
index ae8a168..158a2ab 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -34,3 +34,21 @@ static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
struct audio_status {
uint8_t code;
} __attribute__((packed));
+
+#define AUDIO_OP_OPEN 0x01
+struct audio_preset {
+ uint8_t len;
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct audio_cmd_open {
+ uint16_t uuid;
+ uint8_t codec;
+ uint8_t presets;
+ uint8_t len;
+ struct audio_preset preset[0];
+} __attribute__((packed));
+
+struct audio_rsp_open {
+ uint8_t id;
+} __attribute__((packed));
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 04/10] android/A2DP: Add initial code to handle audio IPC commands
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds initial code to handle audio IPC commands.
---
android/a2dp.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 581d094..c12d8f1 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -44,6 +44,8 @@
#include "utils.h"
#include "bluetooth.h"
#include "avdtp.h"
+#include "audio-msg.h"
+#include "audio-ipc.h"
#define L2CAP_PSM_AVDTP 0x19
#define SVC_HINT_CAPTURING 0x08
@@ -352,6 +354,9 @@ static sdp_record_t *a2dp_record(void)
return record;
}
+static const struct ipc_handler audio_handlers[] = {
+};
+
bool bt_a2dp_register(const bdaddr_t *addr)
{
GError *err = NULL;
@@ -359,6 +364,8 @@ bool bt_a2dp_register(const bdaddr_t *addr)
DBG("");
+ audio_ipc_init();
+
bacpy(&adapter_addr, addr);
server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
@@ -388,6 +395,8 @@ bool bt_a2dp_register(const bdaddr_t *addr)
ipc_register(HAL_SERVICE_ID_A2DP, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
+ audio_ipc_register(audio_handlers, G_N_ELEMENTS(audio_handlers));
+
return true;
fail:
@@ -411,8 +420,9 @@ void bt_a2dp_unregister(void)
g_slist_foreach(devices, a2dp_device_disconnected, NULL);
devices = NULL;
-
ipc_unregister(HAL_SERVICE_ID_A2DP);
+ audio_ipc_unregister();
+
bt_adapter_remove_record(record_id);
record_id = 0;
@@ -421,4 +431,6 @@ void bt_a2dp_unregister(void)
g_io_channel_unref(server);
server = NULL;
}
+
+ audio_ipc_cleanup();
}
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 03/10] android/ipc: Add audio_ipc_send_rsp and audio_ipc_send_rsp_full
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
These functions can be used to respond to commands recieved over audio
IPC.
---
android/audio-ipc.c | 23 +++++++++++++++++++++++
android/audio-ipc.h | 3 +++
android/audio-msg.h | 8 ++++++++
android/ipc.c | 2 +-
android/ipc.h | 2 ++
5 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/android/audio-ipc.c b/android/audio-ipc.c
index 0c5433a..f4b55e3 100644
--- a/android/audio-ipc.c
+++ b/android/audio-ipc.c
@@ -123,3 +123,26 @@ void audio_ipc_unregister(void)
service.handler = NULL;
service.size = 0;
}
+
+void audio_ipc_send_rsp(uint8_t opcode, uint8_t status)
+{
+ struct audio_status s;
+ int sk;
+
+ sk = g_io_channel_unix_get_fd(audio_io);
+
+ if (status == AUDIO_STATUS_SUCCESS) {
+ ipc_send(sk, AUDIO_SERVICE_ID, opcode, 0, NULL, -1);
+ return;
+ }
+
+ s.code = status;
+
+ ipc_send(sk, AUDIO_SERVICE_ID, AUDIO_OP_STATUS, sizeof(s), &s, -1);
+}
+
+void audio_ipc_send_rsp_full(uint8_t opcode, uint16_t len, void *param, int fd)
+{
+ ipc_send(g_io_channel_unix_get_fd(audio_io), AUDIO_SERVICE_ID, opcode,
+ len, param, fd);
+}
diff --git a/android/audio-ipc.h b/android/audio-ipc.h
index 1dfa245..0b5f216 100644
--- a/android/audio-ipc.h
+++ b/android/audio-ipc.h
@@ -26,3 +26,6 @@ void audio_ipc_cleanup(void);
void audio_ipc_register(const struct ipc_handler *handlers, uint8_t size);
void audio_ipc_unregister(void);
+
+void audio_ipc_send_rsp(uint8_t opcode, uint8_t status);
+void audio_ipc_send_rsp_full(uint8_t opcode, uint16_t len, void *param, int fd);
diff --git a/android/audio-msg.h b/android/audio-msg.h
index 1ec2520..ae8a168 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -26,3 +26,11 @@
static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
#define AUDIO_SERVICE_ID 0
+
+#define AUDIO_STATUS_SUCCESS 0x00
+#define AUDIO_STATUS_FAILED 0x01
+
+#define AUDIO_OP_STATUS 0x00
+struct audio_status {
+ uint8_t code;
+} __attribute__((packed));
diff --git a/android/ipc.c b/android/ipc.c
index 1499962..03bdc35 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -245,7 +245,7 @@ void ipc_cleanup(void)
}
}
-static void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
+void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
void *param, int fd)
{
struct msghdr msg;
diff --git a/android/ipc.h b/android/ipc.h
index 7b8bdeb..b1cc5c5 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -43,6 +43,8 @@ void ipc_send_rsp_full(uint8_t service_id, uint8_t opcode, uint16_t len,
void *param, int fd);
void ipc_send_notif(uint8_t service_id, uint8_t opcode, uint16_t len,
void *param);
+void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
+ void *param, int fd);
void ipc_register(uint8_t service, const struct ipc_handler *handlers,
uint8_t size);
void ipc_unregister(uint8_t service);
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 02/10] android/ipc: Add message handling for audio IPC
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389095603-30504-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds audio_ipc_register and audio_ipc_unregister and adapt
ipc_handle_msg to be able to handle audio services messages.
---
android/audio-ipc.c | 23 +++++++++++++++++++-
android/audio-ipc.h | 3 +++
android/audio-msg.h | 2 ++
android/ipc.c | 60 +++++++++++++++++++++++++----------------------------
android/ipc.h | 8 +++++++
5 files changed, 63 insertions(+), 33 deletions(-)
diff --git a/android/audio-ipc.c b/android/audio-ipc.c
index b537f21..0c5433a 100644
--- a/android/audio-ipc.c
+++ b/android/audio-ipc.c
@@ -41,12 +41,14 @@
static GIOChannel *audio_io = NULL;
+static struct service_handler service;
+
static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
char buf[BLUEZ_AUDIO_MTU];
ssize_t ret;
- int fd;
+ int fd, err;
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
info("Audio IPC: command socket closed");
@@ -61,6 +63,13 @@ static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
goto fail;
}
+ err = ipc_handle_msg(&service, AUDIO_SERVICE_ID, buf, ret);
+ if (err < 0) {
+ error("Audio IPC: failed to handle message (%s)",
+ strerror(-err));
+ goto fail;
+ }
+
return TRUE;
fail:
@@ -102,3 +111,15 @@ void audio_ipc_cleanup(void)
audio_io = NULL;
}
}
+
+void audio_ipc_register(const struct ipc_handler *handlers, uint8_t size)
+{
+ service.handler = handlers;
+ service.size = size;
+}
+
+void audio_ipc_unregister(void)
+{
+ service.handler = NULL;
+ service.size = 0;
+}
diff --git a/android/audio-ipc.h b/android/audio-ipc.h
index 769bfd6..1dfa245 100644
--- a/android/audio-ipc.h
+++ b/android/audio-ipc.h
@@ -23,3 +23,6 @@
void audio_ipc_init(void);
void audio_ipc_cleanup(void);
+
+void audio_ipc_register(const struct ipc_handler *handlers, uint8_t size);
+void audio_ipc_unregister(void);
diff --git a/android/audio-msg.h b/android/audio-msg.h
index d5b4099..1ec2520 100644
--- a/android/audio-msg.h
+++ b/android/audio-msg.h
@@ -24,3 +24,5 @@
#define BLUEZ_AUDIO_MTU 1024
static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
+
+#define AUDIO_SERVICE_ID 0
diff --git a/android/ipc.c b/android/ipc.c
index 8a91248..1499962 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -40,56 +40,45 @@
#include "ipc.h"
#include "log.h"
-struct service_handler {
- const struct ipc_handler *handler;
- uint8_t size;
-};
-
static struct service_handler services[HAL_SERVICE_ID_MAX + 1];
static GIOChannel *cmd_io = NULL;
static GIOChannel *notif_io = NULL;
-static void ipc_handle_msg(const void *buf, ssize_t len)
+int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
+ const void *buf, ssize_t len)
{
const struct hal_hdr *msg = buf;
const struct ipc_handler *handler;
if (len < (ssize_t) sizeof(*msg)) {
- error("IPC: message too small (%zd bytes), terminating", len);
- raise(SIGTERM);
- return;
+ DBG("message too small (%zd bytes)", len);
+ return -EBADMSG;
}
if (len != (ssize_t) (sizeof(*msg) + msg->len)) {
- error("IPC: message malformed (%zd bytes), terminating", len);
- raise(SIGTERM);
- return;
+ DBG("message malformed (%zd bytes)", len);
+ return -EBADMSG;
}
/* if service is valid */
- if (msg->service_id > HAL_SERVICE_ID_MAX) {
- error("IPC: unknown service (0x%x), terminating",
- msg->service_id);
- raise(SIGTERM);
- return;
+ if (msg->service_id > max_index) {
+ DBG("unknown service (0x%x)", msg->service_id);
+ return -EOPNOTSUPP;
}
/* if service is registered */
- if (!services[msg->service_id].handler) {
- error("IPC: unregistered service (0x%x), terminating",
- msg->service_id);
- raise(SIGTERM);
- return;
+ if (!handlers[msg->service_id].handler) {
+ DBG("service not registered (0x%x)", msg->service_id);
+ return -EOPNOTSUPP;
}
/* if opcode is valid */
if (msg->opcode == HAL_OP_STATUS ||
- msg->opcode > services[msg->service_id].size) {
- error("IPC: invalid opcode 0x%x for service 0x%x, terminating",
- msg->opcode, msg->service_id);
- raise(SIGTERM);
- return;
+ msg->opcode > handlers[msg->service_id].size) {
+ DBG("invalid opcode 0x%x for service 0x%x", msg->opcode,
+ msg->service_id);
+ return -EOPNOTSUPP;
}
/* opcode is table offset + 1 */
@@ -98,13 +87,14 @@ static void ipc_handle_msg(const void *buf, ssize_t len)
/* if payload size is valid */
if ((handler->var_len && handler->data_len > msg->len) ||
(!handler->var_len && handler->data_len != msg->len)) {
- error("IPC: size invalid opcode 0x%x service 0x%x, terminating",
+ DBG("invalid size for opcode 0x%x service 0x%x",
msg->service_id, msg->opcode);
- raise(SIGTERM);
- return;
+ return -EMSGSIZE;
}
handler->handler(msg->payload, msg->len);
+
+ return 0;
}
static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
@@ -112,7 +102,7 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
{
char buf[BLUEZ_HAL_MTU];
ssize_t ret;
- int fd;
+ int fd, err;
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
info("IPC: command socket closed, terminating");
@@ -128,7 +118,13 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
goto fail;
}
- ipc_handle_msg(buf, ret);
+ err = ipc_handle_msg(services, HAL_SERVICE_ID_MAX, buf, ret);
+ if (err < 0) {
+ error("IPC: failed to handle message, terminating (%s)",
+ strerror(-err));
+ goto fail;
+ }
+
return TRUE;
fail:
diff --git a/android/ipc.h b/android/ipc.h
index 02ad6bb..7b8bdeb 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -26,9 +26,17 @@ struct ipc_handler {
bool var_len;
size_t data_len;
};
+
+struct service_handler {
+ const struct ipc_handler *handler;
+ uint8_t size;
+};
+
void ipc_init(void);
void ipc_cleanup(void);
GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb);
+int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
+ const void *buf, ssize_t len);
void ipc_send_rsp(uint8_t service_id, uint8_t opcode, uint8_t status);
void ipc_send_rsp_full(uint8_t service_id, uint8_t opcode, uint16_t len,
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v3 01/10] android/ipc: Add initial code for audio IPC
From: Luiz Augusto von Dentz @ 2014-01-07 11:53 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This add initial code for listen and accept connections on the abstract
socket defined for the audio IPC.
---
v2: Split audio IPC services for HAL services and fix invalid messages or
disconnections causing the daemon to exit. The audio HAL is independent of
bluetooth and should only affect A2DP service.
v3: Split audio IPC related functions to separate files (audio-ipc.{c,h}),
please disregard git thinking there is a copy of hdp code because they are
similar.
android/Android.mk | 1 +
android/Makefile.am | 2 +
android/audio-ipc.c | 104 +++++++++++++++++++++
.../health/hdp_manager.h => android/audio-ipc.h | 7 +-
monitor/analyze.h => android/audio-msg.h | 7 +-
android/ipc.c | 14 +--
android/ipc.h | 1 +
7 files changed, 124 insertions(+), 12 deletions(-)
create mode 100644 android/audio-ipc.c
copy profiles/health/hdp_manager.h => android/audio-ipc.h (86%)
copy monitor/analyze.h => android/audio-msg.h (83%)
diff --git a/android/Android.mk b/android/Android.mk
index 7d9cc4f..27631cc 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -26,6 +26,7 @@ LOCAL_SRC_FILES := \
hidhost.c \
socket.c \
ipc.c ipc.h \
+ audio-ipc.c audio-ipc.h \
avdtp.c \
a2dp.c \
pan.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 7d9b580..8810369 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -15,6 +15,7 @@ noinst_PROGRAMS += android/bluetoothd
android_bluetoothd_SOURCES = android/main.c \
src/log.c \
android/hal-msg.h \
+ android/audio-msg.h \
android/utils.h \
src/sdpd-database.c src/sdpd-server.c \
src/sdpd-service.c src/sdpd-request.c \
@@ -25,6 +26,7 @@ android_bluetoothd_SOURCES = android/main.c \
android/bluetooth.h android/bluetooth.c \
android/hidhost.h android/hidhost.c \
android/ipc.h android/ipc.c \
+ android/audio-ipc.h android/audio-ipc.c \
android/avdtp.h android/avdtp.c \
android/a2dp.h android/a2dp.c \
android/socket.h android/socket.c \
diff --git a/android/audio-ipc.c b/android/audio-ipc.c
new file mode 100644
index 0000000..b537f21
--- /dev/null
+++ b/android/audio-ipc.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stddef.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "ipc.h"
+#include "log.h"
+#include "audio-msg.h"
+#include "audio-ipc.h"
+
+static GIOChannel *audio_io = NULL;
+
+static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ char buf[BLUEZ_AUDIO_MTU];
+ ssize_t ret;
+ int fd;
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ info("Audio IPC: command socket closed");
+ goto fail;
+ }
+
+ fd = g_io_channel_unix_get_fd(io);
+
+ ret = read(fd, buf, sizeof(buf));
+ if (ret < 0) {
+ error("Audio IPC: command read failed (%s)", strerror(errno));
+ goto fail;
+ }
+
+ return TRUE;
+
+fail:
+ audio_ipc_cleanup();
+ return FALSE;
+}
+
+static gboolean audio_connect_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ DBG("");
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ error("Audio IPC: socket connect failed");
+ audio_ipc_cleanup();
+ return FALSE;
+ }
+
+ cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+
+ g_io_add_watch(audio_io, cond, audio_watch_cb, NULL);
+
+ info("Audio IPC: successfully connected");
+
+ return FALSE;
+}
+
+void audio_ipc_init(void)
+{
+ audio_io = ipc_connect(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
+ audio_connect_cb);
+}
+
+void audio_ipc_cleanup(void)
+{
+ if (audio_io) {
+ g_io_channel_shutdown(audio_io, TRUE, NULL);
+ g_io_channel_unref(audio_io);
+ audio_io = NULL;
+ }
+}
diff --git a/profiles/health/hdp_manager.h b/android/audio-ipc.h
similarity index 86%
copy from profiles/health/hdp_manager.h
copy to android/audio-ipc.h
index 1cab4d0..769bfd6 100644
--- a/profiles/health/hdp_manager.h
+++ b/android/audio-ipc.h
@@ -2,7 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
*
* 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
@@ -20,5 +21,5 @@
*
*/
-int hdp_manager_init(void);
-void hdp_manager_exit(void);
+void audio_ipc_init(void);
+void audio_ipc_cleanup(void);
diff --git a/monitor/analyze.h b/android/audio-msg.h
similarity index 83%
copy from monitor/analyze.h
copy to android/audio-msg.h
index 7cdda51..d5b4099 100644
--- a/monitor/analyze.h
+++ b/android/audio-msg.h
@@ -2,8 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2011-2012 Intel Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
*
*
* This library is free software; you can redistribute it and/or
@@ -22,4 +21,6 @@
*
*/
-void analyze_trace(const char *path);
+#define BLUEZ_AUDIO_MTU 1024
+
+static const char BLUEZ_AUDIO_SK_PATH[] = "\0bluez_audio_socket";
diff --git a/android/ipc.c b/android/ipc.c
index 9e8ccc3..8a91248 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -145,7 +145,7 @@ static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
-static GIOChannel *connect_hal(GIOFunc connect_cb)
+GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb)
{
struct sockaddr_un addr;
GIOCondition cond;
@@ -167,11 +167,11 @@ static GIOChannel *connect_hal(GIOFunc connect_cb)
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
- memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
+ memcpy(addr.sun_path, path, size);
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- error("IPC: failed to connect HAL socket: %d (%s)", errno,
- strerror(errno));
+ error("IPC: failed to connect HAL socket %s: %d (%s)", &path[1],
+ errno, strerror(errno));
g_io_channel_unref(io);
return NULL;
}
@@ -218,7 +218,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
- notif_io = connect_hal(notif_connect_cb);
+ notif_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
+ notif_connect_cb);
if (!notif_io)
raise(SIGTERM);
@@ -227,7 +228,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
void ipc_init(void)
{
- cmd_io = connect_hal(cmd_connect_cb);
+ cmd_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
+ cmd_connect_cb);
if (!cmd_io)
raise(SIGTERM);
}
diff --git a/android/ipc.h b/android/ipc.h
index 6cd102b..02ad6bb 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -28,6 +28,7 @@ struct ipc_handler {
};
void ipc_init(void);
void ipc_cleanup(void);
+GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb);
void ipc_send_rsp(uint8_t service_id, uint8_t opcode, uint8_t status);
void ipc_send_rsp_full(uint8_t service_id, uint8_t opcode, uint16_t len,
--
1.8.4.2
^ permalink raw reply related
* [PATCH_v2 4/4] android/pan: Remove connected PAN devices on profile unregister call
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389093533-13210-1-git-send-email-ravikumar.veeramally@linux.intel.com>
---
android/pan.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/android/pan.c b/android/pan.c
index 65777c8..e195061 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -764,10 +764,20 @@ bool bt_pan_register(const bdaddr_t *addr)
return true;
}
+static void pan_device_disconnected(gpointer data, gpointer user_data)
+{
+ struct pan_device *dev = data;
+
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
void bt_pan_unregister(void)
{
DBG("");
+ g_slist_foreach(devices, pan_device_disconnected, NULL);
+ devices = NULL;
+
bnep_cleanup();
ipc_unregister(HAL_SERVICE_ID_PAN);
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v2 3/4] android/pan: Implement PAN enable HAL api at daemon side
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389093533-13210-1-git-send-email-ravikumar.veeramally@linux.intel.com>
---
android/pan.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 0b32fbc..65777c8 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -589,18 +589,38 @@ static void bt_pan_enable(const void *buf, uint16_t len)
{
const struct hal_cmd_pan_enable *cmd = buf;
uint8_t status;
+ int err;
+
+ DBG("");
+
+ if (local_role == cmd->local_role) {
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
+ }
+
+ /* destroy existing server */
+ destroy_nap_device();
switch (cmd->local_role) {
case HAL_PAN_ROLE_PANU:
- case HAL_PAN_ROLE_NAP:
- DBG("Not Implemented");
- status = HAL_STATUS_FAILED;
- break;
- default:
status = HAL_STATUS_UNSUPPORTED;
- break;
+ goto reply;
+ case HAL_PAN_ROLE_NONE:
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
+ }
+
+ local_role = cmd->local_role;
+ err = register_nap_server();
+ if (err < 0) {
+ status = HAL_STATUS_FAILED;
+ destroy_nap_device();
+ goto reply;
}
+ status = HAL_STATUS_SUCCESS;
+
+reply:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_ENABLE, status);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v2 2/4] android/pan: Listen for incoming connections and accept in NAP role
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389093533-13210-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Listen for incoming connections and accept it. Create bnep interface
add it to bridge and notify control and connection state information
through HAL. Remove the device on disconnect request. If android
settings UI does not have bluetooth tethering enabled it immediately
sends disconnect signal.
---
android/pan.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 190 insertions(+), 2 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 80eb275..0b32fbc 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -63,12 +63,17 @@ struct pan_device {
uint8_t role;
GIOChannel *io;
struct bnep *session;
+ guint watch;
};
static struct {
uint32_t record_id;
+ guint watch;
+ GIOChannel *io;
} nap_dev = {
.record_id = 0,
+ .watch = 0,
+ .io = NULL,
};
static int device_cmp(gconstpointer s, gconstpointer user_data)
@@ -81,13 +86,21 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
static void pan_device_free(struct pan_device *dev)
{
+ if (dev->watch > 0) {
+ bnep_server_delete(BNEP_BRIDGE, dev->iface, &dev->dst);
+ g_source_remove(dev->watch);
+ dev->watch = 0;
+ }
+
if (dev->io) {
g_io_channel_shutdown(dev->io, FALSE, NULL);
g_io_channel_unref(dev->io);
dev->io = NULL;
}
- bnep_free(dev->session);
+ if (dev->session)
+ bnep_free(dev->session);
+
devices = g_slist_remove(devices, dev);
g_free(dev);
@@ -298,7 +311,7 @@ static void bt_pan_disconnect(const void *buf, uint16_t len)
dev = l->data;
- if (dev->conn_state == HAL_PAN_STATE_CONNECTED)
+ if (dev->conn_state == HAL_PAN_STATE_CONNECTED && dev->session)
bnep_disconnect(dev->session);
bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
@@ -308,6 +321,154 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
}
+static gboolean nap_watchdog_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+
+ DBG("disconnected");
+
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+
+ return FALSE;
+}
+static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+ uint8_t packet[BNEP_MTU];
+ struct bnep_setup_conn_req *req = (void *) packet;
+ uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
+ int sk, n;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ error("Hangup or error or inval on BNEP socket");
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
+ n = read(sk, packet, sizeof(packet));
+ if (n < 0) {
+ error("read(): %s(%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ /* Highest known control command id BNEP_FILTER_MULT_ADDR_RSP 0x06 */
+ if (req->type == BNEP_CONTROL &&
+ req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
+ error("cmd not understood");
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_CMD_NOT_UNDERSTOOD,
+ req->ctrl);
+ goto failed;
+ }
+
+ if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) {
+ error("cmd is not BNEP_SETUP_CONN_REQ %02X %02X", req->type,
+ req->ctrl);
+ goto failed;
+ }
+
+ rsp = bnep_setup_decode(req, &dst_role, &src_role);
+ if (rsp) {
+ error("bnep_setup_decode failed");
+ goto failed;
+ }
+
+ rsp = bnep_setup_chk(dst_role, src_role);
+ if (rsp) {
+ error("benp_setup_chk failed");
+ goto failed;
+ }
+
+ if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
+ &dev->dst) < 0) {
+ error("server_connadd failed");
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto failed;
+ }
+
+ rsp = BNEP_SUCCESS;
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+
+ dev->watch = g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ nap_watchdog_cb, dev);
+ g_io_channel_unref(dev->io);
+ dev->io = NULL;
+
+ bt_pan_notify_ctrl_state(dev, HAL_PAN_CTRL_ENABLED);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTED);
+
+ return FALSE;
+
+failed:
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+ pan_device_free(dev);
+
+ return FALSE;
+}
+
+static void nap_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+
+ DBG("");
+
+ if (err) {
+ error("%s", err->message);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+ return;
+ }
+
+ g_io_channel_set_close_on_unref(chan, TRUE);
+ dev->watch = g_io_add_watch(chan,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ nap_setup_cb, dev);
+}
+
+static void nap_confirm_cb(GIOChannel *chan, gpointer data)
+{
+ struct pan_device *dev = NULL;
+ bdaddr_t dst;
+ char address[18];
+ GError *err = NULL;
+
+ DBG("");
+
+ bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ DBG("incoming connect request from %s", address);
+ dev = g_new0(struct pan_device, 1);
+ bacpy(&dev->dst, &dst);
+ local_role = HAL_PAN_ROLE_NAP;
+ dev->role = HAL_PAN_ROLE_PANU;
+
+ dev->io = g_io_channel_ref(chan);
+ g_io_channel_set_close_on_unref(dev->io, TRUE);
+
+ if (!bt_io_accept(dev->io, nap_connect_cb, dev, NULL, &err)) {
+ error("bt_io_accept: %s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ devices = g_slist_append(devices, dev);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTING);
+
+ return;
+
+failed:
+ g_free(dev);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
static int set_forward_delay(void)
{
FILE *f;
@@ -382,10 +543,22 @@ static void destroy_nap_device(void)
nap_remove_bridge();
nap_dev.record_id = 0;
+
+ if (nap_dev.watch > 0) {
+ g_source_remove(nap_dev.watch);
+ nap_dev.watch = 0;
+ }
+
+ if (nap_dev.io) {
+ g_io_channel_shutdown(nap_dev.io, FALSE, NULL);
+ g_io_channel_unref(nap_dev.io);
+ nap_dev.io = NULL;
+ }
}
static int register_nap_server(void)
{
+ GError *gerr;
int err;
DBG("");
@@ -394,6 +567,21 @@ static int register_nap_server(void)
if (err < 0)
return err;
+ nap_dev.io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_PSM, BNEP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_OMTU, BNEP_MTU,
+ BT_IO_OPT_IMTU, BNEP_MTU,
+ BT_IO_OPT_INVALID);
+
+ if (!nap_dev.io) {
+ destroy_nap_device();
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return -EINVAL;
+ }
+
return 0;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v2 1/4] android/pan: Register Network Access Point
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389093533-13210-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Register NAP server and adds bnep bridge. Removes bridge
on destroy call. Bridge mechanism is needed when device acting
as a server and listen for incoming connections.
---
android/pan.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 112 insertions(+), 4 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 38e353d..80eb275 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -28,6 +28,11 @@
#include <unistd.h>
#include <fcntl.h>
#include <glib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <net/if.h>
+#include <linux/sockios.h>
#include "btio/btio.h"
#include "lib/bluetooth.h"
@@ -45,11 +50,11 @@
#include "bluetooth.h"
#define SVC_HINT_NETWORKING 0x02
+#define BNEP_BRIDGE "bnep"
static bdaddr_t adapter_addr;
GSList *devices = NULL;
uint8_t local_role = HAL_PAN_ROLE_NONE;
-static uint32_t record_id = 0;
struct pan_device {
char iface[16];
@@ -60,6 +65,12 @@ struct pan_device {
struct bnep *session;
};
+static struct {
+ uint32_t record_id;
+} nap_dev = {
+ .record_id = 0,
+};
+
static int device_cmp(gconstpointer s, gconstpointer user_data)
{
const struct pan_device *dev = s;
@@ -297,6 +308,95 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
}
+static int set_forward_delay(void)
+{
+ FILE *f;
+ char *path;
+
+ path = g_strdup_printf("/sys/class/net/%s/bridge/forward_delay",
+ BNEP_BRIDGE);
+ if (!path)
+ return -ENOMEM;
+
+ f = fopen(path, "r+");
+ g_free(path);
+ if (!f)
+ return -errno;
+
+ fprintf(f, "%d", 0);
+ fclose(f);
+
+ return 0;
+}
+
+static int nap_create_bridge(void)
+{
+ int sk, err;
+
+ DBG(" %s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) == -1) {
+ err = -errno;
+ if (err != -EEXIST) {
+ close(sk);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ err = set_forward_delay();
+ if (err < 0)
+ ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+
+ close(sk);
+
+ return err;
+}
+
+static int nap_remove_bridge(void)
+{
+ int sk, err;
+
+ DBG(" %s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ err = ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+ close(sk);
+
+ if (err < 0)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static void destroy_nap_device(void)
+{
+ DBG("");
+
+ nap_remove_bridge();
+
+ nap_dev.record_id = 0;
+}
+
+static int register_nap_server(void)
+{
+ int err;
+
+ DBG("");
+
+ err = nap_create_bridge();
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
static void bt_pan_enable(const void *buf, uint16_t len)
{
const struct hal_cmd_pan_enable *cmd = buf;
@@ -441,7 +541,15 @@ bool bt_pan_register(const bdaddr_t *addr)
return false;
}
- record_id = rec->handle;
+ err = register_nap_server();
+ if (err < 0) {
+ bt_adapter_remove_record(rec->handle);
+ sdp_record_free(rec);
+ bnep_cleanup();
+ return false;
+ }
+
+ nap_dev.record_id = rec->handle;
ipc_register(HAL_SERVICE_ID_PAN, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
@@ -455,6 +563,6 @@ void bt_pan_unregister(void)
bnep_cleanup();
ipc_unregister(HAL_SERVICE_ID_PAN);
- bt_adapter_remove_record(record_id);
- record_id = 0;
+ bt_adapter_remove_record(nap_dev.record_id);
+ destroy_nap_device();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v2 0/4] Add support for NAP role
From: Ravi kumar Veeramally @ 2014-01-07 11:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
v2: Fixed Johan's comments.
v1: This patch set add support for NAP role. It register NAP server and create
bnep bridge and listen for incoming connections from client devices.
On incoming connection request it accepts connection, creates bnep interface
and notifies control state and connection state infromation. Removes device
on disconnect request. Android related changes are required to enable this
role. Patches sent to respective ML.
Ravi kumar Veeramally (4):
android/pan: Register Network Access Point
android/pan: Listen for incoming connections and accept in NAP role
android/pan: Implement PAN enable HAL api at daemon side
android/pan: Remove connected PAN devices on profile unregister call
android/pan.c | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 338 insertions(+), 12 deletions(-)
--
1.8.3.2
^ permalink raw reply
* [PATCHv2 5/5] emulator/bthost: Add method to create rfcomm server
From: Marcin Kraglak @ 2014-01-07 10:59 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389092354-32544-1-git-send-email-marcin.kraglak@tieto.com>
It allows user to create rfcomm server on bthost.
---
emulator/bthost.c | 32 ++++++++++++++++++++++++++++++++
emulator/bthost.h | 6 ++++++
2 files changed, 38 insertions(+)
diff --git a/emulator/bthost.c b/emulator/bthost.c
index 8638f13..676c0ae 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -99,6 +99,13 @@ struct l2cap_conn_cb_data {
struct l2cap_conn_cb_data *next;
};
+struct rfcomm_conn_cb_data {
+ uint8_t channel;
+ bthost_rfcomm_connect_cb func;
+ void *user_data;
+ struct rfcomm_conn_cb_data *next;
+};
+
struct bthost {
uint8_t bdaddr[6];
bthost_send_func send_handler;
@@ -111,6 +118,7 @@ struct bthost {
bthost_new_conn_cb new_conn_cb;
void *new_conn_data;
struct l2cap_conn_cb_data *new_l2cap_conn_data;
+ struct rfcomm_conn_cb_data *new_rfcomm_conn_data;
struct l2cap_pending_req *l2reqs;
};
@@ -246,6 +254,13 @@ void bthost_destroy(struct bthost *bthost)
free(cb);
}
+ while (bthost->new_rfcomm_conn_data) {
+ struct rfcomm_conn_cb_data *cb = bthost->new_rfcomm_conn_data;
+
+ bthost->new_rfcomm_conn_data = cb->next;
+ free(cb);
+ }
+
free(bthost);
}
@@ -1392,6 +1407,23 @@ void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm,
bthost->new_l2cap_conn_data = data;
}
+void bthost_add_rfcomm_server(struct bthost *bthost, uint8_t channel,
+ bthost_rfcomm_connect_cb func, void *user_data)
+{
+ struct rfcomm_conn_cb_data *data;
+
+ data = malloc(sizeof(struct rfcomm_conn_cb_data));
+ if (!data)
+ return;
+
+ data->channel = channel;
+ data->user_data = user_data;
+ data->func = func;
+ data->next = bthost->new_rfcomm_conn_data;
+
+ bthost->new_rfcomm_conn_data = data;
+}
+
void bthost_start(struct bthost *bthost)
{
if (!bthost)
diff --git a/emulator/bthost.h b/emulator/bthost.h
index 97f011b..7186aa0 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
@@ -80,5 +80,11 @@ typedef void (*bthost_l2cap_connect_cb) (uint16_t handle, uint16_t cid,
void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm,
bthost_l2cap_connect_cb func, void *user_data);
+typedef void (*bthost_rfcomm_connect_cb) (uint16_t handle, uint16_t cid,
+ uint8_t channel, void *user_data);
+
+void bthost_add_rfcomm_server(struct bthost *bthost, uint8_t channel,
+ bthost_rfcomm_connect_cb func, void *user_data);
+
void bthost_start(struct bthost *bthost);
void bthost_stop(struct bthost *bthost);
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 4/5] emulator/bthost: Add initial rfcomm handling
From: Marcin Kraglak @ 2014-01-07 10:59 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389092354-32544-1-git-send-email-marcin.kraglak@tieto.com>
This is initial rfcomm handling in bthost.
---
emulator/bthost.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 66 insertions(+), 1 deletion(-)
diff --git a/emulator/bthost.c b/emulator/bthost.c
index 83bfdee..8638f13 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -36,6 +36,7 @@
#include "bluetooth/bluetooth.h"
#include "monitor/bt.h"
+#include "monitor/rfcomm.h"
#include "bthost.h"
/* ACL handle and flags pack/unpack */
@@ -1173,6 +1174,64 @@ static struct cid_hook *find_cid_hook(struct btconn *conn, uint16_t cid)
return NULL;
}
+static void rfcomm_sabm_recv(struct bthost *bthost, struct btconn *conn,
+ struct l2conn *l2conn, const void *data,
+ uint16_t len)
+{
+}
+
+static void rfcomm_disc_recv(struct bthost *bthost, struct btconn *conn,
+ struct l2conn *l2conn, const void *data,
+ uint16_t len)
+{
+}
+
+static void rfcomm_ua_recv(struct bthost *bthost, struct btconn *conn,
+ struct l2conn *l2conn, const void *data,
+ uint16_t len)
+{
+}
+
+static void rfcomm_dm_recv(struct bthost *bthost, struct btconn *conn,
+ struct l2conn *l2conn, const void *data,
+ uint16_t len)
+{
+}
+
+static void rfcomm_uih_recv(struct bthost *bthost, struct btconn *conn,
+ struct l2conn *l2conn, const void *data,
+ uint16_t len)
+{
+}
+
+static void process_rfcomm(struct bthost *bthost, struct btconn *conn,
+ struct l2conn *l2conn, const void *data,
+ uint16_t len)
+{
+ const struct rfcomm_hdr *hdr = data;
+
+ switch (RFCOMM_GET_TYPE(hdr->control)) {
+ case RFCOMM_SABM:
+ rfcomm_sabm_recv(bthost, conn, l2conn, data, len);
+ break;
+ case RFCOMM_DISC:
+ rfcomm_disc_recv(bthost, conn, l2conn, data, len);
+ break;
+ case RFCOMM_UA:
+ rfcomm_ua_recv(bthost, conn, l2conn, data, len);
+ break;
+ case RFCOMM_DM:
+ rfcomm_dm_recv(bthost, conn, l2conn, data, len);
+ break;
+ case RFCOMM_UIH:
+ rfcomm_uih_recv(bthost, conn, l2conn, data, len);
+ break;
+ default:
+ printf("Unknown frame type\n");
+ break;
+ }
+}
+
static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
{
const struct bt_hci_acl_hdr *acl_hdr = data;
@@ -1180,6 +1239,7 @@ static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
uint16_t handle, cid, acl_len, l2_len;
struct cid_hook *hook;
struct btconn *conn;
+ struct l2conn *l2conn;
const void *l2_data;
if (len < sizeof(*acl_hdr) + sizeof(*l2_hdr))
@@ -1218,7 +1278,12 @@ static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
l2cap_le_sig(bthost, conn, l2_data, l2_len);
break;
default:
- printf("Packet for unknown CID 0x%04x (%u)\n", cid, cid);
+ l2conn = btconn_find_l2cap_conn_by_scid(conn, cid);
+ if (l2conn->psm == 0x0003)
+ process_rfcomm(bthost, conn, l2conn, l2_data, l2_len);
+ else
+ printf("Packet for unknown CID 0x%04x (%u)\n", cid,
+ cid);
break;
}
}
--
1.8.3.1
^ permalink raw reply related
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