Blame view

net/batman-adv/routing.c 29.3 KB
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1
  /*
64afe3539   Sven Eckelmann   batman-adv: Updat...
2
   * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *
   * Marek Lindner, Simon Wunderlich
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   * 02110-1301, USA
   *
   */
  
  #include "main.h"
  #include "routing.h"
  #include "send.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
25
26
27
28
29
  #include "soft-interface.h"
  #include "hard-interface.h"
  #include "icmp_socket.h"
  #include "translation-table.h"
  #include "originator.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
30
  #include "vis.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
31
  #include "unicast.h"
fc9572756   Marek Lindner   batman-adv: agglo...
32
  #include "bat_ogm.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
33

e6c10f433   Marek Lindner   batman-adv: renam...
34
  void slide_own_bcast_window(struct hard_iface *hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
35
  {
e6c10f433   Marek Lindner   batman-adv: renam...
36
  	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
37
  	struct hashtable_t *hash = bat_priv->orig_hash;
7aadf889e   Marek Lindner   batman-adv: remov...
38
  	struct hlist_node *node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
39
  	struct hlist_head *head;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
40
41
  	struct orig_node *orig_node;
  	unsigned long *word;
c90681b85   Antonio Quartulli   batman-adv: fixed...
42
  	uint32_t i;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
43
  	size_t word_index;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
44
45
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
fb778ea17   Marek Lindner   batman-adv: prote...
46
  		rcu_read_lock();
7aadf889e   Marek Lindner   batman-adv: remov...
47
  		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
2ae2daf6c   Marek Lindner   batman-adv: prote...
48
  			spin_lock_bh(&orig_node->ogm_cnt_lock);
e6c10f433   Marek Lindner   batman-adv: renam...
49
  			word_index = hard_iface->if_num * NUM_WORDS;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
50
51
52
  			word = &(orig_node->bcast_own[word_index]);
  
  			bit_get_packet(bat_priv, word, 1, 0);
e6c10f433   Marek Lindner   batman-adv: renam...
53
  			orig_node->bcast_own_sum[hard_iface->if_num] =
c6c8fea29   Sven Eckelmann   net: Add batman-a...
54
  				bit_packet_count(word);
2ae2daf6c   Marek Lindner   batman-adv: prote...
55
  			spin_unlock_bh(&orig_node->ogm_cnt_lock);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
56
  		}
fb778ea17   Marek Lindner   batman-adv: prote...
57
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
58
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
59
  }
fc9572756   Marek Lindner   batman-adv: agglo...
60
61
62
  static void _update_route(struct bat_priv *bat_priv,
  			  struct orig_node *orig_node,
  			  struct neigh_node *neigh_node)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
63
  {
e1a5382f9   Linus Lüssing   batman-adv: Make ...
64
65
66
  	struct neigh_node *curr_router;
  
  	curr_router = orig_node_get_router(orig_node);
a8e7f4bc3   Marek Lindner   batman-adv: prote...
67

c6c8fea29   Sven Eckelmann   net: Add batman-a...
68
  	/* route deleted */
e1a5382f9   Linus Lüssing   batman-adv: Make ...
69
  	if ((curr_router) && (!neigh_node)) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
70
71
72
  		bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM
  ",
  			orig_node->orig);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
73
  		tt_global_del_orig(bat_priv, orig_node,
a73105b8d   Antonio Quartulli   batman-adv: impro...
74
  				    "Deleted route towards originator");
c6c8fea29   Sven Eckelmann   net: Add batman-a...
75

e1a5382f9   Linus Lüssing   batman-adv: Make ...
76
77
  	/* route added */
  	} else if ((!curr_router) && (neigh_node)) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
78
79
80
81
82
  
  		bat_dbg(DBG_ROUTES, bat_priv,
  			"Adding route towards: %pM (via %pM)
  ",
  			orig_node->orig, neigh_node->addr);
e1a5382f9   Linus Lüssing   batman-adv: Make ...
83
  	/* route changed */
bb899b89f   Sven Eckelmann   batman-adv: Ensur...
84
  	} else if (neigh_node && curr_router) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
85
86
87
88
89
  		bat_dbg(DBG_ROUTES, bat_priv,
  			"Changing route towards: %pM "
  			"(now via %pM - was via %pM)
  ",
  			orig_node->orig, neigh_node->addr,
e1a5382f9   Linus Lüssing   batman-adv: Make ...
90
  			curr_router->addr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
91
  	}
e1a5382f9   Linus Lüssing   batman-adv: Make ...
92
93
94
95
  	if (curr_router)
  		neigh_node_free_ref(curr_router);
  
  	/* increase refcount of new best neighbor */
44524fcdf   Marek Lindner   batman-adv: Corre...
96
97
  	if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount))
  		neigh_node = NULL;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
98
99
100
101
102
103
104
105
  
  	spin_lock_bh(&orig_node->neigh_list_lock);
  	rcu_assign_pointer(orig_node->router, neigh_node);
  	spin_unlock_bh(&orig_node->neigh_list_lock);
  
  	/* decrease refcount of previous best neighbor */
  	if (curr_router)
  		neigh_node_free_ref(curr_router);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
106
  }
fc9572756   Marek Lindner   batman-adv: agglo...
107
108
  void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
  		  struct neigh_node *neigh_node)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
