public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH]Generic Netlink Interface
@ 2009-02-20 14:02 alok barsode
  2009-02-20 20:07 ` Marcel Holtmann
  0 siblings, 1 reply; 4+ messages in thread
From: alok barsode @ 2009-02-20 14:02 UTC (permalink / raw)
  To: linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 577 bytes --]

Marcel,

As per our last discussion, i am attaching a patch for the generic
netlink interface.
I am also attaching a test program (can be compiled with -lnl ) to
test the interface.

I am using "flags" to bring up the device and returning "changed",
which indicate the changed bits in the flags.
right now the module only supports 'up', 'iscan' and 'pscan'.
so i can issue a NEWHOST command with HCI_UP | HCI_PSCAN | HCI_ISCAN.
I am not sure if this is the right approach.
OR Do you want individual commands for operations ?

Let me know what you think of this.

Cheers,
Alok.

[-- Attachment #2: 0001-Adding-netlink-support-to-bluetooth.patch --]
[-- Type: text/x-diff, Size: 8028 bytes --]

From 1e5cb0bbe2c0bbffe4e4d53e863bb878395a0367 Mon Sep 17 00:00:00 2001
From: Alok Barsode <alokbarsode@gmail.com>
Date: Wed, 18 Feb 2009 19:54:20 +0530
Subject: [PATCH] Adding netlink support to bluetooth.
 Adding files netlink.c and netlink.h to net/bluetooth for netlink support.
 Adding support for NEWHOST.
 Redefining hci_req_lock to use down_trylock

Signed-off-by: Alok Barsode <alokbarsode@gmail.com>
---
 include/net/bluetooth/hci_core.h |    4 +-
 net/bluetooth/Makefile           |    2 +-
 net/bluetooth/hci_core.c         |   31 ++++++
 net/bluetooth/netlink.c          |  212 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/netlink.h          |   31 ++++++
 5 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/bluetooth/netlink.c
 create mode 100644 net/bluetooth/netlink.h

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 01f9316..094c5dd 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -695,9 +695,11 @@ struct hci_sec_filter {
 #define HCI_REQ_PEND	  1
 #define HCI_REQ_CANCELED  2
 
-#define hci_req_lock(d)		down(&d->req_lock)
+#define hci_req_lock(d)		down_trylock(&d->req_lock)
 #define hci_req_unlock(d)	up(&d->req_lock)
 
 void hci_req_complete(struct hci_dev *hdev, int result);
 
+/* FIXME: This is temporarily added to export __hci_request and hci_init_req */
+int hci_handle_request(struct hci_dev *hdev, int event, unsigned long opt);
 #endif /* __HCI_CORE_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index d1e433f..f014d48 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_BNEP)	+= bnep/
 obj-$(CONFIG_BT_CMTP)	+= cmtp/
 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
+bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o netlink.o
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ba78cc1..5b8e890 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -291,6 +291,37 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
 	hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
 }
 
+int hci_handle_request(struct hci_dev *hdev, int event, unsigned long opt)
+{
+	int err = 0;
+
+	if (!hdev)
+		return -ENODEV;
+
+	switch (event) {
+	case HCI_DEV_UP:
+		err = __hci_request(hdev, hci_init_req, opt,
+				msecs_to_jiffies(HCI_INIT_TIMEOUT));
+		break;
+
+	case HCI_DEV_DOWN:
+		err = __hci_request(hdev, hci_reset_req, opt,
+				    msecs_to_jiffies(250));
+		break;
+
+	case HCISETSCAN:
+		err = hci_request(hdev, hci_scan_req, opt,
+					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
 /* Get HCI device by index.
  * Device is held on return. */
 struct hci_dev *hci_dev_get(int index)
diff --git a/net/bluetooth/netlink.c b/net/bluetooth/netlink.c
new file mode 100644
index 0000000..97be0b6
--- /dev/null
+++ b/net/bluetooth/netlink.c
@@ -0,0 +1,212 @@
+/*
+ * This is the netlink-based bluetooth interface.
+ *
+ * Copyright 2008 Alok Barsode <alok.barsode@azingo.com>
+ */
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <net/genetlink.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "netlink.h"
+
+#define BLUETOOTH_GENL_FAMILY_NAME           "bluetooth"
+
+/* family definition */
+static struct genl_family family = {
+	.id = GENL_ID_GENERATE,
+	.hdrsize = 0,
+	.name = BLUETOOTH_GENL_FAMILY_NAME,
+	.version = VERSION,
+	.maxattr = ATTR_MAX
+};
+
+static struct nla_policy policy[ATTR_MAX + 1] = {
+	[INDEX]	  = { .type = NLA_U16 },
+	[TYPE]	  = { .type = NLA_U16 },
+	[FLAGS]   = { .type = NLA_U32 },
+	[CHANGED] = { .type = NLA_U32 },
+};
+
+static int bluetooth_newhost(struct sk_buff *skb, struct genl_info *info)
+{
+	__u16 index;
+	void *hdr;
+	int ret=0;
+	unsigned long flags = 0, changed = 0;
+	struct hci_dev *hdev;
+	struct sk_buff *msg;
+
+	if (!info->attrs[INDEX])
+		return -EINVAL;
+
+	index = nla_get_u16(info->attrs[INDEX]);
+
+	if (!(hdev = hci_dev_get(index)))
+		return -ENODEV;
+
+	printk("%s %p", hdev->name, hdev);
+
+	if (hci_req_lock(hdev))
+		return -EBUSY;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg) {
+		ret = -ENOBUFS;
+		goto done;
+	}
+
+	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &family, 0, NEWHOST);
+	if (hdr == NULL){
+		nlmsg_free(msg);
+		ret =  -ENOBUFS;
+		goto done;
+	}
+
+	NLA_PUT_U16(msg, INDEX, index);
+
+	if (!info->attrs[FLAGS])
+		goto proceed;
+
+	flags = nla_get_u16(info->attrs[FLAGS]);
+
+	if (!test_bit(HCI_UP, &flags) && test_bit(HCI_UP, &hdev->flags))
+		goto proceed;
+
+	if (!test_bit(HCI_UP, &flags) && !test_bit(HCI_UP, &hdev->flags)){
+		ret = -EHOSTDOWN;
+		goto done;
+	}
+
+	if (test_bit(HCI_UP, &hdev->flags)) {
+		ret = -EALREADY;
+		goto done;
+	}
+
+	if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
+		set_bit(HCI_RAW, &hdev->flags);
+
+	if (hdev->open(hdev)) {
+		ret = -EIO;
+		goto done;
+	}
+
+	if (!test_bit(HCI_RAW, &hdev->flags)) {
+		atomic_set(&hdev->cmd_cnt, 1);
+		set_bit(HCI_INIT, &hdev->flags);
+
+		ret = hci_handle_request(hdev, HCI_DEV_UP, 0);
+		clear_bit(HCI_INIT, &hdev->flags);
+	}
+
+	if (!ret) {
+		hci_dev_hold(hdev);
+		set_bit(HCI_UP, &hdev->flags);
+		set_bit(HCI_UP, &changed);
+		goto proceed;
+	}
+
+	/* Init failed, cleanup */
+	tasklet_kill(&hdev->rx_task);
+	tasklet_kill(&hdev->tx_task);
+	tasklet_kill(&hdev->cmd_task);
+
+	skb_queue_purge(&hdev->cmd_q);
+	skb_queue_purge(&hdev->rx_q);
+
+	if (hdev->flush)
+		hdev->flush(hdev);
+
+	if (hdev->sent_cmd) {
+		kfree_skb(hdev->sent_cmd);
+		hdev->sent_cmd = NULL;
+	}
+
+	hdev->close(hdev);
+	hdev->flags = 0;
+	goto done;
+
+ proceed:
+	if (test_bit(HCI_PSCAN, &flags)) {
+		ret = hci_handle_request(hdev, HCISETSCAN, SCAN_PAGE);
+		if (!ret)
+			set_bit(HCI_PSCAN, &changed);
+	}
+
+	if (test_bit(HCI_ISCAN, &flags)) {
+		ret = hci_handle_request(hdev, HCISETSCAN, SCAN_INQUIRY);
+		if (!ret)
+			set_bit(HCI_ISCAN, &changed);
+	}
+
+	NLA_PUT_U32(msg, CHANGED, changed);
+
+	genlmsg_end(msg, hdr);
+	goto done;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	ret = -EMSGSIZE;
+ done:
+	hci_req_unlock(hdev);
+	hci_dev_put(hdev);
+
+	if (ret < 0)
+		return ret;
+
+	return genlmsg_unicast(msg, info->snd_pid);
+}
+
+static int bluetooth_delhost(struct sk_buff *skb, struct genl_info *info)
+{
+	return 0;
+}
+
+static struct genl_ops ops[] = {
+	{	.cmd = NEWHOST,
+		.policy = policy,
+		.doit = bluetooth_newhost,
+		.flags = GENL_ADMIN_PERM,
+		.dumpit = NULL,
+	},
+	{	.cmd = DELHOST,
+		.policy = policy,
+		.doit = bluetooth_delhost,
+		.flags = GENL_ADMIN_PERM,
+		.dumpit = NULL,
+	},
+};
+
+/* initialisation/exit functions */
+int __init bluetooth_netlink_init(void)
+{
+	int err, i;
+
+	err = genl_register_family(&family);
+	if (err)
+		return err;
+
+	for (i = 0; i < ARRAY_SIZE(ops); i++) {
+		err = genl_register_ops(&family, &ops[i]);
+		if (err)
+			goto err_out;
+	}
+
+	return 0;
+
+err_out:
+	genl_unregister_family(&family);
+	return err;
+}
+
+void bluetooth_netlink_cleanup(void)
+{
+	genl_unregister_family(&family);
+}
diff --git a/net/bluetooth/netlink.h b/net/bluetooth/netlink.h
new file mode 100644
index 0000000..ea99c79
--- /dev/null
+++ b/net/bluetooth/netlink.h
@@ -0,0 +1,31 @@
+/*
+ * This is the netlink-based bluetooth interface.
+ *
+ * Copyright 2008 Alok Barsode <alok.barsode@azingo.com>
+ */
+#ifndef __NETLINK_H
+#define __NETLINK_H
+
+#define VERSION 0x01
+
+enum bluetooth_attr {
+	ATTR_UNSPEC,
+	INDEX,
+	TYPE,
+	FLAGS,
+	CHANGED,
+	/* Add attributes here */
+	__ATTR_MAX,
+	ATTR_MAX  =  __ATTR_MAX - 1
+};
+
+enum bluetooth_cmds {
+	CMD_UNSPEC,
+	NEWHOST,
+	DELHOST,
+	/* Add command here */
+	__CMD_MAX,
+	CMD_MAX  = __CMD_MAX - 1
+};
+
+#endif /* __NETLINK_H */
-- 
1.5.6.3


[-- Attachment #3: test-up.c --]
[-- Type: text/x-csrc, Size: 2319 bytes --]

#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

#define VERSION 0x01

enum bluetooth_attr {
	ATTR_UNSPEC,
	INDEX,
	TYPE,
	FLAGS,
	CHANGED,
	/* Add attributes here */
	__ATTR_MAX,
	ATTR_MAX  =  __ATTR_MAX - 1
};

enum bluetooth_cmds {
	CMD_UNSPEC,
	NEWHOST,
	DELHOST,
	/* Add command here */
	__CMD_MAX,
	CMD_MAX  = __CMD_MAX - 1
};

static inline void set_bit(int nr, void *addr)
{
	*((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31));
}

static inline int test_bit(int nr, void *addr)
{
	return *((uint32_t *) addr + (nr >> 5)) & (1 << (nr & 31));
}

static struct nla_policy bluetooth_policy[ATTR_MAX + 1] = {
	[INDEX]	  = { .type = NLA_U16 },
	[TYPE]	  = { .type = NLA_U16 },
	[FLAGS]   = { .type = NLA_U32 },
	[CHANGED] = { .type = NLA_U32 },
};

static int parse_cb(struct nl_msg *msg, void *arg)
{
	int err,i=0;
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct nlattr *attrs[ATTR_MAX+1];

	struct genlmsghdr *ghdr = nlmsg_data(nlh);

	err = genlmsg_parse(nlh, 0, attrs, ATTR_MAX, NULL);
	if (err < 0)
		return -EINVAL;
	printf("\nhello\n");
	switch(ghdr->cmd) {
	case NEWHOST:
		  if(!attrs[INDEX]) {
			printf("\nNo index\n");
			return -EINVAL;
		}
		int index = nla_get_u16(attrs[INDEX]);
		uint32_t changed = nla_get_u16(attrs[CHANGED]);
		if (test_bit(HCI_UP, &changed))
		printf("Hci%d UP  changed %d", index, changed);
		break;
	default:
		printf("\nUnknown command");
		break;
	}

	return 0;
}

int main()
{
	struct nl_handle *sock;
	struct nl_msg *msg;
	int family;
	int err;
	uint32_t flags = 0;
	sock = nl_handle_alloc();

	genl_connect(sock);

	family = genl_ctrl_resolve(sock, "bluetooth");

	msg = nlmsg_alloc();

	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0,
			NLM_F_REQUEST, NEWHOST, VERSION);

	nla_put_u16(msg, INDEX, 0);

	set_bit(HCI_UP, &flags);
	set_bit(HCI_PSCAN, &flags);

	nla_put_u32(msg, FLAGS, flags);
	nl_send_auto_complete(sock, msg);

	nlmsg_free(msg);
	nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
	err = nl_recvmsgs_default(sock);

	printf("\nerr = %d\n", err);

	return 0;
}


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH]Generic Netlink Interface
  2009-02-20 14:02 [PATCH]Generic Netlink Interface alok barsode
@ 2009-02-20 20:07 ` Marcel Holtmann
  2009-02-23 13:40   ` alok barsode
  0 siblings, 1 reply; 4+ messages in thread
From: Marcel Holtmann @ 2009-02-20 20:07 UTC (permalink / raw)
  To: alok barsode; +Cc: linux-bluetooth

Hi Alok,

> As per our last discussion, i am attaching a patch for the generic
> netlink interface.
> I am also attaching a test program (can be compiled with -lnl ) to
> test the interface.
> 
> I am using "flags" to bring up the device and returning "changed",
> which indicate the changed bits in the flags.
> right now the module only supports 'up', 'iscan' and 'pscan'.
> so i can issue a NEWHOST command with HCI_UP | HCI_PSCAN | HCI_ISCAN.
> I am not sure if this is the right approach.
> OR Do you want individual commands for operations ?

the first thing that we have to change the try_lock() change. We can't
do that. It has way to many implications on the code. So why do you
really need the try_lock() in this case. And if, then don't change
current locking code. Just create a new define for the the try_lock()
case.

I am thinking about not exposing the ->flags directly and just creating
a new one for the netlink interface. For example for PSCAN and ISCAN I
like to have clear primitives that say connectable, discoverable etc.

We did a lot of changes in the D-Bus API for 4.x during the last month
and the best way would be if the netlink API reflects these changes in a
more closer way. So it might be better to just have primitives that map
1:1 the properties powered, connectable, discoverable etc.

We could actually just have PROPERTY primitive and then turn the
properties into parameters. Netlink should be fine with listing multiple
parameters in the same message.

What do you think?

Regards

Marcel



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH]Generic Netlink Interface
  2009-02-20 20:07 ` Marcel Holtmann
