diff options
author | Sven Eckelmann <sven@narfation.org> | 2010-12-13 06:19:28 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-16 16:44:24 -0500 |
commit | c6c8fea29769d998d94fcec9b9f14d4b52b349d3 (patch) | |
tree | 2c8dc8d1a64d48c5737a5745e3c510ff53a23047 | |
parent | b236da6931e2482bfe44a7865dd4e7bb036f3496 (diff) |
net: Add batman-adv meshing protocol
B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is a routing
protocol for multi-hop ad-hoc mesh networks. The networks may be wired or
wireless. See http://www.open-mesh.org/ for more information and user space
tools.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
46 files changed, 10278 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-net-batman-adv b/Documentation/ABI/testing/sysfs-class-net-batman-adv new file mode 100644 index 000000000000..38dd762def4b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-net-batman-adv | |||
@@ -0,0 +1,14 @@ | |||
1 | |||
2 | What: /sys/class/net/<iface>/batman-adv/mesh_iface | ||
3 | Date: May 2010 | ||
4 | Contact: Marek Lindner <lindner_marek@yahoo.de> | ||
5 | Description: | ||
6 | The /sys/class/net/<iface>/batman-adv/mesh_iface file | ||
7 | displays the batman mesh interface this <iface> | ||
8 | currently is associated with. | ||
9 | |||
10 | What: /sys/class/net/<iface>/batman-adv/iface_status | ||
11 | Date: May 2010 | ||
12 | Contact: Marek Lindner <lindner_marek@yahoo.de> | ||
13 | Description: | ||
14 | Indicates the status of <iface> as it is seen by batman. | ||
diff --git a/Documentation/ABI/testing/sysfs-class-net-mesh b/Documentation/ABI/testing/sysfs-class-net-mesh new file mode 100644 index 000000000000..748fe1701d25 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-net-mesh | |||
@@ -0,0 +1,69 @@ | |||
1 | |||
2 | What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms | ||
3 | Date: May 2010 | ||
4 | Contact: Marek Lindner <lindner_marek@yahoo.de> | ||
5 | Description: | ||
6 | Indicates whether the batman protocol messages of the | ||
7 | mesh <mesh_iface> shall be aggregated or not. | ||
8 | |||
9 | What: /sys/class/net/<mesh_iface>/mesh/bonding | ||
10 | Date: June 2010 | ||
11 | Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | ||
12 | Description: | ||
13 | Indicates whether the data traffic going through the | ||
14 | mesh will be sent using multiple interfaces at the | ||
15 | same time (if available). | ||
16 | |||
17 | What: /sys/class/net/<mesh_iface>/mesh/fragmentation | ||
18 | Date: October 2010 | ||
19 | Contact: Andreas Langer <an.langer@gmx.de> | ||
20 | Description: | ||
21 | Indicates whether the data traffic going through the | ||
22 | mesh will be fragmented or silently discarded if the | ||
23 | packet size exceeds the outgoing interface MTU. | ||
24 | |||
25 | What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth | ||
26 | Date: October 2010 | ||
27 | Contact: Marek Lindner <lindner_marek@yahoo.de> | ||
28 | Description: | ||
29 | Defines the bandwidth which is propagated by this | ||
30 | node if gw_mode was set to 'server'. | ||
31 | |||
32 | What: /sys/class/net/<mesh_iface>/mesh/gw_mode | ||
33 | Date: October 2010 | ||
34 | Contact: Marek Lindner <lindner_marek@yahoo.de> | ||
35 | Description: | ||
36 | Defines the state of the gateway features. Can be | ||
37 | either 'off', 'client' or 'server'. | ||
38 | |||
39 | What: /sys/class/net/<mesh_iface>/mesh/gw_sel_class | ||
40 | Date: October 2010 | ||
41 | Contact: Marek Lindner <lindner_marek@yahoo.de> | ||
42 | Description: | ||
43 | Defines the selection criteria this node will use | ||
44 | to choose a gateway if gw_mode was set to 'client'. | ||
45 | |||
46 | What: /sys/class/net/<mesh_iface>/mesh/orig_interval | ||
47 | Date: May 2010 | ||
48 | Contact: Marek Lindner <lindner_marek@yahoo.de> | ||
49 | Description: | ||
50 | Defines the interval in milliseconds in which batman | ||
51 | sends its protocol messages. | ||
52 | |||
53 | What: /sys/class/net/<mesh_iface>/mesh/hop_penalty | ||
54 | Date: Oct 2010 | ||
55 | Contact: Linus Lüssing <linus.luessing@web.de> | ||
56 | Description: | ||
57 | Defines the penalty which will be applied to an | ||
58 | originator message's tq-field on every hop. | ||
59 | |||
60 | What: /sys/class/net/<mesh_iface>/mesh/vis_mode | ||
61 | Date: May 2010 | ||
62 | Contact: Marek Lindner <lindner_marek@yahoo.de> | ||
63 | Description: | ||
64 | Each batman node only maintains information about its | ||
65 | own local neighborhood, therefore generating graphs | ||
66 | showing the topology of the entire mesh is not easily | ||
67 | feasible without having a central instance to collect | ||
68 | the local topologies from all nodes. This file allows | ||
69 | to activate the collecting (server) mode. | ||
diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt new file mode 100644 index 000000000000..77f0cdd5b0dd --- /dev/null +++ b/Documentation/networking/batman-adv.txt | |||
@@ -0,0 +1,240 @@ | |||
1 | [state: 21-11-2010] | ||
2 | |||
3 | BATMAN-ADV | ||
4 | ---------- | ||
5 | |||
6 | Batman advanced is a new approach to wireless networking which | ||
7 | does no longer operate on the IP basis. Unlike the batman daemon, | ||
8 | which exchanges information using UDP packets and sets routing | ||
9 | tables, batman-advanced operates on ISO/OSI Layer 2 only and uses | ||
10 | and routes (or better: bridges) Ethernet Frames. It emulates a | ||
11 | virtual network switch of all nodes participating. Therefore all | ||
12 | nodes appear to be link local, thus all higher operating proto- | ||
13 | cols won't be affected by any changes within the network. You can | ||
14 | run almost any protocol above batman advanced, prominent examples | ||
15 | are: IPv4, IPv6, DHCP, IPX. | ||
16 | |||
17 | Batman advanced was implemented as a Linux kernel driver to re- | ||
18 | duce the overhead to a minimum. It does not depend on any (other) | ||
19 | network driver, and can be used on wifi as well as ethernet lan, | ||
20 | vpn, etc ... (anything with ethernet-style layer 2). | ||
21 | |||
22 | CONFIGURATION | ||
23 | ------------- | ||
24 | |||
25 | Load the batman-adv module into your kernel: | ||
26 | |||
27 | # insmod batman-adv.ko | ||
28 | |||
29 | The module is now waiting for activation. You must add some in- | ||
30 | terfaces on which batman can operate. After loading the module | ||
31 | batman advanced will scan your systems interfaces to search for | ||
32 | compatible interfaces. Once found, it will create subfolders in | ||
33 | the /sys directories of each supported interface, e.g. | ||
34 | |||
35 | # ls /sys/class/net/eth0/batman_adv/ | ||
36 | # iface_status mesh_iface | ||
37 | |||
38 | If an interface does not have the "batman_adv" subfolder it prob- | ||
39 | ably is not supported. Not supported interfaces are: loopback, | ||
40 | non-ethernet and batman's own interfaces. | ||
41 | |||
42 | Note: After the module was loaded it will continuously watch for | ||
43 | new interfaces to verify the compatibility. There is no need to | ||
44 | reload the module if you plug your USB wifi adapter into your ma- | ||
45 | chine after batman advanced was initially loaded. | ||
46 | |||
47 | To activate a given interface simply write "bat0" into its | ||
48 | "mesh_iface" file inside the batman_adv subfolder: | ||
49 | |||
50 | # echo bat0 > /sys/class/net/eth0/batman_adv/mesh_iface | ||
51 | |||
52 | Repeat this step for all interfaces you wish to add. Now batman | ||
53 | starts using/broadcasting on this/these interface(s). | ||
54 | |||
55 | By reading the "iface_status" file you can check its status: | ||
56 | |||
57 | # cat /sys/class/net/eth0/batman_adv/iface_status | ||
58 | # active | ||
59 | |||
60 | To deactivate an interface you have to write "none" into its | ||
61 | "mesh_iface" file: | ||
62 | |||
63 | # echo none > /sys/class/net/eth0/batman_adv/mesh_iface | ||
64 | |||
65 | |||
66 | All mesh wide settings can be found in batman's own interface | ||
67 | folder: | ||
68 | |||
69 | # ls /sys/class/net/bat0/mesh/ | ||
70 | # aggregated_ogms bonding fragmentation orig_interval | ||
71 | # vis_mode | ||
72 | |||
73 | |||
74 | There is a special folder for debugging informations: | ||
75 | |||
76 | # ls /sys/kernel/debug/batman_adv/bat0/ | ||
77 | # originators socket transtable_global transtable_local | ||
78 | # vis_data | ||
79 | |||
80 | |||
81 | Some of the files contain all sort of status information regard- | ||
82 | ing the mesh network. For example, you can view the table of | ||
83 | originators (mesh participants) with: | ||
84 | |||
85 | # cat /sys/kernel/debug/batman_adv/bat0/originators | ||
86 | |||
87 | Other files allow to change batman's behaviour to better fit your | ||
88 | requirements. For instance, you can check the current originator | ||
89 | interval (value in milliseconds which determines how often batman | ||
90 | sends its broadcast packets): | ||
91 | |||
92 | # cat /sys/class/net/bat0/mesh/orig_interval | ||
93 | # 1000 | ||
94 | |||
95 | and also change its value: | ||
96 | |||
97 | # echo 3000 > /sys/class/net/bat0/mesh/orig_interval | ||
98 | |||
99 | In very mobile scenarios, you might want to adjust the originator | ||
100 | interval to a lower value. This will make the mesh more respon- | ||
101 | sive to topology changes, but will also increase the overhead. | ||
102 | |||
103 | |||
104 | USAGE | ||
105 | ----- | ||
106 | |||
107 | To make use of your newly created mesh, batman advanced provides | ||
108 | a new interface "bat0" which you should use from this point on. | ||
109 | All interfaces added to batman advanced are not relevant any | ||
110 | longer because batman handles them for you. Basically, one "hands | ||
111 | over" the data by using the batman interface and batman will make | ||
112 | sure it reaches its destination. | ||
113 | |||
114 | The "bat0" interface can be used like any other regular inter- | ||
115 | face. It needs an IP address which can be either statically con- | ||
116 | figured or dynamically (by using DHCP or similar services): | ||
117 | |||
118 | # NodeA: ifconfig bat0 192.168.0.1 | ||
119 | # NodeB: ifconfig bat0 192.168.0.2 | ||
120 | # NodeB: ping 192.168.0.1 | ||
121 | |||
122 | Note: In order to avoid problems remove all IP addresses previ- | ||
123 | ously assigned to interfaces now used by batman advanced, e.g. | ||
124 | |||
125 | # ifconfig eth0 0.0.0.0 | ||
126 | |||
127 | |||
128 | VISUALIZATION | ||
129 | ------------- | ||
130 | |||
131 | If you want topology visualization, at least one mesh node must | ||
132 | be configured as VIS-server: | ||
133 | |||
134 | # echo "server" > /sys/class/net/bat0/mesh/vis_mode | ||
135 | |||
136 | Each node is either configured as "server" or as "client" (de- | ||
137 | fault: "client"). Clients send their topology data to the server | ||
138 | next to them, and server synchronize with other servers. If there | ||
139 | is no server configured (default) within the mesh, no topology | ||
140 | information will be transmitted. With these "synchronizing | ||
141 | servers", there can be 1 or more vis servers sharing the same (or | ||
142 | at least very similar) data. | ||
143 | |||
144 | When configured as server, you can get a topology snapshot of | ||
145 | your mesh: | ||
146 | |||
147 | # cat /sys/kernel/debug/batman_adv/bat0/vis_data | ||
148 | |||
149 | This raw output is intended to be easily parsable and convertable | ||
150 | with other tools. Have a look at the batctl README if you want a | ||
151 | vis output in dot or json format for instance and how those out- | ||
152 | puts could then be visualised in an image. | ||
153 | |||
154 | The raw format consists of comma separated values per entry where | ||
155 | each entry is giving information about a certain source inter- | ||
156 | face. Each entry can/has to have the following values: | ||
157 | -> "mac" - mac address of an originator's source interface | ||
158 | (each line begins with it) | ||
159 | -> "TQ mac value" - src mac's link quality towards mac address | ||
160 | of a neighbor originator's interface which | ||
161 | is being used for routing | ||
162 | -> "HNA mac" - HNA announced by source mac | ||
163 | -> "PRIMARY" - this is a primary interface | ||
164 | -> "SEC mac" - secondary mac address of source | ||
165 | (requires preceding PRIMARY) | ||
166 | |||
167 | The TQ value has a range from 4 to 255 with 255 being the best. | ||
168 | The HNA entries are showing which hosts are connected to the mesh | ||
169 | via bat0 or being bridged into the mesh network. The PRIMARY/SEC | ||
170 | values are only applied on primary interfaces | ||
171 | |||
172 | |||
173 | LOGGING/DEBUGGING | ||
174 | ----------------- | ||
175 | |||
176 | All error messages, warnings and information messages are sent to | ||
177 | the kernel log. Depending on your operating system distribution | ||
178 | this can be read in one of a number of ways. Try using the com- | ||
179 | mands: dmesg, logread, or looking in the files /var/log/kern.log | ||
180 | or /var/log/syslog. All batman-adv messages are prefixed with | ||
181 | "batman-adv:" So to see just these messages try | ||
182 | |||
183 | # dmesg | grep batman-adv | ||
184 | |||
185 | When investigating problems with your mesh network it is some- | ||
186 | times necessary to see more detail debug messages. This must be | ||
187 | enabled when compiling the batman-adv module. When building bat- | ||
188 | man-adv as part of kernel, use "make menuconfig" and enable the | ||
189 | option "B.A.T.M.A.N. debugging". | ||
190 | |||
191 | Those additional debug messages can be accessed using a special | ||
192 | file in debugfs | ||
193 | |||
194 | # cat /sys/kernel/debug/batman_adv/bat0/log | ||
195 | |||
196 | The additional debug output is by default disabled. It can be en- | ||
197 | abled during run time. Following log_levels are defined: | ||
198 | |||
199 | 0 - All debug output disabled | ||
200 | 1 - Enable messages related to routing / flooding / broadcasting | ||
201 | 2 - Enable route or hna added / changed / deleted | ||
202 | 3 - Enable all messages | ||
203 | |||
204 | The debug output can be changed at runtime using the file | ||
205 | /sys/class/net/bat0/mesh/log_level. e.g. | ||
206 | |||
207 | # echo 2 > /sys/class/net/bat0/mesh/log_level | ||
208 | |||
209 | will enable debug messages for when routes or HNAs change. | ||
210 | |||
211 | |||
212 | BATCTL | ||
213 | ------ | ||
214 | |||
215 | As batman advanced operates on layer 2 all hosts participating in | ||
216 | the virtual switch are completely transparent for all protocols | ||
217 | above layer 2. Therefore the common diagnosis tools do not work | ||
218 | as expected. To overcome these problems batctl was created. At | ||
219 | the moment the batctl contains ping, traceroute, tcpdump and | ||
220 | interfaces to the kernel module settings. | ||
221 | |||
222 | For more information, please see the manpage (man batctl). | ||
223 | |||
224 | batctl is available on http://www.open-mesh.org/ | ||
225 | |||
226 | |||
227 | CONTACT | ||
228 | ------- | ||
229 | |||
230 | Please send us comments, experiences, questions, anything :) | ||
231 | |||
232 | IRC: #batman on irc.freenode.org | ||
233 | Mailing-list: b.a.t.m.a.n@b.a.t.m.a.n@lists.open-mesh.org | ||
234 | (optional subscription at | ||
235 | https://lists.open-mesh.org/mm/listinfo/b.a.t.m.a.n) | ||
236 | |||
237 | You can also contact the Authors: | ||
238 | |||
239 | Marek Lindner <lindner_marek@yahoo.de> | ||
240 | Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | ||
diff --git a/MAINTAINERS b/MAINTAINERS index f16ce8f46934..2a5e60fb3b5d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1264,6 +1264,15 @@ S: Maintained | |||
1264 | F: drivers/video/backlight/ | 1264 | F: drivers/video/backlight/ |
1265 | F: include/linux/backlight.h | 1265 | F: include/linux/backlight.h |
1266 | 1266 | ||
1267 | BATMAN ADVANCED | ||
1268 | M: Marek Lindner <lindner_marek@yahoo.de> | ||
1269 | M: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | ||
1270 | M: Sven Eckelmann <sven@narfation.org> | ||
1271 | L: b.a.t.m.a.n@lists.open-mesh.org | ||
1272 | W: http://www.open-mesh.org/ | ||
1273 | S: Maintained | ||
1274 | F: net/batman-adv/ | ||
1275 | |||
1267 | BAYCOM/HDLCDRV DRIVERS FOR AX.25 | 1276 | BAYCOM/HDLCDRV DRIVERS FOR AX.25 |
1268 | M: Thomas Sailer <t.sailer@alumni.ethz.ch> | 1277 | M: Thomas Sailer <t.sailer@alumni.ethz.ch> |
1269 | L: linux-hams@vger.kernel.org | 1278 | L: linux-hams@vger.kernel.org |
diff --git a/net/Kconfig b/net/Kconfig index 126c2af0fc1f..ad0aafe903f8 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -214,6 +214,7 @@ source "net/ieee802154/Kconfig" | |||
214 | source "net/sched/Kconfig" | 214 | source "net/sched/Kconfig" |
215 | source "net/dcb/Kconfig" | 215 | source "net/dcb/Kconfig" |
216 | source "net/dns_resolver/Kconfig" | 216 | source "net/dns_resolver/Kconfig" |
217 | source "net/batman-adv/Kconfig" | ||
217 | 218 | ||
218 | config RPS | 219 | config RPS |
219 | boolean | 220 | boolean |
diff --git a/net/Makefile b/net/Makefile index 6b7bfd7f1416..a3330ebe2c53 100644 --- a/net/Makefile +++ b/net/Makefile | |||
@@ -69,3 +69,4 @@ endif | |||
69 | obj-$(CONFIG_WIMAX) += wimax/ | 69 | obj-$(CONFIG_WIMAX) += wimax/ |
70 | obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ | 70 | obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ |
71 | obj-$(CONFIG_CEPH_LIB) += ceph/ | 71 | obj-$(CONFIG_CEPH_LIB) += ceph/ |
72 | obj-$(CONFIG_BATMAN_ADV) += batman-adv/ | ||
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig new file mode 100644 index 000000000000..6c051ad833eb --- /dev/null +++ b/net/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 | depends on NET | ||
8 | default n | ||
9 | ---help--- | ||
10 | |||
11 | B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is | ||
12 | a routing protocol for multi-hop ad-hoc mesh networks. The | ||
13 | networks may be wired or wireless. See | ||
14 | http://www.open-mesh.org/ for more information and user space | ||
15 | tools. | ||
16 | |||
17 | config BATMAN_ADV_DEBUG | ||
18 | bool "B.A.T.M.A.N. debugging" | ||
19 | depends on BATMAN_ADV != n | ||
20 | ---help--- | ||
21 | |||
22 | This is an option for use by developers; most people should | ||
23 | say N here. This enables compilation of support for | ||
24 | outputting debugging information to the kernel log. The | ||
25 | output is controlled via the module parameter debug. | ||
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile new file mode 100644 index 000000000000..d936aeccd194 --- /dev/null +++ b/net/batman-adv/Makefile | |||
@@ -0,0 +1,39 @@ | |||
1 | # | ||
2 | # Copyright (C) 2007-2010 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-$(CONFIG_BATMAN_ADV) += batman-adv.o | ||
22 | batman-adv-y += aggregation.o | ||
23 | batman-adv-y += bat_debugfs.o | ||
24 | batman-adv-y += bat_sysfs.o | ||
25 | batman-adv-y += bitarray.o | ||
26 | batman-adv-y += gateway_client.o | ||
27 | batman-adv-y += gateway_common.o | ||
28 | batman-adv-y += hard-interface.o | ||
29 | batman-adv-y += hash.o | ||
30 | batman-adv-y += icmp_socket.o | ||
31 | batman-adv-y += main.o | ||
32 | batman-adv-y += originator.o | ||
33 | batman-adv-y += ring_buffer.o | ||
34 | batman-adv-y += routing.o | ||
35 | batman-adv-y += send.o | ||
36 | batman-adv-y += soft-interface.o | ||
37 | batman-adv-y += translation-table.o | ||
38 | batman-adv-y += unicast.o | ||
39 | batman-adv-y += vis.o | ||
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c new file mode 100644 index 000000000000..3850a3ecf947 --- /dev/null +++ b/net/batman-adv/aggregation.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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->skb->data; | ||
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 | time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS), | ||
56 | forw_packet->send_time) && | ||
57 | (aggregated_bytes <= MAX_AGGREGATION_BYTES)) { | ||
58 | |||
59 | /** | ||
60 | * check aggregation compatibility | ||
61 | * -> direct link packets are broadcasted on | ||
62 | * their interface only | ||
63 | * -> aggregate packet if the current packet is | ||
64 | * a "global" packet as well as the base | ||
65 | * packet | ||
66 | */ | ||
67 | |||
68 | /* packets without direct link flag and high TTL | ||
69 | * are flooded through the net */ | ||
70 | if ((!directlink) && | ||
71 | (!(batman_packet->flags & DIRECTLINK)) && | ||
72 | (batman_packet->ttl != 1) && | ||
73 | |||
74 | /* own packets originating non-primary | ||
75 | * interfaces leave only that interface */ | ||
76 | ((!forw_packet->own) || | ||
77 | (forw_packet->if_incoming->if_num == 0))) | ||
78 | return true; | ||
79 | |||
80 | /* if the incoming packet is sent via this one | ||
81 | * interface only - we still can aggregate */ | ||
82 | if ((directlink) && | ||
83 | (new_batman_packet->ttl == 1) && | ||
84 | (forw_packet->if_incoming == if_incoming) && | ||
85 | |||
86 | /* packets from direct neighbors or | ||
87 | * own secondary interface packets | ||
88 | * (= secondary interface packets in general) */ | ||
89 | (batman_packet->flags & DIRECTLINK || | ||
90 | (forw_packet->own && | ||
91 | forw_packet->if_incoming->if_num != 0))) | ||
92 | return true; | ||
93 | } | ||
94 | |||
95 | return false; | ||
96 | } | ||
97 | |||
98 | #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) | ||
99 | /* create a new aggregated packet and add this packet to it */ | ||
100 | static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, | ||
101 | unsigned long send_time, bool direct_link, | ||
102 | struct batman_if *if_incoming, | ||
103 | int own_packet) | ||
104 | { | ||
105 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
106 | struct forw_packet *forw_packet_aggr; | ||
107 | unsigned char *skb_buff; | ||
108 | |||
109 | /* own packet should always be scheduled */ | ||
110 | if (!own_packet) { | ||
111 | if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) { | ||
112 | bat_dbg(DBG_BATMAN, bat_priv, | ||
113 | "batman packet queue full\n"); | ||
114 | return; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); | ||
119 | if (!forw_packet_aggr) { | ||
120 | if (!own_packet) | ||
121 | atomic_inc(&bat_priv->batman_queue_left); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | if ((atomic_read(&bat_priv->aggregated_ogms)) && | ||
126 | (packet_len < MAX_AGGREGATION_BYTES)) | ||
127 | forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES + | ||
128 | sizeof(struct ethhdr)); | ||
129 | else | ||
130 | forw_packet_aggr->skb = dev_alloc_skb(packet_len + | ||
131 | sizeof(struct ethhdr)); | ||
132 | |||
133 | if (!forw_packet_aggr->skb) { | ||
134 | if (!own_packet) | ||
135 | atomic_inc(&bat_priv->batman_queue_left); | ||
136 | kfree(forw_packet_aggr); | ||
137 | return; | ||
138 | } | ||
139 | skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr)); | ||
140 | |||
141 | INIT_HLIST_NODE(&forw_packet_aggr->list); | ||
142 | |||
143 | skb_buff = skb_put(forw_packet_aggr->skb, packet_len); | ||
144 | forw_packet_aggr->packet_len = packet_len; | ||
145 | memcpy(skb_buff, packet_buff, packet_len); | ||
146 | |||
147 | forw_packet_aggr->own = own_packet; | ||
148 | forw_packet_aggr->if_incoming = if_incoming; | ||
149 | forw_packet_aggr->num_packets = 0; | ||
150 | forw_packet_aggr->direct_link_flags = 0; | ||
151 | forw_packet_aggr->send_time = send_time; | ||
152 | |||
153 | /* save packet direct link flag status */ | ||
154 | if (direct_link) | ||
155 | forw_packet_aggr->direct_link_flags |= 1; | ||
156 | |||
157 | /* add new packet to packet list */ | ||
158 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
159 | hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list); | ||
160 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
161 | |||
162 | /* start timer for this packet */ | ||
163 | INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, | ||
164 | send_outstanding_bat_packet); | ||
165 | queue_delayed_work(bat_event_workqueue, | ||
166 | &forw_packet_aggr->delayed_work, | ||
167 | send_time - jiffies); | ||
168 | } | ||
169 | |||
170 | /* aggregate a new packet into the existing aggregation */ | ||
171 | static void aggregate(struct forw_packet *forw_packet_aggr, | ||
172 | unsigned char *packet_buff, | ||
173 | int packet_len, | ||
174 | bool direct_link) | ||
175 | { | ||
176 | unsigned char *skb_buff; | ||
177 | |||
178 | skb_buff = skb_put(forw_packet_aggr->skb, packet_len); | ||
179 | memcpy(skb_buff, packet_buff, packet_len); | ||
180 | forw_packet_aggr->packet_len += packet_len; | ||
181 | forw_packet_aggr->num_packets++; | ||
182 | |||
183 | /* save packet direct link flag status */ | ||
184 | if (direct_link) | ||
185 | forw_packet_aggr->direct_link_flags |= | ||
186 | (1 << forw_packet_aggr->num_packets); | ||
187 | } | ||
188 | |||
189 | void add_bat_packet_to_list(struct bat_priv *bat_priv, | ||
190 | unsigned char *packet_buff, int packet_len, | ||
191 | struct batman_if *if_incoming, char own_packet, | ||
192 | unsigned long send_time) | ||
193 | { | ||
194 | /** | ||
195 | * _aggr -> pointer to the packet we want to aggregate with | ||
196 | * _pos -> pointer to the position in the queue | ||
197 | */ | ||
198 | struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL; | ||
199 | struct hlist_node *tmp_node; | ||
200 | struct batman_packet *batman_packet = | ||
201 | (struct batman_packet *)packet_buff; | ||
202 | bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; | ||
203 | |||
204 | /* find position for the packet in the forward queue */ | ||
205 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
206 | /* own packets are not to be aggregated */ | ||
207 | if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { | ||
208 | hlist_for_each_entry(forw_packet_pos, tmp_node, | ||
209 | &bat_priv->forw_bat_list, list) { | ||
210 | if (can_aggregate_with(batman_packet, | ||
211 | packet_len, | ||
212 | send_time, | ||
213 | direct_link, | ||
214 | if_incoming, | ||
215 | forw_packet_pos)) { | ||
216 | forw_packet_aggr = forw_packet_pos; | ||
217 | break; | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | /* nothing to aggregate with - either aggregation disabled or no | ||
223 | * suitable aggregation packet found */ | ||
224 | if (!forw_packet_aggr) { | ||
225 | /* the following section can run without the lock */ | ||
226 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
227 | |||
228 | /** | ||
229 | * if we could not aggregate this packet with one of the others | ||
230 | * we hold it back for a while, so that it might be aggregated | ||
231 | * later on | ||
232 | */ | ||
233 | if ((!own_packet) && | ||
234 | (atomic_read(&bat_priv->aggregated_ogms))) | ||
235 | send_time += msecs_to_jiffies(MAX_AGGREGATION_MS); | ||
236 | |||
237 | new_aggregated_packet(packet_buff, packet_len, | ||
238 | send_time, direct_link, | ||
239 | if_incoming, own_packet); | ||
240 | } else { | ||
241 | aggregate(forw_packet_aggr, | ||
242 | packet_buff, packet_len, | ||
243 | direct_link); | ||
244 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /* unpack the aggregated packets and process them one by one */ | ||
249 | void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, | ||
250 | int packet_len, struct batman_if *if_incoming) | ||
251 | { | ||
252 | struct batman_packet *batman_packet; | ||
253 | int buff_pos = 0; | ||
254 | unsigned char *hna_buff; | ||
255 | |||
256 | batman_packet = (struct batman_packet *)packet_buff; | ||
257 | |||
258 | do { | ||
259 | /* network to host order for our 32bit seqno, and the | ||
260 | orig_interval. */ | ||
261 | batman_packet->seqno = ntohl(batman_packet->seqno); | ||
262 | |||
263 | hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN; | ||
264 | receive_bat_packet(ethhdr, batman_packet, | ||
265 | hna_buff, hna_len(batman_packet), | ||
266 | if_incoming); | ||
267 | |||
268 | buff_pos += BAT_PACKET_LEN + hna_len(batman_packet); | ||
269 | batman_packet = (struct batman_packet *) | ||
270 | (packet_buff + buff_pos); | ||
271 | } while (aggregated_packet(buff_pos, packet_len, | ||
272 | batman_packet->num_hna)); | ||
273 | } | ||
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h new file mode 100644 index 000000000000..71a91b3da913 --- /dev/null +++ b/net/batman-adv/aggregation.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_AGGREGATION_H_ | ||
23 | #define _NET_BATMAN_ADV_AGGREGATION_H_ | ||
24 | |||
25 | #include "main.h" | ||
26 | |||
27 | /* is there another aggregated packet here? */ | ||
28 | static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna) | ||
29 | { | ||
30 | int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN); | ||
31 | |||
32 | return (next_buff_pos <= packet_len) && | ||
33 | (next_buff_pos <= MAX_AGGREGATION_BYTES); | ||
34 | } | ||
35 | |||
36 | void add_bat_packet_to_list(struct bat_priv *bat_priv, | ||
37 | unsigned char *packet_buff, int packet_len, | ||
38 | struct batman_if *if_incoming, char own_packet, | ||
39 | unsigned long send_time); | ||
40 | void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, | ||
41 | int packet_len, struct batman_if *if_incoming); | ||
42 | |||
43 | #endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */ | ||
diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c new file mode 100644 index 000000000000..0ae81d07f102 --- /dev/null +++ b/net/batman-adv/bat_debugfs.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 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 | |||
24 | #include <linux/debugfs.h> | ||
25 | |||
26 | #include "bat_debugfs.h" | ||
27 | #include "translation-table.h" | ||
28 | #include "originator.h" | ||
29 | #include "hard-interface.h" | ||
30 | #include "gateway_common.h" | ||
31 | #include "gateway_client.h" | ||
32 | #include "soft-interface.h" | ||
33 | #include "vis.h" | ||
34 | #include "icmp_socket.h" | ||
35 | |||
36 | static struct dentry *bat_debugfs; | ||
37 | |||
38 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
39 | #define LOG_BUFF_MASK (log_buff_len-1) | ||
40 | #define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK]) | ||
41 | |||
42 | static int log_buff_len = LOG_BUF_LEN; | ||
43 | |||
44 | static void emit_log_char(struct debug_log *debug_log, char c) | ||
45 | { | ||
46 | LOG_BUFF(debug_log->log_end) = c; | ||
47 | debug_log->log_end++; | ||
48 | |||
49 | if (debug_log->log_end - debug_log->log_start > log_buff_len) | ||
50 | debug_log->log_start = debug_log->log_end - log_buff_len; | ||
51 | } | ||
52 | |||
53 | static int fdebug_log(struct debug_log *debug_log, char *fmt, ...) | ||
54 | { | ||
55 | int printed_len; | ||
56 | va_list args; | ||
57 | static char debug_log_buf[256]; | ||
58 | char *p; | ||
59 | |||
60 | if (!debug_log) | ||
61 | return 0; | ||
62 | |||
63 | spin_lock_bh(&debug_log->lock); | ||
64 | va_start(args, fmt); | ||
65 | printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), | ||
66 | fmt, args); | ||
67 | va_end(args); | ||
68 | |||
69 | for (p = debug_log_buf; *p != 0; p++) | ||
70 | emit_log_char(debug_log, *p); | ||
71 | |||
72 | spin_unlock_bh(&debug_log->lock); | ||
73 | |||
74 | wake_up(&debug_log->queue_wait); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | int debug_log(struct bat_priv *bat_priv, char *fmt, ...) | ||
80 | { | ||
81 | va_list args; | ||
82 | char tmp_log_buf[256]; | ||
83 | |||
84 | va_start(args, fmt); | ||
85 | vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); | ||
86 | fdebug_log(bat_priv->debug_log, "[%10u] %s", | ||
87 | (jiffies / HZ), tmp_log_buf); | ||
88 | va_end(args); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int log_open(struct inode *inode, struct file *file) | ||
94 | { | ||
95 | nonseekable_open(inode, file); | ||
96 | file->private_data = inode->i_private; | ||
97 | inc_module_count(); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int log_release(struct inode *inode, struct file *file) | ||
102 | { | ||
103 | dec_module_count(); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static ssize_t log_read(struct file *file, char __user *buf, | ||
108 | size_t count, loff_t *ppos) | ||
109 | { | ||
110 | struct bat_priv *bat_priv = file->private_data; | ||
111 | struct debug_log *debug_log = bat_priv->debug_log; | ||
112 | int error, i = 0; | ||
113 | char c; | ||
114 | |||
115 | if ((file->f_flags & O_NONBLOCK) && | ||
116 | !(debug_log->log_end - debug_log->log_start)) | ||
117 | return -EAGAIN; | ||
118 | |||
119 | if ((!buf) || (count < 0)) | ||
120 | return -EINVAL; | ||
121 | |||
122 | if (count == 0) | ||
123 | return 0; | ||
124 | |||
125 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
126 | return -EFAULT; | ||
127 | |||
128 | error = wait_event_interruptible(debug_log->queue_wait, | ||
129 | (debug_log->log_start - debug_log->log_end)); | ||
130 | |||
131 | if (error) | ||
132 | return error; | ||
133 | |||
134 | spin_lock_bh(&debug_log->lock); | ||
135 | |||
136 | while ((!error) && (i < count) && | ||
137 | (debug_log->log_start != debug_log->log_end)) { | ||
138 | c = LOG_BUFF(debug_log->log_start); | ||
139 | |||
140 | debug_log->log_start++; | ||
141 | |||
142 | spin_unlock_bh(&debug_log->lock); | ||
143 | |||
144 | error = __put_user(c, buf); | ||
145 | |||
146 | spin_lock_bh(&debug_log->lock); | ||
147 | |||
148 | buf++; | ||
149 | i++; | ||
150 | |||
151 | } | ||
152 | |||
153 | spin_unlock_bh(&debug_log->lock); | ||
154 | |||
155 | if (!error) | ||
156 | return i; | ||
157 | |||
158 | return error; | ||
159 | } | ||
160 | |||
161 | static unsigned int log_poll(struct file *file, poll_table *wait) | ||
162 | { | ||
163 | struct bat_priv *bat_priv = file->private_data; | ||
164 | struct debug_log *debug_log = bat_priv->debug_log; | ||
165 | |||
166 | poll_wait(file, &debug_log->queue_wait, wait); | ||
167 | |||
168 | if (debug_log->log_end - debug_log->log_start) | ||
169 | return POLLIN | POLLRDNORM; | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static const struct file_operations log_fops = { | ||
175 | .open = log_open, | ||
176 | .release = log_release, | ||
177 | .read = log_read, | ||
178 | .poll = log_poll, | ||
179 | .llseek = no_llseek, | ||
180 | }; | ||
181 | |||
182 | static int debug_log_setup(struct bat_priv *bat_priv) | ||
183 | { | ||
184 | struct dentry *d; | ||
185 | |||
186 | if (!bat_priv->debug_dir) | ||
187 | goto err; | ||
188 | |||
189 | bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC); | ||
190 | if (!bat_priv->debug_log) | ||
191 | goto err; | ||
192 | |||
193 | spin_lock_init(&bat_priv->debug_log->lock); | ||
194 | init_waitqueue_head(&bat_priv->debug_log->queue_wait); | ||
195 | |||
196 | d = debugfs_create_file("log", S_IFREG | S_IRUSR, | ||
197 | bat_priv->debug_dir, bat_priv, &log_fops); | ||
198 | if (d) | ||
199 | goto err; | ||
200 | |||
201 | return 0; | ||
202 | |||
203 | err: | ||
204 | return 1; | ||
205 | } | ||
206 | |||
207 | static void debug_log_cleanup(struct bat_priv *bat_priv) | ||
208 | { | ||
209 | kfree(bat_priv->debug_log); | ||
210 | bat_priv->debug_log = NULL; | ||
211 | } | ||
212 | #else /* CONFIG_BATMAN_ADV_DEBUG */ | ||
213 | static int debug_log_setup(struct bat_priv *bat_priv) | ||
214 | { | ||
215 | bat_priv->debug_log = NULL; | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static void debug_log_cleanup(struct bat_priv *bat_priv) | ||
220 | { | ||
221 | return; | ||
222 | } | ||
223 | #endif | ||
224 | |||
225 | static int originators_open(struct inode *inode, struct file *file) | ||
226 | { | ||
227 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
228 | return single_open(file, orig_seq_print_text, net_dev); | ||
229 | } | ||
230 | |||
231 | static int gateways_open(struct inode *inode, struct file *file) | ||
232 | { | ||
233 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
234 | return single_open(file, gw_client_seq_print_text, net_dev); | ||
235 | } | ||
236 | |||
237 | static int softif_neigh_open(struct inode *inode, struct file *file) | ||
238 | { | ||
239 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
240 | return single_open(file, softif_neigh_seq_print_text, net_dev); | ||
241 | } | ||
242 | |||
243 | static int transtable_global_open(struct inode *inode, struct file *file) | ||
244 | { | ||
245 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
246 | return single_open(file, hna_global_seq_print_text, net_dev); | ||
247 | } | ||
248 | |||
249 | static int transtable_local_open(struct inode *inode, struct file *file) | ||
250 | { | ||
251 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
252 | return single_open(file, hna_local_seq_print_text, net_dev); | ||
253 | } | ||
254 | |||
255 | static int vis_data_open(struct inode *inode, struct file *file) | ||
256 | { | ||
257 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
258 | return single_open(file, vis_seq_print_text, net_dev); | ||
259 | } | ||
260 | |||
261 | struct bat_debuginfo { | ||
262 | struct attribute attr; | ||
263 | const struct file_operations fops; | ||
264 | }; | ||
265 | |||
266 | #define BAT_DEBUGINFO(_name, _mode, _open) \ | ||
267 | struct bat_debuginfo bat_debuginfo_##_name = { \ | ||
268 | .attr = { .name = __stringify(_name), \ | ||
269 | .mode = _mode, }, \ | ||
270 | .fops = { .owner = THIS_MODULE, \ | ||
271 | .open = _open, \ | ||
272 | .read = seq_read, \ | ||
273 | .llseek = seq_lseek, \ | ||
274 | .release = single_release, \ | ||
275 | } \ | ||
276 | }; | ||
277 | |||
278 | static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); | ||
279 | static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); | ||
280 | static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); | ||
281 | static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); | ||
282 | static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); | ||
283 | static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); | ||
284 | |||
285 | static struct bat_debuginfo *mesh_debuginfos[] = { | ||
286 | &bat_debuginfo_originators, | ||
287 | &bat_debuginfo_gateways, | ||
288 | &bat_debuginfo_softif_neigh, | ||
289 | &bat_debuginfo_transtable_global, | ||
290 | &bat_debuginfo_transtable_local, | ||
291 | &bat_debuginfo_vis_data, | ||
292 | NULL, | ||
293 | }; | ||
294 | |||
295 | void debugfs_init(void) | ||
296 | { | ||
297 | bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); | ||
298 | if (bat_debugfs == ERR_PTR(-ENODEV)) | ||
299 | bat_debugfs = NULL; | ||
300 | } | ||
301 | |||
302 | void debugfs_destroy(void) | ||
303 | { | ||
304 | if (bat_debugfs) { | ||
305 | debugfs_remove_recursive(bat_debugfs); | ||
306 | bat_debugfs = NULL; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | int debugfs_add_meshif(struct net_device *dev) | ||
311 | { | ||
312 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
313 | struct bat_debuginfo **bat_debug; | ||
314 | struct dentry *file; | ||
315 | |||
316 | if (!bat_debugfs) | ||
317 | goto out; | ||
318 | |||
319 | bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs); | ||
320 | if (!bat_priv->debug_dir) | ||
321 | goto out; | ||
322 | |||
323 | bat_socket_setup(bat_priv); | ||
324 | debug_log_setup(bat_priv); | ||
325 | |||
326 | for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { | ||
327 | file = debugfs_create_file(((*bat_debug)->attr).name, | ||
328 | S_IFREG | ((*bat_debug)->attr).mode, | ||
329 | bat_priv->debug_dir, | ||
330 | dev, &(*bat_debug)->fops); | ||
331 | if (!file) { | ||
332 | bat_err(dev, "Can't add debugfs file: %s/%s\n", | ||
333 | dev->name, ((*bat_debug)->attr).name); | ||
334 | goto rem_attr; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | return 0; | ||
339 | rem_attr: | ||
340 | debugfs_remove_recursive(bat_priv->debug_dir); | ||
341 | bat_priv->debug_dir = NULL; | ||
342 | out: | ||
343 | #ifdef CONFIG_DEBUG_FS | ||
344 | return -ENOMEM; | ||
345 | #else | ||
346 | return 0; | ||
347 | #endif /* CONFIG_DEBUG_FS */ | ||
348 | } | ||
349 | |||
350 | void debugfs_del_meshif(struct net_device *dev) | ||
351 | { | ||
352 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
353 | |||
354 | debug_log_cleanup(bat_priv); | ||
355 | |||
356 | if (bat_debugfs) { | ||
357 | debugfs_remove_recursive(bat_priv->debug_dir); | ||
358 | bat_priv->debug_dir = NULL; | ||
359 | } | ||
360 | } | ||
diff --git a/net/batman-adv/bat_debugfs.h b/net/batman-adv/bat_debugfs.h new file mode 100644 index 000000000000..72df532b7d5f --- /dev/null +++ b/net/batman-adv/bat_debugfs.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 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 | |||
23 | #ifndef _NET_BATMAN_ADV_DEBUGFS_H_ | ||
24 | #define _NET_BATMAN_ADV_DEBUGFS_H_ | ||
25 | |||
26 | #define DEBUGFS_BAT_SUBDIR "batman_adv" | ||
27 | |||
28 | void debugfs_init(void); | ||
29 | void debugfs_destroy(void); | ||
30 | int debugfs_add_meshif(struct net_device *dev); | ||
31 | void debugfs_del_meshif(struct net_device *dev); | ||
32 | |||
33 | #endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */ | ||
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c new file mode 100644 index 000000000000..cd7bb51825f1 --- /dev/null +++ b/net/batman-adv/bat_sysfs.c | |||
@@ -0,0 +1,593 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 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 "bat_sysfs.h" | ||
24 | #include "translation-table.h" | ||
25 | #include "originator.h" | ||
26 | #include "hard-interface.h" | ||
27 | #include "gateway_common.h" | ||
28 | #include "gateway_client.h" | ||
29 | #include "vis.h" | ||
30 | |||
31 | #define to_dev(obj) container_of(obj, struct device, kobj) | ||
32 | #define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent)) | ||
33 | #define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj)) | ||
34 | |||
35 | /* Use this, if you have customized show and store functions */ | ||
36 | #define BAT_ATTR(_name, _mode, _show, _store) \ | ||
37 | struct bat_attribute bat_attr_##_name = { \ | ||
38 | .attr = {.name = __stringify(_name), \ | ||
39 | .mode = _mode }, \ | ||
40 | .show = _show, \ | ||
41 | .store = _store, \ | ||
42 | }; | ||
43 | |||
44 | #define BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
45 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
46 | char *buff, size_t count) \ | ||
47 | { \ | ||
48 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
49 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
50 | return __store_bool_attr(buff, count, _post_func, attr, \ | ||
51 | &bat_priv->_name, net_dev); \ | ||
52 | } | ||
53 | |||
54 | #define BAT_ATTR_SHOW_BOOL(_name) \ | ||
55 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
56 | char *buff) \ | ||
57 | { \ | ||
58 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
59 | return sprintf(buff, "%s\n", \ | ||
60 | atomic_read(&bat_priv->_name) == 0 ? \ | ||
61 | "disabled" : "enabled"); \ | ||
62 | } \ | ||
63 | |||
64 | /* Use this, if you are going to turn a [name] in bat_priv on or off */ | ||
65 | #define BAT_ATTR_BOOL(_name, _mode, _post_func) \ | ||
66 | static BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
67 | static BAT_ATTR_SHOW_BOOL(_name) \ | ||
68 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
69 | |||
70 | |||
71 | #define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
72 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
73 | char *buff, size_t count) \ | ||
74 | { \ | ||
75 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
76 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
77 | return __store_uint_attr(buff, count, _min, _max, _post_func, \ | ||
78 | attr, &bat_priv->_name, net_dev); \ | ||
79 | } | ||
80 | |||
81 | #define BAT_ATTR_SHOW_UINT(_name) \ | ||
82 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
83 | char *buff) \ | ||
84 | { \ | ||
85 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
86 | return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ | ||
87 | } \ | ||
88 | |||
89 | /* Use this, if you are going to set [name] in bat_priv to unsigned integer | ||
90 | * values only */ | ||
91 | #define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \ | ||
92 | static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
93 | static BAT_ATTR_SHOW_UINT(_name) \ | ||
94 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
95 | |||
96 | |||
97 | static int store_bool_attr(char *buff, size_t count, | ||
98 | struct net_device *net_dev, | ||
99 | char *attr_name, atomic_t *attr) | ||
100 | { | ||
101 | int enabled = -1; | ||
102 | |||
103 | if (buff[count - 1] == '\n') | ||
104 | buff[count - 1] = '\0'; | ||
105 | |||
106 | if ((strncmp(buff, "1", 2) == 0) || | ||
107 | (strncmp(buff, "enable", 7) == 0) || | ||
108 | (strncmp(buff, "enabled", 8) == 0)) | ||
109 | enabled = 1; | ||
110 | |||
111 | if ((strncmp(buff, "0", 2) == 0) || | ||
112 | (strncmp(buff, "disable", 8) == 0) || | ||
113 | (strncmp(buff, "disabled", 9) == 0)) | ||
114 | enabled = 0; | ||
115 | |||
116 | if (enabled < 0) { | ||
117 | bat_info(net_dev, | ||
118 | "%s: Invalid parameter received: %s\n", | ||
119 | attr_name, buff); | ||
120 | return -EINVAL; | ||
121 | } | ||
122 | |||
123 | if (atomic_read(attr) == enabled) | ||
124 | return count; | ||
125 | |||
126 | bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, | ||
127 | atomic_read(attr) == 1 ? "enabled" : "disabled", | ||
128 | enabled == 1 ? "enabled" : "disabled"); | ||
129 | |||
130 | atomic_set(attr, (unsigned)enabled); | ||
131 | return count; | ||
132 | } | ||
133 | |||
134 | static inline ssize_t __store_bool_attr(char *buff, size_t count, | ||
135 | void (*post_func)(struct net_device *), | ||
136 | struct attribute *attr, | ||
137 | atomic_t *attr_store, struct net_device *net_dev) | ||
138 | { | ||
139 | int ret; | ||
140 | |||
141 | ret = store_bool_attr(buff, count, net_dev, (char *)attr->name, | ||
142 | attr_store); | ||
143 | if (post_func && ret) | ||
144 | post_func(net_dev); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static int store_uint_attr(char *buff, size_t count, | ||
150 | struct net_device *net_dev, char *attr_name, | ||
151 | unsigned int min, unsigned int max, atomic_t *attr) | ||
152 | { | ||
153 | unsigned long uint_val; | ||
154 | int ret; | ||
155 | |||
156 | ret = strict_strtoul(buff, 10, &uint_val); | ||
157 | if (ret) { | ||
158 | bat_info(net_dev, | ||
159 | "%s: Invalid parameter received: %s\n", | ||
160 | attr_name, buff); | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | |||
164 | if (uint_val < min) { | ||
165 | bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", | ||
166 | attr_name, uint_val, min); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | if (uint_val > max) { | ||
171 | bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", | ||
172 | attr_name, uint_val, max); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | if (atomic_read(attr) == uint_val) | ||
177 | return count; | ||
178 | |||
179 | bat_info(net_dev, "%s: Changing from: %i to: %lu\n", | ||
180 | attr_name, atomic_read(attr), uint_val); | ||
181 | |||
182 | atomic_set(attr, uint_val); | ||
183 | return count; | ||
184 | } | ||
185 | |||
186 | static inline ssize_t __store_uint_attr(char *buff, size_t count, | ||
187 | int min, int max, | ||
188 | void (*post_func)(struct net_device *), | ||
189 | struct attribute *attr, | ||
190 | atomic_t *attr_store, struct net_device *net_dev) | ||
191 | { | ||
192 | int ret; | ||
193 | |||
194 | ret = store_uint_attr(buff, count, net_dev, (char *)attr->name, | ||
195 | min, max, attr_store); | ||
196 | if (post_func && ret) | ||
197 | post_func(net_dev); | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
203 | char *buff) | ||
204 | { | ||
205 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
206 | int vis_mode = atomic_read(&bat_priv->vis_mode); | ||
207 | |||
208 | return sprintf(buff, "%s\n", | ||
209 | vis_mode == VIS_TYPE_CLIENT_UPDATE ? | ||
210 | "client" : "server"); | ||
211 | } | ||
212 | |||
213 | static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
214 | char *buff, size_t count) | ||
215 | { | ||
216 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
217 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
218 | unsigned long val; | ||
219 | int ret, vis_mode_tmp = -1; | ||
220 | |||
221 | ret = strict_strtoul(buff, 10, &val); | ||
222 | |||
223 | if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) || | ||
224 | (strncmp(buff, "client", 6) == 0) || | ||
225 | (strncmp(buff, "off", 3) == 0)) | ||
226 | vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE; | ||
227 | |||
228 | if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) || | ||
229 | (strncmp(buff, "server", 6) == 0)) | ||
230 | vis_mode_tmp = VIS_TYPE_SERVER_SYNC; | ||
231 | |||
232 | if (vis_mode_tmp < 0) { | ||
233 | if (buff[count - 1] == '\n') | ||
234 | buff[count - 1] = '\0'; | ||
235 | |||
236 | bat_info(net_dev, | ||
237 | "Invalid parameter for 'vis mode' setting received: " | ||
238 | "%s\n", buff); | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | |||
242 | if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) | ||
243 | return count; | ||
244 | |||
245 | bat_info(net_dev, "Changing vis mode from: %s to: %s\n", | ||
246 | atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ? | ||
247 | "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ? | ||
248 | "client" : "server"); | ||
249 | |||
250 | atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp); | ||
251 | return count; | ||
252 | } | ||
253 | |||
254 | static void post_gw_deselect(struct net_device *net_dev) | ||
255 | { | ||
256 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
257 | gw_deselect(bat_priv); | ||
258 | } | ||
259 | |||
260 | static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
261 | char *buff) | ||
262 | { | ||
263 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
264 | int bytes_written; | ||
265 | |||
266 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
267 | case GW_MODE_CLIENT: | ||
268 | bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME); | ||
269 | break; | ||
270 | case GW_MODE_SERVER: | ||
271 | bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME); | ||
272 | break; | ||
273 | default: | ||
274 | bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME); | ||
275 | break; | ||
276 | } | ||
277 | |||
278 | return bytes_written; | ||
279 | } | ||
280 | |||
281 | static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
282 | char *buff, size_t count) | ||
283 | { | ||
284 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
285 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
286 | char *curr_gw_mode_str; | ||
287 | int gw_mode_tmp = -1; | ||
288 | |||
289 | if (buff[count - 1] == '\n') | ||
290 | buff[count - 1] = '\0'; | ||
291 | |||
292 | if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) | ||
293 | gw_mode_tmp = GW_MODE_OFF; | ||
294 | |||
295 | if (strncmp(buff, GW_MODE_CLIENT_NAME, | ||
296 | strlen(GW_MODE_CLIENT_NAME)) == 0) | ||
297 | gw_mode_tmp = GW_MODE_CLIENT; | ||
298 | |||
299 | if (strncmp(buff, GW_MODE_SERVER_NAME, | ||
300 | strlen(GW_MODE_SERVER_NAME)) == 0) | ||
301 | gw_mode_tmp = GW_MODE_SERVER; | ||
302 | |||
303 | if (gw_mode_tmp < 0) { | ||
304 | bat_info(net_dev, | ||
305 | "Invalid parameter for 'gw mode' setting received: " | ||
306 | "%s\n", buff); | ||
307 | return -EINVAL; | ||
308 | } | ||
309 | |||
310 | if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) | ||
311 | return count; | ||
312 | |||
313 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
314 | case GW_MODE_CLIENT: | ||
315 | curr_gw_mode_str = GW_MODE_CLIENT_NAME; | ||
316 | break; | ||
317 | case GW_MODE_SERVER: | ||
318 | curr_gw_mode_str = GW_MODE_SERVER_NAME; | ||
319 | break; | ||
320 | default: | ||
321 | curr_gw_mode_str = GW_MODE_OFF_NAME; | ||
322 | break; | ||
323 | } | ||
324 | |||
325 | bat_info(net_dev, "Changing gw mode from: %s to: %s\n", | ||
326 | curr_gw_mode_str, buff); | ||
327 | |||
328 | gw_deselect(bat_priv); | ||
329 | atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); | ||
330 | return count; | ||
331 | } | ||
332 | |||
333 | static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
334 | char *buff) | ||
335 | { | ||
336 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
337 | int down, up; | ||
338 | int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); | ||
339 | |||
340 | gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); | ||
341 | return sprintf(buff, "%i%s/%i%s\n", | ||
342 | (down > 2048 ? down / 1024 : down), | ||
343 | (down > 2048 ? "MBit" : "KBit"), | ||
344 | (up > 2048 ? up / 1024 : up), | ||
345 | (up > 2048 ? "MBit" : "KBit")); | ||
346 | } | ||
347 | |||
348 | static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
349 | char *buff, size_t count) | ||
350 | { | ||
351 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
352 | |||
353 | if (buff[count - 1] == '\n') | ||
354 | buff[count - 1] = '\0'; | ||
355 | |||
356 | return gw_bandwidth_set(net_dev, buff, count); | ||
357 | } | ||
358 | |||
359 | BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); | ||
360 | BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); | ||
361 | BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); | ||
362 | static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); | ||
363 | static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); | ||
364 | BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); | ||
365 | BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); | ||
366 | BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE, | ||
367 | post_gw_deselect); | ||
368 | static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, | ||
369 | store_gw_bwidth); | ||
370 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
371 | BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); | ||
372 | #endif | ||
373 | |||
374 | static struct bat_attribute *mesh_attrs[] = { | ||
375 | &bat_attr_aggregated_ogms, | ||
376 | &bat_attr_bonding, | ||
377 | &bat_attr_fragmentation, | ||
378 | &bat_attr_vis_mode, | ||
379 | &bat_attr_gw_mode, | ||
380 | &bat_attr_orig_interval, | ||
381 | &bat_attr_hop_penalty, | ||
382 | &bat_attr_gw_sel_class, | ||
383 | &bat_attr_gw_bandwidth, | ||
384 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
385 | &bat_attr_log_level, | ||
386 | #endif | ||
387 | NULL, | ||
388 | }; | ||
389 | |||
390 | int sysfs_add_meshif(struct net_device *dev) | ||
391 | { | ||
392 | struct kobject *batif_kobject = &dev->dev.kobj; | ||
393 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
394 | struct bat_attribute **bat_attr; | ||
395 | int err; | ||
396 | |||
397 | bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR, | ||
398 | batif_kobject); | ||
399 | if (!bat_priv->mesh_obj) { | ||
400 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
401 | SYSFS_IF_MESH_SUBDIR); | ||
402 | goto out; | ||
403 | } | ||
404 | |||
405 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) { | ||
406 | err = sysfs_create_file(bat_priv->mesh_obj, | ||
407 | &((*bat_attr)->attr)); | ||
408 | if (err) { | ||
409 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
410 | dev->name, SYSFS_IF_MESH_SUBDIR, | ||
411 | ((*bat_attr)->attr).name); | ||
412 | goto rem_attr; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | |||
418 | rem_attr: | ||
419 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
420 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
421 | |||
422 | kobject_put(bat_priv->mesh_obj); | ||
423 | bat_priv->mesh_obj = NULL; | ||
424 | out: | ||
425 | return -ENOMEM; | ||
426 | } | ||
427 | |||
428 | void sysfs_del_meshif(struct net_device *dev) | ||
429 | { | ||
430 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
431 | struct bat_attribute **bat_attr; | ||
432 | |||
433 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
434 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
435 | |||
436 | kobject_put(bat_priv->mesh_obj); | ||
437 | bat_priv->mesh_obj = NULL; | ||
438 | } | ||
439 | |||
440 | static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
441 | char *buff) | ||
442 | { | ||
443 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
444 | struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); | ||
445 | ssize_t length; | ||
446 | |||
447 | if (!batman_if) | ||
448 | return 0; | ||
449 | |||
450 | length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ? | ||
451 | "none" : batman_if->soft_iface->name); | ||
452 | |||
453 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
454 | |||
455 | return length; | ||
456 | } | ||
457 | |||
458 | static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
459 | char *buff, size_t count) | ||
460 | { | ||
461 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
462 | struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); | ||
463 | int status_tmp = -1; | ||
464 | int ret; | ||
465 | |||
466 | if (!batman_if) | ||
467 | return count; | ||
468 | |||
469 | if (buff[count - 1] == '\n') | ||
470 | buff[count - 1] = '\0'; | ||
471 | |||
472 | if (strlen(buff) >= IFNAMSIZ) { | ||
473 | pr_err("Invalid parameter for 'mesh_iface' setting received: " | ||
474 | "interface name too long '%s'\n", buff); | ||
475 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | |||
479 | if (strncmp(buff, "none", 4) == 0) | ||
480 | status_tmp = IF_NOT_IN_USE; | ||
481 | else | ||
482 | status_tmp = IF_I_WANT_YOU; | ||
483 | |||
484 | if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) && | ||
485 | (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) { | ||
486 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
487 | return count; | ||
488 | } | ||
489 | |||
490 | if (status_tmp == IF_NOT_IN_USE) { | ||
491 | rtnl_lock(); | ||
492 | hardif_disable_interface(batman_if); | ||
493 | rtnl_unlock(); | ||
494 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
495 | return count; | ||
496 | } | ||
497 | |||
498 | /* if the interface already is in use */ | ||
499 | if (batman_if->if_status != IF_NOT_IN_USE) { | ||
500 | rtnl_lock(); | ||
501 | hardif_disable_interface(batman_if); | ||
502 | rtnl_unlock(); | ||
503 | } | ||
504 | |||
505 | ret = hardif_enable_interface(batman_if, buff); | ||
506 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
507 | |||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, | ||
512 | char *buff) | ||
513 | { | ||
514 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
515 | struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); | ||
516 | ssize_t length; | ||
517 | |||
518 | if (!batman_if) | ||
519 | return 0; | ||
520 | |||
521 | switch (batman_if->if_status) { | ||
522 | case IF_TO_BE_REMOVED: | ||
523 | length = sprintf(buff, "disabling\n"); | ||
524 | break; | ||
525 | case IF_INACTIVE: | ||
526 | length = sprintf(buff, "inactive\n"); | ||
527 | break; | ||
528 | case IF_ACTIVE: | ||
529 | length = sprintf(buff, "active\n"); | ||
530 | break; | ||
531 | case IF_TO_BE_ACTIVATED: | ||
532 | length = sprintf(buff, "enabling\n"); | ||
533 | break; | ||
534 | case IF_NOT_IN_USE: | ||
535 | default: | ||
536 | length = sprintf(buff, "not in use\n"); | ||
537 | break; | ||
538 | } | ||
539 | |||
540 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
541 | |||
542 | return length; | ||
543 | } | ||
544 | |||
545 | static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR, | ||
546 | show_mesh_iface, store_mesh_iface); | ||
547 | static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL); | ||
548 | |||
549 | static struct bat_attribute *batman_attrs[] = { | ||
550 | &bat_attr_mesh_iface, | ||
551 | &bat_attr_iface_status, | ||
552 | NULL, | ||
553 | }; | ||
554 | |||
555 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev) | ||
556 | { | ||
557 | struct kobject *hardif_kobject = &dev->dev.kobj; | ||
558 | struct bat_attribute **bat_attr; | ||
559 | int err; | ||
560 | |||
561 | *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR, | ||
562 | hardif_kobject); | ||
563 | |||
564 | if (!*hardif_obj) { | ||
565 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
566 | SYSFS_IF_BAT_SUBDIR); | ||
567 | goto out; | ||
568 | } | ||
569 | |||
570 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) { | ||
571 | err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr)); | ||
572 | if (err) { | ||
573 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
574 | dev->name, SYSFS_IF_BAT_SUBDIR, | ||
575 | ((*bat_attr)->attr).name); | ||
576 | goto rem_attr; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | |||
582 | rem_attr: | ||
583 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) | ||
584 | sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr)); | ||
585 | out: | ||
586 | return -ENOMEM; | ||
587 | } | ||
588 | |||
589 | void sysfs_del_hardif(struct kobject **hardif_obj) | ||
590 | { | ||
591 | kobject_put(*hardif_obj); | ||
592 | *hardif_obj = NULL; | ||
593 | } | ||
diff --git a/net/batman-adv/bat_sysfs.h b/net/batman-adv/bat_sysfs.h new file mode 100644 index 000000000000..7f186c007b4f --- /dev/null +++ b/net/batman-adv/bat_sysfs.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 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 | |||
23 | #ifndef _NET_BATMAN_ADV_SYSFS_H_ | ||
24 | #define _NET_BATMAN_ADV_SYSFS_H_ | ||
25 | |||
26 | #define SYSFS_IF_MESH_SUBDIR "mesh" | ||
27 | #define SYSFS_IF_BAT_SUBDIR "batman_adv" | ||
28 | |||
29 | struct bat_attribute { | ||
30 | struct attribute attr; | ||
31 | ssize_t (*show)(struct kobject *kobj, struct attribute *attr, | ||
32 | char *buf); | ||
33 | ssize_t (*store)(struct kobject *kobj, struct attribute *attr, | ||
34 | char *buf, size_t count); | ||
35 | }; | ||
36 | |||
37 | int sysfs_add_meshif(struct net_device *dev); | ||
38 | void sysfs_del_meshif(struct net_device *dev); | ||
39 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev); | ||
40 | void sysfs_del_hardif(struct kobject **hardif_obj); | ||
41 | |||
42 | #endif /* _NET_BATMAN_ADV_SYSFS_H_ */ | ||
diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c new file mode 100644 index 000000000000..bbcd8f744cdd --- /dev/null +++ b/net/batman-adv/bitarray.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 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 | |||
25 | #include <linux/bitops.h> | ||
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(unsigned long *seq_bits, uint32_t last_seqno, | ||
30 | uint32_t curr_seqno) | ||
31 | { | ||
32 | int32_t diff, word_offset, word_num; | ||
33 | |||
34 | diff = last_seqno - curr_seqno; | ||
35 | if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) { | ||
36 | return 0; | ||
37 | } else { | ||
38 | /* which word */ | ||
39 | word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE; | ||
40 | /* which position in the selected word */ | ||
41 | word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE; | ||
42 | |||
43 | if (test_bit(word_offset, &seq_bits[word_num])) | ||
44 | return 1; | ||
45 | else | ||
46 | return 0; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | /* turn corresponding bit on, so we can remember that we got the packet */ | ||
51 | void bit_mark(unsigned long *seq_bits, int32_t n) | ||
52 | { | ||
53 | int32_t word_offset, word_num; | ||
54 | |||
55 | /* if too old, just drop it */ | ||
56 | if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE) | ||
57 | return; | ||
58 | |||
59 | /* which word */ | ||
60 | word_num = n / WORD_BIT_SIZE; | ||
61 | /* which position in the selected word */ | ||
62 | word_offset = n % WORD_BIT_SIZE; | ||
63 | |||
64 | set_bit(word_offset, &seq_bits[word_num]); /* turn the position on */ | ||
65 | } | ||
66 | |||
67 | /* shift the packet array by n places. */ | ||
68 | static void bit_shift(unsigned long *seq_bits, int32_t n) | ||
69 | { | ||
70 | int32_t word_offset, word_num; | ||
71 | int32_t i; | ||
72 | |||
73 | if (n <= 0 || n >= TQ_LOCAL_WINDOW_SIZE) | ||
74 | return; | ||
75 | |||
76 | word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */ | ||
77 | word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */ | ||
78 | |||
79 | for (i = NUM_WORDS - 1; i > word_num; i--) { | ||
80 | /* going from old to new, so we don't overwrite the data we copy | ||
81 | * from. | ||
82 | * | ||
83 | * left is high, right is low: FEDC BA98 7654 3210 | ||
84 | * ^^ ^^ | ||
85 | * vvvv | ||
86 | * ^^^^ = from, vvvvv =to, we'd have word_num==1 and | ||
87 | * word_offset==WORD_BIT_SIZE/2 ????? in this example. | ||
88 | * (=24 bits) | ||
89 | * | ||
90 | * our desired output would be: 9876 5432 1000 0000 | ||
91 | * */ | ||
92 | |||
93 | seq_bits[i] = | ||
94 | (seq_bits[i - word_num] << word_offset) + | ||
95 | /* take the lower port from the left half, shift it left | ||
96 | * to its final position */ | ||
97 | (seq_bits[i - word_num - 1] >> | ||
98 | (WORD_BIT_SIZE-word_offset)); | ||
99 | /* and the upper part of the right half and shift it left to | ||
100 | * it's position */ | ||
101 | /* for our example that would be: word[0] = 9800 + 0076 = | ||
102 | * 9876 */ | ||
103 | } | ||
104 | /* now for our last word, i==word_num, we only have the it's "left" | ||
105 | * half. that's the 1000 word in our example.*/ | ||
106 | |||
107 | seq_bits[i] = (seq_bits[i - word_num] << word_offset); | ||
108 | |||
109 | /* pad the rest with 0, if there is anything */ | ||
110 | i--; | ||
111 | |||
112 | for (; i >= 0; i--) | ||
113 | seq_bits[i] = 0; | ||
114 | } | ||
115 | |||
116 | static void bit_reset_window(unsigned long *seq_bits) | ||
117 | { | ||
118 | int i; | ||
119 | for (i = 0; i < NUM_WORDS; i++) | ||
120 | seq_bits[i] = 0; | ||
121 | } | ||
122 | |||
123 | |||
124 | /* receive and process one packet within the sequence number window. | ||
125 | * | ||
126 | * returns: | ||
127 | * 1 if the window was moved (either new or very old) | ||
128 | * 0 if the window was not moved/shifted. | ||
129 | */ | ||
130 | char bit_get_packet(void *priv, unsigned long *seq_bits, | ||
131 | int32_t seq_num_diff, int8_t set_mark) | ||
132 | { | ||
133 | struct bat_priv *bat_priv = (struct bat_priv *)priv; | ||
134 | |||
135 | /* sequence number is slightly older. We already got a sequence number | ||
136 | * higher than this one, so we just mark it. */ | ||
137 | |||
138 | if ((seq_num_diff <= 0) && (seq_num_diff > -TQ_LOCAL_WINDOW_SIZE)) { | ||
139 | if (set_mark) | ||
140 | bit_mark(seq_bits, -seq_num_diff); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | /* sequence number is slightly newer, so we shift the window and | ||
145 | * set the mark if required */ | ||
146 | |||
147 | if ((seq_num_diff > 0) && (seq_num_diff < TQ_LOCAL_WINDOW_SIZE)) { | ||
148 | bit_shift(seq_bits, seq_num_diff); | ||
149 | |||
150 | if (set_mark) | ||
151 | bit_mark(seq_bits, 0); | ||
152 | return 1; | ||
153 | } | ||
154 | |||
155 | /* sequence number is much newer, probably missed a lot of packets */ | ||
156 | |||
157 | if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE) | ||
158 | || (seq_num_diff < EXPECTED_SEQNO_RANGE)) { | ||
159 | bat_dbg(DBG_BATMAN, bat_priv, | ||
160 | "We missed a lot of packets (%i) !\n", | ||
161 | seq_num_diff - 1); | ||
162 | bit_reset_window(seq_bits); | ||
163 | if (set_mark) | ||
164 | bit_mark(seq_bits, 0); | ||
165 | return 1; | ||
166 | } | ||
167 | |||
168 | /* received a much older packet. The other host either restarted | ||
169 | * or the old packet got delayed somewhere in the network. The | ||
170 | * packet should be dropped without calling this function if the | ||
171 | * seqno window is protected. */ | ||
172 | |||
173 | if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) | ||
174 | || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { | ||
175 | |||
176 | bat_dbg(DBG_BATMAN, bat_priv, | ||
177 | "Other host probably restarted!\n"); | ||
178 | |||
179 | bit_reset_window(seq_bits); | ||
180 | if (set_mark) | ||
181 | bit_mark(seq_bits, 0); | ||
182 | |||
183 | return 1; | ||
184 | } | ||
185 | |||
186 | /* never reached */ | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* count the hamming weight, how many good packets did we receive? just count | ||
191 | * the 1's. | ||
192 | */ | ||
193 | int bit_packet_count(unsigned long *seq_bits) | ||
194 | { | ||
195 | int i, hamming = 0; | ||
196 | |||
197 | for (i = 0; i < NUM_WORDS; i++) | ||
198 | hamming += hweight_long(seq_bits[i]); | ||
199 | |||
200 | return hamming; | ||
201 | } | ||
diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h new file mode 100644 index 000000000000..ac54017601b1 --- /dev/null +++ b/net/batman-adv/bitarray.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 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 _NET_BATMAN_ADV_BITARRAY_H_ | ||
23 | #define _NET_BATMAN_ADV_BITARRAY_H_ | ||
24 | |||
25 | #define WORD_BIT_SIZE (sizeof(unsigned long) * 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(unsigned long *seq_bits, uint32_t last_seqno, | ||
30 | uint32_t curr_seqno); | ||
31 | |||
32 | /* turn corresponding bit on, so we can remember that we got the packet */ | ||
33 | void bit_mark(unsigned long *seq_bits, int32_t n); | ||
34 | |||
35 | |||
36 | /* receive and process one packet, returns 1 if received seq_num is considered | ||
37 | * new, 0 if old */ | ||
38 | char bit_get_packet(void *priv, unsigned long *seq_bits, | ||
39 | int32_t seq_num_diff, int8_t set_mark); | ||
40 | |||
41 | /* count the hamming weight, how many good packets did we receive? */ | ||
42 | int bit_packet_count(unsigned long *seq_bits); | ||
43 | |||
44 | #endif /* _NET_BATMAN_ADV_BITARRAY_H_ */ | ||
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c new file mode 100644 index 000000000000..0065ffb8d96d --- /dev/null +++ b/net/batman-adv/gateway_client.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 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 "gateway_client.h" | ||
24 | #include "gateway_common.h" | ||
25 | #include "hard-interface.h" | ||
26 | #include <linux/ip.h> | ||
27 | #include <linux/ipv6.h> | ||
28 | #include <linux/udp.h> | ||
29 | #include <linux/if_vlan.h> | ||
30 | |||
31 | static void gw_node_free_ref(struct kref *refcount) | ||
32 | { | ||
33 | struct gw_node *gw_node; | ||
34 | |||
35 | gw_node = container_of(refcount, struct gw_node, refcount); | ||
36 | kfree(gw_node); | ||
37 | } | ||
38 | |||
39 | static void gw_node_free_rcu(struct rcu_head *rcu) | ||
40 | { | ||
41 | struct gw_node *gw_node; | ||
42 | |||
43 | gw_node = container_of(rcu, struct gw_node, rcu); | ||
44 | kref_put(&gw_node->refcount, gw_node_free_ref); | ||
45 | } | ||
46 | |||
47 | void *gw_get_selected(struct bat_priv *bat_priv) | ||
48 | { | ||
49 | struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; | ||
50 | |||
51 | if (!curr_gateway_tmp) | ||
52 | return NULL; | ||
53 | |||
54 | return curr_gateway_tmp->orig_node; | ||
55 | } | ||
56 | |||
57 | void gw_deselect(struct bat_priv *bat_priv) | ||
58 | { | ||
59 | struct gw_node *gw_node = bat_priv->curr_gw; | ||
60 | |||
61 | bat_priv->curr_gw = NULL; | ||
62 | |||
63 | if (gw_node) | ||
64 | kref_put(&gw_node->refcount, gw_node_free_ref); | ||
65 | } | ||
66 | |||
67 | static struct gw_node *gw_select(struct bat_priv *bat_priv, | ||
68 | struct gw_node *new_gw_node) | ||
69 | { | ||
70 | struct gw_node *curr_gw_node = bat_priv->curr_gw; | ||
71 | |||
72 | if (new_gw_node) | ||
73 | kref_get(&new_gw_node->refcount); | ||
74 | |||
75 | bat_priv->curr_gw = new_gw_node; | ||
76 | return curr_gw_node; | ||
77 | } | ||
78 | |||
79 | void gw_election(struct bat_priv *bat_priv) | ||
80 | { | ||
81 | struct hlist_node *node; | ||
82 | struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = NULL; | ||
83 | uint8_t max_tq = 0; | ||
84 | uint32_t max_gw_factor = 0, tmp_gw_factor = 0; | ||
85 | int down, up; | ||
86 | |||
87 | /** | ||
88 | * The batman daemon checks here if we already passed a full originator | ||
89 | * cycle in order to make sure we don't choose the first gateway we | ||
90 | * hear about. This check is based on the daemon's uptime which we | ||
91 | * don't have. | ||
92 | **/ | ||
93 | if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) | ||
94 | return; | ||
95 | |||
96 | if (bat_priv->curr_gw) | ||
97 | return; | ||
98 | |||
99 | rcu_read_lock(); | ||
100 | if (hlist_empty(&bat_priv->gw_list)) { | ||
101 | rcu_read_unlock(); | ||
102 | |||
103 | if (bat_priv->curr_gw) { | ||
104 | bat_dbg(DBG_BATMAN, bat_priv, | ||
105 | "Removing selected gateway - " | ||
106 | "no gateway in range\n"); | ||
107 | gw_deselect(bat_priv); | ||
108 | } | ||
109 | |||
110 | return; | ||
111 | } | ||
112 | |||
113 | hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { | ||
114 | if (!gw_node->orig_node->router) | ||
115 | continue; | ||
116 | |||
117 | if (gw_node->deleted) | ||
118 | continue; | ||
119 | |||
120 | switch (atomic_read(&bat_priv->gw_sel_class)) { | ||
121 | case 1: /* fast connection */ | ||
122 | gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, | ||
123 | &down, &up); | ||
124 | |||
125 | tmp_gw_factor = (gw_node->orig_node->router->tq_avg * | ||
126 | gw_node->orig_node->router->tq_avg * | ||
127 | down * 100 * 100) / | ||
128 | (TQ_LOCAL_WINDOW_SIZE * | ||
129 | TQ_LOCAL_WINDOW_SIZE * 64); | ||
130 | |||
131 | if ((tmp_gw_factor > max_gw_factor) || | ||
132 | ((tmp_gw_factor == max_gw_factor) && | ||
133 | (gw_node->orig_node->router->tq_avg > max_tq))) | ||
134 | curr_gw_tmp = gw_node; | ||
135 | break; | ||
136 | |||
137 | default: /** | ||
138 | * 2: stable connection (use best statistic) | ||
139 | * 3: fast-switch (use best statistic but change as | ||
140 | * soon as a better gateway appears) | ||
141 | * XX: late-switch (use best statistic but change as | ||
142 | * soon as a better gateway appears which has | ||
143 | * $routing_class more tq points) | ||
144 | **/ | ||
145 | if (gw_node->orig_node->router->tq_avg > max_tq) | ||
146 | curr_gw_tmp = gw_node; | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | if (gw_node->orig_node->router->tq_avg > max_tq) | ||
151 | max_tq = gw_node->orig_node->router->tq_avg; | ||
152 | |||
153 | if (tmp_gw_factor > max_gw_factor) | ||
154 | max_gw_factor = tmp_gw_factor; | ||
155 | } | ||
156 | |||
157 | if (bat_priv->curr_gw != curr_gw_tmp) { | ||
158 | if ((bat_priv->curr_gw) && (!curr_gw_tmp)) | ||
159 | bat_dbg(DBG_BATMAN, bat_priv, | ||
160 | "Removing selected gateway - " | ||
161 | "no gateway in range\n"); | ||
162 | else if ((!bat_priv->curr_gw) && (curr_gw_tmp)) | ||
163 | bat_dbg(DBG_BATMAN, bat_priv, | ||
164 | "Adding route to gateway %pM " | ||
165 | "(gw_flags: %i, tq: %i)\n", | ||
166 | curr_gw_tmp->orig_node->orig, | ||
167 | curr_gw_tmp->orig_node->gw_flags, | ||
168 | curr_gw_tmp->orig_node->router->tq_avg); | ||
169 | else | ||
170 | bat_dbg(DBG_BATMAN, bat_priv, | ||
171 | "Changing route to gateway %pM " | ||
172 | "(gw_flags: %i, tq: %i)\n", | ||
173 | curr_gw_tmp->orig_node->orig, | ||
174 | curr_gw_tmp->orig_node->gw_flags, | ||
175 | curr_gw_tmp->orig_node->router->tq_avg); | ||
176 | |||
177 | old_gw_node = gw_select(bat_priv, curr_gw_tmp); | ||
178 | } | ||
179 | |||
180 | rcu_read_unlock(); | ||
181 | |||
182 | /* the kfree() has to be outside of the rcu lock */ | ||
183 | if (old_gw_node) | ||
184 | kref_put(&old_gw_node->refcount, gw_node_free_ref); | ||
185 | } | ||
186 | |||
187 | void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) | ||
188 | { | ||
189 | struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; | ||
190 | uint8_t gw_tq_avg, orig_tq_avg; | ||
191 | |||
192 | if (!curr_gateway_tmp) | ||
193 | return; | ||
194 | |||
195 | if (!curr_gateway_tmp->orig_node) | ||
196 | goto deselect; | ||
197 | |||
198 | if (!curr_gateway_tmp->orig_node->router) | ||
199 | goto deselect; | ||
200 | |||
201 | /* this node already is the gateway */ | ||
202 | if (curr_gateway_tmp->orig_node == orig_node) | ||
203 | return; | ||
204 | |||
205 | if (!orig_node->router) | ||
206 | return; | ||
207 | |||
208 | gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; | ||
209 | orig_tq_avg = orig_node->router->tq_avg; | ||
210 | |||
211 | /* the TQ value has to be better */ | ||
212 | if (orig_tq_avg < gw_tq_avg) | ||
213 | return; | ||
214 | |||
215 | /** | ||
216 | * if the routing class is greater than 3 the value tells us how much | ||
217 | * greater the TQ value of the new gateway must be | ||
218 | **/ | ||
219 | if ((atomic_read(&bat_priv->gw_sel_class) > 3) && | ||
220 | (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class))) | ||
221 | return; | ||
222 | |||
223 | bat_dbg(DBG_BATMAN, bat_priv, | ||
224 | "Restarting gateway selection: better gateway found (tq curr: " | ||
225 | "%i, tq new: %i)\n", | ||
226 | gw_tq_avg, orig_tq_avg); | ||
227 | |||
228 | deselect: | ||
229 | gw_deselect(bat_priv); | ||
230 | } | ||
231 | |||
232 | static void gw_node_add(struct bat_priv *bat_priv, | ||
233 | struct orig_node *orig_node, uint8_t new_gwflags) | ||
234 | { | ||
235 | struct gw_node *gw_node; | ||
236 | int down, up; | ||
237 | |||
238 | gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC); | ||
239 | if (!gw_node) | ||
240 | return; | ||
241 | |||
242 | memset(gw_node, 0, sizeof(struct gw_node)); | ||
243 | INIT_HLIST_NODE(&gw_node->list); | ||
244 | gw_node->orig_node = orig_node; | ||
245 | kref_init(&gw_node->refcount); | ||
246 | |||
247 | spin_lock_bh(&bat_priv->gw_list_lock); | ||
248 | hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list); | ||
249 | spin_unlock_bh(&bat_priv->gw_list_lock); | ||
250 | |||
251 | gw_bandwidth_to_kbit(new_gwflags, &down, &up); | ||
252 | bat_dbg(DBG_BATMAN, bat_priv, | ||
253 | "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n", | ||
254 | orig_node->orig, new_gwflags, | ||
255 | (down > 2048 ? down / 1024 : down), | ||
256 | (down > 2048 ? "MBit" : "KBit"), | ||
257 | (up > 2048 ? up / 1024 : up), | ||
258 | (up > 2048 ? "MBit" : "KBit")); | ||
259 | } | ||
260 | |||
261 | void gw_node_update(struct bat_priv *bat_priv, | ||
262 | struct orig_node *orig_node, uint8_t new_gwflags) | ||
263 | { | ||
264 | struct hlist_node *node; | ||
265 | struct gw_node *gw_node; | ||
266 | |||
267 | rcu_read_lock(); | ||
268 | hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { | ||
269 | if (gw_node->orig_node != orig_node) | ||
270 | continue; | ||
271 | |||
272 | bat_dbg(DBG_BATMAN, bat_priv, | ||
273 | "Gateway class of originator %pM changed from " | ||
274 | "%i to %i\n", | ||
275 | orig_node->orig, gw_node->orig_node->gw_flags, | ||
276 | new_gwflags); | ||
277 | |||
278 | gw_node->deleted = 0; | ||
279 | |||
280 | if (new_gwflags == 0) { | ||
281 | gw_node->deleted = jiffies; | ||
282 | bat_dbg(DBG_BATMAN, bat_priv, | ||
283 | "Gateway %pM removed from gateway list\n", | ||
284 | orig_node->orig); | ||
285 | |||
286 | if (gw_node == bat_priv->curr_gw) { | ||
287 | rcu_read_unlock(); | ||
288 | gw_deselect(bat_priv); | ||
289 | return; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | rcu_read_unlock(); | ||
294 | return; | ||
295 | } | ||
296 | rcu_read_unlock(); | ||
297 | |||
298 | if (new_gwflags == 0) | ||
299 | return; | ||
300 | |||
301 | gw_node_add(bat_priv, orig_node, new_gwflags); | ||
302 | } | ||
303 | |||
304 | void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) | ||
305 | { | ||
306 | return gw_node_update(bat_priv, orig_node, 0); | ||
307 | } | ||
308 | |||
309 | void gw_node_purge(struct bat_priv *bat_priv) | ||
310 | { | ||
311 | struct gw_node *gw_node; | ||
312 | struct hlist_node *node, *node_tmp; | ||
313 | unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; | ||
314 | |||
315 | spin_lock_bh(&bat_priv->gw_list_lock); | ||
316 | |||
317 | hlist_for_each_entry_safe(gw_node, node, node_tmp, | ||
318 | &bat_priv->gw_list, list) { | ||
319 | if (((!gw_node->deleted) || | ||
320 | (time_before(jiffies, gw_node->deleted + timeout))) && | ||
321 | atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) | ||
322 | continue; | ||
323 | |||
324 | if (bat_priv->curr_gw == gw_node) | ||
325 | gw_deselect(bat_priv); | ||
326 | |||
327 | hlist_del_rcu(&gw_node->list); | ||
328 | call_rcu(&gw_node->rcu, gw_node_free_rcu); | ||
329 | } | ||
330 | |||
331 | |||
332 | spin_unlock_bh(&bat_priv->gw_list_lock); | ||
333 | } | ||
334 | |||
335 | static int _write_buffer_text(struct bat_priv *bat_priv, | ||
336 | struct seq_file *seq, struct gw_node *gw_node) | ||
337 | { | ||
338 | int down, up; | ||
339 | |||
340 | gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); | ||
341 | |||
342 | return seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", | ||
343 | (bat_priv->curr_gw == gw_node ? "=>" : " "), | ||
344 | gw_node->orig_node->orig, | ||
345 | gw_node->orig_node->router->tq_avg, | ||
346 | gw_node->orig_node->router->addr, | ||
347 | gw_node->orig_node->router->if_incoming->net_dev->name, | ||
348 | gw_node->orig_node->gw_flags, | ||
349 | (down > 2048 ? down / 1024 : down), | ||
350 | (down > 2048 ? "MBit" : "KBit"), | ||
351 | (up > 2048 ? up / 1024 : up), | ||
352 | (up > 2048 ? "MBit" : "KBit")); | ||
353 | } | ||
354 | |||
355 | int gw_client_seq_print_text(struct seq_file *seq, void *offset) | ||
356 | { | ||
357 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
358 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
359 | struct gw_node *gw_node; | ||
360 | struct hlist_node *node; | ||
361 | int gw_count = 0; | ||
362 | |||
363 | if (!bat_priv->primary_if) { | ||
364 | |||
365 | return seq_printf(seq, "BATMAN mesh %s disabled - please " | ||
366 | "specify interfaces to enable it\n", | ||
367 | net_dev->name); | ||
368 | } | ||
369 | |||
370 | if (bat_priv->primary_if->if_status != IF_ACTIVE) { | ||
371 | |||
372 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
373 | "primary interface not active\n", | ||
374 | net_dev->name); | ||
375 | } | ||
376 | |||
377 | seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " | ||
378 | "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", | ||
379 | "Gateway", "#", TQ_MAX_VALUE, "Nexthop", | ||
380 | "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, | ||
381 | bat_priv->primary_if->net_dev->name, | ||
382 | bat_priv->primary_if->net_dev->dev_addr, net_dev->name); | ||
383 | |||
384 | rcu_read_lock(); | ||
385 | hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { | ||
386 | if (gw_node->deleted) | ||
387 | continue; | ||
388 | |||
389 | if (!gw_node->orig_node->router) | ||
390 | continue; | ||
391 | |||
392 | _write_buffer_text(bat_priv, seq, gw_node); | ||
393 | gw_count++; | ||
394 | } | ||
395 | rcu_read_unlock(); | ||
396 | |||
397 | if (gw_count == 0) | ||
398 | seq_printf(seq, "No gateways in range ...\n"); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) | ||
404 | { | ||
405 | struct ethhdr *ethhdr; | ||
406 | struct iphdr *iphdr; | ||
407 | struct ipv6hdr *ipv6hdr; | ||
408 | struct udphdr *udphdr; | ||
409 | unsigned int header_len = 0; | ||
410 | |||
411 | if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) | ||
412 | return 0; | ||
413 | |||
414 | /* check for ethernet header */ | ||
415 | if (!pskb_may_pull(skb, header_len + ETH_HLEN)) | ||
416 | return 0; | ||
417 | ethhdr = (struct ethhdr *)skb->data; | ||
418 | header_len += ETH_HLEN; | ||
419 | |||
420 | /* check for initial vlan header */ | ||
421 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { | ||
422 | if (!pskb_may_pull(skb, header_len + VLAN_HLEN)) | ||
423 | return 0; | ||
424 | ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN); | ||
425 | header_len += VLAN_HLEN; | ||
426 | } | ||
427 | |||
428 | /* check for ip header */ | ||
429 | switch (ntohs(ethhdr->h_proto)) { | ||
430 | case ETH_P_IP: | ||
431 | if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr))) | ||
432 | return 0; | ||
433 | iphdr = (struct iphdr *)(skb->data + header_len); | ||
434 | header_len += iphdr->ihl * 4; | ||
435 | |||
436 | /* check for udp header */ | ||
437 | if (iphdr->protocol != IPPROTO_UDP) | ||
438 | return 0; | ||
439 | |||
440 | break; | ||
441 | case ETH_P_IPV6: | ||
442 | if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr))) | ||
443 | return 0; | ||
444 | ipv6hdr = (struct ipv6hdr *)(skb->data + header_len); | ||
445 | header_len += sizeof(struct ipv6hdr); | ||
446 | |||
447 | /* check for udp header */ | ||
448 | if (ipv6hdr->nexthdr != IPPROTO_UDP) | ||
449 | return 0; | ||
450 | |||
451 | break; | ||
452 | default: | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr))) | ||
457 | return 0; | ||
458 | udphdr = (struct udphdr *)(skb->data + header_len); | ||
459 | header_len += sizeof(struct udphdr); | ||
460 | |||
461 | /* check for bootp port */ | ||
462 | if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && | ||
463 | (ntohs(udphdr->dest) != 67)) | ||
464 | return 0; | ||
465 | |||
466 | if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) && | ||
467 | (ntohs(udphdr->dest) != 547)) | ||
468 | return 0; | ||
469 | |||
470 | if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) | ||
471 | return -1; | ||
472 | |||
473 | if (!bat_priv->curr_gw) | ||
474 | return 0; | ||
475 | |||
476 | return 1; | ||
477 | } | ||
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h new file mode 100644 index 000000000000..4585e6549844 --- /dev/null +++ b/net/batman-adv/gateway_client.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 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 | #ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ | ||
23 | #define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ | ||
24 | |||
25 | void gw_deselect(struct bat_priv *bat_priv); | ||
26 | void gw_election(struct bat_priv *bat_priv); | ||
27 | void *gw_get_selected(struct bat_priv *bat_priv); | ||
28 | void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); | ||
29 | void gw_node_update(struct bat_priv *bat_priv, | ||
30 | struct orig_node *orig_node, uint8_t new_gwflags); | ||
31 | void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); | ||
32 | void gw_node_purge(struct bat_priv *bat_priv); | ||
33 | int gw_client_seq_print_text(struct seq_file *seq, void *offset); | ||
34 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb); | ||
35 | |||
36 | #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ | ||
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c new file mode 100644 index 000000000000..b962982f017e --- /dev/null +++ b/net/batman-adv/gateway_common.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 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 "gateway_common.h" | ||
24 | #include "gateway_client.h" | ||
25 | |||
26 | /* calculates the gateway class from kbit */ | ||
27 | static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class) | ||
28 | { | ||
29 | int mdown = 0, tdown, tup, difference; | ||
30 | uint8_t sbit, part; | ||
31 | |||
32 | *gw_srv_class = 0; | ||
33 | difference = 0x0FFFFFFF; | ||
34 | |||
35 | /* test all downspeeds */ | ||
36 | for (sbit = 0; sbit < 2; sbit++) { | ||
37 | for (part = 0; part < 16; part++) { | ||
38 | tdown = 32 * (sbit + 2) * (1 << part); | ||
39 | |||
40 | if (abs(tdown - down) < difference) { | ||
41 | *gw_srv_class = (sbit << 7) + (part << 3); | ||
42 | difference = abs(tdown - down); | ||
43 | mdown = tdown; | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | |||
48 | /* test all upspeeds */ | ||
49 | difference = 0x0FFFFFFF; | ||
50 | |||
51 | for (part = 0; part < 8; part++) { | ||
52 | tup = ((part + 1) * (mdown)) / 8; | ||
53 | |||
54 | if (abs(tup - up) < difference) { | ||
55 | *gw_srv_class = (*gw_srv_class & 0xF8) | part; | ||
56 | difference = abs(tup - up); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | /* returns the up and downspeeds in kbit, calculated from the class */ | ||
62 | void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up) | ||
63 | { | ||
64 | char sbit = (gw_srv_class & 0x80) >> 7; | ||
65 | char dpart = (gw_srv_class & 0x78) >> 3; | ||
66 | char upart = (gw_srv_class & 0x07); | ||
67 | |||
68 | if (!gw_srv_class) { | ||
69 | *down = 0; | ||
70 | *up = 0; | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | *down = 32 * (sbit + 2) * (1 << dpart); | ||
75 | *up = ((upart + 1) * (*down)) / 8; | ||
76 | } | ||
77 | |||
78 | static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff, | ||
79 | long *up, long *down) | ||
80 | { | ||
81 | int ret, multi = 1; | ||
82 | char *slash_ptr, *tmp_ptr; | ||
83 | |||
84 | slash_ptr = strchr(buff, '/'); | ||
85 | if (slash_ptr) | ||
86 | *slash_ptr = 0; | ||
87 | |||
88 | if (strlen(buff) > 4) { | ||
89 | tmp_ptr = buff + strlen(buff) - 4; | ||
90 | |||
91 | if (strnicmp(tmp_ptr, "mbit", 4) == 0) | ||
92 | multi = 1024; | ||
93 | |||
94 | if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || | ||
95 | (multi > 1)) | ||
96 | *tmp_ptr = '\0'; | ||
97 | } | ||
98 | |||
99 | ret = strict_strtoul(buff, 10, down); | ||
100 | if (ret) { | ||
101 | bat_err(net_dev, | ||
102 | "Download speed of gateway mode invalid: %s\n", | ||
103 | buff); | ||
104 | return false; | ||
105 | } | ||
106 | |||
107 | *down *= multi; | ||
108 | |||
109 | /* we also got some upload info */ | ||
110 | if (slash_ptr) { | ||
111 | multi = 1; | ||
112 | |||
113 | if (strlen(slash_ptr + 1) > 4) { | ||
114 | tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); | ||
115 | |||
116 | if (strnicmp(tmp_ptr, "mbit", 4) == 0) | ||
117 | multi = 1024; | ||
118 | |||
119 | if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || | ||
120 | (multi > 1)) | ||
121 | *tmp_ptr = '\0'; | ||
122 | } | ||
123 | |||
124 | ret = strict_strtoul(slash_ptr + 1, 10, up); | ||
125 | if (ret) { | ||
126 | bat_err(net_dev, | ||
127 | "Upload speed of gateway mode invalid: " | ||
128 | "%s\n", slash_ptr + 1); | ||
129 | return false; | ||
130 | } | ||
131 | |||
132 | *up *= multi; | ||
133 | } | ||
134 | |||
135 | return true; | ||
136 | } | ||
137 | |||
138 | ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) | ||
139 | { | ||
140 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
141 | long gw_bandwidth_tmp = 0, up = 0, down = 0; | ||
142 | bool ret; | ||
143 | |||
144 | ret = parse_gw_bandwidth(net_dev, buff, &up, &down); | ||
145 | if (!ret) | ||
146 | goto end; | ||
147 | |||
148 | if ((!down) || (down < 256)) | ||
149 | down = 2000; | ||
150 | |||
151 | if (!up) | ||
152 | up = down / 5; | ||
153 | |||
154 | kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp); | ||
155 | |||
156 | /** | ||
157 | * the gw bandwidth we guessed above might not match the given | ||
158 | * speeds, hence we need to calculate it back to show the number | ||
159 | * that is going to be propagated | ||
160 | **/ | ||
161 | gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, | ||
162 | (int *)&down, (int *)&up); | ||
163 | |||
164 | gw_deselect(bat_priv); | ||
165 | bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' " | ||
166 | "(propagating: %ld%s/%ld%s)\n", | ||
167 | atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, | ||
168 | (down > 2048 ? down / 1024 : down), | ||
169 | (down > 2048 ? "MBit" : "KBit"), | ||
170 | (up > 2048 ? up / 1024 : up), | ||
171 | (up > 2048 ? "MBit" : "KBit")); | ||
172 | |||
173 | atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp); | ||
174 | |||
175 | end: | ||
176 | return count; | ||
177 | } | ||
diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h new file mode 100644 index 000000000000..5e728d0b7959 --- /dev/null +++ b/net/batman-adv/gateway_common.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 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 | #ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_ | ||
23 | #define _NET_BATMAN_ADV_GATEWAY_COMMON_H_ | ||
24 | |||
25 | enum gw_modes { | ||
26 | GW_MODE_OFF, | ||
27 | GW_MODE_CLIENT, | ||
28 | GW_MODE_SERVER, | ||
29 | }; | ||
30 | |||
31 | #define GW_MODE_OFF_NAME "off" | ||
32 | #define GW_MODE_CLIENT_NAME "client" | ||
33 | #define GW_MODE_SERVER_NAME "server" | ||
34 | |||
35 | void gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up); | ||
36 | ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count); | ||
37 | |||
38 | #endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */ | ||
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c new file mode 100644 index 000000000000..4f95777ce080 --- /dev/null +++ b/net/batman-adv/hard-interface.c | |||
@@ -0,0 +1,651 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 "soft-interface.h" | ||
25 | #include "send.h" | ||
26 | #include "translation-table.h" | ||
27 | #include "routing.h" | ||
28 | #include "bat_sysfs.h" | ||
29 | #include "originator.h" | ||
30 | #include "hash.h" | ||
31 | |||
32 | #include <linux/if_arp.h> | ||
33 | |||
34 | /* protect update critical side of if_list - but not the content */ | ||
35 | static DEFINE_SPINLOCK(if_list_lock); | ||
36 | |||
37 | static void hardif_free_rcu(struct rcu_head *rcu) | ||
38 | { | ||
39 | struct batman_if *batman_if; | ||
40 | |||
41 | batman_if = container_of(rcu, struct batman_if, rcu); | ||
42 | dev_put(batman_if->net_dev); | ||
43 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
44 | } | ||
45 | |||
46 | struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev) | ||
47 | { | ||
48 | struct batman_if *batman_if; | ||
49 | |||
50 | rcu_read_lock(); | ||
51 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
52 | if (batman_if->net_dev == net_dev) | ||
53 | goto out; | ||
54 | } | ||
55 | |||
56 | batman_if = NULL; | ||
57 | |||
58 | out: | ||
59 | if (batman_if) | ||
60 | kref_get(&batman_if->refcount); | ||
61 | |||
62 | rcu_read_unlock(); | ||
63 | return batman_if; | ||
64 | } | ||
65 | |||
66 | static int is_valid_iface(struct net_device *net_dev) | ||
67 | { | ||
68 | if (net_dev->flags & IFF_LOOPBACK) | ||
69 | return 0; | ||
70 | |||
71 | if (net_dev->type != ARPHRD_ETHER) | ||
72 | return 0; | ||
73 | |||
74 | if (net_dev->addr_len != ETH_ALEN) | ||
75 | return 0; | ||
76 | |||
77 | /* no batman over batman */ | ||
78 | #ifdef HAVE_NET_DEVICE_OPS | ||
79 | if (net_dev->netdev_ops->ndo_start_xmit == interface_tx) | ||
80 | return 0; | ||
81 | #else | ||
82 | if (net_dev->hard_start_xmit == interface_tx) | ||
83 | return 0; | ||
84 | #endif | ||
85 | |||
86 | /* Device is being bridged */ | ||
87 | /* if (net_dev->priv_flags & IFF_BRIDGE_PORT) | ||
88 | return 0; */ | ||
89 | |||
90 | return 1; | ||
91 | } | ||
92 | |||
93 | static struct batman_if *get_active_batman_if(struct net_device *soft_iface) | ||
94 | { | ||
95 | struct batman_if *batman_if; | ||
96 | |||
97 | rcu_read_lock(); | ||
98 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
99 | if (batman_if->soft_iface != soft_iface) | ||
100 | continue; | ||
101 | |||
102 | if (batman_if->if_status == IF_ACTIVE) | ||
103 | goto out; | ||
104 | } | ||
105 | |||
106 | batman_if = NULL; | ||
107 | |||
108 | out: | ||
109 | if (batman_if) | ||
110 | kref_get(&batman_if->refcount); | ||
111 | |||
112 | rcu_read_unlock(); | ||
113 | return batman_if; | ||
114 | } | ||
115 | |||
116 | static void update_primary_addr(struct bat_priv *bat_priv) | ||
117 | { | ||
118 | struct vis_packet *vis_packet; | ||
119 | |||
120 | vis_packet = (struct vis_packet *) | ||
121 | bat_priv->my_vis_info->skb_packet->data; | ||
122 | memcpy(vis_packet->vis_orig, | ||
123 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
124 | memcpy(vis_packet->sender_orig, | ||
125 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
126 | } | ||
127 | |||
128 | static void set_primary_if(struct bat_priv *bat_priv, | ||
129 | struct batman_if *batman_if) | ||
130 | { | ||
131 | struct batman_packet *batman_packet; | ||
132 | struct batman_if *old_if; | ||
133 | |||
134 | if (batman_if) | ||
135 | kref_get(&batman_if->refcount); | ||
136 | |||
137 | old_if = bat_priv->primary_if; | ||
138 | bat_priv->primary_if = batman_if; | ||
139 | |||
140 | if (old_if) | ||
141 | kref_put(&old_if->refcount, hardif_free_ref); | ||
142 | |||
143 | if (!bat_priv->primary_if) | ||
144 | return; | ||
145 | |||
146 | batman_packet = (struct batman_packet *)(batman_if->packet_buff); | ||
147 | batman_packet->flags = PRIMARIES_FIRST_HOP; | ||
148 | batman_packet->ttl = TTL; | ||
149 | |||
150 | update_primary_addr(bat_priv); | ||
151 | |||
152 | /*** | ||
153 | * hacky trick to make sure that we send the HNA information via | ||
154 | * our new primary interface | ||
155 | */ | ||
156 | atomic_set(&bat_priv->hna_local_changed, 1); | ||
157 | } | ||
158 | |||
159 | static bool hardif_is_iface_up(struct batman_if *batman_if) | ||
160 | { | ||
161 | if (batman_if->net_dev->flags & IFF_UP) | ||
162 | return true; | ||
163 | |||
164 | return false; | ||
165 | } | ||
166 | |||
167 | static void update_mac_addresses(struct batman_if *batman_if) | ||
168 | { | ||
169 | memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, | ||
170 | batman_if->net_dev->dev_addr, ETH_ALEN); | ||
171 | memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender, | ||
172 | batman_if->net_dev->dev_addr, ETH_ALEN); | ||
173 | } | ||
174 | |||
175 | static void check_known_mac_addr(struct net_device *net_dev) | ||
176 | { | ||
177 | struct batman_if *batman_if; | ||
178 | |||
179 | rcu_read_lock(); | ||
180 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
181 | if ((batman_if->if_status != IF_ACTIVE) && | ||
182 | (batman_if->if_status != IF_TO_BE_ACTIVATED)) | ||
183 | continue; | ||
184 | |||
185 | if (batman_if->net_dev == net_dev) | ||
186 | continue; | ||
187 | |||
188 | if (!compare_orig(batman_if->net_dev->dev_addr, | ||
189 | net_dev->dev_addr)) | ||
190 | continue; | ||
191 | |||
192 | pr_warning("The newly added mac address (%pM) already exists " | ||
193 | "on: %s\n", net_dev->dev_addr, | ||
194 | batman_if->net_dev->name); | ||
195 | pr_warning("It is strongly recommended to keep mac addresses " | ||
196 | "unique to avoid problems!\n"); | ||
197 | } | ||
198 | rcu_read_unlock(); | ||
199 | } | ||
200 | |||
201 | int hardif_min_mtu(struct net_device *soft_iface) | ||
202 | { | ||
203 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
204 | struct batman_if *batman_if; | ||
205 | /* allow big frames if all devices are capable to do so | ||
206 | * (have MTU > 1500 + BAT_HEADER_LEN) */ | ||
207 | int min_mtu = ETH_DATA_LEN; | ||
208 | |||
209 | if (atomic_read(&bat_priv->fragmentation)) | ||
210 | goto out; | ||
211 | |||
212 | rcu_read_lock(); | ||
213 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
214 | if ((batman_if->if_status != IF_ACTIVE) && | ||
215 | (batman_if->if_status != IF_TO_BE_ACTIVATED)) | ||
216 | continue; | ||
217 | |||
218 | if (batman_if->soft_iface != soft_iface) | ||
219 | continue; | ||
220 | |||
221 | min_mtu = min_t(int, batman_if->net_dev->mtu - BAT_HEADER_LEN, | ||
222 | min_mtu); | ||
223 | } | ||
224 | rcu_read_unlock(); | ||
225 | out: | ||
226 | return min_mtu; | ||
227 | } | ||
228 | |||
229 | /* adjusts the MTU if a new interface with a smaller MTU appeared. */ | ||
230 | void update_min_mtu(struct net_device *soft_iface) | ||
231 | { | ||
232 | int min_mtu; | ||
233 | |||
234 | min_mtu = hardif_min_mtu(soft_iface); | ||
235 | if (soft_iface->mtu != min_mtu) | ||
236 | soft_iface->mtu = min_mtu; | ||
237 | } | ||
238 | |||
239 | static void hardif_activate_interface(struct batman_if *batman_if) | ||
240 | { | ||
241 | struct bat_priv *bat_priv; | ||
242 | |||
243 | if (batman_if->if_status != IF_INACTIVE) | ||
244 | return; | ||
245 | |||
246 | bat_priv = netdev_priv(batman_if->soft_iface); | ||
247 | |||
248 | update_mac_addresses(batman_if); | ||
249 | batman_if->if_status = IF_TO_BE_ACTIVATED; | ||
250 | |||
251 | /** | ||
252 | * the first active interface becomes our primary interface or | ||
253 | * the next active interface after the old primay interface was removed | ||
254 | */ | ||
255 | if (!bat_priv->primary_if) | ||
256 | set_primary_if(bat_priv, batman_if); | ||
257 | |||
258 | bat_info(batman_if->soft_iface, "Interface activated: %s\n", | ||
259 | batman_if->net_dev->name); | ||
260 | |||
261 | update_min_mtu(batman_if->soft_iface); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | static void hardif_deactivate_interface(struct batman_if *batman_if) | ||
266 | { | ||
267 | if ((batman_if->if_status != IF_ACTIVE) && | ||
268 | (batman_if->if_status != IF_TO_BE_ACTIVATED)) | ||
269 | return; | ||
270 | |||
271 | batman_if->if_status = IF_INACTIVE; | ||
272 | |||
273 | bat_info(batman_if->soft_iface, "Interface deactivated: %s\n", | ||
274 | batman_if->net_dev->name); | ||
275 | |||
276 | update_min_mtu(batman_if->soft_iface); | ||
277 | } | ||
278 | |||
279 | int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) | ||
280 | { | ||
281 | struct bat_priv *bat_priv; | ||
282 | struct batman_packet *batman_packet; | ||
283 | |||
284 | if (batman_if->if_status != IF_NOT_IN_USE) | ||
285 | goto out; | ||
286 | |||
287 | batman_if->soft_iface = dev_get_by_name(&init_net, iface_name); | ||
288 | |||
289 | if (!batman_if->soft_iface) { | ||
290 | batman_if->soft_iface = softif_create(iface_name); | ||
291 | |||
292 | if (!batman_if->soft_iface) | ||
293 | goto err; | ||
294 | |||
295 | /* dev_get_by_name() increases the reference counter for us */ | ||
296 | dev_hold(batman_if->soft_iface); | ||
297 | } | ||
298 | |||
299 | bat_priv = netdev_priv(batman_if->soft_iface); | ||
300 | batman_if->packet_len = BAT_PACKET_LEN; | ||
301 | batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_ATOMIC); | ||
302 | |||
303 | if (!batman_if->packet_buff) { | ||
304 | bat_err(batman_if->soft_iface, "Can't add interface packet " | ||
305 | "(%s): out of memory\n", batman_if->net_dev->name); | ||
306 | goto err; | ||
307 | } | ||
308 | |||
309 | batman_packet = (struct batman_packet *)(batman_if->packet_buff); | ||
310 | batman_packet->packet_type = BAT_PACKET; | ||
311 | batman_packet->version = COMPAT_VERSION; | ||
312 | batman_packet->flags = 0; | ||
313 | batman_packet->ttl = 2; | ||
314 | batman_packet->tq = TQ_MAX_VALUE; | ||
315 | batman_packet->num_hna = 0; | ||
316 | |||
317 | batman_if->if_num = bat_priv->num_ifaces; | ||
318 | bat_priv->num_ifaces++; | ||
319 | batman_if->if_status = IF_INACTIVE; | ||
320 | orig_hash_add_if(batman_if, bat_priv->num_ifaces); | ||
321 | |||
322 | batman_if->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN); | ||
323 | batman_if->batman_adv_ptype.func = batman_skb_recv; | ||
324 | batman_if->batman_adv_ptype.dev = batman_if->net_dev; | ||
325 | kref_get(&batman_if->refcount); | ||
326 | dev_add_pack(&batman_if->batman_adv_ptype); | ||
327 | |||
328 | atomic_set(&batman_if->seqno, 1); | ||
329 | atomic_set(&batman_if->frag_seqno, 1); | ||
330 | bat_info(batman_if->soft_iface, "Adding interface: %s\n", | ||
331 | batman_if->net_dev->name); | ||
332 | |||
333 | if (atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < | ||
334 | ETH_DATA_LEN + BAT_HEADER_LEN) | ||
335 | bat_info(batman_if->soft_iface, | ||
336 | "The MTU of interface %s is too small (%i) to handle " | ||
337 | "the transport of batman-adv packets. Packets going " | ||
338 | "over this interface will be fragmented on layer2 " | ||
339 | "which could impact the performance. Setting the MTU " | ||
340 | "to %zi would solve the problem.\n", | ||
341 | batman_if->net_dev->name, batman_if->net_dev->mtu, | ||
342 | ETH_DATA_LEN + BAT_HEADER_LEN); | ||
343 | |||
344 | if (!atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < | ||
345 | ETH_DATA_LEN + BAT_HEADER_LEN) | ||
346 | bat_info(batman_if->soft_iface, | ||
347 | "The MTU of interface %s is too small (%i) to handle " | ||
348 | "the transport of batman-adv packets. If you experience" | ||
349 | " problems getting traffic through try increasing the " | ||
350 | "MTU to %zi.\n", | ||
351 | batman_if->net_dev->name, batman_if->net_dev->mtu, | ||
352 | ETH_DATA_LEN + BAT_HEADER_LEN); | ||
353 | |||
354 | if (hardif_is_iface_up(batman_if)) | ||
355 | hardif_activate_interface(batman_if); | ||
356 | else | ||
357 | bat_err(batman_if->soft_iface, "Not using interface %s " | ||
358 | "(retrying later): interface not active\n", | ||
359 | batman_if->net_dev->name); | ||
360 | |||
361 | /* begin scheduling originator messages on that interface */ | ||
362 | schedule_own_packet(batman_if); | ||
363 | |||
364 | out: | ||
365 | return 0; | ||
366 | |||
367 | err: | ||
368 | return -ENOMEM; | ||
369 | } | ||
370 | |||
371 | void hardif_disable_interface(struct batman_if *batman_if) | ||
372 | { | ||
373 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
374 | |||
375 | if (batman_if->if_status == IF_ACTIVE) | ||
376 | hardif_deactivate_interface(batman_if); | ||
377 | |||
378 | if (batman_if->if_status != IF_INACTIVE) | ||
379 | return; | ||
380 | |||
381 | bat_info(batman_if->soft_iface, "Removing interface: %s\n", | ||
382 | batman_if->net_dev->name); | ||
383 | dev_remove_pack(&batman_if->batman_adv_ptype); | ||
384 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
385 | |||
386 | bat_priv->num_ifaces--; | ||
387 | orig_hash_del_if(batman_if, bat_priv->num_ifaces); | ||
388 | |||
389 | if (batman_if == bat_priv->primary_if) { | ||
390 | struct batman_if *new_if; | ||
391 | |||
392 | new_if = get_active_batman_if(batman_if->soft_iface); | ||
393 | set_primary_if(bat_priv, new_if); | ||
394 | |||
395 | if (new_if) | ||
396 | kref_put(&new_if->refcount, hardif_free_ref); | ||
397 | } | ||
398 | |||
399 | kfree(batman_if->packet_buff); | ||
400 | batman_if->packet_buff = NULL; | ||
401 | batman_if->if_status = IF_NOT_IN_USE; | ||
402 | |||
403 | /* delete all references to this batman_if */ | ||
404 | purge_orig_ref(bat_priv); | ||
405 | purge_outstanding_packets(bat_priv, batman_if); | ||
406 | dev_put(batman_if->soft_iface); | ||
407 | |||
408 | /* nobody uses this interface anymore */ | ||
409 | if (!bat_priv->num_ifaces) | ||
410 | softif_destroy(batman_if->soft_iface); | ||
411 | |||
412 | batman_if->soft_iface = NULL; | ||
413 | } | ||
414 | |||
415 | static struct batman_if *hardif_add_interface(struct net_device *net_dev) | ||
416 | { | ||
417 | struct batman_if *batman_if; | ||
418 | int ret; | ||
419 | |||
420 | ret = is_valid_iface(net_dev); | ||
421 | if (ret != 1) | ||
422 | goto out; | ||
423 | |||
424 | dev_hold(net_dev); | ||
425 | |||
426 | batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC); | ||
427 | if (!batman_if) { | ||
428 | pr_err("Can't add interface (%s): out of memory\n", | ||
429 | net_dev->name); | ||
430 | goto release_dev; | ||
431 | } | ||
432 | |||
433 | ret = sysfs_add_hardif(&batman_if->hardif_obj, net_dev); | ||
434 | if (ret) | ||
435 | goto free_if; | ||
436 | |||
437 | batman_if->if_num = -1; | ||
438 | batman_if->net_dev = net_dev; | ||
439 | batman_if->soft_iface = NULL; | ||
440 | batman_if->if_status = IF_NOT_IN_USE; | ||
441 | INIT_LIST_HEAD(&batman_if->list); | ||
442 | kref_init(&batman_if->refcount); | ||
443 | |||
444 | check_known_mac_addr(batman_if->net_dev); | ||
445 | |||
446 | spin_lock(&if_list_lock); | ||
447 | list_add_tail_rcu(&batman_if->list, &if_list); | ||
448 | spin_unlock(&if_list_lock); | ||
449 | |||
450 | /* extra reference for return */ | ||
451 | kref_get(&batman_if->refcount); | ||
452 | return batman_if; | ||
453 | |||
454 | free_if: | ||
455 | kfree(batman_if); | ||
456 | release_dev: | ||
457 | dev_put(net_dev); | ||
458 | out: | ||
459 | return NULL; | ||
460 | } | ||
461 | |||
462 | static void hardif_remove_interface(struct batman_if *batman_if) | ||
463 | { | ||
464 | /* first deactivate interface */ | ||
465 | if (batman_if->if_status != IF_NOT_IN_USE) | ||
466 | hardif_disable_interface(batman_if); | ||
467 | |||
468 | if (batman_if->if_status != IF_NOT_IN_USE) | ||
469 | return; | ||
470 | |||
471 | batman_if->if_status = IF_TO_BE_REMOVED; | ||
472 | sysfs_del_hardif(&batman_if->hardif_obj); | ||
473 | call_rcu(&batman_if->rcu, hardif_free_rcu); | ||
474 | } | ||
475 | |||
476 | void hardif_remove_interfaces(void) | ||
477 | { | ||
478 | struct batman_if *batman_if, *batman_if_tmp; | ||
479 | struct list_head if_queue; | ||
480 | |||
481 | INIT_LIST_HEAD(&if_queue); | ||
482 | |||
483 | spin_lock(&if_list_lock); | ||
484 | list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) { | ||
485 | list_del_rcu(&batman_if->list); | ||
486 | list_add_tail(&batman_if->list, &if_queue); | ||
487 | } | ||
488 | spin_unlock(&if_list_lock); | ||
489 | |||
490 | rtnl_lock(); | ||
491 | list_for_each_entry_safe(batman_if, batman_if_tmp, &if_queue, list) { | ||
492 | hardif_remove_interface(batman_if); | ||
493 | } | ||
494 | rtnl_unlock(); | ||
495 | } | ||
496 | |||
497 | static int hard_if_event(struct notifier_block *this, | ||
498 | unsigned long event, void *ptr) | ||
499 | { | ||
500 | struct net_device *net_dev = (struct net_device *)ptr; | ||
501 | struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); | ||
502 | struct bat_priv *bat_priv; | ||
503 | |||
504 | if (!batman_if && event == NETDEV_REGISTER) | ||
505 | batman_if = hardif_add_interface(net_dev); | ||
506 | |||
507 | if (!batman_if) | ||
508 | goto out; | ||
509 | |||
510 | switch (event) { | ||
511 | case NETDEV_UP: | ||
512 | hardif_activate_interface(batman_if); | ||
513 | break; | ||
514 | case NETDEV_GOING_DOWN: | ||
515 | case NETDEV_DOWN: | ||
516 | hardif_deactivate_interface(batman_if); | ||
517 | break; | ||
518 | case NETDEV_UNREGISTER: | ||
519 | spin_lock(&if_list_lock); | ||
520 | list_del_rcu(&batman_if->list); | ||
521 | spin_unlock(&if_list_lock); | ||
522 | |||
523 | hardif_remove_interface(batman_if); | ||
524 | break; | ||
525 | case NETDEV_CHANGEMTU: | ||
526 | if (batman_if->soft_iface) | ||
527 | update_min_mtu(batman_if->soft_iface); | ||
528 | break; | ||
529 | case NETDEV_CHANGEADDR: | ||
530 | if (batman_if->if_status == IF_NOT_IN_USE) | ||
531 | goto hardif_put; | ||
532 | |||
533 | check_known_mac_addr(batman_if->net_dev); | ||
534 | update_mac_addresses(batman_if); | ||
535 | |||
536 | bat_priv = netdev_priv(batman_if->soft_iface); | ||
537 | if (batman_if == bat_priv->primary_if) | ||
538 | update_primary_addr(bat_priv); | ||
539 | break; | ||
540 | default: | ||
541 | break; | ||
542 | }; | ||
543 | |||
544 | hardif_put: | ||
545 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
546 | out: | ||
547 | return NOTIFY_DONE; | ||
548 | } | ||
549 | |||
550 | /* receive a packet with the batman ethertype coming on a hard | ||
551 | * interface */ | ||
552 | int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, | ||
553 | struct packet_type *ptype, struct net_device *orig_dev) | ||
554 | { | ||
555 | struct bat_priv *bat_priv; | ||
556 | struct batman_packet *batman_packet; | ||
557 | struct batman_if *batman_if; | ||
558 | int ret; | ||
559 | |||
560 | batman_if = container_of(ptype, struct batman_if, batman_adv_ptype); | ||
561 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
562 | |||
563 | /* skb was released by skb_share_check() */ | ||
564 | if (!skb) | ||
565 | goto err_out; | ||
566 | |||
567 | /* packet should hold at least type and version */ | ||
568 | if (unlikely(!pskb_may_pull(skb, 2))) | ||
569 | goto err_free; | ||
570 | |||
571 | /* expect a valid ethernet header here. */ | ||
572 | if (unlikely(skb->mac_len != sizeof(struct ethhdr) | ||
573 | || !skb_mac_header(skb))) | ||
574 | goto err_free; | ||
575 | |||
576 | if (!batman_if->soft_iface) | ||
577 | goto err_free; | ||
578 | |||
579 | bat_priv = netdev_priv(batman_if->soft_iface); | ||
580 | |||
581 | if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) | ||
582 | goto err_free; | ||
583 | |||
584 | /* discard frames on not active interfaces */ | ||
585 | if (batman_if->if_status != IF_ACTIVE) | ||
586 | goto err_free; | ||
587 | |||
588 | batman_packet = (struct batman_packet *)skb->data; | ||
589 | |||
590 | if (batman_packet->version != COMPAT_VERSION) { | ||
591 | bat_dbg(DBG_BATMAN, bat_priv, | ||
592 | "Drop packet: incompatible batman version (%i)\n", | ||
593 | batman_packet->version); | ||
594 | goto err_free; | ||
595 | } | ||
596 | |||
597 | /* all receive handlers return whether they received or reused | ||
598 | * the supplied skb. if not, we have to free the skb. */ | ||
599 | |||
600 | switch (batman_packet->packet_type) { | ||
601 | /* batman originator packet */ | ||
602 | case BAT_PACKET: | ||
603 | ret = recv_bat_packet(skb, batman_if); | ||
604 | break; | ||
605 | |||
606 | /* batman icmp packet */ | ||
607 | case BAT_ICMP: | ||
608 | ret = recv_icmp_packet(skb, batman_if); | ||
609 | break; | ||
610 | |||
611 | /* unicast packet */ | ||
612 | case BAT_UNICAST: | ||
613 | ret = recv_unicast_packet(skb, batman_if); | ||
614 | break; | ||
615 | |||
616 | /* fragmented unicast packet */ | ||
617 | case BAT_UNICAST_FRAG: | ||
618 | ret = recv_ucast_frag_packet(skb, batman_if); | ||
619 | break; | ||
620 | |||
621 | /* broadcast packet */ | ||
622 | case BAT_BCAST: | ||
623 | ret = recv_bcast_packet(skb, batman_if); | ||
624 | break; | ||
625 | |||
626 | /* vis packet */ | ||
627 | case BAT_VIS: | ||
628 | ret = recv_vis_packet(skb, batman_if); | ||
629 | break; | ||
630 | default: | ||
631 | ret = NET_RX_DROP; | ||
632 | } | ||
633 | |||
634 | if (ret == NET_RX_DROP) | ||
635 | kfree_skb(skb); | ||
636 | |||
637 | /* return NET_RX_SUCCESS in any case as we | ||
638 | * most probably dropped the packet for | ||
639 | * routing-logical reasons. */ | ||
640 | |||
641 | return NET_RX_SUCCESS; | ||
642 | |||
643 | err_free: | ||
644 | kfree_skb(skb); | ||
645 | err_out: | ||
646 | return NET_RX_DROP; | ||
647 | } | ||
648 | |||
649 | struct notifier_block hard_if_notifier = { | ||
650 | .notifier_call = hard_if_event, | ||
651 | }; | ||
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h new file mode 100644 index 000000000000..30ec3b8db459 --- /dev/null +++ b/net/batman-adv/hard-interface.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_ | ||
23 | #define _NET_BATMAN_ADV_HARD_INTERFACE_H_ | ||
24 | |||
25 | #define IF_NOT_IN_USE 0 | ||
26 | #define IF_TO_BE_REMOVED 1 | ||
27 | #define IF_INACTIVE 2 | ||
28 | #define IF_ACTIVE 3 | ||
29 | #define IF_TO_BE_ACTIVATED 4 | ||
30 | #define IF_I_WANT_YOU 5 | ||
31 | |||
32 | extern struct notifier_block hard_if_notifier; | ||
33 | |||
34 | struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev); | ||
35 | int hardif_enable_interface(struct batman_if *batman_if, char *iface_name); | ||
36 | void hardif_disable_interface(struct batman_if *batman_if); | ||
37 | void hardif_remove_interfaces(void); | ||
38 | int batman_skb_recv(struct sk_buff *skb, | ||
39 | struct net_device *dev, | ||
40 | struct packet_type *ptype, | ||
41 | struct net_device *orig_dev); | ||
42 | int hardif_min_mtu(struct net_device *soft_iface); | ||
43 | void update_min_mtu(struct net_device *soft_iface); | ||
44 | |||
45 | static inline void hardif_free_ref(struct kref *refcount) | ||
46 | { | ||
47 | struct batman_if *batman_if; | ||
48 | |||
49 | batman_if = container_of(refcount, struct batman_if, refcount); | ||
50 | kfree(batman_if); | ||
51 | } | ||
52 | |||
53 | #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ | ||
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c new file mode 100644 index 000000000000..26e623eb9def --- /dev/null +++ b/net/batman-adv/hash.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 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 | static void hash_init(struct hashtable_t *hash) | ||
27 | { | ||
28 | int i; | ||
29 | |||
30 | for (i = 0 ; i < hash->size; i++) | ||
31 | INIT_HLIST_HEAD(&hash->table[i]); | ||
32 | } | ||
33 | |||
34 | /* free only the hashtable and the hash itself. */ | ||
35 | void hash_destroy(struct hashtable_t *hash) | ||
36 | { | ||
37 | kfree(hash->table); | ||
38 | kfree(hash); | ||
39 | } | ||
40 | |||
41 | /* allocates and clears the hash */ | ||
42 | struct hashtable_t *hash_new(int size) | ||
43 | { | ||
44 | struct hashtable_t *hash; | ||
45 | |||
46 | hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC); | ||
47 | |||
48 | if (!hash) | ||
49 | return NULL; | ||
50 | |||
51 | hash->size = size; | ||
52 | hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC); | ||
53 | |||
54 | if (!hash->table) { | ||
55 | kfree(hash); | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | hash_init(hash); | ||
60 | |||
61 | return hash; | ||
62 | } | ||
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h new file mode 100644 index 000000000000..09216ade16f1 --- /dev/null +++ b/net/batman-adv/hash.h | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 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 _NET_BATMAN_ADV_HASH_H_ | ||
23 | #define _NET_BATMAN_ADV_HASH_H_ | ||
24 | |||
25 | #include <linux/list.h> | ||
26 | |||
27 | /* callback to a compare function. should | ||
28 | * compare 2 element datas for their keys, | ||
29 | * return 0 if same and not 0 if not | ||
30 | * same */ | ||
31 | typedef int (*hashdata_compare_cb)(void *, void *); | ||
32 | |||
33 | /* the hashfunction, should return an index | ||
34 | * based on the key in the data of the first | ||
35 | * argument and the size the second */ | ||
36 | typedef int (*hashdata_choose_cb)(void *, int); | ||
37 | typedef void (*hashdata_free_cb)(void *, void *); | ||
38 | |||
39 | struct element_t { | ||
40 | void *data; /* pointer to the data */ | ||
41 | struct hlist_node hlist; /* bucket list pointer */ | ||
42 | }; | ||
43 | |||
44 | struct hashtable_t { | ||
45 | struct hlist_head *table; /* the hashtable itself, with the buckets */ | ||
46 | int size; /* size of hashtable */ | ||
47 | }; | ||
48 | |||
49 | /* allocates and clears the hash */ | ||
50 | struct hashtable_t *hash_new(int size); | ||
51 | |||
52 | /* remove element if you already found the element you want to delete and don't | ||
53 | * need the overhead to find it again with hash_remove(). But usually, you | ||
54 | * don't want to use this function, as it fiddles with hash-internals. */ | ||
55 | void *hash_remove_element(struct hashtable_t *hash, struct element_t *elem); | ||
56 | |||
57 | /* free only the hashtable and the hash itself. */ | ||
58 | void hash_destroy(struct hashtable_t *hash); | ||
59 | |||
60 | /* remove the hash structure. if hashdata_free_cb != NULL, this function will be | ||
61 | * called to remove the elements inside of the hash. if you don't remove the | ||
62 | * elements, memory might be leaked. */ | ||
63 | static inline void hash_delete(struct hashtable_t *hash, | ||
64 | hashdata_free_cb free_cb, void *arg) | ||
65 | { | ||
66 | struct hlist_head *head; | ||
67 | struct hlist_node *walk, *safe; | ||
68 | struct element_t *bucket; | ||
69 | int i; | ||
70 | |||
71 | for (i = 0; i < hash->size; i++) { | ||
72 | head = &hash->table[i]; | ||
73 | |||
74 | hlist_for_each_safe(walk, safe, head) { | ||
75 | bucket = hlist_entry(walk, struct element_t, hlist); | ||
76 | if (free_cb) | ||
77 | free_cb(bucket->data, arg); | ||
78 | |||
79 | hlist_del(walk); | ||
80 | kfree(bucket); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | hash_destroy(hash); | ||
85 | } | ||
86 | |||
87 | /* adds data to the hashtable. returns 0 on success, -1 on error */ | ||
88 | static inline int hash_add(struct hashtable_t *hash, | ||
89 | hashdata_compare_cb compare, | ||
90 | hashdata_choose_cb choose, void *data) | ||
91 | { | ||
92 | int index; | ||
93 | struct hlist_head *head; | ||
94 | struct hlist_node *walk, *safe; | ||
95 | struct element_t *bucket; | ||
96 | |||
97 | if (!hash) | ||
98 | return -1; | ||
99 | |||
100 | index = choose(data, hash->size); | ||
101 | head = &hash->table[index]; | ||
102 | |||
103 | hlist_for_each_safe(walk, safe, head) { | ||
104 | bucket = hlist_entry(walk, struct element_t, hlist); | ||
105 | if (compare(bucket->data, data)) | ||
106 | return -1; | ||
107 | } | ||
108 | |||
109 | /* no duplicate found in list, add new element */ | ||
110 | bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); | ||
111 | |||
112 | if (!bucket) | ||
113 | return -1; | ||
114 | |||
115 | bucket->data = data; | ||
116 | hlist_add_head(&bucket->hlist, head); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* removes data from hash, if found. returns pointer do data on success, so you | ||
122 | * can remove the used structure yourself, or NULL on error . data could be the | ||
123 | * structure you use with just the key filled, we just need the key for | ||
124 | * comparing. */ | ||
125 | static inline void *hash_remove(struct hashtable_t *hash, | ||
126 | hashdata_compare_cb compare, | ||
127 | hashdata_choose_cb choose, void *data) | ||
128 | { | ||
129 | size_t index; | ||
130 | struct hlist_node *walk; | ||
131 | struct element_t *bucket; | ||
132 | struct hlist_head *head; | ||
133 | void *data_save; | ||
134 | |||
135 | index = choose(data, hash->size); | ||
136 | head = &hash->table[index]; | ||
137 | |||
138 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
139 | if (compare(bucket->data, data)) { | ||
140 | data_save = bucket->data; | ||
141 | hlist_del(walk); | ||
142 | kfree(bucket); | ||
143 | return data_save; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | return NULL; | ||
148 | } | ||
149 | |||
150 | /* finds data, based on the key in keydata. returns the found data on success, | ||
151 | * or NULL on error */ | ||
152 | static inline void *hash_find(struct hashtable_t *hash, | ||
153 | hashdata_compare_cb compare, | ||
154 | hashdata_choose_cb choose, void *keydata) | ||
155 | { | ||
156 | int index; | ||
157 | struct hlist_head *head; | ||
158 | struct hlist_node *walk; | ||
159 | struct element_t *bucket; | ||
160 | |||
161 | if (!hash) | ||
162 | return NULL; | ||
163 | |||
164 | index = choose(keydata , hash->size); | ||
165 | head = &hash->table[index]; | ||
166 | |||
167 | hlist_for_each(walk, head) { | ||
168 | bucket = hlist_entry(walk, struct element_t, hlist); | ||
169 | if (compare(bucket->data, keydata)) | ||
170 | return bucket->data; | ||
171 | } | ||
172 | |||
173 | return NULL; | ||
174 | } | ||
175 | |||
176 | #endif /* _NET_BATMAN_ADV_HASH_H_ */ | ||
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c new file mode 100644 index 000000000000..ecf6d7ffab2e --- /dev/null +++ b/net/batman-adv/icmp_socket.c | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 <linux/debugfs.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include "icmp_socket.h" | ||
26 | #include "send.h" | ||
27 | #include "types.h" | ||
28 | #include "hash.h" | ||
29 | #include "originator.h" | ||
30 | #include "hard-interface.h" | ||
31 | |||
32 | static struct socket_client *socket_client_hash[256]; | ||
33 | |||
34 | static void bat_socket_add_packet(struct socket_client *socket_client, | ||
35 | struct icmp_packet_rr *icmp_packet, | ||
36 | size_t icmp_len); | ||
37 | |||
38 | void bat_socket_init(void) | ||
39 | { | ||
40 | memset(socket_client_hash, 0, sizeof(socket_client_hash)); | ||
41 | } | ||
42 | |||
43 | static int bat_socket_open(struct inode *inode, struct file *file) | ||
44 | { | ||
45 | unsigned int i; | ||
46 | struct socket_client *socket_client; | ||
47 | |||
48 | nonseekable_open(inode, file); | ||
49 | |||
50 | socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL); | ||
51 | |||
52 | if (!socket_client) | ||
53 | return -ENOMEM; | ||
54 | |||
55 | for (i = 0; i < ARRAY_SIZE(socket_client_hash); i++) { | ||
56 | if (!socket_client_hash[i]) { | ||
57 | socket_client_hash[i] = socket_client; | ||
58 | break; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | if (i == ARRAY_SIZE(socket_client_hash)) { | ||
63 | pr_err("Error - can't add another packet client: " | ||
64 | "maximum number of clients reached\n"); | ||
65 | kfree(socket_client); | ||
66 | return -EXFULL; | ||
67 | } | ||
68 | |||
69 | INIT_LIST_HEAD(&socket_client->queue_list); | ||
70 | socket_client->queue_len = 0; | ||
71 | socket_client->index = i; | ||
72 | socket_client->bat_priv = inode->i_private; | ||
73 | spin_lock_init(&socket_client->lock); | ||
74 | init_waitqueue_head(&socket_client->queue_wait); | ||
75 | |||
76 | file->private_data = socket_client; | ||
77 | |||
78 | inc_module_count(); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int bat_socket_release(struct inode *inode, struct file *file) | ||
83 | { | ||
84 | struct socket_client *socket_client = file->private_data; | ||
85 | struct socket_packet *socket_packet; | ||
86 | struct list_head *list_pos, *list_pos_tmp; | ||
87 | |||
88 | spin_lock_bh(&socket_client->lock); | ||
89 | |||
90 | /* for all packets in the queue ... */ | ||
91 | list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) { | ||
92 | socket_packet = list_entry(list_pos, | ||
93 | struct socket_packet, list); | ||
94 | |||
95 | list_del(list_pos); | ||
96 | kfree(socket_packet); | ||
97 | } | ||
98 | |||
99 | socket_client_hash[socket_client->index] = NULL; | ||
100 | spin_unlock_bh(&socket_client->lock); | ||
101 | |||
102 | kfree(socket_client); | ||
103 | dec_module_count(); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static ssize_t bat_socket_read(struct file *file, char __user *buf, | ||
109 | size_t count, loff_t *ppos) | ||
110 | { | ||
111 | struct socket_client *socket_client = file->private_data; | ||
112 | struct socket_packet *socket_packet; | ||
113 | size_t packet_len; | ||
114 | int error; | ||
115 | |||
116 | if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0)) | ||
117 | return -EAGAIN; | ||
118 | |||
119 | if ((!buf) || (count < sizeof(struct icmp_packet))) | ||
120 | return -EINVAL; | ||
121 | |||
122 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
123 | return -EFAULT; | ||
124 | |||
125 | error = wait_event_interruptible(socket_client->queue_wait, | ||
126 | socket_client->queue_len); | ||
127 | |||
128 | if (error) | ||
129 | return error; | ||
130 | |||
131 | spin_lock_bh(&socket_client->lock); | ||
132 | |||
133 | socket_packet = list_first_entry(&socket_client->queue_list, | ||
134 | struct socket_packet, list); | ||
135 | list_del(&socket_packet->list); | ||
136 | socket_client->queue_len--; | ||
137 | |||
138 | spin_unlock_bh(&socket_client->lock); | ||
139 | |||
140 | error = __copy_to_user(buf, &socket_packet->icmp_packet, | ||
141 | socket_packet->icmp_len); | ||
142 | |||
143 | packet_len = socket_packet->icmp_len; | ||
144 | kfree(socket_packet); | ||
145 | |||
146 | if (error) | ||
147 | return -EFAULT; | ||
148 | |||
149 | return packet_len; | ||
150 | } | ||
151 | |||
152 | static ssize_t bat_socket_write(struct file *file, const char __user *buff, | ||
153 | size_t len, loff_t *off) | ||
154 | { | ||
155 | struct socket_client *socket_client = file->private_data; | ||
156 | struct bat_priv *bat_priv = socket_client->bat_priv; | ||
157 | struct sk_buff *skb; | ||
158 | struct icmp_packet_rr *icmp_packet; | ||
159 | |||
160 | struct orig_node *orig_node; | ||
161 | struct batman_if *batman_if; | ||
162 | size_t packet_len = sizeof(struct icmp_packet); | ||
163 | uint8_t dstaddr[ETH_ALEN]; | ||
164 | |||
165 | if (len < sizeof(struct icmp_packet)) { | ||
166 | bat_dbg(DBG_BATMAN, bat_priv, | ||
167 | "Error - can't send packet from char device: " | ||
168 | "invalid packet size\n"); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | if (!bat_priv->primary_if) | ||
173 | return -EFAULT; | ||
174 | |||
175 | if (len >= sizeof(struct icmp_packet_rr)) | ||
176 | packet_len = sizeof(struct icmp_packet_rr); | ||
177 | |||
178 | skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr)); | ||
179 | if (!skb) | ||
180 | return -ENOMEM; | ||
181 | |||
182 | skb_reserve(skb, sizeof(struct ethhdr)); | ||
183 | icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); | ||
184 | |||
185 | if (!access_ok(VERIFY_READ, buff, packet_len)) { | ||
186 | len = -EFAULT; | ||
187 | goto free_skb; | ||
188 | } | ||
189 | |||
190 | if (__copy_from_user(icmp_packet, buff, packet_len)) { | ||
191 | len = -EFAULT; | ||
192 | goto free_skb; | ||
193 | } | ||
194 | |||
195 | if (icmp_packet->packet_type != BAT_ICMP) { | ||
196 | bat_dbg(DBG_BATMAN, bat_priv, | ||
197 | "Error - can't send packet from char device: " | ||
198 | "got bogus packet type (expected: BAT_ICMP)\n"); | ||
199 | len = -EINVAL; | ||
200 | goto free_skb; | ||
201 | } | ||
202 | |||
203 | if (icmp_packet->msg_type != ECHO_REQUEST) { | ||
204 | bat_dbg(DBG_BATMAN, bat_priv, | ||
205 | "Error - can't send packet from char device: " | ||
206 | "got bogus message type (expected: ECHO_REQUEST)\n"); | ||
207 | len = -EINVAL; | ||
208 | goto free_skb; | ||
209 | } | ||
210 | |||
211 | icmp_packet->uid = socket_client->index; | ||
212 | |||
213 | if (icmp_packet->version != COMPAT_VERSION) { | ||
214 | icmp_packet->msg_type = PARAMETER_PROBLEM; | ||
215 | icmp_packet->ttl = COMPAT_VERSION; | ||
216 | bat_socket_add_packet(socket_client, icmp_packet, packet_len); | ||
217 | goto free_skb; | ||
218 | } | ||
219 | |||
220 | if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) | ||
221 | goto dst_unreach; | ||
222 | |||
223 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
224 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
225 | compare_orig, choose_orig, | ||
226 | icmp_packet->dst)); | ||
227 | |||
228 | if (!orig_node) | ||
229 | goto unlock; | ||
230 | |||
231 | if (!orig_node->router) | ||
232 | goto unlock; | ||
233 | |||
234 | batman_if = orig_node->router->if_incoming; | ||
235 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
236 | |||
237 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
238 | |||
239 | if (!batman_if) | ||
240 | goto dst_unreach; | ||
241 | |||
242 | if (batman_if->if_status != IF_ACTIVE) | ||
243 | goto dst_unreach; | ||
244 | |||
245 | memcpy(icmp_packet->orig, | ||
246 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
247 | |||
248 | if (packet_len == sizeof(struct icmp_packet_rr)) | ||
249 | memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN); | ||
250 | |||
251 | |||
252 | send_skb_packet(skb, batman_if, dstaddr); | ||
253 | |||
254 | goto out; | ||
255 | |||
256 | unlock: | ||
257 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
258 | dst_unreach: | ||
259 | icmp_packet->msg_type = DESTINATION_UNREACHABLE; | ||
260 | bat_socket_add_packet(socket_client, icmp_packet, packet_len); | ||
261 | free_skb: | ||
262 | kfree_skb(skb); | ||
263 | out: | ||
264 | return len; | ||
265 | } | ||
266 | |||
267 | static unsigned int bat_socket_poll(struct file *file, poll_table *wait) | ||
268 | { | ||
269 | struct socket_client *socket_client = file->private_data; | ||
270 | |||
271 | poll_wait(file, &socket_client->queue_wait, wait); | ||
272 | |||
273 | if (socket_client->queue_len > 0) | ||
274 | return POLLIN | POLLRDNORM; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static const struct file_operations fops = { | ||
280 | .owner = THIS_MODULE, | ||
281 | .open = bat_socket_open, | ||
282 | .release = bat_socket_release, | ||
283 | .read = bat_socket_read, | ||
284 | .write = bat_socket_write, | ||
285 | .poll = bat_socket_poll, | ||
286 | .llseek = no_llseek, | ||
287 | }; | ||
288 | |||
289 | int bat_socket_setup(struct bat_priv *bat_priv) | ||
290 | { | ||
291 | struct dentry *d; | ||
292 | |||
293 | if (!bat_priv->debug_dir) | ||
294 | goto err; | ||
295 | |||
296 | d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR, | ||
297 | bat_priv->debug_dir, bat_priv, &fops); | ||
298 | if (d) | ||
299 | goto err; | ||
300 | |||
301 | return 0; | ||
302 | |||
303 | err: | ||
304 | return 1; | ||
305 | } | ||
306 | |||
307 | static void bat_socket_add_packet(struct socket_client *socket_client, | ||
308 | struct icmp_packet_rr *icmp_packet, | ||
309 | size_t icmp_len) | ||
310 | { | ||
311 | struct socket_packet *socket_packet; | ||
312 | |||
313 | socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC); | ||
314 | |||
315 | if (!socket_packet) | ||
316 | return; | ||
317 | |||
318 | INIT_LIST_HEAD(&socket_packet->list); | ||
319 | memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len); | ||
320 | socket_packet->icmp_len = icmp_len; | ||
321 | |||
322 | spin_lock_bh(&socket_client->lock); | ||
323 | |||
324 | /* while waiting for the lock the socket_client could have been | ||
325 | * deleted */ | ||
326 | if (!socket_client_hash[icmp_packet->uid]) { | ||
327 | spin_unlock_bh(&socket_client->lock); | ||
328 | kfree(socket_packet); | ||
329 | return; | ||
330 | } | ||
331 | |||
332 | list_add_tail(&socket_packet->list, &socket_client->queue_list); | ||
333 | socket_client->queue_len++; | ||
334 | |||
335 | if (socket_client->queue_len > 100) { | ||
336 | socket_packet = list_first_entry(&socket_client->queue_list, | ||
337 | struct socket_packet, list); | ||
338 | |||
339 | list_del(&socket_packet->list); | ||
340 | kfree(socket_packet); | ||
341 | socket_client->queue_len--; | ||
342 | } | ||
343 | |||
344 | spin_unlock_bh(&socket_client->lock); | ||
345 | |||
346 | wake_up(&socket_client->queue_wait); | ||
347 | } | ||
348 | |||
349 | void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet, | ||
350 | size_t icmp_len) | ||
351 | { | ||
352 | struct socket_client *hash = socket_client_hash[icmp_packet->uid]; | ||
353 | |||
354 | if (hash) | ||
355 | bat_socket_add_packet(hash, icmp_packet, icmp_len); | ||
356 | } | ||
diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h new file mode 100644 index 000000000000..bf9b348cde27 --- /dev/null +++ b/net/batman-adv/icmp_socket.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_ | ||
23 | #define _NET_BATMAN_ADV_ICMP_SOCKET_H_ | ||
24 | |||
25 | #include "types.h" | ||
26 | |||
27 | #define ICMP_SOCKET "socket" | ||
28 | |||
29 | void bat_socket_init(void); | ||
30 | int bat_socket_setup(struct bat_priv *bat_priv); | ||
31 | void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet, | ||
32 | size_t icmp_len); | ||
33 | |||
34 | #endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */ | ||
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c new file mode 100644 index 000000000000..b827f6a158cb --- /dev/null +++ b/net/batman-adv/main.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 "bat_sysfs.h" | ||
24 | #include "bat_debugfs.h" | ||
25 | #include "routing.h" | ||
26 | #include "send.h" | ||
27 | #include "originator.h" | ||
28 | #include "soft-interface.h" | ||
29 | #include "icmp_socket.h" | ||
30 | #include "translation-table.h" | ||
31 | #include "hard-interface.h" | ||
32 | #include "gateway_client.h" | ||
33 | #include "types.h" | ||
34 | #include "vis.h" | ||
35 | #include "hash.h" | ||
36 | |||
37 | struct list_head if_list; | ||
38 | |||
39 | unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
40 | |||
41 | struct workqueue_struct *bat_event_workqueue; | ||
42 | |||
43 | static int __init batman_init(void) | ||
44 | { | ||
45 | INIT_LIST_HEAD(&if_list); | ||
46 | |||
47 | /* the name should not be longer than 10 chars - see | ||
48 | * http://lwn.net/Articles/23634/ */ | ||
49 | bat_event_workqueue = create_singlethread_workqueue("bat_events"); | ||
50 | |||
51 | if (!bat_event_workqueue) | ||
52 | return -ENOMEM; | ||
53 | |||
54 | bat_socket_init(); | ||
55 | debugfs_init(); | ||
56 | |||
57 | register_netdevice_notifier(&hard_if_notifier); | ||
58 | |||
59 | pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) " | ||
60 | "loaded\n", SOURCE_VERSION, REVISION_VERSION_STR, | ||
61 | COMPAT_VERSION); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static void __exit batman_exit(void) | ||
67 | { | ||
68 | debugfs_destroy(); | ||
69 | unregister_netdevice_notifier(&hard_if_notifier); | ||
70 | hardif_remove_interfaces(); | ||
71 | |||
72 | flush_workqueue(bat_event_workqueue); | ||
73 | destroy_workqueue(bat_event_workqueue); | ||
74 | bat_event_workqueue = NULL; | ||
75 | |||
76 | rcu_barrier(); | ||
77 | } | ||
78 | |||
79 | int mesh_init(struct net_device *soft_iface) | ||
80 | { | ||
81 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
82 | |||
83 | spin_lock_init(&bat_priv->orig_hash_lock); | ||
84 | spin_lock_init(&bat_priv->forw_bat_list_lock); | ||
85 | spin_lock_init(&bat_priv->forw_bcast_list_lock); | ||
86 | spin_lock_init(&bat_priv->hna_lhash_lock); | ||
87 | spin_lock_init(&bat_priv->hna_ghash_lock); | ||
88 | spin_lock_init(&bat_priv->gw_list_lock); | ||
89 | spin_lock_init(&bat_priv->vis_hash_lock); | ||
90 | spin_lock_init(&bat_priv->vis_list_lock); | ||
91 | spin_lock_init(&bat_priv->softif_neigh_lock); | ||
92 | |||
93 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); | ||
94 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); | ||
95 | INIT_HLIST_HEAD(&bat_priv->gw_list); | ||
96 | INIT_HLIST_HEAD(&bat_priv->softif_neigh_list); | ||
97 | |||
98 | if (originator_init(bat_priv) < 1) | ||
99 | goto err; | ||
100 | |||
101 | if (hna_local_init(bat_priv) < 1) | ||
102 | goto err; | ||
103 | |||
104 | if (hna_global_init(bat_priv) < 1) | ||
105 | goto err; | ||
106 | |||
107 | hna_local_add(soft_iface, soft_iface->dev_addr); | ||
108 | |||
109 | if (vis_init(bat_priv) < 1) | ||
110 | goto err; | ||
111 | |||
112 | atomic_set(&bat_priv->mesh_state, MESH_ACTIVE); | ||
113 | goto end; | ||
114 | |||
115 | err: | ||
116 | pr_err("Unable to allocate memory for mesh information structures: " | ||
117 | "out of mem ?\n"); | ||
118 | mesh_free(soft_iface); | ||
119 | return -1; | ||
120 | |||
121 | end: | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | void mesh_free(struct net_device *soft_iface) | ||
126 | { | ||
127 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
128 | |||
129 | atomic_set(&bat_priv->mesh_state, MESH_DEACTIVATING); | ||
130 | |||
131 | purge_outstanding_packets(bat_priv, NULL); | ||
132 | |||
133 | vis_quit(bat_priv); | ||
134 | |||
135 | gw_node_purge(bat_priv); | ||
136 | originator_free(bat_priv); | ||
137 | |||
138 | hna_local_free(bat_priv); | ||
139 | hna_global_free(bat_priv); | ||
140 | |||
141 | softif_neigh_purge(bat_priv); | ||
142 | |||
143 | atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); | ||
144 | } | ||
145 | |||
146 | void inc_module_count(void) | ||
147 | { | ||
148 | try_module_get(THIS_MODULE); | ||
149 | } | ||
150 | |||
151 | void dec_module_count(void) | ||
152 | { | ||
153 | module_put(THIS_MODULE); | ||
154 | } | ||
155 | |||
156 | int is_my_mac(uint8_t *addr) | ||
157 | { | ||
158 | struct batman_if *batman_if; | ||
159 | |||
160 | rcu_read_lock(); | ||
161 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
162 | if (batman_if->if_status != IF_ACTIVE) | ||
163 | continue; | ||
164 | |||
165 | if (compare_orig(batman_if->net_dev->dev_addr, addr)) { | ||
166 | rcu_read_unlock(); | ||
167 | return 1; | ||
168 | } | ||
169 | } | ||
170 | rcu_read_unlock(); | ||
171 | return 0; | ||
172 | |||
173 | } | ||
174 | |||
175 | module_init(batman_init); | ||
176 | module_exit(batman_exit); | ||
177 | |||
178 | MODULE_LICENSE("GPL"); | ||
179 | |||
180 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
181 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
182 | MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE); | ||
183 | #ifdef REVISION_VERSION | ||
184 | MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION); | ||
185 | #else | ||
186 | MODULE_VERSION(SOURCE_VERSION); | ||
187 | #endif | ||
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h new file mode 100644 index 000000000000..d4d9926c2201 --- /dev/null +++ b/net/batman-adv/main.h | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_MAIN_H_ | ||
23 | #define _NET_BATMAN_ADV_MAIN_H_ | ||
24 | |||
25 | /* Kernel Programming */ | ||
26 | #define LINUX | ||
27 | |||
28 | #define DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, " \ | ||
29 | "Simon Wunderlich <siwu@hrz.tu-chemnitz.de>" | ||
30 | #define DRIVER_DESC "B.A.T.M.A.N. advanced" | ||
31 | #define DRIVER_DEVICE "batman-adv" | ||
32 | |||
33 | #define SOURCE_VERSION "next" | ||
34 | |||
35 | |||
36 | /* B.A.T.M.A.N. parameters */ | ||
37 | |||
38 | #define TQ_MAX_VALUE 255 | ||
39 | #define JITTER 20 | ||
40 | #define TTL 50 /* Time To Live of broadcast messages */ | ||
41 | |||
42 | #define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no | ||
43 | * valid packet comes in -> TODO: check | ||
44 | * influence on TQ_LOCAL_WINDOW_SIZE */ | ||
45 | #define LOCAL_HNA_TIMEOUT 3600 /* in seconds */ | ||
46 | |||
47 | #define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator | ||
48 | * messages in squence numbers (should be a | ||
49 | * multiple of our word size) */ | ||
50 | #define TQ_GLOBAL_WINDOW_SIZE 5 | ||
51 | #define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 | ||
52 | #define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 | ||
53 | #define TQ_TOTAL_BIDRECT_LIMIT 1 | ||
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 | |||
60 | #define VIS_INTERVAL 5000 /* 5 seconds */ | ||
61 | |||
62 | /* how much worse secondary interfaces may be to | ||
63 | * to be considered as bonding candidates */ | ||
64 | |||
65 | #define BONDING_TQ_THRESHOLD 50 | ||
66 | |||
67 | #define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or | ||
68 | * change the size of | ||
69 | * forw_packet->direct_link_flags */ | ||
70 | #define MAX_AGGREGATION_MS 100 | ||
71 | |||
72 | #define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */ | ||
73 | |||
74 | #define RESET_PROTECTION_MS 30000 | ||
75 | #define EXPECTED_SEQNO_RANGE 65536 | ||
76 | /* don't reset again within 30 seconds */ | ||
77 | |||
78 | #define MESH_INACTIVE 0 | ||
79 | #define MESH_ACTIVE 1 | ||
80 | #define MESH_DEACTIVATING 2 | ||
81 | |||
82 | #define BCAST_QUEUE_LEN 256 | ||
83 | #define BATMAN_QUEUE_LEN 256 | ||
84 | |||
85 | /* | ||
86 | * Debug Messages | ||
87 | */ | ||
88 | #ifdef pr_fmt | ||
89 | #undef pr_fmt | ||
90 | #endif | ||
91 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before | ||
92 | * kernel messages */ | ||
93 | |||
94 | #define DBG_BATMAN 1 /* all messages related to routing / flooding / | ||
95 | * broadcasting / etc */ | ||
96 | #define DBG_ROUTES 2 /* route or hna added / changed / deleted */ | ||
97 | #define DBG_ALL 3 | ||
98 | |||
99 | #define LOG_BUF_LEN 8192 /* has to be a power of 2 */ | ||
100 | |||
101 | |||
102 | /* | ||
103 | * Vis | ||
104 | */ | ||
105 | |||
106 | /* #define VIS_SUBCLUSTERS_DISABLED */ | ||
107 | |||
108 | /* | ||
109 | * Kernel headers | ||
110 | */ | ||
111 | |||
112 | #include <linux/mutex.h> /* mutex */ | ||
113 | #include <linux/module.h> /* needed by all modules */ | ||
114 | #include <linux/netdevice.h> /* netdevice */ | ||
115 | #include <linux/etherdevice.h> /* ethernet address classifaction */ | ||
116 | #include <linux/if_ether.h> /* ethernet header */ | ||
117 | #include <linux/poll.h> /* poll_table */ | ||
118 | #include <linux/kthread.h> /* kernel threads */ | ||
119 | #include <linux/pkt_sched.h> /* schedule types */ | ||
120 | #include <linux/workqueue.h> /* workqueue */ | ||
121 | #include <linux/slab.h> | ||
122 | #include <net/sock.h> /* struct sock */ | ||
123 | #include <linux/jiffies.h> | ||
124 | #include <linux/seq_file.h> | ||
125 | #include "types.h" | ||
126 | |||
127 | #ifndef REVISION_VERSION | ||
128 | #define REVISION_VERSION_STR "" | ||
129 | #else | ||
130 | #define REVISION_VERSION_STR " "REVISION_VERSION | ||
131 | #endif | ||
132 | |||
133 | extern struct list_head if_list; | ||
134 | |||
135 | extern unsigned char broadcast_addr[]; | ||
136 | extern struct workqueue_struct *bat_event_workqueue; | ||
137 | |||
138 | int mesh_init(struct net_device *soft_iface); | ||
139 | void mesh_free(struct net_device *soft_iface); | ||
140 | void inc_module_count(void); | ||
141 | void dec_module_count(void); | ||
142 | int is_my_mac(uint8_t *addr); | ||
143 | |||
144 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
145 | int debug_log(struct bat_priv *bat_priv, char *fmt, ...); | ||
146 | |||
147 | #define bat_dbg(type, bat_priv, fmt, arg...) \ | ||
148 | do { \ | ||
149 | if (atomic_read(&bat_priv->log_level) & type) \ | ||
150 | debug_log(bat_priv, fmt, ## arg); \ | ||
151 | } \ | ||
152 | while (0) | ||
153 | #else /* !CONFIG_BATMAN_ADV_DEBUG */ | ||
154 | static inline void bat_dbg(char type __attribute__((unused)), | ||
155 | struct bat_priv *bat_priv __attribute__((unused)), | ||
156 | char *fmt __attribute__((unused)), ...) | ||
157 | { | ||
158 | } | ||
159 | #endif | ||
160 | |||
161 | #define bat_warning(net_dev, fmt, arg...) \ | ||
162 | do { \ | ||
163 | struct net_device *_netdev = (net_dev); \ | ||
164 | struct bat_priv *_batpriv = netdev_priv(_netdev); \ | ||
165 | bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ | ||
166 | pr_warning("%s: " fmt, _netdev->name, ## arg); \ | ||
167 | } while (0) | ||
168 | #define bat_info(net_dev, fmt, arg...) \ | ||
169 | do { \ | ||
170 | struct net_device *_netdev = (net_dev); \ | ||
171 | struct bat_priv *_batpriv = netdev_priv(_netdev); \ | ||
172 | bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ | ||
173 | pr_info("%s: " fmt, _netdev->name, ## arg); \ | ||
174 | } while (0) | ||
175 | #define bat_err(net_dev, fmt, arg...) \ | ||
176 | do { \ | ||
177 | struct net_device *_netdev = (net_dev); \ | ||
178 | struct bat_priv *_batpriv = netdev_priv(_netdev); \ | ||
179 | bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ | ||
180 | pr_err("%s: " fmt, _netdev->name, ## arg); \ | ||
181 | } while (0) | ||
182 | |||
183 | #endif /* _NET_BATMAN_ADV_MAIN_H_ */ | ||
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c new file mode 100644 index 000000000000..6b7fb6b7e6f9 --- /dev/null +++ b/net/batman-adv/originator.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 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 | /* increase the reference counter for this originator */ | ||
23 | |||
24 | #include "main.h" | ||
25 | #include "originator.h" | ||
26 | #include "hash.h" | ||
27 | #include "translation-table.h" | ||
28 | #include "routing.h" | ||
29 | #include "gateway_client.h" | ||
30 | #include "hard-interface.h" | ||
31 | #include "unicast.h" | ||
32 | #include "soft-interface.h" | ||
33 | |||
34 | static void purge_orig(struct work_struct *work); | ||
35 | |||
36 | static void start_purge_timer(struct bat_priv *bat_priv) | ||
37 | { | ||
38 | INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig); | ||
39 | queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ); | ||
40 | } | ||
41 | |||
42 | int originator_init(struct bat_priv *bat_priv) | ||
43 | { | ||
44 | if (bat_priv->orig_hash) | ||
45 | return 1; | ||
46 | |||
47 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
48 | bat_priv->orig_hash = hash_new(1024); | ||
49 | |||
50 | if (!bat_priv->orig_hash) | ||
51 | goto err; | ||
52 | |||
53 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
54 | start_purge_timer(bat_priv); | ||
55 | return 1; | ||
56 | |||
57 | err: | ||
58 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | struct neigh_node * | ||
63 | create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, | ||
64 | uint8_t *neigh, struct batman_if *if_incoming) | ||
65 | { | ||
66 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
67 | struct neigh_node *neigh_node; | ||
68 | |||
69 | bat_dbg(DBG_BATMAN, bat_priv, | ||
70 | "Creating new last-hop neighbor of originator\n"); | ||
71 | |||
72 | neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC); | ||
73 | if (!neigh_node) | ||
74 | return NULL; | ||
75 | |||
76 | INIT_LIST_HEAD(&neigh_node->list); | ||
77 | |||
78 | memcpy(neigh_node->addr, neigh, ETH_ALEN); | ||
79 | neigh_node->orig_node = orig_neigh_node; | ||
80 | neigh_node->if_incoming = if_incoming; | ||
81 | |||
82 | list_add_tail(&neigh_node->list, &orig_node->neigh_list); | ||
83 | return neigh_node; | ||
84 | } | ||
85 | |||
86 | static void free_orig_node(void *data, void *arg) | ||
87 | { | ||
88 | struct list_head *list_pos, *list_pos_tmp; | ||
89 | struct neigh_node *neigh_node; | ||
90 | struct orig_node *orig_node = (struct orig_node *)data; | ||
91 | struct bat_priv *bat_priv = (struct bat_priv *)arg; | ||
92 | |||
93 | /* for all neighbors towards this originator ... */ | ||
94 | list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { | ||
95 | neigh_node = list_entry(list_pos, struct neigh_node, list); | ||
96 | |||
97 | list_del(list_pos); | ||
98 | kfree(neigh_node); | ||
99 | } | ||
100 | |||
101 | frag_list_free(&orig_node->frag_list); | ||
102 | hna_global_del_orig(bat_priv, orig_node, "originator timed out"); | ||
103 | |||
104 | kfree(orig_node->bcast_own); | ||
105 | kfree(orig_node->bcast_own_sum); | ||
106 | kfree(orig_node); | ||
107 | } | ||
108 | |||
109 | void originator_free(struct bat_priv *bat_priv) | ||
110 | { | ||
111 | if (!bat_priv->orig_hash) | ||
112 | return; | ||
113 | |||
114 | cancel_delayed_work_sync(&bat_priv->orig_work); | ||
115 | |||
116 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
117 | hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv); | ||
118 | bat_priv->orig_hash = NULL; | ||
119 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
120 | } | ||
121 | |||
122 | /* this function finds or creates an originator entry for the given | ||
123 | * address if it does not exits */ | ||
124 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) | ||
125 | { | ||
126 | struct orig_node *orig_node; | ||
127 | int size; | ||
128 | int hash_added; | ||
129 | |||
130 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
131 | compare_orig, choose_orig, | ||
132 | addr)); | ||
133 | |||
134 | if (orig_node) | ||
135 | return orig_node; | ||
136 | |||
137 | bat_dbg(DBG_BATMAN, bat_priv, | ||
138 | "Creating new originator: %pM\n", addr); | ||
139 | |||
140 | orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC); | ||
141 | if (!orig_node) | ||
142 | return NULL; | ||
143 | |||
144 | INIT_LIST_HEAD(&orig_node->neigh_list); | ||
145 | |||
146 | memcpy(orig_node->orig, addr, ETH_ALEN); | ||
147 | orig_node->router = NULL; | ||
148 | orig_node->hna_buff = NULL; | ||
149 | orig_node->bcast_seqno_reset = jiffies - 1 | ||
150 | - msecs_to_jiffies(RESET_PROTECTION_MS); | ||
151 | orig_node->batman_seqno_reset = jiffies - 1 | ||
152 | - msecs_to_jiffies(RESET_PROTECTION_MS); | ||
153 | |||
154 | size = bat_priv->num_ifaces * sizeof(unsigned long) * NUM_WORDS; | ||
155 | |||
156 | orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); | ||
157 | if (!orig_node->bcast_own) | ||
158 | goto free_orig_node; | ||
159 | |||
160 | size = bat_priv->num_ifaces * sizeof(uint8_t); | ||
161 | orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); | ||
162 | |||
163 | INIT_LIST_HEAD(&orig_node->frag_list); | ||
164 | orig_node->last_frag_packet = 0; | ||
165 | |||
166 | if (!orig_node->bcast_own_sum) | ||
167 | goto free_bcast_own; | ||
168 | |||
169 | hash_added = hash_add(bat_priv->orig_hash, compare_orig, choose_orig, | ||
170 | orig_node); | ||
171 | if (hash_added < 0) | ||
172 | goto free_bcast_own_sum; | ||
173 | |||
174 | return orig_node; | ||
175 | free_bcast_own_sum: | ||
176 | kfree(orig_node->bcast_own_sum); | ||
177 | free_bcast_own: | ||
178 | kfree(orig_node->bcast_own); | ||
179 | free_orig_node: | ||
180 | kfree(orig_node); | ||
181 | return NULL; | ||
182 | } | ||
183 | |||
184 | static bool purge_orig_neighbors(struct bat_priv *bat_priv, | ||
185 | struct orig_node *orig_node, | ||
186 | struct neigh_node **best_neigh_node) | ||
187 | { | ||
188 | struct list_head *list_pos, *list_pos_tmp; | ||
189 | struct neigh_node *neigh_node; | ||
190 | bool neigh_purged = false; | ||
191 | |||
192 | *best_neigh_node = NULL; | ||
193 | |||
194 | /* for all neighbors towards this originator ... */ | ||
195 | list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { | ||
196 | neigh_node = list_entry(list_pos, struct neigh_node, list); | ||
197 | |||
198 | if ((time_after(jiffies, | ||
199 | neigh_node->last_valid + PURGE_TIMEOUT * HZ)) || | ||
200 | (neigh_node->if_incoming->if_status == IF_INACTIVE) || | ||
201 | (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) { | ||
202 | |||
203 | if (neigh_node->if_incoming->if_status == | ||
204 | IF_TO_BE_REMOVED) | ||
205 | bat_dbg(DBG_BATMAN, bat_priv, | ||
206 | "neighbor purge: originator %pM, " | ||
207 | "neighbor: %pM, iface: %s\n", | ||
208 | orig_node->orig, neigh_node->addr, | ||
209 | neigh_node->if_incoming->net_dev->name); | ||
210 | else | ||
211 | bat_dbg(DBG_BATMAN, bat_priv, | ||
212 | "neighbor timeout: originator %pM, " | ||
213 | "neighbor: %pM, last_valid: %lu\n", | ||
214 | orig_node->orig, neigh_node->addr, | ||
215 | (neigh_node->last_valid / HZ)); | ||
216 | |||
217 | neigh_purged = true; | ||
218 | list_del(list_pos); | ||
219 | kfree(neigh_node); | ||
220 | } else { | ||
221 | if ((!*best_neigh_node) || | ||
222 | (neigh_node->tq_avg > (*best_neigh_node)->tq_avg)) | ||
223 | *best_neigh_node = neigh_node; | ||
224 | } | ||
225 | } | ||
226 | return neigh_purged; | ||
227 | } | ||
228 | |||
229 | static bool purge_orig_node(struct bat_priv *bat_priv, | ||
230 | struct orig_node *orig_node) | ||
231 | { | ||
232 | struct neigh_node *best_neigh_node; | ||
233 | |||
234 | if (time_after(jiffies, | ||
235 | orig_node->last_valid + 2 * PURGE_TIMEOUT * HZ)) { | ||
236 | |||
237 | bat_dbg(DBG_BATMAN, bat_priv, | ||
238 | "Originator timeout: originator %pM, last_valid %lu\n", | ||
239 | orig_node->orig, (orig_node->last_valid / HZ)); | ||
240 | return true; | ||
241 | } else { | ||
242 | if (purge_orig_neighbors(bat_priv, orig_node, | ||
243 | &best_neigh_node)) { | ||
244 | update_routes(bat_priv, orig_node, | ||
245 | best_neigh_node, | ||
246 | orig_node->hna_buff, | ||
247 | orig_node->hna_buff_len); | ||
248 | /* update bonding candidates, we could have lost | ||
249 | * some candidates. */ | ||
250 | update_bonding_candidates(bat_priv, orig_node); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | return false; | ||
255 | } | ||
256 | |||
257 | static void _purge_orig(struct bat_priv *bat_priv) | ||
258 | { | ||
259 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
260 | struct hlist_node *walk, *safe; | ||
261 | struct hlist_head *head; | ||
262 | struct element_t *bucket; | ||
263 | struct orig_node *orig_node; | ||
264 | int i; | ||
265 | |||
266 | if (!hash) | ||
267 | return; | ||
268 | |||
269 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
270 | |||
271 | /* for all origins... */ | ||
272 | for (i = 0; i < hash->size; i++) { | ||
273 | head = &hash->table[i]; | ||
274 | |||
275 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | ||
276 | orig_node = bucket->data; | ||
277 | |||
278 | if (purge_orig_node(bat_priv, orig_node)) { | ||
279 | if (orig_node->gw_flags) | ||
280 | gw_node_delete(bat_priv, orig_node); | ||
281 | hlist_del(walk); | ||
282 | kfree(bucket); | ||
283 | free_orig_node(orig_node, bat_priv); | ||
284 | } | ||
285 | |||
286 | if (time_after(jiffies, orig_node->last_frag_packet + | ||
287 | msecs_to_jiffies(FRAG_TIMEOUT))) | ||
288 | frag_list_free(&orig_node->frag_list); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
293 | |||
294 | gw_node_purge(bat_priv); | ||
295 | gw_election(bat_priv); | ||
296 | |||
297 | softif_neigh_purge(bat_priv); | ||
298 | } | ||
299 | |||
300 | static void purge_orig(struct work_struct *work) | ||
301 | { | ||
302 | struct delayed_work *delayed_work = | ||
303 | container_of(work, struct delayed_work, work); | ||
304 | struct bat_priv *bat_priv = | ||
305 | container_of(delayed_work, struct bat_priv, orig_work); | ||
306 | |||
307 | _purge_orig(bat_priv); | ||
308 | start_purge_timer(bat_priv); | ||
309 | } | ||
310 | |||
311 | void purge_orig_ref(struct bat_priv *bat_priv) | ||
312 | { | ||
313 | _purge_orig(bat_priv); | ||
314 | } | ||
315 | |||
316 | int orig_seq_print_text(struct seq_file *seq, void *offset) | ||
317 | { | ||
318 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
319 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
320 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
321 | struct hlist_node *walk; | ||
322 | struct hlist_head *head; | ||
323 | struct element_t *bucket; | ||
324 | struct orig_node *orig_node; | ||
325 | struct neigh_node *neigh_node; | ||
326 | int batman_count = 0; | ||
327 | int last_seen_secs; | ||
328 | int last_seen_msecs; | ||
329 | int i; | ||
330 | |||
331 | if ((!bat_priv->primary_if) || | ||
332 | (bat_priv->primary_if->if_status != IF_ACTIVE)) { | ||
333 | if (!bat_priv->primary_if) | ||
334 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
335 | "please specify interfaces to enable it\n", | ||
336 | net_dev->name); | ||
337 | |||
338 | return seq_printf(seq, "BATMAN mesh %s " | ||
339 | "disabled - primary interface not active\n", | ||
340 | net_dev->name); | ||
341 | } | ||
342 | |||
343 | seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", | ||
344 | SOURCE_VERSION, REVISION_VERSION_STR, | ||
345 | bat_priv->primary_if->net_dev->name, | ||
346 | bat_priv->primary_if->net_dev->dev_addr, net_dev->name); | ||
347 | seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", | ||
348 | "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", | ||
349 | "outgoingIF", "Potential nexthops"); | ||
350 | |||
351 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
352 | |||
353 | for (i = 0; i < hash->size; i++) { | ||
354 | head = &hash->table[i]; | ||
355 | |||
356 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
357 | orig_node = bucket->data; | ||
358 | |||
359 | if (!orig_node->router) | ||
360 | continue; | ||
361 | |||
362 | if (orig_node->router->tq_avg == 0) | ||
363 | continue; | ||
364 | |||
365 | last_seen_secs = jiffies_to_msecs(jiffies - | ||
366 | orig_node->last_valid) / 1000; | ||
367 | last_seen_msecs = jiffies_to_msecs(jiffies - | ||
368 | orig_node->last_valid) % 1000; | ||
369 | |||
370 | neigh_node = orig_node->router; | ||
371 | seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", | ||
372 | orig_node->orig, last_seen_secs, | ||
373 | last_seen_msecs, neigh_node->tq_avg, | ||
374 | neigh_node->addr, | ||
375 | neigh_node->if_incoming->net_dev->name); | ||
376 | |||
377 | list_for_each_entry(neigh_node, &orig_node->neigh_list, | ||
378 | list) { | ||
379 | seq_printf(seq, " %pM (%3i)", neigh_node->addr, | ||
380 | neigh_node->tq_avg); | ||
381 | } | ||
382 | |||
383 | seq_printf(seq, "\n"); | ||
384 | batman_count++; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
389 | |||
390 | if ((batman_count == 0)) | ||
391 | seq_printf(seq, "No batman nodes in range ...\n"); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) | ||
397 | { | ||
398 | void *data_ptr; | ||
399 | |||
400 | data_ptr = kmalloc(max_if_num * sizeof(unsigned long) * NUM_WORDS, | ||
401 | GFP_ATOMIC); | ||
402 | if (!data_ptr) { | ||
403 | pr_err("Can't resize orig: out of memory\n"); | ||
404 | return -1; | ||
405 | } | ||
406 | |||
407 | memcpy(data_ptr, orig_node->bcast_own, | ||
408 | (max_if_num - 1) * sizeof(unsigned long) * NUM_WORDS); | ||
409 | kfree(orig_node->bcast_own); | ||
410 | orig_node->bcast_own = data_ptr; | ||
411 | |||
412 | data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); | ||
413 | if (!data_ptr) { | ||
414 | pr_err("Can't resize orig: out of memory\n"); | ||
415 | return -1; | ||
416 | } | ||
417 | |||
418 | memcpy(data_ptr, orig_node->bcast_own_sum, | ||
419 | (max_if_num - 1) * sizeof(uint8_t)); | ||
420 | kfree(orig_node->bcast_own_sum); | ||
421 | orig_node->bcast_own_sum = data_ptr; | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) | ||
427 | { | ||
428 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
429 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
430 | struct hlist_node *walk; | ||
431 | struct hlist_head *head; | ||
432 | struct element_t *bucket; | ||
433 | struct orig_node *orig_node; | ||
434 | int i; | ||
435 | |||
436 | /* resize all orig nodes because orig_node->bcast_own(_sum) depend on | ||
437 | * if_num */ | ||
438 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
439 | |||
440 | for (i = 0; i < hash->size; i++) { | ||
441 | head = &hash->table[i]; | ||
442 | |||
443 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
444 | orig_node = bucket->data; | ||
445 | |||
446 | if (orig_node_add_if(orig_node, max_if_num) == -1) | ||
447 | goto err; | ||
448 | } | ||
449 | } | ||
450 | |||
451 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
452 | return 0; | ||
453 | |||
454 | err: | ||
455 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
456 | return -ENOMEM; | ||
457 | } | ||
458 | |||
459 | static int orig_node_del_if(struct orig_node *orig_node, | ||
460 | int max_if_num, int del_if_num) | ||
461 | { | ||
462 | void *data_ptr = NULL; | ||
463 | int chunk_size; | ||
464 | |||
465 | /* last interface was removed */ | ||
466 | if (max_if_num == 0) | ||
467 | goto free_bcast_own; | ||
468 | |||
469 | chunk_size = sizeof(unsigned long) * NUM_WORDS; | ||
470 | data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC); | ||
471 | if (!data_ptr) { | ||
472 | pr_err("Can't resize orig: out of memory\n"); | ||
473 | return -1; | ||
474 | } | ||
475 | |||
476 | /* copy first part */ | ||
477 | memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size); | ||
478 | |||
479 | /* copy second part */ | ||
480 | memcpy(data_ptr + del_if_num * chunk_size, | ||
481 | orig_node->bcast_own + ((del_if_num + 1) * chunk_size), | ||
482 | (max_if_num - del_if_num) * chunk_size); | ||
483 | |||
484 | free_bcast_own: | ||
485 | kfree(orig_node->bcast_own); | ||
486 | orig_node->bcast_own = data_ptr; | ||
487 | |||
488 | if (max_if_num == 0) | ||
489 | goto free_own_sum; | ||
490 | |||
491 | data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); | ||
492 | if (!data_ptr) { | ||
493 | pr_err("Can't resize orig: out of memory\n"); | ||
494 | return -1; | ||
495 | } | ||
496 | |||
497 | memcpy(data_ptr, orig_node->bcast_own_sum, | ||
498 | del_if_num * sizeof(uint8_t)); | ||
499 | |||
500 | memcpy(data_ptr + del_if_num * sizeof(uint8_t), | ||
501 | orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)), | ||
502 | (max_if_num - del_if_num) * sizeof(uint8_t)); | ||
503 | |||
504 | free_own_sum: | ||
505 | kfree(orig_node->bcast_own_sum); | ||
506 | orig_node->bcast_own_sum = data_ptr; | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) | ||
512 | { | ||
513 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
514 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
515 | struct hlist_node *walk; | ||
516 | struct hlist_head *head; | ||
517 | struct element_t *bucket; | ||
518 | struct batman_if *batman_if_tmp; | ||
519 | struct orig_node *orig_node; | ||
520 | int i, ret; | ||
521 | |||
522 | /* resize all orig nodes because orig_node->bcast_own(_sum) depend on | ||
523 | * if_num */ | ||
524 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
525 | |||
526 | for (i = 0; i < hash->size; i++) { | ||
527 | head = &hash->table[i]; | ||
528 | |||
529 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
530 | orig_node = bucket->data; | ||
531 | |||
532 | ret = orig_node_del_if(orig_node, max_if_num, | ||
533 | batman_if->if_num); | ||
534 | |||
535 | if (ret == -1) | ||
536 | goto err; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | /* renumber remaining batman interfaces _inside_ of orig_hash_lock */ | ||
541 | rcu_read_lock(); | ||
542 | list_for_each_entry_rcu(batman_if_tmp, &if_list, list) { | ||
543 | if (batman_if_tmp->if_status == IF_NOT_IN_USE) | ||
544 | continue; | ||
545 | |||
546 | if (batman_if == batman_if_tmp) | ||
547 | continue; | ||
548 | |||
549 | if (batman_if->soft_iface != batman_if_tmp->soft_iface) | ||
550 | continue; | ||
551 | |||
552 | if (batman_if_tmp->if_num > batman_if->if_num) | ||
553 | batman_if_tmp->if_num--; | ||
554 | } | ||
555 | rcu_read_unlock(); | ||
556 | |||
557 | batman_if->if_num = -1; | ||
558 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
559 | return 0; | ||
560 | |||
561 | err: | ||
562 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
563 | return -ENOMEM; | ||
564 | } | ||
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h new file mode 100644 index 000000000000..d474ceb2a4eb --- /dev/null +++ b/net/batman-adv/originator.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_ORIGINATOR_H_ | ||
23 | #define _NET_BATMAN_ADV_ORIGINATOR_H_ | ||
24 | |||
25 | int originator_init(struct bat_priv *bat_priv); | ||
26 | void originator_free(struct bat_priv *bat_priv); | ||
27 | void purge_orig_ref(struct bat_priv *bat_priv); | ||
28 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); | ||
29 | struct neigh_node * | ||
30 | create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, | ||
31 | uint8_t *neigh, struct batman_if *if_incoming); | ||
32 | int orig_seq_print_text(struct seq_file *seq, void *offset); | ||
33 | int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); | ||
34 | int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); | ||
35 | |||
36 | |||
37 | /* returns 1 if they are the same originator */ | ||
38 | static inline int compare_orig(void *data1, void *data2) | ||
39 | { | ||
40 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | ||
41 | } | ||
42 | |||
43 | /* hashfunction to choose an entry in a hash table of given size */ | ||
44 | /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ | ||
45 | static inline int choose_orig(void *data, int32_t size) | ||
46 | { | ||
47 | unsigned char *key = data; | ||
48 | uint32_t hash = 0; | ||
49 | size_t i; | ||
50 | |||
51 | for (i = 0; i < 6; i++) { | ||
52 | hash += key[i]; | ||
53 | hash += (hash << 10); | ||
54 | hash ^= (hash >> 6); | ||
55 | } | ||
56 | |||
57 | hash += (hash << 3); | ||
58 | hash ^= (hash >> 11); | ||
59 | hash += (hash << 15); | ||
60 | |||
61 | return hash % size; | ||
62 | } | ||
63 | |||
64 | #endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ | ||
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h new file mode 100644 index 000000000000..b49fdf70a6d5 --- /dev/null +++ b/net/batman-adv/packet.h | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_PACKET_H_ | ||
23 | #define _NET_BATMAN_ADV_PACKET_H_ | ||
24 | |||
25 | #define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */ | ||
26 | |||
27 | #define BAT_PACKET 0x01 | ||
28 | #define BAT_ICMP 0x02 | ||
29 | #define BAT_UNICAST 0x03 | ||
30 | #define BAT_BCAST 0x04 | ||
31 | #define BAT_VIS 0x05 | ||
32 | #define BAT_UNICAST_FRAG 0x06 | ||
33 | |||
34 | /* this file is included by batctl which needs these defines */ | ||
35 | #define COMPAT_VERSION 12 | ||
36 | #define DIRECTLINK 0x40 | ||
37 | #define VIS_SERVER 0x20 | ||
38 | #define PRIMARIES_FIRST_HOP 0x10 | ||
39 | |||
40 | /* ICMP message types */ | ||
41 | #define ECHO_REPLY 0 | ||
42 | #define DESTINATION_UNREACHABLE 3 | ||
43 | #define ECHO_REQUEST 8 | ||
44 | #define TTL_EXCEEDED 11 | ||
45 | #define PARAMETER_PROBLEM 12 | ||
46 | |||
47 | /* vis defines */ | ||
48 | #define VIS_TYPE_SERVER_SYNC 0 | ||
49 | #define VIS_TYPE_CLIENT_UPDATE 1 | ||
50 | |||
51 | /* fragmentation defines */ | ||
52 | #define UNI_FRAG_HEAD 0x01 | ||
53 | |||
54 | struct batman_packet { | ||
55 | uint8_t packet_type; | ||
56 | uint8_t version; /* batman version field */ | ||
57 | uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ | ||
58 | uint8_t tq; | ||
59 | uint32_t seqno; | ||
60 | uint8_t orig[6]; | ||
61 | uint8_t prev_sender[6]; | ||
62 | uint8_t ttl; | ||
63 | uint8_t num_hna; | ||
64 | uint8_t gw_flags; /* flags related to gateway class */ | ||
65 | uint8_t align; | ||
66 | } __attribute__((packed)); | ||
67 | |||
68 | #define BAT_PACKET_LEN sizeof(struct batman_packet) | ||
69 | |||
70 | struct icmp_packet { | ||
71 | uint8_t packet_type; | ||
72 | uint8_t version; /* batman version field */ | ||
73 | uint8_t msg_type; /* see ICMP message types above */ | ||
74 | uint8_t ttl; | ||
75 | uint8_t dst[6]; | ||
76 | uint8_t orig[6]; | ||
77 | uint16_t seqno; | ||
78 | uint8_t uid; | ||
79 | } __attribute__((packed)); | ||
80 | |||
81 | #define BAT_RR_LEN 16 | ||
82 | |||
83 | /* icmp_packet_rr must start with all fields from imcp_packet | ||
84 | * as this is assumed by code that handles ICMP packets */ | ||
85 | struct icmp_packet_rr { | ||
86 | uint8_t packet_type; | ||
87 | uint8_t version; /* batman version field */ | ||
88 | uint8_t msg_type; /* see ICMP message types above */ | ||
89 | uint8_t ttl; | ||
90 | uint8_t dst[6]; | ||
91 | uint8_t orig[6]; | ||
92 | uint16_t seqno; | ||
93 | uint8_t uid; | ||
94 | uint8_t rr_cur; | ||
95 | uint8_t rr[BAT_RR_LEN][ETH_ALEN]; | ||
96 | } __attribute__((packed)); | ||
97 | |||
98 | struct unicast_packet { | ||
99 | uint8_t packet_type; | ||
100 | uint8_t version; /* batman version field */ | ||
101 | uint8_t dest[6]; | ||
102 | uint8_t ttl; | ||
103 | } __attribute__((packed)); | ||
104 | |||
105 | struct unicast_frag_packet { | ||
106 | uint8_t packet_type; | ||
107 | uint8_t version; /* batman version field */ | ||
108 | uint8_t dest[6]; | ||
109 | uint8_t ttl; | ||
110 | uint8_t flags; | ||
111 | uint8_t orig[6]; | ||
112 | uint16_t seqno; | ||
113 | } __attribute__((packed)); | ||
114 | |||
115 | struct bcast_packet { | ||
116 | uint8_t packet_type; | ||
117 | uint8_t version; /* batman version field */ | ||
118 | uint8_t orig[6]; | ||
119 | uint8_t ttl; | ||
120 | uint32_t seqno; | ||
121 | } __attribute__((packed)); | ||
122 | |||
123 | struct vis_packet { | ||
124 | uint8_t packet_type; | ||
125 | uint8_t version; /* batman version field */ | ||
126 | uint8_t vis_type; /* which type of vis-participant sent this? */ | ||
127 | uint8_t entries; /* number of entries behind this struct */ | ||
128 | uint32_t seqno; /* sequence number */ | ||
129 | uint8_t ttl; /* TTL */ | ||
130 | uint8_t vis_orig[6]; /* originator that informs about its | ||
131 | * neighbors */ | ||
132 | uint8_t target_orig[6]; /* who should receive this packet */ | ||
133 | uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ | ||
134 | } __attribute__((packed)); | ||
135 | |||
136 | #endif /* _NET_BATMAN_ADV_PACKET_H_ */ | ||
diff --git a/net/batman-adv/ring_buffer.c b/net/batman-adv/ring_buffer.c new file mode 100644 index 000000000000..defd37c9be1f --- /dev/null +++ b/net/batman-adv/ring_buffer.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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/net/batman-adv/ring_buffer.h b/net/batman-adv/ring_buffer.h new file mode 100644 index 000000000000..6b0cb9aaeba5 --- /dev/null +++ b/net/batman-adv/ring_buffer.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_RING_BUFFER_H_ | ||
23 | #define _NET_BATMAN_ADV_RING_BUFFER_H_ | ||
24 | |||
25 | void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value); | ||
26 | uint8_t ring_buffer_avg(uint8_t lq_recv[]); | ||
27 | |||
28 | #endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */ | ||
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c new file mode 100644 index 000000000000..8828eddd3f72 --- /dev/null +++ b/net/batman-adv/routing.c | |||
@@ -0,0 +1,1397 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 "routing.h" | ||
24 | #include "send.h" | ||
25 | #include "hash.h" | ||
26 | #include "soft-interface.h" | ||
27 | #include "hard-interface.h" | ||
28 | #include "icmp_socket.h" | ||
29 | #include "translation-table.h" | ||
30 | #include "originator.h" | ||
31 | #include "types.h" | ||
32 | #include "ring_buffer.h" | ||
33 | #include "vis.h" | ||
34 | #include "aggregation.h" | ||
35 | #include "gateway_common.h" | ||
36 | #include "gateway_client.h" | ||
37 | #include "unicast.h" | ||
38 | |||
39 | void slide_own_bcast_window(struct batman_if *batman_if) | ||
40 | { | ||
41 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
42 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
43 | struct hlist_node *walk; | ||
44 | struct hlist_head *head; | ||
45 | struct element_t *bucket; | ||
46 | struct orig_node *orig_node; | ||
47 | unsigned long *word; | ||
48 | int i; | ||
49 | size_t word_index; | ||
50 | |||
51 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
52 | |||
53 | for (i = 0; i < hash->size; i++) { | ||
54 | head = &hash->table[i]; | ||
55 | |||
56 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
57 | orig_node = bucket->data; | ||
58 | word_index = batman_if->if_num * NUM_WORDS; | ||
59 | word = &(orig_node->bcast_own[word_index]); | ||
60 | |||
61 | bit_get_packet(bat_priv, word, 1, 0); | ||
62 | orig_node->bcast_own_sum[batman_if->if_num] = | ||
63 | bit_packet_count(word); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
68 | } | ||
69 | |||
70 | static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node, | ||
71 | unsigned char *hna_buff, int hna_buff_len) | ||
72 | { | ||
73 | if ((hna_buff_len != orig_node->hna_buff_len) || | ||
74 | ((hna_buff_len > 0) && | ||
75 | (orig_node->hna_buff_len > 0) && | ||
76 | (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) { | ||
77 | |||
78 | if (orig_node->hna_buff_len > 0) | ||
79 | hna_global_del_orig(bat_priv, orig_node, | ||
80 | "originator changed hna"); | ||
81 | |||
82 | if ((hna_buff_len > 0) && (hna_buff)) | ||
83 | hna_global_add_orig(bat_priv, orig_node, | ||
84 | hna_buff, hna_buff_len); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void update_route(struct bat_priv *bat_priv, | ||
89 | struct orig_node *orig_node, | ||
90 | struct neigh_node *neigh_node, | ||
91 | unsigned char *hna_buff, int hna_buff_len) | ||
92 | { | ||
93 | /* route deleted */ | ||
94 | if ((orig_node->router) && (!neigh_node)) { | ||
95 | |||
96 | bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", | ||
97 | orig_node->orig); | ||
98 | hna_global_del_orig(bat_priv, orig_node, | ||
99 | "originator timed out"); | ||
100 | |||
101 | /* route added */ | ||
102 | } else if ((!orig_node->router) && (neigh_node)) { | ||
103 | |||
104 | bat_dbg(DBG_ROUTES, bat_priv, | ||
105 | "Adding route towards: %pM (via %pM)\n", | ||
106 | orig_node->orig, neigh_node->addr); | ||
107 | hna_global_add_orig(bat_priv, orig_node, | ||
108 | hna_buff, hna_buff_len); | ||
109 | |||
110 | /* route changed */ | ||
111 | } else { | ||
112 | bat_dbg(DBG_ROUTES, bat_priv, | ||
113 | "Changing route towards: %pM " | ||
114 | "(now via %pM - was via %pM)\n", | ||
115 | orig_node->orig, neigh_node->addr, | ||
116 | orig_node->router->addr); | ||
117 | } | ||
118 | |||
119 | orig_node->router = neigh_node; | ||
120 | } | ||
121 | |||
122 | |||
123 | void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, | ||
124 | struct neigh_node *neigh_node, unsigned char *hna_buff, | ||
125 | int hna_buff_len) | ||
126 | { | ||
127 | |||
128 | if (!orig_node) | ||
129 | return; | ||
130 | |||
131 | if (orig_node->router != neigh_node) | ||
132 | update_route(bat_priv, orig_node, neigh_node, | ||
133 | hna_buff, hna_buff_len); | ||
134 | /* may be just HNA changed */ | ||
135 | else | ||
136 | update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len); | ||
137 | } | ||
138 | |||
139 | static int is_bidirectional_neigh(struct orig_node *orig_node, | ||
140 | struct orig_node *orig_neigh_node, | ||
141 | struct batman_packet *batman_packet, | ||
142 | struct batman_if *if_incoming) | ||
143 | { | ||
144 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
145 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | ||
146 | unsigned char total_count; | ||
147 | |||
148 | if (orig_node == orig_neigh_node) { | ||
149 | list_for_each_entry(tmp_neigh_node, | ||
150 | &orig_node->neigh_list, | ||
151 | list) { | ||
152 | |||
153 | if (compare_orig(tmp_neigh_node->addr, | ||
154 | orig_neigh_node->orig) && | ||
155 | (tmp_neigh_node->if_incoming == if_incoming)) | ||
156 | neigh_node = tmp_neigh_node; | ||
157 | } | ||
158 | |||
159 | if (!neigh_node) | ||
160 | neigh_node = create_neighbor(orig_node, | ||
161 | orig_neigh_node, | ||
162 | orig_neigh_node->orig, | ||
163 | if_incoming); | ||
164 | /* create_neighbor failed, return 0 */ | ||
165 | if (!neigh_node) | ||
166 | return 0; | ||
167 | |||
168 | neigh_node->last_valid = jiffies; | ||
169 | } else { | ||
170 | /* find packet count of corresponding one hop neighbor */ | ||
171 | list_for_each_entry(tmp_neigh_node, | ||
172 | &orig_neigh_node->neigh_list, list) { | ||
173 | |||
174 | if (compare_orig(tmp_neigh_node->addr, | ||
175 | orig_neigh_node->orig) && | ||
176 | (tmp_neigh_node->if_incoming == if_incoming)) | ||
177 | neigh_node = tmp_neigh_node; | ||
178 | } | ||
179 | |||
180 | if (!neigh_node) | ||
181 | neigh_node = create_neighbor(orig_neigh_node, | ||
182 | orig_neigh_node, | ||
183 | orig_neigh_node->orig, | ||
184 | if_incoming); | ||
185 | /* create_neighbor failed, return 0 */ | ||
186 | if (!neigh_node) | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | orig_node->last_valid = jiffies; | ||
191 | |||
192 | /* pay attention to not get a value bigger than 100 % */ | ||
193 | total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > | ||
194 | neigh_node->real_packet_count ? | ||
195 | neigh_node->real_packet_count : | ||
196 | orig_neigh_node->bcast_own_sum[if_incoming->if_num]); | ||
197 | |||
198 | /* if we have too few packets (too less data) we set tq_own to zero */ | ||
199 | /* if we receive too few packets it is not considered bidirectional */ | ||
200 | if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || | ||
201 | (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) | ||
202 | orig_neigh_node->tq_own = 0; | ||
203 | else | ||
204 | /* neigh_node->real_packet_count is never zero as we | ||
205 | * only purge old information when getting new | ||
206 | * information */ | ||
207 | orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / | ||
208 | neigh_node->real_packet_count; | ||
209 | |||
210 | /* | ||
211 | * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does | ||
212 | * affect the nearly-symmetric links only a little, but | ||
213 | * punishes asymmetric links more. This will give a value | ||
214 | * between 0 and TQ_MAX_VALUE | ||
215 | */ | ||
216 | orig_neigh_node->tq_asym_penalty = | ||
217 | TQ_MAX_VALUE - | ||
218 | (TQ_MAX_VALUE * | ||
219 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * | ||
220 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * | ||
221 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / | ||
222 | (TQ_LOCAL_WINDOW_SIZE * | ||
223 | TQ_LOCAL_WINDOW_SIZE * | ||
224 | TQ_LOCAL_WINDOW_SIZE); | ||
225 | |||
226 | batman_packet->tq = ((batman_packet->tq * | ||
227 | orig_neigh_node->tq_own * | ||
228 | orig_neigh_node->tq_asym_penalty) / | ||
229 | (TQ_MAX_VALUE * TQ_MAX_VALUE)); | ||
230 | |||
231 | bat_dbg(DBG_BATMAN, bat_priv, | ||
232 | "bidirectional: " | ||
233 | "orig = %-15pM neigh = %-15pM => own_bcast = %2i, " | ||
234 | "real recv = %2i, local tq: %3i, asym_penalty: %3i, " | ||
235 | "total tq: %3i\n", | ||
236 | orig_node->orig, orig_neigh_node->orig, total_count, | ||
237 | neigh_node->real_packet_count, orig_neigh_node->tq_own, | ||
238 | orig_neigh_node->tq_asym_penalty, batman_packet->tq); | ||
239 | |||
240 | /* if link has the minimum required transmission quality | ||
241 | * consider it bidirectional */ | ||
242 | if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) | ||
243 | return 1; | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static void update_orig(struct bat_priv *bat_priv, | ||
249 | struct orig_node *orig_node, | ||
250 | struct ethhdr *ethhdr, | ||
251 | struct batman_packet *batman_packet, | ||
252 | struct batman_if *if_incoming, | ||
253 | unsigned char *hna_buff, int hna_buff_len, | ||
254 | char is_duplicate) | ||
255 | { | ||
256 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | ||
257 | int tmp_hna_buff_len; | ||
258 | |||
259 | bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " | ||
260 | "Searching and updating originator entry of received packet\n"); | ||
261 | |||
262 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
263 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && | ||
264 | (tmp_neigh_node->if_incoming == if_incoming)) { | ||
265 | neigh_node = tmp_neigh_node; | ||
266 | continue; | ||
267 | } | ||
268 | |||
269 | if (is_duplicate) | ||
270 | continue; | ||
271 | |||
272 | ring_buffer_set(tmp_neigh_node->tq_recv, | ||
273 | &tmp_neigh_node->tq_index, 0); | ||
274 | tmp_neigh_node->tq_avg = | ||
275 | ring_buffer_avg(tmp_neigh_node->tq_recv); | ||
276 | } | ||
277 | |||
278 | if (!neigh_node) { | ||
279 | struct orig_node *orig_tmp; | ||
280 | |||
281 | orig_tmp = get_orig_node(bat_priv, ethhdr->h_source); | ||
282 | if (!orig_tmp) | ||
283 | return; | ||
284 | |||
285 | neigh_node = create_neighbor(orig_node, orig_tmp, | ||
286 | ethhdr->h_source, if_incoming); | ||
287 | if (!neigh_node) | ||
288 | return; | ||
289 | } else | ||
290 | bat_dbg(DBG_BATMAN, bat_priv, | ||
291 | "Updating existing last-hop neighbor of originator\n"); | ||
292 | |||
293 | orig_node->flags = batman_packet->flags; | ||
294 | neigh_node->last_valid = jiffies; | ||
295 | |||
296 | ring_buffer_set(neigh_node->tq_recv, | ||
297 | &neigh_node->tq_index, | ||
298 | batman_packet->tq); | ||
299 | neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); | ||
300 | |||
301 | if (!is_duplicate) { | ||
302 | orig_node->last_ttl = batman_packet->ttl; | ||
303 | neigh_node->last_ttl = batman_packet->ttl; | ||
304 | } | ||
305 | |||
306 | tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? | ||
307 | batman_packet->num_hna * ETH_ALEN : hna_buff_len); | ||
308 | |||
309 | /* if this neighbor already is our next hop there is nothing | ||
310 | * to change */ | ||
311 | if (orig_node->router == neigh_node) | ||
312 | goto update_hna; | ||
313 | |||
314 | /* if this neighbor does not offer a better TQ we won't consider it */ | ||
315 | if ((orig_node->router) && | ||
316 | (orig_node->router->tq_avg > neigh_node->tq_avg)) | ||
317 | goto update_hna; | ||
318 | |||
319 | /* if the TQ is the same and the link not more symetric we | ||
320 | * won't consider it either */ | ||
321 | if ((orig_node->router) && | ||
322 | ((neigh_node->tq_avg == orig_node->router->tq_avg) && | ||
323 | (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] | ||
324 | >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num]))) | ||
325 | goto update_hna; | ||
326 | |||
327 | update_routes(bat_priv, orig_node, neigh_node, | ||
328 | hna_buff, tmp_hna_buff_len); | ||
329 | goto update_gw; | ||
330 | |||
331 | update_hna: | ||
332 | update_routes(bat_priv, orig_node, orig_node->router, | ||
333 | hna_buff, tmp_hna_buff_len); | ||
334 | |||
335 | update_gw: | ||
336 | if (orig_node->gw_flags != batman_packet->gw_flags) | ||
337 | gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); | ||
338 | |||
339 | orig_node->gw_flags = batman_packet->gw_flags; | ||
340 | |||
341 | /* restart gateway selection if fast or late switching was enabled */ | ||
342 | if ((orig_node->gw_flags) && | ||
343 | (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) && | ||
344 | (atomic_read(&bat_priv->gw_sel_class) > 2)) | ||
345 | gw_check_election(bat_priv, orig_node); | ||
346 | } | ||
347 | |||
348 | /* checks whether the host restarted and is in the protection time. | ||
349 | * returns: | ||
350 | * 0 if the packet is to be accepted | ||
351 | * 1 if the packet is to be ignored. | ||
352 | */ | ||
353 | static int window_protected(struct bat_priv *bat_priv, | ||
354 | int32_t seq_num_diff, | ||
355 | unsigned long *last_reset) | ||
356 | { | ||
357 | if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) | ||
358 | || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { | ||
359 | if (time_after(jiffies, *last_reset + | ||
360 | msecs_to_jiffies(RESET_PROTECTION_MS))) { | ||
361 | |||
362 | *last_reset = jiffies; | ||
363 | bat_dbg(DBG_BATMAN, bat_priv, | ||
364 | "old packet received, start protection\n"); | ||
365 | |||
366 | return 0; | ||
367 | } else | ||
368 | return 1; | ||
369 | } | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | /* processes a batman packet for all interfaces, adjusts the sequence number and | ||
374 | * finds out whether it is a duplicate. | ||
375 | * returns: | ||
376 | * 1 the packet is a duplicate | ||
377 | * 0 the packet has not yet been received | ||
378 | * -1 the packet is old and has been received while the seqno window | ||
379 | * was protected. Caller should drop it. | ||
380 | */ | ||
381 | static char count_real_packets(struct ethhdr *ethhdr, | ||
382 | struct batman_packet *batman_packet, | ||
383 | struct batman_if *if_incoming) | ||
384 | { | ||
385 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
386 | struct orig_node *orig_node; | ||
387 | struct neigh_node *tmp_neigh_node; | ||
388 | char is_duplicate = 0; | ||
389 | int32_t seq_diff; | ||
390 | int need_update = 0; | ||
391 | int set_mark; | ||
392 | |||
393 | orig_node = get_orig_node(bat_priv, batman_packet->orig); | ||
394 | if (!orig_node) | ||
395 | return 0; | ||
396 | |||
397 | seq_diff = batman_packet->seqno - orig_node->last_real_seqno; | ||
398 | |||
399 | /* signalize caller that the packet is to be dropped. */ | ||
400 | if (window_protected(bat_priv, seq_diff, | ||
401 | &orig_node->batman_seqno_reset)) | ||
402 | return -1; | ||
403 | |||
404 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
405 | |||
406 | is_duplicate |= get_bit_status(tmp_neigh_node->real_bits, | ||
407 | orig_node->last_real_seqno, | ||
408 | batman_packet->seqno); | ||
409 | |||
410 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && | ||
411 | (tmp_neigh_node->if_incoming == if_incoming)) | ||
412 | set_mark = 1; | ||
413 | else | ||
414 | set_mark = 0; | ||
415 | |||
416 | /* if the window moved, set the update flag. */ | ||
417 | need_update |= bit_get_packet(bat_priv, | ||
418 | tmp_neigh_node->real_bits, | ||
419 | seq_diff, set_mark); | ||
420 | |||
421 | tmp_neigh_node->real_packet_count = | ||
422 | bit_packet_count(tmp_neigh_node->real_bits); | ||
423 | } | ||
424 | |||
425 | if (need_update) { | ||
426 | bat_dbg(DBG_BATMAN, bat_priv, | ||
427 | "updating last_seqno: old %d, new %d\n", | ||
428 | orig_node->last_real_seqno, batman_packet->seqno); | ||
429 | orig_node->last_real_seqno = batman_packet->seqno; | ||
430 | } | ||
431 | |||
432 | return is_duplicate; | ||
433 | } | ||
434 | |||
435 | /* copy primary address for bonding */ | ||
436 | static void mark_bonding_address(struct bat_priv *bat_priv, | ||
437 | struct orig_node *orig_node, | ||
438 | struct orig_node *orig_neigh_node, | ||
439 | struct batman_packet *batman_packet) | ||
440 | |||
441 | { | ||
442 | if (batman_packet->flags & PRIMARIES_FIRST_HOP) | ||
443 | memcpy(orig_neigh_node->primary_addr, | ||
444 | orig_node->orig, ETH_ALEN); | ||
445 | |||
446 | return; | ||
447 | } | ||
448 | |||
449 | /* mark possible bond.candidates in the neighbor list */ | ||
450 | void update_bonding_candidates(struct bat_priv *bat_priv, | ||
451 | struct orig_node *orig_node) | ||
452 | { | ||
453 | int candidates; | ||
454 | int interference_candidate; | ||
455 | int best_tq; | ||
456 | struct neigh_node *tmp_neigh_node, *tmp_neigh_node2; | ||
457 | struct neigh_node *first_candidate, *last_candidate; | ||
458 | |||
459 | /* update the candidates for this originator */ | ||
460 | if (!orig_node->router) { | ||
461 | orig_node->bond.candidates = 0; | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | best_tq = orig_node->router->tq_avg; | ||
466 | |||
467 | /* update bond.candidates */ | ||
468 | |||
469 | candidates = 0; | ||
470 | |||
471 | /* mark other nodes which also received "PRIMARIES FIRST HOP" packets | ||
472 | * as "bonding partner" */ | ||
473 | |||
474 | /* first, zero the list */ | ||
475 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
476 | tmp_neigh_node->next_bond_candidate = NULL; | ||
477 | } | ||
478 | |||
479 | first_candidate = NULL; | ||
480 | last_candidate = NULL; | ||
481 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
482 | |||
483 | /* only consider if it has the same primary address ... */ | ||
484 | if (memcmp(orig_node->orig, | ||
485 | tmp_neigh_node->orig_node->primary_addr, | ||
486 | ETH_ALEN) != 0) | ||
487 | continue; | ||
488 | |||
489 | /* ... and is good enough to be considered */ | ||
490 | if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD) | ||
491 | continue; | ||
492 | |||
493 | /* check if we have another candidate with the same | ||
494 | * mac address or interface. If we do, we won't | ||
495 | * select this candidate because of possible interference. */ | ||
496 | |||
497 | interference_candidate = 0; | ||
498 | list_for_each_entry(tmp_neigh_node2, | ||
499 | &orig_node->neigh_list, list) { | ||
500 | |||
501 | if (tmp_neigh_node2 == tmp_neigh_node) | ||
502 | continue; | ||
503 | |||
504 | /* we only care if the other candidate is even | ||
505 | * considered as candidate. */ | ||
506 | if (!tmp_neigh_node2->next_bond_candidate) | ||
507 | continue; | ||
508 | |||
509 | |||
510 | if ((tmp_neigh_node->if_incoming == | ||
511 | tmp_neigh_node2->if_incoming) | ||
512 | || (memcmp(tmp_neigh_node->addr, | ||
513 | tmp_neigh_node2->addr, ETH_ALEN) == 0)) { | ||
514 | |||
515 | interference_candidate = 1; | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | /* don't care further if it is an interference candidate */ | ||
520 | if (interference_candidate) | ||
521 | continue; | ||
522 | |||
523 | if (!first_candidate) { | ||
524 | first_candidate = tmp_neigh_node; | ||
525 | tmp_neigh_node->next_bond_candidate = first_candidate; | ||
526 | } else | ||
527 | tmp_neigh_node->next_bond_candidate = last_candidate; | ||
528 | |||
529 | last_candidate = tmp_neigh_node; | ||
530 | |||
531 | candidates++; | ||
532 | } | ||
533 | |||
534 | if (candidates > 0) { | ||
535 | first_candidate->next_bond_candidate = last_candidate; | ||
536 | orig_node->bond.selected = first_candidate; | ||
537 | } | ||
538 | |||
539 | orig_node->bond.candidates = candidates; | ||
540 | } | ||
541 | |||
542 | void receive_bat_packet(struct ethhdr *ethhdr, | ||
543 | struct batman_packet *batman_packet, | ||
544 | unsigned char *hna_buff, int hna_buff_len, | ||
545 | struct batman_if *if_incoming) | ||
546 | { | ||
547 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
548 | struct batman_if *batman_if; | ||
549 | struct orig_node *orig_neigh_node, *orig_node; | ||
550 | char has_directlink_flag; | ||
551 | char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; | ||
552 | char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; | ||
553 | char is_duplicate; | ||
554 | uint32_t if_incoming_seqno; | ||
555 | |||
556 | /* Silently drop when the batman packet is actually not a | ||
557 | * correct packet. | ||
558 | * | ||
559 | * This might happen if a packet is padded (e.g. Ethernet has a | ||
560 | * minimum frame length of 64 byte) and the aggregation interprets | ||
561 | * it as an additional length. | ||
562 | * | ||
563 | * TODO: A more sane solution would be to have a bit in the | ||
564 | * batman_packet to detect whether the packet is the last | ||
565 | * packet in an aggregation. Here we expect that the padding | ||
566 | * is always zero (or not 0x01) | ||
567 | */ | ||
568 | if (batman_packet->packet_type != BAT_PACKET) | ||
569 | return; | ||
570 | |||
571 | /* could be changed by schedule_own_packet() */ | ||
572 | if_incoming_seqno = atomic_read(&if_incoming->seqno); | ||
573 | |||
574 | has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0); | ||
575 | |||
576 | is_single_hop_neigh = (compare_orig(ethhdr->h_source, | ||
577 | batman_packet->orig) ? 1 : 0); | ||
578 | |||
579 | bat_dbg(DBG_BATMAN, bat_priv, | ||
580 | "Received BATMAN packet via NB: %pM, IF: %s [%pM] " | ||
581 | "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, " | ||
582 | "TTL %d, V %d, IDF %d)\n", | ||
583 | ethhdr->h_source, if_incoming->net_dev->name, | ||
584 | if_incoming->net_dev->dev_addr, batman_packet->orig, | ||
585 | batman_packet->prev_sender, batman_packet->seqno, | ||
586 | batman_packet->tq, batman_packet->ttl, batman_packet->version, | ||
587 | has_directlink_flag); | ||
588 | |||
589 | rcu_read_lock(); | ||
590 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
591 | if (batman_if->if_status != IF_ACTIVE) | ||
592 | continue; | ||
593 | |||
594 | if (batman_if->soft_iface != if_incoming->soft_iface) | ||
595 | continue; | ||
596 | |||
597 | if (compare_orig(ethhdr->h_source, | ||
598 | batman_if->net_dev->dev_addr)) | ||
599 | is_my_addr = 1; | ||
600 | |||
601 | if (compare_orig(batman_packet->orig, | ||
602 | batman_if->net_dev->dev_addr)) | ||
603 | is_my_orig = 1; | ||
604 | |||
605 | if (compare_orig(batman_packet->prev_sender, | ||
606 | batman_if->net_dev->dev_addr)) | ||
607 | is_my_oldorig = 1; | ||
608 | |||
609 | if (compare_orig(ethhdr->h_source, broadcast_addr)) | ||
610 | is_broadcast = 1; | ||
611 | } | ||
612 | rcu_read_unlock(); | ||
613 | |||
614 | if (batman_packet->version != COMPAT_VERSION) { | ||
615 | bat_dbg(DBG_BATMAN, bat_priv, | ||
616 | "Drop packet: incompatible batman version (%i)\n", | ||
617 | batman_packet->version); | ||
618 | return; | ||
619 | } | ||
620 | |||
621 | if (is_my_addr) { | ||
622 | bat_dbg(DBG_BATMAN, bat_priv, | ||
623 | "Drop packet: received my own broadcast (sender: %pM" | ||
624 | ")\n", | ||
625 | ethhdr->h_source); | ||
626 | return; | ||
627 | } | ||
628 | |||
629 | if (is_broadcast) { | ||
630 | bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " | ||
631 | "ignoring all packets with broadcast source addr (sender: %pM" | ||
632 | ")\n", ethhdr->h_source); | ||
633 | return; | ||
634 | } | ||
635 | |||
636 | if (is_my_orig) { | ||
637 | unsigned long *word; | ||
638 | int offset; | ||
639 | |||
640 | orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source); | ||
641 | |||
642 | if (!orig_neigh_node) | ||
643 | return; | ||
644 | |||
645 | /* neighbor has to indicate direct link and it has to | ||
646 | * come via the corresponding interface */ | ||
647 | /* if received seqno equals last send seqno save new | ||
648 | * seqno for bidirectional check */ | ||
649 | if (has_directlink_flag && | ||
650 | compare_orig(if_incoming->net_dev->dev_addr, | ||
651 | batman_packet->orig) && | ||
652 | (batman_packet->seqno - if_incoming_seqno + 2 == 0)) { | ||
653 | offset = if_incoming->if_num * NUM_WORDS; | ||
654 | word = &(orig_neigh_node->bcast_own[offset]); | ||
655 | bit_mark(word, 0); | ||
656 | orig_neigh_node->bcast_own_sum[if_incoming->if_num] = | ||
657 | bit_packet_count(word); | ||
658 | } | ||
659 | |||
660 | bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " | ||
661 | "originator packet from myself (via neighbor)\n"); | ||
662 | return; | ||
663 | } | ||
664 | |||
665 | if (is_my_oldorig) { | ||
666 | bat_dbg(DBG_BATMAN, bat_priv, | ||
667 | "Drop packet: ignoring all rebroadcast echos (sender: " | ||
668 | "%pM)\n", ethhdr->h_source); | ||
669 | return; | ||
670 | } | ||
671 | |||
672 | orig_node = get_orig_node(bat_priv, batman_packet->orig); | ||
673 | if (!orig_node) | ||
674 | return; | ||
675 | |||
676 | is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming); | ||
677 | |||
678 | if (is_duplicate == -1) { | ||
679 | bat_dbg(DBG_BATMAN, bat_priv, | ||
680 | "Drop packet: packet within seqno protection time " | ||
681 | "(sender: %pM)\n", ethhdr->h_source); | ||
682 | return; | ||
683 | } | ||
684 | |||
685 | if (batman_packet->tq == 0) { | ||
686 | bat_dbg(DBG_BATMAN, bat_priv, | ||
687 | "Drop packet: originator packet with tq equal 0\n"); | ||
688 | return; | ||
689 | } | ||
690 | |||
691 | /* avoid temporary routing loops */ | ||
692 | if ((orig_node->router) && | ||
693 | (orig_node->router->orig_node->router) && | ||
694 | (compare_orig(orig_node->router->addr, | ||
695 | batman_packet->prev_sender)) && | ||
696 | !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) && | ||
697 | (compare_orig(orig_node->router->addr, | ||
698 | orig_node->router->orig_node->router->addr))) { | ||
699 | bat_dbg(DBG_BATMAN, bat_priv, | ||
700 | "Drop packet: ignoring all rebroadcast packets that " | ||
701 | "may make me loop (sender: %pM)\n", ethhdr->h_source); | ||
702 | return; | ||
703 | } | ||
704 | |||
705 | /* if sender is a direct neighbor the sender mac equals | ||
706 | * originator mac */ | ||
707 | orig_neigh_node = (is_single_hop_neigh ? | ||
708 | orig_node : | ||
709 | get_orig_node(bat_priv, ethhdr->h_source)); | ||
710 | if (!orig_neigh_node) | ||
711 | return; | ||
712 | |||
713 | /* drop packet if sender is not a direct neighbor and if we | ||
714 | * don't route towards it */ | ||
715 | if (!is_single_hop_neigh && (!orig_neigh_node->router)) { | ||
716 | bat_dbg(DBG_BATMAN, bat_priv, | ||
717 | "Drop packet: OGM via unknown neighbor!\n"); | ||
718 | return; | ||
719 | } | ||
720 | |||
721 | is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node, | ||
722 | batman_packet, if_incoming); | ||
723 | |||
724 | /* update ranking if it is not a duplicate or has the same | ||
725 | * seqno and similar ttl as the non-duplicate */ | ||
726 | if (is_bidirectional && | ||
727 | (!is_duplicate || | ||
728 | ((orig_node->last_real_seqno == batman_packet->seqno) && | ||
729 | (orig_node->last_ttl - 3 <= batman_packet->ttl)))) | ||
730 | update_orig(bat_priv, orig_node, ethhdr, batman_packet, | ||
731 | if_incoming, hna_buff, hna_buff_len, is_duplicate); | ||
732 | |||
733 | mark_bonding_address(bat_priv, orig_node, | ||
734 | orig_neigh_node, batman_packet); | ||
735 | update_bonding_candidates(bat_priv, orig_node); | ||
736 | |||
737 | /* is single hop (direct) neighbor */ | ||
738 | if (is_single_hop_neigh) { | ||
739 | |||
740 | /* mark direct link on incoming interface */ | ||
741 | schedule_forward_packet(orig_node, ethhdr, batman_packet, | ||
742 | 1, hna_buff_len, if_incoming); | ||
743 | |||
744 | bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " | ||
745 | "rebroadcast neighbor packet with direct link flag\n"); | ||
746 | return; | ||
747 | } | ||
748 | |||
749 | /* multihop originator */ | ||
750 | if (!is_bidirectional) { | ||
751 | bat_dbg(DBG_BATMAN, bat_priv, | ||
752 | "Drop packet: not received via bidirectional link\n"); | ||
753 | return; | ||
754 | } | ||
755 | |||
756 | if (is_duplicate) { | ||
757 | bat_dbg(DBG_BATMAN, bat_priv, | ||
758 | "Drop packet: duplicate packet received\n"); | ||
759 | return; | ||
760 | } | ||
761 | |||
762 | bat_dbg(DBG_BATMAN, bat_priv, | ||
763 | "Forwarding packet: rebroadcast originator packet\n"); | ||
764 | schedule_forward_packet(orig_node, ethhdr, batman_packet, | ||
765 | 0, hna_buff_len, if_incoming); | ||
766 | } | ||
767 | |||
768 | int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) | ||
769 | { | ||
770 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
771 | struct ethhdr *ethhdr; | ||
772 | |||
773 | /* drop packet if it has not necessary minimum size */ | ||
774 | if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet)))) | ||
775 | return NET_RX_DROP; | ||
776 | |||
777 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
778 | |||
779 | /* packet with broadcast indication but unicast recipient */ | ||
780 | if (!is_broadcast_ether_addr(ethhdr->h_dest)) | ||
781 | return NET_RX_DROP; | ||
782 | |||
783 | /* packet with broadcast sender address */ | ||
784 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
785 | return NET_RX_DROP; | ||
786 | |||
787 | /* create a copy of the skb, if needed, to modify it. */ | ||
788 | if (skb_cow(skb, 0) < 0) | ||
789 | return NET_RX_DROP; | ||
790 | |||
791 | /* keep skb linear */ | ||
792 | if (skb_linearize(skb) < 0) | ||
793 | return NET_RX_DROP; | ||
794 | |||
795 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
796 | |||
797 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
798 | receive_aggr_bat_packet(ethhdr, | ||
799 | skb->data, | ||
800 | skb_headlen(skb), | ||
801 | batman_if); | ||
802 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
803 | |||
804 | kfree_skb(skb); | ||
805 | return NET_RX_SUCCESS; | ||
806 | } | ||
807 | |||
808 | static int recv_my_icmp_packet(struct bat_priv *bat_priv, | ||
809 | struct sk_buff *skb, size_t icmp_len) | ||
810 | { | ||
811 | struct orig_node *orig_node; | ||
812 | struct icmp_packet_rr *icmp_packet; | ||
813 | struct ethhdr *ethhdr; | ||
814 | struct batman_if *batman_if; | ||
815 | int ret; | ||
816 | uint8_t dstaddr[ETH_ALEN]; | ||
817 | |||
818 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
819 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
820 | |||
821 | /* add data to device queue */ | ||
822 | if (icmp_packet->msg_type != ECHO_REQUEST) { | ||
823 | bat_socket_receive_packet(icmp_packet, icmp_len); | ||
824 | return NET_RX_DROP; | ||
825 | } | ||
826 | |||
827 | if (!bat_priv->primary_if) | ||
828 | return NET_RX_DROP; | ||
829 | |||
830 | /* answer echo request (ping) */ | ||
831 | /* get routing information */ | ||
832 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
833 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
834 | compare_orig, choose_orig, | ||
835 | icmp_packet->orig)); | ||
836 | ret = NET_RX_DROP; | ||
837 | |||
838 | if ((orig_node) && (orig_node->router)) { | ||
839 | |||
840 | /* don't lock while sending the packets ... we therefore | ||
841 | * copy the required data before sending */ | ||
842 | batman_if = orig_node->router->if_incoming; | ||
843 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
844 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
845 | |||
846 | /* create a copy of the skb, if needed, to modify it. */ | ||
847 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | ||
848 | return NET_RX_DROP; | ||
849 | |||
850 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
851 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
852 | |||
853 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | ||
854 | memcpy(icmp_packet->orig, | ||
855 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
856 | icmp_packet->msg_type = ECHO_REPLY; | ||
857 | icmp_packet->ttl = TTL; | ||
858 | |||
859 | send_skb_packet(skb, batman_if, dstaddr); | ||
860 | ret = NET_RX_SUCCESS; | ||
861 | |||
862 | } else | ||
863 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
864 | |||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | ||
869 | struct sk_buff *skb, size_t icmp_len) | ||
870 | { | ||
871 | struct orig_node *orig_node; | ||
872 | struct icmp_packet *icmp_packet; | ||
873 | struct ethhdr *ethhdr; | ||
874 | struct batman_if *batman_if; | ||
875 | int ret; | ||
876 | uint8_t dstaddr[ETH_ALEN]; | ||
877 | |||
878 | icmp_packet = (struct icmp_packet *)skb->data; | ||
879 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
880 | |||
881 | /* send TTL exceeded if packet is an echo request (traceroute) */ | ||
882 | if (icmp_packet->msg_type != ECHO_REQUEST) { | ||
883 | pr_debug("Warning - can't forward icmp packet from %pM to " | ||
884 | "%pM: ttl exceeded\n", icmp_packet->orig, | ||
885 | icmp_packet->dst); | ||
886 | return NET_RX_DROP; | ||
887 | } | ||
888 | |||
889 | if (!bat_priv->primary_if) | ||
890 | return NET_RX_DROP; | ||
891 | |||
892 | /* get routing information */ | ||
893 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
894 | orig_node = ((struct orig_node *) | ||
895 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
896 | icmp_packet->orig)); | ||
897 | ret = NET_RX_DROP; | ||
898 | |||
899 | if ((orig_node) && (orig_node->router)) { | ||
900 | |||
901 | /* don't lock while sending the packets ... we therefore | ||
902 | * copy the required data before sending */ | ||
903 | batman_if = orig_node->router->if_incoming; | ||
904 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
905 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
906 | |||
907 | /* create a copy of the skb, if needed, to modify it. */ | ||
908 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | ||
909 | return NET_RX_DROP; | ||
910 | |||
911 | icmp_packet = (struct icmp_packet *) skb->data; | ||
912 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
913 | |||
914 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | ||
915 | memcpy(icmp_packet->orig, | ||
916 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
917 | icmp_packet->msg_type = TTL_EXCEEDED; | ||
918 | icmp_packet->ttl = TTL; | ||
919 | |||
920 | send_skb_packet(skb, batman_if, dstaddr); | ||
921 | ret = NET_RX_SUCCESS; | ||
922 | |||
923 | } else | ||
924 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
925 | |||
926 | return ret; | ||
927 | } | ||
928 | |||
929 | |||
930 | int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
931 | { | ||
932 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
933 | struct icmp_packet_rr *icmp_packet; | ||
934 | struct ethhdr *ethhdr; | ||
935 | struct orig_node *orig_node; | ||
936 | struct batman_if *batman_if; | ||
937 | int hdr_size = sizeof(struct icmp_packet); | ||
938 | int ret; | ||
939 | uint8_t dstaddr[ETH_ALEN]; | ||
940 | |||
941 | /** | ||
942 | * we truncate all incoming icmp packets if they don't match our size | ||
943 | */ | ||
944 | if (skb->len >= sizeof(struct icmp_packet_rr)) | ||
945 | hdr_size = sizeof(struct icmp_packet_rr); | ||
946 | |||
947 | /* drop packet if it has not necessary minimum size */ | ||
948 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
949 | return NET_RX_DROP; | ||
950 | |||
951 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
952 | |||
953 | /* packet with unicast indication but broadcast recipient */ | ||
954 | if (is_broadcast_ether_addr(ethhdr->h_dest)) | ||
955 | return NET_RX_DROP; | ||
956 | |||
957 | /* packet with broadcast sender address */ | ||
958 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
959 | return NET_RX_DROP; | ||
960 | |||
961 | /* not for me */ | ||
962 | if (!is_my_mac(ethhdr->h_dest)) | ||
963 | return NET_RX_DROP; | ||
964 | |||
965 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
966 | |||
967 | /* add record route information if not full */ | ||
968 | if ((hdr_size == sizeof(struct icmp_packet_rr)) && | ||
969 | (icmp_packet->rr_cur < BAT_RR_LEN)) { | ||
970 | memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), | ||
971 | ethhdr->h_dest, ETH_ALEN); | ||
972 | icmp_packet->rr_cur++; | ||
973 | } | ||
974 | |||
975 | /* packet for me */ | ||
976 | if (is_my_mac(icmp_packet->dst)) | ||
977 | return recv_my_icmp_packet(bat_priv, skb, hdr_size); | ||
978 | |||
979 | /* TTL exceeded */ | ||
980 | if (icmp_packet->ttl < 2) | ||
981 | return recv_icmp_ttl_exceeded(bat_priv, skb, hdr_size); | ||
982 | |||
983 | ret = NET_RX_DROP; | ||
984 | |||
985 | /* get routing information */ | ||
986 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
987 | orig_node = ((struct orig_node *) | ||
988 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
989 | icmp_packet->dst)); | ||
990 | |||
991 | if ((orig_node) && (orig_node->router)) { | ||
992 | |||
993 | /* don't lock while sending the packets ... we therefore | ||
994 | * copy the required data before sending */ | ||
995 | batman_if = orig_node->router->if_incoming; | ||
996 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
997 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
998 | |||
999 | /* create a copy of the skb, if needed, to modify it. */ | ||
1000 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | ||
1001 | return NET_RX_DROP; | ||
1002 | |||
1003 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
1004 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1005 | |||
1006 | /* decrement ttl */ | ||
1007 | icmp_packet->ttl--; | ||
1008 | |||
1009 | /* route it */ | ||
1010 | send_skb_packet(skb, batman_if, dstaddr); | ||
1011 | ret = NET_RX_SUCCESS; | ||
1012 | |||
1013 | } else | ||
1014 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1015 | |||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | /* find a suitable router for this originator, and use | ||
1020 | * bonding if possible. */ | ||
1021 | struct neigh_node *find_router(struct bat_priv *bat_priv, | ||
1022 | struct orig_node *orig_node, | ||
1023 | struct batman_if *recv_if) | ||
1024 | { | ||
1025 | struct orig_node *primary_orig_node; | ||
1026 | struct orig_node *router_orig; | ||
1027 | struct neigh_node *router, *first_candidate, *best_router; | ||
1028 | static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; | ||
1029 | int bonding_enabled; | ||
1030 | |||
1031 | if (!orig_node) | ||
1032 | return NULL; | ||
1033 | |||
1034 | if (!orig_node->router) | ||
1035 | return NULL; | ||
1036 | |||
1037 | /* without bonding, the first node should | ||
1038 | * always choose the default router. */ | ||
1039 | |||
1040 | bonding_enabled = atomic_read(&bat_priv->bonding); | ||
1041 | |||
1042 | if ((!recv_if) && (!bonding_enabled)) | ||
1043 | return orig_node->router; | ||
1044 | |||
1045 | router_orig = orig_node->router->orig_node; | ||
1046 | |||
1047 | /* if we have something in the primary_addr, we can search | ||
1048 | * for a potential bonding candidate. */ | ||
1049 | if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0) | ||
1050 | return orig_node->router; | ||
1051 | |||
1052 | /* find the orig_node which has the primary interface. might | ||
1053 | * even be the same as our router_orig in many cases */ | ||
1054 | |||
1055 | if (memcmp(router_orig->primary_addr, | ||
1056 | router_orig->orig, ETH_ALEN) == 0) { | ||
1057 | primary_orig_node = router_orig; | ||
1058 | } else { | ||
1059 | primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig, | ||
1060 | choose_orig, | ||
1061 | router_orig->primary_addr); | ||
1062 | |||
1063 | if (!primary_orig_node) | ||
1064 | return orig_node->router; | ||
1065 | } | ||
1066 | |||
1067 | /* with less than 2 candidates, we can't do any | ||
1068 | * bonding and prefer the original router. */ | ||
1069 | |||
1070 | if (primary_orig_node->bond.candidates < 2) | ||
1071 | return orig_node->router; | ||
1072 | |||
1073 | |||
1074 | /* all nodes between should choose a candidate which | ||
1075 | * is is not on the interface where the packet came | ||
1076 | * in. */ | ||
1077 | first_candidate = primary_orig_node->bond.selected; | ||
1078 | router = first_candidate; | ||
1079 | |||
1080 | if (bonding_enabled) { | ||
1081 | /* in the bonding case, send the packets in a round | ||
1082 | * robin fashion over the remaining interfaces. */ | ||
1083 | do { | ||
1084 | /* recv_if == NULL on the first node. */ | ||
1085 | if (router->if_incoming != recv_if) | ||
1086 | break; | ||
1087 | |||
1088 | router = router->next_bond_candidate; | ||
1089 | } while (router != first_candidate); | ||
1090 | |||
1091 | primary_orig_node->bond.selected = router->next_bond_candidate; | ||
1092 | |||
1093 | } else { | ||
1094 | /* if bonding is disabled, use the best of the | ||
1095 | * remaining candidates which are not using | ||
1096 | * this interface. */ | ||
1097 | best_router = first_candidate; | ||
1098 | |||
1099 | do { | ||
1100 | /* recv_if == NULL on the first node. */ | ||
1101 | if ((router->if_incoming != recv_if) && | ||
1102 | (router->tq_avg > best_router->tq_avg)) | ||
1103 | best_router = router; | ||
1104 | |||
1105 | router = router->next_bond_candidate; | ||
1106 | } while (router != first_candidate); | ||
1107 | |||
1108 | router = best_router; | ||
1109 | } | ||
1110 | |||
1111 | return router; | ||
1112 | } | ||
1113 | |||
1114 | static int check_unicast_packet(struct sk_buff *skb, int hdr_size) | ||
1115 | { | ||
1116 | struct ethhdr *ethhdr; | ||
1117 | |||
1118 | /* drop packet if it has not necessary minimum size */ | ||
1119 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
1120 | return -1; | ||
1121 | |||
1122 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1123 | |||
1124 | /* packet with unicast indication but broadcast recipient */ | ||
1125 | if (is_broadcast_ether_addr(ethhdr->h_dest)) | ||
1126 | return -1; | ||
1127 | |||
1128 | /* packet with broadcast sender address */ | ||
1129 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
1130 | return -1; | ||
1131 | |||
1132 | /* not for me */ | ||
1133 | if (!is_my_mac(ethhdr->h_dest)) | ||
1134 | return -1; | ||
1135 | |||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | ||
1140 | int hdr_size) | ||
1141 | { | ||
1142 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1143 | struct orig_node *orig_node; | ||
1144 | struct neigh_node *router; | ||
1145 | struct batman_if *batman_if; | ||
1146 | uint8_t dstaddr[ETH_ALEN]; | ||
1147 | struct unicast_packet *unicast_packet; | ||
1148 | struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1149 | int ret; | ||
1150 | struct sk_buff *new_skb; | ||
1151 | |||
1152 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1153 | |||
1154 | /* TTL exceeded */ | ||
1155 | if (unicast_packet->ttl < 2) { | ||
1156 | pr_debug("Warning - can't forward unicast packet from %pM to " | ||
1157 | "%pM: ttl exceeded\n", ethhdr->h_source, | ||
1158 | unicast_packet->dest); | ||
1159 | return NET_RX_DROP; | ||
1160 | } | ||
1161 | |||
1162 | /* get routing information */ | ||
1163 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
1164 | orig_node = ((struct orig_node *) | ||
1165 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
1166 | unicast_packet->dest)); | ||
1167 | |||
1168 | router = find_router(bat_priv, orig_node, recv_if); | ||
1169 | |||
1170 | if (!router) { | ||
1171 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1172 | return NET_RX_DROP; | ||
1173 | } | ||
1174 | |||
1175 | /* don't lock while sending the packets ... we therefore | ||
1176 | * copy the required data before sending */ | ||
1177 | |||
1178 | batman_if = router->if_incoming; | ||
1179 | memcpy(dstaddr, router->addr, ETH_ALEN); | ||
1180 | |||
1181 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1182 | |||
1183 | /* create a copy of the skb, if needed, to modify it. */ | ||
1184 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | ||
1185 | return NET_RX_DROP; | ||
1186 | |||
1187 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1188 | |||
1189 | if (unicast_packet->packet_type == BAT_UNICAST && | ||
1190 | atomic_read(&bat_priv->fragmentation) && | ||
1191 | skb->len > batman_if->net_dev->mtu) | ||
1192 | return frag_send_skb(skb, bat_priv, batman_if, | ||
1193 | dstaddr); | ||
1194 | |||
1195 | if (unicast_packet->packet_type == BAT_UNICAST_FRAG && | ||
1196 | 2 * skb->len - hdr_size <= batman_if->net_dev->mtu) { | ||
1197 | |||
1198 | ret = frag_reassemble_skb(skb, bat_priv, &new_skb); | ||
1199 | |||
1200 | if (ret == NET_RX_DROP) | ||
1201 | return NET_RX_DROP; | ||
1202 | |||
1203 | /* packet was buffered for late merge */ | ||
1204 | if (!new_skb) | ||
1205 | return NET_RX_SUCCESS; | ||
1206 | |||
1207 | skb = new_skb; | ||
1208 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1209 | } | ||
1210 | |||
1211 | /* decrement ttl */ | ||
1212 | unicast_packet->ttl--; | ||
1213 | |||
1214 | /* route it */ | ||
1215 | send_skb_packet(skb, batman_if, dstaddr); | ||
1216 | |||
1217 | return NET_RX_SUCCESS; | ||
1218 | } | ||
1219 | |||
1220 | int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
1221 | { | ||
1222 | struct unicast_packet *unicast_packet; | ||
1223 | int hdr_size = sizeof(struct unicast_packet); | ||
1224 | |||
1225 | if (check_unicast_packet(skb, hdr_size) < 0) | ||
1226 | return NET_RX_DROP; | ||
1227 | |||
1228 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1229 | |||
1230 | /* packet for me */ | ||
1231 | if (is_my_mac(unicast_packet->dest)) { | ||
1232 | interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); | ||
1233 | return NET_RX_SUCCESS; | ||
1234 | } | ||
1235 | |||
1236 | return route_unicast_packet(skb, recv_if, hdr_size); | ||
1237 | } | ||
1238 | |||
1239 | int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
1240 | { | ||
1241 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1242 | struct unicast_frag_packet *unicast_packet; | ||
1243 | int hdr_size = sizeof(struct unicast_frag_packet); | ||
1244 | struct sk_buff *new_skb = NULL; | ||
1245 | int ret; | ||
1246 | |||
1247 | if (check_unicast_packet(skb, hdr_size) < 0) | ||
1248 | return NET_RX_DROP; | ||
1249 | |||
1250 | unicast_packet = (struct unicast_frag_packet *)skb->data; | ||
1251 | |||
1252 | /* packet for me */ | ||
1253 | if (is_my_mac(unicast_packet->dest)) { | ||
1254 | |||
1255 | ret = frag_reassemble_skb(skb, bat_priv, &new_skb); | ||
1256 | |||
1257 | if (ret == NET_RX_DROP) | ||
1258 | return NET_RX_DROP; | ||
1259 | |||
1260 | /* packet was buffered for late merge */ | ||
1261 | if (!new_skb) | ||
1262 | return NET_RX_SUCCESS; | ||
1263 | |||
1264 | interface_rx(recv_if->soft_iface, new_skb, recv_if, | ||
1265 | sizeof(struct unicast_packet)); | ||
1266 | return NET_RX_SUCCESS; | ||
1267 | } | ||
1268 | |||
1269 | return route_unicast_packet(skb, recv_if, hdr_size); | ||
1270 | } | ||
1271 | |||
1272 | |||
1273 | int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
1274 | { | ||
1275 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1276 | struct orig_node *orig_node; | ||
1277 | struct bcast_packet *bcast_packet; | ||
1278 | struct ethhdr *ethhdr; | ||
1279 | int hdr_size = sizeof(struct bcast_packet); | ||
1280 | int32_t seq_diff; | ||
1281 | |||
1282 | /* drop packet if it has not necessary minimum size */ | ||
1283 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
1284 | return NET_RX_DROP; | ||
1285 | |||
1286 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1287 | |||
1288 | /* packet with broadcast indication but unicast recipient */ | ||
1289 | if (!is_broadcast_ether_addr(ethhdr->h_dest)) | ||
1290 | return NET_RX_DROP; | ||
1291 | |||
1292 | /* packet with broadcast sender address */ | ||
1293 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
1294 | return NET_RX_DROP; | ||
1295 | |||
1296 | /* ignore broadcasts sent by myself */ | ||
1297 | if (is_my_mac(ethhdr->h_source)) | ||
1298 | return NET_RX_DROP; | ||
1299 | |||
1300 | bcast_packet = (struct bcast_packet *)skb->data; | ||
1301 | |||
1302 | /* ignore broadcasts originated by myself */ | ||
1303 | if (is_my_mac(bcast_packet->orig)) | ||
1304 | return NET_RX_DROP; | ||
1305 | |||
1306 | if (bcast_packet->ttl < 2) | ||
1307 | return NET_RX_DROP; | ||
1308 | |||
1309 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
1310 | orig_node = ((struct orig_node *) | ||
1311 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
1312 | bcast_packet->orig)); | ||
1313 | |||
1314 | if (!orig_node) { | ||
1315 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1316 | return NET_RX_DROP; | ||
1317 | } | ||
1318 | |||
1319 | /* check whether the packet is a duplicate */ | ||
1320 | if (get_bit_status(orig_node->bcast_bits, | ||
1321 | orig_node->last_bcast_seqno, | ||
1322 | ntohl(bcast_packet->seqno))) { | ||
1323 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1324 | return NET_RX_DROP; | ||
1325 | } | ||
1326 | |||
1327 | seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno; | ||
1328 | |||
1329 | /* check whether the packet is old and the host just restarted. */ | ||
1330 | if (window_protected(bat_priv, seq_diff, | ||
1331 | &orig_node->bcast_seqno_reset)) { | ||
1332 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1333 | return NET_RX_DROP; | ||
1334 | } | ||
1335 | |||
1336 | /* mark broadcast in flood history, update window position | ||
1337 | * if required. */ | ||
1338 | if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) | ||
1339 | orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno); | ||
1340 | |||
1341 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1342 | /* rebroadcast packet */ | ||
1343 | add_bcast_packet_to_list(bat_priv, skb); | ||
1344 | |||
1345 | /* broadcast for me */ | ||
1346 | interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); | ||
1347 | |||
1348 | return NET_RX_SUCCESS; | ||
1349 | } | ||
1350 | |||
1351 | int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
1352 | { | ||
1353 | struct vis_packet *vis_packet; | ||
1354 | struct ethhdr *ethhdr; | ||
1355 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1356 | int hdr_size = sizeof(struct vis_packet); | ||
1357 | |||
1358 | /* keep skb linear */ | ||
1359 | if (skb_linearize(skb) < 0) | ||
1360 | return NET_RX_DROP; | ||
1361 | |||
1362 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
1363 | return NET_RX_DROP; | ||
1364 | |||
1365 | vis_packet = (struct vis_packet *)skb->data; | ||
1366 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1367 | |||
1368 | /* not for me */ | ||
1369 | if (!is_my_mac(ethhdr->h_dest)) | ||
1370 | return NET_RX_DROP; | ||
1371 | |||
1372 | /* ignore own packets */ | ||
1373 | if (is_my_mac(vis_packet->vis_orig)) | ||
1374 | return NET_RX_DROP; | ||
1375 | |||
1376 | if (is_my_mac(vis_packet->sender_orig)) | ||
1377 | return NET_RX_DROP; | ||
1378 | |||
1379 | switch (vis_packet->vis_type) { | ||
1380 | case VIS_TYPE_SERVER_SYNC: | ||
1381 | receive_server_sync_packet(bat_priv, vis_packet, | ||
1382 | skb_headlen(skb)); | ||
1383 | break; | ||
1384 | |||
1385 | case VIS_TYPE_CLIENT_UPDATE: | ||
1386 | receive_client_update_packet(bat_priv, vis_packet, | ||
1387 | skb_headlen(skb)); | ||
1388 | break; | ||
1389 | |||
1390 | default: /* ignore unknown packet */ | ||
1391 | break; | ||
1392 | } | ||
1393 | |||
1394 | /* We take a copy of the data in the packet, so we should | ||
1395 | always free the skbuf. */ | ||
1396 | return NET_RX_DROP; | ||
1397 | } | ||
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h new file mode 100644 index 000000000000..f108f230bfdb --- /dev/null +++ b/net/batman-adv/routing.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_ROUTING_H_ | ||
23 | #define _NET_BATMAN_ADV_ROUTING_H_ | ||
24 | |||
25 | #include "types.h" | ||
26 | |||
27 | void slide_own_bcast_window(struct batman_if *batman_if); | ||
28 | void receive_bat_packet(struct ethhdr *ethhdr, | ||
29 | struct batman_packet *batman_packet, | ||
30 | unsigned char *hna_buff, int hna_buff_len, | ||
31 | struct batman_if *if_incoming); | ||
32 | void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, | ||
33 | struct neigh_node *neigh_node, unsigned char *hna_buff, | ||
34 | int hna_buff_len); | ||
35 | int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | ||
36 | int hdr_size); | ||
37 | int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
38 | int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
39 | int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
40 | int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
41 | int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
42 | int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
43 | struct neigh_node *find_router(struct bat_priv *bat_priv, | ||
44 | struct orig_node *orig_node, struct batman_if *recv_if); | ||
45 | void update_bonding_candidates(struct bat_priv *bat_priv, | ||
46 | struct orig_node *orig_node); | ||
47 | |||
48 | #endif /* _NET_BATMAN_ADV_ROUTING_H_ */ | ||
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c new file mode 100644 index 000000000000..b89b9f7709ae --- /dev/null +++ b/net/batman-adv/send.c | |||
@@ -0,0 +1,585 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 "routing.h" | ||
25 | #include "translation-table.h" | ||
26 | #include "soft-interface.h" | ||
27 | #include "hard-interface.h" | ||
28 | #include "types.h" | ||
29 | #include "vis.h" | ||
30 | #include "aggregation.h" | ||
31 | #include "gateway_common.h" | ||
32 | #include "originator.h" | ||
33 | |||
34 | static void send_outstanding_bcast_packet(struct work_struct *work); | ||
35 | |||
36 | /* apply hop penalty for a normal link */ | ||
37 | static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv) | ||
38 | { | ||
39 | int hop_penalty = atomic_read(&bat_priv->hop_penalty); | ||
40 | return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE); | ||
41 | } | ||
42 | |||
43 | /* when do we schedule our own packet to be sent */ | ||
44 | static unsigned long own_send_time(struct bat_priv *bat_priv) | ||
45 | { | ||
46 | return jiffies + msecs_to_jiffies( | ||
47 | atomic_read(&bat_priv->orig_interval) - | ||
48 | JITTER + (random32() % 2*JITTER)); | ||
49 | } | ||
50 | |||
51 | /* when do we schedule a forwarded packet to be sent */ | ||
52 | static unsigned long forward_send_time(struct bat_priv *bat_priv) | ||
53 | { | ||
54 | return jiffies + msecs_to_jiffies(random32() % (JITTER/2)); | ||
55 | } | ||
56 | |||
57 | /* send out an already prepared packet to the given address via the | ||
58 | * specified batman interface */ | ||
59 | int send_skb_packet(struct sk_buff *skb, | ||
60 | struct batman_if *batman_if, | ||
61 | uint8_t *dst_addr) | ||
62 | { | ||
63 | struct ethhdr *ethhdr; | ||
64 | |||
65 | if (batman_if->if_status != IF_ACTIVE) | ||
66 | goto send_skb_err; | ||
67 | |||
68 | if (unlikely(!batman_if->net_dev)) | ||
69 | goto send_skb_err; | ||
70 | |||
71 | if (!(batman_if->net_dev->flags & IFF_UP)) { | ||
72 | pr_warning("Interface %s is not up - can't send packet via " | ||
73 | "that interface!\n", batman_if->net_dev->name); | ||
74 | goto send_skb_err; | ||
75 | } | ||
76 | |||
77 | /* push to the ethernet header. */ | ||
78 | if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0) | ||
79 | goto send_skb_err; | ||
80 | |||
81 | skb_reset_mac_header(skb); | ||
82 | |||
83 | ethhdr = (struct ethhdr *) skb_mac_header(skb); | ||
84 | memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN); | ||
85 | memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); | ||
86 | ethhdr->h_proto = __constant_htons(ETH_P_BATMAN); | ||
87 | |||
88 | skb_set_network_header(skb, ETH_HLEN); | ||
89 | skb->priority = TC_PRIO_CONTROL; | ||
90 | skb->protocol = __constant_htons(ETH_P_BATMAN); | ||
91 | |||
92 | skb->dev = batman_if->net_dev; | ||
93 | |||
94 | /* dev_queue_xmit() returns a negative result on error. However on | ||
95 | * congestion and traffic shaping, it drops and returns NET_XMIT_DROP | ||
96 | * (which is > 0). This will not be treated as an error. */ | ||
97 | |||
98 | return dev_queue_xmit(skb); | ||
99 | send_skb_err: | ||
100 | kfree_skb(skb); | ||
101 | return NET_XMIT_DROP; | ||
102 | } | ||
103 | |||
104 | /* Send a packet to a given interface */ | ||
105 | static void send_packet_to_if(struct forw_packet *forw_packet, | ||
106 | struct batman_if *batman_if) | ||
107 | { | ||
108 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
109 | char *fwd_str; | ||
110 | uint8_t packet_num; | ||
111 | int16_t buff_pos; | ||
112 | struct batman_packet *batman_packet; | ||
113 | struct sk_buff *skb; | ||
114 | |||
115 | if (batman_if->if_status != IF_ACTIVE) | ||
116 | return; | ||
117 | |||
118 | packet_num = 0; | ||
119 | buff_pos = 0; | ||
120 | batman_packet = (struct batman_packet *)forw_packet->skb->data; | ||
121 | |||
122 | /* adjust all flags and log packets */ | ||
123 | while (aggregated_packet(buff_pos, | ||
124 | forw_packet->packet_len, | ||
125 | batman_packet->num_hna)) { | ||
126 | |||
127 | /* we might have aggregated direct link packets with an | ||
128 | * ordinary base packet */ | ||
129 | if ((forw_packet->direct_link_flags & (1 << packet_num)) && | ||
130 | (forw_packet->if_incoming == batman_if)) | ||
131 | batman_packet->flags |= DIRECTLINK; | ||
132 | else | ||
133 | batman_packet->flags &= ~DIRECTLINK; | ||
134 | |||
135 | fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ? | ||
136 | "Sending own" : | ||
137 | "Forwarding")); | ||
138 | bat_dbg(DBG_BATMAN, bat_priv, | ||
139 | "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d," | ||
140 | " IDF %s) on interface %s [%pM]\n", | ||
141 | fwd_str, (packet_num > 0 ? "aggregated " : ""), | ||
142 | batman_packet->orig, ntohl(batman_packet->seqno), | ||
143 | batman_packet->tq, batman_packet->ttl, | ||
144 | (batman_packet->flags & DIRECTLINK ? | ||
145 | "on" : "off"), | ||
146 | batman_if->net_dev->name, batman_if->net_dev->dev_addr); | ||
147 | |||
148 | buff_pos += sizeof(struct batman_packet) + | ||
149 | (batman_packet->num_hna * ETH_ALEN); | ||
150 | packet_num++; | ||
151 | batman_packet = (struct batman_packet *) | ||
152 | (forw_packet->skb->data + buff_pos); | ||
153 | } | ||
154 | |||
155 | /* create clone because function is called more than once */ | ||
156 | skb = skb_clone(forw_packet->skb, GFP_ATOMIC); | ||
157 | if (skb) | ||
158 | send_skb_packet(skb, batman_if, broadcast_addr); | ||
159 | } | ||
160 | |||
161 | /* send a batman packet */ | ||
162 | static void send_packet(struct forw_packet *forw_packet) | ||
163 | { | ||
164 | struct batman_if *batman_if; | ||
165 | struct net_device *soft_iface; | ||
166 | struct bat_priv *bat_priv; | ||
167 | struct batman_packet *batman_packet = | ||
168 | (struct batman_packet *)(forw_packet->skb->data); | ||
169 | unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0); | ||
170 | |||
171 | if (!forw_packet->if_incoming) { | ||
172 | pr_err("Error - can't forward packet: incoming iface not " | ||
173 | "specified\n"); | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | soft_iface = forw_packet->if_incoming->soft_iface; | ||
178 | bat_priv = netdev_priv(soft_iface); | ||
179 | |||
180 | if (forw_packet->if_incoming->if_status != IF_ACTIVE) | ||
181 | return; | ||
182 | |||
183 | /* multihomed peer assumed */ | ||
184 | /* non-primary OGMs are only broadcasted on their interface */ | ||
185 | if ((directlink && (batman_packet->ttl == 1)) || | ||
186 | (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) { | ||
187 | |||
188 | /* FIXME: what about aggregated packets ? */ | ||
189 | bat_dbg(DBG_BATMAN, bat_priv, | ||
190 | "%s packet (originator %pM, seqno %d, TTL %d) " | ||
191 | "on interface %s [%pM]\n", | ||
192 | (forw_packet->own ? "Sending own" : "Forwarding"), | ||
193 | batman_packet->orig, ntohl(batman_packet->seqno), | ||
194 | batman_packet->ttl, | ||
195 | forw_packet->if_incoming->net_dev->name, | ||
196 | forw_packet->if_incoming->net_dev->dev_addr); | ||
197 | |||
198 | /* skb is only used once and than forw_packet is free'd */ | ||
199 | send_skb_packet(forw_packet->skb, forw_packet->if_incoming, | ||
200 | broadcast_addr); | ||
201 | forw_packet->skb = NULL; | ||
202 | |||
203 | return; | ||
204 | } | ||
205 | |||
206 | /* broadcast on every interface */ | ||
207 | rcu_read_lock(); | ||
208 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
209 | if (batman_if->soft_iface != soft_iface) | ||
210 | continue; | ||
211 | |||
212 | send_packet_to_if(forw_packet, batman_if); | ||
213 | } | ||
214 | rcu_read_unlock(); | ||
215 | } | ||
216 | |||
217 | static void rebuild_batman_packet(struct bat_priv *bat_priv, | ||
218 | struct batman_if *batman_if) | ||
219 | { | ||
220 | int new_len; | ||
221 | unsigned char *new_buff; | ||
222 | struct batman_packet *batman_packet; | ||
223 | |||
224 | new_len = sizeof(struct batman_packet) + | ||
225 | (bat_priv->num_local_hna * ETH_ALEN); | ||
226 | new_buff = kmalloc(new_len, GFP_ATOMIC); | ||
227 | |||
228 | /* keep old buffer if kmalloc should fail */ | ||
229 | if (new_buff) { | ||
230 | memcpy(new_buff, batman_if->packet_buff, | ||
231 | sizeof(struct batman_packet)); | ||
232 | batman_packet = (struct batman_packet *)new_buff; | ||
233 | |||
234 | batman_packet->num_hna = hna_local_fill_buffer(bat_priv, | ||
235 | new_buff + sizeof(struct batman_packet), | ||
236 | new_len - sizeof(struct batman_packet)); | ||
237 | |||
238 | kfree(batman_if->packet_buff); | ||
239 | batman_if->packet_buff = new_buff; | ||
240 | batman_if->packet_len = new_len; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | void schedule_own_packet(struct batman_if *batman_if) | ||
245 | { | ||
246 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
247 | unsigned long send_time; | ||
248 | struct batman_packet *batman_packet; | ||
249 | int vis_server; | ||
250 | |||
251 | if ((batman_if->if_status == IF_NOT_IN_USE) || | ||
252 | (batman_if->if_status == IF_TO_BE_REMOVED)) | ||
253 | return; | ||
254 | |||
255 | vis_server = atomic_read(&bat_priv->vis_mode); | ||
256 | |||
257 | /** | ||
258 | * the interface gets activated here to avoid race conditions between | ||
259 | * the moment of activating the interface in | ||
260 | * hardif_activate_interface() where the originator mac is set and | ||
261 | * outdated packets (especially uninitialized mac addresses) in the | ||
262 | * packet queue | ||
263 | */ | ||
264 | if (batman_if->if_status == IF_TO_BE_ACTIVATED) | ||
265 | batman_if->if_status = IF_ACTIVE; | ||
266 | |||
267 | /* if local hna has changed and interface is a primary interface */ | ||
268 | if ((atomic_read(&bat_priv->hna_local_changed)) && | ||
269 | (batman_if == bat_priv->primary_if)) | ||
270 | rebuild_batman_packet(bat_priv, batman_if); | ||
271 | |||
272 | /** | ||
273 | * NOTE: packet_buff might just have been re-allocated in | ||
274 | * rebuild_batman_packet() | ||
275 | */ | ||
276 | batman_packet = (struct batman_packet *)batman_if->packet_buff; | ||
277 | |||
278 | /* change sequence number to network order */ | ||
279 | batman_packet->seqno = | ||
280 | htonl((uint32_t)atomic_read(&batman_if->seqno)); | ||
281 | |||
282 | if (vis_server == VIS_TYPE_SERVER_SYNC) | ||
283 | batman_packet->flags |= VIS_SERVER; | ||
284 | else | ||
285 | batman_packet->flags &= ~VIS_SERVER; | ||
286 | |||
287 | if ((batman_if == bat_priv->primary_if) && | ||
288 | (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) | ||
289 | batman_packet->gw_flags = | ||
290 | (uint8_t)atomic_read(&bat_priv->gw_bandwidth); | ||
291 | else | ||
292 | batman_packet->gw_flags = 0; | ||
293 | |||
294 | atomic_inc(&batman_if->seqno); | ||
295 | |||
296 | slide_own_bcast_window(batman_if); | ||
297 | send_time = own_send_time(bat_priv); | ||
298 | add_bat_packet_to_list(bat_priv, | ||
299 | batman_if->packet_buff, | ||
300 | batman_if->packet_len, | ||
301 | batman_if, 1, send_time); | ||
302 | } | ||
303 | |||
304 | void schedule_forward_packet(struct orig_node *orig_node, | ||
305 | struct ethhdr *ethhdr, | ||
306 | struct batman_packet *batman_packet, | ||
307 | uint8_t directlink, int hna_buff_len, | ||
308 | struct batman_if *if_incoming) | ||
309 | { | ||
310 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
311 | unsigned char in_tq, in_ttl, tq_avg = 0; | ||
312 | unsigned long send_time; | ||
313 | |||
314 | if (batman_packet->ttl <= 1) { | ||
315 | bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | in_tq = batman_packet->tq; | ||
320 | in_ttl = batman_packet->ttl; | ||
321 | |||
322 | batman_packet->ttl--; | ||
323 | memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN); | ||
324 | |||
325 | /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast | ||
326 | * of our best tq value */ | ||
327 | if ((orig_node->router) && (orig_node->router->tq_avg != 0)) { | ||
328 | |||
329 | /* rebroadcast ogm of best ranking neighbor as is */ | ||
330 | if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) { | ||
331 | batman_packet->tq = orig_node->router->tq_avg; | ||
332 | |||
333 | if (orig_node->router->last_ttl) | ||
334 | batman_packet->ttl = orig_node->router->last_ttl | ||
335 | - 1; | ||
336 | } | ||
337 | |||
338 | tq_avg = orig_node->router->tq_avg; | ||
339 | } | ||
340 | |||
341 | /* apply hop penalty */ | ||
342 | batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); | ||
343 | |||
344 | bat_dbg(DBG_BATMAN, bat_priv, | ||
345 | "Forwarding packet: tq_orig: %i, tq_avg: %i, " | ||
346 | "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n", | ||
347 | in_tq, tq_avg, batman_packet->tq, in_ttl - 1, | ||
348 | batman_packet->ttl); | ||
349 | |||
350 | batman_packet->seqno = htonl(batman_packet->seqno); | ||
351 | |||
352 | /* switch of primaries first hop flag when forwarding */ | ||
353 | batman_packet->flags &= ~PRIMARIES_FIRST_HOP; | ||
354 | if (directlink) | ||
355 | batman_packet->flags |= DIRECTLINK; | ||
356 | else | ||
357 | batman_packet->flags &= ~DIRECTLINK; | ||
358 | |||
359 | send_time = forward_send_time(bat_priv); | ||
360 | add_bat_packet_to_list(bat_priv, | ||
361 | (unsigned char *)batman_packet, | ||
362 | sizeof(struct batman_packet) + hna_buff_len, | ||
363 | if_incoming, 0, send_time); | ||
364 | } | ||
365 | |||
366 | static void forw_packet_free(struct forw_packet *forw_packet) | ||
367 | { | ||
368 | if (forw_packet->skb) | ||
369 | kfree_skb(forw_packet->skb); | ||
370 | kfree(forw_packet); | ||
371 | } | ||
372 | |||
373 | static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, | ||
374 | struct forw_packet *forw_packet, | ||
375 | unsigned long send_time) | ||
376 | { | ||
377 | INIT_HLIST_NODE(&forw_packet->list); | ||
378 | |||
379 | /* add new packet to packet list */ | ||
380 | spin_lock_bh(&bat_priv->forw_bcast_list_lock); | ||
381 | hlist_add_head(&forw_packet->list, &bat_priv->forw_bcast_list); | ||
382 | spin_unlock_bh(&bat_priv->forw_bcast_list_lock); | ||
383 | |||
384 | /* start timer for this packet */ | ||
385 | INIT_DELAYED_WORK(&forw_packet->delayed_work, | ||
386 | send_outstanding_bcast_packet); | ||
387 | queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work, | ||
388 | send_time); | ||
389 | } | ||
390 | |||
391 | #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) | ||
392 | /* add a broadcast packet to the queue and setup timers. broadcast packets | ||
393 | * are sent multiple times to increase probability for beeing received. | ||
394 | * | ||
395 | * This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on | ||
396 | * errors. | ||
397 | * | ||
398 | * The skb is not consumed, so the caller should make sure that the | ||
399 | * skb is freed. */ | ||
400 | int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) | ||
401 | { | ||
402 | struct forw_packet *forw_packet; | ||
403 | struct bcast_packet *bcast_packet; | ||
404 | |||
405 | if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) { | ||
406 | bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n"); | ||
407 | goto out; | ||
408 | } | ||
409 | |||
410 | if (!bat_priv->primary_if) | ||
411 | goto out; | ||
412 | |||
413 | forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); | ||
414 | |||
415 | if (!forw_packet) | ||
416 | goto out_and_inc; | ||
417 | |||
418 | skb = skb_copy(skb, GFP_ATOMIC); | ||
419 | if (!skb) | ||
420 | goto packet_free; | ||
421 | |||
422 | /* as we have a copy now, it is safe to decrease the TTL */ | ||
423 | bcast_packet = (struct bcast_packet *)skb->data; | ||
424 | bcast_packet->ttl--; | ||
425 | |||
426 | skb_reset_mac_header(skb); | ||
427 | |||
428 | forw_packet->skb = skb; | ||
429 | forw_packet->if_incoming = bat_priv->primary_if; | ||
430 | |||
431 | /* how often did we send the bcast packet ? */ | ||
432 | forw_packet->num_packets = 0; | ||
433 | |||
434 | _add_bcast_packet_to_list(bat_priv, forw_packet, 1); | ||
435 | return NETDEV_TX_OK; | ||
436 | |||
437 | packet_free: | ||
438 | kfree(forw_packet); | ||
439 | out_and_inc: | ||
440 | atomic_inc(&bat_priv->bcast_queue_left); | ||
441 | out: | ||
442 | return NETDEV_TX_BUSY; | ||
443 | } | ||
444 | |||
445 | static void send_outstanding_bcast_packet(struct work_struct *work) | ||
446 | { | ||
447 | struct batman_if *batman_if; | ||
448 | struct delayed_work *delayed_work = | ||
449 | container_of(work, struct delayed_work, work); | ||
450 | struct forw_packet *forw_packet = | ||
451 | container_of(delayed_work, struct forw_packet, delayed_work); | ||
452 | struct sk_buff *skb1; | ||
453 | struct net_device *soft_iface = forw_packet->if_incoming->soft_iface; | ||
454 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
455 | |||
456 | spin_lock_bh(&bat_priv->forw_bcast_list_lock); | ||
457 | hlist_del(&forw_packet->list); | ||
458 | spin_unlock_bh(&bat_priv->forw_bcast_list_lock); | ||
459 | |||
460 | if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) | ||
461 | goto out; | ||
462 | |||
463 | /* rebroadcast packet */ | ||
464 | rcu_read_lock(); | ||
465 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
466 | if (batman_if->soft_iface != soft_iface) | ||
467 | continue; | ||
468 | |||
469 | /* send a copy of the saved skb */ | ||
470 | skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC); | ||
471 | if (skb1) | ||
472 | send_skb_packet(skb1, batman_if, broadcast_addr); | ||
473 | } | ||
474 | rcu_read_unlock(); | ||
475 | |||
476 | forw_packet->num_packets++; | ||
477 | |||
478 | /* if we still have some more bcasts to send */ | ||
479 | if (forw_packet->num_packets < 3) { | ||
480 | _add_bcast_packet_to_list(bat_priv, forw_packet, | ||
481 | ((5 * HZ) / 1000)); | ||
482 | return; | ||
483 | } | ||
484 | |||
485 | out: | ||
486 | forw_packet_free(forw_packet); | ||
487 | atomic_inc(&bat_priv->bcast_queue_left); | ||
488 | } | ||
489 | |||
490 | void send_outstanding_bat_packet(struct work_struct *work) | ||
491 | { | ||
492 | struct delayed_work *delayed_work = | ||
493 | container_of(work, struct delayed_work, work); | ||
494 | struct forw_packet *forw_packet = | ||
495 | container_of(delayed_work, struct forw_packet, delayed_work); | ||
496 | struct bat_priv *bat_priv; | ||
497 | |||
498 | bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface); | ||
499 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
500 | hlist_del(&forw_packet->list); | ||
501 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
502 | |||
503 | if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) | ||
504 | goto out; | ||
505 | |||
506 | send_packet(forw_packet); | ||
507 | |||
508 | /** | ||
509 | * we have to have at least one packet in the queue | ||
510 | * to determine the queues wake up time unless we are | ||
511 | * shutting down | ||
512 | */ | ||
513 | if (forw_packet->own) | ||
514 | schedule_own_packet(forw_packet->if_incoming); | ||
515 | |||
516 | out: | ||
517 | /* don't count own packet */ | ||
518 | if (!forw_packet->own) | ||
519 | atomic_inc(&bat_priv->batman_queue_left); | ||
520 | |||
521 | forw_packet_free(forw_packet); | ||
522 | } | ||
523 | |||
524 | void purge_outstanding_packets(struct bat_priv *bat_priv, | ||
525 | struct batman_if *batman_if) | ||
526 | { | ||
527 | struct forw_packet *forw_packet; | ||
528 | struct hlist_node *tmp_node, *safe_tmp_node; | ||
529 | |||
530 | if (batman_if) | ||
531 | bat_dbg(DBG_BATMAN, bat_priv, | ||
532 | "purge_outstanding_packets(): %s\n", | ||
533 | batman_if->net_dev->name); | ||
534 | else | ||
535 | bat_dbg(DBG_BATMAN, bat_priv, | ||
536 | "purge_outstanding_packets()\n"); | ||
537 | |||
538 | /* free bcast list */ | ||
539 | spin_lock_bh(&bat_priv->forw_bcast_list_lock); | ||
540 | hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, | ||
541 | &bat_priv->forw_bcast_list, list) { | ||
542 | |||
543 | /** | ||
544 | * if purge_outstanding_packets() was called with an argmument | ||
545 | * we delete only packets belonging to the given interface | ||
546 | */ | ||
547 | if ((batman_if) && | ||
548 | (forw_packet->if_incoming != batman_if)) | ||
549 | continue; | ||
550 | |||
551 | spin_unlock_bh(&bat_priv->forw_bcast_list_lock); | ||
552 | |||
553 | /** | ||
554 | * send_outstanding_bcast_packet() will lock the list to | ||
555 | * delete the item from the list | ||
556 | */ | ||
557 | cancel_delayed_work_sync(&forw_packet->delayed_work); | ||
558 | spin_lock_bh(&bat_priv->forw_bcast_list_lock); | ||
559 | } | ||
560 | spin_unlock_bh(&bat_priv->forw_bcast_list_lock); | ||
561 | |||
562 | /* free batman packet list */ | ||
563 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
564 | hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, | ||
565 | &bat_priv->forw_bat_list, list) { | ||
566 | |||
567 | /** | ||
568 | * if purge_outstanding_packets() was called with an argmument | ||
569 | * we delete only packets belonging to the given interface | ||
570 | */ | ||
571 | if ((batman_if) && | ||
572 | (forw_packet->if_incoming != batman_if)) | ||
573 | continue; | ||
574 | |||
575 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
576 | |||
577 | /** | ||
578 | * send_outstanding_bat_packet() will lock the list to | ||
579 | * delete the item from the list | ||
580 | */ | ||
581 | cancel_delayed_work_sync(&forw_packet->delayed_work); | ||
582 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
583 | } | ||
584 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
585 | } | ||
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h new file mode 100644 index 000000000000..c4cefa8e4f85 --- /dev/null +++ b/net/batman-adv/send.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_SEND_H_ | ||
23 | #define _NET_BATMAN_ADV_SEND_H_ | ||
24 | |||
25 | #include "types.h" | ||
26 | |||
27 | int send_skb_packet(struct sk_buff *skb, | ||
28 | struct batman_if *batman_if, | ||
29 | uint8_t *dst_addr); | ||
30 | void schedule_own_packet(struct batman_if *batman_if); | ||
31 | void schedule_forward_packet(struct orig_node *orig_node, | ||
32 | struct ethhdr *ethhdr, | ||
33 | struct batman_packet *batman_packet, | ||
34 | uint8_t directlink, int hna_buff_len, | ||
35 | struct batman_if *if_outgoing); | ||
36 | int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb); | ||
37 | void send_outstanding_bat_packet(struct work_struct *work); | ||
38 | void purge_outstanding_packets(struct bat_priv *bat_priv, | ||
39 | struct batman_if *batman_if); | ||
40 | |||
41 | #endif /* _NET_BATMAN_ADV_SEND_H_ */ | ||
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c new file mode 100644 index 000000000000..e89ede192ed0 --- /dev/null +++ b/net/batman-adv/soft-interface.c | |||
@@ -0,0 +1,697 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 "routing.h" | ||
26 | #include "send.h" | ||
27 | #include "bat_debugfs.h" | ||
28 | #include "translation-table.h" | ||
29 | #include "types.h" | ||
30 | #include "hash.h" | ||
31 | #include "gateway_common.h" | ||
32 | #include "gateway_client.h" | ||
33 | #include "send.h" | ||
34 | #include "bat_sysfs.h" | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/ethtool.h> | ||
37 | #include <linux/etherdevice.h> | ||
38 | #include <linux/if_vlan.h> | ||
39 | #include "unicast.h" | ||
40 | #include "routing.h" | ||
41 | |||
42 | |||
43 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); | ||
44 | static void bat_get_drvinfo(struct net_device *dev, | ||
45 | struct ethtool_drvinfo *info); | ||
46 | static u32 bat_get_msglevel(struct net_device *dev); | ||
47 | static void bat_set_msglevel(struct net_device *dev, u32 value); | ||
48 | static u32 bat_get_link(struct net_device *dev); | ||
49 | static u32 bat_get_rx_csum(struct net_device *dev); | ||
50 | static int bat_set_rx_csum(struct net_device *dev, u32 data); | ||
51 | |||
52 | static const struct ethtool_ops bat_ethtool_ops = { | ||
53 | .get_settings = bat_get_settings, | ||
54 | .get_drvinfo = bat_get_drvinfo, | ||
55 | .get_msglevel = bat_get_msglevel, | ||
56 | .set_msglevel = bat_set_msglevel, | ||
57 | .get_link = bat_get_link, | ||
58 | .get_rx_csum = bat_get_rx_csum, | ||
59 | .set_rx_csum = bat_set_rx_csum | ||
60 | }; | ||
61 | |||
62 | int my_skb_head_push(struct sk_buff *skb, unsigned int len) | ||
63 | { | ||
64 | int result; | ||
65 | |||
66 | /** | ||
67 | * TODO: We must check if we can release all references to non-payload | ||
68 | * data using skb_header_release in our skbs to allow skb_cow_header to | ||
69 | * work optimally. This means that those skbs are not allowed to read | ||
70 | * or write any data which is before the current position of skb->data | ||
71 | * after that call and thus allow other skbs with the same data buffer | ||
72 | * to write freely in that area. | ||
73 | */ | ||
74 | result = skb_cow_head(skb, len); | ||
75 | if (result < 0) | ||
76 | return result; | ||
77 | |||
78 | skb_push(skb, len); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static void softif_neigh_free_ref(struct kref *refcount) | ||
83 | { | ||
84 | struct softif_neigh *softif_neigh; | ||
85 | |||
86 | softif_neigh = container_of(refcount, struct softif_neigh, refcount); | ||
87 | kfree(softif_neigh); | ||
88 | } | ||
89 | |||
90 | static void softif_neigh_free_rcu(struct rcu_head *rcu) | ||
91 | { | ||
92 | struct softif_neigh *softif_neigh; | ||
93 | |||
94 | softif_neigh = container_of(rcu, struct softif_neigh, rcu); | ||
95 | kref_put(&softif_neigh->refcount, softif_neigh_free_ref); | ||
96 | } | ||
97 | |||
98 | void softif_neigh_purge(struct bat_priv *bat_priv) | ||
99 | { | ||
100 | struct softif_neigh *softif_neigh, *softif_neigh_tmp; | ||
101 | struct hlist_node *node, *node_tmp; | ||
102 | |||
103 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
104 | |||
105 | hlist_for_each_entry_safe(softif_neigh, node, node_tmp, | ||
106 | &bat_priv->softif_neigh_list, list) { | ||
107 | |||
108 | if ((!time_after(jiffies, softif_neigh->last_seen + | ||
109 | msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && | ||
110 | (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) | ||
111 | continue; | ||
112 | |||
113 | hlist_del_rcu(&softif_neigh->list); | ||
114 | |||
115 | if (bat_priv->softif_neigh == softif_neigh) { | ||
116 | bat_dbg(DBG_ROUTES, bat_priv, | ||
117 | "Current mesh exit point '%pM' vanished " | ||
118 | "(vid: %d).\n", | ||
119 | softif_neigh->addr, softif_neigh->vid); | ||
120 | softif_neigh_tmp = bat_priv->softif_neigh; | ||
121 | bat_priv->softif_neigh = NULL; | ||
122 | kref_put(&softif_neigh_tmp->refcount, | ||
123 | softif_neigh_free_ref); | ||
124 | } | ||
125 | |||
126 | call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); | ||
127 | } | ||
128 | |||
129 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
130 | } | ||
131 | |||
132 | static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, | ||
133 | uint8_t *addr, short vid) | ||
134 | { | ||
135 | struct softif_neigh *softif_neigh; | ||
136 | struct hlist_node *node; | ||
137 | |||
138 | rcu_read_lock(); | ||
139 | hlist_for_each_entry_rcu(softif_neigh, node, | ||
140 | &bat_priv->softif_neigh_list, list) { | ||
141 | if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) | ||
142 | continue; | ||
143 | |||
144 | if (softif_neigh->vid != vid) | ||
145 | continue; | ||
146 | |||
147 | softif_neigh->last_seen = jiffies; | ||
148 | goto found; | ||
149 | } | ||
150 | |||
151 | softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); | ||
152 | if (!softif_neigh) | ||
153 | goto out; | ||
154 | |||
155 | memcpy(softif_neigh->addr, addr, ETH_ALEN); | ||
156 | softif_neigh->vid = vid; | ||
157 | softif_neigh->last_seen = jiffies; | ||
158 | kref_init(&softif_neigh->refcount); | ||
159 | |||
160 | INIT_HLIST_NODE(&softif_neigh->list); | ||
161 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
162 | hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); | ||
163 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
164 | |||
165 | found: | ||
166 | kref_get(&softif_neigh->refcount); | ||
167 | out: | ||
168 | rcu_read_unlock(); | ||
169 | return softif_neigh; | ||
170 | } | ||
171 | |||
172 | int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | ||
173 | { | ||
174 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
175 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
176 | struct softif_neigh *softif_neigh; | ||
177 | struct hlist_node *node; | ||
178 | size_t buf_size, pos; | ||
179 | char *buff; | ||
180 | |||
181 | if (!bat_priv->primary_if) { | ||
182 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
183 | "please specify interfaces to enable it\n", | ||
184 | net_dev->name); | ||
185 | } | ||
186 | |||
187 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); | ||
188 | |||
189 | buf_size = 1; | ||
190 | /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */ | ||
191 | rcu_read_lock(); | ||
192 | hlist_for_each_entry_rcu(softif_neigh, node, | ||
193 | &bat_priv->softif_neigh_list, list) | ||
194 | buf_size += 30; | ||
195 | rcu_read_unlock(); | ||
196 | |||
197 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
198 | if (!buff) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | buff[0] = '\0'; | ||
202 | pos = 0; | ||
203 | |||
204 | rcu_read_lock(); | ||
205 | hlist_for_each_entry_rcu(softif_neigh, node, | ||
206 | &bat_priv->softif_neigh_list, list) { | ||
207 | pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n", | ||
208 | bat_priv->softif_neigh == softif_neigh | ||
209 | ? "=>" : " ", softif_neigh->addr, | ||
210 | softif_neigh->vid); | ||
211 | } | ||
212 | rcu_read_unlock(); | ||
213 | |||
214 | seq_printf(seq, "%s", buff); | ||
215 | kfree(buff); | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | ||
220 | short vid) | ||
221 | { | ||
222 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
223 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
224 | struct batman_packet *batman_packet; | ||
225 | struct softif_neigh *softif_neigh, *softif_neigh_tmp; | ||
226 | |||
227 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) | ||
228 | batman_packet = (struct batman_packet *) | ||
229 | (skb->data + ETH_HLEN + VLAN_HLEN); | ||
230 | else | ||
231 | batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); | ||
232 | |||
233 | if (batman_packet->version != COMPAT_VERSION) | ||
234 | goto err; | ||
235 | |||
236 | if (batman_packet->packet_type != BAT_PACKET) | ||
237 | goto err; | ||
238 | |||
239 | if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) | ||
240 | goto err; | ||
241 | |||
242 | if (is_my_mac(batman_packet->orig)) | ||
243 | goto err; | ||
244 | |||
245 | softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); | ||
246 | |||
247 | if (!softif_neigh) | ||
248 | goto err; | ||
249 | |||
250 | if (bat_priv->softif_neigh == softif_neigh) | ||
251 | goto out; | ||
252 | |||
253 | /* we got a neighbor but its mac is 'bigger' than ours */ | ||
254 | if (memcmp(bat_priv->primary_if->net_dev->dev_addr, | ||
255 | softif_neigh->addr, ETH_ALEN) < 0) | ||
256 | goto out; | ||
257 | |||
258 | /* switch to new 'smallest neighbor' */ | ||
259 | if ((bat_priv->softif_neigh) && | ||
260 | (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, | ||
261 | ETH_ALEN) < 0)) { | ||
262 | bat_dbg(DBG_ROUTES, bat_priv, | ||
263 | "Changing mesh exit point from %pM (vid: %d) " | ||
264 | "to %pM (vid: %d).\n", | ||
265 | bat_priv->softif_neigh->addr, | ||
266 | bat_priv->softif_neigh->vid, | ||
267 | softif_neigh->addr, softif_neigh->vid); | ||
268 | softif_neigh_tmp = bat_priv->softif_neigh; | ||
269 | bat_priv->softif_neigh = softif_neigh; | ||
270 | kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); | ||
271 | /* we need to hold the additional reference */ | ||
272 | goto err; | ||
273 | } | ||
274 | |||
275 | /* close own batX device and use softif_neigh as exit node */ | ||
276 | if ((!bat_priv->softif_neigh) && | ||
277 | (memcmp(softif_neigh->addr, | ||
278 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { | ||
279 | bat_dbg(DBG_ROUTES, bat_priv, | ||
280 | "Setting mesh exit point to %pM (vid: %d).\n", | ||
281 | softif_neigh->addr, softif_neigh->vid); | ||
282 | bat_priv->softif_neigh = softif_neigh; | ||
283 | /* we need to hold the additional reference */ | ||
284 | goto err; | ||
285 | } | ||
286 | |||
287 | out: | ||
288 | kref_put(&softif_neigh->refcount, softif_neigh_free_ref); | ||
289 | err: | ||
290 | kfree_skb(skb); | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | static int interface_open(struct net_device *dev) | ||
295 | { | ||
296 | netif_start_queue(dev); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int interface_release(struct net_device *dev) | ||
301 | { | ||
302 | netif_stop_queue(dev); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static struct net_device_stats *interface_stats(struct net_device *dev) | ||
307 | { | ||
308 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
309 | return &bat_priv->stats; | ||
310 | } | ||
311 | |||
312 | static int interface_set_mac_addr(struct net_device *dev, void *p) | ||
313 | { | ||
314 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
315 | struct sockaddr *addr = p; | ||
316 | |||
317 | if (!is_valid_ether_addr(addr->sa_data)) | ||
318 | return -EADDRNOTAVAIL; | ||
319 | |||
320 | /* only modify hna-table if it has been initialised before */ | ||
321 | if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { | ||
322 | hna_local_remove(bat_priv, dev->dev_addr, | ||
323 | "mac address changed"); | ||
324 | hna_local_add(dev, addr->sa_data); | ||
325 | } | ||
326 | |||
327 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int interface_change_mtu(struct net_device *dev, int new_mtu) | ||
332 | { | ||
333 | /* check ranges */ | ||
334 | if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev))) | ||
335 | return -EINVAL; | ||
336 | |||
337 | dev->mtu = new_mtu; | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | ||
343 | { | ||
344 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
345 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
346 | struct bcast_packet *bcast_packet; | ||
347 | struct vlan_ethhdr *vhdr; | ||
348 | int data_len = skb->len, ret; | ||
349 | short vid = -1; | ||
350 | bool do_bcast = false; | ||
351 | |||
352 | if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) | ||
353 | goto dropped; | ||
354 | |||
355 | soft_iface->trans_start = jiffies; | ||
356 | |||
357 | switch (ntohs(ethhdr->h_proto)) { | ||
358 | case ETH_P_8021Q: | ||
359 | vhdr = (struct vlan_ethhdr *)skb->data; | ||
360 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
361 | |||
362 | if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) | ||
363 | break; | ||
364 | |||
365 | /* fall through */ | ||
366 | case ETH_P_BATMAN: | ||
367 | softif_batman_recv(skb, soft_iface, vid); | ||
368 | goto end; | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * if we have a another chosen mesh exit node in range | ||
373 | * it will transport the packets to the mesh | ||
374 | */ | ||
375 | if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) | ||
376 | goto dropped; | ||
377 | |||
378 | /* TODO: check this for locks */ | ||
379 | hna_local_add(soft_iface, ethhdr->h_source); | ||
380 | |||
381 | if (is_multicast_ether_addr(ethhdr->h_dest)) { | ||
382 | ret = gw_is_target(bat_priv, skb); | ||
383 | |||
384 | if (ret < 0) | ||
385 | goto dropped; | ||
386 | |||
387 | if (ret == 0) | ||
388 | do_bcast = true; | ||
389 | } | ||
390 | |||
391 | /* ethernet packet should be broadcasted */ | ||
392 | if (do_bcast) { | ||
393 | if (!bat_priv->primary_if) | ||
394 | goto dropped; | ||
395 | |||
396 | if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) | ||
397 | goto dropped; | ||
398 | |||
399 | bcast_packet = (struct bcast_packet *)skb->data; | ||
400 | bcast_packet->version = COMPAT_VERSION; | ||
401 | bcast_packet->ttl = TTL; | ||
402 | |||
403 | /* batman packet type: broadcast */ | ||
404 | bcast_packet->packet_type = BAT_BCAST; | ||
405 | |||
406 | /* hw address of first interface is the orig mac because only | ||
407 | * this mac is known throughout the mesh */ | ||
408 | memcpy(bcast_packet->orig, | ||
409 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
410 | |||
411 | /* set broadcast sequence number */ | ||
412 | bcast_packet->seqno = | ||
413 | htonl(atomic_inc_return(&bat_priv->bcast_seqno)); | ||
414 | |||
415 | add_bcast_packet_to_list(bat_priv, skb); | ||
416 | |||
417 | /* a copy is stored in the bcast list, therefore removing | ||
418 | * the original skb. */ | ||
419 | kfree_skb(skb); | ||
420 | |||
421 | /* unicast packet */ | ||
422 | } else { | ||
423 | ret = unicast_send_skb(skb, bat_priv); | ||
424 | if (ret != 0) | ||
425 | goto dropped_freed; | ||
426 | } | ||
427 | |||
428 | bat_priv->stats.tx_packets++; | ||
429 | bat_priv->stats.tx_bytes += data_len; | ||
430 | goto end; | ||
431 | |||
432 | dropped: | ||
433 | kfree_skb(skb); | ||
434 | dropped_freed: | ||
435 | bat_priv->stats.tx_dropped++; | ||
436 | end: | ||
437 | return NETDEV_TX_OK; | ||
438 | } | ||
439 | |||
440 | void interface_rx(struct net_device *soft_iface, | ||
441 | struct sk_buff *skb, struct batman_if *recv_if, | ||
442 | int hdr_size) | ||
443 | { | ||
444 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
445 | struct unicast_packet *unicast_packet; | ||
446 | struct ethhdr *ethhdr; | ||
447 | struct vlan_ethhdr *vhdr; | ||
448 | short vid = -1; | ||
449 | int ret; | ||
450 | |||
451 | /* check if enough space is available for pulling, and pull */ | ||
452 | if (!pskb_may_pull(skb, hdr_size)) | ||
453 | goto dropped; | ||
454 | |||
455 | skb_pull_rcsum(skb, hdr_size); | ||
456 | skb_reset_mac_header(skb); | ||
457 | |||
458 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
459 | |||
460 | switch (ntohs(ethhdr->h_proto)) { | ||
461 | case ETH_P_8021Q: | ||
462 | vhdr = (struct vlan_ethhdr *)skb->data; | ||
463 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
464 | |||
465 | if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) | ||
466 | break; | ||
467 | |||
468 | /* fall through */ | ||
469 | case ETH_P_BATMAN: | ||
470 | goto dropped; | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * if we have a another chosen mesh exit node in range | ||
475 | * it will transport the packets to the non-mesh network | ||
476 | */ | ||
477 | if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { | ||
478 | skb_push(skb, hdr_size); | ||
479 | unicast_packet = (struct unicast_packet *)skb->data; | ||
480 | |||
481 | if ((unicast_packet->packet_type != BAT_UNICAST) && | ||
482 | (unicast_packet->packet_type != BAT_UNICAST_FRAG)) | ||
483 | goto dropped; | ||
484 | |||
485 | skb_reset_mac_header(skb); | ||
486 | |||
487 | memcpy(unicast_packet->dest, | ||
488 | bat_priv->softif_neigh->addr, ETH_ALEN); | ||
489 | ret = route_unicast_packet(skb, recv_if, hdr_size); | ||
490 | if (ret == NET_RX_DROP) | ||
491 | goto dropped; | ||
492 | |||
493 | goto out; | ||
494 | } | ||
495 | |||
496 | /* skb->dev & skb->pkt_type are set here */ | ||
497 | if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) | ||
498 | goto dropped; | ||
499 | skb->protocol = eth_type_trans(skb, soft_iface); | ||
500 | |||
501 | /* should not be neccesary anymore as we use skb_pull_rcsum() | ||
502 | * TODO: please verify this and remove this TODO | ||
503 | * -- Dec 21st 2009, Simon Wunderlich */ | ||
504 | |||
505 | /* skb->ip_summed = CHECKSUM_UNNECESSARY;*/ | ||
506 | |||
507 | bat_priv->stats.rx_packets++; | ||
508 | bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr); | ||
509 | |||
510 | soft_iface->last_rx = jiffies; | ||
511 | |||
512 | netif_rx(skb); | ||
513 | return; | ||
514 | |||
515 | dropped: | ||
516 | kfree_skb(skb); | ||
517 | out: | ||
518 | return; | ||
519 | } | ||
520 | |||
521 | #ifdef HAVE_NET_DEVICE_OPS | ||
522 | static const struct net_device_ops bat_netdev_ops = { | ||
523 | .ndo_open = interface_open, | ||
524 | .ndo_stop = interface_release, | ||
525 | .ndo_get_stats = interface_stats, | ||
526 | .ndo_set_mac_address = interface_set_mac_addr, | ||
527 | .ndo_change_mtu = interface_change_mtu, | ||
528 | .ndo_start_xmit = interface_tx, | ||
529 | .ndo_validate_addr = eth_validate_addr | ||
530 | }; | ||
531 | #endif | ||
532 | |||
533 | static void interface_setup(struct net_device *dev) | ||
534 | { | ||
535 | struct bat_priv *priv = netdev_priv(dev); | ||
536 | char dev_addr[ETH_ALEN]; | ||
537 | |||
538 | ether_setup(dev); | ||
539 | |||
540 | #ifdef HAVE_NET_DEVICE_OPS | ||
541 | dev->netdev_ops = &bat_netdev_ops; | ||
542 | #else | ||
543 | dev->open = interface_open; | ||
544 | dev->stop = interface_release; | ||
545 | dev->get_stats = interface_stats; | ||
546 | dev->set_mac_address = interface_set_mac_addr; | ||
547 | dev->change_mtu = interface_change_mtu; | ||
548 | dev->hard_start_xmit = interface_tx; | ||
549 | #endif | ||
550 | dev->destructor = free_netdev; | ||
551 | |||
552 | /** | ||
553 | * can't call min_mtu, because the needed variables | ||
554 | * have not been initialized yet | ||
555 | */ | ||
556 | dev->mtu = ETH_DATA_LEN; | ||
557 | dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the | ||
558 | * skbuff for our header */ | ||
559 | |||
560 | /* generate random address */ | ||
561 | random_ether_addr(dev_addr); | ||
562 | memcpy(dev->dev_addr, dev_addr, ETH_ALEN); | ||
563 | |||
564 | SET_ETHTOOL_OPS(dev, &bat_ethtool_ops); | ||
565 | |||
566 | memset(priv, 0, sizeof(struct bat_priv)); | ||
567 | } | ||
568 | |||
569 | struct net_device *softif_create(char *name) | ||
570 | { | ||
571 | struct net_device *soft_iface; | ||
572 | struct bat_priv *bat_priv; | ||
573 | int ret; | ||
574 | |||
575 | soft_iface = alloc_netdev(sizeof(struct bat_priv) , name, | ||
576 | interface_setup); | ||
577 | |||
578 | if (!soft_iface) { | ||
579 | pr_err("Unable to allocate the batman interface: %s\n", name); | ||
580 | goto out; | ||
581 | } | ||
582 | |||
583 | ret = register_netdev(soft_iface); | ||
584 | if (ret < 0) { | ||
585 | pr_err("Unable to register the batman interface '%s': %i\n", | ||
586 | name, ret); | ||
587 | goto free_soft_iface; | ||
588 | } | ||
589 | |||
590 | bat_priv = netdev_priv(soft_iface); | ||
591 | |||
592 | atomic_set(&bat_priv->aggregated_ogms, 1); | ||
593 | atomic_set(&bat_priv->bonding, 0); | ||
594 | atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); | ||
595 | atomic_set(&bat_priv->gw_mode, GW_MODE_OFF); | ||
596 | atomic_set(&bat_priv->gw_sel_class, 20); | ||
597 | atomic_set(&bat_priv->gw_bandwidth, 41); | ||
598 | atomic_set(&bat_priv->orig_interval, 1000); | ||
599 | atomic_set(&bat_priv->hop_penalty, 10); | ||
600 | atomic_set(&bat_priv->log_level, 0); | ||
601 | atomic_set(&bat_priv->fragmentation, 1); | ||
602 | atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN); | ||
603 | atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN); | ||
604 | |||
605 | atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); | ||
606 | atomic_set(&bat_priv->bcast_seqno, 1); | ||
607 | atomic_set(&bat_priv->hna_local_changed, 0); | ||
608 | |||
609 | bat_priv->primary_if = NULL; | ||
610 | bat_priv->num_ifaces = 0; | ||
611 | bat_priv->softif_neigh = NULL; | ||
612 | |||
613 | ret = sysfs_add_meshif(soft_iface); | ||
614 | if (ret < 0) | ||
615 | goto unreg_soft_iface; | ||
616 | |||
617 | ret = debugfs_add_meshif(soft_iface); | ||
618 | if (ret < 0) | ||
619 | goto unreg_sysfs; | ||
620 | |||
621 | ret = mesh_init(soft_iface); | ||
622 | if (ret < 0) | ||
623 | goto unreg_debugfs; | ||
624 | |||
625 | return soft_iface; | ||
626 | |||
627 | unreg_debugfs: | ||
628 | debugfs_del_meshif(soft_iface); | ||
629 | unreg_sysfs: | ||
630 | sysfs_del_meshif(soft_iface); | ||
631 | unreg_soft_iface: | ||
632 | unregister_netdev(soft_iface); | ||
633 | return NULL; | ||
634 | |||
635 | free_soft_iface: | ||
636 | free_netdev(soft_iface); | ||
637 | out: | ||
638 | return NULL; | ||
639 | } | ||
640 | |||
641 | void softif_destroy(struct net_device *soft_iface) | ||
642 | { | ||
643 | debugfs_del_meshif(soft_iface); | ||
644 | sysfs_del_meshif(soft_iface); | ||
645 | mesh_free(soft_iface); | ||
646 | unregister_netdevice(soft_iface); | ||
647 | } | ||
648 | |||
649 | /* ethtool */ | ||
650 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
651 | { | ||
652 | cmd->supported = 0; | ||
653 | cmd->advertising = 0; | ||
654 | cmd->speed = SPEED_10; | ||
655 | cmd->duplex = DUPLEX_FULL; | ||
656 | cmd->port = PORT_TP; | ||
657 | cmd->phy_address = 0; | ||
658 | cmd->transceiver = XCVR_INTERNAL; | ||
659 | cmd->autoneg = AUTONEG_DISABLE; | ||
660 | cmd->maxtxpkt = 0; | ||
661 | cmd->maxrxpkt = 0; | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | static void bat_get_drvinfo(struct net_device *dev, | ||
667 | struct ethtool_drvinfo *info) | ||
668 | { | ||
669 | strcpy(info->driver, "B.A.T.M.A.N. advanced"); | ||
670 | strcpy(info->version, SOURCE_VERSION); | ||
671 | strcpy(info->fw_version, "N/A"); | ||
672 | strcpy(info->bus_info, "batman"); | ||
673 | } | ||
674 | |||
675 | static u32 bat_get_msglevel(struct net_device *dev) | ||
676 | { | ||
677 | return -EOPNOTSUPP; | ||
678 | } | ||
679 | |||
680 | static void bat_set_msglevel(struct net_device *dev, u32 value) | ||
681 | { | ||
682 | } | ||
683 | |||
684 | static u32 bat_get_link(struct net_device *dev) | ||
685 | { | ||
686 | return 1; | ||
687 | } | ||
688 | |||
689 | static u32 bat_get_rx_csum(struct net_device *dev) | ||
690 | { | ||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static int bat_set_rx_csum(struct net_device *dev, u32 data) | ||
695 | { | ||
696 | return -EOPNOTSUPP; | ||
697 | } | ||
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h new file mode 100644 index 000000000000..02b77334d10d --- /dev/null +++ b/net/batman-adv/soft-interface.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_ | ||
23 | #define _NET_BATMAN_ADV_SOFT_INTERFACE_H_ | ||
24 | |||
25 | int my_skb_head_push(struct sk_buff *skb, unsigned int len); | ||
26 | int softif_neigh_seq_print_text(struct seq_file *seq, void *offset); | ||
27 | void softif_neigh_purge(struct bat_priv *bat_priv); | ||
28 | int interface_tx(struct sk_buff *skb, struct net_device *soft_iface); | ||
29 | void interface_rx(struct net_device *soft_iface, | ||
30 | struct sk_buff *skb, struct batman_if *recv_if, | ||
31 | int hdr_size); | ||
32 | struct net_device *softif_create(char *name); | ||
33 | void softif_destroy(struct net_device *soft_iface); | ||
34 | |||
35 | #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ | ||
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c new file mode 100644 index 000000000000..a19e16c94da5 --- /dev/null +++ b/net/batman-adv/translation-table.c | |||
@@ -0,0 +1,534 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 "soft-interface.h" | ||
25 | #include "types.h" | ||
26 | #include "hash.h" | ||
27 | #include "originator.h" | ||
28 | |||
29 | static void hna_local_purge(struct work_struct *work); | ||
30 | static void _hna_global_del_orig(struct bat_priv *bat_priv, | ||
31 | struct hna_global_entry *hna_global_entry, | ||
32 | char *message); | ||
33 | |||
34 | static void hna_local_start_timer(struct bat_priv *bat_priv) | ||
35 | { | ||
36 | INIT_DELAYED_WORK(&bat_priv->hna_work, hna_local_purge); | ||
37 | queue_delayed_work(bat_event_workqueue, &bat_priv->hna_work, 10 * HZ); | ||
38 | } | ||
39 | |||
40 | int hna_local_init(struct bat_priv *bat_priv) | ||
41 | { | ||
42 | if (bat_priv->hna_local_hash) | ||
43 | return 1; | ||
44 | |||
45 | bat_priv->hna_local_hash = hash_new(1024); | ||
46 | |||
47 | if (!bat_priv->hna_local_hash) | ||
48 | return 0; | ||
49 | |||
50 | atomic_set(&bat_priv->hna_local_changed, 0); | ||
51 | hna_local_start_timer(bat_priv); | ||
52 | |||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | void hna_local_add(struct net_device *soft_iface, uint8_t *addr) | ||
57 | { | ||
58 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
59 | struct hna_local_entry *hna_local_entry; | ||
60 | struct hna_global_entry *hna_global_entry; | ||
61 | int required_bytes; | ||
62 | |||
63 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
64 | hna_local_entry = | ||
65 | ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, | ||
66 | compare_orig, choose_orig, | ||
67 | addr)); | ||
68 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
69 | |||
70 | if (hna_local_entry) { | ||
71 | hna_local_entry->last_seen = jiffies; | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | /* only announce as many hosts as possible in the batman-packet and | ||
76 | space in batman_packet->num_hna That also should give a limit to | ||
77 | MAC-flooding. */ | ||
78 | required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN; | ||
79 | required_bytes += BAT_PACKET_LEN; | ||
80 | |||
81 | if ((required_bytes > ETH_DATA_LEN) || | ||
82 | (atomic_read(&bat_priv->aggregated_ogms) && | ||
83 | required_bytes > MAX_AGGREGATION_BYTES) || | ||
84 | (bat_priv->num_local_hna + 1 > 255)) { | ||
85 | bat_dbg(DBG_ROUTES, bat_priv, | ||
86 | "Can't add new local hna entry (%pM): " | ||
87 | "number of local hna entries exceeds packet size\n", | ||
88 | addr); | ||
89 | return; | ||
90 | } | ||
91 | |||
92 | bat_dbg(DBG_ROUTES, bat_priv, | ||
93 | "Creating new local hna entry: %pM\n", addr); | ||
94 | |||
95 | hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC); | ||
96 | if (!hna_local_entry) | ||
97 | return; | ||
98 | |||
99 | memcpy(hna_local_entry->addr, addr, ETH_ALEN); | ||
100 | hna_local_entry->last_seen = jiffies; | ||
101 | |||
102 | /* the batman interface mac address should never be purged */ | ||
103 | if (compare_orig(addr, soft_iface->dev_addr)) | ||
104 | hna_local_entry->never_purge = 1; | ||
105 | else | ||
106 | hna_local_entry->never_purge = 0; | ||
107 | |||
108 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
109 | |||
110 | hash_add(bat_priv->hna_local_hash, compare_orig, choose_orig, | ||
111 | hna_local_entry); | ||
112 | bat_priv->num_local_hna++; | ||
113 | atomic_set(&bat_priv->hna_local_changed, 1); | ||
114 | |||
115 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
116 | |||
117 | /* remove address from global hash if present */ | ||
118 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
119 | |||
120 | hna_global_entry = ((struct hna_global_entry *) | ||
121 | hash_find(bat_priv->hna_global_hash, | ||
122 | compare_orig, choose_orig, addr)); | ||
123 | |||
124 | if (hna_global_entry) | ||
125 | _hna_global_del_orig(bat_priv, hna_global_entry, | ||
126 | "local hna received"); | ||
127 | |||
128 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
129 | } | ||
130 | |||
131 | int hna_local_fill_buffer(struct bat_priv *bat_priv, | ||
132 | unsigned char *buff, int buff_len) | ||
133 | { | ||
134 | struct hashtable_t *hash = bat_priv->hna_local_hash; | ||
135 | struct hna_local_entry *hna_local_entry; | ||
136 | struct element_t *bucket; | ||
137 | int i; | ||
138 | struct hlist_node *walk; | ||
139 | struct hlist_head *head; | ||
140 | int count = 0; | ||
141 | |||
142 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
143 | |||
144 | for (i = 0; i < hash->size; i++) { | ||
145 | head = &hash->table[i]; | ||
146 | |||
147 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
148 | |||
149 | if (buff_len < (count + 1) * ETH_ALEN) | ||
150 | break; | ||
151 | |||
152 | hna_local_entry = bucket->data; | ||
153 | memcpy(buff + (count * ETH_ALEN), hna_local_entry->addr, | ||
154 | ETH_ALEN); | ||
155 | |||
156 | count++; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /* if we did not get all new local hnas see you next time ;-) */ | ||
161 | if (count == bat_priv->num_local_hna) | ||
162 | atomic_set(&bat_priv->hna_local_changed, 0); | ||
163 | |||
164 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
165 | return i; | ||
166 | } | ||
167 | |||
168 | int hna_local_seq_print_text(struct seq_file *seq, void *offset) | ||
169 | { | ||
170 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
171 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
172 | struct hashtable_t *hash = bat_priv->hna_local_hash; | ||
173 | struct hna_local_entry *hna_local_entry; | ||
174 | int i; | ||
175 | struct hlist_node *walk; | ||
176 | struct hlist_head *head; | ||
177 | struct element_t *bucket; | ||
178 | size_t buf_size, pos; | ||
179 | char *buff; | ||
180 | |||
181 | if (!bat_priv->primary_if) { | ||
182 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
183 | "please specify interfaces to enable it\n", | ||
184 | net_dev->name); | ||
185 | } | ||
186 | |||
187 | seq_printf(seq, "Locally retrieved addresses (from %s) " | ||
188 | "announced via HNA:\n", | ||
189 | net_dev->name); | ||
190 | |||
191 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
192 | |||
193 | buf_size = 1; | ||
194 | /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */ | ||
195 | for (i = 0; i < hash->size; i++) { | ||
196 | head = &hash->table[i]; | ||
197 | |||
198 | hlist_for_each(walk, head) | ||
199 | buf_size += 21; | ||
200 | } | ||
201 | |||
202 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
203 | if (!buff) { | ||
204 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | buff[0] = '\0'; | ||
208 | pos = 0; | ||
209 | |||
210 | for (i = 0; i < hash->size; i++) { | ||
211 | head = &hash->table[i]; | ||
212 | |||
213 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
214 | hna_local_entry = bucket->data; | ||
215 | |||
216 | pos += snprintf(buff + pos, 22, " * %pM\n", | ||
217 | hna_local_entry->addr); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
222 | |||
223 | seq_printf(seq, "%s", buff); | ||
224 | kfree(buff); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static void _hna_local_del(void *data, void *arg) | ||
229 | { | ||
230 | struct bat_priv *bat_priv = (struct bat_priv *)arg; | ||
231 | |||
232 | kfree(data); | ||
233 | bat_priv->num_local_hna--; | ||
234 | atomic_set(&bat_priv->hna_local_changed, 1); | ||
235 | } | ||
236 | |||
237 | static void hna_local_del(struct bat_priv *bat_priv, | ||
238 | struct hna_local_entry *hna_local_entry, | ||
239 | char *message) | ||
240 | { | ||
241 | bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n", | ||
242 | hna_local_entry->addr, message); | ||
243 | |||
244 | hash_remove(bat_priv->hna_local_hash, compare_orig, choose_orig, | ||
245 | hna_local_entry->addr); | ||
246 | _hna_local_del(hna_local_entry, bat_priv); | ||
247 | } | ||
248 | |||
249 | void hna_local_remove(struct bat_priv *bat_priv, | ||
250 | uint8_t *addr, char *message) | ||
251 | { | ||
252 | struct hna_local_entry *hna_local_entry; | ||
253 | |||
254 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
255 | |||
256 | hna_local_entry = (struct hna_local_entry *) | ||
257 | hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig, | ||
258 | addr); | ||
259 | |||
260 | if (hna_local_entry) | ||
261 | hna_local_del(bat_priv, hna_local_entry, message); | ||
262 | |||
263 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
264 | } | ||
265 | |||
266 | static void hna_local_purge(struct work_struct *work) | ||
267 | { | ||
268 | struct delayed_work *delayed_work = | ||
269 | container_of(work, struct delayed_work, work); | ||
270 | struct bat_priv *bat_priv = | ||
271 | container_of(delayed_work, struct bat_priv, hna_work); | ||
272 | struct hashtable_t *hash = bat_priv->hna_local_hash; | ||
273 | struct hna_local_entry *hna_local_entry; | ||
274 | int i; | ||
275 | struct hlist_node *walk, *safe; | ||
276 | struct hlist_head *head; | ||
277 | struct element_t *bucket; | ||
278 | unsigned long timeout; | ||
279 | |||
280 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
281 | |||
282 | for (i = 0; i < hash->size; i++) { | ||
283 | head = &hash->table[i]; | ||
284 | |||
285 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | ||
286 | hna_local_entry = bucket->data; | ||
287 | |||
288 | timeout = hna_local_entry->last_seen; | ||
289 | timeout += LOCAL_HNA_TIMEOUT * HZ; | ||
290 | |||
291 | if ((!hna_local_entry->never_purge) && | ||
292 | time_after(jiffies, timeout)) | ||
293 | hna_local_del(bat_priv, hna_local_entry, | ||
294 | "address timed out"); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
299 | hna_local_start_timer(bat_priv); | ||
300 | } | ||
301 | |||
302 | void hna_local_free(struct bat_priv *bat_priv) | ||
303 | { | ||
304 | if (!bat_priv->hna_local_hash) | ||
305 | return; | ||
306 | |||
307 | cancel_delayed_work_sync(&bat_priv->hna_work); | ||
308 | hash_delete(bat_priv->hna_local_hash, _hna_local_del, bat_priv); | ||
309 | bat_priv->hna_local_hash = NULL; | ||
310 | } | ||
311 | |||
312 | int hna_global_init(struct bat_priv *bat_priv) | ||
313 | { | ||
314 | if (bat_priv->hna_global_hash) | ||
315 | return 1; | ||
316 | |||
317 | bat_priv->hna_global_hash = hash_new(1024); | ||
318 | |||
319 | if (!bat_priv->hna_global_hash) | ||
320 | return 0; | ||
321 | |||
322 | return 1; | ||
323 | } | ||
324 | |||
325 | void hna_global_add_orig(struct bat_priv *bat_priv, | ||
326 | struct orig_node *orig_node, | ||
327 | unsigned char *hna_buff, int hna_buff_len) | ||
328 | { | ||
329 | struct hna_global_entry *hna_global_entry; | ||
330 | struct hna_local_entry *hna_local_entry; | ||
331 | int hna_buff_count = 0; | ||
332 | unsigned char *hna_ptr; | ||
333 | |||
334 | while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { | ||
335 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
336 | |||
337 | hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); | ||
338 | hna_global_entry = (struct hna_global_entry *) | ||
339 | hash_find(bat_priv->hna_global_hash, compare_orig, | ||
340 | choose_orig, hna_ptr); | ||
341 | |||
342 | if (!hna_global_entry) { | ||
343 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
344 | |||
345 | hna_global_entry = | ||
346 | kmalloc(sizeof(struct hna_global_entry), | ||
347 | GFP_ATOMIC); | ||
348 | |||
349 | if (!hna_global_entry) | ||
350 | break; | ||
351 | |||
352 | memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN); | ||
353 | |||
354 | bat_dbg(DBG_ROUTES, bat_priv, | ||
355 | "Creating new global hna entry: " | ||
356 | "%pM (via %pM)\n", | ||
357 | hna_global_entry->addr, orig_node->orig); | ||
358 | |||
359 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
360 | hash_add(bat_priv->hna_global_hash, compare_orig, | ||
361 | choose_orig, hna_global_entry); | ||
362 | |||
363 | } | ||
364 | |||
365 | hna_global_entry->orig_node = orig_node; | ||
366 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
367 | |||
368 | /* remove address from local hash if present */ | ||
369 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
370 | |||
371 | hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); | ||
372 | hna_local_entry = (struct hna_local_entry *) | ||
373 | hash_find(bat_priv->hna_local_hash, compare_orig, | ||
374 | choose_orig, hna_ptr); | ||
375 | |||
376 | if (hna_local_entry) | ||
377 | hna_local_del(bat_priv, hna_local_entry, | ||
378 | "global hna received"); | ||
379 | |||
380 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
381 | |||
382 | hna_buff_count++; | ||
383 | } | ||
384 | |||
385 | /* initialize, and overwrite if malloc succeeds */ | ||
386 | orig_node->hna_buff = NULL; | ||
387 | orig_node->hna_buff_len = 0; | ||
388 | |||
389 | if (hna_buff_len > 0) { | ||
390 | orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC); | ||
391 | if (orig_node->hna_buff) { | ||
392 | memcpy(orig_node->hna_buff, hna_buff, hna_buff_len); | ||
393 | orig_node->hna_buff_len = hna_buff_len; | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | |||
398 | int hna_global_seq_print_text(struct seq_file *seq, void *offset) | ||
399 | { | ||
400 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
401 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
402 | struct hashtable_t *hash = bat_priv->hna_global_hash; | ||
403 | struct hna_global_entry *hna_global_entry; | ||
404 | int i; | ||
405 | struct hlist_node *walk; | ||
406 | struct hlist_head *head; | ||
407 | struct element_t *bucket; | ||
408 | size_t buf_size, pos; | ||
409 | char *buff; | ||
410 | |||
411 | if (!bat_priv->primary_if) { | ||
412 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
413 | "please specify interfaces to enable it\n", | ||
414 | net_dev->name); | ||
415 | } | ||
416 | |||
417 | seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", | ||
418 | net_dev->name); | ||
419 | |||
420 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
421 | |||
422 | buf_size = 1; | ||
423 | /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ | ||
424 | for (i = 0; i < hash->size; i++) { | ||
425 | head = &hash->table[i]; | ||
426 | |||
427 | hlist_for_each(walk, head) | ||
428 | buf_size += 43; | ||
429 | } | ||
430 | |||
431 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
432 | if (!buff) { | ||
433 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
434 | return -ENOMEM; | ||
435 | } | ||
436 | buff[0] = '\0'; | ||
437 | pos = 0; | ||
438 | |||
439 | for (i = 0; i < hash->size; i++) { | ||
440 | head = &hash->table[i]; | ||
441 | |||
442 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
443 | hna_global_entry = bucket->data; | ||
444 | |||
445 | pos += snprintf(buff + pos, 44, | ||
446 | " * %pM via %pM\n", | ||
447 | hna_global_entry->addr, | ||
448 | hna_global_entry->orig_node->orig); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
453 | |||
454 | seq_printf(seq, "%s", buff); | ||
455 | kfree(buff); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static void _hna_global_del_orig(struct bat_priv *bat_priv, | ||
460 | struct hna_global_entry *hna_global_entry, | ||
461 | char *message) | ||
462 | { | ||
463 | bat_dbg(DBG_ROUTES, bat_priv, | ||
464 | "Deleting global hna entry %pM (via %pM): %s\n", | ||
465 | hna_global_entry->addr, hna_global_entry->orig_node->orig, | ||
466 | message); | ||
467 | |||
468 | hash_remove(bat_priv->hna_global_hash, compare_orig, choose_orig, | ||
469 | hna_global_entry->addr); | ||
470 | kfree(hna_global_entry); | ||
471 | } | ||
472 | |||
473 | void hna_global_del_orig(struct bat_priv *bat_priv, | ||
474 | struct orig_node *orig_node, char *message) | ||
475 | { | ||
476 | struct hna_global_entry *hna_global_entry; | ||
477 | int hna_buff_count = 0; | ||
478 | unsigned char *hna_ptr; | ||
479 | |||
480 | if (orig_node->hna_buff_len == 0) | ||
481 | return; | ||
482 | |||
483 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
484 | |||
485 | while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { | ||
486 | hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); | ||
487 | hna_global_entry = (struct hna_global_entry *) | ||
488 | hash_find(bat_priv->hna_global_hash, compare_orig, | ||
489 | choose_orig, hna_ptr); | ||
490 | |||
491 | if ((hna_global_entry) && | ||
492 | (hna_global_entry->orig_node == orig_node)) | ||
493 | _hna_global_del_orig(bat_priv, hna_global_entry, | ||
494 | message); | ||
495 | |||
496 | hna_buff_count++; | ||
497 | } | ||
498 | |||
499 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
500 | |||
501 | orig_node->hna_buff_len = 0; | ||
502 | kfree(orig_node->hna_buff); | ||
503 | orig_node->hna_buff = NULL; | ||
504 | } | ||
505 | |||
506 | static void hna_global_del(void *data, void *arg) | ||
507 | { | ||
508 | kfree(data); | ||
509 | } | ||
510 | |||
511 | void hna_global_free(struct bat_priv *bat_priv) | ||
512 | { | ||
513 | if (!bat_priv->hna_global_hash) | ||
514 | return; | ||
515 | |||
516 | hash_delete(bat_priv->hna_global_hash, hna_global_del, NULL); | ||
517 | bat_priv->hna_global_hash = NULL; | ||
518 | } | ||
519 | |||
520 | struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr) | ||
521 | { | ||
522 | struct hna_global_entry *hna_global_entry; | ||
523 | |||
524 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
525 | hna_global_entry = (struct hna_global_entry *) | ||
526 | hash_find(bat_priv->hna_global_hash, | ||
527 | compare_orig, choose_orig, addr); | ||
528 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
529 | |||
530 | if (!hna_global_entry) | ||
531 | return NULL; | ||
532 | |||
533 | return hna_global_entry->orig_node; | ||
534 | } | ||
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h new file mode 100644 index 000000000000..10c4c5c319b6 --- /dev/null +++ b/net/batman-adv/translation-table.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ | ||
23 | #define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ | ||
24 | |||
25 | #include "types.h" | ||
26 | |||
27 | int hna_local_init(struct bat_priv *bat_priv); | ||
28 | void hna_local_add(struct net_device *soft_iface, uint8_t *addr); | ||
29 | void hna_local_remove(struct bat_priv *bat_priv, | ||
30 | uint8_t *addr, char *message); | ||
31 | int hna_local_fill_buffer(struct bat_priv *bat_priv, | ||
32 | unsigned char *buff, int buff_len); | ||
33 | int hna_local_seq_print_text(struct seq_file *seq, void *offset); | ||
34 | void hna_local_free(struct bat_priv *bat_priv); | ||
35 | int hna_global_init(struct bat_priv *bat_priv); | ||
36 | void hna_global_add_orig(struct bat_priv *bat_priv, | ||
37 | struct orig_node *orig_node, | ||
38 | unsigned char *hna_buff, int hna_buff_len); | ||
39 | int hna_global_seq_print_text(struct seq_file *seq, void *offset); | ||
40 | void hna_global_del_orig(struct bat_priv *bat_priv, | ||
41 | struct orig_node *orig_node, char *message); | ||
42 | void hna_global_free(struct bat_priv *bat_priv); | ||
43 | struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr); | ||
44 | |||
45 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ | ||
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h new file mode 100644 index 000000000000..97cb23dd3e69 --- /dev/null +++ b/net/batman-adv/types.h | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | #ifndef _NET_BATMAN_ADV_TYPES_H_ | ||
25 | #define _NET_BATMAN_ADV_TYPES_H_ | ||
26 | |||
27 | #include "packet.h" | ||
28 | #include "bitarray.h" | ||
29 | |||
30 | #define BAT_HEADER_LEN (sizeof(struct ethhdr) + \ | ||
31 | ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? \ | ||
32 | sizeof(struct unicast_packet) : \ | ||
33 | sizeof(struct bcast_packet)))) | ||
34 | |||
35 | |||
36 | struct batman_if { | ||
37 | struct list_head list; | ||
38 | int16_t if_num; | ||
39 | char if_status; | ||
40 | struct net_device *net_dev; | ||
41 | atomic_t seqno; | ||
42 | atomic_t frag_seqno; | ||
43 | unsigned char *packet_buff; | ||
44 | int packet_len; | ||
45 | struct kobject *hardif_obj; | ||
46 | struct kref refcount; | ||
47 | struct packet_type batman_adv_ptype; | ||
48 | struct net_device *soft_iface; | ||
49 | struct rcu_head rcu; | ||
50 | }; | ||
51 | |||
52 | /** | ||
53 | * orig_node - structure for orig_list maintaining nodes of mesh | ||
54 | * @primary_addr: hosts primary interface address | ||
55 | * @last_valid: when last packet from this node was received | ||
56 | * @bcast_seqno_reset: time when the broadcast seqno window was reset | ||
57 | * @batman_seqno_reset: time when the batman seqno window was reset | ||
58 | * @gw_flags: flags related to gateway class | ||
59 | * @flags: for now only VIS_SERVER flag | ||
60 | * @last_real_seqno: last and best known squence number | ||
61 | * @last_ttl: ttl of last received packet | ||
62 | * @last_bcast_seqno: last broadcast sequence number received by this host | ||
63 | * | ||
64 | * @candidates: how many candidates are available | ||
65 | * @selected: next bonding candidate | ||
66 | */ | ||
67 | struct orig_node { | ||
68 | uint8_t orig[ETH_ALEN]; | ||
69 | uint8_t primary_addr[ETH_ALEN]; | ||
70 | struct neigh_node *router; | ||
71 | unsigned long *bcast_own; | ||
72 | uint8_t *bcast_own_sum; | ||
73 | uint8_t tq_own; | ||
74 | int tq_asym_penalty; | ||
75 | unsigned long last_valid; | ||
76 | unsigned long bcast_seqno_reset; | ||
77 | unsigned long batman_seqno_reset; | ||
78 | uint8_t gw_flags; | ||
79 | uint8_t flags; | ||
80 | unsigned char *hna_buff; | ||
81 | int16_t hna_buff_len; | ||
82 | uint32_t last_real_seqno; | ||
83 | uint8_t last_ttl; | ||
84 | unsigned long bcast_bits[NUM_WORDS]; | ||
85 | uint32_t last_bcast_seqno; | ||
86 | struct list_head neigh_list; | ||
87 | struct list_head frag_list; | ||
88 | unsigned long last_frag_packet; | ||
89 | struct { | ||
90 | uint8_t candidates; | ||
91 | struct neigh_node *selected; | ||
92 | } bond; | ||
93 | }; | ||
94 | |||
95 | struct gw_node { | ||
96 | struct hlist_node list; | ||
97 | struct orig_node *orig_node; | ||
98 | unsigned long deleted; | ||
99 | struct kref refcount; | ||
100 | struct rcu_head rcu; | ||
101 | }; | ||
102 | |||
103 | /** | ||
104 | * neigh_node | ||
105 | * @last_valid: when last packet via this neighbor was received | ||
106 | */ | ||
107 | struct neigh_node { | ||
108 | struct list_head list; | ||
109 | uint8_t addr[ETH_ALEN]; | ||
110 | uint8_t real_packet_count; | ||
111 | uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE]; | ||
112 | uint8_t tq_index; | ||
113 | uint8_t tq_avg; | ||
114 | uint8_t last_ttl; | ||
115 | struct neigh_node *next_bond_candidate; | ||
116 | unsigned long last_valid; | ||
117 | unsigned long real_bits[NUM_WORDS]; | ||
118 | struct orig_node *orig_node; | ||
119 | struct batman_if *if_incoming; | ||
120 | }; | ||
121 | |||
122 | |||
123 | struct bat_priv { | ||
124 | atomic_t mesh_state; | ||
125 | struct net_device_stats stats; | ||
126 | atomic_t aggregated_ogms; /* boolean */ | ||
127 | atomic_t bonding; /* boolean */ | ||
128 | atomic_t fragmentation; /* boolean */ | ||
129 | atomic_t vis_mode; /* VIS_TYPE_* */ | ||
130 | atomic_t gw_mode; /* GW_MODE_* */ | ||
131 | atomic_t gw_sel_class; /* uint */ | ||
132 | atomic_t gw_bandwidth; /* gw bandwidth */ | ||
133 | atomic_t orig_interval; /* uint */ | ||
134 | atomic_t hop_penalty; /* uint */ | ||
135 | atomic_t log_level; /* uint */ | ||
136 | atomic_t bcast_seqno; | ||
137 | atomic_t bcast_queue_left; | ||
138 | atomic_t batman_queue_left; | ||
139 | char num_ifaces; | ||
140 | struct hlist_head softif_neigh_list; | ||
141 | struct softif_neigh *softif_neigh; | ||
142 | struct debug_log *debug_log; | ||
143 | struct batman_if *primary_if; | ||
144 | struct kobject *mesh_obj; | ||
145 | struct dentry *debug_dir; | ||
146 | struct hlist_head forw_bat_list; | ||
147 | struct hlist_head forw_bcast_list; | ||
148 | struct hlist_head gw_list; | ||
149 | struct list_head vis_send_list; | ||
150 | struct hashtable_t *orig_hash; | ||
151 | struct hashtable_t *hna_local_hash; | ||
152 | struct hashtable_t *hna_global_hash; | ||
153 | struct hashtable_t *vis_hash; | ||
154 | spinlock_t orig_hash_lock; /* protects orig_hash */ | ||
155 | spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ | ||
156 | spinlock_t forw_bcast_list_lock; /* protects */ | ||
157 | spinlock_t hna_lhash_lock; /* protects hna_local_hash */ | ||
158 | spinlock_t hna_ghash_lock; /* protects hna_global_hash */ | ||
159 | spinlock_t gw_list_lock; /* protects gw_list */ | ||
160 | spinlock_t vis_hash_lock; /* protects vis_hash */ | ||
161 | spinlock_t vis_list_lock; /* protects vis_info::recv_list */ | ||
162 | spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ | ||
163 | int16_t num_local_hna; | ||
164 | atomic_t hna_local_changed; | ||
165 | struct delayed_work hna_work; | ||
166 | struct delayed_work orig_work; | ||
167 | struct delayed_work vis_work; | ||
168 | struct gw_node *curr_gw; | ||
169 | struct vis_info *my_vis_info; | ||
170 | }; | ||
171 | |||
172 | struct socket_client { | ||
173 | struct list_head queue_list; | ||
174 | unsigned int queue_len; | ||
175 | unsigned char index; | ||
176 | spinlock_t lock; /* protects queue_list, queue_len, index */ | ||
177 | wait_queue_head_t queue_wait; | ||
178 | struct bat_priv *bat_priv; | ||
179 | }; | ||
180 | |||
181 | struct socket_packet { | ||
182 | struct list_head list; | ||
183 | size_t icmp_len; | ||
184 | struct icmp_packet_rr icmp_packet; | ||
185 | }; | ||
186 | |||
187 | struct hna_local_entry { | ||
188 | uint8_t addr[ETH_ALEN]; | ||
189 | unsigned long last_seen; | ||
190 | char never_purge; | ||
191 | }; | ||
192 | |||
193 | struct hna_global_entry { | ||
194 | uint8_t addr[ETH_ALEN]; | ||
195 | struct orig_node *orig_node; | ||
196 | }; | ||
197 | |||
198 | /** | ||
199 | * forw_packet - structure for forw_list maintaining packets to be | ||
200 | * send/forwarded | ||
201 | */ | ||
202 | struct forw_packet { | ||
203 | struct hlist_node list; | ||
204 | unsigned long send_time; | ||
205 | uint8_t own; | ||
206 | struct sk_buff *skb; | ||
207 | uint16_t packet_len; | ||
208 | uint32_t direct_link_flags; | ||
209 | uint8_t num_packets; | ||
210 | struct delayed_work delayed_work; | ||
211 | struct batman_if *if_incoming; | ||
212 | }; | ||
213 | |||
214 | /* While scanning for vis-entries of a particular vis-originator | ||
215 | * this list collects its interfaces to create a subgraph/cluster | ||
216 | * out of them later | ||
217 | */ | ||
218 | struct if_list_entry { | ||
219 | uint8_t addr[ETH_ALEN]; | ||
220 | bool primary; | ||
221 | struct hlist_node list; | ||
222 | }; | ||
223 | |||
224 | struct debug_log { | ||
225 | char log_buff[LOG_BUF_LEN]; | ||
226 | unsigned long log_start; | ||
227 | unsigned long log_end; | ||
228 | spinlock_t lock; /* protects log_buff, log_start and log_end */ | ||
229 | wait_queue_head_t queue_wait; | ||
230 | }; | ||
231 | |||
232 | struct frag_packet_list_entry { | ||
233 | struct list_head list; | ||
234 | uint16_t seqno; | ||
235 | struct sk_buff *skb; | ||
236 | }; | ||
237 | |||
238 | struct vis_info { | ||
239 | unsigned long first_seen; | ||
240 | struct list_head recv_list; | ||
241 | /* list of server-neighbors we received a vis-packet | ||
242 | * from. we should not reply to them. */ | ||
243 | struct list_head send_list; | ||
244 | struct kref refcount; | ||
245 | struct bat_priv *bat_priv; | ||
246 | /* this packet might be part of the vis send queue. */ | ||
247 | struct sk_buff *skb_packet; | ||
248 | /* vis_info may follow here*/ | ||
249 | } __attribute__((packed)); | ||
250 | |||
251 | struct vis_info_entry { | ||
252 | uint8_t src[ETH_ALEN]; | ||
253 | uint8_t dest[ETH_ALEN]; | ||
254 | uint8_t quality; /* quality = 0 means HNA */ | ||
255 | } __attribute__((packed)); | ||
256 | |||
257 | struct recvlist_node { | ||
258 | struct list_head list; | ||
259 | uint8_t mac[ETH_ALEN]; | ||
260 | }; | ||
261 | |||
262 | struct softif_neigh { | ||
263 | struct hlist_node list; | ||
264 | uint8_t addr[ETH_ALEN]; | ||
265 | unsigned long last_seen; | ||
266 | short vid; | ||
267 | struct kref refcount; | ||
268 | struct rcu_head rcu; | ||
269 | }; | ||
270 | |||
271 | #endif /* _NET_BATMAN_ADV_TYPES_H_ */ | ||
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c new file mode 100644 index 000000000000..dc2e28bed844 --- /dev/null +++ b/net/batman-adv/unicast.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Andreas Langer | ||
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 "unicast.h" | ||
24 | #include "send.h" | ||
25 | #include "soft-interface.h" | ||
26 | #include "gateway_client.h" | ||
27 | #include "originator.h" | ||
28 | #include "hash.h" | ||
29 | #include "translation-table.h" | ||
30 | #include "routing.h" | ||
31 | #include "hard-interface.h" | ||
32 | |||
33 | |||
34 | static struct sk_buff *frag_merge_packet(struct list_head *head, | ||
35 | struct frag_packet_list_entry *tfp, | ||
36 | struct sk_buff *skb) | ||
37 | { | ||
38 | struct unicast_frag_packet *up = | ||
39 | (struct unicast_frag_packet *)skb->data; | ||
40 | struct sk_buff *tmp_skb; | ||
41 | struct unicast_packet *unicast_packet; | ||
42 | int hdr_len = sizeof(struct unicast_packet), | ||
43 | uni_diff = sizeof(struct unicast_frag_packet) - hdr_len; | ||
44 | |||
45 | /* set skb to the first part and tmp_skb to the second part */ | ||
46 | if (up->flags & UNI_FRAG_HEAD) { | ||
47 | tmp_skb = tfp->skb; | ||
48 | } else { | ||
49 | tmp_skb = skb; | ||
50 | skb = tfp->skb; | ||
51 | } | ||
52 | |||
53 | skb_pull(tmp_skb, sizeof(struct unicast_frag_packet)); | ||
54 | if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) { | ||
55 | /* free buffered skb, skb will be freed later */ | ||
56 | kfree_skb(tfp->skb); | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | /* move free entry to end */ | ||
61 | tfp->skb = NULL; | ||
62 | tfp->seqno = 0; | ||
63 | list_move_tail(&tfp->list, head); | ||
64 | |||
65 | memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len); | ||
66 | kfree_skb(tmp_skb); | ||
67 | |||
68 | memmove(skb->data + uni_diff, skb->data, hdr_len); | ||
69 | unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff); | ||
70 | unicast_packet->packet_type = BAT_UNICAST; | ||
71 | |||
72 | return skb; | ||
73 | } | ||
74 | |||
75 | static void frag_create_entry(struct list_head *head, struct sk_buff *skb) | ||
76 | { | ||
77 | struct frag_packet_list_entry *tfp; | ||
78 | struct unicast_frag_packet *up = | ||
79 | (struct unicast_frag_packet *)skb->data; | ||
80 | |||
81 | /* free and oldest packets stand at the end */ | ||
82 | tfp = list_entry((head)->prev, typeof(*tfp), list); | ||
83 | kfree_skb(tfp->skb); | ||
84 | |||
85 | tfp->seqno = ntohs(up->seqno); | ||
86 | tfp->skb = skb; | ||
87 | list_move(&tfp->list, head); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | static int frag_create_buffer(struct list_head *head) | ||
92 | { | ||
93 | int i; | ||
94 | struct frag_packet_list_entry *tfp; | ||
95 | |||
96 | for (i = 0; i < FRAG_BUFFER_SIZE; i++) { | ||
97 | tfp = kmalloc(sizeof(struct frag_packet_list_entry), | ||
98 | GFP_ATOMIC); | ||
99 | if (!tfp) { | ||
100 | frag_list_free(head); | ||
101 | return -ENOMEM; | ||
102 | } | ||
103 | tfp->skb = NULL; | ||
104 | tfp->seqno = 0; | ||
105 | INIT_LIST_HEAD(&tfp->list); | ||
106 | list_add(&tfp->list, head); | ||
107 | } | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static struct frag_packet_list_entry *frag_search_packet(struct list_head *head, | ||
113 | struct unicast_frag_packet *up) | ||
114 | { | ||
115 | struct frag_packet_list_entry *tfp; | ||
116 | struct unicast_frag_packet *tmp_up = NULL; | ||
117 | uint16_t search_seqno; | ||
118 | |||
119 | if (up->flags & UNI_FRAG_HEAD) | ||
120 | search_seqno = ntohs(up->seqno)+1; | ||
121 | else | ||
122 | search_seqno = ntohs(up->seqno)-1; | ||
123 | |||
124 | list_for_each_entry(tfp, head, list) { | ||
125 | |||
126 | if (!tfp->skb) | ||
127 | continue; | ||
128 | |||
129 | if (tfp->seqno == ntohs(up->seqno)) | ||
130 | goto mov_tail; | ||
131 | |||
132 | tmp_up = (struct unicast_frag_packet *)tfp->skb->data; | ||
133 | |||
134 | if (tfp->seqno == search_seqno) { | ||
135 | |||
136 | if ((tmp_up->flags & UNI_FRAG_HEAD) != | ||
137 | (up->flags & UNI_FRAG_HEAD)) | ||
138 | return tfp; | ||
139 | else | ||
140 | goto mov_tail; | ||
141 | } | ||
142 | } | ||
143 | return NULL; | ||
144 | |||
145 | mov_tail: | ||
146 | list_move_tail(&tfp->list, head); | ||
147 | return NULL; | ||
148 | } | ||
149 | |||
150 | void frag_list_free(struct list_head *head) | ||
151 | { | ||
152 | struct frag_packet_list_entry *pf, *tmp_pf; | ||
153 | |||
154 | if (!list_empty(head)) { | ||
155 | |||
156 | list_for_each_entry_safe(pf, tmp_pf, head, list) { | ||
157 | kfree_skb(pf->skb); | ||
158 | list_del(&pf->list); | ||
159 | kfree(pf); | ||
160 | } | ||
161 | } | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | /* frag_reassemble_skb(): | ||
166 | * returns NET_RX_DROP if the operation failed - skb is left intact | ||
167 | * returns NET_RX_SUCCESS if the fragment was buffered (skb_new will be NULL) | ||
168 | * or the skb could be reassembled (skb_new will point to the new packet and | ||
169 | * skb was freed) | ||
170 | */ | ||
171 | int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | ||
172 | struct sk_buff **new_skb) | ||
173 | { | ||
174 | struct orig_node *orig_node; | ||
175 | struct frag_packet_list_entry *tmp_frag_entry; | ||
176 | int ret = NET_RX_DROP; | ||
177 | struct unicast_frag_packet *unicast_packet = | ||
178 | (struct unicast_frag_packet *)skb->data; | ||
179 | |||
180 | *new_skb = NULL; | ||
181 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
182 | orig_node = ((struct orig_node *) | ||
183 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
184 | unicast_packet->orig)); | ||
185 | |||
186 | if (!orig_node) { | ||
187 | pr_debug("couldn't find originator in orig_hash\n"); | ||
188 | goto out; | ||
189 | } | ||
190 | |||
191 | orig_node->last_frag_packet = jiffies; | ||
192 | |||
193 | if (list_empty(&orig_node->frag_list) && | ||
194 | frag_create_buffer(&orig_node->frag_list)) { | ||
195 | pr_debug("couldn't create frag buffer\n"); | ||
196 | goto out; | ||
197 | } | ||
198 | |||
199 | tmp_frag_entry = frag_search_packet(&orig_node->frag_list, | ||
200 | unicast_packet); | ||
201 | |||
202 | if (!tmp_frag_entry) { | ||
203 | frag_create_entry(&orig_node->frag_list, skb); | ||
204 | ret = NET_RX_SUCCESS; | ||
205 | goto out; | ||
206 | } | ||
207 | |||
208 | *new_skb = frag_merge_packet(&orig_node->frag_list, tmp_frag_entry, | ||
209 | skb); | ||
210 | /* if not, merge failed */ | ||
211 | if (*new_skb) | ||
212 | ret = NET_RX_SUCCESS; | ||
213 | out: | ||
214 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | ||
220 | struct batman_if *batman_if, uint8_t dstaddr[]) | ||
221 | { | ||
222 | struct unicast_packet tmp_uc, *unicast_packet; | ||
223 | struct sk_buff *frag_skb; | ||
224 | struct unicast_frag_packet *frag1, *frag2; | ||
225 | int uc_hdr_len = sizeof(struct unicast_packet); | ||
226 | int ucf_hdr_len = sizeof(struct unicast_frag_packet); | ||
227 | int data_len = skb->len; | ||
228 | |||
229 | if (!bat_priv->primary_if) | ||
230 | goto dropped; | ||
231 | |||
232 | unicast_packet = (struct unicast_packet *) skb->data; | ||
233 | |||
234 | memcpy(&tmp_uc, unicast_packet, uc_hdr_len); | ||
235 | frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); | ||
236 | skb_split(skb, frag_skb, data_len / 2); | ||
237 | |||
238 | if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 || | ||
239 | my_skb_head_push(frag_skb, ucf_hdr_len) < 0) | ||
240 | goto drop_frag; | ||
241 | |||
242 | frag1 = (struct unicast_frag_packet *)skb->data; | ||
243 | frag2 = (struct unicast_frag_packet *)frag_skb->data; | ||
244 | |||
245 | memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet)); | ||
246 | |||
247 | frag1->ttl--; | ||
248 | frag1->version = COMPAT_VERSION; | ||
249 | frag1->packet_type = BAT_UNICAST_FRAG; | ||
250 | |||
251 | memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
252 | memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); | ||
253 | |||
254 | frag1->flags |= UNI_FRAG_HEAD; | ||
255 | frag2->flags &= ~UNI_FRAG_HEAD; | ||
256 | |||
257 | frag1->seqno = htons((uint16_t)atomic_inc_return( | ||
258 | &batman_if->frag_seqno)); | ||
259 | frag2->seqno = htons((uint16_t)atomic_inc_return( | ||
260 | &batman_if->frag_seqno)); | ||
261 | |||
262 | send_skb_packet(skb, batman_if, dstaddr); | ||
263 | send_skb_packet(frag_skb, batman_if, dstaddr); | ||
264 | return NET_RX_SUCCESS; | ||
265 | |||
266 | drop_frag: | ||
267 | kfree_skb(frag_skb); | ||
268 | dropped: | ||
269 | kfree_skb(skb); | ||
270 | return NET_RX_DROP; | ||
271 | } | ||
272 | |||
273 | int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) | ||
274 | { | ||
275 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
276 | struct unicast_packet *unicast_packet; | ||
277 | struct orig_node *orig_node; | ||
278 | struct batman_if *batman_if; | ||
279 | struct neigh_node *router; | ||
280 | int data_len = skb->len; | ||
281 | uint8_t dstaddr[6]; | ||
282 | |||
283 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
284 | |||
285 | /* get routing information */ | ||
286 | if (is_multicast_ether_addr(ethhdr->h_dest)) | ||
287 | orig_node = (struct orig_node *)gw_get_selected(bat_priv); | ||
288 | else | ||
289 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
290 | compare_orig, | ||
291 | choose_orig, | ||
292 | ethhdr->h_dest)); | ||
293 | |||
294 | /* check for hna host */ | ||
295 | if (!orig_node) | ||
296 | orig_node = transtable_search(bat_priv, ethhdr->h_dest); | ||
297 | |||
298 | router = find_router(bat_priv, orig_node, NULL); | ||
299 | |||
300 | if (!router) | ||
301 | goto unlock; | ||
302 | |||
303 | /* don't lock while sending the packets ... we therefore | ||
304 | * copy the required data before sending */ | ||
305 | |||
306 | batman_if = router->if_incoming; | ||
307 | memcpy(dstaddr, router->addr, ETH_ALEN); | ||
308 | |||
309 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
310 | |||
311 | if (batman_if->if_status != IF_ACTIVE) | ||
312 | goto dropped; | ||
313 | |||
314 | if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) | ||
315 | goto dropped; | ||
316 | |||
317 | unicast_packet = (struct unicast_packet *)skb->data; | ||
318 | |||
319 | unicast_packet->version = COMPAT_VERSION; | ||
320 | /* batman packet type: unicast */ | ||
321 | unicast_packet->packet_type = BAT_UNICAST; | ||
322 | /* set unicast ttl */ | ||
323 | unicast_packet->ttl = TTL; | ||
324 | /* copy the destination for faster routing */ | ||
325 | memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); | ||
326 | |||
327 | if (atomic_read(&bat_priv->fragmentation) && | ||
328 | data_len + sizeof(struct unicast_packet) > | ||
329 | batman_if->net_dev->mtu) { | ||
330 | /* send frag skb decreases ttl */ | ||
331 | unicast_packet->ttl++; | ||
332 | return frag_send_skb(skb, bat_priv, batman_if, | ||
333 | dstaddr); | ||
334 | } | ||
335 | send_skb_packet(skb, batman_if, dstaddr); | ||
336 | return 0; | ||
337 | |||
338 | unlock: | ||
339 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
340 | dropped: | ||
341 | kfree_skb(skb); | ||
342 | return 1; | ||
343 | } | ||
diff --git a/net/batman-adv/unicast.h b/net/batman-adv/unicast.h new file mode 100644 index 000000000000..e32b7867a9a4 --- /dev/null +++ b/net/batman-adv/unicast.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Andreas Langer | ||
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 _NET_BATMAN_ADV_UNICAST_H_ | ||
23 | #define _NET_BATMAN_ADV_UNICAST_H_ | ||
24 | |||
25 | #define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */ | ||
26 | #define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */ | ||
27 | |||
28 | int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | ||
29 | struct sk_buff **new_skb); | ||
30 | void frag_list_free(struct list_head *head); | ||
31 | int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); | ||
32 | int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | ||
33 | struct batman_if *batman_if, uint8_t dstaddr[]); | ||
34 | |||
35 | #endif /* _NET_BATMAN_ADV_UNICAST_H_ */ | ||
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c new file mode 100644 index 000000000000..cd4c4231fa48 --- /dev/null +++ b/net/batman-adv/vis.c | |||
@@ -0,0 +1,949 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2010 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 "soft-interface.h" | ||
27 | #include "hard-interface.h" | ||
28 | #include "hash.h" | ||
29 | #include "originator.h" | ||
30 | |||
31 | #define MAX_VIS_PACKET_SIZE 1000 | ||
32 | |||
33 | /* Returns the smallest signed integer in two's complement with the sizeof x */ | ||
34 | #define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u))) | ||
35 | |||
36 | /* Checks if a sequence number x is a predecessor/successor of y. | ||
37 | * they handle overflows/underflows and can correctly check for a | ||
38 | * predecessor/successor unless the variable sequence number has grown by | ||
39 | * more then 2**(bitwidth(x)-1)-1. | ||
40 | * This means that for a uint8_t with the maximum value 255, it would think: | ||
41 | * - when adding nothing - it is neither a predecessor nor a successor | ||
42 | * - before adding more than 127 to the starting value - it is a predecessor, | ||
43 | * - when adding 128 - it is neither a predecessor nor a successor, | ||
44 | * - after adding more than 127 to the starting value - it is a successor */ | ||
45 | #define seq_before(x, y) ({typeof(x) _dummy = (x - y); \ | ||
46 | _dummy > smallest_signed_int(_dummy); }) | ||
47 | #define seq_after(x, y) seq_before(y, x) | ||
48 | |||
49 | static void start_vis_timer(struct bat_priv *bat_priv); | ||
50 | |||
51 | /* free the info */ | ||
52 | static void free_info(struct kref *ref) | ||
53 | { | ||
54 | struct vis_info *info = container_of(ref, struct vis_info, refcount); | ||
55 | struct bat_priv *bat_priv = info->bat_priv; | ||
56 | struct recvlist_node *entry, *tmp; | ||
57 | |||
58 | list_del_init(&info->send_list); | ||
59 | spin_lock_bh(&bat_priv->vis_list_lock); | ||
60 | list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { | ||
61 | list_del(&entry->list); | ||
62 | kfree(entry); | ||
63 | } | ||
64 | |||
65 | spin_unlock_bh(&bat_priv->vis_list_lock); | ||
66 | kfree_skb(info->skb_packet); | ||
67 | } | ||
68 | |||
69 | /* Compare two vis packets, used by the hashing algorithm */ | ||
70 | static int vis_info_cmp(void *data1, void *data2) | ||
71 | { | ||
72 | struct vis_info *d1, *d2; | ||
73 | struct vis_packet *p1, *p2; | ||
74 | d1 = data1; | ||
75 | d2 = data2; | ||
76 | p1 = (struct vis_packet *)d1->skb_packet->data; | ||
77 | p2 = (struct vis_packet *)d2->skb_packet->data; | ||
78 | return compare_orig(p1->vis_orig, p2->vis_orig); | ||
79 | } | ||
80 | |||
81 | /* hash function to choose an entry in a hash table of given size */ | ||
82 | /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ | ||
83 | static int vis_info_choose(void *data, int size) | ||
84 | { | ||
85 | struct vis_info *vis_info = data; | ||
86 | struct vis_packet *packet; | ||
87 | unsigned char *key; | ||
88 | uint32_t hash = 0; | ||
89 | size_t i; | ||
90 | |||
91 | packet = (struct vis_packet *)vis_info->skb_packet->data; | ||
92 | key = packet->vis_orig; | ||
93 | for (i = 0; i < ETH_ALEN; i++) { | ||
94 | hash += key[i]; | ||
95 | hash += (hash << 10); | ||
96 | hash ^= (hash >> 6); | ||
97 | } | ||
98 | |||
99 | hash += (hash << 3); | ||
100 | hash ^= (hash >> 11); | ||
101 | hash += (hash << 15); | ||
102 | |||
103 | return hash % size; | ||
104 | } | ||
105 | |||
106 | /* insert interface to the list of interfaces of one originator, if it | ||
107 | * does not already exist in the list */ | ||
108 | static void vis_data_insert_interface(const uint8_t *interface, | ||
109 | struct hlist_head *if_list, | ||
110 | bool primary) | ||
111 | { | ||
112 | struct if_list_entry *entry; | ||
113 | struct hlist_node *pos; | ||
114 | |||
115 | hlist_for_each_entry(entry, pos, if_list, list) { | ||
116 | if (compare_orig(entry->addr, (void *)interface)) | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | /* its a new address, add it to the list */ | ||
121 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
122 | if (!entry) | ||
123 | return; | ||
124 | memcpy(entry->addr, interface, ETH_ALEN); | ||
125 | entry->primary = primary; | ||
126 | hlist_add_head(&entry->list, if_list); | ||
127 | } | ||
128 | |||
129 | static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list) | ||
130 | { | ||
131 | struct if_list_entry *entry; | ||
132 | struct hlist_node *pos; | ||
133 | size_t len = 0; | ||
134 | |||
135 | hlist_for_each_entry(entry, pos, if_list, list) { | ||
136 | if (entry->primary) | ||
137 | len += sprintf(buff + len, "PRIMARY, "); | ||
138 | else | ||
139 | len += sprintf(buff + len, "SEC %pM, ", entry->addr); | ||
140 | } | ||
141 | |||
142 | return len; | ||
143 | } | ||
144 | |||
145 | static size_t vis_data_count_prim_sec(struct hlist_head *if_list) | ||
146 | { | ||
147 | struct if_list_entry *entry; | ||
148 | struct hlist_node *pos; | ||
149 | size_t count = 0; | ||
150 | |||
151 | hlist_for_each_entry(entry, pos, if_list, list) { | ||
152 | if (entry->primary) | ||
153 | count += 9; | ||
154 | else | ||
155 | count += 23; | ||
156 | } | ||
157 | |||
158 | return count; | ||
159 | } | ||
160 | |||
161 | /* read an entry */ | ||
162 | static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, | ||
163 | uint8_t *src, bool primary) | ||
164 | { | ||
165 | /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ | ||
166 | if (primary && entry->quality == 0) | ||
167 | return sprintf(buff, "HNA %pM, ", entry->dest); | ||
168 | else if (compare_orig(entry->src, src)) | ||
169 | return sprintf(buff, "TQ %pM %d, ", entry->dest, | ||
170 | entry->quality); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | int vis_seq_print_text(struct seq_file *seq, void *offset) | ||
176 | { | ||
177 | struct hlist_node *walk; | ||
178 | struct hlist_head *head; | ||
179 | struct element_t *bucket; | ||
180 | struct vis_info *info; | ||
181 | struct vis_packet *packet; | ||
182 | struct vis_info_entry *entries; | ||
183 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
184 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
185 | struct hashtable_t *hash = bat_priv->vis_hash; | ||
186 | HLIST_HEAD(vis_if_list); | ||
187 | struct if_list_entry *entry; | ||
188 | struct hlist_node *pos, *n; | ||
189 | int i, j; | ||
190 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
191 | size_t buff_pos, buf_size; | ||
192 | char *buff; | ||
193 | int compare; | ||
194 | |||
195 | if ((!bat_priv->primary_if) || | ||
196 | (vis_server == VIS_TYPE_CLIENT_UPDATE)) | ||
197 | return 0; | ||
198 | |||
199 | buf_size = 1; | ||
200 | /* Estimate length */ | ||
201 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
202 | for (i = 0; i < hash->size; i++) { | ||
203 | head = &hash->table[i]; | ||
204 | |||
205 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
206 | info = bucket->data; | ||
207 | packet = (struct vis_packet *)info->skb_packet->data; | ||
208 | entries = (struct vis_info_entry *) | ||
209 | ((char *)packet + sizeof(struct vis_packet)); | ||
210 | |||
211 | for (j = 0; j < packet->entries; j++) { | ||
212 | if (entries[j].quality == 0) | ||
213 | continue; | ||
214 | compare = | ||
215 | compare_orig(entries[j].src, packet->vis_orig); | ||
216 | vis_data_insert_interface(entries[j].src, | ||
217 | &vis_if_list, | ||
218 | compare); | ||
219 | } | ||
220 | |||
221 | hlist_for_each_entry(entry, pos, &vis_if_list, list) { | ||
222 | buf_size += 18 + 26 * packet->entries; | ||
223 | |||
224 | /* add primary/secondary records */ | ||
225 | if (compare_orig(entry->addr, packet->vis_orig)) | ||
226 | buf_size += | ||
227 | vis_data_count_prim_sec(&vis_if_list); | ||
228 | |||
229 | buf_size += 1; | ||
230 | } | ||
231 | |||
232 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, | ||
233 | list) { | ||
234 | hlist_del(&entry->list); | ||
235 | kfree(entry); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
241 | if (!buff) { | ||
242 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
243 | return -ENOMEM; | ||
244 | } | ||
245 | buff[0] = '\0'; | ||
246 | buff_pos = 0; | ||
247 | |||
248 | for (i = 0; i < hash->size; i++) { | ||
249 | head = &hash->table[i]; | ||
250 | |||
251 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
252 | info = bucket->data; | ||
253 | packet = (struct vis_packet *)info->skb_packet->data; | ||
254 | entries = (struct vis_info_entry *) | ||
255 | ((char *)packet + sizeof(struct vis_packet)); | ||
256 | |||
257 | for (j = 0; j < packet->entries; j++) { | ||
258 | if (entries[j].quality == 0) | ||
259 | continue; | ||
260 | compare = | ||
261 | compare_orig(entries[j].src, packet->vis_orig); | ||
262 | vis_data_insert_interface(entries[j].src, | ||
263 | &vis_if_list, | ||
264 | compare); | ||
265 | } | ||
266 | |||
267 | hlist_for_each_entry(entry, pos, &vis_if_list, list) { | ||
268 | buff_pos += sprintf(buff + buff_pos, "%pM,", | ||
269 | entry->addr); | ||
270 | |||
271 | for (i = 0; i < packet->entries; i++) | ||
272 | buff_pos += vis_data_read_entry( | ||
273 | buff + buff_pos, | ||
274 | &entries[i], | ||
275 | entry->addr, | ||
276 | entry->primary); | ||
277 | |||
278 | /* add primary/secondary records */ | ||
279 | if (compare_orig(entry->addr, packet->vis_orig)) | ||
280 | buff_pos += | ||
281 | vis_data_read_prim_sec(buff + buff_pos, | ||
282 | &vis_if_list); | ||
283 | |||
284 | buff_pos += sprintf(buff + buff_pos, "\n"); | ||
285 | } | ||
286 | |||
287 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, | ||
288 | list) { | ||
289 | hlist_del(&entry->list); | ||
290 | kfree(entry); | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
296 | |||
297 | seq_printf(seq, "%s", buff); | ||
298 | kfree(buff); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /* add the info packet to the send list, if it was not | ||
304 | * already linked in. */ | ||
305 | static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info) | ||
306 | { | ||
307 | if (list_empty(&info->send_list)) { | ||
308 | kref_get(&info->refcount); | ||
309 | list_add_tail(&info->send_list, &bat_priv->vis_send_list); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | /* delete the info packet from the send list, if it was | ||
314 | * linked in. */ | ||
315 | static void send_list_del(struct vis_info *info) | ||
316 | { | ||
317 | if (!list_empty(&info->send_list)) { | ||
318 | list_del_init(&info->send_list); | ||
319 | kref_put(&info->refcount, free_info); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | /* tries to add one entry to the receive list. */ | ||
324 | static void recv_list_add(struct bat_priv *bat_priv, | ||
325 | struct list_head *recv_list, char *mac) | ||
326 | { | ||
327 | struct recvlist_node *entry; | ||
328 | |||
329 | entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC); | ||
330 | if (!entry) | ||
331 | return; | ||
332 | |||
333 | memcpy(entry->mac, mac, ETH_ALEN); | ||
334 | spin_lock_bh(&bat_priv->vis_list_lock); | ||
335 | list_add_tail(&entry->list, recv_list); | ||
336 | spin_unlock_bh(&bat_priv->vis_list_lock); | ||
337 | } | ||
338 | |||
339 | /* returns 1 if this mac is in the recv_list */ | ||
340 | static int recv_list_is_in(struct bat_priv *bat_priv, | ||
341 | struct list_head *recv_list, char *mac) | ||
342 | { | ||
343 | struct recvlist_node *entry; | ||
344 | |||
345 | spin_lock_bh(&bat_priv->vis_list_lock); | ||
346 | list_for_each_entry(entry, recv_list, list) { | ||
347 | if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { | ||
348 | spin_unlock_bh(&bat_priv->vis_list_lock); | ||
349 | return 1; | ||
350 | } | ||
351 | } | ||
352 | spin_unlock_bh(&bat_priv->vis_list_lock); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old, | ||
357 | * broken.. ). vis hash must be locked outside. is_new is set when the packet | ||
358 | * is newer than old entries in the hash. */ | ||
359 | static struct vis_info *add_packet(struct bat_priv *bat_priv, | ||
360 | struct vis_packet *vis_packet, | ||
361 | int vis_info_len, int *is_new, | ||
362 | int make_broadcast) | ||
363 | { | ||
364 | struct vis_info *info, *old_info; | ||
365 | struct vis_packet *search_packet, *old_packet; | ||
366 | struct vis_info search_elem; | ||
367 | struct vis_packet *packet; | ||
368 | int hash_added; | ||
369 | |||
370 | *is_new = 0; | ||
371 | /* sanity check */ | ||
372 | if (!bat_priv->vis_hash) | ||
373 | return NULL; | ||
374 | |||
375 | /* see if the packet is already in vis_hash */ | ||
376 | search_elem.skb_packet = dev_alloc_skb(sizeof(struct vis_packet)); | ||
377 | if (!search_elem.skb_packet) | ||
378 | return NULL; | ||
379 | search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet, | ||
380 | sizeof(struct vis_packet)); | ||
381 | |||
382 | memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); | ||
383 | old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | ||
384 | &search_elem); | ||
385 | kfree_skb(search_elem.skb_packet); | ||
386 | |||
387 | if (old_info) { | ||
388 | old_packet = (struct vis_packet *)old_info->skb_packet->data; | ||
389 | if (!seq_after(ntohl(vis_packet->seqno), | ||
390 | ntohl(old_packet->seqno))) { | ||
391 | if (old_packet->seqno == vis_packet->seqno) { | ||
392 | recv_list_add(bat_priv, &old_info->recv_list, | ||
393 | vis_packet->sender_orig); | ||
394 | return old_info; | ||
395 | } else { | ||
396 | /* newer packet is already in hash. */ | ||
397 | return NULL; | ||
398 | } | ||
399 | } | ||
400 | /* remove old entry */ | ||
401 | hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | ||
402 | old_info); | ||
403 | send_list_del(old_info); | ||
404 | kref_put(&old_info->refcount, free_info); | ||
405 | } | ||
406 | |||
407 | info = kmalloc(sizeof(struct vis_info), GFP_ATOMIC); | ||
408 | if (!info) | ||
409 | return NULL; | ||
410 | |||
411 | info->skb_packet = dev_alloc_skb(sizeof(struct vis_packet) + | ||
412 | vis_info_len + sizeof(struct ethhdr)); | ||
413 | if (!info->skb_packet) { | ||
414 | kfree(info); | ||
415 | return NULL; | ||
416 | } | ||
417 | skb_reserve(info->skb_packet, sizeof(struct ethhdr)); | ||
418 | packet = (struct vis_packet *)skb_put(info->skb_packet, | ||
419 | sizeof(struct vis_packet) + | ||
420 | vis_info_len); | ||
421 | |||
422 | kref_init(&info->refcount); | ||
423 | INIT_LIST_HEAD(&info->send_list); | ||
424 | INIT_LIST_HEAD(&info->recv_list); | ||
425 | info->first_seen = jiffies; | ||
426 | info->bat_priv = bat_priv; | ||
427 | memcpy(packet, vis_packet, sizeof(struct vis_packet) + vis_info_len); | ||
428 | |||
429 | /* initialize and add new packet. */ | ||
430 | *is_new = 1; | ||
431 | |||
432 | /* Make it a broadcast packet, if required */ | ||
433 | if (make_broadcast) | ||
434 | memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); | ||
435 | |||
436 | /* repair if entries is longer than packet. */ | ||
437 | if (packet->entries * sizeof(struct vis_info_entry) > vis_info_len) | ||
438 | packet->entries = vis_info_len / sizeof(struct vis_info_entry); | ||
439 | |||
440 | recv_list_add(bat_priv, &info->recv_list, packet->sender_orig); | ||
441 | |||
442 | /* try to add it */ | ||
443 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | ||
444 | info); | ||
445 | if (hash_added < 0) { | ||
446 | /* did not work (for some reason) */ | ||
447 | kref_put(&old_info->refcount, free_info); | ||
448 | info = NULL; | ||
449 | } | ||
450 | |||
451 | return info; | ||
452 | } | ||
453 | |||
454 | /* handle the server sync packet, forward if needed. */ | ||
455 | void receive_server_sync_packet(struct bat_priv *bat_priv, | ||
456 | struct vis_packet *vis_packet, | ||
457 | int vis_info_len) | ||
458 | { | ||
459 | struct vis_info *info; | ||
460 | int is_new, make_broadcast; | ||
461 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
462 | |||
463 | make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC); | ||
464 | |||
465 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
466 | info = add_packet(bat_priv, vis_packet, vis_info_len, | ||
467 | &is_new, make_broadcast); | ||
468 | if (!info) | ||
469 | goto end; | ||
470 | |||
471 | /* only if we are server ourselves and packet is newer than the one in | ||
472 | * hash.*/ | ||
473 | if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) | ||
474 | send_list_add(bat_priv, info); | ||
475 | end: | ||
476 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
477 | } | ||
478 | |||
479 | /* handle an incoming client update packet and schedule forward if needed. */ | ||
480 | void receive_client_update_packet(struct bat_priv *bat_priv, | ||
481 | struct vis_packet *vis_packet, | ||
482 | int vis_info_len) | ||
483 | { | ||
484 | struct vis_info *info; | ||
485 | struct vis_packet *packet; | ||
486 | int is_new; | ||
487 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
488 | int are_target = 0; | ||
489 | |||
490 | /* clients shall not broadcast. */ | ||
491 | if (is_broadcast_ether_addr(vis_packet->target_orig)) | ||
492 | return; | ||
493 | |||
494 | /* Are we the target for this VIS packet? */ | ||
495 | if (vis_server == VIS_TYPE_SERVER_SYNC && | ||
496 | is_my_mac(vis_packet->target_orig)) | ||
497 | are_target = 1; | ||
498 | |||
499 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
500 | info = add_packet(bat_priv, vis_packet, vis_info_len, | ||
501 | &is_new, are_target); | ||
502 | |||
503 | if (!info) | ||
504 | goto end; | ||
505 | /* note that outdated packets will be dropped at this point. */ | ||
506 | |||
507 | packet = (struct vis_packet *)info->skb_packet->data; | ||
508 | |||
509 | /* send only if we're the target server or ... */ | ||
510 | if (are_target && is_new) { | ||
511 | packet->vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */ | ||
512 | send_list_add(bat_priv, info); | ||
513 | |||
514 | /* ... we're not the recipient (and thus need to forward). */ | ||
515 | } else if (!is_my_mac(packet->target_orig)) { | ||
516 | send_list_add(bat_priv, info); | ||
517 | } | ||
518 | |||
519 | end: | ||
520 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
521 | } | ||
522 | |||
523 | /* Walk the originators and find the VIS server with the best tq. Set the packet | ||
524 | * address to its address and return the best_tq. | ||
525 | * | ||
526 | * Must be called with the originator hash locked */ | ||
527 | static int find_best_vis_server(struct bat_priv *bat_priv, | ||
528 | struct vis_info *info) | ||
529 | { | ||
530 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
531 | struct hlist_node *walk; | ||
532 | struct hlist_head *head; | ||
533 | struct element_t *bucket; | ||
534 | struct orig_node *orig_node; | ||
535 | struct vis_packet *packet; | ||
536 | int best_tq = -1, i; | ||
537 | |||
538 | packet = (struct vis_packet *)info->skb_packet->data; | ||
539 | |||
540 | for (i = 0; i < hash->size; i++) { | ||
541 | head = &hash->table[i]; | ||
542 | |||
543 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
544 | orig_node = bucket->data; | ||
545 | if ((orig_node) && (orig_node->router) && | ||
546 | (orig_node->flags & VIS_SERVER) && | ||
547 | (orig_node->router->tq_avg > best_tq)) { | ||
548 | best_tq = orig_node->router->tq_avg; | ||
549 | memcpy(packet->target_orig, orig_node->orig, | ||
550 | ETH_ALEN); | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | |||
555 | return best_tq; | ||
556 | } | ||
557 | |||
558 | /* Return true if the vis packet is full. */ | ||
559 | static bool vis_packet_full(struct vis_info *info) | ||
560 | { | ||
561 | struct vis_packet *packet; | ||
562 | packet = (struct vis_packet *)info->skb_packet->data; | ||
563 | |||
564 | if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry) | ||
565 | < packet->entries + 1) | ||
566 | return true; | ||
567 | return false; | ||
568 | } | ||
569 | |||
570 | /* generates a packet of own vis data, | ||
571 | * returns 0 on success, -1 if no packet could be generated */ | ||
572 | static int generate_vis_packet(struct bat_priv *bat_priv) | ||
573 | { | ||
574 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
575 | struct hlist_node *walk; | ||
576 | struct hlist_head *head; | ||
577 | struct element_t *bucket; | ||
578 | struct orig_node *orig_node; | ||
579 | struct neigh_node *neigh_node; | ||
580 | struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; | ||
581 | struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; | ||
582 | struct vis_info_entry *entry; | ||
583 | struct hna_local_entry *hna_local_entry; | ||
584 | int best_tq = -1, i; | ||
585 | |||
586 | info->first_seen = jiffies; | ||
587 | packet->vis_type = atomic_read(&bat_priv->vis_mode); | ||
588 | |||
589 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
590 | memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); | ||
591 | packet->ttl = TTL; | ||
592 | packet->seqno = htonl(ntohl(packet->seqno) + 1); | ||
593 | packet->entries = 0; | ||
594 | skb_trim(info->skb_packet, sizeof(struct vis_packet)); | ||
595 | |||
596 | if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) { | ||
597 | best_tq = find_best_vis_server(bat_priv, info); | ||
598 | |||
599 | if (best_tq < 0) { | ||
600 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
601 | return -1; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | for (i = 0; i < hash->size; i++) { | ||
606 | head = &hash->table[i]; | ||
607 | |||
608 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
609 | orig_node = bucket->data; | ||
610 | neigh_node = orig_node->router; | ||
611 | |||
612 | if (!neigh_node) | ||
613 | continue; | ||
614 | |||
615 | if (!compare_orig(neigh_node->addr, orig_node->orig)) | ||
616 | continue; | ||
617 | |||
618 | if (neigh_node->if_incoming->if_status != IF_ACTIVE) | ||
619 | continue; | ||
620 | |||
621 | if (neigh_node->tq_avg < 1) | ||
622 | continue; | ||
623 | |||
624 | /* fill one entry into buffer. */ | ||
625 | entry = (struct vis_info_entry *) | ||
626 | skb_put(info->skb_packet, sizeof(*entry)); | ||
627 | memcpy(entry->src, | ||
628 | neigh_node->if_incoming->net_dev->dev_addr, | ||
629 | ETH_ALEN); | ||
630 | memcpy(entry->dest, orig_node->orig, ETH_ALEN); | ||
631 | entry->quality = neigh_node->tq_avg; | ||
632 | packet->entries++; | ||
633 | |||
634 | if (vis_packet_full(info)) { | ||
635 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
636 | return 0; | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | |||
641 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
642 | |||
643 | hash = bat_priv->hna_local_hash; | ||
644 | |||
645 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
646 | for (i = 0; i < hash->size; i++) { | ||
647 | head = &hash->table[i]; | ||
648 | |||
649 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
650 | hna_local_entry = bucket->data; | ||
651 | entry = (struct vis_info_entry *) | ||
652 | skb_put(info->skb_packet, | ||
653 | sizeof(*entry)); | ||
654 | memset(entry->src, 0, ETH_ALEN); | ||
655 | memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN); | ||
656 | entry->quality = 0; /* 0 means HNA */ | ||
657 | packet->entries++; | ||
658 | |||
659 | if (vis_packet_full(info)) { | ||
660 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
661 | return 0; | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | |||
666 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | /* free old vis packets. Must be called with this vis_hash_lock | ||
671 | * held */ | ||
672 | static void purge_vis_packets(struct bat_priv *bat_priv) | ||
673 | { | ||
674 | int i; | ||
675 | struct hashtable_t *hash = bat_priv->vis_hash; | ||
676 | struct hlist_node *walk, *safe; | ||
677 | struct hlist_head *head; | ||
678 | struct element_t *bucket; | ||
679 | struct vis_info *info; | ||
680 | |||
681 | for (i = 0; i < hash->size; i++) { | ||
682 | head = &hash->table[i]; | ||
683 | |||
684 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | ||
685 | info = bucket->data; | ||
686 | |||
687 | /* never purge own data. */ | ||
688 | if (info == bat_priv->my_vis_info) | ||
689 | continue; | ||
690 | |||
691 | if (time_after(jiffies, | ||
692 | info->first_seen + VIS_TIMEOUT * HZ)) { | ||
693 | hlist_del(walk); | ||
694 | kfree(bucket); | ||
695 | send_list_del(info); | ||
696 | kref_put(&info->refcount, free_info); | ||
697 | } | ||
698 | } | ||
699 | } | ||
700 | } | ||
701 | |||
702 | static void broadcast_vis_packet(struct bat_priv *bat_priv, | ||
703 | struct vis_info *info) | ||
704 | { | ||
705 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
706 | struct hlist_node *walk; | ||
707 | struct hlist_head *head; | ||
708 | struct element_t *bucket; | ||
709 | struct orig_node *orig_node; | ||
710 | struct vis_packet *packet; | ||
711 | struct sk_buff *skb; | ||
712 | struct batman_if *batman_if; | ||
713 | uint8_t dstaddr[ETH_ALEN]; | ||
714 | int i; | ||
715 | |||
716 | |||
717 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
718 | packet = (struct vis_packet *)info->skb_packet->data; | ||
719 | |||
720 | /* send to all routers in range. */ | ||
721 | for (i = 0; i < hash->size; i++) { | ||
722 | head = &hash->table[i]; | ||
723 | |||
724 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
725 | orig_node = bucket->data; | ||
726 | |||
727 | /* if it's a vis server and reachable, send it. */ | ||
728 | if ((!orig_node) || (!orig_node->router)) | ||
729 | continue; | ||
730 | if (!(orig_node->flags & VIS_SERVER)) | ||
731 | continue; | ||
732 | /* don't send it if we already received the packet from | ||
733 | * this node. */ | ||
734 | if (recv_list_is_in(bat_priv, &info->recv_list, | ||
735 | orig_node->orig)) | ||
736 | continue; | ||
737 | |||
738 | memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); | ||
739 | batman_if = orig_node->router->if_incoming; | ||
740 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
741 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
742 | |||
743 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | ||
744 | if (skb) | ||
745 | send_skb_packet(skb, batman_if, dstaddr); | ||
746 | |||
747 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
748 | } | ||
749 | |||
750 | } | ||
751 | |||
752 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
753 | } | ||
754 | |||
755 | static void unicast_vis_packet(struct bat_priv *bat_priv, | ||
756 | struct vis_info *info) | ||
757 | { | ||
758 | struct orig_node *orig_node; | ||
759 | struct sk_buff *skb; | ||
760 | struct vis_packet *packet; | ||
761 | struct batman_if *batman_if; | ||
762 | uint8_t dstaddr[ETH_ALEN]; | ||
763 | |||
764 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
765 | packet = (struct vis_packet *)info->skb_packet->data; | ||
766 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
767 | compare_orig, choose_orig, | ||
768 | packet->target_orig)); | ||
769 | |||
770 | if ((!orig_node) || (!orig_node->router)) | ||
771 | goto out; | ||
772 | |||
773 | /* don't lock while sending the packets ... we therefore | ||
774 | * copy the required data before sending */ | ||
775 | batman_if = orig_node->router->if_incoming; | ||
776 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
777 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
778 | |||
779 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | ||
780 | if (skb) | ||
781 | send_skb_packet(skb, batman_if, dstaddr); | ||
782 | |||
783 | return; | ||
784 | |||
785 | out: | ||
786 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
787 | } | ||
788 | |||
789 | /* only send one vis packet. called from send_vis_packets() */ | ||
790 | static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) | ||
791 | { | ||
792 | struct vis_packet *packet; | ||
793 | |||
794 | packet = (struct vis_packet *)info->skb_packet->data; | ||
795 | if (packet->ttl < 2) { | ||
796 | pr_debug("Error - can't send vis packet: ttl exceeded\n"); | ||
797 | return; | ||
798 | } | ||
799 | |||
800 | memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, | ||
801 | ETH_ALEN); | ||
802 | packet->ttl--; | ||
803 | |||
804 | if (is_broadcast_ether_addr(packet->target_orig)) | ||
805 | broadcast_vis_packet(bat_priv, info); | ||
806 | else | ||
807 | unicast_vis_packet(bat_priv, info); | ||
808 | packet->ttl++; /* restore TTL */ | ||
809 | } | ||
810 | |||
811 | /* called from timer; send (and maybe generate) vis packet. */ | ||
812 | static void send_vis_packets(struct work_struct *work) | ||
813 | { | ||
814 | struct delayed_work *delayed_work = | ||
815 | container_of(work, struct delayed_work, work); | ||
816 | struct bat_priv *bat_priv = | ||
817 | container_of(delayed_work, struct bat_priv, vis_work); | ||
818 | struct vis_info *info, *temp; | ||
819 | |||
820 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
821 | purge_vis_packets(bat_priv); | ||
822 | |||
823 | if (generate_vis_packet(bat_priv) == 0) { | ||
824 | /* schedule if generation was successful */ | ||
825 | send_list_add(bat_priv, bat_priv->my_vis_info); | ||
826 | } | ||
827 | |||
828 | list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list, | ||
829 | send_list) { | ||
830 | |||
831 | kref_get(&info->refcount); | ||
832 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
833 | |||
834 | if (bat_priv->primary_if) | ||
835 | send_vis_packet(bat_priv, info); | ||
836 | |||
837 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
838 | send_list_del(info); | ||
839 | kref_put(&info->refcount, free_info); | ||
840 | } | ||
841 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
842 | start_vis_timer(bat_priv); | ||
843 | } | ||
844 | |||
845 | /* init the vis server. this may only be called when if_list is already | ||
846 | * initialized (e.g. bat0 is initialized, interfaces have been added) */ | ||
847 | int vis_init(struct bat_priv *bat_priv) | ||
848 | { | ||
849 | struct vis_packet *packet; | ||
850 | int hash_added; | ||
851 | |||
852 | if (bat_priv->vis_hash) | ||
853 | return 1; | ||
854 | |||
855 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
856 | |||
857 | bat_priv->vis_hash = hash_new(256); | ||
858 | if (!bat_priv->vis_hash) { | ||
859 | pr_err("Can't initialize vis_hash\n"); | ||
860 | goto err; | ||
861 | } | ||
862 | |||
863 | bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC); | ||
864 | if (!bat_priv->my_vis_info) { | ||
865 | pr_err("Can't initialize vis packet\n"); | ||
866 | goto err; | ||
867 | } | ||
868 | |||
869 | bat_priv->my_vis_info->skb_packet = dev_alloc_skb( | ||
870 | sizeof(struct vis_packet) + | ||
871 | MAX_VIS_PACKET_SIZE + | ||
872 | sizeof(struct ethhdr)); | ||
873 | if (!bat_priv->my_vis_info->skb_packet) | ||
874 | goto free_info; | ||
875 | |||
876 | skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr)); | ||
877 | packet = (struct vis_packet *)skb_put( | ||
878 | bat_priv->my_vis_info->skb_packet, | ||
879 | sizeof(struct vis_packet)); | ||
880 | |||
881 | /* prefill the vis info */ | ||
882 | bat_priv->my_vis_info->first_seen = jiffies - | ||
883 | msecs_to_jiffies(VIS_INTERVAL); | ||
884 | INIT_LIST_HEAD(&bat_priv->my_vis_info->recv_list); | ||
885 | INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list); | ||
886 | kref_init(&bat_priv->my_vis_info->refcount); | ||
887 | bat_priv->my_vis_info->bat_priv = bat_priv; | ||
888 | packet->version = COMPAT_VERSION; | ||
889 | packet->packet_type = BAT_VIS; | ||
890 | packet->ttl = TTL; | ||
891 | packet->seqno = 0; | ||
892 | packet->entries = 0; | ||
893 | |||
894 | INIT_LIST_HEAD(&bat_priv->vis_send_list); | ||
895 | |||
896 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | ||
897 | bat_priv->my_vis_info); | ||
898 | if (hash_added < 0) { | ||
899 | pr_err("Can't add own vis packet into hash\n"); | ||
900 | /* not in hash, need to remove it manually. */ | ||
901 | kref_put(&bat_priv->my_vis_info->refcount, free_info); | ||
902 | goto err; | ||
903 | } | ||
904 | |||
905 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
906 | start_vis_timer(bat_priv); | ||
907 | return 1; | ||
908 | |||
909 | free_info: | ||
910 | kfree(bat_priv->my_vis_info); | ||
911 | bat_priv->my_vis_info = NULL; | ||
912 | err: | ||
913 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
914 | vis_quit(bat_priv); | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | /* Decrease the reference count on a hash item info */ | ||
919 | static void free_info_ref(void *data, void *arg) | ||
920 | { | ||
921 | struct vis_info *info = data; | ||
922 | |||
923 | send_list_del(info); | ||
924 | kref_put(&info->refcount, free_info); | ||
925 | } | ||
926 | |||
927 | /* shutdown vis-server */ | ||
928 | void vis_quit(struct bat_priv *bat_priv) | ||
929 | { | ||
930 | if (!bat_priv->vis_hash) | ||
931 | return; | ||
932 | |||
933 | cancel_delayed_work_sync(&bat_priv->vis_work); | ||
934 | |||
935 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
936 | /* properly remove, kill timers ... */ | ||
937 | hash_delete(bat_priv->vis_hash, free_info_ref, NULL); | ||
938 | bat_priv->vis_hash = NULL; | ||
939 | bat_priv->my_vis_info = NULL; | ||
940 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
941 | } | ||
942 | |||
943 | /* schedule packets for (re)transmission */ | ||
944 | static void start_vis_timer(struct bat_priv *bat_priv) | ||
945 | { | ||
946 | INIT_DELAYED_WORK(&bat_priv->vis_work, send_vis_packets); | ||
947 | queue_delayed_work(bat_event_workqueue, &bat_priv->vis_work, | ||
948 | msecs_to_jiffies(VIS_INTERVAL)); | ||
949 | } | ||
diff --git a/net/batman-adv/vis.h b/net/batman-adv/vis.h new file mode 100644 index 000000000000..2c3b33089a9b --- /dev/null +++ b/net/batman-adv/vis.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2010 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 _NET_BATMAN_ADV_VIS_H_ | ||
23 | #define _NET_BATMAN_ADV_VIS_H_ | ||
24 | |||
25 | #define VIS_TIMEOUT 200 /* timeout of vis packets in seconds */ | ||
26 | |||
27 | int vis_seq_print_text(struct seq_file *seq, void *offset); | ||
28 | void receive_server_sync_packet(struct bat_priv *bat_priv, | ||
29 | struct vis_packet *vis_packet, | ||
30 | int vis_info_len); | ||
31 | void receive_client_update_packet(struct bat_priv *bat_priv, | ||
32 | struct vis_packet *vis_packet, | ||
33 | int vis_info_len); | ||
34 | int vis_init(struct bat_priv *bat_priv); | ||
35 | void vis_quit(struct bat_priv *bat_priv); | ||
36 | |||
37 | #endif /* _NET_BATMAN_ADV_VIS_H_ */ | ||