109
  {
e1a5382f9   Linus Lüssing   batman-adv: Make ...
110
  	struct neigh_node *router = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
111
112
  
  	if (!orig_node)
e1a5382f9   Linus Lüssing   batman-adv: Make ...
113
114
115
  		goto out;
  
  	router = orig_node_get_router(orig_node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
116

e1a5382f9   Linus Lüssing   batman-adv: Make ...
117
  	if (router != neigh_node)
fc9572756   Marek Lindner   batman-adv: agglo...
118
  		_update_route(bat_priv, orig_node, neigh_node);
e1a5382f9   Linus Lüssing   batman-adv: Make ...
119
120
121
122
  
  out:
  	if (router)
  		neigh_node_free_ref(router);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
123
  }
a4c135c56   Simon Wunderlich   batman-adv: prote...
124
125
126
127
128
129
130
131
132
  /* caller must hold the neigh_list_lock */
  void bonding_candidate_del(struct orig_node *orig_node,
  			   struct neigh_node *neigh_node)
  {
  	/* this neighbor is not part of our candidate list */
  	if (list_empty(&neigh_node->bonding_list))
  		goto out;
  
  	list_del_rcu(&neigh_node->bonding_list);
a4c135c56   Simon Wunderlich   batman-adv: prote...
133
  	INIT_LIST_HEAD(&neigh_node->bonding_list);
44524fcdf   Marek Lindner   batman-adv: Corre...
134
  	neigh_node_free_ref(neigh_node);
a4c135c56   Simon Wunderlich   batman-adv: prote...
135
136
137
138
139
  	atomic_dec(&orig_node->bond_candidates);
  
  out:
  	return;
  }
fc9572756   Marek Lindner   batman-adv: agglo...
140
141
  void bonding_candidate_add(struct orig_node *orig_node,
  			   struct neigh_node *neigh_node)
a4c135c56   Simon Wunderlich   batman-adv: prote...
142
143
  {
  	struct hlist_node *node;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
144
145
  	struct neigh_node *tmp_neigh_node, *router = NULL;
  	uint8_t interference_candidate = 0;
a4c135c56   Simon Wunderlich   batman-adv: prote...
146
147
148
149
  
  	spin_lock_bh(&orig_node->neigh_list_lock);
  
  	/* only consider if it has the same primary address ...  */
39901e716   Marek Lindner   batman-adv: separ...
150
151
  	if (!compare_eth(orig_node->orig,
  			 neigh_node->orig_node->primary_addr))
a4c135c56   Simon Wunderlich   batman-adv: prote...
152
  		goto candidate_del;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
153
154
  	router = orig_node_get_router(orig_node);
  	if (!router)
a4c135c56   Simon Wunderlich   batman-adv: prote...
155
  		goto candidate_del;
a4c135c56   Simon Wunderlich   batman-adv: prote...
156
  	/* ... and is good enough to be considered */
e1a5382f9   Linus Lüssing   batman-adv: Make ...
157
  	if (neigh_node->tq_avg < router->tq_avg - BONDING_TQ_THRESHOLD)
a4c135c56   Simon Wunderlich   batman-adv: prote...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  		goto candidate_del;
  
  	/**
  	 * check if we have another candidate with the same mac address or
  	 * interface. If we do, we won't select this candidate because of
  	 * possible interference.
  	 */
  	hlist_for_each_entry_rcu(tmp_neigh_node, node,
  				 &orig_node->neigh_list, list) {
  
  		if (tmp_neigh_node == neigh_node)
  			continue;
  
  		/* we only care if the other candidate is even
  		* considered as candidate. */
  		if (list_empty(&tmp_neigh_node->bonding_list))
  			continue;
  
  		if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) ||
39901e716   Marek Lindner   batman-adv: separ...
177
  		    (compare_eth(neigh_node->addr, tmp_neigh_node->addr))) {
a4c135c56   Simon Wunderlich   batman-adv: prote...
178
179
180
181
182
183
184
185
186
187
188
189
  			interference_candidate = 1;
  			break;
  		}
  	}
  
  	/* don't care further if it is an interference candidate */
  	if (interference_candidate)
  		goto candidate_del;
  
  	/* this neighbor already is part of our candidate list */
  	if (!list_empty(&neigh_node->bonding_list))
  		goto out;
44524fcdf   Marek Lindner   batman-adv: Corre...
190
191
  	if (!atomic_inc_not_zero(&neigh_node->refcount))
  		goto out;
a4c135c56   Simon Wunderlich   batman-adv: prote...
192
  	list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list);
a4c135c56   Simon Wunderlich   batman-adv: prote...
193
194
195
196
197
198
199
200
  	atomic_inc(&orig_node->bond_candidates);
  	goto out;
  
  candidate_del:
  	bonding_candidate_del(orig_node, neigh_node);
  
  out:
  	spin_unlock_bh(&orig_node->neigh_list_lock);
e1a5382f9   Linus Lüssing   batman-adv: Make ...
201
202
203
  
  	if (router)
  		neigh_node_free_ref(router);
a4c135c56   Simon Wunderlich   batman-adv: prote...
204
205
206
  }
  
  /* copy primary address for bonding */
fc9572756   Marek Lindner   batman-adv: agglo...
207
208
209
  void bonding_save_primary(const struct orig_node *orig_node,
  			  struct orig_node *orig_neigh_node,
  			  const struct batman_ogm_packet *batman_ogm_packet)
a4c135c56   Simon Wunderlich   batman-adv: prote...
210
  {
b6da4bf5d   Marek Lindner   batman-adv: renam...
211
  	if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
a4c135c56   Simon Wunderlich   batman-adv: prote...
212
213
214
215
  		return;
  
  	memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
  }
c6c8fea29   Sven Eckelmann   net: Add batman-a...
216
217
218
219
220
  /* checks whether the host restarted and is in the protection time.
   * returns:
   *  0 if the packet is to be accepted
   *  1 if the packet is to be ignored.
   */