@ 2009-02-23 13:40   ` alok barsode
  2009-03-03 15:40     ` alok barsode
  0 siblings, 1 reply; 4+ messages in thread
From: alok barsode @ 2009-02-23 13:40 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth

Hi Marcel,

On Sat, Feb 21, 2009 at 1:37 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Alok,
>
>> As per our last discussion, i am attaching a patch for the generic
>> netlink interface.
>> I am also attaching a test program (can be compiled with -lnl ) to
>> test the interface.
>>
>> I am using "flags" to bring up the device and returning "changed",
>> which indicate the changed bits in the flags.
>> right now the module only supports 'up', 'iscan' and 'pscan'.
>> so i can issue a NEWHOST command with HCI_UP | HCI_PSCAN | HCI_ISCAN.
>> I am not sure if this is the right approach.
>> OR Do you want individual commands for operations ?
>
> the first thing that we have to change the try_lock() change. We can't
> do that. It has way to many implications on the code. So why do you
> really need the try_lock() in this case. And if, then don't change
> current locking code. Just create a new define for the the try_lock()
> case.

I was using try_lock to safeguard the code from being re-entrant.
will create a new define in netlink.c.

>
> I am thinking about not exposing the ->flags directly and just creating
> a new one for the netlink interface. For example for PSCAN and ISCAN I
> like to have clear primitives that say connectable, discoverable etc.
>
> We did a lot of changes in the D-Bus API for 4.x during the last month
> and the best way would be if the netlink API reflects these changes in a
> more closer way. So it might be better to just have primitives that map
> 1:1 the properties powered, connectable, discoverable etc.

