]>
Commit | Line | Data |
---|---|---|
5beef3c9 | 1 | /* |
9b6d10b7 | 2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: |
5beef3c9 AL |
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 | ||
5beef3c9 AL |
22 | #include "main.h" |
23 | #include "routing.h" | |
5beef3c9 | 24 | #include "send.h" |
8a2e042c | 25 | #include "hash.h" |
5beef3c9 AL |
26 | #include "soft-interface.h" |
27 | #include "hard-interface.h" | |
28 | #include "device.h" | |
29 | #include "translation-table.h" | |
8a2e042c | 30 | #include "originator.h" |
5beef3c9 | 31 | #include "types.h" |
5beef3c9 AL |
32 | #include "ring_buffer.h" |
33 | #include "vis.h" | |
34 | #include "aggregation.h" | |
5beef3c9 | 35 | |
5beef3c9 | 36 | DECLARE_WAIT_QUEUE_HEAD(thread_wait); |
5beef3c9 | 37 | |
5beef3c9 AL |
38 | void slide_own_bcast_window(struct batman_if *batman_if) |
39 | { | |
b6c35976 | 40 | HASHIT(hashit); |
5beef3c9 | 41 | struct orig_node *orig_node; |
4efe0b06 | 42 | TYPE_OF_WORD *word; |
e7017195 | 43 | unsigned long flags; |
5beef3c9 | 44 | |
e7017195 | 45 | spin_lock_irqsave(&orig_hash_lock, flags); |
5beef3c9 | 46 | |
b6c35976 SW |
47 | while (hash_iterate(orig_hash, &hashit)) { |
48 | orig_node = hashit.bucket->data; | |
4efe0b06 | 49 | word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]); |
5beef3c9 | 50 | |
4efe0b06 AL |
51 | bit_get_packet(word, 1, 0); |
52 | orig_node->bcast_own_sum[batman_if->if_num] = | |
53 | bit_packet_count(word); | |
5beef3c9 AL |
54 | } |
55 | ||
e7017195 | 56 | spin_unlock_irqrestore(&orig_hash_lock, flags); |
5beef3c9 AL |
57 | } |
58 | ||
4efe0b06 AL |
59 | static void update_HNA(struct orig_node *orig_node, |
60 | unsigned char *hna_buff, int hna_buff_len) | |
5beef3c9 | 61 | { |
4efe0b06 AL |
62 | if ((hna_buff_len != orig_node->hna_buff_len) || |
63 | ((hna_buff_len > 0) && | |
64 | (orig_node->hna_buff_len > 0) && | |
65 | (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) { | |
5beef3c9 | 66 | |
4efe0b06 AL |
67 | if (orig_node->hna_buff_len > 0) |
68 | hna_global_del_orig(orig_node, | |
69 | "originator changed hna"); | |
5beef3c9 | 70 | |
4efe0b06 | 71 | if ((hna_buff_len > 0) && (hna_buff != NULL)) |
5beef3c9 | 72 | hna_global_add_orig(orig_node, hna_buff, hna_buff_len); |
4efe0b06 AL |
73 | } |
74 | } | |
5beef3c9 | 75 | |
4efe0b06 AL |
76 | static void update_route(struct orig_node *orig_node, |
77 | struct neigh_node *neigh_node, | |
78 | unsigned char *hna_buff, int hna_buff_len) | |
79 | { | |
4efe0b06 AL |
80 | /* route deleted */ |
81 | if ((orig_node->router != NULL) && (neigh_node == NULL)) { | |
5beef3c9 | 82 | |
b9b27e4e AL |
83 | bat_dbg(DBG_ROUTES, "Deleting route towards: %pM\n", |
84 | orig_node->orig); | |
4efe0b06 | 85 | hna_global_del_orig(orig_node, "originator timed out"); |
5beef3c9 | 86 | |
4efe0b06 AL |
87 | /* route added */ |
88 | } else if ((orig_node->router == NULL) && (neigh_node != NULL)) { | |
5beef3c9 | 89 | |
4efe0b06 | 90 | bat_dbg(DBG_ROUTES, |
b9b27e4e AL |
91 | "Adding route towards: %pM (via %pM)\n", |
92 | orig_node->orig, neigh_node->addr); | |
4efe0b06 AL |
93 | hna_global_add_orig(orig_node, hna_buff, hna_buff_len); |
94 | ||
95 | /* route changed */ | |
5beef3c9 | 96 | } else { |
b9b27e4e | 97 | bat_dbg(DBG_ROUTES, "Changing route towards: %pM (now via %pM - was via %pM)\n", orig_node->orig, neigh_node->addr, orig_node->router->addr); |
4efe0b06 | 98 | } |
5beef3c9 | 99 | |
4efe0b06 AL |
100 | orig_node->router = neigh_node; |
101 | } | |
5beef3c9 | 102 | |
5beef3c9 | 103 | |
8a2e042c | 104 | void update_routes(struct orig_node *orig_node, |
4efe0b06 AL |
105 | struct neigh_node *neigh_node, |
106 | unsigned char *hna_buff, int hna_buff_len) | |
107 | { | |
5beef3c9 | 108 | |
4efe0b06 AL |
109 | if (orig_node == NULL) |
110 | return; | |
111 | ||
112 | if (orig_node->router != neigh_node) | |
113 | update_route(orig_node, neigh_node, hna_buff, hna_buff_len); | |
114 | /* may be just HNA changed */ | |
115 | else | |
116 | update_HNA(orig_node, hna_buff, hna_buff_len); | |
5beef3c9 AL |
117 | } |
118 | ||
4efe0b06 AL |
119 | static int isBidirectionalNeigh(struct orig_node *orig_node, |
120 | struct orig_node *orig_neigh_node, | |
121 | struct batman_packet *batman_packet, | |
122 | struct batman_if *if_incoming) | |
5beef3c9 AL |
123 | { |
124 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | |
5beef3c9 AL |
125 | unsigned char total_count; |
126 | ||
5beef3c9 | 127 | if (orig_node == orig_neigh_node) { |
4efe0b06 AL |
128 | list_for_each_entry(tmp_neigh_node, |
129 | &orig_node->neigh_list, | |
130 | list) { | |
5beef3c9 | 131 | |
4efe0b06 AL |
132 | if (compare_orig(tmp_neigh_node->addr, |
133 | orig_neigh_node->orig) && | |
134 | (tmp_neigh_node->if_incoming == if_incoming)) | |
5beef3c9 AL |
135 | neigh_node = tmp_neigh_node; |
136 | } | |
137 | ||
c4bf05d3 | 138 | if (!neigh_node) |
4efe0b06 AL |
139 | neigh_node = create_neighbor(orig_node, |
140 | orig_neigh_node, | |
141 | orig_neigh_node->orig, | |
142 | if_incoming); | |
c4bf05d3 SW |
143 | /* create_neighbor failed, return 0 */ |
144 | if (!neigh_node) | |
145 | return 0; | |
5beef3c9 AL |
146 | |
147 | neigh_node->last_valid = jiffies; | |
148 | } else { | |
149 | /* find packet count of corresponding one hop neighbor */ | |
4efe0b06 AL |
150 | list_for_each_entry(tmp_neigh_node, |
151 | &orig_neigh_node->neigh_list, list) { | |
5beef3c9 | 152 | |
4efe0b06 AL |
153 | if (compare_orig(tmp_neigh_node->addr, |
154 | orig_neigh_node->orig) && | |
155 | (tmp_neigh_node->if_incoming == if_incoming)) | |
5beef3c9 AL |
156 | neigh_node = tmp_neigh_node; |
157 | } | |
158 | ||
c4bf05d3 | 159 | if (!neigh_node) |
4efe0b06 AL |
160 | neigh_node = create_neighbor(orig_neigh_node, |
161 | orig_neigh_node, | |
162 | orig_neigh_node->orig, | |
163 | if_incoming); | |
c4bf05d3 SW |
164 | /* create_neighbor failed, return 0 */ |
165 | if (!neigh_node) | |
166 | return 0; | |
5beef3c9 AL |
167 | } |
168 | ||
169 | orig_node->last_valid = jiffies; | |
170 | ||
171 | /* pay attention to not get a value bigger than 100 % */ | |
4efe0b06 AL |
172 | total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > |
173 | neigh_node->real_packet_count ? | |
174 | neigh_node->real_packet_count : | |
175 | orig_neigh_node->bcast_own_sum[if_incoming->if_num]); | |
5beef3c9 AL |
176 | |
177 | /* if we have too few packets (too less data) we set tq_own to zero */ | |
178 | /* if we receive too few packets it is not considered bidirectional */ | |
4efe0b06 AL |
179 | if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || |
180 | (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) | |
5beef3c9 AL |
181 | orig_neigh_node->tq_own = 0; |
182 | else | |
4efe0b06 AL |
183 | /* neigh_node->real_packet_count is never zero as we |
184 | * only purge old information when getting new | |
185 | * information */ | |
186 | orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / | |
187 | neigh_node->real_packet_count; | |
5beef3c9 AL |
188 | |
189 | /* | |
4efe0b06 AL |
190 | * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does |
191 | * affect the nearly-symmetric links only a little, but | |
192 | * punishes asymmetric links more. This will give a value | |
193 | * between 0 and TQ_MAX_VALUE | |
5beef3c9 | 194 | */ |
4efe0b06 AL |
195 | orig_neigh_node->tq_asym_penalty = |
196 | TQ_MAX_VALUE - | |
197 | (TQ_MAX_VALUE * | |
198 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * | |
199 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * | |
200 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / | |
201 | (TQ_LOCAL_WINDOW_SIZE * | |
202 | TQ_LOCAL_WINDOW_SIZE * | |
203 | TQ_LOCAL_WINDOW_SIZE); | |
204 | ||
205 | batman_packet->tq = ((batman_packet->tq * | |
206 | orig_neigh_node->tq_own * | |
207 | orig_neigh_node->tq_asym_penalty) / | |
208e13e4 | 208 | (TQ_MAX_VALUE * TQ_MAX_VALUE)); |
5beef3c9 | 209 | |
0887635b | 210 | bat_dbg(DBG_BATMAN, "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i\n", |
b9b27e4e | 211 | orig_node->orig, orig_neigh_node->orig, total_count, |
4efe0b06 AL |
212 | neigh_node->real_packet_count, orig_neigh_node->tq_own, |
213 | orig_neigh_node->tq_asym_penalty, batman_packet->tq); | |
5beef3c9 | 214 | |
4efe0b06 AL |
215 | /* if link has the minimum required transmission quality |
216 | * consider it bidirectional */ | |
5beef3c9 AL |
217 | if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) |
218 | return 1; | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
4efe0b06 AL |
223 | static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, |
224 | struct batman_packet *batman_packet, | |
225 | struct batman_if *if_incoming, | |
226 | unsigned char *hna_buff, int hna_buff_len, | |
227 | char is_duplicate) | |
5beef3c9 AL |
228 | { |
229 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | |
230 | int tmp_hna_buff_len; | |
231 | ||
0887635b | 232 | bat_dbg(DBG_BATMAN, "update_originator(): Searching and updating originator entry of received packet\n"); |
5beef3c9 AL |
233 | |
234 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | |
4efe0b06 AL |
235 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && |
236 | (tmp_neigh_node->if_incoming == if_incoming)) { | |
5beef3c9 AL |
237 | neigh_node = tmp_neigh_node; |
238 | continue; | |
239 | } | |
240 | ||
241 | if (is_duplicate) | |
242 | continue; | |
243 | ||
4efe0b06 AL |
244 | ring_buffer_set(tmp_neigh_node->tq_recv, |
245 | &tmp_neigh_node->tq_index, 0); | |
246 | tmp_neigh_node->tq_avg = | |
247 | ring_buffer_avg(tmp_neigh_node->tq_recv); | |
5beef3c9 AL |
248 | } |
249 | ||
c4bf05d3 SW |
250 | if (!neigh_node) { |
251 | struct orig_node *orig_tmp; | |
252 | ||
253 | orig_tmp = get_orig_node(ethhdr->h_source); | |
254 | if (!orig_tmp) | |
255 | return; | |
256 | ||
4efe0b06 | 257 | neigh_node = create_neighbor(orig_node, |
c4bf05d3 | 258 | orig_tmp, |
4efe0b06 | 259 | ethhdr->h_source, if_incoming); |
c4bf05d3 SW |
260 | if (!neigh_node) |
261 | return; | |
262 | } else | |
4efe0b06 | 263 | bat_dbg(DBG_BATMAN, |
5ea84fa3 | 264 | "Updating existing last-hop neighbor of originator\n"); |
5beef3c9 AL |
265 | |
266 | orig_node->flags = batman_packet->flags; | |
267 | neigh_node->last_valid = jiffies; | |
268 | ||
4efe0b06 AL |
269 | ring_buffer_set(neigh_node->tq_recv, |
270 | &neigh_node->tq_index, | |
271 | batman_packet->tq); | |
5beef3c9 AL |
272 | neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); |
273 | ||
274 | if (!is_duplicate) { | |
275 | orig_node->last_ttl = batman_packet->ttl; | |
276 | neigh_node->last_ttl = batman_packet->ttl; | |
277 | } | |
278 | ||
4efe0b06 AL |
279 | tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? |
280 | batman_packet->num_hna * ETH_ALEN : hna_buff_len); | |
5beef3c9 | 281 | |
4efe0b06 AL |
282 | /* if this neighbor already is our next hop there is nothing |
283 | * to change */ | |
5beef3c9 AL |
284 | if (orig_node->router == neigh_node) |
285 | goto update_hna; | |
286 | ||
287 | /* if this neighbor does not offer a better TQ we won't consider it */ | |
288 | if ((orig_node->router) && | |
289 | (orig_node->router->tq_avg > neigh_node->tq_avg)) | |
290 | goto update_hna; | |
291 | ||
4efe0b06 AL |
292 | /* if the TQ is the same and the link not more symetric we |
293 | * won't consider it either */ | |
5beef3c9 AL |
294 | if ((orig_node->router) && |
295 | ((neigh_node->tq_avg == orig_node->router->tq_avg) && | |
4efe0b06 AL |
296 | (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] |
297 | >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num]))) | |
5beef3c9 AL |
298 | goto update_hna; |
299 | ||
300 | update_routes(orig_node, neigh_node, hna_buff, tmp_hna_buff_len); | |
301 | return; | |
302 | ||
303 | update_hna: | |
304 | update_routes(orig_node, orig_node->router, hna_buff, tmp_hna_buff_len); | |
5beef3c9 AL |
305 | } |
306 | ||
f94cee24 SW |
307 | /* checks whether the host restarted and is in the protection time. |
308 | * returns: | |
309 | * 0 if the packet is to be accepted | |
310 | * 1 if the packet is to be ignored. | |
311 | */ | |
312 | static int window_protected(int16_t seq_num_diff, | |
313 | unsigned long *last_reset) | |
314 | { | |
315 | if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) | |
316 | || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { | |
317 | if (time_after(jiffies, *last_reset + | |
318 | msecs_to_jiffies(RESET_PROTECTION_MS))) { | |
319 | ||
320 | *last_reset = jiffies; | |
321 | bat_dbg(DBG_BATMAN, | |
322 | "old packet received, start protection\n"); | |
323 | ||
324 | return 0; | |
325 | } else | |
326 | return 1; | |
327 | } | |
328 | return 0; | |
329 | } | |
330 | ||
331 | /* processes a batman packet for all interfaces, adjusts the sequence number and | |
332 | * finds out whether it is a duplicate. | |
333 | * returns: | |
334 | * 1 the packet is a duplicate | |
335 | * 0 the packet has not yet been received | |
336 | * -1 the packet is old and has been received while the seqno window | |
337 | * was protected. Caller should drop it. | |
338 | */ | |
4efe0b06 AL |
339 | static char count_real_packets(struct ethhdr *ethhdr, |
340 | struct batman_packet *batman_packet, | |
341 | struct batman_if *if_incoming) | |
5beef3c9 AL |
342 | { |
343 | struct orig_node *orig_node; | |
344 | struct neigh_node *tmp_neigh_node; | |
345 | char is_duplicate = 0; | |
f94cee24 SW |
346 | int16_t seq_diff; |
347 | int need_update = 0; | |
348 | int set_mark; | |
5beef3c9 AL |
349 | |
350 | orig_node = get_orig_node(batman_packet->orig); | |
351 | if (orig_node == NULL) | |
352 | return 0; | |
353 | ||
f94cee24 SW |
354 | seq_diff = batman_packet->seqno - orig_node->last_real_seqno; |
355 | ||
356 | /* signalize caller that the packet is to be dropped. */ | |
357 | if (window_protected(seq_diff, &orig_node->batman_seqno_reset)) | |
358 | return -1; | |
359 | ||
5beef3c9 AL |
360 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { |
361 | ||
f94cee24 | 362 | is_duplicate |= get_bit_status(tmp_neigh_node->real_bits, |
4efe0b06 AL |
363 | orig_node->last_real_seqno, |
364 | batman_packet->seqno); | |
f94cee24 | 365 | |
4efe0b06 AL |
366 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && |
367 | (tmp_neigh_node->if_incoming == if_incoming)) | |
f94cee24 | 368 | set_mark = 1; |
5beef3c9 | 369 | else |
f94cee24 SW |
370 | set_mark = 0; |
371 | ||
372 | /* if the window moved, set the update flag. */ | |
373 | need_update |= bit_get_packet(tmp_neigh_node->real_bits, | |
374 | seq_diff, set_mark); | |
5beef3c9 | 375 | |
4efe0b06 AL |
376 | tmp_neigh_node->real_packet_count = |
377 | bit_packet_count(tmp_neigh_node->real_bits); | |
5beef3c9 AL |
378 | } |
379 | ||
f94cee24 | 380 | if (need_update) { |
0887635b | 381 | bat_dbg(DBG_BATMAN, "updating last_seqno: old %d, new %d\n", |
bad2239e | 382 | orig_node->last_real_seqno, batman_packet->seqno); |
5beef3c9 AL |
383 | orig_node->last_real_seqno = batman_packet->seqno; |
384 | } | |
385 | ||
386 | return is_duplicate; | |
387 | } | |
388 | ||
4efe0b06 | 389 | void receive_bat_packet(struct ethhdr *ethhdr, |
e7017195 SW |
390 | struct batman_packet *batman_packet, |
391 | unsigned char *hna_buff, int hna_buff_len, | |
392 | struct batman_if *if_incoming) | |
5beef3c9 AL |
393 | { |
394 | struct batman_if *batman_if; | |
395 | struct orig_node *orig_neigh_node, *orig_node; | |
5beef3c9 | 396 | char has_directlink_flag; |
4efe0b06 AL |
397 | char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; |
398 | char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; | |
399 | char is_duplicate; | |
5beef3c9 AL |
400 | unsigned short if_incoming_seqno; |
401 | ||
4efe0b06 AL |
402 | /* Silently drop when the batman packet is actually not a |
403 | * correct packet. | |
5beef3c9 AL |
404 | * |
405 | * This might happen if a packet is padded (e.g. Ethernet has a | |
406 | * minimum frame length of 64 byte) and the aggregation interprets | |
407 | * it as an additional length. | |
408 | * | |
4efe0b06 AL |
409 | * TODO: A more sane solution would be to have a bit in the |
410 | * batman_packet to detect whether the packet is the last | |
411 | * packet in an aggregation. Here we expect that the padding | |
412 | * is always zero (or not 0x01) | |
5beef3c9 AL |
413 | */ |
414 | if (batman_packet->packet_type != BAT_PACKET) | |
415 | return; | |
416 | ||
417 | /* could be changed by schedule_own_packet() */ | |
418 | if_incoming_seqno = atomic_read(&if_incoming->seqno); | |
419 | ||
5beef3c9 AL |
420 | has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0); |
421 | ||
4efe0b06 AL |
422 | is_single_hop_neigh = (compare_orig(ethhdr->h_source, |
423 | batman_packet->orig) ? 1 : 0); | |
5beef3c9 | 424 | |
0887635b | 425 | bat_dbg(DBG_BATMAN, "Received BATMAN packet via NB: %pM, IF: %s [%s] (from OG: %pM, via prev OG: %pM, seqno %d, tq %d, TTL %d, V %d, IDF %d)\n", |
b9b27e4e AL |
426 | ethhdr->h_source, if_incoming->dev, if_incoming->addr_str, |
427 | batman_packet->orig, batman_packet->prev_sender, | |
428 | batman_packet->seqno, batman_packet->tq, batman_packet->ttl, | |
429 | batman_packet->version, has_directlink_flag); | |
5beef3c9 AL |
430 | |
431 | list_for_each_entry_rcu(batman_if, &if_list, list) { | |
208e13e4 | 432 | if (batman_if->if_status != IF_ACTIVE) |
5beef3c9 AL |
433 | continue; |
434 | ||
4efe0b06 AL |
435 | if (compare_orig(ethhdr->h_source, |
436 | batman_if->net_dev->dev_addr)) | |
5beef3c9 AL |
437 | is_my_addr = 1; |
438 | ||
4efe0b06 AL |
439 | if (compare_orig(batman_packet->orig, |
440 | batman_if->net_dev->dev_addr)) | |
5beef3c9 AL |
441 | is_my_orig = 1; |
442 | ||
4efe0b06 AL |
443 | if (compare_orig(batman_packet->prev_sender, |
444 | batman_if->net_dev->dev_addr)) | |
5beef3c9 AL |
445 | is_my_oldorig = 1; |
446 | ||
447 | if (compare_orig(ethhdr->h_source, broadcastAddr)) | |
448 | is_broadcast = 1; | |
449 | } | |
450 | ||
451 | if (batman_packet->version != COMPAT_VERSION) { | |
4efe0b06 AL |
452 | bat_dbg(DBG_BATMAN, |
453 | "Drop packet: incompatible batman version (%i)\n", | |
454 | batman_packet->version); | |
5beef3c9 AL |
455 | return; |
456 | } | |
457 | ||
458 | if (is_my_addr) { | |
4efe0b06 | 459 | bat_dbg(DBG_BATMAN, |
b9b27e4e AL |
460 | "Drop packet: received my own broadcast (sender: %pM)\n", |
461 | ethhdr->h_source); | |
5beef3c9 AL |
462 | return; |
463 | } | |
464 | ||
465 | if (is_broadcast) { | |
0887635b | 466 | bat_dbg(DBG_BATMAN, "Drop packet: ignoring all packets with broadcast source addr (sender: %pM)\n", ethhdr->h_source); |
5beef3c9 AL |
467 | return; |
468 | } | |
469 | ||
470 | if (is_my_orig) { | |
4efe0b06 AL |
471 | TYPE_OF_WORD *word; |
472 | int offset; | |
473 | ||
5beef3c9 AL |
474 | orig_neigh_node = get_orig_node(ethhdr->h_source); |
475 | ||
c4bf05d3 SW |
476 | if (!orig_neigh_node) |
477 | return; | |
478 | ||
5ea84fa3 | 479 | /* neighbor has to indicate direct link and it has to |
4efe0b06 AL |
480 | * come via the corresponding interface */ |
481 | /* if received seqno equals last send seqno save new | |
482 | * seqno for bidirectional check */ | |
483 | if (has_directlink_flag && | |
484 | compare_orig(if_incoming->net_dev->dev_addr, | |
485 | batman_packet->orig) && | |
486 | (batman_packet->seqno - if_incoming_seqno + 2 == 0)) { | |
487 | offset = if_incoming->if_num * NUM_WORDS; | |
488 | word = &(orig_neigh_node->bcast_own[offset]); | |
489 | bit_mark(word, 0); | |
490 | orig_neigh_node->bcast_own_sum[if_incoming->if_num] = | |
491 | bit_packet_count(word); | |
5beef3c9 AL |
492 | } |
493 | ||
0887635b | 494 | bat_dbg(DBG_BATMAN, "Drop packet: originator packet from myself (via neighbor)\n"); |
5beef3c9 AL |
495 | return; |
496 | } | |
497 | ||
5beef3c9 | 498 | if (is_my_oldorig) { |
0887635b | 499 | bat_dbg(DBG_BATMAN, "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n", ethhdr->h_source); |
5beef3c9 AL |
500 | return; |
501 | } | |
502 | ||
5beef3c9 AL |
503 | orig_node = get_orig_node(batman_packet->orig); |
504 | if (orig_node == NULL) | |
505 | return; | |
506 | ||
f94cee24 SW |
507 | is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming); |
508 | ||
509 | if (is_duplicate == -1) { | |
510 | bat_dbg(DBG_BATMAN, "Drop packet: packet within seqno protection time (sender: %pM)\n", ethhdr->h_source); | |
511 | return; | |
512 | } | |
513 | ||
514 | if (batman_packet->tq == 0) { | |
515 | bat_dbg(DBG_BATMAN, "Drop packet: originator packet with tq equal 0\n"); | |
516 | return; | |
517 | } | |
518 | ||
5beef3c9 | 519 | /* avoid temporary routing loops */ |
4efe0b06 AL |
520 | if ((orig_node->router) && |
521 | (orig_node->router->orig_node->router) && | |
522 | (compare_orig(orig_node->router->addr, | |
523 | batman_packet->prev_sender)) && | |
5beef3c9 | 524 | !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) && |
4efe0b06 AL |
525 | (compare_orig(orig_node->router->addr, |
526 | orig_node->router->orig_node->router->addr))) { | |
0887635b | 527 | bat_dbg(DBG_BATMAN, "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", ethhdr->h_source); |
5beef3c9 AL |
528 | return; |
529 | } | |
530 | ||
4efe0b06 AL |
531 | /* if sender is a direct neighbor the sender mac equals |
532 | * originator mac */ | |
533 | orig_neigh_node = (is_single_hop_neigh ? | |
534 | orig_node : get_orig_node(ethhdr->h_source)); | |
5beef3c9 AL |
535 | if (orig_neigh_node == NULL) |
536 | return; | |
537 | ||
4efe0b06 AL |
538 | /* drop packet if sender is not a direct neighbor and if we |
539 | * don't route towards it */ | |
540 | if (!is_single_hop_neigh && | |
541 | (orig_neigh_node->router == NULL)) { | |
bad2239e | 542 | bat_dbg(DBG_BATMAN, "Drop packet: OGM via unknown neighbor!\n"); |
5beef3c9 AL |
543 | return; |
544 | } | |
545 | ||
4efe0b06 AL |
546 | is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node, |
547 | batman_packet, if_incoming); | |
5beef3c9 | 548 | |
4efe0b06 AL |
549 | /* update ranking if it is not a duplicate or has the same |
550 | * seqno and similar ttl as the non-duplicate */ | |
551 | if (is_bidirectional && | |
552 | (!is_duplicate || | |
553 | ((orig_node->last_real_seqno == batman_packet->seqno) && | |
554 | (orig_node->last_ttl - 3 <= batman_packet->ttl)))) | |
555 | update_orig(orig_node, ethhdr, batman_packet, | |
556 | if_incoming, hna_buff, hna_buff_len, is_duplicate); | |
5beef3c9 | 557 | |
5ea84fa3 | 558 | /* is single hop (direct) neighbor */ |
5beef3c9 AL |
559 | if (is_single_hop_neigh) { |
560 | ||
561 | /* mark direct link on incoming interface */ | |
4efe0b06 AL |
562 | schedule_forward_packet(orig_node, ethhdr, batman_packet, |
563 | 1, hna_buff_len, if_incoming); | |
5beef3c9 | 564 | |
5ea84fa3 | 565 | bat_dbg(DBG_BATMAN, "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); |
5beef3c9 AL |
566 | return; |
567 | } | |
568 | ||
569 | /* multihop originator */ | |
570 | if (!is_bidirectional) { | |
4efe0b06 AL |
571 | bat_dbg(DBG_BATMAN, |
572 | "Drop packet: not received via bidirectional link\n"); | |
5beef3c9 AL |
573 | return; |
574 | } | |
575 | ||
576 | if (is_duplicate) { | |
bad2239e | 577 | bat_dbg(DBG_BATMAN, "Drop packet: duplicate packet received\n"); |
5beef3c9 AL |
578 | return; |
579 | } | |
580 | ||
4efe0b06 AL |
581 | bat_dbg(DBG_BATMAN, |
582 | "Forwarding packet: rebroadcast originator packet\n"); | |
583 | schedule_forward_packet(orig_node, ethhdr, batman_packet, | |
584 | 0, hna_buff_len, if_incoming); | |
5beef3c9 AL |
585 | } |
586 | ||
e7017195 SW |
587 | int recv_bat_packet(struct sk_buff *skb, |
588 | struct batman_if *batman_if) | |
5beef3c9 | 589 | { |
e7017195 SW |
590 | struct ethhdr *ethhdr; |
591 | unsigned long flags; | |
f347b873 | 592 | struct sk_buff *skb_old; |
5beef3c9 | 593 | |
e7017195 SW |
594 | /* drop packet if it has not necessary minimum size */ |
595 | if (skb_headlen(skb) < sizeof(struct batman_packet)) | |
596 | return NET_RX_DROP; | |
5beef3c9 | 597 | |
e7017195 | 598 | ethhdr = (struct ethhdr *)skb_mac_header(skb); |
5beef3c9 | 599 | |
4efe0b06 AL |
600 | /* packet with broadcast indication but unicast recipient */ |
601 | if (!is_bcast(ethhdr->h_dest)) | |
e7017195 | 602 | return NET_RX_DROP; |
4efe0b06 AL |
603 | |
604 | /* packet with broadcast sender address */ | |
605 | if (is_bcast(ethhdr->h_source)) | |
e7017195 SW |
606 | return NET_RX_DROP; |
607 | ||
e7017195 SW |
608 | /* TODO: we use headlen instead of "length", because |
609 | * only this data is paged in. */ | |
f347b873 SE |
610 | |
611 | /* create a copy of the skb, if needed, to modify it. */ | |
612 | if (!skb_clone_writable(skb, skb_headlen(skb))) { | |
613 | skb_old = skb; | |
614 | skb = skb_copy(skb, GFP_ATOMIC); | |
615 | if (!skb) | |
616 | return NET_RX_DROP; | |
617 | kfree_skb(skb_old); | |
618 | } | |
619 | ||
620 | spin_lock_irqsave(&orig_hash_lock, flags); | |
4efe0b06 | 621 | receive_aggr_bat_packet(ethhdr, |
e7017195 SW |
622 | skb->data, |
623 | skb_headlen(skb), | |
4efe0b06 | 624 | batman_if); |
e7017195 SW |
625 | spin_unlock_irqrestore(&orig_hash_lock, flags); |
626 | ||
627 | kfree_skb(skb); | |
628 | return NET_RX_SUCCESS; | |
4efe0b06 AL |
629 | } |
630 | ||
e7017195 | 631 | static int recv_my_icmp_packet(struct sk_buff *skb) |
5beef3c9 | 632 | { |
5beef3c9 | 633 | struct orig_node *orig_node; |
e7017195 SW |
634 | struct icmp_packet *icmp_packet; |
635 | struct ethhdr *ethhdr; | |
636 | struct sk_buff *skb_old; | |
637 | struct batman_if *batman_if; | |
638 | int ret; | |
639 | unsigned long flags; | |
640 | uint8_t dstaddr[ETH_ALEN]; | |
641 | ||
642 | icmp_packet = (struct icmp_packet *) skb->data; | |
643 | ethhdr = (struct ethhdr *) skb_mac_header(skb); | |
5beef3c9 | 644 | |
4efe0b06 AL |
645 | /* add data to device queue */ |
646 | if (icmp_packet->msg_type != ECHO_REQUEST) { | |
647 | bat_device_receive_packet(icmp_packet); | |
e7017195 | 648 | return NET_RX_DROP; |
5beef3c9 AL |
649 | } |
650 | ||
4efe0b06 AL |
651 | /* answer echo request (ping) */ |
652 | /* get routing information */ | |
e7017195 | 653 | spin_lock_irqsave(&orig_hash_lock, flags); |
4efe0b06 AL |
654 | orig_node = ((struct orig_node *)hash_find(orig_hash, |
655 | icmp_packet->orig)); | |
e7017195 | 656 | ret = NET_RX_DROP; |
4efe0b06 AL |
657 | |
658 | if ((orig_node != NULL) && | |
4efe0b06 | 659 | (orig_node->router != NULL)) { |
e7017195 SW |
660 | |
661 | /* don't lock while sending the packets ... we therefore | |
662 | * copy the required data before sending */ | |
35bd69d4 | 663 | batman_if = orig_node->router->if_incoming; |
e7017195 SW |
664 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); |
665 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
666 | ||
667 | /* create a copy of the skb, if needed, to modify it. */ | |
668 | skb_old = NULL; | |
669 | if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { | |
670 | skb_old = skb; | |
671 | skb = skb_copy(skb, GFP_ATOMIC); | |
672 | if (!skb) | |
673 | return NET_RX_DROP; | |
674 | icmp_packet = (struct icmp_packet *) skb->data; | |
675 | kfree_skb(skb_old); | |
676 | } | |
677 | ||
4efe0b06 AL |
678 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); |
679 | memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); | |
680 | icmp_packet->msg_type = ECHO_REPLY; | |
681 | icmp_packet->ttl = TTL; | |
682 | ||
e7017195 SW |
683 | send_skb_packet(skb, batman_if, dstaddr); |
684 | ret = NET_RX_SUCCESS; | |
5beef3c9 | 685 | |
e7017195 SW |
686 | } else |
687 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
688 | ||
689 | return ret; | |
4efe0b06 | 690 | } |
5beef3c9 | 691 | |
e7017195 | 692 | static int recv_icmp_ttl_exceeded(struct sk_buff *skb) |
4efe0b06 | 693 | { |
4efe0b06 | 694 | struct orig_node *orig_node; |
e7017195 SW |
695 | struct icmp_packet *icmp_packet; |
696 | struct ethhdr *ethhdr; | |
697 | struct sk_buff *skb_old; | |
698 | struct batman_if *batman_if; | |
699 | int ret; | |
700 | unsigned long flags; | |
701 | uint8_t dstaddr[ETH_ALEN]; | |
702 | ||
149de2e5 ML |
703 | icmp_packet = (struct icmp_packet *)skb->data; |
704 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | |
5beef3c9 | 705 | |
4efe0b06 | 706 | /* send TTL exceeded if packet is an echo request (traceroute) */ |
149de2e5 ML |
707 | if (icmp_packet->msg_type != ECHO_REQUEST) { |
708 | printk(KERN_WARNING "batman-adv:Warning - can't forward icmp packet from %pM to %pM: ttl exceeded\n", | |
709 | icmp_packet->orig, icmp_packet->dst); | |
e7017195 | 710 | return NET_RX_DROP; |
149de2e5 | 711 | } |
5beef3c9 | 712 | |
4efe0b06 | 713 | /* get routing information */ |
e7017195 | 714 | spin_lock_irqsave(&orig_hash_lock, flags); |
4efe0b06 AL |
715 | orig_node = ((struct orig_node *) |
716 | hash_find(orig_hash, icmp_packet->orig)); | |
e7017195 | 717 | ret = NET_RX_DROP; |
4efe0b06 AL |
718 | |
719 | if ((orig_node != NULL) && | |
4efe0b06 | 720 | (orig_node->router != NULL)) { |
e7017195 SW |
721 | |
722 | /* don't lock while sending the packets ... we therefore | |
723 | * copy the required data before sending */ | |
35bd69d4 | 724 | batman_if = orig_node->router->if_incoming; |
e7017195 SW |
725 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); |
726 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
727 | ||
728 | /* create a copy of the skb, if needed, to modify it. */ | |
729 | if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { | |
730 | skb_old = skb; | |
731 | skb = skb_copy(skb, GFP_ATOMIC); | |
732 | if (!skb) | |
733 | return NET_RX_DROP; | |
734 | icmp_packet = (struct icmp_packet *) skb->data; | |
735 | kfree_skb(skb_old); | |
736 | } | |
737 | ||
4efe0b06 AL |
738 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); |
739 | memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); | |
740 | icmp_packet->msg_type = TTL_EXCEEDED; | |
741 | icmp_packet->ttl = TTL; | |
742 | ||
e7017195 SW |
743 | send_skb_packet(skb, batman_if, dstaddr); |
744 | ret = NET_RX_SUCCESS; | |
5beef3c9 | 745 | |
e7017195 SW |
746 | } else |
747 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
5beef3c9 | 748 | |
e7017195 | 749 | return ret; |
4efe0b06 | 750 | } |
5beef3c9 | 751 | |
5beef3c9 | 752 | |
e7017195 | 753 | int recv_icmp_packet(struct sk_buff *skb) |
4efe0b06 AL |
754 | { |
755 | struct icmp_packet *icmp_packet; | |
e7017195 | 756 | struct ethhdr *ethhdr; |
4efe0b06 | 757 | struct orig_node *orig_node; |
e7017195 SW |
758 | struct sk_buff *skb_old; |
759 | struct batman_if *batman_if; | |
760 | int hdr_size = sizeof(struct icmp_packet); | |
761 | int ret; | |
762 | unsigned long flags; | |
763 | uint8_t dstaddr[ETH_ALEN]; | |
764 | ||
765 | /* drop packet if it has not necessary minimum size */ | |
766 | if (skb_headlen(skb) < hdr_size) | |
767 | return NET_RX_DROP; | |
768 | ||
769 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | |
5beef3c9 | 770 | |
4efe0b06 AL |
771 | /* packet with unicast indication but broadcast recipient */ |
772 | if (is_bcast(ethhdr->h_dest)) | |
e7017195 | 773 | return NET_RX_DROP; |
5beef3c9 | 774 | |
4efe0b06 AL |
775 | /* packet with broadcast sender address */ |
776 | if (is_bcast(ethhdr->h_source)) | |
e7017195 | 777 | return NET_RX_DROP; |
5beef3c9 | 778 | |
4efe0b06 AL |
779 | /* not for me */ |
780 | if (!is_my_mac(ethhdr->h_dest)) | |
e7017195 | 781 | return NET_RX_DROP; |
5beef3c9 | 782 | |
e7017195 | 783 | icmp_packet = (struct icmp_packet *) skb->data; |
5beef3c9 | 784 | |
4efe0b06 AL |
785 | /* packet for me */ |
786 | if (is_my_mac(icmp_packet->dst)) | |
e7017195 | 787 | return recv_my_icmp_packet(skb); |
5beef3c9 | 788 | |
4efe0b06 | 789 | /* TTL exceeded */ |
e7017195 SW |
790 | if (icmp_packet->ttl < 2) |
791 | return recv_icmp_ttl_exceeded(skb); | |
5beef3c9 | 792 | |
e7017195 | 793 | ret = NET_RX_DROP; |
5beef3c9 | 794 | |
4efe0b06 | 795 | /* get routing information */ |
e7017195 | 796 | spin_lock_irqsave(&orig_hash_lock, flags); |
4efe0b06 AL |
797 | orig_node = ((struct orig_node *) |
798 | hash_find(orig_hash, icmp_packet->dst)); | |
5beef3c9 | 799 | |
4efe0b06 | 800 | if ((orig_node != NULL) && |
4efe0b06 | 801 | (orig_node->router != NULL)) { |
5beef3c9 | 802 | |
e7017195 SW |
803 | /* don't lock while sending the packets ... we therefore |
804 | * copy the required data before sending */ | |
35bd69d4 | 805 | batman_if = orig_node->router->if_incoming; |
e7017195 SW |
806 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); |
807 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
808 | ||
809 | /* create a copy of the skb, if needed, to modify it. */ | |
810 | if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) { | |
811 | skb_old = skb; | |
812 | skb = skb_copy(skb, GFP_ATOMIC); | |
813 | if (!skb) | |
814 | return NET_RX_DROP; | |
815 | icmp_packet = (struct icmp_packet *) skb->data; | |
816 | kfree_skb(skb_old); | |
817 | } | |
818 | ||
4efe0b06 AL |
819 | /* decrement ttl */ |
820 | icmp_packet->ttl--; | |
5beef3c9 | 821 | |
4efe0b06 | 822 | /* route it */ |
e7017195 SW |
823 | send_skb_packet(skb, batman_if, dstaddr); |
824 | ret = NET_RX_SUCCESS; | |
825 | ||
826 | } else | |
827 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
828 | ||
829 | return ret; | |
4efe0b06 | 830 | } |
5beef3c9 | 831 | |
e7017195 | 832 | int recv_unicast_packet(struct sk_buff *skb) |
4efe0b06 AL |
833 | { |
834 | struct unicast_packet *unicast_packet; | |
4efe0b06 | 835 | struct orig_node *orig_node; |
e7017195 SW |
836 | struct ethhdr *ethhdr; |
837 | struct batman_if *batman_if; | |
838 | struct sk_buff *skb_old; | |
839 | uint8_t dstaddr[ETH_ALEN]; | |
840 | int hdr_size = sizeof(struct unicast_packet); | |
841 | int ret; | |
842 | unsigned long flags; | |
843 | ||
844 | /* drop packet if it has not necessary minimum size */ | |
845 | if (skb_headlen(skb) < hdr_size) | |
846 | return NET_RX_DROP; | |
847 | ||
848 | ethhdr = (struct ethhdr *) skb_mac_header(skb); | |
5beef3c9 | 849 | |
4efe0b06 AL |
850 | /* packet with unicast indication but broadcast recipient */ |
851 | if (is_bcast(ethhdr->h_dest)) | |
e7017195 | 852 | return NET_RX_DROP; |
5beef3c9 | 853 | |
4efe0b06 AL |
854 | /* packet with broadcast sender address */ |
855 | if (is_bcast(ethhdr->h_source)) | |
e7017195 | 856 | return NET_RX_DROP; |
5beef3c9 | 857 | |
4efe0b06 AL |
858 | /* not for me */ |
859 | if (!is_my_mac(ethhdr->h_dest)) | |
e7017195 | 860 | return NET_RX_DROP; |
5beef3c9 | 861 | |
e7017195 | 862 | unicast_packet = (struct unicast_packet *) skb->data; |
5beef3c9 | 863 | |
4efe0b06 AL |
864 | /* packet for me */ |
865 | if (is_my_mac(unicast_packet->dest)) { | |
e7017195 SW |
866 | interface_rx(skb, hdr_size); |
867 | return NET_RX_SUCCESS; | |
4efe0b06 | 868 | } |
5beef3c9 | 869 | |
4efe0b06 AL |
870 | /* TTL exceeded */ |
871 | if (unicast_packet->ttl < 2) { | |
149de2e5 ML |
872 | printk(KERN_WARNING "batman-adv:Warning - can't forward unicast packet from %pM to %pM: ttl exceeded\n", |
873 | ethhdr->h_source, unicast_packet->dest); | |
e7017195 | 874 | return NET_RX_DROP; |
4efe0b06 | 875 | } |
5beef3c9 | 876 | |
e7017195 | 877 | ret = NET_RX_DROP; |
4efe0b06 | 878 | /* get routing information */ |
e7017195 | 879 | spin_lock_irqsave(&orig_hash_lock, flags); |
4efe0b06 AL |
880 | orig_node = ((struct orig_node *) |
881 | hash_find(orig_hash, unicast_packet->dest)); | |
882 | ||
883 | if ((orig_node != NULL) && | |
4efe0b06 | 884 | (orig_node->router != NULL)) { |
e7017195 SW |
885 | |
886 | /* don't lock while sending the packets ... we therefore | |
887 | * copy the required data before sending */ | |
35bd69d4 | 888 | batman_if = orig_node->router->if_incoming; |
e7017195 SW |
889 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); |
890 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
891 | ||
892 | /* create a copy of the skb, if needed, to modify it. */ | |
893 | if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) { | |
894 | skb_old = skb; | |
895 | skb = skb_copy(skb, GFP_ATOMIC); | |
896 | if (!skb) | |
897 | return NET_RX_DROP; | |
898 | unicast_packet = (struct unicast_packet *) skb->data; | |
899 | kfree_skb(skb_old); | |
900 | } | |
4efe0b06 AL |
901 | /* decrement ttl */ |
902 | unicast_packet->ttl--; | |
903 | ||
904 | /* route it */ | |
e7017195 SW |
905 | send_skb_packet(skb, batman_if, dstaddr); |
906 | ret = NET_RX_SUCCESS; | |
907 | ||
908 | } else | |
909 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
910 | ||
911 | return ret; | |
4efe0b06 | 912 | } |
5beef3c9 | 913 | |
e7017195 | 914 | int recv_bcast_packet(struct sk_buff *skb) |
4efe0b06 AL |
915 | { |
916 | struct orig_node *orig_node; | |
917 | struct bcast_packet *bcast_packet; | |
e7017195 SW |
918 | struct ethhdr *ethhdr; |
919 | int hdr_size = sizeof(struct bcast_packet); | |
f94cee24 | 920 | int16_t seq_diff; |
e7017195 SW |
921 | unsigned long flags; |
922 | ||
923 | /* drop packet if it has not necessary minimum size */ | |
924 | if (skb_headlen(skb) < hdr_size) | |
925 | return NET_RX_DROP; | |
926 | ||
927 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | |
5beef3c9 | 928 | |
4efe0b06 AL |
929 | /* packet with broadcast indication but unicast recipient */ |
930 | if (!is_bcast(ethhdr->h_dest)) | |
e7017195 | 931 | return NET_RX_DROP; |
5beef3c9 | 932 | |
4efe0b06 AL |
933 | /* packet with broadcast sender address */ |
934 | if (is_bcast(ethhdr->h_source)) | |
e7017195 | 935 | return NET_RX_DROP; |
5beef3c9 | 936 | |
4efe0b06 AL |
937 | /* ignore broadcasts sent by myself */ |
938 | if (is_my_mac(ethhdr->h_source)) | |
e7017195 | 939 | return NET_RX_DROP; |
5beef3c9 | 940 | |
208e13e4 | 941 | bcast_packet = (struct bcast_packet *)skb->data; |
5beef3c9 | 942 | |
4efe0b06 AL |
943 | /* ignore broadcasts originated by myself */ |
944 | if (is_my_mac(bcast_packet->orig)) | |
e7017195 | 945 | return NET_RX_DROP; |
5beef3c9 | 946 | |
e7017195 | 947 | spin_lock_irqsave(&orig_hash_lock, flags); |
4efe0b06 AL |
948 | orig_node = ((struct orig_node *) |
949 | hash_find(orig_hash, bcast_packet->orig)); | |
5beef3c9 | 950 | |
4efe0b06 | 951 | if (orig_node == NULL) { |
e7017195 SW |
952 | spin_unlock_irqrestore(&orig_hash_lock, flags); |
953 | return NET_RX_DROP; | |
4efe0b06 | 954 | } |
5beef3c9 | 955 | |
f94cee24 | 956 | /* check whether the packet is a duplicate */ |
4efe0b06 AL |
957 | if (get_bit_status(orig_node->bcast_bits, |
958 | orig_node->last_bcast_seqno, | |
959 | ntohs(bcast_packet->seqno))) { | |
e7017195 SW |
960 | spin_unlock_irqrestore(&orig_hash_lock, flags); |
961 | return NET_RX_DROP; | |
4efe0b06 | 962 | } |
5beef3c9 | 963 | |
f94cee24 SW |
964 | seq_diff = ntohs(bcast_packet->seqno) - orig_node->last_bcast_seqno; |
965 | ||
966 | /* check whether the packet is old and the host just restarted. */ | |
967 | if (window_protected(seq_diff, &orig_node->bcast_seqno_reset)) { | |
968 | spin_unlock_irqrestore(&orig_hash_lock, flags); | |
969 | return NET_RX_DROP; | |
970 | } | |
971 | ||
972 | /* mark broadcast in flood history, update window position | |
973 | * if required. */ | |
974 | if (bit_get_packet(orig_node->bcast_bits, seq_diff, 1)) | |
4efe0b06 | 975 | orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno); |
5beef3c9 | 976 | |
e7017195 | 977 | spin_unlock_irqrestore(&orig_hash_lock, flags); |
e7017195 SW |
978 | /* rebroadcast packet */ |
979 | add_bcast_packet_to_list(skb); | |
5beef3c9 | 980 | |
4efe0b06 | 981 | /* broadcast for me */ |
e7017195 | 982 | interface_rx(skb, hdr_size); |
5beef3c9 | 983 | |
e7017195 | 984 | return NET_RX_SUCCESS; |
4efe0b06 | 985 | } |
5beef3c9 | 986 | |
e7017195 | 987 | int recv_vis_packet(struct sk_buff *skb) |
4efe0b06 AL |
988 | { |
989 | struct vis_packet *vis_packet; | |
e7017195 | 990 | struct ethhdr *ethhdr; |
14741240 | 991 | struct bat_priv *bat_priv; |
e7017195 | 992 | int hdr_size = sizeof(struct vis_packet); |
5beef3c9 | 993 | |
e7017195 SW |
994 | if (skb_headlen(skb) < hdr_size) |
995 | return NET_RX_DROP; | |
996 | ||
997 | vis_packet = (struct vis_packet *) skb->data; | |
998 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | |
5beef3c9 | 999 | |
4efe0b06 AL |
1000 | /* not for me */ |
1001 | if (!is_my_mac(ethhdr->h_dest)) | |
e7017195 | 1002 | return NET_RX_DROP; |
5beef3c9 | 1003 | |
4efe0b06 AL |
1004 | /* ignore own packets */ |
1005 | if (is_my_mac(vis_packet->vis_orig)) | |
e7017195 | 1006 | return NET_RX_DROP; |
5beef3c9 | 1007 | |
4efe0b06 | 1008 | if (is_my_mac(vis_packet->sender_orig)) |
e7017195 | 1009 | return NET_RX_DROP; |
5beef3c9 | 1010 | |
14741240 ML |
1011 | /* FIXME: each batman_if will be attached to a softif */ |
1012 | bat_priv = netdev_priv(soft_device); | |
1013 | ||
4efe0b06 AL |
1014 | switch (vis_packet->vis_type) { |
1015 | case VIS_TYPE_SERVER_SYNC: | |
e7017195 | 1016 | /* TODO: handle fragmented skbs properly */ |
14741240 ML |
1017 | receive_server_sync_packet(bat_priv, vis_packet, |
1018 | skb_headlen(skb)); | |
4efe0b06 | 1019 | break; |
5beef3c9 | 1020 | |
4efe0b06 | 1021 | case VIS_TYPE_CLIENT_UPDATE: |
e7017195 | 1022 | /* TODO: handle fragmented skbs properly */ |
14741240 ML |
1023 | receive_client_update_packet(bat_priv, vis_packet, |
1024 | skb_headlen(skb)); | |
4efe0b06 | 1025 | break; |
5beef3c9 | 1026 | |
4efe0b06 AL |
1027 | default: /* ignore unknown packet */ |
1028 | break; | |
1029 | } | |
8d03847c AL |
1030 | |
1031 | /* We take a copy of the data in the packet, so we should | |
1032 | always free the skbuf. */ | |
1033 | return NET_RX_DROP; | |
5beef3c9 | 1034 | } |