fc9572756   Marek Lindner   batman-adv: agglo...
221
222
  int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
  		     unsigned long *last_reset)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  {
  	if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
  		|| (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
  		if (time_after(jiffies, *last_reset +
  			msecs_to_jiffies(RESET_PROTECTION_MS))) {
  
  			*last_reset = jiffies;
  			bat_dbg(DBG_BATMAN, bat_priv,
  				"old packet received, start protection
  ");
  
  			return 0;
  		} else
  			return 1;
  	}
  	return 0;
  }
fc9572756   Marek Lindner   batman-adv: agglo...
240
  int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
241
  {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
242
243
244
  	struct ethhdr *ethhdr;
  
  	/* drop packet if it has not necessary minimum size */
b6da4bf5d   Marek Lindner   batman-adv: renam...
245
  	if (unlikely(!pskb_may_pull(skb, BATMAN_OGM_LEN)))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  		return NET_RX_DROP;
  
  	ethhdr = (struct ethhdr *)skb_mac_header(skb);
  
  	/* packet with broadcast indication but unicast recipient */
  	if (!is_broadcast_ether_addr(ethhdr->h_dest))
  		return NET_RX_DROP;
  
  	/* packet with broadcast sender address */
  	if (is_broadcast_ether_addr(ethhdr->h_source))
  		return NET_RX_DROP;
  
  	/* create a copy of the skb, if needed, to modify it. */
  	if (skb_cow(skb, 0) < 0)
  		return NET_RX_DROP;
  
  	/* keep skb linear */
  	if (skb_linearize(skb) < 0)
  		return NET_RX_DROP;
  
  	ethhdr = (struct ethhdr *)skb_mac_header(skb);
fc9572756   Marek Lindner   batman-adv: agglo...
267
  	bat_ogm_receive(ethhdr, skb->data, skb_headlen(skb), hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
268
269
270
271
272
273
274
275
  
  	kfree_skb(skb);
  	return NET_RX_SUCCESS;
  }
  
  static int recv_my_icmp_packet(struct bat_priv *bat_priv,
  			       struct sk_buff *skb, size_t icmp_len)
  {
32ae9b221   Marek Lindner   batman-adv: Make ...
276
  	struct hard_iface *primary_if = NULL;
44524fcdf   Marek Lindner   batman-adv: Corre...
277
  	struct orig_node *orig_node = NULL;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
278
  	struct neigh_node *router = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
279
  	struct icmp_packet_rr *icmp_packet;
44524fcdf   Marek Lindner   batman-adv: Corre...
280
  	int ret = NET_RX_DROP;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
281
282
  
  	icmp_packet = (struct icmp_packet_rr *)skb->data;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
283
284
285
286
  
  	/* add data to device queue */
  	if (icmp_packet->msg_type != ECHO_REQUEST) {
  		bat_socket_receive_packet(icmp_packet, icmp_len);
44524fcdf   Marek Lindner   batman-adv: Corre...
287
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
288
  	}
32ae9b221   Marek Lindner   batman-adv: Make ...
289
290
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
44524fcdf   Marek Lindner   batman-adv: Corre...
291
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
292
293
294
  
  	/* answer echo request (ping) */
  	/* get routing information */
7aadf889e   Marek Lindner   batman-adv: remov...
295
  	orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
44524fcdf   Marek Lindner   batman-adv: Corre...
296
  	if (!orig_node)
e1a5382f9   Linus Lüssing   batman-adv: Make ...
297
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
298

e1a5382f9   Linus Lüssing   batman-adv: Make ...
299
300
301
  	router = orig_node_get_router(orig_node);
  	if (!router)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
302

44524fcdf   Marek Lindner   batman-adv: Corre...
303
304
305
306
307
308
309
  	/* create a copy of the skb, if needed, to modify it. */
  	if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
  		goto out;
  
  	icmp_packet = (struct icmp_packet_rr *)skb->data;
  
  	memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
32ae9b221   Marek Lindner   batman-adv: Make ...
310
  	memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
44524fcdf   Marek Lindner   batman-adv: Corre...
311
312
  	icmp_packet->msg_type = ECHO_REPLY;
  	icmp_packet->ttl = TTL;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
313
  	send_skb_packet(skb, router->if_incoming, router->addr);
44524fcdf   Marek Lindner   batman-adv: Corre...
314
  	ret = NET_RX_SUCCESS;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
315

44524fcdf   Marek Lindner   batman-adv: Corre...
316
  out:
32ae9b221   Marek Lindner   batman-adv: Make ...
317
318
  	if (primary_if)
  		hardif_free_ref(primary_if);
e1a5382f9   Linus Lüssing   batman-adv: Make ...
319
320
  	if (router)
  		neigh_node_free_ref(router);
44524fcdf   Marek Lindner   batman-adv: Corre...
321
  	if (orig_node)
7b36e8eef   Marek Lindner   batman-adv: Corre...
322
  		orig_node_free_ref(orig_node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
323
324
325
326
  	return ret;
  }
  
  static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
74ef11535   Simon Wunderlich   batman-adv: remov...
327
  				  struct sk_buff *skb)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
328
  {
32ae9b221   Marek Lindner   batman-adv: Make ...
329
  	struct hard_iface *primary_if = NULL;
44524fcdf   Marek Lindner   batman-adv: Corre...
330
  	struct orig_node *orig_node = NULL;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
331
  	struct neigh_node *router = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
332
  	struct icmp_packet *icmp_packet;
44524fcdf   Marek Lindner   batman-adv: Corre...
333
  	int ret = NET_RX_DROP;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
334
335
  
  	icmp_packet = (struct icmp_packet *)skb->data;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
336
337
338
339
340
341
342
  
  	/* send TTL exceeded if packet is an echo request (traceroute) */
  	if (icmp_packet->msg_type != ECHO_REQUEST) {
  		pr_debug("Warning - can't forward icmp packet from %pM to "
  			 "%pM: ttl exceeded
  ", icmp_packet->orig,
  			 icmp_packet->dst);
44524fcdf   Marek Lindner   batman-adv: Corre...
343
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
344
  	}
32ae9b221   Marek Lindner   batman-adv: Make ...
345
346
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
44524fcdf   Marek Lindner   batman-adv: Corre...
347
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
348
349
  
  	/* get routing information */
7aadf889e   Marek Lindner   batman-adv: remov...
350
  	orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
44524fcdf   Marek Lindner   batman-adv: Corre...
351
  	if (!orig_node)
e1a5382f9   Linus Lüssing   batman-adv: Make ...
352
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
353

e1a5382f9   Linus Lüssing   batman-adv: Make ...
354
355
356
  	router = orig_node_get_router(orig_node);
  	if (!router)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
357

44524fcdf   Marek Lindner   batman-adv: Corre...
358
359
360
  	/* create a copy of the skb, if needed, to modify it. */
  	if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
361

44524fcdf   Marek Lindner   batman-adv: Corre...
362
  	icmp_packet = (struct icmp_packet *)skb->data;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
363

44524fcdf   Marek Lindner   batman-adv: Corre...
364
  	memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
32ae9b221   Marek Lindner   batman-adv: Make ...
365
  	memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
44524fcdf   Marek Lindner   batman-adv: Corre...
366
367
  	icmp_packet->msg_type = TTL_EXCEEDED;
  	icmp_packet->ttl = TTL;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
368
  	send_skb_packet(skb, router->if_incoming, router->addr);
44524fcdf   Marek Lindner   batman-adv: Corre...
369
  	ret = NET_RX_SUCCESS;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
370

44524fcdf   Marek Lindner   batman-adv: Corre...
371
  out:
32ae9b221   Marek Lindner   batman-adv: Make ...
372
373
  	if (primary_if)
  		hardif_free_ref(primary_if);
e1a5382f9   Linus Lüssing   batman-adv: Make ...
374
375
  	if (router)
  		neigh_node_free_ref(router);
44524fcdf   Marek Lindner   batman-adv: Corre...
376
  	if (orig_node)
7b36e8eef   Marek Lindner   batman-adv: Corre...
377
  		orig_node_free_ref(orig_node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
378
379
  	return ret;
  }
e6c10f433   Marek Lindner   batman-adv: renam...
380
  int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
381
382
383
384
  {
  	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
  	struct icmp_packet_rr *icmp_packet;
  	struct ethhdr *ethhdr;
44524fcdf   Marek Lindner   batman-adv: Corre...
385
  	struct orig_node *orig_node = NULL;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
386
  	struct neigh_node *router = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
387
  	int hdr_size = sizeof(struct icmp_packet);
44524fcdf   Marek Lindner   batman-adv: Corre...
388
  	int ret = NET_RX_DROP;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
389
390
391
392
393
394
395
396
397
  
  	/**
  	 * we truncate all incoming icmp packets if they don't match our size
  	 */
  	if (skb->len >= sizeof(struct icmp_packet_rr))
  		hdr_size = sizeof(struct icmp_packet_rr);
  
  	/* drop packet if it has not necessary minimum size */
  	if (unlikely(!pskb_may_pull(skb, hdr_size)))
44524fcdf   Marek Lindner   batman-adv: Corre...
398
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
399
400
401
402
403
  
  	ethhdr = (struct ethhdr *)skb_mac_header(skb);
  
  	/* packet with unicast indication but broadcast recipient */
  	if (is_broadcast_ether_addr(ethhdr->h_dest))
44524fcdf   Marek Lindner   batman-adv: Corre...
404
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
405
406
407
  
  	/* packet with broadcast sender address */
  	if (is_broadcast_ether_addr(ethhdr->h_source))
44524fcdf   Marek Lindner   batman-adv: Corre...
408
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
409
410
411
  
  	/* not for me */
  	if (!is_my_mac(ethhdr->h_dest))
44524fcdf   Marek Lindner   batman-adv: Corre...
412
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  
  	icmp_packet = (struct icmp_packet_rr *)skb->data;
  
  	/* add record route information if not full */
  	if ((hdr_size == sizeof(struct icmp_packet_rr)) &&
  	    (icmp_packet->rr_cur < BAT_RR_LEN)) {
  		memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]),
  			ethhdr->h_dest, ETH_ALEN);
  		icmp_packet->rr_cur++;
  	}
  
  	/* packet for me */
  	if (is_my_mac(icmp_packet->dst))
  		return recv_my_icmp_packet(bat_priv, skb, hdr_size);
  
  	/* TTL exceeded */
  	if (icmp_packet->ttl < 2)
74ef11535   Simon Wunderlich   batman-adv: remov...
430
  		return recv_icmp_ttl_exceeded(bat_priv, skb);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
431

c6c8fea29   Sven Eckelmann   net: Add batman-a...
432
  	/* get routing information */
7aadf889e   Marek Lindner   batman-adv: remov...
433
  	orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
44524fcdf   Marek Lindner   batman-adv: Corre...
434
  	if (!orig_node)
e1a5382f9   Linus Lüssing   batman-adv: Make ...
435
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
436

e1a5382f9   Linus Lüssing   batman-adv: Make ...
437
438
439
  	router = orig_node_get_router(orig_node);
  	if (!router)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
440

44524fcdf   Marek Lindner   batman-adv: Corre...
441
442
443
  	/* create a copy of the skb, if needed, to modify it. */
  	if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
444

44524fcdf   Marek Lindner   batman-adv: Corre...
445
  	icmp_packet = (struct icmp_packet_rr *)skb->data;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
446

44524fcdf   Marek Lindner   batman-adv: Corre...
447
448
449
450
  	/* decrement ttl */
  	icmp_packet->ttl--;
  
  	/* route it */
e1a5382f9   Linus Lüssing   batman-adv: Make ...
451
  	send_skb_packet(skb, router->if_incoming, router->addr);
44524fcdf   Marek Lindner   batman-adv: Corre...
452
  	ret = NET_RX_SUCCESS;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
453

44524fcdf   Marek Lindner   batman-adv: Corre...
454
  out:
e1a5382f9   Linus Lüssing   batman-adv: Make ...
455
456
  	if (router)
  		neigh_node_free_ref(router);
44524fcdf   Marek Lindner   batman-adv: Corre...
457
  	if (orig_node)
7b36e8eef   Marek Lindner   batman-adv: Corre...
458
  		orig_node_free_ref(orig_node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
459
460
  	return ret;
  }
551586292   Linus Lüssing   batman-adv: Move ...
461
462
463
464
465
466
  /* In the bonding case, send the packets in a round
   * robin fashion over the remaining interfaces.
   *
   * This method rotates the bonding list and increases the
   * returned router's refcount. */
  static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
747e4221a   Sven Eckelmann   batman-adv: Add c...
467
  					   const struct hard_iface *recv_if)