sounds good.

>
> We could actually just have PROPERTY primitive and then turn the
> properties into parameters. Netlink should be fine with listing multiple
> parameters in the same message.

PROPERTY can be a nested primitive which holds the parameter <name:
value> pair.
so NEWHOST takes a list of parameter name:value pairs.

did I understand you correctly?

Cheers,
Alok.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH]Generic Netlink Interface
  2009-02-23 13:40   ` alok barsode
@ 2009-03-03 15:40     ` alok barsode
  0 siblings, 0 replies; 4+ messages in thread
From: alok barsode @ 2009-03-03 15:40 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 2814 bytes --]

Hi Marcel,

I am attaching a modified patch for the netlink interface. The changes are:

1. Adding a HOST command. It take INDEX and EVENT as parameter. EVENT
can be UP or DOWN.
this is similar to hciconfig hci0 up/down.

2. Registering a bluetooth-events multicast group. Userspace can
subscribe to this group and receive the following events
a. HOST events (device is up or down through 'changed' flag)
b. NEWHOST (a new device is registered)
c. DELHOST (an existing device is unregistered)
All above events include the INDEX.

I am attaching a simple program (listen.c) which can be used to test
and above events.
It subscribes to bluetooth-events grp and listens to the events.


Do let me know what you think of it.

