From: Samuel Ortiz <samuel-jcdQHdrhKHMdnm+yROfE0A@public.gmane.org>
To: "David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
netdev-BkyiQQGWkgE@public.gmane.org,
irda-users-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: [PATCH 1/4] [net-2.6.22] IrDA: IrLAP raw mode
Date: Sat, 17 Mar 2007 03:57:29 +0200 [thread overview]
Message-ID: <20070317015729.GA3429@sortiz.org> (raw)
This patch allows us to bypass the IrDA stack down to the IrLAP level.
Sending and receiving frames is done through a character device.
This is useful for e.g. doing real IrDA sniffing, testing external IrDA
stacks and for Lirc (once I will add the framing disabling switch).
Signed-off-by: Samuel Ortiz <samuel-jcdQHdrhKHMdnm+yROfE0A@public.gmane.org>
---
include/net/irda/irlap.h | 5 +
include/net/irda/irlap_raw.h | 57 +++++++
net/irda/Kconfig | 10 ++
net/irda/Makefile | 1 +
net/irda/irlap.c | 5 +
net/irda/irlap_event.c | 3 +
net/irda/irlap_frame.c | 4 +
net/irda/irlap_raw.c | 358 ++++++++++++++++++++++++++++++++++++++++++
net/irda/irsysctl.c | 16 ++-
9 files changed, 458 insertions(+), 1 deletions(-)
create mode 100644 include/net/irda/irlap_raw.h
create mode 100644 net/irda/irlap_raw.c
diff --git a/include/net/irda/irlap.h b/include/net/irda/irlap.h
index e77eb88..1b24cfc 100644
--- a/include/net/irda/irlap.h
+++ b/include/net/irda/irlap.h
@@ -36,6 +36,7 @@
#include <net/irda/qos.h> /* struct qos_info */
#include <net/irda/discovery.h> /* discovery_t */
#include <net/irda/irlap_event.h> /* IRLAP_STATE, ... */
+#include <net/irda/irlap_raw.h> /* IRLAP raw definitions */
#include <net/irda/irmod.h> /* struct notify_t */
#define CONFIG_IRDA_DYNAMIC_WINDOW 1
@@ -208,6 +209,10 @@ struct irlap_cb {
int xbofs_delay; /* Nr of XBOF's used to MTT */
int bofs_count; /* Negotiated extra BOFs */
int next_bofs; /* Negotiated extra BOFs after next frame */
+#ifdef CONFIG_IRDA_RAW
+ int raw_mode;
+ struct irlap_raw * irlap_raw;
+#endif
};
/*
diff --git a/include/net/irda/irlap_raw.h b/include/net/irda/irlap_raw.h
new file mode 100644
index 0000000..ce90563
--- /dev/null
+++ b/include/net/irda/irlap_raw.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 Samuel Ortiz (samuel-jcdQHdrhKHMdnm+yROfE0A@public.gmane.org)
+ *
+ * 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, version 2.
+ *
+ */
+
+#ifndef _IRLAP_RAW_H
+#define _IRLAP_RAW_H
+
+struct irlap_cb;
+
+#ifdef CONFIG_IRDA_RAW
+
+extern int irlap_raw_recv_frame(struct sk_buff *skb, struct net_device *dev);
+extern int irlap_raw_register_device(struct net_device * dev);
+extern int irlap_raw_unregister_device(struct net_device * dev);
+extern int irlap_raw_mode(struct irlap_cb *self);
+
+#else
+
+static inline int irlap_raw_recv_frame(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ if (skb == NULL)
+ return -EINVAL;
+
+ if (dev->atalk_ptr == NULL)
+ return -ENODEV;
+
+ return 0;
+}
+
+static inline int irlap_raw_register_device(struct net_device * dev)
+{
+ if (dev == NULL)
+ return -ENODEV;
+ return 0;
+}
+
+static inline int irlap_raw_unregister_device(struct net_device * dev)
+{
+ if (dev == NULL)
+ return -ENODEV;
+ return 0;
+}
+
+static inline int irlap_raw_mode(struct irlap_cb *self)
+{
+ return 0;
+}
+
+#endif
+
+#endif
diff --git a/net/irda/Kconfig b/net/irda/Kconfig
index 9efb17b..310a036 100644
--- a/net/irda/Kconfig
+++ b/net/irda/Kconfig
@@ -92,5 +92,15 @@ config IRDA_DEBUG
If unsure, say Y (since it makes it easier to find the bugs).
+config IRDA_RAW
+ bool "IrLAP raw"
+ depends on IRDA
+ help
+ Say Y if you want to bypass the IrDA stack, down to the IrLAP level.
+ This option allows you to send and receive IrLAP frames from
+ userspace, by writing and reading to a character device
+ (/dev/irdaX_raw). Note that the IrDA stack will be mostly disabled.
+ If unsure, say N.
+
source "drivers/net/irda/Kconfig"
diff --git a/net/irda/Makefile b/net/irda/Makefile
index d1366c2..11d5ffb 100644
--- a/net/irda/Makefile
+++ b/net/irda/Makefile
@@ -13,3 +13,4 @@ irda-y := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \
discovery.o parameters.o irmod.o
irda-$(CONFIG_PROC_FS) += irproc.o
irda-$(CONFIG_SYSCTL) += irsysctl.o
+irda-$(CONFIG_IRDA_RAW) += irlap_raw.o
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index d93ebd1..656c949 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -173,6 +173,8 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
irlmp_register_link(self, self->saddr, &self->notify);
+ irlap_raw_register_device(dev);
+
return self;
}
EXPORT_SYMBOL(irlap_open);
@@ -234,6 +236,9 @@ void irlap_close(struct irlap_cb *self)
IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __FUNCTION__);
return;
}
+
+ irlap_raw_unregister_device(self->netdev);
+
__irlap_close(lap);
}
EXPORT_SYMBOL(irlap_close);
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 7b6433f..3a11c3e 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -241,6 +241,9 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
if (!self || self->magic != LAP_MAGIC)
return;
+ if (irlap_raw_mode(self))
+ return;
+
IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __FUNCTION__,
irlap_event[event], irlap_state[self->state]);
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 803ac41..5a3a868 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -1325,6 +1325,10 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
return -1;
}
+ if (irlap_raw_mode(self)) {
+ return irlap_raw_recv_frame(skb, dev);
+ }
+
/* We are no longer an "old" protocol, so we need to handle
* share and non linear skbs. This should never happen, so
* we don't need to be clever about it. Jean II */
diff --git a/net/irda/irlap_raw.c b/net/irda/irlap_raw.c
new file mode 100644
index 0000000..705424e
--- /dev/null
+++ b/net/irda/irlap_raw.c
@@ -0,0 +1,358 @@
+/*
+ * net/irda/irlap_raw.c Raw IrLAP character device.
+ * Copyright (C) 2007 Samuel Ortiz (samuel-jcdQHdrhKHMdnm+yROfE0A@public.gmane.org)
+ *
+ * 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, version 2.
+ *
+ * From /dev/irdaN_raw, you can read and write raw IrLAP frames.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/irlap.h>
+#include <net/irda/irlap_raw.h>
+
+/* We keep the last 10 IrLAP frames */
+unsigned int sysctl_raw_ring_length = 10;
+
+struct irlap_raw {
+ struct list_head list;
+ char name[IFNAMSIZ + 8];
+ struct miscdevice misc_device;
+ struct irlap_cb * irlap;
+ struct sk_buff_head skb_ring;
+ wait_queue_head_t rx_wait;
+ unsigned int refcount;
+ struct mutex rx_mutex;
+ struct mutex tx_mutex;
+ struct work_struct skb_ring_work;
+};
+
+static LIST_HEAD(irlap_raw_list);
+static DEFINE_MUTEX(irlap_raw_mutex);
+
+static void irlap_raw_skb_ring_gc(struct work_struct *work)
+{
+ struct irlap_raw * raw =
+ container_of(work, struct irlap_raw, skb_ring_work);
+
+ IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+
+ if (mutex_lock_interruptible(&raw->rx_mutex))
+ return;
+
+ while(skb_queue_len(&raw->skb_ring) > sysctl_raw_ring_length) {
+ struct sk_buff * old_skb;
+
+ IRDA_DEBUG(3, "%s(): We still have %d entries\n",
+ __FUNCTION__, skb_queue_len(&raw->skb_ring));
+
+ old_skb = skb_dequeue_tail(&raw->skb_ring);
+ dev_kfree_skb(old_skb);
+ }
+
+ mutex_unlock(&raw->rx_mutex);
+}
+
+int irlap_raw_recv_frame(struct sk_buff *skb, struct net_device *dev)
+{
+ struct irlap_cb * irlap;
+ struct irlap_raw * raw;
+
+ IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+
+ irlap = dev->atalk_ptr;
+ if (irlap == NULL)
+ return -ENODEV;
+
+ if (skb == NULL)
+ return -EINVAL;
+
+ raw = irlap->irlap_raw;
+ if (raw == NULL)
+ return -ENODEV;
+
+ skb_queue_head(&raw->skb_ring, skb);
+
+ wake_up_interruptible(&raw->rx_wait);
+
+ /*
+ * We call the "garbage collector" in process
+ * context, so that we can lock the skb removal
+ * against read().
+ */
+ if (skb_queue_len(&raw->skb_ring) > sysctl_raw_ring_length) {
+ IRDA_DEBUG(3, "%s(): We have %d entries, time to clean up\n",
+ __FUNCTION__, skb_queue_len(&raw->skb_ring));
+ schedule_work(&raw->skb_ring_work);
+ }
+
+ return 0;
+}
+
+ssize_t irlap_raw_read(struct file * file, char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ int ret = 0;
+ struct irlap_raw * raw;
+ struct sk_buff * frame;
+
+ IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+
+ raw = file->private_data;
+
+ ret = mutex_lock_interruptible(&raw->rx_mutex);
+ if (ret)
+ return ret;
+
+ ret = wait_event_interruptible(raw->rx_wait,
+ !skb_queue_empty(&raw->skb_ring));
+ if (ret < 0)
+ goto out;
+
+ if (skb_queue_empty(&raw->skb_ring)) {
+ ret = -EINTR;
+ IRDA_DEBUG(3, "%s(): Queue is empty\n", __FUNCTION__);
+ goto out;
+ }
+
+ frame = skb_dequeue_tail(&raw->skb_ring);
+
+ if (frame == NULL) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (copy_to_user(buf, frame->data, frame->len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = frame->len;
+ dev_kfree_skb(frame);
+
+ out:
+ mutex_unlock(&raw->rx_mutex);
+
+ IRDA_DEBUG(3, "%s(): Read %d bytes\n", __FUNCTION__, ret);
+ return ret;
+}
+
+extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);
+ssize_t irlap_raw_write(struct file * file, const char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ int ret;
+ struct irlap_raw * raw;
+ struct sk_buff *tx_skb;
+
+ IRDA_DEBUG(3, "%s(): Trying to write %d bytes\n", __FUNCTION__, count);
+
+ raw = file->private_data;
+
+ ret = mutex_lock_interruptible(&raw->tx_mutex);
+ if (ret)
+ return ret;
+
+ if (count == 0)
+ goto out;
+
+ tx_skb = alloc_skb(IRDA_SIR_MAX_FRAME, GFP_KERNEL);
+ if (tx_skb == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(skb_put(tx_skb, count), buf, count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ irlap_queue_xmit(raw->irlap, tx_skb);
+
+ ret = count;
+ out:
+ mutex_unlock(&raw->tx_mutex);
+
+ IRDA_DEBUG(3, "%s(): Wrote %d bytes\n", __FUNCTION__, ret);
+ return ret;
+}
+
+unsigned int irlap_raw_poll(struct file * file,
+ struct poll_table_struct * table)
+{
+ int ret = 0;
+ struct irlap_raw * raw;
+
+ raw = file->private_data;
+
+ poll_wait(file, &raw->rx_wait, table);
+
+ if (!skb_queue_empty(&raw->skb_ring))
+ ret = POLLIN | POLLRDNORM;
+ else
+ ret = POLLOUT | POLLWRNORM;
+
+ return ret;
+}
+
+int irlap_raw_open(struct inode * inode, struct file * file)
+{
+ unsigned int minor = iminor(inode);
+ int ret = -ENODEV;
+ struct irlap_raw * raw, * tmp;
+
+ IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+
+ mutex_lock_interruptible(&irlap_raw_mutex);
+ list_for_each_entry_safe(raw, tmp, &irlap_raw_list, list) {
+ if (raw->misc_device.minor == minor) {
+ IRDA_DEBUG(3, "%s(): Found raw (minor: %d)\n",
+ __FUNCTION__, minor);
+ file->private_data = raw;
+ raw->irlap->raw_mode = 1;
+ raw->refcount++;
+ mutex_unlock(&irlap_raw_mutex);
+ return 0;
+ }
+ }
+
+ mutex_unlock(&irlap_raw_mutex);
+ return ret;
+}
+
+int irlap_raw_release(struct inode * inode, struct file * file)
+{
+ struct irlap_raw * raw;
+
+ if (file->private_data) {
+ mutex_lock_interruptible(&irlap_raw_mutex);
+
+ raw = file->private_data;
+ if (raw->refcount > 0)
+ raw->refcount--;
+
+ if (raw->refcount == 0) {
+ skb_queue_purge(&raw->skb_ring);
+ raw->irlap->raw_mode = 0;
+ }
+
+ file->private_data = NULL;
+
+ mutex_unlock(&irlap_raw_mutex);
+ }
+
+ return 0;
+}
+
+static const struct file_operations irlap_raw_fops = {
+ .owner = THIS_MODULE,
+ .read = irlap_raw_read,
+ .write = irlap_raw_write,
+ .poll = irlap_raw_poll,
+ .open = irlap_raw_open,
+ .release = irlap_raw_release,
+};
+
+
+int irlap_raw_register_device(struct net_device * dev)
+{
+ int ret = 0;
+ struct irlap_cb * irlap;
+ struct irlap_raw * raw;
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ raw = kzalloc(sizeof(struct irlap_raw), GFP_KERNEL);
+ if (raw == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&raw->list);
+ INIT_WORK(&raw->skb_ring_work, irlap_raw_skb_ring_gc);
+ mutex_init(&raw->rx_mutex);
+ mutex_init(&raw->tx_mutex);
+ raw->refcount = 0;
+ skb_queue_head_init(&raw->skb_ring);
+
+ sprintf(raw->name, "%s_raw", dev->name);
+ raw->misc_device.minor = MISC_DYNAMIC_MINOR;
+ raw->misc_device.name = raw->name;
+ raw->misc_device.fops = &irlap_raw_fops;
+
+ list_add(&raw->list, &irlap_raw_list);
+
+ irlap = dev->atalk_ptr;
+ if (irlap == NULL) {
+ ret = -ENODEV;
+ goto out_err;
+ }
+
+ /* We'll enter raw mode whenever the device is open */
+ irlap->raw_mode = 0;
+ irlap->irlap_raw = raw;
+
+ init_waitqueue_head(&raw->rx_wait);
+
+ raw->irlap = irlap;
+
+ ret = misc_register(&raw->misc_device);
+ if (!ret) {
+ printk(KERN_INFO "Registered %s raw IrLAP device\n", raw->name);
+ return ret;
+ }
+
+ out_err:
+ irlap->irlap_raw = NULL;
+ kfree(raw);
+ return ret;
+
+}
+
+int irlap_raw_unregister_device(struct net_device * dev)
+{
+ struct irlap_cb * irlap;
+ struct irlap_raw * raw;
+
+ irlap = dev->atalk_ptr;
+ if (irlap == NULL)
+ return -ENODEV;
+
+ raw = irlap->irlap_raw;
+ mutex_lock_interruptible(&irlap_raw_mutex);
+ if (raw->refcount) {
+ mutex_unlock(&irlap_raw_mutex);
+ return -EBUSY;
+ }
+
+ printk(KERN_INFO "%s unregistered\n", raw->name);
+
+ list_del(&raw->list);
+ misc_deregister(&raw->misc_device);
+
+ mutex_unlock(&irlap_raw_mutex);
+
+ kfree(raw);
+
+ return 0;
+}
+
+inline int irlap_raw_mode(struct irlap_cb *self)
+{
+ return self->raw_mode;
+}
diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c
index 2e968e7..a7e967d 100644
--- a/net/irda/irsysctl.c
+++ b/net/irda/irsysctl.c
@@ -35,7 +35,7 @@
enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS,
DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME,
MAX_TX_DATA_SIZE, MAX_TX_WINDOW, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME,
- LAP_KEEPALIVE_TIME };
+ LAP_KEEPALIVE_TIME, RAW_RING_LENGTH };
extern int sysctl_discovery;
extern int sysctl_discovery_slots;
@@ -50,6 +50,9 @@ extern int sysctl_max_tx_window;
extern int sysctl_max_noreply_time;
extern int sysctl_warn_noreply_time;
extern int sysctl_lap_keepalive_time;
+#ifdef CONFIG_IRDA_RAW
+extern unsigned int sysctl_raw_ring_length;
+#endif
/* this is needed for the proc_dointvec_minmax - Jean II */
static int max_discovery_slots = 16; /* ??? */
@@ -237,6 +240,17 @@ static ctl_table irda_table[] = {
.extra1 = &min_lap_keepalive_time,
.extra2 = &max_lap_keepalive_time
},
+#ifdef CONFIG_IRDA_RAW
+ {
+ .ctl_name = RAW_RING_LENGTH,
+ .procname = "raw_ring_length",
+ .data = &sysctl_raw_ring_length,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
+#endif
+
{ .ctl_name = 0 }
};
--
1.5.0.2
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
next reply other threads:[~2007-03-17 1:57 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-17 1:57 Samuel Ortiz [this message]
2007-03-17 3:34 ` [PATCH 1/4] [net-2.6.22] IrDA: IrLAP raw mode David Miller
[not found] ` <20070316.203451.102575913.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2007-04-06 23:53 ` Samuel Ortiz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070317015729.GA3429@sortiz.org \
--to=samuel-jcdqhdrhkhmdnm+yrofe0a@public.gmane.org \
--cc=davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org \
--cc=irda-users-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
--cc=netdev-BkyiQQGWkgE@public.gmane.org \
--cc=netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.