551586292   Linus Lüssing   batman-adv: Move ...
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  {
  	struct neigh_node *tmp_neigh_node;
  	struct neigh_node *router = NULL, *first_candidate = NULL;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
  				bonding_list) {
  		if (!first_candidate)
  			first_candidate = tmp_neigh_node;
  
  		/* recv_if == NULL on the first node. */
  		if (tmp_neigh_node->if_incoming == recv_if)
  			continue;
  
  		if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
  			continue;
  
  		router = tmp_neigh_node;
  		break;
  	}
  
  	/* use the first candidate if nothing was found. */
  	if (!router && first_candidate &&
  	    atomic_inc_not_zero(&first_candidate->refcount))
  		router = first_candidate;
  
  	if (!router)
  		goto out;
  
  	/* selected should point to the next element
  	 * after the current router */
  	spin_lock_bh(&primary_orig->neigh_list_lock);
  	/* this is a list_move(), which unfortunately
  	 * does not exist as rcu version */
  	list_del_rcu(&primary_orig->bond_list);
  	list_add_rcu(&primary_orig->bond_list,
  		     &router->bonding_list);
  	spin_unlock_bh(&primary_orig->neigh_list_lock);
  
  out:
  	rcu_read_unlock();
  	return router;
  }
  
  /* Interface Alternating: Use the best of the
   * remaining candidates which are not using
   * this interface.
   *
   * Increases the returned router's refcount */
  static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
747e4221a   Sven Eckelmann   batman-adv: Add c...
518
  					      const struct hard_iface *recv_if)