Cheers,
Alok.

On Mon, Feb 23, 2009 at 7:10 PM, alok barsode <alokbarsode@gmail.com> wrote:
> Hi Marcel,
>
> On Sat, Feb 21, 2009 at 1:37 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
>> Hi Alok,
>>
>>> As per our last discussion, i am attaching a patch for the generic
>>> netlink interface.
>>> I am also attaching a test program (can be compiled with -lnl ) to
>>> test the interface.
>>>
>>> I am using "flags" to bring up the device and returning "changed",
>>> which indicate the changed bits in the flags.
>>> right now the module only supports 'up', 'iscan' and 'pscan'.
>>> so i can issue a NEWHOST command with HCI_UP | HCI_PSCAN | HCI_ISCAN.
>>> I am not sure if this is the right approach.
>>> OR Do you want individual commands for operations ?
>>
>> the first thing that we have to change the try_lock() change. We can't
>> do that. It has way to many implications on the code. So why do you
>> really need the try_lock() in this case. And if, then don't change
>> current locking code. Just create a new define for the the try_lock()
>> case.
>
> I was using try_lock to safeguard the code from being re-entrant.
> will create a new define in netlink.c.
>
>>
>> I am thinking about not exposing the ->flags directly and just creating
>> a new one for the netlink interface. For example for PSCAN and ISCAN I
>> like to have clear primitives that say connectable, discoverable etc.
>>
>> We did a lot of changes in the D-Bus API for 4.x during the last month
>> and the best way would be if the netlink API reflects these changes in a
>> more closer way. So it might be better to just have primitives that map
>> 1:1 the properties powered, connectable, discoverable etc.
>
> sounds good.
>
>>
>> We could actually just have PROPERTY primitive and then turn the
>> properties into parameters. Netlink should be fine with listing multiple
>> parameters in the same message.
>
> PROPERTY can be a nested primitive which holds the parameter <name:
> value> pair.
> so NEWHOST takes a list of parameter name:value pairs.
>
> did I understand you correctly?
>
> Cheers,
> Alok.
>

