The following commit has been merged in the linux branch: commit e9e792fe425b833807c617d00b6443bda920c1c3 Merge: 5d13fd6477a22b77e955003f1023f1264fd67a83 187cb65b6b3bc9b7bdc8020ce4f5031f6600f15c Author: Sven Eckelmann sven.eckelmann@gmx.de Date: Sun Nov 21 22:58:03 2010 +0100
Merge remote branch 'origin/next' into linux
Conflicts: drivers/staging/batman-adv/CHANGELOG drivers/staging/batman-adv/Makefile.kbuild drivers/staging/batman-adv/README drivers/staging/batman-adv/bat_printk.c drivers/staging/batman-adv/compat.h drivers/staging/batman-adv/hard-interface.c drivers/staging/batman-adv/icmp_socket.c drivers/staging/batman-adv/originator.c drivers/staging/batman-adv/routing.c drivers/staging/batman-adv/send.c drivers/staging/batman-adv/soft-interface.c drivers/staging/batman-adv/translation-table.c drivers/staging/batman-adv/vis.c
diff --combined drivers/staging/batman-adv/Makefile index 7892428,0000000..d936aec mode 100644,000000..100644 --- a/drivers/staging/batman-adv/Makefile +++ b/drivers/staging/batman-adv/Makefile @@@ -1,22 -1,0 +1,39 @@@ +# +# 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 +# + +obj-$(CONFIG_BATMAN_ADV) += batman-adv.o - batman-adv-y := 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 unicast.o ++batman-adv-y += aggregation.o ++batman-adv-y += bat_debugfs.o ++batman-adv-y += bat_sysfs.o ++batman-adv-y += bitarray.o ++batman-adv-y += gateway_client.o ++batman-adv-y += gateway_common.o ++batman-adv-y += hard-interface.o ++batman-adv-y += hash.o ++batman-adv-y += icmp_socket.o ++batman-adv-y += main.o ++batman-adv-y += originator.o ++batman-adv-y += ring_buffer.o ++batman-adv-y += routing.o ++batman-adv-y += send.o ++batman-adv-y += soft-interface.o ++batman-adv-y += translation-table.o ++batman-adv-y += unicast.o ++batman-adv-y += vis.o diff --combined drivers/staging/batman-adv/README index 7c878bb,0000000..77f0cdd mode 100644,000000..100644 --- a/drivers/staging/batman-adv/README +++ b/drivers/staging/batman-adv/README @@@ -1,240 -1,0 +1,240 @@@ - [state: 04-09-2010] ++[state: 21-11-2010] + +BATMAN-ADV +---------- + +Batman advanced is a new approach to wireless networking which +does no longer operate on the IP basis. Unlike the batman daemon, +which exchanges information using UDP packets and sets routing +tables, batman-advanced operates on ISO/OSI Layer 2 only and uses +and routes (or better: bridges) Ethernet Frames. It emulates a +virtual network switch of all nodes participating. Therefore all +nodes appear to be link local, thus all higher operating proto- +cols won't be affected by any changes within the network. You can +run almost any protocol above batman advanced, prominent examples +are: IPv4, IPv6, DHCP, IPX. + +Batman advanced was implemented as a Linux kernel driver to re- +duce the overhead to a minimum. It does not depend on any (other) +network driver, and can be used on wifi as well as ethernet lan, +vpn, etc ... (anything with ethernet-style layer 2). + +CONFIGURATION +------------- + +Load the batman-adv module into your kernel: + +# insmod batman-adv.ko + +The module is now waiting for activation. You must add some in- +terfaces on which batman can operate. After loading the module +batman advanced will scan your systems interfaces to search for +compatible interfaces. Once found, it will create subfolders in +the /sys directories of each supported interface, e.g. + +# ls /sys/class/net/eth0/batman_adv/ +# iface_status mesh_iface + +If an interface does not have the "batman_adv" subfolder it prob- +ably is not supported. Not supported interfaces are: loopback, +non-ethernet and batman's own interfaces. + +Note: After the module was loaded it will continuously watch for +new interfaces to verify the compatibility. There is no need to +reload the module if you plug your USB wifi adapter into your ma- +chine after batman advanced was initially loaded. + +To activate a given interface simply write "bat0" into its +"mesh_iface" file inside the batman_adv subfolder: + +# echo bat0 > /sys/class/net/eth0/batman_adv/mesh_iface + +Repeat this step for all interfaces you wish to add. Now batman +starts using/broadcasting on this/these interface(s). + +By reading the "iface_status" file you can check its status: + +# cat /sys/class/net/eth0/batman_adv/iface_status +# active + +To deactivate an interface you have to write "none" into its +"mesh_iface" file: + +# echo none > /sys/class/net/eth0/batman_adv/mesh_iface + + +All mesh wide settings can be found in batman's own interface +folder: + +# ls /sys/class/net/bat0/mesh/ - # aggregated_ogms bonding orig_interval vis_mode ++# aggregated_ogms bonding fragmentation orig_interval ++# vis_mode + + +There is a special folder for debugging informations: + +# ls /sys/kernel/debug/batman_adv/bat0/ +# originators socket transtable_global transtable_local +# vis_data + + +Some of the files contain all sort of status information regard- +ing the mesh network. For example, you can view the table of +originators (mesh participants) with: + +# cat /sys/kernel/debug/batman_adv/bat0/originators + +Other files allow to change batman's behaviour to better fit your +requirements. For instance, you can check the current originator +interval (value in milliseconds which determines how often batman +sends its broadcast packets): + +# cat /sys/class/net/bat0/mesh/orig_interval +# 1000 + +and also change its value: + +# echo 3000 > /sys/class/net/bat0/mesh/orig_interval + +In very mobile scenarios, you might want to adjust the originator +interval to a lower value. This will make the mesh more respon- +sive to topology changes, but will also increase the overhead. + + +USAGE +----- + +To make use of your newly created mesh, batman advanced provides +a new interface "bat0" which you should use from this point on. +All interfaces added to batman advanced are not relevant any +longer because batman handles them for you. Basically, one "hands +over" the data by using the batman interface and batman will make +sure it reaches its destination. + +The "bat0" interface can be used like any other regular inter- +face. It needs an IP address which can be either statically con- +figured or dynamically (by using DHCP or similar services): + +# NodeA: ifconfig bat0 192.168.0.1 +# NodeB: ifconfig bat0 192.168.0.2 +# NodeB: ping 192.168.0.1 + +Note: In order to avoid problems remove all IP addresses previ- +ously assigned to interfaces now used by batman advanced, e.g. + +# ifconfig eth0 0.0.0.0 + + +VISUALIZATION +------------- + +If you want topology visualization, at least one mesh node must +be configured as VIS-server: + +# echo "server" > /sys/class/net/bat0/mesh/vis_mode + +Each node is either configured as "server" or as "client" (de- +fault: "client"). Clients send their topology data to the server +next to them, and server synchronize with other servers. If there +is no server configured (default) within the mesh, no topology +information will be transmitted. With these "synchronizing +servers", there can be 1 or more vis servers sharing the same (or +at least very similar) data. + +When configured as server, you can get a topology snapshot of +your mesh: + +# cat /sys/kernel/debug/batman_adv/bat0/vis_data + +This raw output is intended to be easily parsable and convertable +with other tools. Have a look at the batctl README if you want a +vis output in dot or json format for instance and how those out- +puts could then be visualised in an image. + +The raw format consists of comma separated values per entry where +each entry is giving information about a certain source inter- +face. Each entry can/has to have the following values: +-> "mac" - mac address of an originator's source interface + (each line begins with it) +-> "TQ mac value" - src mac's link quality towards mac address + of a neighbor originator's interface which + is being used for routing +-> "HNA mac" - HNA announced by source mac +-> "PRIMARY" - this is a primary interface +-> "SEC mac" - secondary mac address of source + (requires preceding PRIMARY) + +The TQ value has a range from 4 to 255 with 255 being the best. +The HNA entries are showing which hosts are connected to the mesh +via bat0 or being bridged into the mesh network. The PRIMARY/SEC +values are only applied on primary interfaces + + +LOGGING/DEBUGGING +----------------- + +All error messages, warnings and information messages are sent to +the kernel log. Depending on your operating system distribution +this can be read in one of a number of ways. Try using the com- +mands: dmesg, logread, or looking in the files /var/log/kern.log +or /var/log/syslog. All batman-adv messages are prefixed with +"batman-adv:" So to see just these messages try + +# dmesg | grep batman-adv + +When investigating problems with your mesh network it is some- +times necessary to see more detail debug messages. This must be +enabled when compiling the batman-adv module. When building bat- +man-adv as part of kernel, use "make menuconfig" and enable the +option "B.A.T.M.A.N. debugging". + +Those additional debug messages can be accessed using a special +file in debugfs + +# cat /sys/kernel/debug/batman_adv/bat0/log + +The additional debug output is by default disabled. It can be en- +abled during run time. Following log_levels are defined: + +0 - All debug output disabled +1 - Enable messages related to routing / flooding / broadcasting +2 - Enable route or hna added / changed / deleted +3 - Enable all messages + +The debug output can be changed at runtime using the file +/sys/class/net/bat0/mesh/log_level. e.g. + +# echo 2 > /sys/class/net/bat0/mesh/log_level + +will enable debug messages for when routes or HNAs change. + + +BATCTL +------ + +As batman advanced operates on layer 2 all hosts participating in +the virtual switch are completely transparent for all protocols +above layer 2. Therefore the common diagnosis tools do not work +as expected. To overcome these problems batctl was created. At +the moment the batctl contains ping, traceroute, tcpdump and +interfaces to the kernel module settings. + +For more information, please see the manpage (man batctl). + +batctl is available on http://www.open-mesh.org/ + + +CONTACT +------- + +Please send us comments, experiences, questions, anything :) + +IRC: #batman on irc.freenode.org +Mailing-list: b.a.t.m.a.n@b.a.t.m.a.n@lists.open-mesh.org + (optional subscription at + https://lists.open-mesh.org/mm/listinfo/b.a.t.m.a.n) + +You can also contact the Authors: + +Marek Lindner lindner_marek@yahoo.de +Simon Wunderlich siwu@hrz.tu-chemnitz.de - diff --combined drivers/staging/batman-adv/TODO index 7967ffa,0000000..ba69ba3 mode 100644,000000..100644 --- a/drivers/staging/batman-adv/TODO +++ b/drivers/staging/batman-adv/TODO @@@ -1,14 -1,0 +1,10 @@@ - * remove own list functionality from hash - * use hlist_head, hlist_node in hash - * don't use callbacks for compare+choose in hash - * think about more efficient ways instead of abstraction of hash + * Request a new review + * Process the comments from the review + * Move into mainline proper + +Please send all patches to: + Marek Lindner lindner_marek@yahoo.de + Simon Wunderlich siwu@hrz.tu-chemnitz.de + Sven Eckelmann sven.eckelmann@gmx.de + b.a.t.m.a.n@lists.open-mesh.org + Greg Kroah-Hartman gregkh@suse.de diff --combined drivers/staging/batman-adv/aggregation.c index 08624d4,0c92e3b..0c92e3b --- a/drivers/staging/batman-adv/aggregation.c +++ b/drivers/staging/batman-adv/aggregation.c @@@ -104,7 -104,6 +104,6 @@@ static void new_aggregated_packet(unsig { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct forw_packet *forw_packet_aggr; - unsigned long flags; unsigned char *skb_buff;
/* own packet should always be scheduled */ @@@ -123,7 -122,7 +122,7 @@@ return; }
- if ((atomic_read(&bat_priv->aggregation_enabled)) && + if ((atomic_read(&bat_priv->aggregated_ogms)) && (packet_len < MAX_AGGREGATION_BYTES)) forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES + sizeof(struct ethhdr)); @@@ -156,9 -155,9 +155,9 @@@ forw_packet_aggr->direct_link_flags |= 1;
/* add new packet to packet list */ - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list); - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock);
/* start timer for this packet */ INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, @@@ -201,12 -200,11 +200,11 @@@ void add_bat_packet_to_list(struct bat_ struct batman_packet *batman_packet = (struct batman_packet *)packet_buff; bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; - unsigned long flags;
/* find position for the packet in the forward queue */ - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); /* own packets are not to be aggregated */ - if ((atomic_read(&bat_priv->aggregation_enabled)) && (!own_packet)) { + if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { hlist_for_each_entry(forw_packet_pos, tmp_node, &bat_priv->forw_bat_list, list) { if (can_aggregate_with(batman_packet, @@@ -225,7 -223,7 +223,7 @@@ * suitable aggregation packet found */ if (forw_packet_aggr == NULL) { /* the following section can run without the lock */ - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock);
/** * if we could not aggregate this packet with one of the others @@@ -233,7 -231,7 +231,7 @@@ * later on */ if ((!own_packet) && - (atomic_read(&bat_priv->aggregation_enabled))) + (atomic_read(&bat_priv->aggregated_ogms))) send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
new_aggregated_packet(packet_buff, packet_len, @@@ -243,7 -241,7 +241,7 @@@ aggregate(forw_packet_aggr, packet_buff, packet_len, direct_link); - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); } }
diff --combined drivers/staging/batman-adv/bat_debugfs.c index 57f84a9,0ae81d0..0ae81d0 --- a/drivers/staging/batman-adv/bat_debugfs.c +++ b/drivers/staging/batman-adv/bat_debugfs.c @@@ -27,6 -27,9 +27,9 @@@ #include "translation-table.h" #include "originator.h" #include "hard-interface.h" + #include "gateway_common.h" + #include "gateway_client.h" + #include "soft-interface.h" #include "vis.h" #include "icmp_socket.h"
@@@ -53,12 -56,11 +56,11 @@@ static int fdebug_log(struct debug_log va_list args; static char debug_log_buf[256]; char *p; - unsigned long flags;
if (!debug_log) return 0;
- spin_lock_irqsave(&debug_log->lock, flags); + spin_lock_bh(&debug_log->lock); va_start(args, fmt); printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args); @@@ -67,7 -69,7 +69,7 @@@ for (p = debug_log_buf; *p != 0; p++) emit_log_char(debug_log, *p);
- spin_unlock_irqrestore(&debug_log->lock, flags); + spin_unlock_bh(&debug_log->lock);
wake_up(&debug_log->queue_wait);
@@@ -109,7 -111,6 +111,6 @@@ static ssize_t log_read(struct file *fi struct debug_log *debug_log = bat_priv->debug_log; int error, i = 0; char c; - unsigned long flags;
if ((file->f_flags & O_NONBLOCK) && !(debug_log->log_end - debug_log->log_start)) @@@ -130,7 -131,7 +131,7 @@@ if (error) return error;
- spin_lock_irqsave(&debug_log->lock, flags); + spin_lock_bh(&debug_log->lock);
while ((!error) && (i < count) && (debug_log->log_start != debug_log->log_end)) { @@@ -138,18 -139,18 +139,18 @@@
debug_log->log_start++;
- spin_unlock_irqrestore(&debug_log->lock, flags); + spin_unlock_bh(&debug_log->lock);
error = __put_user(c, buf);
- spin_lock_irqsave(&debug_log->lock, flags); + spin_lock_bh(&debug_log->lock);
buf++; i++;
}
- spin_unlock_irqrestore(&debug_log->lock, flags); + spin_unlock_bh(&debug_log->lock);
if (!error) return i; @@@ -227,6 -228,18 +228,18 @@@ static int originators_open(struct inod return single_open(file, orig_seq_print_text, net_dev); }
+ static int gateways_open(struct inode *inode, struct file *file) + { + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, gw_client_seq_print_text, net_dev); + } + + static int softif_neigh_open(struct inode *inode, struct file *file) + { + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, softif_neigh_seq_print_text, net_dev); + } + static int transtable_global_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; @@@ -263,12 -276,16 +276,16 @@@ struct bat_debuginfo bat_debuginfo_##_n };
static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); + static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); + static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
static struct bat_debuginfo *mesh_debuginfos[] = { &bat_debuginfo_originators, + &bat_debuginfo_gateways, + &bat_debuginfo_softif_neigh, &bat_debuginfo_transtable_global, &bat_debuginfo_transtable_local, &bat_debuginfo_vis_data, diff --combined drivers/staging/batman-adv/bat_sysfs.c index bc17fb8,cd7bb51..cd7bb51 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@@ -24,10 -24,15 +24,15 @@@ #include "translation-table.h" #include "originator.h" #include "hard-interface.h" + #include "gateway_common.h" + #include "gateway_client.h" #include "vis.h"
- #define to_dev(obj) container_of(obj, struct device, kobj) + #define to_dev(obj) container_of(obj, struct device, kobj) + #define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent)) + #define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj))
+ /* Use this, if you have customized show and store functions */ #define BAT_ATTR(_name, _mode, _show, _store) \ struct bat_attribute bat_attr_##_name = { \ .attr = {.name = __stringify(_name), \ @@@ -36,159 -41,168 +41,168 @@@ .store = _store, \ };
- static ssize_t show_aggr_ogms(struct kobject *kobj, struct attribute *attr, - char *buff) - { - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int aggr_status = atomic_read(&bat_priv->aggregation_enabled); + #define BAT_ATTR_STORE_BOOL(_name, _post_func) \ + ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff, size_t count) \ + { \ + struct net_device *net_dev = kobj_to_netdev(kobj); \ + struct bat_priv *bat_priv = netdev_priv(net_dev); \ + return __store_bool_attr(buff, count, _post_func, attr, \ + &bat_priv->_name, net_dev); \ + }
- return sprintf(buff, "%s\n", - aggr_status == 0 ? "disabled" : "enabled"); + #define BAT_ATTR_SHOW_BOOL(_name) \ + ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff) \ + { \ + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ + return sprintf(buff, "%s\n", \ + atomic_read(&bat_priv->_name) == 0 ? \ + "disabled" : "enabled"); \ + } \ + + /* Use this, if you are going to turn a [name] in bat_priv on or off */ + #define BAT_ATTR_BOOL(_name, _mode, _post_func) \ + static BAT_ATTR_STORE_BOOL(_name, _post_func) \ + static BAT_ATTR_SHOW_BOOL(_name) \ + static BAT_ATTR(_name, _mode, show_##_name, store_##_name) + + + #define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ + ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff, size_t count) \ + { \ + struct net_device *net_dev = kobj_to_netdev(kobj); \ + struct bat_priv *bat_priv = netdev_priv(net_dev); \ + return __store_uint_attr(buff, count, _min, _max, _post_func, \ + attr, &bat_priv->_name, net_dev); \ }
- static ssize_t store_aggr_ogms(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) + #define BAT_ATTR_SHOW_UINT(_name) \ + ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff) \ + { \ + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ + return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ + } \ + + /* Use this, if you are going to set [name] in bat_priv to unsigned integer + * values only */ + #define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \ + static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ + static BAT_ATTR_SHOW_UINT(_name) \ + static BAT_ATTR(_name, _mode, show_##_name, store_##_name) + + + static int store_bool_attr(char *buff, size_t count, + struct net_device *net_dev, + char *attr_name, atomic_t *attr) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - struct bat_priv *bat_priv = netdev_priv(net_dev); - int aggr_tmp = -1; + int enabled = -1;
- if (((count == 2) && (buff[0] == '1')) || - (strncmp(buff, "enable", 6) == 0)) - aggr_tmp = 1; + if (buff[count - 1] == '\n') + buff[count - 1] = '\0';
- if (((count == 2) && (buff[0] == '0')) || - (strncmp(buff, "disable", 7) == 0)) - aggr_tmp = 0; + if ((strncmp(buff, "1", 2) == 0) || + (strncmp(buff, "enable", 7) == 0) || + (strncmp(buff, "enabled", 8) == 0)) + enabled = 1;
- if (aggr_tmp < 0) { - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; + if ((strncmp(buff, "0", 2) == 0) || + (strncmp(buff, "disable", 8) == 0) || + (strncmp(buff, "disabled", 9) == 0)) + enabled = 0;
+ if (enabled < 0) { bat_info(net_dev, - "Invalid parameter for 'aggregate OGM' setting" - "received: %s\n", buff); + "%s: Invalid parameter received: %s\n", + attr_name, buff); return -EINVAL; }
- if (atomic_read(&bat_priv->aggregation_enabled) == aggr_tmp) + if (atomic_read(attr) == enabled) return count;
- bat_info(net_dev, "Changing aggregation from: %s to: %s\n", - atomic_read(&bat_priv->aggregation_enabled) == 1 ? - "enabled" : "disabled", aggr_tmp == 1 ? "enabled" : - "disabled"); + bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, + atomic_read(attr) == 1 ? "enabled" : "disabled", + enabled == 1 ? "enabled" : "disabled");
- atomic_set(&bat_priv->aggregation_enabled, (unsigned)aggr_tmp); + atomic_set(attr, (unsigned)enabled); return count; }
- static ssize_t show_bond(struct kobject *kobj, struct attribute *attr, - char *buff) + static inline ssize_t __store_bool_attr(char *buff, size_t count, + void (*post_func)(struct net_device *), + struct attribute *attr, + atomic_t *attr_store, struct net_device *net_dev) { - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int bond_status = atomic_read(&bat_priv->bonding_enabled); + int ret;
- return sprintf(buff, "%s\n", - bond_status == 0 ? "disabled" : "enabled"); + ret = store_bool_attr(buff, count, net_dev, (char *)attr->name, + attr_store); + if (post_func && ret) + post_func(net_dev); + + return ret; }
- static ssize_t store_bond(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) + static int store_uint_attr(char *buff, size_t count, + struct net_device *net_dev, char *attr_name, + unsigned int min, unsigned int max, atomic_t *attr) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - struct bat_priv *bat_priv = netdev_priv(net_dev); - int bonding_enabled_tmp = -1; - - if (((count == 2) && (buff[0] == '1')) || - (strncmp(buff, "enable", 6) == 0)) - bonding_enabled_tmp = 1; + unsigned long uint_val; + int ret;
- if (((count == 2) && (buff[0] == '0')) || - (strncmp(buff, "disable", 7) == 0)) - bonding_enabled_tmp = 0; + ret = strict_strtoul(buff, 10, &uint_val); + if (ret) { + bat_info(net_dev, + "%s: Invalid parameter received: %s\n", + attr_name, buff); + return -EINVAL; + }
- if (bonding_enabled_tmp < 0) { - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; + if (uint_val < min) { + bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", + attr_name, uint_val, min); + return -EINVAL; + }
- bat_err(net_dev, - "Invalid parameter for 'bonding' setting received: " - "%s\n", buff); + if (uint_val > max) { + bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", + attr_name, uint_val, max); return -EINVAL; }
- if (atomic_read(&bat_priv->bonding_enabled) == bonding_enabled_tmp) + if (atomic_read(attr) == uint_val) return count;
- bat_info(net_dev, "Changing bonding from: %s to: %s\n", - atomic_read(&bat_priv->bonding_enabled) == 1 ? - "enabled" : "disabled", - bonding_enabled_tmp == 1 ? "enabled" : "disabled"); + bat_info(net_dev, "%s: Changing from: %i to: %lu\n", + attr_name, atomic_read(attr), uint_val);
- atomic_set(&bat_priv->bonding_enabled, (unsigned)bonding_enabled_tmp); + atomic_set(attr, uint_val); return count; }
- static ssize_t show_frag(struct kobject *kobj, struct attribute *attr, - char *buff) - { - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int frag_status = atomic_read(&bat_priv->frag_enabled); - - return sprintf(buff, "%s\n", - frag_status == 0 ? "disabled" : "enabled"); - } - - static ssize_t store_frag(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) + static inline ssize_t __store_uint_attr(char *buff, size_t count, + int min, int max, + void (*post_func)(struct net_device *), + struct attribute *attr, + atomic_t *attr_store, struct net_device *net_dev) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - struct bat_priv *bat_priv = netdev_priv(net_dev); - int frag_enabled_tmp = -1; - - if (((count == 2) && (buff[0] == '1')) || - (strncmp(buff, "enable", 6) == 0)) - frag_enabled_tmp = 1; - - if (((count == 2) && (buff[0] == '0')) || - (strncmp(buff, "disable", 7) == 0)) - frag_enabled_tmp = 0; - - if (frag_enabled_tmp < 0) { - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; - - bat_err(net_dev, - "Invalid parameter for 'fragmentation' setting on mesh" - "received: %s\n", buff); - return -EINVAL; - } - - if (atomic_read(&bat_priv->frag_enabled) == frag_enabled_tmp) - return count; + int ret;
- bat_info(net_dev, "Changing fragmentation from: %s to: %s\n", - atomic_read(&bat_priv->frag_enabled) == 1 ? - "enabled" : "disabled", - frag_enabled_tmp == 1 ? "enabled" : "disabled"); + ret = store_uint_attr(buff, count, net_dev, (char *)attr->name, + min, max, attr_store); + if (post_func && ret) + post_func(net_dev);
- atomic_set(&bat_priv->frag_enabled, (unsigned)frag_enabled_tmp); - update_min_mtu(net_dev); - return count; + return ret; }
static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, char *buff) { - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); int vis_mode = atomic_read(&bat_priv->vis_mode);
return sprintf(buff, "%s\n", @@@ -199,8 -213,7 +213,7 @@@ static ssize_t store_vis_mode(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 net_device *net_dev = kobj_to_netdev(kobj); struct bat_priv *bat_priv = netdev_priv(net_dev); unsigned long val; int ret, vis_mode_tmp = -1; @@@ -238,103 -251,124 +251,124 @@@ return count; }
- static ssize_t show_orig_interval(struct kobject *kobj, struct attribute *attr, - char *buff) + static void post_gw_deselect(struct net_device *net_dev) { - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); + struct bat_priv *bat_priv = netdev_priv(net_dev); + gw_deselect(bat_priv); + } + + static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr, + char *buff) + { + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); + int bytes_written; + + switch (atomic_read(&bat_priv->gw_mode)) { + case GW_MODE_CLIENT: + bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME); + break; + case GW_MODE_SERVER: + bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME); + break; + default: + bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME); + break; + }
- return sprintf(buff, "%i\n", - atomic_read(&bat_priv->orig_interval)); + return bytes_written; }
- static ssize_t store_orig_interval(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) + static ssize_t store_gw_mode(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 net_device *net_dev = kobj_to_netdev(kobj); struct bat_priv *bat_priv = netdev_priv(net_dev); - unsigned long orig_interval_tmp; - int ret; + char *curr_gw_mode_str; + int gw_mode_tmp = -1;
- ret = strict_strtoul(buff, 10, &orig_interval_tmp); - if (ret) { - bat_info(net_dev, "Invalid parameter for 'orig_interval' " - "setting received: %s\n", buff); - return -EINVAL; - } + if (buff[count - 1] == '\n') + buff[count - 1] = '\0'; + + if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) + gw_mode_tmp = GW_MODE_OFF; + + if (strncmp(buff, GW_MODE_CLIENT_NAME, + strlen(GW_MODE_CLIENT_NAME)) == 0) + gw_mode_tmp = GW_MODE_CLIENT;
- if (orig_interval_tmp < JITTER * 2) { - bat_info(net_dev, "New originator interval too small: %li " - "(min: %i)\n", orig_interval_tmp, JITTER * 2); + if (strncmp(buff, GW_MODE_SERVER_NAME, + strlen(GW_MODE_SERVER_NAME)) == 0) + gw_mode_tmp = GW_MODE_SERVER; + + if (gw_mode_tmp < 0) { + bat_info(net_dev, + "Invalid parameter for 'gw mode' setting received: " + "%s\n", buff); return -EINVAL; }
- if (atomic_read(&bat_priv->orig_interval) == orig_interval_tmp) + if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) return count;
- bat_info(net_dev, "Changing originator interval from: %i to: %li\n", - atomic_read(&bat_priv->orig_interval), - orig_interval_tmp); + switch (atomic_read(&bat_priv->gw_mode)) { + case GW_MODE_CLIENT: + curr_gw_mode_str = GW_MODE_CLIENT_NAME; + break; + case GW_MODE_SERVER: + curr_gw_mode_str = GW_MODE_SERVER_NAME; + break; + default: + curr_gw_mode_str = GW_MODE_OFF_NAME; + break; + } + + bat_info(net_dev, "Changing gw mode from: %s to: %s\n", + curr_gw_mode_str, buff);
- atomic_set(&bat_priv->orig_interval, orig_interval_tmp); + gw_deselect(bat_priv); + atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); return count; }
- #ifdef CONFIG_BATMAN_ADV_DEBUG - static ssize_t show_log_level(struct kobject *kobj, struct attribute *attr, - char *buff) + static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr, + char *buff) { - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int log_level = atomic_read(&bat_priv->log_level); - - return sprintf(buff, "%d\n", log_level); + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); + int down, up; + int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); + + gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); + return sprintf(buff, "%i%s/%i%s\n", + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); }
- static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) + static ssize_t store_gw_bwidth(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 bat_priv *bat_priv = netdev_priv(net_dev); - unsigned long log_level_tmp; - int ret; + struct net_device *net_dev = kobj_to_netdev(kobj);
- ret = strict_strtoul(buff, 10, &log_level_tmp); - if (ret) { - bat_info(net_dev, "Invalid parameter for 'log_level' " - "setting received: %s\n", buff); - return -EINVAL; - } - - if (log_level_tmp > 3) { - bat_info(net_dev, "New log level too big: %li " - "(max: %i)\n", log_level_tmp, 3); - return -EINVAL; - } - - if (atomic_read(&bat_priv->log_level) == log_level_tmp) - return count; - - bat_info(net_dev, "Changing log level from: %i to: %li\n", - atomic_read(&bat_priv->log_level), - log_level_tmp); + if (buff[count - 1] == '\n') + buff[count - 1] = '\0';
- atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp); - return count; + return gw_bandwidth_set(net_dev, buff, count); } - #endif
- static BAT_ATTR(aggregated_ogms, S_IRUGO | S_IWUSR, - show_aggr_ogms, store_aggr_ogms); - static BAT_ATTR(bonding, S_IRUGO | S_IWUSR, show_bond, store_bond); - static BAT_ATTR(fragmentation, S_IRUGO | S_IWUSR, show_frag, store_frag); + BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); + BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); + BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); - static BAT_ATTR(orig_interval, S_IRUGO | S_IWUSR, - show_orig_interval, store_orig_interval); + static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); + BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); + BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); + BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE, + post_gw_deselect); + static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, + store_gw_bwidth); #ifdef CONFIG_BATMAN_ADV_DEBUG - static BAT_ATTR(log_level, S_IRUGO | S_IWUSR, show_log_level, store_log_level); + BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); #endif
static struct bat_attribute *mesh_attrs[] = { @@@ -342,7 -376,11 +376,11 @@@ &bat_attr_bonding, &bat_attr_fragmentation, &bat_attr_vis_mode, + &bat_attr_gw_mode, &bat_attr_orig_interval, + &bat_attr_hop_penalty, + &bat_attr_gw_sel_class, + &bat_attr_gw_bandwidth, #ifdef CONFIG_BATMAN_ADV_DEBUG &bat_attr_log_level, #endif @@@ -402,8 -440,7 +440,7 @@@ void sysfs_del_meshif(struct net_devic 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 net_device *net_dev = kobj_to_netdev(kobj); struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); ssize_t length;
@@@ -413,7 -450,7 +450,7 @@@ length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ? "none" : batman_if->soft_iface->name);
- hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref);
return length; } @@@ -421,8 -458,7 +458,7 @@@ 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 net_device *net_dev = kobj_to_netdev(kobj); struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); int status_tmp = -1; int ret; @@@ -436,7 -472,7 +472,7 @@@ if (strlen(buff) >= IFNAMSIZ) { pr_err("Invalid parameter for 'mesh_iface' setting received: " "interface name too long '%s'\n", buff); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return -EINVAL; }
@@@ -447,7 -483,7 +483,7 @@@
if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) && (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) { - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return count; }
@@@ -455,7 -491,7 +491,7 @@@ rtnl_lock(); hardif_disable_interface(batman_if); rtnl_unlock(); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return count; }
@@@ -467,7 -503,7 +503,7 @@@ }
ret = hardif_enable_interface(batman_if, buff); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref);
return ret; } @@@ -475,8 -511,7 +511,7 @@@ 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 net_device *net_dev = kobj_to_netdev(kobj); struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); ssize_t length;
@@@ -502,7 -537,7 +537,7 @@@ break; }
- hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref);
return length; } diff --combined drivers/staging/batman-adv/gateway_client.c index 0000000,0065ffb..0065ffb mode 000000,100644..100644 --- a/drivers/staging/batman-adv/gateway_client.c +++ b/drivers/staging/batman-adv/gateway_client.c @@@ -1,0 -1,477 +1,477 @@@ + /* + * Copyright (C) 2009-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 "main.h" + #include "gateway_client.h" + #include "gateway_common.h" + #include "hard-interface.h" + #include <linux/ip.h> + #include <linux/ipv6.h> + #include <linux/udp.h> + #include <linux/if_vlan.h> + + static void gw_node_free_ref(struct kref *refcount) + { + struct gw_node *gw_node; + + gw_node = container_of(refcount, struct gw_node, refcount); + kfree(gw_node); + } + + static void gw_node_free_rcu(struct rcu_head *rcu) + { + struct gw_node *gw_node; + + gw_node = container_of(rcu, struct gw_node, rcu); + kref_put(&gw_node->refcount, gw_node_free_ref); + } + + void *gw_get_selected(struct bat_priv *bat_priv) + { + struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; + + if (!curr_gateway_tmp) + return NULL; + + return curr_gateway_tmp->orig_node; + } + + void gw_deselect(struct bat_priv *bat_priv) + { + struct gw_node *gw_node = bat_priv->curr_gw; + + bat_priv->curr_gw = NULL; + + if (gw_node) + kref_put(&gw_node->refcount, gw_node_free_ref); + } + + static struct gw_node *gw_select(struct bat_priv *bat_priv, + struct gw_node *new_gw_node) + { + struct gw_node *curr_gw_node = bat_priv->curr_gw; + + if (new_gw_node) + kref_get(&new_gw_node->refcount); + + bat_priv->curr_gw = new_gw_node; + return curr_gw_node; + } + + void gw_election(struct bat_priv *bat_priv) + { + struct hlist_node *node; + struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = NULL; + uint8_t max_tq = 0; + uint32_t max_gw_factor = 0, tmp_gw_factor = 0; + int down, up; + + /** + * The batman daemon checks here if we already passed a full originator + * cycle in order to make sure we don't choose the first gateway we + * hear about. This check is based on the daemon's uptime which we + * don't have. + **/ + if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) + return; + + if (bat_priv->curr_gw) + return; + + rcu_read_lock(); + if (hlist_empty(&bat_priv->gw_list)) { + rcu_read_unlock(); + + if (bat_priv->curr_gw) { + bat_dbg(DBG_BATMAN, bat_priv, + "Removing selected gateway - " + "no gateway in range\n"); + gw_deselect(bat_priv); + } + + return; + } + + hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { + if (!gw_node->orig_node->router) + continue; + + if (gw_node->deleted) + continue; + + switch (atomic_read(&bat_priv->gw_sel_class)) { + case 1: /* fast connection */ + gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, + &down, &up); + + tmp_gw_factor = (gw_node->orig_node->router->tq_avg * + gw_node->orig_node->router->tq_avg * + down * 100 * 100) / + (TQ_LOCAL_WINDOW_SIZE * + TQ_LOCAL_WINDOW_SIZE * 64); + + if ((tmp_gw_factor > max_gw_factor) || + ((tmp_gw_factor == max_gw_factor) && + (gw_node->orig_node->router->tq_avg > max_tq))) + curr_gw_tmp = gw_node; + break; + + default: /** + * 2: stable connection (use best statistic) + * 3: fast-switch (use best statistic but change as + * soon as a better gateway appears) + * XX: late-switch (use best statistic but change as + * soon as a better gateway appears which has + * $routing_class more tq points) + **/ + if (gw_node->orig_node->router->tq_avg > max_tq) + curr_gw_tmp = gw_node; + break; + } + + if (gw_node->orig_node->router->tq_avg > max_tq) + max_tq = gw_node->orig_node->router->tq_avg; + + if (tmp_gw_factor > max_gw_factor) + max_gw_factor = tmp_gw_factor; + } + + if (bat_priv->curr_gw != curr_gw_tmp) { + if ((bat_priv->curr_gw) && (!curr_gw_tmp)) + bat_dbg(DBG_BATMAN, bat_priv, + "Removing selected gateway - " + "no gateway in range\n"); + else if ((!bat_priv->curr_gw) && (curr_gw_tmp)) + bat_dbg(DBG_BATMAN, bat_priv, + "Adding route to gateway %pM " + "(gw_flags: %i, tq: %i)\n", + curr_gw_tmp->orig_node->orig, + curr_gw_tmp->orig_node->gw_flags, + curr_gw_tmp->orig_node->router->tq_avg); + else + bat_dbg(DBG_BATMAN, bat_priv, + "Changing route to gateway %pM " + "(gw_flags: %i, tq: %i)\n", + curr_gw_tmp->orig_node->orig, + curr_gw_tmp->orig_node->gw_flags, + curr_gw_tmp->orig_node->router->tq_avg); + + old_gw_node = gw_select(bat_priv, curr_gw_tmp); + } + + rcu_read_unlock(); + + /* the kfree() has to be outside of the rcu lock */ + if (old_gw_node) + kref_put(&old_gw_node->refcount, gw_node_free_ref); + } + + void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) + { + struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; + uint8_t gw_tq_avg, orig_tq_avg; + + if (!curr_gateway_tmp) + return; + + if (!curr_gateway_tmp->orig_node) + goto deselect; + + if (!curr_gateway_tmp->orig_node->router) + goto deselect; + + /* this node already is the gateway */ + if (curr_gateway_tmp->orig_node == orig_node) + return; + + if (!orig_node->router) + return; + + gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; + orig_tq_avg = orig_node->router->tq_avg; + + /* the TQ value has to be better */ + if (orig_tq_avg < gw_tq_avg) + return; + + /** + * if the routing class is greater than 3 the value tells us how much + * greater the TQ value of the new gateway must be + **/ + if ((atomic_read(&bat_priv->gw_sel_class) > 3) && + (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class))) + return; + + bat_dbg(DBG_BATMAN, bat_priv, + "Restarting gateway selection: better gateway found (tq curr: " + "%i, tq new: %i)\n", + gw_tq_avg, orig_tq_avg); + + deselect: + gw_deselect(bat_priv); + } + + static void gw_node_add(struct bat_priv *bat_priv, + struct orig_node *orig_node, uint8_t new_gwflags) + { + struct gw_node *gw_node; + int down, up; + + gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC); + if (!gw_node) + return; + + memset(gw_node, 0, sizeof(struct gw_node)); + INIT_HLIST_NODE(&gw_node->list); + gw_node->orig_node = orig_node; + kref_init(&gw_node->refcount); + + spin_lock_bh(&bat_priv->gw_list_lock); + hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list); + spin_unlock_bh(&bat_priv->gw_list_lock); + + gw_bandwidth_to_kbit(new_gwflags, &down, &up); + bat_dbg(DBG_BATMAN, bat_priv, + "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n", + orig_node->orig, new_gwflags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); + } + + void gw_node_update(struct bat_priv *bat_priv, + struct orig_node *orig_node, uint8_t new_gwflags) + { + struct hlist_node *node; + struct gw_node *gw_node; + + rcu_read_lock(); + hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { + if (gw_node->orig_node != orig_node) + continue; + + bat_dbg(DBG_BATMAN, bat_priv, + "Gateway class of originator %pM changed from " + "%i to %i\n", + orig_node->orig, gw_node->orig_node->gw_flags, + new_gwflags); + + gw_node->deleted = 0; + + if (new_gwflags == 0) { + gw_node->deleted = jiffies; + bat_dbg(DBG_BATMAN, bat_priv, + "Gateway %pM removed from gateway list\n", + orig_node->orig); + + if (gw_node == bat_priv->curr_gw) { + rcu_read_unlock(); + gw_deselect(bat_priv); + return; + } + } + + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + + if (new_gwflags == 0) + return; + + gw_node_add(bat_priv, orig_node, new_gwflags); + } + + void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) + { + return gw_node_update(bat_priv, orig_node, 0); + } + + void gw_node_purge(struct bat_priv *bat_priv) + { + struct gw_node *gw_node; + struct hlist_node *node, *node_tmp; + unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; + + spin_lock_bh(&bat_priv->gw_list_lock); + + hlist_for_each_entry_safe(gw_node, node, node_tmp, + &bat_priv->gw_list, list) { + if (((!gw_node->deleted) || + (time_before(jiffies, gw_node->deleted + timeout))) && + atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) + continue; + + if (bat_priv->curr_gw == gw_node) + gw_deselect(bat_priv); + + hlist_del_rcu(&gw_node->list); + call_rcu(&gw_node->rcu, gw_node_free_rcu); + } + + + spin_unlock_bh(&bat_priv->gw_list_lock); + } + + static int _write_buffer_text(struct bat_priv *bat_priv, + struct seq_file *seq, struct gw_node *gw_node) + { + int down, up; + + gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); + + return seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", + (bat_priv->curr_gw == gw_node ? "=>" : " "), + gw_node->orig_node->orig, + gw_node->orig_node->router->tq_avg, + gw_node->orig_node->router->addr, + gw_node->orig_node->router->if_incoming->net_dev->name, + gw_node->orig_node->gw_flags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); + } + + int gw_client_seq_print_text(struct seq_file *seq, void *offset) + { + struct net_device *net_dev = (struct net_device *)seq->private; + struct bat_priv *bat_priv = netdev_priv(net_dev); + struct gw_node *gw_node; + struct hlist_node *node; + int gw_count = 0; + + if (!bat_priv->primary_if) { + + return seq_printf(seq, "BATMAN mesh %s disabled - please " + "specify interfaces to enable it\n", + net_dev->name); + } + + if (bat_priv->primary_if->if_status != IF_ACTIVE) { + + return seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + } + + seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " + "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", + "Gateway", "#", TQ_MAX_VALUE, "Nexthop", + "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, + bat_priv->primary_if->net_dev->name, + bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + + rcu_read_lock(); + hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { + if (gw_node->deleted) + continue; + + if (!gw_node->orig_node->router) + continue; + + _write_buffer_text(bat_priv, seq, gw_node); + gw_count++; + } + rcu_read_unlock(); + + if (gw_count == 0) + seq_printf(seq, "No gateways in range ...\n"); + + return 0; + } + + int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) + { + struct ethhdr *ethhdr; + struct iphdr *iphdr; + struct ipv6hdr *ipv6hdr; + struct udphdr *udphdr; + unsigned int header_len = 0; + + if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) + return 0; + + /* check for ethernet header */ + if (!pskb_may_pull(skb, header_len + ETH_HLEN)) + return 0; + ethhdr = (struct ethhdr *)skb->data; + header_len += ETH_HLEN; + + /* check for initial vlan header */ + if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { + if (!pskb_may_pull(skb, header_len + VLAN_HLEN)) + return 0; + ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN); + header_len += VLAN_HLEN; + } + + /* check for ip header */ + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_IP: + if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr))) + return 0; + iphdr = (struct iphdr *)(skb->data + header_len); + header_len += iphdr->ihl * 4; + + /* check for udp header */ + if (iphdr->protocol != IPPROTO_UDP) + return 0; + + break; + case ETH_P_IPV6: + if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr))) + return 0; + ipv6hdr = (struct ipv6hdr *)(skb->data + header_len); + header_len += sizeof(struct ipv6hdr); + + /* check for udp header */ + if (ipv6hdr->nexthdr != IPPROTO_UDP) + return 0; + + break; + default: + return 0; + } + + if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr))) + return 0; + udphdr = (struct udphdr *)(skb->data + header_len); + header_len += sizeof(struct udphdr); + + /* check for bootp port */ + if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && + (ntohs(udphdr->dest) != 67)) + return 0; + + if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) && + (ntohs(udphdr->dest) != 547)) + return 0; + + if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) + return -1; + + if (!bat_priv->curr_gw) + return 0; + + return 1; + } diff --combined drivers/staging/batman-adv/gateway_client.h index 0000000,4585e65..4585e65 mode 000000,100644..100644 --- a/drivers/staging/batman-adv/gateway_client.h +++ b/drivers/staging/batman-adv/gateway_client.h @@@ -1,0 -1,36 +1,36 @@@ + /* + * Copyright (C) 2009-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 _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ + #define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ + + void gw_deselect(struct bat_priv *bat_priv); + void gw_election(struct bat_priv *bat_priv); + void *gw_get_selected(struct bat_priv *bat_priv); + void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); + void gw_node_update(struct bat_priv *bat_priv, + struct orig_node *orig_node, uint8_t new_gwflags); + void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); + void gw_node_purge(struct bat_priv *bat_priv); + int gw_client_seq_print_text(struct seq_file *seq, void *offset); + int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb); + + #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ diff --combined drivers/staging/batman-adv/gateway_common.c index 0000000,b962982..b962982 mode 000000,100644..100644 --- a/drivers/staging/batman-adv/gateway_common.c +++ b/drivers/staging/batman-adv/gateway_common.c @@@ -1,0 -1,177 +1,177 @@@ + /* + * Copyright (C) 2009-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 "main.h" + #include "gateway_common.h" + #include "gateway_client.h" + + /* calculates the gateway class from kbit */ + static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class) + { + int mdown = 0, tdown, tup, difference; + uint8_t sbit, part; + + *gw_srv_class = 0; + difference = 0x0FFFFFFF; + + /* test all downspeeds */ + for (sbit = 0; sbit < 2; sbit++) { + for (part = 0; part < 16; part++) { + tdown = 32 * (sbit + 2) * (1 << part); + + if (abs(tdown - down) < difference) { + *gw_srv_class = (sbit << 7) + (part << 3); + difference = abs(tdown - down); + mdown = tdown; + } + } + } + + /* test all upspeeds */ + difference = 0x0FFFFFFF; + + for (part = 0; part < 8; part++) { + tup = ((part + 1) * (mdown)) / 8; + + if (abs(tup - up) < difference) { + *gw_srv_class = (*gw_srv_class & 0xF8) | part; + difference = abs(tup - up); + } + } + } + + /* returns the up and downspeeds in kbit, calculated from the class */ + void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up) + { + char sbit = (gw_srv_class & 0x80) >> 7; + char dpart = (gw_srv_class & 0x78) >> 3; + char upart = (gw_srv_class & 0x07); + + if (!gw_srv_class) { + *down = 0; + *up = 0; + return; + } + + *down = 32 * (sbit + 2) * (1 << dpart); + *up = ((upart + 1) * (*down)) / 8; + } + + static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff, + long *up, long *down) + { + int ret, multi = 1; + char *slash_ptr, *tmp_ptr; + + slash_ptr = strchr(buff, '/'); + if (slash_ptr) + *slash_ptr = 0; + + if (strlen(buff) > 4) { + tmp_ptr = buff + strlen(buff) - 4; + + if (strnicmp(tmp_ptr, "mbit", 4) == 0) + multi = 1024; + + if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || + (multi > 1)) + *tmp_ptr = '\0'; + } + + ret = strict_strtoul(buff, 10, down); + if (ret) { + bat_err(net_dev, + "Download speed of gateway mode invalid: %s\n", + buff); + return false; + } + + *down *= multi; + + /* we also got some upload info */ + if (slash_ptr) { + multi = 1; + + if (strlen(slash_ptr + 1) > 4) { + tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); + + if (strnicmp(tmp_ptr, "mbit", 4) == 0) + multi = 1024; + + if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || + (multi > 1)) + *tmp_ptr = '\0'; + } + + ret = strict_strtoul(slash_ptr + 1, 10, up); + if (ret) { + bat_err(net_dev, + "Upload speed of gateway mode invalid: " + "%s\n", slash_ptr + 1); + return false; + } + + *up *= multi; + } + + return true; + } + + ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) + { + struct bat_priv *bat_priv = netdev_priv(net_dev); + long gw_bandwidth_tmp = 0, up = 0, down = 0; + bool ret; + + ret = parse_gw_bandwidth(net_dev, buff, &up, &down); + if (!ret) + goto end; + + if ((!down) || (down < 256)) + down = 2000; + + if (!up) + up = down / 5; + + kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp); + + /** + * the gw bandwidth we guessed above might not match the given + * speeds, hence we need to calculate it back to show the number + * that is going to be propagated + **/ + gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, + (int *)&down, (int *)&up); + + gw_deselect(bat_priv); + bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' " + "(propagating: %ld%s/%ld%s)\n", + atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); + + atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp); + + end: + return count; + } diff --combined drivers/staging/batman-adv/gateway_common.h index 0000000,5e728d0..5e728d0 mode 000000,100644..100644 --- a/drivers/staging/batman-adv/gateway_common.h +++ b/drivers/staging/batman-adv/gateway_common.h @@@ -1,0 -1,38 +1,38 @@@ + /* + * Copyright (C) 2009-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 _NET_BATMAN_ADV_GATEWAY_COMMON_H_ + #define _NET_BATMAN_ADV_GATEWAY_COMMON_H_ + + enum gw_modes { + GW_MODE_OFF, + GW_MODE_CLIENT, + GW_MODE_SERVER, + }; + + #define GW_MODE_OFF_NAME "off" + #define GW_MODE_CLIENT_NAME "client" + #define GW_MODE_SERVER_NAME "server" + + void gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up); + ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count); + + #endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */ diff --combined drivers/staging/batman-adv/hard-interface.c index b68a7e5,bf98b90..bf98b90 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@@ -31,11 -31,18 +31,18 @@@
#include <linux/if_arp.h>
/* protect update critical side of if_list - but not the content */ static DEFINE_SPINLOCK(if_list_lock);
+ static void hardif_free_rcu(struct rcu_head *rcu) + { + struct batman_if *batman_if; + + batman_if = container_of(rcu, struct batman_if, rcu); + dev_put(batman_if->net_dev); + kref_put(&batman_if->refcount, hardif_free_ref); + } + struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev) { struct batman_if *batman_if; @@@ -50,7 -57,7 +57,7 @@@
out: if (batman_if) - hardif_hold(batman_if); + kref_get(&batman_if->refcount);
rcu_read_unlock(); return batman_if; @@@ -100,7 -107,7 +107,7 @@@ static struct batman_if *get_active_bat
out: if (batman_if) - hardif_hold(batman_if); + kref_get(&batman_if->refcount);
rcu_read_unlock(); return batman_if; @@@ -125,13 -132,13 +132,13 @@@ static void set_primary_if(struct bat_p struct batman_if *old_if;
if (batman_if) - hardif_hold(batman_if); + kref_get(&batman_if->refcount);
old_if = bat_priv->primary_if; bat_priv->primary_if = batman_if;
if (old_if) - hardif_put(old_if); + kref_put(&old_if->refcount, hardif_free_ref);
if (!bat_priv->primary_if) return; @@@ -199,7 -206,7 +206,7 @@@ int hardif_min_mtu(struct net_device *s * (have MTU > 1500 + BAT_HEADER_LEN) */ int min_mtu = ETH_DATA_LEN;
- if (atomic_read(&bat_priv->frag_enabled)) + if (atomic_read(&bat_priv->fragmentation)) goto out;
rcu_read_lock(); @@@ -211,8 -218,8 +218,8 @@@ if (batman_if->soft_iface != soft_iface) continue;
- min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN, - min_mtu); + min_mtu = min_t(int, batman_if->net_dev->mtu - BAT_HEADER_LEN, + min_mtu); } rcu_read_unlock(); out: @@@ -315,7 -322,7 +322,7 @@@ int hardif_enable_interface(struct batm batman_if->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN); batman_if->batman_adv_ptype.func = batman_skb_recv; batman_if->batman_adv_ptype.dev = batman_if->net_dev; - hardif_hold(batman_if); + kref_get(&batman_if->refcount); dev_add_pack(&batman_if->batman_adv_ptype);
atomic_set(&batman_if->seqno, 1); @@@ -323,7 -330,7 +330,7 @@@ bat_info(batman_if->soft_iface, "Adding interface: %s\n", batman_if->net_dev->name);
- if (atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu < + if (atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < ETH_DATA_LEN + BAT_HEADER_LEN) bat_info(batman_if->soft_iface, "The MTU of interface %s is too small (%i) to handle " @@@ -334,7 -341,7 +341,7 @@@ batman_if->net_dev->name, batman_if->net_dev->mtu, ETH_DATA_LEN + BAT_HEADER_LEN);
- if (!atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu < + if (!atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < ETH_DATA_LEN + BAT_HEADER_LEN) bat_info(batman_if->soft_iface, "The MTU of interface %s is too small (%i) to handle " @@@ -374,7 -381,7 +381,7 @@@ void hardif_disable_interface(struct ba bat_info(batman_if->soft_iface, "Removing interface: %s\n", batman_if->net_dev->name); dev_remove_pack(&batman_if->batman_adv_ptype); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref);
bat_priv->num_ifaces--; orig_hash_del_if(batman_if, bat_priv->num_ifaces); @@@ -386,7 -393,7 +393,7 @@@ set_primary_if(bat_priv, new_if);
if (new_if) - hardif_put(new_if); + kref_put(&new_if->refcount, hardif_free_ref); }
kfree(batman_if->packet_buff); @@@ -432,8 -439,7 +439,7 @@@ static struct batman_if *hardif_add_int batman_if->soft_iface = NULL; batman_if->if_status = IF_NOT_IN_USE; INIT_LIST_HEAD(&batman_if->list); - atomic_set(&batman_if->refcnt, 0); - hardif_hold(batman_if); + kref_init(&batman_if->refcount);
check_known_mac_addr(batman_if->net_dev);
@@@ -442,7 -448,7 +448,7 @@@ spin_unlock(&if_list_lock);
/* extra reference for return */ - hardif_hold(batman_if); + kref_get(&batman_if->refcount); return batman_if;
free_if: @@@ -463,24 -469,28 +469,28 @@@ static void hardif_remove_interface(str return;
batman_if->if_status = IF_TO_BE_REMOVED; - - /* caller must take if_list_lock */ - list_del_rcu(&batman_if->list); - synchronize_rcu(); sysfs_del_hardif(&batman_if->hardif_obj); - hardif_put(batman_if); + call_rcu(&batman_if->rcu, hardif_free_rcu); }
void hardif_remove_interfaces(void) { struct batman_if *batman_if, *batman_if_tmp; + struct list_head if_list_queue; + + INIT_LIST_HEAD(&if_list_queue);
- rtnl_lock(); spin_lock(&if_list_lock); list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) { - hardif_remove_interface(batman_if); + list_del_rcu(&batman_if->list); + list_add_tail(&batman_if->list, &if_list_queue); } spin_unlock(&if_list_lock); + + rtnl_lock(); + list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list_queue, list) { + hardif_remove_interface(batman_if); + } rtnl_unlock(); }
@@@ -507,18 -517,18 +517,18 @@@ static int hard_if_event(struct notifie break; case NETDEV_UNREGISTER: spin_lock(&if_list_lock); - hardif_remove_interface(batman_if); + list_del_rcu(&batman_if->list); spin_unlock(&if_list_lock); + + hardif_remove_interface(batman_if); break; case NETDEV_CHANGEMTU: if (batman_if->soft_iface) update_min_mtu(batman_if->soft_iface); break; case NETDEV_CHANGEADDR: - if (batman_if->if_status == IF_NOT_IN_USE) { - hardif_put(batman_if); - goto out; - } + if (batman_if->if_status == IF_NOT_IN_USE) + goto hardif_put;
check_known_mac_addr(batman_if->net_dev); update_mac_addresses(batman_if); @@@ -530,8 -540,9 +540,9 @@@ default: break; }; - hardif_put(batman_if);
+ hardif_put: + kref_put(&batman_if->refcount, hardif_free_ref); out: return NOTIFY_DONE; } diff --combined drivers/staging/batman-adv/hard-interface.h index d550889,30ec3b8..30ec3b8 --- a/drivers/staging/batman-adv/hard-interface.h +++ b/drivers/staging/batman-adv/hard-interface.h @@@ -42,17 -42,12 +42,12 @@@ int batman_skb_recv(struct sk_buff *skb int hardif_min_mtu(struct net_device *soft_iface); void update_min_mtu(struct net_device *soft_iface);
- static inline void hardif_hold(struct batman_if *batman_if) + static inline void hardif_free_ref(struct kref *refcount) { - atomic_inc(&batman_if->refcnt); - } + struct batman_if *batman_if;
- static inline void hardif_put(struct batman_if *batman_if) - { - if (atomic_dec_and_test(&batman_if->refcnt)) { - dev_put(batman_if->net_dev); - kfree(batman_if); - } + batman_if = container_of(refcount, struct batman_if, refcount); + kfree(batman_if); }
#endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ diff --combined drivers/staging/batman-adv/hash.c index 8ef26eb,8605e2f..8605e2f --- a/drivers/staging/batman-adv/hash.c +++ b/drivers/staging/batman-adv/hash.c @@@ -30,31 -30,7 +30,7 @@@ static void hash_init(struct hashtable_ hash->elements = 0;
for (i = 0 ; i < hash->size; i++) - hash->table[i] = NULL; - } - - /* remove the hash structure. if hashdata_free_cb != NULL, this function will be - * called to remove the elements inside of the hash. if you don't remove the - * elements, memory might be leaked. */ - void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg) - { - struct element_t *bucket, *last_bucket; - int i; - - for (i = 0; i < hash->size; i++) { - bucket = hash->table[i]; - - while (bucket != NULL) { - if (free_cb != NULL) - free_cb(bucket->data, arg); - - last_bucket = bucket; - bucket = bucket->next; - kfree(last_bucket); - } - } - - hash_destroy(hash); + INIT_HLIST_HEAD(&hash->table[i]); }
/* free only the hashtable and the hash itself. */ @@@ -64,81 -40,8 +40,8 @@@ void hash_destroy(struct hashtable_t *h kfree(hash); }
- /* iterate though the hash. First element is selected if an iterator - * initialized with HASHIT() is supplied as iter. Use the returned - * (or supplied) iterator to access the elements until hash_iterate returns - * NULL. */ - - struct hash_it_t *hash_iterate(struct hashtable_t *hash, - struct hash_it_t *iter) - { - if (!hash) - return NULL; - if (!iter) - return NULL; - - /* sanity checks first (if our bucket got deleted in the last - * iteration): */ - if (iter->bucket != NULL) { - if (iter->first_bucket != NULL) { - /* we're on the first element and it got removed after - * the last iteration. */ - if ((*iter->first_bucket) != iter->bucket) { - /* there are still other elements in the list */ - if ((*iter->first_bucket) != NULL) { - iter->prev_bucket = NULL; - iter->bucket = (*iter->first_bucket); - iter->first_bucket = - &hash->table[iter->index]; - return iter; - } else { - iter->bucket = NULL; - } - } - } else if (iter->prev_bucket != NULL) { - /* - * we're not on the first element, and the bucket got - * removed after the last iteration. the last bucket's - * next pointer is not pointing to our actual bucket - * anymore. select the next. - */ - if (iter->prev_bucket->next != iter->bucket) - iter->bucket = iter->prev_bucket; - } - } - - /* now as we are sane, select the next one if there is some */ - if (iter->bucket != NULL) { - if (iter->bucket->next != NULL) { - iter->prev_bucket = iter->bucket; - iter->bucket = iter->bucket->next; - iter->first_bucket = NULL; - return iter; - } - } - - /* if not returned yet, we've reached the last one on the index and have - * to search forward */ - iter->index++; - /* go through the entries of the hash table */ - while (iter->index < hash->size) { - if ((hash->table[iter->index]) != NULL) { - iter->prev_bucket = NULL; - iter->bucket = hash->table[iter->index]; - iter->first_bucket = &hash->table[iter->index]; - return iter; - } else { - iter->index++; - } - } - - /* nothing to iterate over anymore */ - return NULL; - } - /* allocates and clears the hash */ - struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, - hashdata_choose_cb choose) + struct hashtable_t *hash_new(int size) { struct hashtable_t *hash;
@@@ -157,74 -60,9 +60,9 @@@
hash_init(hash);
return hash; }
- /* adds data to the hashtable. returns 0 on success, -1 on error */ - int hash_add(struct hashtable_t *hash, void *data) - { - int index; - struct element_t *bucket, *prev_bucket = NULL; - - if (!hash) - return -1; - - index = hash->choose(data, hash->size); - bucket = hash->table[index]; - - while (bucket != NULL) { - if (hash->compare(bucket->data, data)) - return -1; - - prev_bucket = bucket; - bucket = bucket->next; - } - - /* found the tail of the list, add new element */ - bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); - - if (bucket == NULL) - return -1; - - bucket->data = data; - bucket->next = NULL; - - /* and link it */ - if (prev_bucket == NULL) - hash->table[index] = bucket; - else - prev_bucket->next = bucket; - - hash->elements++; - return 0; - } - - /* finds data, based on the key in keydata. returns the found data on success, - * or NULL on error */ - void *hash_find(struct hashtable_t *hash, void *keydata) - { - int index; - struct element_t *bucket; - - if (!hash) - return NULL; - - index = hash->choose(keydata , hash->size); - bucket = hash->table[index]; - - while (bucket != NULL) { - if (hash->compare(bucket->data, keydata)) - return bucket->data; - - bucket = bucket->next; - } - - return NULL; - } - /* remove bucket (this might be used in hash_iterate() if you already found the * bucket you want to delete and don't need the overhead to find it again with * hash_remove(). But usually, you don't want to use this function, as it @@@ -232,75 -70,14 +70,14 @@@ void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) { void *data_save; + struct element_t *bucket;
- data_save = hash_it_t->bucket->data; - - if (hash_it_t->prev_bucket != NULL) - hash_it_t->prev_bucket->next = hash_it_t->bucket->next; - else if (hash_it_t->first_bucket != NULL) - (*hash_it_t->first_bucket) = hash_it_t->bucket->next; + bucket = hlist_entry(hash_it_t->walk, struct element_t, hlist); + data_save = bucket->data;
- kfree(hash_it_t->bucket); + hlist_del(hash_it_t->walk); + kfree(bucket); hash->elements--;
return data_save; } - - /* removes data from hash, if found. returns pointer do data on success, so you - * can remove the used structure yourself, or NULL on error . data could be the - * structure you use with just the key filled, we just need the key for - * comparing. */ - void *hash_remove(struct hashtable_t *hash, void *data) - { - struct hash_it_t hash_it_t; - - hash_it_t.index = hash->choose(data, hash->size); - hash_it_t.bucket = hash->table[hash_it_t.index]; - hash_it_t.prev_bucket = NULL; - - while (hash_it_t.bucket != NULL) { - if (hash->compare(hash_it_t.bucket->data, data)) { - hash_it_t.first_bucket = - (hash_it_t.bucket == - hash->table[hash_it_t.index] ? - &hash->table[hash_it_t.index] : NULL); - return hash_remove_bucket(hash, &hash_it_t); - } - - hash_it_t.prev_bucket = hash_it_t.bucket; - hash_it_t.bucket = hash_it_t.bucket->next; - } - - return NULL; - } - - /* resize the hash, returns the pointer to the new hash or NULL on - * error. removes the old hash on success. */ - struct hashtable_t *hash_resize(struct hashtable_t *hash, int size) - { - struct hashtable_t *new_hash; - struct element_t *bucket; - int i; - - /* initialize a new hash with the new size */ - new_hash = hash_new(size, hash->compare, hash->choose); - - if (new_hash == NULL) - return NULL; - - /* copy the elements */ - for (i = 0; i < hash->size; i++) { - bucket = hash->table[i]; - - while (bucket != NULL) { - hash_add(new_hash, bucket->data); - bucket = bucket->next; - } - } - - /* remove hash and eventual overflow buckets but not the content - * itself. */ - hash_delete(hash, NULL, NULL); - - return new_hash; - } diff --combined drivers/staging/batman-adv/hash.h index 2c8e176,0b61c6e..0b61c6e --- a/drivers/staging/batman-adv/hash.h +++ b/drivers/staging/batman-adv/hash.h @@@ -22,44 -22,43 +22,43 @@@ #ifndef _NET_BATMAN_ADV_HASH_H_ #define _NET_BATMAN_ADV_HASH_H_
- #define HASHIT(name) struct hash_it_t name = { \ - .index = -1, .bucket = NULL, \ - .prev_bucket = NULL, \ - .first_bucket = NULL } + #include <linux/list.h>
+ #define HASHIT(name) struct hash_it_t name = { \ + .index = 0, .walk = NULL, \ + .safe = NULL}
+ /* callback to a compare function. should + * compare 2 element datas for their keys, + * return 0 if same and not 0 if not + * same */ typedef int (*hashdata_compare_cb)(void *, void *); + + /* the hashfunction, should return an index + * based on the key in the data of the first + * argument and the size the second */ typedef int (*hashdata_choose_cb)(void *, int); typedef void (*hashdata_free_cb)(void *, void *);
struct element_t { void *data; /* pointer to the data */ - struct element_t *next; /* overflow bucket pointer */ + struct hlist_node hlist; /* bucket list pointer */ };
struct hash_it_t { - int index; - struct element_t *bucket; - struct element_t *prev_bucket; - struct element_t **first_bucket; + size_t index; + struct hlist_node *walk; + struct hlist_node *safe; };
struct hashtable_t { - struct element_t **table; /* the hashtable itself, with the buckets */ + struct hlist_head *table; /* the hashtable itself, with the buckets */ int elements; /* number of elements registered */ int size; /* size of hashtable */ };
/* allocates and clears the hash */ - struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, - hashdata_choose_cb choose); + struct hashtable_t *hash_new(int size);
/* remove bucket (this might be used in hash_iterate() if you already found the * bucket you want to delete and don't need the overhead to find it again with @@@ -67,34 -66,194 +66,194 @@@ * fiddles with hash-internals. */ void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t);
+ /* free only the hashtable and the hash itself. */ + void hash_destroy(struct hashtable_t *hash); + /* remove the hash structure. if hashdata_free_cb != NULL, this function will be * called to remove the elements inside of the hash. if you don't remove the * elements, memory might be leaked. */ - void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg); + static inline void hash_delete(struct hashtable_t *hash, + hashdata_free_cb free_cb, void *arg) + { + struct hlist_head *head; + struct hlist_node *walk, *safe; + struct element_t *bucket; + int i;
- /* free only the hashtable and the hash itself. */ - void hash_destroy(struct hashtable_t *hash); + for (i = 0; i < hash->size; i++) { + head = &hash->table[i]; + + hlist_for_each_safe(walk, safe, head) { + bucket = hlist_entry(walk, struct element_t, hlist); + if (free_cb != NULL) + free_cb(bucket->data, arg); + + hlist_del(walk); + kfree(bucket); + } + } + + hash_destroy(hash); + }
/* adds data to the hashtable. returns 0 on success, -1 on error */ - int hash_add(struct hashtable_t *hash, void *data); + static inline int hash_add(struct hashtable_t *hash, + hashdata_compare_cb compare, + hashdata_choose_cb choose, void *data) + { + int index; + struct hlist_head *head; + struct hlist_node *walk, *safe; + struct element_t *bucket; + + if (!hash) + return -1; + + index = choose(data, hash->size); + head = &hash->table[index]; + + hlist_for_each_safe(walk, safe, head) { + bucket = hlist_entry(walk, struct element_t, hlist); + if (compare(bucket->data, data)) + return -1; + } + + /* no duplicate found in list, add new element */ + bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); + + if (bucket == NULL) + return -1; + + bucket->data = data; + hlist_add_head(&bucket->hlist, head); + + hash->elements++; + return 0; + }
/* removes data from hash, if found. returns pointer do data on success, so you * can remove the used structure yourself, or NULL on error . data could be the * structure you use with just the key filled, we just need the key for * comparing. */ - void *hash_remove(struct hashtable_t *hash, void *data); + static inline void *hash_remove(struct hashtable_t *hash, + hashdata_compare_cb compare, + hashdata_choose_cb choose, void *data) + { + struct hash_it_t hash_it_t; + struct element_t *bucket; + struct hlist_head *head; + + hash_it_t.index = choose(data, hash->size); + head = &hash->table[hash_it_t.index]; + + hlist_for_each(hash_it_t.walk, head) { + bucket = hlist_entry(hash_it_t.walk, struct element_t, hlist); + if (compare(bucket->data, data)) + return hash_remove_bucket(hash, &hash_it_t); + } + + return NULL; + }
/* finds data, based on the key in keydata. returns the found data on success, * or NULL on error */ - void *hash_find(struct hashtable_t *hash, void *keydata); + static inline void *hash_find(struct hashtable_t *hash, + hashdata_compare_cb compare, + hashdata_choose_cb choose, void *keydata) + { + int index; + struct hlist_head *head; + struct hlist_node *walk; + struct element_t *bucket; + + if (!hash) + return NULL; + + index = choose(keydata , hash->size); + head = &hash->table[index]; + + hlist_for_each(walk, head) { + bucket = hlist_entry(walk, struct element_t, hlist); + if (compare(bucket->data, keydata)) + return bucket->data; + } + + return NULL; + }
/* resize the hash, returns the pointer to the new hash or NULL on * error. removes the old hash on success */ - struct hashtable_t *hash_resize(struct hashtable_t *hash, int size); + static inline struct hashtable_t *hash_resize(struct hashtable_t *hash, + hashdata_choose_cb choose, + int size) + { + struct hashtable_t *new_hash; + struct hlist_head *head, *new_head; + struct hlist_node *walk, *safe; + struct element_t *bucket; + int i, new_index; + + /* initialize a new hash with the new size */ + new_hash = hash_new(size); + + if (new_hash == NULL) + return NULL; + + /* copy the elements */ + for (i = 0; i < hash->size; i++) { + head = &hash->table[i]; + + hlist_for_each_safe(walk, safe, head) { + bucket = hlist_entry(walk, struct element_t, hlist); + + new_index = choose(bucket->data, size); + new_head = &new_hash->table[new_index]; + + hlist_del(walk); + hlist_add_head(walk, new_head); + } + } + + hash_destroy(hash); + + return new_hash; + } + + /* iterate though the hash. First element is selected if an iterator + * initialized with HASHIT() is supplied as iter. Use the returned + * (or supplied) iterator to access the elements until hash_iterate returns + * NULL. */ + static inline struct hash_it_t *hash_iterate(struct hashtable_t *hash, + struct hash_it_t *iter) + { + if (!hash) + return NULL; + if (!iter) + return NULL; + + iter->walk = iter->safe; + + /* we search for the next head with list entries */ + if (!iter->walk) { + while (iter->index < hash->size) { + if (hlist_empty(&hash->table[iter->index])) + iter->index++; + else { + iter->walk = hash->table[iter->index].first; + + /* search next time */ + ++iter->index; + break; + } + } + } + + /* return iter when we found bucket otherwise null */ + if (!iter->walk) + return NULL;
- /* iterate though the hash. first element is selected with iter_in NULL. use - * the returned iterator to access the elements until hash_it_t returns NULL. */ - struct hash_it_t *hash_iterate(struct hashtable_t *hash, - struct hash_it_t *iter_in); + iter->safe = iter->walk->next; + return iter; + }
#endif /* _NET_BATMAN_ADV_HASH_H_ */ diff --combined drivers/staging/batman-adv/icmp_socket.c index 48856ca,ecf6d7f..ecf6d7f --- a/drivers/staging/batman-adv/icmp_socket.c +++ b/drivers/staging/batman-adv/icmp_socket.c @@@ -26,9 -26,9 +26,9 @@@ #include "send.h" #include "types.h" #include "hash.h" + #include "originator.h" #include "hard-interface.h"
- static struct socket_client *socket_client_hash[256];
static void bat_socket_add_packet(struct socket_client *socket_client, @@@ -84,9 -84,8 +84,8 @@@ static int bat_socket_release(struct in struct socket_client *socket_client = file->private_data; struct socket_packet *socket_packet; struct list_head *list_pos, *list_pos_tmp; - unsigned long flags;
- spin_lock_irqsave(&socket_client->lock, flags); + spin_lock_bh(&socket_client->lock);
/* for all packets in the queue ... */ list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) { @@@ -98,7 -97,7 +97,7 @@@ }
socket_client_hash[socket_client->index] = NULL; - spin_unlock_irqrestore(&socket_client->lock, flags); + spin_unlock_bh(&socket_client->lock);
kfree(socket_client); dec_module_count(); @@@ -113,7 -112,6 +112,6 @@@ static ssize_t bat_socket_read(struct f struct socket_packet *socket_packet; size_t packet_len; int error; - unsigned long flags;
if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0)) return -EAGAIN; @@@ -130,14 -128,14 +128,14 @@@ if (error) return error;
- spin_lock_irqsave(&socket_client->lock, flags); + spin_lock_bh(&socket_client->lock);
socket_packet = list_first_entry(&socket_client->queue_list, struct socket_packet, list); list_del(&socket_packet->list); socket_client->queue_len--;
- spin_unlock_irqrestore(&socket_client->lock, flags); + spin_unlock_bh(&socket_client->lock);
error = __copy_to_user(buf, &socket_packet->icmp_packet, socket_packet->icmp_len); @@@ -163,7 -161,6 +161,6 @@@ static ssize_t bat_socket_write(struct struct batman_if *batman_if; size_t packet_len = sizeof(struct icmp_packet); uint8_t dstaddr[ETH_ALEN]; - unsigned long flags;
if (len < sizeof(struct icmp_packet)) { bat_dbg(DBG_BATMAN, bat_priv, @@@ -223,8 -220,9 +220,9 @@@ if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dst_unreach;
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, choose_orig, icmp_packet->dst));
if (!orig_node) @@@ -236,7 -234,7 +234,7 @@@ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
if (!batman_if) goto dst_unreach; @@@ -256,7 -254,7 +254,7 @@@ goto out;
unlock: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); dst_unreach: icmp_packet->msg_type = DESTINATION_UNREACHABLE; bat_socket_add_packet(socket_client, icmp_packet, packet_len); @@@ -311,7 -309,6 +309,6 @@@ static void bat_socket_add_packet(struc size_t icmp_len) { struct socket_packet *socket_packet; - unsigned long flags;
socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC);
@@@ -322,12 -319,12 +319,12 @@@ memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len); socket_packet->icmp_len = icmp_len;
- spin_lock_irqsave(&socket_client->lock, flags); + spin_lock_bh(&socket_client->lock);
/* while waiting for the lock the socket_client could have been * deleted */ if (!socket_client_hash[icmp_packet->uid]) { - spin_unlock_irqrestore(&socket_client->lock, flags); + spin_unlock_bh(&socket_client->lock); kfree(socket_packet); return; } @@@ -344,7 -341,7 +341,7 @@@ socket_client->queue_len--; }
- spin_unlock_irqrestore(&socket_client->lock, flags); + spin_unlock_bh(&socket_client->lock);
wake_up(&socket_client->queue_wait); } diff --combined drivers/staging/batman-adv/main.c index 0587940,b827f6a..b827f6a --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@@ -29,6 -29,7 +29,7 @@@ #include "icmp_socket.h" #include "translation-table.h" #include "hard-interface.h" + #include "gateway_client.h" #include "types.h" #include "vis.h" #include "hash.h" @@@ -84,11 -85,15 +85,15 @@@ int mesh_init(struct net_device *soft_i spin_lock_init(&bat_priv->forw_bcast_list_lock); spin_lock_init(&bat_priv->hna_lhash_lock); spin_lock_init(&bat_priv->hna_ghash_lock); + spin_lock_init(&bat_priv->gw_list_lock); spin_lock_init(&bat_priv->vis_hash_lock); spin_lock_init(&bat_priv->vis_list_lock); + spin_lock_init(&bat_priv->softif_neigh_lock);
INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); + INIT_HLIST_HEAD(&bat_priv->gw_list); + INIT_HLIST_HEAD(&bat_priv->softif_neigh_list);
if (originator_init(bat_priv) < 1) goto err; @@@ -127,11 -132,14 +132,14 @@@ void mesh_free(struct net_device *soft_
vis_quit(bat_priv);
+ gw_node_purge(bat_priv); originator_free(bat_priv);
hna_local_free(bat_priv); hna_global_free(bat_priv);
+ softif_neigh_purge(bat_priv); + atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); }
@@@ -145,34 -153,6 +153,6 @@@ void dec_module_count(void module_put(THIS_MODULE); }
- /* returns 1 if they are the same originator */ - - int compare_orig(void *data1, void *data2) - { - return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); - } - - /* hashfunction to choose an entry in a hash table of given size */ - /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ - int choose_orig(void *data, int32_t size) - { - unsigned char *key = data; - uint32_t hash = 0; - size_t i; - - for (i = 0; i < 6; i++) { - hash += key[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - - return hash % size; - } - int is_my_mac(uint8_t *addr) { struct batman_if *batman_if; @@@ -192,16 -172,6 +172,6 @@@
}
- int is_bcast(uint8_t *addr) - { - return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff); - } - - int is_mcast(uint8_t *addr) - { - return *addr & 0x01; - } - module_init(batman_init); module_exit(batman_exit);
diff --combined drivers/staging/batman-adv/main.h index 5e3f516,0000000..d4d9926 mode 100644,000000..100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@@ -1,183 -1,0 +1,183 @@@ +/* + * 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 + * + */ + +#ifndef _NET_BATMAN_ADV_MAIN_H_ +#define _NET_BATMAN_ADV_MAIN_H_ + +/* Kernel Programming */ +#define LINUX + +#define DRIVER_AUTHOR "Marek Lindner lindner_marek@yahoo.de, " \ + "Simon Wunderlich siwu@hrz.tu-chemnitz.de" +#define DRIVER_DESC "B.A.T.M.A.N. advanced" +#define DRIVER_DEVICE "batman-adv" + +#define SOURCE_VERSION "next" + + +/* B.A.T.M.A.N. parameters */ + +#define TQ_MAX_VALUE 255 +#define JITTER 20 +#define TTL 50 /* Time To Live of broadcast messages */ + +#define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no + * valid packet comes in -> TODO: check + * influence on TQ_LOCAL_WINDOW_SIZE */ +#define LOCAL_HNA_TIMEOUT 3600 /* in seconds */ + +#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator + * messages in squence numbers (should be a + * multiple of our word size) */ +#define TQ_GLOBAL_WINDOW_SIZE 5 +#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 +#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 +#define TQ_TOTAL_BIDRECT_LIMIT 1 + - #define TQ_HOP_PENALTY 10 - +#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) + +#define PACKBUFF_SIZE 2000 +#define LOG_BUF_LEN 8192 /* has to be a power of 2 */ + +#define VIS_INTERVAL 5000 /* 5 seconds */ + +/* how much worse secondary interfaces may be to + * to be considered as bonding candidates */ + +#define BONDING_TQ_THRESHOLD 50 + +#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or + * change the size of + * forw_packet->direct_link_flags */ +#define MAX_AGGREGATION_MS 100 + ++#define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */ ++ +#define RESET_PROTECTION_MS 30000 +#define EXPECTED_SEQNO_RANGE 65536 +/* don't reset again within 30 seconds */ + +#define MESH_INACTIVE 0 +#define MESH_ACTIVE 1 +#define MESH_DEACTIVATING 2 + +#define BCAST_QUEUE_LEN 256 +#define BATMAN_QUEUE_LEN 256 + +/* + * Debug Messages + */ ++#ifdef pr_fmt ++#undef pr_fmt ++#endif +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before + * kernel messages */ + +#define DBG_BATMAN 1 /* all messages related to routing / flooding / + * broadcasting / etc */ +#define DBG_ROUTES 2 /* route or hna added / changed / deleted */ +#define DBG_ALL 3 + +#define LOG_BUF_LEN 8192 /* has to be a power of 2 */ + + +/* + * Vis + */ + +/* #define VIS_SUBCLUSTERS_DISABLED */ + +/* + * Kernel headers + */ + +#include <linux/mutex.h> /* mutex */ +#include <linux/module.h> /* needed by all modules */ +#include <linux/netdevice.h> /* netdevice */ ++#include <linux/etherdevice.h> /* ethernet address classifaction */ +#include <linux/if_ether.h> /* ethernet header */ +#include <linux/poll.h> /* poll_table */ +#include <linux/kthread.h> /* kernel threads */ +#include <linux/pkt_sched.h> /* schedule types */ +#include <linux/workqueue.h> /* workqueue */ +#include <linux/slab.h> +#include <net/sock.h> /* struct sock */ +#include <linux/jiffies.h> +#include <linux/seq_file.h> +#include "types.h" + +#ifndef REVISION_VERSION +#define REVISION_VERSION_STR "" +#else +#define REVISION_VERSION_STR " "REVISION_VERSION +#endif + +extern struct list_head if_list; + +extern unsigned char broadcast_addr[]; +extern struct workqueue_struct *bat_event_workqueue; + +int mesh_init(struct net_device *soft_iface); +void mesh_free(struct net_device *soft_iface); +void inc_module_count(void); +void dec_module_count(void); - int compare_orig(void *data1, void *data2); - int choose_orig(void *data, int32_t size); +int is_my_mac(uint8_t *addr); - int is_bcast(uint8_t *addr); - int is_mcast(uint8_t *addr); + +#ifdef CONFIG_BATMAN_ADV_DEBUG +int debug_log(struct bat_priv *bat_priv, char *fmt, ...); + +#define bat_dbg(type, bat_priv, fmt, arg...) \ + do { \ + if (atomic_read(&bat_priv->log_level) & type) \ + debug_log(bat_priv, fmt, ## arg); \ + } \ + while (0) +#else /* !CONFIG_BATMAN_ADV_DEBUG */ +static inline void bat_dbg(char type __attribute__((unused)), + struct bat_priv *bat_priv __attribute__((unused)), + char *fmt __attribute__((unused)), ...) +{ +} +#endif + +#define bat_warning(net_dev, fmt, arg...) \ + do { \ + struct net_device *_netdev = (net_dev); \ + struct bat_priv *_batpriv = netdev_priv(_netdev); \ + bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ + pr_warning("%s: " fmt, _netdev->name, ## arg); \ + } while (0) +#define bat_info(net_dev, fmt, arg...) \ + do { \ + struct net_device *_netdev = (net_dev); \ + struct bat_priv *_batpriv = netdev_priv(_netdev); \ + bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ + pr_info("%s: " fmt, _netdev->name, ## arg); \ + } while (0) +#define bat_err(net_dev, fmt, arg...) \ + do { \ + struct net_device *_netdev = (net_dev); \ + struct bat_priv *_batpriv = netdev_priv(_netdev); \ + bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ + pr_err("%s: " fmt, _netdev->name, ## arg); \ + } while (0) + +#endif /* _NET_BATMAN_ADV_MAIN_H_ */ diff --combined drivers/staging/batman-adv/originator.c index 5527008,89ec021..89ec021 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@@ -26,8 -26,10 +26,10 @@@ #include "hash.h" #include "translation-table.h" #include "routing.h" + #include "gateway_client.h" #include "hard-interface.h" #include "unicast.h" + #include "soft-interface.h"
static void purge_orig(struct work_struct *work);
@@@ -39,22 -41,21 +41,21 @@@ static void start_purge_timer(struct ba
int originator_init(struct bat_priv *bat_priv) { if (bat_priv->orig_hash) return 1;
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); - bat_priv->orig_hash = hash_new(128, compare_orig, choose_orig); + spin_lock_bh(&bat_priv->orig_hash_lock); + bat_priv->orig_hash = hash_new(128);
if (!bat_priv->orig_hash) goto err;
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); start_purge_timer(bat_priv); return 1;
err: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; }
@@@ -107,17 -108,15 +108,15 @@@ static void free_orig_node(void *data,
void originator_free(struct bat_priv *bat_priv) { - unsigned long flags; - if (!bat_priv->orig_hash) return;
cancel_delayed_work_sync(&bat_priv->orig_work);
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv); bat_priv->orig_hash = NULL; - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); }
/* this function finds or creates an originator entry for the given @@@ -127,8 -126,11 +126,11 @@@ struct orig_node *get_orig_node(struct struct orig_node *orig_node; struct hashtable_t *swaphash; int size; + int hash_added;
- orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, addr)); + orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, choose_orig, + addr));
if (orig_node) return orig_node; @@@ -165,11 -167,13 +167,13 @@@ if (!orig_node->bcast_own_sum) goto free_bcast_own;
- if (hash_add(bat_priv->orig_hash, orig_node) < 0) + hash_added = hash_add(bat_priv->orig_hash, compare_orig, choose_orig, + orig_node); + if (hash_added < 0) goto free_bcast_own_sum;
if (bat_priv->orig_hash->elements * 4 > bat_priv->orig_hash->size) { - swaphash = hash_resize(bat_priv->orig_hash, + swaphash = hash_resize(bat_priv->orig_hash, choose_orig, bat_priv->orig_hash->size * 2);
if (!swaphash) @@@ -265,16 -269,19 +269,19 @@@ static bool purge_orig_node(struct bat_ static void _purge_orig(struct bat_priv *bat_priv) { HASHIT(hashit); + struct element_t *bucket; struct orig_node *orig_node; - unsigned long flags;
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock);
/* for all origins... */ while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data;
if (purge_orig_node(bat_priv, orig_node)) { + if (orig_node->gw_flags) + gw_node_delete(bat_priv, orig_node); hash_remove_bucket(bat_priv->orig_hash, &hashit); free_orig_node(orig_node, bat_priv); } @@@ -284,8 -291,12 +291,12 @@@ frag_list_free(&orig_node->frag_list); }
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); + + gw_node_purge(bat_priv); + gw_election(bat_priv);
+ softif_neigh_purge(bat_priv); }
static void purge_orig(struct work_struct *work) @@@ -307,6 -318,7 +318,7 @@@ void purge_orig_ref(struct bat_priv *ba int orig_seq_print_text(struct seq_file *seq, void *offset) { HASHIT(hashit); + struct element_t *bucket; struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); struct orig_node *orig_node; @@@ -314,7 -326,6 +326,6 @@@ int batman_count = 0; int last_seen_secs; int last_seen_msecs; - unsigned long flags;
if ((!bat_priv->primary_if) || (bat_priv->primary_if->if_status != IF_ACTIVE)) { @@@ -336,11 -347,11 +347,11 @@@ "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops");
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock);
while (hash_iterate(bat_priv->orig_hash, &hashit)) { - - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data;
if (!orig_node->router) continue; @@@ -367,7 -378,7 +378,7 @@@ batman_count++; }
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
if ((batman_count == 0)) seq_printf(seq, "No batman nodes in range ...\n"); @@@ -409,25 -420,26 +420,26 @@@ int orig_hash_add_if(struct batman_if * { struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct orig_node *orig_node; - unsigned long flags; HASHIT(hashit); + struct element_t *bucket;
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock);
while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data;
if (orig_node_add_if(orig_node, max_if_num) == -1) goto err; }
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return 0;
err: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return -ENOMEM; }
@@@ -488,16 -500,17 +500,17 @@@ int orig_hash_del_if(struct batman_if * struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct batman_if *batman_if_tmp; struct orig_node *orig_node; - unsigned long flags; HASHIT(hashit); + struct element_t *bucket; int ret;
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock);
while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data;
ret = orig_node_del_if(orig_node, max_if_num, batman_if->if_num); @@@ -524,10 -537,10 +537,10 @@@ rcu_read_unlock();
batman_if->if_num = -1; - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return 0;
err: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return -ENOMEM; } diff --combined drivers/staging/batman-adv/originator.h index a97c4004,d474ceb..d474ceb --- a/drivers/staging/batman-adv/originator.h +++ b/drivers/staging/batman-adv/originator.h @@@ -33,4 -33,32 +33,32 @@@ int orig_seq_print_text(struct seq_fil 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);
+ + /* returns 1 if they are the same originator */ + static inline int compare_orig(void *data1, void *data2) + { + return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); + } + + /* hashfunction to choose an entry in a hash table of given size */ + /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ + static inline int choose_orig(void *data, int32_t size) + { + unsigned char *key = data; + uint32_t hash = 0; + size_t i; + + for (i = 0; i < 6; i++) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash % size; + } + #endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ diff --combined drivers/staging/batman-adv/packet.h index 2693383,b49fdf7..b49fdf7 --- a/drivers/staging/batman-adv/packet.h +++ b/drivers/staging/batman-adv/packet.h @@@ -32,7 -32,7 +32,7 @@@ #define BAT_UNICAST_FRAG 0x06
/* this file is included by batctl which needs these defines */ - #define COMPAT_VERSION 13 + #define COMPAT_VERSION 12 #define DIRECTLINK 0x40 #define VIS_SERVER 0x20 #define PRIMARIES_FIRST_HOP 0x10 @@@ -61,6 -61,8 +61,8 @@@ struct batman_packet uint8_t prev_sender[6]; uint8_t ttl; uint8_t num_hna; + uint8_t gw_flags; /* flags related to gateway class */ + uint8_t align; } __attribute__((packed));
#define BAT_PACKET_LEN sizeof(struct batman_packet) diff --combined drivers/staging/batman-adv/routing.c index 657b69e,d8b0c5a..d8b0c5a --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@@ -32,20 -32,23 +32,23 @@@ #include "ring_buffer.h" #include "vis.h" #include "aggregation.h" + #include "gateway_common.h" + #include "gateway_client.h" #include "unicast.h"
void slide_own_bcast_window(struct batman_if *batman_if) { struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); HASHIT(hashit); + struct element_t *bucket; struct orig_node *orig_node; TYPE_OF_WORD *word; - unsigned long flags;
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock);
while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]);
bit_get_packet(bat_priv, word, 1, 0); @@@ -53,7 -56,7 +56,7 @@@ bit_packet_count(word); }
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); }
static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node, @@@ -315,11 -318,23 +318,23 @@@ static void update_orig(struct bat_pri
update_routes(bat_priv, orig_node, neigh_node, hna_buff, tmp_hna_buff_len); - return; + goto update_gw;
update_hna: update_routes(bat_priv, orig_node, orig_node->router, hna_buff, tmp_hna_buff_len); + + update_gw: + if (orig_node->gw_flags != batman_packet->gw_flags) + gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); + + orig_node->gw_flags = batman_packet->gw_flags; + + /* restart gateway selection if fast or late switching was enabled */ + if ((orig_node->gw_flags) && + (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) && + (atomic_read(&bat_priv->gw_sel_class) > 2)) + gw_check_election(bat_priv, orig_node); }
/* checks whether the host restarted and is in the protection time. @@@ -747,7 -762,6 +762,6 @@@ int recv_bat_packet(struct sk_buff *skb { struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct ethhdr *ethhdr; - unsigned long flags;
/* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet)))) @@@ -756,11 -770,11 +770,11 @@@ ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with broadcast indication but unicast recipient */ - if (!is_bcast(ethhdr->h_dest)) + if (!is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP;
/* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP;
/* create a copy of the skb, if needed, to modify it. */ @@@ -773,12 -787,12 +787,12 @@@
ethhdr = (struct ethhdr *)skb_mac_header(skb);
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); receive_aggr_bat_packet(ethhdr, skb->data, skb_headlen(skb), batman_if); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
kfree_skb(skb); return NET_RX_SUCCESS; @@@ -792,7 -806,6 +806,6 @@@ static int recv_my_icmp_packet(struct b struct ethhdr *ethhdr; struct batman_if *batman_if; int ret; - unsigned long flags; uint8_t dstaddr[ETH_ALEN];
icmp_packet = (struct icmp_packet_rr *)skb->data; @@@ -809,8 -822,9 +822,9 @@@
/* answer echo request (ping) */ /* get routing information */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, choose_orig, icmp_packet->orig)); ret = NET_RX_DROP;
@@@ -821,7 -835,7 +835,7 @@@ * copy the required data before sending */ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
/* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@@ -840,7 -854,7 +854,7 @@@ ret = NET_RX_SUCCESS;
} else - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
return ret; } @@@ -853,7 -867,6 +867,6 @@@ static int recv_icmp_ttl_exceeded(struc struct ethhdr *ethhdr; struct batman_if *batman_if; int ret; - unsigned long flags; uint8_t dstaddr[ETH_ALEN];
icmp_packet = (struct icmp_packet *)skb->data; @@@ -871,9 -884,10 +884,10 @@@ return NET_RX_DROP;
/* get routing information */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, icmp_packet->orig)); + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, + icmp_packet->orig)); ret = NET_RX_DROP;
if ((orig_node != NULL) && @@@ -883,7 -897,7 +897,7 @@@ * copy the required data before sending */ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
/* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@@ -902,7 -916,7 +916,7 @@@ ret = NET_RX_SUCCESS;
} else - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
return ret; } @@@ -917,7 -931,6 +931,6 @@@ int recv_icmp_packet(struct sk_buff *sk struct batman_if *batman_if; int hdr_size = sizeof(struct icmp_packet); int ret; - unsigned long flags; uint8_t dstaddr[ETH_ALEN];
/** @@@ -933,11 -946,11 +946,11 @@@ ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */ - if (is_bcast(ethhdr->h_dest)) + if (is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP;
/* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP;
/* not for me */ @@@ -965,9 -978,10 +978,10 @@@ ret = NET_RX_DROP;
/* get routing information */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, icmp_packet->dst)); + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, + icmp_packet->dst));
if ((orig_node != NULL) && (orig_node->router != NULL)) { @@@ -976,7 -990,7 +990,7 @@@ * copy the required data before sending */ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
/* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@@ -993,7 -1007,7 +1007,7 @@@ ret = NET_RX_SUCCESS;
} else - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
return ret; } @@@ -1019,7 -1033,7 +1033,7 @@@ struct neigh_node *find_router(struct b /* without bonding, the first node should * always choose the default router. */
- bonding_enabled = atomic_read(&bat_priv->bonding_enabled); + bonding_enabled = atomic_read(&bat_priv->bonding);
if ((!recv_if) && (!bonding_enabled)) return orig_node->router; @@@ -1038,8 -1052,9 +1052,9 @@@ router_orig->orig, ETH_ALEN) == 0) { primary_orig_node = router_orig; } else { - primary_orig_node = hash_find(bat_priv->orig_hash, - router_orig->primary_addr); + primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig, + choose_orig, + router_orig->primary_addr);
if (!primary_orig_node) return orig_node->router; @@@ -1103,11 -1118,11 +1118,11 @@@ static int check_unicast_packet(struct ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */ - if (is_bcast(ethhdr->h_dest)) + if (is_broadcast_ether_addr(ethhdr->h_dest)) return -1;
/* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return -1;
/* not for me */ @@@ -1117,26 -1132,21 +1132,21 @@@ return 0; }
- static int route_unicast_packet(struct sk_buff *skb, - struct batman_if *recv_if, int hdr_size) + int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, + int hdr_size) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct orig_node *orig_node; struct neigh_node *router; struct batman_if *batman_if; uint8_t dstaddr[ETH_ALEN]; - unsigned long flags; struct unicast_packet *unicast_packet; struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); + int ret; + struct sk_buff *new_skb;
unicast_packet = (struct unicast_packet *)skb->data;
- /* packet for me */ - if (is_my_mac(unicast_packet->dest)) { - interface_rx(recv_if->soft_iface, skb, hdr_size); - return NET_RX_SUCCESS; - } - /* TTL exceeded */ if (unicast_packet->ttl < 2) { pr_debug("Warning - can't forward unicast packet from %pM to " @@@ -1146,14 -1156,15 +1156,15 @@@ }
/* get routing information */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, unicast_packet->dest)); + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, + unicast_packet->dest));
router = find_router(bat_priv, orig_node, recv_if);
if (!router) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return NET_RX_DROP; }
@@@ -1163,14 -1174,35 +1174,35 @@@ batman_if = router->if_incoming; memcpy(dstaddr, router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
/* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) return NET_RX_DROP;
unicast_packet = (struct unicast_packet *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); + + if (unicast_packet->packet_type == BAT_UNICAST && + atomic_read(&bat_priv->fragmentation) && + skb->len > batman_if->net_dev->mtu) + return frag_send_skb(skb, bat_priv, batman_if, + dstaddr); + + if (unicast_packet->packet_type == BAT_UNICAST_FRAG && + 2 * skb->len - hdr_size <= batman_if->net_dev->mtu) { + + ret = frag_reassemble_skb(skb, bat_priv, &new_skb); + + if (ret == NET_RX_DROP) + return NET_RX_DROP; + + /* packet was buffered for late merge */ + if (!new_skb) + return NET_RX_SUCCESS; + + skb = new_skb; + unicast_packet = (struct unicast_packet *)skb->data; + }
/* decrement ttl */ unicast_packet->ttl--; @@@ -1193,7 -1225,7 +1225,7 @@@ int recv_unicast_packet(struct sk_buff
/* packet for me */ if (is_my_mac(unicast_packet->dest)) { - interface_rx(recv_if->soft_iface, skb, hdr_size); + interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); return NET_RX_SUCCESS; }
@@@ -1204,10 -1236,9 +1236,9 @@@ int recv_ucast_frag_packet(struct sk_bu { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct unicast_frag_packet *unicast_packet; - struct orig_node *orig_node; - struct frag_packet_list_entry *tmp_frag_entry; int hdr_size = sizeof(struct unicast_frag_packet); - unsigned long flags; + struct sk_buff *new_skb = NULL; + int ret;
if (check_unicast_packet(skb, hdr_size) < 0) return NET_RX_DROP; @@@ -1217,44 -1248,17 +1248,17 @@@ /* packet for me */ if (is_my_mac(unicast_packet->dest)) {
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, unicast_packet->orig)); + ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
- if (!orig_node) { - pr_debug("couldn't find orig node for fragmentation\n"); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, - flags); + if (ret == NET_RX_DROP) return NET_RX_DROP; - } - - orig_node->last_frag_packet = jiffies;
- if (list_empty(&orig_node->frag_list) && - create_frag_buffer(&orig_node->frag_list)) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, - flags); - return NET_RX_DROP; - } - - tmp_frag_entry = - search_frag_packet(&orig_node->frag_list, - unicast_packet); - - if (!tmp_frag_entry) { - create_frag_entry(&orig_node->frag_list, skb); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, - flags); + /* packet was buffered for late merge */ + if (!new_skb) return NET_RX_SUCCESS; - } - - skb = merge_frag_packet(&orig_node->frag_list, - tmp_frag_entry, skb); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); - if (!skb) - return NET_RX_DROP;
- interface_rx(recv_if->soft_iface, skb, hdr_size); + interface_rx(recv_if->soft_iface, new_skb, recv_if, + sizeof(struct unicast_packet)); return NET_RX_SUCCESS; }
@@@ -1270,7 -1274,6 +1274,6 @@@ int recv_bcast_packet(struct sk_buff *s struct ethhdr *ethhdr; int hdr_size = sizeof(struct bcast_packet); int32_t seq_diff; - unsigned long flags;
/* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, hdr_size))) @@@ -1279,11 -1282,11 +1282,11 @@@ ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with broadcast indication but unicast recipient */ - if (!is_bcast(ethhdr->h_dest)) + if (!is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP;
/* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP;
/* ignore broadcasts sent by myself */ @@@ -1299,12 -1302,13 +1302,13 @@@ if (bcast_packet->ttl < 2) return NET_RX_DROP;
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, bcast_packet->orig)); + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, + bcast_packet->orig));
if (orig_node == NULL) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return NET_RX_DROP; }
@@@ -1312,7 -1316,7 +1316,7 @@@ if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, ntohl(bcast_packet->seqno))) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return NET_RX_DROP; }
@@@ -1321,7 -1325,7 +1325,7 @@@ /* check whether the packet is old and the host just restarted. */ if (window_protected(bat_priv, seq_diff, &orig_node->bcast_seqno_reset)) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return NET_RX_DROP; }
@@@ -1330,12 -1334,12 +1334,12 @@@ if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); /* rebroadcast packet */ add_bcast_packet_to_list(bat_priv, skb);
/* broadcast for me */ - interface_rx(recv_if->soft_iface, skb, hdr_size); + interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
return NET_RX_SUCCESS; } diff --combined drivers/staging/batman-adv/routing.h index 92674c8,f108f23..f108f23 --- a/drivers/staging/batman-adv/routing.h +++ b/drivers/staging/batman-adv/routing.h @@@ -32,6 -32,8 +32,8 @@@ void receive_bat_packet(struct ethhdr * void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); + int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, + int hdr_size); int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if); diff --combined drivers/staging/batman-adv/send.c index 7adf76d,b89b9f7..b89b9f7 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@@ -28,14 -28,16 +28,16 @@@ #include "types.h" #include "vis.h" #include "aggregation.h" - + #include "gateway_common.h" + #include "originator.h"
static void send_outstanding_bcast_packet(struct work_struct *work);
/* apply hop penalty for a normal link */ - static uint8_t hop_penalty(const uint8_t tq) + static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv) { - return (tq * (TQ_MAX_VALUE - TQ_HOP_PENALTY)) / (TQ_MAX_VALUE); + int hop_penalty = atomic_read(&bat_priv->hop_penalty); + return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE); }
/* when do we schedule our own packet to be sent */ @@@ -282,6 -284,13 +284,13 @@@ void schedule_own_packet(struct batman_ else batman_packet->flags &= ~VIS_SERVER;
+ if ((batman_if == bat_priv->primary_if) && + (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) + batman_packet->gw_flags = + (uint8_t)atomic_read(&bat_priv->gw_bandwidth); + else + batman_packet->gw_flags = 0; + atomic_inc(&batman_if->seqno);
slide_own_bcast_window(batman_if); @@@ -330,7 -339,7 +339,7 @@@ void schedule_forward_packet(struct ori }
/* apply hop penalty */ - batman_packet->tq = hop_penalty(batman_packet->tq); + batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv);
bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: tq_orig: %i, tq_avg: %i, " @@@ -365,13 -374,12 +374,12 @@@ static void _add_bcast_packet_to_list(s struct forw_packet *forw_packet, unsigned long send_time) { INIT_HLIST_NODE(&forw_packet->list);
/* add new packet to packet list */ - spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bcast_list_lock); hlist_add_head(&forw_packet->list, &bat_priv->forw_bcast_list); - spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
/* start timer for this packet */ INIT_DELAYED_WORK(&forw_packet->delayed_work, @@@ -441,14 -449,13 +449,13 @@@ static void send_outstanding_bcast_pack container_of(work, struct delayed_work, work); struct forw_packet *forw_packet = container_of(delayed_work, struct forw_packet, delayed_work); - unsigned long flags; struct sk_buff *skb1; struct net_device *soft_iface = forw_packet->if_incoming->soft_iface; struct bat_priv *bat_priv = netdev_priv(soft_iface);
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bcast_list_lock); hlist_del(&forw_packet->list); - spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) goto out; @@@ -486,13 -493,12 +493,12 @@@ void send_outstanding_bat_packet(struc container_of(work, struct delayed_work, work); struct forw_packet *forw_packet = container_of(delayed_work, struct forw_packet, delayed_work); struct bat_priv *bat_priv;
bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface); - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); hlist_del(&forw_packet->list); - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock);
if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) goto out; @@@ -520,7 -526,6 +526,6 @@@ void purge_outstanding_packets(struct b { struct forw_packet *forw_packet; struct hlist_node *tmp_node, *safe_tmp_node; - unsigned long flags;
if (batman_if) bat_dbg(DBG_BATMAN, bat_priv, @@@ -531,7 -536,7 +536,7 @@@ "purge_outstanding_packets()\n");
/* free bcast list */ - spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bcast_list_lock); hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, &bat_priv->forw_bcast_list, list) {
@@@ -543,19 -548,19 +548,19 @@@ (forw_packet->if_incoming != batman_if)) continue;
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
/** * send_outstanding_bcast_packet() will lock the list to * delete the item from the list */ cancel_delayed_work_sync(&forw_packet->delayed_work); - spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bcast_list_lock); } - spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
/* free batman packet list */ - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, &bat_priv->forw_bat_list, list) {
@@@ -567,14 -572,14 +572,14 @@@ (forw_packet->if_incoming != batman_if)) continue;
- spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock);
/** * send_outstanding_bat_packet() will lock the list to * delete the item from the list */ cancel_delayed_work_sync(&forw_packet->delayed_work); - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); } - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); } diff --combined drivers/staging/batman-adv/soft-interface.c index 3904db9,e89ede1..e89ede1 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@@ -28,12 -28,16 +28,16 @@@ #include "translation-table.h" #include "types.h" #include "hash.h" + #include "gateway_common.h" + #include "gateway_client.h" #include "send.h" #include "bat_sysfs.h" #include <linux/slab.h> #include <linux/ethtool.h> #include <linux/etherdevice.h> + #include <linux/if_vlan.h> #include "unicast.h" + #include "routing.h"
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); @@@ -75,6 -79,218 +79,218 @@@ int my_skb_head_push(struct sk_buff *sk return 0; }
+ static void softif_neigh_free_ref(struct kref *refcount) + { + struct softif_neigh *softif_neigh; + + softif_neigh = container_of(refcount, struct softif_neigh, refcount); + kfree(softif_neigh); + } + + static void softif_neigh_free_rcu(struct rcu_head *rcu) + { + struct softif_neigh *softif_neigh; + + softif_neigh = container_of(rcu, struct softif_neigh, rcu); + kref_put(&softif_neigh->refcount, softif_neigh_free_ref); + } + + void softif_neigh_purge(struct bat_priv *bat_priv) + { + struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct hlist_node *node, *node_tmp; + + spin_lock_bh(&bat_priv->softif_neigh_lock); + + hlist_for_each_entry_safe(softif_neigh, node, node_tmp, + &bat_priv->softif_neigh_list, list) { + + if ((!time_after(jiffies, softif_neigh->last_seen + + msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && + (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) + continue; + + hlist_del_rcu(&softif_neigh->list); + + if (bat_priv->softif_neigh == softif_neigh) { + bat_dbg(DBG_ROUTES, bat_priv, + "Current mesh exit point '%pM' vanished " + "(vid: %d).\n", + softif_neigh->addr, softif_neigh->vid); + softif_neigh_tmp = bat_priv->softif_neigh; + bat_priv->softif_neigh = NULL; + kref_put(&softif_neigh_tmp->refcount, + softif_neigh_free_ref); + } + + call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); + } + + spin_unlock_bh(&bat_priv->softif_neigh_lock); + } + + static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, + uint8_t *addr, short vid) + { + struct softif_neigh *softif_neigh; + struct hlist_node *node; + + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh, node, + &bat_priv->softif_neigh_list, list) { + if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) + continue; + + if (softif_neigh->vid != vid) + continue; + + softif_neigh->last_seen = jiffies; + goto found; + } + + softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); + if (!softif_neigh) + goto out; + + memcpy(softif_neigh->addr, addr, ETH_ALEN); + softif_neigh->vid = vid; + softif_neigh->last_seen = jiffies; + kref_init(&softif_neigh->refcount); + + INIT_HLIST_NODE(&softif_neigh->list); + spin_lock_bh(&bat_priv->softif_neigh_lock); + hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); + spin_unlock_bh(&bat_priv->softif_neigh_lock); + + found: + kref_get(&softif_neigh->refcount); + out: + rcu_read_unlock(); + return softif_neigh; + } + + int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) + { + struct net_device *net_dev = (struct net_device *)seq->private; + struct bat_priv *bat_priv = netdev_priv(net_dev); + struct softif_neigh *softif_neigh; + struct hlist_node *node; + size_t buf_size, pos; + char *buff; + + if (!bat_priv->primary_if) { + return seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + } + + seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); + + buf_size = 1; + /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */ + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh, node, + &bat_priv->softif_neigh_list, list) + buf_size += 30; + rcu_read_unlock(); + + buff = kmalloc(buf_size, GFP_ATOMIC); + if (!buff) + return -ENOMEM; + + buff[0] = '\0'; + pos = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh, node, + &bat_priv->softif_neigh_list, list) { + pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n", + bat_priv->softif_neigh == softif_neigh + ? "=>" : " ", softif_neigh->addr, + softif_neigh->vid); + } + rcu_read_unlock(); + + seq_printf(seq, "%s", buff); + kfree(buff); + return 0; + } + + static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, + short vid) + { + struct bat_priv *bat_priv = netdev_priv(dev); + struct ethhdr *ethhdr = (struct ethhdr *)skb->data; + struct batman_packet *batman_packet; + struct softif_neigh *softif_neigh, *softif_neigh_tmp; + + if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) + batman_packet = (struct batman_packet *) + (skb->data + ETH_HLEN + VLAN_HLEN); + else + batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); + + if (batman_packet->version != COMPAT_VERSION) + goto err; + + if (batman_packet->packet_type != BAT_PACKET) + goto err; + + if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) + goto err; + + if (is_my_mac(batman_packet->orig)) + goto err; + + softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); + + if (!softif_neigh) + goto err; + + if (bat_priv->softif_neigh == softif_neigh) + goto out; + + /* we got a neighbor but its mac is 'bigger' than ours */ + if (memcmp(bat_priv->primary_if->net_dev->dev_addr, + softif_neigh->addr, ETH_ALEN) < 0) + goto out; + + /* switch to new 'smallest neighbor' */ + if ((bat_priv->softif_neigh) && + (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, + ETH_ALEN) < 0)) { + bat_dbg(DBG_ROUTES, bat_priv, + "Changing mesh exit point from %pM (vid: %d) " + "to %pM (vid: %d).\n", + bat_priv->softif_neigh->addr, + bat_priv->softif_neigh->vid, + softif_neigh->addr, softif_neigh->vid); + softif_neigh_tmp = bat_priv->softif_neigh; + bat_priv->softif_neigh = softif_neigh; + kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); + /* we need to hold the additional reference */ + goto err; + } + + /* close own batX device and use softif_neigh as exit node */ + if ((!bat_priv->softif_neigh) && + (memcmp(softif_neigh->addr, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { + bat_dbg(DBG_ROUTES, bat_priv, + "Setting mesh exit point to %pM (vid: %d).\n", + softif_neigh->addr, softif_neigh->vid); + bat_priv->softif_neigh = softif_neigh; + /* we need to hold the additional reference */ + goto err; + } + + out: + kref_put(&softif_neigh->refcount, softif_neigh_free_ref); + err: + kfree_skb(skb); + return; + } + static int interface_open(struct net_device *dev) { netif_start_queue(dev); @@@ -109,7 -325,6 +325,6 @@@ static int interface_set_mac_addr(struc }
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); - return 0; }
@@@ -129,18 -344,52 +344,52 @@@ int interface_tx(struct sk_buff *skb, s struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bcast_packet *bcast_packet; + struct vlan_ethhdr *vhdr; int data_len = skb->len, ret; + short vid = -1; + bool do_bcast = false;
if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dropped;
soft_iface->trans_start = jiffies;
+ switch (ntohs(ethhdr->h_proto)) { + case ETH_P_8021Q: + vhdr = (struct vlan_ethhdr *)skb->data; + vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; + + if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) + break; + + /* fall through */ + case ETH_P_BATMAN: + softif_batman_recv(skb, soft_iface, vid); + goto end; + } + + /** + * if we have a another chosen mesh exit node in range + * it will transport the packets to the mesh + */ + if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) + goto dropped; + /* TODO: check this for locks */ hna_local_add(soft_iface, ethhdr->h_source);
+ if (is_multicast_ether_addr(ethhdr->h_dest)) { + ret = gw_is_target(bat_priv, skb); + + if (ret < 0) + goto dropped; + + if (ret == 0) + do_bcast = true; + } + /* ethernet packet should be broadcasted */ - if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) { + if (do_bcast) { if (!bat_priv->primary_if) goto dropped;
@@@ -189,19 -438,64 +438,64 @@@ end }
void interface_rx(struct net_device *soft_iface, - struct sk_buff *skb, int hdr_size) + struct sk_buff *skb, struct batman_if *recv_if, + int hdr_size) { - struct bat_priv *priv = netdev_priv(soft_iface); + struct bat_priv *bat_priv = netdev_priv(soft_iface); + struct unicast_packet *unicast_packet; + struct ethhdr *ethhdr; + struct vlan_ethhdr *vhdr; + short vid = -1; + int ret;
/* check if enough space is available for pulling, and pull */ - if (!pskb_may_pull(skb, hdr_size)) { - kfree_skb(skb); - return; - } + if (!pskb_may_pull(skb, hdr_size)) + goto dropped; + skb_pull_rcsum(skb, hdr_size); - /* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/ + skb_reset_mac_header(skb); + + ethhdr = (struct ethhdr *)skb_mac_header(skb); + + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_8021Q: + vhdr = (struct vlan_ethhdr *)skb->data; + vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; + + if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) + break; + + /* fall through */ + case ETH_P_BATMAN: + goto dropped; + } + + /** + * if we have a another chosen mesh exit node in range + * it will transport the packets to the non-mesh network + */ + if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { + skb_push(skb, hdr_size); + unicast_packet = (struct unicast_packet *)skb->data; + + if ((unicast_packet->packet_type != BAT_UNICAST) && + (unicast_packet->packet_type != BAT_UNICAST_FRAG)) + goto dropped; + + skb_reset_mac_header(skb); + + memcpy(unicast_packet->dest, + bat_priv->softif_neigh->addr, ETH_ALEN); + ret = route_unicast_packet(skb, recv_if, hdr_size); + if (ret == NET_RX_DROP) + goto dropped; + + goto out; + }
/* skb->dev & skb->pkt_type are set here */ + if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) + goto dropped; skb->protocol = eth_type_trans(skb, soft_iface);
/* should not be neccesary anymore as we use skb_pull_rcsum() @@@ -210,12 -504,18 +504,18 @@@
/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/
- priv->stats.rx_packets++; - priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr); + bat_priv->stats.rx_packets++; + bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr);
soft_iface->last_rx = jiffies;
netif_rx(skb); + return; + + dropped: + kfree_skb(skb); + out: + return; }
#ifdef HAVE_NET_DEVICE_OPS @@@ -289,12 -589,16 +589,16 @@@ struct net_device *softif_create(char *
bat_priv = netdev_priv(soft_iface);
- atomic_set(&bat_priv->aggregation_enabled, 1); - atomic_set(&bat_priv->bonding_enabled, 0); + atomic_set(&bat_priv->aggregated_ogms, 1); + atomic_set(&bat_priv->bonding, 0); atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); + atomic_set(&bat_priv->gw_mode, GW_MODE_OFF); + atomic_set(&bat_priv->gw_sel_class, 20); + atomic_set(&bat_priv->gw_bandwidth, 41); atomic_set(&bat_priv->orig_interval, 1000); + atomic_set(&bat_priv->hop_penalty, 10); atomic_set(&bat_priv->log_level, 0); - atomic_set(&bat_priv->frag_enabled, 1); + atomic_set(&bat_priv->fragmentation, 1); atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN); atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN);
@@@ -304,6 -608,7 +608,7 @@@
bat_priv->primary_if = NULL; bat_priv->num_ifaces = 0; + bat_priv->softif_neigh = NULL;
ret = sysfs_add_meshif(soft_iface); if (ret < 0) diff --combined drivers/staging/batman-adv/soft-interface.h index 843a7ec,02b7733..02b7733 --- a/drivers/staging/batman-adv/soft-interface.h +++ b/drivers/staging/batman-adv/soft-interface.h @@@ -23,9 -23,12 +23,12 @@@ #define _NET_BATMAN_ADV_SOFT_INTERFACE_H_
int my_skb_head_push(struct sk_buff *skb, unsigned int len); + int softif_neigh_seq_print_text(struct seq_file *seq, void *offset); + void softif_neigh_purge(struct bat_priv *bat_priv); int interface_tx(struct sk_buff *skb, struct net_device *soft_iface); void interface_rx(struct net_device *soft_iface, - struct sk_buff *skb, int hdr_size); + struct sk_buff *skb, struct batman_if *recv_if, + int hdr_size); struct net_device *softif_create(char *name); void softif_destroy(struct net_device *soft_iface);
diff --combined drivers/staging/batman-adv/sysfs-class-net-mesh index b4cdb60,748fe17..748fe17 --- a/drivers/staging/batman-adv/sysfs-class-net-mesh +++ b/drivers/staging/batman-adv/sysfs-class-net-mesh @@@ -22,6 -22,27 +22,27 @@@ Description mesh will be fragmented or silently discarded if the packet size exceeds the outgoing interface MTU.
+ What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth + Date: October 2010 + Contact: Marek Lindner lindner_marek@yahoo.de + Description: + Defines the bandwidth which is propagated by this + node if gw_mode was set to 'server'. + + What: /sys/class/net/<mesh_iface>/mesh/gw_mode + Date: October 2010 + Contact: Marek Lindner lindner_marek@yahoo.de + Description: + Defines the state of the gateway features. Can be + either 'off', 'client' or 'server'. + + What: /sys/class/net/<mesh_iface>/mesh/gw_sel_class + Date: October 2010 + Contact: Marek Lindner lindner_marek@yahoo.de + Description: + Defines the selection criteria this node will use + to choose a gateway if gw_mode was set to 'client'. + What: /sys/class/net/<mesh_iface>/mesh/orig_interval Date: May 2010 Contact: Marek Lindner lindner_marek@yahoo.de @@@ -29,6 -50,13 +50,13 @@@ Description Defines the interval in milliseconds in which batman sends its protocol messages.
+ What: /sys/class/net/<mesh_iface>/mesh/hop_penalty + Date: Oct 2010 + Contact: Linus Lüssing linus.luessing@web.de + Description: + Defines the penalty which will be applied to an + originator message's tq-field on every hop. + What: /sys/class/net/<mesh_iface>/mesh/vis_mode Date: May 2010 Contact: Marek Lindner lindner_marek@yahoo.de diff --combined drivers/staging/batman-adv/translation-table.c index 681ccbd,4b0a107..4b0a107 --- a/drivers/staging/batman-adv/translation-table.c +++ b/drivers/staging/batman-adv/translation-table.c @@@ -24,6 -24,7 +24,7 @@@ #include "soft-interface.h" #include "types.h" #include "hash.h" + #include "originator.h"
static void hna_local_purge(struct work_struct *work); static void _hna_global_del_orig(struct bat_priv *bat_priv, @@@ -41,7 -42,7 +42,7 @@@ int hna_local_init(struct bat_priv *bat if (bat_priv->hna_local_hash) return 1;
- bat_priv->hna_local_hash = hash_new(128, compare_orig, choose_orig); + bat_priv->hna_local_hash = hash_new(128);
if (!bat_priv->hna_local_hash) return 0; @@@ -58,14 -59,14 +59,14 @@@ void hna_local_add(struct net_device *s struct hna_local_entry *hna_local_entry; struct hna_global_entry *hna_global_entry; struct hashtable_t *swaphash; - unsigned long flags; int required_bytes;
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); hna_local_entry = ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, + compare_orig, choose_orig, addr)); - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock);
if (hna_local_entry) { hna_local_entry->last_seen = jiffies; @@@ -79,7 -80,7 +80,7 @@@ required_bytes += BAT_PACKET_LEN;
if ((required_bytes > ETH_DATA_LEN) || - (atomic_read(&bat_priv->aggregation_enabled) && + (atomic_read(&bat_priv->aggregated_ogms) && required_bytes > MAX_AGGREGATION_BYTES) || (bat_priv->num_local_hna + 1 > 255)) { bat_dbg(DBG_ROUTES, bat_priv, @@@ -105,15 -106,16 +106,16 @@@ else hna_local_entry->never_purge = 0;
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock);
- hash_add(bat_priv->hna_local_hash, hna_local_entry); + hash_add(bat_priv->hna_local_hash, compare_orig, choose_orig, + hna_local_entry); bat_priv->num_local_hna++; atomic_set(&bat_priv->hna_local_changed, 1);
if (bat_priv->hna_local_hash->elements * 4 > bat_priv->hna_local_hash->size) { - swaphash = hash_resize(bat_priv->hna_local_hash, + swaphash = hash_resize(bat_priv->hna_local_hash, choose_orig, bat_priv->hna_local_hash->size * 2);
if (!swaphash) @@@ -122,37 -124,39 +124,39 @@@ bat_priv->hna_local_hash = swaphash; }
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock);
/* remove address from global hash if present */ - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock);
hna_global_entry = ((struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, addr)); + hash_find(bat_priv->hna_global_hash, + compare_orig, choose_orig, addr));
if (hna_global_entry) _hna_global_del_orig(bat_priv, hna_global_entry, "local hna received");
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); }
int hna_local_fill_buffer(struct bat_priv *bat_priv, unsigned char *buff, int buff_len) { struct hna_local_entry *hna_local_entry; + struct element_t *bucket; HASHIT(hashit); int i = 0; - unsigned long flags;
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock);
while (hash_iterate(bat_priv->hna_local_hash, &hashit)) {
if (buff_len < (i + 1) * ETH_ALEN) break;
- hna_local_entry = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + hna_local_entry = bucket->data; memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
i++; @@@ -162,7 -166,7 +166,7 @@@ if (i == bat_priv->num_local_hna) atomic_set(&bat_priv->hna_local_changed, 0);
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); return i; }
@@@ -173,7 -177,7 +177,7 @@@ int hna_local_seq_print_text(struct seq struct hna_local_entry *hna_local_entry; HASHIT(hashit); HASHIT(hashit_count); - unsigned long flags; + struct element_t *bucket; size_t buf_size, pos; char *buff;
@@@ -187,7 -191,7 +191,7 @@@ "announced via HNA:\n", net_dev->name);
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock);
buf_size = 1; /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */ @@@ -196,20 -200,21 +200,21 @@@
buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); return -ENOMEM; } buff[0] = '\0'; pos = 0;
while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { - hna_local_entry = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + hna_local_entry = bucket->data;
pos += snprintf(buff + pos, 22, " * %pM\n", hna_local_entry->addr); }
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock);
seq_printf(seq, "%s", buff); kfree(buff); @@@ -232,7 -237,8 +237,8 @@@ static void hna_local_del(struct bat_pr bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n", hna_local_entry->addr, message);
- hash_remove(bat_priv->hna_local_hash, hna_local_entry->addr); + hash_remove(bat_priv->hna_local_hash, compare_orig, choose_orig, + hna_local_entry->addr); _hna_local_del(hna_local_entry, bat_priv); }
@@@ -240,16 -246,16 +246,16 @@@ void hna_local_remove(struct bat_priv * uint8_t *addr, char *message) { struct hna_local_entry *hna_local_entry; - unsigned long flags;
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock);
hna_local_entry = (struct hna_local_entry *) - hash_find(bat_priv->hna_local_hash, addr); + hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig, + addr); if (hna_local_entry) hna_local_del(bat_priv, hna_local_entry, message);
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); }
static void hna_local_purge(struct work_struct *work) @@@ -260,13 -266,14 +266,14 @@@ container_of(delayed_work, struct bat_priv, hna_work); struct hna_local_entry *hna_local_entry; HASHIT(hashit); - unsigned long flags; + struct element_t *bucket; unsigned long timeout;
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock);
while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { - hna_local_entry = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + hna_local_entry = bucket->data;
timeout = hna_local_entry->last_seen + LOCAL_HNA_TIMEOUT * HZ;
@@@ -276,7 -283,7 +283,7 @@@ "address timed out"); }
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); hna_local_start_timer(bat_priv); }
@@@ -295,7 -302,7 +302,7 @@@ int hna_global_init(struct bat_priv *ba if (bat_priv->hna_global_hash) return 1;
- bat_priv->hna_global_hash = hash_new(128, compare_orig, choose_orig); + bat_priv->hna_global_hash = hash_new(128);
if (!bat_priv->hna_global_hash) return 0; @@@ -311,19 -318,18 +318,18 @@@ void hna_global_add_orig(struct bat_pri struct hna_local_entry *hna_local_entry; struct hashtable_t *swaphash; int hna_buff_count = 0; unsigned char *hna_ptr;
while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock);
hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, hna_ptr); + hash_find(bat_priv->hna_global_hash, compare_orig, + choose_orig, hna_ptr);
if (!hna_global_entry) { - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, - flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock);
hna_global_entry = kmalloc(sizeof(struct hna_global_entry), @@@ -339,26 -345,28 +345,28 @@@ "%pM (via %pM)\n", hna_global_entry->addr, orig_node->orig);
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); - hash_add(bat_priv->hna_global_hash, hna_global_entry); + spin_lock_bh(&bat_priv->hna_ghash_lock); + hash_add(bat_priv->hna_global_hash, compare_orig, + choose_orig, hna_global_entry);
}
hna_global_entry->orig_node = orig_node; - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock);
/* remove address from local hash if present */ - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock);
hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_local_entry = (struct hna_local_entry *) - hash_find(bat_priv->hna_local_hash, hna_ptr); + hash_find(bat_priv->hna_local_hash, compare_orig, + choose_orig, hna_ptr);
if (hna_local_entry) hna_local_del(bat_priv, hna_local_entry, "global hna received");
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock);
hna_buff_count++; } @@@ -375,11 -383,11 +383,11 @@@ } }
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock);
if (bat_priv->hna_global_hash->elements * 4 > bat_priv->hna_global_hash->size) { - swaphash = hash_resize(bat_priv->hna_global_hash, + swaphash = hash_resize(bat_priv->hna_global_hash, choose_orig, bat_priv->hna_global_hash->size * 2);
if (!swaphash) @@@ -388,7 -396,7 +396,7 @@@ bat_priv->hna_global_hash = swaphash; }
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); }
int hna_global_seq_print_text(struct seq_file *seq, void *offset) @@@ -398,7 -406,7 +406,7 @@@ struct hna_global_entry *hna_global_entry; HASHIT(hashit); HASHIT(hashit_count); - unsigned long flags; + struct element_t *bucket; size_t buf_size, pos; char *buff;
@@@ -411,7 -419,7 +419,7 @@@ seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", net_dev->name);
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock);
buf_size = 1; /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ @@@ -420,21 -428,22 +428,22 @@@
buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); return -ENOMEM; } buff[0] = '\0'; pos = 0;
while (hash_iterate(bat_priv->hna_global_hash, &hashit)) { - hna_global_entry = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + hna_global_entry = bucket->data;
pos += snprintf(buff + pos, 44, " * %pM via %pM\n", hna_global_entry->addr, hna_global_entry->orig_node->orig); }
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock);
seq_printf(seq, "%s", buff); kfree(buff); @@@ -450,7 -459,8 +459,8 @@@ static void _hna_global_del_orig(struc hna_global_entry->addr, hna_global_entry->orig_node->orig, message);
- hash_remove(bat_priv->hna_global_hash, hna_global_entry->addr); + hash_remove(bat_priv->hna_global_hash, compare_orig, choose_orig, + hna_global_entry->addr); kfree(hna_global_entry); }
@@@ -459,18 -469,18 +469,18 @@@ void hna_global_del_orig(struct bat_pri { struct hna_global_entry *hna_global_entry; int hna_buff_count = 0; - unsigned long flags; unsigned char *hna_ptr;
if (orig_node->hna_buff_len == 0) return;
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock);
while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, hna_ptr); + hash_find(bat_priv->hna_global_hash, compare_orig, + choose_orig, hna_ptr);
if ((hna_global_entry) && (hna_global_entry->orig_node == orig_node)) @@@ -480,7 -490,7 +490,7 @@@ hna_buff_count++; }
- spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock);
orig_node->hna_buff_len = 0; kfree(orig_node->hna_buff); @@@ -504,12 -514,12 +514,12 @@@ void hna_global_free(struct bat_priv *b struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr) { struct hna_global_entry *hna_global_entry; - unsigned long flags;
- spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock); hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, addr); - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + hash_find(bat_priv->hna_global_hash, + compare_orig, choose_orig, addr); + spin_unlock_bh(&bat_priv->hna_ghash_lock);
if (!hna_global_entry) return NULL; diff --combined drivers/staging/batman-adv/types.h index f3f7366,1d00849..1d00849 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@@ -43,9 -43,10 +43,10 @@@ struct batman_if unsigned char *packet_buff; int packet_len; struct kobject *hardif_obj; - atomic_t refcnt; + struct kref refcount; struct packet_type batman_adv_ptype; struct net_device *soft_iface; + struct rcu_head rcu; };
/** @@@ -54,6 -55,7 +55,7 @@@ * @last_valid: when last packet from this node was received * @bcast_seqno_reset: time when the broadcast seqno window was reset * @batman_seqno_reset: time when the batman seqno window was reset + * @gw_flags: flags related to gateway class * @flags: for now only VIS_SERVER flag * @last_real_seqno: last and best known squence number * @last_ttl: ttl of last received packet @@@ -73,7 -75,8 +75,8 @@@ struct orig_node unsigned long last_valid; unsigned long bcast_seqno_reset; unsigned long batman_seqno_reset; - uint8_t flags; + uint8_t gw_flags; + uint8_t flags; unsigned char *hna_buff; int16_t hna_buff_len; uint32_t last_real_seqno; @@@ -89,6 -92,14 +92,14 @@@ } bond; };
+ struct gw_node { + struct hlist_node list; + struct orig_node *orig_node; + unsigned long deleted; + struct kref refcount; + struct rcu_head rcu; + }; + /** * neigh_node * @last_valid: when last packet via this neighbor was received @@@ -112,22 -123,29 +123,29 @@@ struct neigh_node struct bat_priv { atomic_t mesh_state; struct net_device_stats stats; - atomic_t aggregation_enabled; - atomic_t bonding_enabled; - atomic_t frag_enabled; - atomic_t vis_mode; - atomic_t orig_interval; - atomic_t log_level; + atomic_t aggregated_ogms; /* boolean */ + atomic_t bonding; /* boolean */ + atomic_t fragmentation; /* boolean */ + atomic_t vis_mode; /* VIS_TYPE_* */ + atomic_t gw_mode; /* GW_MODE_* */ + atomic_t gw_sel_class; /* uint */ + atomic_t gw_bandwidth; /* gw bandwidth */ + atomic_t orig_interval; /* uint */ + atomic_t hop_penalty; /* uint */ + atomic_t log_level; /* uint */ atomic_t bcast_seqno; atomic_t bcast_queue_left; atomic_t batman_queue_left; char num_ifaces; + struct hlist_head softif_neigh_list; + struct softif_neigh *softif_neigh; struct debug_log *debug_log; struct batman_if *primary_if; struct kobject *mesh_obj; struct dentry *debug_dir; struct hlist_head forw_bat_list; struct hlist_head forw_bcast_list; + struct hlist_head gw_list; struct list_head vis_send_list; struct hashtable_t *orig_hash; struct hashtable_t *hna_local_hash; @@@ -138,13 -156,16 +156,16 @@@ spinlock_t forw_bcast_list_lock; /* protects */ spinlock_t hna_lhash_lock; /* protects hna_local_hash */ spinlock_t hna_ghash_lock; /* protects hna_global_hash */ + spinlock_t gw_list_lock; /* protects gw_list */ spinlock_t vis_hash_lock; /* protects vis_hash */ spinlock_t vis_list_lock; /* protects vis_info::recv_list */ + spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ int16_t num_local_hna; atomic_t hna_local_changed; struct delayed_work hna_work; struct delayed_work orig_work; struct delayed_work vis_work; + struct gw_node *curr_gw; struct vis_info *my_vis_info; };
@@@ -238,4 -259,13 +259,13 @@@ struct recvlist_node uint8_t mac[ETH_ALEN]; };
+ struct softif_neigh { + struct hlist_node list; + uint8_t addr[ETH_ALEN]; + unsigned long last_seen; + short vid; + struct kref refcount; + struct rcu_head rcu; + }; + #endif /* _NET_BATMAN_ADV_TYPES_H_ */ diff --combined drivers/staging/batman-adv/unicast.c index 0459413,dc2e28b..dc2e28b --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@@ -23,19 -23,24 +23,24 @@@ #include "unicast.h" #include "send.h" #include "soft-interface.h" + #include "gateway_client.h" + #include "originator.h" #include "hash.h" #include "translation-table.h" #include "routing.h" #include "hard-interface.h"
- struct sk_buff *merge_frag_packet(struct list_head *head, - struct frag_packet_list_entry *tfp, - struct sk_buff *skb) + static struct sk_buff *frag_merge_packet(struct list_head *head, + struct frag_packet_list_entry *tfp, + struct sk_buff *skb) { struct unicast_frag_packet *up = (struct unicast_frag_packet *)skb->data; struct sk_buff *tmp_skb; + struct unicast_packet *unicast_packet; + int hdr_len = sizeof(struct unicast_packet), + uni_diff = sizeof(struct unicast_frag_packet) - hdr_len;
/* set skb to the first part and tmp_skb to the second part */ if (up->flags & UNI_FRAG_HEAD) { @@@ -59,10 -64,15 +64,15 @@@
memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len); kfree_skb(tmp_skb); + + memmove(skb->data + uni_diff, skb->data, hdr_len); + unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff); + unicast_packet->packet_type = BAT_UNICAST; + return skb; }
- void create_frag_entry(struct list_head *head, struct sk_buff *skb) + static void frag_create_entry(struct list_head *head, struct sk_buff *skb) { struct frag_packet_list_entry *tfp; struct unicast_frag_packet *up = @@@ -78,7 -88,7 +88,7 @@@ return; }
- int create_frag_buffer(struct list_head *head) + static int frag_create_buffer(struct list_head *head) { int i; struct frag_packet_list_entry *tfp; @@@ -99,7 -109,7 +109,7 @@@ return 0; }
- struct frag_packet_list_entry *search_frag_packet(struct list_head *head, + static struct frag_packet_list_entry *frag_search_packet(struct list_head *head, struct unicast_frag_packet *up) { struct frag_packet_list_entry *tfp; @@@ -152,55 -162,112 +162,112 @@@ void frag_list_free(struct list_head *h return; }
- static int unicast_send_frag_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct batman_if *batman_if, uint8_t dstaddr[], - struct orig_node *orig_node) + /* frag_reassemble_skb(): + * returns NET_RX_DROP if the operation failed - skb is left intact + * returns NET_RX_SUCCESS if the fragment was buffered (skb_new will be NULL) + * or the skb could be reassembled (skb_new will point to the new packet and + * skb was freed) + */ + int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct sk_buff **new_skb) { - struct unicast_frag_packet *ucast_frag1, *ucast_frag2; - int hdr_len = sizeof(struct unicast_frag_packet); + struct orig_node *orig_node; + struct frag_packet_list_entry *tmp_frag_entry; + int ret = NET_RX_DROP; + struct unicast_frag_packet *unicast_packet = + (struct unicast_frag_packet *)skb->data; + + *new_skb = NULL; + spin_lock_bh(&bat_priv->orig_hash_lock); + orig_node = ((struct orig_node *) + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, + unicast_packet->orig)); + + if (!orig_node) { + pr_debug("couldn't find originator in orig_hash\n"); + goto out; + } + + orig_node->last_frag_packet = jiffies; + + if (list_empty(&orig_node->frag_list) && + frag_create_buffer(&orig_node->frag_list)) { + pr_debug("couldn't create frag buffer\n"); + goto out; + } + + tmp_frag_entry = frag_search_packet(&orig_node->frag_list, + unicast_packet); + + if (!tmp_frag_entry) { + frag_create_entry(&orig_node->frag_list, skb); + ret = NET_RX_SUCCESS; + goto out; + } + + *new_skb = frag_merge_packet(&orig_node->frag_list, tmp_frag_entry, + skb); + /* if not, merge failed */ + if (*new_skb) + ret = NET_RX_SUCCESS; + out: + spin_unlock_bh(&bat_priv->orig_hash_lock); + + return ret; + } + + int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct batman_if *batman_if, uint8_t dstaddr[]) + { + struct unicast_packet tmp_uc, *unicast_packet; struct sk_buff *frag_skb; + struct unicast_frag_packet *frag1, *frag2; + int uc_hdr_len = sizeof(struct unicast_packet); + int ucf_hdr_len = sizeof(struct unicast_frag_packet); int data_len = skb->len;
if (!bat_priv->primary_if) goto dropped;
- frag_skb = dev_alloc_skb(data_len - (data_len / 2) + hdr_len); + unicast_packet = (struct unicast_packet *) skb->data; + + memcpy(&tmp_uc, unicast_packet, uc_hdr_len); + frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); skb_split(skb, frag_skb, data_len / 2);
- if (my_skb_head_push(frag_skb, hdr_len) < 0 || - my_skb_head_push(skb, hdr_len) < 0) + if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 || + my_skb_head_push(frag_skb, ucf_hdr_len) < 0) goto drop_frag;
- ucast_frag1 = (struct unicast_frag_packet *)skb->data; - ucast_frag2 = (struct unicast_frag_packet *)frag_skb->data; + frag1 = (struct unicast_frag_packet *)skb->data; + frag2 = (struct unicast_frag_packet *)frag_skb->data;
- ucast_frag1->version = COMPAT_VERSION; - ucast_frag1->packet_type = BAT_UNICAST_FRAG; - ucast_frag1->ttl = TTL; - memcpy(ucast_frag1->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - memcpy(ucast_frag1->dest, orig_node->orig, ETH_ALEN); + memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet));
- memcpy(ucast_frag2, ucast_frag1, sizeof(struct unicast_frag_packet)); + frag1->ttl--; + frag1->version = COMPAT_VERSION; + frag1->packet_type = BAT_UNICAST_FRAG;
- ucast_frag1->flags |= UNI_FRAG_HEAD; - ucast_frag2->flags &= ~UNI_FRAG_HEAD; + memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(frag2, frag1, sizeof(struct unicast_frag_packet));
- ucast_frag1->seqno = htons((uint16_t)atomic_inc_return( - &batman_if->frag_seqno)); + frag1->flags |= UNI_FRAG_HEAD; + frag2->flags &= ~UNI_FRAG_HEAD;
- ucast_frag2->seqno = htons((uint16_t)atomic_inc_return( - &batman_if->frag_seqno)); + frag1->seqno = htons((uint16_t)atomic_inc_return( + &batman_if->frag_seqno)); + frag2->seqno = htons((uint16_t)atomic_inc_return( + &batman_if->frag_seqno));
send_skb_packet(skb, batman_if, dstaddr); send_skb_packet(frag_skb, batman_if, dstaddr); - return 0; + return NET_RX_SUCCESS;
drop_frag: kfree_skb(frag_skb); dropped: kfree_skb(skb); - return 1; + return NET_RX_DROP; }
int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) @@@ -212,13 -279,17 +279,17 @@@ struct neigh_node *router; int data_len = skb->len; uint8_t dstaddr[6]; - unsigned long flags;
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock);
/* get routing information */ - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - ethhdr->h_dest)); + if (is_multicast_ether_addr(ethhdr->h_dest)) + orig_node = (struct orig_node *)gw_get_selected(bat_priv); + else + orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, + choose_orig, + ethhdr->h_dest));
/* check for hna host */ if (!orig_node) @@@ -235,16 -306,11 +306,11 @@@ batman_if = router->if_incoming; memcpy(dstaddr, router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
if (batman_if->if_status != IF_ACTIVE) goto dropped;
- if (atomic_read(&bat_priv->frag_enabled) && - data_len + sizeof(struct unicast_packet) > batman_if->net_dev->mtu) - return unicast_send_frag_skb(skb, bat_priv, batman_if, - dstaddr, orig_node); - if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) goto dropped;
@@@ -258,11 -324,19 +324,19 @@@ /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+ if (atomic_read(&bat_priv->fragmentation) && + data_len + sizeof(struct unicast_packet) > + batman_if->net_dev->mtu) { + /* send frag skb decreases ttl */ + unicast_packet->ttl++; + return frag_send_skb(skb, bat_priv, batman_if, + dstaddr); + } send_skb_packet(skb, batman_if, dstaddr); return 0;
unlock: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); dropped: kfree_skb(skb); return 1; diff --combined drivers/staging/batman-adv/unicast.h index 7973697,e32b786..e32b786 --- a/drivers/staging/batman-adv/unicast.h +++ b/drivers/staging/batman-adv/unicast.h @@@ -25,15 -25,11 +25,11 @@@ #define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */ #define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */
- struct sk_buff *merge_frag_packet(struct list_head *head, - struct frag_packet_list_entry *tfp, - struct sk_buff *skb); - - void create_frag_entry(struct list_head *head, struct sk_buff *skb); - int create_frag_buffer(struct list_head *head); - struct frag_packet_list_entry *search_frag_packet(struct list_head *head, - struct unicast_frag_packet *up); + int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct sk_buff **new_skb); void frag_list_free(struct list_head *head); int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); + int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct batman_if *batman_if, uint8_t dstaddr[]);
#endif /* _NET_BATMAN_ADV_UNICAST_H_ */ diff --combined drivers/staging/batman-adv/vis.c index 4473cc8,957a086..957a086 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@@ -26,6 -26,7 +26,7 @@@ #include "soft-interface.h" #include "hard-interface.h" #include "hash.h" + #include "originator.h"
#define MAX_VIS_PACKET_SIZE 1000
@@@ -53,16 -54,15 +54,15 @@@ static void free_info(struct kref *ref struct vis_info *info = container_of(ref, struct vis_info, refcount); struct bat_priv *bat_priv = info->bat_priv; struct recvlist_node *entry, *tmp; - unsigned long flags;
list_del_init(&info->send_list); - spin_lock_irqsave(&bat_priv->vis_list_lock, flags); + spin_lock_bh(&bat_priv->vis_list_lock); list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { list_del(&entry->list); kfree(entry); }
- spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags); + spin_unlock_bh(&bat_priv->vis_list_lock); kfree_skb(info->skb_packet); }
@@@ -176,6 -176,7 +176,7 @@@ int vis_seq_print_text(struct seq_file { HASHIT(hashit); HASHIT(hashit_count); + struct element_t *bucket; struct vis_info *info; struct vis_packet *packet; struct vis_info_entry *entries; @@@ -185,7 -186,6 +186,6 @@@ struct if_list_entry *entry; struct hlist_node *pos, *n; int i; - unsigned long flags; int vis_server = atomic_read(&bat_priv->vis_mode); size_t buff_pos, buf_size; char *buff; @@@ -196,9 -196,11 +196,11 @@@
buf_size = 1; /* Estimate length */ - spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); while (hash_iterate(bat_priv->vis_hash, &hashit_count)) { - info = hashit_count.bucket->data; + bucket = hlist_entry(hashit_count.walk, struct element_t, + hlist); + info = bucket->data; packet = (struct vis_packet *)info->skb_packet->data; entries = (struct vis_info_entry *) ((char *)packet + sizeof(struct vis_packet)); @@@ -229,14 -231,15 +231,15 @@@
buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); return -ENOMEM; } buff[0] = '\0'; buff_pos = 0;
while (hash_iterate(bat_priv->vis_hash, &hashit)) { - info = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + info = bucket->data; packet = (struct vis_packet *)info->skb_packet->data; entries = (struct vis_info_entry *) ((char *)packet + sizeof(struct vis_packet)); @@@ -273,7 -276,7 +276,7 @@@ } }
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock);
seq_printf(seq, "%s", buff); kfree(buff); @@@ -306,16 -309,15 +309,15 @@@ static void recv_list_add(struct bat_pr struct list_head *recv_list, char *mac) { struct recvlist_node *entry; - unsigned long flags;
entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC); if (!entry) return;
memcpy(entry->mac, mac, ETH_ALEN); - spin_lock_irqsave(&bat_priv->vis_list_lock, flags); + spin_lock_bh(&bat_priv->vis_list_lock); list_add_tail(&entry->list, recv_list); - spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags); + spin_unlock_bh(&bat_priv->vis_list_lock); }
/* returns 1 if this mac is in the recv_list */ @@@ -323,17 -325,15 +325,15 @@@ static int recv_list_is_in(struct bat_p struct list_head *recv_list, char *mac) { struct recvlist_node *entry; - unsigned long flags;
- spin_lock_irqsave(&bat_priv->vis_list_lock, flags); + spin_lock_bh(&bat_priv->vis_list_lock); list_for_each_entry(entry, recv_list, list) { if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { - spin_unlock_irqrestore(&bat_priv->vis_list_lock, - flags); + spin_unlock_bh(&bat_priv->vis_list_lock); return 1; } } - spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags); + spin_unlock_bh(&bat_priv->vis_list_lock); return 0; }
@@@ -349,6 -349,7 +349,7 @@@ static struct vis_info *add_packet(stru struct vis_packet *search_packet, *old_packet; struct vis_info search_elem; struct vis_packet *packet; + int hash_added;
*is_new = 0; /* sanity check */ @@@ -363,7 -364,8 +364,8 @@@ sizeof(struct vis_packet));
memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); - old_info = hash_find(bat_priv->vis_hash, &search_elem); + old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, + &search_elem); kfree_skb(search_elem.skb_packet);
if (old_info != NULL) { @@@ -380,7 -382,8 +382,8 @@@ } } /* remove old entry */ - hash_remove(bat_priv->vis_hash, old_info); + hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, + old_info); send_list_del(old_info); kref_put(&old_info->refcount, free_info); } @@@ -421,7 -424,9 +424,9 @@@ recv_list_add(bat_priv, &info->recv_list, packet->sender_orig);
/* try to add it */ - if (hash_add(bat_priv->vis_hash, info) < 0) { + hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, + info); + if (hash_added < 0) { /* did not work (for some reason) */ kref_put(&old_info->refcount, free_info); info = NULL; @@@ -437,12 -442,11 +442,11 @@@ void receive_server_sync_packet(struct { struct vis_info *info; int is_new, make_broadcast; - unsigned long flags; int vis_server = atomic_read(&bat_priv->vis_mode);
make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC);
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); info = add_packet(bat_priv, vis_packet, vis_info_len, &is_new, make_broadcast); if (!info) @@@ -453,7 -457,7 +457,7 @@@ if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) send_list_add(bat_priv, info); end: - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); }
/* handle an incoming client update packet and schedule forward if needed. */ @@@ -464,12 -468,11 +468,11 @@@ void receive_client_update_packet(struc struct vis_info *info; struct vis_packet *packet; int is_new; - unsigned long flags; int vis_server = atomic_read(&bat_priv->vis_mode); int are_target = 0;
/* clients shall not broadcast. */ - if (is_bcast(vis_packet->target_orig)) + if (is_broadcast_ether_addr(vis_packet->target_orig)) return;
/* Are we the target for this VIS packet? */ @@@ -477,7 -480,7 +480,7 @@@ is_my_mac(vis_packet->target_orig)) are_target = 1;
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); info = add_packet(bat_priv, vis_packet, vis_info_len, &is_new, are_target);
@@@ -498,7 -501,7 +501,7 @@@ }
end: - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); }
/* Walk the originators and find the VIS server with the best tq. Set the packet @@@ -509,6 -512,7 +512,7 @@@ static int find_best_vis_server(struct struct vis_info *info) { HASHIT(hashit); + struct element_t *bucket; struct orig_node *orig_node; struct vis_packet *packet; int best_tq = -1; @@@ -516,7 -520,8 +520,8 @@@ packet = (struct vis_packet *)info->skb_packet->data;
while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; if ((orig_node) && (orig_node->router) && (orig_node->flags & VIS_SERVER) && (orig_node->router->tq_avg > best_tq)) { @@@ -545,18 -550,18 +550,18 @@@ static int generate_vis_packet(struct b { HASHIT(hashit_local); HASHIT(hashit_global); + struct element_t *bucket; struct orig_node *orig_node; struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; struct vis_info_entry *entry; struct hna_local_entry *hna_local_entry; int best_tq = -1; - unsigned long flags;
info->first_seen = jiffies; packet->vis_type = atomic_read(&bat_priv->vis_mode);
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); packet->ttl = TTL; packet->seqno = htonl(ntohl(packet->seqno) + 1); @@@ -567,14 -572,15 +572,15 @@@ best_tq = find_best_vis_server(bat_priv, info);
if (best_tq < 0) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, - flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return -1; } }
while (hash_iterate(bat_priv->orig_hash, &hashit_global)) { - orig_node = hashit_global.bucket->data; + bucket = hlist_entry(hashit_global.walk, struct element_t, + hlist); + orig_node = bucket->data;
if (!orig_node->router) continue; @@@ -599,17 -605,18 +605,18 @@@ packet->entries++;
if (vis_packet_full(info)) { - spin_unlock_irqrestore( - &bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; } }
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
- spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); while (hash_iterate(bat_priv->hna_local_hash, &hashit_local)) { - hna_local_entry = hashit_local.bucket->data; + bucket = hlist_entry(hashit_local.walk, struct element_t, + hlist); + hna_local_entry = bucket->data; entry = (struct vis_info_entry *)skb_put(info->skb_packet, sizeof(*entry)); memset(entry->src, 0, ETH_ALEN); @@@ -618,13 -625,12 +625,12 @@@ packet->entries++;
if (vis_packet_full(info)) { - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, - flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); return 0; } }
- spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); return 0; }
@@@ -633,10 -639,12 +639,12 @@@ static void purge_vis_packets(struct bat_priv *bat_priv) { HASHIT(hashit); + struct element_t *bucket; struct vis_info *info;
while (hash_iterate(bat_priv->vis_hash, &hashit)) { - info = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + info = bucket->data;
/* never purge own data. */ if (info == bat_priv->my_vis_info) @@@ -655,20 -663,21 +663,21 @@@ static void broadcast_vis_packet(struc struct vis_info *info) { HASHIT(hashit); + struct element_t *bucket; struct orig_node *orig_node; struct vis_packet *packet; struct sk_buff *skb; - unsigned long flags; struct batman_if *batman_if; uint8_t dstaddr[ETH_ALEN];
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); packet = (struct vis_packet *)info->skb_packet->data;
/* send to all routers in range. */ while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data;
/* if it's a vis server and reachable, send it. */ if ((!orig_node) || (!orig_node->router)) @@@ -684,17 -693,17 +693,17 @@@ memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) send_skb_packet(skb, batman_if, dstaddr);
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock);
}
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); }
static void unicast_vis_packet(struct bat_priv *bat_priv, @@@ -703,13 -712,13 +712,13 @@@ struct orig_node *orig_node; struct sk_buff *skb; struct vis_packet *packet; struct batman_if *batman_if; uint8_t dstaddr[ETH_ALEN];
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); packet = (struct vis_packet *)info->skb_packet->data; orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, choose_orig, packet->target_orig));
if ((!orig_node) || (!orig_node->router)) @@@ -719,7 -728,7 +728,7 @@@ * copy the required data before sending */ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock);
skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) @@@ -728,7 -737,7 +737,7 @@@ return;
out: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); }
/* only send one vis packet. called from send_vis_packets() */ @@@ -746,7 -755,7 +755,7 @@@ static void send_vis_packet(struct bat_ ETH_ALEN); packet->ttl--;
- if (is_bcast(packet->target_orig)) + if (is_broadcast_ether_addr(packet->target_orig)) broadcast_vis_packet(bat_priv, info); else unicast_vis_packet(bat_priv, info); @@@ -761,9 -770,8 +770,8 @@@ static void send_vis_packets(struct wor struct bat_priv *bat_priv = container_of(delayed_work, struct bat_priv, vis_work); struct vis_info *info, *temp; - unsigned long flags;
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); purge_vis_packets(bat_priv);
if (generate_vis_packet(bat_priv) == 0) { @@@ -775,16 -783,16 +783,16 @@@ send_list) {
kref_get(&info->refcount); - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock);
if (bat_priv->primary_if) send_vis_packet(bat_priv, info);
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); send_list_del(info); kref_put(&info->refcount, free_info); } - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); start_vis_timer(bat_priv); }
@@@ -793,14 -801,14 +801,14 @@@ int vis_init(struct bat_priv *bat_priv) { struct vis_packet *packet; - unsigned long flags; + int hash_added;
if (bat_priv->vis_hash) return 1;
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock);
- bat_priv->vis_hash = hash_new(256, vis_info_cmp, vis_info_choose); + bat_priv->vis_hash = hash_new(256); if (!bat_priv->vis_hash) { pr_err("Can't initialize vis_hash\n"); goto err; @@@ -839,14 -847,16 +847,16 @@@
INIT_LIST_HEAD(&bat_priv->vis_send_list);
- if (hash_add(bat_priv->vis_hash, bat_priv->my_vis_info) < 0) { + hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, + bat_priv->my_vis_info); + if (hash_added < 0) { pr_err("Can't add own vis packet into hash\n"); /* not in hash, need to remove it manually. */ kref_put(&bat_priv->my_vis_info->refcount, free_info); goto err; }
- spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); start_vis_timer(bat_priv); return 1;
@@@ -854,7 -864,7 +864,7 @@@ free_info kfree(bat_priv->my_vis_info); bat_priv->my_vis_info = NULL; err: - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); vis_quit(bat_priv); return 0; } @@@ -871,18 -881,17 +881,17 @@@ static void free_info_ref(void *data, v /* shutdown vis-server */ void vis_quit(struct bat_priv *bat_priv) { - unsigned long flags; if (!bat_priv->vis_hash) return;
cancel_delayed_work_sync(&bat_priv->vis_work);
- spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); /* properly remove, kill timers ... */ hash_delete(bat_priv->vis_hash, free_info_ref, NULL); bat_priv->vis_hash = NULL; bat_priv->my_vis_info = NULL; - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); }
/* schedule packets for (re)transmission */