551586292   Linus Lüssing   batman-adv: Move ...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  {
  	struct neigh_node *tmp_neigh_node;
  	struct neigh_node *router = NULL, *first_candidate = NULL;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
  				bonding_list) {
  		if (!first_candidate)
  			first_candidate = tmp_neigh_node;
  
  		/* recv_if == NULL on the first node. */
  		if (tmp_neigh_node->if_incoming == recv_if)
  			continue;
  
  		if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
  			continue;
  
  		/* if we don't have a router yet
  		 * or this one is better, choose it. */
  		if ((!router) ||
  		    (tmp_neigh_node->tq_avg > router->tq_avg)) {
  			/* decrement refcount of
  			 * previously selected router */
  			if (router)
  				neigh_node_free_ref(router);
  
  			router = tmp_neigh_node;
  			atomic_inc_not_zero(&router->refcount);
  		}
  
  		neigh_node_free_ref(tmp_neigh_node);
  	}
  
  	/* use the first candidate if nothing was found. */
  	if (!router && first_candidate &&
  	    atomic_inc_not_zero(&first_candidate->refcount))
  		router = first_candidate;
  
  	rcu_read_unlock();
  	return router;
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
560
561
562
563
  int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
  {
  	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
  	struct tt_query_packet *tt_query;
8b7342d67   Antonio Quartulli   batman-adv: check...
564
  	uint16_t tt_len;
a73105b8d   Antonio Quartulli   batman-adv: impro...
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
  	struct ethhdr *ethhdr;
  
  	/* drop packet if it has not necessary minimum size */
  	if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet))))
  		goto out;
  
  	/* I could need to modify it */
  	if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0)
  		goto out;
  
  	ethhdr = (struct ethhdr *)skb_mac_header(skb);
  
  	/* packet with unicast indication but broadcast recipient */
  	if (is_broadcast_ether_addr(ethhdr->h_dest))
  		goto out;
  
  	/* packet with broadcast sender address */
  	if (is_broadcast_ether_addr(ethhdr->h_source))
  		goto out;
  
  	tt_query = (struct tt_query_packet *)skb->data;
  
  	tt_query->tt_data = ntohs(tt_query->tt_data);
  
  	switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
  	case TT_REQUEST:
  		/* If we cannot provide an answer the tt_request is
  		 * forwarded */
  		if (!send_tt_response(bat_priv, tt_query)) {
  			bat_dbg(DBG_TT, bat_priv,
  				"Routing TT_REQUEST to %pM [%c]
  ",
  				tt_query->dst,
  				(tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
  			tt_query->tt_data = htons(tt_query->tt_data);
  			return route_unicast_packet(skb, recv_if);
  		}
  		break;
  	case TT_RESPONSE:
dc58fe32e   Antonio Quartulli   batman-adv: linea...
604
605
606
607
608
  		if (is_my_mac(tt_query->dst)) {
  			/* packet needs to be linearized to access the TT
  			 * changes */
  			if (skb_linearize(skb) < 0)
  				goto out;
a73105b8d   Antonio Quartulli   batman-adv: impro...
609

8b7342d67   Antonio Quartulli   batman-adv: check...
610
611
612
613
  			tt_len = tt_query->tt_data * sizeof(struct tt_change);
  
  			/* Ensure we have all the claimed data */
  			if (unlikely(skb_headlen(skb) <
69497c17c   Antonio Quartulli   batman-adv: forma...
614
  				     sizeof(struct tt_query_packet) + tt_len))
8b7342d67   Antonio Quartulli   batman-adv: check...
615
  				goto out;
a73105b8d   Antonio Quartulli   batman-adv: impro...
616
  			handle_tt_response(bat_priv, tt_query);
dc58fe32e   Antonio Quartulli   batman-adv: linea...
617
  		} else {
a73105b8d   Antonio Quartulli   batman-adv: impro...
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
  			bat_dbg(DBG_TT, bat_priv,
  				"Routing TT_RESPONSE to %pM [%c]
  ",
  				tt_query->dst,
  				(tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
  			tt_query->tt_data = htons(tt_query->tt_data);
  			return route_unicast_packet(skb, recv_if);
  		}
  		break;
  	}
  
  out:
  	/* returning NET_RX_DROP will make the caller function kfree the skb */
  	return NET_RX_DROP;
  }
cc47f66e6   Antonio Quartulli   batman-adv: impro...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
  {
  	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
  	struct roam_adv_packet *roam_adv_packet;
  	struct orig_node *orig_node;
  	struct ethhdr *ethhdr;
  
  	/* drop packet if it has not necessary minimum size */
  	if (unlikely(!pskb_may_pull(skb, sizeof(struct roam_adv_packet))))
  		goto out;
  
  	ethhdr = (struct ethhdr *)skb_mac_header(skb);
  
  	/* packet with unicast indication but broadcast recipient */
  	if (is_broadcast_ether_addr(ethhdr->h_dest))
  		goto out;
  
  	/* packet with broadcast sender address */
  	if (is_broadcast_ether_addr(ethhdr->h_source))
  		goto out;
  
  	roam_adv_packet = (struct roam_adv_packet *)skb->data;
  
  	if (!is_my_mac(roam_adv_packet->dst))
  		return route_unicast_packet(skb, recv_if);
  
  	orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
  	if (!orig_node)
  		goto out;
  
  	bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM "
  		"(client %pM)
  ", roam_adv_packet->src,
  		roam_adv_packet->client);
  
  	tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
bc2790808   Antonio Quartulli   batman-adv: detec...
669
  		      atomic_read(&orig_node->last_ttvn) + 1, true, false);
cc47f66e6   Antonio Quartulli   batman-adv: impro...
670
671
672
673
674
675
676
677
678
679
680
  
  	/* Roaming phase starts: I have new information but the ttvn has not
  	 * been incremented yet. This flag will make me check all the incoming
  	 * packets for the correct destination. */
  	bat_priv->tt_poss_change = true;
  
  	orig_node_free_ref(orig_node);
  out:
  	/* returning NET_RX_DROP will make the caller function kfree the skb */
  	return NET_RX_DROP;
  }
c6c8fea29   Sven Eckelmann   net: Add batman-a...
681
  /* find a suitable router for this originator, and use
a4c135c56   Simon Wunderlich   batman-adv: prote...
682
683
   * bonding if possible. increases the found neighbors
   * refcount.*/
c6c8fea29   Sven Eckelmann   net: Add batman-a...
684
685
  struct neigh_node *find_router(struct bat_priv *bat_priv,
  			       struct orig_node *orig_node,
747e4221a   Sven Eckelmann   batman-adv: Add c...
686
  			       const struct hard_iface *recv_if)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
