diff options
Diffstat (limited to 'drivers/staging/batman-adv')
31 files changed, 1678 insertions, 1833 deletions
diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig index 1d74dabf951..1e7e0a8dbc8 100644 --- a/drivers/staging/batman-adv/Kconfig +++ b/drivers/staging/batman-adv/Kconfig @@ -4,7 +4,7 @@ config BATMAN_ADV tristate "B.A.T.M.A.N. Advanced Meshing Protocol" - depends on PROC_FS && PACKET + depends on PROC_FS && NET default n ---help--- @@ -14,10 +14,10 @@ config BATMAN_ADV http://www.open-mesh.org/ for more information and user space tools. -config BATMAN_DEBUG +config BATMAN_ADV_DEBUG bool "B.A.T.M.A.N. debugging" depends on BATMAN_ADV != n - help + ---help--- This is an option for use by developers; most people should say N here. This enables compilation of support for diff --git a/drivers/staging/batman-adv/Makefile b/drivers/staging/batman-adv/Makefile index 02da87134fc..42b4e637026 100644 --- a/drivers/staging/batman-adv/Makefile +++ b/drivers/staging/batman-adv/Makefile @@ -19,4 +19,4 @@ # obj-m += batman-adv.o -batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o log.o +batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o diff --git a/drivers/staging/batman-adv/README b/drivers/staging/batman-adv/README index 3aaf393ebaa..7d666ad0435 100644 --- a/drivers/staging/batman-adv/README +++ b/drivers/staging/batman-adv/README @@ -1,4 +1,4 @@ -[state: 07-11-2009] +[state: 06-01-2010] BATMAN-ADV ---------- @@ -15,19 +15,6 @@ above B.A.T.M.A.N. Advanced, prominent examples are: IPv4, IPv6, DHCP, IPX. This is batman-advanced implemented as Linux kernel driver. It does not depend on any network (other) driver, and can be used on wifi as well as ethernet, vpn, etc ... (anything with ethernet-style layer 2). -It compiles against and should work with Linux 2.6.20 - 2.6.31. Supporting older -versions is not planned, but it's probably easy to backport it. If you work on a -backport, feel free to contact us. :-) - -COMPILE -------- -To compile against your currently installed kernel, just type: - -# make - -if you want to compile against some other kernel, use: - -# make KERNELPATH=/path/to/kernel USAGE ----- @@ -73,16 +60,9 @@ When configured as server, you can get a topology snapshot of your mesh: # cat /proc/net/batman-adv/vis -This output format is a graphviz formatted text file which can be -processed with graphviz-tools like dot. -The labels are similar/compatible to the ETX metric, 1.0 means perfect -connection (100%), 2.0 means 50%, 3.0 means 33% and so on. - -Alternatively, a JSON output format is available. The format can be set -using by writing either "dot_draw" or "json" into the vis_format file. -"dot_draw" is selected by default. - -echo "json" > /proc/net/batman-adv/vis_format +The output is in a generic raw format. Use the batctl tool (See below) +to convert this to other formats more suitable for graphing, eg +graphviz dot, or JSON data-interchange format. In very mobile scenarios, you might want to adjust the originator interval to a lower value. This will make the mesh more responsive to @@ -96,15 +76,59 @@ To deactivate batman, do: # echo "" > /proc/net/batman-adv/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 commands: 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 sometimes +necessary to see more detail debug messages. This must be enabled when +compiling the batman-adv module. Use "make menuconfig" and enable the +option "B.A.T.M.A.N. debugging". + +The additional debug output is by default disabled. It can be enabled +either at kernel module load time or during run time. To enable debug +output at module load time, add the module parameter debug=<value>. +<value> can take one of four values. + +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 + +e.g. + +modprobe batman-adv debug=2 + +will load the module and enable debug messages for when routes or HNAs +change. + +The debug output can also be changed at runtime using the file +/sys/module/batman-adv/parameters/debug. e.g. + +echo 2 > /sys/module/batman-adv/parameters/debug + +enables debug messages for when routes or HNAs + +The debug output is sent to the kernel logs. So try dmesg, logread etc +to see the debug messages. + BATCTL ------ -B.A.T.M.A.N. advanced operates on layer 2 and thus all hosts partici- -pating in the virtual switch are completely transparent for all proto- -cols 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. +B.A.T.M.A.N. advanced operates on layer 2 and thus 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). diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO index ea6dcf94d66..2f15136b18e 100644 --- a/drivers/staging/batman-adv/TODO +++ b/drivers/staging/batman-adv/TODO @@ -17,30 +17,6 @@ -> transtable_global (read-only) [outputs the global translation table] -> transtable_local (read-only) [outputs the local translation table] -=> vis "raw" data output -* the raw format shall replace dot draw / json to offer a neutral that can -* be converted -* the format (comma seperated entries): --> "mac" -> mac address of an originator (each line begins with it) --> "TQ mac value" -> src mac's link quality towards mac address --> "HNA mac" -> HNA announced by source mac --> "PRIMARY" -> this is a primary interface --> "SEC mac" -> secondary mac address of source (requires preceeding --> PRIMARY) - -=> logging -* the log level LOG_TYPE_CRIT, LOG_TYPE_WARN & LOG_TYPE_NOTICE will be -* unified to use printk -* LOG_TYPE_BATMAN & LOG_TYPE_ROUTES will also use printk but only after the -* internal debug level has been raised -* the internal debug level can be modified using a module parameter (debug) -* or at run time via /sys/module/batman-adv/parameters/debug -* make use of printk %pM support instead of converting mac addresses -* manually - -=> strip out all backward compatibility support to older kernels - (only found in compat.h) - => fix checkpatch.pl errors Please send all patches to: diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c index 9c6e681f6fb..7917322a7e2 100644 --- a/drivers/staging/batman-adv/aggregation.c +++ b/drivers/staging/batman-adv/aggregation.c @@ -96,6 +96,7 @@ static void new_aggregated_packet(unsigned char *packet_buff, int own_packet) { struct forw_packet *forw_packet_aggr; + unsigned long flags; forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); if (!forw_packet_aggr) @@ -115,6 +116,7 @@ static void new_aggregated_packet(unsigned char *packet_buff, packet_buff, forw_packet_aggr->packet_len); + forw_packet_aggr->skb = NULL; forw_packet_aggr->own = own_packet; forw_packet_aggr->if_incoming = if_incoming; forw_packet_aggr->num_packets = 0; @@ -126,9 +128,9 @@ static void new_aggregated_packet(unsigned char *packet_buff, forw_packet_aggr->direct_link_flags |= 1; /* add new packet to packet list */ - spin_lock(&forw_bat_list_lock); + spin_lock_irqsave(&forw_bat_list_lock, flags); hlist_add_head(&forw_packet_aggr->list, &forw_bat_list); - spin_unlock(&forw_bat_list_lock); + spin_unlock_irqrestore(&forw_bat_list_lock, flags); /* start timer for this packet */ INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, @@ -168,9 +170,10 @@ void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len, 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(&forw_bat_list_lock); + spin_lock_irqsave(&forw_bat_list_lock, flags); /* own packets are not to be aggregated */ if ((atomic_read(&aggregation_enabled)) && (!own_packet)) { hlist_for_each_entry(forw_packet_pos, tmp_node, &forw_bat_list, @@ -191,7 +194,7 @@ void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len, * suitable aggregation packet found */ if (forw_packet_aggr == NULL) { /* the following section can run without the lock */ - spin_unlock(&forw_bat_list_lock); + spin_unlock_irqrestore(&forw_bat_list_lock, flags); new_aggregated_packet(packet_buff, packet_len, send_time, direct_link, if_incoming, own_packet); @@ -199,7 +202,7 @@ void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len, aggregate(forw_packet_aggr, packet_buff, packet_len, direct_link); - spin_unlock(&forw_bat_list_lock); + spin_unlock_irqrestore(&forw_bat_list_lock, flags); } } diff --git a/drivers/staging/batman-adv/bitarray.c b/drivers/staging/batman-adv/bitarray.c index 3c67f5f42b2..212eef93afe 100644 --- a/drivers/staging/batman-adv/bitarray.c +++ b/drivers/staging/batman-adv/bitarray.c @@ -21,7 +21,6 @@ #include "main.h" #include "bitarray.h" -#include "log.h" /* returns true if the corresponding bit in the given seq_bits indicates true * and curr_seqno is within range of last_seqno */ @@ -80,8 +79,8 @@ void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n) * from. * * left is high, right is low: FEDC BA98 7654 3210 - * ^^ ^^ - * vvvv + * ^^ ^^ + * vvvv * ^^^^ = from, vvvvv =to, we'd have word_num==1 and * word_offset==WORD_BIT_SIZE/2 ????? in this example. * (=24 bits) @@ -133,13 +132,13 @@ char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff, (seq_num_diff < -TQ_LOCAL_WINDOW_SIZE)) { if (seq_num_diff > TQ_LOCAL_WINDOW_SIZE) - debug_log(LOG_TYPE_BATMAN, - "We missed a lot of packets (%i) !\n", - seq_num_diff-1); + bat_dbg(DBG_BATMAN, + "We missed a lot of packets (%i) !\n", + seq_num_diff-1); if (-seq_num_diff > TQ_LOCAL_WINDOW_SIZE) - debug_log(LOG_TYPE_BATMAN, - "Other host probably restarted !\n"); + bat_dbg(DBG_BATMAN, + "Other host probably restarted !\n"); for (i = 0; i < NUM_WORDS; i++) seq_bits[i] = 0; diff --git a/drivers/staging/batman-adv/compat.h b/drivers/staging/batman-adv/compat.h deleted file mode 100644 index f4e0a4564ba..00000000000 --- a/drivers/staging/batman-adv/compat.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2007-2009 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 - * - * - * This file contains macros for maintaining compatibility with older versions - * of the Linux kernel. - */ - -#include <linux/version.h> /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) - -#define skb_set_network_header(_skb, _offset) \ - do { (_skb)->nh.raw = (_skb)->data + (_offset); } while (0) - -#define skb_reset_mac_header(_skb) \ - do { (_skb)->mac.raw = (_skb)->data; } while (0) - -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) - -#define device_create(_cls, _parent, _devt, _device, _fmt) \ - class_device_create(_cls, _parent, _devt, _device, _fmt) - -#define device_destroy(_cls, _device) \ - class_device_destroy(_cls, _device) - -#else - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) - -#define device_create(_cls, _parent, _devt, _device, _fmt) \ - device_create_drvdata(_cls, _parent, _devt, _device, _fmt) - -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) */ - -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) - -#define cancel_delayed_work_sync(wq) cancel_rearming_delayed_work(wq) - -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) -#define strict_strtoul(cp, base, res) \ - ({ \ - int ret = 0; \ - char *endp; \ - *res = simple_strtoul(cp, &endp, base); \ - if (cp == endp) \ - ret = -EINVAL; \ - ret; \ -}) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) */ diff --git a/drivers/staging/batman-adv/device.c b/drivers/staging/batman-adv/device.c index 1e7d1f88674..e7f44215b5f 100644 --- a/drivers/staging/batman-adv/device.c +++ b/drivers/staging/batman-adv/device.c @@ -19,14 +19,13 @@ * */ +#include <linux/device.h> #include "main.h" #include "device.h" -#include "log.h" #include "send.h" #include "types.h" #include "hash.h" - -#include "compat.h" +#include "hard-interface.h" static struct class *batman_class; @@ -60,7 +59,7 @@ int bat_device_setup(void) /* register our device - kernel assigns a free major number */ tmp_major = register_chrdev(0, DRIVER_DEVICE, &fops); if (tmp_major < 0) { - debug_log(LOG_TYPE_WARN, "Registering the character device failed with %d\n", + printk(KERN_ERR "batman-adv:Registering the character device failed with %d\n", tmp_major); return 0; } @@ -68,7 +67,7 @@ int bat_device_setup(void) batman_class = class_create(THIS_MODULE, "batman-adv"); if (IS_ERR(batman_class)) { - debug_log(LOG_TYPE_WARN, "Could not register class 'batman-adv' \n"); + printk(KERN_ERR "batman-adv:Could not register class 'batman-adv' \n"); return 0; } @@ -111,7 +110,7 @@ int bat_device_open(struct inode *inode, struct file *file) } if (device_client_hash[i] != device_client) { - debug_log(LOG_TYPE_WARN, "Error - can't add another packet client: maximum number of clients reached \n"); + printk(KERN_ERR "batman-adv:Error - can't add another packet client: maximum number of clients reached \n"); kfree(device_client); return -EXFULL; } @@ -119,7 +118,7 @@ int bat_device_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&device_client->queue_list); device_client->queue_len = 0; device_client->index = i; - device_client->lock = __SPIN_LOCK_UNLOCKED(device_client->lock); + spin_lock_init(&device_client->lock); init_waitqueue_head(&device_client->queue_wait); file->private_data = device_client; @@ -134,8 +133,9 @@ int bat_device_release(struct inode *inode, struct file *file) (struct device_client *)file->private_data; struct device_packet *device_packet; struct list_head *list_pos, *list_pos_tmp; + unsigned long flags; - spin_lock(&device_client->lock); + spin_lock_irqsave(&device_client->lock, flags); /* for all packets in the queue ... */ list_for_each_safe(list_pos, list_pos_tmp, &device_client->queue_list) { @@ -147,7 +147,7 @@ int bat_device_release(struct inode *inode, struct file *file) } device_client_hash[device_client->index] = NULL; - spin_unlock(&device_client->lock); + spin_unlock_irqrestore(&device_client->lock, flags); kfree(device_client); dec_module_count(); @@ -162,6 +162,7 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, (struct device_client *)file->private_data; struct device_packet *device_packet; int error; + unsigned long flags; if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0)) return -EAGAIN; @@ -178,14 +179,14 @@ ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, if (error) return error; - spin_lock(&device_client->lock); + spin_lock_irqsave(&device_client->lock, flags); device_packet = list_first_entry(&device_client->queue_list, struct device_packet, list); list_del(&device_packet->list); device_client->queue_len--; - spin_unlock(&device_client->lock); + spin_unlock_irqrestore(&device_client->lock, flags); error = __copy_to_user(buf, &device_packet->icmp_packet, sizeof(struct icmp_packet)); @@ -206,9 +207,11 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, struct icmp_packet icmp_packet; struct orig_node *orig_node; struct batman_if *batman_if; + uint8_t dstaddr[ETH_ALEN]; + unsigned long flags; if (len < sizeof(struct icmp_packet)) { - debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: invalid packet size\n"); + bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: invalid packet size\n"); return -EINVAL; } @@ -219,12 +222,12 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, return -EFAULT; if (icmp_packet.packet_type != BAT_ICMP) { - debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); + bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); return -EINVAL; } if (icmp_packet.msg_type != ECHO_REQUEST) { - debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n"); + bat_dbg(DBG_BATMAN, "batman-adv:Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n"); return -EINVAL; } @@ -240,7 +243,7 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, if (atomic_read(&module_state) != MODULE_ACTIVE) goto dst_unreach; - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst)); if (!orig_node) @@ -250,9 +253,15 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, goto unlock; batman_if = orig_node->batman_if; + memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + + spin_unlock_irqrestore(&orig_hash_lock, flags); if (!batman_if) - goto unlock; + goto dst_unreach; + + if (batman_if->if_active != IF_ACTIVE) + goto dst_unreach; memcpy(icmp_packet.orig, batman_if->net_dev->dev_addr, @@ -260,13 +269,12 @@ ssize_t bat_device_write(struct file *file, const char __user *buff, send_raw_packet((unsigned char *)&icmp_packet, sizeof(struct icmp_packet), - batman_if, orig_node->router->addr); + batman_if, dstaddr); - spin_unlock(&orig_hash_lock); goto out; unlock: - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); dst_unreach: icmp_packet.msg_type = DESTINATION_UNREACHABLE; bat_device_add_packet(device_client, &icmp_packet); @@ -291,6 +299,7 @@ void bat_device_add_packet(struct device_client *device_client, struct icmp_packet *icmp_packet) { struct device_packet *device_packet; + unsigned long flags; device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL); @@ -301,12 +310,12 @@ void bat_device_add_packet(struct device_client *device_client, memcpy(&device_packet->icmp_packet, icmp_packet, sizeof(struct icmp_packet)); - spin_lock(&device_client->lock); + spin_lock_irqsave(&device_client->lock, flags); /* while waiting for the lock the device_client could have been * deleted */ if (!device_client_hash[icmp_packet->uid]) { - spin_unlock(&device_client->lock); + spin_unlock_irqrestore(&device_client->lock, flags); kfree(device_packet); return; } @@ -323,7 +332,7 @@ void bat_device_add_packet(struct device_client *device_client, device_client->queue_len--; } - spin_unlock(&device_client->lock); + spin_unlock_irqrestore(&device_client->lock, flags); wake_up(&device_client->queue_wait); } diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 5ea35da5ee7..befd4883951 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -21,13 +21,11 @@ #include "main.h" #include "hard-interface.h" -#include "log.h" #include "soft-interface.h" #include "send.h" #include "translation-table.h" #include "routing.h" #include "hash.h" -#include "compat.h" #define MIN(x, y) ((x) < (y) ? (x) : (y)) @@ -75,7 +73,6 @@ int hardif_min_mtu(void) static void check_known_mac_addr(uint8_t *addr) { struct batman_if *batman_if; - char mac_string[ETH_STR_LEN]; rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { @@ -86,10 +83,9 @@ static void check_known_mac_addr(uint8_t *addr) if (!compare_orig(batman_if->net_dev->dev_addr, addr)) continue; - addr_to_string(mac_string, addr); - debug_log(LOG_TYPE_WARN, "The newly added mac address (%s) already exists on: %s\n", - mac_string, batman_if->dev); - debug_log(LOG_TYPE_WARN, "It is strongly recommended to keep mac addresses unique to avoid problems!\n"); + printk(KERN_WARNING "batman-adv:The newly added mac address (%pM) already exists on: %s\n", + addr, batman_if->dev); + printk(KERN_WARNING "batman-adv:It is strongly recommended to keep mac addresses unique to avoid problems!\n"); } rcu_read_unlock(); } @@ -154,9 +150,6 @@ void hardif_deactivate_interface(struct batman_if *batman_if) if (batman_if->if_active != IF_ACTIVE) return; - if (batman_if->raw_sock) - sock_release(batman_if->raw_sock); - /** * batman_if->net_dev has been acquired by dev_get_by_name() in * proc_interfaces_write() and has to be unreferenced. @@ -165,22 +158,16 @@ void hardif_deactivate_interface(struct batman_if *batman_if) if (batman_if->net_dev) dev_put(batman_if->net_dev); - batman_if->raw_sock = NULL; - batman_if->net_dev = NULL; - batman_if->if_active = IF_INACTIVE; active_ifs--; - debug_log(LOG_TYPE_NOTICE, "Interface deactivated: %s\n", - batman_if->dev); + printk(KERN_INFO "batman-adv:Interface deactivated: %s\n", + batman_if->dev); } /* (re)activate given interface. */ static void hardif_activate_interface(struct batman_if *batman_if) { - struct sockaddr_ll bind_addr; - int retval; - if (batman_if->if_active != IF_INACTIVE) return; @@ -192,35 +179,8 @@ static void hardif_activate_interface(struct batman_if *batman_if) if (!batman_if->net_dev) goto dev_err; - retval = sock_create_kern(PF_PACKET, SOCK_RAW, - __constant_htons(ETH_P_BATMAN), - &batman_if->raw_sock); - - if (retval < 0) { - debug_log(LOG_TYPE_WARN, "Can't create raw socket: %i\n", - retval); - goto sock_err; - } - - bind_addr.sll_family = AF_PACKET; - bind_addr.sll_ifindex = batman_if->net_dev->ifindex; - bind_addr.sll_protocol = 0; /* is set by the kernel */ - - retval = kernel_bind(batman_if->raw_sock, - (struct sockaddr *)&bind_addr, sizeof(bind_addr)); - - if (retval < 0) { - debug_log(LOG_TYPE_WARN, "Can't create bind raw socket: %i\n", - retval); - goto bind_err; - } - check_known_mac_addr(batman_if->net_dev->dev_addr); - batman_if->raw_sock->sk->sk_user_data = - batman_if->raw_sock->sk->sk_data_ready; - batman_if->raw_sock->sk->sk_data_ready = batman_data_ready; - addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr); memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, @@ -235,17 +195,12 @@ static void hardif_activate_interface(struct batman_if *batman_if) if (batman_if->if_num == 0) set_main_if_addr(batman_if->net_dev->dev_addr); - debug_log(LOG_TYPE_NOTICE, "Interface activated: %s\n", - batman_if->dev); + printk(KERN_INFO "batman-adv:Interface activated: %s\n", + batman_if->dev); return; -bind_err: - sock_release(batman_if->raw_sock); -sock_err: - dev_put(batman_if->net_dev); dev_err: - batman_if->raw_sock = NULL; batman_if->net_dev = NULL; } @@ -290,7 +245,7 @@ static int resize_orig(struct orig_node *orig_node, int if_num) data_ptr = kmalloc((if_num + 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS, GFP_ATOMIC); if (!data_ptr) { - debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n"); + printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n"); return -1; } @@ -301,7 +256,7 @@ static int resize_orig(struct orig_node *orig_node, int if_num) data_ptr = kmalloc((if_num + 1) * sizeof(uint8_t), GFP_ATOMIC); if (!data_ptr) { - debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n"); + printk(KERN_ERR "batman-adv:Can't resize orig: out of memory\n"); return -1; } @@ -319,16 +274,16 @@ int hardif_add_interface(char *dev, int if_num) struct batman_if *batman_if; struct batman_packet *batman_packet; struct orig_node *orig_node; - struct hash_it_t *hashit = NULL; + unsigned long flags; + HASHIT(hashit); batman_if = kmalloc(sizeof(struct batman_if), GFP_KERNEL); if (!batman_if) { - debug_log(LOG_TYPE_WARN, "Can't add interface (%s): out of memory\n", dev); + printk(KERN_ERR "batman-adv:Can't add interface (%s): out of memory\n", dev); return -1; } - batman_if->raw_sock = NULL; batman_if->net_dev = NULL; if ((if_num == 0) && (num_hna > 0)) @@ -339,7 +294,7 @@ int hardif_add_interface(char *dev, int if_num) batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_KERNEL); if (!batman_if->packet_buff) { - debug_log(LOG_TYPE_WARN, "Can't add interface packet (%s): out of memory\n", dev); + printk(KERN_ERR "batman-adv:Can't add interface packet (%s): out of memory\n", dev); goto out; } @@ -348,7 +303,7 @@ int hardif_add_interface(char *dev, int if_num) batman_if->if_active = IF_INACTIVE; INIT_RCU_HEAD(&batman_if->rcu); - debug_log(LOG_TYPE_NOTICE, "Adding interface: %s\n", dev); + printk(KERN_INFO "batman-adv:Adding interface: %s\n", dev); avail_ifs++; INIT_LIST_HEAD(&batman_if->list); @@ -376,20 +331,20 @@ int hardif_add_interface(char *dev, int if_num) /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); - while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { - orig_node = hashit->bucket->data; + while (hash_iterate(orig_hash, &hashit)) { + orig_node = hashit.bucket->data; if (resize_orig(orig_node, if_num) == -1) { - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); goto out; } } - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); if (!hardif_is_interface_up(batman_if->dev)) - debug_log(LOG_TYPE_WARN, "Not using interface %s (retrying later): interface not active\n", batman_if->dev); + printk(KERN_ERR "batman-adv:Not using interface %s (retrying later): interface not active\n", batman_if->dev); else hardif_activate_interface(batman_if); @@ -400,8 +355,7 @@ int hardif_add_interface(char *dev, int if_num) return 1; out: - if (batman_if->packet_buff) - kfree(batman_if->packet_buff); + kfree(batman_if->packet_buff); kfree(batman_if); kfree(dev); return -1; @@ -413,7 +367,7 @@ char hardif_get_active_if_num(void) } static int hard_if_event(struct notifier_block *this, - unsigned long event, void *ptr) + unsigned long event, void *ptr) { struct net_device *dev = (struct net_device *)ptr; struct batman_if *batman_if = get_batman_if_by_name(dev->name); @@ -436,7 +390,6 @@ static int hard_if_event(struct notifier_block *this, break; /* NETDEV_CHANGEADDR - mac address change - what are we doing here ? */ default: - /* debug_log(LOG_TYPE_CRIT, "hard_if_event: %s %i\n", dev->name, event); */ break; }; @@ -446,6 +399,122 @@ out: return NOTIFY_DONE; } +/* find batman interface by netdev. assumes rcu_read_lock on */ +static struct batman_if *find_batman_if(struct net_device *dev) +{ + struct batman_if *batman_if; + + rcu_read_lock(); + list_for_each_entry_rcu(batman_if, &if_list, list) { + if (batman_if->net_dev == dev) { + rcu_read_unlock(); + return batman_if; + } + } + rcu_read_unlock(); + return NULL; +} + + +/* receive a packet with the batman ethertype coming on a hard + * interface */ +int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, struct net_device *orig_dev) +{ + struct batman_packet *batman_packet; + struct batman_if *batman_if; + struct net_device_stats *stats; + int ret; + + skb = skb_share_check(skb, GFP_ATOMIC); + + /* skb was released by skb_share_check() */ + if (!skb) + goto err_out; + + if (atomic_read(&module_state) != MODULE_ACTIVE) + goto err_free; + + /* packet should hold at least type and version */ + if (unlikely(skb_headlen(skb) < 2)) + goto err_free; + + /* expect a valid ethernet header here. */ + if (unlikely(skb->mac_len != sizeof(struct ethhdr) + || !skb_mac_header(skb))) + goto err_free; + + batman_if = find_batman_if(skb->dev); + if (!batman_if) + goto err_free; + + /* discard frames on not active interfaces */ + if (batman_if->if_active != IF_ACTIVE) + goto err_free; + + stats = (struct net_device_stats *)dev_get_stats(skb->dev); + if (stats) { + stats->rx_packets++; + stats->rx_bytes += skb->len; + } + + batman_packet = (struct batman_packet *)skb->data; + + if (batman_packet->version != COMPAT_VERSION) { + bat_dbg(DBG_BATMAN, + "Drop packet: incompatible batman version (%i)\n", + batman_packet->version); + goto err_free; + } + + /* all receive handlers return whether they received or reused + * the supplied skb. if not, we have to free the skb. */ + + switch (batman_packet->packet_type) { + /* batman originator packet */ + case BAT_PACKET: + ret = recv_bat_packet(skb, batman_if); + break; + + /* batman icmp packet */ + case BAT_ICMP: + ret = recv_icmp_packet(skb); + break; + + /* unicast packet */ + case BAT_UNICAST: + ret = recv_unicast_packet(skb); + break; + + /* broadcast packet */ + case BAT_BCAST: + ret = recv_bcast_packet(skb); + break; + + /* vis packet */ + case BAT_VIS: + ret = recv_vis_packet(skb); + break; + default: + ret = NET_RX_DROP; + } + + if (ret == NET_RX_DROP) + kfree_skb(skb); + + /* return NET_RX_SUCCESS in any case as we + * most probably dropped the packet for + * routing-logical reasons. */ + + return NET_RX_SUCCESS; + +err_free: + kfree_skb(skb); +err_out: + return NET_RX_DROP; +} + + struct notifier_block hard_if_notifier = { - .notifier_call = hard_if_event, + .notifier_call = hard_if_event, }; diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h index 742358c00c0..97c6ecb9e08 100644 --- a/drivers/staging/batman-adv/hard-interface.h +++ b/drivers/staging/batman-adv/hard-interface.h @@ -32,5 +32,9 @@ void hardif_deactivate_interface(struct batman_if *batman_if); char hardif_get_active_if_num(void); void hardif_check_interfaces_status(void); void hardif_check_interfaces_status_wq(struct work_struct *work); +int batman_skb_recv(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *ptype, + struct net_device *orig_dev); int hardif_min_mtu(void); void update_min_mtu(void); diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c index 61cb4a20ebc..5a2018de3ff 100644 --- a/drivers/staging/batman-adv/hash.c +++ b/drivers/staging/batman-adv/hash.c @@ -64,24 +64,18 @@ void hash_destroy(struct hashtable_t *hash) kfree(hash); } -/* 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. */ +/* 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_in) + struct hash_it_t *iter) { - struct hash_it_t *iter; - if (!hash) return NULL; - - if (iter_in == NULL) { - iter = kmalloc(sizeof(struct hash_it_t), GFP_ATOMIC); - iter->index = -1; - iter->bucket = NULL; - iter->prev_bucket = NULL; - } else { - iter = iter_in; - } + if (!iter) + return NULL; /* sanity checks first (if our bucket got deleted in the last * iteration): */ @@ -139,7 +133,6 @@ struct hash_it_t *hash_iterate(struct hashtable_t *hash, } /* nothing to iterate over anymore */ - kfree(iter); return NULL; } diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h index bb60f082be6..a70d6d6e1c7 100644 --- a/drivers/staging/batman-adv/hash.h +++ b/drivers/staging/batman-adv/hash.h @@ -21,6 +21,11 @@ #ifndef _BATMAN_HASH_H #define _BATMAN_HASH_H +#define HASHIT(name) struct hash_it_t name = { \ + .index = -1, .bucket = NULL, \ + .prev_bucket = NULL, \ + .first_bucket = NULL } + typedef int (*hashdata_compare_cb)(void *, void *); typedef int (*hashdata_choose_cb)(void *, int); diff --git a/drivers/staging/batman-adv/log.c b/drivers/staging/batman-adv/log.c deleted file mode 100644 index f37c7f01a9f..00000000000 --- a/drivers/staging/batman-adv/log.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "log.h" - -#define LOG_BUF_MASK (log_buf_len-1) -#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) - -static char log_buf[LOG_BUF_LEN]; -static int log_buf_len = LOG_BUF_LEN; -static unsigned long log_start; -static unsigned long log_end; -uint8_t log_level; - -static DEFINE_SPINLOCK(logbuf_lock); - -const struct file_operations proc_log_operations = { - .open = log_open, - .release = log_release, - .read = log_read, - .write = log_write, - .poll = log_poll, -}; - -static DECLARE_WAIT_QUEUE_HEAD(log_wait); - -static void emit_log_char(char c) -{ - LOG_BUF(log_end) = c; - log_end++; - - if (log_end - log_start > log_buf_len) - log_start = log_end - log_buf_len; -} - -static int fdebug_log(char *fmt, ...) -{ - int printed_len; - char *p; - va_list args; - static char debug_log_buf[256]; - unsigned long flags; - - spin_lock_irqsave(&logbuf_lock, flags); - va_start(args, fmt); - printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, - args); - va_end(args); - - for (p = debug_log_buf; *p != 0; p++) - emit_log_char(*p); - - spin_unlock_irqrestore(&logbuf_lock, flags); - - wake_up(&log_wait); - - return 0; -} - -int debug_log(int type, char *fmt, ...) -{ - va_list args; - int retval = 0; - char tmp_log_buf[256]; - - /* only critical information get into the official kernel log */ - if (type == LOG_TYPE_CRIT) { - va_start(args, fmt); - vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); - printk(KERN_ERR "batman-adv: %s", tmp_log_buf); - va_end(args); - } - - if ((type == LOG_TYPE_CRIT) || (log_level & type)) { - va_start(args, fmt); - vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); - fdebug_log("[%10u] %s", (jiffies / HZ), tmp_log_buf); - va_end(args); - } - - return retval; -} - -int log_open(struct inode *inode, struct file *file) -{ - inc_module_count(); - return 0; -} - -int log_release(struct inode *inode, struct file *file) -{ - dec_module_count(); - return 0; -} - -ssize_t log_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - int error, i = 0; - char c; - unsigned long flags; - - if ((file->f_flags & O_NONBLOCK) && !(log_end - log_start)) - return -EAGAIN; - - if ((!buf) || (count < 0)) - return -EINVAL; - - if (count == 0) - return 0; - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - - error = wait_event_interruptible(log_wait, (log_start - log_end)); - - if (error) - return error; - - spin_lock_irqsave(&logbuf_lock, flags); - - while ((!error) && (log_start != log_end) && (i < count)) { - c = LOG_BUF(log_start); - - log_start++; - - spin_unlock_irqrestore(&logbuf_lock, flags); - - error = __put_user(c, buf); - - spin_lock_irqsave(&logbuf_lock, flags); - - buf++; - i++; - - } - - spin_unlock_irqrestore(&logbuf_lock, flags); - - if (!error) - return i; - - return error; -} - -ssize_t log_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos) -{ - return count; -} - -unsigned int log_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &log_wait, wait); - - if (log_end - log_start) - return POLLIN | POLLRDNORM; - - return 0; -} diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index bb89bfc5dda..2e0b482e710 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -21,9 +21,9 @@ #include "main.h" #include "proc.h" -#include "log.h" #include "routing.h" #include "send.h" +#include "originator.h" #include "soft-interface.h" #include "device.h" #include "translation-table.h" @@ -31,7 +31,6 @@ #include "types.h" #include "vis.h" #include "hash.h" -#include "compat.h" struct list_head if_list; struct hlist_head forw_bat_list; @@ -44,19 +43,34 @@ DEFINE_SPINLOCK(forw_bcast_list_lock); atomic_t originator_interval; atomic_t vis_interval; +atomic_t vis_mode; atomic_t aggregation_enabled; int16_t num_hna; int16_t num_ifs; struct net_device *soft_device; -static struct task_struct *kthread_task; - unsigned char broadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; atomic_t module_state; +static struct packet_type batman_adv_packet_type __read_mostly = { + .type = __constant_htons(ETH_P_BATMAN), + .func = batman_skb_recv, +}; + struct workqueue_struct *bat_event_workqueue; +#ifdef CONFIG_BATMAN_ADV_DEBUG +int debug; + +module_param(debug, int, 0644); + +int bat_debug_type(int type) +{ + return debug & type; +} +#endif + int init_module(void) { int retval; @@ -70,6 +84,7 @@ int init_module(void) atomic_set(&originator_interval, 1000); atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only * for debugging now. */ + atomic_set(&vis_mode, VIS_TYPE_CLIENT_UPDATE); atomic_set(&aggregation_enabled, 1); /* the name should not be longer than 10 chars - see @@ -90,21 +105,22 @@ int init_module(void) interface_setup); if (!soft_device) { - debug_log(LOG_TYPE_CRIT, "Unable to allocate the batman interface\n"); + printk(KERN_ERR "batman-adv:Unable to allocate the batman interface\n"); goto end; } retval = register_netdev(soft_device); if (retval < 0) { - debug_log(LOG_TYPE_CRIT, "Unable to register the batman interface: %i\n", retval); + printk(KERN_ERR "batman-adv:Unable to register the batman interface: %i\n", retval); goto free_soft_device; } register_netdevice_notifier(&hard_if_notifier); + dev_add_pack(&batman_adv_packet_type); - debug_log(LOG_TYPE_CRIT, "B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n", - SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION); + printk(KERN_INFO "batman-adv:B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n", + SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION); return 0; @@ -124,6 +140,8 @@ void cleanup_module(void) soft_device = NULL; } + dev_remove_pack(&batman_adv_packet_type); + unregister_netdevice_notifier(&hard_if_notifier); cleanup_procfs(); @@ -151,22 +169,12 @@ void activate_module(void) if (vis_init() < 1) goto err; - /* (re)start kernel thread for packet processing */ - if (!kthread_task) { - kthread_task = kthread_run(packet_recv_thread, NULL, "batman-adv"); - - if (IS_ERR(kthread_task)) { - debug_log(LOG_TYPE_CRIT, "Unable to start packet receive thread\n"); - kthread_task = NULL; - } - } - update_min_mtu(); atomic_set(&module_state, MODULE_ACTIVE); goto end; err: - debug_log(LOG_TYPE_CRIT, "Unable to allocate memory for mesh information structures: out of mem ?\n"); + printk(KERN_ERR "batman-adv:Unable to allocate memory for mesh information structures: out of mem ?\n"); shutdown_module(); end: return; @@ -182,14 +190,7 @@ void shutdown_module(void) vis_quit(); - /* deactivate kernel thread for packet processing (if running) */ - if (kthread_task) { - atomic_set(&exit_cond, 1); - wake_up_interruptible(&thread_wait); - kthread_stop(kthread_task); - - kthread_task = NULL; - } + /* TODO: unregister BATMAN pack */ originator_free(); diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h index facb6b79ee5..deb41f5beda 100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@ -33,16 +33,16 @@ #define TQ_MAX_VALUE 255 #define JITTER 20 -#define TTL 50 /* Time To Live of broadcast messages */ -#define MAX_ADDR 16 /* number of interfaces which can be added to +#define TTL 50 /* Time To Live of broadcast messages */ +#define MAX_ADDR 16 /* number of interfaces which can be added to * batman. */ -#define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no +#define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no * valid packet comes in -> TODO: check * influence on TQ_LOCAL_WINDOW_SIZE */ #define LOCAL_HNA_TIMEOUT 3600000 -#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator +#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 @@ -69,24 +69,27 @@ /* - * Logging + * Debug Messages */ -#define LOG_TYPE_CRIT 0 /* highest priority for fatal errors such as - * blocked sockets / failed packet delivery / - * programming errors */ -#define LOG_TYPE_WARN 1 /* warnings for small errors like wrong user - * input / damaged packets / etc */ -#define LOG_TYPE_NOTICE 2 /* notice information for new interfaces / - * changed settings / new originators / etc */ -#define LOG_TYPE_BATMAN 4 /* all messages related to routing / flooding / - * broadcasting / etc */ -#define LOG_TYPE_ROUTES 8 /* route or hna added / changed / deleted */ -#define LOG_TYPE_CRIT_NAME "critical" -#define LOG_TYPE_WARN_NAME "warnings" -#define LOG_TYPE_NOTICE_NAME "notices" -#define LOG_TYPE_BATMAN_NAME "batman" -#define LOG_TYPE_ROUTES_NAME "routes" +#define DBG_BATMAN 1 /* all messages related to routing / flooding / + * broadcasting / etc */ +#define DBG_ROUTES 2 /* route or hna added / changed / deleted */ + +#ifdef CONFIG_BATMAN_ADV_DEBUG +extern int debug; + +extern int bat_debug_type(int type); +#define bat_dbg(type, fmt, arg...) do { \ + if (bat_debug_type(type)) \ + printk(KERN_DEBUG "batman-adv:" fmt, ## arg); \ + } \ + while (0) +#else /* !CONFIG_BATMAN_ADV_DEBUG */ +#define bat_dbg(type, fmt, arg...) do { \ + } \ + while (0) +#endif /* * Vis @@ -127,6 +130,7 @@ extern spinlock_t forw_bcast_list_lock; extern atomic_t originator_interval; extern atomic_t vis_interval; +extern atomic_t vis_mode; extern atomic_t aggregation_enabled; extern int16_t num_hna; extern int16_t num_ifs; @@ -147,5 +151,3 @@ 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); - - diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c new file mode 100644 index 00000000000..29c241119a3 --- /dev/null +++ b/drivers/staging/batman-adv/originator.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2009 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 + * + */ + +/* increase the reference counter for this originator */ + +#include "main.h" +#include "originator.h" +#include "hash.h" +#include "translation-table.h" +#include "routing.h" + +static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig); + +static void start_purge_timer(void) +{ + queue_delayed_work(bat_event_workqueue, &purge_orig_wq, 1 * HZ); +} + +int originator_init(void) +{ + unsigned long flags; + if (orig_hash) + return 1; + + spin_lock_irqsave(&orig_hash_lock, flags); + orig_hash = hash_new(128, compare_orig, choose_orig); + + if (!orig_hash) + goto err; + + spin_unlock_irqrestore(&orig_hash_lock, flags); + start_purge_timer(); + return 1; + +err: + spin_unlock_irqrestore(&orig_hash_lock, flags); + return 0; +} + +void originator_free(void) +{ + unsigned long flags; + + if (!orig_hash) + return; + + cancel_delayed_work_sync(&purge_orig_wq); + + spin_lock_irqsave(&orig_hash_lock, flags); + hash_delete(orig_hash, free_orig_node); + orig_hash = NULL; + spin_unlock_irqrestore(&orig_hash_lock, flags); +} + +struct neigh_node * +create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, + uint8_t *neigh, struct batman_if *if_incoming) +{ + struct neigh_node *neigh_node; + + bat_dbg(DBG_BATMAN, "Creating new last-hop neighbor of originator\n"); + + neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC); + if (!neigh_node) + return NULL; + + INIT_LIST_HEAD(&neigh_node->list); + + memcpy(neigh_node->addr, neigh, ETH_ALEN); + neigh_node->orig_node = orig_neigh_node; + neigh_node->if_incoming = if_incoming; + + list_add_tail(&neigh_node->list, &orig_node->neigh_list); + return neigh_node; +} + +void free_orig_node(void *data) +{ + struct list_head *list_pos, *list_pos_tmp; + struct neigh_node *neigh_node; + struct orig_node *orig_node = (struct orig_node *)data; + + /* for all neighbors towards this originator ... */ + list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { + neigh_node = list_entry(list_pos, struct neigh_node, list); + + list_del(list_pos); + kfree(neigh_node); + } + + hna_global_del_orig(orig_node, "originator timed out"); + + kfree(orig_node->bcast_own); + kfree(orig_node->bcast_own_sum); + kfree(orig_node); +} + +/* this function finds or creates an originator entry for the given + * address if it does not exits */ +struct orig_node *get_orig_node(uint8_t *addr) +{ + struct orig_node *orig_node; + struct hashtable_t *swaphash; + int size; + + orig_node = ((struct orig_node *)hash_find(orig_hash, addr)); + + if (orig_node != NULL) + return orig_node; + + bat_dbg(DBG_BATMAN, "Creating new originator: %pM \n", addr); + + orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC); + if (!orig_node) + return NULL; + + INIT_LIST_HEAD(&orig_node->neigh_list); + + memcpy(orig_node->orig, addr, ETH_ALEN); + orig_node->router = NULL; + orig_node->batman_if = NULL; + orig_node->hna_buff = NULL; + + size = num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS; + + orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); + if (!orig_node->bcast_own) + goto free_orig_node; + + size = num_ifs * sizeof(uint8_t); + orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); + if (!orig_node->bcast_own_sum) + goto free_bcast_own; + + if (hash_add(orig_hash, orig_node) < 0) + goto free_bcast_own_sum; + + if (orig_hash->elements * 4 > orig_hash->size) { + swaphash = hash_resize(orig_hash, orig_hash->size * 2); + + if (swaphash == NULL) + printk(KERN_ERR + "batman-adv:Couldn't resize orig hash table \n"); + else + orig_hash = swaphash; + } + + return orig_node; +free_bcast_own_sum: + kfree(orig_node->bcast_own_sum); +free_bcast_own: + kfree(orig_node->bcast_own); +free_orig_node: + kfree(orig_node); + return NULL; +} + +static bool purge_orig_neighbors(struct orig_node *orig_node, + struct neigh_node **best_neigh_node) +{ + struct list_head *list_pos, *list_pos_tmp; + struct neigh_node *neigh_node; + bool neigh_purged = false; + + *best_neigh_node = NULL; + + + /* for all neighbors towards this originator ... */ + list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { + neigh_node = list_entry(list_pos, struct neigh_node, list); + + if (time_after(jiffies, + (neigh_node->last_valid + + ((PURGE_TIMEOUT * HZ) / 1000)))) { + + bat_dbg(DBG_BATMAN, "neighbor timeout: originator %pM, neighbor: %pM, last_valid %lu\n", orig_node->orig, neigh_node->addr, (neigh_node->last_valid / HZ)); + + neigh_purged = true; + list_del(list_pos); + kfree(neigh_node); + } else { + if ((*best_neigh_node == NULL) || + (neigh_node->tq_avg > (*best_neigh_node)->tq_avg)) + *best_neigh_node = neigh_node; + } + } + return neigh_purged; +} + + +static bool purge_orig_node(struct orig_node *orig_node) +{ + struct neigh_node *best_neigh_node; + + if (time_after(jiffies, + (orig_node->last_valid + + ((2 * PURGE_TIMEOUT * HZ) / 1000)))) { + + bat_dbg(DBG_BATMAN, + "Originator timeout: originator %pM, last_valid %lu\n", + orig_node->orig, (orig_node->last_valid / HZ)); + return true; + } else { + if (purge_orig_neighbors(orig_node, &best_neigh_node)) + update_routes(orig_node, best_neigh_node, + orig_node->hna_buff, + orig_node->hna_buff_len); + } + return false; +} + +void purge_orig(struct work_struct *work) +{ + HASHIT(hashit); + struct orig_node *orig_node; + unsigned long flags; + + spin_lock_irqsave(&orig_hash_lock, flags); + + /* for all origins... */ + while (hash_iterate(orig_hash, &hashit)) { + orig_node = hashit.bucket->data; + if (purge_orig_node(orig_node)) { + hash_remove_bucket(orig_hash, &hashit); + free_orig_node(orig_node); + } + } + + spin_unlock_irqrestore(&orig_hash_lock, flags); + + start_purge_timer(); +} + + diff --git a/drivers/staging/batman-adv/log.h b/drivers/staging/batman-adv/originator.h index 780e3abb48f..6ef7a054a0a 100644 --- a/drivers/staging/batman-adv/log.h +++ b/drivers/staging/batman-adv/originator.h @@ -19,14 +19,13 @@ * */ -extern const struct file_operations proc_log_operations; -extern uint8_t log_level; +int originator_init(void); +void free_orig_node(void *data); +void originator_free(void); +void purge_orig(struct work_struct *work); +struct orig_node *orig_find(char *mac); +struct orig_node *get_orig_node(uint8_t *addr); +struct neigh_node * +create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, + uint8_t *neigh, struct batman_if *if_incoming); -int debug_log(int type, char *fmt, ...); -int log_open(struct inode *inode, struct file *file); -int log_release(struct inode *inode, struct file *file); -ssize_t log_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos); -ssize_t log_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos); -unsigned int log_poll(struct file *file, poll_table *wait); diff --git a/drivers/staging/batman-adv/packet.h b/drivers/staging/batman-adv/packet.h index 5627ca32601..ad006ce8b13 100644 --- a/drivers/staging/batman-adv/packet.h +++ b/drivers/staging/batman-adv/packet.h @@ -90,7 +90,7 @@ struct vis_packet { uint8_t entries; /* number of entries behind this struct */ uint8_t ttl; /* TTL */ uint8_t vis_orig[6]; /* originator that informs about its - * neighbours */ + * neighbors */ uint8_t target_orig[6]; /* who should receive this packet */ uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ } __attribute__((packed)); diff --git a/drivers/staging/batman-adv/proc.c b/drivers/staging/batman-adv/proc.c index aac3df7f13f..7de60e84bc9 100644 --- a/drivers/staging/batman-adv/proc.c +++ b/drivers/staging/batman-adv/proc.c @@ -21,23 +21,18 @@ #include "main.h" #include "proc.h" -#include "log.h" #include "routing.h" #include "translation-table.h" #include "hard-interface.h" #include "types.h" #include "hash.h" #include "vis.h" -#include "compat.h" - -static uint8_t vis_format = DOT_DRAW; static struct proc_dir_entry *proc_batman_dir, *proc_interface_file; static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file; -static struct proc_dir_entry *proc_log_file, *proc_log_level_file; static struct proc_dir_entry *proc_transt_local_file; static struct proc_dir_entry *proc_transt_global_file; -static struct proc_dir_entry *proc_vis_file, *proc_vis_format_file; +static struct proc_dir_entry *proc_vis_srv_file, *proc_vis_data_file; static struct proc_dir_entry *proc_aggr_file; static int proc_interfaces_read(struct seq_file *seq, void *offset) @@ -68,7 +63,7 @@ static ssize_t proc_interfaces_write(struct file *instance, size_t count, loff_t *data) { char *if_string, *colon_ptr = NULL, *cr_ptr = NULL; - int not_copied = 0, if_num = 0; + int not_copied = 0, if_num = 0, add_success; struct batman_if *batman_if = NULL; if_string = kmalloc(count, GFP_KERNEL); @@ -77,8 +72,7 @@ static ssize_t proc_interfaces_write(struct file *instance, return -ENOMEM; if (count > IFNAMSIZ - 1) { - debug_log(LOG_TYPE_WARN, - "Can't add interface: device name is too long\n"); + printk(KERN_WARNING "batman-adv:Can't add interface: device name is too long\n"); goto end; } @@ -105,7 +99,7 @@ static ssize_t proc_interfaces_write(struct file *instance, rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { if (strncmp(batman_if->dev, if_string, count) == 0) { - debug_log(LOG_TYPE_WARN, "Given interface is already active: %s\n", if_string); + printk(KERN_ERR "batman-adv:Given interface is already active: %s\n", if_string); rcu_read_unlock(); goto end; @@ -115,22 +109,17 @@ static ssize_t proc_interfaces_write(struct file *instance, } rcu_read_unlock(); - hardif_add_interface(if_string, if_num); + add_success = hardif_add_interface(if_string, if_num); + if (add_success < 0) + goto end; + + num_ifs = if_num + 1; if ((atomic_read(&module_state) == MODULE_INACTIVE) && (hardif_get_active_if_num() > 0)) activate_module(); - rcu_read_lock(); - if (list_empty(&if_list)) { - rcu_read_unlock(); - goto end; - } - rcu_read_unlock(); - - num_ifs = if_num + 1; return count; - end: kfree(if_string); return count; @@ -162,20 +151,18 @@ static ssize_t proc_orig_interval_write(struct file *file, retval = strict_strtoul(interval_string, 10, &originator_interval_tmp); if (retval) { - debug_log(LOG_TYPE_WARN, "New originator interval invalid\n"); + printk(KERN_ERR "batman-adv:New originator interval invalid\n"); goto end; } if (originator_interval_tmp <= JITTER * 2) { - debug_log(LOG_TYPE_WARN, - "New originator interval too small: %i (min: %i)\n", - originator_interval_tmp, JITTER * 2); + printk(KERN_WARNING "batman-adv:New originator interval too small: %li (min: %i)\n", + originator_interval_tmp, JITTER * 2); goto end; } - debug_log(LOG_TYPE_NOTICE, - "Changing originator interval from: %i to: %i\n", - atomic_read(&originator_interval), originator_interval_tmp); + printk(KERN_INFO "batman-adv:Changing originator interval from: %i to: %li\n", + atomic_read(&originator_interval), originator_interval_tmp); atomic_set(&originator_interval, originator_interval_tmp); @@ -191,11 +178,12 @@ static int proc_orig_interval_open(struct inode *inode, struct file *file) static int proc_originators_read(struct seq_file *seq, void *offset) { - struct hash_it_t *hashit = NULL; + HASHIT(hashit); struct orig_node *orig_node; struct neigh_node *neigh_node; int batman_count = 0; char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN]; + unsigned long flags; rcu_read_lock(); if (list_empty(&if_list)) { @@ -218,11 +206,11 @@ static int proc_originators_read(struct seq_file *seq, void *offset) ((struct batman_if *)if_list.next)->addr_str); rcu_read_unlock(); - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); - while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { + while (hash_iterate(orig_hash, &hashit)) { - orig_node = hashit->bucket->data; + orig_node = hashit.bucket->data; if (!orig_node->router) continue; @@ -249,7 +237,7 @@ static int proc_originators_read(struct seq_file *seq, void *offset) } - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); if (batman_count == 0) seq_printf(seq, "No batman nodes in range ... \n"); @@ -263,84 +251,6 @@ static int proc_originators_open(struct inode *inode, struct file *file) return single_open(file, proc_originators_read, NULL); } -static int proc_log_level_read(struct seq_file *seq, void *offset) -{ - - seq_printf(seq, "[x] %s (%d)\n", LOG_TYPE_CRIT_NAME, LOG_TYPE_CRIT); - seq_printf(seq, "[%c] %s (%d)\n", - (LOG_TYPE_WARN & log_level) ? 'x' : ' ', - LOG_TYPE_WARN_NAME, LOG_TYPE_WARN); - seq_printf(seq, "[%c] %s (%d)\n", - (LOG_TYPE_NOTICE & log_level) ? 'x' : ' ', - LOG_TYPE_NOTICE_NAME, LOG_TYPE_NOTICE); - seq_printf(seq, "[%c] %s (%d)\n", - (LOG_TYPE_BATMAN & log_level) ? 'x' : ' ', - LOG_TYPE_BATMAN_NAME, LOG_TYPE_BATMAN); - seq_printf(seq, "[%c] %s (%d)\n", - (LOG_TYPE_ROUTES & log_level) ? 'x' : ' ', - LOG_TYPE_ROUTES_NAME, LOG_TYPE_ROUTES); - return 0; -} - -static int proc_log_level_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_log_level_read, NULL); -} - -static ssize_t proc_log_level_write(struct file *instance, - const char __user *userbuffer, - size_t count, loff_t *data) -{ - char *log_level_string, *tokptr, *cp; - int finished, not_copied = 0; - unsigned long log_level_tmp = 0; - - log_level_string = kmalloc(count, GFP_KERNEL); - - if (!log_level_string) - return -ENOMEM; - - not_copied = copy_from_user(log_level_string, userbuffer, count); - log_level_string[count - not_copied - 1] = 0; - - if (strict_strtoul(log_level_string, 10, &log_level_tmp) < 0) { - /* was not a number, doing textual parsing */ - log_level_tmp = 0; - tokptr = log_level_string; - - for (cp = log_level_string, finished = 0; !finished; cp++) { - switch (*cp) { - case 0: - finished = 1; - case ' ': - case '\n': - case '\t': - *cp = 0; - /* compare */ - if (strcmp(tokptr, LOG_TYPE_WARN_NAME) == 0) - log_level_tmp |= LOG_TYPE_WARN; - if (strcmp(tokptr, LOG_TYPE_NOTICE_NAME) == 0) - log_level_tmp |= LOG_TYPE_NOTICE; - if (strcmp(tokptr, LOG_TYPE_BATMAN_NAME) == 0) - log_level_tmp |= LOG_TYPE_BATMAN; - if (strcmp(tokptr, LOG_TYPE_ROUTES_NAME) == 0) - log_level_tmp |= LOG_TYPE_ROUTES; - tokptr = cp + 1; - break; - default: - ; - } - } - } - - debug_log(LOG_TYPE_CRIT, "Changing log_level from: %i to: %i\n", - log_level, log_level_tmp); - log_level = log_level_tmp; - - kfree(log_level_string); - return count; -} - static int proc_transt_local_read(struct seq_file *seq, void *offset) { char *buf; @@ -405,172 +315,8 @@ static int proc_transt_global_open(struct inode *inode, struct file *file) return single_open(file, proc_transt_global_read, NULL); } -/* insert interface to the list of interfaces of one originator */ - -static void proc_vis_insert_interface(const uint8_t *interface, - struct vis_if_list **if_entry, - bool primary) -{ - /* Did we get an empty list? (then insert imediately) */ - if(*if_entry == NULL) { - *if_entry = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL); - if (*if_entry == NULL) - return; - - (*if_entry)->primary = primary; - (*if_entry)->next = NULL; - memcpy((*if_entry)->addr, interface, ETH_ALEN); - } else { - struct vis_if_list *head_if_entry = *if_entry; - /* Do we already have this interface in our list? */ - while (!compare_orig((*if_entry)->addr, (void *)interface)) { - - /* Or did we reach the end (then append the interface) */ - if ((*if_entry)->next == NULL) { - (*if_entry)->next = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL); - if ((*if_entry)->next == NULL) - return; - - memcpy((*if_entry)->next->addr, interface, ETH_ALEN); - (*if_entry)->next->primary = primary; - (*if_entry)->next->next = NULL; - break; - } - *if_entry = (*if_entry)->next; - } - /* Rewind the list to its head */ - *if_entry = head_if_entry; - } -} -/* read an entry */ - -static void proc_vis_read_entry(struct seq_file *seq, - struct vis_info_entry *entry, - struct vis_if_list **if_entry, - uint8_t *vis_orig, - uint8_t current_format, - uint8_t first_line) -{ - char from[40]; - char to[40]; - int int_part, frac_part; - - addr_to_string(to, entry->dest); - if (entry->quality == 0) { -#ifndef VIS_SUBCLUSTERS_DISABLED - proc_vis_insert_interface(vis_orig, if_entry, true); -#endif /* VIS_SUBCLUSTERS_DISABLED */ - addr_to_string(from, vis_orig); - if (current_format == DOT_DRAW) { - seq_printf(seq, "\t\"%s\" -> \"%s\" [label=\"HNA\"]\n", - from, to); - } else { - seq_printf(seq, - "%s\t{ router : \"%s\", gateway : \"%s\", label : \"HNA\" }", - (first_line ? "" : ",\n"), from, to); - } - } else { -#ifndef VIS_SUBCLUSTERS_DISABLED - proc_vis_insert_interface(entry->src, if_entry, compare_orig(entry->src, vis_orig)); -#endif /* VIS_SUBCLUSTERS_DISABLED */ - addr_to_string(from, entry->src); - - /* kernel has no printf-support for %f? it'd be better to return - * this in float. */ - - int_part = TQ_MAX_VALUE / entry->quality; - frac_part = 1000 * TQ_MAX_VALUE / entry->quality - int_part * 1000; - - if (current_format == DOT_DRAW) { - seq_printf(seq, - "\t\"%s\" -> \"%s\" [label=\"%d.%d\"]\n", - from, to, int_part, frac_part); - } else { - seq_printf(seq, - "%s\t{ router : \"%s\", neighbour : \"%s\", label : %d.%d }", - (first_line ? "" : ",\n"), from, to, int_part, frac_part); - } - } -} - - -static int proc_vis_read(struct seq_file *seq, void *offset) -{ - struct hash_it_t *hashit = NULL; - struct vis_info *info; - struct vis_info_entry *entries; - struct vis_if_list *if_entries = NULL; - int i; - uint8_t current_format, first_line = 1; -#ifndef VIS_SUBCLUSTERS_DISABLED - char tmp_addr_str[ETH_STR_LEN]; - struct vis_if_list *tmp_if_next; -#endif /* VIS_SUBCLUSTERS_DISABLED */ - - current_format = vis_format; - - rcu_read_lock(); - if (list_empty(&if_list) || (!is_vis_server())) { - rcu_read_unlock(); - if (current_format == DOT_DRAW) - seq_printf(seq, "digraph {\n}\n"); - goto end; - } - - rcu_read_unlock(); - - if (current_format == DOT_DRAW) - seq_printf(seq, "digraph {\n"); - - spin_lock(&vis_hash_lock); - while (NULL != (hashit = hash_iterate(vis_hash, hashit))) { - info = hashit->bucket->data; - entries = (struct vis_info_entry *) - ((char *)info + sizeof(struct vis_info)); - - for (i = 0; i < info->packet.entries; i++) { - proc_vis_read_entry(seq, &entries[i], &if_entries, - info->packet.vis_orig, - current_format, first_line); - if (first_line) - first_line = 0; - } - -#ifndef VIS_SUBCLUSTERS_DISABLED - /* Generate subgraphs from the collected items */ - if (current_format == DOT_DRAW) { - - addr_to_string(tmp_addr_str, info->packet.vis_orig); - seq_printf(seq, "\tsubgraph \"cluster_%s\" {\n", tmp_addr_str); - while (if_entries != NULL) { - - addr_to_string(tmp_addr_str, if_entries->addr); - if (if_entries->primary) - seq_printf(seq, "\t\t\"%s\" [peripheries=2]\n", tmp_addr_str); - else - seq_printf(seq, "\t\t\"%s\"\n", tmp_addr_str); - - /* ... and empty the list while doing this */ - tmp_if_next = if_entries->next; - kfree(if_entries); - if_entries = tmp_if_next; - } - seq_printf(seq, "\t}\n"); - } -#endif /* VIS_SUBCLUSTERS_DISABLED */ - } - spin_unlock(&vis_hash_lock); - - if (current_format == DOT_DRAW) - seq_printf(seq, "}\n"); - else - seq_printf(seq, "\n"); -end: - return 0; -} - /* setting the mode of the vis server by the user */ -static ssize_t proc_vis_write(struct file *file, const char __user * buffer, +static ssize_t proc_vis_srv_write(struct file *file, const char __user * buffer, size_t count, loff_t *ppos) { char *vis_mode_string; @@ -584,72 +330,84 @@ static ssize_t proc_vis_write(struct file *file, const char __user * buffer, not_copied = copy_from_user(vis_mode_string, buffer, count); vis_mode_string[count - not_copied - 1] = 0; - if (strcmp(vis_mode_string, "client") == 0) { - debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to client\n"); - vis_set_mode(VIS_TYPE_CLIENT_UPDATE); - } else if (strcmp(vis_mode_string, "server") == 0) { - debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to server\n"); - vis_set_mode(VIS_TYPE_SERVER_SYNC); + if ((strcmp(vis_mode_string, "client") == 0) || + (strcmp(vis_mode_string, "disabled") == 0)) { + printk(KERN_INFO "batman-adv:Setting VIS mode to client (disabling vis server)\n"); + atomic_set(&vis_mode, VIS_TYPE_CLIENT_UPDATE); + } else if ((strcmp(vis_mode_string, "server") == 0) || + (strcmp(vis_mode_string, "enabled") == 0)) { + printk(KERN_INFO "batman-adv:Setting VIS mode to server (enabling vis server)\n"); + atomic_set(&vis_mode, VIS_TYPE_SERVER_SYNC); } else - debug_log(LOG_TYPE_WARN, "Unknown VIS mode: %s\n", - vis_mode_string); + printk(KERN_ERR "batman-adv:Unknown VIS mode: %s\n", + vis_mode_string); kfree(vis_mode_string); return count; } -static int proc_vis_open(struct inode *inode, struct file *file) +static int proc_vis_srv_read(struct seq_file *seq, void *offset) { - return single_open(file, proc_vis_read, NULL); -} + int vis_server = atomic_read(&vis_mode); + + seq_printf(seq, "[%c] client mode (server disabled) \n", + (vis_server == VIS_TYPE_CLIENT_UPDATE) ? 'x' : ' '); + seq_printf(seq, "[%c] server mode (server enabled) \n", + (vis_server == VIS_TYPE_SERVER_SYNC) ? 'x' : ' '); -static int proc_vis_format_read(struct seq_file *seq, void *offset) -{ - uint8_t current_format = vis_format; - - seq_printf(seq, "[%c] %s\n", - (current_format == DOT_DRAW) ? 'x' : ' ', - VIS_FORMAT_DD_NAME); - seq_printf(seq, "[%c] %s\n", - (current_format == JSON) ? 'x' : ' ', - VIS_FORMAT_JSON_NAME); return 0; } -static int proc_vis_format_open(struct inode *inode, struct file *file) +static int proc_vis_srv_open(struct inode *inode, struct file *file) { - return single_open(file, proc_vis_format_read, NULL); + return single_open(file, proc_vis_srv_read, NULL); } -static ssize_t proc_vis_format_write(struct file *file, - const char __user *buffer, - size_t count, loff_t *ppos) +static int proc_vis_data_read(struct seq_file *seq, void *offset) { - char *vis_format_string; - int not_copied = 0; + HASHIT(hashit); + struct vis_info *info; + struct vis_info_entry *entries; + HLIST_HEAD(vis_if_list); + int i; + char tmp_addr_str[ETH_STR_LEN]; + unsigned long flags; + int vis_server = atomic_read(&vis_mode); + + rcu_read_lock(); + if (list_empty(&if_list) || (vis_server == VIS_TYPE_CLIENT_UPDATE)) { + rcu_read_unlock(); + goto end; + } - vis_format_string = kmalloc(count, GFP_KERNEL); + rcu_read_unlock(); - if (!vis_format_string) - return -ENOMEM; + spin_lock_irqsave(&vis_hash_lock, flags); + while (hash_iterate(vis_hash, &hashit)) { + info = hashit.bucket->data; + entries = (struct vis_info_entry *) + ((char *)info + sizeof(struct vis_info)); + addr_to_string(tmp_addr_str, info->packet.vis_orig); + seq_printf(seq, "%s,", tmp_addr_str); - not_copied = copy_from_user(vis_format_string, buffer, count); - vis_format_string[count - not_copied - 1] = 0; - - if (strcmp(vis_format_string, VIS_FORMAT_DD_NAME) == 0) { - debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n", - VIS_FORMAT_DD_NAME); - vis_format = DOT_DRAW; - } else if (strcmp(vis_format_string, VIS_FORMAT_JSON_NAME) == 0) { - debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n", - VIS_FORMAT_JSON_NAME); - vis_format = JSON; - } else - debug_log(LOG_TYPE_WARN, "Unknown VIS output format: %s\n", - vis_format_string); + for (i = 0; i < info->packet.entries; i++) { + proc_vis_read_entry(seq, &entries[i], &vis_if_list, + info->packet.vis_orig); + } - kfree(vis_format_string); - return count; + /* add primary/secondary records */ + proc_vis_read_prim_sec(seq, &vis_if_list); + seq_printf(seq, "\n"); + } + spin_unlock_irqrestore(&vis_hash_lock, flags); + +end: + return 0; +} + +static int proc_vis_data_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_vis_data_read, NULL); } static int proc_aggr_read(struct seq_file *seq, void *offset) @@ -665,6 +423,7 @@ static ssize_t proc_aggr_write(struct file *file, const char __user *buffer, char *aggr_string; int not_copied = 0; unsigned long aggregation_enabled_tmp; + int retval; aggr_string = kmalloc(count, GFP_KERNEL); @@ -674,22 +433,21 @@ static ssize_t proc_aggr_write(struct file *file, const char __user *buffer, not_copied = copy_from_user(aggr_string, buffer, count); aggr_string[count - not_copied - 1] = 0; - strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp); + retval = strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp); - if ((aggregation_enabled_tmp != 0) && (aggregation_enabled_tmp != 1)) { - debug_log(LOG_TYPE_WARN, "Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp); - goto end; + if (retval || aggregation_enabled_tmp > 1) { + printk(KERN_ERR "batman-adv:Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp); + } else { + printk(KERN_INFO "batman-adv:Changing aggregation from: %s (%i) to: %s (%li)\n", + (atomic_read(&aggregation_enabled) == 1 ? + "enabled" : "disabled"), + atomic_read(&aggregation_enabled), + (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"), + aggregation_enabled_tmp); + atomic_set(&aggregation_enabled, + (unsigned)aggregation_enabled_tmp); } - debug_log(LOG_TYPE_NOTICE, "Changing aggregation from: %s (%i) to: %s (%li)\n", - (atomic_read(&aggregation_enabled) == 1 ? - "enabled" : "disabled"), - atomic_read(&aggregation_enabled), - (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"), - aggregation_enabled_tmp); - - atomic_set(&aggregation_enabled, (unsigned)aggregation_enabled_tmp); -end: kfree(aggr_string); return count; } @@ -715,20 +473,20 @@ static const struct file_operations proc_aggr_fops = { .release = single_release, }; -static const struct file_operations proc_vis_format_fops = { +static const struct file_operations proc_vis_srv_fops = { .owner = THIS_MODULE, - .open = proc_vis_format_open, + .open = proc_vis_srv_open, .read = seq_read, - .write = proc_vis_format_write, + .write = proc_vis_srv_write, .llseek = seq_lseek, .release = single_release, }; -static const struct file_operations proc_vis_fops = { +static const struct file_operations proc_vis_data_fops = { .owner = THIS_MODULE, - .open = proc_vis_open, + .open = proc_vis_data_open, .read = seq_read, - .write = proc_vis_write, + .write = proc_dummy_write, .llseek = seq_lseek, .release = single_release, }; @@ -760,15 +518,6 @@ static const struct file_operations proc_transt_global_fops = { .release = single_release, }; -static const struct file_operations proc_log_level_fops = { - .owner = THIS_MODULE, - .open = proc_log_level_open, - .read = seq_read, - .write = proc_log_level_write, - .llseek = seq_lseek, - .release = single_release, -}; - static const struct file_operations proc_interfaces_fops = { .owner = THIS_MODULE, .open = proc_interfaces_open, @@ -795,12 +544,6 @@ void cleanup_procfs(void) if (proc_transt_local_file) remove_proc_entry(PROC_FILE_TRANST_LOCAL, proc_batman_dir); - if (proc_log_file) - remove_proc_entry(PROC_FILE_LOG, proc_batman_dir); - - if (proc_log_level_file) - remove_proc_entry(PROC_FILE_LOG_LEVEL, proc_batman_dir); - if (proc_originators_file) remove_proc_entry(PROC_FILE_ORIGINATORS, proc_batman_dir); @@ -810,11 +553,11 @@ void cleanup_procfs(void) if (proc_interface_file) remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir); - if (proc_vis_file) - remove_proc_entry(PROC_FILE_VIS, proc_batman_dir); + if (proc_vis_data_file) + remove_proc_entry(PROC_FILE_VIS_DATA, proc_batman_dir); - if (proc_vis_format_file) - remove_proc_entry(PROC_FILE_VIS_FORMAT, proc_batman_dir); + if (proc_vis_srv_file) + remove_proc_entry(PROC_FILE_VIS_SRV, proc_batman_dir); if (proc_aggr_file) remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir); @@ -862,17 +605,6 @@ int setup_procfs(void) return -EFAULT; } - proc_log_level_file = create_proc_entry(PROC_FILE_LOG_LEVEL, - S_IWUSR | S_IRUGO, - proc_batman_dir); - if (proc_log_level_file) { - proc_log_level_file->proc_fops = &proc_log_level_fops; - } else { - printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_LOG_LEVEL); - cleanup_procfs(); - return -EFAULT; - } - proc_originators_file = create_proc_entry(PROC_FILE_ORIGINATORS, S_IRUGO, proc_batman_dir); if (proc_originators_file) { @@ -883,16 +615,6 @@ int setup_procfs(void) return -EFAULT; } - proc_log_file = create_proc_entry(PROC_FILE_LOG, - S_IRUGO, proc_batman_dir); - if (proc_log_file) { - proc_log_file->proc_fops = &proc_log_operations; - } else { - printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_FILE_LOG, PROC_FILE_GATEWAYS); - cleanup_procfs(); - return -EFAULT; - } - proc_transt_local_file = create_proc_entry(PROC_FILE_TRANST_LOCAL, S_IRUGO, proc_batman_dir); if (proc_transt_local_file) { @@ -913,23 +635,23 @@ int setup_procfs(void) return -EFAULT; } - proc_vis_file = create_proc_entry(PROC_FILE_VIS, S_IWUSR | S_IRUGO, - proc_batman_dir); - if (proc_vis_file) { - proc_vis_file->proc_fops = &proc_vis_fops; + proc_vis_srv_file = create_proc_entry(PROC_FILE_VIS_SRV, + S_IWUSR | S_IRUGO, + proc_batman_dir); + if (proc_vis_srv_file) { + proc_vis_srv_file->proc_fops = &proc_vis_srv_fops; } else { - printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS); + printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_SRV); cleanup_procfs(); return -EFAULT; } - proc_vis_format_file = create_proc_entry(PROC_FILE_VIS_FORMAT, - S_IWUSR | S_IRUGO, - proc_batman_dir); - if (proc_vis_format_file) { - proc_vis_format_file->proc_fops = &proc_vis_format_fops; + proc_vis_data_file = create_proc_entry(PROC_FILE_VIS_DATA, S_IRUGO, + proc_batman_dir); + if (proc_vis_data_file) { + proc_vis_data_file->proc_fops = &proc_vis_data_fops; } else { - printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_FORMAT); + printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_DATA); cleanup_procfs(); return -EFAULT; } @@ -946,5 +668,3 @@ int setup_procfs(void) return 0; } - - diff --git a/drivers/staging/batman-adv/proc.h b/drivers/staging/batman-adv/proc.h index 16d3efdebe5..cd690e0f3e4 100644 --- a/drivers/staging/batman-adv/proc.h +++ b/drivers/staging/batman-adv/proc.h @@ -31,19 +31,10 @@ #define PROC_FILE_LOG_LEVEL "log_level" #define PROC_FILE_TRANST_LOCAL "transtable_local" #define PROC_FILE_TRANST_GLOBAL "transtable_global" -#define PROC_FILE_VIS "vis" -#define PROC_FILE_VIS_FORMAT "vis_format" +#define PROC_FILE_VIS_SRV "vis_server" +#define PROC_FILE_VIS_DATA "vis_data" #define PROC_FILE_AGGR "aggregate_ogm" void cleanup_procfs(void); int setup_procfs(void); -/* While scanning for vis-entries of a particular vis-originator - * this list collects its interfaces to create a subgraph/cluster - * out of them later - */ -struct vis_if_list { - uint8_t addr[ETH_ALEN]; - bool primary; - struct vis_if_list *next; -}; diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 4a14c363ac2..d89048beebe 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -19,304 +19,226 @@ * */ - - - - #include "main.h" #include "routing.h" -#include "log.h" #include "send.h" +#include "hash.h" #include "soft-interface.h" #include "hard-interface.h" #include "device.h" #include "translation-table.h" +#include "originator.h" #include "types.h" -#include "hash.h" #include "ring_buffer.h" #include "vis.h" #include "aggregation.h" -#include "compat.h" - - DECLARE_WAIT_QUEUE_HEAD(thread_wait); -static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig); - -static atomic_t data_ready_cond; -atomic_t exit_cond; - -static void start_purge_timer(void) -{ - queue_delayed_work(bat_event_workqueue, &purge_orig_wq, 1 * HZ); -} - -int originator_init(void) -{ - if (orig_hash) - return 1; - - spin_lock(&orig_hash_lock); - orig_hash = hash_new(128, compare_orig, choose_orig); - - if (!orig_hash) - goto err; - - spin_unlock(&orig_hash_lock); - start_purge_timer(); - return 1; - -err: - spin_unlock(&orig_hash_lock); - return 0; -} - -void originator_free(void) -{ - if (!orig_hash) - return; - - cancel_delayed_work_sync(&purge_orig_wq); - - spin_lock(&orig_hash_lock); - hash_delete(orig_hash, free_orig_node); - orig_hash = NULL; - spin_unlock(&orig_hash_lock); -} -static struct neigh_node *create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, struct batman_if *if_incoming) +void slide_own_bcast_window(struct batman_if *batman_if) { - struct neigh_node *neigh_node; + HASHIT(hashit); + struct orig_node *orig_node; + TYPE_OF_WORD *word; + unsigned long flags; - debug_log(LOG_TYPE_BATMAN, "Creating new last-hop neighbour of originator\n"); + spin_lock_irqsave(&orig_hash_lock, flags); - neigh_node = kmalloc(sizeof(struct neigh_node), GFP_ATOMIC); - memset(neigh_node, 0, sizeof(struct neigh_node)); - INIT_LIST_HEAD(&neigh_node->list); + while (hash_iterate(orig_hash, &hashit)) { + orig_node = hashit.bucket->data; + word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]); - memcpy(neigh_node->addr, neigh, ETH_ALEN); - neigh_node->orig_node = orig_neigh_node; - neigh_node->if_incoming = if_incoming; + bit_get_packet(word, 1, 0); + orig_node->bcast_own_sum[batman_if->if_num] = + bit_packet_count(word); + } - list_add_tail(&neigh_node->list, &orig_node->neigh_list); - return neigh_node; + spin_unlock_irqrestore(&orig_hash_lock, flags); } -void free_orig_node(void *data) +static void update_HNA(struct orig_node *orig_node, + unsigned char *hna_buff, int hna_buff_len) { - struct list_head *list_pos, *list_pos_tmp; - struct neigh_node *neigh_node; - struct orig_node *orig_node = (struct orig_node *)data; + if ((hna_buff_len != orig_node->hna_buff_len) || + ((hna_buff_len > 0) && + (orig_node->hna_buff_len > 0) && + (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) { - /* for all neighbours towards this originator ... */ - list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { - neigh_node = list_entry(list_pos, struct neigh_node, list); + if (orig_node->hna_buff_len > 0) + hna_global_del_orig(orig_node, + "originator changed hna"); - list_del(list_pos); - kfree(neigh_node); + if ((hna_buff_len > 0) && (hna_buff != NULL)) + hna_global_add_orig(orig_node, hna_buff, hna_buff_len); } - - hna_global_del_orig(orig_node, "originator timed out"); - - kfree(orig_node->bcast_own); - kfree(orig_node->bcast_own_sum); - kfree(orig_node); } -/* this function finds or creates an originator entry for the given address if it does not exits */ -static struct orig_node *get_orig_node(uint8_t *addr) +static void update_route(struct orig_node *orig_node, + struct neigh_node *neigh_node, + unsigned char *hna_buff, int hna_buff_len) { - struct orig_node *orig_node; - struct hashtable_t *swaphash; - char orig_str[ETH_STR_LEN]; - - orig_node = ((struct orig_node *)hash_find(orig_hash, addr)); - - if (orig_node != NULL) - return orig_node; - - addr_to_string(orig_str, addr); - debug_log(LOG_TYPE_BATMAN, "Creating new originator: %s \n", orig_str); - - orig_node = kmalloc(sizeof(struct orig_node), GFP_ATOMIC); - memset(orig_node, 0, sizeof(struct orig_node)); - INIT_LIST_HEAD(&orig_node->neigh_list); - - memcpy(orig_node->orig, addr, ETH_ALEN); - orig_node->router = NULL; - orig_node->batman_if = NULL; - orig_node->hna_buff = NULL; + /* route deleted */ + if ((orig_node->router != NULL) && (neigh_node == NULL)) { - orig_node->bcast_own = kmalloc(num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS, GFP_ATOMIC); - memset(orig_node->bcast_own, 0, num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS); + bat_dbg(DBG_ROUTES, "Deleting route towards: %pM\n", + orig_node->orig); + hna_global_del_orig(orig_node, "originator timed out"); - orig_node->bcast_own_sum = kmalloc(num_ifs * sizeof(uint8_t), GFP_ATOMIC); - memset(orig_node->bcast_own_sum, 0, num_ifs * sizeof(uint8_t)); - - hash_add(orig_hash, orig_node); + /* route added */ + } else if ((orig_node->router == NULL) && (neigh_node != NULL)) { - if (orig_hash->elements * 4 > orig_hash->size) { - swaphash = hash_resize(orig_hash, orig_hash->size * 2); + bat_dbg(DBG_ROUTES, + "Adding route towards: %pM (via %pM)\n", + orig_node->orig, neigh_node->addr); + hna_global_add_orig(orig_node, hna_buff, hna_buff_len); - if (swaphash == NULL) - debug_log(LOG_TYPE_CRIT, "Couldn't resize orig hash table \n"); - else - orig_hash = swaphash; + /* route changed */ + } else { + bat_dbg(DBG_ROUTES, "Changing route towards: %pM (now via %pM - was via %pM)\n", orig_node->orig, neigh_node->addr, orig_node->router->addr); } - return orig_node; -} - -void slide_own_bcast_window(struct batman_if *batman_if) -{ - struct hash_it_t *hashit = NULL; - struct orig_node *orig_node; - - spin_lock(&orig_hash_lock); - - while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { - orig_node = hashit->bucket->data; - - bit_get_packet((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]), 1, 0); - orig_node->bcast_own_sum[batman_if->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS])); - } + if (neigh_node != NULL) + orig_node->batman_if = neigh_node->if_incoming; + else + orig_node->batman_if = NULL; - spin_unlock(&orig_hash_lock); + orig_node->router = neigh_node; } -static void update_routes(struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len) + +void update_routes(struct orig_node *orig_node, + struct neigh_node *neigh_node, + unsigned char *hna_buff, int hna_buff_len) { - char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], router_str[ETH_STR_LEN]; if (orig_node == NULL) return; - if (orig_node->router != neigh_node) { - addr_to_string(orig_str, orig_node->orig); - - /* route deleted */ - if ((orig_node->router != NULL) && (neigh_node == NULL)) { - - debug_log(LOG_TYPE_ROUTES, "Deleting route towards: %s\n", orig_str); - hna_global_del_orig(orig_node, "originator timed out"); - - /* route added */ - } else if ((orig_node->router == NULL) && (neigh_node != NULL)) { - - addr_to_string(neigh_str, neigh_node->addr); - debug_log(LOG_TYPE_ROUTES, "Adding route towards: %s (via %s)\n", orig_str, neigh_str); - hna_global_add_orig(orig_node, hna_buff, hna_buff_len); - - /* route changed */ - } else { - - addr_to_string(neigh_str, neigh_node->addr); - addr_to_string(router_str, orig_node->router->addr); - debug_log(LOG_TYPE_ROUTES, "Changing route towards: %s (now via %s - was via %s)\n", orig_str, neigh_str, router_str); - - } - - if (neigh_node != NULL) - orig_node->batman_if = neigh_node->if_incoming; - else - orig_node->batman_if = NULL; - - orig_node->router = neigh_node; - + if (orig_node->router != neigh_node) + update_route(orig_node, neigh_node, hna_buff, hna_buff_len); /* may be just HNA changed */ - } else { - - if ((hna_buff_len != orig_node->hna_buff_len) || ((hna_buff_len > 0) && (orig_node->hna_buff_len > 0) && (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) { - - if (orig_node->hna_buff_len > 0) - hna_global_del_orig(orig_node, "originator changed hna"); - - if ((hna_buff_len > 0) && (hna_buff != NULL)) - hna_global_add_orig(orig_node, hna_buff, hna_buff_len); - - } - - } + else + update_HNA(orig_node, hna_buff, hna_buff_len); } -static int isBidirectionalNeigh(struct orig_node *orig_node, struct orig_node *orig_neigh_node, struct batman_packet *batman_packet, struct batman_if *if_incoming) +static int isBidirectionalNeigh(struct orig_node *orig_node, + struct orig_node *orig_neigh_node, + struct batman_packet *batman_packet, + struct batman_if *if_incoming) { struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; - char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN]; unsigned char total_count; - addr_to_string(orig_str, orig_node->orig); - addr_to_string(neigh_str, orig_neigh_node->orig); - if (orig_node == orig_neigh_node) { - list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { + list_for_each_entry(tmp_neigh_node, + &orig_node->neigh_list, + list) { - if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming)) + if (compare_orig(tmp_neigh_node->addr, + orig_neigh_node->orig) && + (tmp_neigh_node->if_incoming == if_incoming)) neigh_node = tmp_neigh_node; } - if (neigh_node == NULL) - neigh_node = create_neighbor(orig_node, orig_neigh_node, orig_neigh_node->orig, if_incoming); + if (!neigh_node) + neigh_node = create_neighbor(orig_node, + orig_neigh_node, + orig_neigh_node->orig, + if_incoming); + /* create_neighbor failed, return 0 */ + if (!neigh_node) + return 0; neigh_node->last_valid = jiffies; } else { /* find packet count of corresponding one hop neighbor */ - list_for_each_entry(tmp_neigh_node, &orig_neigh_node->neigh_list, list) { + list_for_each_entry(tmp_neigh_node, + &orig_neigh_node->neigh_list, list) { - if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming)) + if (compare_orig(tmp_neigh_node->addr, + orig_neigh_node->orig) && + (tmp_neigh_node->if_incoming == if_incoming)) neigh_node = tmp_neigh_node; } - if (neigh_node == NULL) - neigh_node = create_neighbor(orig_neigh_node, orig_neigh_node, orig_neigh_node->orig, if_incoming); + if (!neigh_node) + neigh_node = create_neighbor(orig_neigh_node, + orig_neigh_node, + orig_neigh_node->orig, + if_incoming); + /* create_neighbor failed, return 0 */ + if (!neigh_node) + return 0; } orig_node->last_valid = jiffies; /* pay attention to not get a value bigger than 100 % */ - total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > neigh_node->real_packet_count ? neigh_node->real_packet_count : orig_neigh_node->bcast_own_sum[if_incoming->if_num]); + total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > + neigh_node->real_packet_count ? + neigh_node->real_packet_count : + orig_neigh_node->bcast_own_sum[if_incoming->if_num]); /* if we have too few packets (too less data) we set tq_own to zero */ /* if we receive too few packets it is not considered bidirectional */ - if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) + if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || + (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) orig_neigh_node->tq_own = 0; else - /* neigh_node->real_packet_count is never zero as we only purge old information when getting new information */ - orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / neigh_node->real_packet_count; + /* neigh_node->real_packet_count is never zero as we + * only purge old information when getting new + * information */ + orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / + neigh_node->real_packet_count; /* - * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE - * this does affect the nearly-symmetric links only a little, - * but punishes asymmetric links more. - * this will give a value between 0 and TQ_MAX_VALUE + * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does + * affect the nearly-symmetric links only a little, but + * punishes asymmetric links more. This will give a value + * between 0 and TQ_MAX_VALUE */ - orig_neigh_node->tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / - (TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE); - - batman_packet->tq = ((batman_packet->tq * orig_neigh_node->tq_own * orig_neigh_node->tq_asym_penalty) / (TQ_MAX_VALUE * TQ_MAX_VALUE)); - - debug_log(LOG_TYPE_BATMAN, "bidirectional: orig = %-15s neigh = %-15s => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n", - orig_str, neigh_str, total_count, neigh_node->real_packet_count, orig_neigh_node->tq_own, orig_neigh_node->tq_asym_penalty, batman_packet->tq); - - /* if link has the minimum required transmission quality consider it bidirectional */ + orig_neigh_node->tq_asym_penalty = + TQ_MAX_VALUE - + (TQ_MAX_VALUE * + (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * + (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * + (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / + (TQ_LOCAL_WINDOW_SIZE * + TQ_LOCAL_WINDOW_SIZE * + TQ_LOCAL_WINDOW_SIZE); + + batman_packet->tq = ((batman_packet->tq * + orig_neigh_node->tq_own * + orig_neigh_node->tq_asym_penalty) / + (TQ_MAX_VALUE * TQ_MAX_VALUE)); + + bat_dbg(DBG_BATMAN, "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n", + orig_node->orig, orig_neigh_node->orig, total_count, + neigh_node->real_packet_count, orig_neigh_node->tq_own, + orig_neigh_node->tq_asym_penalty, batman_packet->tq); + + /* if link has the minimum required transmission quality + * consider it bidirectional */ if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) return 1; return 0; } -static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming, unsigned char *hna_buff, int hna_buff_len, char is_duplicate) +static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, + struct batman_packet *batman_packet, + struct batman_if *if_incoming, + unsigned char *hna_buff, int hna_buff_len, + char is_duplicate) { struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; int tmp_hna_buff_len; - debug_log(LOG_TYPE_BATMAN, "update_originator(): Searching and updating originator entry of received packet \n"); + bat_dbg(DBG_BATMAN, "update_originator(): Searching and updating originator entry of received packet \n"); list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { - if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming)) { + if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && + (tmp_neigh_node->if_incoming == if_incoming)) { neigh_node = tmp_neigh_node; continue; } @@ -324,19 +246,34 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru if (is_duplicate) continue; - ring_buffer_set(tmp_neigh_node->tq_recv, &tmp_neigh_node->tq_index, 0); - tmp_neigh_node->tq_avg = ring_buffer_avg(tmp_neigh_node->tq_recv); + ring_buffer_set(tmp_neigh_node->tq_recv, + &tmp_neigh_node->tq_index, 0); + tmp_neigh_node->tq_avg = + ring_buffer_avg(tmp_neigh_node->tq_recv); } - if (neigh_node == NULL) - neigh_node = create_neighbor(orig_node, get_orig_node(ethhdr->h_source), ethhdr->h_source, if_incoming); - else - debug_log(LOG_TYPE_BATMAN, "Updating existing last-hop neighbour of originator\n"); + if (!neigh_node) { + struct orig_node *orig_tmp; + + orig_tmp = get_orig_node(ethhdr->h_source); + if (!orig_tmp) + return; + + neigh_node = create_neighbor(orig_node, + orig_tmp, + ethhdr->h_source, if_incoming); + if (!neigh_node) + return; + } else + bat_dbg(DBG_BATMAN, + "Updating existing last-hop neighbor of originator\n"); orig_node->flags = batman_packet->flags; neigh_node->last_valid = jiffies; - ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, batman_packet->tq); + ring_buffer_set(neigh_node->tq_recv, + &neigh_node->tq_index, + batman_packet->tq); neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); if (!is_duplicate) { @@ -344,9 +281,11 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru neigh_node->last_ttl = batman_packet->ttl; } - tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? batman_packet->num_hna * ETH_ALEN : hna_buff_len); + tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? + batman_packet->num_hna * ETH_ALEN : hna_buff_len); - /* if this neighbor already is our next hop there is nothing to change */ + /* if this neighbor already is our next hop there is nothing + * to change */ if (orig_node->router == neigh_node) goto update_hna; @@ -355,11 +294,12 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru (orig_node->router->tq_avg > neigh_node->tq_avg)) goto update_hna; - /* if the TQ is the same and the link not more symetric we won't consider it either */ + /* if the TQ is the same and the link not more symetric we + * won't consider it either */ if ((orig_node->router) && ((neigh_node->tq_avg == orig_node->router->tq_avg) && - (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] >= - neigh_node->orig_node->bcast_own_sum[if_incoming->if_num]))) + (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] + >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num]))) goto update_hna; update_routes(orig_node, neigh_node, hna_buff, tmp_hna_buff_len); @@ -367,60 +307,72 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, stru update_hna: update_routes(orig_node, orig_node->router, hna_buff, tmp_hna_buff_len); - return; } -static char count_real_packets(struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming) +static char count_real_packets(struct ethhdr *ethhdr, + struct batman_packet *batman_packet, + struct batman_if *if_incoming) { struct orig_node *orig_node; struct neigh_node *tmp_neigh_node; char is_duplicate = 0; - + uint16_t seq_diff; orig_node = get_orig_node(batman_packet->orig); if (orig_node == NULL) return 0; - list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { if (!is_duplicate) - is_duplicate = get_bit_status(tmp_neigh_node->real_bits, orig_node->last_real_seqno, batman_packet->seqno); - - if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming)) - bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 1); + is_duplicate = + get_bit_status(tmp_neigh_node->real_bits, + orig_node->last_real_seqno, + batman_packet->seqno); + seq_diff = batman_packet->seqno - orig_node->last_real_seqno; + if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && + (tmp_neigh_node->if_incoming == if_incoming)) + bit_get_packet(tmp_neigh_node->real_bits, seq_diff, 1); else - bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 0); + bit_get_packet(tmp_neigh_node->real_bits, seq_diff, 0); - tmp_neigh_node->real_packet_count = bit_packet_count(tmp_neigh_node->real_bits); + tmp_neigh_node->real_packet_count = + bit_packet_count(tmp_neigh_node->real_bits); } if (!is_duplicate) { - debug_log(LOG_TYPE_BATMAN, "updating last_seqno: old %d, new %d \n", orig_node->last_real_seqno, batman_packet->seqno); + bat_dbg(DBG_BATMAN, "updating last_seqno: old %d, new %d \n", + orig_node->last_real_seqno, batman_packet->seqno); orig_node->last_real_seqno = batman_packet->seqno; } return is_duplicate; } -void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming) +void receive_bat_packet(struct ethhdr *ethhdr, + struct batman_packet *batman_packet, + unsigned char *hna_buff, int hna_buff_len, + struct batman_if *if_incoming) { struct batman_if *batman_if; struct orig_node *orig_neigh_node, *orig_node; - char orig_str[ETH_STR_LEN], prev_sender_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN]; char has_directlink_flag; - char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0, is_broadcast = 0, is_bidirectional, is_single_hop_neigh, is_duplicate; + char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; + char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; + char is_duplicate; unsigned short if_incoming_seqno; - /* Silently drop when the batman packet is actually not a correct packet. + /* Silently drop when the batman packet is actually not a + * correct packet. * * This might happen if a packet is padded (e.g. Ethernet has a * minimum frame length of 64 byte) and the aggregation interprets * it as an additional length. * - * TODO: A more sane solution would be to have a bit in the batman_packet - * to detect whether the packet is the last packet in an aggregation. - * Here we expect that the padding is always zero (or not 0x01) + * TODO: A more sane solution would be to have a bit in the + * batman_packet to detect whether the packet is the last + * packet in an aggregation. Here we expect that the padding + * is always zero (or not 0x01) */ if (batman_packet->packet_type != BAT_PACKET) return; @@ -428,27 +380,31 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack /* could be changed by schedule_own_packet() */ if_incoming_seqno = atomic_read(&if_incoming->seqno); - addr_to_string(orig_str, batman_packet->orig); - addr_to_string(prev_sender_str, batman_packet->prev_sender); - addr_to_string(neigh_str, ethhdr->h_source); - has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0); - is_single_hop_neigh = (compare_orig(ethhdr->h_source, batman_packet->orig) ? 1 : 0); + is_single_hop_neigh = (compare_orig(ethhdr->h_source, + batman_packet->orig) ? 1 : 0); - debug_log(LOG_TYPE_BATMAN, "Received BATMAN packet via NB: %s, IF: %s [%s] (from OG: %s, via prev OG: %s, seqno %d, tq %d, TTL %d, V %d, IDF %d) \n", neigh_str, if_incoming->dev, if_incoming->addr_str, orig_str, prev_sender_str, batman_packet->seqno, batman_packet->tq, batman_packet->ttl, batman_packet->version, has_directlink_flag); + bat_dbg(DBG_BATMAN, "Received BATMAN packet via NB: %pM, IF: %s [%s] (from OG: %pM, via prev OG: %pM, seqno %d, tq %d, TTL %d, V %d, IDF %d) \n", + ethhdr->h_source, if_incoming->dev, if_incoming->addr_str, + batman_packet->orig, batman_packet->prev_sender, + batman_packet->seqno, batman_packet->tq, batman_packet->ttl, + batman_packet->version, has_directlink_flag); list_for_each_entry_rcu(batman_if, &if_list, list) { if (batman_if->if_active != IF_ACTIVE) continue; - if (compare_orig(ethhdr->h_source, batman_if->net_dev->dev_addr)) + if (compare_orig(ethhdr->h_source, + batman_if->net_dev->dev_addr)) is_my_addr = 1; - if (compare_orig(batman_packet->orig, batman_if->net_dev->dev_addr)) + if (compare_orig(batman_packet->orig, + batman_if->net_dev->dev_addr)) is_my_orig = 1; - if (compare_orig(batman_packet->prev_sender, batman_if->net_dev->dev_addr)) + if (compare_orig(batman_packet->prev_sender, + batman_if->net_dev->dev_addr)) is_my_oldorig = 1; if (compare_orig(ethhdr->h_source, broadcastAddr)) @@ -456,44 +412,61 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack } if (batman_packet->version != COMPAT_VERSION) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version); + bat_dbg(DBG_BATMAN, + "Drop packet: incompatible batman version (%i)\n", + batman_packet->version); return; } if (is_my_addr) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: received my own broadcast (sender: %s) \n", neigh_str); + bat_dbg(DBG_BATMAN, + "Drop packet: received my own broadcast (sender: %pM)\n", + ethhdr->h_source); return; } if (is_broadcast) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all packets with broadcast source addr (sender: %s) \n", neigh_str); + bat_dbg(DBG_BATMAN, "Drop packet: ignoring all packets with broadcast source addr (sender: %pM) \n", ethhdr->h_source); return; } if (is_my_orig) { + TYPE_OF_WORD *word; + int offset; + orig_neigh_node = get_orig_node(ethhdr->h_source); - /* neighbour has to indicate direct link and it has to come via the corresponding interface */ - /* if received seqno equals last send seqno save new seqno for bidirectional check */ - if (has_directlink_flag && compare_orig(if_incoming->net_dev->dev_addr, batman_packet->orig) && - (batman_packet->seqno - if_incoming_seqno + 2 == 0)) { - bit_mark((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS]), 0); - orig_neigh_node->bcast_own_sum[if_incoming->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS])); + if (!orig_neigh_node) + return; + + /* neighbor has to indicate direct link and it has to + * come via the corresponding interface */ + /* if received seqno equals last send seqno save new + * seqno for bidirectional check */ + if (has_directlink_flag && + compare_orig(if_incoming->net_dev->dev_addr, + batman_packet->orig) && + (batman_packet->seqno - if_incoming_seqno + 2 == 0)) { + offset = if_incoming->if_num * NUM_WORDS; + word = &(orig_neigh_node->bcast_own[offset]); + bit_mark(word, 0); + orig_neigh_node->bcast_own_sum[if_incoming->if_num] = + bit_packet_count(word); } - debug_log(LOG_TYPE_BATMAN, "Drop packet: originator packet from myself (via neighbour) \n"); + bat_dbg(DBG_BATMAN, "Drop packet: originator packet from myself (via neighbor) \n"); return; } if (batman_packet->tq == 0) { count_real_packets(ethhdr, batman_packet, if_incoming); - debug_log(LOG_TYPE_BATMAN, "Drop packet: originator packet with tq equal 0 \n"); + bat_dbg(DBG_BATMAN, "Drop packet: originator packet with tq equal 0 \n"); return; } if (is_my_oldorig) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all rebroadcast echos (sender: %s) \n", neigh_str); + bat_dbg(DBG_BATMAN, "Drop packet: ignoring all rebroadcast echos (sender: %pM) \n", ethhdr->h_source); return; } @@ -504,507 +477,502 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_pack return; /* avoid temporary routing loops */ - if ((orig_node->router) && (orig_node->router->orig_node->router) && - (compare_orig(orig_node->router->addr, batman_packet->prev_sender)) && + if ((orig_node->router) && + (orig_node->router->orig_node->router) && + (compare_orig(orig_node->router->addr, + batman_packet->prev_sender)) && !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) && - (compare_orig(orig_node->router->addr, orig_node->router->orig_node->router->addr))) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %s) \n", neigh_str); + (compare_orig(orig_node->router->addr, + orig_node->router->orig_node->router->addr))) { + bat_dbg(DBG_BATMAN, "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM) \n", ethhdr->h_source); return; } - /* if sender is a direct neighbor the sender mac equals originator mac */ - orig_neigh_node = (is_single_hop_neigh ? orig_node : get_orig_node(ethhdr->h_source)); + /* if sender is a direct neighbor the sender mac equals + * originator mac */ + orig_neigh_node = (is_single_hop_neigh ? + orig_node : get_orig_node(ethhdr->h_source)); if (orig_neigh_node == NULL) return; - /* drop packet if sender is not a direct neighbor and if we don't route towards it */ - if (!is_single_hop_neigh && (orig_neigh_node->router == NULL)) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: OGM via unknown neighbor! \n"); + /* drop packet if sender is not a direct neighbor and if we + * don't route towards it */ + if (!is_single_hop_neigh && + (orig_neigh_node->router == NULL)) { + bat_dbg(DBG_BATMAN, "Drop packet: OGM via unknown neighbor!\n"); return; } - is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node, batman_packet, if_incoming); + is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node, + batman_packet, if_incoming); - /* update ranking if it is not a duplicate or has the same seqno and similar ttl as the non-duplicate */ - if (is_bidirectional && (!is_duplicate || - ((orig_node->last_real_seqno == batman_packet->seqno) && - (orig_node->last_ttl - 3 <= batman_packet->ttl)))) - update_orig(orig_node, ethhdr, batman_packet, if_incoming, hna_buff, hna_buff_len, is_duplicate); + /* update ranking if it is not a duplicate or has the same + * seqno and similar ttl as the non-duplicate */ + if (is_bidirectional && + (!is_duplicate || + ((orig_node->last_real_seqno == batman_packet->seqno) && + (orig_node->last_ttl - 3 <= batman_packet->ttl)))) + update_orig(orig_node, ethhdr, batman_packet, + if_incoming, hna_buff, hna_buff_len, is_duplicate); - /* is single hop (direct) neighbour */ + /* is single hop (direct) neighbor */ if (is_single_hop_neigh) { /* mark direct link on incoming interface */ - schedule_forward_packet(orig_node, ethhdr, batman_packet, 1, hna_buff_len, if_incoming); + schedule_forward_packet(orig_node, ethhdr, batman_packet, + 1, hna_buff_len, if_incoming); - debug_log(LOG_TYPE_BATMAN, "Forwarding packet: rebroadcast neighbour packet with direct link flag \n"); + bat_dbg(DBG_BATMAN, "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); return; } /* multihop originator */ if (!is_bidirectional) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: not received via bidirectional link\n"); + bat_dbg(DBG_BATMAN, + "Drop packet: not received via bidirectional link\n"); return; } if (is_duplicate) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: duplicate packet received\n"); + bat_dbg(DBG_BATMAN, "Drop packet: duplicate packet received\n"); return; } - debug_log(LOG_TYPE_BATMAN, "Forwarding packet: rebroadcast originator packet \n"); - schedule_forward_packet(orig_node, ethhdr, batman_packet, 0, hna_buff_len, if_incoming); + bat_dbg(DBG_BATMAN, + "Forwarding packet: rebroadcast originator packet\n"); + schedule_forward_packet(orig_node, ethhdr, batman_packet, + 0, hna_buff_len, if_incoming); } -void purge_orig(struct work_struct *work) +int recv_bat_packet(struct sk_buff *skb, + struct batman_if *batman_if) { - struct list_head *list_pos, *list_pos_tmp; - struct hash_it_t *hashit = NULL; - struct orig_node *orig_node; - struct neigh_node *neigh_node, *best_neigh_node; - char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], neigh_purged; - - spin_lock(&orig_hash_lock); - - /* for all origins... */ - while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { - - orig_node = hashit->bucket->data; - addr_to_string(orig_str, orig_node->orig); - - if (time_after(jiffies, orig_node->last_valid + ((2 * PURGE_TIMEOUT * HZ) / 1000))) { - - debug_log(LOG_TYPE_BATMAN, "Originator timeout: originator %s, last_valid %u \n", orig_str, (orig_node->last_valid / HZ)); - - hash_remove_bucket(orig_hash, hashit); - free_orig_node(orig_node); - - } else { - - best_neigh_node = NULL; - neigh_purged = 0; - - /* for all neighbours towards this originator ... */ - list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { - neigh_node = list_entry(list_pos, struct neigh_node, list); - - if (time_after(jiffies, neigh_node->last_valid + ((PURGE_TIMEOUT * HZ) / 1000))) { - - addr_to_string(neigh_str, neigh_node->addr); - debug_log(LOG_TYPE_BATMAN, "Neighbour timeout: originator %s, neighbour: %s, last_valid %u \n", orig_str, neigh_str, (neigh_node->last_valid / HZ)); - - neigh_purged = 1; - list_del(list_pos); - kfree(neigh_node); - - } else { - - if ((best_neigh_node == NULL) || (neigh_node->tq_avg > best_neigh_node->tq_avg)) - best_neigh_node = neigh_node; - - } - - } + struct ethhdr *ethhdr; + unsigned long flags; + + /* drop packet if it has not necessary minimum size */ + if (skb_headlen(skb) < sizeof(struct batman_packet)) + return NET_RX_DROP; + + ethhdr = (struct ethhdr *)skb_mac_header(skb); + + /* packet with broadcast indication but unicast recipient */ + if (!is_bcast(ethhdr->h_dest)) + return NET_RX_DROP; + + /* packet with broadcast sender address */ + if (is_bcast(ethhdr->h_source)) + return NET_RX_DROP; + + spin_lock_irqsave(&orig_hash_lock, flags); + /* TODO: we use headlen instead of "length", because + * only this data is paged in. */ + /* TODO: is another skb_copy needed here? there will be + * written on the data, but nobody (?) should further use + * this data */ + receive_aggr_bat_packet(ethhdr, + skb->data, + skb_headlen(skb), + batman_if); + spin_unlock_irqrestore(&orig_hash_lock, flags); + + kfree_skb(skb); + return NET_RX_SUCCESS; +} - if (neigh_purged) - update_routes(orig_node, best_neigh_node, orig_node->hna_buff, orig_node->hna_buff_len); +static int recv_my_icmp_packet(struct sk_buff *skb) +{ + struct orig_node *orig_node; + struct icmp_packet *icmp_packet; + struct ethhdr *ethhdr; + struct sk_buff *skb_old; + struct batman_if *batman_if; + int ret; + unsigned long flags; + uint8_t dstaddr[ETH_ALEN]; - } + icmp_packet = (struct icmp_packet *) skb->data; + ethhdr = (struct ethhdr *) skb_mac_header(skb); + /* add data to device queue */ + if (icmp_packet->msg_type != ECHO_REQUEST) { + bat_device_receive_packet(icmp_packet); + return NET_RX_DROP; } - spin_unlock(&orig_hash_lock); + /* answer echo request (ping) */ + /* get routing information */ + spin_lock_irqsave(&orig_hash_lock, flags); + orig_node = ((struct orig_node *)hash_find(orig_hash, + icmp_packet->orig)); + ret = NET_RX_DROP; + + if ((orig_node != NULL) && + (orig_node->batman_if != NULL) && + (orig_node->router != NULL)) { + + /* don't lock while sending the packets ... we therefore + * copy the required data before sending */ + batman_if = orig_node->batman_if; + memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + spin_unlock_irqrestore(&orig_hash_lock, flags); + + /* create a copy of the skb, if needed, to modify it. */ + skb_old = NULL; + if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + skb_old = skb; + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + icmp_packet = (struct icmp_packet *) skb->data; + kfree_skb(skb_old); + } - start_purge_timer(); -} + memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); + memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); + icmp_packet->msg_type = ECHO_REPLY; + icmp_packet->ttl = TTL; -static int receive_raw_packet(struct socket *raw_sock, unsigned char *packet_buff, int packet_buff_len) -{ - struct kvec iov; - struct msghdr msg; + send_skb_packet(skb, batman_if, dstaddr); + ret = NET_RX_SUCCESS; - iov.iov_base = packet_buff; - iov.iov_len = packet_buff_len; + } else + spin_unlock_irqrestore(&orig_hash_lock, flags); - msg.msg_flags = MSG_DONTWAIT; /* non-blocking */ - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = NULL; - - return kernel_recvmsg(raw_sock, &msg, &iov, 1, packet_buff_len, MSG_DONTWAIT); + return ret; } -int packet_recv_thread(void *data) +static int recv_icmp_ttl_exceeded(struct sk_buff *skb) { - struct batman_if *batman_if; - struct ethhdr *ethhdr; - struct batman_packet *batman_packet; - struct unicast_packet *unicast_packet; - struct bcast_packet *bcast_packet; - struct icmp_packet *icmp_packet; - struct vis_packet *vis_packet; struct orig_node *orig_node; - unsigned char *packet_buff, src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN]; - int vis_info_len; - int result; - - atomic_set(&data_ready_cond, 0); - atomic_set(&exit_cond, 0); - packet_buff = kmalloc(PACKBUFF_SIZE, GFP_KERNEL); - if (!packet_buff) { - debug_log(LOG_TYPE_CRIT, "Could allocate memory for the packet buffer. :(\n"); - return -1; + struct icmp_packet *icmp_packet; + struct ethhdr *ethhdr; + struct sk_buff *skb_old; + struct batman_if *batman_if; + int ret; + unsigned long flags; + uint8_t dstaddr[ETH_ALEN]; + + icmp_packet = (struct icmp_packet *)skb->data; + ethhdr = (struct ethhdr *)skb_mac_header(skb); + + /* send TTL exceeded if packet is an echo request (traceroute) */ + if (icmp_packet->msg_type != ECHO_REQUEST) { + printk(KERN_WARNING "batman-adv:Warning - can't forward icmp packet from %pM to %pM: ttl exceeded\n", + icmp_packet->orig, icmp_packet->dst); + return NET_RX_DROP; } - while ((!kthread_should_stop()) && (!atomic_read(&exit_cond))) { - - wait_event_interruptible(thread_wait, (atomic_read(&data_ready_cond) || atomic_read(&exit_cond))); - - atomic_set(&data_ready_cond, 0); - - if (kthread_should_stop() || atomic_read(&exit_cond)) - break; - - /* we only want to safely traverse the list, hard-interfaces - * won't be deleted anyway as long as this thread runs. */ - - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - rcu_read_unlock(); - - result = -1; - - while (1) { - if (batman_if->if_active != IF_ACTIVE) { - if (batman_if->if_active != IF_TO_BE_ACTIVATED) - debug_log(LOG_TYPE_NOTICE, - "Could not read from deactivated interface %s!\n", - batman_if->dev); - - if (batman_if->raw_sock) - receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE); - result = 0; - break; - } - - result = receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE); - if (result <= 0) - break; - - if (result < sizeof(struct ethhdr) + 2) - continue; - - ethhdr = (struct ethhdr *)packet_buff; - batman_packet = (struct batman_packet *)(packet_buff + sizeof(struct ethhdr)); - - if (batman_packet->version != COMPAT_VERSION) { - debug_log(LOG_TYPE_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version); - continue; - } - - switch (batman_packet->packet_type) { - /* batman originator packet */ - case BAT_PACKET: - /* packet with broadcast indication but unicast recipient */ - if (!is_bcast(ethhdr->h_dest)) - continue; - - /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) - continue; - - /* drop packet if it has not at least one batman packet as payload */ - if (result < sizeof(struct ethhdr) + sizeof(struct batman_packet)) - continue; - - spin_lock(&orig_hash_lock); - receive_aggr_bat_packet(ethhdr, - packet_buff + sizeof(struct ethhdr), - result - sizeof(struct ethhdr), - batman_if); - spin_unlock(&orig_hash_lock); - - break; - - /* batman icmp packet */ - case BAT_ICMP: - /* packet with unicast indication but broadcast recipient */ - if (is_bcast(ethhdr->h_dest)) - continue; - - /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) - continue; - - /* not for me */ - if (!is_my_mac(ethhdr->h_dest)) - continue; - - /* drop packet if it has not necessary minimum size */ - if (result < sizeof(struct ethhdr) + sizeof(struct icmp_packet)) - continue; - - icmp_packet = (struct icmp_packet *)(packet_buff + sizeof(struct ethhdr)); - - /* packet for me */ - if (is_my_mac(icmp_packet->dst)) { - - /* add data to device queue */ - if (icmp_packet->msg_type != ECHO_REQUEST) { - bat_device_receive_packet(icmp_packet); - continue; - } - - /* answer echo request (ping) */ - /* get routing information */ - spin_lock(&orig_hash_lock); - orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig)); - - if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) { - - memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); - icmp_packet->msg_type = ECHO_REPLY; - icmp_packet->ttl = TTL; - - send_raw_packet(packet_buff + sizeof(struct ethhdr), - result - sizeof(struct ethhdr), - orig_node->batman_if, - orig_node->router->addr); - - } - - spin_unlock(&orig_hash_lock); - continue; - - } - - /* TTL exceeded */ - if (icmp_packet->ttl < 2) { - - addr_to_string(src_str, icmp_packet->orig); - addr_to_string(dst_str, icmp_packet->dst); - - debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str); - - /* send TTL exceeded if packet is an echo request (traceroute) */ - if (icmp_packet->msg_type != ECHO_REQUEST) - continue; - - /* get routing information */ - spin_lock(&orig_hash_lock); - orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig)); - - if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) { - - memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); - icmp_packet->msg_type = TTL_EXCEEDED; - icmp_packet->ttl = TTL; - - send_raw_packet(packet_buff + sizeof(struct ethhdr), - result - sizeof(struct ethhdr), - orig_node->batman_if, - orig_node->router->addr); + /* get routing information */ + spin_lock_irqsave(&orig_hash_lock, flags); + orig_node = ((struct orig_node *) + hash_find(orig_hash, icmp_packet->orig)); + ret = NET_RX_DROP; + + if ((orig_node != NULL) && + (orig_node->batman_if != NULL) && + (orig_node->router != NULL)) { + + /* don't lock while sending the packets ... we therefore + * copy the required data before sending */ + batman_if = orig_node->batman_if; + memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + spin_unlock_irqrestore(&orig_hash_lock, flags); + + /* create a copy of the skb, if needed, to modify it. */ + if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + skb_old = skb; + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + icmp_packet = (struct icmp_packet *) skb->data; + kfree_skb(skb_old); + } - } + memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); + memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); + icmp_packet->msg_type = TTL_EXCEEDED; + icmp_packet->ttl = TTL; - spin_unlock(&orig_hash_lock); - continue; + send_skb_packet(skb, batman_if, dstaddr); + ret = NET_RX_SUCCESS; - } + } else + spin_unlock_irqrestore(&orig_hash_lock, flags); - /* get routing information */ - spin_lock(&orig_hash_lock); - orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->dst)); + return ret; +} - if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) { - /* decrement ttl */ - icmp_packet->ttl--; +int recv_icmp_packet(struct sk_buff *skb) +{ + struct icmp_packet *icmp_packet; + struct ethhdr *ethhdr; + struct orig_node *orig_node; + struct sk_buff *skb_old; + struct batman_if *batman_if; + int hdr_size = sizeof(struct icmp_packet); + int ret; + unsigned long flags; + uint8_t dstaddr[ETH_ALEN]; + + /* drop packet if it has not necessary minimum size */ + if (skb_headlen(skb) < hdr_size) + return NET_RX_DROP; + + ethhdr = (struct ethhdr *)skb_mac_header(skb); + + /* packet with unicast indication but broadcast recipient */ + if (is_bcast(ethhdr->h_dest)) + return NET_RX_DROP; + + /* packet with broadcast sender address */ + if (is_bcast(ethhdr->h_source)) + return NET_RX_DROP; + + /* not for me */ + if (!is_my_mac(ethhdr->h_dest)) + return NET_RX_DROP; + + icmp_packet = (struct icmp_packet *) skb->data; + + /* packet for me */ + if (is_my_mac(icmp_packet->dst)) + return recv_my_icmp_packet(skb); + + /* TTL exceeded */ + if (icmp_packet->ttl < 2) + return recv_icmp_ttl_exceeded(skb); + + ret = NET_RX_DROP; + + /* get routing information */ + spin_lock_irqsave(&orig_hash_lock, flags); + orig_node = ((struct orig_node *) + hash_find(orig_hash, icmp_packet->dst)); + + if ((orig_node != NULL) && + (orig_node->batman_if != NULL) && + (orig_node->router != NULL)) { + + /* don't lock while sending the packets ... we therefore + * copy the required data before sending */ + batman_if = orig_node->batman_if; + memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + spin_unlock_irqrestore(&orig_hash_lock, flags); + + /* create a copy of the skb, if needed, to modify it. */ + if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { + skb_old = skb; + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + icmp_packet = (struct icmp_packet *) skb->data; + kfree_skb(skb_old); + } - /* route it */ - send_raw_packet(packet_buff + sizeof(struct ethhdr), - result - sizeof(struct ethhdr), - orig_node->batman_if, - orig_node->router->addr); - } + /* decrement ttl */ + icmp_packet->ttl--; - spin_unlock(&orig_hash_lock); - break; + /* route it */ + send_skb_packet(skb, batman_if, dstaddr); + ret = NET_RX_SUCCESS; - /* unicast packet */ - case BAT_UNICAST: - /* packet with unicast indication but broadcast recipient */ - if (is_bcast(ethhdr->h_dest)) - continue; + } else + spin_unlock_irqrestore(&orig_hash_lock, flags); - /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) - continue; + return ret; +} - /* not for me */ - if (!is_my_mac(ethhdr->h_dest)) - continue; +int recv_unicast_packet(struct sk_buff *skb) +{ + struct unicast_packet *unicast_packet; + struct orig_node *orig_node; + struct ethhdr *ethhdr; + struct batman_if *batman_if; + struct sk_buff *skb_old; + uint8_t dstaddr[ETH_ALEN]; + int hdr_size = sizeof(struct unicast_packet); + int ret; + unsigned long flags; - /* drop packet if it has not necessary minimum size */ - if (result < sizeof(struct ethhdr) + sizeof(struct unicast_packet)) - continue; + /* drop packet if it has not necessary minimum size */ + if (skb_headlen(skb) < hdr_size) + return NET_RX_DROP; - unicast_packet = (struct unicast_packet *)(packet_buff + sizeof(struct ethhdr)); + ethhdr = (struct ethhdr *) skb_mac_header(skb); - /* packet for me */ - if (is_my_mac(unicast_packet->dest)) { + /* packet with unicast indication but broadcast recipient */ + if (is_bcast(ethhdr->h_dest)) + return NET_RX_DROP; - interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct unicast_packet), result - sizeof(struct ethhdr) - sizeof(struct unicast_packet)); - continue; + /* packet with broadcast sender address */ + if (is_bcast(ethhdr->h_source)) + return NET_RX_DROP; - } + /* not for me */ + if (!is_my_mac(ethhdr->h_dest)) + return NET_RX_DROP; - /* TTL exceeded */ - if (unicast_packet->ttl < 2) { - addr_to_string(src_str, ((struct ethhdr *)(unicast_packet + 1))->h_source); - addr_to_string(dst_str, unicast_packet->dest); + unicast_packet = (struct unicast_packet *) skb->data; - debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str); - continue; - } + /* packet for me */ + if (is_my_mac(unicast_packet->dest)) { + interface_rx(skb, hdr_size); + return NET_RX_SUCCESS; + } - /* get routing information */ - spin_lock(&orig_hash_lock); - orig_node = ((struct orig_node *)hash_find(orig_hash, unicast_packet->dest)); + /* TTL exceeded */ + if (unicast_packet->ttl < 2) { + printk(KERN_WARNING "batman-adv:Warning - can't forward unicast packet from %pM to %pM: ttl exceeded\n", + ethhdr->h_source, unicast_packet->dest); + return NET_RX_DROP; + } - if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) { - /* decrement ttl */ - unicast_packet->ttl--; + ret = NET_RX_DROP; + /* get routing information */ + spin_lock_irqsave(&orig_hash_lock, flags); + orig_node = ((struct orig_node *) + hash_find(orig_hash, unicast_packet->dest)); + + if ((orig_node != NULL) && + (orig_node->batman_if != NULL) && + (orig_node->router != NULL)) { + + /* don't lock while sending the packets ... we therefore + * copy the required data before sending */ + batman_if = orig_node->batman_if; + memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + spin_unlock_irqrestore(&orig_hash_lock, flags); + + /* create a copy of the skb, if needed, to modify it. */ + if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) { + skb_old = skb; + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + unicast_packet = (struct unicast_packet *) skb->data; + kfree_skb(skb_old); + } + /* decrement ttl */ + unicast_packet->ttl--; - /* route it */ - send_raw_packet(packet_buff + sizeof(struct ethhdr), - result - sizeof(struct ethhdr), - orig_node->batman_if, - orig_node->router->addr); - } + /* route it */ + send_skb_packet(skb, batman_if, dstaddr); + ret = NET_RX_SUCCESS; - spin_unlock(&orig_hash_lock); - break; + } else + spin_unlock_irqrestore(&orig_hash_lock, flags); - /* broadcast packet */ - case BAT_BCAST: - /* packet with broadcast indication but unicast recipient */ - if (!is_bcast(ethhdr->h_dest)) - continue; + return ret; +} - /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) - continue; - /* drop packet if it has not necessary minimum size */ - if (result < sizeof(struct ethhdr) + sizeof(struct bcast_packet)) - continue; +int recv_bcast_packet(struct sk_buff *skb) +{ + struct orig_node *orig_node; + struct bcast_packet *bcast_packet; + struct ethhdr *ethhdr; + int hdr_size = sizeof(struct bcast_packet); + unsigned long flags; - /* ignore broadcasts sent by myself */ - if (is_my_mac(ethhdr->h_source)) - continue; + /* drop packet if it has not necessary minimum size */ + if (skb_headlen(skb) < hdr_size) + return NET_RX_DROP; - bcast_packet = (struct bcast_packet *)(packet_buff + sizeof(struct ethhdr)); + ethhdr = (struct ethhdr *)skb_mac_header(skb); - /* ignore broadcasts originated by myself */ - if (is_my_mac(bcast_packet->orig)) - continue; + /* packet with broadcast indication but unicast recipient */ + if (!is_bcast(ethhdr->h_dest)) + return NET_RX_DROP; - spin_lock(&orig_hash_lock); - orig_node = ((struct orig_node *)hash_find(orig_hash, bcast_packet->orig)); + /* packet with broadcast sender address */ + if (is_bcast(ethhdr->h_source)) + return NET_RX_DROP; - if (orig_node == NULL) { - spin_unlock(&orig_hash_lock); - continue; - } + /* ignore broadcasts sent by myself */ + if (is_my_mac(ethhdr->h_source)) + return NET_RX_DROP; - /* check flood history */ - if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, ntohs(bcast_packet->seqno))) { - spin_unlock(&orig_hash_lock); - continue; - } + bcast_packet = (struct bcast_packet *) skb->data; - /* mark broadcast in flood history */ - if (bit_get_packet(orig_node->bcast_bits, ntohs(bcast_packet->seqno) - orig_node->last_bcast_seqno, 1)) - orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno); + /* ignore broadcasts originated by myself */ + if (is_my_mac(bcast_packet->orig)) + return NET_RX_DROP; - spin_unlock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); + orig_node = ((struct orig_node *) + hash_find(orig_hash, bcast_packet->orig)); - /* broadcast for me */ - interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct bcast_packet), result - sizeof(struct ethhdr) - sizeof(struct bcast_packet)); + if (orig_node == NULL) { + spin_unlock_irqrestore(&orig_hash_lock, flags); + return NET_RX_DROP; + } - /* rebroadcast packet */ - add_bcast_packet_to_list(packet_buff + sizeof(struct ethhdr), - result - sizeof(struct ethhdr)); + /* check flood history */ + if (get_bit_status(orig_node->bcast_bits, + orig_node->last_bcast_seqno, + ntohs(bcast_packet->seqno))) { + spin_unlock_irqrestore(&orig_hash_lock, flags); + return NET_RX_DROP; + } - break; + /* mark broadcast in flood history */ + if (bit_get_packet(orig_node->bcast_bits, + ntohs(bcast_packet->seqno) - + orig_node->last_bcast_seqno, 1)) + orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno); - /* vis packet */ - case BAT_VIS: - /* drop if too short. */ - if (result < sizeof(struct ethhdr) + sizeof(struct vis_packet)) - continue; + spin_unlock_irqrestore(&orig_hash_lock, flags); - /* not for me */ - if (!is_my_mac(ethhdr->h_dest)) - continue; + /* rebroadcast packet */ + add_bcast_packet_to_list(skb); - vis_packet = (struct vis_packet *)(packet_buff + sizeof(struct ethhdr)); - vis_info_len = result - sizeof(struct ethhdr) - sizeof(struct vis_packet); + /* broadcast for me */ + interface_rx(skb, hdr_size); - /* ignore own packets */ - if (is_my_mac(vis_packet->vis_orig)) - continue; + return NET_RX_SUCCESS; +} - if (is_my_mac(vis_packet->sender_orig)) - continue; +int recv_vis_packet(struct sk_buff *skb) +{ + struct vis_packet *vis_packet; + struct ethhdr *ethhdr; + int hdr_size = sizeof(struct vis_packet); - switch (vis_packet->vis_type) { - case VIS_TYPE_SERVER_SYNC: - receive_server_sync_packet(vis_packet, vis_info_len); - break; + if (skb_headlen(skb) < hdr_size) + return NET_RX_DROP; - case VIS_TYPE_CLIENT_UPDATE: - receive_client_update_packet(vis_packet, vis_info_len); - break; + vis_packet = (struct vis_packet *) skb->data; + ethhdr = (struct ethhdr *)skb_mac_header(skb); - default: /* ignore unknown packet */ - break; - } + /* not for me */ + if (!is_my_mac(ethhdr->h_dest)) + return NET_RX_DROP; - break; - } + /* ignore own packets */ + if (is_my_mac(vis_packet->vis_orig)) + return NET_RX_DROP; - } + if (is_my_mac(vis_packet->sender_orig)) + return NET_RX_DROP; - if ((result < 0) && (result != -EAGAIN)) - debug_log(LOG_TYPE_CRIT, "Could not receive packet from interface %s: %i\n", batman_if->dev, result); + switch (vis_packet->vis_type) { + case VIS_TYPE_SERVER_SYNC: + /* TODO: handle fragmented skbs properly */ + receive_server_sync_packet(vis_packet, skb_headlen(skb)); + break; - /* lock for the next iteration */ - rcu_read_lock(); - } - rcu_read_unlock(); + case VIS_TYPE_CLIENT_UPDATE: + /* TODO: handle fragmented skbs properly */ + receive_client_update_packet(vis_packet, skb_headlen(skb)); + break; + default: /* ignore unknown packet */ + break; } - kfree(packet_buff); - - /* do not exit until kthread_stop() is actually called, otherwise it will wait for us - * forever. */ - while (!kthread_should_stop()) - schedule(); - - return 0; -} - -void batman_data_ready(struct sock *sk, int len) -{ - void (*data_ready)(struct sock *, int) = sk->sk_user_data; - - data_ready(sk, len); - atomic_set(&data_ready_cond, 1); - wake_up_interruptible(&thread_wait); + /* We take a copy of the data in the packet, so we should + always free the skbuf. */ + return NET_RX_DROP; } - diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h index 0123ea86deb..939b8d4f733 100644 --- a/drivers/staging/batman-adv/routing.h +++ b/drivers/staging/batman-adv/routing.h @@ -22,13 +22,18 @@ #include "types.h" extern wait_queue_head_t thread_wait; -extern atomic_t exit_cond; -int originator_init(void); -void free_orig_node(void *data); -void originator_free(void); void slide_own_bcast_window(struct batman_if *batman_if); -void batman_data_ready(struct sock *sk, int len); -void purge_orig(struct work_struct *work); -int packet_recv_thread(void *data); -void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, unsigned char *hna_buff, int hna_buff_len, struct batman_if *if_incoming); +void receive_bat_packet(struct ethhdr *ethhdr, + struct batman_packet *batman_packet, + unsigned char *hna_buff, int hna_buff_len, + struct batman_if *if_incoming); +void update_routes(struct orig_node *orig_node, + struct neigh_node *neigh_node, + unsigned char *hna_buff, int hna_buff_len); +int recv_icmp_packet(struct sk_buff *skb); +int recv_unicast_packet(struct sk_buff *skb); +int recv_bcast_packet(struct sk_buff *skb); +int recv_vis_packet(struct sk_buff *skb); +int recv_bat_packet(struct sk_buff *skb, + struct batman_if *batman_if); diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c index eb617508cca..2a9fac8c240 100644 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@ -21,16 +21,14 @@ #include "main.h" #include "send.h" -#include "log.h" #include "routing.h" #include "translation-table.h" +#include "soft-interface.h" #include "hard-interface.h" #include "types.h" #include "vis.h" #include "aggregation.h" -#include "compat.h" - /* apply hop penalty for a normal link */ static uint8_t hop_penalty(const uint8_t tq) { @@ -59,51 +57,69 @@ static unsigned long forward_send_time(void) return send_time; } -/* sends a raw packet. */ -void send_raw_packet(unsigned char *pack_buff, int pack_buff_len, - struct batman_if *batman_if, uint8_t *dst_addr) +/* send out an already prepared packet to the given address via the + * specified batman interface */ +int send_skb_packet(struct sk_buff *skb, + struct batman_if *batman_if, + uint8_t *dst_addr) { struct ethhdr *ethhdr; - struct sk_buff *skb; - int retval; - char *data; if (batman_if->if_active != IF_ACTIVE) - return; + goto send_skb_err; + + if (unlikely(!batman_if->net_dev)) + goto send_skb_err; if (!(batman_if->net_dev->flags & IFF_UP)) { - debug_log(LOG_TYPE_WARN, - "Interface %s is not up - can't send packet via that interface (IF_TO_BE_DEACTIVATED was here) !\n", - batman_if->dev); - return; + printk(KERN_WARNING + "batman-adv:Interface %s is not up - can't send packet via that interface!\n", + batman_if->dev); + goto send_skb_err; } - skb = dev_alloc_skb(pack_buff_len + sizeof(struct ethhdr)); - if (!skb) - return; - data = skb_put(skb, pack_buff_len + sizeof(struct ethhdr)); + /* push to the ethernet header. */ + if (my_skb_push(skb, sizeof(struct ethhdr)) < 0) + goto send_skb_err; - memcpy(data + sizeof(struct ethhdr), pack_buff, pack_buff_len); + skb_reset_mac_header(skb); - ethhdr = (struct ethhdr *) data; + ethhdr = (struct ethhdr *) skb_mac_header(skb); memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN); memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); ethhdr->h_proto = __constant_htons(ETH_P_BATMAN); - skb_reset_mac_header(skb); skb_set_network_header(skb, ETH_HLEN); skb->priority = TC_PRIO_CONTROL; skb->protocol = __constant_htons(ETH_P_BATMAN); + skb->dev = batman_if->net_dev; /* dev_queue_xmit() returns a negative result on error. However on * congestion and traffic shaping, it drops and returns NET_XMIT_DROP * (which is > 0). This will not be treated as an error. */ - retval = dev_queue_xmit(skb); - if (retval < 0) - debug_log(LOG_TYPE_CRIT, - "Can't write to raw socket (IF_TO_BE_DEACTIVATED was here): %i\n", - retval); + + return dev_queue_xmit(skb); +send_skb_err: + kfree_skb(skb); + return NET_XMIT_DROP; +} + +/* sends a raw packet. */ +void send_raw_packet(unsigned char *pack_buff, int pack_buff_len, + struct batman_if *batman_if, uint8_t *dst_addr) +{ + struct sk_buff *skb; + char *data; + + skb = dev_alloc_skb(pack_buff_len + sizeof(struct ethhdr)); + if (!skb) + return; + data = skb_put(skb, pack_buff_len + sizeof(struct ethhdr)); + memcpy(data + sizeof(struct ethhdr), pack_buff, pack_buff_len); + /* pull back to the batman "network header" */ + skb_pull(skb, sizeof(struct ethhdr)); + send_skb_packet(skb, batman_if, dst_addr); } /* Send a packet to a given interface */ @@ -114,7 +130,6 @@ static void send_packet_to_if(struct forw_packet *forw_packet, uint8_t packet_num; int16_t buff_pos; struct batman_packet *batman_packet; - char orig_str[ETH_STR_LEN]; if (batman_if->if_active != IF_ACTIVE) return; @@ -136,19 +151,18 @@ static void send_packet_to_if(struct forw_packet *forw_packet, else batman_packet->flags &= ~DIRECTLINK; - addr_to_string(orig_str, batman_packet->orig); fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ? "Sending own" : "Forwarding")); - debug_log(LOG_TYPE_BATMAN, - "%s %spacket (originator %s, seqno %d, TQ %d, TTL %d, IDF %s) on interface %s [%s]\n", - fwd_str, - (packet_num > 0 ? "aggregated " : ""), - orig_str, ntohs(batman_packet->seqno), - batman_packet->tq, batman_packet->ttl, - (batman_packet->flags & DIRECTLINK ? - "on" : "off"), - batman_if->dev, batman_if->addr_str); + bat_dbg(DBG_BATMAN, + "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d, IDF %s) on interface %s [%s]\n", + fwd_str, + (packet_num > 0 ? "aggregated " : ""), + batman_packet->orig, ntohs(batman_packet->seqno), + batman_packet->tq, batman_packet->ttl, + (batman_packet->flags & DIRECTLINK ? + "on" : "off"), + batman_if->dev, batman_if->addr_str); buff_pos += sizeof(struct batman_packet) + (batman_packet->num_hna * ETH_ALEN); @@ -168,32 +182,28 @@ static void send_packet(struct forw_packet *forw_packet) struct batman_if *batman_if; struct batman_packet *batman_packet = (struct batman_packet *)(forw_packet->packet_buff); - char orig_str[ETH_STR_LEN]; unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0); if (!forw_packet->if_incoming) { - debug_log(LOG_TYPE_CRIT, - "Error - can't forward packet: incoming iface not specified\n"); + printk(KERN_ERR "batman-adv: Error - can't forward packet: incoming iface not specified\n"); return; } if (forw_packet->if_incoming->if_active != IF_ACTIVE) return; - addr_to_string(orig_str, batman_packet->orig); - /* multihomed peer assumed */ /* non-primary OGMs are only broadcasted on their interface */ if ((directlink && (batman_packet->ttl == 1)) || (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) { /* FIXME: what about aggregated packets ? */ - debug_log(LOG_TYPE_BATMAN, - "%s packet (originator %s, seqno %d, TTL %d) on interface %s [%s]\n", - (forw_packet->own ? "Sending own" : "Forwarding"), - orig_str, ntohs(batman_packet->seqno), - batman_packet->ttl, forw_packet->if_incoming->dev, - forw_packet->if_incoming->addr_str); + bat_dbg(DBG_BATMAN, + "%s packet (originator %pM, seqno %d, TTL %d) on interface %s [%s]\n", + (forw_packet->own ? "Sending own" : "Forwarding"), + batman_packet->orig, ntohs(batman_packet->seqno), + batman_packet->ttl, forw_packet->if_incoming->dev, + forw_packet->if_incoming->addr_str); send_raw_packet(forw_packet->packet_buff, forw_packet->packet_len, @@ -238,6 +248,7 @@ void schedule_own_packet(struct batman_if *batman_if) { unsigned long send_time; struct batman_packet *batman_packet; + int vis_server = atomic_read(&vis_mode); /** * the interface gets activated here to avoid race conditions between @@ -262,7 +273,7 @@ void schedule_own_packet(struct batman_if *batman_if) /* change sequence number to network order */ batman_packet->seqno = htons((uint16_t)atomic_read(&batman_if->seqno)); - if (is_vis_server()) + if (vis_server == VIS_TYPE_SERVER_SYNC) batman_packet->flags = VIS_SERVER; else batman_packet->flags = 0; @@ -286,7 +297,7 @@ void schedule_forward_packet(struct orig_node *orig_node, unsigned long send_time; if (batman_packet->ttl <= 1) { - debug_log(LOG_TYPE_BATMAN, "ttl exceeded \n"); + bat_dbg(DBG_BATMAN, "ttl exceeded \n"); return; } @@ -314,9 +325,9 @@ void schedule_forward_packet(struct orig_node *orig_node, /* apply hop penalty */ batman_packet->tq = hop_penalty(batman_packet->tq); - debug_log(LOG_TYPE_BATMAN, "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n", - in_tq, tq_avg, batman_packet->tq, in_ttl - 1, - batman_packet->ttl); + bat_dbg(DBG_BATMAN, "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n", + in_tq, tq_avg, batman_packet->tq, in_ttl - 1, + batman_packet->ttl); batman_packet->seqno = htons(batman_packet->seqno); @@ -333,6 +344,8 @@ void schedule_forward_packet(struct orig_node *orig_node, static void forw_packet_free(struct forw_packet *forw_packet) { + if (forw_packet->skb) + kfree_skb(forw_packet->skb); kfree(forw_packet->packet_buff); kfree(forw_packet); } @@ -340,12 +353,13 @@ static void forw_packet_free(struct forw_packet *forw_packet) static void _add_bcast_packet_to_list(struct forw_packet *forw_packet, unsigned long send_time) { + unsigned long flags; INIT_HLIST_NODE(&forw_packet->list); /* add new packet to packet list */ - spin_lock(&forw_bcast_list_lock); + spin_lock_irqsave(&forw_bcast_list_lock, flags); hlist_add_head(&forw_packet->list, &forw_bcast_list); - spin_unlock(&forw_bcast_list_lock); + spin_unlock_irqrestore(&forw_bcast_list_lock, flags); /* start timer for this packet */ INIT_DELAYED_WORK(&forw_packet->delayed_work, @@ -354,7 +368,7 @@ static void _add_bcast_packet_to_list(struct forw_packet *forw_packet, send_time); } -void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len) +void add_bcast_packet_to_list(struct sk_buff *skb) { struct forw_packet *forw_packet; @@ -362,14 +376,16 @@ void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len) if (!forw_packet) return; - forw_packet->packet_buff = kmalloc(packet_len, GFP_ATOMIC); - if (!forw_packet->packet_buff) { + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) { kfree(forw_packet); return; } - forw_packet->packet_len = packet_len; - memcpy(forw_packet->packet_buff, packet_buff, forw_packet->packet_len); + skb_reset_mac_header(skb); + + forw_packet->skb = skb; + forw_packet->packet_buff = NULL; /* how often did we send the bcast packet ? */ forw_packet->num_packets = 0; @@ -384,16 +400,20 @@ void send_outstanding_bcast_packet(struct work_struct *work) 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; - spin_lock(&forw_bcast_list_lock); + spin_lock_irqsave(&forw_bcast_list_lock, flags); hlist_del(&forw_packet->list); - spin_unlock(&forw_bcast_list_lock); + spin_unlock_irqrestore(&forw_bcast_list_lock, flags); /* rebroadcast packet */ rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { - send_raw_packet(forw_packet->packet_buff, - forw_packet->packet_len, + /* send a copy of the saved skb */ + skb1 = skb_copy(forw_packet->skb, GFP_ATOMIC); + if (skb1) + send_skb_packet(skb1, batman_if, broadcastAddr); } rcu_read_unlock(); @@ -415,10 +435,11 @@ void send_outstanding_bat_packet(struct work_struct *work) container_of(work, struct delayed_work, work); struct forw_packet *forw_packet = container_of(delayed_work, struct forw_packet, delayed_work); + unsigned long flags; - spin_lock(&forw_bat_list_lock); + spin_lock_irqsave(&forw_bat_list_lock, flags); hlist_del(&forw_packet->list); - spin_unlock(&forw_bat_list_lock); + spin_unlock_irqrestore(&forw_bat_list_lock, flags); send_packet(forw_packet); @@ -438,38 +459,39 @@ void purge_outstanding_packets(void) { struct forw_packet *forw_packet; struct hlist_node *tmp_node, *safe_tmp_node; + unsigned long flags; - debug_log(LOG_TYPE_BATMAN, "purge_outstanding_packets()\n"); + bat_dbg(DBG_BATMAN, "purge_outstanding_packets()\n"); /* free bcast list */ - spin_lock(&forw_bcast_list_lock); + spin_lock_irqsave(&forw_bcast_list_lock, flags); hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, &forw_bcast_list, list) { - spin_unlock(&forw_bcast_list_lock); + spin_unlock_irqrestore(&forw_bcast_list_lock, flags); /** * 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(&forw_bcast_list_lock); + spin_lock_irqsave(&forw_bcast_list_lock, flags); } - spin_unlock(&forw_bcast_list_lock); + spin_unlock_irqrestore(&forw_bcast_list_lock, flags); /* free batman packet list */ - spin_lock(&forw_bat_list_lock); + spin_lock_irqsave(&forw_bat_list_lock, flags); hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, &forw_bat_list, list) { - spin_unlock(&forw_bat_list_lock); + spin_unlock_irqrestore(&forw_bat_list_lock, flags); /** * 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(&forw_bat_list_lock); + spin_lock_irqsave(&forw_bat_list_lock, flags); } - spin_unlock(&forw_bat_list_lock); + spin_unlock_irqrestore(&forw_bat_list_lock, flags); } diff --git a/drivers/staging/batman-adv/send.h b/drivers/staging/batman-adv/send.h index 59d500917a3..5fc6f3417cb 100644 --- a/drivers/staging/batman-adv/send.h +++ b/drivers/staging/batman-adv/send.h @@ -22,6 +22,9 @@ #include "types.h" void send_own_packet_work(struct work_struct *work); +int send_skb_packet(struct sk_buff *skb, + struct batman_if *batman_if, + uint8_t *dst_addr); void send_raw_packet(unsigned char *pack_buff, int pack_buff_len, struct batman_if *batman_if, uint8_t *dst_addr); void schedule_own_packet(struct batman_if *batman_if); @@ -30,7 +33,7 @@ void schedule_forward_packet(struct orig_node *orig_node, struct batman_packet *batman_packet, uint8_t directlink, int hna_buff_len, struct batman_if *if_outgoing); -void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len); +void add_bcast_packet_to_list(struct sk_buff *skb); void send_outstanding_bcast_packet(struct work_struct *work); void send_outstanding_bat_packet(struct work_struct *work); void purge_outstanding_packets(void); diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index d543f50b647..c9b35d9f799 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -24,18 +24,15 @@ #include "hard-interface.h" #include "send.h" #include "translation-table.h" -#include "log.h" #include "types.h" #include "hash.h" #include <linux/ethtool.h> #include <linux/etherdevice.h> -#include "compat.h" static uint16_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid * broadcast storms */ static int32_t skb_packets; static int32_t skb_bad_packets; -static int32_t lock_dropped; unsigned char mainIfAddr[ETH_ALEN]; static unsigned char mainIfAddr_default[ETH_ALEN]; @@ -68,12 +65,12 @@ int main_if_was_up(void) return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0); } -static int my_skb_push(struct sk_buff *skb, unsigned int len) +int my_skb_push(struct sk_buff *skb, unsigned int len) { int result = 0; skb_packets++; - if (skb->data - len < skb->head) { + if (skb_headroom(skb) < len) { skb_bad_packets++; result = pskb_expand_head(skb, len, 0, GFP_ATOMIC); @@ -122,7 +119,7 @@ void interface_setup(struct net_device *dev) /* generate random address */ random_ether_addr(dev_addr); - memcpy(dev->dev_addr, dev_addr, sizeof(dev->dev_addr)); + memcpy(dev->dev_addr, dev_addr, ETH_ALEN); SET_ETHTOOL_OPS(dev, &bat_ethtool_ops); @@ -147,9 +144,18 @@ struct net_device_stats *interface_stats(struct net_device *dev) return &priv->stats; } -int interface_set_mac_addr(struct net_device *dev, void *addr) +int interface_set_mac_addr(struct net_device *dev, void *p) { - return -EBUSY; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + hna_local_remove(dev->dev_addr, "mac address changed"); + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + hna_local_add(dev->dev_addr); + + return 0; } int interface_change_mtu(struct net_device *dev, int new_mtu) @@ -170,7 +176,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) struct orig_node *orig_node; struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct bat_priv *priv = netdev_priv(dev); + struct batman_if *batman_if; + uint8_t dstaddr[6]; int data_len = skb->len; + unsigned long flags; if (atomic_read(&module_state) != MODULE_ACTIVE) goto dropped; @@ -186,7 +195,6 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) goto dropped; bcast_packet = (struct bcast_packet *)skb->data; - bcast_packet->version = COMPAT_VERSION; /* batman packet type: broadcast */ @@ -195,27 +203,21 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) /* hw address of first interface is the orig mac because only * this mac is known throughout the mesh */ memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN); + /* set broadcast sequence number */ bcast_packet->seqno = htons(bcast_seqno); bcast_seqno++; /* broadcast packet */ - add_bcast_packet_to_list(skb->data, skb->len); + add_bcast_packet_to_list(skb); + /* a copy is stored in the bcast list, therefore removing + * the original skb. */ + kfree_skb(skb); /* unicast packet */ } else { - - /* simply spin_lock()ing can deadlock when the lock is already - * hold. */ - /* TODO: defer the work in a working queue instead of - * dropping */ - if (!spin_trylock(&orig_hash_lock)) { - lock_dropped++; - debug_log(LOG_TYPE_NOTICE, "%d packets dropped because lock was hold\n", lock_dropped); - goto dropped; - } - + spin_lock_irqsave(&orig_hash_lock, flags); /* get routing information */ orig_node = ((struct orig_node *)hash_find(orig_hash, ethhdr->h_dest)); @@ -244,14 +246,17 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) if (orig_node->batman_if->if_active != IF_ACTIVE) goto unlock; - send_raw_packet(skb->data, skb->len, - orig_node->batman_if, - orig_node->router->addr); + /* don't lock while sending the packets ... we therefore + * copy the required data before sending */ + + batman_if = orig_node->batman_if; + memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + spin_unlock_irqrestore(&orig_hash_lock, flags); + + send_skb_packet(skb, batman_if, dstaddr); } else { goto unlock; } - - spin_unlock(&orig_hash_lock); } priv->stats.tx_packets++; @@ -259,42 +264,44 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) goto end; unlock: - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); dropped: priv->stats.tx_dropped++; end: - kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } -void interface_rx(struct net_device *dev, void *packet, int packet_len) +void interface_rx(struct sk_buff *skb, int hdr_size) { - struct sk_buff *skb; + struct net_device *dev = soft_device; struct bat_priv *priv = netdev_priv(dev); - skb = dev_alloc_skb(packet_len); - - if (!skb) { - priv->stats.rx_dropped++; - goto out; + /* check if enough space is available for pulling, and pull */ + if (!pskb_may_pull(skb, hdr_size)) { + kfree_skb(skb); + return; } + skb_pull_rcsum(skb, hdr_size); +/* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/ - memcpy(skb_put(skb, packet_len), packet, packet_len); - - /* Write metadata, and then pass to the receive level */ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* should not be neccesary anymore as we use skb_pull_rcsum() + * TODO: please verify this and remove this TODO + * -- Dec 21st 2009, Simon Wunderlich */ + +/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/ + + /* TODO: set skb->pkt_type to PACKET_BROADCAST, PACKET_MULTICAST, + * PACKET_OTHERHOST or PACKET_HOST */ priv->stats.rx_packets++; - priv->stats.rx_bytes += packet_len; + priv->stats.rx_bytes += skb->len; dev->last_rx = jiffies; netif_rx(skb); - -out: - return; } /* ethtool */ @@ -330,7 +337,6 @@ static u32 bat_get_msglevel(struct net_device *dev) static void bat_set_msglevel(struct net_device *dev, u32 value) { - return; } static u32 bat_get_link(struct net_device *dev) diff --git a/drivers/staging/batman-adv/soft-interface.h b/drivers/staging/batman-adv/soft-interface.h index 515e276ef53..c0cad8134b2 100644 --- a/drivers/staging/batman-adv/soft-interface.h +++ b/drivers/staging/batman-adv/soft-interface.h @@ -28,6 +28,7 @@ struct net_device_stats *interface_stats(struct net_device *dev); int interface_set_mac_addr(struct net_device *dev, void *addr); int interface_change_mtu(struct net_device *dev, int new_mtu); int interface_tx(struct sk_buff *skb, struct net_device *dev); -void interface_rx(struct net_device *dev, void *packet, int packet_len); +void interface_rx(struct sk_buff *skb, int hdr_size); +int my_skb_push(struct sk_buff *skb, unsigned int len); extern unsigned char mainIfAddr[]; diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c index c2190e177c5..d56f6654de0 100644 --- a/drivers/staging/batman-adv/translation-table.c +++ b/drivers/staging/batman-adv/translation-table.c @@ -21,11 +21,9 @@ #include "main.h" #include "translation-table.h" -#include "log.h" #include "soft-interface.h" #include "types.h" #include "hash.h" -#include "compat.h" struct hashtable_t *hna_local_hash; static struct hashtable_t *hna_global_hash; @@ -62,7 +60,6 @@ void hna_local_add(uint8_t *addr) struct hna_local_entry *hna_local_entry; struct hna_global_entry *hna_global_entry; struct hashtable_t *swaphash; - char hna_str[ETH_STR_LEN]; unsigned long flags; spin_lock_irqsave(&hna_local_hash_lock, flags); @@ -75,19 +72,17 @@ void hna_local_add(uint8_t *addr) return; } - addr_to_string(hna_str, addr); - /* only announce as many hosts as possible in the batman-packet and space in batman_packet->num_hna That also should give a limit to MAC-flooding. */ if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) || (num_hna + 1 > 255)) { - debug_log(LOG_TYPE_ROUTES, "Can't add new local hna entry (%s): number of local hna entries exceeds packet size \n", hna_str); + bat_dbg(DBG_ROUTES, "Can't add new local hna entry (%pM): number of local hna entries exceeds packet size \n", addr); return; } - debug_log(LOG_TYPE_ROUTES, "Creating new local hna entry: %s \n", - hna_str); + bat_dbg(DBG_ROUTES, "Creating new local hna entry: %pM \n", + addr); hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC); if (!hna_local_entry) @@ -113,7 +108,7 @@ void hna_local_add(uint8_t *addr) hna_local_hash->size * 2); if (swaphash == NULL) - debug_log(LOG_TYPE_CRIT, "Couldn't resize local hna hash table \n"); + printk(KERN_ERR "batman-adv:Couldn't resize local hna hash table \n"); else hna_local_hash = swaphash; } @@ -135,18 +130,18 @@ void hna_local_add(uint8_t *addr) int hna_local_fill_buffer(unsigned char *buff, int buff_len) { struct hna_local_entry *hna_local_entry; - struct hash_it_t *hashit = NULL; + HASHIT(hashit); int i = 0; unsigned long flags; spin_lock_irqsave(&hna_local_hash_lock, flags); - while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) { + while (hash_iterate(hna_local_hash, &hashit)) { if (buff_len < (i + 1) * ETH_ALEN) break; - hna_local_entry = hashit->bucket->data; + hna_local_entry = hashit.bucket->data; memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN); i++; @@ -164,18 +159,18 @@ int hna_local_fill_buffer(unsigned char *buff, int buff_len) int hna_local_fill_buffer_text(unsigned char *buff, int buff_len) { struct hna_local_entry *hna_local_entry; - struct hash_it_t *hashit = NULL; + HASHIT(hashit); int bytes_written = 0; unsigned long flags; spin_lock_irqsave(&hna_local_hash_lock, flags); - while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) { + while (hash_iterate(hna_local_hash, &hashit)) { if (buff_len < bytes_written + ETH_STR_LEN + 4) break; - hna_local_entry = hashit->bucket->data; + hna_local_entry = hashit.bucket->data; bytes_written += snprintf(buff + bytes_written, ETH_STR_LEN + 4, " * %02x:%02x:%02x:%02x:%02x:%02x\n", @@ -202,27 +197,39 @@ static void _hna_local_del(void *data) static void hna_local_del(struct hna_local_entry *hna_local_entry, char *message) { - char hna_str[ETH_STR_LEN]; - - addr_to_string(hna_str, hna_local_entry->addr); - debug_log(LOG_TYPE_ROUTES, "Deleting local hna entry (%s): %s \n", - hna_str, message); + bat_dbg(DBG_ROUTES, "Deleting local hna entry (%pM): %s \n", + hna_local_entry->addr, message); hash_remove(hna_local_hash, hna_local_entry->addr); _hna_local_del(hna_local_entry); } +void hna_local_remove(uint8_t *addr, char *message) +{ + struct hna_local_entry *hna_local_entry; + unsigned long flags; + + spin_lock_irqsave(&hna_local_hash_lock, flags); + + hna_local_entry = (struct hna_local_entry *) + hash_find(hna_local_hash, addr); + if (hna_local_entry) + hna_local_del(hna_local_entry, message); + + spin_unlock_irqrestore(&hna_local_hash_lock, flags); +} + void hna_local_purge(struct work_struct *work) { struct hna_local_entry *hna_local_entry; - struct hash_it_t *hashit = NULL; + HASHIT(hashit); unsigned long flags; unsigned long timeout; spin_lock_irqsave(&hna_local_hash_lock, flags); - while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) { - hna_local_entry = hashit->bucket->data; + while (hash_iterate(hna_local_hash, &hashit)) { + hna_local_entry = hashit.bucket->data; timeout = hna_local_entry->last_seen + ((LOCAL_HNA_TIMEOUT / 1000) * HZ); @@ -264,13 +271,10 @@ void hna_global_add_orig(struct orig_node *orig_node, struct hna_global_entry *hna_global_entry; struct hna_local_entry *hna_local_entry; struct hashtable_t *swaphash; - char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN]; int hna_buff_count = 0; unsigned long flags; unsigned char *hna_ptr; - addr_to_string(orig_str, orig_node->orig); - while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { spin_lock_irqsave(&hna_global_hash_lock, flags); @@ -290,8 +294,9 @@ void hna_global_add_orig(struct orig_node *orig_node, memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN); - addr_to_string(hna_str, hna_global_entry->addr); - debug_log(LOG_TYPE_ROUTES, "Creating new global hna entry: %s (via %s)\n", hna_str, orig_str); + bat_dbg(DBG_ROUTES, + "Creating new global hna entry: %pM (via %pM)\n", + hna_global_entry->addr, orig_node->orig); spin_lock_irqsave(&hna_global_hash_lock, flags); hash_add(hna_global_hash, hna_global_entry); @@ -316,14 +321,16 @@ void hna_global_add_orig(struct orig_node *orig_node, hna_buff_count++; } - orig_node->hna_buff_len = hna_buff_len; + /* initialize, and overwrite if malloc succeeds */ + orig_node->hna_buff = NULL; + orig_node->hna_buff_len = 0; - if (orig_node->hna_buff_len > 0) { - orig_node->hna_buff = kmalloc(orig_node->hna_buff_len, - GFP_ATOMIC); - memcpy(orig_node->hna_buff, hna_buff, orig_node->hna_buff_len); - } else { - orig_node->hna_buff = NULL; + if (hna_buff_len > 0) { + orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC); + if (orig_node->hna_buff) { + memcpy(orig_node->hna_buff, hna_buff, hna_buff_len); + orig_node->hna_buff_len = hna_buff_len; + } } spin_lock_irqsave(&hna_global_hash_lock, flags); @@ -333,7 +340,7 @@ void hna_global_add_orig(struct orig_node *orig_node, hna_global_hash->size * 2); if (swaphash == NULL) - debug_log(LOG_TYPE_CRIT, "Couldn't resize global hna hash table \n"); + printk(KERN_ERR "batman-adv:Couldn't resize global hna hash table \n"); else hna_global_hash = swaphash; } @@ -344,17 +351,17 @@ void hna_global_add_orig(struct orig_node *orig_node, int hna_global_fill_buffer_text(unsigned char *buff, int buff_len) { struct hna_global_entry *hna_global_entry; - struct hash_it_t *hashit = NULL; + HASHIT(hashit); int bytes_written = 0; unsigned long flags; spin_lock_irqsave(&hna_global_hash_lock, flags); - while (NULL != (hashit = hash_iterate(hna_global_hash, hashit))) { + while (hash_iterate(hna_global_hash, &hashit)) { if (buff_len < bytes_written + (2 * ETH_STR_LEN) + 10) break; - hna_global_entry = hashit->bucket->data; + hna_global_entry = hashit.bucket->data; bytes_written += snprintf(buff + bytes_written, (2 * ETH_STR_LEN) + 10, @@ -381,12 +388,9 @@ int hna_global_fill_buffer_text(unsigned char *buff, int buff_len) void _hna_global_del_orig(struct hna_global_entry *hna_global_entry, char *message) { - char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN]; - - addr_to_string(orig_str, hna_global_entry->orig_node->orig); - addr_to_string(hna_str, hna_global_entry->addr); - - debug_log(LOG_TYPE_ROUTES, "Deleting global hna entry %s (via %s): %s \n", hna_str, orig_str, message); + bat_dbg(DBG_ROUTES, "Deleting global hna entry %pM (via %pM): %s \n", + hna_global_entry->addr, hna_global_entry->orig_node->orig, + message); hash_remove(hna_global_hash, hna_global_entry->addr); kfree(hna_global_entry); diff --git a/drivers/staging/batman-adv/translation-table.h b/drivers/staging/batman-adv/translation-table.h index f7da8112931..281125b729f 100644 --- a/drivers/staging/batman-adv/translation-table.h +++ b/drivers/staging/batman-adv/translation-table.h @@ -23,6 +23,7 @@ int hna_local_init(void); void hna_local_add(uint8_t *addr); +void hna_local_remove(uint8_t *addr, char *message); int hna_local_fill_buffer(unsigned char *buff, int buff_len); int hna_local_fill_buffer_text(unsigned char *buff, int buff_len); void hna_local_purge(struct work_struct *work); diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index 3a0ef0c38c9..dec1b54031b 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -39,7 +39,6 @@ struct batman_if { char if_active; char addr_str[ETH_STR_LEN]; struct net_device *net_dev; - struct socket *raw_sock; atomic_t seqno; unsigned char *packet_buff; int packet_len; @@ -75,7 +74,7 @@ struct neigh_node { uint8_t tq_index; uint8_t tq_avg; uint8_t last_ttl; - unsigned long last_valid; /* when last packet via this neighbour was received */ + unsigned long last_valid; /* when last packet via this neighbor was received */ TYPE_OF_WORD real_bits[NUM_WORDS]; struct orig_node *orig_node; struct batman_if *if_incoming; @@ -113,6 +112,7 @@ struct forw_packet { /* structure for forw_list maintaining packet struct hlist_node list; unsigned long send_time; uint8_t own; + struct sk_buff *skb; unsigned char *packet_buff; uint16_t packet_len; uint32_t direct_link_flags; @@ -121,4 +121,14 @@ struct forw_packet { /* structure for forw_list maintaining packet struct batman_if *if_incoming; }; +/* While scanning for vis-entries of a particular vis-originator + * this list collects its interfaces to create a subgraph/cluster + * out of them later + */ +struct if_list_entry { + uint8_t addr[ETH_ALEN]; + bool primary; + struct hlist_node list; +}; + #endif diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index f6c9acb289e..fedec1bb309 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -23,11 +23,9 @@ #include "send.h" #include "translation-table.h" #include "vis.h" -#include "log.h" #include "soft-interface.h" #include "hard-interface.h" #include "hash.h" -#include "compat.h" struct hashtable_t *vis_hash; DEFINE_SPINLOCK(vis_hash_lock); @@ -50,39 +48,6 @@ static void free_info(void *data) kfree(info); } -/* set the mode of the visualization to client or server */ -void vis_set_mode(int mode) -{ - spin_lock(&vis_hash_lock); - - if (my_vis_info != NULL) - my_vis_info->packet.vis_type = mode; - - spin_unlock(&vis_hash_lock); -} - -/* is_vis_server(), locked outside */ -static int is_vis_server_locked(void) -{ - if (my_vis_info != NULL) - if (my_vis_info->packet.vis_type == VIS_TYPE_SERVER_SYNC) - return 1; - - return 0; -} - -/* get the current set mode */ -int is_vis_server(void) -{ - int ret = 0; - - spin_lock(&vis_hash_lock); - ret = is_vis_server_locked(); - spin_unlock(&vis_hash_lock); - - return ret; -} - /* Compare two vis packets, used by the hashing algorithm */ static int vis_info_cmp(void *data1, void *data2) { @@ -115,6 +80,68 @@ static int vis_info_choose(void *data, int size) return hash % size; } +/* insert interface to the list of interfaces of one originator, if it + * does not already exist in the list */ +static void proc_vis_insert_interface(const uint8_t *interface, + struct hlist_head *if_list, + bool primary) +{ + struct if_list_entry *entry; + struct hlist_node *pos; + + hlist_for_each_entry(entry, pos, if_list, list) { + if (compare_orig(entry->addr, (void *)interface)) + return; + } + + /* its a new address, add it to the list */ + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return; + memcpy(entry->addr, interface, ETH_ALEN); + entry->primary = primary; + hlist_add_head(&entry->list, if_list); +} + +void proc_vis_read_prim_sec(struct seq_file *seq, + struct hlist_head *if_list) +{ + struct if_list_entry *entry; + struct hlist_node *pos, *n; + char tmp_addr_str[ETH_STR_LEN]; + + hlist_for_each_entry_safe(entry, pos, n, if_list, list) { + if (entry->primary) { + seq_printf(seq, "PRIMARY, "); + } else { + addr_to_string(tmp_addr_str, entry->addr); + seq_printf(seq, "SEC %s, ", tmp_addr_str); + } + + hlist_del(&entry->list); + kfree(entry); + } +} + +/* read an entry */ +void proc_vis_read_entry(struct seq_file *seq, + struct vis_info_entry *entry, + struct hlist_head *if_list, + uint8_t *vis_orig) +{ + char to[40]; + + addr_to_string(to, entry->dest); + if (entry->quality == 0) { + proc_vis_insert_interface(vis_orig, if_list, true); + seq_printf(seq, "HNA %s, ", to); + } else { + proc_vis_insert_interface(entry->src, if_list, + compare_orig(entry->src, vis_orig)); + seq_printf(seq, "TQ %s %d, ", to, entry->quality); + } +} + /* tries to add one entry to the receive list. */ static void recv_list_add(struct list_head *recv_list, char *mac) { @@ -208,21 +235,23 @@ void receive_server_sync_packet(struct vis_packet *vis_packet, int vis_info_len) { struct vis_info *info; int is_new; + unsigned long flags; + int vis_server = atomic_read(&vis_mode); - spin_lock(&vis_hash_lock); + spin_lock_irqsave(&vis_hash_lock, flags); info = add_packet(vis_packet, vis_info_len, &is_new); if (info == NULL) goto end; /* only if we are server ourselves and packet is newer than the one in * hash.*/ - if (is_vis_server_locked() && is_new) { + if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) { memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); if (list_empty(&info->send_list)) list_add_tail(&info->send_list, &send_list); } end: - spin_unlock(&vis_hash_lock); + spin_unlock_irqrestore(&vis_hash_lock, flags); } /* handle an incoming client update packet and schedule forward if needed. */ @@ -231,12 +260,14 @@ void receive_client_update_packet(struct vis_packet *vis_packet, { struct vis_info *info; int is_new; + unsigned long flags; + int vis_server = atomic_read(&vis_mode); /* clients shall not broadcast. */ if (is_bcast(vis_packet->target_orig)) return; - spin_lock(&vis_hash_lock); + spin_lock_irqsave(&vis_hash_lock, flags); info = add_packet(vis_packet, vis_info_len, &is_new); if (info == NULL) goto end; @@ -244,7 +275,7 @@ void receive_client_update_packet(struct vis_packet *vis_packet, /* send only if we're the target server or ... */ - if (is_vis_server_locked() && + if (vis_server == VIS_TYPE_SERVER_SYNC && is_my_mac(info->packet.target_orig) && is_new) { info->packet.vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */ @@ -258,7 +289,7 @@ void receive_client_update_packet(struct vis_packet *vis_packet, list_add_tail(&info->send_list, &send_list); } end: - spin_unlock(&vis_hash_lock); + spin_unlock_irqrestore(&vis_hash_lock, flags); } /* Walk the originators and find the VIS server with the best tq. Set the packet @@ -267,12 +298,12 @@ end: * Must be called with the originator hash locked */ static int find_best_vis_server(struct vis_info *info) { - struct hash_it_t *hashit = NULL; + HASHIT(hashit); struct orig_node *orig_node; int best_tq = -1; - while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { - orig_node = hashit->bucket->data; + while (hash_iterate(orig_hash, &hashit)) { + orig_node = hashit.bucket->data; if ((orig_node != NULL) && (orig_node->router != NULL) && (orig_node->flags & VIS_SERVER) && @@ -298,7 +329,8 @@ static bool vis_packet_full(struct vis_info *info) * returns 0 on success, -1 if no packet could be generated */ static int generate_vis_packet(void) { - struct hash_it_t *hashit = NULL; + HASHIT(hashit_local); + HASHIT(hashit_global); struct orig_node *orig_node; struct vis_info *info = (struct vis_info *)my_vis_info; struct vis_info_entry *entry, *entry_array; @@ -307,27 +339,27 @@ static int generate_vis_packet(void) unsigned long flags; info->first_seen = jiffies; + info->packet.vis_type = atomic_read(&vis_mode); - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); info->packet.ttl = TTL; info->packet.seqno++; info->packet.entries = 0; - if (!is_vis_server_locked()) { + if (info->packet.vis_type == VIS_TYPE_CLIENT_UPDATE) { best_tq = find_best_vis_server(info); if (best_tq < 0) { - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return -1; } } - hashit = NULL; entry_array = (struct vis_info_entry *) ((char *)info + sizeof(struct vis_info)); - while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { - orig_node = hashit->bucket->data; + while (hash_iterate(orig_hash, &hashit_global)) { + orig_node = hashit_global.bucket->data; if (orig_node->router != NULL && compare_orig(orig_node->router->addr, orig_node->orig) && orig_node->batman_if @@ -342,18 +374,17 @@ static int generate_vis_packet(void) info->packet.entries++; if (vis_packet_full(info)) { - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return 0; } } } - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); - hashit = NULL; spin_lock_irqsave(&hna_local_hash_lock, flags); - while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) { - hna_local_entry = hashit->bucket->data; + while (hash_iterate(hna_local_hash, &hashit_local)) { + hna_local_entry = hashit_local.bucket->data; entry = &entry_array[info->packet.entries]; memset(entry->src, 0, ETH_ALEN); memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN); @@ -371,16 +402,16 @@ static int generate_vis_packet(void) static void purge_vis_packets(void) { - struct hash_it_t *hashit = NULL; + HASHIT(hashit); struct vis_info *info; - while (NULL != (hashit = hash_iterate(vis_hash, hashit))) { - info = hashit->bucket->data; + while (hash_iterate(vis_hash, &hashit)) { + info = hashit.bucket->data; if (info == my_vis_info) /* never purge own data. */ continue; if (time_after(jiffies, - info->first_seen + (VIS_TIMEOUT/1000)*HZ)) { - hash_remove_bucket(vis_hash, hashit); + info->first_seen + (VIS_TIMEOUT*HZ)/1000)) { + hash_remove_bucket(vis_hash, &hashit); free_info(info); } } @@ -388,14 +419,15 @@ static void purge_vis_packets(void) static void broadcast_vis_packet(struct vis_info *info, int packet_length) { - struct hash_it_t *hashit = NULL; + HASHIT(hashit); struct orig_node *orig_node; + unsigned long flags; - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); /* send to all routers in range. */ - while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { - orig_node = hashit->bucket->data; + while (hash_iterate(orig_hash, &hashit)) { + orig_node = hashit.bucket->data; /* if it's a vis server and reachable, send it. */ if (orig_node && @@ -418,14 +450,15 @@ static void broadcast_vis_packet(struct vis_info *info, int packet_length) } } memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); } static void unicast_vis_packet(struct vis_info *info, int packet_length) { struct orig_node *orig_node; + unsigned long flags; - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); orig_node = ((struct orig_node *) hash_find(orig_hash, info->packet.target_orig)); @@ -436,7 +469,7 @@ static void unicast_vis_packet(struct vis_info *info, int packet_length) orig_node->batman_if, orig_node->router->addr); } - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); } /* only send one vis packet. called from send_vis_packets() */ @@ -445,8 +478,7 @@ static void send_vis_packet(struct vis_info *info) int packet_length; if (info->packet.ttl < 2) { - debug_log(LOG_TYPE_NOTICE, - "Error - can't send vis packet: ttl exceeded\n"); + printk(KERN_WARNING "batman-adv: Error - can't send vis packet: ttl exceeded\n"); return; } @@ -467,8 +499,9 @@ static void send_vis_packet(struct vis_info *info) static void send_vis_packets(struct work_struct *work) { struct vis_info *info, *temp; + unsigned long flags; - spin_lock(&vis_hash_lock); + spin_lock_irqsave(&vis_hash_lock, flags); purge_vis_packets(); if (generate_vis_packet() == 0) @@ -479,7 +512,7 @@ static void send_vis_packets(struct work_struct *work) list_del_init(&info->send_list); send_vis_packet(info); } - spin_unlock(&vis_hash_lock); + spin_unlock_irqrestore(&vis_hash_lock, flags); start_vis_timer(); } static DECLARE_DELAYED_WORK(vis_timer_wq, send_vis_packets); @@ -488,20 +521,21 @@ static DECLARE_DELAYED_WORK(vis_timer_wq, send_vis_packets); * initialized (e.g. bat0 is initialized, interfaces have been added) */ int vis_init(void) { + unsigned long flags; if (vis_hash) return 1; - spin_lock(&vis_hash_lock); + spin_lock_irqsave(&vis_hash_lock, flags); vis_hash = hash_new(256, vis_info_cmp, vis_info_choose); if (!vis_hash) { - debug_log(LOG_TYPE_CRIT, "Can't initialize vis_hash\n"); + printk(KERN_ERR "batman-adv:Can't initialize vis_hash\n"); goto err; } my_vis_info = kmalloc(1000, GFP_ATOMIC); if (!my_vis_info) { - debug_log(LOG_TYPE_CRIT, "Can't initialize vis packet\n"); + printk(KERN_ERR "batman-adv:Can't initialize vis packet\n"); goto err; } @@ -511,7 +545,6 @@ int vis_init(void) INIT_LIST_HEAD(&my_vis_info->send_list); my_vis_info->packet.version = COMPAT_VERSION; my_vis_info->packet.packet_type = BAT_VIS; - my_vis_info->packet.vis_type = VIS_TYPE_CLIENT_UPDATE; my_vis_info->packet.ttl = TTL; my_vis_info->packet.seqno = 0; my_vis_info->packet.entries = 0; @@ -522,19 +555,19 @@ int vis_init(void) memcpy(my_vis_info->packet.sender_orig, mainIfAddr, ETH_ALEN); if (hash_add(vis_hash, my_vis_info) < 0) { - debug_log(LOG_TYPE_CRIT, - "Can't add own vis packet into hash\n"); + printk(KERN_ERR + "batman-adv:Can't add own vis packet into hash\n"); free_info(my_vis_info); /* not in hash, need to remove it * manually. */ goto err; } - spin_unlock(&vis_hash_lock); + spin_unlock_irqrestore(&vis_hash_lock, flags); start_vis_timer(); return 1; err: - spin_unlock(&vis_hash_lock); + spin_unlock_irqrestore(&vis_hash_lock, flags); vis_quit(); return 0; } @@ -542,23 +575,23 @@ err: /* shutdown vis-server */ void vis_quit(void) { + unsigned long flags; if (!vis_hash) return; cancel_delayed_work_sync(&vis_timer_wq); - spin_lock(&vis_hash_lock); + spin_lock_irqsave(&vis_hash_lock, flags); /* properly remove, kill timers ... */ hash_delete(vis_hash, free_info); vis_hash = NULL; my_vis_info = NULL; - spin_unlock(&vis_hash_lock); + spin_unlock_irqrestore(&vis_hash_lock, flags); } /* schedule packets for (re)transmission */ static void start_vis_timer(void) { queue_delayed_work(bat_event_workqueue, &vis_timer_wq, - (atomic_read(&vis_interval)/1000) * HZ); + (atomic_read(&vis_interval) * HZ) / 1000); } - diff --git a/drivers/staging/batman-adv/vis.h b/drivers/staging/batman-adv/vis.h index 276fabab4e8..0cdafde0ec3 100644 --- a/drivers/staging/batman-adv/vis.h +++ b/drivers/staging/batman-adv/vis.h @@ -45,16 +45,15 @@ struct recvlist_node { uint8_t mac[ETH_ALEN]; }; -enum vis_formats { - DOT_DRAW, - JSON, -}; - extern struct hashtable_t *vis_hash; extern spinlock_t vis_hash_lock; -void vis_set_mode(int mode); -int is_vis_server(void); +void proc_vis_read_entry(struct seq_file *seq, + struct vis_info_entry *entry, + struct hlist_head *if_list, + uint8_t *vis_orig); +void proc_vis_read_prim_sec(struct seq_file *seq, + struct hlist_head *if_list); void receive_server_sync_packet(struct vis_packet *vis_packet, int vis_info_len); void receive_client_update_packet(struct vis_packet *vis_packet, |