[-- Attachment #2: 0001-Initial-Netlink-support.patch --]
[-- Type: text/x-diff, Size: 11608 bytes --]

From 7e2aa37a35723ab72e53e78d58c348e3caf1ae78 Mon Sep 17 00:00:00 2001
From: Alok Barsode <alokbarsode@gmail.com>
Date: Tue, 3 Mar 2009 20:57:01 +0530
Subject: [PATCH] Initial Netlink support.

Signed-off-by: Alok Barsode <alokbarsode@gmail.com>
---
 include/net/bluetooth/bluetooth.h |    3 +
 include/net/bluetooth/hci_core.h  |    2 +
 net/bluetooth/Makefile            |    2 +-
 net/bluetooth/af_bluetooth.c      |    6 +
 net/bluetooth/hci_core.c          |   37 +++++
 net/bluetooth/netlink.c           |  307 +++++++++++++++++++++++++++++++++++++
 net/bluetooth/netlink.h           |   40 +++++
 7 files changed, 396 insertions(+), 1 deletions(-)
 create mode 100644 net/bluetooth/netlink.c
 create mode 100644 net/bluetooth/netlink.h

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 3ad5390..e3d792a 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -190,4 +190,7 @@ extern void bt_sysfs_cleanup(void);
 
 extern struct class *bt_class;
 
+extern int bluetooth_netlink_init(void);
+extern void bluetooth_netlink_cleanup(void);
+
 #endif /* __BLUETOOTH_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 01f9316..cc5d33b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -700,4 +700,6 @@ struct hci_sec_filter {
 
 void hci_req_complete(struct hci_dev *hdev, int result);
 
+/* FIXME: This is temporarily added to export __hci_request and hci_init_req */
+int hci_handle_request(struct hci_dev *hdev, int event, unsigned long opt);
 #endif /* __HCI_CORE_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index d1e433f..f014d48 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_BNEP)	+= bnep/
 obj-$(CONFIG_BT_CMTP)	+= cmtp/
 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
+bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o netlink.o
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 02b9baa..987dbb9 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -422,6 +422,10 @@ static int __init bt_init(void)
 	if (err < 0)
 		return err;
 
+	err = bluetooth_netlink_init();
+	if (err < 0)
+		return err;
+
 	err = sock_register(&bt_sock_family_ops);
 	if (err < 0) {
 		bt_sysfs_cleanup();
@@ -442,6 +446,8 @@ static void __exit bt_exit(void)
 	sock_unregister(PF_BLUETOOTH);
 
 	bt_sysfs_cleanup();
+
+	bluetooth_netlink_cleanup();
 }
 
 subsys_initcall(bt_init);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index cd06151..aec38a0 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -48,6 +48,8 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
+#include "netlink.h"
+
 static void hci_cmd_task(unsigned long arg);
 static void hci_rx_task(unsigned long arg);
 static void hci_tx_task(unsigned long arg);
@@ -291,6 +293,37 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
 	hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
 }
 