687
688
689
  {
  	struct orig_node *primary_orig_node;
  	struct orig_node *router_orig;
551586292   Linus Lüssing   batman-adv: Move ...
690
  	struct neigh_node *router;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
691
692
693
694
695
  	static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
  	int bonding_enabled;
  
  	if (!orig_node)
  		return NULL;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
696
697
  	router = orig_node_get_router(orig_node);
  	if (!router)
01df2b65e   Marek Lindner   batman-adv: Fix r...
698
  		goto err;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
699
700
701
  
  	/* without bonding, the first node should
  	 * always choose the default router. */
c6c8fea29   Sven Eckelmann   net: Add batman-a...
702
  	bonding_enabled = atomic_read(&bat_priv->bonding);
a4c135c56   Simon Wunderlich   batman-adv: prote...
703
704
  	rcu_read_lock();
  	/* select default router to output */
e1a5382f9   Linus Lüssing   batman-adv: Make ...
705
  	router_orig = router->orig_node;
01df2b65e   Marek Lindner   batman-adv: Fix r...
706
707
  	if (!router_orig)
  		goto err_unlock;
a4c135c56   Simon Wunderlich   batman-adv: prote...
708

a4c135c56   Simon Wunderlich   batman-adv: prote...
709
710
  	if ((!recv_if) && (!bonding_enabled))
  		goto return_router;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
711
712
713
  
  	/* if we have something in the primary_addr, we can search
  	 * for a potential bonding candidate. */
39901e716   Marek Lindner   batman-adv: separ...
714
  	if (compare_eth(router_orig->primary_addr, zero_mac))
a4c135c56   Simon Wunderlich   batman-adv: prote...
715
  		goto return_router;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
716
717
718
  
  	/* find the orig_node which has the primary interface. might
  	 * even be the same as our router_orig in many cases */
39901e716   Marek Lindner   batman-adv: separ...
719
  	if (compare_eth(router_orig->primary_addr, router_orig->orig)) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
720
721
  		primary_orig_node = router_orig;
  	} else {
7aadf889e   Marek Lindner   batman-adv: remov...
722
723
  		primary_orig_node = orig_hash_find(bat_priv,
  						   router_orig->primary_addr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
724
  		if (!primary_orig_node)
a4c135c56   Simon Wunderlich   batman-adv: prote...
725
  			goto return_router;
7aadf889e   Marek Lindner   batman-adv: remov...
726

7b36e8eef   Marek Lindner   batman-adv: Corre...
727
  		orig_node_free_ref(primary_orig_node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
728
729
730
731
  	}
  
  	/* with less than 2 candidates, we can't do any
  	 * bonding and prefer the original router. */
a4c135c56   Simon Wunderlich   batman-adv: prote...
732
733
  	if (atomic_read(&primary_orig_node->bond_candidates) < 2)
  		goto return_router;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
734

c6c8fea29   Sven Eckelmann   net: Add batman-a...
735
736
737
  	/* all nodes between should choose a candidate which
  	 * is is not on the interface where the packet came
  	 * in. */
a4c135c56   Simon Wunderlich   batman-adv: prote...
738

44524fcdf   Marek Lindner   batman-adv: Corre...
739
  	neigh_node_free_ref(router);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
740

551586292   Linus Lüssing   batman-adv: Move ...
741
742
743
744
  	if (bonding_enabled)
  		router = find_bond_router(primary_orig_node, recv_if);
  	else
  		router = find_ifalter_router(primary_orig_node, recv_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
745

a4c135c56   Simon Wunderlich   batman-adv: prote...
746
  return_router:
e2cbc11c0   Antonio Quartulli   batman-adv: move ...
747
748
  	if (router && router->if_incoming->if_status != IF_ACTIVE)
  		goto err_unlock;
a4c135c56   Simon Wunderlich   batman-adv: prote...
749
  	rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
750
  	return router;
01df2b65e   Marek Lindner   batman-adv: Fix r...
751
752
753
754
755
756
  err_unlock:
  	rcu_read_unlock();
  err:
  	if (router)
  		neigh_node_free_ref(router);
  	return NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
  }
  
  static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
  {
  	struct ethhdr *ethhdr;
  
  	/* drop packet if it has not necessary minimum size */
  	if (unlikely(!pskb_may_pull(skb, hdr_size)))
  		return -1;
  
  	ethhdr = (struct ethhdr *)skb_mac_header(skb);
  
  	/* packet with unicast indication but broadcast recipient */
  	if (is_broadcast_ether_addr(ethhdr->h_dest))
  		return -1;
  
  	/* packet with broadcast sender address */
  	if (is_broadcast_ether_addr(ethhdr->h_source))
  		return -1;
  
  	/* not for me */
  	if (!is_my_mac(ethhdr->h_dest))
  		return -1;
  
  	return 0;
  }
7cefb149a   Linus Lüssing   batman-adv: Remov...
783
  int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
784
785
  {
  	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
44524fcdf   Marek Lindner   batman-adv: Corre...
786
787
  	struct orig_node *orig_node = NULL;
  	struct neigh_node *neigh_node = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
788
789
  	struct unicast_packet *unicast_packet;
  	struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
44524fcdf   Marek Lindner   batman-adv: Corre...
790
  	int ret = NET_RX_DROP;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
791
792
793
794
795
796
797
798
799
800
  	struct sk_buff *new_skb;
  
  	unicast_packet = (struct unicast_packet *)skb->data;
  
  	/* TTL exceeded */
  	if (unicast_packet->ttl < 2) {
  		pr_debug("Warning - can't forward unicast packet from %pM to "
  			 "%pM: ttl exceeded
  ", ethhdr->h_source,
  			 unicast_packet->dest);
44524fcdf   Marek Lindner   batman-adv: Corre...
801
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
802
803
804
  	}
  
  	/* get routing information */
7aadf889e   Marek Lindner   batman-adv: remov...
805
  	orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
44524fcdf   Marek Lindner   batman-adv: Corre...
806
  	if (!orig_node)
b5a6f69c5   Antonio Quartulli   batman-adv: orig_...
807
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
808

a4c135c56   Simon Wunderlich   batman-adv: prote...
809
  	/* find_router() increases neigh_nodes refcount if found. */
44524fcdf   Marek Lindner   batman-adv: Corre...
810
  	neigh_node = find_router(bat_priv, orig_node, recv_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
811

d0072609b   Marek Lindner   batman-adv: remov...
812
  	if (!neigh_node)
44524fcdf   Marek Lindner   batman-adv: Corre...
813
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
814
815
816
  
  	/* create a copy of the skb, if needed, to modify it. */
  	if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
44524fcdf   Marek Lindner   batman-adv: Corre...
817
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
818
819
820
821
822
  
  	unicast_packet = (struct unicast_packet *)skb->data;
  
  	if (unicast_packet->packet_type == BAT_UNICAST &&
  	    atomic_read(&bat_priv->fragmentation) &&
d0072609b   Marek Lindner   batman-adv: remov...
823
824
825
826
827
  	    skb->len > neigh_node->if_incoming->net_dev->mtu) {
  		ret = frag_send_skb(skb, bat_priv,
  				    neigh_node->if_incoming, neigh_node->addr);
  		goto out;
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
828
829
  
  	if (unicast_packet->packet_type == BAT_UNICAST_FRAG &&
d0072609b   Marek Lindner   batman-adv: remov...
830
  	    frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
831
832
833
834
  
  		ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
  
  		if (ret == NET_RX_DROP)
44524fcdf   Marek Lindner   batman-adv: Corre...
835
  			goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
836
837
  
  		/* packet was buffered for late merge */
44524fcdf   Marek Lindner   batman-adv: Corre...
838
839
840
841
  		if (!new_skb) {
  			ret = NET_RX_SUCCESS;
  			goto out;
  		}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
842
843
844
845
846
847
848
849
850
  
  		skb = new_skb;
  		unicast_packet = (struct unicast_packet *)skb->data;
  	}
  
  	/* decrement ttl */
  	unicast_packet->ttl--;
  
  	/* route it */
d0072609b   Marek Lindner   batman-adv: remov...
851
  	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
44524fcdf   Marek Lindner   batman-adv: Corre...
852
  	ret = NET_RX_SUCCESS;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
853

44524fcdf   Marek Lindner   batman-adv: Corre...
854
855
856
857
  out:
  	if (neigh_node)
  		neigh_node_free_ref(neigh_node);
  	if (orig_node)
7b36e8eef   Marek Lindner   batman-adv: Corre...
858
  		orig_node_free_ref(orig_node);
44524fcdf   Marek Lindner   batman-adv: Corre...
859
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
860
  }
a73105b8d   Antonio Quartulli   batman-adv: impro...
861
862
863
864
865
866
867
  static int check_unicast_ttvn(struct bat_priv *bat_priv,
  			       struct sk_buff *skb) {
  	uint8_t curr_ttvn;
  	struct orig_node *orig_node;
  	struct ethhdr *ethhdr;
  	struct hard_iface *primary_if;
  	struct unicast_packet *unicast_packet;
cc47f66e6   Antonio Quartulli   batman-adv: impro...
868
  	bool tt_poss_change;
a73105b8d   Antonio Quartulli   batman-adv: impro...
869
870
871
872
873
874
  
  	/* I could need to modify it */
  	if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
  		return 0;
  
  	unicast_packet = (struct unicast_packet *)skb->data;
cc47f66e6   Antonio Quartulli   batman-adv: impro...
875
876
  	if (is_my_mac(unicast_packet->dest)) {
  		tt_poss_change = bat_priv->tt_poss_change;
a73105b8d   Antonio Quartulli   batman-adv: impro...
877
  		curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
cc47f66e6   Antonio Quartulli   batman-adv: impro...
878
  	} else {
a73105b8d   Antonio Quartulli   batman-adv: impro...
879
880
881
882
883
884
  		orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
  
  		if (!orig_node)
  			return 0;
  
  		curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
cc47f66e6   Antonio Quartulli   batman-adv: impro...
885
  		tt_poss_change = orig_node->tt_poss_change;
a73105b8d   Antonio Quartulli   batman-adv: impro...
886
887
888
889
  		orig_node_free_ref(orig_node);
  	}
  
  	/* Check whether I have to reroute the packet */
cc47f66e6   Antonio Quartulli   batman-adv: impro...
890
  	if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) {
a73105b8d   Antonio Quartulli   batman-adv: impro...
891
892
893
894
895
896
  		/* Linearize the skb before accessing it */
  		if (skb_linearize(skb) < 0)
  			return 0;
  
  		ethhdr = (struct ethhdr *)(skb->data +
  			sizeof(struct unicast_packet));
3d393e473   Antonio Quartulli   batman-adv: imple...
897
  		orig_node = transtable_search(bat_priv, NULL, ethhdr->h_dest);
a73105b8d   Antonio Quartulli   batman-adv: impro...
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
  
  		if (!orig_node) {
  			if (!is_my_client(bat_priv, ethhdr->h_dest))
  				return 0;
  			primary_if = primary_if_get_selected(bat_priv);
  			if (!primary_if)
  				return 0;
  			memcpy(unicast_packet->dest,
  			       primary_if->net_dev->dev_addr, ETH_ALEN);
  			hardif_free_ref(primary_if);
  		} else {
  			memcpy(unicast_packet->dest, orig_node->orig,
  			       ETH_ALEN);
  			curr_ttvn = (uint8_t)
  				atomic_read(&orig_node->last_ttvn);
  			orig_node_free_ref(orig_node);
  		}
  
  		bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u "
  			"new_ttvn %u)! Rerouting unicast packet (for %pM) to "
  			"%pM
  ", unicast_packet->ttvn, curr_ttvn,
  			ethhdr->h_dest, unicast_packet->dest);
  
  		unicast_packet->ttvn = curr_ttvn;
  	}
  	return 1;
  }
e6c10f433   Marek Lindner   batman-adv: renam...
926
  int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
927
  {
a73105b8d   Antonio Quartulli   batman-adv: impro...
928
  	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
929
  	struct unicast_packet *unicast_packet;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
930
  	int hdr_size = sizeof(*unicast_packet);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
931
932
933
  
  	if (check_unicast_packet(skb, hdr_size) < 0)
  		return NET_RX_DROP;
a73105b8d   Antonio Quartulli   batman-adv: impro...
934
935
  	if (!check_unicast_ttvn(bat_priv, skb))
  		return NET_RX_DROP;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
936
937
938
939
940
941
942
  	unicast_packet = (struct unicast_packet *)skb->data;
  
  	/* packet for me */
  	if (is_my_mac(unicast_packet->dest)) {
  		interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
  		return NET_RX_SUCCESS;
  	}
7cefb149a   Linus Lüssing   batman-adv: Remov...
943
  	return route_unicast_packet(skb, recv_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
944
  }
e6c10f433   Marek Lindner   batman-adv: renam...
945
  int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
946
947
948
  {
  	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
  	struct unicast_frag_packet *unicast_packet;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
949
  	int hdr_size = sizeof(*unicast_packet);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
950
951
952
953
954
  	struct sk_buff *new_skb = NULL;
  	int ret;
  
  	if (check_unicast_packet(skb, hdr_size) < 0)
  		return NET_RX_DROP;
a73105b8d   Antonio Quartulli   batman-adv: impro...
955
956
  	if (!check_unicast_ttvn(bat_priv, skb))
  		return NET_RX_DROP;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  	unicast_packet = (struct unicast_frag_packet *)skb->data;
  
  	/* packet for me */
  	if (is_my_mac(unicast_packet->dest)) {
  
  		ret = frag_reassemble_skb(skb, bat_priv, &new_skb);
  
  		if (ret == NET_RX_DROP)
  			return NET_RX_DROP;
  
  		/* packet was buffered for late merge */
  		if (!new_skb)
  			return NET_RX_SUCCESS;
  
  		interface_rx(recv_if->soft_iface, new_skb, recv_if,
  			     sizeof(struct unicast_packet));
  		return NET_RX_SUCCESS;
  	}
7cefb149a   Linus Lüssing   batman-adv: Remov...
975
  	return route_unicast_packet(skb, recv_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
976
  }
e6c10f433   Marek Lindner   batman-adv: renam...
977
  int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
978
979
  {
  	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
f3e0008f0   Marek Lindner   batman-adv: make ...
980
  	struct orig_node *orig_node = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
981
982
  	struct bcast_packet *bcast_packet;
  	struct ethhdr *ethhdr;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
983
  	int hdr_size = sizeof(*bcast_packet);
f3e0008f0   Marek Lindner   batman-adv: make ...
984
  	int ret = NET_RX_DROP;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
985
986
987
988
  	int32_t seq_diff;
  
  	/* drop packet if it has not necessary minimum size */
  	if (unlikely(!pskb_may_pull(skb, hdr_size)))
f3e0008f0   Marek Lindner   batman-adv: make ...
989
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
990
991
992
993
994
  
  	ethhdr = (struct ethhdr *)skb_mac_header(skb);
  
  	/* packet with broadcast indication but unicast recipient */
  	if (!is_broadcast_ether_addr(ethhdr->h_dest))
f3e0008f0   Marek Lindner   batman-adv: make ...
995
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
996
997
998
  
  	/* packet with broadcast sender address */
  	if (is_broadcast_ether_addr(ethhdr->h_source))
f3e0008f0   Marek Lindner   batman-adv: make ...
999
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1000
1001
1002
  
  	/* ignore broadcasts sent by myself */
  	if (is_my_mac(ethhdr->h_source))
f3e0008f0   Marek Lindner   batman-adv: make ...
1003
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1004
1005
1006
1007
1008
  
  	bcast_packet = (struct bcast_packet *)skb->data;
  
  	/* ignore broadcasts originated by myself */
  	if (is_my_mac(bcast_packet->orig))
f3e0008f0   Marek Lindner   batman-adv: make ...
1009
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1010
1011
  
  	if (bcast_packet->ttl < 2)
f3e0008f0   Marek Lindner   batman-adv: make ...
1012
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1013

7aadf889e   Marek Lindner   batman-adv: remov...
1014
  	orig_node = orig_hash_find(bat_priv, bcast_packet->orig);
f3e0008f0   Marek Lindner   batman-adv: make ...
1015
1016
  
  	if (!orig_node)
b5a6f69c5   Antonio Quartulli   batman-adv: orig_...
1017
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1018

f3e0008f0   Marek Lindner   batman-adv: make ...
1019
  	spin_lock_bh(&orig_node->bcast_seqno_lock);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1020
1021
  
  	/* check whether the packet is a duplicate */
f3e0008f0   Marek Lindner   batman-adv: make ...
1022
1023
1024
  	if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno,
  			   ntohl(bcast_packet->seqno)))
  		goto spin_unlock;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1025
1026
1027
1028
1029
  
  	seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
  
  	/* check whether the packet is old and the host just restarted. */
  	if (window_protected(bat_priv, seq_diff,
f3e0008f0   Marek Lindner   batman-adv: make ...
1030
1031
  			     &orig_node->bcast_seqno_reset))
  		goto spin_unlock;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1032
1033
1034
1035
1036
  
  	/* mark broadcast in flood history, update window position
  	 * if required. */
  	if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
  		orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
f3e0008f0   Marek Lindner   batman-adv: make ...
1037
  	spin_unlock_bh(&orig_node->bcast_seqno_lock);
f3e0008f0   Marek Lindner   batman-adv: make ...
1038

c6c8fea29   Sven Eckelmann   net: Add batman-a...
1039
  	/* rebroadcast packet */
8698529d2   Antonio Quartulli   batman-adv: add_b...
1040
  	add_bcast_packet_to_list(bat_priv, skb, 1);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1041
1042
1043
  
  	/* broadcast for me */
  	interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
f3e0008f0   Marek Lindner   batman-adv: make ...
1044
1045
  	ret = NET_RX_SUCCESS;
  	goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1046

f3e0008f0   Marek Lindner   batman-adv: make ...
1047
1048
  spin_unlock:
  	spin_unlock_bh(&orig_node->bcast_seqno_lock);
f3e0008f0   Marek Lindner   batman-adv: make ...
1049
1050
  out:
  	if (orig_node)
7b36e8eef   Marek Lindner   batman-adv: Corre...
1051
  		orig_node_free_ref(orig_node);
f3e0008f0   Marek Lindner   batman-adv: make ...
1052
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1053
  }
e6c10f433   Marek Lindner   batman-adv: renam...
1054
  int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1055
1056
1057
1058
  {
  	struct vis_packet *vis_packet;
  	struct ethhdr *ethhdr;
  	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
704509b8d   Sven Eckelmann   batman-adv: Calcu...
1059
  	int hdr_size = sizeof(*vis_packet);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  
  	/* keep skb linear */
  	if (skb_linearize(skb) < 0)
  		return NET_RX_DROP;
  
  	if (unlikely(!pskb_may_pull(skb, hdr_size)))
  		return NET_RX_DROP;
  
  	vis_packet = (struct vis_packet *)skb->data;
  	ethhdr = (struct ethhdr *)skb_mac_header(skb);
  
  	/* not for me */
  	if (!is_my_mac(ethhdr->h_dest))
  		return NET_RX_DROP;
  
  	/* ignore own packets */
  	if (is_my_mac(vis_packet->vis_orig))
  		return NET_RX_DROP;
  
  	if (is_my_mac(vis_packet->sender_orig))
  		return NET_RX_DROP;
  
  	switch (vis_packet->vis_type) {
  	case VIS_TYPE_SERVER_SYNC:
  		receive_server_sync_packet(bat_priv, vis_packet,
  					   skb_headlen(skb));
  		break;
  
  	case VIS_TYPE_CLIENT_UPDATE:
  		receive_client_update_packet(bat_priv, vis_packet,
  					     skb_headlen(skb));
  		break;
  
  	default:	/* ignore unknown packet */
  		break;
  	}
  
  	/* We take a copy of the data in the packet, so we should
  	   always free the skbuf. */
  	return NET_RX_DROP;
  }