blob: 6efd1d0da54aec699d57fae36f993dc80cde5e8b [file] [log] [blame]
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001/*
Sven Eckelmann64afe352011-01-27 10:38:15 +01002 * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00003 *
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"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000031#include "ring_buffer.h"
32#include "vis.h"
33#include "aggregation.h"
34#include "gateway_common.h"
35#include "gateway_client.h"
36#include "unicast.h"
37
Marek Lindnere6c10f42011-02-18 12:33:20 +000038void slide_own_bcast_window(struct hard_iface *hard_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000039{
Marek Lindnere6c10f42011-02-18 12:33:20 +000040 struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000041 struct hashtable_t *hash = bat_priv->orig_hash;
Marek Lindner7aadf882011-02-18 12:28:09 +000042 struct hlist_node *node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000043 struct hlist_head *head;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000044 struct orig_node *orig_node;
45 unsigned long *word;
46 int i;
47 size_t word_index;
48
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000049 for (i = 0; i < hash->size; i++) {
50 head = &hash->table[i];
51
Marek Lindnerfb778ea2011-01-19 20:01:40 +000052 rcu_read_lock();
Marek Lindner7aadf882011-02-18 12:28:09 +000053 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
Marek Lindner2ae2daf2011-01-19 20:01:42 +000054 spin_lock_bh(&orig_node->ogm_cnt_lock);
Marek Lindnere6c10f42011-02-18 12:33:20 +000055 word_index = hard_iface->if_num * NUM_WORDS;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000056 word = &(orig_node->bcast_own[word_index]);
57
58 bit_get_packet(bat_priv, word, 1, 0);
Marek Lindnere6c10f42011-02-18 12:33:20 +000059 orig_node->bcast_own_sum[hard_iface->if_num] =
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000060 bit_packet_count(word);
Marek Lindner2ae2daf2011-01-19 20:01:42 +000061 spin_unlock_bh(&orig_node->ogm_cnt_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000062 }
Marek Lindnerfb778ea2011-01-19 20:01:40 +000063 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000064 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000065}
66
Antonio Quartullia73105b2011-04-27 14:27:44 +020067static void update_route(struct bat_priv *bat_priv,
68 struct orig_node *orig_node,
69 struct neigh_node *neigh_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000070{
Linus Lüssinge1a5382f2011-03-14 22:43:37 +000071 struct neigh_node *curr_router;
72
73 curr_router = orig_node_get_router(orig_node);
Marek Lindnera8e7f4b2010-12-12 21:57:10 +000074
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000075 /* route deleted */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +000076 if ((curr_router) && (!neigh_node)) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000077 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
78 orig_node->orig);
Antonio Quartulli2dafb492011-05-05 08:42:45 +020079 tt_global_del_orig(bat_priv, orig_node,
Antonio Quartullia73105b2011-04-27 14:27:44 +020080 "Deleted route towards originator");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000081
Linus Lüssinge1a5382f2011-03-14 22:43:37 +000082 /* route added */
83 } else if ((!curr_router) && (neigh_node)) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000084
85 bat_dbg(DBG_ROUTES, bat_priv,
86 "Adding route towards: %pM (via %pM)\n",
87 orig_node->orig, neigh_node->addr);
Linus Lüssinge1a5382f2011-03-14 22:43:37 +000088 /* route changed */
Sven Eckelmannbb899b82011-05-10 11:22:37 +020089 } else if (neigh_node && curr_router) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000090 bat_dbg(DBG_ROUTES, bat_priv,
91 "Changing route towards: %pM "
92 "(now via %pM - was via %pM)\n",
93 orig_node->orig, neigh_node->addr,
Linus Lüssinge1a5382f2011-03-14 22:43:37 +000094 curr_router->addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000095 }
96
Linus Lüssinge1a5382f2011-03-14 22:43:37 +000097 if (curr_router)
98 neigh_node_free_ref(curr_router);
99
100 /* increase refcount of new best neighbor */
Marek Lindner44524fc2011-02-10 14:33:53 +0000101 if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount))
102 neigh_node = NULL;
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000103
104 spin_lock_bh(&orig_node->neigh_list_lock);
105 rcu_assign_pointer(orig_node->router, neigh_node);
106 spin_unlock_bh(&orig_node->neigh_list_lock);
107
108 /* decrease refcount of previous best neighbor */
109 if (curr_router)
110 neigh_node_free_ref(curr_router);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000111}
112
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000113void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200114 struct neigh_node *neigh_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000115{
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000116 struct neigh_node *router = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000117
118 if (!orig_node)
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000119 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000120
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000121 router = orig_node_get_router(orig_node);
122
123 if (router != neigh_node)
Antonio Quartullia73105b2011-04-27 14:27:44 +0200124 update_route(bat_priv, orig_node, neigh_node);
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000125
126out:
127 if (router)
128 neigh_node_free_ref(router);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000129}
130
131static int is_bidirectional_neigh(struct orig_node *orig_node,
132 struct orig_node *orig_neigh_node,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200133 struct batman_ogm_packet *batman_ogm_packet,
Marek Lindnere6c10f42011-02-18 12:33:20 +0000134 struct hard_iface *if_incoming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000135{
136 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
Marek Lindner1605d0d2011-02-18 12:28:11 +0000137 struct neigh_node *neigh_node = NULL, *tmp_neigh_node;
Marek Lindner9591a792010-12-12 21:57:11 +0000138 struct hlist_node *node;
Sven Eckelmannb4e17052011-06-15 09:41:37 +0200139 uint8_t total_count;
Marek Lindner0ede9f42011-01-25 21:52:10 +0000140 uint8_t orig_eq_count, neigh_rq_count, tq_own;
141 int tq_asym_penalty, ret = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000142
Daniele Furlan27aea212011-05-07 22:45:19 +0200143 /* find corresponding one hop neighbor */
144 rcu_read_lock();
145 hlist_for_each_entry_rcu(tmp_neigh_node, node,
146 &orig_neigh_node->neigh_list, list) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000147
Daniele Furlan27aea212011-05-07 22:45:19 +0200148 if (!compare_eth(tmp_neigh_node->addr, orig_neigh_node->orig))
149 continue;
Marek Lindner1605d0d2011-02-18 12:28:11 +0000150
Daniele Furlan27aea212011-05-07 22:45:19 +0200151 if (tmp_neigh_node->if_incoming != if_incoming)
152 continue;
Marek Lindner1605d0d2011-02-18 12:28:11 +0000153
Daniele Furlan27aea212011-05-07 22:45:19 +0200154 if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
155 continue;
Marek Lindner1605d0d2011-02-18 12:28:11 +0000156
Daniele Furlan27aea212011-05-07 22:45:19 +0200157 neigh_node = tmp_neigh_node;
158 break;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000159 }
Daniele Furlan27aea212011-05-07 22:45:19 +0200160 rcu_read_unlock();
161
162 if (!neigh_node)
163 neigh_node = create_neighbor(orig_neigh_node,
164 orig_neigh_node,
165 orig_neigh_node->orig,
166 if_incoming);
167
168 if (!neigh_node)
169 goto out;
170
Antonio Quartulli015758d2011-07-09 17:52:13 +0200171 /* if orig_node is direct neighbor update neigh_node last_valid */
Daniele Furlan27aea212011-05-07 22:45:19 +0200172 if (orig_node == orig_neigh_node)
173 neigh_node->last_valid = jiffies;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000174
175 orig_node->last_valid = jiffies;
176
Daniele Furlan27aea212011-05-07 22:45:19 +0200177 /* find packet count of corresponding one hop neighbor */
Marek Lindner0ede9f42011-01-25 21:52:10 +0000178 spin_lock_bh(&orig_node->ogm_cnt_lock);
179 orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num];
180 neigh_rq_count = neigh_node->real_packet_count;
181 spin_unlock_bh(&orig_node->ogm_cnt_lock);
182
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000183 /* pay attention to not get a value bigger than 100 % */
Marek Lindner0ede9f42011-01-25 21:52:10 +0000184 total_count = (orig_eq_count > neigh_rq_count ?
185 neigh_rq_count : orig_eq_count);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000186
187 /* if we have too few packets (too less data) we set tq_own to zero */
188 /* if we receive too few packets it is not considered bidirectional */
189 if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
Marek Lindner0ede9f42011-01-25 21:52:10 +0000190 (neigh_rq_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
191 tq_own = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000192 else
193 /* neigh_node->real_packet_count is never zero as we
194 * only purge old information when getting new
195 * information */
Marek Lindner0ede9f42011-01-25 21:52:10 +0000196 tq_own = (TQ_MAX_VALUE * total_count) / neigh_rq_count;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000197
198 /*
199 * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
200 * affect the nearly-symmetric links only a little, but
201 * punishes asymmetric links more. This will give a value
202 * between 0 and TQ_MAX_VALUE
203 */
Marek Lindner0ede9f42011-01-25 21:52:10 +0000204 tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
205 (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
206 (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
207 (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count)) /
208 (TQ_LOCAL_WINDOW_SIZE *
209 TQ_LOCAL_WINDOW_SIZE *
210 TQ_LOCAL_WINDOW_SIZE);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000211
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200212 batman_ogm_packet->tq = ((batman_ogm_packet->tq * tq_own
213 * tq_asym_penalty) /
Marek Lindner0ede9f42011-01-25 21:52:10 +0000214 (TQ_MAX_VALUE * TQ_MAX_VALUE));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000215
216 bat_dbg(DBG_BATMAN, bat_priv,
217 "bidirectional: "
218 "orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
219 "real recv = %2i, local tq: %3i, asym_penalty: %3i, "
220 "total tq: %3i\n",
221 orig_node->orig, orig_neigh_node->orig, total_count,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200222 neigh_rq_count, tq_own, tq_asym_penalty, batman_ogm_packet->tq);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000223
224 /* if link has the minimum required transmission quality
225 * consider it bidirectional */
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200226 if (batman_ogm_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
Marek Lindnera775eb82011-01-19 20:01:39 +0000227 ret = 1;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000228
Marek Lindnera775eb82011-01-19 20:01:39 +0000229out:
230 if (neigh_node)
Marek Lindner44524fc2011-02-10 14:33:53 +0000231 neigh_node_free_ref(neigh_node);
Marek Lindnera775eb82011-01-19 20:01:39 +0000232 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000233}
234
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000235/* caller must hold the neigh_list_lock */
236void bonding_candidate_del(struct orig_node *orig_node,
237 struct neigh_node *neigh_node)
238{
239 /* this neighbor is not part of our candidate list */
240 if (list_empty(&neigh_node->bonding_list))
241 goto out;
242
243 list_del_rcu(&neigh_node->bonding_list);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000244 INIT_LIST_HEAD(&neigh_node->bonding_list);
Marek Lindner44524fc2011-02-10 14:33:53 +0000245 neigh_node_free_ref(neigh_node);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000246 atomic_dec(&orig_node->bond_candidates);
247
248out:
249 return;
250}
251
252static void bonding_candidate_add(struct orig_node *orig_node,
253 struct neigh_node *neigh_node)
254{
255 struct hlist_node *node;
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000256 struct neigh_node *tmp_neigh_node, *router = NULL;
257 uint8_t interference_candidate = 0;
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000258
259 spin_lock_bh(&orig_node->neigh_list_lock);
260
261 /* only consider if it has the same primary address ... */
Marek Lindner39901e72011-02-18 12:28:08 +0000262 if (!compare_eth(orig_node->orig,
263 neigh_node->orig_node->primary_addr))
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000264 goto candidate_del;
265
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000266 router = orig_node_get_router(orig_node);
267 if (!router)
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000268 goto candidate_del;
269
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000270 /* ... and is good enough to be considered */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000271 if (neigh_node->tq_avg < router->tq_avg - BONDING_TQ_THRESHOLD)
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000272 goto candidate_del;
273
274 /**
275 * check if we have another candidate with the same mac address or
276 * interface. If we do, we won't select this candidate because of
277 * possible interference.
278 */
279 hlist_for_each_entry_rcu(tmp_neigh_node, node,
280 &orig_node->neigh_list, list) {
281
282 if (tmp_neigh_node == neigh_node)
283 continue;
284
285 /* we only care if the other candidate is even
286 * considered as candidate. */
287 if (list_empty(&tmp_neigh_node->bonding_list))
288 continue;
289
290 if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) ||
Marek Lindner39901e72011-02-18 12:28:08 +0000291 (compare_eth(neigh_node->addr, tmp_neigh_node->addr))) {
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000292 interference_candidate = 1;
293 break;
294 }
295 }
296
297 /* don't care further if it is an interference candidate */
298 if (interference_candidate)
299 goto candidate_del;
300
301 /* this neighbor already is part of our candidate list */
302 if (!list_empty(&neigh_node->bonding_list))
303 goto out;
304
Marek Lindner44524fc2011-02-10 14:33:53 +0000305 if (!atomic_inc_not_zero(&neigh_node->refcount))
306 goto out;
307
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000308 list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000309 atomic_inc(&orig_node->bond_candidates);
310 goto out;
311
312candidate_del:
313 bonding_candidate_del(orig_node, neigh_node);
314
315out:
316 spin_unlock_bh(&orig_node->neigh_list_lock);
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000317
318 if (router)
319 neigh_node_free_ref(router);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000320}
321
322/* copy primary address for bonding */
Sven Eckelmann747e4222011-05-14 23:14:50 +0200323static void bonding_save_primary(const struct orig_node *orig_node,
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000324 struct orig_node *orig_neigh_node,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200325 const struct batman_ogm_packet
326 *batman_ogm_packet)
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000327{
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200328 if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000329 return;
330
331 memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
332}
333
Sven Eckelmann747e4222011-05-14 23:14:50 +0200334static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
335 const struct ethhdr *ethhdr,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200336 const struct batman_ogm_packet *batman_ogm_packet,
Marek Lindnere6c10f42011-02-18 12:33:20 +0000337 struct hard_iface *if_incoming,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200338 const unsigned char *tt_buff, int is_duplicate)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000339{
340 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000341 struct neigh_node *router = NULL;
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000342 struct orig_node *orig_node_tmp;
Marek Lindner9591a792010-12-12 21:57:11 +0000343 struct hlist_node *node;
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000344 uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000345
346 bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
347 "Searching and updating originator entry of received packet\n");
348
Marek Lindnerf987ed62010-12-12 21:57:12 +0000349 rcu_read_lock();
350 hlist_for_each_entry_rcu(tmp_neigh_node, node,
351 &orig_node->neigh_list, list) {
Marek Lindner39901e72011-02-18 12:28:08 +0000352 if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
Marek Lindner44524fc2011-02-10 14:33:53 +0000353 (tmp_neigh_node->if_incoming == if_incoming) &&
354 atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
355 if (neigh_node)
356 neigh_node_free_ref(neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000357 neigh_node = tmp_neigh_node;
358 continue;
359 }
360
361 if (is_duplicate)
362 continue;
363
Linus Lüssing68003902011-03-14 22:43:40 +0000364 spin_lock_bh(&tmp_neigh_node->tq_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000365 ring_buffer_set(tmp_neigh_node->tq_recv,
366 &tmp_neigh_node->tq_index, 0);
367 tmp_neigh_node->tq_avg =
368 ring_buffer_avg(tmp_neigh_node->tq_recv);
Linus Lüssing68003902011-03-14 22:43:40 +0000369 spin_unlock_bh(&tmp_neigh_node->tq_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000370 }
371
372 if (!neigh_node) {
373 struct orig_node *orig_tmp;
374
375 orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
376 if (!orig_tmp)
Marek Lindnera775eb82011-01-19 20:01:39 +0000377 goto unlock;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000378
379 neigh_node = create_neighbor(orig_node, orig_tmp,
380 ethhdr->h_source, if_incoming);
Marek Lindner16b1aba2011-01-19 20:01:42 +0000381
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000382 orig_node_free_ref(orig_tmp);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000383 if (!neigh_node)
Marek Lindnera775eb82011-01-19 20:01:39 +0000384 goto unlock;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000385 } else
386 bat_dbg(DBG_BATMAN, bat_priv,
387 "Updating existing last-hop neighbor of originator\n");
388
Marek Lindnera775eb82011-01-19 20:01:39 +0000389 rcu_read_unlock();
390
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200391 orig_node->flags = batman_ogm_packet->flags;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000392 neigh_node->last_valid = jiffies;
393
Linus Lüssing68003902011-03-14 22:43:40 +0000394 spin_lock_bh(&neigh_node->tq_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000395 ring_buffer_set(neigh_node->tq_recv,
396 &neigh_node->tq_index,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200397 batman_ogm_packet->tq);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000398 neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
Linus Lüssing68003902011-03-14 22:43:40 +0000399 spin_unlock_bh(&neigh_node->tq_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000400
401 if (!is_duplicate) {
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200402 orig_node->last_ttl = batman_ogm_packet->ttl;
403 neigh_node->last_ttl = batman_ogm_packet->ttl;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000404 }
405
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000406 bonding_candidate_add(orig_node, neigh_node);
407
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000408 /* if this neighbor already is our next hop there is nothing
409 * to change */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000410 router = orig_node_get_router(orig_node);
411 if (router == neigh_node)
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200412 goto update_tt;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000413
414 /* if this neighbor does not offer a better TQ we won't consider it */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000415 if (router && (router->tq_avg > neigh_node->tq_avg))
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200416 goto update_tt;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000417
Antonio Quartulli015758d2011-07-09 17:52:13 +0200418 /* if the TQ is the same and the link not more symmetric we
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000419 * won't consider it either */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000420 if (router && (neigh_node->tq_avg == router->tq_avg)) {
421 orig_node_tmp = router->orig_node;
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000422 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
423 bcast_own_sum_orig =
424 orig_node_tmp->bcast_own_sum[if_incoming->if_num];
425 spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
426
427 orig_node_tmp = neigh_node->orig_node;
428 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
429 bcast_own_sum_neigh =
430 orig_node_tmp->bcast_own_sum[if_incoming->if_num];
431 spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
432
433 if (bcast_own_sum_orig >= bcast_own_sum_neigh)
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200434 goto update_tt;
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000435 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000436
Antonio Quartullia73105b2011-04-27 14:27:44 +0200437 update_routes(bat_priv, orig_node, neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000438
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200439update_tt:
Antonio Quartullia73105b2011-04-27 14:27:44 +0200440 /* I have to check for transtable changes only if the OGM has been
441 * sent through a primary interface */
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200442 if (((batman_ogm_packet->orig != ethhdr->h_source) &&
443 (batman_ogm_packet->ttl > 2)) ||
444 (batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
Marek Lindnera943cac2011-07-30 13:10:18 +0200445 tt_update_orig(bat_priv, orig_node, tt_buff,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200446 batman_ogm_packet->tt_num_changes,
447 batman_ogm_packet->ttvn,
448 batman_ogm_packet->tt_crc);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000449
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200450 if (orig_node->gw_flags != batman_ogm_packet->gw_flags)
451 gw_node_update(bat_priv, orig_node,
452 batman_ogm_packet->gw_flags);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000453
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200454 orig_node->gw_flags = batman_ogm_packet->gw_flags;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000455
456 /* restart gateway selection if fast or late switching was enabled */
457 if ((orig_node->gw_flags) &&
458 (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&
459 (atomic_read(&bat_priv->gw_sel_class) > 2))
460 gw_check_election(bat_priv, orig_node);
Marek Lindnera775eb82011-01-19 20:01:39 +0000461
462 goto out;
463
464unlock:
465 rcu_read_unlock();
466out:
467 if (neigh_node)
Marek Lindner44524fc2011-02-10 14:33:53 +0000468 neigh_node_free_ref(neigh_node);
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000469 if (router)
470 neigh_node_free_ref(router);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000471}
472
473/* checks whether the host restarted and is in the protection time.
474 * returns:
475 * 0 if the packet is to be accepted
476 * 1 if the packet is to be ignored.
477 */
478static int window_protected(struct bat_priv *bat_priv,
479 int32_t seq_num_diff,
480 unsigned long *last_reset)
481{
482 if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
483 || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
484 if (time_after(jiffies, *last_reset +
485 msecs_to_jiffies(RESET_PROTECTION_MS))) {
486
487 *last_reset = jiffies;
488 bat_dbg(DBG_BATMAN, bat_priv,
489 "old packet received, start protection\n");
490
491 return 0;
492 } else
493 return 1;
494 }
495 return 0;
496}
497
498/* processes a batman packet for all interfaces, adjusts the sequence number and
499 * finds out whether it is a duplicate.
500 * returns:
501 * 1 the packet is a duplicate
502 * 0 the packet has not yet been received
503 * -1 the packet is old and has been received while the seqno window
504 * was protected. Caller should drop it.
505 */
David Howellsb2c44a52011-06-15 09:41:36 +0200506static int count_real_packets(const struct ethhdr *ethhdr,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200507 const struct batman_ogm_packet *batman_ogm_packet,
508 const struct hard_iface *if_incoming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000509{
510 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
511 struct orig_node *orig_node;
512 struct neigh_node *tmp_neigh_node;
Marek Lindner9591a792010-12-12 21:57:11 +0000513 struct hlist_node *node;
David Howellsb2c44a52011-06-15 09:41:36 +0200514 int is_duplicate = 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000515 int32_t seq_diff;
516 int need_update = 0;
Marek Lindner0ede9f42011-01-25 21:52:10 +0000517 int set_mark, ret = -1;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000518
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200519 orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000520 if (!orig_node)
521 return 0;
522
Marek Lindner0ede9f42011-01-25 21:52:10 +0000523 spin_lock_bh(&orig_node->ogm_cnt_lock);
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200524 seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000525
526 /* signalize caller that the packet is to be dropped. */
527 if (window_protected(bat_priv, seq_diff,
528 &orig_node->batman_seqno_reset))
Marek Lindner0ede9f42011-01-25 21:52:10 +0000529 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000530
Marek Lindnerf987ed62010-12-12 21:57:12 +0000531 rcu_read_lock();
532 hlist_for_each_entry_rcu(tmp_neigh_node, node,
533 &orig_node->neigh_list, list) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000534
535 is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
536 orig_node->last_real_seqno,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200537 batman_ogm_packet->seqno);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000538
Marek Lindner39901e72011-02-18 12:28:08 +0000539 if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000540 (tmp_neigh_node->if_incoming == if_incoming))
541 set_mark = 1;
542 else
543 set_mark = 0;
544
545 /* if the window moved, set the update flag. */
546 need_update |= bit_get_packet(bat_priv,
547 tmp_neigh_node->real_bits,
548 seq_diff, set_mark);
549
550 tmp_neigh_node->real_packet_count =
551 bit_packet_count(tmp_neigh_node->real_bits);
552 }
Marek Lindnerf987ed62010-12-12 21:57:12 +0000553 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000554
555 if (need_update) {
556 bat_dbg(DBG_BATMAN, bat_priv,
557 "updating last_seqno: old %d, new %d\n",
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200558 orig_node->last_real_seqno, batman_ogm_packet->seqno);
559 orig_node->last_real_seqno = batman_ogm_packet->seqno;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000560 }
561
Marek Lindner0ede9f42011-01-25 21:52:10 +0000562 ret = is_duplicate;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000563
Marek Lindner0ede9f42011-01-25 21:52:10 +0000564out:
565 spin_unlock_bh(&orig_node->ogm_cnt_lock);
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000566 orig_node_free_ref(orig_node);
Marek Lindner0ede9f42011-01-25 21:52:10 +0000567 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000568}
569
Sven Eckelmann747e4222011-05-14 23:14:50 +0200570void receive_bat_packet(const struct ethhdr *ethhdr,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200571 struct batman_ogm_packet *batman_ogm_packet,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200572 const unsigned char *tt_buff,
Marek Lindnere6c10f42011-02-18 12:33:20 +0000573 struct hard_iface *if_incoming)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000574{
575 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
Marek Lindnere6c10f42011-02-18 12:33:20 +0000576 struct hard_iface *hard_iface;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000577 struct orig_node *orig_neigh_node, *orig_node;
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000578 struct neigh_node *router = NULL, *router_router = NULL;
579 struct neigh_node *orig_neigh_router = NULL;
Sven Eckelmannb4e17052011-06-15 09:41:37 +0200580 int has_directlink_flag;
581 int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
582 int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
David Howellsb2c44a52011-06-15 09:41:36 +0200583 int is_duplicate;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000584 uint32_t if_incoming_seqno;
585
586 /* Silently drop when the batman packet is actually not a
587 * correct packet.
588 *
589 * This might happen if a packet is padded (e.g. Ethernet has a
590 * minimum frame length of 64 byte) and the aggregation interprets
591 * it as an additional length.
592 *
593 * TODO: A more sane solution would be to have a bit in the
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200594 * batman_ogm_packet to detect whether the packet is the last
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000595 * packet in an aggregation. Here we expect that the padding
596 * is always zero (or not 0x01)
597 */
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200598 if (batman_ogm_packet->packet_type != BAT_OGM)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000599 return;
600
601 /* could be changed by schedule_own_packet() */
602 if_incoming_seqno = atomic_read(&if_incoming->seqno);
603
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200604 has_directlink_flag = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000605
Marek Lindner39901e72011-02-18 12:28:08 +0000606 is_single_hop_neigh = (compare_eth(ethhdr->h_source,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200607 batman_ogm_packet->orig) ? 1 : 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000608
609 bat_dbg(DBG_BATMAN, bat_priv,
610 "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
Antonio Quartullia73105b2011-04-27 14:27:44 +0200611 "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, "
612 "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000613 ethhdr->h_source, if_incoming->net_dev->name,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200614 if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
615 batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,
616 batman_ogm_packet->ttvn, batman_ogm_packet->tt_crc,
617 batman_ogm_packet->tt_num_changes, batman_ogm_packet->tq,
618 batman_ogm_packet->ttl, batman_ogm_packet->version,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000619 has_directlink_flag);
620
621 rcu_read_lock();
Marek Lindnere6c10f42011-02-18 12:33:20 +0000622 list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
623 if (hard_iface->if_status != IF_ACTIVE)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000624 continue;
625
Marek Lindnere6c10f42011-02-18 12:33:20 +0000626 if (hard_iface->soft_iface != if_incoming->soft_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000627 continue;
628
Marek Lindner39901e72011-02-18 12:28:08 +0000629 if (compare_eth(ethhdr->h_source,
Marek Lindnere6c10f42011-02-18 12:33:20 +0000630 hard_iface->net_dev->dev_addr))
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000631 is_my_addr = 1;
632
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200633 if (compare_eth(batman_ogm_packet->orig,
Marek Lindnere6c10f42011-02-18 12:33:20 +0000634 hard_iface->net_dev->dev_addr))
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000635 is_my_orig = 1;
636
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200637 if (compare_eth(batman_ogm_packet->prev_sender,
Marek Lindnere6c10f42011-02-18 12:33:20 +0000638 hard_iface->net_dev->dev_addr))
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000639 is_my_oldorig = 1;
640
Antonio Quartulli44e92bc2011-05-21 01:33:07 +0200641 if (is_broadcast_ether_addr(ethhdr->h_source))
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000642 is_broadcast = 1;
643 }
644 rcu_read_unlock();
645
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200646 if (batman_ogm_packet->version != COMPAT_VERSION) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000647 bat_dbg(DBG_BATMAN, bat_priv,
648 "Drop packet: incompatible batman version (%i)\n",
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200649 batman_ogm_packet->version);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000650 return;
651 }
652
653 if (is_my_addr) {
654 bat_dbg(DBG_BATMAN, bat_priv,
655 "Drop packet: received my own broadcast (sender: %pM"
656 ")\n",
657 ethhdr->h_source);
658 return;
659 }
660
661 if (is_broadcast) {
662 bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
663 "ignoring all packets with broadcast source addr (sender: %pM"
664 ")\n", ethhdr->h_source);
665 return;
666 }
667
668 if (is_my_orig) {
669 unsigned long *word;
670 int offset;
671
672 orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000673 if (!orig_neigh_node)
674 return;
675
676 /* neighbor has to indicate direct link and it has to
677 * come via the corresponding interface */
Daniele Furland1829fa2011-06-07 00:45:55 +0200678 /* save packet seqno for bidirectional check */
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000679 if (has_directlink_flag &&
Marek Lindner39901e72011-02-18 12:28:08 +0000680 compare_eth(if_incoming->net_dev->dev_addr,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200681 batman_ogm_packet->orig)) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000682 offset = if_incoming->if_num * NUM_WORDS;
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000683
684 spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000685 word = &(orig_neigh_node->bcast_own[offset]);
Daniele Furland1829fa2011-06-07 00:45:55 +0200686 bit_mark(word,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200687 if_incoming_seqno -
688 batman_ogm_packet->seqno - 2);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000689 orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
690 bit_packet_count(word);
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000691 spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000692 }
693
694 bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
695 "originator packet from myself (via neighbor)\n");
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000696 orig_node_free_ref(orig_neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000697 return;
698 }
699
700 if (is_my_oldorig) {
701 bat_dbg(DBG_BATMAN, bat_priv,
702 "Drop packet: ignoring all rebroadcast echos (sender: "
703 "%pM)\n", ethhdr->h_source);
704 return;
705 }
706
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200707 orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000708 if (!orig_node)
709 return;
710
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200711 is_duplicate = count_real_packets(ethhdr, batman_ogm_packet,
712 if_incoming);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000713
714 if (is_duplicate == -1) {
715 bat_dbg(DBG_BATMAN, bat_priv,
716 "Drop packet: packet within seqno protection time "
717 "(sender: %pM)\n", ethhdr->h_source);
Marek Lindner16b1aba2011-01-19 20:01:42 +0000718 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000719 }
720
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200721 if (batman_ogm_packet->tq == 0) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000722 bat_dbg(DBG_BATMAN, bat_priv,
723 "Drop packet: originator packet with tq equal 0\n");
Marek Lindner16b1aba2011-01-19 20:01:42 +0000724 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000725 }
726
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000727 router = orig_node_get_router(orig_node);
728 if (router)
729 router_router = orig_node_get_router(router->orig_node);
730
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000731 /* avoid temporary routing loops */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000732 if (router && router_router &&
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200733 (compare_eth(router->addr, batman_ogm_packet->prev_sender)) &&
734 !(compare_eth(batman_ogm_packet->orig,
735 batman_ogm_packet->prev_sender)) &&
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000736 (compare_eth(router->addr, router_router->addr))) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000737 bat_dbg(DBG_BATMAN, bat_priv,
738 "Drop packet: ignoring all rebroadcast packets that "
739 "may make me loop (sender: %pM)\n", ethhdr->h_source);
Marek Lindner16b1aba2011-01-19 20:01:42 +0000740 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000741 }
742
743 /* if sender is a direct neighbor the sender mac equals
744 * originator mac */
745 orig_neigh_node = (is_single_hop_neigh ?
746 orig_node :
747 get_orig_node(bat_priv, ethhdr->h_source));
748 if (!orig_neigh_node)
Marek Lindnerd0072602011-01-19 20:01:44 +0000749 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000750
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000751 orig_neigh_router = orig_node_get_router(orig_neigh_node);
752
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000753 /* drop packet if sender is not a direct neighbor and if we
754 * don't route towards it */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000755 if (!is_single_hop_neigh && (!orig_neigh_router)) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000756 bat_dbg(DBG_BATMAN, bat_priv,
757 "Drop packet: OGM via unknown neighbor!\n");
Marek Lindner16b1aba2011-01-19 20:01:42 +0000758 goto out_neigh;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000759 }
760
761 is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200762 batman_ogm_packet,
763 if_incoming);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000764
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200765 bonding_save_primary(orig_node, orig_neigh_node, batman_ogm_packet);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000766
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000767 /* update ranking if it is not a duplicate or has the same
768 * seqno and similar ttl as the non-duplicate */
769 if (is_bidirectional &&
770 (!is_duplicate ||
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200771 ((orig_node->last_real_seqno == batman_ogm_packet->seqno) &&
772 (orig_node->last_ttl - 3 <= batman_ogm_packet->ttl))))
773 update_orig(bat_priv, orig_node, ethhdr, batman_ogm_packet,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200774 if_incoming, tt_buff, is_duplicate);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000775
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000776 /* is single hop (direct) neighbor */
777 if (is_single_hop_neigh) {
778
779 /* mark direct link on incoming interface */
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200780 schedule_forward_packet(orig_node, ethhdr, batman_ogm_packet,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200781 1, if_incoming);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000782
783 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
784 "rebroadcast neighbor packet with direct link flag\n");
Marek Lindner16b1aba2011-01-19 20:01:42 +0000785 goto out_neigh;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000786 }
787
788 /* multihop originator */
789 if (!is_bidirectional) {
790 bat_dbg(DBG_BATMAN, bat_priv,
791 "Drop packet: not received via bidirectional link\n");
Marek Lindner16b1aba2011-01-19 20:01:42 +0000792 goto out_neigh;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000793 }
794
795 if (is_duplicate) {
796 bat_dbg(DBG_BATMAN, bat_priv,
797 "Drop packet: duplicate packet received\n");
Marek Lindner16b1aba2011-01-19 20:01:42 +0000798 goto out_neigh;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000799 }
800
801 bat_dbg(DBG_BATMAN, bat_priv,
802 "Forwarding packet: rebroadcast originator packet\n");
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200803 schedule_forward_packet(orig_node, ethhdr, batman_ogm_packet,
Antonio Quartullia73105b2011-04-27 14:27:44 +0200804 0, if_incoming);
Marek Lindner16b1aba2011-01-19 20:01:42 +0000805
806out_neigh:
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000807 if ((orig_neigh_node) && (!is_single_hop_neigh))
808 orig_node_free_ref(orig_neigh_node);
Marek Lindner16b1aba2011-01-19 20:01:42 +0000809out:
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000810 if (router)
811 neigh_node_free_ref(router);
812 if (router_router)
813 neigh_node_free_ref(router_router);
814 if (orig_neigh_router)
815 neigh_node_free_ref(orig_neigh_router);
816
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000817 orig_node_free_ref(orig_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000818}
819
Marek Lindnere6c10f42011-02-18 12:33:20 +0000820int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000821{
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000822 struct ethhdr *ethhdr;
823
824 /* drop packet if it has not necessary minimum size */
Marek Lindnerb6da4bf2011-07-29 17:31:50 +0200825 if (unlikely(!pskb_may_pull(skb, BATMAN_OGM_LEN)))
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000826 return NET_RX_DROP;
827
828 ethhdr = (struct ethhdr *)skb_mac_header(skb);
829
830 /* packet with broadcast indication but unicast recipient */
831 if (!is_broadcast_ether_addr(ethhdr->h_dest))
832 return NET_RX_DROP;
833
834 /* packet with broadcast sender address */
835 if (is_broadcast_ether_addr(ethhdr->h_source))
836 return NET_RX_DROP;
837
838 /* create a copy of the skb, if needed, to modify it. */
839 if (skb_cow(skb, 0) < 0)
840 return NET_RX_DROP;
841
842 /* keep skb linear */
843 if (skb_linearize(skb) < 0)
844 return NET_RX_DROP;
845
846 ethhdr = (struct ethhdr *)skb_mac_header(skb);
847
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000848 receive_aggr_bat_packet(ethhdr,
849 skb->data,
850 skb_headlen(skb),
Marek Lindnere6c10f42011-02-18 12:33:20 +0000851 hard_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000852
853 kfree_skb(skb);
854 return NET_RX_SUCCESS;
855}
856
857static int recv_my_icmp_packet(struct bat_priv *bat_priv,
858 struct sk_buff *skb, size_t icmp_len)
859{
Marek Lindner32ae9b22011-04-20 15:40:58 +0200860 struct hard_iface *primary_if = NULL;
Marek Lindner44524fc2011-02-10 14:33:53 +0000861 struct orig_node *orig_node = NULL;
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000862 struct neigh_node *router = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000863 struct icmp_packet_rr *icmp_packet;
Marek Lindner44524fc2011-02-10 14:33:53 +0000864 int ret = NET_RX_DROP;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000865
866 icmp_packet = (struct icmp_packet_rr *)skb->data;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000867
868 /* add data to device queue */
869 if (icmp_packet->msg_type != ECHO_REQUEST) {
870 bat_socket_receive_packet(icmp_packet, icmp_len);
Marek Lindner44524fc2011-02-10 14:33:53 +0000871 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000872 }
873
Marek Lindner32ae9b22011-04-20 15:40:58 +0200874 primary_if = primary_if_get_selected(bat_priv);
875 if (!primary_if)
Marek Lindner44524fc2011-02-10 14:33:53 +0000876 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000877
878 /* answer echo request (ping) */
879 /* get routing information */
Marek Lindner7aadf882011-02-18 12:28:09 +0000880 orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
Marek Lindner44524fc2011-02-10 14:33:53 +0000881 if (!orig_node)
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000882 goto out;
Marek Lindner44524fc2011-02-10 14:33:53 +0000883
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000884 router = orig_node_get_router(orig_node);
885 if (!router)
886 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000887
Marek Lindner44524fc2011-02-10 14:33:53 +0000888 /* create a copy of the skb, if needed, to modify it. */
889 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
890 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000891
Marek Lindner44524fc2011-02-10 14:33:53 +0000892 icmp_packet = (struct icmp_packet_rr *)skb->data;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000893
Marek Lindner44524fc2011-02-10 14:33:53 +0000894 memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
Marek Lindner32ae9b22011-04-20 15:40:58 +0200895 memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
Marek Lindner44524fc2011-02-10 14:33:53 +0000896 icmp_packet->msg_type = ECHO_REPLY;
897 icmp_packet->ttl = TTL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000898
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000899 send_skb_packet(skb, router->if_incoming, router->addr);
Marek Lindner44524fc2011-02-10 14:33:53 +0000900 ret = NET_RX_SUCCESS;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000901
Marek Lindner44524fc2011-02-10 14:33:53 +0000902out:
Marek Lindner32ae9b22011-04-20 15:40:58 +0200903 if (primary_if)
904 hardif_free_ref(primary_if);
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000905 if (router)
906 neigh_node_free_ref(router);
Marek Lindner44524fc2011-02-10 14:33:53 +0000907 if (orig_node)
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000908 orig_node_free_ref(orig_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000909 return ret;
910}
911
912static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
Simon Wunderlich74ef1152010-12-29 16:15:19 +0000913 struct sk_buff *skb)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000914{
Marek Lindner32ae9b22011-04-20 15:40:58 +0200915 struct hard_iface *primary_if = NULL;
Marek Lindner44524fc2011-02-10 14:33:53 +0000916 struct orig_node *orig_node = NULL;
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000917 struct neigh_node *router = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000918 struct icmp_packet *icmp_packet;
Marek Lindner44524fc2011-02-10 14:33:53 +0000919 int ret = NET_RX_DROP;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000920
921 icmp_packet = (struct icmp_packet *)skb->data;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000922
923 /* send TTL exceeded if packet is an echo request (traceroute) */
924 if (icmp_packet->msg_type != ECHO_REQUEST) {
925 pr_debug("Warning - can't forward icmp packet from %pM to "
926 "%pM: ttl exceeded\n", icmp_packet->orig,
927 icmp_packet->dst);
Marek Lindner44524fc2011-02-10 14:33:53 +0000928 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000929 }
930
Marek Lindner32ae9b22011-04-20 15:40:58 +0200931 primary_if = primary_if_get_selected(bat_priv);
932 if (!primary_if)
Marek Lindner44524fc2011-02-10 14:33:53 +0000933 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000934
935 /* get routing information */
Marek Lindner7aadf882011-02-18 12:28:09 +0000936 orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
Marek Lindner44524fc2011-02-10 14:33:53 +0000937 if (!orig_node)
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000938 goto out;
Marek Lindner44524fc2011-02-10 14:33:53 +0000939
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000940 router = orig_node_get_router(orig_node);
941 if (!router)
942 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000943
Marek Lindner44524fc2011-02-10 14:33:53 +0000944 /* create a copy of the skb, if needed, to modify it. */
945 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
946 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000947
Marek Lindner44524fc2011-02-10 14:33:53 +0000948 icmp_packet = (struct icmp_packet *)skb->data;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000949
Marek Lindner44524fc2011-02-10 14:33:53 +0000950 memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
Marek Lindner32ae9b22011-04-20 15:40:58 +0200951 memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
Marek Lindner44524fc2011-02-10 14:33:53 +0000952 icmp_packet->msg_type = TTL_EXCEEDED;
953 icmp_packet->ttl = TTL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000954
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000955 send_skb_packet(skb, router->if_incoming, router->addr);
Marek Lindner44524fc2011-02-10 14:33:53 +0000956 ret = NET_RX_SUCCESS;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000957
Marek Lindner44524fc2011-02-10 14:33:53 +0000958out:
Marek Lindner32ae9b22011-04-20 15:40:58 +0200959 if (primary_if)
960 hardif_free_ref(primary_if);
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000961 if (router)
962 neigh_node_free_ref(router);
Marek Lindner44524fc2011-02-10 14:33:53 +0000963 if (orig_node)
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000964 orig_node_free_ref(orig_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000965 return ret;
966}
967
968
Marek Lindnere6c10f42011-02-18 12:33:20 +0000969int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000970{
971 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
972 struct icmp_packet_rr *icmp_packet;
973 struct ethhdr *ethhdr;
Marek Lindner44524fc2011-02-10 14:33:53 +0000974 struct orig_node *orig_node = NULL;
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000975 struct neigh_node *router = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000976 int hdr_size = sizeof(struct icmp_packet);
Marek Lindner44524fc2011-02-10 14:33:53 +0000977 int ret = NET_RX_DROP;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000978
979 /**
980 * we truncate all incoming icmp packets if they don't match our size
981 */
982 if (skb->len >= sizeof(struct icmp_packet_rr))
983 hdr_size = sizeof(struct icmp_packet_rr);
984
985 /* drop packet if it has not necessary minimum size */
986 if (unlikely(!pskb_may_pull(skb, hdr_size)))
Marek Lindner44524fc2011-02-10 14:33:53 +0000987 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000988
989 ethhdr = (struct ethhdr *)skb_mac_header(skb);
990
991 /* packet with unicast indication but broadcast recipient */
992 if (is_broadcast_ether_addr(ethhdr->h_dest))
Marek Lindner44524fc2011-02-10 14:33:53 +0000993 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000994
995 /* packet with broadcast sender address */
996 if (is_broadcast_ether_addr(ethhdr->h_source))
Marek Lindner44524fc2011-02-10 14:33:53 +0000997 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000998
999 /* not for me */
1000 if (!is_my_mac(ethhdr->h_dest))
Marek Lindner44524fc2011-02-10 14:33:53 +00001001 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001002
1003 icmp_packet = (struct icmp_packet_rr *)skb->data;
1004
1005 /* add record route information if not full */
1006 if ((hdr_size == sizeof(struct icmp_packet_rr)) &&
1007 (icmp_packet->rr_cur < BAT_RR_LEN)) {
1008 memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]),
1009 ethhdr->h_dest, ETH_ALEN);
1010 icmp_packet->rr_cur++;
1011 }
1012
1013 /* packet for me */
1014 if (is_my_mac(icmp_packet->dst))
1015 return recv_my_icmp_packet(bat_priv, skb, hdr_size);
1016
1017 /* TTL exceeded */
1018 if (icmp_packet->ttl < 2)
Simon Wunderlich74ef1152010-12-29 16:15:19 +00001019 return recv_icmp_ttl_exceeded(bat_priv, skb);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001020
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001021 /* get routing information */
Marek Lindner7aadf882011-02-18 12:28:09 +00001022 orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
Marek Lindner44524fc2011-02-10 14:33:53 +00001023 if (!orig_node)
Linus Lüssinge1a5382f2011-03-14 22:43:37 +00001024 goto out;
Marek Lindner44524fc2011-02-10 14:33:53 +00001025
Linus Lüssinge1a5382f2011-03-14 22:43:37 +00001026 router = orig_node_get_router(orig_node);
1027 if (!router)
1028 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001029
Marek Lindner44524fc2011-02-10 14:33:53 +00001030 /* create a copy of the skb, if needed, to modify it. */
1031 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
1032 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001033
Marek Lindner44524fc2011-02-10 14:33:53 +00001034 icmp_packet = (struct icmp_packet_rr *)skb->data;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001035
Marek Lindner44524fc2011-02-10 14:33:53 +00001036 /* decrement ttl */
1037 icmp_packet->ttl--;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001038
Marek Lindner44524fc2011-02-10 14:33:53 +00001039 /* route it */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +00001040 send_skb_packet(skb, router->if_incoming, router->addr);
Marek Lindner44524fc2011-02-10 14:33:53 +00001041 ret = NET_RX_SUCCESS;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001042
Marek Lindner44524fc2011-02-10 14:33:53 +00001043out:
Linus Lüssinge1a5382f2011-03-14 22:43:37 +00001044 if (router)
1045 neigh_node_free_ref(router);
Marek Lindner44524fc2011-02-10 14:33:53 +00001046 if (orig_node)
Marek Lindner7b36e8e2011-02-18 12:28:10 +00001047 orig_node_free_ref(orig_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001048 return ret;
1049}
1050
Linus Lüssing55158622011-03-14 22:43:27 +00001051/* In the bonding case, send the packets in a round
1052 * robin fashion over the remaining interfaces.
1053 *
1054 * This method rotates the bonding list and increases the
1055 * returned router's refcount. */
1056static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
Sven Eckelmann747e4222011-05-14 23:14:50 +02001057 const struct hard_iface *recv_if)
Linus Lüssing55158622011-03-14 22:43:27 +00001058{
1059 struct neigh_node *tmp_neigh_node;
1060 struct neigh_node *router = NULL, *first_candidate = NULL;
1061
1062 rcu_read_lock();
1063 list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
1064 bonding_list) {
1065 if (!first_candidate)
1066 first_candidate = tmp_neigh_node;
1067
1068 /* recv_if == NULL on the first node. */
1069 if (tmp_neigh_node->if_incoming == recv_if)
1070 continue;
1071
1072 if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
1073 continue;
1074
1075 router = tmp_neigh_node;
1076 break;
1077 }
1078
1079 /* use the first candidate if nothing was found. */
1080 if (!router && first_candidate &&
1081 atomic_inc_not_zero(&first_candidate->refcount))
1082 router = first_candidate;
1083
1084 if (!router)
1085 goto out;
1086
1087 /* selected should point to the next element
1088 * after the current router */
1089 spin_lock_bh(&primary_orig->neigh_list_lock);
1090 /* this is a list_move(), which unfortunately
1091 * does not exist as rcu version */
1092 list_del_rcu(&primary_orig->bond_list);
1093 list_add_rcu(&primary_orig->bond_list,
1094 &router->bonding_list);
1095 spin_unlock_bh(&primary_orig->neigh_list_lock);
1096
1097out:
1098 rcu_read_unlock();
1099 return router;
1100}
1101
1102/* Interface Alternating: Use the best of the
1103 * remaining candidates which are not using
1104 * this interface.
1105 *
1106 * Increases the returned router's refcount */
1107static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
Sven Eckelmann747e4222011-05-14 23:14:50 +02001108 const struct hard_iface *recv_if)
Linus Lüssing55158622011-03-14 22:43:27 +00001109{
1110 struct neigh_node *tmp_neigh_node;
1111 struct neigh_node *router = NULL, *first_candidate = NULL;
1112
1113 rcu_read_lock();
1114 list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
1115 bonding_list) {
1116 if (!first_candidate)
1117 first_candidate = tmp_neigh_node;
1118
1119 /* recv_if == NULL on the first node. */
1120 if (tmp_neigh_node->if_incoming == recv_if)
1121 continue;
1122
1123 if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
1124 continue;
1125
1126 /* if we don't have a router yet
1127 * or this one is better, choose it. */
1128 if ((!router) ||
1129 (tmp_neigh_node->tq_avg > router->tq_avg)) {
1130 /* decrement refcount of
1131 * previously selected router */
1132 if (router)
1133 neigh_node_free_ref(router);
1134
1135 router = tmp_neigh_node;
1136 atomic_inc_not_zero(&router->refcount);
1137 }
1138
1139 neigh_node_free_ref(tmp_neigh_node);
1140 }
1141
1142 /* use the first candidate if nothing was found. */
1143 if (!router && first_candidate &&
1144 atomic_inc_not_zero(&first_candidate->refcount))
1145 router = first_candidate;
1146
1147 rcu_read_unlock();
1148 return router;
1149}
1150
Antonio Quartullia73105b2011-04-27 14:27:44 +02001151int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
1152{
1153 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1154 struct tt_query_packet *tt_query;
1155 struct ethhdr *ethhdr;
1156
1157 /* drop packet if it has not necessary minimum size */
1158 if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet))))
1159 goto out;
1160
1161 /* I could need to modify it */
1162 if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0)
1163 goto out;
1164
1165 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1166
1167 /* packet with unicast indication but broadcast recipient */
1168 if (is_broadcast_ether_addr(ethhdr->h_dest))
1169 goto out;
1170
1171 /* packet with broadcast sender address */
1172 if (is_broadcast_ether_addr(ethhdr->h_source))
1173 goto out;
1174
1175 tt_query = (struct tt_query_packet *)skb->data;
1176
1177 tt_query->tt_data = ntohs(tt_query->tt_data);
1178
1179 switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
1180 case TT_REQUEST:
1181 /* If we cannot provide an answer the tt_request is
1182 * forwarded */
1183 if (!send_tt_response(bat_priv, tt_query)) {
1184 bat_dbg(DBG_TT, bat_priv,
1185 "Routing TT_REQUEST to %pM [%c]\n",
1186 tt_query->dst,
1187 (tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
1188 tt_query->tt_data = htons(tt_query->tt_data);
1189 return route_unicast_packet(skb, recv_if);
1190 }
1191 break;
1192 case TT_RESPONSE:
Antonio Quartulli015758d2011-07-09 17:52:13 +02001193 /* packet needs to be linearized to access the TT changes */
Antonio Quartullia73105b2011-04-27 14:27:44 +02001194 if (skb_linearize(skb) < 0)
1195 goto out;
1196
1197 if (is_my_mac(tt_query->dst))
1198 handle_tt_response(bat_priv, tt_query);
1199 else {
1200 bat_dbg(DBG_TT, bat_priv,
1201 "Routing TT_RESPONSE to %pM [%c]\n",
1202 tt_query->dst,
1203 (tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
1204 tt_query->tt_data = htons(tt_query->tt_data);
1205 return route_unicast_packet(skb, recv_if);
1206 }
1207 break;
1208 }
1209
1210out:
1211 /* returning NET_RX_DROP will make the caller function kfree the skb */
1212 return NET_RX_DROP;
1213}
1214
Antonio Quartullicc47f662011-04-27 14:27:57 +02001215int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
1216{
1217 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1218 struct roam_adv_packet *roam_adv_packet;
1219 struct orig_node *orig_node;
1220 struct ethhdr *ethhdr;
1221
1222 /* drop packet if it has not necessary minimum size */
1223 if (unlikely(!pskb_may_pull(skb, sizeof(struct roam_adv_packet))))
1224 goto out;
1225
1226 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1227
1228 /* packet with unicast indication but broadcast recipient */
1229 if (is_broadcast_ether_addr(ethhdr->h_dest))
1230 goto out;
1231
1232 /* packet with broadcast sender address */
1233 if (is_broadcast_ether_addr(ethhdr->h_source))
1234 goto out;
1235
1236 roam_adv_packet = (struct roam_adv_packet *)skb->data;
1237
1238 if (!is_my_mac(roam_adv_packet->dst))
1239 return route_unicast_packet(skb, recv_if);
1240
1241 orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
1242 if (!orig_node)
1243 goto out;
1244
1245 bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM "
1246 "(client %pM)\n", roam_adv_packet->src,
1247 roam_adv_packet->client);
1248
1249 tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
Antonio Quartullibc279082011-07-07 15:35:35 +02001250 atomic_read(&orig_node->last_ttvn) + 1, true, false);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001251
1252 /* Roaming phase starts: I have new information but the ttvn has not
1253 * been incremented yet. This flag will make me check all the incoming
1254 * packets for the correct destination. */
1255 bat_priv->tt_poss_change = true;
1256
1257 orig_node_free_ref(orig_node);
1258out:
1259 /* returning NET_RX_DROP will make the caller function kfree the skb */
1260 return NET_RX_DROP;
1261}
1262
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001263/* find a suitable router for this originator, and use
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001264 * bonding if possible. increases the found neighbors
1265 * refcount.*/
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001266struct neigh_node *find_router(struct bat_priv *bat_priv,
1267 struct orig_node *orig_node,
Sven Eckelmann747e4222011-05-14 23:14:50 +02001268 const struct hard_iface *recv_if)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001269{
1270 struct orig_node *primary_orig_node;
1271 struct orig_node *router_orig;
Linus Lüssing55158622011-03-14 22:43:27 +00001272 struct neigh_node *router;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001273 static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
1274 int bonding_enabled;
1275
1276 if (!orig_node)
1277 return NULL;
1278
Linus Lüssinge1a5382f2011-03-14 22:43:37 +00001279 router = orig_node_get_router(orig_node);
1280 if (!router)
Marek Lindner01df2b62011-05-05 14:14:46 +02001281 goto err;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001282
1283 /* without bonding, the first node should
1284 * always choose the default router. */
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001285 bonding_enabled = atomic_read(&bat_priv->bonding);
1286
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001287 rcu_read_lock();
1288 /* select default router to output */
Linus Lüssinge1a5382f2011-03-14 22:43:37 +00001289 router_orig = router->orig_node;
Marek Lindner01df2b62011-05-05 14:14:46 +02001290 if (!router_orig)
1291 goto err_unlock;
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001292
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001293 if ((!recv_if) && (!bonding_enabled))
1294 goto return_router;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001295
1296 /* if we have something in the primary_addr, we can search
1297 * for a potential bonding candidate. */
Marek Lindner39901e72011-02-18 12:28:08 +00001298 if (compare_eth(router_orig->primary_addr, zero_mac))
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001299 goto return_router;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001300
1301 /* find the orig_node which has the primary interface. might
1302 * even be the same as our router_orig in many cases */
1303
Marek Lindner39901e72011-02-18 12:28:08 +00001304 if (compare_eth(router_orig->primary_addr, router_orig->orig)) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001305 primary_orig_node = router_orig;
1306 } else {
Marek Lindner7aadf882011-02-18 12:28:09 +00001307 primary_orig_node = orig_hash_find(bat_priv,
1308 router_orig->primary_addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001309 if (!primary_orig_node)
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001310 goto return_router;
Marek Lindner7aadf882011-02-18 12:28:09 +00001311
Marek Lindner7b36e8e2011-02-18 12:28:10 +00001312 orig_node_free_ref(primary_orig_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001313 }
1314
1315 /* with less than 2 candidates, we can't do any
1316 * bonding and prefer the original router. */
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001317 if (atomic_read(&primary_orig_node->bond_candidates) < 2)
1318 goto return_router;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001319
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001320 /* all nodes between should choose a candidate which
1321 * is is not on the interface where the packet came
1322 * in. */
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001323
Marek Lindner44524fc2011-02-10 14:33:53 +00001324 neigh_node_free_ref(router);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001325
Linus Lüssing55158622011-03-14 22:43:27 +00001326 if (bonding_enabled)
1327 router = find_bond_router(primary_orig_node, recv_if);
1328 else
1329 router = find_ifalter_router(primary_orig_node, recv_if);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001330
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001331return_router:
Antonio Quartullie2cbc112011-05-08 20:52:57 +02001332 if (router && router->if_incoming->if_status != IF_ACTIVE)
1333 goto err_unlock;
1334
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001335 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001336 return router;
Marek Lindner01df2b62011-05-05 14:14:46 +02001337err_unlock:
1338 rcu_read_unlock();
1339err:
1340 if (router)
1341 neigh_node_free_ref(router);
1342 return NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001343}
1344
1345static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
1346{
1347 struct ethhdr *ethhdr;
1348
1349 /* drop packet if it has not necessary minimum size */
1350 if (unlikely(!pskb_may_pull(skb, hdr_size)))
1351 return -1;
1352
1353 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1354
1355 /* packet with unicast indication but broadcast recipient */
1356 if (is_broadcast_ether_addr(ethhdr->h_dest))
1357 return -1;
1358
1359 /* packet with broadcast sender address */
1360 if (is_broadcast_ether_addr(ethhdr->h_source))
1361 return -1;
1362
1363 /* not for me */
1364 if (!is_my_mac(ethhdr->h_dest))
1365 return -1;
1366
1367 return 0;
1368}
1369
Linus Lüssing7cefb142011-03-02 17:39:31 +00001370int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001371{
1372 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
Marek Lindner44524fc2011-02-10 14:33:53 +00001373 struct orig_node *orig_node = NULL;
1374 struct neigh_node *neigh_node = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001375 struct unicast_packet *unicast_packet;
1376 struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
Marek Lindner44524fc2011-02-10 14:33:53 +00001377 int ret = NET_RX_DROP;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001378 struct sk_buff *new_skb;
1379
1380 unicast_packet = (struct unicast_packet *)skb->data;
1381
1382 /* TTL exceeded */
1383 if (unicast_packet->ttl < 2) {
1384 pr_debug("Warning - can't forward unicast packet from %pM to "
1385 "%pM: ttl exceeded\n", ethhdr->h_source,
1386 unicast_packet->dest);
Marek Lindner44524fc2011-02-10 14:33:53 +00001387 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001388 }
1389
1390 /* get routing information */
Marek Lindner7aadf882011-02-18 12:28:09 +00001391 orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
1392
Marek Lindner44524fc2011-02-10 14:33:53 +00001393 if (!orig_node)
Antonio Quartullib5a6f692011-04-16 11:30:57 +02001394 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001395
Simon Wunderlicha4c135c2011-01-19 20:01:43 +00001396 /* find_router() increases neigh_nodes refcount if found. */
Marek Lindner44524fc2011-02-10 14:33:53 +00001397 neigh_node = find_router(bat_priv, orig_node, recv_if);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001398
Marek Lindnerd0072602011-01-19 20:01:44 +00001399 if (!neigh_node)
Marek Lindner44524fc2011-02-10 14:33:53 +00001400 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001401
1402 /* create a copy of the skb, if needed, to modify it. */
1403 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
Marek Lindner44524fc2011-02-10 14:33:53 +00001404 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001405
1406 unicast_packet = (struct unicast_packet *)skb->data;
1407
1408 if (unicast_packet->packet_type == BAT_UNICAST &&
1409 atomic_read(&bat_priv->fragmentation) &&
Marek Lindnerd0072602011-01-19 20:01:44 +00001410 skb->len > neigh_node->if_incoming->net_dev->mtu) {
1411 ret = frag_send_skb(skb, bat_priv,
1412 neigh_node->if_incoming, neigh_node->addr);
1413 goto out;
1414 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001415
1416 if (unicast_packet->packet_type == BAT_UNICAST_FRAG &&
Marek Lindnerd0072602011-01-19 20:01:44 +00001417 frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001418
1419 ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
1420
1421 if (ret == NET_RX_DROP)
Marek Lindner44524fc2011-02-10 14:33:53 +00001422 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001423
1424 /* packet was buffered for late merge */
Marek Lindner44524fc2011-02-10 14:33:53 +00001425 if (!new_skb) {
1426 ret = NET_RX_SUCCESS;
1427 goto out;
1428 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001429
1430 skb = new_skb;
1431 unicast_packet = (struct unicast_packet *)skb->data;
1432 }
1433
1434 /* decrement ttl */
1435 unicast_packet->ttl--;
1436
1437 /* route it */
Marek Lindnerd0072602011-01-19 20:01:44 +00001438 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
Marek Lindner44524fc2011-02-10 14:33:53 +00001439 ret = NET_RX_SUCCESS;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001440
Marek Lindner44524fc2011-02-10 14:33:53 +00001441out:
1442 if (neigh_node)
1443 neigh_node_free_ref(neigh_node);
1444 if (orig_node)
Marek Lindner7b36e8e2011-02-18 12:28:10 +00001445 orig_node_free_ref(orig_node);
Marek Lindner44524fc2011-02-10 14:33:53 +00001446 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001447}
1448
Antonio Quartullia73105b2011-04-27 14:27:44 +02001449static int check_unicast_ttvn(struct bat_priv *bat_priv,
1450 struct sk_buff *skb) {
1451 uint8_t curr_ttvn;
1452 struct orig_node *orig_node;
1453 struct ethhdr *ethhdr;
1454 struct hard_iface *primary_if;
1455 struct unicast_packet *unicast_packet;
Antonio Quartullicc47f662011-04-27 14:27:57 +02001456 bool tt_poss_change;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001457
1458 /* I could need to modify it */
1459 if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
1460 return 0;
1461
1462 unicast_packet = (struct unicast_packet *)skb->data;
1463
Antonio Quartullicc47f662011-04-27 14:27:57 +02001464 if (is_my_mac(unicast_packet->dest)) {
1465 tt_poss_change = bat_priv->tt_poss_change;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001466 curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001467 } else {
Antonio Quartullia73105b2011-04-27 14:27:44 +02001468 orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
1469
1470 if (!orig_node)
1471 return 0;
1472
1473 curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
Antonio Quartullicc47f662011-04-27 14:27:57 +02001474 tt_poss_change = orig_node->tt_poss_change;
Antonio Quartullia73105b2011-04-27 14:27:44 +02001475 orig_node_free_ref(orig_node);
1476 }
1477
1478 /* Check whether I have to reroute the packet */
Antonio Quartullicc47f662011-04-27 14:27:57 +02001479 if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) {
Antonio Quartullia73105b2011-04-27 14:27:44 +02001480 /* Linearize the skb before accessing it */
1481 if (skb_linearize(skb) < 0)
1482 return 0;
1483
1484 ethhdr = (struct ethhdr *)(skb->data +
1485 sizeof(struct unicast_packet));
Antonio Quartulli3d393e42011-07-07 15:35:37 +02001486 orig_node = transtable_search(bat_priv, NULL, ethhdr->h_dest);
Antonio Quartullia73105b2011-04-27 14:27:44 +02001487
1488 if (!orig_node) {
1489 if (!is_my_client(bat_priv, ethhdr->h_dest))
1490 return 0;
1491 primary_if = primary_if_get_selected(bat_priv);
1492 if (!primary_if)
1493 return 0;
1494 memcpy(unicast_packet->dest,
1495 primary_if->net_dev->dev_addr, ETH_ALEN);
1496 hardif_free_ref(primary_if);
1497 } else {
1498 memcpy(unicast_packet->dest, orig_node->orig,
1499 ETH_ALEN);
1500 curr_ttvn = (uint8_t)
1501 atomic_read(&orig_node->last_ttvn);
1502 orig_node_free_ref(orig_node);
1503 }
1504
1505 bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u "
1506 "new_ttvn %u)! Rerouting unicast packet (for %pM) to "
1507 "%pM\n", unicast_packet->ttvn, curr_ttvn,
1508 ethhdr->h_dest, unicast_packet->dest);
1509
1510 unicast_packet->ttvn = curr_ttvn;
1511 }
1512 return 1;
1513}
1514
Marek Lindnere6c10f42011-02-18 12:33:20 +00001515int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001516{
Antonio Quartullia73105b2011-04-27 14:27:44 +02001517 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001518 struct unicast_packet *unicast_packet;
Sven Eckelmann704509b2011-05-14 23:14:54 +02001519 int hdr_size = sizeof(*unicast_packet);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001520
1521 if (check_unicast_packet(skb, hdr_size) < 0)
1522 return NET_RX_DROP;
1523
Antonio Quartullia73105b2011-04-27 14:27:44 +02001524 if (!check_unicast_ttvn(bat_priv, skb))
1525 return NET_RX_DROP;
1526
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001527 unicast_packet = (struct unicast_packet *)skb->data;
1528
1529 /* packet for me */
1530 if (is_my_mac(unicast_packet->dest)) {
1531 interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
1532 return NET_RX_SUCCESS;
1533 }
1534
Linus Lüssing7cefb142011-03-02 17:39:31 +00001535 return route_unicast_packet(skb, recv_if);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001536}
1537
Marek Lindnere6c10f42011-02-18 12:33:20 +00001538int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001539{
1540 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1541 struct unicast_frag_packet *unicast_packet;
Sven Eckelmann704509b2011-05-14 23:14:54 +02001542 int hdr_size = sizeof(*unicast_packet);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001543 struct sk_buff *new_skb = NULL;
1544 int ret;
1545
1546 if (check_unicast_packet(skb, hdr_size) < 0)
1547 return NET_RX_DROP;
1548
Antonio Quartullia73105b2011-04-27 14:27:44 +02001549 if (!check_unicast_ttvn(bat_priv, skb))
1550 return NET_RX_DROP;
1551
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001552 unicast_packet = (struct unicast_frag_packet *)skb->data;
1553
1554 /* packet for me */
1555 if (is_my_mac(unicast_packet->dest)) {
1556
1557 ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
1558
1559 if (ret == NET_RX_DROP)
1560 return NET_RX_DROP;
1561
1562 /* packet was buffered for late merge */
1563 if (!new_skb)
1564 return NET_RX_SUCCESS;
1565
1566 interface_rx(recv_if->soft_iface, new_skb, recv_if,
1567 sizeof(struct unicast_packet));
1568 return NET_RX_SUCCESS;
1569 }
1570
Linus Lüssing7cefb142011-03-02 17:39:31 +00001571 return route_unicast_packet(skb, recv_if);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001572}
1573
1574
Marek Lindnere6c10f42011-02-18 12:33:20 +00001575int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001576{
1577 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
Marek Lindnerf3e00082011-01-25 21:52:11 +00001578 struct orig_node *orig_node = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001579 struct bcast_packet *bcast_packet;
1580 struct ethhdr *ethhdr;
Sven Eckelmann704509b2011-05-14 23:14:54 +02001581 int hdr_size = sizeof(*bcast_packet);
Marek Lindnerf3e00082011-01-25 21:52:11 +00001582 int ret = NET_RX_DROP;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001583 int32_t seq_diff;
1584
1585 /* drop packet if it has not necessary minimum size */
1586 if (unlikely(!pskb_may_pull(skb, hdr_size)))
Marek Lindnerf3e00082011-01-25 21:52:11 +00001587 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001588
1589 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1590
1591 /* packet with broadcast indication but unicast recipient */
1592 if (!is_broadcast_ether_addr(ethhdr->h_dest))
Marek Lindnerf3e00082011-01-25 21:52:11 +00001593 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001594
1595 /* packet with broadcast sender address */
1596 if (is_broadcast_ether_addr(ethhdr->h_source))
Marek Lindnerf3e00082011-01-25 21:52:11 +00001597 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001598
1599 /* ignore broadcasts sent by myself */
1600 if (is_my_mac(ethhdr->h_source))
Marek Lindnerf3e00082011-01-25 21:52:11 +00001601 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001602
1603 bcast_packet = (struct bcast_packet *)skb->data;
1604
1605 /* ignore broadcasts originated by myself */
1606 if (is_my_mac(bcast_packet->orig))
Marek Lindnerf3e00082011-01-25 21:52:11 +00001607 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001608
1609 if (bcast_packet->ttl < 2)
Marek Lindnerf3e00082011-01-25 21:52:11 +00001610 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001611
Marek Lindner7aadf882011-02-18 12:28:09 +00001612 orig_node = orig_hash_find(bat_priv, bcast_packet->orig);
Marek Lindnerf3e00082011-01-25 21:52:11 +00001613
1614 if (!orig_node)
Antonio Quartullib5a6f692011-04-16 11:30:57 +02001615 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001616
Marek Lindnerf3e00082011-01-25 21:52:11 +00001617 spin_lock_bh(&orig_node->bcast_seqno_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001618
1619 /* check whether the packet is a duplicate */
Marek Lindnerf3e00082011-01-25 21:52:11 +00001620 if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno,
1621 ntohl(bcast_packet->seqno)))
1622 goto spin_unlock;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001623
1624 seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
1625
1626 /* check whether the packet is old and the host just restarted. */
1627 if (window_protected(bat_priv, seq_diff,
Marek Lindnerf3e00082011-01-25 21:52:11 +00001628 &orig_node->bcast_seqno_reset))
1629 goto spin_unlock;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001630
1631 /* mark broadcast in flood history, update window position
1632 * if required. */
1633 if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
1634 orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
1635
Marek Lindnerf3e00082011-01-25 21:52:11 +00001636 spin_unlock_bh(&orig_node->bcast_seqno_lock);
Marek Lindnerf3e00082011-01-25 21:52:11 +00001637
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001638 /* rebroadcast packet */
Antonio Quartulli86985292011-06-25 19:09:12 +02001639 add_bcast_packet_to_list(bat_priv, skb, 1);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001640
1641 /* broadcast for me */
1642 interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
Marek Lindnerf3e00082011-01-25 21:52:11 +00001643 ret = NET_RX_SUCCESS;
1644 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001645
Marek Lindnerf3e00082011-01-25 21:52:11 +00001646spin_unlock:
1647 spin_unlock_bh(&orig_node->bcast_seqno_lock);
Marek Lindnerf3e00082011-01-25 21:52:11 +00001648out:
1649 if (orig_node)
Marek Lindner7b36e8e2011-02-18 12:28:10 +00001650 orig_node_free_ref(orig_node);
Marek Lindnerf3e00082011-01-25 21:52:11 +00001651 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001652}
1653
Marek Lindnere6c10f42011-02-18 12:33:20 +00001654int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001655{
1656 struct vis_packet *vis_packet;
1657 struct ethhdr *ethhdr;
1658 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
Sven Eckelmann704509b2011-05-14 23:14:54 +02001659 int hdr_size = sizeof(*vis_packet);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00001660
1661 /* keep skb linear */
1662 if (skb_linearize(skb) < 0)
1663 return NET_RX_DROP;
1664
1665 if (unlikely(!pskb_may_pull(skb, hdr_size)))
1666 return NET_RX_DROP;
1667
1668 vis_packet = (struct vis_packet *)skb->data;
1669 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1670
1671 /* not for me */
1672 if (!is_my_mac(ethhdr->h_dest))
1673 return NET_RX_DROP;
1674
1675 /* ignore own packets */
1676 if (is_my_mac(vis_packet->vis_orig))
1677 return NET_RX_DROP;
1678
1679 if (is_my_mac(vis_packet->sender_orig))
1680 return NET_RX_DROP;
1681
1682 switch (vis_packet->vis_type) {
1683 case VIS_TYPE_SERVER_SYNC:
1684 receive_server_sync_packet(bat_priv, vis_packet,
1685 skb_headlen(skb));
1686 break;
1687
1688 case VIS_TYPE_CLIENT_UPDATE:
1689 receive_client_update_packet(bat_priv, vis_packet,
1690 skb_headlen(skb));
1691 break;
1692
1693 default: /* ignore unknown packet */
1694 break;
1695 }
1696
1697 /* We take a copy of the data in the packet, so we should
1698 always free the skbuf. */
1699 return NET_RX_DROP;
1700}