+int hci_handle_request(struct hci_dev *hdev, int event, unsigned long opt)
+{
+	int err = 0;
+
+	if (!hdev)
+		return -ENODEV;
+
+	switch (event) {
+	case HCI_DEV_UP:
+		err = __hci_request(hdev, hci_init_req, opt,
+				msecs_to_jiffies(HCI_INIT_TIMEOUT));
+		break;
+
+	case HCI_DEV_DOWN:
+		err = __hci_request(hdev, hci_reset_req, opt,
+				    msecs_to_jiffies(250));
+		break;
+
+	case HCISETSCAN:
+		err = hci_request(hdev, hci_scan_req, opt,
+					msecs_to_jiffies(HCI_INIT_TIMEOUT));
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
 /* Get HCI device by index.
  * Device is held on return. */
 struct hci_dev *hci_dev_get(int index)
@@ -902,6 +935,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	hci_notify(hdev, HCI_DEV_REG);
 
+	bluetooth_notify(hdev, HCI_DEV_REG);
+
 	return id;
 }
 EXPORT_SYMBOL(hci_register_dev);
@@ -924,6 +959,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
 	hci_notify(hdev, HCI_DEV_UNREG);
 
+	bluetooth_notify(hdev, HCI_DEV_UNREG);
+
 	hci_unregister_sysfs(hdev);
 
 	__hci_dev_put(hdev);
diff --git a/net/bluetooth/netlink.c b/net/bluetooth/netlink.c
new file mode 100644
index 0000000..c6ecafd
--- /dev/null
+++ b/net/bluetooth/netlink.c
@@ -0,0 +1,307 @@
+/*
+ * This is the netlink-based bluetooth interface.
+ *
+ * Copyright 2008 Alok Barsode <alok.barsode@azingo.com>
+ */
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <net/genetlink.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "netlink.h"
+
+#define BLUETOOTH_FAMILY_NAME	"bluetooth"
+#define BLUETOOTH_MCAST_GROUP	"bluetooth-events"
+
+/* family definition */
+static struct genl_family family = {
+	.id = GENL_ID_GENERATE,
+	.hdrsize = 0,
+	.name = BLUETOOTH_FAMILY_NAME,
+	.version = VERSION,
+	.maxattr = ATTR_MAX
+};
+
+static struct genl_multicast_group mcgrp = {
+	.name = BLUETOOTH_MCAST_GROUP,
+};
+
+static struct nla_policy policy[ATTR_MAX + 1] = {
+	[INDEX]		= { .type = NLA_U16 },
+	[CHANGED]	= { .type = NLA_U32 },
+	[EVENT]		= { .type = NLA_U16 },
+	[GRPID]		= { .type = NLA_U32 },
+};
+
+static void inquiry_cache_flush(struct hci_dev *hdev)
+{
+	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct inquiry_entry *next  = cache->list, *e;
+
+	BT_DBG("cache %p", cache);
+
+	cache->list = NULL;
+	while ((e = next)) {
+		next = e->next;
+		kfree(e);
+	}
+}
+
+static int bluetooth_event(int cmd, struct hci_dev *hdev, unsigned long changed)
+{
+	void *hdr;
+	struct sk_buff *msg=NULL;
+	int err = -ENOBUFS;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		goto err_out;
+
+	hdr = genlmsg_put(msg, 0, 0, &family, 0, cmd);
+	if (hdr == NULL){
+		nlmsg_free(msg);
+		goto err_out;
+	}
+	nla_put_u16(msg, INDEX, hdev->id);
+	nla_put_u32(msg, CHANGED, changed);
+
+	genlmsg_end(msg, hdr);
+
+	err = genlmsg_multicast(msg, 0, mcgrp.id, GFP_ATOMIC);
+ err_out:
+	return err;
+}
+
+int bluetooth_notify(struct hci_dev *hdev, int event)
+{
+	int err = 0;
+
+	switch (event) {
+	case HCI_DEV_REG:
+		err = bluetooth_event(NEWHOST, hdev, ~0U);
+		break;
+	case HCI_DEV_UNREG:
+		err = bluetooth_event(DELHOST, hdev, ~0U);
+		break;
+	case HCI_DEV_UP:
+	case HCI_DEV_DOWN:
+		err = bluetooth_event(HOST, hdev, HCI_UP|HCI_RUNNING);
+		break;
+	default:
+		err = -EINVAL;
+		printk("\nUnknown event\n");
+		break;
+	}
+	return err;
+}
+
+static int bluetooth_host(struct sk_buff *skb, struct genl_info *info)
+{
+	__u16 index;
+	int ret=0, event;
+	struct hci_dev *hdev;
+
+	if (!info->attrs[INDEX])
+		return -EINVAL;
+
+	index = nla_get_u16(info->attrs[INDEX]);
+
+	/* Nothing to do, return */
+	if (!info->attrs[EVENT])
+		return 0;
+
+	/* event = UP/DOWN */
+	event = nla_get_u16(info->attrs[EVENT]);
+
+	if (!(hdev = hci_dev_get(index)))
+		return -ENODEV;
+
+	printk("%s %p", hdev->name, hdev);
+
+	if (lock(hdev)){
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* Device is already up */
+	if (event & test_bit(HCI_UP, &hdev->flags)){
+		ret = -EALREADY;
+		goto unlock;
+	}
+	
+	/* Device is already down */
+	if (!event & !test_bit(HCI_UP, &hdev->flags)){
+		ret = -EALREADY;
+		goto unlock;
+	}
+
+	if (event == DOWN)
+		goto down;
+
+	if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
+		set_bit(HCI_RAW, &hdev->flags);
+
+	if (hdev->open(hdev)) {
+		ret = -EIO;
+		goto unlock;
+	}
+
+	if (!test_bit(HCI_RAW, &hdev->flags)) {
+		atomic_set(&hdev->cmd_cnt, 1);
+
+		set_bit(HCI_INIT, &hdev->flags);
+		ret = hci_handle_request(hdev, HCI_DEV_UP, 0);
+		clear_bit(HCI_INIT, &hdev->flags);
+	}
+
+	/* Host is UP */
+	if (!ret) {
+		hci_dev_hold(hdev);
+
+		set_bit(HCI_UP, &hdev->flags);
+		ret = bluetooth_notify(hdev, HCI_DEV_UP);
+		goto unlock;
+	}
+ down:
+	if (hdev->req_status == HCI_REQ_PEND) {
+		hdev->req_result = ENODEV;
+		hdev->req_status = HCI_REQ_CANCELED;
+		wake_up_interruptible(&hdev->req_wait_q);
+	}  
+	  
+	if (!test_and_clear_bit(HCI_UP, &hdev->flags)){
+		ret = -EBUSY;
+		goto unlock;
+	}
+	
+	/* Kill RX and TX tasks */
+	tasklet_kill(&hdev->rx_task);
+	tasklet_kill(&hdev->tx_task);
+
+	hci_dev_lock_bh(hdev);
+	inquiry_cache_flush(hdev);
+	hci_conn_hash_flush(hdev);
+	hci_dev_unlock_bh(hdev);
+
+	if (hdev->flush)
+		hdev->flush(hdev);
+
+	/* Reset device */
+	skb_queue_purge(&hdev->cmd_q);
+	atomic_set(&hdev->cmd_cnt, 1);
+	if (!test_bit(HCI_RAW, &hdev->flags)) {
+		set_bit(HCI_INIT, &hdev->flags);
+		ret = hci_handle_request(hdev, HCI_DEV_DOWN, 0);
+		clear_bit(HCI_INIT, &hdev->flags);
+	}
+
+	/* Kill cmd task */
+	tasklet_kill(&hdev->cmd_task);
+
+	/* Drop queues */
+	skb_queue_purge(&hdev->rx_q);
+	skb_queue_purge(&hdev->cmd_q);
+	skb_queue_purge(&hdev->raw_q);
+
+	/* Drop last sent command */
+	if (hdev->sent_cmd) {
+		kfree_skb(hdev->sent_cmd);
+		hdev->sent_cmd = NULL;
+	}
+
+	/* After this point our queues are empty
+	 * and no tasks are scheduled. */
+	hdev->close(hdev);
+
+	/* Clear flags */
+	hdev->flags = 0;
+	ret = bluetooth_notify(hdev, HCI_DEV_DOWN);
+	hci_dev_put(hdev);
+ unlock:
+	unlock(hdev);
+ done:
+	hci_dev_put(hdev);
+	return ret;
+}
+
+/* Unfortunately Generic netlink doesn't provide a mechanism to get the groupID. */
+int get_grp_id(struct sk_buff *skb_2, struct genl_info *info)
+{
+	void *hdr;
+	struct sk_buff *msg;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOBUFS;
+
+	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &family, 0, GETGRPID);
+
+	if (hdr == NULL){
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
+
+	NLA_PUT_U32(msg, GRPID, mcgrp.id);
+
+	genlmsg_end(msg, hdr);
+
+	return genlmsg_unicast(msg, info->snd_pid);
+
+nla_put_failure:
+        genlmsg_cancel(msg, hdr);
+        return -EMSGSIZE;
+}
+
+static struct genl_ops ops[] = { 
+	{
+		.cmd = HOST,
+		.policy = policy,
+		.doit = bluetooth_host,
+		.flags = GENL_ADMIN_PERM,
+		.dumpit = NULL,
+	},
+	{
+		.cmd = GETGRPID,
+		.flags = 0,
+		.policy = policy,
+		.doit = get_grp_id,
+		.dumpit = NULL,
+	},
+};
+
+/* initialisation/exit functions */
+int __init bluetooth_netlink_init(void)
+{
+	int err, i; 
+
+	err = genl_register_family(&family);
+	if (err)
+		return err;
+
+	err = genl_register_mc_group(&family, &mcgrp);
+	if (err)
+		goto err_out;
+
+	for (i = 0; i < ARRAY_SIZE(ops); i++) {
+	err = genl_register_ops(&family, &ops[i]);
+		if (err)
+			goto err_out;
+	}
+	return 0;
+
+err_out:
+	genl_unregister_family(&family);
+	return err;
+}
+
+void bluetooth_netlink_cleanup(void)
+{
+	genl_unregister_family(&family);
+}
diff --git a/net/bluetooth/netlink.h b/net/bluetooth/netlink.h
new file mode 100644
index 0000000..cffc4cf
--- /dev/null
+++ b/net/bluetooth/netlink.h
@@ -0,0 +1,40 @@
+/*
+ * This is the netlink-based bluetooth interface.
+ *
+ * Copyright 2008 Alok Barsode <alok.barsode@azingo.com>
+ */
+#ifndef __NETLINK_H
+#define __NETLINK_H
+
+#define VERSION 0x01
+#define lock(d)		down_trylock(&d->req_lock)
+#define unlock(d)	up(&d->req_lock)
+
+#define DOWN	0
+#define UP	1
+
+enum {
+	ATTR_UNSPEC,
+	INDEX,
+	CHANGED,
+	EVENT,
+	GRPID,
+	/* Add attributes here */
+	__ATTR_MAX,
+	ATTR_MAX  =  __ATTR_MAX - 1
+};
+
+enum {
+	CMD_UNSPEC,
+	NEWHOST,
+	DELHOST,
+	HOST,
+	GETGRPID,
+	/* Add command here */
+	__CMD_MAX,
+	CMD_MAX  = __CMD_MAX - 1
+};
+
+int bluetooth_notify(struct hci_dev *hdev, int event);
+
+#endif /* __NETLINK_H */
-- 
1.5.6.3


[-- Attachment #3: listen.c --]
[-- Type: text/x-csrc, Size: 2985 bytes --]

#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define GENL_FAMILY_NAME		"bluetooth"
#define GENL_VERSION			0x01

static int family;

#define DOWN	0
#define UP	1

enum {
	ATTR_UNSPEC,
	INDEX,
	CHANGED,
	EVENT,
	GRPID,
	/* Add attributes here */
	__ATTR_MAX,
	ATTR_MAX  =  __ATTR_MAX - 1
};

static struct nla_policy policy[ATTR_MAX + 1] = {
	[INDEX]		= { .type = NLA_U16 },
	[CHANGED]	= { .type = NLA_U32 },
	[EVENT]		= { .type = NLA_U16 },
	[GRPID]		= { .type = NLA_U32 },
};

enum {
	CMD_UNSPEC,
	NEWHOST,
	DELHOST,
	HOST,
	GETGRPID,
	/* Add command here */
	__CMD_MAX,
	CMD_MAX  = __CMD_MAX - 1
};


static int parse_cb(struct nl_msg *msg, void *arg)
{
	int err, ret;
	int *id = arg;
	int index, changed;
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct nlattr *attrs[ATTR_MAX+1];

	struct genlmsghdr *ghdr = nlmsg_data(nlh);

	err = genlmsg_parse(nlh, 0, attrs, ATTR_MAX, NULL);
	if (err < 0)
		return -EINVAL;

	switch (ghdr->cmd) {
	case HOST:
		index = nla_get_u16(attrs[INDEX]);
		changed = nla_get_u32(attrs[CHANGED]);
		printf("\nHCI%d : changed0x%x\n", index, changed);
		ret = 0;
		break;
	case NEWHOST:
		index = nla_get_u16(attrs[INDEX]);
		changed = nla_get_u32(attrs[CHANGED]);
		printf("\nNew Device HCI%d : changed0x%x\n", index, changed);
		ret = 0;
		break;
	case DELHOST:
		index = nla_get_u16(attrs[INDEX]);
		changed = nla_get_u32(attrs[CHANGED]);
		printf("\nRemoved Device HCI%d : changed0x%x\n", index, changed);
		ret = 0;
		break;
	case GETGRPID:
		if(!attrs[GRPID]) {
			printf("\nNo Group ID\n");
			ret = -EINVAL;
		} else
			*id =  nla_get_u32(attrs[GRPID]);
			ret = 0;
		break;

	default:
		printf("\nUnknown command");
		ret = -EINVAL;
		break;
	}

	return ret;
}

static int ack_handler(struct nl_msg *msg, void *arg)
{
	int *ret = arg;
	*ret = 0;
	return NL_STOP;
}

int get_group_id(struct nl_handle *sock)
{
	int ret = 1, grpid;
	struct nl_msg *msg;
	struct nl_cb *cb;
	
	msg = nlmsg_alloc();
	cb = nl_cb_alloc(NL_CB_DEFAULT);
	
	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0,
			NLM_F_REQUEST, GETGRPID, GENL_VERSION);

	nl_send_auto_complete(sock, msg);

	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, &grpid);
	
	while (ret > 0)
		nl_recvmsgs(sock, cb);

	nl_cb_put(cb);
	nlmsg_free(msg);

	return grpid;
}

int main()
{
	struct nl_handle *sock;
	struct nl_msg *msg;
	int err;
	int grp_id;

	sock = nl_handle_alloc();

	genl_connect(sock);

	family = genl_ctrl_resolve(sock, GENL_FAMILY_NAME);
	if (family < 0)
		return -1;

	grp_id = get_group_id(sock);
	if (grp_id < 0)
		return -1;

	err = nl_socket_add_membership(sock, grp_id);
	if (err < 0)
		return -1;

	nl_socket_modify_cb(sock, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, parse_cb, NULL);
	while(1)
	err = nl_recvmsgs_default(sock);

	return 0;
}


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-03-03 15:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-02-20 14:02 [PATCH]Generic Netlink Interface alok barsode
2009-02-20 20:07 ` Marcel Holtmann
2009-02-23 13:40   ` alok barsode
2009-03-03 15:40     ` alok barsode

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox