You need to sign in or sign up before continuing.
提交 c4121432 编写于 作者: S Sven Eckelmann 提交者: Greg Kroah-Hartman

Staging: batman-adv: Move device for icmp injection to debugfs

batctl uses /dev/batman-adv to send special batman-adv icmp packets to
other nodes in the mesh. To get it working with multiple batX devices we
must ensure that every mesh device can have their own socket which is
used to inject those packets in exactly one mesh.

The current implementation still doesn't allow to use complete separated
meshes as we rely on structures which are not part of the private data
of a batman device.
Signed-off-by: NSven Eckelmann <sven.eckelmann@gmx.de>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 1bd2c215
...@@ -19,4 +19,4 @@ ...@@ -19,4 +19,4 @@
# #
obj-m += batman-adv.o obj-m += batman-adv.o
batman-adv-objs := main.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o bat_sysfs.o batman-adv-objs := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o
/*
* Copyright (C) 2010 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* 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 Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#include <linux/debugfs.h>
#include "main.h"
#include "bat_debugfs.h"
#include "translation-table.h"
#include "originator.h"
#include "hard-interface.h"
#include "vis.h"
#include "icmp_socket.h"
static struct dentry *bat_debugfs;
void debugfs_init(void)
{
bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL);
}
void debugfs_destroy(void)
{
if (bat_debugfs) {
debugfs_remove_recursive(bat_debugfs);
bat_debugfs = NULL;
}
}
int debugfs_add_meshif(struct net_device *dev)
{
struct bat_priv *bat_priv = netdev_priv(dev);
if (!bat_debugfs)
goto out;
bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs);
if (!bat_priv->debug_dir)
goto out;
bat_socket_setup(bat_priv);
return 0;
out:
#ifdef CONFIG_DEBUG_FS
return -ENOMEM;
#else
return 0;
#endif /* CONFIG_DEBUG_FS */
}
void debugfs_del_meshif(struct net_device *dev)
{
struct bat_priv *bat_priv = netdev_priv(dev);
if (bat_debugfs) {
debugfs_remove_recursive(bat_priv->debug_dir);
bat_priv->debug_dir = NULL;
}
}
/*
* Copyright (C) 2010 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* 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 Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*
*/
#ifndef BAT_DEBUGFS_H
#define BAT_DEBUGFS_H
#define DEBUGFS_BAT_SUBDIR "batman_adv"
void debugfs_init(void);
void debugfs_destroy(void);
int debugfs_add_meshif(struct net_device *dev);
void debugfs_del_meshif(struct net_device *dev);
#endif
...@@ -19,154 +19,101 @@ ...@@ -19,154 +19,101 @@
* *
*/ */
#include <linux/device.h> #include <linux/debugfs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "main.h" #include "main.h"
#include "device.h" #include "icmp_socket.h"
#include "send.h" #include "send.h"
#include "types.h" #include "types.h"
#include "hash.h" #include "hash.h"
#include "hard-interface.h" #include "hard-interface.h"
static struct class *batman_class;
static int Major; /* Major number assigned to our device driver */ static struct socket_client *socket_client_hash[256];
static const struct file_operations fops = { static void bat_socket_add_packet(struct socket_client *socket_client,
.open = bat_device_open, struct icmp_packet *icmp_packet);
.release = bat_device_release,
.read = bat_device_read,
.write = bat_device_write,
.poll = bat_device_poll,
};
static struct device_client *device_client_hash[256];
void bat_device_init(void)
{
memset(device_client_hash, 0, sizeof(device_client_hash));
}
int bat_device_setup(void)
{
int tmp_major;
if (Major)
return 1;
/* register our device - kernel assigns a free major number */
tmp_major = register_chrdev(0, DRIVER_DEVICE, &fops);
if (tmp_major < 0) {
printk(KERN_ERR "batman-adv:"
"Registering the character device failed with %d\n",
tmp_major);
return 0;
}
batman_class = class_create(THIS_MODULE, "batman-adv");
if (IS_ERR(batman_class)) {
printk(KERN_ERR "batman-adv:"
"Could not register class 'batman-adv'\n");
return 0;
}
device_create(batman_class, NULL, MKDEV(tmp_major, 0), NULL,
"batman-adv");
Major = tmp_major;
return 1;
}
void bat_device_destroy(void) void bat_socket_init(void)
{ {
if (!Major) memset(socket_client_hash, 0, sizeof(socket_client_hash));
return;
device_destroy(batman_class, MKDEV(Major, 0));
class_destroy(batman_class);
/* Unregister the device */
unregister_chrdev(Major, DRIVER_DEVICE);
Major = 0;
} }
int bat_device_open(struct inode *inode, struct file *file) static int bat_socket_open(struct inode *inode, struct file *file)
{ {
unsigned int i; unsigned int i;
struct device_client *device_client; struct socket_client *socket_client;
device_client = kmalloc(sizeof(struct device_client), GFP_KERNEL); socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL);
if (!device_client) if (!socket_client)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(device_client_hash); i++) { for (i = 0; i < ARRAY_SIZE(socket_client_hash); i++) {
if (!device_client_hash[i]) { if (!socket_client_hash[i]) {
device_client_hash[i] = device_client; socket_client_hash[i] = socket_client;
break; break;
} }
} }
if (i == ARRAY_SIZE(device_client_hash)) { if (i == ARRAY_SIZE(socket_client_hash)) {
printk(KERN_ERR "batman-adv:" printk(KERN_ERR "batman-adv:"
"Error - can't add another packet client: " "Error - can't add another packet client: "
"maximum number of clients reached\n"); "maximum number of clients reached\n");
kfree(device_client); kfree(socket_client);
return -EXFULL; return -EXFULL;
} }
INIT_LIST_HEAD(&device_client->queue_list); INIT_LIST_HEAD(&socket_client->queue_list);
device_client->queue_len = 0; socket_client->queue_len = 0;
device_client->index = i; socket_client->index = i;
spin_lock_init(&device_client->lock); spin_lock_init(&socket_client->lock);
init_waitqueue_head(&device_client->queue_wait); init_waitqueue_head(&socket_client->queue_wait);
file->private_data = device_client; file->private_data = socket_client;
inc_module_count(); inc_module_count();
return 0; return 0;
} }
int bat_device_release(struct inode *inode, struct file *file) static int bat_socket_release(struct inode *inode, struct file *file)
{ {
struct device_client *device_client = struct socket_client *socket_client =
(struct device_client *)file->private_data; (struct socket_client *)file->private_data;
struct device_packet *device_packet; struct socket_packet *socket_packet;
struct list_head *list_pos, *list_pos_tmp; struct list_head *list_pos, *list_pos_tmp;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&device_client->lock, flags); spin_lock_irqsave(&socket_client->lock, flags);
/* for all packets in the queue ... */ /* for all packets in the queue ... */
list_for_each_safe(list_pos, list_pos_tmp, &device_client->queue_list) { list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) {
device_packet = list_entry(list_pos, socket_packet = list_entry(list_pos,
struct device_packet, list); struct socket_packet, list);
list_del(list_pos); list_del(list_pos);
kfree(device_packet); kfree(socket_packet);
} }
device_client_hash[device_client->index] = NULL; socket_client_hash[socket_client->index] = NULL;
spin_unlock_irqrestore(&device_client->lock, flags); spin_unlock_irqrestore(&socket_client->lock, flags);
kfree(device_client); kfree(socket_client);
dec_module_count(); dec_module_count();
return 0; return 0;
} }
ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, static ssize_t bat_socket_read(struct file *file, char __user *buf,
loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct device_client *device_client = struct socket_client *socket_client =
(struct device_client *)file->private_data; (struct socket_client *)file->private_data;
struct device_packet *device_packet; struct socket_packet *socket_packet;
int error; int error;
unsigned long flags; unsigned long flags;
if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0)) if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0))
return -EAGAIN; return -EAGAIN;
if ((!buf) || (count < sizeof(struct icmp_packet))) if ((!buf) || (count < sizeof(struct icmp_packet)))
...@@ -175,25 +122,25 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, ...@@ -175,25 +122,25 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
if (!access_ok(VERIFY_WRITE, buf, count)) if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT; return -EFAULT;
error = wait_event_interruptible(device_client->queue_wait, error = wait_event_interruptible(socket_client->queue_wait,
device_client->queue_len); socket_client->queue_len);
if (error) if (error)
return error; return error;
spin_lock_irqsave(&device_client->lock, flags); spin_lock_irqsave(&socket_client->lock, flags);
device_packet = list_first_entry(&device_client->queue_list, socket_packet = list_first_entry(&socket_client->queue_list,
struct device_packet, list); struct socket_packet, list);
list_del(&device_packet->list); list_del(&socket_packet->list);
device_client->queue_len--; socket_client->queue_len--;
spin_unlock_irqrestore(&device_client->lock, flags); spin_unlock_irqrestore(&socket_client->lock, flags);
error = __copy_to_user(buf, &device_packet->icmp_packet, error = __copy_to_user(buf, &socket_packet->icmp_packet,
sizeof(struct icmp_packet)); sizeof(struct icmp_packet));
kfree(device_packet); kfree(socket_packet);
if (error) if (error)
return -EFAULT; return -EFAULT;
...@@ -201,11 +148,11 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, ...@@ -201,11 +148,11 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
return sizeof(struct icmp_packet); return sizeof(struct icmp_packet);
} }
ssize_t bat_device_write(struct file *file, const char __user *buff, static ssize_t bat_socket_write(struct file *file, const char __user *buff,
size_t len, loff_t *off) size_t len, loff_t *off)
{ {
struct device_client *device_client = struct socket_client *socket_client =
(struct device_client *)file->private_data; (struct socket_client *)file->private_data;
struct icmp_packet icmp_packet; struct icmp_packet icmp_packet;
struct orig_node *orig_node; struct orig_node *orig_node;
struct batman_if *batman_if; struct batman_if *batman_if;
...@@ -239,12 +186,12 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, ...@@ -239,12 +186,12 @@ ssize_t bat_device_write(struct file *file, const char __user *buff,
return -EINVAL; return -EINVAL;
} }
icmp_packet.uid = device_client->index; icmp_packet.uid = socket_client->index;
if (icmp_packet.version != COMPAT_VERSION) { if (icmp_packet.version != COMPAT_VERSION) {
icmp_packet.msg_type = PARAMETER_PROBLEM; icmp_packet.msg_type = PARAMETER_PROBLEM;
icmp_packet.ttl = COMPAT_VERSION; icmp_packet.ttl = COMPAT_VERSION;
bat_device_add_packet(device_client, &icmp_packet); bat_socket_add_packet(socket_client, &icmp_packet);
goto out; goto out;
} }
...@@ -285,70 +232,97 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, ...@@ -285,70 +232,97 @@ ssize_t bat_device_write(struct file *file, const char __user *buff,
spin_unlock_irqrestore(&orig_hash_lock, flags); spin_unlock_irqrestore(&orig_hash_lock, flags);
dst_unreach: dst_unreach:
icmp_packet.msg_type = DESTINATION_UNREACHABLE; icmp_packet.msg_type = DESTINATION_UNREACHABLE;
bat_device_add_packet(device_client, &icmp_packet); bat_socket_add_packet(socket_client, &icmp_packet);
out: out:
return len; return len;
} }
unsigned int bat_device_poll(struct file *file, poll_table *wait) static unsigned int bat_socket_poll(struct file *file, poll_table *wait)
{ {
struct device_client *device_client = struct socket_client *socket_client =
(struct device_client *)file->private_data; (struct socket_client *)file->private_data;
poll_wait(file, &device_client->queue_wait, wait); poll_wait(file, &socket_client->queue_wait, wait);
if (device_client->queue_len > 0) if (socket_client->queue_len > 0)
return POLLIN | POLLRDNORM; return POLLIN | POLLRDNORM;
return 0; return 0;
} }
void bat_device_add_packet(struct device_client *device_client, static const struct file_operations fops = {
struct icmp_packet *icmp_packet) .owner = THIS_MODULE,
.open = bat_socket_open,
.release = bat_socket_release,
.read = bat_socket_read,
.write = bat_socket_write,
.poll = bat_socket_poll,
};
int bat_socket_setup(struct bat_priv *bat_priv)
{
struct dentry *d;
if (!bat_priv->debug_dir)
goto err;
d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR,
bat_priv->debug_dir, NULL, &fops);
if (d)
goto err;
return 0;
err:
return 1;
}
static void bat_socket_add_packet(struct socket_client *socket_client,
struct icmp_packet *icmp_packet)
{ {
struct device_packet *device_packet; struct socket_packet *socket_packet;
unsigned long flags; unsigned long flags;
device_packet = kmalloc(sizeof(struct device_packet), GFP_ATOMIC); socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC);
if (!device_packet) if (!socket_packet)
return; return;
INIT_LIST_HEAD(&device_packet->list); INIT_LIST_HEAD(&socket_packet->list);
memcpy(&device_packet->icmp_packet, icmp_packet, memcpy(&socket_packet->icmp_packet, icmp_packet,
sizeof(struct icmp_packet)); sizeof(struct icmp_packet));
spin_lock_irqsave(&device_client->lock, flags); spin_lock_irqsave(&socket_client->lock, flags);
/* while waiting for the lock the device_client could have been /* while waiting for the lock the socket_client could have been
* deleted */ * deleted */
if (!device_client_hash[icmp_packet->uid]) { if (!socket_client_hash[icmp_packet->uid]) {
spin_unlock_irqrestore(&device_client->lock, flags); spin_unlock_irqrestore(&socket_client->lock, flags);
kfree(device_packet); kfree(socket_packet);
return; return;
} }
list_add_tail(&device_packet->list, &device_client->queue_list); list_add_tail(&socket_packet->list, &socket_client->queue_list);
device_client->queue_len++; socket_client->queue_len++;
if (device_client->queue_len > 100) { if (socket_client->queue_len > 100) {
device_packet = list_first_entry(&device_client->queue_list, socket_packet = list_first_entry(&socket_client->queue_list,
struct device_packet, list); struct socket_packet, list);
list_del(&device_packet->list); list_del(&socket_packet->list);
kfree(device_packet); kfree(socket_packet);
device_client->queue_len--; socket_client->queue_len--;
} }
spin_unlock_irqrestore(&device_client->lock, flags); spin_unlock_irqrestore(&socket_client->lock, flags);
wake_up(&device_client->queue_wait); wake_up(&socket_client->queue_wait);
} }
void bat_device_receive_packet(struct icmp_packet *icmp_packet) void bat_socket_receive_packet(struct icmp_packet *icmp_packet)
{ {
struct device_client *hash = device_client_hash[icmp_packet->uid]; struct socket_client *hash = socket_client_hash[icmp_packet->uid];
if (hash) if (hash)
bat_device_add_packet(hash, icmp_packet); bat_socket_add_packet(hash, icmp_packet);
} }
...@@ -21,16 +21,8 @@ ...@@ -21,16 +21,8 @@
#include "types.h" #include "types.h"
void bat_device_init(void); #define ICMP_SOCKET "socket"
int bat_device_setup(void);
void bat_device_destroy(void); void bat_socket_init(void);
int bat_device_open(struct inode *inode, struct file *file); int bat_socket_setup(struct bat_priv *bat_priv);
int bat_device_release(struct inode *inode, struct file *file); void bat_socket_receive_packet(struct icmp_packet *icmp_packet);
ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos);
ssize_t bat_device_write(struct file *file, const char __user *buff,
size_t len, loff_t *off);
unsigned int bat_device_poll(struct file *file, poll_table *wait);
void bat_device_add_packet(struct device_client *device_client,
struct icmp_packet *icmp_packet);
void bat_device_receive_packet(struct icmp_packet *icmp_packet);
...@@ -21,11 +21,12 @@ ...@@ -21,11 +21,12 @@
#include "main.h" #include "main.h"
#include "bat_sysfs.h" #include "bat_sysfs.h"
#include "bat_debugfs.h"
#include "routing.h" #include "routing.h"
#include "send.h" #include "send.h"
#include "originator.h" #include "originator.h"
#include "soft-interface.h" #include "soft-interface.h"
#include "device.h" #include "icmp_socket.h"
#include "translation-table.h" #include "translation-table.h"
#include "hard-interface.h" #include "hard-interface.h"
#include "types.h" #include "types.h"
...@@ -89,7 +90,8 @@ int init_module(void) ...@@ -89,7 +90,8 @@ int init_module(void)
if (!bat_event_workqueue) if (!bat_event_workqueue)
return -ENOMEM; return -ENOMEM;
bat_device_init(); bat_socket_init();
debugfs_init();
/* initialize layer 2 interface */ /* initialize layer 2 interface */
soft_device = alloc_netdev(sizeof(struct bat_priv) , "bat%d", soft_device = alloc_netdev(sizeof(struct bat_priv) , "bat%d",
...@@ -114,6 +116,11 @@ int init_module(void) ...@@ -114,6 +116,11 @@ int init_module(void)
if (retval < 0) if (retval < 0)
goto unreg_soft_device; goto unreg_soft_device;
retval = debugfs_add_meshif(soft_device);
if (retval < 0)
goto unreg_sysfs;
register_netdevice_notifier(&hard_if_notifier); register_netdevice_notifier(&hard_if_notifier);
dev_add_pack(&batman_adv_packet_type); dev_add_pack(&batman_adv_packet_type);
...@@ -123,6 +130,8 @@ int init_module(void) ...@@ -123,6 +130,8 @@ int init_module(void)
return 0; return 0;
unreg_sysfs:
sysfs_del_meshif(soft_device);
unreg_soft_device: unreg_soft_device:
unregister_netdev(soft_device); unregister_netdev(soft_device);
soft_device = NULL; soft_device = NULL;
...@@ -143,6 +152,7 @@ void cleanup_module(void) ...@@ -143,6 +152,7 @@ void cleanup_module(void)
hardif_remove_interfaces(); hardif_remove_interfaces();
if (soft_device) { if (soft_device) {
debugfs_del_meshif(soft_device);
sysfs_del_meshif(soft_device); sysfs_del_meshif(soft_device);
unregister_netdev(soft_device); unregister_netdev(soft_device);
soft_device = NULL; soft_device = NULL;
...@@ -154,7 +164,7 @@ void cleanup_module(void) ...@@ -154,7 +164,7 @@ void cleanup_module(void)
bat_event_workqueue = NULL; bat_event_workqueue = NULL;
} }
/* activates the module, creates bat device, starts timer ... */ /* activates the module, starts timer ... */
void activate_module(void) void activate_module(void)
{ {
if (originator_init() < 1) if (originator_init() < 1)
...@@ -168,9 +178,6 @@ void activate_module(void) ...@@ -168,9 +178,6 @@ void activate_module(void)
hna_local_add(soft_device->dev_addr); hna_local_add(soft_device->dev_addr);
if (bat_device_setup() < 1)
goto end;
if (vis_init() < 1) if (vis_init() < 1)
goto err; goto err;
...@@ -205,7 +212,7 @@ void deactivate_module(void) ...@@ -205,7 +212,7 @@ void deactivate_module(void)
hna_global_free(); hna_global_free();
synchronize_net(); synchronize_net();
bat_device_destroy(); debugfs_destroy();
synchronize_rcu(); synchronize_rcu();
atomic_set(&module_state, MODULE_INACTIVE); atomic_set(&module_state, MODULE_INACTIVE);
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "hash.h" #include "hash.h"
#include "soft-interface.h" #include "soft-interface.h"
#include "hard-interface.h" #include "hard-interface.h"
#include "device.h" #include "icmp_socket.h"
#include "translation-table.h" #include "translation-table.h"
#include "originator.h" #include "originator.h"
#include "types.h" #include "types.h"
...@@ -668,7 +668,7 @@ static int recv_my_icmp_packet(struct sk_buff *skb) ...@@ -668,7 +668,7 @@ static int recv_my_icmp_packet(struct sk_buff *skb)
/* add data to device queue */ /* add data to device queue */
if (icmp_packet->msg_type != ECHO_REQUEST) { if (icmp_packet->msg_type != ECHO_REQUEST) {
bat_device_receive_packet(icmp_packet); bat_socket_receive_packet(icmp_packet);
return NET_RX_DROP; return NET_RX_DROP;
} }
......
...@@ -106,9 +106,10 @@ struct bat_priv { ...@@ -106,9 +106,10 @@ struct bat_priv {
char num_ifaces; char num_ifaces;
struct batman_if *primary_if; struct batman_if *primary_if;
struct kobject *mesh_obj; struct kobject *mesh_obj;
struct dentry *debug_dir;
}; };
struct device_client { struct socket_client {
struct list_head queue_list; struct list_head queue_list;
unsigned int queue_len; unsigned int queue_len;
unsigned char index; unsigned char index;
...@@ -116,7 +117,7 @@ struct device_client { ...@@ -116,7 +117,7 @@ struct device_client {
wait_queue_head_t queue_wait; wait_queue_head_t queue_wait;
}; };
struct device_packet { struct socket_packet {
struct list_head list; struct list_head list;
struct icmp_packet icmp_packet; struct icmp_packet icmp_packet;
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册