Commit 208e13e4 authored by Marek Lindner's avatar Marek Lindner Committed by Greg Kroah-Hartman

Staging: batman-adv: move /proc interface handling to /sys

Instead of having a single /proc file "interfaces" in which you have
to echo the wanted interface batman-adv will create a subfolder in each
suitable /sys/class/net folder. This subfolder contains files for the
interface specific settings. For example, mesh_iface to add/remove an
interface from a virtual mesh network (at the moment only bat0 is
supported).

Example:
echo bat0 > /sys/class/net/eth0/batman-adv/mesh_iface

to deactivate:
echo none > /sys/class/net/eth0/batman-adv/mesh_iface

Interfaces which are not compatible with batman-adv won't contain the
batman-adv folder, therefore can't be activated. Not supported are:
loopback, non-ethernet, non-ARP and virtual mesh network interfaces
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
Signed-off-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 35bd69d4
...@@ -19,4 +19,4 @@ ...@@ -19,4 +19,4 @@
# #
obj-m += batman-adv.o obj-m += batman-adv.o
batman-adv-objs := main.o proc.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 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
...@@ -36,6 +36,14 @@ struct bat_attribute { ...@@ -36,6 +36,14 @@ struct bat_attribute {
char *buf, size_t count); char *buf, size_t count);
}; };
struct hardif_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
char *buf);
ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
char *buf, size_t count);
};
#define BAT_ATTR(_name, _mode, _show, _store) \ #define BAT_ATTR(_name, _mode, _show, _store) \
struct bat_attribute bat_attr_##_name = { \ struct bat_attribute bat_attr_##_name = { \
.attr = {.name = __stringify(_name), \ .attr = {.name = __stringify(_name), \
...@@ -52,6 +60,14 @@ struct bin_attribute bat_attr_##_name = { \ ...@@ -52,6 +60,14 @@ struct bin_attribute bat_attr_##_name = { \
.write = _write, \ .write = _write, \
}; };
#define HARDIF_ATTR(_name, _mode, _show, _store) \
struct hardif_attribute hardif_attr_##_name = { \
.attr = {.name = __stringify(_name), \
.mode = _mode }, \
.show = _show, \
.store = _store, \
};
static ssize_t show_aggr_ogm(struct kobject *kobj, struct attribute *attr, static ssize_t show_aggr_ogm(struct kobject *kobj, struct attribute *attr,
char *buff) char *buff)
{ {
...@@ -275,6 +291,8 @@ int sysfs_add_meshif(struct net_device *dev) ...@@ -275,6 +291,8 @@ int sysfs_add_meshif(struct net_device *dev)
atomic_set(&bat_priv->aggregation_enabled, 1); atomic_set(&bat_priv->aggregation_enabled, 1);
atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
atomic_set(&bat_priv->orig_interval, 1000); atomic_set(&bat_priv->orig_interval, 1000);
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR, bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR,
batif_kobject); batif_kobject);
...@@ -335,3 +353,132 @@ void sysfs_del_meshif(struct net_device *dev) ...@@ -335,3 +353,132 @@ void sysfs_del_meshif(struct net_device *dev)
kobject_put(bat_priv->mesh_obj); kobject_put(bat_priv->mesh_obj);
bat_priv->mesh_obj = NULL; bat_priv->mesh_obj = NULL;
} }
static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
char *buff)
{
struct device *dev = to_dev(kobj->parent);
struct net_device *net_dev = to_net_dev(dev);
struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
if (!batman_if)
return 0;
return sprintf(buff, "status: %s\ncommands: none, bat0 \n",
batman_if->if_status == IF_NOT_IN_USE ?
"none" : "bat0");
}
static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
char *buff, size_t count)
{
struct device *dev = to_dev(kobj->parent);
struct net_device *net_dev = to_net_dev(dev);
struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
int status_tmp = -1;
if (!batman_if)
return count;
if (strncmp(buff, "none", 4) == 0)
status_tmp = IF_NOT_IN_USE;
if (strncmp(buff, "bat0", 4) == 0)
status_tmp = IF_I_WANT_YOU;
if (status_tmp < 0) {
if (buff[count - 1] == '\n')
buff[count - 1] = '\0';
printk(KERN_ERR "batman-adv:Invalid parameter for 'mesh_iface' setting received: %s\n",
buff);
return -EINVAL;
}
if ((batman_if->if_status == status_tmp) ||
((status_tmp == IF_I_WANT_YOU) &&
(batman_if->if_status != IF_NOT_IN_USE)))
return count;
if (status_tmp == IF_I_WANT_YOU)
status_tmp = hardif_enable_interface(batman_if);
else
hardif_disable_interface(batman_if);
return (status_tmp < 0 ? status_tmp : count);
}
static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
char *buff)
{
struct device *dev = to_dev(kobj->parent);
struct net_device *net_dev = to_net_dev(dev);
struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
if (!batman_if)
return 0;
switch (batman_if->if_status) {
case IF_TO_BE_REMOVED:
return sprintf(buff, "disabling\n");
case IF_INACTIVE:
return sprintf(buff, "inactive\n");
case IF_ACTIVE:
return sprintf(buff, "active\n");
case IF_TO_BE_ACTIVATED:
return sprintf(buff, "enabling\n");
case IF_NOT_IN_USE:
default:
return sprintf(buff, "not in use\n");
}
}
static HARDIF_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
show_mesh_iface, store_mesh_iface);
static HARDIF_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
static struct hardif_attribute *batman_attrs[] = {
&hardif_attr_mesh_iface,
&hardif_attr_iface_status,
NULL,
};
int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
{
struct kobject *hardif_kobject = &dev->dev.kobj;
struct hardif_attribute **hardif_attr;
int err;
*hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR,
hardif_kobject);
if (!*hardif_obj) {
printk(KERN_ERR "batman-adv:Can't add sysfs directory: %s/%s\n",
dev->name, SYSFS_IF_BAT_SUBDIR);
goto out;
}
for (hardif_attr = batman_attrs; *hardif_attr; ++hardif_attr) {
err = sysfs_create_file(*hardif_obj, &((*hardif_attr)->attr));
if (err) {
printk(KERN_ERR "batman-adv:Can't add sysfs file: %s/%s/%s\n",
dev->name, SYSFS_IF_BAT_SUBDIR,
((*hardif_attr)->attr).name);
goto rem_attr;
}
}
return 0;
rem_attr:
for (hardif_attr = batman_attrs; *hardif_attr; ++hardif_attr)
sysfs_remove_file(*hardif_obj, &((*hardif_attr)->attr));
out:
return -ENOMEM;
}
void sysfs_del_hardif(struct kobject **hardif_obj)
{
kobject_put(*hardif_obj);
*hardif_obj = NULL;
}
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#define SYSFS_IF_MESH_SUBDIR "mesh" #define SYSFS_IF_MESH_SUBDIR "mesh"
#define SYSFS_IF_BAT_SUBDIR "batman_adv"
int sysfs_add_meshif(struct net_device *dev); int sysfs_add_meshif(struct net_device *dev);
void sysfs_del_meshif(struct net_device *dev); void sysfs_del_meshif(struct net_device *dev);
int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
void sysfs_del_hardif(struct kobject **hardif_obj);
...@@ -258,7 +258,7 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, ...@@ -258,7 +258,7 @@ ssize_t bat_device_write(struct file *file, const char __user *buff,
if (!batman_if) if (!batman_if)
goto dst_unreach; goto dst_unreach;
if (batman_if->if_active != IF_ACTIVE) if (batman_if->if_status != IF_ACTIVE)
goto dst_unreach; goto dst_unreach;
memcpy(icmp_packet.orig, memcpy(icmp_packet.orig,
......
This diff is collapsed.
...@@ -19,19 +19,19 @@ ...@@ -19,19 +19,19 @@
* *
*/ */
#define IF_INACTIVE 0 #define IF_NOT_IN_USE 0
#define IF_ACTIVE 1 #define IF_TO_BE_REMOVED 1
/* #define IF_TO_BE_DEACTIVATED 2 - not needed anymore */ #define IF_INACTIVE 2
#define IF_TO_BE_ACTIVATED 3 #define IF_ACTIVE 3
#define IF_TO_BE_ACTIVATED 4
#define IF_I_WANT_YOU 5
extern struct notifier_block hard_if_notifier; extern struct notifier_block hard_if_notifier;
struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev);
int hardif_enable_interface(struct batman_if *batman_if);
void hardif_disable_interface(struct batman_if *batman_if);
void hardif_remove_interfaces(void); void hardif_remove_interfaces(void);
int hardif_add_interface(char *dev, int if_num);
void hardif_deactivate_interface(struct batman_if *batman_if);
char hardif_get_active_if_num(void);
void hardif_check_interfaces_status(void);
void hardif_check_interfaces_status_wq(struct work_struct *work);
int batman_skb_recv(struct sk_buff *skb, int batman_skb_recv(struct sk_buff *skb,
struct net_device *dev, struct net_device *dev,
struct packet_type *ptype, struct packet_type *ptype,
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
*/ */
#include "main.h" #include "main.h"
#include "proc.h"
#include "bat_sysfs.h" #include "bat_sysfs.h"
#include "routing.h" #include "routing.h"
#include "send.h" #include "send.h"
...@@ -44,7 +43,6 @@ DEFINE_SPINLOCK(forw_bcast_list_lock); ...@@ -44,7 +43,6 @@ DEFINE_SPINLOCK(forw_bcast_list_lock);
atomic_t vis_interval; atomic_t vis_interval;
int16_t num_hna; int16_t num_hna;
int16_t num_ifs;
struct net_device *soft_device; struct net_device *soft_device;
...@@ -89,10 +87,6 @@ int init_module(void) ...@@ -89,10 +87,6 @@ int init_module(void)
if (!bat_event_workqueue) if (!bat_event_workqueue)
return -ENOMEM; return -ENOMEM;
retval = setup_procfs();
if (retval < 0)
return retval;
bat_device_init(); bat_device_init();
/* initialize layer 2 interface */ /* initialize layer 2 interface */
...@@ -135,7 +129,10 @@ int init_module(void) ...@@ -135,7 +129,10 @@ int init_module(void)
void cleanup_module(void) void cleanup_module(void)
{ {
shutdown_module(); deactivate_module();
unregister_netdevice_notifier(&hard_if_notifier);
hardif_remove_interfaces();
if (soft_device) { if (soft_device) {
sysfs_del_meshif(soft_device); sysfs_del_meshif(soft_device);
...@@ -145,9 +142,6 @@ void cleanup_module(void) ...@@ -145,9 +142,6 @@ void cleanup_module(void)
dev_remove_pack(&batman_adv_packet_type); dev_remove_pack(&batman_adv_packet_type);
unregister_netdevice_notifier(&hard_if_notifier);
cleanup_procfs();
destroy_workqueue(bat_event_workqueue); destroy_workqueue(bat_event_workqueue);
bat_event_workqueue = NULL; bat_event_workqueue = NULL;
} }
...@@ -178,17 +172,17 @@ void activate_module(void) ...@@ -178,17 +172,17 @@ void activate_module(void)
err: err:
printk(KERN_ERR "batman-adv:Unable to allocate memory for mesh information structures: out of mem ?\n"); printk(KERN_ERR "batman-adv:Unable to allocate memory for mesh information structures: out of mem ?\n");
shutdown_module(); deactivate_module();
end: end:
return; return;
} }
/* shuts down the whole module.*/ /* shuts down the whole module.*/
void shutdown_module(void) void deactivate_module(void)
{ {
atomic_set(&module_state, MODULE_DEACTIVATING); atomic_set(&module_state, MODULE_DEACTIVATING);
purge_outstanding_packets(); purge_outstanding_packets(NULL);
flush_workqueue(bat_event_workqueue); flush_workqueue(bat_event_workqueue);
vis_quit(); vis_quit();
...@@ -203,7 +197,6 @@ void shutdown_module(void) ...@@ -203,7 +197,6 @@ void shutdown_module(void)
synchronize_net(); synchronize_net();
bat_device_destroy(); bat_device_destroy();
hardif_remove_interfaces();
synchronize_rcu(); synchronize_rcu();
atomic_set(&module_state, MODULE_INACTIVE); atomic_set(&module_state, MODULE_INACTIVE);
} }
......
...@@ -129,7 +129,6 @@ extern spinlock_t forw_bcast_list_lock; ...@@ -129,7 +129,6 @@ extern spinlock_t forw_bcast_list_lock;
extern atomic_t vis_interval; extern atomic_t vis_interval;
extern int16_t num_hna; extern int16_t num_hna;
extern int16_t num_ifs;
extern struct net_device *soft_device; extern struct net_device *soft_device;
...@@ -138,7 +137,7 @@ extern atomic_t module_state; ...@@ -138,7 +137,7 @@ extern atomic_t module_state;
extern struct workqueue_struct *bat_event_workqueue; extern struct workqueue_struct *bat_event_workqueue;
void activate_module(void); void activate_module(void);
void shutdown_module(void); void deactivate_module(void);
void inc_module_count(void); void inc_module_count(void);
void dec_module_count(void); void dec_module_count(void);
int addr_to_string(char *buff, uint8_t *addr); int addr_to_string(char *buff, uint8_t *addr);
......
...@@ -118,6 +118,8 @@ void free_orig_node(void *data) ...@@ -118,6 +118,8 @@ void free_orig_node(void *data)
* address if it does not exits */ * address if it does not exits */
struct orig_node *get_orig_node(uint8_t *addr) struct orig_node *get_orig_node(uint8_t *addr)
{ {
/* FIXME: each batman_if will be attached to a softif */
struct bat_priv *bat_priv = netdev_priv(soft_device);
struct orig_node *orig_node; struct orig_node *orig_node;
struct hashtable_t *swaphash; struct hashtable_t *swaphash;
int size; int size;
...@@ -139,13 +141,13 @@ struct orig_node *get_orig_node(uint8_t *addr) ...@@ -139,13 +141,13 @@ struct orig_node *get_orig_node(uint8_t *addr)
orig_node->router = NULL; orig_node->router = NULL;
orig_node->hna_buff = NULL; orig_node->hna_buff = NULL;
size = num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS; size = bat_priv->num_ifaces * sizeof(TYPE_OF_WORD) * NUM_WORDS;
orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
if (!orig_node->bcast_own) if (!orig_node->bcast_own)
goto free_orig_node; goto free_orig_node;
size = num_ifs * sizeof(uint8_t); size = bat_priv->num_ifaces * sizeof(uint8_t);
orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
if (!orig_node->bcast_own_sum) if (!orig_node->bcast_own_sum)
goto free_bcast_own; goto free_bcast_own;
...@@ -182,16 +184,25 @@ static bool purge_orig_neighbors(struct orig_node *orig_node, ...@@ -182,16 +184,25 @@ static bool purge_orig_neighbors(struct orig_node *orig_node,
*best_neigh_node = NULL; *best_neigh_node = NULL;
/* for all neighbors towards this originator ... */ /* for all neighbors towards this originator ... */
list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
neigh_node = list_entry(list_pos, struct neigh_node, list); neigh_node = list_entry(list_pos, struct neigh_node, list);
if (time_after(jiffies, if ((time_after(jiffies,
(neigh_node->last_valid + (neigh_node->last_valid +
((PURGE_TIMEOUT * HZ) / 1000)))) { ((PURGE_TIMEOUT * HZ) / 1000)))) ||
(neigh_node->if_incoming->if_status ==
bat_dbg(DBG_BATMAN, "neighbor timeout: originator %pM, neighbor: %pM, last_valid %lu\n", orig_node->orig, neigh_node->addr, (neigh_node->last_valid / HZ)); IF_TO_BE_REMOVED)) {
if (neigh_node->if_incoming->if_status ==
IF_TO_BE_REMOVED)
bat_dbg(DBG_BATMAN, "neighbor purge: originator %pM, neighbor: %pM, iface: %s\n",
orig_node->orig, neigh_node->addr,
neigh_node->if_incoming->dev);
else
bat_dbg(DBG_BATMAN, "neighbor timeout: originator %pM, neighbor: %pM, last_valid: %lu\n",
orig_node->orig, neigh_node->addr,
(neigh_node->last_valid / HZ));
neigh_purged = true; neigh_purged = true;
list_del(list_pos); list_del(list_pos);
...@@ -246,6 +257,9 @@ void purge_orig(struct work_struct *work) ...@@ -246,6 +257,9 @@ void purge_orig(struct work_struct *work)
spin_unlock_irqrestore(&orig_hash_lock, flags); spin_unlock_irqrestore(&orig_hash_lock, flags);
/* if work == NULL we were not called by the timer
* and thus do not need to re-arm the timer */
if (work)
start_purge_timer(); start_purge_timer();
} }
...@@ -253,6 +267,7 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, ...@@ -253,6 +267,7 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
size_t count, loff_t off) size_t count, loff_t off)
{ {
HASHIT(hashit); HASHIT(hashit);
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct orig_node *orig_node; struct orig_node *orig_node;
struct neigh_node *neigh_node; struct neigh_node *neigh_node;
size_t hdr_len, tmp_len; size_t hdr_len, tmp_len;
...@@ -260,10 +275,7 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, ...@@ -260,10 +275,7 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
unsigned long flags; unsigned long flags;
char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN]; char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
rcu_read_lock(); if (!bat_priv->primary_if) {
if (list_empty(&if_list)) {
rcu_read_unlock();
if (off == 0) if (off == 0)
return sprintf(buff, return sprintf(buff,
"BATMAN mesh %s disabled - please specify interfaces to enable it\n", "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
...@@ -272,9 +284,7 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, ...@@ -272,9 +284,7 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
return 0; return 0;
} }
if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) { if (bat_priv->primary_if->if_status != IF_ACTIVE) {
rcu_read_unlock();
if (off == 0) if (off == 0)
return sprintf(buff, return sprintf(buff,
"BATMAN mesh %s disabled - primary interface not active\n", "BATMAN mesh %s disabled - primary interface not active\n",
...@@ -283,12 +293,12 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, ...@@ -283,12 +293,12 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
return 0; return 0;
} }
rcu_read_lock();
hdr_len = sprintf(buff, hdr_len = sprintf(buff,
" %-14s (%s/%i) %17s [%10s]: %20s ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s (%s)] \n", " %-14s (%s/%i) %17s [%10s]: %20s ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s (%s)] \n",
"Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF",
"Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR, "Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR,
((struct batman_if *)if_list.next)->dev, bat_priv->primary_if->dev, bat_priv->primary_if->addr_str,
((struct batman_if *)if_list.next)->addr_str,
net_dev->name); net_dev->name);
rcu_read_unlock(); rcu_read_unlock();
...@@ -347,3 +357,152 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, ...@@ -347,3 +357,152 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
return bytes_written; return bytes_written;
} }
static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
{
void *data_ptr;
data_ptr = kmalloc(max_if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS,
GFP_ATOMIC);
if (!data_ptr) {
printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n");
return -1;
}
memcpy(data_ptr, orig_node->bcast_own,
(max_if_num - 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS);
kfree(orig_node->bcast_own);
orig_node->bcast_own = data_ptr;
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr) {
printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n");
return -1;
}
memcpy(data_ptr, orig_node->bcast_own_sum,
(max_if_num - 1) * sizeof(uint8_t));
kfree(orig_node->bcast_own_sum);
orig_node->bcast_own_sum = data_ptr;
return 0;
}
int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
{
struct orig_node *orig_node;
HASHIT(hashit);
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
spin_lock(&orig_hash_lock);
while (hash_iterate(orig_hash, &hashit)) {
orig_node = hashit.bucket->data;
if (orig_node_add_if(orig_node, max_if_num) == -1)
goto err;
}
spin_unlock(&orig_hash_lock);
return 0;
err:
spin_unlock(&orig_hash_lock);
return -ENOMEM;
}
static int orig_node_del_if(struct orig_node *orig_node,
int max_if_num, int del_if_num)
{
void *data_ptr = NULL;
int chunk_size;
/* last interface was removed */
if (max_if_num == 0)
goto free_bcast_own;
chunk_size = sizeof(TYPE_OF_WORD) * NUM_WORDS;
data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
if (!data_ptr) {
printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n");
return -1;
}
/* copy first part */
memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
/* copy second part */
memcpy(data_ptr,
orig_node->bcast_own + ((del_if_num + 1) * chunk_size),
(max_if_num - del_if_num) * chunk_size);
free_bcast_own:
kfree(orig_node->bcast_own);
orig_node->bcast_own = data_ptr;
if (max_if_num == 0)
goto free_own_sum;
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr) {
printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n");
return -1;
}
memcpy(data_ptr, orig_node->bcast_own_sum,
del_if_num * sizeof(uint8_t));
memcpy(data_ptr,
orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)),
(max_if_num - del_if_num) * sizeof(uint8_t));
free_own_sum:
kfree(orig_node->bcast_own_sum);
orig_node->bcast_own_sum = data_ptr;
return 0;
}
int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
{
struct batman_if *batman_if_tmp;
struct orig_node *orig_node;
HASHIT(hashit);
int ret;
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
spin_lock(&orig_hash_lock);
while (hash_iterate(orig_hash, &hashit)) {
orig_node = hashit.bucket->data;
ret = orig_node_del_if(orig_node, max_if_num,
batman_if->if_num);
if (ret == -1)
goto err;
}
/* renumber remaining batman interfaces _inside_ of orig_hash_lock */
rcu_read_lock();
list_for_each_entry_rcu(batman_if_tmp, &if_list, list) {
if (batman_if_tmp->if_status == IF_NOT_IN_USE)
continue;
if (batman_if == batman_if_tmp)
continue;
if (batman_if_tmp->if_num > batman_if->if_num)
batman_if_tmp->if_num--;
}
rcu_read_unlock();
batman_if->if_num = -1;
spin_unlock(&orig_hash_lock);
return 0;
err:
spin_unlock(&orig_hash_lock);
return -ENOMEM;
}
...@@ -30,3 +30,5 @@ create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, ...@@ -30,3 +30,5 @@ create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
uint8_t *neigh, struct batman_if *if_incoming); uint8_t *neigh, struct batman_if *if_incoming);
ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
size_t count, loff_t off); size_t count, loff_t off);
int orig_hash_add_if(struct batman_if *batman_if, int max_if_num);
int orig_hash_del_if(struct batman_if *batman_if, int max_if_num);
/*
* Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* 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 "main.h"
#include "proc.h"
#include "routing.h"
#include "translation-table.h"
#include "hard-interface.h"
#include "types.h"
#include "hash.h"
#include "vis.h"
static struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
static int proc_interfaces_read(struct seq_file *seq, void *offset)
{
struct batman_if *batman_if;
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
seq_printf(seq, "[%8s] %s %s\n",
(batman_if->if_active == IF_ACTIVE ?
"active" : "inactive"),
batman_if->dev,
(batman_if->if_active == IF_ACTIVE ?
batman_if->addr_str : " "));
}
rcu_read_unlock();
return 0;
}
static int proc_interfaces_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_interfaces_read, NULL);
}
static ssize_t proc_interfaces_write(struct file *instance,
const char __user *userbuffer,
size_t count, loff_t *data)
{
char *if_string, *colon_ptr = NULL, *cr_ptr = NULL;
int not_copied = 0, if_num = 0, add_success;
struct batman_if *batman_if = NULL;
if_string = kmalloc(count, GFP_KERNEL);
if (!if_string)
return -ENOMEM;
if (count > IFNAMSIZ - 1) {
printk(KERN_WARNING "batman-adv:Can't add interface: device name is too long\n");
goto end;
}
not_copied = copy_from_user(if_string, userbuffer, count);
if_string[count - not_copied - 1] = 0;
colon_ptr = strchr(if_string, ':');
if (colon_ptr)
*colon_ptr = 0;
if (!colon_ptr) {
cr_ptr = strchr(if_string, '\n');
if (cr_ptr)
*cr_ptr = 0;
}
if (strlen(if_string) == 0) {
shutdown_module();
num_ifs = 0;
goto end;
}
/* add interface */
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
if (strncmp(batman_if->dev, if_string, count) == 0) {
printk(KERN_ERR "batman-adv:Given interface is already active: %s\n", if_string);
rcu_read_unlock();
goto end;
}
if_num++;
}
rcu_read_unlock();
add_success = hardif_add_interface(if_string, if_num);
if (add_success < 0)
goto end;
num_ifs = if_num + 1;
if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
(hardif_get_active_if_num() > 0))
activate_module();
return count;
end:
kfree(if_string);
return count;
}
static const struct file_operations proc_interfaces_fops = {
.owner = THIS_MODULE,
.open = proc_interfaces_open,
.read = seq_read,
.write = proc_interfaces_write,
.llseek = seq_lseek,
.release = single_release,
};
void cleanup_procfs(void)
{
if (proc_interface_file)
remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
if (proc_batman_dir)
#ifdef __NET_NET_NAMESPACE_H
remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
#else
remove_proc_entry(PROC_ROOT_DIR, proc_net);
#endif
}
int setup_procfs(void)
{
#ifdef __NET_NET_NAMESPACE_H
proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net);
#else
proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net);
#endif
if (!proc_batman_dir) {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR);
return -EFAULT;
}
proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES,
S_IWUSR | S_IRUGO,
proc_batman_dir);
if (proc_interface_file) {
proc_interface_file->proc_fops = &proc_interfaces_fops;
} else {
printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES);
cleanup_procfs();
return -EFAULT;
}
return 0;
}
/*
* Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
* 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/proc_fs.h>
#include <linux/seq_file.h>
#define PROC_ROOT_DIR "batman-adv"
#define PROC_FILE_INTERFACES "interfaces"
void cleanup_procfs(void);
int setup_procfs(void);
...@@ -387,7 +387,7 @@ void receive_bat_packet(struct ethhdr *ethhdr, ...@@ -387,7 +387,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
batman_packet->version, has_directlink_flag); batman_packet->version, has_directlink_flag);
list_for_each_entry_rcu(batman_if, &if_list, list) { list_for_each_entry_rcu(batman_if, &if_list, list) {
if (batman_if->if_active != IF_ACTIVE) if (batman_if->if_status != IF_ACTIVE)
continue; continue;
if (compare_orig(ethhdr->h_source, if (compare_orig(ethhdr->h_source,
...@@ -893,7 +893,7 @@ int recv_bcast_packet(struct sk_buff *skb) ...@@ -893,7 +893,7 @@ int recv_bcast_packet(struct sk_buff *skb)
if (is_my_mac(ethhdr->h_source)) if (is_my_mac(ethhdr->h_source))
return NET_RX_DROP; return NET_RX_DROP;
bcast_packet = (struct bcast_packet *) skb->data; bcast_packet = (struct bcast_packet *)skb->data;
/* ignore broadcasts originated by myself */ /* ignore broadcasts originated by myself */
if (is_my_mac(bcast_packet->orig)) if (is_my_mac(bcast_packet->orig))
......
...@@ -57,7 +57,7 @@ int send_skb_packet(struct sk_buff *skb, ...@@ -57,7 +57,7 @@ int send_skb_packet(struct sk_buff *skb,
{ {
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
if (batman_if->if_active != IF_ACTIVE) if (batman_if->if_status != IF_ACTIVE)
goto send_skb_err; goto send_skb_err;
if (unlikely(!batman_if->net_dev)) if (unlikely(!batman_if->net_dev))
...@@ -123,7 +123,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet, ...@@ -123,7 +123,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
int16_t buff_pos; int16_t buff_pos;
struct batman_packet *batman_packet; struct batman_packet *batman_packet;
if (batman_if->if_active != IF_ACTIVE) if (batman_if->if_status != IF_ACTIVE)
return; return;
packet_num = 0; packet_num = 0;
...@@ -182,7 +182,7 @@ static void send_packet(struct forw_packet *forw_packet) ...@@ -182,7 +182,7 @@ static void send_packet(struct forw_packet *forw_packet)
return; return;
} }
if (forw_packet->if_incoming->if_active != IF_ACTIVE) if (forw_packet->if_incoming->if_status != IF_ACTIVE)
return; return;
/* multihomed peer assumed */ /* multihomed peer assumed */
...@@ -243,7 +243,13 @@ void schedule_own_packet(struct batman_if *batman_if) ...@@ -243,7 +243,13 @@ void schedule_own_packet(struct batman_if *batman_if)
struct bat_priv *bat_priv = netdev_priv(soft_device); struct bat_priv *bat_priv = netdev_priv(soft_device);
unsigned long send_time; unsigned long send_time;
struct batman_packet *batman_packet; struct batman_packet *batman_packet;
int vis_server = atomic_read(&bat_priv->vis_mode); int vis_server;
if ((batman_if->if_status == IF_NOT_IN_USE) ||
(batman_if->if_status == IF_TO_BE_REMOVED))
return;
vis_server = atomic_read(&bat_priv->vis_mode);
/** /**
* the interface gets activated here to avoid race conditions between * the interface gets activated here to avoid race conditions between
...@@ -252,11 +258,12 @@ void schedule_own_packet(struct batman_if *batman_if) ...@@ -252,11 +258,12 @@ void schedule_own_packet(struct batman_if *batman_if)
* outdated packets (especially uninitialized mac addresses) in the * outdated packets (especially uninitialized mac addresses) in the
* packet queue * packet queue
*/ */
if (batman_if->if_active == IF_TO_BE_ACTIVATED) if (batman_if->if_status == IF_TO_BE_ACTIVATED)
batman_if->if_active = IF_ACTIVE; batman_if->if_status = IF_ACTIVE;
/* if local hna has changed and interface is a primary interface */ /* if local hna has changed and interface is a primary interface */
if ((atomic_read(&hna_local_changed)) && (batman_if->if_num == 0)) if ((atomic_read(&hna_local_changed)) &&
(batman_if == bat_priv->primary_if))
rebuild_batman_packet(batman_if); rebuild_batman_packet(batman_if);
/** /**
...@@ -374,13 +381,11 @@ void add_bcast_packet_to_list(struct sk_buff *skb) ...@@ -374,13 +381,11 @@ void add_bcast_packet_to_list(struct sk_buff *skb)
forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
if (!forw_packet) if (!forw_packet)
return; goto out;
skb = skb_copy(skb, GFP_ATOMIC); skb = skb_copy(skb, GFP_ATOMIC);
if (!skb) { if (!skb)
kfree(forw_packet); goto packet_free;
return;
}
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
...@@ -391,6 +396,12 @@ void add_bcast_packet_to_list(struct sk_buff *skb) ...@@ -391,6 +396,12 @@ void add_bcast_packet_to_list(struct sk_buff *skb)
forw_packet->num_packets = 0; forw_packet->num_packets = 0;
_add_bcast_packet_to_list(forw_packet, 1); _add_bcast_packet_to_list(forw_packet, 1);
return;
packet_free:
kfree(forw_packet);
out:
return;
} }
void send_outstanding_bcast_packet(struct work_struct *work) void send_outstanding_bcast_packet(struct work_struct *work)
...@@ -455,12 +466,16 @@ void send_outstanding_bat_packet(struct work_struct *work) ...@@ -455,12 +466,16 @@ void send_outstanding_bat_packet(struct work_struct *work)
forw_packet_free(forw_packet); forw_packet_free(forw_packet);
} }
void purge_outstanding_packets(void) void purge_outstanding_packets(struct batman_if *batman_if)
{ {
struct forw_packet *forw_packet; struct forw_packet *forw_packet;
struct hlist_node *tmp_node, *safe_tmp_node; struct hlist_node *tmp_node, *safe_tmp_node;
unsigned long flags; unsigned long flags;
if (batman_if)
bat_dbg(DBG_BATMAN, "purge_outstanding_packets(): %s\n",
batman_if->dev);
else
bat_dbg(DBG_BATMAN, "purge_outstanding_packets()\n"); bat_dbg(DBG_BATMAN, "purge_outstanding_packets()\n");
/* free bcast list */ /* free bcast list */
...@@ -468,6 +483,14 @@ void purge_outstanding_packets(void) ...@@ -468,6 +483,14 @@ void purge_outstanding_packets(void)
hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
&forw_bcast_list, list) { &forw_bcast_list, list) {
/**
* if purge_outstanding_packets() was called with an argmument
* we delete only packets belonging to the given interface
*/
if ((batman_if) &&
(forw_packet->if_incoming != batman_if))
continue;
spin_unlock_irqrestore(&forw_bcast_list_lock, flags); spin_unlock_irqrestore(&forw_bcast_list_lock, flags);
/** /**
...@@ -484,6 +507,14 @@ void purge_outstanding_packets(void) ...@@ -484,6 +507,14 @@ void purge_outstanding_packets(void)
hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
&forw_bat_list, list) { &forw_bat_list, list) {
/**
* if purge_outstanding_packets() was called with an argmument
* we delete only packets belonging to the given interface
*/
if ((batman_if) &&
(forw_packet->if_incoming != batman_if))
continue;
spin_unlock_irqrestore(&forw_bat_list_lock, flags); spin_unlock_irqrestore(&forw_bat_list_lock, flags);
/** /**
......
...@@ -36,4 +36,4 @@ void schedule_forward_packet(struct orig_node *orig_node, ...@@ -36,4 +36,4 @@ void schedule_forward_packet(struct orig_node *orig_node,
void add_bcast_packet_to_list(struct sk_buff *skb); void add_bcast_packet_to_list(struct sk_buff *skb);
void send_outstanding_bcast_packet(struct work_struct *work); void send_outstanding_bcast_packet(struct work_struct *work);
void send_outstanding_bat_packet(struct work_struct *work); void send_outstanding_bat_packet(struct work_struct *work);
void purge_outstanding_packets(void); void purge_outstanding_packets(struct batman_if *batman_if);
...@@ -251,7 +251,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -251,7 +251,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
/* net_dev won't be available when not active */ /* net_dev won't be available when not active */
if (orig_node->router->if_incoming->if_active != IF_ACTIVE) if (orig_node->router->if_incoming->if_status != IF_ACTIVE)
goto unlock; goto unlock;
/* don't lock while sending the packets ... we therefore /* don't lock while sending the packets ... we therefore
......
...@@ -159,16 +159,14 @@ int hna_local_fill_buffer(unsigned char *buff, int buff_len) ...@@ -159,16 +159,14 @@ int hna_local_fill_buffer(unsigned char *buff, int buff_len)
int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff, int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff,
size_t count, loff_t off) size_t count, loff_t off)
{ {
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hna_local_entry *hna_local_entry; struct hna_local_entry *hna_local_entry;
HASHIT(hashit); HASHIT(hashit);
int bytes_written = 0; int bytes_written = 0;
unsigned long flags; unsigned long flags;
size_t hdr_len; size_t hdr_len;
rcu_read_lock(); if (!bat_priv->primary_if) {
if (list_empty(&if_list)) {
rcu_read_unlock();
if (off == 0) if (off == 0)
return sprintf(buff, return sprintf(buff,
"BATMAN mesh %s disabled - please specify interfaces to enable it\n", "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
...@@ -176,7 +174,6 @@ int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff, ...@@ -176,7 +174,6 @@ int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff,
return 0; return 0;
} }
rcu_read_unlock();
hdr_len = sprintf(buff, hdr_len = sprintf(buff,
"Locally retrieved addresses (from %s) announced via HNA:\n", "Locally retrieved addresses (from %s) announced via HNA:\n",
...@@ -376,16 +373,14 @@ void hna_global_add_orig(struct orig_node *orig_node, ...@@ -376,16 +373,14 @@ void hna_global_add_orig(struct orig_node *orig_node,
int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff, int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff,
size_t count, loff_t off) size_t count, loff_t off)
{ {
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hna_global_entry *hna_global_entry; struct hna_global_entry *hna_global_entry;
HASHIT(hashit); HASHIT(hashit);
int bytes_written = 0; int bytes_written = 0;
unsigned long flags; unsigned long flags;
size_t hdr_len; size_t hdr_len;
rcu_read_lock(); if (!bat_priv->primary_if) {
if (list_empty(&if_list)) {
rcu_read_unlock();
if (off == 0) if (off == 0)
return sprintf(buff, return sprintf(buff,
"BATMAN mesh %s disabled - please specify interfaces to enable it\n", "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
...@@ -393,7 +388,6 @@ int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff, ...@@ -393,7 +388,6 @@ int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff,
return 0; return 0;
} }
rcu_read_unlock();
hdr_len = sprintf(buff, hdr_len = sprintf(buff,
"Globally announced HNAs received via the mesh %s (translation table):\n", "Globally announced HNAs received via the mesh %s (translation table):\n",
......
...@@ -36,12 +36,13 @@ struct batman_if { ...@@ -36,12 +36,13 @@ struct batman_if {
struct list_head list; struct list_head list;
int16_t if_num; int16_t if_num;
char *dev; char *dev;
char if_active; char if_status;
char addr_str[ETH_STR_LEN]; char addr_str[ETH_STR_LEN];
struct net_device *net_dev; struct net_device *net_dev;
atomic_t seqno; atomic_t seqno;
unsigned char *packet_buff; unsigned char *packet_buff;
int packet_len; int packet_len;
struct kobject *hardif_obj;
struct rcu_head rcu; struct rcu_head rcu;
}; };
...@@ -84,6 +85,8 @@ struct bat_priv { ...@@ -84,6 +85,8 @@ struct bat_priv {
atomic_t aggregation_enabled; atomic_t aggregation_enabled;
atomic_t vis_mode; atomic_t vis_mode;
atomic_t orig_interval; atomic_t orig_interval;
char num_ifaces;
struct batman_if *primary_if;
struct kobject *mesh_obj; struct kobject *mesh_obj;
}; };
......
...@@ -173,13 +173,10 @@ ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff, ...@@ -173,13 +173,10 @@ ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff,
unsigned long flags; unsigned long flags;
int vis_server = atomic_read(&bat_priv->vis_mode); int vis_server = atomic_read(&bat_priv->vis_mode);
rcu_read_lock(); if ((!bat_priv->primary_if) ||
if (list_empty(&if_list) || (vis_server == VIS_TYPE_CLIENT_UPDATE)) { (vis_server == VIS_TYPE_CLIENT_UPDATE))
rcu_read_unlock();
return 0; return 0;
}
rcu_read_unlock();
hdr_len = 0; hdr_len = 0;
spin_lock_irqsave(&vis_hash_lock, flags); spin_lock_irqsave(&vis_hash_lock, flags);
...@@ -498,7 +495,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) ...@@ -498,7 +495,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
if (orig_node->router != NULL if (orig_node->router != NULL
&& compare_orig(orig_node->router->addr, && compare_orig(orig_node->router->addr,
orig_node->orig) orig_node->orig)
&& (orig_node->router->if_incoming->if_active == && (orig_node->router->if_incoming->if_status ==
IF_ACTIVE) IF_ACTIVE)
&& orig_node->router->tq_avg > 0) { && orig_node->router->tq_avg > 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment