diff options
38 files changed, 7101 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 6fbbedbc7fe7..d30fa451e6f3 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
| @@ -129,6 +129,8 @@ source "drivers/staging/wlags49_h2/Kconfig" | |||
| 129 | 129 | ||
| 130 | source "drivers/staging/wlags49_h25/Kconfig" | 130 | source "drivers/staging/wlags49_h25/Kconfig" |
| 131 | 131 | ||
| 132 | source "drivers/staging/batman-adv/Kconfig" | ||
| 133 | |||
| 132 | source "drivers/staging/strip/Kconfig" | 134 | source "drivers/staging/strip/Kconfig" |
| 133 | 135 | ||
| 134 | source "drivers/staging/arlan/Kconfig" | 136 | source "drivers/staging/arlan/Kconfig" |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 61a81c148c9f..910e55dd7914 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
| @@ -46,6 +46,7 @@ obj-$(CONFIG_IIO) += iio/ | |||
| 46 | obj-$(CONFIG_RAMZSWAP) += ramzswap/ | 46 | obj-$(CONFIG_RAMZSWAP) += ramzswap/ |
| 47 | obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ | 47 | obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ |
| 48 | obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ | 48 | obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ |
| 49 | obj-$(CONFIG_BATMAN_ADV) += batman-adv/ | ||
| 49 | obj-$(CONFIG_STRIP) += strip/ | 50 | obj-$(CONFIG_STRIP) += strip/ |
| 50 | obj-$(CONFIG_ARLAN) += arlan/ | 51 | obj-$(CONFIG_ARLAN) += arlan/ |
| 51 | obj-$(CONFIG_WAVELAN) += wavelan/ | 52 | obj-$(CONFIG_WAVELAN) += wavelan/ |
diff --git a/drivers/staging/batman-adv/CHANGELOG b/drivers/staging/batman-adv/CHANGELOG new file mode 100644 index 000000000000..8a181639ceaa --- /dev/null +++ b/drivers/staging/batman-adv/CHANGELOG | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | batman-adv 0.2: | ||
| 2 | |||
| 3 | * support latest kernels (2.6.20 - 2.6.31) | ||
| 4 | * temporary routing loops / TTL code bug / ghost entries in originator table fixed | ||
| 5 | * internal packet queue for packet aggregation & transmission retry (ARQ) | ||
| 6 | for payload broadcasts added | ||
| 7 | * interface detection converted to event based handling to avoid timers | ||
| 8 | * major linux coding style adjustments applied | ||
| 9 | * all kernel version compatibility functions has been moved to compat.h | ||
| 10 | * use random ethernet address generator from the kernel | ||
| 11 | * /sys/module/batman_adv/version to export kernel module version | ||
| 12 | * vis: secondary interface export for dot draw format + JSON output format added | ||
| 13 | * many bugs (alignment issues, race conditions, deadlocks, etc) squashed | ||
| 14 | |||
| 15 | -- Sat, 07 Nov 2009 15:44:31 +0100 | ||
| 16 | |||
| 17 | batman-adv 0.1: | ||
| 18 | |||
| 19 | * support latest kernels (2.6.20 - 2.6.28) | ||
| 20 | * LOTS of cleanup: locking, stack usage, memory leaks | ||
| 21 | * Change Ethertype from 0x0842 to 0x4305 | ||
| 22 | unregistered at IEEE, if you want to sponsor an official Ethertype ($2500) | ||
| 23 | please contact us | ||
| 24 | |||
| 25 | -- Sun, 28 Dec 2008 00:44:31 +0100 | ||
| 26 | |||
| 27 | batman-adv 0.1-beta: | ||
| 28 | |||
| 29 | * layer 2 meshing based on BATMAN TQ algorithm in kernelland | ||
| 30 | * operates on any ethernet like interface | ||
| 31 | * supports IPv4, IPv6, DHCP, etc | ||
| 32 | * is controlled via /proc/net/batman-adv/ | ||
| 33 | * bridging via brctl is supported | ||
| 34 | * interface watchdog (interfaces can be (de)activated dynamically) | ||
| 35 | * offers integrated vis server which meshes/syncs with other vis servers in range | ||
| 36 | |||
| 37 | -- Mon, 05 May 2008 14:10:04 +0200 | ||
diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig new file mode 100644 index 000000000000..b9742e7c7d9e --- /dev/null +++ b/drivers/staging/batman-adv/Kconfig | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | # | ||
| 2 | # B.A.T.M.A.N meshing protocol | ||
| 3 | # | ||
| 4 | |||
| 5 | config BATMAN_ADV | ||
| 6 | tristate "B.A.T.M.A.N. Advanced Meshing Protocol" | ||
| 7 | default n | ||
| 8 | ---help--- | ||
| 9 | |||
| 10 | B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is | ||
| 11 | a routing protocol for multi-hop ad-hoc mesh networks. The | ||
| 12 | networks may be wired or wireless. See | ||
| 13 | http://www.open-mesh.org/ for more information and user space | ||
| 14 | tools. | ||
| 15 | |||
| 16 | config BATMAN_DEBUG | ||
| 17 | bool "B.A.T.M.A.N. debugging" | ||
| 18 | depends on BATMAN != n | ||
| 19 | help | ||
| 20 | |||
| 21 | This is an option for use by developers; most people should | ||
| 22 | say N here. This enables compilation of support for | ||
| 23 | outputting debugging information to the kernel log. The | ||
| 24 | output is controlled via the module parameter debug. | ||
| 25 | |||
diff --git a/drivers/staging/batman-adv/Makefile b/drivers/staging/batman-adv/Makefile new file mode 100644 index 000000000000..02da87134fce --- /dev/null +++ b/drivers/staging/batman-adv/Makefile | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | # | ||
| 2 | # Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | # | ||
| 4 | # Marek Lindner, Simon Wunderlich | ||
| 5 | # | ||
| 6 | # This program is free software; you can redistribute it and/or | ||
| 7 | # modify it under the terms of version 2 of the GNU General Public | ||
| 8 | # License as published by the Free Software Foundation. | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, but | ||
| 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | # General Public License for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License | ||
| 16 | # along with this program; if not, write to the Free Software | ||
| 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | # 02110-1301, USA | ||
| 19 | # | ||
| 20 | |||
| 21 | obj-m += batman-adv.o | ||
| 22 | 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 | ||
diff --git a/drivers/staging/batman-adv/README b/drivers/staging/batman-adv/README new file mode 100644 index 000000000000..3aaf393ebaa7 --- /dev/null +++ b/drivers/staging/batman-adv/README | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | [state: 07-11-2009] | ||
| 2 | |||
| 3 | BATMAN-ADV | ||
| 4 | ---------- | ||
| 5 | |||
| 6 | Batman-advanced is a new approach to wireless networking which does no longer | ||
| 7 | operate on the IP basis. Unlike B.A.T.M.A.N, which exchanges information | ||
| 8 | using UDP packets and sets routing tables, batman-advanced operates on ISO/OSI | ||
| 9 | Layer 2 only and uses and routes (or better: bridges) Ethernet Frames. It | ||
| 10 | emulates a virtual network switch of all nodes participating. Therefore all | ||
| 11 | nodes appear to be link local, thus all higher operating protocols won't be | ||
| 12 | affected by any changes within the network. You can run almost any protocol | ||
| 13 | above B.A.T.M.A.N. Advanced, prominent examples are: IPv4, IPv6, DHCP, IPX. | ||
| 14 | |||
| 15 | This is batman-advanced implemented as Linux kernel driver. It does not depend | ||
| 16 | on any network (other) driver, and can be used on wifi as well as ethernet, | ||
| 17 | vpn, etc ... (anything with ethernet-style layer 2). | ||
| 18 | It compiles against and should work with Linux 2.6.20 - 2.6.31. Supporting older | ||
| 19 | versions is not planned, but it's probably easy to backport it. If you work on a | ||
| 20 | backport, feel free to contact us. :-) | ||
| 21 | |||
| 22 | COMPILE | ||
| 23 | ------- | ||
| 24 | To compile against your currently installed kernel, just type: | ||
| 25 | |||
| 26 | # make | ||
| 27 | |||
| 28 | if you want to compile against some other kernel, use: | ||
| 29 | |||
| 30 | # make KERNELPATH=/path/to/kernel | ||
| 31 | |||
| 32 | USAGE | ||
| 33 | ----- | ||
| 34 | |||
| 35 | insmod the batman-adv.ko in your kernel: | ||
| 36 | |||
| 37 | # insmod batman-adv.ko | ||
| 38 | |||
| 39 | the module is now waiting for activation. You must add some interfaces | ||
| 40 | on which batman can operate. Each interface must be added separately: | ||
| 41 | |||
| 42 | # echo wlan0 > /proc/net/batman-adv/interfaces | ||
| 43 | |||
| 44 | ( # echo wlan1 > /proc/net/batman-adv/interfaces ) | ||
| 45 | ( # echo eth0 > /proc/net/batman-adv/interfaces ) | ||
| 46 | ( ... ) | ||
| 47 | |||
| 48 | Now batman starts broadcasting on this interface. | ||
| 49 | You can now view the table of originators (mesh participants) with: | ||
| 50 | |||
| 51 | # cat /proc/net/batman-adv/originators | ||
| 52 | |||
| 53 | The module will create a new interface "bat0", which can be used as a | ||
| 54 | regular interface: | ||
| 55 | |||
| 56 | # ifconfig bat0 inet 192.168.0.1 up | ||
| 57 | # ping 192.168.0.2 | ||
| 58 | ... | ||
| 59 | |||
| 60 | If you want topology visualization, your meshnode must be configured | ||
| 61 | as VIS-server: | ||
| 62 | |||
| 63 | # echo "server" > /proc/net/batman-adv/vis | ||
| 64 | |||
| 65 | Each node is either configured as "server" or as "client" (default: | ||
| 66 | "client"). Clients send their topology data to the server next to them, | ||
| 67 | and server synchronize with other servers. If there is no server | ||
| 68 | configured (default) within the mesh, no topology information will be | ||
| 69 | transmitted. With these "synchronizing servers", there can be 1 or | ||
| 70 | more vis servers sharing the same (or at least very similar) data. | ||
| 71 | |||
| 72 | When configured as server, you can get a topology snapshot of your mesh: | ||
| 73 | |||
| 74 | # cat /proc/net/batman-adv/vis | ||
| 75 | |||
| 76 | This output format is a graphviz formatted text file which can be | ||
| 77 | processed with graphviz-tools like dot. | ||
| 78 | The labels are similar/compatible to the ETX metric, 1.0 means perfect | ||
| 79 | connection (100%), 2.0 means 50%, 3.0 means 33% and so on. | ||
| 80 | |||
| 81 | Alternatively, a JSON output format is available. The format can be set | ||
| 82 | using by writing either "dot_draw" or "json" into the vis_format file. | ||
| 83 | "dot_draw" is selected by default. | ||
| 84 | |||
| 85 | echo "json" > /proc/net/batman-adv/vis_format | ||
| 86 | |||
| 87 | In very mobile scenarios, you might want to adjust the originator | ||
| 88 | interval to a lower value. This will make the mesh more responsive to | ||
| 89 | topology changes, but will also increase the overhead. Please make sure | ||
| 90 | that all nodes in your mesh use the same interval. The default value | ||
| 91 | is 1000 ms (1 second). | ||
| 92 | |||
| 93 | # echo 1000 > /proc/net/batman-adv/orig_interval | ||
| 94 | |||
| 95 | To deactivate batman, do: | ||
| 96 | |||
| 97 | # echo "" > /proc/net/batman-adv/interfaces | ||
| 98 | |||
| 99 | BATCTL | ||
| 100 | ------ | ||
| 101 | |||
| 102 | B.A.T.M.A.N. advanced operates on layer 2 and thus all hosts partici- | ||
| 103 | pating in the virtual switch are completely transparent for all proto- | ||
| 104 | cols above layer 2. Therefore the common diagnosis tools do not work as | ||
| 105 | expected. To overcome these problems batctl was created. At the moment | ||
| 106 | the batctl contains ping, traceroute, tcpdump and interfaces to the | ||
| 107 | kernel module settings. | ||
| 108 | |||
| 109 | For more information, please see the manpage (man batctl). | ||
| 110 | |||
| 111 | batctl is available on http://www.open-mesh.net/ | ||
| 112 | |||
| 113 | CONTACT | ||
| 114 | ------- | ||
| 115 | |||
| 116 | Please send us comments, experiences, questions, anything :) | ||
| 117 | |||
| 118 | IRC: #batman on irc.freenode.org | ||
| 119 | Mailing-list: b.a.t.m.a.n@open-mesh.net | ||
| 120 | (subscription at https://list.open-mesh.net/mm/listinfo/b.a.t.m.a.n ) | ||
| 121 | |||
| 122 | You can also contact the Authors: | ||
| 123 | |||
| 124 | Marek Lindner <lindner_marek@yahoo.de> | ||
| 125 | Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | ||
diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO new file mode 100644 index 000000000000..ea6dcf94d661 --- /dev/null +++ b/drivers/staging/batman-adv/TODO | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | => proc interface | ||
| 2 | * implement new interface to add/delete interfaces and setting options | ||
| 3 | * /proc/sys/net/batman-adv/ as main folder | ||
| 4 | * in interfaces/ list every available interface of the host | ||
| 5 | * each interfaces/$iface/ contains the following files: | ||
| 6 | -> enable (def: 0) [add/remove this interface to batman-adv] | ||
| 7 | -> ogm_interval (def: 1000) [ogm interval of that interface] | ||
| 8 | -> context (def: bat0) [later we want to support multiple mesh instances via | ||
| 9 | -> bat0/bat1/bat2/..] | ||
| 10 | -> status (read-only) [outputs the interface status from batman's | ||
| 11 | -> perspective] | ||
| 12 | * in mesh/batX/ list every available mesh subnet | ||
| 13 | -> vis_server (def: 0) [enable/disable vis server for that mesh] | ||
| 14 | -> vis_data (read-only) [outputs the vis data in a raw format] | ||
| 15 | -> aggregate_ogm (def: 1) [enable/disable ogm aggregation for that mesh] | ||
| 16 | -> originators (read-only) [outputs the originator table] | ||
| 17 | -> transtable_global (read-only) [outputs the global translation table] | ||
| 18 | -> transtable_local (read-only) [outputs the local translation table] | ||
| 19 | |||
| 20 | => vis "raw" data output | ||
| 21 | * the raw format shall replace dot draw / json to offer a neutral that can | ||
| 22 | * be converted | ||
| 23 | * the format (comma seperated entries): | ||
| 24 | -> "mac" -> mac address of an originator (each line begins with it) | ||
| 25 | -> "TQ mac value" -> src mac's link quality towards mac address | ||
| 26 | -> "HNA mac" -> HNA announced by source mac | ||
| 27 | -> "PRIMARY" -> this is a primary interface | ||
| 28 | -> "SEC mac" -> secondary mac address of source (requires preceeding | ||
| 29 | -> PRIMARY) | ||
| 30 | |||
| 31 | => logging | ||
| 32 | * the log level LOG_TYPE_CRIT, LOG_TYPE_WARN & LOG_TYPE_NOTICE will be | ||
| 33 | * unified to use printk | ||
| 34 | * LOG_TYPE_BATMAN & LOG_TYPE_ROUTES will also use printk but only after the | ||
| 35 | * internal debug level has been raised | ||
| 36 | * the internal debug level can be modified using a module parameter (debug) | ||
| 37 | * or at run time via /sys/module/batman-adv/parameters/debug | ||
| 38 | * make use of printk %pM support instead of converting mac addresses | ||
| 39 | * manually | ||
| 40 | |||
| 41 | => strip out all backward compatibility support to older kernels | ||
| 42 | (only found in compat.h) | ||
| 43 | |||
| 44 | => fix checkpatch.pl errors | ||
| 45 | |||
| 46 | Please send all patches to: | ||
| 47 | Marek Lindner <lindner_marek@yahoo.de> | ||
| 48 | Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | ||
| 49 | Andrew Lunn <andrew@lunn.ch> | ||
| 50 | b.a.t.m.a.n@lists.open-mesh.net | ||
| 51 | Greg Kroah-Hartman <gregkh@suse.de> | ||
diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c new file mode 100644 index 000000000000..9c6e681f6fb6 --- /dev/null +++ b/drivers/staging/batman-adv/aggregation.c | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "aggregation.h" | ||
| 24 | #include "send.h" | ||
| 25 | #include "routing.h" | ||
| 26 | |||
| 27 | /* calculate the size of the hna information for a given packet */ | ||
| 28 | static int hna_len(struct batman_packet *batman_packet) | ||
| 29 | { | ||
| 30 | return batman_packet->num_hna * ETH_ALEN; | ||
| 31 | } | ||
| 32 | |||
| 33 | /* return true if new_packet can be aggregated with forw_packet */ | ||
| 34 | static bool can_aggregate_with(struct batman_packet *new_batman_packet, | ||
| 35 | int packet_len, | ||
| 36 | unsigned long send_time, | ||
| 37 | bool directlink, | ||
| 38 | struct batman_if *if_incoming, | ||
| 39 | struct forw_packet *forw_packet) | ||
| 40 | { | ||
| 41 | struct batman_packet *batman_packet = | ||
| 42 | (struct batman_packet *)forw_packet->packet_buff; | ||
| 43 | int aggregated_bytes = forw_packet->packet_len + packet_len; | ||
| 44 | |||
| 45 | /** | ||
| 46 | * we can aggregate the current packet to this aggregated packet | ||
| 47 | * if: | ||
| 48 | * | ||
| 49 | * - the send time is within our MAX_AGGREGATION_MS time | ||
| 50 | * - the resulting packet wont be bigger than | ||
| 51 | * MAX_AGGREGATION_BYTES | ||
| 52 | */ | ||
| 53 | |||
| 54 | if (time_before(send_time, forw_packet->send_time) && | ||
| 55 | (aggregated_bytes <= MAX_AGGREGATION_BYTES)) { | ||
| 56 | |||
| 57 | /** | ||
| 58 | * check aggregation compatibility | ||
| 59 | * -> direct link packets are broadcasted on | ||
| 60 | * their interface only | ||
| 61 | * -> aggregate packet if the current packet is | ||
| 62 | * a "global" packet as well as the base | ||
| 63 | * packet | ||
| 64 | */ | ||
| 65 | |||
| 66 | /* packets without direct link flag and high TTL | ||
| 67 | * are flooded through the net */ | ||
| 68 | if ((!directlink) && | ||
| 69 | (!(batman_packet->flags & DIRECTLINK)) && | ||
| 70 | (batman_packet->ttl != 1) && | ||
| 71 | |||
| 72 | /* own packets originating non-primary | ||
| 73 | * interfaces leave only that interface */ | ||
| 74 | ((!forw_packet->own) || | ||
| 75 | (forw_packet->if_incoming->if_num == 0))) | ||
| 76 | return true; | ||
| 77 | |||
| 78 | /* if the incoming packet is sent via this one | ||
| 79 | * interface only - we still can aggregate */ | ||
| 80 | if ((directlink) && | ||
| 81 | (new_batman_packet->ttl == 1) && | ||
| 82 | (forw_packet->if_incoming == if_incoming)) | ||
| 83 | return true; | ||
| 84 | |||
| 85 | } | ||
| 86 | |||
| 87 | return false; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* create a new aggregated packet and add this packet to it */ | ||
| 91 | static void new_aggregated_packet(unsigned char *packet_buff, | ||
| 92 | int packet_len, | ||
| 93 | unsigned long send_time, | ||
| 94 | bool direct_link, | ||
| 95 | struct batman_if *if_incoming, | ||
| 96 | int own_packet) | ||
| 97 | { | ||
| 98 | struct forw_packet *forw_packet_aggr; | ||
| 99 | |||
| 100 | forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); | ||
| 101 | if (!forw_packet_aggr) | ||
| 102 | return; | ||
| 103 | |||
| 104 | forw_packet_aggr->packet_buff = kmalloc(MAX_AGGREGATION_BYTES, | ||
| 105 | GFP_ATOMIC); | ||
| 106 | if (!forw_packet_aggr->packet_buff) { | ||
| 107 | kfree(forw_packet_aggr); | ||
| 108 | return; | ||
| 109 | } | ||
| 110 | |||
| 111 | INIT_HLIST_NODE(&forw_packet_aggr->list); | ||
| 112 | |||
| 113 | forw_packet_aggr->packet_len = packet_len; | ||
| 114 | memcpy(forw_packet_aggr->packet_buff, | ||
| 115 | packet_buff, | ||
| 116 | forw_packet_aggr->packet_len); | ||
| 117 | |||
| 118 | forw_packet_aggr->own = own_packet; | ||
| 119 | forw_packet_aggr->if_incoming = if_incoming; | ||
| 120 | forw_packet_aggr->num_packets = 0; | ||
| 121 | forw_packet_aggr->direct_link_flags = 0; | ||
| 122 | forw_packet_aggr->send_time = send_time; | ||
| 123 | |||
| 124 | /* save packet direct link flag status */ | ||
| 125 | if (direct_link) | ||
| 126 | forw_packet_aggr->direct_link_flags |= 1; | ||
| 127 | |||
| 128 | /* add new packet to packet list */ | ||
| 129 | spin_lock(&forw_bat_list_lock); | ||
| 130 | hlist_add_head(&forw_packet_aggr->list, &forw_bat_list); | ||
| 131 | spin_unlock(&forw_bat_list_lock); | ||
| 132 | |||
| 133 | /* start timer for this packet */ | ||
| 134 | INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, | ||
| 135 | send_outstanding_bat_packet); | ||
| 136 | queue_delayed_work(bat_event_workqueue, | ||
| 137 | &forw_packet_aggr->delayed_work, | ||
| 138 | send_time - jiffies); | ||
| 139 | } | ||
| 140 | |||
| 141 | /* aggregate a new packet into the existing aggregation */ | ||
| 142 | static void aggregate(struct forw_packet *forw_packet_aggr, | ||
| 143 | unsigned char *packet_buff, | ||
| 144 | int packet_len, | ||
| 145 | bool direct_link) | ||
| 146 | { | ||
| 147 | memcpy((forw_packet_aggr->packet_buff + forw_packet_aggr->packet_len), | ||
| 148 | packet_buff, packet_len); | ||
| 149 | forw_packet_aggr->packet_len += packet_len; | ||
| 150 | forw_packet_aggr->num_packets++; | ||
| 151 | |||
| 152 | /* save packet direct link flag status */ | ||
| 153 | if (direct_link) | ||
| 154 | forw_packet_aggr->direct_link_flags |= | ||
| 155 | (1 << forw_packet_aggr->num_packets); | ||
| 156 | } | ||
| 157 | |||
| 158 | void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len, | ||
| 159 | struct batman_if *if_incoming, char own_packet, | ||
| 160 | unsigned long send_time) | ||
| 161 | { | ||
| 162 | /** | ||
| 163 | * _aggr -> pointer to the packet we want to aggregate with | ||
| 164 | * _pos -> pointer to the position in the queue | ||
| 165 | */ | ||
| 166 | struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL; | ||
| 167 | struct hlist_node *tmp_node; | ||
| 168 | struct batman_packet *batman_packet = | ||
| 169 | (struct batman_packet *)packet_buff; | ||
| 170 | bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; | ||
| 171 | |||
| 172 | /* find position for the packet in the forward queue */ | ||
| 173 | spin_lock(&forw_bat_list_lock); | ||
| 174 | /* own packets are not to be aggregated */ | ||
| 175 | if ((atomic_read(&aggregation_enabled)) && (!own_packet)) { | ||
| 176 | hlist_for_each_entry(forw_packet_pos, tmp_node, &forw_bat_list, | ||
| 177 | list) { | ||
| 178 | if (can_aggregate_with(batman_packet, | ||
| 179 | packet_len, | ||
| 180 | send_time, | ||
| 181 | direct_link, | ||
| 182 | if_incoming, | ||
| 183 | forw_packet_pos)) { | ||
| 184 | forw_packet_aggr = forw_packet_pos; | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | /* nothing to aggregate with - either aggregation disabled or no | ||
| 191 | * suitable aggregation packet found */ | ||
| 192 | if (forw_packet_aggr == NULL) { | ||
| 193 | /* the following section can run without the lock */ | ||
| 194 | spin_unlock(&forw_bat_list_lock); | ||
| 195 | new_aggregated_packet(packet_buff, packet_len, | ||
| 196 | send_time, direct_link, | ||
| 197 | if_incoming, own_packet); | ||
| 198 | } else { | ||
| 199 | aggregate(forw_packet_aggr, | ||
| 200 | packet_buff, packet_len, | ||
| 201 | direct_link); | ||
| 202 | spin_unlock(&forw_bat_list_lock); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | /* unpack the aggregated packets and process them one by one */ | ||
| 207 | void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, | ||
| 208 | int packet_len, struct batman_if *if_incoming) | ||
| 209 | { | ||
| 210 | struct batman_packet *batman_packet; | ||
| 211 | int buff_pos = 0; | ||
| 212 | unsigned char *hna_buff; | ||
| 213 | |||
| 214 | batman_packet = (struct batman_packet *)packet_buff; | ||
| 215 | |||
| 216 | while (aggregated_packet(buff_pos, packet_len, | ||
| 217 | batman_packet->num_hna)) { | ||
| 218 | |||
| 219 | /* network to host order for our 16bit seqno, and the | ||
| 220 | orig_interval. */ | ||
| 221 | batman_packet->seqno = ntohs(batman_packet->seqno); | ||
| 222 | |||
| 223 | hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN; | ||
| 224 | receive_bat_packet(ethhdr, batman_packet, | ||
| 225 | hna_buff, hna_len(batman_packet), | ||
| 226 | if_incoming); | ||
| 227 | |||
| 228 | buff_pos += BAT_PACKET_LEN + hna_len(batman_packet); | ||
| 229 | batman_packet = (struct batman_packet *) | ||
| 230 | (packet_buff + buff_pos); | ||
| 231 | } | ||
| 232 | } | ||
diff --git a/drivers/staging/batman-adv/aggregation.h b/drivers/staging/batman-adv/aggregation.h new file mode 100644 index 000000000000..6da8df9f99b7 --- /dev/null +++ b/drivers/staging/batman-adv/aggregation.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | |||
| 24 | /* is there another aggregated packet here? */ | ||
| 25 | static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna) | ||
| 26 | { | ||
| 27 | int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN); | ||
| 28 | |||
| 29 | return (next_buff_pos <= packet_len) && | ||
| 30 | (next_buff_pos <= MAX_AGGREGATION_BYTES); | ||
| 31 | } | ||
| 32 | |||
| 33 | void add_bat_packet_to_list(unsigned char *packet_buff, int packet_len, | ||
| 34 | struct batman_if *if_outgoing, char own_packet, | ||
| 35 | unsigned long send_time); | ||
| 36 | void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, | ||
| 37 | int packet_len, struct batman_if *if_incoming); | ||
diff --git a/drivers/staging/batman-adv/bitarray.c b/drivers/staging/batman-adv/bitarray.c new file mode 100644 index 000000000000..3c67f5f42b2b --- /dev/null +++ b/drivers/staging/batman-adv/bitarray.c | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2006-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Simon Wunderlich, Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "bitarray.h" | ||
| 24 | #include "log.h" | ||
| 25 | |||
| 26 | /* returns true if the corresponding bit in the given seq_bits indicates true | ||
| 27 | * and curr_seqno is within range of last_seqno */ | ||
| 28 | uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno, | ||
| 29 | uint16_t curr_seqno) | ||
| 30 | { | ||
| 31 | int16_t diff, word_offset, word_num; | ||
| 32 | |||
| 33 | diff = last_seqno - curr_seqno; | ||
| 34 | if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) { | ||
| 35 | return 0; | ||
| 36 | } else { | ||
| 37 | /* which word */ | ||
| 38 | word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE; | ||
| 39 | /* which position in the selected word */ | ||
| 40 | word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE; | ||
| 41 | |||
| 42 | if (seq_bits[word_num] & 1 << word_offset) | ||
| 43 | return 1; | ||
| 44 | else | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | /* turn corresponding bit on, so we can remember that we got the packet */ | ||
| 50 | void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n) | ||
| 51 | { | ||
| 52 | int32_t word_offset, word_num; | ||
| 53 | |||
| 54 | /* if too old, just drop it */ | ||
| 55 | if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE) | ||
| 56 | return; | ||
| 57 | |||
| 58 | /* which word */ | ||
| 59 | word_num = n / WORD_BIT_SIZE; | ||
| 60 | /* which position in the selected word */ | ||
| 61 | word_offset = n % WORD_BIT_SIZE; | ||
| 62 | |||
| 63 | seq_bits[word_num] |= 1 << word_offset; /* turn the position on */ | ||
| 64 | } | ||
| 65 | |||
| 66 | /* shift the packet array by n places. */ | ||
| 67 | void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n) | ||
| 68 | { | ||
| 69 | int32_t word_offset, word_num; | ||
| 70 | int32_t i; | ||
| 71 | |||
| 72 | if (n <= 0) | ||
| 73 | return; | ||
| 74 | |||
| 75 | word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */ | ||
| 76 | word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */ | ||
| 77 | |||
| 78 | for (i = NUM_WORDS - 1; i > word_num; i--) { | ||
| 79 | /* going from old to new, so we don't overwrite the data we copy | ||
| 80 | * from. | ||
| 81 | * | ||
| 82 | * left is high, right is low: FEDC BA98 7654 3210 | ||
| 83 | * ^^ ^^ | ||
| 84 | * vvvv | ||
| 85 | * ^^^^ = from, vvvvv =to, we'd have word_num==1 and | ||
| 86 | * word_offset==WORD_BIT_SIZE/2 ????? in this example. | ||
| 87 | * (=24 bits) | ||
| 88 | * | ||
| 89 | * our desired output would be: 9876 5432 1000 0000 | ||
| 90 | * */ | ||
| 91 | |||
| 92 | seq_bits[i] = | ||
| 93 | (seq_bits[i - word_num] << word_offset) + | ||
| 94 | /* take the lower port from the left half, shift it left | ||
| 95 | * to its final position */ | ||
| 96 | (seq_bits[i - word_num - 1] >> | ||
| 97 | (WORD_BIT_SIZE-word_offset)); | ||
| 98 | /* and the upper part of the right half and shift it left to | ||
| 99 | * it's position */ | ||
| 100 | /* for our example that would be: word[0] = 9800 + 0076 = | ||
| 101 | * 9876 */ | ||
| 102 | } | ||
| 103 | /* now for our last word, i==word_num, we only have the it's "left" | ||
| 104 | * half. that's the 1000 word in our example.*/ | ||
| 105 | |||
| 106 | seq_bits[i] = (seq_bits[i - word_num] << word_offset); | ||
| 107 | |||
| 108 | /* pad the rest with 0, if there is anything */ | ||
| 109 | i--; | ||
| 110 | |||
| 111 | for (; i >= 0; i--) | ||
| 112 | seq_bits[i] = 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | |||
| 116 | /* receive and process one packet, returns 1 if received seq_num is considered | ||
| 117 | * new, 0 if old */ | ||
| 118 | char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff, | ||
| 119 | int8_t set_mark) | ||
| 120 | { | ||
| 121 | int i; | ||
| 122 | |||
| 123 | /* we already got a sequence number higher than this one, so we just | ||
| 124 | * mark it. this should wrap around the integer just fine */ | ||
| 125 | if ((seq_num_diff < 0) && (seq_num_diff >= -TQ_LOCAL_WINDOW_SIZE)) { | ||
| 126 | if (set_mark) | ||
| 127 | bit_mark(seq_bits, -seq_num_diff); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | /* it seems we missed a lot of packets or the other host restarted */ | ||
| 132 | if ((seq_num_diff > TQ_LOCAL_WINDOW_SIZE) || | ||
| 133 | (seq_num_diff < -TQ_LOCAL_WINDOW_SIZE)) { | ||
| 134 | |||
| 135 | if (seq_num_diff > TQ_LOCAL_WINDOW_SIZE) | ||
| 136 | debug_log(LOG_TYPE_BATMAN, | ||
| 137 | "We missed a lot of packets (%i) !\n", | ||
| 138 | seq_num_diff-1); | ||
| 139 | |||
| 140 | if (-seq_num_diff > TQ_LOCAL_WINDOW_SIZE) | ||
| 141 | debug_log(LOG_TYPE_BATMAN, | ||
| 142 | "Other host probably restarted !\n"); | ||
| 143 | |||
| 144 | for (i = 0; i < NUM_WORDS; i++) | ||
| 145 | seq_bits[i] = 0; | ||
| 146 | |||
| 147 | if (set_mark) | ||
| 148 | seq_bits[0] = 1; /* we only have the latest packet */ | ||
| 149 | } else { | ||
| 150 | bit_shift(seq_bits, seq_num_diff); | ||
| 151 | |||
| 152 | if (set_mark) | ||
| 153 | bit_mark(seq_bits, 0); | ||
| 154 | } | ||
| 155 | |||
| 156 | return 1; | ||
| 157 | } | ||
| 158 | |||
| 159 | /* count the hamming weight, how many good packets did we receive? just count | ||
| 160 | * the 1's. The inner loop uses the Kernighan algorithm, see | ||
| 161 | * http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan | ||
| 162 | */ | ||
| 163 | int bit_packet_count(TYPE_OF_WORD *seq_bits) | ||
| 164 | { | ||
| 165 | int i, hamming = 0; | ||
| 166 | TYPE_OF_WORD word; | ||
| 167 | |||
| 168 | for (i = 0; i < NUM_WORDS; i++) { | ||
| 169 | word = seq_bits[i]; | ||
| 170 | |||
| 171 | while (word) { | ||
| 172 | word &= word-1; | ||
| 173 | hamming++; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | return hamming; | ||
| 177 | } | ||
diff --git a/drivers/staging/batman-adv/bitarray.h b/drivers/staging/batman-adv/bitarray.h new file mode 100644 index 000000000000..ec72dd784362 --- /dev/null +++ b/drivers/staging/batman-adv/bitarray.h | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2006-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Simon Wunderlich, Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | |||
| 23 | /* you should choose something big, if you don't want to waste cpu */ | ||
| 24 | #define TYPE_OF_WORD unsigned long | ||
| 25 | #define WORD_BIT_SIZE (sizeof(TYPE_OF_WORD) * 8) | ||
| 26 | |||
| 27 | /* returns true if the corresponding bit in the given seq_bits indicates true | ||
| 28 | * and curr_seqno is within range of last_seqno */ | ||
| 29 | uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno, | ||
| 30 | uint16_t curr_seqno); | ||
| 31 | |||
| 32 | /* turn corresponding bit on, so we can remember that we got the packet */ | ||
| 33 | void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n); | ||
| 34 | |||
| 35 | /* shift the packet array by n places. */ | ||
| 36 | void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n); | ||
| 37 | |||
| 38 | |||
| 39 | /* receive and process one packet, returns 1 if received seq_num is considered | ||
| 40 | * new, 0 if old */ | ||
| 41 | char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff, | ||
| 42 | int8_t set_mark); | ||
| 43 | |||
| 44 | /* count the hamming weight, how many good packets did we receive? */ | ||
| 45 | int bit_packet_count(TYPE_OF_WORD *seq_bits); | ||
diff --git a/drivers/staging/batman-adv/compat.h b/drivers/staging/batman-adv/compat.h new file mode 100644 index 000000000000..f4e0a4564ba7 --- /dev/null +++ b/drivers/staging/batman-adv/compat.h | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | * | ||
| 21 | * This file contains macros for maintaining compatibility with older versions | ||
| 22 | * of the Linux kernel. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <linux/version.h> /* LINUX_VERSION_CODE */ | ||
| 26 | |||
| 27 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) | ||
| 28 | |||
| 29 | #define skb_set_network_header(_skb, _offset) \ | ||
| 30 | do { (_skb)->nh.raw = (_skb)->data + (_offset); } while (0) | ||
| 31 | |||
| 32 | #define skb_reset_mac_header(_skb) \ | ||
| 33 | do { (_skb)->mac.raw = (_skb)->data; } while (0) | ||
| 34 | |||
| 35 | #define list_first_entry(ptr, type, member) \ | ||
| 36 | list_entry((ptr)->next, type, member) | ||
| 37 | |||
| 38 | #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */ | ||
| 39 | |||
| 40 | |||
| 41 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) | ||
| 42 | |||
| 43 | #define device_create(_cls, _parent, _devt, _device, _fmt) \ | ||
| 44 | class_device_create(_cls, _parent, _devt, _device, _fmt) | ||
| 45 | |||
| 46 | #define device_destroy(_cls, _device) \ | ||
| 47 | class_device_destroy(_cls, _device) | ||
| 48 | |||
| 49 | #else | ||
| 50 | |||
| 51 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) | ||
| 52 | |||
| 53 | #define device_create(_cls, _parent, _devt, _device, _fmt) \ | ||
| 54 | device_create_drvdata(_cls, _parent, _devt, _device, _fmt) | ||
| 55 | |||
| 56 | #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) */ | ||
| 57 | |||
| 58 | #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) */ | ||
| 59 | |||
| 60 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) | ||
| 61 | |||
| 62 | #define cancel_delayed_work_sync(wq) cancel_rearming_delayed_work(wq) | ||
| 63 | |||
| 64 | #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) */ | ||
| 65 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) | ||
| 66 | #define strict_strtoul(cp, base, res) \ | ||
| 67 | ({ \ | ||
| 68 | int ret = 0; \ | ||
| 69 | char *endp; \ | ||
| 70 | *res = simple_strtoul(cp, &endp, base); \ | ||
| 71 | if (cp == endp) \ | ||
| 72 | ret = -EINVAL; \ | ||
| 73 | ret; \ | ||
| 74 | }) | ||
| 75 | #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 new file mode 100644 index 000000000000..1e7d1f88674f --- /dev/null +++ b/drivers/staging/batman-adv/device.c | |||
| @@ -0,0 +1,337 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "device.h" | ||
| 24 | #include "log.h" | ||
| 25 | #include "send.h" | ||
| 26 | #include "types.h" | ||
| 27 | #include "hash.h" | ||
| 28 | |||
| 29 | #include "compat.h" | ||
| 30 | |||
| 31 | static struct class *batman_class; | ||
| 32 | |||
| 33 | static int Major; /* Major number assigned to our device driver */ | ||
| 34 | |||
| 35 | static const struct file_operations fops = { | ||
| 36 | .open = bat_device_open, | ||
| 37 | .release = bat_device_release, | ||
| 38 | .read = bat_device_read, | ||
| 39 | .write = bat_device_write, | ||
| 40 | .poll = bat_device_poll, | ||
| 41 | }; | ||
| 42 | |||
| 43 | static struct device_client *device_client_hash[256]; | ||
| 44 | |||
| 45 | void bat_device_init(void) | ||
| 46 | { | ||
| 47 | int i; | ||
| 48 | |||
| 49 | for (i = 0; i < 256; i++) | ||
| 50 | device_client_hash[i] = NULL; | ||
| 51 | } | ||
| 52 | |||
| 53 | int bat_device_setup(void) | ||
| 54 | { | ||
| 55 | int tmp_major; | ||
| 56 | |||
| 57 | if (Major) | ||
| 58 | return 1; | ||
| 59 | |||
| 60 | /* register our device - kernel assigns a free major number */ | ||
| 61 | tmp_major = register_chrdev(0, DRIVER_DEVICE, &fops); | ||
| 62 | if (tmp_major < 0) { | ||
| 63 | debug_log(LOG_TYPE_WARN, "Registering the character device failed with %d\n", | ||
| 64 | tmp_major); | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | batman_class = class_create(THIS_MODULE, "batman-adv"); | ||
| 69 | |||
| 70 | if (IS_ERR(batman_class)) { | ||
| 71 | debug_log(LOG_TYPE_WARN, "Could not register class 'batman-adv' \n"); | ||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | device_create(batman_class, NULL, MKDEV(tmp_major, 0), NULL, | ||
| 76 | "batman-adv"); | ||
| 77 | |||
| 78 | Major = tmp_major; | ||
| 79 | return 1; | ||
| 80 | } | ||
| 81 | |||
| 82 | void bat_device_destroy(void) | ||
| 83 | { | ||
| 84 | if (!Major) | ||
| 85 | return; | ||
| 86 | |||
| 87 | device_destroy(batman_class, MKDEV(Major, 0)); | ||
| 88 | class_destroy(batman_class); | ||
| 89 | |||
| 90 | /* Unregister the device */ | ||
| 91 | unregister_chrdev(Major, DRIVER_DEVICE); | ||
| 92 | |||
| 93 | Major = 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | int bat_device_open(struct inode *inode, struct file *file) | ||
| 97 | { | ||
| 98 | unsigned int i; | ||
| 99 | struct device_client *device_client; | ||
| 100 | |||
| 101 | device_client = kmalloc(sizeof(struct device_client), GFP_KERNEL); | ||
| 102 | |||
| 103 | if (!device_client) | ||
| 104 | return -ENOMEM; | ||
| 105 | |||
| 106 | for (i = 0; i < 256; i++) { | ||
| 107 | if (!device_client_hash[i]) { | ||
| 108 | device_client_hash[i] = device_client; | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | if (device_client_hash[i] != device_client) { | ||
| 114 | debug_log(LOG_TYPE_WARN, "Error - can't add another packet client: maximum number of clients reached \n"); | ||
| 115 | kfree(device_client); | ||
| 116 | return -EXFULL; | ||
| 117 | } | ||
| 118 | |||
| 119 | INIT_LIST_HEAD(&device_client->queue_list); | ||
| 120 | device_client->queue_len = 0; | ||
| 121 | device_client->index = i; | ||
| 122 | device_client->lock = __SPIN_LOCK_UNLOCKED(device_client->lock); | ||
| 123 | init_waitqueue_head(&device_client->queue_wait); | ||
| 124 | |||
| 125 | file->private_data = device_client; | ||
| 126 | |||
| 127 | inc_module_count(); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | int bat_device_release(struct inode *inode, struct file *file) | ||
| 132 | { | ||
| 133 | struct device_client *device_client = | ||
| 134 | (struct device_client *)file->private_data; | ||
| 135 | struct device_packet *device_packet; | ||
| 136 | struct list_head *list_pos, *list_pos_tmp; | ||
| 137 | |||
| 138 | spin_lock(&device_client->lock); | ||
| 139 | |||
| 140 | /* for all packets in the queue ... */ | ||
| 141 | list_for_each_safe(list_pos, list_pos_tmp, &device_client->queue_list) { | ||
| 142 | device_packet = list_entry(list_pos, | ||
| 143 | struct device_packet, list); | ||
| 144 | |||
| 145 | list_del(list_pos); | ||
| 146 | kfree(device_packet); | ||
| 147 | } | ||
| 148 | |||
| 149 | device_client_hash[device_client->index] = NULL; | ||
| 150 | spin_unlock(&device_client->lock); | ||
| 151 | |||
| 152 | kfree(device_client); | ||
| 153 | dec_module_count(); | ||
| 154 | |||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, | ||
| 159 | loff_t *ppos) | ||
| 160 | { | ||
| 161 | struct device_client *device_client = | ||
| 162 | (struct device_client *)file->private_data; | ||
| 163 | struct device_packet *device_packet; | ||
| 164 | int error; | ||
| 165 | |||
| 166 | if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0)) | ||
| 167 | return -EAGAIN; | ||
| 168 | |||
| 169 | if ((!buf) || (count < sizeof(struct icmp_packet))) | ||
| 170 | return -EINVAL; | ||
| 171 | |||
| 172 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
| 173 | return -EFAULT; | ||
| 174 | |||
| 175 | error = wait_event_interruptible(device_client->queue_wait, | ||
| 176 | device_client->queue_len); | ||
| 177 | |||
| 178 | if (error) | ||
| 179 | return error; | ||
| 180 | |||
| 181 | spin_lock(&device_client->lock); | ||
| 182 | |||
| 183 | device_packet = list_first_entry(&device_client->queue_list, | ||
| 184 | struct device_packet, list); | ||
| 185 | list_del(&device_packet->list); | ||
| 186 | device_client->queue_len--; | ||
| 187 | |||
| 188 | spin_unlock(&device_client->lock); | ||
| 189 | |||
| 190 | error = __copy_to_user(buf, &device_packet->icmp_packet, | ||
| 191 | sizeof(struct icmp_packet)); | ||
| 192 | |||
| 193 | kfree(device_packet); | ||
| 194 | |||
| 195 | if (error) | ||
| 196 | return error; | ||
| 197 | |||
| 198 | return sizeof(struct icmp_packet); | ||
| 199 | } | ||
| 200 | |||
| 201 | ssize_t bat_device_write(struct file *file, const char __user *buff, | ||
| 202 | size_t len, loff_t *off) | ||
| 203 | { | ||
| 204 | struct device_client *device_client = | ||
| 205 | (struct device_client *)file->private_data; | ||
| 206 | struct icmp_packet icmp_packet; | ||
| 207 | struct orig_node *orig_node; | ||
| 208 | struct batman_if *batman_if; | ||
| 209 | |||
| 210 | if (len < sizeof(struct icmp_packet)) { | ||
| 211 | debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: invalid packet size\n"); | ||
| 212 | return -EINVAL; | ||
| 213 | } | ||
| 214 | |||
| 215 | if (!access_ok(VERIFY_READ, buff, sizeof(struct icmp_packet))) | ||
| 216 | return -EFAULT; | ||
| 217 | |||
| 218 | if (__copy_from_user(&icmp_packet, buff, sizeof(icmp_packet))) | ||
| 219 | return -EFAULT; | ||
| 220 | |||
| 221 | if (icmp_packet.packet_type != BAT_ICMP) { | ||
| 222 | debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); | ||
| 223 | return -EINVAL; | ||
| 224 | } | ||
| 225 | |||
| 226 | if (icmp_packet.msg_type != ECHO_REQUEST) { | ||
| 227 | debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n"); | ||
| 228 | return -EINVAL; | ||
| 229 | } | ||
| 230 | |||
| 231 | icmp_packet.uid = device_client->index; | ||
| 232 | |||
| 233 | if (icmp_packet.version != COMPAT_VERSION) { | ||
| 234 | icmp_packet.msg_type = PARAMETER_PROBLEM; | ||
| 235 | icmp_packet.ttl = COMPAT_VERSION; | ||
| 236 | bat_device_add_packet(device_client, &icmp_packet); | ||
| 237 | goto out; | ||
| 238 | } | ||
| 239 | |||
| 240 | if (atomic_read(&module_state) != MODULE_ACTIVE) | ||
| 241 | goto dst_unreach; | ||
| 242 | |||
| 243 | spin_lock(&orig_hash_lock); | ||
| 244 | orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst)); | ||
| 245 | |||
| 246 | if (!orig_node) | ||
| 247 | goto unlock; | ||
| 248 | |||
| 249 | if (!orig_node->router) | ||
| 250 | goto unlock; | ||
| 251 | |||
| 252 | batman_if = orig_node->batman_if; | ||
| 253 | |||
| 254 | if (!batman_if) | ||
| 255 | goto unlock; | ||
| 256 | |||
| 257 | memcpy(icmp_packet.orig, | ||
| 258 | batman_if->net_dev->dev_addr, | ||
| 259 | ETH_ALEN); | ||
| 260 | |||
| 261 | send_raw_packet((unsigned char *)&icmp_packet, | ||
| 262 | sizeof(struct icmp_packet), | ||
| 263 | batman_if, orig_node->router->addr); | ||
| 264 | |||
| 265 | spin_unlock(&orig_hash_lock); | ||
| 266 | goto out; | ||
| 267 | |||
| 268 | unlock: | ||
| 269 | spin_unlock(&orig_hash_lock); | ||
| 270 | dst_unreach: | ||
| 271 | icmp_packet.msg_type = DESTINATION_UNREACHABLE; | ||
| 272 | bat_device_add_packet(device_client, &icmp_packet); | ||
| 273 | out: | ||
| 274 | return len; | ||
| 275 | } | ||
| 276 | |||
| 277 | unsigned int bat_device_poll(struct file *file, poll_table *wait) | ||
| 278 | { | ||
| 279 | struct device_client *device_client = | ||
| 280 | (struct device_client *)file->private_data; | ||
| 281 | |||
| 282 | poll_wait(file, &device_client->queue_wait, wait); | ||
| 283 | |||
| 284 | if (device_client->queue_len > 0) | ||
| 285 | return POLLIN | POLLRDNORM; | ||
| 286 | |||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 290 | void bat_device_add_packet(struct device_client *device_client, | ||
| 291 | struct icmp_packet *icmp_packet) | ||
| 292 | { | ||
| 293 | struct device_packet *device_packet; | ||
| 294 | |||
| 295 | device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL); | ||
| 296 | |||
| 297 | if (!device_packet) | ||
| 298 | return; | ||
| 299 | |||
| 300 | INIT_LIST_HEAD(&device_packet->list); | ||
| 301 | memcpy(&device_packet->icmp_packet, icmp_packet, | ||
| 302 | sizeof(struct icmp_packet)); | ||
| 303 | |||
| 304 | spin_lock(&device_client->lock); | ||
| 305 | |||
| 306 | /* while waiting for the lock the device_client could have been | ||
| 307 | * deleted */ | ||
| 308 | if (!device_client_hash[icmp_packet->uid]) { | ||
| 309 | spin_unlock(&device_client->lock); | ||
| 310 | kfree(device_packet); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | list_add_tail(&device_packet->list, &device_client->queue_list); | ||
| 315 | device_client->queue_len++; | ||
| 316 | |||
| 317 | if (device_client->queue_len > 100) { | ||
| 318 | device_packet = list_first_entry(&device_client->queue_list, | ||
| 319 | struct device_packet, list); | ||
| 320 | |||
| 321 | list_del(&device_packet->list); | ||
| 322 | kfree(device_packet); | ||
| 323 | device_client->queue_len--; | ||
| 324 | } | ||
| 325 | |||
| 326 | spin_unlock(&device_client->lock); | ||
| 327 | |||
| 328 | wake_up(&device_client->queue_wait); | ||
| 329 | } | ||
| 330 | |||
| 331 | void bat_device_receive_packet(struct icmp_packet *icmp_packet) | ||
| 332 | { | ||
| 333 | struct device_client *hash = device_client_hash[icmp_packet->uid]; | ||
| 334 | |||
| 335 | if (hash) | ||
| 336 | bat_device_add_packet(hash, icmp_packet); | ||
| 337 | } | ||
diff --git a/drivers/staging/batman-adv/device.h b/drivers/staging/batman-adv/device.h new file mode 100644 index 000000000000..46c0f4496527 --- /dev/null +++ b/drivers/staging/batman-adv/device.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "types.h" | ||
| 23 | |||
| 24 | void bat_device_init(void); | ||
| 25 | int bat_device_setup(void); | ||
| 26 | void bat_device_destroy(void); | ||
| 27 | int bat_device_open(struct inode *inode, struct file *file); | ||
| 28 | int bat_device_release(struct inode *inode, struct file *file); | ||
| 29 | ssize_t bat_device_read(struct file *file, char __user *buf, size_t count, | ||
| 30 | loff_t *ppos); | ||
| 31 | ssize_t bat_device_write(struct file *file, const char __user *buff, | ||
| 32 | size_t len, loff_t *off); | ||
| 33 | unsigned int bat_device_poll(struct file *file, poll_table *wait); | ||
| 34 | void bat_device_add_packet(struct device_client *device_client, | ||
| 35 | struct icmp_packet *icmp_packet); | ||
| 36 | void bat_device_receive_packet(struct icmp_packet *icmp_packet); | ||
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c new file mode 100644 index 000000000000..5ea35da5ee7a --- /dev/null +++ b/drivers/staging/batman-adv/hard-interface.c | |||
| @@ -0,0 +1,451 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "hard-interface.h" | ||
| 24 | #include "log.h" | ||
| 25 | #include "soft-interface.h" | ||
| 26 | #include "send.h" | ||
| 27 | #include "translation-table.h" | ||
| 28 | #include "routing.h" | ||
| 29 | #include "hash.h" | ||
| 30 | #include "compat.h" | ||
| 31 | |||
| 32 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) | ||
| 33 | |||
| 34 | static char avail_ifs; | ||
| 35 | static char active_ifs; | ||
| 36 | |||
| 37 | static void hardif_free_interface(struct rcu_head *rcu); | ||
| 38 | |||
| 39 | static struct batman_if *get_batman_if_by_name(char *name) | ||
| 40 | { | ||
| 41 | struct batman_if *batman_if; | ||
| 42 | |||
| 43 | rcu_read_lock(); | ||
| 44 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 45 | if (strncmp(batman_if->dev, name, IFNAMSIZ) == 0) | ||
| 46 | goto out; | ||
| 47 | } | ||
| 48 | |||
| 49 | batman_if = NULL; | ||
| 50 | |||
| 51 | out: | ||
| 52 | rcu_read_unlock(); | ||
| 53 | return batman_if; | ||
| 54 | } | ||
| 55 | |||
| 56 | int hardif_min_mtu(void) | ||
| 57 | { | ||
| 58 | struct batman_if *batman_if; | ||
| 59 | /* allow big frames if all devices are capable to do so | ||
| 60 | * (have MTU > 1500 + BAT_HEADER_LEN) */ | ||
| 61 | int min_mtu = ETH_DATA_LEN; | ||
| 62 | |||
| 63 | rcu_read_lock(); | ||
| 64 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 65 | if ((batman_if->if_active == IF_ACTIVE) || | ||
| 66 | (batman_if->if_active == IF_TO_BE_ACTIVATED)) | ||
| 67 | min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN, | ||
| 68 | min_mtu); | ||
| 69 | } | ||
| 70 | rcu_read_unlock(); | ||
| 71 | |||
| 72 | return min_mtu; | ||
| 73 | } | ||
| 74 | |||
| 75 | static void check_known_mac_addr(uint8_t *addr) | ||
| 76 | { | ||
| 77 | struct batman_if *batman_if; | ||
| 78 | char mac_string[ETH_STR_LEN]; | ||
| 79 | |||
| 80 | rcu_read_lock(); | ||
| 81 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 82 | if ((batman_if->if_active != IF_ACTIVE) && | ||
| 83 | (batman_if->if_active != IF_TO_BE_ACTIVATED)) | ||
| 84 | continue; | ||
| 85 | |||
| 86 | if (!compare_orig(batman_if->net_dev->dev_addr, addr)) | ||
| 87 | continue; | ||
| 88 | |||
| 89 | addr_to_string(mac_string, addr); | ||
| 90 | debug_log(LOG_TYPE_WARN, "The newly added mac address (%s) already exists on: %s\n", | ||
| 91 | mac_string, batman_if->dev); | ||
| 92 | debug_log(LOG_TYPE_WARN, "It is strongly recommended to keep mac addresses unique to avoid problems!\n"); | ||
| 93 | } | ||
| 94 | rcu_read_unlock(); | ||
| 95 | } | ||
| 96 | |||
| 97 | /* adjusts the MTU if a new interface with a smaller MTU appeared. */ | ||
| 98 | void update_min_mtu(void) | ||
| 99 | { | ||
| 100 | int min_mtu; | ||
| 101 | |||
| 102 | min_mtu = hardif_min_mtu(); | ||
| 103 | if (soft_device->mtu != min_mtu) | ||
| 104 | soft_device->mtu = min_mtu; | ||
| 105 | } | ||
| 106 | |||
| 107 | /* checks if the interface is up. (returns 1 if it is) */ | ||
| 108 | static int hardif_is_interface_up(char *dev) | ||
| 109 | { | ||
| 110 | struct net_device *net_dev; | ||
| 111 | |||
| 112 | /** | ||
| 113 | * if we already have an interface in our interface list and | ||
| 114 | * the current interface is not the primary interface and | ||
| 115 | * the primary interface is not up and | ||
| 116 | * the primary interface has never been up - don't activate any | ||
| 117 | * secondary interface ! | ||
| 118 | */ | ||
| 119 | |||
| 120 | rcu_read_lock(); | ||
| 121 | if ((!list_empty(&if_list)) && | ||
| 122 | strncmp(((struct batman_if *)if_list.next)->dev, dev, IFNAMSIZ) && | ||
| 123 | !(((struct batman_if *)if_list.next)->if_active == IF_ACTIVE) && | ||
| 124 | !(((struct batman_if *)if_list.next)->if_active == IF_TO_BE_ACTIVATED) && | ||
| 125 | (!main_if_was_up())) { | ||
| 126 | rcu_read_unlock(); | ||
| 127 | goto end; | ||
| 128 | } | ||
| 129 | rcu_read_unlock(); | ||
| 130 | |||
| 131 | #ifdef __NET_NET_NAMESPACE_H | ||
| 132 | net_dev = dev_get_by_name(&init_net, dev); | ||
| 133 | #else | ||
| 134 | net_dev = dev_get_by_name(dev); | ||
| 135 | #endif | ||
| 136 | if (!net_dev) | ||
| 137 | goto end; | ||
| 138 | |||
| 139 | if (!(net_dev->flags & IFF_UP)) | ||
| 140 | goto failure; | ||
| 141 | |||
| 142 | dev_put(net_dev); | ||
| 143 | return 1; | ||
| 144 | |||
| 145 | failure: | ||
| 146 | dev_put(net_dev); | ||
| 147 | end: | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | /* deactivates the interface. */ | ||
| 152 | void hardif_deactivate_interface(struct batman_if *batman_if) | ||
| 153 | { | ||
| 154 | if (batman_if->if_active != IF_ACTIVE) | ||
| 155 | return; | ||
| 156 | |||
| 157 | if (batman_if->raw_sock) | ||
| 158 | sock_release(batman_if->raw_sock); | ||
| 159 | |||
| 160 | /** | ||
| 161 | * batman_if->net_dev has been acquired by dev_get_by_name() in | ||
| 162 | * proc_interfaces_write() and has to be unreferenced. | ||
| 163 | */ | ||
| 164 | |||
| 165 | if (batman_if->net_dev) | ||
| 166 | dev_put(batman_if->net_dev); | ||
| 167 | |||
| 168 | batman_if->raw_sock = NULL; | ||
| 169 | batman_if->net_dev = NULL; | ||
| 170 | |||
| 171 | batman_if->if_active = IF_INACTIVE; | ||
| 172 | active_ifs--; | ||
| 173 | |||
| 174 | debug_log(LOG_TYPE_NOTICE, "Interface deactivated: %s\n", | ||
| 175 | batman_if->dev); | ||
| 176 | } | ||
| 177 | |||
| 178 | /* (re)activate given interface. */ | ||
| 179 | static void hardif_activate_interface(struct batman_if *batman_if) | ||
| 180 | { | ||
| 181 | struct sockaddr_ll bind_addr; | ||
| 182 | int retval; | ||
| 183 | |||
| 184 | if (batman_if->if_active != IF_INACTIVE) | ||
| 185 | return; | ||
| 186 | |||
| 187 | #ifdef __NET_NET_NAMESPACE_H | ||
| 188 | batman_if->net_dev = dev_get_by_name(&init_net, batman_if->dev); | ||
| 189 | #else | ||
| 190 | batman_if->net_dev = dev_get_by_name(batman_if->dev); | ||
| 191 | #endif | ||
| 192 | if (!batman_if->net_dev) | ||
| 193 | goto dev_err; | ||
| 194 | |||
| 195 | retval = sock_create_kern(PF_PACKET, SOCK_RAW, | ||
| 196 | __constant_htons(ETH_P_BATMAN), | ||
| 197 | &batman_if->raw_sock); | ||
| 198 | |||
| 199 | if (retval < 0) { | ||
| 200 | debug_log(LOG_TYPE_WARN, "Can't create raw socket: %i\n", | ||
| 201 | retval); | ||
| 202 | goto sock_err; | ||
| 203 | } | ||
| 204 | |||
| 205 | bind_addr.sll_family = AF_PACKET; | ||
| 206 | bind_addr.sll_ifindex = batman_if->net_dev->ifindex; | ||
| 207 | bind_addr.sll_protocol = 0; /* is set by the kernel */ | ||
| 208 | |||
| 209 | retval = kernel_bind(batman_if->raw_sock, | ||
| 210 | (struct sockaddr *)&bind_addr, sizeof(bind_addr)); | ||
| 211 | |||
| 212 | if (retval < 0) { | ||
| 213 | debug_log(LOG_TYPE_WARN, "Can't create bind raw socket: %i\n", | ||
| 214 | retval); | ||
| 215 | goto bind_err; | ||
| 216 | } | ||
| 217 | |||
| 218 | check_known_mac_addr(batman_if->net_dev->dev_addr); | ||
| 219 | |||
| 220 | batman_if->raw_sock->sk->sk_user_data = | ||
| 221 | batman_if->raw_sock->sk->sk_data_ready; | ||
| 222 | batman_if->raw_sock->sk->sk_data_ready = batman_data_ready; | ||
| 223 | |||
| 224 | addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr); | ||
| 225 | |||
| 226 | memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, | ||
| 227 | batman_if->net_dev->dev_addr, ETH_ALEN); | ||
| 228 | memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender, | ||
| 229 | batman_if->net_dev->dev_addr, ETH_ALEN); | ||
| 230 | |||
| 231 | batman_if->if_active = IF_TO_BE_ACTIVATED; | ||
| 232 | active_ifs++; | ||
| 233 | |||
| 234 | /* save the mac address if it is our primary interface */ | ||
| 235 | if (batman_if->if_num == 0) | ||
| 236 | set_main_if_addr(batman_if->net_dev->dev_addr); | ||
| 237 | |||
| 238 | debug_log(LOG_TYPE_NOTICE, "Interface activated: %s\n", | ||
| 239 | batman_if->dev); | ||
| 240 | |||
| 241 | return; | ||
| 242 | |||
| 243 | bind_err: | ||
| 244 | sock_release(batman_if->raw_sock); | ||
| 245 | sock_err: | ||
| 246 | dev_put(batman_if->net_dev); | ||
| 247 | dev_err: | ||
| 248 | batman_if->raw_sock = NULL; | ||
| 249 | batman_if->net_dev = NULL; | ||
| 250 | } | ||
| 251 | |||
| 252 | static void hardif_free_interface(struct rcu_head *rcu) | ||
| 253 | { | ||
| 254 | struct batman_if *batman_if = container_of(rcu, struct batman_if, rcu); | ||
| 255 | |||
| 256 | kfree(batman_if->packet_buff); | ||
| 257 | kfree(batman_if->dev); | ||
| 258 | kfree(batman_if); | ||
| 259 | } | ||
| 260 | |||
| 261 | /** | ||
| 262 | * called by | ||
| 263 | * - echo '' > /proc/.../interfaces | ||
| 264 | * - modprobe -r batman-adv-core | ||
| 265 | */ | ||
| 266 | /* removes and frees all interfaces */ | ||
| 267 | void hardif_remove_interfaces(void) | ||
| 268 | { | ||
| 269 | struct batman_if *batman_if = NULL; | ||
| 270 | |||
| 271 | avail_ifs = 0; | ||
| 272 | |||
| 273 | /* no lock needed - we don't delete somewhere else */ | ||
| 274 | list_for_each_entry(batman_if, &if_list, list) { | ||
| 275 | |||
| 276 | list_del_rcu(&batman_if->list); | ||
| 277 | |||
| 278 | /* first deactivate interface */ | ||
| 279 | if (batman_if->if_active != IF_INACTIVE) | ||
| 280 | hardif_deactivate_interface(batman_if); | ||
| 281 | |||
| 282 | call_rcu(&batman_if->rcu, hardif_free_interface); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | static int resize_orig(struct orig_node *orig_node, int if_num) | ||
| 287 | { | ||
| 288 | void *data_ptr; | ||
| 289 | |||
| 290 | data_ptr = kmalloc((if_num + 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS, | ||
| 291 | GFP_ATOMIC); | ||
| 292 | if (!data_ptr) { | ||
| 293 | debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n"); | ||
| 294 | return -1; | ||
| 295 | } | ||
| 296 | |||
| 297 | memcpy(data_ptr, orig_node->bcast_own, | ||
| 298 | if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS); | ||
| 299 | kfree(orig_node->bcast_own); | ||
| 300 | orig_node->bcast_own = data_ptr; | ||
| 301 | |||
| 302 | data_ptr = kmalloc((if_num + 1) * sizeof(uint8_t), GFP_ATOMIC); | ||
| 303 | if (!data_ptr) { | ||
| 304 | debug_log(LOG_TYPE_WARN, "Can't resize orig: out of memory\n"); | ||
| 305 | return -1; | ||
| 306 | } | ||
| 307 | |||
| 308 | memcpy(data_ptr, orig_node->bcast_own_sum, if_num * sizeof(uint8_t)); | ||
| 309 | kfree(orig_node->bcast_own_sum); | ||
| 310 | orig_node->bcast_own_sum = data_ptr; | ||
| 311 | |||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | |||
| 316 | /* adds an interface the interface list and activate it, if possible */ | ||
| 317 | int hardif_add_interface(char *dev, int if_num) | ||
| 318 | { | ||
| 319 | struct batman_if *batman_if; | ||
| 320 | struct batman_packet *batman_packet; | ||
| 321 | struct orig_node *orig_node; | ||
| 322 | struct hash_it_t *hashit = NULL; | ||
| 323 | |||
| 324 | batman_if = kmalloc(sizeof(struct batman_if), GFP_KERNEL); | ||
| 325 | |||
| 326 | if (!batman_if) { | ||
| 327 | debug_log(LOG_TYPE_WARN, "Can't add interface (%s): out of memory\n", dev); | ||
| 328 | return -1; | ||
| 329 | } | ||
| 330 | |||
| 331 | batman_if->raw_sock = NULL; | ||
| 332 | batman_if->net_dev = NULL; | ||
| 333 | |||
| 334 | if ((if_num == 0) && (num_hna > 0)) | ||
| 335 | batman_if->packet_len = BAT_PACKET_LEN + num_hna * ETH_ALEN; | ||
| 336 | else | ||
| 337 | batman_if->packet_len = BAT_PACKET_LEN; | ||
| 338 | |||
| 339 | batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_KERNEL); | ||
| 340 | |||
| 341 | if (!batman_if->packet_buff) { | ||
| 342 | debug_log(LOG_TYPE_WARN, "Can't add interface packet (%s): out of memory\n", dev); | ||
| 343 | goto out; | ||
| 344 | } | ||
| 345 | |||
| 346 | batman_if->if_num = if_num; | ||
| 347 | batman_if->dev = dev; | ||
| 348 | batman_if->if_active = IF_INACTIVE; | ||
| 349 | INIT_RCU_HEAD(&batman_if->rcu); | ||
| 350 | |||
| 351 | debug_log(LOG_TYPE_NOTICE, "Adding interface: %s\n", dev); | ||
| 352 | avail_ifs++; | ||
| 353 | |||
| 354 | INIT_LIST_HEAD(&batman_if->list); | ||
| 355 | |||
| 356 | batman_packet = (struct batman_packet *)(batman_if->packet_buff); | ||
| 357 | batman_packet->packet_type = BAT_PACKET; | ||
| 358 | batman_packet->version = COMPAT_VERSION; | ||
| 359 | batman_packet->flags = 0x00; | ||
| 360 | batman_packet->ttl = (batman_if->if_num > 0 ? 2 : TTL); | ||
| 361 | batman_packet->flags = 0; | ||
| 362 | batman_packet->tq = TQ_MAX_VALUE; | ||
| 363 | batman_packet->num_hna = 0; | ||
| 364 | |||
| 365 | if (batman_if->packet_len != BAT_PACKET_LEN) { | ||
| 366 | unsigned char *hna_buff; | ||
| 367 | int hna_len; | ||
| 368 | |||
| 369 | hna_buff = batman_if->packet_buff + BAT_PACKET_LEN; | ||
| 370 | hna_len = batman_if->packet_len - BAT_PACKET_LEN; | ||
| 371 | batman_packet->num_hna = hna_local_fill_buffer(hna_buff, | ||
| 372 | hna_len); | ||
| 373 | } | ||
| 374 | |||
| 375 | atomic_set(&batman_if->seqno, 1); | ||
| 376 | |||
| 377 | /* resize all orig nodes because orig_node->bcast_own(_sum) depend on | ||
| 378 | * if_num */ | ||
| 379 | spin_lock(&orig_hash_lock); | ||
| 380 | |||
| 381 | while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { | ||
| 382 | orig_node = hashit->bucket->data; | ||
| 383 | if (resize_orig(orig_node, if_num) == -1) { | ||
| 384 | spin_unlock(&orig_hash_lock); | ||
| 385 | goto out; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | spin_unlock(&orig_hash_lock); | ||
| 390 | |||
| 391 | if (!hardif_is_interface_up(batman_if->dev)) | ||
| 392 | debug_log(LOG_TYPE_WARN, "Not using interface %s (retrying later): interface not active\n", batman_if->dev); | ||
| 393 | else | ||
| 394 | hardif_activate_interface(batman_if); | ||
| 395 | |||
| 396 | list_add_tail_rcu(&batman_if->list, &if_list); | ||
| 397 | |||
| 398 | /* begin sending originator messages on that interface */ | ||
| 399 | schedule_own_packet(batman_if); | ||
| 400 | return 1; | ||
| 401 | |||
| 402 | out: | ||
| 403 | if (batman_if->packet_buff) | ||
| 404 | kfree(batman_if->packet_buff); | ||
| 405 | kfree(batman_if); | ||
| 406 | kfree(dev); | ||
| 407 | return -1; | ||
| 408 | } | ||
| 409 | |||
| 410 | char hardif_get_active_if_num(void) | ||
| 411 | { | ||
| 412 | return active_ifs; | ||
| 413 | } | ||
| 414 | |||
| 415 | static int hard_if_event(struct notifier_block *this, | ||
| 416 | unsigned long event, void *ptr) | ||
| 417 | { | ||
| 418 | struct net_device *dev = (struct net_device *)ptr; | ||
| 419 | struct batman_if *batman_if = get_batman_if_by_name(dev->name); | ||
| 420 | |||
| 421 | if (!batman_if) | ||
| 422 | goto out; | ||
| 423 | |||
| 424 | switch (event) { | ||
| 425 | case NETDEV_GOING_DOWN: | ||
| 426 | case NETDEV_DOWN: | ||
| 427 | case NETDEV_UNREGISTER: | ||
| 428 | hardif_deactivate_interface(batman_if); | ||
| 429 | break; | ||
| 430 | case NETDEV_UP: | ||
| 431 | hardif_activate_interface(batman_if); | ||
| 432 | if ((atomic_read(&module_state) == MODULE_INACTIVE) && | ||
| 433 | (hardif_get_active_if_num() > 0)) { | ||
| 434 | activate_module(); | ||
| 435 | } | ||
| 436 | break; | ||
| 437 | /* NETDEV_CHANGEADDR - mac address change - what are we doing here ? */ | ||
| 438 | default: | ||
| 439 | /* debug_log(LOG_TYPE_CRIT, "hard_if_event: %s %i\n", dev->name, event); */ | ||
| 440 | break; | ||
| 441 | }; | ||
| 442 | |||
| 443 | update_min_mtu(); | ||
| 444 | |||
| 445 | out: | ||
| 446 | return NOTIFY_DONE; | ||
| 447 | } | ||
| 448 | |||
| 449 | struct notifier_block hard_if_notifier = { | ||
| 450 | .notifier_call = hard_if_event, | ||
| 451 | }; | ||
diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h new file mode 100644 index 000000000000..742358c00c0e --- /dev/null +++ b/drivers/staging/batman-adv/hard-interface.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #define IF_INACTIVE 0 | ||
| 23 | #define IF_ACTIVE 1 | ||
| 24 | /* #define IF_TO_BE_DEACTIVATED 2 - not needed anymore */ | ||
| 25 | #define IF_TO_BE_ACTIVATED 3 | ||
| 26 | |||
| 27 | extern struct notifier_block hard_if_notifier; | ||
| 28 | |||
| 29 | void hardif_remove_interfaces(void); | ||
| 30 | int hardif_add_interface(char *dev, int if_num); | ||
| 31 | void hardif_deactivate_interface(struct batman_if *batman_if); | ||
| 32 | char hardif_get_active_if_num(void); | ||
| 33 | void hardif_check_interfaces_status(void); | ||
| 34 | void hardif_check_interfaces_status_wq(struct work_struct *work); | ||
| 35 | int hardif_min_mtu(void); | ||
| 36 | void update_min_mtu(void); | ||
diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c new file mode 100644 index 000000000000..61cb4a20ebca --- /dev/null +++ b/drivers/staging/batman-adv/hash.c | |||
| @@ -0,0 +1,313 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2006-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Simon Wunderlich, Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "hash.h" | ||
| 24 | |||
| 25 | /* clears the hash */ | ||
| 26 | void hash_init(struct hashtable_t *hash) | ||
| 27 | { | ||
| 28 | int i; | ||
| 29 | |||
| 30 | hash->elements = 0; | ||
| 31 | |||
| 32 | for (i = 0 ; i < hash->size; i++) | ||
| 33 | hash->table[i] = NULL; | ||
| 34 | } | ||
| 35 | |||
| 36 | /* remove the hash structure. if hashdata_free_cb != NULL, this function will be | ||
| 37 | * called to remove the elements inside of the hash. if you don't remove the | ||
| 38 | * elements, memory might be leaked. */ | ||
| 39 | void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb) | ||
| 40 | { | ||
| 41 | struct element_t *bucket, *last_bucket; | ||
| 42 | int i; | ||
| 43 | |||
| 44 | for (i = 0; i < hash->size; i++) { | ||
| 45 | bucket = hash->table[i]; | ||
| 46 | |||
| 47 | while (bucket != NULL) { | ||
| 48 | if (free_cb != NULL) | ||
| 49 | free_cb(bucket->data); | ||
| 50 | |||
| 51 | last_bucket = bucket; | ||
| 52 | bucket = bucket->next; | ||
| 53 | kfree(last_bucket); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | hash_destroy(hash); | ||
| 58 | } | ||
| 59 | |||
| 60 | /* free only the hashtable and the hash itself. */ | ||
| 61 | void hash_destroy(struct hashtable_t *hash) | ||
| 62 | { | ||
| 63 | kfree(hash->table); | ||
| 64 | kfree(hash); | ||
| 65 | } | ||
| 66 | |||
| 67 | /* iterate though the hash. first element is selected with iter_in NULL. use | ||
| 68 | * the returned iterator to access the elements until hash_it_t returns NULL. */ | ||
| 69 | struct hash_it_t *hash_iterate(struct hashtable_t *hash, | ||
| 70 | struct hash_it_t *iter_in) | ||
| 71 | { | ||
| 72 | struct hash_it_t *iter; | ||
| 73 | |||
| 74 | if (!hash) | ||
| 75 | return NULL; | ||
| 76 | |||
| 77 | if (iter_in == NULL) { | ||
| 78 | iter = kmalloc(sizeof(struct hash_it_t), GFP_ATOMIC); | ||
| 79 | iter->index = -1; | ||
| 80 | iter->bucket = NULL; | ||
| 81 | iter->prev_bucket = NULL; | ||
| 82 | } else { | ||
| 83 | iter = iter_in; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* sanity checks first (if our bucket got deleted in the last | ||
| 87 | * iteration): */ | ||
| 88 | if (iter->bucket != NULL) { | ||
| 89 | if (iter->first_bucket != NULL) { | ||
| 90 | /* we're on the first element and it got removed after | ||
| 91 | * the last iteration. */ | ||
| 92 | if ((*iter->first_bucket) != iter->bucket) { | ||
| 93 | /* there are still other elements in the list */ | ||
| 94 | if ((*iter->first_bucket) != NULL) { | ||
| 95 | iter->prev_bucket = NULL; | ||
| 96 | iter->bucket = (*iter->first_bucket); | ||
| 97 | iter->first_bucket = | ||
| 98 | &hash->table[iter->index]; | ||
| 99 | return iter; | ||
| 100 | } else { | ||
| 101 | iter->bucket = NULL; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } else if (iter->prev_bucket != NULL) { | ||
| 105 | /* | ||
| 106 | * we're not on the first element, and the bucket got | ||
| 107 | * removed after the last iteration. the last bucket's | ||
| 108 | * next pointer is not pointing to our actual bucket | ||
| 109 | * anymore. select the next. | ||
| 110 | */ | ||
| 111 | if (iter->prev_bucket->next != iter->bucket) | ||
| 112 | iter->bucket = iter->prev_bucket; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | /* now as we are sane, select the next one if there is some */ | ||
| 117 | if (iter->bucket != NULL) { | ||
| 118 | if (iter->bucket->next != NULL) { | ||
| 119 | iter->prev_bucket = iter->bucket; | ||
| 120 | iter->bucket = iter->bucket->next; | ||
| 121 | iter->first_bucket = NULL; | ||
| 122 | return iter; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | /* if not returned yet, we've reached the last one on the index and have | ||
| 127 | * to search forward */ | ||
| 128 | iter->index++; | ||
| 129 | /* go through the entries of the hash table */ | ||
| 130 | while (iter->index < hash->size) { | ||
| 131 | if ((hash->table[iter->index]) != NULL) { | ||
| 132 | iter->prev_bucket = NULL; | ||
| 133 | iter->bucket = hash->table[iter->index]; | ||
| 134 | iter->first_bucket = &hash->table[iter->index]; | ||
| 135 | return iter; | ||
| 136 | } else { | ||
| 137 | iter->index++; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | /* nothing to iterate over anymore */ | ||
| 142 | kfree(iter); | ||
| 143 | return NULL; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* allocates and clears the hash */ | ||
| 147 | struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, | ||
| 148 | hashdata_choose_cb choose) | ||
| 149 | { | ||
| 150 | struct hashtable_t *hash; | ||
| 151 | |||
| 152 | hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC); | ||
| 153 | |||
| 154 | if (hash == NULL) | ||
| 155 | return NULL; | ||
| 156 | |||
| 157 | hash->size = size; | ||
| 158 | hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC); | ||
| 159 | |||
| 160 | if (hash->table == NULL) { | ||
| 161 | kfree(hash); | ||
| 162 | return NULL; | ||
| 163 | } | ||
| 164 | |||
| 165 | hash_init(hash); | ||
| 166 | |||
| 167 | hash->compare = compare; | ||
| 168 | hash->choose = choose; | ||
| 169 | |||
| 170 | return hash; | ||
| 171 | } | ||
| 172 | |||
| 173 | /* adds data to the hashtable. returns 0 on success, -1 on error */ | ||
| 174 | int hash_add(struct hashtable_t *hash, void *data) | ||
| 175 | { | ||
| 176 | int index; | ||
| 177 | struct element_t *bucket, *prev_bucket = NULL; | ||
| 178 | |||
| 179 | if (!hash) | ||
| 180 | return -1; | ||
| 181 | |||
| 182 | index = hash->choose(data, hash->size); | ||
| 183 | bucket = hash->table[index]; | ||
| 184 | |||
| 185 | while (bucket != NULL) { | ||
| 186 | if (hash->compare(bucket->data, data)) | ||
| 187 | return -1; | ||
| 188 | |||
| 189 | prev_bucket = bucket; | ||
| 190 | bucket = bucket->next; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* found the tail of the list, add new element */ | ||
| 194 | bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); | ||
| 195 | |||
| 196 | if (bucket == NULL) | ||
| 197 | return -1; | ||
| 198 | |||
| 199 | bucket->data = data; | ||
| 200 | bucket->next = NULL; | ||
| 201 | |||
| 202 | /* and link it */ | ||
| 203 | if (prev_bucket == NULL) | ||
| 204 | hash->table[index] = bucket; | ||
| 205 | else | ||
| 206 | prev_bucket->next = bucket; | ||
| 207 | |||
| 208 | hash->elements++; | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | /* finds data, based on the key in keydata. returns the found data on success, | ||
| 213 | * or NULL on error */ | ||
| 214 | void *hash_find(struct hashtable_t *hash, void *keydata) | ||
| 215 | { | ||
| 216 | int index; | ||
| 217 | struct element_t *bucket; | ||
| 218 | |||
| 219 | if (!hash) | ||
| 220 | return NULL; | ||
| 221 | |||
| 222 | index = hash->choose(keydata , hash->size); | ||
| 223 | bucket = hash->table[index]; | ||
| 224 | |||
| 225 | while (bucket != NULL) { | ||
| 226 | if (hash->compare(bucket->data, keydata)) | ||
| 227 | return bucket->data; | ||
| 228 | |||
| 229 | bucket = bucket->next; | ||
| 230 | } | ||
| 231 | |||
| 232 | return NULL; | ||
| 233 | } | ||
| 234 | |||
| 235 | /* remove bucket (this might be used in hash_iterate() if you already found the | ||
| 236 | * bucket you want to delete and don't need the overhead to find it again with | ||
| 237 | * hash_remove(). But usually, you don't want to use this function, as it | ||
| 238 | * fiddles with hash-internals. */ | ||
| 239 | void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) | ||
| 240 | { | ||
| 241 | void *data_save; | ||
| 242 | |||
| 243 | data_save = hash_it_t->bucket->data; | ||
| 244 | |||
| 245 | if (hash_it_t->prev_bucket != NULL) | ||
| 246 | hash_it_t->prev_bucket->next = hash_it_t->bucket->next; | ||
| 247 | else if (hash_it_t->first_bucket != NULL) | ||
| 248 | (*hash_it_t->first_bucket) = hash_it_t->bucket->next; | ||
| 249 | |||
| 250 | kfree(hash_it_t->bucket); | ||
| 251 | hash->elements--; | ||
| 252 | |||
| 253 | return data_save; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* removes data from hash, if found. returns pointer do data on success, so you | ||
| 257 | * can remove the used structure yourself, or NULL on error . data could be the | ||
| 258 | * structure you use with just the key filled, we just need the key for | ||
| 259 | * comparing. */ | ||
| 260 | void *hash_remove(struct hashtable_t *hash, void *data) | ||
| 261 | { | ||
| 262 | struct hash_it_t hash_it_t; | ||
| 263 | |||
| 264 | hash_it_t.index = hash->choose(data, hash->size); | ||
| 265 | hash_it_t.bucket = hash->table[hash_it_t.index]; | ||
| 266 | hash_it_t.prev_bucket = NULL; | ||
| 267 | |||
| 268 | while (hash_it_t.bucket != NULL) { | ||
| 269 | if (hash->compare(hash_it_t.bucket->data, data)) { | ||
| 270 | hash_it_t.first_bucket = | ||
| 271 | (hash_it_t.bucket == | ||
| 272 | hash->table[hash_it_t.index] ? | ||
| 273 | &hash->table[hash_it_t.index] : NULL); | ||
| 274 | return hash_remove_bucket(hash, &hash_it_t); | ||
| 275 | } | ||
| 276 | |||
| 277 | hash_it_t.prev_bucket = hash_it_t.bucket; | ||
| 278 | hash_it_t.bucket = hash_it_t.bucket->next; | ||
| 279 | } | ||
| 280 | |||
| 281 | return NULL; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* resize the hash, returns the pointer to the new hash or NULL on | ||
| 285 | * error. removes the old hash on success. */ | ||
| 286 | struct hashtable_t *hash_resize(struct hashtable_t *hash, int size) | ||
| 287 | { | ||
| 288 | struct hashtable_t *new_hash; | ||
| 289 | struct element_t *bucket; | ||
| 290 | int i; | ||
| 291 | |||
| 292 | /* initialize a new hash with the new size */ | ||
| 293 | new_hash = hash_new(size, hash->compare, hash->choose); | ||
| 294 | |||
| 295 | if (new_hash == NULL) | ||
| 296 | return NULL; | ||
| 297 | |||
| 298 | /* copy the elements */ | ||
| 299 | for (i = 0; i < hash->size; i++) { | ||
| 300 | bucket = hash->table[i]; | ||
| 301 | |||
| 302 | while (bucket != NULL) { | ||
| 303 | hash_add(new_hash, bucket->data); | ||
| 304 | bucket = bucket->next; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | /* remove hash and eventual overflow buckets but not the content | ||
| 309 | * itself. */ | ||
| 310 | hash_delete(hash, NULL); | ||
| 311 | |||
| 312 | return new_hash; | ||
| 313 | } | ||
diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h new file mode 100644 index 000000000000..bb60f082be6a --- /dev/null +++ b/drivers/staging/batman-adv/hash.h | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2006-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Simon Wunderlich, Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifndef _BATMAN_HASH_H | ||
| 23 | #define _BATMAN_HASH_H | ||
| 24 | |||
| 25 | typedef int (*hashdata_compare_cb)(void *, void *); | ||
| 26 | typedef int (*hashdata_choose_cb)(void *, int); | ||
| 27 | typedef void (*hashdata_free_cb)(void *); | ||
| 28 | |||
| 29 | struct element_t { | ||
| 30 | void *data; /* pointer to the data */ | ||
| 31 | struct element_t *next; /* overflow bucket pointer */ | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct hash_it_t { | ||
| 35 | int index; | ||
| 36 | struct element_t *bucket; | ||
| 37 | struct element_t *prev_bucket; | ||
| 38 | struct element_t **first_bucket; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct hashtable_t { | ||
| 42 | struct element_t **table; /* the hashtable itself, with the buckets */ | ||
| 43 | int elements; /* number of elements registered */ | ||
| 44 | int size; /* size of hashtable */ | ||
| 45 | hashdata_compare_cb compare;/* callback to a compare function. should | ||
| 46 | * compare 2 element datas for their keys, | ||
| 47 | * return 0 if same and not 0 if not | ||
| 48 | * same */ | ||
| 49 | hashdata_choose_cb choose; /* the hashfunction, should return an index | ||
| 50 | * based on the key in the data of the first | ||
| 51 | * argument and the size the second */ | ||
| 52 | }; | ||
| 53 | |||
| 54 | /* clears the hash */ | ||
| 55 | void hash_init(struct hashtable_t *hash); | ||
| 56 | |||
| 57 | /* allocates and clears the hash */ | ||
| 58 | struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, | ||
| 59 | hashdata_choose_cb choose); | ||
| 60 | |||
| 61 | /* remove bucket (this might be used in hash_iterate() if you already found the | ||
| 62 | * bucket you want to delete and don't need the overhead to find it again with | ||
| 63 | * hash_remove(). But usually, you don't want to use this function, as it | ||
| 64 | * fiddles with hash-internals. */ | ||
| 65 | void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t); | ||
| 66 | |||
| 67 | /* remove the hash structure. if hashdata_free_cb != NULL, this function will be | ||
| 68 | * called to remove the elements inside of the hash. if you don't remove the | ||
| 69 | * elements, memory might be leaked. */ | ||
| 70 | void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb); | ||
| 71 | |||
| 72 | /* free only the hashtable and the hash itself. */ | ||
| 73 | void hash_destroy(struct hashtable_t *hash); | ||
| 74 | |||
| 75 | /* adds data to the hashtable. returns 0 on success, -1 on error */ | ||
| 76 | int hash_add(struct hashtable_t *hash, void *data); | ||
| 77 | |||
| 78 | /* removes data from hash, if found. returns pointer do data on success, so you | ||
| 79 | * can remove the used structure yourself, or NULL on error . data could be the | ||
| 80 | * structure you use with just the key filled, we just need the key for | ||
| 81 | * comparing. */ | ||
| 82 | void *hash_remove(struct hashtable_t *hash, void *data); | ||
| 83 | |||
| 84 | /* finds data, based on the key in keydata. returns the found data on success, | ||
| 85 | * or NULL on error */ | ||
| 86 | void *hash_find(struct hashtable_t *hash, void *keydata); | ||
| 87 | |||
| 88 | /* resize the hash, returns the pointer to the new hash or NULL on | ||
| 89 | * error. removes the old hash on success */ | ||
| 90 | struct hashtable_t *hash_resize(struct hashtable_t *hash, int size); | ||
| 91 | |||
| 92 | /* iterate though the hash. first element is selected with iter_in NULL. use | ||
| 93 | * the returned iterator to access the elements until hash_it_t returns NULL. */ | ||
| 94 | struct hash_it_t *hash_iterate(struct hashtable_t *hash, | ||
| 95 | struct hash_it_t *iter_in); | ||
| 96 | |||
| 97 | /* print the hash table for debugging */ | ||
| 98 | void hash_debug(struct hashtable_t *hash); | ||
| 99 | #endif | ||
diff --git a/drivers/staging/batman-adv/log.c b/drivers/staging/batman-adv/log.c new file mode 100644 index 000000000000..f37c7f01a9f5 --- /dev/null +++ b/drivers/staging/batman-adv/log.c | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "log.h" | ||
| 24 | |||
| 25 | #define LOG_BUF_MASK (log_buf_len-1) | ||
| 26 | #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) | ||
| 27 | |||
| 28 | static char log_buf[LOG_BUF_LEN]; | ||
| 29 | static int log_buf_len = LOG_BUF_LEN; | ||
| 30 | static unsigned long log_start; | ||
| 31 | static unsigned long log_end; | ||
| 32 | uint8_t log_level; | ||
| 33 | |||
| 34 | static DEFINE_SPINLOCK(logbuf_lock); | ||
| 35 | |||
| 36 | const struct file_operations proc_log_operations = { | ||
| 37 | .open = log_open, | ||
| 38 | .release = log_release, | ||
| 39 | .read = log_read, | ||
| 40 | .write = log_write, | ||
| 41 | .poll = log_poll, | ||
| 42 | }; | ||
| 43 | |||
| 44 | static DECLARE_WAIT_QUEUE_HEAD(log_wait); | ||
| 45 | |||
| 46 | static void emit_log_char(char c) | ||
| 47 | { | ||
| 48 | LOG_BUF(log_end) = c; | ||
| 49 | log_end++; | ||
| 50 | |||
| 51 | if (log_end - log_start > log_buf_len) | ||
| 52 | log_start = log_end - log_buf_len; | ||
| 53 | } | ||
| 54 | |||
| 55 | static int fdebug_log(char *fmt, ...) | ||
| 56 | { | ||
| 57 | int printed_len; | ||
| 58 | char *p; | ||
| 59 | va_list args; | ||
| 60 | static char debug_log_buf[256]; | ||
| 61 | unsigned long flags; | ||
| 62 | |||
| 63 | spin_lock_irqsave(&logbuf_lock, flags); | ||
| 64 | va_start(args, fmt); | ||
| 65 | printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, | ||
| 66 | args); | ||
| 67 | va_end(args); | ||
| 68 | |||
| 69 | for (p = debug_log_buf; *p != 0; p++) | ||
| 70 | emit_log_char(*p); | ||
| 71 | |||
| 72 | spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 73 | |||
| 74 | wake_up(&log_wait); | ||
| 75 | |||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | int debug_log(int type, char *fmt, ...) | ||
| 80 | { | ||
| 81 | va_list args; | ||
| 82 | int retval = 0; | ||
| 83 | char tmp_log_buf[256]; | ||
| 84 | |||
| 85 | /* only critical information get into the official kernel log */ | ||
| 86 | if (type == LOG_TYPE_CRIT) { | ||
| 87 | va_start(args, fmt); | ||
| 88 | vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); | ||
| 89 | printk(KERN_ERR "batman-adv: %s", tmp_log_buf); | ||
| 90 | va_end(args); | ||
| 91 | } | ||
| 92 | |||
| 93 | if ((type == LOG_TYPE_CRIT) || (log_level & type)) { | ||
| 94 | va_start(args, fmt); | ||
| 95 | vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); | ||
| 96 | fdebug_log("[%10u] %s", (jiffies / HZ), tmp_log_buf); | ||
| 97 | va_end(args); | ||
| 98 | } | ||
| 99 | |||
| 100 | return retval; | ||
| 101 | } | ||
| 102 | |||
| 103 | int log_open(struct inode *inode, struct file *file) | ||
| 104 | { | ||
| 105 | inc_module_count(); | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | int log_release(struct inode *inode, struct file *file) | ||
| 110 | { | ||
| 111 | dec_module_count(); | ||
| 112 | return 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | ssize_t log_read(struct file *file, char __user *buf, size_t count, | ||
| 116 | loff_t *ppos) | ||
| 117 | { | ||
| 118 | int error, i = 0; | ||
| 119 | char c; | ||
| 120 | unsigned long flags; | ||
| 121 | |||
| 122 | if ((file->f_flags & O_NONBLOCK) && !(log_end - log_start)) | ||
| 123 | return -EAGAIN; | ||
| 124 | |||
| 125 | if ((!buf) || (count < 0)) | ||
| 126 | return -EINVAL; | ||
| 127 | |||
| 128 | if (count == 0) | ||
| 129 | return 0; | ||
| 130 | |||
| 131 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
| 132 | return -EFAULT; | ||
| 133 | |||
| 134 | error = wait_event_interruptible(log_wait, (log_start - log_end)); | ||
| 135 | |||
| 136 | if (error) | ||
| 137 | return error; | ||
| 138 | |||
| 139 | spin_lock_irqsave(&logbuf_lock, flags); | ||
| 140 | |||
| 141 | while ((!error) && (log_start != log_end) && (i < count)) { | ||
| 142 | c = LOG_BUF(log_start); | ||
| 143 | |||
| 144 | log_start++; | ||
| 145 | |||
| 146 | spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 147 | |||
| 148 | error = __put_user(c, buf); | ||
| 149 | |||
| 150 | spin_lock_irqsave(&logbuf_lock, flags); | ||
| 151 | |||
| 152 | buf++; | ||
| 153 | i++; | ||
| 154 | |||
| 155 | } | ||
| 156 | |||
| 157 | spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 158 | |||
| 159 | if (!error) | ||
| 160 | return i; | ||
| 161 | |||
| 162 | return error; | ||
| 163 | } | ||
| 164 | |||
| 165 | ssize_t log_write(struct file *file, const char __user *buf, size_t count, | ||
| 166 | loff_t *ppos) | ||
| 167 | { | ||
| 168 | return count; | ||
| 169 | } | ||
| 170 | |||
| 171 | unsigned int log_poll(struct file *file, poll_table *wait) | ||
| 172 | { | ||
| 173 | poll_wait(file, &log_wait, wait); | ||
| 174 | |||
| 175 | if (log_end - log_start) | ||
| 176 | return POLLIN | POLLRDNORM; | ||
| 177 | |||
| 178 | return 0; | ||
| 179 | } | ||
diff --git a/drivers/staging/batman-adv/log.h b/drivers/staging/batman-adv/log.h new file mode 100644 index 000000000000..780e3abb48f9 --- /dev/null +++ b/drivers/staging/batman-adv/log.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | extern const struct file_operations proc_log_operations; | ||
| 23 | extern uint8_t log_level; | ||
| 24 | |||
| 25 | int debug_log(int type, char *fmt, ...); | ||
| 26 | int log_open(struct inode *inode, struct file *file); | ||
| 27 | int log_release(struct inode *inode, struct file *file); | ||
| 28 | ssize_t log_read(struct file *file, char __user *buf, size_t count, | ||
| 29 | loff_t *ppos); | ||
| 30 | ssize_t log_write(struct file *file, const char __user *buf, size_t count, | ||
| 31 | loff_t *ppos); | ||
| 32 | unsigned int log_poll(struct file *file, poll_table *wait); | ||
diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c new file mode 100644 index 000000000000..bb89bfc5dda6 --- /dev/null +++ b/drivers/staging/batman-adv/main.c | |||
| @@ -0,0 +1,286 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "proc.h" | ||
| 24 | #include "log.h" | ||
| 25 | #include "routing.h" | ||
| 26 | #include "send.h" | ||
| 27 | #include "soft-interface.h" | ||
| 28 | #include "device.h" | ||
| 29 | #include "translation-table.h" | ||
| 30 | #include "hard-interface.h" | ||
| 31 | #include "types.h" | ||
| 32 | #include "vis.h" | ||
| 33 | #include "hash.h" | ||
| 34 | #include "compat.h" | ||
| 35 | |||
| 36 | struct list_head if_list; | ||
| 37 | struct hlist_head forw_bat_list; | ||
| 38 | struct hlist_head forw_bcast_list; | ||
| 39 | struct hashtable_t *orig_hash; | ||
| 40 | |||
| 41 | DEFINE_SPINLOCK(orig_hash_lock); | ||
| 42 | DEFINE_SPINLOCK(forw_bat_list_lock); | ||
| 43 | DEFINE_SPINLOCK(forw_bcast_list_lock); | ||
| 44 | |||
| 45 | atomic_t originator_interval; | ||
| 46 | atomic_t vis_interval; | ||
| 47 | atomic_t aggregation_enabled; | ||
| 48 | int16_t num_hna; | ||
| 49 | int16_t num_ifs; | ||
| 50 | |||
| 51 | struct net_device *soft_device; | ||
| 52 | |||
| 53 | static struct task_struct *kthread_task; | ||
| 54 | |||
| 55 | unsigned char broadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
| 56 | atomic_t module_state; | ||
| 57 | |||
| 58 | struct workqueue_struct *bat_event_workqueue; | ||
| 59 | |||
| 60 | int init_module(void) | ||
| 61 | { | ||
| 62 | int retval; | ||
| 63 | |||
| 64 | INIT_LIST_HEAD(&if_list); | ||
| 65 | INIT_HLIST_HEAD(&forw_bat_list); | ||
| 66 | INIT_HLIST_HEAD(&forw_bcast_list); | ||
| 67 | |||
| 68 | atomic_set(&module_state, MODULE_INACTIVE); | ||
| 69 | |||
| 70 | atomic_set(&originator_interval, 1000); | ||
| 71 | atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only | ||
| 72 | * for debugging now. */ | ||
| 73 | atomic_set(&aggregation_enabled, 1); | ||
| 74 | |||
| 75 | /* the name should not be longer than 10 chars - see | ||
| 76 | * http://lwn.net/Articles/23634/ */ | ||
| 77 | bat_event_workqueue = create_singlethread_workqueue("bat_events"); | ||
| 78 | |||
| 79 | if (!bat_event_workqueue) | ||
| 80 | return -ENOMEM; | ||
| 81 | |||
| 82 | retval = setup_procfs(); | ||
| 83 | if (retval < 0) | ||
| 84 | return retval; | ||
| 85 | |||
| 86 | bat_device_init(); | ||
| 87 | |||
| 88 | /* initialize layer 2 interface */ | ||
| 89 | soft_device = alloc_netdev(sizeof(struct bat_priv) , "bat%d", | ||
| 90 | interface_setup); | ||
| 91 | |||
| 92 | if (!soft_device) { | ||
| 93 | debug_log(LOG_TYPE_CRIT, "Unable to allocate the batman interface\n"); | ||
| 94 | goto end; | ||
| 95 | } | ||
| 96 | |||
| 97 | retval = register_netdev(soft_device); | ||
| 98 | |||
| 99 | if (retval < 0) { | ||
| 100 | debug_log(LOG_TYPE_CRIT, "Unable to register the batman interface: %i\n", retval); | ||
| 101 | goto free_soft_device; | ||
| 102 | } | ||
| 103 | |||
| 104 | register_netdevice_notifier(&hard_if_notifier); | ||
| 105 | |||
| 106 | debug_log(LOG_TYPE_CRIT, "B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded \n", | ||
| 107 | SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION); | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | |||
| 111 | free_soft_device: | ||
| 112 | free_netdev(soft_device); | ||
| 113 | soft_device = NULL; | ||
| 114 | end: | ||
| 115 | return -ENOMEM; | ||
| 116 | } | ||
| 117 | |||
| 118 | void cleanup_module(void) | ||
| 119 | { | ||
| 120 | shutdown_module(); | ||
| 121 | |||
| 122 | if (soft_device) { | ||
| 123 | unregister_netdev(soft_device); | ||
| 124 | soft_device = NULL; | ||
| 125 | } | ||
| 126 | |||
| 127 | unregister_netdevice_notifier(&hard_if_notifier); | ||
| 128 | cleanup_procfs(); | ||
| 129 | |||
| 130 | destroy_workqueue(bat_event_workqueue); | ||
| 131 | bat_event_workqueue = NULL; | ||
| 132 | } | ||
| 133 | |||
| 134 | /* activates the module, creates bat device, starts timer ... */ | ||
| 135 | void activate_module(void) | ||
| 136 | { | ||
| 137 | if (originator_init() < 1) | ||
| 138 | goto err; | ||
| 139 | |||
| 140 | if (hna_local_init() < 1) | ||
| 141 | goto err; | ||
| 142 | |||
| 143 | if (hna_global_init() < 1) | ||
| 144 | goto err; | ||
| 145 | |||
| 146 | hna_local_add(soft_device->dev_addr); | ||
| 147 | |||
| 148 | if (bat_device_setup() < 1) | ||
| 149 | goto end; | ||
| 150 | |||
| 151 | if (vis_init() < 1) | ||
| 152 | goto err; | ||
| 153 | |||
| 154 | /* (re)start kernel thread for packet processing */ | ||
| 155 | if (!kthread_task) { | ||
| 156 | kthread_task = kthread_run(packet_recv_thread, NULL, "batman-adv"); | ||
| 157 | |||
| 158 | if (IS_ERR(kthread_task)) { | ||
| 159 | debug_log(LOG_TYPE_CRIT, "Unable to start packet receive thread\n"); | ||
| 160 | kthread_task = NULL; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | update_min_mtu(); | ||
| 165 | atomic_set(&module_state, MODULE_ACTIVE); | ||
| 166 | goto end; | ||
| 167 | |||
| 168 | err: | ||
| 169 | debug_log(LOG_TYPE_CRIT, "Unable to allocate memory for mesh information structures: out of mem ?\n"); | ||
| 170 | shutdown_module(); | ||
| 171 | end: | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | |||
| 175 | /* shuts down the whole module.*/ | ||
| 176 | void shutdown_module(void) | ||
| 177 | { | ||
| 178 | atomic_set(&module_state, MODULE_DEACTIVATING); | ||
| 179 | |||
| 180 | purge_outstanding_packets(); | ||
| 181 | flush_workqueue(bat_event_workqueue); | ||
| 182 | |||
| 183 | vis_quit(); | ||
| 184 | |||
| 185 | /* deactivate kernel thread for packet processing (if running) */ | ||
| 186 | if (kthread_task) { | ||
| 187 | atomic_set(&exit_cond, 1); | ||
| 188 | wake_up_interruptible(&thread_wait); | ||
| 189 | kthread_stop(kthread_task); | ||
| 190 | |||
| 191 | kthread_task = NULL; | ||
| 192 | } | ||
| 193 | |||
| 194 | originator_free(); | ||
| 195 | |||
| 196 | hna_local_free(); | ||
| 197 | hna_global_free(); | ||
| 198 | |||
| 199 | synchronize_net(); | ||
| 200 | bat_device_destroy(); | ||
| 201 | |||
| 202 | hardif_remove_interfaces(); | ||
| 203 | synchronize_rcu(); | ||
| 204 | atomic_set(&module_state, MODULE_INACTIVE); | ||
| 205 | } | ||
| 206 | |||
| 207 | void inc_module_count(void) | ||
| 208 | { | ||
| 209 | try_module_get(THIS_MODULE); | ||
| 210 | } | ||
| 211 | |||
| 212 | void dec_module_count(void) | ||
| 213 | { | ||
| 214 | module_put(THIS_MODULE); | ||
| 215 | } | ||
| 216 | |||
| 217 | int addr_to_string(char *buff, uint8_t *addr) | ||
| 218 | { | ||
| 219 | return sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x", | ||
| 220 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | ||
| 221 | } | ||
| 222 | |||
| 223 | /* returns 1 if they are the same originator */ | ||
| 224 | |||
| 225 | int compare_orig(void *data1, void *data2) | ||
| 226 | { | ||
| 227 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | ||
| 228 | } | ||
| 229 | |||
| 230 | /* hashfunction to choose an entry in a hash table of given size */ | ||
| 231 | /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ | ||
| 232 | int choose_orig(void *data, int32_t size) | ||
| 233 | { | ||
| 234 | unsigned char *key = data; | ||
| 235 | uint32_t hash = 0; | ||
| 236 | size_t i; | ||
| 237 | |||
| 238 | for (i = 0; i < 6; i++) { | ||
| 239 | hash += key[i]; | ||
| 240 | hash += (hash << 10); | ||
| 241 | hash ^= (hash >> 6); | ||
| 242 | } | ||
| 243 | |||
| 244 | hash += (hash << 3); | ||
| 245 | hash ^= (hash >> 11); | ||
| 246 | hash += (hash << 15); | ||
| 247 | |||
| 248 | return hash % size; | ||
| 249 | } | ||
| 250 | |||
| 251 | int is_my_mac(uint8_t *addr) | ||
| 252 | { | ||
| 253 | struct batman_if *batman_if; | ||
| 254 | rcu_read_lock(); | ||
| 255 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 256 | if ((batman_if->net_dev) && | ||
| 257 | (compare_orig(batman_if->net_dev->dev_addr, addr))) { | ||
| 258 | rcu_read_unlock(); | ||
| 259 | return 1; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | rcu_read_unlock(); | ||
| 263 | return 0; | ||
| 264 | |||
| 265 | } | ||
| 266 | |||
| 267 | int is_bcast(uint8_t *addr) | ||
| 268 | { | ||
| 269 | return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff); | ||
| 270 | } | ||
| 271 | |||
| 272 | int is_mcast(uint8_t *addr) | ||
| 273 | { | ||
| 274 | return *addr & 0x01; | ||
| 275 | } | ||
| 276 | |||
| 277 | MODULE_LICENSE("GPL"); | ||
| 278 | |||
| 279 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 280 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 281 | MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE); | ||
| 282 | #ifdef REVISION_VERSION | ||
| 283 | MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION); | ||
| 284 | #else | ||
| 285 | MODULE_VERSION(SOURCE_VERSION); | ||
| 286 | #endif | ||
diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h new file mode 100644 index 000000000000..facb6b79ee52 --- /dev/null +++ b/drivers/staging/batman-adv/main.h | |||
| @@ -0,0 +1,151 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | /* Kernel Programming */ | ||
| 23 | #define LINUX | ||
| 24 | |||
| 25 | #define DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, Simon Wunderlich <siwu@hrz.tu-chemnitz.de>" | ||
| 26 | #define DRIVER_DESC "B.A.T.M.A.N. advanced" | ||
| 27 | #define DRIVER_DEVICE "batman-adv" | ||
| 28 | |||
| 29 | #define SOURCE_VERSION "0.2.1-beta" | ||
| 30 | |||
| 31 | |||
| 32 | /* B.A.T.M.A.N. parameters */ | ||
| 33 | |||
| 34 | #define TQ_MAX_VALUE 255 | ||
| 35 | #define JITTER 20 | ||
| 36 | #define TTL 50 /* Time To Live of broadcast messages */ | ||
| 37 | #define MAX_ADDR 16 /* number of interfaces which can be added to | ||
| 38 | * batman. */ | ||
| 39 | |||
| 40 | #define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no | ||
| 41 | * valid packet comes in -> TODO: check | ||
| 42 | * influence on TQ_LOCAL_WINDOW_SIZE */ | ||
| 43 | #define LOCAL_HNA_TIMEOUT 3600000 | ||
| 44 | |||
| 45 | #define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator | ||
| 46 | * messages in squence numbers (should be a | ||
| 47 | * multiple of our word size) */ | ||
| 48 | #define TQ_GLOBAL_WINDOW_SIZE 5 | ||
| 49 | #define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 | ||
| 50 | #define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 | ||
| 51 | #define TQ_TOTAL_BIDRECT_LIMIT 1 | ||
| 52 | |||
| 53 | #define TQ_HOP_PENALTY 10 | ||
| 54 | |||
| 55 | #define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) | ||
| 56 | |||
| 57 | #define PACKBUFF_SIZE 2000 | ||
| 58 | #define LOG_BUF_LEN 8192 /* has to be a power of 2 */ | ||
| 59 | #define ETH_STR_LEN 20 | ||
| 60 | |||
| 61 | #define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or | ||
| 62 | * change the size of | ||
| 63 | * forw_packet->direct_link_flags */ | ||
| 64 | #define MAX_AGGREGATION_MS 100 | ||
| 65 | |||
| 66 | #define MODULE_INACTIVE 0 | ||
| 67 | #define MODULE_ACTIVE 1 | ||
| 68 | #define MODULE_DEACTIVATING 2 | ||
| 69 | |||
| 70 | |||
| 71 | /* | ||
| 72 | * Logging | ||
| 73 | */ | ||
| 74 | |||
| 75 | #define LOG_TYPE_CRIT 0 /* highest priority for fatal errors such as | ||
| 76 | * blocked sockets / failed packet delivery / | ||
| 77 | * programming errors */ | ||
| 78 | #define LOG_TYPE_WARN 1 /* warnings for small errors like wrong user | ||
| 79 | * input / damaged packets / etc */ | ||
| 80 | #define LOG_TYPE_NOTICE 2 /* notice information for new interfaces / | ||
| 81 | * changed settings / new originators / etc */ | ||
| 82 | #define LOG_TYPE_BATMAN 4 /* all messages related to routing / flooding / | ||
| 83 | * broadcasting / etc */ | ||
| 84 | #define LOG_TYPE_ROUTES 8 /* route or hna added / changed / deleted */ | ||
| 85 | #define LOG_TYPE_CRIT_NAME "critical" | ||
| 86 | #define LOG_TYPE_WARN_NAME "warnings" | ||
| 87 | #define LOG_TYPE_NOTICE_NAME "notices" | ||
| 88 | #define LOG_TYPE_BATMAN_NAME "batman" | ||
| 89 | #define LOG_TYPE_ROUTES_NAME "routes" | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Vis | ||
| 93 | */ | ||
| 94 | |||
| 95 | /* #define VIS_SUBCLUSTERS_DISABLED */ | ||
| 96 | |||
| 97 | /* | ||
| 98 | * Kernel headers | ||
| 99 | */ | ||
| 100 | |||
| 101 | #include <linux/mutex.h> /* mutex */ | ||
| 102 | #include <linux/module.h> /* needed by all modules */ | ||
| 103 | #include <linux/netdevice.h> /* netdevice */ | ||
| 104 | #include <linux/if_ether.h> /* ethernet header */ | ||
| 105 | #include <linux/poll.h> /* poll_table */ | ||
| 106 | #include <linux/kthread.h> /* kernel threads */ | ||
| 107 | #include <linux/pkt_sched.h> /* schedule types */ | ||
| 108 | #include <linux/workqueue.h> /* workqueue */ | ||
| 109 | #include <net/sock.h> /* struct sock */ | ||
| 110 | #include <linux/jiffies.h> | ||
| 111 | #include "types.h" | ||
| 112 | |||
| 113 | #ifndef REVISION_VERSION | ||
| 114 | #define REVISION_VERSION_STR "" | ||
| 115 | #else | ||
| 116 | #define REVISION_VERSION_STR " "REVISION_VERSION | ||
| 117 | #endif | ||
| 118 | |||
| 119 | extern struct list_head if_list; | ||
| 120 | extern struct hlist_head forw_bat_list; | ||
| 121 | extern struct hlist_head forw_bcast_list; | ||
| 122 | extern struct hashtable_t *orig_hash; | ||
| 123 | |||
| 124 | extern spinlock_t orig_hash_lock; | ||
| 125 | extern spinlock_t forw_bat_list_lock; | ||
| 126 | extern spinlock_t forw_bcast_list_lock; | ||
| 127 | |||
| 128 | extern atomic_t originator_interval; | ||
| 129 | extern atomic_t vis_interval; | ||
| 130 | extern atomic_t aggregation_enabled; | ||
| 131 | extern int16_t num_hna; | ||
| 132 | extern int16_t num_ifs; | ||
| 133 | |||
| 134 | extern struct net_device *soft_device; | ||
| 135 | |||
| 136 | extern unsigned char broadcastAddr[]; | ||
| 137 | extern atomic_t module_state; | ||
| 138 | extern struct workqueue_struct *bat_event_workqueue; | ||
| 139 | |||
| 140 | void activate_module(void); | ||
| 141 | void shutdown_module(void); | ||
| 142 | void inc_module_count(void); | ||
| 143 | void dec_module_count(void); | ||
| 144 | int addr_to_string(char *buff, uint8_t *addr); | ||
| 145 | int compare_orig(void *data1, void *data2); | ||
| 146 | int choose_orig(void *data, int32_t size); | ||
| 147 | int is_my_mac(uint8_t *addr); | ||
| 148 | int is_bcast(uint8_t *addr); | ||
| 149 | int is_mcast(uint8_t *addr); | ||
| 150 | |||
| 151 | |||
diff --git a/drivers/staging/batman-adv/packet.h b/drivers/staging/batman-adv/packet.h new file mode 100644 index 000000000000..5627ca326018 --- /dev/null +++ b/drivers/staging/batman-adv/packet.h | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */ | ||
| 23 | |||
| 24 | #define BAT_PACKET 0x01 | ||
| 25 | #define BAT_ICMP 0x02 | ||
| 26 | #define BAT_UNICAST 0x03 | ||
| 27 | #define BAT_BCAST 0x04 | ||
| 28 | #define BAT_VIS 0x05 | ||
| 29 | |||
| 30 | /* this file is included by batctl which needs these defines */ | ||
| 31 | #define COMPAT_VERSION 8 | ||
| 32 | #define DIRECTLINK 0x40 | ||
| 33 | #define VIS_SERVER 0x20 | ||
| 34 | |||
| 35 | /* ICMP message types */ | ||
| 36 | #define ECHO_REPLY 0 | ||
| 37 | #define DESTINATION_UNREACHABLE 3 | ||
| 38 | #define ECHO_REQUEST 8 | ||
| 39 | #define TTL_EXCEEDED 11 | ||
| 40 | #define PARAMETER_PROBLEM 12 | ||
| 41 | |||
| 42 | /* vis defines */ | ||
| 43 | #define VIS_TYPE_SERVER_SYNC 0 | ||
| 44 | #define VIS_TYPE_CLIENT_UPDATE 1 | ||
| 45 | |||
| 46 | struct batman_packet { | ||
| 47 | uint8_t packet_type; | ||
| 48 | uint8_t version; /* batman version field */ | ||
| 49 | uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ | ||
| 50 | uint8_t tq; | ||
| 51 | uint16_t seqno; | ||
| 52 | uint8_t orig[6]; | ||
| 53 | uint8_t prev_sender[6]; | ||
| 54 | uint8_t ttl; | ||
| 55 | uint8_t num_hna; | ||
| 56 | } __attribute__((packed)); | ||
| 57 | |||
| 58 | #define BAT_PACKET_LEN sizeof(struct batman_packet) | ||
| 59 | |||
| 60 | struct icmp_packet { | ||
| 61 | uint8_t packet_type; | ||
| 62 | uint8_t version; /* batman version field */ | ||
| 63 | uint8_t msg_type; /* see ICMP message types above */ | ||
| 64 | uint8_t ttl; | ||
| 65 | uint8_t dst[6]; | ||
| 66 | uint8_t orig[6]; | ||
| 67 | uint16_t seqno; | ||
| 68 | uint8_t uid; | ||
| 69 | } __attribute__((packed)); | ||
| 70 | |||
| 71 | struct unicast_packet { | ||
| 72 | uint8_t packet_type; | ||
| 73 | uint8_t version; /* batman version field */ | ||
| 74 | uint8_t dest[6]; | ||
| 75 | uint8_t ttl; | ||
| 76 | } __attribute__((packed)); | ||
| 77 | |||
| 78 | struct bcast_packet { | ||
| 79 | uint8_t packet_type; | ||
| 80 | uint8_t version; /* batman version field */ | ||
| 81 | uint8_t orig[6]; | ||
| 82 | uint16_t seqno; | ||
| 83 | } __attribute__((packed)); | ||
| 84 | |||
| 85 | struct vis_packet { | ||
| 86 | uint8_t packet_type; | ||
| 87 | uint8_t version; /* batman version field */ | ||
| 88 | uint8_t vis_type; /* which type of vis-participant sent this? */ | ||
| 89 | uint8_t seqno; /* sequence number */ | ||
| 90 | uint8_t entries; /* number of entries behind this struct */ | ||
| 91 | uint8_t ttl; /* TTL */ | ||
| 92 | uint8_t vis_orig[6]; /* originator that informs about its | ||
| 93 | * neighbours */ | ||
| 94 | uint8_t target_orig[6]; /* who should receive this packet */ | ||
| 95 | uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ | ||
| 96 | } __attribute__((packed)); | ||
diff --git a/drivers/staging/batman-adv/proc.c b/drivers/staging/batman-adv/proc.c new file mode 100644 index 000000000000..aac3df7f13fb --- /dev/null +++ b/drivers/staging/batman-adv/proc.c | |||
| @@ -0,0 +1,950 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "proc.h" | ||
| 24 | #include "log.h" | ||
| 25 | #include "routing.h" | ||
| 26 | #include "translation-table.h" | ||
| 27 | #include "hard-interface.h" | ||
| 28 | #include "types.h" | ||
| 29 | #include "hash.h" | ||
| 30 | #include "vis.h" | ||
| 31 | #include "compat.h" | ||
| 32 | |||
| 33 | static uint8_t vis_format = DOT_DRAW; | ||
| 34 | |||
| 35 | static struct proc_dir_entry *proc_batman_dir, *proc_interface_file; | ||
| 36 | static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file; | ||
| 37 | static struct proc_dir_entry *proc_log_file, *proc_log_level_file; | ||
| 38 | static struct proc_dir_entry *proc_transt_local_file; | ||
| 39 | static struct proc_dir_entry *proc_transt_global_file; | ||
| 40 | static struct proc_dir_entry *proc_vis_file, *proc_vis_format_file; | ||
| 41 | static struct proc_dir_entry *proc_aggr_file; | ||
| 42 | |||
| 43 | static int proc_interfaces_read(struct seq_file *seq, void *offset) | ||
| 44 | { | ||
| 45 | struct batman_if *batman_if; | ||
| 46 | |||
| 47 | rcu_read_lock(); | ||
| 48 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 49 | seq_printf(seq, "[%8s] %s %s \n", | ||
| 50 | (batman_if->if_active == IF_ACTIVE ? | ||
| 51 | "active" : "inactive"), | ||
| 52 | batman_if->dev, | ||
| 53 | (batman_if->if_active == IF_ACTIVE ? | ||
| 54 | batman_if->addr_str : " ")); | ||
| 55 | } | ||
| 56 | rcu_read_unlock(); | ||
| 57 | |||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | static int proc_interfaces_open(struct inode *inode, struct file *file) | ||
| 62 | { | ||
| 63 | return single_open(file, proc_interfaces_read, NULL); | ||
| 64 | } | ||
| 65 | |||
| 66 | static ssize_t proc_interfaces_write(struct file *instance, | ||
| 67 | const char __user *userbuffer, | ||
| 68 | size_t count, loff_t *data) | ||
| 69 | { | ||
| 70 | char *if_string, *colon_ptr = NULL, *cr_ptr = NULL; | ||
| 71 | int not_copied = 0, if_num = 0; | ||
| 72 | struct batman_if *batman_if = NULL; | ||
| 73 | |||
| 74 | if_string = kmalloc(count, GFP_KERNEL); | ||
| 75 | |||
| 76 | if (!if_string) | ||
| 77 | return -ENOMEM; | ||
| 78 | |||
| 79 | if (count > IFNAMSIZ - 1) { | ||
| 80 | debug_log(LOG_TYPE_WARN, | ||
| 81 | "Can't add interface: device name is too long\n"); | ||
| 82 | goto end; | ||
| 83 | } | ||
| 84 | |||
| 85 | not_copied = copy_from_user(if_string, userbuffer, count); | ||
| 86 | if_string[count - not_copied - 1] = 0; | ||
| 87 | |||
| 88 | colon_ptr = strchr(if_string, ':'); | ||
| 89 | if (colon_ptr) | ||
| 90 | *colon_ptr = 0; | ||
| 91 | |||
| 92 | if (!colon_ptr) { | ||
| 93 | cr_ptr = strchr(if_string, '\n'); | ||
| 94 | if (cr_ptr) | ||
| 95 | *cr_ptr = 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | if (strlen(if_string) == 0) { | ||
| 99 | shutdown_module(); | ||
| 100 | num_ifs = 0; | ||
| 101 | goto end; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* add interface */ | ||
| 105 | rcu_read_lock(); | ||
| 106 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 107 | if (strncmp(batman_if->dev, if_string, count) == 0) { | ||
| 108 | debug_log(LOG_TYPE_WARN, "Given interface is already active: %s\n", if_string); | ||
| 109 | rcu_read_unlock(); | ||
| 110 | goto end; | ||
| 111 | |||
| 112 | } | ||
| 113 | |||
| 114 | if_num++; | ||
| 115 | } | ||
| 116 | rcu_read_unlock(); | ||
| 117 | |||
| 118 | hardif_add_interface(if_string, if_num); | ||
| 119 | |||
| 120 | if ((atomic_read(&module_state) == MODULE_INACTIVE) && | ||
| 121 | (hardif_get_active_if_num() > 0)) | ||
| 122 | activate_module(); | ||
| 123 | |||
| 124 | rcu_read_lock(); | ||
| 125 | if (list_empty(&if_list)) { | ||
| 126 | rcu_read_unlock(); | ||
| 127 | goto end; | ||
| 128 | } | ||
| 129 | rcu_read_unlock(); | ||
| 130 | |||
| 131 | num_ifs = if_num + 1; | ||
| 132 | return count; | ||
| 133 | |||
| 134 | end: | ||
| 135 | kfree(if_string); | ||
| 136 | return count; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int proc_orig_interval_read(struct seq_file *seq, void *offset) | ||
| 140 | { | ||
| 141 | seq_printf(seq, "%i\n", atomic_read(&originator_interval)); | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | static ssize_t proc_orig_interval_write(struct file *file, | ||
| 147 | const char __user *buffer, | ||
| 148 | size_t count, loff_t *ppos) | ||
| 149 | { | ||
| 150 | char *interval_string; | ||
| 151 | int not_copied = 0; | ||
| 152 | unsigned long originator_interval_tmp; | ||
| 153 | int retval; | ||
| 154 | |||
| 155 | interval_string = kmalloc(count, GFP_KERNEL); | ||
| 156 | |||
| 157 | if (!interval_string) | ||
| 158 | return -ENOMEM; | ||
| 159 | |||
| 160 | not_copied = copy_from_user(interval_string, buffer, count); | ||
| 161 | interval_string[count - not_copied - 1] = 0; | ||
| 162 | |||
| 163 | retval = strict_strtoul(interval_string, 10, &originator_interval_tmp); | ||
| 164 | if (retval) { | ||
| 165 | debug_log(LOG_TYPE_WARN, "New originator interval invalid\n"); | ||
| 166 | goto end; | ||
| 167 | } | ||
| 168 | |||
| 169 | if (originator_interval_tmp <= JITTER * 2) { | ||
| 170 | debug_log(LOG_TYPE_WARN, | ||
| 171 | "New originator interval too small: %i (min: %i)\n", | ||
| 172 | originator_interval_tmp, JITTER * 2); | ||
| 173 | goto end; | ||
| 174 | } | ||
| 175 | |||
| 176 | debug_log(LOG_TYPE_NOTICE, | ||
| 177 | "Changing originator interval from: %i to: %i\n", | ||
| 178 | atomic_read(&originator_interval), originator_interval_tmp); | ||
| 179 | |||
| 180 | atomic_set(&originator_interval, originator_interval_tmp); | ||
| 181 | |||
| 182 | end: | ||
| 183 | kfree(interval_string); | ||
| 184 | return count; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int proc_orig_interval_open(struct inode *inode, struct file *file) | ||
| 188 | { | ||
| 189 | return single_open(file, proc_orig_interval_read, NULL); | ||
| 190 | } | ||
| 191 | |||
| 192 | static int proc_originators_read(struct seq_file *seq, void *offset) | ||
| 193 | { | ||
| 194 | struct hash_it_t *hashit = NULL; | ||
| 195 | struct orig_node *orig_node; | ||
| 196 | struct neigh_node *neigh_node; | ||
| 197 | int batman_count = 0; | ||
| 198 | char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN]; | ||
| 199 | |||
| 200 | rcu_read_lock(); | ||
| 201 | if (list_empty(&if_list)) { | ||
| 202 | rcu_read_unlock(); | ||
| 203 | seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n"); | ||
| 204 | goto end; | ||
| 205 | } | ||
| 206 | |||
| 207 | if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) { | ||
| 208 | rcu_read_unlock(); | ||
| 209 | seq_printf(seq, "BATMAN disabled - primary interface not active \n"); | ||
| 210 | goto end; | ||
| 211 | } | ||
| 212 | |||
| 213 | seq_printf(seq, | ||
| 214 | " %-14s (%s/%i) %17s [%10s]: %20s ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s] \n", | ||
| 215 | "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", | ||
| 216 | "Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR, | ||
| 217 | ((struct batman_if *)if_list.next)->dev, | ||
| 218 | ((struct batman_if *)if_list.next)->addr_str); | ||
| 219 | |||
| 220 | rcu_read_unlock(); | ||
| 221 | spin_lock(&orig_hash_lock); | ||
| 222 | |||
| 223 | while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { | ||
| 224 | |||
| 225 | orig_node = hashit->bucket->data; | ||
| 226 | |||
| 227 | if (!orig_node->router) | ||
| 228 | continue; | ||
| 229 | |||
| 230 | if (orig_node->router->tq_avg == 0) | ||
| 231 | continue; | ||
| 232 | |||
| 233 | batman_count++; | ||
| 234 | |||
| 235 | addr_to_string(orig_str, orig_node->orig); | ||
| 236 | addr_to_string(router_str, orig_node->router->addr); | ||
| 237 | |||
| 238 | seq_printf(seq, "%-17s (%3i) %17s [%10s]:", | ||
| 239 | orig_str, orig_node->router->tq_avg, | ||
| 240 | router_str, orig_node->router->if_incoming->dev); | ||
| 241 | |||
| 242 | list_for_each_entry(neigh_node, &orig_node->neigh_list, list) { | ||
| 243 | addr_to_string(orig_str, neigh_node->addr); | ||
| 244 | seq_printf(seq, " %17s (%3i)", | ||
| 245 | orig_str, neigh_node->tq_avg); | ||
| 246 | } | ||
| 247 | |||
| 248 | seq_printf(seq, "\n"); | ||
| 249 | |||
| 250 | } | ||
| 251 | |||
| 252 | spin_unlock(&orig_hash_lock); | ||
| 253 | |||
| 254 | if (batman_count == 0) | ||
| 255 | seq_printf(seq, "No batman nodes in range ... \n"); | ||
| 256 | |||
| 257 | end: | ||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | static int proc_originators_open(struct inode *inode, struct file *file) | ||
| 262 | { | ||
| 263 | return single_open(file, proc_originators_read, NULL); | ||
| 264 | } | ||
| 265 | |||
| 266 | static int proc_log_level_read(struct seq_file *seq, void *offset) | ||
| 267 | { | ||
| 268 | |||
| 269 | seq_printf(seq, "[x] %s (%d)\n", LOG_TYPE_CRIT_NAME, LOG_TYPE_CRIT); | ||
| 270 | seq_printf(seq, "[%c] %s (%d)\n", | ||
| 271 | (LOG_TYPE_WARN & log_level) ? 'x' : ' ', | ||
| 272 | LOG_TYPE_WARN_NAME, LOG_TYPE_WARN); | ||
| 273 | seq_printf(seq, "[%c] %s (%d)\n", | ||
| 274 | (LOG_TYPE_NOTICE & log_level) ? 'x' : ' ', | ||
| 275 | LOG_TYPE_NOTICE_NAME, LOG_TYPE_NOTICE); | ||
| 276 | seq_printf(seq, "[%c] %s (%d)\n", | ||
| 277 | (LOG_TYPE_BATMAN & log_level) ? 'x' : ' ', | ||
| 278 | LOG_TYPE_BATMAN_NAME, LOG_TYPE_BATMAN); | ||
| 279 | seq_printf(seq, "[%c] %s (%d)\n", | ||
| 280 | (LOG_TYPE_ROUTES & log_level) ? 'x' : ' ', | ||
| 281 | LOG_TYPE_ROUTES_NAME, LOG_TYPE_ROUTES); | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int proc_log_level_open(struct inode *inode, struct file *file) | ||
| 286 | { | ||
| 287 | return single_open(file, proc_log_level_read, NULL); | ||
| 288 | } | ||
| 289 | |||
| 290 | static ssize_t proc_log_level_write(struct file *instance, | ||
| 291 | const char __user *userbuffer, | ||
| 292 | size_t count, loff_t *data) | ||
| 293 | { | ||
| 294 | char *log_level_string, *tokptr, *cp; | ||
| 295 | int finished, not_copied = 0; | ||
| 296 | unsigned long log_level_tmp = 0; | ||
| 297 | |||
| 298 | log_level_string = kmalloc(count, GFP_KERNEL); | ||
| 299 | |||
| 300 | if (!log_level_string) | ||
| 301 | return -ENOMEM; | ||
| 302 | |||
| 303 | not_copied = copy_from_user(log_level_string, userbuffer, count); | ||
| 304 | log_level_string[count - not_copied - 1] = 0; | ||
| 305 | |||
| 306 | if (strict_strtoul(log_level_string, 10, &log_level_tmp) < 0) { | ||
| 307 | /* was not a number, doing textual parsing */ | ||
| 308 | log_level_tmp = 0; | ||
| 309 | tokptr = log_level_string; | ||
| 310 | |||
| 311 | for (cp = log_level_string, finished = 0; !finished; cp++) { | ||
| 312 | switch (*cp) { | ||
| 313 | case 0: | ||
| 314 | finished = 1; | ||
| 315 | case ' ': | ||
| 316 | case '\n': | ||
| 317 | case '\t': | ||
| 318 | *cp = 0; | ||
| 319 | /* compare */ | ||
| 320 | if (strcmp(tokptr, LOG_TYPE_WARN_NAME) == 0) | ||
| 321 | log_level_tmp |= LOG_TYPE_WARN; | ||
| 322 | if (strcmp(tokptr, LOG_TYPE_NOTICE_NAME) == 0) | ||
| 323 | log_level_tmp |= LOG_TYPE_NOTICE; | ||
| 324 | if (strcmp(tokptr, LOG_TYPE_BATMAN_NAME) == 0) | ||
| 325 | log_level_tmp |= LOG_TYPE_BATMAN; | ||
| 326 | if (strcmp(tokptr, LOG_TYPE_ROUTES_NAME) == 0) | ||
| 327 | log_level_tmp |= LOG_TYPE_ROUTES; | ||
| 328 | tokptr = cp + 1; | ||
| 329 | break; | ||
| 330 | default: | ||
| 331 | ; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | debug_log(LOG_TYPE_CRIT, "Changing log_level from: %i to: %i\n", | ||
| 337 | log_level, log_level_tmp); | ||
| 338 | log_level = log_level_tmp; | ||
| 339 | |||
| 340 | kfree(log_level_string); | ||
| 341 | return count; | ||
| 342 | } | ||
| 343 | |||
| 344 | static int proc_transt_local_read(struct seq_file *seq, void *offset) | ||
| 345 | { | ||
| 346 | char *buf; | ||
| 347 | |||
| 348 | buf = kmalloc(4096, GFP_KERNEL); | ||
| 349 | if (!buf) | ||
| 350 | return 0; | ||
| 351 | |||
| 352 | rcu_read_lock(); | ||
| 353 | if (list_empty(&if_list)) { | ||
| 354 | rcu_read_unlock(); | ||
| 355 | seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n"); | ||
| 356 | goto end; | ||
| 357 | } | ||
| 358 | |||
| 359 | rcu_read_unlock(); | ||
| 360 | |||
| 361 | seq_printf(seq, "Locally retrieved addresses (from %s) announced via HNA:\n", soft_device->name); | ||
| 362 | |||
| 363 | hna_local_fill_buffer_text(buf, 4096); | ||
| 364 | seq_printf(seq, "%s", buf); | ||
| 365 | |||
| 366 | end: | ||
| 367 | kfree(buf); | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | static int proc_transt_local_open(struct inode *inode, struct file *file) | ||
| 372 | { | ||
| 373 | return single_open(file, proc_transt_local_read, NULL); | ||
| 374 | } | ||
| 375 | |||
| 376 | static int proc_transt_global_read(struct seq_file *seq, void *offset) | ||
| 377 | { | ||
| 378 | char *buf; | ||
| 379 | |||
| 380 | buf = kmalloc(4096, GFP_KERNEL); | ||
| 381 | if (!buf) | ||
| 382 | return 0; | ||
| 383 | |||
| 384 | rcu_read_lock(); | ||
| 385 | if (list_empty(&if_list)) { | ||
| 386 | rcu_read_unlock(); | ||
| 387 | seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n"); | ||
| 388 | goto end; | ||
| 389 | } | ||
| 390 | rcu_read_unlock(); | ||
| 391 | |||
| 392 | |||
| 393 | seq_printf(seq, "Globally announced HNAs received via the mesh (translation table):\n"); | ||
| 394 | |||
| 395 | hna_global_fill_buffer_text(buf, 4096); | ||
| 396 | seq_printf(seq, "%s", buf); | ||
| 397 | |||
| 398 | end: | ||
| 399 | kfree(buf); | ||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | |||
| 403 | static int proc_transt_global_open(struct inode *inode, struct file *file) | ||
| 404 | { | ||
| 405 | return single_open(file, proc_transt_global_read, NULL); | ||
| 406 | } | ||
| 407 | |||
| 408 | /* insert interface to the list of interfaces of one originator */ | ||
| 409 | |||
| 410 | static void proc_vis_insert_interface(const uint8_t *interface, | ||
| 411 | struct vis_if_list **if_entry, | ||
| 412 | bool primary) | ||
| 413 | { | ||
| 414 | /* Did we get an empty list? (then insert imediately) */ | ||
| 415 | if(*if_entry == NULL) { | ||
| 416 | *if_entry = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL); | ||
| 417 | if (*if_entry == NULL) | ||
| 418 | return; | ||
| 419 | |||
| 420 | (*if_entry)->primary = primary; | ||
| 421 | (*if_entry)->next = NULL; | ||
| 422 | memcpy((*if_entry)->addr, interface, ETH_ALEN); | ||
| 423 | } else { | ||
| 424 | struct vis_if_list *head_if_entry = *if_entry; | ||
| 425 | /* Do we already have this interface in our list? */ | ||
| 426 | while (!compare_orig((*if_entry)->addr, (void *)interface)) { | ||
| 427 | |||
| 428 | /* Or did we reach the end (then append the interface) */ | ||
| 429 | if ((*if_entry)->next == NULL) { | ||
| 430 | (*if_entry)->next = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL); | ||
| 431 | if ((*if_entry)->next == NULL) | ||
| 432 | return; | ||
| 433 | |||
| 434 | memcpy((*if_entry)->next->addr, interface, ETH_ALEN); | ||
| 435 | (*if_entry)->next->primary = primary; | ||
| 436 | (*if_entry)->next->next = NULL; | ||
| 437 | break; | ||
| 438 | } | ||
| 439 | *if_entry = (*if_entry)->next; | ||
| 440 | } | ||
| 441 | /* Rewind the list to its head */ | ||
| 442 | *if_entry = head_if_entry; | ||
| 443 | } | ||
| 444 | } | ||
| 445 | /* read an entry */ | ||
| 446 | |||
| 447 | static void proc_vis_read_entry(struct seq_file *seq, | ||
| 448 | struct vis_info_entry *entry, | ||
| 449 | struct vis_if_list **if_entry, | ||
| 450 | uint8_t *vis_orig, | ||
| 451 | uint8_t current_format, | ||
| 452 | uint8_t first_line) | ||
| 453 | { | ||
| 454 | char from[40]; | ||
| 455 | char to[40]; | ||
| 456 | int int_part, frac_part; | ||
| 457 | |||
| 458 | addr_to_string(to, entry->dest); | ||
| 459 | if (entry->quality == 0) { | ||
| 460 | #ifndef VIS_SUBCLUSTERS_DISABLED | ||
| 461 | proc_vis_insert_interface(vis_orig, if_entry, true); | ||
| 462 | #endif /* VIS_SUBCLUSTERS_DISABLED */ | ||
| 463 | addr_to_string(from, vis_orig); | ||
| 464 | if (current_format == DOT_DRAW) { | ||
| 465 | seq_printf(seq, "\t\"%s\" -> \"%s\" [label=\"HNA\"]\n", | ||
| 466 | from, to); | ||
| 467 | } else { | ||
| 468 | seq_printf(seq, | ||
| 469 | "%s\t{ router : \"%s\", gateway : \"%s\", label : \"HNA\" }", | ||
| 470 | (first_line ? "" : ",\n"), from, to); | ||
| 471 | } | ||
| 472 | } else { | ||
| 473 | #ifndef VIS_SUBCLUSTERS_DISABLED | ||
| 474 | proc_vis_insert_interface(entry->src, if_entry, compare_orig(entry->src, vis_orig)); | ||
| 475 | #endif /* VIS_SUBCLUSTERS_DISABLED */ | ||
| 476 | addr_to_string(from, entry->src); | ||
| 477 | |||
| 478 | /* kernel has no printf-support for %f? it'd be better to return | ||
| 479 | * this in float. */ | ||
| 480 | |||
| 481 | int_part = TQ_MAX_VALUE / entry->quality; | ||
| 482 | frac_part = 1000 * TQ_MAX_VALUE / entry->quality - int_part * 1000; | ||
| 483 | |||
| 484 | if (current_format == DOT_DRAW) { | ||
| 485 | seq_printf(seq, | ||
| 486 | "\t\"%s\" -> \"%s\" [label=\"%d.%d\"]\n", | ||
| 487 | from, to, int_part, frac_part); | ||
| 488 | } else { | ||
| 489 | seq_printf(seq, | ||
| 490 | "%s\t{ router : \"%s\", neighbour : \"%s\", label : %d.%d }", | ||
| 491 | (first_line ? "" : ",\n"), from, to, int_part, frac_part); | ||
| 492 | } | ||
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 496 | |||
| 497 | static int proc_vis_read(struct seq_file *seq, void *offset) | ||
| 498 | { | ||
| 499 | struct hash_it_t *hashit = NULL; | ||
| 500 | struct vis_info *info; | ||
| 501 | struct vis_info_entry *entries; | ||
| 502 | struct vis_if_list *if_entries = NULL; | ||
| 503 | int i; | ||
| 504 | uint8_t current_format, first_line = 1; | ||
| 505 | #ifndef VIS_SUBCLUSTERS_DISABLED | ||
| 506 | char tmp_addr_str[ETH_STR_LEN]; | ||
| 507 | struct vis_if_list *tmp_if_next; | ||
| 508 | #endif /* VIS_SUBCLUSTERS_DISABLED */ | ||
| 509 | |||
| 510 | current_format = vis_format; | ||
| 511 | |||
| 512 | rcu_read_lock(); | ||
| 513 | if (list_empty(&if_list) || (!is_vis_server())) { | ||
| 514 | rcu_read_unlock(); | ||
| 515 | if (current_format == DOT_DRAW) | ||
| 516 | seq_printf(seq, "digraph {\n}\n"); | ||
| 517 | goto end; | ||
| 518 | } | ||
| 519 | |||
| 520 | rcu_read_unlock(); | ||
| 521 | |||
| 522 | if (current_format == DOT_DRAW) | ||
| 523 | seq_printf(seq, "digraph {\n"); | ||
| 524 | |||
| 525 | spin_lock(&vis_hash_lock); | ||
| 526 | while (NULL != (hashit = hash_iterate(vis_hash, hashit))) { | ||
| 527 | info = hashit->bucket->data; | ||
| 528 | entries = (struct vis_info_entry *) | ||
| 529 | ((char *)info + sizeof(struct vis_info)); | ||
| 530 | |||
| 531 | for (i = 0; i < info->packet.entries; i++) { | ||
| 532 | proc_vis_read_entry(seq, &entries[i], &if_entries, | ||
| 533 | info->packet.vis_orig, | ||
| 534 | current_format, first_line); | ||
| 535 | if (first_line) | ||
| 536 | first_line = 0; | ||
| 537 | } | ||
| 538 | |||
| 539 | #ifndef VIS_SUBCLUSTERS_DISABLED | ||
| 540 | /* Generate subgraphs from the collected items */ | ||
| 541 | if (current_format == DOT_DRAW) { | ||
| 542 | |||
| 543 | addr_to_string(tmp_addr_str, info->packet.vis_orig); | ||
| 544 | seq_printf(seq, "\tsubgraph \"cluster_%s\" {\n", tmp_addr_str); | ||
| 545 | while (if_entries != NULL) { | ||
| 546 | |||
| 547 | addr_to_string(tmp_addr_str, if_entries->addr); | ||
| 548 | if (if_entries->primary) | ||
| 549 | seq_printf(seq, "\t\t\"%s\" [peripheries=2]\n", tmp_addr_str); | ||
| 550 | else | ||
| 551 | seq_printf(seq, "\t\t\"%s\"\n", tmp_addr_str); | ||
| 552 | |||
| 553 | /* ... and empty the list while doing this */ | ||
| 554 | tmp_if_next = if_entries->next; | ||
| 555 | kfree(if_entries); | ||
| 556 | if_entries = tmp_if_next; | ||
| 557 | } | ||
| 558 | seq_printf(seq, "\t}\n"); | ||
| 559 | } | ||
| 560 | #endif /* VIS_SUBCLUSTERS_DISABLED */ | ||
| 561 | } | ||
| 562 | spin_unlock(&vis_hash_lock); | ||
| 563 | |||
| 564 | if (current_format == DOT_DRAW) | ||
| 565 | seq_printf(seq, "}\n"); | ||
| 566 | else | ||
| 567 | seq_printf(seq, "\n"); | ||
| 568 | end: | ||
| 569 | return 0; | ||
| 570 | } | ||
| 571 | |||
| 572 | /* setting the mode of the vis server by the user */ | ||
| 573 | static ssize_t proc_vis_write(struct file *file, const char __user * buffer, | ||
| 574 | size_t count, loff_t *ppos) | ||
| 575 | { | ||
| 576 | char *vis_mode_string; | ||
| 577 | int not_copied = 0; | ||
| 578 | |||
| 579 | vis_mode_string = kmalloc(count, GFP_KERNEL); | ||
| 580 | |||
| 581 | if (!vis_mode_string) | ||
| 582 | return -ENOMEM; | ||
| 583 | |||
| 584 | not_copied = copy_from_user(vis_mode_string, buffer, count); | ||
| 585 | vis_mode_string[count - not_copied - 1] = 0; | ||
| 586 | |||
| 587 | if (strcmp(vis_mode_string, "client") == 0) { | ||
| 588 | debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to client\n"); | ||
| 589 | vis_set_mode(VIS_TYPE_CLIENT_UPDATE); | ||
| 590 | } else if (strcmp(vis_mode_string, "server") == 0) { | ||
| 591 | debug_log(LOG_TYPE_NOTICE, "Setting VIS mode to server\n"); | ||
| 592 | vis_set_mode(VIS_TYPE_SERVER_SYNC); | ||
| 593 | } else | ||
| 594 | debug_log(LOG_TYPE_WARN, "Unknown VIS mode: %s\n", | ||
| 595 | vis_mode_string); | ||
| 596 | |||
| 597 | kfree(vis_mode_string); | ||
| 598 | return count; | ||
| 599 | } | ||
| 600 | |||
| 601 | static int proc_vis_open(struct inode *inode, struct file *file) | ||
| 602 | { | ||
| 603 | return single_open(file, proc_vis_read, NULL); | ||
| 604 | } | ||
| 605 | |||
| 606 | static int proc_vis_format_read(struct seq_file *seq, void *offset) | ||
| 607 | { | ||
| 608 | uint8_t current_format = vis_format; | ||
| 609 | |||
| 610 | seq_printf(seq, "[%c] %s\n", | ||
| 611 | (current_format == DOT_DRAW) ? 'x' : ' ', | ||
| 612 | VIS_FORMAT_DD_NAME); | ||
| 613 | seq_printf(seq, "[%c] %s\n", | ||
| 614 | (current_format == JSON) ? 'x' : ' ', | ||
| 615 | VIS_FORMAT_JSON_NAME); | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | static int proc_vis_format_open(struct inode *inode, struct file *file) | ||
| 620 | { | ||
| 621 | return single_open(file, proc_vis_format_read, NULL); | ||
| 622 | } | ||
| 623 | |||
| 624 | static ssize_t proc_vis_format_write(struct file *file, | ||
| 625 | const char __user *buffer, | ||
| 626 | size_t count, loff_t *ppos) | ||
| 627 | { | ||
| 628 | char *vis_format_string; | ||
| 629 | int not_copied = 0; | ||
| 630 | |||
| 631 | vis_format_string = kmalloc(count, GFP_KERNEL); | ||
| 632 | |||
| 633 | if (!vis_format_string) | ||
| 634 | return -ENOMEM; | ||
| 635 | |||
| 636 | not_copied = copy_from_user(vis_format_string, buffer, count); | ||
| 637 | vis_format_string[count - not_copied - 1] = 0; | ||
| 638 | |||
| 639 | if (strcmp(vis_format_string, VIS_FORMAT_DD_NAME) == 0) { | ||
| 640 | debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n", | ||
| 641 | VIS_FORMAT_DD_NAME); | ||
| 642 | vis_format = DOT_DRAW; | ||
| 643 | } else if (strcmp(vis_format_string, VIS_FORMAT_JSON_NAME) == 0) { | ||
| 644 | debug_log(LOG_TYPE_NOTICE, "Setting VIS output format to: %s\n", | ||
| 645 | VIS_FORMAT_JSON_NAME); | ||
| 646 | vis_format = JSON; | ||
| 647 | } else | ||
| 648 | debug_log(LOG_TYPE_WARN, "Unknown VIS output format: %s\n", | ||
| 649 | vis_format_string); | ||
| 650 | |||
| 651 | kfree(vis_format_string); | ||
| 652 | return count; | ||
| 653 | } | ||
| 654 | |||
| 655 | static int proc_aggr_read(struct seq_file *seq, void *offset) | ||
| 656 | { | ||
| 657 | seq_printf(seq, "%i\n", atomic_read(&aggregation_enabled)); | ||
| 658 | |||
| 659 | return 0; | ||
| 660 | } | ||
| 661 | |||
| 662 | static ssize_t proc_aggr_write(struct file *file, const char __user *buffer, | ||
| 663 | size_t count, loff_t *ppos) | ||
| 664 | { | ||
| 665 | char *aggr_string; | ||
| 666 | int not_copied = 0; | ||
| 667 | unsigned long aggregation_enabled_tmp; | ||
| 668 | |||
| 669 | aggr_string = kmalloc(count, GFP_KERNEL); | ||
| 670 | |||
| 671 | if (!aggr_string) | ||
| 672 | return -ENOMEM; | ||
| 673 | |||
| 674 | not_copied = copy_from_user(aggr_string, buffer, count); | ||
| 675 | aggr_string[count - not_copied - 1] = 0; | ||
| 676 | |||
| 677 | strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp); | ||
| 678 | |||
| 679 | if ((aggregation_enabled_tmp != 0) && (aggregation_enabled_tmp != 1)) { | ||
| 680 | debug_log(LOG_TYPE_WARN, "Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp); | ||
| 681 | goto end; | ||
| 682 | } | ||
| 683 | |||
| 684 | debug_log(LOG_TYPE_NOTICE, "Changing aggregation from: %s (%i) to: %s (%li)\n", | ||
| 685 | (atomic_read(&aggregation_enabled) == 1 ? | ||
| 686 | "enabled" : "disabled"), | ||
| 687 | atomic_read(&aggregation_enabled), | ||
| 688 | (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"), | ||
| 689 | aggregation_enabled_tmp); | ||
| 690 | |||
| 691 | atomic_set(&aggregation_enabled, (unsigned)aggregation_enabled_tmp); | ||
| 692 | end: | ||
| 693 | kfree(aggr_string); | ||
| 694 | return count; | ||
| 695 | } | ||
| 696 | |||
| 697 | static int proc_aggr_open(struct inode *inode, struct file *file) | ||
| 698 | { | ||
| 699 | return single_open(file, proc_aggr_read, NULL); | ||
| 700 | } | ||
| 701 | |||
| 702 | /* satisfying different prototypes ... */ | ||
| 703 | static ssize_t proc_dummy_write(struct file *file, const char __user *buffer, | ||
| 704 | size_t count, loff_t *ppos) | ||
| 705 | { | ||
| 706 | return count; | ||
| 707 | } | ||
| 708 | |||
| 709 | static const struct file_operations proc_aggr_fops = { | ||
| 710 | .owner = THIS_MODULE, | ||
| 711 | .open = proc_aggr_open, | ||
| 712 | .read = seq_read, | ||
| 713 | .write = proc_aggr_write, | ||
| 714 | .llseek = seq_lseek, | ||
| 715 | .release = single_release, | ||
| 716 | }; | ||
| 717 | |||
| 718 | static const struct file_operations proc_vis_format_fops = { | ||
| 719 | .owner = THIS_MODULE, | ||
| 720 | .open = proc_vis_format_open, | ||
| 721 | .read = seq_read, | ||
| 722 | .write = proc_vis_format_write, | ||
| 723 | .llseek = seq_lseek, | ||
| 724 | .release = single_release, | ||
| 725 | }; | ||
| 726 | |||
| 727 | static const struct file_operations proc_vis_fops = { | ||
| 728 | .owner = THIS_MODULE, | ||
| 729 | .open = proc_vis_open, | ||
| 730 | .read = seq_read, | ||
| 731 | .write = proc_vis_write, | ||
| 732 | .llseek = seq_lseek, | ||
| 733 | .release = single_release, | ||
| 734 | }; | ||
| 735 | |||
| 736 | static const struct file_operations proc_originators_fops = { | ||
| 737 | .owner = THIS_MODULE, | ||
| 738 | .open = proc_originators_open, | ||
| 739 | .read = seq_read, | ||
| 740 | .write = proc_dummy_write, | ||
| 741 | .llseek = seq_lseek, | ||
| 742 | .release = single_release, | ||
| 743 | }; | ||
| 744 | |||
| 745 | static const struct file_operations proc_transt_local_fops = { | ||
| 746 | .owner = THIS_MODULE, | ||
| 747 | .open = proc_transt_local_open, | ||
| 748 | .read = seq_read, | ||
| 749 | .write = proc_dummy_write, | ||
| 750 | .llseek = seq_lseek, | ||
| 751 | .release = single_release, | ||
| 752 | }; | ||
| 753 | |||
| 754 | static const struct file_operations proc_transt_global_fops = { | ||
| 755 | .owner = THIS_MODULE, | ||
| 756 | .open = proc_transt_global_open, | ||
| 757 | .read = seq_read, | ||
| 758 | .write = proc_dummy_write, | ||
| 759 | .llseek = seq_lseek, | ||
| 760 | .release = single_release, | ||
| 761 | }; | ||
| 762 | |||
| 763 | static const struct file_operations proc_log_level_fops = { | ||
| 764 | .owner = THIS_MODULE, | ||
| 765 | .open = proc_log_level_open, | ||
| 766 | .read = seq_read, | ||
| 767 | .write = proc_log_level_write, | ||
| 768 | .llseek = seq_lseek, | ||
| 769 | .release = single_release, | ||
| 770 | }; | ||
| 771 | |||
| 772 | static const struct file_operations proc_interfaces_fops = { | ||
| 773 | .owner = THIS_MODULE, | ||
| 774 | .open = proc_interfaces_open, | ||
| 775 | .read = seq_read, | ||
| 776 | .write = proc_interfaces_write, | ||
| 777 | .llseek = seq_lseek, | ||
| 778 | .release = single_release, | ||
| 779 | }; | ||
| 780 | |||
| 781 | static const struct file_operations proc_orig_interval_fops = { | ||
| 782 | .owner = THIS_MODULE, | ||
| 783 | .open = proc_orig_interval_open, | ||
| 784 | .read = seq_read, | ||
| 785 | .write = proc_orig_interval_write, | ||
| 786 | .llseek = seq_lseek, | ||
| 787 | .release = single_release, | ||
| 788 | }; | ||
| 789 | |||
| 790 | void cleanup_procfs(void) | ||
| 791 | { | ||
| 792 | if (proc_transt_global_file) | ||
| 793 | remove_proc_entry(PROC_FILE_TRANST_GLOBAL, proc_batman_dir); | ||
| 794 | |||
| 795 | if (proc_transt_local_file) | ||
| 796 | remove_proc_entry(PROC_FILE_TRANST_LOCAL, proc_batman_dir); | ||
| 797 | |||
| 798 | if (proc_log_file) | ||
| 799 | remove_proc_entry(PROC_FILE_LOG, proc_batman_dir); | ||
| 800 | |||
| 801 | if (proc_log_level_file) | ||
| 802 | remove_proc_entry(PROC_FILE_LOG_LEVEL, proc_batman_dir); | ||
| 803 | |||
| 804 | if (proc_originators_file) | ||
| 805 | remove_proc_entry(PROC_FILE_ORIGINATORS, proc_batman_dir); | ||
| 806 | |||
| 807 | if (proc_orig_interval_file) | ||
| 808 | remove_proc_entry(PROC_FILE_ORIG_INTERVAL, proc_batman_dir); | ||
| 809 | |||
| 810 | if (proc_interface_file) | ||
| 811 | remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir); | ||
| 812 | |||
| 813 | if (proc_vis_file) | ||
| 814 | remove_proc_entry(PROC_FILE_VIS, proc_batman_dir); | ||
| 815 | |||
| 816 | if (proc_vis_format_file) | ||
| 817 | remove_proc_entry(PROC_FILE_VIS_FORMAT, proc_batman_dir); | ||
| 818 | |||
| 819 | if (proc_aggr_file) | ||
| 820 | remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir); | ||
| 821 | |||
| 822 | if (proc_batman_dir) | ||
| 823 | #ifdef __NET_NET_NAMESPACE_H | ||
| 824 | remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net); | ||
| 825 | #else | ||
| 826 | remove_proc_entry(PROC_ROOT_DIR, proc_net); | ||
| 827 | #endif | ||
| 828 | } | ||
| 829 | |||
| 830 | int setup_procfs(void) | ||
| 831 | { | ||
| 832 | #ifdef __NET_NET_NAMESPACE_H | ||
| 833 | proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net); | ||
| 834 | #else | ||
| 835 | proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net); | ||
| 836 | #endif | ||
| 837 | |||
| 838 | if (!proc_batman_dir) { | ||
| 839 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR); | ||
| 840 | return -EFAULT; | ||
| 841 | } | ||
| 842 | |||
| 843 | proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES, | ||
| 844 | S_IWUSR | S_IRUGO, | ||
| 845 | proc_batman_dir); | ||
| 846 | if (proc_interface_file) { | ||
| 847 | proc_interface_file->proc_fops = &proc_interfaces_fops; | ||
| 848 | } else { | ||
| 849 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES); | ||
| 850 | cleanup_procfs(); | ||
| 851 | return -EFAULT; | ||
| 852 | } | ||
| 853 | |||
| 854 | proc_orig_interval_file = create_proc_entry(PROC_FILE_ORIG_INTERVAL, | ||
| 855 | S_IWUSR | S_IRUGO, | ||
| 856 | proc_batman_dir); | ||
| 857 | if (proc_orig_interval_file) { | ||
| 858 | proc_orig_interval_file->proc_fops = &proc_orig_interval_fops; | ||
| 859 | } else { | ||
| 860 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIG_INTERVAL); | ||
| 861 | cleanup_procfs(); | ||
| 862 | return -EFAULT; | ||
| 863 | } | ||
| 864 | |||
| 865 | proc_log_level_file = create_proc_entry(PROC_FILE_LOG_LEVEL, | ||
| 866 | S_IWUSR | S_IRUGO, | ||
| 867 | proc_batman_dir); | ||
| 868 | if (proc_log_level_file) { | ||
| 869 | proc_log_level_file->proc_fops = &proc_log_level_fops; | ||
| 870 | } else { | ||
| 871 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_LOG_LEVEL); | ||
| 872 | cleanup_procfs(); | ||
| 873 | return -EFAULT; | ||
| 874 | } | ||
| 875 | |||
| 876 | proc_originators_file = create_proc_entry(PROC_FILE_ORIGINATORS, | ||
| 877 | S_IRUGO, proc_batman_dir); | ||
| 878 | if (proc_originators_file) { | ||
| 879 | proc_originators_file->proc_fops = &proc_originators_fops; | ||
| 880 | } else { | ||
| 881 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIGINATORS); | ||
| 882 | cleanup_procfs(); | ||
| 883 | return -EFAULT; | ||
| 884 | } | ||
| 885 | |||
| 886 | proc_log_file = create_proc_entry(PROC_FILE_LOG, | ||
| 887 | S_IRUGO, proc_batman_dir); | ||
| 888 | if (proc_log_file) { | ||
| 889 | proc_log_file->proc_fops = &proc_log_operations; | ||
| 890 | } else { | ||
| 891 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_FILE_LOG, PROC_FILE_GATEWAYS); | ||
| 892 | cleanup_procfs(); | ||
| 893 | return -EFAULT; | ||
| 894 | } | ||
| 895 | |||
| 896 | proc_transt_local_file = create_proc_entry(PROC_FILE_TRANST_LOCAL, | ||
| 897 | S_IRUGO, proc_batman_dir); | ||
| 898 | if (proc_transt_local_file) { | ||
| 899 | proc_transt_local_file->proc_fops = &proc_transt_local_fops; | ||
| 900 | } else { | ||
| 901 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_LOCAL); | ||
| 902 | cleanup_procfs(); | ||
| 903 | return -EFAULT; | ||
| 904 | } | ||
| 905 | |||
| 906 | proc_transt_global_file = create_proc_entry(PROC_FILE_TRANST_GLOBAL, | ||
| 907 | S_IRUGO, proc_batman_dir); | ||
| 908 | if (proc_transt_global_file) { | ||
| 909 | proc_transt_global_file->proc_fops = &proc_transt_global_fops; | ||
| 910 | } else { | ||
| 911 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_GLOBAL); | ||
| 912 | cleanup_procfs(); | ||
| 913 | return -EFAULT; | ||
| 914 | } | ||
| 915 | |||
| 916 | proc_vis_file = create_proc_entry(PROC_FILE_VIS, S_IWUSR | S_IRUGO, | ||
| 917 | proc_batman_dir); | ||
| 918 | if (proc_vis_file) { | ||
| 919 | proc_vis_file->proc_fops = &proc_vis_fops; | ||
| 920 | } else { | ||
| 921 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS); | ||
| 922 | cleanup_procfs(); | ||
| 923 | return -EFAULT; | ||
| 924 | } | ||
| 925 | |||
| 926 | proc_vis_format_file = create_proc_entry(PROC_FILE_VIS_FORMAT, | ||
| 927 | S_IWUSR | S_IRUGO, | ||
| 928 | proc_batman_dir); | ||
| 929 | if (proc_vis_format_file) { | ||
| 930 | proc_vis_format_file->proc_fops = &proc_vis_format_fops; | ||
| 931 | } else { | ||
| 932 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_FORMAT); | ||
| 933 | cleanup_procfs(); | ||
| 934 | return -EFAULT; | ||
| 935 | } | ||
| 936 | |||
| 937 | proc_aggr_file = create_proc_entry(PROC_FILE_AGGR, S_IWUSR | S_IRUGO, | ||
| 938 | proc_batman_dir); | ||
| 939 | if (proc_aggr_file) { | ||
| 940 | proc_aggr_file->proc_fops = &proc_aggr_fops; | ||
| 941 | } else { | ||
| 942 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_AGGR); | ||
| 943 | cleanup_procfs(); | ||
| 944 | return -EFAULT; | ||
| 945 | } | ||
| 946 | |||
| 947 | return 0; | ||
| 948 | } | ||
| 949 | |||
| 950 | |||
diff --git a/drivers/staging/batman-adv/proc.h b/drivers/staging/batman-adv/proc.h new file mode 100644 index 000000000000..16d3efdebe52 --- /dev/null +++ b/drivers/staging/batman-adv/proc.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/proc_fs.h> | ||
| 23 | #include <linux/seq_file.h> | ||
| 24 | |||
| 25 | #define PROC_ROOT_DIR "batman-adv" | ||
| 26 | #define PROC_FILE_INTERFACES "interfaces" | ||
| 27 | #define PROC_FILE_ORIG_INTERVAL "orig_interval" | ||
| 28 | #define PROC_FILE_ORIGINATORS "originators" | ||
| 29 | #define PROC_FILE_GATEWAYS "gateways" | ||
| 30 | #define PROC_FILE_LOG "log" | ||
| 31 | #define PROC_FILE_LOG_LEVEL "log_level" | ||
| 32 | #define PROC_FILE_TRANST_LOCAL "transtable_local" | ||
| 33 | #define PROC_FILE_TRANST_GLOBAL "transtable_global" | ||
| 34 | #define PROC_FILE_VIS "vis" | ||
| 35 | #define PROC_FILE_VIS_FORMAT "vis_format" | ||
| 36 | #define PROC_FILE_AGGR "aggregate_ogm" | ||
| 37 | |||
| 38 | void cleanup_procfs(void); | ||
| 39 | int setup_procfs(void); | ||
| 40 | |||
| 41 | /* While scanning for vis-entries of a particular vis-originator | ||
| 42 | * this list collects its interfaces to create a subgraph/cluster | ||
| 43 | * out of them later | ||
| 44 | */ | ||
| 45 | struct vis_if_list { | ||
| 46 | uint8_t addr[ETH_ALEN]; | ||
| 47 | bool primary; | ||
| 48 | struct vis_if_list *next; | ||
| 49 | }; | ||
diff --git a/drivers/staging/batman-adv/ring_buffer.c b/drivers/staging/batman-adv/ring_buffer.c new file mode 100644 index 000000000000..751c899f54c5 --- /dev/null +++ b/drivers/staging/batman-adv/ring_buffer.c | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "ring_buffer.h" | ||
| 24 | |||
| 25 | void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value) | ||
| 26 | { | ||
| 27 | lq_recv[*lq_index] = value; | ||
| 28 | *lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE; | ||
| 29 | } | ||
| 30 | |||
| 31 | uint8_t ring_buffer_avg(uint8_t lq_recv[]) | ||
| 32 | { | ||
| 33 | uint8_t *ptr; | ||
| 34 | uint16_t count = 0, i = 0, sum = 0; | ||
| 35 | |||
| 36 | ptr = lq_recv; | ||
| 37 | |||
| 38 | while (i < TQ_GLOBAL_WINDOW_SIZE) { | ||
| 39 | if (*ptr != 0) { | ||
| 40 | count++; | ||
| 41 | sum += *ptr; | ||
| 42 | } | ||
| 43 | |||
| 44 | i++; | ||
| 45 | ptr++; | ||
| 46 | } | ||
| 47 | |||
| 48 | if (count == 0) | ||
| 49 | return 0; | ||
| 50 | |||
| 51 | return (uint8_t)(sum / count); | ||
| 52 | } | ||
diff --git a/drivers/staging/batman-adv/ring_buffer.h b/drivers/staging/batman-adv/ring_buffer.h new file mode 100644 index 000000000000..6839ba97eeb3 --- /dev/null +++ b/drivers/staging/batman-adv/ring_buffer.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value); | ||
| 23 | uint8_t ring_buffer_avg(uint8_t lq_recv[]); | ||
diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c new file mode 100644 index 000000000000..4a14c363ac2b --- /dev/null +++ b/drivers/staging/batman-adv/routing.c | |||
| @@ -0,0 +1,1010 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | #include "main.h" | ||
| 27 | #include "routing.h" | ||
| 28 | #include "log.h" | ||
| 29 | #include "send.h" | ||
| 30 | #include "soft-interface.h" | ||
| 31 | #include "hard-interface.h" | ||
| 32 | #include "device.h" | ||
| 33 | #include "translation-table.h" | ||
| 34 | #include "types.h" | ||
| 35 | #include "hash.h" | ||
| 36 | #include "ring_buffer.h" | ||
| 37 | #include "vis.h" | ||
| 38 | #include "aggregation.h" | ||
| 39 | #include "compat.h" | ||
| 40 | |||
| 41 | |||
| 42 | |||
| 43 | DECLARE_WAIT_QUEUE_HEAD(thread_wait); | ||
| 44 | static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig); | ||
| 45 | |||
| 46 | static atomic_t data_ready_cond; | ||
| 47 | atomic_t exit_cond; | ||
| 48 | |||
| 49 | static void start_purge_timer(void) | ||
| 50 | { | ||
| 51 | queue_delayed_work(bat_event_workqueue, &purge_orig_wq, 1 * HZ); | ||
| 52 | } | ||
| 53 | |||
| 54 | int originator_init(void) | ||
| 55 | { | ||
| 56 | if (orig_hash) | ||
| 57 | return 1; | ||
| 58 | |||
| 59 | spin_lock(&orig_hash_lock); | ||
| 60 | orig_hash = hash_new(128, compare_orig, choose_orig); | ||
| 61 | |||
| 62 | if (!orig_hash) | ||
| 63 | goto err; | ||
| 64 | |||
| 65 | spin_unlock(&orig_hash_lock); | ||
| 66 | start_purge_timer(); | ||
| 67 | return 1; | ||
| 68 | |||
| 69 | err: | ||
| 70 | spin_unlock(&orig_hash_lock); | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | void originator_free(void) | ||
| 75 | { | ||
| 76 | if (!orig_hash) | ||
| 77 | return; | ||
| 78 | |||
| 79 | cancel_delayed_work_sync(&purge_orig_wq); | ||
| 80 | |||
| 81 | spin_lock(&orig_hash_lock); | ||
| 82 | hash_delete(orig_hash, free_orig_node); | ||
| 83 | orig_hash = NULL; | ||
| 84 | spin_unlock(&orig_hash_lock); | ||
| 85 | } | ||
| 86 | |||
| 87 | 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) | ||
| 88 | { | ||
| 89 | struct neigh_node *neigh_node; | ||
| 90 | |||
| 91 | debug_log(LOG_TYPE_BATMAN, "Creating new last-hop neighbour of originator\n"); | ||
| 92 | |||
| 93 | neigh_node = kmalloc(sizeof(struct neigh_node), GFP_ATOMIC); | ||
| 94 | memset(neigh_node, 0, sizeof(struct neigh_node)); | ||
| 95 | INIT_LIST_HEAD(&neigh_node->list); | ||
| 96 | |||
| 97 | memcpy(neigh_node->addr, neigh, ETH_ALEN); | ||
| 98 | neigh_node->orig_node = orig_neigh_node; | ||
| 99 | neigh_node->if_incoming = if_incoming; | ||
| 100 | |||
| 101 | list_add_tail(&neigh_node->list, &orig_node->neigh_list); | ||
| 102 | return neigh_node; | ||
| 103 | } | ||
| 104 | |||
| 105 | void free_orig_node(void *data) | ||
| 106 | { | ||
| 107 | struct list_head *list_pos, *list_pos_tmp; | ||
| 108 | struct neigh_node *neigh_node; | ||
| 109 | struct orig_node *orig_node = (struct orig_node *)data; | ||
| 110 | |||
| 111 | /* for all neighbours towards this originator ... */ | ||
| 112 | list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { | ||
| 113 | neigh_node = list_entry(list_pos, struct neigh_node, list); | ||
| 114 | |||
| 115 | list_del(list_pos); | ||
| 116 | kfree(neigh_node); | ||
| 117 | } | ||
| 118 | |||
| 119 | hna_global_del_orig(orig_node, "originator timed out"); | ||
| 120 | |||
| 121 | kfree(orig_node->bcast_own); | ||
| 122 | kfree(orig_node->bcast_own_sum); | ||
| 123 | kfree(orig_node); | ||
| 124 | } | ||
| 125 | |||
| 126 | /* this function finds or creates an originator entry for the given address if it does not exits */ | ||
| 127 | static struct orig_node *get_orig_node(uint8_t *addr) | ||
| 128 | { | ||
| 129 | struct orig_node *orig_node; | ||
| 130 | struct hashtable_t *swaphash; | ||
| 131 | char orig_str[ETH_STR_LEN]; | ||
| 132 | |||
| 133 | orig_node = ((struct orig_node *)hash_find(orig_hash, addr)); | ||
| 134 | |||
| 135 | if (orig_node != NULL) | ||
| 136 | return orig_node; | ||
| 137 | |||
| 138 | addr_to_string(orig_str, addr); | ||
| 139 | debug_log(LOG_TYPE_BATMAN, "Creating new originator: %s \n", orig_str); | ||
| 140 | |||
| 141 | orig_node = kmalloc(sizeof(struct orig_node), GFP_ATOMIC); | ||
| 142 | memset(orig_node, 0, sizeof(struct orig_node)); | ||
| 143 | INIT_LIST_HEAD(&orig_node->neigh_list); | ||
| 144 | |||
| 145 | memcpy(orig_node->orig, addr, ETH_ALEN); | ||
| 146 | orig_node->router = NULL; | ||
| 147 | orig_node->batman_if = NULL; | ||
| 148 | orig_node->hna_buff = NULL; | ||
| 149 | |||
| 150 | orig_node->bcast_own = kmalloc(num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS, GFP_ATOMIC); | ||
| 151 | memset(orig_node->bcast_own, 0, num_ifs * sizeof(TYPE_OF_WORD) * NUM_WORDS); | ||
| 152 | |||
| 153 | orig_node->bcast_own_sum = kmalloc(num_ifs * sizeof(uint8_t), GFP_ATOMIC); | ||
| 154 | memset(orig_node->bcast_own_sum, 0, num_ifs * sizeof(uint8_t)); | ||
| 155 | |||
| 156 | hash_add(orig_hash, orig_node); | ||
| 157 | |||
| 158 | if (orig_hash->elements * 4 > orig_hash->size) { | ||
| 159 | swaphash = hash_resize(orig_hash, orig_hash->size * 2); | ||
| 160 | |||
| 161 | if (swaphash == NULL) | ||
| 162 | debug_log(LOG_TYPE_CRIT, "Couldn't resize orig hash table \n"); | ||
| 163 | else | ||
| 164 | orig_hash = swaphash; | ||
| 165 | } | ||
| 166 | |||
| 167 | return orig_node; | ||
| 168 | } | ||
| 169 | |||
| 170 | void slide_own_bcast_window(struct batman_if *batman_if) | ||
| 171 | { | ||
| 172 | struct hash_it_t *hashit = NULL; | ||
| 173 | struct orig_node *orig_node; | ||
| 174 | |||
| 175 | spin_lock(&orig_hash_lock); | ||
| 176 | |||
| 177 | while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { | ||
| 178 | orig_node = hashit->bucket->data; | ||
| 179 | |||
| 180 | bit_get_packet((TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]), 1, 0); | ||
| 181 | 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])); | ||
| 182 | } | ||
| 183 | |||
| 184 | spin_unlock(&orig_hash_lock); | ||
| 185 | } | ||
| 186 | |||
| 187 | static void update_routes(struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len) | ||
| 188 | { | ||
| 189 | char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], router_str[ETH_STR_LEN]; | ||
| 190 | |||
| 191 | if (orig_node == NULL) | ||
| 192 | return; | ||
| 193 | |||
| 194 | if (orig_node->router != neigh_node) { | ||
| 195 | addr_to_string(orig_str, orig_node->orig); | ||
| 196 | |||
| 197 | /* route deleted */ | ||
| 198 | if ((orig_node->router != NULL) && (neigh_node == NULL)) { | ||
| 199 | |||
| 200 | debug_log(LOG_TYPE_ROUTES, "Deleting route towards: %s\n", orig_str); | ||
| 201 | hna_global_del_orig(orig_node, "originator timed out"); | ||
| 202 | |||
| 203 | /* route added */ | ||
| 204 | } else if ((orig_node->router == NULL) && (neigh_node != NULL)) { | ||
| 205 | |||
| 206 | addr_to_string(neigh_str, neigh_node->addr); | ||
| 207 | debug_log(LOG_TYPE_ROUTES, "Adding route towards: %s (via %s)\n", orig_str, neigh_str); | ||
| 208 | hna_global_add_orig(orig_node, hna_buff, hna_buff_len); | ||
| 209 | |||
| 210 | /* route changed */ | ||
| 211 | } else { | ||
| 212 | |||
| 213 | addr_to_string(neigh_str, neigh_node->addr); | ||
| 214 | addr_to_string(router_str, orig_node->router->addr); | ||
| 215 | debug_log(LOG_TYPE_ROUTES, "Changing route towards: %s (now via %s - was via %s)\n", orig_str, neigh_str, router_str); | ||
| 216 | |||
| 217 | } | ||
| 218 | |||
| 219 | if (neigh_node != NULL) | ||
| 220 | orig_node->batman_if = neigh_node->if_incoming; | ||
| 221 | else | ||
| 222 | orig_node->batman_if = NULL; | ||
| 223 | |||
| 224 | orig_node->router = neigh_node; | ||
| 225 | |||
| 226 | /* may be just HNA changed */ | ||
| 227 | } else { | ||
| 228 | |||
| 229 | 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))) { | ||
| 230 | |||
| 231 | if (orig_node->hna_buff_len > 0) | ||
| 232 | hna_global_del_orig(orig_node, "originator changed hna"); | ||
| 233 | |||
| 234 | if ((hna_buff_len > 0) && (hna_buff != NULL)) | ||
| 235 | hna_global_add_orig(orig_node, hna_buff, hna_buff_len); | ||
| 236 | |||
| 237 | } | ||
| 238 | |||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | static int isBidirectionalNeigh(struct orig_node *orig_node, struct orig_node *orig_neigh_node, struct batman_packet *batman_packet, struct batman_if *if_incoming) | ||
| 243 | { | ||
| 244 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | ||
| 245 | char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN]; | ||
| 246 | unsigned char total_count; | ||
| 247 | |||
| 248 | addr_to_string(orig_str, orig_node->orig); | ||
| 249 | addr_to_string(neigh_str, orig_neigh_node->orig); | ||
| 250 | |||
| 251 | if (orig_node == orig_neigh_node) { | ||
| 252 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
| 253 | |||
| 254 | if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming)) | ||
| 255 | neigh_node = tmp_neigh_node; | ||
| 256 | } | ||
| 257 | |||
| 258 | if (neigh_node == NULL) | ||
| 259 | neigh_node = create_neighbor(orig_node, orig_neigh_node, orig_neigh_node->orig, if_incoming); | ||
| 260 | |||
| 261 | neigh_node->last_valid = jiffies; | ||
| 262 | } else { | ||
| 263 | /* find packet count of corresponding one hop neighbor */ | ||
| 264 | list_for_each_entry(tmp_neigh_node, &orig_neigh_node->neigh_list, list) { | ||
| 265 | |||
| 266 | if (compare_orig(tmp_neigh_node->addr, orig_neigh_node->orig) && (tmp_neigh_node->if_incoming == if_incoming)) | ||
| 267 | neigh_node = tmp_neigh_node; | ||
| 268 | } | ||
| 269 | |||
| 270 | if (neigh_node == NULL) | ||
| 271 | neigh_node = create_neighbor(orig_neigh_node, orig_neigh_node, orig_neigh_node->orig, if_incoming); | ||
| 272 | } | ||
| 273 | |||
| 274 | orig_node->last_valid = jiffies; | ||
| 275 | |||
| 276 | /* pay attention to not get a value bigger than 100 % */ | ||
| 277 | 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]); | ||
| 278 | |||
| 279 | /* if we have too few packets (too less data) we set tq_own to zero */ | ||
| 280 | /* if we receive too few packets it is not considered bidirectional */ | ||
| 281 | if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) | ||
| 282 | orig_neigh_node->tq_own = 0; | ||
| 283 | else | ||
| 284 | /* neigh_node->real_packet_count is never zero as we only purge old information when getting new information */ | ||
| 285 | orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / neigh_node->real_packet_count; | ||
| 286 | |||
| 287 | /* | ||
| 288 | * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE | ||
| 289 | * this does affect the nearly-symmetric links only a little, | ||
| 290 | * but punishes asymmetric links more. | ||
| 291 | * this will give a value between 0 and TQ_MAX_VALUE | ||
| 292 | */ | ||
| 293 | orig_neigh_node->tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE * | ||
| 294 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * | ||
| 295 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * | ||
| 296 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / | ||
| 297 | (TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE); | ||
| 298 | |||
| 299 | batman_packet->tq = ((batman_packet->tq * orig_neigh_node->tq_own * orig_neigh_node->tq_asym_penalty) / (TQ_MAX_VALUE * TQ_MAX_VALUE)); | ||
| 300 | |||
| 301 | 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", | ||
| 302 | 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); | ||
| 303 | |||
| 304 | /* if link has the minimum required transmission quality consider it bidirectional */ | ||
| 305 | if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) | ||
| 306 | return 1; | ||
| 307 | |||
| 308 | return 0; | ||
| 309 | } | ||
| 310 | |||
| 311 | 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) | ||
| 312 | { | ||
| 313 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | ||
| 314 | int tmp_hna_buff_len; | ||
| 315 | |||
| 316 | debug_log(LOG_TYPE_BATMAN, "update_originator(): Searching and updating originator entry of received packet \n"); | ||
| 317 | |||
| 318 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
| 319 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming)) { | ||
| 320 | neigh_node = tmp_neigh_node; | ||
| 321 | continue; | ||
| 322 | } | ||
| 323 | |||
| 324 | if (is_duplicate) | ||
| 325 | continue; | ||
| 326 | |||
| 327 | ring_buffer_set(tmp_neigh_node->tq_recv, &tmp_neigh_node->tq_index, 0); | ||
| 328 | tmp_neigh_node->tq_avg = ring_buffer_avg(tmp_neigh_node->tq_recv); | ||
| 329 | } | ||
| 330 | |||
| 331 | if (neigh_node == NULL) | ||
| 332 | neigh_node = create_neighbor(orig_node, get_orig_node(ethhdr->h_source), ethhdr->h_source, if_incoming); | ||
| 333 | else | ||
| 334 | debug_log(LOG_TYPE_BATMAN, "Updating existing last-hop neighbour of originator\n"); | ||
| 335 | |||
| 336 | orig_node->flags = batman_packet->flags; | ||
| 337 | neigh_node->last_valid = jiffies; | ||
| 338 | |||
| 339 | ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, batman_packet->tq); | ||
| 340 | neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); | ||
| 341 | |||
| 342 | if (!is_duplicate) { | ||
| 343 | orig_node->last_ttl = batman_packet->ttl; | ||
| 344 | neigh_node->last_ttl = batman_packet->ttl; | ||
| 345 | } | ||
| 346 | |||
| 347 | tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? batman_packet->num_hna * ETH_ALEN : hna_buff_len); | ||
| 348 | |||
| 349 | /* if this neighbor already is our next hop there is nothing to change */ | ||
| 350 | if (orig_node->router == neigh_node) | ||
| 351 | goto update_hna; | ||
| 352 | |||
| 353 | /* if this neighbor does not offer a better TQ we won't consider it */ | ||
| 354 | if ((orig_node->router) && | ||
| 355 | (orig_node->router->tq_avg > neigh_node->tq_avg)) | ||
| 356 | goto update_hna; | ||
| 357 | |||
| 358 | /* if the TQ is the same and the link not more symetric we won't consider it either */ | ||
| 359 | if ((orig_node->router) && | ||
| 360 | ((neigh_node->tq_avg == orig_node->router->tq_avg) && | ||
| 361 | (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] >= | ||
| 362 | neigh_node->orig_node->bcast_own_sum[if_incoming->if_num]))) | ||
| 363 | goto update_hna; | ||
| 364 | |||
| 365 | update_routes(orig_node, neigh_node, hna_buff, tmp_hna_buff_len); | ||
| 366 | return; | ||
| 367 | |||
| 368 | update_hna: | ||
| 369 | update_routes(orig_node, orig_node->router, hna_buff, tmp_hna_buff_len); | ||
| 370 | return; | ||
| 371 | } | ||
| 372 | |||
| 373 | static char count_real_packets(struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct batman_if *if_incoming) | ||
| 374 | { | ||
| 375 | struct orig_node *orig_node; | ||
| 376 | struct neigh_node *tmp_neigh_node; | ||
| 377 | char is_duplicate = 0; | ||
| 378 | |||
| 379 | |||
| 380 | orig_node = get_orig_node(batman_packet->orig); | ||
| 381 | if (orig_node == NULL) | ||
| 382 | return 0; | ||
| 383 | |||
| 384 | |||
| 385 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
| 386 | |||
| 387 | if (!is_duplicate) | ||
| 388 | is_duplicate = get_bit_status(tmp_neigh_node->real_bits, orig_node->last_real_seqno, batman_packet->seqno); | ||
| 389 | |||
| 390 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && (tmp_neigh_node->if_incoming == if_incoming)) | ||
| 391 | bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 1); | ||
| 392 | else | ||
| 393 | bit_get_packet(tmp_neigh_node->real_bits, batman_packet->seqno - orig_node->last_real_seqno, 0); | ||
| 394 | |||
| 395 | tmp_neigh_node->real_packet_count = bit_packet_count(tmp_neigh_node->real_bits); | ||
| 396 | } | ||
| 397 | |||
| 398 | if (!is_duplicate) { | ||
| 399 | debug_log(LOG_TYPE_BATMAN, "updating last_seqno: old %d, new %d \n", orig_node->last_real_seqno, batman_packet->seqno); | ||
| 400 | orig_node->last_real_seqno = batman_packet->seqno; | ||
| 401 | } | ||
| 402 | |||
| 403 | return is_duplicate; | ||
| 404 | } | ||
| 405 | |||
| 406 | 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) | ||
| 407 | { | ||
| 408 | struct batman_if *batman_if; | ||
| 409 | struct orig_node *orig_neigh_node, *orig_node; | ||
| 410 | char orig_str[ETH_STR_LEN], prev_sender_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN]; | ||
| 411 | char has_directlink_flag; | ||
| 412 | char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0, is_broadcast = 0, is_bidirectional, is_single_hop_neigh, is_duplicate; | ||
| 413 | unsigned short if_incoming_seqno; | ||
| 414 | |||
| 415 | /* Silently drop when the batman packet is actually not a correct packet. | ||
| 416 | * | ||
| 417 | * This might happen if a packet is padded (e.g. Ethernet has a | ||
| 418 | * minimum frame length of 64 byte) and the aggregation interprets | ||
| 419 | * it as an additional length. | ||
| 420 | * | ||
| 421 | * TODO: A more sane solution would be to have a bit in the batman_packet | ||
| 422 | * to detect whether the packet is the last packet in an aggregation. | ||
| 423 | * Here we expect that the padding is always zero (or not 0x01) | ||
| 424 | */ | ||
| 425 | if (batman_packet->packet_type != BAT_PACKET) | ||
| 426 | return; | ||
| 427 | |||
| 428 | /* could be changed by schedule_own_packet() */ | ||
| 429 | if_incoming_seqno = atomic_read(&if_incoming->seqno); | ||
| 430 | |||
| 431 | addr_to_string(orig_str, batman_packet->orig); | ||
| 432 | addr_to_string(prev_sender_str, batman_packet->prev_sender); | ||
| 433 | addr_to_string(neigh_str, ethhdr->h_source); | ||
| 434 | |||
| 435 | has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0); | ||
| 436 | |||
| 437 | is_single_hop_neigh = (compare_orig(ethhdr->h_source, batman_packet->orig) ? 1 : 0); | ||
| 438 | |||
| 439 | 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); | ||
| 440 | |||
| 441 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 442 | if (batman_if->if_active != IF_ACTIVE) | ||
| 443 | continue; | ||
| 444 | |||
| 445 | if (compare_orig(ethhdr->h_source, batman_if->net_dev->dev_addr)) | ||
| 446 | is_my_addr = 1; | ||
| 447 | |||
| 448 | if (compare_orig(batman_packet->orig, batman_if->net_dev->dev_addr)) | ||
| 449 | is_my_orig = 1; | ||
| 450 | |||
| 451 | if (compare_orig(batman_packet->prev_sender, batman_if->net_dev->dev_addr)) | ||
| 452 | is_my_oldorig = 1; | ||
| 453 | |||
| 454 | if (compare_orig(ethhdr->h_source, broadcastAddr)) | ||
| 455 | is_broadcast = 1; | ||
| 456 | } | ||
| 457 | |||
| 458 | if (batman_packet->version != COMPAT_VERSION) { | ||
| 459 | debug_log(LOG_TYPE_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version); | ||
| 460 | return; | ||
| 461 | } | ||
| 462 | |||
| 463 | if (is_my_addr) { | ||
| 464 | debug_log(LOG_TYPE_BATMAN, "Drop packet: received my own broadcast (sender: %s) \n", neigh_str); | ||
| 465 | return; | ||
| 466 | } | ||
| 467 | |||
| 468 | if (is_broadcast) { | ||
| 469 | debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all packets with broadcast source addr (sender: %s) \n", neigh_str); | ||
| 470 | return; | ||
| 471 | } | ||
| 472 | |||
| 473 | if (is_my_orig) { | ||
| 474 | orig_neigh_node = get_orig_node(ethhdr->h_source); | ||
| 475 | |||
| 476 | /* neighbour has to indicate direct link and it has to come via the corresponding interface */ | ||
| 477 | /* if received seqno equals last send seqno save new seqno for bidirectional check */ | ||
| 478 | if (has_directlink_flag && compare_orig(if_incoming->net_dev->dev_addr, batman_packet->orig) && | ||
| 479 | (batman_packet->seqno - if_incoming_seqno + 2 == 0)) { | ||
| 480 | bit_mark((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * NUM_WORDS]), 0); | ||
| 481 | 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])); | ||
| 482 | } | ||
| 483 | |||
| 484 | debug_log(LOG_TYPE_BATMAN, "Drop packet: originator packet from myself (via neighbour) \n"); | ||
| 485 | return; | ||
| 486 | } | ||
| 487 | |||
| 488 | if (batman_packet->tq == 0) { | ||
| 489 | count_real_packets(ethhdr, batman_packet, if_incoming); | ||
| 490 | |||
| 491 | debug_log(LOG_TYPE_BATMAN, "Drop packet: originator packet with tq equal 0 \n"); | ||
| 492 | return; | ||
| 493 | } | ||
| 494 | |||
| 495 | if (is_my_oldorig) { | ||
| 496 | debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all rebroadcast echos (sender: %s) \n", neigh_str); | ||
| 497 | return; | ||
| 498 | } | ||
| 499 | |||
| 500 | is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming); | ||
| 501 | |||
| 502 | orig_node = get_orig_node(batman_packet->orig); | ||
| 503 | if (orig_node == NULL) | ||
| 504 | return; | ||
| 505 | |||
| 506 | /* avoid temporary routing loops */ | ||
| 507 | if ((orig_node->router) && (orig_node->router->orig_node->router) && | ||
| 508 | (compare_orig(orig_node->router->addr, batman_packet->prev_sender)) && | ||
| 509 | !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) && | ||
| 510 | (compare_orig(orig_node->router->addr, orig_node->router->orig_node->router->addr))) { | ||
| 511 | debug_log(LOG_TYPE_BATMAN, "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %s) \n", neigh_str); | ||
| 512 | return; | ||
| 513 | } | ||
| 514 | |||
| 515 | /* if sender is a direct neighbor the sender mac equals originator mac */ | ||
| 516 | orig_neigh_node = (is_single_hop_neigh ? orig_node : get_orig_node(ethhdr->h_source)); | ||
| 517 | if (orig_neigh_node == NULL) | ||
| 518 | return; | ||
| 519 | |||
| 520 | /* drop packet if sender is not a direct neighbor and if we don't route towards it */ | ||
| 521 | if (!is_single_hop_neigh && (orig_neigh_node->router == NULL)) { | ||
| 522 | debug_log(LOG_TYPE_BATMAN, "Drop packet: OGM via unknown neighbor! \n"); | ||
| 523 | return; | ||
| 524 | } | ||
| 525 | |||
| 526 | is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node, batman_packet, if_incoming); | ||
| 527 | |||
| 528 | /* update ranking if it is not a duplicate or has the same seqno and similar ttl as the non-duplicate */ | ||
| 529 | if (is_bidirectional && (!is_duplicate || | ||
| 530 | ((orig_node->last_real_seqno == batman_packet->seqno) && | ||
| 531 | (orig_node->last_ttl - 3 <= batman_packet->ttl)))) | ||
| 532 | update_orig(orig_node, ethhdr, batman_packet, if_incoming, hna_buff, hna_buff_len, is_duplicate); | ||
| 533 | |||
| 534 | /* is single hop (direct) neighbour */ | ||
| 535 | if (is_single_hop_neigh) { | ||
| 536 | |||
| 537 | /* mark direct link on incoming interface */ | ||
| 538 | schedule_forward_packet(orig_node, ethhdr, batman_packet, 1, hna_buff_len, if_incoming); | ||
| 539 | |||
| 540 | debug_log(LOG_TYPE_BATMAN, "Forwarding packet: rebroadcast neighbour packet with direct link flag \n"); | ||
| 541 | return; | ||
| 542 | } | ||
| 543 | |||
| 544 | /* multihop originator */ | ||
| 545 | if (!is_bidirectional) { | ||
| 546 | debug_log(LOG_TYPE_BATMAN, "Drop packet: not received via bidirectional link\n"); | ||
| 547 | return; | ||
| 548 | } | ||
| 549 | |||
| 550 | if (is_duplicate) { | ||
| 551 | debug_log(LOG_TYPE_BATMAN, "Drop packet: duplicate packet received\n"); | ||
| 552 | return; | ||
| 553 | } | ||
| 554 | |||
| 555 | debug_log(LOG_TYPE_BATMAN, "Forwarding packet: rebroadcast originator packet \n"); | ||
| 556 | schedule_forward_packet(orig_node, ethhdr, batman_packet, 0, hna_buff_len, if_incoming); | ||
| 557 | } | ||
| 558 | |||
| 559 | void purge_orig(struct work_struct *work) | ||
| 560 | { | ||
| 561 | struct list_head *list_pos, *list_pos_tmp; | ||
| 562 | struct hash_it_t *hashit = NULL; | ||
| 563 | struct orig_node *orig_node; | ||
| 564 | struct neigh_node *neigh_node, *best_neigh_node; | ||
| 565 | char orig_str[ETH_STR_LEN], neigh_str[ETH_STR_LEN], neigh_purged; | ||
| 566 | |||
| 567 | spin_lock(&orig_hash_lock); | ||
| 568 | |||
| 569 | /* for all origins... */ | ||
| 570 | while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { | ||
| 571 | |||
| 572 | orig_node = hashit->bucket->data; | ||
| 573 | addr_to_string(orig_str, orig_node->orig); | ||
| 574 | |||
| 575 | if (time_after(jiffies, orig_node->last_valid + ((2 * PURGE_TIMEOUT * HZ) / 1000))) { | ||
| 576 | |||
| 577 | debug_log(LOG_TYPE_BATMAN, "Originator timeout: originator %s, last_valid %u \n", orig_str, (orig_node->last_valid / HZ)); | ||
| 578 | |||
| 579 | hash_remove_bucket(orig_hash, hashit); | ||
| 580 | free_orig_node(orig_node); | ||
| 581 | |||
| 582 | } else { | ||
| 583 | |||
| 584 | best_neigh_node = NULL; | ||
| 585 | neigh_purged = 0; | ||
| 586 | |||
| 587 | /* for all neighbours towards this originator ... */ | ||
| 588 | list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { | ||
| 589 | neigh_node = list_entry(list_pos, struct neigh_node, list); | ||
| 590 | |||
| 591 | if (time_after(jiffies, neigh_node->last_valid + ((PURGE_TIMEOUT * HZ) / 1000))) { | ||
| 592 | |||
| 593 | addr_to_string(neigh_str, neigh_node->addr); | ||
| 594 | debug_log(LOG_TYPE_BATMAN, "Neighbour timeout: originator %s, neighbour: %s, last_valid %u \n", orig_str, neigh_str, (neigh_node->last_valid / HZ)); | ||
| 595 | |||
| 596 | neigh_purged = 1; | ||
| 597 | list_del(list_pos); | ||
| 598 | kfree(neigh_node); | ||
| 599 | |||
| 600 | } else { | ||
| 601 | |||
| 602 | if ((best_neigh_node == NULL) || (neigh_node->tq_avg > best_neigh_node->tq_avg)) | ||
| 603 | best_neigh_node = neigh_node; | ||
| 604 | |||
| 605 | } | ||
| 606 | |||
| 607 | } | ||
| 608 | |||
| 609 | if (neigh_purged) | ||
| 610 | update_routes(orig_node, best_neigh_node, orig_node->hna_buff, orig_node->hna_buff_len); | ||
| 611 | |||
| 612 | } | ||
| 613 | |||
| 614 | } | ||
| 615 | |||
| 616 | spin_unlock(&orig_hash_lock); | ||
| 617 | |||
| 618 | start_purge_timer(); | ||
| 619 | } | ||
| 620 | |||
| 621 | static int receive_raw_packet(struct socket *raw_sock, unsigned char *packet_buff, int packet_buff_len) | ||
| 622 | { | ||
| 623 | struct kvec iov; | ||
| 624 | struct msghdr msg; | ||
| 625 | |||
| 626 | iov.iov_base = packet_buff; | ||
| 627 | iov.iov_len = packet_buff_len; | ||
| 628 | |||
| 629 | msg.msg_flags = MSG_DONTWAIT; /* non-blocking */ | ||
| 630 | msg.msg_name = NULL; | ||
| 631 | msg.msg_namelen = 0; | ||
| 632 | msg.msg_control = NULL; | ||
| 633 | |||
| 634 | return kernel_recvmsg(raw_sock, &msg, &iov, 1, packet_buff_len, MSG_DONTWAIT); | ||
| 635 | } | ||
| 636 | |||
| 637 | int packet_recv_thread(void *data) | ||
| 638 | { | ||
| 639 | struct batman_if *batman_if; | ||
| 640 | struct ethhdr *ethhdr; | ||
| 641 | struct batman_packet *batman_packet; | ||
| 642 | struct unicast_packet *unicast_packet; | ||
| 643 | struct bcast_packet *bcast_packet; | ||
| 644 | struct icmp_packet *icmp_packet; | ||
| 645 | struct vis_packet *vis_packet; | ||
| 646 | struct orig_node *orig_node; | ||
| 647 | unsigned char *packet_buff, src_str[ETH_STR_LEN], dst_str[ETH_STR_LEN]; | ||
| 648 | int vis_info_len; | ||
| 649 | int result; | ||
| 650 | |||
| 651 | atomic_set(&data_ready_cond, 0); | ||
| 652 | atomic_set(&exit_cond, 0); | ||
| 653 | packet_buff = kmalloc(PACKBUFF_SIZE, GFP_KERNEL); | ||
| 654 | if (!packet_buff) { | ||
| 655 | debug_log(LOG_TYPE_CRIT, "Could allocate memory for the packet buffer. :(\n"); | ||
| 656 | return -1; | ||
| 657 | } | ||
| 658 | |||
| 659 | while ((!kthread_should_stop()) && (!atomic_read(&exit_cond))) { | ||
| 660 | |||
| 661 | wait_event_interruptible(thread_wait, (atomic_read(&data_ready_cond) || atomic_read(&exit_cond))); | ||
| 662 | |||
| 663 | atomic_set(&data_ready_cond, 0); | ||
| 664 | |||
| 665 | if (kthread_should_stop() || atomic_read(&exit_cond)) | ||
| 666 | break; | ||
| 667 | |||
| 668 | /* we only want to safely traverse the list, hard-interfaces | ||
| 669 | * won't be deleted anyway as long as this thread runs. */ | ||
| 670 | |||
| 671 | rcu_read_lock(); | ||
| 672 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 673 | rcu_read_unlock(); | ||
| 674 | |||
| 675 | result = -1; | ||
| 676 | |||
| 677 | while (1) { | ||
| 678 | if (batman_if->if_active != IF_ACTIVE) { | ||
| 679 | if (batman_if->if_active != IF_TO_BE_ACTIVATED) | ||
| 680 | debug_log(LOG_TYPE_NOTICE, | ||
| 681 | "Could not read from deactivated interface %s!\n", | ||
| 682 | batman_if->dev); | ||
| 683 | |||
| 684 | if (batman_if->raw_sock) | ||
| 685 | receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE); | ||
| 686 | result = 0; | ||
| 687 | break; | ||
| 688 | } | ||
| 689 | |||
| 690 | result = receive_raw_packet(batman_if->raw_sock, packet_buff, PACKBUFF_SIZE); | ||
| 691 | if (result <= 0) | ||
| 692 | break; | ||
| 693 | |||
| 694 | if (result < sizeof(struct ethhdr) + 2) | ||
| 695 | continue; | ||
| 696 | |||
| 697 | ethhdr = (struct ethhdr *)packet_buff; | ||
| 698 | batman_packet = (struct batman_packet *)(packet_buff + sizeof(struct ethhdr)); | ||
| 699 | |||
| 700 | if (batman_packet->version != COMPAT_VERSION) { | ||
| 701 | debug_log(LOG_TYPE_BATMAN, "Drop packet: incompatible batman version (%i) \n", batman_packet->version); | ||
| 702 | continue; | ||
| 703 | } | ||
| 704 | |||
| 705 | switch (batman_packet->packet_type) { | ||
| 706 | /* batman originator packet */ | ||
| 707 | case BAT_PACKET: | ||
| 708 | /* packet with broadcast indication but unicast recipient */ | ||
| 709 | if (!is_bcast(ethhdr->h_dest)) | ||
| 710 | continue; | ||
| 711 | |||
| 712 | /* packet with broadcast sender address */ | ||
| 713 | if (is_bcast(ethhdr->h_source)) | ||
| 714 | continue; | ||
| 715 | |||
| 716 | /* drop packet if it has not at least one batman packet as payload */ | ||
| 717 | if (result < sizeof(struct ethhdr) + sizeof(struct batman_packet)) | ||
| 718 | continue; | ||
| 719 | |||
| 720 | spin_lock(&orig_hash_lock); | ||
| 721 | receive_aggr_bat_packet(ethhdr, | ||
| 722 | packet_buff + sizeof(struct ethhdr), | ||
| 723 | result - sizeof(struct ethhdr), | ||
| 724 | batman_if); | ||
| 725 | spin_unlock(&orig_hash_lock); | ||
| 726 | |||
| 727 | break; | ||
| 728 | |||
| 729 | /* batman icmp packet */ | ||
| 730 | case BAT_ICMP: | ||
| 731 | /* packet with unicast indication but broadcast recipient */ | ||
| 732 | if (is_bcast(ethhdr->h_dest)) | ||
| 733 | continue; | ||
| 734 | |||
| 735 | /* packet with broadcast sender address */ | ||
| 736 | if (is_bcast(ethhdr->h_source)) | ||
| 737 | continue; | ||
| 738 | |||
| 739 | /* not for me */ | ||
| 740 | if (!is_my_mac(ethhdr->h_dest)) | ||
| 741 | continue; | ||
| 742 | |||
| 743 | /* drop packet if it has not necessary minimum size */ | ||
| 744 | if (result < sizeof(struct ethhdr) + sizeof(struct icmp_packet)) | ||
| 745 | continue; | ||
| 746 | |||
| 747 | icmp_packet = (struct icmp_packet *)(packet_buff + sizeof(struct ethhdr)); | ||
| 748 | |||
| 749 | /* packet for me */ | ||
| 750 | if (is_my_mac(icmp_packet->dst)) { | ||
| 751 | |||
| 752 | /* add data to device queue */ | ||
| 753 | if (icmp_packet->msg_type != ECHO_REQUEST) { | ||
| 754 | bat_device_receive_packet(icmp_packet); | ||
| 755 | continue; | ||
| 756 | } | ||
| 757 | |||
| 758 | /* answer echo request (ping) */ | ||
| 759 | /* get routing information */ | ||
| 760 | spin_lock(&orig_hash_lock); | ||
| 761 | orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig)); | ||
| 762 | |||
| 763 | if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) { | ||
| 764 | |||
| 765 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | ||
| 766 | memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); | ||
| 767 | icmp_packet->msg_type = ECHO_REPLY; | ||
| 768 | icmp_packet->ttl = TTL; | ||
| 769 | |||
| 770 | send_raw_packet(packet_buff + sizeof(struct ethhdr), | ||
| 771 | result - sizeof(struct ethhdr), | ||
| 772 | orig_node->batman_if, | ||
| 773 | orig_node->router->addr); | ||
| 774 | |||
| 775 | } | ||
| 776 | |||
| 777 | spin_unlock(&orig_hash_lock); | ||
| 778 | continue; | ||
| 779 | |||
| 780 | } | ||
| 781 | |||
| 782 | /* TTL exceeded */ | ||
| 783 | if (icmp_packet->ttl < 2) { | ||
| 784 | |||
| 785 | addr_to_string(src_str, icmp_packet->orig); | ||
| 786 | addr_to_string(dst_str, icmp_packet->dst); | ||
| 787 | |||
| 788 | debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str); | ||
| 789 | |||
| 790 | /* send TTL exceeded if packet is an echo request (traceroute) */ | ||
| 791 | if (icmp_packet->msg_type != ECHO_REQUEST) | ||
| 792 | continue; | ||
| 793 | |||
| 794 | /* get routing information */ | ||
| 795 | spin_lock(&orig_hash_lock); | ||
| 796 | orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->orig)); | ||
| 797 | |||
| 798 | if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) { | ||
| 799 | |||
| 800 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | ||
| 801 | memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); | ||
| 802 | icmp_packet->msg_type = TTL_EXCEEDED; | ||
| 803 | icmp_packet->ttl = TTL; | ||
| 804 | |||
| 805 | send_raw_packet(packet_buff + sizeof(struct ethhdr), | ||
| 806 | result - sizeof(struct ethhdr), | ||
| 807 | orig_node->batman_if, | ||
| 808 | orig_node->router->addr); | ||
| 809 | |||
| 810 | } | ||
| 811 | |||
| 812 | spin_unlock(&orig_hash_lock); | ||
| 813 | continue; | ||
| 814 | |||
| 815 | } | ||
| 816 | |||
| 817 | /* get routing information */ | ||
| 818 | spin_lock(&orig_hash_lock); | ||
| 819 | orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet->dst)); | ||
| 820 | |||
| 821 | if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) { | ||
| 822 | |||
| 823 | /* decrement ttl */ | ||
| 824 | icmp_packet->ttl--; | ||
| 825 | |||
| 826 | /* route it */ | ||
| 827 | send_raw_packet(packet_buff + sizeof(struct ethhdr), | ||
| 828 | result - sizeof(struct ethhdr), | ||
| 829 | orig_node->batman_if, | ||
| 830 | orig_node->router->addr); | ||
| 831 | } | ||
| 832 | |||
| 833 | spin_unlock(&orig_hash_lock); | ||
| 834 | break; | ||
| 835 | |||
| 836 | /* unicast packet */ | ||
| 837 | case BAT_UNICAST: | ||
| 838 | /* packet with unicast indication but broadcast recipient */ | ||
| 839 | if (is_bcast(ethhdr->h_dest)) | ||
| 840 | continue; | ||
| 841 | |||
| 842 | /* packet with broadcast sender address */ | ||
| 843 | if (is_bcast(ethhdr->h_source)) | ||
| 844 | continue; | ||
| 845 | |||
| 846 | /* not for me */ | ||
| 847 | if (!is_my_mac(ethhdr->h_dest)) | ||
| 848 | continue; | ||
| 849 | |||
| 850 | /* drop packet if it has not necessary minimum size */ | ||
| 851 | if (result < sizeof(struct ethhdr) + sizeof(struct unicast_packet)) | ||
| 852 | continue; | ||
| 853 | |||
| 854 | unicast_packet = (struct unicast_packet *)(packet_buff + sizeof(struct ethhdr)); | ||
| 855 | |||
| 856 | /* packet for me */ | ||
| 857 | if (is_my_mac(unicast_packet->dest)) { | ||
| 858 | |||
| 859 | interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct unicast_packet), result - sizeof(struct ethhdr) - sizeof(struct unicast_packet)); | ||
| 860 | continue; | ||
| 861 | |||
| 862 | } | ||
| 863 | |||
| 864 | /* TTL exceeded */ | ||
| 865 | if (unicast_packet->ttl < 2) { | ||
| 866 | addr_to_string(src_str, ((struct ethhdr *)(unicast_packet + 1))->h_source); | ||
| 867 | addr_to_string(dst_str, unicast_packet->dest); | ||
| 868 | |||
| 869 | debug_log(LOG_TYPE_NOTICE, "Error - can't send packet from %s to %s: ttl exceeded\n", src_str, dst_str); | ||
| 870 | continue; | ||
| 871 | } | ||
| 872 | |||
| 873 | /* get routing information */ | ||
| 874 | spin_lock(&orig_hash_lock); | ||
| 875 | orig_node = ((struct orig_node *)hash_find(orig_hash, unicast_packet->dest)); | ||
| 876 | |||
| 877 | if ((orig_node != NULL) && (orig_node->batman_if != NULL) && (orig_node->router != NULL)) { | ||
| 878 | /* decrement ttl */ | ||
| 879 | unicast_packet->ttl--; | ||
| 880 | |||
| 881 | /* route it */ | ||
| 882 | send_raw_packet(packet_buff + sizeof(struct ethhdr), | ||
| 883 | result - sizeof(struct ethhdr), | ||
| 884 | orig_node->batman_if, | ||
| 885 | orig_node->router->addr); | ||
| 886 | } | ||
| 887 | |||
| 888 | spin_unlock(&orig_hash_lock); | ||
| 889 | break; | ||
| 890 | |||
| 891 | /* broadcast packet */ | ||
| 892 | case BAT_BCAST: | ||
| 893 | /* packet with broadcast indication but unicast recipient */ | ||
| 894 | if (!is_bcast(ethhdr->h_dest)) | ||
| 895 | continue; | ||
| 896 | |||
| 897 | /* packet with broadcast sender address */ | ||
| 898 | if (is_bcast(ethhdr->h_source)) | ||
| 899 | continue; | ||
| 900 | |||
| 901 | /* drop packet if it has not necessary minimum size */ | ||
| 902 | if (result < sizeof(struct ethhdr) + sizeof(struct bcast_packet)) | ||
| 903 | continue; | ||
| 904 | |||
| 905 | /* ignore broadcasts sent by myself */ | ||
| 906 | if (is_my_mac(ethhdr->h_source)) | ||
| 907 | continue; | ||
| 908 | |||
| 909 | bcast_packet = (struct bcast_packet *)(packet_buff + sizeof(struct ethhdr)); | ||
| 910 | |||
| 911 | /* ignore broadcasts originated by myself */ | ||
| 912 | if (is_my_mac(bcast_packet->orig)) | ||
| 913 | continue; | ||
| 914 | |||
| 915 | spin_lock(&orig_hash_lock); | ||
| 916 | orig_node = ((struct orig_node *)hash_find(orig_hash, bcast_packet->orig)); | ||
| 917 | |||
| 918 | if (orig_node == NULL) { | ||
| 919 | spin_unlock(&orig_hash_lock); | ||
| 920 | continue; | ||
| 921 | } | ||
| 922 | |||
| 923 | /* check flood history */ | ||
| 924 | if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, ntohs(bcast_packet->seqno))) { | ||
| 925 | spin_unlock(&orig_hash_lock); | ||
| 926 | continue; | ||
| 927 | } | ||
| 928 | |||
| 929 | /* mark broadcast in flood history */ | ||
| 930 | if (bit_get_packet(orig_node->bcast_bits, ntohs(bcast_packet->seqno) - orig_node->last_bcast_seqno, 1)) | ||
| 931 | orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno); | ||
| 932 | |||
| 933 | spin_unlock(&orig_hash_lock); | ||
| 934 | |||
| 935 | /* broadcast for me */ | ||
| 936 | interface_rx(soft_device, packet_buff + sizeof(struct ethhdr) + sizeof(struct bcast_packet), result - sizeof(struct ethhdr) - sizeof(struct bcast_packet)); | ||
| 937 | |||
| 938 | /* rebroadcast packet */ | ||
| 939 | add_bcast_packet_to_list(packet_buff + sizeof(struct ethhdr), | ||
| 940 | result - sizeof(struct ethhdr)); | ||
| 941 | |||
| 942 | break; | ||
| 943 | |||
| 944 | /* vis packet */ | ||
| 945 | case BAT_VIS: | ||
| 946 | /* drop if too short. */ | ||
| 947 | if (result < sizeof(struct ethhdr) + sizeof(struct vis_packet)) | ||
| 948 | continue; | ||
| 949 | |||
| 950 | /* not for me */ | ||
| 951 | if (!is_my_mac(ethhdr->h_dest)) | ||
| 952 | continue; | ||
| 953 | |||
| 954 | vis_packet = (struct vis_packet *)(packet_buff + sizeof(struct ethhdr)); | ||
| 955 | vis_info_len = result - sizeof(struct ethhdr) - sizeof(struct vis_packet); | ||
| 956 | |||
| 957 | /* ignore own packets */ | ||
| 958 | if (is_my_mac(vis_packet->vis_orig)) | ||
| 959 | continue; | ||
| 960 | |||
| 961 | if (is_my_mac(vis_packet->sender_orig)) | ||
| 962 | continue; | ||
| 963 | |||
| 964 | switch (vis_packet->vis_type) { | ||
| 965 | case VIS_TYPE_SERVER_SYNC: | ||
| 966 | receive_server_sync_packet(vis_packet, vis_info_len); | ||
| 967 | break; | ||
| 968 | |||
| 969 | case VIS_TYPE_CLIENT_UPDATE: | ||
| 970 | receive_client_update_packet(vis_packet, vis_info_len); | ||
| 971 | break; | ||
| 972 | |||
| 973 | default: /* ignore unknown packet */ | ||
| 974 | break; | ||
| 975 | } | ||
| 976 | |||
| 977 | break; | ||
| 978 | } | ||
| 979 | |||
| 980 | } | ||
| 981 | |||
| 982 | if ((result < 0) && (result != -EAGAIN)) | ||
| 983 | debug_log(LOG_TYPE_CRIT, "Could not receive packet from interface %s: %i\n", batman_if->dev, result); | ||
| 984 | |||
| 985 | /* lock for the next iteration */ | ||
| 986 | rcu_read_lock(); | ||
| 987 | } | ||
| 988 | rcu_read_unlock(); | ||
| 989 | |||
| 990 | } | ||
| 991 | kfree(packet_buff); | ||
| 992 | |||
| 993 | /* do not exit until kthread_stop() is actually called, otherwise it will wait for us | ||
| 994 | * forever. */ | ||
| 995 | while (!kthread_should_stop()) | ||
| 996 | schedule(); | ||
| 997 | |||
| 998 | return 0; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | void batman_data_ready(struct sock *sk, int len) | ||
| 1002 | { | ||
| 1003 | void (*data_ready)(struct sock *, int) = sk->sk_user_data; | ||
| 1004 | |||
| 1005 | data_ready(sk, len); | ||
| 1006 | |||
| 1007 | atomic_set(&data_ready_cond, 1); | ||
| 1008 | wake_up_interruptible(&thread_wait); | ||
| 1009 | } | ||
| 1010 | |||
diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h new file mode 100644 index 000000000000..0123ea86debb --- /dev/null +++ b/drivers/staging/batman-adv/routing.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "types.h" | ||
| 23 | |||
| 24 | extern wait_queue_head_t thread_wait; | ||
| 25 | extern atomic_t exit_cond; | ||
| 26 | |||
| 27 | int originator_init(void); | ||
| 28 | void free_orig_node(void *data); | ||
| 29 | void originator_free(void); | ||
| 30 | void slide_own_bcast_window(struct batman_if *batman_if); | ||
| 31 | void batman_data_ready(struct sock *sk, int len); | ||
| 32 | void purge_orig(struct work_struct *work); | ||
| 33 | int packet_recv_thread(void *data); | ||
| 34 | 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); | ||
diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c new file mode 100644 index 000000000000..d724798278d6 --- /dev/null +++ b/drivers/staging/batman-adv/send.c | |||
| @@ -0,0 +1,473 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "send.h" | ||
| 24 | #include "log.h" | ||
| 25 | #include "routing.h" | ||
| 26 | #include "translation-table.h" | ||
| 27 | #include "hard-interface.h" | ||
| 28 | #include "types.h" | ||
| 29 | #include "vis.h" | ||
| 30 | #include "aggregation.h" | ||
| 31 | |||
| 32 | #include "compat.h" | ||
| 33 | |||
| 34 | /* apply hop penalty for a normal link */ | ||
| 35 | static uint8_t hop_penalty(const uint8_t tq) | ||
| 36 | { | ||
| 37 | return (tq * (TQ_MAX_VALUE - TQ_HOP_PENALTY)) / (TQ_MAX_VALUE); | ||
| 38 | } | ||
| 39 | |||
| 40 | /* when do we schedule our own packet to be sent */ | ||
| 41 | static unsigned long own_send_time(void) | ||
| 42 | { | ||
| 43 | return jiffies + | ||
| 44 | (((atomic_read(&originator_interval) - JITTER + | ||
| 45 | (random32() % 2*JITTER)) * HZ) / 1000); | ||
| 46 | } | ||
| 47 | |||
| 48 | /* when do we schedule a forwarded packet to be sent */ | ||
| 49 | static unsigned long forward_send_time(void) | ||
| 50 | { | ||
| 51 | unsigned long send_time = jiffies; /* Starting now plus... */ | ||
| 52 | |||
| 53 | if (atomic_read(&aggregation_enabled)) | ||
| 54 | send_time += (((MAX_AGGREGATION_MS - (JITTER/2) + | ||
| 55 | (random32() % JITTER)) * HZ) / 1000); | ||
| 56 | else | ||
| 57 | send_time += (((random32() % (JITTER/2)) * HZ) / 1000); | ||
| 58 | |||
| 59 | return send_time; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* sends a raw packet. */ | ||
| 63 | void send_raw_packet(unsigned char *pack_buff, int pack_buff_len, | ||
| 64 | struct batman_if *batman_if, uint8_t *dst_addr) | ||
| 65 | { | ||
| 66 | struct ethhdr *ethhdr; | ||
| 67 | struct sk_buff *skb; | ||
| 68 | int retval; | ||
| 69 | char *data; | ||
| 70 | |||
| 71 | if (batman_if->if_active != IF_ACTIVE) | ||
| 72 | return; | ||
| 73 | |||
| 74 | if (!(batman_if->net_dev->flags & IFF_UP)) { | ||
| 75 | debug_log(LOG_TYPE_WARN, | ||
| 76 | "Interface %s is not up - can't send packet via that interface (IF_TO_BE_DEACTIVATED was here) !\n", | ||
| 77 | batman_if->dev); | ||
| 78 | return; | ||
| 79 | } | ||
| 80 | |||
| 81 | skb = dev_alloc_skb(pack_buff_len + sizeof(struct ethhdr)); | ||
| 82 | if (!skb) | ||
| 83 | return; | ||
| 84 | data = skb_put(skb, pack_buff_len + sizeof(struct ethhdr)); | ||
| 85 | |||
| 86 | memcpy(data + sizeof(struct ethhdr), pack_buff, pack_buff_len); | ||
| 87 | |||
| 88 | ethhdr = (struct ethhdr *) data; | ||
| 89 | memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN); | ||
| 90 | memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); | ||
| 91 | ethhdr->h_proto = __constant_htons(ETH_P_BATMAN); | ||
| 92 | |||
| 93 | skb_reset_mac_header(skb); | ||
| 94 | skb_set_network_header(skb, ETH_HLEN); | ||
| 95 | skb->priority = TC_PRIO_CONTROL; | ||
| 96 | skb->protocol = __constant_htons(ETH_P_BATMAN); | ||
| 97 | skb->dev = batman_if->net_dev; | ||
| 98 | |||
| 99 | /* dev_queue_xmit() returns a negative result on error. However on | ||
| 100 | * congestion and traffic shaping, it drops and returns NET_XMIT_DROP | ||
| 101 | * (which is > 0). This will not be treated as an error. */ | ||
| 102 | retval = dev_queue_xmit(skb); | ||
| 103 | if (retval < 0) | ||
| 104 | debug_log(LOG_TYPE_CRIT, | ||
| 105 | "Can't write to raw socket (IF_TO_BE_DEACTIVATED was here): %i\n", | ||
| 106 | retval); | ||
| 107 | } | ||
| 108 | |||
| 109 | /* Send a packet to a given interface */ | ||
| 110 | static void send_packet_to_if(struct forw_packet *forw_packet, | ||
| 111 | struct batman_if *batman_if) | ||
| 112 | { | ||
| 113 | char *fwd_str; | ||
| 114 | uint8_t packet_num; | ||
| 115 | int16_t buff_pos; | ||
| 116 | struct batman_packet *batman_packet; | ||
| 117 | char orig_str[ETH_STR_LEN]; | ||
| 118 | |||
| 119 | if (batman_if->if_active != IF_ACTIVE) | ||
| 120 | return; | ||
| 121 | |||
| 122 | packet_num = buff_pos = 0; | ||
| 123 | batman_packet = (struct batman_packet *) | ||
| 124 | (forw_packet->packet_buff); | ||
| 125 | |||
| 126 | /* adjust all flags and log packets */ | ||
| 127 | while (aggregated_packet(buff_pos, | ||
| 128 | forw_packet->packet_len, | ||
| 129 | batman_packet->num_hna)) { | ||
| 130 | |||
| 131 | /* we might have aggregated direct link packets with an | ||
| 132 | * ordinary base packet */ | ||
| 133 | if ((forw_packet->direct_link_flags & (1 << packet_num)) && | ||
| 134 | (forw_packet->if_incoming == batman_if)) | ||
| 135 | batman_packet->flags |= DIRECTLINK; | ||
| 136 | else | ||
| 137 | batman_packet->flags &= ~DIRECTLINK; | ||
| 138 | |||
| 139 | addr_to_string(orig_str, batman_packet->orig); | ||
| 140 | fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ? | ||
| 141 | "Sending own" : | ||
| 142 | "Forwarding")); | ||
| 143 | debug_log(LOG_TYPE_BATMAN, | ||
| 144 | "%s %spacket (originator %s, seqno %d, TQ %d, TTL %d, IDF %s) on interface %s [%s]\n", | ||
| 145 | fwd_str, | ||
| 146 | (packet_num > 0 ? "aggregated " : ""), | ||
| 147 | orig_str, ntohs(batman_packet->seqno), | ||
| 148 | batman_packet->tq, batman_packet->ttl, | ||
| 149 | (batman_packet->flags & DIRECTLINK ? | ||
| 150 | "on" : "off"), | ||
| 151 | batman_if->dev, batman_if->addr_str); | ||
| 152 | |||
| 153 | buff_pos += sizeof(struct batman_packet) + | ||
| 154 | (batman_packet->num_hna * ETH_ALEN); | ||
| 155 | packet_num++; | ||
| 156 | batman_packet = (struct batman_packet *) | ||
| 157 | (forw_packet->packet_buff + buff_pos); | ||
| 158 | } | ||
| 159 | |||
| 160 | send_raw_packet(forw_packet->packet_buff, | ||
| 161 | forw_packet->packet_len, | ||
| 162 | batman_if, broadcastAddr); | ||
| 163 | } | ||
| 164 | |||
| 165 | /* send a batman packet */ | ||
| 166 | static void send_packet(struct forw_packet *forw_packet) | ||
| 167 | { | ||
| 168 | struct batman_if *batman_if; | ||
| 169 | struct batman_packet *batman_packet = | ||
| 170 | (struct batman_packet *)(forw_packet->packet_buff); | ||
| 171 | char orig_str[ETH_STR_LEN]; | ||
| 172 | unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0); | ||
| 173 | |||
| 174 | if (!forw_packet->if_incoming) { | ||
| 175 | debug_log(LOG_TYPE_CRIT, | ||
| 176 | "Error - can't forward packet: incoming iface not specified\n"); | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | |||
| 180 | if (forw_packet->if_incoming->if_active != IF_ACTIVE) | ||
| 181 | return; | ||
| 182 | |||
| 183 | addr_to_string(orig_str, batman_packet->orig); | ||
| 184 | |||
| 185 | /* multihomed peer assumed */ | ||
| 186 | /* non-primary OGMs are only broadcasted on their interface */ | ||
| 187 | if ((directlink && (batman_packet->ttl == 1)) || | ||
| 188 | (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) { | ||
| 189 | |||
| 190 | /* FIXME: what about aggregated packets ? */ | ||
| 191 | debug_log(LOG_TYPE_BATMAN, | ||
| 192 | "%s packet (originator %s, seqno %d, TTL %d) on interface %s [%s]\n", | ||
| 193 | (forw_packet->own ? "Sending own" : "Forwarding"), | ||
| 194 | orig_str, ntohs(batman_packet->seqno), | ||
| 195 | batman_packet->ttl, forw_packet->if_incoming->dev, | ||
| 196 | forw_packet->if_incoming->addr_str); | ||
| 197 | |||
| 198 | send_raw_packet(forw_packet->packet_buff, | ||
| 199 | forw_packet->packet_len, | ||
| 200 | forw_packet->if_incoming, | ||
| 201 | broadcastAddr); | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* broadcast on every interface */ | ||
| 206 | rcu_read_lock(); | ||
| 207 | list_for_each_entry_rcu(batman_if, &if_list, list) | ||
| 208 | send_packet_to_if(forw_packet, batman_if); | ||
| 209 | rcu_read_unlock(); | ||
| 210 | } | ||
| 211 | |||
| 212 | static void rebuild_batman_packet(struct batman_if *batman_if) | ||
| 213 | { | ||
| 214 | int new_len; | ||
| 215 | unsigned char *new_buff; | ||
| 216 | struct batman_packet *batman_packet; | ||
| 217 | |||
| 218 | new_len = sizeof(struct batman_packet) + (num_hna * ETH_ALEN); | ||
| 219 | new_buff = kmalloc(new_len, GFP_ATOMIC); | ||
| 220 | |||
| 221 | /* keep old buffer if kmalloc should fail */ | ||
| 222 | if (new_buff) { | ||
| 223 | memcpy(new_buff, batman_if->packet_buff, | ||
| 224 | sizeof(struct batman_packet)); | ||
| 225 | batman_packet = (struct batman_packet *)new_buff; | ||
| 226 | |||
| 227 | batman_packet->num_hna = hna_local_fill_buffer( | ||
| 228 | new_buff + sizeof(struct batman_packet), | ||
| 229 | new_len - sizeof(struct batman_packet)); | ||
| 230 | |||
| 231 | kfree(batman_if->packet_buff); | ||
| 232 | batman_if->packet_buff = new_buff; | ||
| 233 | batman_if->packet_len = new_len; | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | void schedule_own_packet(struct batman_if *batman_if) | ||
| 238 | { | ||
| 239 | unsigned long send_time; | ||
| 240 | struct batman_packet *batman_packet; | ||
| 241 | |||
| 242 | /** | ||
| 243 | * the interface gets activated here to avoid race conditions between | ||
| 244 | * the moment of activating the interface in | ||
| 245 | * hardif_activate_interface() where the originator mac is set and | ||
| 246 | * outdated packets (especially uninitialized mac addresses) in the | ||
| 247 | * packet queue | ||
| 248 | */ | ||
| 249 | if (batman_if->if_active == IF_TO_BE_ACTIVATED) | ||
| 250 | batman_if->if_active = IF_ACTIVE; | ||
| 251 | |||
| 252 | /* if local hna has changed and interface is a primary interface */ | ||
| 253 | if ((atomic_read(&hna_local_changed)) && (batman_if->if_num == 0)) | ||
| 254 | rebuild_batman_packet(batman_if); | ||
| 255 | |||
| 256 | /** | ||
| 257 | * NOTE: packet_buff might just have been re-allocated in | ||
| 258 | * rebuild_batman_packet() | ||
| 259 | */ | ||
| 260 | batman_packet = (struct batman_packet *)batman_if->packet_buff; | ||
| 261 | |||
| 262 | /* change sequence number to network order */ | ||
| 263 | batman_packet->seqno = htons((uint16_t)atomic_read(&batman_if->seqno)); | ||
| 264 | |||
| 265 | if (is_vis_server()) | ||
| 266 | batman_packet->flags = VIS_SERVER; | ||
| 267 | else | ||
| 268 | batman_packet->flags = 0; | ||
| 269 | |||
| 270 | /* could be read by receive_bat_packet() */ | ||
| 271 | atomic_inc(&batman_if->seqno); | ||
| 272 | |||
| 273 | slide_own_bcast_window(batman_if); | ||
| 274 | send_time = own_send_time(); | ||
| 275 | add_bat_packet_to_list(batman_if->packet_buff, | ||
| 276 | batman_if->packet_len, batman_if, 1, send_time); | ||
| 277 | } | ||
| 278 | |||
| 279 | void schedule_forward_packet(struct orig_node *orig_node, | ||
| 280 | struct ethhdr *ethhdr, | ||
| 281 | struct batman_packet *batman_packet, | ||
| 282 | uint8_t directlink, int hna_buff_len, | ||
| 283 | struct batman_if *if_incoming) | ||
| 284 | { | ||
| 285 | unsigned char in_tq, in_ttl, tq_avg = 0; | ||
| 286 | unsigned long send_time; | ||
| 287 | |||
| 288 | if (batman_packet->ttl <= 1) { | ||
| 289 | debug_log(LOG_TYPE_BATMAN, "ttl exceeded \n"); | ||
| 290 | return; | ||
| 291 | } | ||
| 292 | |||
| 293 | in_tq = batman_packet->tq; | ||
| 294 | in_ttl = batman_packet->ttl; | ||
| 295 | |||
| 296 | batman_packet->ttl--; | ||
| 297 | memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN); | ||
| 298 | |||
| 299 | /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast | ||
| 300 | * of our best tq value */ | ||
| 301 | if ((orig_node->router) && (orig_node->router->tq_avg != 0)) { | ||
| 302 | |||
| 303 | /* rebroadcast ogm of best ranking neighbor as is */ | ||
| 304 | if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) { | ||
| 305 | batman_packet->tq = orig_node->router->tq_avg; | ||
| 306 | |||
| 307 | if (orig_node->router->last_ttl) | ||
| 308 | batman_packet->ttl = orig_node->router->last_ttl - 1; | ||
| 309 | } | ||
| 310 | |||
| 311 | tq_avg = orig_node->router->tq_avg; | ||
| 312 | } | ||
| 313 | |||
| 314 | /* apply hop penalty */ | ||
| 315 | batman_packet->tq = hop_penalty(batman_packet->tq); | ||
| 316 | |||
| 317 | debug_log(LOG_TYPE_BATMAN, "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n", | ||
| 318 | in_tq, tq_avg, batman_packet->tq, in_ttl - 1, | ||
| 319 | batman_packet->ttl); | ||
| 320 | |||
| 321 | batman_packet->seqno = htons(batman_packet->seqno); | ||
| 322 | |||
| 323 | if (directlink) | ||
| 324 | batman_packet->flags |= DIRECTLINK; | ||
| 325 | else | ||
| 326 | batman_packet->flags &= ~DIRECTLINK; | ||
| 327 | |||
| 328 | send_time = forward_send_time(); | ||
| 329 | add_bat_packet_to_list((unsigned char *)batman_packet, | ||
| 330 | sizeof(struct batman_packet) + hna_buff_len, | ||
| 331 | if_incoming, 0, send_time); | ||
| 332 | } | ||
| 333 | |||
| 334 | static void forw_packet_free(struct forw_packet *forw_packet) | ||
| 335 | { | ||
| 336 | kfree(forw_packet->packet_buff); | ||
| 337 | kfree(forw_packet); | ||
| 338 | } | ||
| 339 | |||
| 340 | static void _add_bcast_packet_to_list(struct forw_packet *forw_packet, | ||
| 341 | unsigned long send_time) | ||
| 342 | { | ||
| 343 | INIT_HLIST_NODE(&forw_packet->list); | ||
| 344 | |||
| 345 | /* add new packet to packet list */ | ||
| 346 | spin_lock(&forw_bcast_list_lock); | ||
| 347 | hlist_add_head(&forw_packet->list, &forw_bcast_list); | ||
| 348 | spin_unlock(&forw_bcast_list_lock); | ||
| 349 | |||
| 350 | /* start timer for this packet */ | ||
| 351 | INIT_DELAYED_WORK(&forw_packet->delayed_work, | ||
| 352 | send_outstanding_bcast_packet); | ||
| 353 | queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work, | ||
| 354 | send_time); | ||
| 355 | } | ||
| 356 | |||
| 357 | void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len) | ||
| 358 | { | ||
| 359 | struct forw_packet *forw_packet; | ||
| 360 | |||
| 361 | forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); | ||
| 362 | if (!forw_packet) | ||
| 363 | return; | ||
| 364 | |||
| 365 | forw_packet->packet_buff = kmalloc(packet_len, GFP_ATOMIC); | ||
| 366 | if (!forw_packet->packet_buff) | ||
| 367 | return; | ||
| 368 | |||
| 369 | forw_packet->packet_len = packet_len; | ||
| 370 | memcpy(forw_packet->packet_buff, packet_buff, forw_packet->packet_len); | ||
| 371 | |||
| 372 | /* how often did we send the bcast packet ? */ | ||
| 373 | forw_packet->num_packets = 0; | ||
| 374 | |||
| 375 | _add_bcast_packet_to_list(forw_packet, 1); | ||
| 376 | } | ||
| 377 | |||
| 378 | void send_outstanding_bcast_packet(struct work_struct *work) | ||
| 379 | { | ||
| 380 | struct batman_if *batman_if; | ||
| 381 | struct delayed_work *delayed_work = | ||
| 382 | container_of(work, struct delayed_work, work); | ||
| 383 | struct forw_packet *forw_packet = | ||
| 384 | container_of(delayed_work, struct forw_packet, delayed_work); | ||
| 385 | |||
| 386 | spin_lock(&forw_bcast_list_lock); | ||
| 387 | hlist_del(&forw_packet->list); | ||
| 388 | spin_unlock(&forw_bcast_list_lock); | ||
| 389 | |||
| 390 | /* rebroadcast packet */ | ||
| 391 | rcu_read_lock(); | ||
| 392 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
| 393 | send_raw_packet(forw_packet->packet_buff, | ||
| 394 | forw_packet->packet_len, | ||
| 395 | batman_if, broadcastAddr); | ||
| 396 | } | ||
| 397 | rcu_read_unlock(); | ||
| 398 | |||
| 399 | forw_packet->num_packets++; | ||
| 400 | |||
| 401 | /* if we still have some more bcasts to send and we are not shutting | ||
| 402 | * down */ | ||
| 403 | if ((forw_packet->num_packets < 3) && | ||
| 404 | (atomic_read(&module_state) != MODULE_DEACTIVATING)) | ||
| 405 | _add_bcast_packet_to_list(forw_packet, ((5 * HZ) / 1000)); | ||
| 406 | else | ||
| 407 | forw_packet_free(forw_packet); | ||
| 408 | } | ||
| 409 | |||
| 410 | void send_outstanding_bat_packet(struct work_struct *work) | ||
| 411 | { | ||
| 412 | struct delayed_work *delayed_work = | ||
| 413 | container_of(work, struct delayed_work, work); | ||
| 414 | struct forw_packet *forw_packet = | ||
| 415 | container_of(delayed_work, struct forw_packet, delayed_work); | ||
| 416 | |||
| 417 | spin_lock(&forw_bat_list_lock); | ||
| 418 | hlist_del(&forw_packet->list); | ||
| 419 | spin_unlock(&forw_bat_list_lock); | ||
| 420 | |||
| 421 | send_packet(forw_packet); | ||
| 422 | |||
| 423 | /** | ||
| 424 | * we have to have at least one packet in the queue | ||
| 425 | * to determine the queues wake up time unless we are | ||
| 426 | * shutting down | ||
| 427 | */ | ||
| 428 | if ((forw_packet->own) && | ||
| 429 | (atomic_read(&module_state) != MODULE_DEACTIVATING)) | ||
| 430 | schedule_own_packet(forw_packet->if_incoming); | ||
| 431 | |||
| 432 | forw_packet_free(forw_packet); | ||
| 433 | } | ||
| 434 | |||
| 435 | void purge_outstanding_packets(void) | ||
| 436 | { | ||
| 437 | struct forw_packet *forw_packet; | ||
| 438 | struct hlist_node *tmp_node, *safe_tmp_node; | ||
| 439 | |||
| 440 | debug_log(LOG_TYPE_BATMAN, "purge_outstanding_packets()\n"); | ||
| 441 | |||
| 442 | /* free bcast list */ | ||
| 443 | spin_lock(&forw_bcast_list_lock); | ||
| 444 | hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, | ||
| 445 | &forw_bcast_list, list) { | ||
| 446 | |||
| 447 | spin_unlock(&forw_bcast_list_lock); | ||
| 448 | |||
| 449 | /** | ||
| 450 | * send_outstanding_bcast_packet() will lock the list to | ||
| 451 | * delete the item from the list | ||
| 452 | */ | ||
| 453 | cancel_delayed_work_sync(&forw_packet->delayed_work); | ||
| 454 | spin_lock(&forw_bcast_list_lock); | ||
| 455 | } | ||
| 456 | spin_unlock(&forw_bcast_list_lock); | ||
| 457 | |||
| 458 | /* free batman packet list */ | ||
| 459 | spin_lock(&forw_bat_list_lock); | ||
| 460 | hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, | ||
| 461 | &forw_bat_list, list) { | ||
| 462 | |||
| 463 | spin_unlock(&forw_bat_list_lock); | ||
| 464 | |||
| 465 | /** | ||
| 466 | * send_outstanding_bat_packet() will lock the list to | ||
| 467 | * delete the item from the list | ||
| 468 | */ | ||
| 469 | cancel_delayed_work_sync(&forw_packet->delayed_work); | ||
| 470 | spin_lock(&forw_bat_list_lock); | ||
| 471 | } | ||
| 472 | spin_unlock(&forw_bat_list_lock); | ||
| 473 | } | ||
diff --git a/drivers/staging/batman-adv/send.h b/drivers/staging/batman-adv/send.h new file mode 100644 index 000000000000..59d500917a35 --- /dev/null +++ b/drivers/staging/batman-adv/send.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "types.h" | ||
| 23 | |||
| 24 | void send_own_packet_work(struct work_struct *work); | ||
| 25 | void send_raw_packet(unsigned char *pack_buff, int pack_buff_len, | ||
| 26 | struct batman_if *batman_if, uint8_t *dst_addr); | ||
| 27 | void schedule_own_packet(struct batman_if *batman_if); | ||
| 28 | void schedule_forward_packet(struct orig_node *orig_node, | ||
| 29 | struct ethhdr *ethhdr, | ||
| 30 | struct batman_packet *batman_packet, | ||
| 31 | uint8_t directlink, int hna_buff_len, | ||
| 32 | struct batman_if *if_outgoing); | ||
| 33 | void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len); | ||
| 34 | void send_outstanding_bcast_packet(struct work_struct *work); | ||
| 35 | void send_outstanding_bat_packet(struct work_struct *work); | ||
| 36 | void purge_outstanding_packets(void); | ||
diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c new file mode 100644 index 000000000000..d543f50b647f --- /dev/null +++ b/drivers/staging/batman-adv/soft-interface.c | |||
| @@ -0,0 +1,349 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "soft-interface.h" | ||
| 24 | #include "hard-interface.h" | ||
| 25 | #include "send.h" | ||
| 26 | #include "translation-table.h" | ||
| 27 | #include "log.h" | ||
| 28 | #include "types.h" | ||
| 29 | #include "hash.h" | ||
| 30 | #include <linux/ethtool.h> | ||
| 31 | #include <linux/etherdevice.h> | ||
| 32 | #include "compat.h" | ||
| 33 | |||
| 34 | static uint16_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid | ||
| 35 | * broadcast storms */ | ||
| 36 | static int32_t skb_packets; | ||
| 37 | static int32_t skb_bad_packets; | ||
| 38 | static int32_t lock_dropped; | ||
| 39 | |||
| 40 | unsigned char mainIfAddr[ETH_ALEN]; | ||
| 41 | static unsigned char mainIfAddr_default[ETH_ALEN]; | ||
| 42 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); | ||
| 43 | static void bat_get_drvinfo(struct net_device *dev, | ||
| 44 | struct ethtool_drvinfo *info); | ||
| 45 | static u32 bat_get_msglevel(struct net_device *dev); | ||
| 46 | static void bat_set_msglevel(struct net_device *dev, u32 value); | ||
| 47 | static u32 bat_get_link(struct net_device *dev); | ||
| 48 | static u32 bat_get_rx_csum(struct net_device *dev); | ||
| 49 | static int bat_set_rx_csum(struct net_device *dev, u32 data); | ||
| 50 | |||
| 51 | static const struct ethtool_ops bat_ethtool_ops = { | ||
| 52 | .get_settings = bat_get_settings, | ||
| 53 | .get_drvinfo = bat_get_drvinfo, | ||
| 54 | .get_msglevel = bat_get_msglevel, | ||
| 55 | .set_msglevel = bat_set_msglevel, | ||
| 56 | .get_link = bat_get_link, | ||
| 57 | .get_rx_csum = bat_get_rx_csum, | ||
| 58 | .set_rx_csum = bat_set_rx_csum | ||
| 59 | }; | ||
| 60 | |||
| 61 | void set_main_if_addr(uint8_t *addr) | ||
| 62 | { | ||
| 63 | memcpy(mainIfAddr, addr, ETH_ALEN); | ||
| 64 | } | ||
| 65 | |||
| 66 | int main_if_was_up(void) | ||
| 67 | { | ||
| 68 | return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0); | ||
| 69 | } | ||
| 70 | |||
| 71 | static int my_skb_push(struct sk_buff *skb, unsigned int len) | ||
| 72 | { | ||
| 73 | int result = 0; | ||
| 74 | |||
| 75 | skb_packets++; | ||
| 76 | if (skb->data - len < skb->head) { | ||
| 77 | skb_bad_packets++; | ||
| 78 | result = pskb_expand_head(skb, len, 0, GFP_ATOMIC); | ||
| 79 | |||
| 80 | if (result < 0) | ||
| 81 | return result; | ||
| 82 | } | ||
| 83 | |||
| 84 | skb_push(skb, len); | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | #ifdef HAVE_NET_DEVICE_OPS | ||
| 89 | static const struct net_device_ops bat_netdev_ops = { | ||
| 90 | .ndo_open = interface_open, | ||
| 91 | .ndo_stop = interface_release, | ||
| 92 | .ndo_get_stats = interface_stats, | ||
| 93 | .ndo_set_mac_address = interface_set_mac_addr, | ||
| 94 | .ndo_change_mtu = interface_change_mtu, | ||
| 95 | .ndo_start_xmit = interface_tx, | ||
| 96 | .ndo_validate_addr = eth_validate_addr | ||
| 97 | }; | ||
| 98 | #endif | ||
| 99 | |||
| 100 | void interface_setup(struct net_device *dev) | ||
| 101 | { | ||
| 102 | struct bat_priv *priv = netdev_priv(dev); | ||
| 103 | char dev_addr[ETH_ALEN]; | ||
| 104 | |||
| 105 | ether_setup(dev); | ||
| 106 | |||
| 107 | #ifdef HAVE_NET_DEVICE_OPS | ||
| 108 | dev->netdev_ops = &bat_netdev_ops; | ||
| 109 | #else | ||
| 110 | dev->open = interface_open; | ||
| 111 | dev->stop = interface_release; | ||
| 112 | dev->get_stats = interface_stats; | ||
| 113 | dev->set_mac_address = interface_set_mac_addr; | ||
| 114 | dev->change_mtu = interface_change_mtu; | ||
| 115 | dev->hard_start_xmit = interface_tx; | ||
| 116 | #endif | ||
| 117 | dev->destructor = free_netdev; | ||
| 118 | |||
| 119 | dev->mtu = hardif_min_mtu(); | ||
| 120 | dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the | ||
| 121 | * skbuff for our header */ | ||
| 122 | |||
| 123 | /* generate random address */ | ||
| 124 | random_ether_addr(dev_addr); | ||
| 125 | memcpy(dev->dev_addr, dev_addr, sizeof(dev->dev_addr)); | ||
| 126 | |||
| 127 | SET_ETHTOOL_OPS(dev, &bat_ethtool_ops); | ||
| 128 | |||
| 129 | memset(priv, 0, sizeof(struct bat_priv)); | ||
| 130 | } | ||
| 131 | |||
| 132 | int interface_open(struct net_device *dev) | ||
| 133 | { | ||
| 134 | netif_start_queue(dev); | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | int interface_release(struct net_device *dev) | ||
| 139 | { | ||
| 140 | netif_stop_queue(dev); | ||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | struct net_device_stats *interface_stats(struct net_device *dev) | ||
| 145 | { | ||
| 146 | struct bat_priv *priv = netdev_priv(dev); | ||
| 147 | return &priv->stats; | ||
| 148 | } | ||
| 149 | |||
| 150 | int interface_set_mac_addr(struct net_device *dev, void *addr) | ||
| 151 | { | ||
| 152 | return -EBUSY; | ||
| 153 | } | ||
| 154 | |||
| 155 | int interface_change_mtu(struct net_device *dev, int new_mtu) | ||
| 156 | { | ||
| 157 | /* check ranges */ | ||
| 158 | if ((new_mtu < 68) || (new_mtu > hardif_min_mtu())) | ||
| 159 | return -EINVAL; | ||
| 160 | |||
| 161 | dev->mtu = new_mtu; | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | int interface_tx(struct sk_buff *skb, struct net_device *dev) | ||
| 167 | { | ||
| 168 | struct unicast_packet *unicast_packet; | ||
| 169 | struct bcast_packet *bcast_packet; | ||
| 170 | struct orig_node *orig_node; | ||
| 171 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
| 172 | struct bat_priv *priv = netdev_priv(dev); | ||
| 173 | int data_len = skb->len; | ||
| 174 | |||
| 175 | if (atomic_read(&module_state) != MODULE_ACTIVE) | ||
| 176 | goto dropped; | ||
| 177 | |||
| 178 | dev->trans_start = jiffies; | ||
| 179 | /* TODO: check this for locks */ | ||
| 180 | hna_local_add(ethhdr->h_source); | ||
| 181 | |||
| 182 | /* ethernet packet should be broadcasted */ | ||
| 183 | if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) { | ||
| 184 | |||
| 185 | if (my_skb_push(skb, sizeof(struct bcast_packet)) < 0) | ||
| 186 | goto dropped; | ||
| 187 | |||
| 188 | bcast_packet = (struct bcast_packet *)skb->data; | ||
| 189 | |||
| 190 | bcast_packet->version = COMPAT_VERSION; | ||
| 191 | |||
| 192 | /* batman packet type: broadcast */ | ||
| 193 | bcast_packet->packet_type = BAT_BCAST; | ||
| 194 | |||
| 195 | /* hw address of first interface is the orig mac because only | ||
| 196 | * this mac is known throughout the mesh */ | ||
| 197 | memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN); | ||
| 198 | /* set broadcast sequence number */ | ||
| 199 | bcast_packet->seqno = htons(bcast_seqno); | ||
| 200 | |||
| 201 | bcast_seqno++; | ||
| 202 | |||
| 203 | /* broadcast packet */ | ||
| 204 | add_bcast_packet_to_list(skb->data, skb->len); | ||
| 205 | |||
| 206 | /* unicast packet */ | ||
| 207 | } else { | ||
| 208 | |||
| 209 | /* simply spin_lock()ing can deadlock when the lock is already | ||
| 210 | * hold. */ | ||
| 211 | /* TODO: defer the work in a working queue instead of | ||
| 212 | * dropping */ | ||
| 213 | if (!spin_trylock(&orig_hash_lock)) { | ||
| 214 | lock_dropped++; | ||
| 215 | debug_log(LOG_TYPE_NOTICE, "%d packets dropped because lock was hold\n", lock_dropped); | ||
| 216 | goto dropped; | ||
| 217 | } | ||
| 218 | |||
| 219 | /* get routing information */ | ||
| 220 | orig_node = ((struct orig_node *)hash_find(orig_hash, | ||
| 221 | ethhdr->h_dest)); | ||
| 222 | |||
| 223 | /* check for hna host */ | ||
| 224 | if (!orig_node) | ||
| 225 | orig_node = transtable_search(ethhdr->h_dest); | ||
| 226 | |||
| 227 | if ((orig_node) && | ||
| 228 | (orig_node->batman_if) && | ||
| 229 | (orig_node->router)) { | ||
| 230 | if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0) | ||
| 231 | goto unlock; | ||
| 232 | |||
| 233 | unicast_packet = (struct unicast_packet *)skb->data; | ||
| 234 | |||
| 235 | unicast_packet->version = COMPAT_VERSION; | ||
| 236 | /* batman packet type: unicast */ | ||
| 237 | unicast_packet->packet_type = BAT_UNICAST; | ||
| 238 | /* set unicast ttl */ | ||
| 239 | unicast_packet->ttl = TTL; | ||
| 240 | /* copy the destination for faster routing */ | ||
| 241 | memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); | ||
| 242 | |||
| 243 | /* net_dev won't be available when not active */ | ||
| 244 | if (orig_node->batman_if->if_active != IF_ACTIVE) | ||
| 245 | goto unlock; | ||
| 246 | |||
| 247 | send_raw_packet(skb->data, skb->len, | ||
| 248 | orig_node->batman_if, | ||
| 249 | orig_node->router->addr); | ||
| 250 | } else { | ||
| 251 | goto unlock; | ||
| 252 | } | ||
| 253 | |||
| 254 | spin_unlock(&orig_hash_lock); | ||
| 255 | } | ||
| 256 | |||
| 257 | priv->stats.tx_packets++; | ||
| 258 | priv->stats.tx_bytes += data_len; | ||
| 259 | goto end; | ||
| 260 | |||
| 261 | unlock: | ||
| 262 | spin_unlock(&orig_hash_lock); | ||
| 263 | dropped: | ||
| 264 | priv->stats.tx_dropped++; | ||
| 265 | end: | ||
| 266 | kfree_skb(skb); | ||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | |||
| 270 | void interface_rx(struct net_device *dev, void *packet, int packet_len) | ||
| 271 | { | ||
| 272 | struct sk_buff *skb; | ||
| 273 | struct bat_priv *priv = netdev_priv(dev); | ||
| 274 | |||
| 275 | skb = dev_alloc_skb(packet_len); | ||
| 276 | |||
| 277 | if (!skb) { | ||
| 278 | priv->stats.rx_dropped++; | ||
| 279 | goto out; | ||
| 280 | } | ||
| 281 | |||
| 282 | memcpy(skb_put(skb, packet_len), packet, packet_len); | ||
| 283 | |||
| 284 | /* Write metadata, and then pass to the receive level */ | ||
| 285 | skb->dev = dev; | ||
| 286 | skb->protocol = eth_type_trans(skb, dev); | ||
| 287 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 288 | |||
| 289 | priv->stats.rx_packets++; | ||
| 290 | priv->stats.rx_bytes += packet_len; | ||
| 291 | |||
| 292 | dev->last_rx = jiffies; | ||
| 293 | |||
| 294 | netif_rx(skb); | ||
| 295 | |||
| 296 | out: | ||
| 297 | return; | ||
| 298 | } | ||
| 299 | |||
| 300 | /* ethtool */ | ||
| 301 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
| 302 | { | ||
| 303 | cmd->supported = 0; | ||
| 304 | cmd->advertising = 0; | ||
| 305 | cmd->speed = SPEED_10; | ||
| 306 | cmd->duplex = DUPLEX_FULL; | ||
| 307 | cmd->port = PORT_TP; | ||
| 308 | cmd->phy_address = 0; | ||
| 309 | cmd->transceiver = XCVR_INTERNAL; | ||
| 310 | cmd->autoneg = AUTONEG_DISABLE; | ||
| 311 | cmd->maxtxpkt = 0; | ||
| 312 | cmd->maxrxpkt = 0; | ||
| 313 | |||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | |||
| 317 | static void bat_get_drvinfo(struct net_device *dev, | ||
| 318 | struct ethtool_drvinfo *info) | ||
| 319 | { | ||
| 320 | strcpy(info->driver, "B.A.T.M.A.N. advanced"); | ||
| 321 | strcpy(info->version, SOURCE_VERSION); | ||
| 322 | strcpy(info->fw_version, "N/A"); | ||
| 323 | strcpy(info->bus_info, "batman"); | ||
| 324 | } | ||
| 325 | |||
| 326 | static u32 bat_get_msglevel(struct net_device *dev) | ||
| 327 | { | ||
| 328 | return -EOPNOTSUPP; | ||
| 329 | } | ||
| 330 | |||
| 331 | static void bat_set_msglevel(struct net_device *dev, u32 value) | ||
| 332 | { | ||
| 333 | return; | ||
| 334 | } | ||
| 335 | |||
| 336 | static u32 bat_get_link(struct net_device *dev) | ||
| 337 | { | ||
| 338 | return 1; | ||
| 339 | } | ||
| 340 | |||
| 341 | static u32 bat_get_rx_csum(struct net_device *dev) | ||
| 342 | { | ||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | static int bat_set_rx_csum(struct net_device *dev, u32 data) | ||
| 347 | { | ||
| 348 | return -EOPNOTSUPP; | ||
| 349 | } | ||
diff --git a/drivers/staging/batman-adv/soft-interface.h b/drivers/staging/batman-adv/soft-interface.h new file mode 100644 index 000000000000..515e276ef53d --- /dev/null +++ b/drivers/staging/batman-adv/soft-interface.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | void set_main_if_addr(uint8_t *addr); | ||
| 23 | int main_if_was_up(void); | ||
| 24 | void interface_setup(struct net_device *dev); | ||
| 25 | int interface_open(struct net_device *dev); | ||
| 26 | int interface_release(struct net_device *dev); | ||
| 27 | struct net_device_stats *interface_stats(struct net_device *dev); | ||
| 28 | int interface_set_mac_addr(struct net_device *dev, void *addr); | ||
| 29 | int interface_change_mtu(struct net_device *dev, int new_mtu); | ||
| 30 | int interface_tx(struct sk_buff *skb, struct net_device *dev); | ||
| 31 | void interface_rx(struct net_device *dev, void *packet, int packet_len); | ||
| 32 | |||
| 33 | extern unsigned char mainIfAddr[]; | ||
diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c new file mode 100644 index 000000000000..c2190e177c56 --- /dev/null +++ b/drivers/staging/batman-adv/translation-table.c | |||
| @@ -0,0 +1,454 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "translation-table.h" | ||
| 24 | #include "log.h" | ||
| 25 | #include "soft-interface.h" | ||
| 26 | #include "types.h" | ||
| 27 | #include "hash.h" | ||
| 28 | #include "compat.h" | ||
| 29 | |||
| 30 | struct hashtable_t *hna_local_hash; | ||
| 31 | static struct hashtable_t *hna_global_hash; | ||
| 32 | atomic_t hna_local_changed; | ||
| 33 | |||
| 34 | DEFINE_SPINLOCK(hna_local_hash_lock); | ||
| 35 | static DEFINE_SPINLOCK(hna_global_hash_lock); | ||
| 36 | |||
| 37 | static DECLARE_DELAYED_WORK(hna_local_purge_wq, hna_local_purge); | ||
| 38 | |||
| 39 | static void hna_local_start_timer(void) | ||
| 40 | { | ||
| 41 | queue_delayed_work(bat_event_workqueue, &hna_local_purge_wq, 10 * HZ); | ||
| 42 | } | ||
| 43 | |||
| 44 | int hna_local_init(void) | ||
| 45 | { | ||
| 46 | if (hna_local_hash) | ||
| 47 | return 1; | ||
| 48 | |||
| 49 | hna_local_hash = hash_new(128, compare_orig, choose_orig); | ||
| 50 | |||
| 51 | if (!hna_local_hash) | ||
| 52 | return 0; | ||
| 53 | |||
| 54 | atomic_set(&hna_local_changed, 0); | ||
| 55 | hna_local_start_timer(); | ||
| 56 | |||
| 57 | return 1; | ||
| 58 | } | ||
| 59 | |||
| 60 | void hna_local_add(uint8_t *addr) | ||
| 61 | { | ||
| 62 | struct hna_local_entry *hna_local_entry; | ||
| 63 | struct hna_global_entry *hna_global_entry; | ||
| 64 | struct hashtable_t *swaphash; | ||
| 65 | char hna_str[ETH_STR_LEN]; | ||
| 66 | unsigned long flags; | ||
| 67 | |||
| 68 | spin_lock_irqsave(&hna_local_hash_lock, flags); | ||
| 69 | hna_local_entry = | ||
| 70 | ((struct hna_local_entry *)hash_find(hna_local_hash, addr)); | ||
| 71 | spin_unlock_irqrestore(&hna_local_hash_lock, flags); | ||
| 72 | |||
| 73 | if (hna_local_entry != NULL) { | ||
| 74 | hna_local_entry->last_seen = jiffies; | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | |||
| 78 | addr_to_string(hna_str, addr); | ||
| 79 | |||
| 80 | /* only announce as many hosts as possible in the batman-packet and | ||
| 81 | space in batman_packet->num_hna That also should give a limit to | ||
| 82 | MAC-flooding. */ | ||
| 83 | if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) || | ||
| 84 | (num_hna + 1 > 255)) { | ||
| 85 | debug_log(LOG_TYPE_ROUTES, "Can't add new local hna entry (%s): number of local hna entries exceeds packet size \n", hna_str); | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 89 | debug_log(LOG_TYPE_ROUTES, "Creating new local hna entry: %s \n", | ||
| 90 | hna_str); | ||
| 91 | |||
| 92 | hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC); | ||
| 93 | if (!hna_local_entry) | ||
| 94 | return; | ||
| 95 | |||
| 96 | memcpy(hna_local_entry->addr, addr, ETH_ALEN); | ||
| 97 | hna_local_entry->last_seen = jiffies; | ||
| 98 | |||
| 99 | /* the batman interface mac address should never be purged */ | ||
| 100 | if (compare_orig(addr, soft_device->dev_addr)) | ||
| 101 | hna_local_entry->never_purge = 1; | ||
| 102 | else | ||
| 103 | hna_local_entry->never_purge = 0; | ||
| 104 | |||
| 105 | spin_lock_irqsave(&hna_local_hash_lock, flags); | ||
| 106 | |||
| 107 | hash_add(hna_local_hash, hna_local_entry); | ||
| 108 | num_hna++; | ||
| 109 | atomic_set(&hna_local_changed, 1); | ||
| 110 | |||
| 111 | if (hna_local_hash->elements * 4 > hna_local_hash->size) { | ||
| 112 | swaphash = hash_resize(hna_local_hash, | ||
| 113 | hna_local_hash->size * 2); | ||
| 114 | |||
| 115 | if (swaphash == NULL) | ||
| 116 | debug_log(LOG_TYPE_CRIT, "Couldn't resize local hna hash table \n"); | ||
| 117 | else | ||
| 118 | hna_local_hash = swaphash; | ||
| 119 | } | ||
| 120 | |||
| 121 | spin_unlock_irqrestore(&hna_local_hash_lock, flags); | ||
| 122 | |||
| 123 | /* remove address from global hash if present */ | ||
| 124 | spin_lock_irqsave(&hna_global_hash_lock, flags); | ||
| 125 | |||
| 126 | hna_global_entry = | ||
| 127 | ((struct hna_global_entry *)hash_find(hna_global_hash, addr)); | ||
| 128 | |||
| 129 | if (hna_global_entry != NULL) | ||
| 130 | _hna_global_del_orig(hna_global_entry, "local hna received"); | ||
| 131 | |||
| 132 | spin_unlock_irqrestore(&hna_global_hash_lock, flags); | ||
| 133 | } | ||
| 134 | |||
| 135 | int hna_local_fill_buffer(unsigned char *buff, int buff_len) | ||
| 136 | { | ||
| 137 | struct hna_local_entry *hna_local_entry; | ||
| 138 | struct hash_it_t *hashit = NULL; | ||
| 139 | int i = 0; | ||
| 140 | unsigned long flags; | ||
| 141 | |||
| 142 | spin_lock_irqsave(&hna_local_hash_lock, flags); | ||
| 143 | |||
| 144 | while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) { | ||
| 145 | |||
| 146 | if (buff_len < (i + 1) * ETH_ALEN) | ||
| 147 | break; | ||
| 148 | |||
| 149 | hna_local_entry = hashit->bucket->data; | ||
| 150 | memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN); | ||
| 151 | |||
| 152 | i++; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* if we did not get all new local hnas see you next time ;-) */ | ||
| 156 | if (i == num_hna) | ||
| 157 | atomic_set(&hna_local_changed, 0); | ||
| 158 | |||
| 159 | spin_unlock_irqrestore(&hna_local_hash_lock, flags); | ||
| 160 | |||
| 161 | return i; | ||
| 162 | } | ||
| 163 | |||
| 164 | int hna_local_fill_buffer_text(unsigned char *buff, int buff_len) | ||
| 165 | { | ||
| 166 | struct hna_local_entry *hna_local_entry; | ||
| 167 | struct hash_it_t *hashit = NULL; | ||
| 168 | int bytes_written = 0; | ||
| 169 | unsigned long flags; | ||
| 170 | |||
| 171 | spin_lock_irqsave(&hna_local_hash_lock, flags); | ||
| 172 | |||
| 173 | while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) { | ||
| 174 | |||
| 175 | if (buff_len < bytes_written + ETH_STR_LEN + 4) | ||
| 176 | break; | ||
| 177 | |||
| 178 | hna_local_entry = hashit->bucket->data; | ||
| 179 | |||
| 180 | bytes_written += snprintf(buff + bytes_written, ETH_STR_LEN + 4, | ||
| 181 | " * %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
| 182 | hna_local_entry->addr[0], | ||
| 183 | hna_local_entry->addr[1], | ||
| 184 | hna_local_entry->addr[2], | ||
| 185 | hna_local_entry->addr[3], | ||
| 186 | hna_local_entry->addr[4], | ||
| 187 | hna_local_entry->addr[5]); | ||
| 188 | } | ||
| 189 | |||
| 190 | spin_unlock_irqrestore(&hna_local_hash_lock, flags); | ||
| 191 | |||
| 192 | return bytes_written; | ||
| 193 | } | ||
| 194 | |||
| 195 | static void _hna_local_del(void *data) | ||
| 196 | { | ||
| 197 | kfree(data); | ||
| 198 | num_hna--; | ||
| 199 | atomic_set(&hna_local_changed, 1); | ||
| 200 | } | ||
| 201 | |||
| 202 | static void hna_local_del(struct hna_local_entry *hna_local_entry, | ||
| 203 | char *message) | ||
| 204 | { | ||
| 205 | char hna_str[ETH_STR_LEN]; | ||
| 206 | |||
| 207 | addr_to_string(hna_str, hna_local_entry->addr); | ||
| 208 | debug_log(LOG_TYPE_ROUTES, "Deleting local hna entry (%s): %s \n", | ||
| 209 | hna_str, message); | ||
| 210 | |||
| 211 | hash_remove(hna_local_hash, hna_local_entry->addr); | ||
| 212 | _hna_local_del(hna_local_entry); | ||
| 213 | } | ||
| 214 | |||
| 215 | void hna_local_purge(struct work_struct *work) | ||
| 216 | { | ||
| 217 | struct hna_local_entry *hna_local_entry; | ||
| 218 | struct hash_it_t *hashit = NULL; | ||
| 219 | unsigned long flags; | ||
| 220 | unsigned long timeout; | ||
| 221 | |||
| 222 | spin_lock_irqsave(&hna_local_hash_lock, flags); | ||
| 223 | |||
| 224 | while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) { | ||
| 225 | hna_local_entry = hashit->bucket->data; | ||
| 226 | |||
| 227 | timeout = hna_local_entry->last_seen + | ||
| 228 | ((LOCAL_HNA_TIMEOUT / 1000) * HZ); | ||
| 229 | if ((!hna_local_entry->never_purge) && | ||
| 230 | time_after(jiffies, timeout)) | ||
| 231 | hna_local_del(hna_local_entry, "address timed out"); | ||
| 232 | } | ||
| 233 | |||
| 234 | spin_unlock_irqrestore(&hna_local_hash_lock, flags); | ||
| 235 | hna_local_start_timer(); | ||
| 236 | } | ||
| 237 | |||
| 238 | void hna_local_free(void) | ||
| 239 | { | ||
| 240 | if (!hna_local_hash) | ||
| 241 | return; | ||
| 242 | |||
| 243 | cancel_delayed_work_sync(&hna_local_purge_wq); | ||
| 244 | hash_delete(hna_local_hash, _hna_local_del); | ||
| 245 | hna_local_hash = NULL; | ||
| 246 | } | ||
| 247 | |||
| 248 | int hna_global_init(void) | ||
| 249 | { | ||
| 250 | if (hna_global_hash) | ||
| 251 | return 1; | ||
| 252 | |||
| 253 | hna_global_hash = hash_new(128, compare_orig, choose_orig); | ||
| 254 | |||
| 255 | if (!hna_global_hash) | ||
| 256 | return 0; | ||
| 257 | |||
| 258 | return 1; | ||
| 259 | } | ||
| 260 | |||
| 261 | void hna_global_add_orig(struct orig_node *orig_node, | ||
| 262 | unsigned char *hna_buff, int hna_buff_len) | ||
| 263 | { | ||
| 264 | struct hna_global_entry *hna_global_entry; | ||
| 265 | struct hna_local_entry *hna_local_entry; | ||
| 266 | struct hashtable_t *swaphash; | ||
| 267 | char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN]; | ||
| 268 | int hna_buff_count = 0; | ||
| 269 | unsigned long flags; | ||
| 270 | unsigned char *hna_ptr; | ||
| 271 | |||
| 272 | addr_to_string(orig_str, orig_node->orig); | ||
| 273 | |||
| 274 | while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { | ||
| 275 | spin_lock_irqsave(&hna_global_hash_lock, flags); | ||
| 276 | |||
| 277 | hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); | ||
| 278 | hna_global_entry = (struct hna_global_entry *) | ||
| 279 | hash_find(hna_global_hash, hna_ptr); | ||
| 280 | |||
| 281 | if (hna_global_entry == NULL) { | ||
| 282 | spin_unlock_irqrestore(&hna_global_hash_lock, flags); | ||
| 283 | |||
| 284 | hna_global_entry = | ||
| 285 | kmalloc(sizeof(struct hna_global_entry), | ||
| 286 | GFP_ATOMIC); | ||
| 287 | |||
| 288 | if (!hna_global_entry) | ||
| 289 | break; | ||
| 290 | |||
| 291 | memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN); | ||
| 292 | |||
| 293 | addr_to_string(hna_str, hna_global_entry->addr); | ||
| 294 | debug_log(LOG_TYPE_ROUTES, "Creating new global hna entry: %s (via %s)\n", hna_str, orig_str); | ||
| 295 | |||
| 296 | spin_lock_irqsave(&hna_global_hash_lock, flags); | ||
| 297 | hash_add(hna_global_hash, hna_global_entry); | ||
| 298 | |||
| 299 | } | ||
| 300 | |||
| 301 | hna_global_entry->orig_node = orig_node; | ||
| 302 | spin_unlock_irqrestore(&hna_global_hash_lock, flags); | ||
| 303 | |||
| 304 | /* remove address from local hash if present */ | ||
| 305 | spin_lock_irqsave(&hna_local_hash_lock, flags); | ||
| 306 | |||
| 307 | hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); | ||
| 308 | hna_local_entry = (struct hna_local_entry *) | ||
| 309 | hash_find(hna_local_hash, hna_ptr); | ||
| 310 | |||
| 311 | if (hna_local_entry != NULL) | ||
| 312 | hna_local_del(hna_local_entry, "global hna received"); | ||
| 313 | |||
| 314 | spin_unlock_irqrestore(&hna_local_hash_lock, flags); | ||
| 315 | |||
| 316 | hna_buff_count++; | ||
| 317 | } | ||
| 318 | |||
| 319 | orig_node->hna_buff_len = hna_buff_len; | ||
| 320 | |||
| 321 | if (orig_node->hna_buff_len > 0) { | ||
| 322 | orig_node->hna_buff = kmalloc(orig_node->hna_buff_len, | ||
| 323 | GFP_ATOMIC); | ||
| 324 | memcpy(orig_node->hna_buff, hna_buff, orig_node->hna_buff_len); | ||
| 325 | } else { | ||
| 326 | orig_node->hna_buff = NULL; | ||
| 327 | } | ||
| 328 | |||
| 329 | spin_lock_irqsave(&hna_global_hash_lock, flags); | ||
| 330 | |||
| 331 | if (hna_global_hash->elements * 4 > hna_global_hash->size) { | ||
| 332 | swaphash = hash_resize(hna_global_hash, | ||
| 333 | hna_global_hash->size * 2); | ||
| 334 | |||
| 335 | if (swaphash == NULL) | ||
| 336 | debug_log(LOG_TYPE_CRIT, "Couldn't resize global hna hash table \n"); | ||
| 337 | else | ||
| 338 | hna_global_hash = swaphash; | ||
| 339 | } | ||
| 340 | |||
| 341 | spin_unlock_irqrestore(&hna_global_hash_lock, flags); | ||
| 342 | } | ||
| 343 | |||
| 344 | int hna_global_fill_buffer_text(unsigned char *buff, int buff_len) | ||
| 345 | { | ||
| 346 | struct hna_global_entry *hna_global_entry; | ||
| 347 | struct hash_it_t *hashit = NULL; | ||
| 348 | int bytes_written = 0; | ||
| 349 | unsigned long flags; | ||
| 350 | |||
| 351 | spin_lock_irqsave(&hna_global_hash_lock, flags); | ||
| 352 | |||
| 353 | while (NULL != (hashit = hash_iterate(hna_global_hash, hashit))) { | ||
| 354 | if (buff_len < bytes_written + (2 * ETH_STR_LEN) + 10) | ||
| 355 | break; | ||
| 356 | |||
| 357 | hna_global_entry = hashit->bucket->data; | ||
| 358 | |||
| 359 | bytes_written += snprintf(buff + bytes_written, | ||
| 360 | (2 * ETH_STR_LEN) + 10, | ||
| 361 | " * %02x:%02x:%02x:%02x:%02x:%02x via %02x:%02x:%02x:%02x:%02x:%02x \n", | ||
| 362 | hna_global_entry->addr[0], | ||
| 363 | hna_global_entry->addr[1], | ||
| 364 | hna_global_entry->addr[2], | ||
| 365 | hna_global_entry->addr[3], | ||
| 366 | hna_global_entry->addr[4], | ||
| 367 | hna_global_entry->addr[5], | ||
| 368 | hna_global_entry->orig_node->orig[0], | ||
| 369 | hna_global_entry->orig_node->orig[1], | ||
| 370 | hna_global_entry->orig_node->orig[2], | ||
| 371 | hna_global_entry->orig_node->orig[3], | ||
| 372 | hna_global_entry->orig_node->orig[4], | ||
| 373 | hna_global_entry->orig_node->orig[5]); | ||
| 374 | } | ||
| 375 | |||
| 376 | spin_unlock_irqrestore(&hna_global_hash_lock, flags); | ||
| 377 | |||
| 378 | return bytes_written; | ||
| 379 | } | ||
| 380 | |||
| 381 | void _hna_global_del_orig(struct hna_global_entry *hna_global_entry, | ||
| 382 | char *message) | ||
| 383 | { | ||
| 384 | char hna_str[ETH_STR_LEN], orig_str[ETH_STR_LEN]; | ||
| 385 | |||
| 386 | addr_to_string(orig_str, hna_global_entry->orig_node->orig); | ||
| 387 | addr_to_string(hna_str, hna_global_entry->addr); | ||
| 388 | |||
| 389 | debug_log(LOG_TYPE_ROUTES, "Deleting global hna entry %s (via %s): %s \n", hna_str, orig_str, message); | ||
| 390 | |||
| 391 | hash_remove(hna_global_hash, hna_global_entry->addr); | ||
| 392 | kfree(hna_global_entry); | ||
| 393 | } | ||
| 394 | |||
| 395 | void hna_global_del_orig(struct orig_node *orig_node, char *message) | ||
| 396 | { | ||
| 397 | struct hna_global_entry *hna_global_entry; | ||
| 398 | int hna_buff_count = 0; | ||
| 399 | unsigned long flags; | ||
| 400 | unsigned char *hna_ptr; | ||
| 401 | |||
| 402 | if (orig_node->hna_buff_len == 0) | ||
| 403 | return; | ||
| 404 | |||
| 405 | spin_lock_irqsave(&hna_global_hash_lock, flags); | ||
| 406 | |||
| 407 | while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { | ||
| 408 | hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); | ||
| 409 | hna_global_entry = (struct hna_global_entry *) | ||
| 410 | hash_find(hna_global_hash, hna_ptr); | ||
| 411 | |||
| 412 | if ((hna_global_entry != NULL) && | ||
| 413 | (hna_global_entry->orig_node == orig_node)) | ||
| 414 | _hna_global_del_orig(hna_global_entry, message); | ||
| 415 | |||
| 416 | hna_buff_count++; | ||
| 417 | } | ||
| 418 | |||
| 419 | spin_unlock_irqrestore(&hna_global_hash_lock, flags); | ||
| 420 | |||
| 421 | orig_node->hna_buff_len = 0; | ||
| 422 | kfree(orig_node->hna_buff); | ||
| 423 | orig_node->hna_buff = NULL; | ||
| 424 | } | ||
| 425 | |||
| 426 | static void hna_global_del(void *data) | ||
| 427 | { | ||
| 428 | kfree(data); | ||
| 429 | } | ||
| 430 | |||
| 431 | void hna_global_free(void) | ||
| 432 | { | ||
| 433 | if (!hna_global_hash) | ||
| 434 | return; | ||
| 435 | |||
| 436 | hash_delete(hna_global_hash, hna_global_del); | ||
| 437 | hna_global_hash = NULL; | ||
| 438 | } | ||
| 439 | |||
| 440 | struct orig_node *transtable_search(uint8_t *addr) | ||
| 441 | { | ||
| 442 | struct hna_global_entry *hna_global_entry; | ||
| 443 | unsigned long flags; | ||
| 444 | |||
| 445 | spin_lock_irqsave(&hna_global_hash_lock, flags); | ||
| 446 | hna_global_entry = (struct hna_global_entry *) | ||
| 447 | hash_find(hna_global_hash, addr); | ||
| 448 | spin_unlock_irqrestore(&hna_global_hash_lock, flags); | ||
| 449 | |||
| 450 | if (hna_global_entry == NULL) | ||
| 451 | return NULL; | ||
| 452 | |||
| 453 | return hna_global_entry->orig_node; | ||
| 454 | } | ||
diff --git a/drivers/staging/batman-adv/translation-table.h b/drivers/staging/batman-adv/translation-table.h new file mode 100644 index 000000000000..f7da81129318 --- /dev/null +++ b/drivers/staging/batman-adv/translation-table.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "types.h" | ||
| 23 | |||
| 24 | int hna_local_init(void); | ||
| 25 | void hna_local_add(uint8_t *addr); | ||
| 26 | int hna_local_fill_buffer(unsigned char *buff, int buff_len); | ||
| 27 | int hna_local_fill_buffer_text(unsigned char *buff, int buff_len); | ||
| 28 | void hna_local_purge(struct work_struct *work); | ||
| 29 | void hna_local_free(void); | ||
| 30 | int hna_global_init(void); | ||
| 31 | void hna_global_add_orig(struct orig_node *orig_node, unsigned char *hna_buff, | ||
| 32 | int hna_buff_len); | ||
| 33 | int hna_global_fill_buffer_text(unsigned char *buff, int buff_len); | ||
| 34 | void _hna_global_del_orig(struct hna_global_entry *hna_global_entry, | ||
| 35 | char *orig_str); | ||
| 36 | void hna_global_del_orig(struct orig_node *orig_node, char *message); | ||
| 37 | void hna_global_free(void); | ||
| 38 | struct orig_node *transtable_search(uint8_t *addr); | ||
| 39 | |||
| 40 | extern spinlock_t hna_local_hash_lock; | ||
| 41 | extern struct hashtable_t *hna_local_hash; | ||
| 42 | extern atomic_t hna_local_changed; | ||
diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h new file mode 100644 index 000000000000..3a0ef0c38c93 --- /dev/null +++ b/drivers/staging/batman-adv/types.h | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | #ifndef TYPES_H | ||
| 27 | #define TYPES_H | ||
| 28 | |||
| 29 | #include "packet.h" | ||
| 30 | #include "bitarray.h" | ||
| 31 | |||
| 32 | #define BAT_HEADER_LEN (sizeof(struct ethhdr) + ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? sizeof(struct unicast_packet) : sizeof(struct bcast_packet)))) | ||
| 33 | |||
| 34 | |||
| 35 | struct batman_if { | ||
| 36 | struct list_head list; | ||
| 37 | int16_t if_num; | ||
| 38 | char *dev; | ||
| 39 | char if_active; | ||
| 40 | char addr_str[ETH_STR_LEN]; | ||
| 41 | struct net_device *net_dev; | ||
| 42 | struct socket *raw_sock; | ||
| 43 | atomic_t seqno; | ||
| 44 | unsigned char *packet_buff; | ||
| 45 | int packet_len; | ||
| 46 | struct rcu_head rcu; | ||
| 47 | |||
| 48 | }; | ||
| 49 | |||
| 50 | struct orig_node { /* structure for orig_list maintaining nodes of mesh */ | ||
| 51 | uint8_t orig[ETH_ALEN]; | ||
| 52 | struct neigh_node *router; | ||
| 53 | struct batman_if *batman_if; | ||
| 54 | TYPE_OF_WORD *bcast_own; | ||
| 55 | uint8_t *bcast_own_sum; | ||
| 56 | uint8_t tq_own; | ||
| 57 | int tq_asym_penalty; | ||
| 58 | unsigned long last_valid; /* when last packet from this node was received */ | ||
| 59 | /* uint8_t gwflags; * flags related to gateway functions: gateway class */ | ||
| 60 | uint8_t flags; /* for now only VIS_SERVER flag. */ | ||
| 61 | unsigned char *hna_buff; | ||
| 62 | int16_t hna_buff_len; | ||
| 63 | uint16_t last_real_seqno; /* last and best known squence number */ | ||
| 64 | uint8_t last_ttl; /* ttl of last received packet */ | ||
| 65 | TYPE_OF_WORD bcast_bits[NUM_WORDS]; | ||
| 66 | uint16_t last_bcast_seqno; /* last broadcast sequence number received by this host */ | ||
| 67 | struct list_head neigh_list; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct neigh_node { | ||
| 71 | struct list_head list; | ||
| 72 | uint8_t addr[ETH_ALEN]; | ||
| 73 | uint8_t real_packet_count; | ||
| 74 | uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE]; | ||
| 75 | uint8_t tq_index; | ||
| 76 | uint8_t tq_avg; | ||
| 77 | uint8_t last_ttl; | ||
| 78 | unsigned long last_valid; /* when last packet via this neighbour was received */ | ||
| 79 | TYPE_OF_WORD real_bits[NUM_WORDS]; | ||
| 80 | struct orig_node *orig_node; | ||
| 81 | struct batman_if *if_incoming; | ||
| 82 | }; | ||
| 83 | |||
| 84 | struct bat_priv { | ||
| 85 | struct net_device_stats stats; | ||
| 86 | }; | ||
| 87 | |||
| 88 | struct device_client { | ||
| 89 | struct list_head queue_list; | ||
| 90 | unsigned int queue_len; | ||
| 91 | unsigned char index; | ||
| 92 | spinlock_t lock; | ||
| 93 | wait_queue_head_t queue_wait; | ||
| 94 | }; | ||
| 95 | |||
| 96 | struct device_packet { | ||
| 97 | struct list_head list; | ||
| 98 | struct icmp_packet icmp_packet; | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct hna_local_entry { | ||
| 102 | uint8_t addr[ETH_ALEN]; | ||
| 103 | unsigned long last_seen; | ||
| 104 | char never_purge; | ||
| 105 | }; | ||
| 106 | |||
| 107 | struct hna_global_entry { | ||
| 108 | uint8_t addr[ETH_ALEN]; | ||
| 109 | struct orig_node *orig_node; | ||
| 110 | }; | ||
| 111 | |||
| 112 | struct forw_packet { /* structure for forw_list maintaining packets to be send/forwarded */ | ||
| 113 | struct hlist_node list; | ||
| 114 | unsigned long send_time; | ||
| 115 | uint8_t own; | ||
| 116 | unsigned char *packet_buff; | ||
| 117 | uint16_t packet_len; | ||
| 118 | uint32_t direct_link_flags; | ||
| 119 | uint8_t num_packets; | ||
| 120 | struct delayed_work delayed_work; | ||
| 121 | struct batman_if *if_incoming; | ||
| 122 | }; | ||
| 123 | |||
| 124 | #endif | ||
diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c new file mode 100644 index 000000000000..f6c9acb289ed --- /dev/null +++ b/drivers/staging/batman-adv/vis.c | |||
| @@ -0,0 +1,564 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "send.h" | ||
| 24 | #include "translation-table.h" | ||
| 25 | #include "vis.h" | ||
| 26 | #include "log.h" | ||
| 27 | #include "soft-interface.h" | ||
| 28 | #include "hard-interface.h" | ||
| 29 | #include "hash.h" | ||
| 30 | #include "compat.h" | ||
| 31 | |||
| 32 | struct hashtable_t *vis_hash; | ||
| 33 | DEFINE_SPINLOCK(vis_hash_lock); | ||
| 34 | static struct vis_info *my_vis_info; | ||
| 35 | static struct list_head send_list; /* always locked with vis_hash_lock */ | ||
| 36 | |||
| 37 | static void start_vis_timer(void); | ||
| 38 | |||
| 39 | /* free the info */ | ||
| 40 | static void free_info(void *data) | ||
| 41 | { | ||
| 42 | struct vis_info *info = data; | ||
| 43 | struct recvlist_node *entry, *tmp; | ||
| 44 | |||
| 45 | list_del_init(&info->send_list); | ||
| 46 | list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { | ||
| 47 | list_del(&entry->list); | ||
| 48 | kfree(entry); | ||
| 49 | } | ||
| 50 | kfree(info); | ||
| 51 | } | ||
| 52 | |||
| 53 | /* set the mode of the visualization to client or server */ | ||
| 54 | void vis_set_mode(int mode) | ||
| 55 | { | ||
| 56 | spin_lock(&vis_hash_lock); | ||
| 57 | |||
| 58 | if (my_vis_info != NULL) | ||
| 59 | my_vis_info->packet.vis_type = mode; | ||
| 60 | |||
| 61 | spin_unlock(&vis_hash_lock); | ||
| 62 | } | ||
| 63 | |||
| 64 | /* is_vis_server(), locked outside */ | ||
| 65 | static int is_vis_server_locked(void) | ||
| 66 | { | ||
| 67 | if (my_vis_info != NULL) | ||
| 68 | if (my_vis_info->packet.vis_type == VIS_TYPE_SERVER_SYNC) | ||
| 69 | return 1; | ||
| 70 | |||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* get the current set mode */ | ||
| 75 | int is_vis_server(void) | ||
| 76 | { | ||
| 77 | int ret = 0; | ||
| 78 | |||
| 79 | spin_lock(&vis_hash_lock); | ||
| 80 | ret = is_vis_server_locked(); | ||
| 81 | spin_unlock(&vis_hash_lock); | ||
| 82 | |||
| 83 | return ret; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* Compare two vis packets, used by the hashing algorithm */ | ||
| 87 | static int vis_info_cmp(void *data1, void *data2) | ||
| 88 | { | ||
| 89 | struct vis_info *d1, *d2; | ||
| 90 | d1 = data1; | ||
| 91 | d2 = data2; | ||
| 92 | return compare_orig(d1->packet.vis_orig, d2->packet.vis_orig); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* hash function to choose an entry in a hash table of given size */ | ||
| 96 | /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ | ||
| 97 | static int vis_info_choose(void *data, int size) | ||
| 98 | { | ||
| 99 | struct vis_info *vis_info = data; | ||
| 100 | unsigned char *key; | ||
| 101 | uint32_t hash = 0; | ||
| 102 | size_t i; | ||
| 103 | |||
| 104 | key = vis_info->packet.vis_orig; | ||
| 105 | for (i = 0; i < ETH_ALEN; i++) { | ||
| 106 | hash += key[i]; | ||
| 107 | hash += (hash << 10); | ||
| 108 | hash ^= (hash >> 6); | ||
| 109 | } | ||
| 110 | |||
| 111 | hash += (hash << 3); | ||
| 112 | hash ^= (hash >> 11); | ||
| 113 | hash += (hash << 15); | ||
| 114 | |||
| 115 | return hash % size; | ||
| 116 | } | ||
| 117 | |||
| 118 | /* tries to add one entry to the receive list. */ | ||
| 119 | static void recv_list_add(struct list_head *recv_list, char *mac) | ||
| 120 | { | ||
| 121 | struct recvlist_node *entry; | ||
| 122 | entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC); | ||
| 123 | if (!entry) | ||
| 124 | return; | ||
| 125 | |||
| 126 | memcpy(entry->mac, mac, ETH_ALEN); | ||
| 127 | list_add_tail(&entry->list, recv_list); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* returns 1 if this mac is in the recv_list */ | ||
| 131 | static int recv_list_is_in(struct list_head *recv_list, char *mac) | ||
| 132 | { | ||
| 133 | struct recvlist_node *entry; | ||
| 134 | |||
| 135 | list_for_each_entry(entry, recv_list, list) { | ||
| 136 | if (memcmp(entry->mac, mac, ETH_ALEN) == 0) | ||
| 137 | return 1; | ||
| 138 | } | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old, | ||
| 144 | * broken.. ). vis hash must be locked outside. is_new is set when the packet | ||
| 145 | * is newer than old entries in the hash. */ | ||
| 146 | static struct vis_info *add_packet(struct vis_packet *vis_packet, | ||
| 147 | int vis_info_len, int *is_new) | ||
| 148 | { | ||
| 149 | struct vis_info *info, *old_info; | ||
| 150 | struct vis_info search_elem; | ||
| 151 | |||
| 152 | *is_new = 0; | ||
| 153 | /* sanity check */ | ||
| 154 | if (vis_hash == NULL) | ||
| 155 | return NULL; | ||
| 156 | |||
| 157 | /* see if the packet is already in vis_hash */ | ||
| 158 | memcpy(search_elem.packet.vis_orig, vis_packet->vis_orig, ETH_ALEN); | ||
| 159 | old_info = hash_find(vis_hash, &search_elem); | ||
| 160 | |||
| 161 | if (old_info != NULL) { | ||
| 162 | if (vis_packet->seqno - old_info->packet.seqno <= 0) { | ||
| 163 | if (old_info->packet.seqno == vis_packet->seqno) { | ||
| 164 | recv_list_add(&old_info->recv_list, | ||
| 165 | vis_packet->sender_orig); | ||
| 166 | return old_info; | ||
| 167 | } else { | ||
| 168 | /* newer packet is already in hash. */ | ||
| 169 | return NULL; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | /* remove old entry */ | ||
| 173 | hash_remove(vis_hash, old_info); | ||
| 174 | free_info(old_info); | ||
| 175 | } | ||
| 176 | |||
| 177 | info = kmalloc(sizeof(struct vis_info) + vis_info_len, GFP_ATOMIC); | ||
| 178 | if (info == NULL) | ||
| 179 | return NULL; | ||
| 180 | |||
| 181 | INIT_LIST_HEAD(&info->send_list); | ||
| 182 | INIT_LIST_HEAD(&info->recv_list); | ||
| 183 | info->first_seen = jiffies; | ||
| 184 | memcpy(&info->packet, vis_packet, | ||
| 185 | sizeof(struct vis_packet) + vis_info_len); | ||
| 186 | |||
| 187 | /* initialize and add new packet. */ | ||
| 188 | *is_new = 1; | ||
| 189 | |||
| 190 | /* repair if entries is longer than packet. */ | ||
| 191 | if (info->packet.entries * sizeof(struct vis_info_entry) > vis_info_len) | ||
| 192 | info->packet.entries = vis_info_len / sizeof(struct vis_info_entry); | ||
| 193 | |||
| 194 | recv_list_add(&info->recv_list, info->packet.sender_orig); | ||
| 195 | |||
| 196 | /* try to add it */ | ||
| 197 | if (hash_add(vis_hash, info) < 0) { | ||
| 198 | /* did not work (for some reason) */ | ||
| 199 | free_info(info); | ||
| 200 | info = NULL; | ||
| 201 | } | ||
| 202 | |||
| 203 | return info; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* handle the server sync packet, forward if needed. */ | ||
| 207 | void receive_server_sync_packet(struct vis_packet *vis_packet, int vis_info_len) | ||
| 208 | { | ||
| 209 | struct vis_info *info; | ||
| 210 | int is_new; | ||
| 211 | |||
| 212 | spin_lock(&vis_hash_lock); | ||
| 213 | info = add_packet(vis_packet, vis_info_len, &is_new); | ||
| 214 | if (info == NULL) | ||
| 215 | goto end; | ||
| 216 | |||
| 217 | /* only if we are server ourselves and packet is newer than the one in | ||
| 218 | * hash.*/ | ||
| 219 | if (is_vis_server_locked() && is_new) { | ||
| 220 | memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); | ||
| 221 | if (list_empty(&info->send_list)) | ||
| 222 | list_add_tail(&info->send_list, &send_list); | ||
| 223 | } | ||
| 224 | end: | ||
| 225 | spin_unlock(&vis_hash_lock); | ||
| 226 | } | ||
| 227 | |||
| 228 | /* handle an incoming client update packet and schedule forward if needed. */ | ||
| 229 | void receive_client_update_packet(struct vis_packet *vis_packet, | ||
| 230 | int vis_info_len) | ||
| 231 | { | ||
| 232 | struct vis_info *info; | ||
| 233 | int is_new; | ||
| 234 | |||
| 235 | /* clients shall not broadcast. */ | ||
| 236 | if (is_bcast(vis_packet->target_orig)) | ||
| 237 | return; | ||
| 238 | |||
| 239 | spin_lock(&vis_hash_lock); | ||
| 240 | info = add_packet(vis_packet, vis_info_len, &is_new); | ||
| 241 | if (info == NULL) | ||
| 242 | goto end; | ||
| 243 | /* note that outdated packets will be dropped at this point. */ | ||
| 244 | |||
| 245 | |||
| 246 | /* send only if we're the target server or ... */ | ||
| 247 | if (is_vis_server_locked() && | ||
| 248 | is_my_mac(info->packet.target_orig) && | ||
| 249 | is_new) { | ||
| 250 | info->packet.vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */ | ||
| 251 | memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); | ||
| 252 | if (list_empty(&info->send_list)) | ||
| 253 | list_add_tail(&info->send_list, &send_list); | ||
| 254 | |||
| 255 | /* ... we're not the recipient (and thus need to forward). */ | ||
| 256 | } else if (!is_my_mac(info->packet.target_orig)) { | ||
| 257 | if (list_empty(&info->send_list)) | ||
| 258 | list_add_tail(&info->send_list, &send_list); | ||
| 259 | } | ||
| 260 | end: | ||
| 261 | spin_unlock(&vis_hash_lock); | ||
| 262 | } | ||
| 263 | |||
| 264 | /* Walk the originators and find the VIS server with the best tq. Set the packet | ||
| 265 | * address to its address and return the best_tq. | ||
| 266 | * | ||
| 267 | * Must be called with the originator hash locked */ | ||
| 268 | static int find_best_vis_server(struct vis_info *info) | ||
| 269 | { | ||
| 270 | struct hash_it_t *hashit = NULL; | ||
| 271 | struct orig_node *orig_node; | ||
| 272 | int best_tq = -1; | ||
| 273 | |||
| 274 | while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { | ||
| 275 | orig_node = hashit->bucket->data; | ||
| 276 | if ((orig_node != NULL) && | ||
| 277 | (orig_node->router != NULL) && | ||
| 278 | (orig_node->flags & VIS_SERVER) && | ||
| 279 | (orig_node->router->tq_avg > best_tq)) { | ||
| 280 | best_tq = orig_node->router->tq_avg; | ||
| 281 | memcpy(info->packet.target_orig, orig_node->orig, | ||
| 282 | ETH_ALEN); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | return best_tq; | ||
| 286 | } | ||
| 287 | |||
| 288 | /* Return true if the vis packet is full. */ | ||
| 289 | static bool vis_packet_full(struct vis_info *info) | ||
| 290 | { | ||
| 291 | if (info->packet.entries + 1 > | ||
| 292 | (1000 - sizeof(struct vis_info)) / sizeof(struct vis_info_entry)) | ||
| 293 | return true; | ||
| 294 | return false; | ||
| 295 | } | ||
| 296 | |||
| 297 | /* generates a packet of own vis data, | ||
| 298 | * returns 0 on success, -1 if no packet could be generated */ | ||
| 299 | static int generate_vis_packet(void) | ||
| 300 | { | ||
| 301 | struct hash_it_t *hashit = NULL; | ||
| 302 | struct orig_node *orig_node; | ||
| 303 | struct vis_info *info = (struct vis_info *)my_vis_info; | ||
| 304 | struct vis_info_entry *entry, *entry_array; | ||
| 305 | struct hna_local_entry *hna_local_entry; | ||
| 306 | int best_tq = -1; | ||
| 307 | unsigned long flags; | ||
| 308 | |||
| 309 | info->first_seen = jiffies; | ||
| 310 | |||
| 311 | spin_lock(&orig_hash_lock); | ||
| 312 | memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); | ||
| 313 | info->packet.ttl = TTL; | ||
| 314 | info->packet.seqno++; | ||
| 315 | info->packet.entries = 0; | ||
| 316 | |||
| 317 | if (!is_vis_server_locked()) { | ||
| 318 | best_tq = find_best_vis_server(info); | ||
| 319 | if (best_tq < 0) { | ||
| 320 | spin_unlock(&orig_hash_lock); | ||
| 321 | return -1; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | hashit = NULL; | ||
| 325 | |||
| 326 | entry_array = (struct vis_info_entry *) | ||
| 327 | ((char *)info + sizeof(struct vis_info)); | ||
| 328 | |||
| 329 | while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { | ||
| 330 | orig_node = hashit->bucket->data; | ||
| 331 | if (orig_node->router != NULL | ||
| 332 | && compare_orig(orig_node->router->addr, orig_node->orig) | ||
| 333 | && orig_node->batman_if | ||
| 334 | && (orig_node->batman_if->if_active == IF_ACTIVE) | ||
| 335 | && orig_node->router->tq_avg > 0) { | ||
| 336 | |||
| 337 | /* fill one entry into buffer. */ | ||
| 338 | entry = &entry_array[info->packet.entries]; | ||
| 339 | memcpy(entry->src, orig_node->batman_if->net_dev->dev_addr, ETH_ALEN); | ||
| 340 | memcpy(entry->dest, orig_node->orig, ETH_ALEN); | ||
| 341 | entry->quality = orig_node->router->tq_avg; | ||
| 342 | info->packet.entries++; | ||
| 343 | |||
| 344 | if (vis_packet_full(info)) { | ||
| 345 | spin_unlock(&orig_hash_lock); | ||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | spin_unlock(&orig_hash_lock); | ||
| 352 | |||
| 353 | hashit = NULL; | ||
| 354 | spin_lock_irqsave(&hna_local_hash_lock, flags); | ||
| 355 | while (NULL != (hashit = hash_iterate(hna_local_hash, hashit))) { | ||
| 356 | hna_local_entry = hashit->bucket->data; | ||
| 357 | entry = &entry_array[info->packet.entries]; | ||
| 358 | memset(entry->src, 0, ETH_ALEN); | ||
| 359 | memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN); | ||
| 360 | entry->quality = 0; /* 0 means HNA */ | ||
| 361 | info->packet.entries++; | ||
| 362 | |||
| 363 | if (vis_packet_full(info)) { | ||
| 364 | spin_unlock_irqrestore(&hna_local_hash_lock, flags); | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | spin_unlock_irqrestore(&hna_local_hash_lock, flags); | ||
| 369 | return 0; | ||
| 370 | } | ||
| 371 | |||
| 372 | static void purge_vis_packets(void) | ||
| 373 | { | ||
| 374 | struct hash_it_t *hashit = NULL; | ||
| 375 | struct vis_info *info; | ||
| 376 | |||
| 377 | while (NULL != (hashit = hash_iterate(vis_hash, hashit))) { | ||
| 378 | info = hashit->bucket->data; | ||
| 379 | if (info == my_vis_info) /* never purge own data. */ | ||
| 380 | continue; | ||
| 381 | if (time_after(jiffies, | ||
| 382 | info->first_seen + (VIS_TIMEOUT/1000)*HZ)) { | ||
| 383 | hash_remove_bucket(vis_hash, hashit); | ||
| 384 | free_info(info); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | static void broadcast_vis_packet(struct vis_info *info, int packet_length) | ||
| 390 | { | ||
| 391 | struct hash_it_t *hashit = NULL; | ||
| 392 | struct orig_node *orig_node; | ||
| 393 | |||
| 394 | spin_lock(&orig_hash_lock); | ||
| 395 | |||
| 396 | /* send to all routers in range. */ | ||
| 397 | while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { | ||
| 398 | orig_node = hashit->bucket->data; | ||
| 399 | |||
| 400 | /* if it's a vis server and reachable, send it. */ | ||
| 401 | if (orig_node && | ||
| 402 | (orig_node->flags & VIS_SERVER) && | ||
| 403 | orig_node->batman_if && | ||
| 404 | orig_node->router) { | ||
| 405 | |||
| 406 | /* don't send it if we already received the packet from | ||
| 407 | * this node. */ | ||
| 408 | if (recv_list_is_in(&info->recv_list, orig_node->orig)) | ||
| 409 | continue; | ||
| 410 | |||
| 411 | memcpy(info->packet.target_orig, | ||
| 412 | orig_node->orig, ETH_ALEN); | ||
| 413 | |||
| 414 | send_raw_packet((unsigned char *) &info->packet, | ||
| 415 | packet_length, | ||
| 416 | orig_node->batman_if, | ||
| 417 | orig_node->router->addr); | ||
| 418 | } | ||
| 419 | } | ||
| 420 | memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN); | ||
| 421 | spin_unlock(&orig_hash_lock); | ||
| 422 | } | ||
| 423 | |||
| 424 | static void unicast_vis_packet(struct vis_info *info, int packet_length) | ||
| 425 | { | ||
| 426 | struct orig_node *orig_node; | ||
| 427 | |||
| 428 | spin_lock(&orig_hash_lock); | ||
| 429 | orig_node = ((struct orig_node *) | ||
| 430 | hash_find(orig_hash, info->packet.target_orig)); | ||
| 431 | |||
| 432 | if ((orig_node != NULL) && | ||
| 433 | (orig_node->batman_if != NULL) && | ||
| 434 | (orig_node->router != NULL)) { | ||
| 435 | send_raw_packet((unsigned char *) &info->packet, packet_length, | ||
| 436 | orig_node->batman_if, | ||
| 437 | orig_node->router->addr); | ||
| 438 | } | ||
| 439 | spin_unlock(&orig_hash_lock); | ||
| 440 | } | ||
| 441 | |||
| 442 | /* only send one vis packet. called from send_vis_packets() */ | ||
| 443 | static void send_vis_packet(struct vis_info *info) | ||
| 444 | { | ||
| 445 | int packet_length; | ||
| 446 | |||
| 447 | if (info->packet.ttl < 2) { | ||
| 448 | debug_log(LOG_TYPE_NOTICE, | ||
| 449 | "Error - can't send vis packet: ttl exceeded\n"); | ||
| 450 | return; | ||
| 451 | } | ||
| 452 | |||
| 453 | memcpy(info->packet.sender_orig, mainIfAddr, ETH_ALEN); | ||
| 454 | info->packet.ttl--; | ||
| 455 | |||
| 456 | packet_length = sizeof(struct vis_packet) + | ||
| 457 | info->packet.entries * sizeof(struct vis_info_entry); | ||
| 458 | |||
| 459 | if (is_bcast(info->packet.target_orig)) | ||
| 460 | broadcast_vis_packet(info, packet_length); | ||
| 461 | else | ||
| 462 | unicast_vis_packet(info, packet_length); | ||
| 463 | info->packet.ttl++; /* restore TTL */ | ||
| 464 | } | ||
| 465 | |||
| 466 | /* called from timer; send (and maybe generate) vis packet. */ | ||
| 467 | static void send_vis_packets(struct work_struct *work) | ||
| 468 | { | ||
| 469 | struct vis_info *info, *temp; | ||
| 470 | |||
| 471 | spin_lock(&vis_hash_lock); | ||
| 472 | purge_vis_packets(); | ||
| 473 | |||
| 474 | if (generate_vis_packet() == 0) | ||
| 475 | /* schedule if generation was successful */ | ||
| 476 | list_add_tail(&my_vis_info->send_list, &send_list); | ||
| 477 | |||
| 478 | list_for_each_entry_safe(info, temp, &send_list, send_list) { | ||
| 479 | list_del_init(&info->send_list); | ||
| 480 | send_vis_packet(info); | ||
| 481 | } | ||
| 482 | spin_unlock(&vis_hash_lock); | ||
| 483 | start_vis_timer(); | ||
| 484 | } | ||
| 485 | static DECLARE_DELAYED_WORK(vis_timer_wq, send_vis_packets); | ||
| 486 | |||
| 487 | /* init the vis server. this may only be called when if_list is already | ||
| 488 | * initialized (e.g. bat0 is initialized, interfaces have been added) */ | ||
| 489 | int vis_init(void) | ||
| 490 | { | ||
| 491 | if (vis_hash) | ||
| 492 | return 1; | ||
| 493 | |||
| 494 | spin_lock(&vis_hash_lock); | ||
| 495 | |||
| 496 | vis_hash = hash_new(256, vis_info_cmp, vis_info_choose); | ||
| 497 | if (!vis_hash) { | ||
| 498 | debug_log(LOG_TYPE_CRIT, "Can't initialize vis_hash\n"); | ||
| 499 | goto err; | ||
| 500 | } | ||
| 501 | |||
| 502 | my_vis_info = kmalloc(1000, GFP_ATOMIC); | ||
| 503 | if (!my_vis_info) { | ||
| 504 | debug_log(LOG_TYPE_CRIT, "Can't initialize vis packet\n"); | ||
| 505 | goto err; | ||
| 506 | } | ||
| 507 | |||
| 508 | /* prefill the vis info */ | ||
| 509 | my_vis_info->first_seen = jiffies - atomic_read(&vis_interval); | ||
| 510 | INIT_LIST_HEAD(&my_vis_info->recv_list); | ||
| 511 | INIT_LIST_HEAD(&my_vis_info->send_list); | ||
| 512 | my_vis_info->packet.version = COMPAT_VERSION; | ||
| 513 | my_vis_info->packet.packet_type = BAT_VIS; | ||
| 514 | my_vis_info->packet.vis_type = VIS_TYPE_CLIENT_UPDATE; | ||
| 515 | my_vis_info->packet.ttl = TTL; | ||
| 516 | my_vis_info->packet.seqno = 0; | ||
| 517 | my_vis_info->packet.entries = 0; | ||
| 518 | |||
| 519 | INIT_LIST_HEAD(&send_list); | ||
| 520 | |||
| 521 | memcpy(my_vis_info->packet.vis_orig, mainIfAddr, ETH_ALEN); | ||
| 522 | memcpy(my_vis_info->packet.sender_orig, mainIfAddr, ETH_ALEN); | ||
| 523 | |||
| 524 | if (hash_add(vis_hash, my_vis_info) < 0) { | ||
| 525 | debug_log(LOG_TYPE_CRIT, | ||
| 526 | "Can't add own vis packet into hash\n"); | ||
| 527 | free_info(my_vis_info); /* not in hash, need to remove it | ||
| 528 | * manually. */ | ||
| 529 | goto err; | ||
| 530 | } | ||
| 531 | |||
| 532 | spin_unlock(&vis_hash_lock); | ||
| 533 | start_vis_timer(); | ||
| 534 | return 1; | ||
| 535 | |||
| 536 | err: | ||
| 537 | spin_unlock(&vis_hash_lock); | ||
| 538 | vis_quit(); | ||
| 539 | return 0; | ||
| 540 | } | ||
| 541 | |||
| 542 | /* shutdown vis-server */ | ||
| 543 | void vis_quit(void) | ||
| 544 | { | ||
| 545 | if (!vis_hash) | ||
| 546 | return; | ||
| 547 | |||
| 548 | cancel_delayed_work_sync(&vis_timer_wq); | ||
| 549 | |||
| 550 | spin_lock(&vis_hash_lock); | ||
| 551 | /* properly remove, kill timers ... */ | ||
| 552 | hash_delete(vis_hash, free_info); | ||
| 553 | vis_hash = NULL; | ||
| 554 | my_vis_info = NULL; | ||
| 555 | spin_unlock(&vis_hash_lock); | ||
| 556 | } | ||
| 557 | |||
| 558 | /* schedule packets for (re)transmission */ | ||
| 559 | static void start_vis_timer(void) | ||
| 560 | { | ||
| 561 | queue_delayed_work(bat_event_workqueue, &vis_timer_wq, | ||
| 562 | (atomic_read(&vis_interval)/1000) * HZ); | ||
| 563 | } | ||
| 564 | |||
diff --git a/drivers/staging/batman-adv/vis.h b/drivers/staging/batman-adv/vis.h new file mode 100644 index 000000000000..276fabab4e88 --- /dev/null +++ b/drivers/staging/batman-adv/vis.h | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008-2009 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Simon Wunderlich, Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #define VIS_TIMEOUT 200000 | ||
| 23 | #define VIS_FORMAT_DD_NAME "dot_draw" | ||
| 24 | #define VIS_FORMAT_JSON_NAME "json" | ||
| 25 | |||
| 26 | struct vis_info { | ||
| 27 | unsigned long first_seen; | ||
| 28 | struct list_head recv_list; | ||
| 29 | /* list of server-neighbors we received a vis-packet | ||
| 30 | * from. we should not reply to them. */ | ||
| 31 | struct list_head send_list; | ||
| 32 | /* this packet might be part of the vis send queue. */ | ||
| 33 | struct vis_packet packet; | ||
| 34 | /* vis_info may follow here*/ | ||
| 35 | } __attribute__((packed)); | ||
| 36 | |||
| 37 | struct vis_info_entry { | ||
| 38 | uint8_t src[ETH_ALEN]; | ||
| 39 | uint8_t dest[ETH_ALEN]; | ||
| 40 | uint8_t quality; /* quality = 0 means HNA */ | ||
| 41 | } __attribute__((packed)); | ||
| 42 | |||
| 43 | struct recvlist_node { | ||
| 44 | struct list_head list; | ||
| 45 | uint8_t mac[ETH_ALEN]; | ||
| 46 | }; | ||
| 47 | |||
| 48 | enum vis_formats { | ||
| 49 | DOT_DRAW, | ||
| 50 | JSON, | ||
| 51 | }; | ||
| 52 | |||
| 53 | extern struct hashtable_t *vis_hash; | ||
| 54 | extern spinlock_t vis_hash_lock; | ||
| 55 | |||
| 56 | void vis_set_mode(int mode); | ||
| 57 | int is_vis_server(void); | ||
| 58 | void receive_server_sync_packet(struct vis_packet *vis_packet, | ||
| 59 | int vis_info_len); | ||
| 60 | void receive_client_update_packet(struct vis_packet *vis_packet, | ||
| 61 | int vis_info_len); | ||
| 62 | int vis_init(void); | ||
| 63 | void vis_quit(void); | ||
