[PATCH]Generic Netlink Interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.
From 1e5cb0bbe2c0bbffe4e4d53e863bb878395a0367 Mon Sep 17 00:00:00 2001
From: Alok Barsode <alokbarsode@xxxxxxxxx>
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@xxxxxxxxx>
---
 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@xxxxxxxxxx>
+ */
+
+#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@xxxxxxxxxx>
+ */
+#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

#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;
}


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux