blob: 4155fa57cf6da5ff1c4d46f3c71d7c5bc349351f [file] [log] [blame]
Antonio Quartulli0da00352016-01-16 16:40:12 +08001/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
2 *
3 * Antonio Quartulli
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public
7 * License as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "bat_v_ogm.h"
19#include "main.h"
20
21#include <linux/atomic.h>
22#include <linux/byteorder/generic.h>
23#include <linux/errno.h>
24#include <linux/etherdevice.h>
25#include <linux/fs.h>
26#include <linux/if_ether.h>
27#include <linux/jiffies.h>
28#include <linux/kernel.h>
Antonio Quartulli93231582016-01-16 16:40:13 +080029#include <linux/list.h>
Antonio Quartulli0da00352016-01-16 16:40:12 +080030#include <linux/netdevice.h>
31#include <linux/random.h>
32#include <linux/rculist.h>
33#include <linux/rcupdate.h>
34#include <linux/skbuff.h>
35#include <linux/slab.h>
36#include <linux/stddef.h>
37#include <linux/string.h>
38#include <linux/types.h>
39#include <linux/workqueue.h>
40
41#include "hard-interface.h"
Antonio Quartulli93231582016-01-16 16:40:13 +080042#include "hash.h"
43#include "originator.h"
Antonio Quartulli0da00352016-01-16 16:40:12 +080044#include "packet.h"
45#include "routing.h"
46#include "send.h"
47#include "translation-table.h"
48
49/**
Antonio Quartulli93231582016-01-16 16:40:13 +080050 * batadv_v_ogm_orig_get - retrieve and possibly create an originator node
51 * @bat_priv: the bat priv with all the soft interface information
52 * @addr: the address of the originator
53 *
54 * Return: the orig_node corresponding to the specified address. If such object
55 * does not exist it is allocated here. In case of allocation failure returns
56 * NULL.
57 */
58struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
59 const u8 *addr)
60{
61 struct batadv_orig_node *orig_node;
62 int hash_added;
63
64 orig_node = batadv_orig_hash_find(bat_priv, addr);
65 if (orig_node)
66 return orig_node;
67
68 orig_node = batadv_orig_node_new(bat_priv, addr);
69 if (!orig_node)
70 return NULL;
71
72 hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
73 batadv_choose_orig, orig_node,
74 &orig_node->hash_entry);
75 if (hash_added != 0) {
76 /* orig_node->refcounter is initialised to 2 by
77 * batadv_orig_node_new()
78 */
79 batadv_orig_node_put(orig_node);
80 batadv_orig_node_put(orig_node);
81 orig_node = NULL;
82 }
83
84 return orig_node;
85}
86
87/**
Antonio Quartulli0da00352016-01-16 16:40:12 +080088 * batadv_v_ogm_start_timer - restart the OGM sending timer
89 * @bat_priv: the bat priv with all the soft interface information
90 */
91static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
92{
93 unsigned long msecs;
94 /* this function may be invoked in different contexts (ogm rescheduling
95 * or hard_iface activation), but the work timer should not be reset
96 */
97 if (delayed_work_pending(&bat_priv->bat_v.ogm_wq))
98 return;
99
100 msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
101 msecs += prandom_u32() % (2 * BATADV_JITTER);
102 queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq,
103 msecs_to_jiffies(msecs));
104}
105
106/**
107 * batadv_v_ogm_send_to_if - send a batman ogm using a given interface
108 * @skb: the OGM to send
109 * @hard_iface: the interface to use to send the OGM
110 */
111static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
112 struct batadv_hard_iface *hard_iface)
113{
114 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
115
116 if (hard_iface->if_status != BATADV_IF_ACTIVE)
117 return;
118
119 batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
120 batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
121 skb->len + ETH_HLEN);
122
Antonio Quartulli95d39272016-01-16 16:40:15 +0800123 batadv_send_broadcast_skb(skb, hard_iface);
Antonio Quartulli0da00352016-01-16 16:40:12 +0800124}
125
126/**
127 * batadv_v_ogm_send - periodic worker broadcasting the own OGM
128 * @work: work queue item
129 */
130static void batadv_v_ogm_send(struct work_struct *work)
131{
132 struct batadv_hard_iface *hard_iface;
133 struct batadv_priv_bat_v *bat_v;
134 struct batadv_priv *bat_priv;
135 struct batadv_ogm2_packet *ogm_packet;
136 struct sk_buff *skb, *skb_tmp;
137 unsigned char *ogm_buff, *pkt_buff;
138 int ogm_buff_len;
139 u16 tvlv_len = 0;
140
141 bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
142 bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
143
144 if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
145 goto out;
146
147 ogm_buff = bat_priv->bat_v.ogm_buff;
148 ogm_buff_len = bat_priv->bat_v.ogm_buff_len;
149 /* tt changes have to be committed before the tvlv data is
150 * appended as it may alter the tt tvlv container
151 */
152 batadv_tt_local_commit_changes(bat_priv);
153 tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
154 &ogm_buff_len,
155 BATADV_OGM2_HLEN);
156
157 bat_priv->bat_v.ogm_buff = ogm_buff;
158 bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
159
160 skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
161 if (!skb)
162 goto reschedule;
163
164 skb_reserve(skb, ETH_HLEN);
165 pkt_buff = skb_put(skb, ogm_buff_len);
166 memcpy(pkt_buff, ogm_buff, ogm_buff_len);
167
168 ogm_packet = (struct batadv_ogm2_packet *)skb->data;
169 ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
170 atomic_inc(&bat_priv->bat_v.ogm_seqno);
171 ogm_packet->tvlv_len = htons(tvlv_len);
172
173 /* broadcast on every interface */
174 rcu_read_lock();
175 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
176 if (hard_iface->soft_iface != bat_priv->soft_iface)
177 continue;
178
179 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
180 "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
181 ogm_packet->orig, ntohl(ogm_packet->seqno),
182 ntohl(ogm_packet->throughput), ogm_packet->ttl,
183 hard_iface->net_dev->name,
184 hard_iface->net_dev->dev_addr);
185
186 /* this skb gets consumed by batadv_v_ogm_send_to_if() */
187 skb_tmp = skb_clone(skb, GFP_ATOMIC);
188 if (!skb_tmp)
189 break;
190
191 batadv_v_ogm_send_to_if(skb_tmp, hard_iface);
192 }
193 rcu_read_unlock();
194
195 consume_skb(skb);
196
197reschedule:
198 batadv_v_ogm_start_timer(bat_priv);
199out:
200 return;
201}
202
203/**
204 * batadv_v_ogm_iface_enable - prepare an interface for B.A.T.M.A.N. V
205 * @hard_iface: the interface to prepare
206 *
207 * Takes care of scheduling own OGM sending routine for this interface.
208 *
209 * Return: 0 on success or a negative error code otherwise
210 */
211int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
212{
213 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
214
215 batadv_v_ogm_start_timer(bat_priv);
216
217 return 0;
218}
219
220/**
221 * batadv_v_ogm_primary_iface_set - set a new primary interface
222 * @primary_iface: the new primary interface
223 */
224void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface)
225{
226 struct batadv_priv *bat_priv = netdev_priv(primary_iface->soft_iface);
227 struct batadv_ogm2_packet *ogm_packet;
228
229 if (!bat_priv->bat_v.ogm_buff)
230 return;
231
232 ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
233 ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
234}
235
236/**
Antonio Quartulli93231582016-01-16 16:40:13 +0800237 * batadv_v_forward_penalty - apply a penalty to the throughput metric forwarded
238 * with B.A.T.M.A.N. V OGMs
239 * @bat_priv: the bat priv with all the soft interface information
240 * @if_incoming: the interface where the OGM has been received
241 * @if_outgoing: the interface where the OGM has to be forwarded to
242 * @throughput: the current throughput
243 *
244 * Apply a penalty on the current throughput metric value based on the
245 * characteristic of the interface where the OGM has been received. The return
246 * value is computed as follows:
247 * - throughput * 50% if the incoming and outgoing interface are the
248 * same WiFi interface and the throughput is above
249 * 1MBit/s
250 * - throughput if the outgoing interface is the default
251 * interface (i.e. this OGM is processed for the
252 * internal table and not forwarded)
253 * - throughput * hop penalty otherwise
254 *
255 * Return: the penalised throughput metric.
256 */
257static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv,
258 struct batadv_hard_iface *if_incoming,
259 struct batadv_hard_iface *if_outgoing,
260 u32 throughput)
261{
262 int hop_penalty = atomic_read(&bat_priv->hop_penalty);
263 int hop_penalty_max = BATADV_TQ_MAX_VALUE;
264
265 /* Don't apply hop penalty in default originator table. */
266 if (if_outgoing == BATADV_IF_DEFAULT)
267 return throughput;
268
269 /* Forwarding on the same WiFi interface cuts the throughput in half
270 * due to the store & forward characteristics of WIFI.
271 * Very low throughput values are the exception.
272 */
273 if ((throughput > 10) &&
274 (if_incoming == if_outgoing) &&
Antonio Quartullic8334842015-11-10 18:50:51 +0100275 !(if_incoming->bat_v.flags & BATADV_FULL_DUPLEX))
Antonio Quartulli93231582016-01-16 16:40:13 +0800276 return throughput / 2;
277
278 /* hop penalty of 255 equals 100% */
279 return throughput * (hop_penalty_max - hop_penalty) / hop_penalty_max;
280}
281
282/**
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100283 * batadv_v_ogm_forward - check conditions and forward an OGM to the given
284 * outgoing interface
Antonio Quartulli93231582016-01-16 16:40:13 +0800285 * @bat_priv: the bat priv with all the soft interface information
286 * @ogm_received: previously received OGM to be forwarded
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100287 * @orig_node: the originator which has been updated
288 * @neigh_node: the neigh_node through with the OGM has been received
Antonio Quartulli93231582016-01-16 16:40:13 +0800289 * @if_incoming: the interface on which this OGM was received on
290 * @if_outgoing: the interface to which the OGM has to be forwarded to
291 *
292 * Forward an OGM to an interface after having altered the throughput metric and
293 * the TTL value contained in it. The original OGM isn't modified.
294 */
295static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
296 const struct batadv_ogm2_packet *ogm_received,
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100297 struct batadv_orig_node *orig_node,
298 struct batadv_neigh_node *neigh_node,
Antonio Quartulli93231582016-01-16 16:40:13 +0800299 struct batadv_hard_iface *if_incoming,
300 struct batadv_hard_iface *if_outgoing)
301{
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100302 struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
303 struct batadv_orig_ifinfo *orig_ifinfo = NULL;
304 struct batadv_neigh_node *router = NULL;
Antonio Quartulli93231582016-01-16 16:40:13 +0800305 struct batadv_ogm2_packet *ogm_forward;
306 unsigned char *skb_buff;
307 struct sk_buff *skb;
308 size_t packet_len;
309 u16 tvlv_len;
310
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100311 /* only forward for specific interfaces, not for the default one. */
312 if (if_outgoing == BATADV_IF_DEFAULT)
313 goto out;
314
315 orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
316 if (!orig_ifinfo)
317 goto out;
318
319 /* acquire possibly updated router */
320 router = batadv_orig_router_get(orig_node, if_outgoing);
321
322 /* strict rule: forward packets coming from the best next hop only */
323 if (neigh_node != router)
324 goto out;
325
326 /* don't forward the same seqno twice on one interface */
327 if (orig_ifinfo->last_seqno_forwarded == ntohl(ogm_received->seqno))
328 goto out;
329
330 orig_ifinfo->last_seqno_forwarded = ntohl(ogm_received->seqno);
331
Antonio Quartulli93231582016-01-16 16:40:13 +0800332 if (ogm_received->ttl <= 1) {
333 batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n");
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100334 goto out;
Antonio Quartulli93231582016-01-16 16:40:13 +0800335 }
336
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100337 neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
338 if (!neigh_ifinfo)
339 goto out;
340
Antonio Quartulli93231582016-01-16 16:40:13 +0800341 tvlv_len = ntohs(ogm_received->tvlv_len);
342
343 packet_len = BATADV_OGM2_HLEN + tvlv_len;
344 skb = netdev_alloc_skb_ip_align(if_outgoing->net_dev,
345 ETH_HLEN + packet_len);
346 if (!skb)
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100347 goto out;
Antonio Quartulli93231582016-01-16 16:40:13 +0800348
349 skb_reserve(skb, ETH_HLEN);
350 skb_buff = skb_put(skb, packet_len);
351 memcpy(skb_buff, ogm_received, packet_len);
352
353 /* apply forward penalty */
354 ogm_forward = (struct batadv_ogm2_packet *)skb_buff;
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100355 ogm_forward->throughput = htonl(neigh_ifinfo->bat_v.throughput);
Antonio Quartulli93231582016-01-16 16:40:13 +0800356 ogm_forward->ttl--;
357
358 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
359 "Forwarding OGM2 packet on %s: throughput %u, ttl %u, received via %s\n",
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100360 if_outgoing->net_dev->name, ntohl(ogm_forward->throughput),
361 ogm_forward->ttl, if_incoming->net_dev->name);
Antonio Quartulli93231582016-01-16 16:40:13 +0800362
363 batadv_v_ogm_send_to_if(skb, if_outgoing);
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100364
365out:
366 if (orig_ifinfo)
367 batadv_orig_ifinfo_put(orig_ifinfo);
368 if (router)
369 batadv_neigh_node_put(router);
370 if (neigh_ifinfo)
371 batadv_neigh_ifinfo_put(neigh_ifinfo);
Antonio Quartulli93231582016-01-16 16:40:13 +0800372}
373
374/**
375 * batadv_v_ogm_metric_update - update route metric based on OGM
376 * @bat_priv: the bat priv with all the soft interface information
377 * @ogm2: OGM2 structure
378 * @orig_node: Originator structure for which the OGM has been received
379 * @neigh_node: the neigh_node through with the OGM has been received
380 * @if_incoming: the interface where this packet was received
381 * @if_outgoing: the interface for which the packet should be considered
382 *
383 * Return:
384 * 1 if the OGM is new,
385 * 0 if it is not new but valid,
386 * <0 on error (e.g. old OGM)
387 */
388static int batadv_v_ogm_metric_update(struct batadv_priv *bat_priv,
389 const struct batadv_ogm2_packet *ogm2,
390 struct batadv_orig_node *orig_node,
391 struct batadv_neigh_node *neigh_node,
392 struct batadv_hard_iface *if_incoming,
393 struct batadv_hard_iface *if_outgoing)
394{
395 struct batadv_orig_ifinfo *orig_ifinfo = NULL;
396 struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
397 bool protection_started = false;
398 int ret = -EINVAL;
399 u32 path_throughput;
400 s32 seq_diff;
401
402 orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
403 if (!orig_ifinfo)
404 goto out;
405
406 seq_diff = ntohl(ogm2->seqno) - orig_ifinfo->last_real_seqno;
407
408 if (!hlist_empty(&orig_node->neigh_list) &&
409 batadv_window_protected(bat_priv, seq_diff,
410 BATADV_OGM_MAX_AGE,
411 &orig_ifinfo->batman_seqno_reset,
412 &protection_started)) {
413 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
414 "Drop packet: packet within window protection time from %pM\n",
415 ogm2->orig);
416 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
417 "Last reset: %ld, %ld\n",
418 orig_ifinfo->batman_seqno_reset, jiffies);
419 goto out;
420 }
421
422 /* drop packets with old seqnos, however accept the first packet after
423 * a host has been rebooted.
424 */
425 if ((seq_diff < 0) && !protection_started)
426 goto out;
427
428 neigh_node->last_seen = jiffies;
429
430 orig_node->last_seen = jiffies;
431
432 orig_ifinfo->last_real_seqno = ntohl(ogm2->seqno);
433 orig_ifinfo->last_ttl = ogm2->ttl;
434
435 neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
436 if (!neigh_ifinfo)
437 goto out;
438
439 path_throughput = batadv_v_forward_penalty(bat_priv, if_incoming,
440 if_outgoing,
441 ntohl(ogm2->throughput));
442 neigh_ifinfo->bat_v.throughput = path_throughput;
443 neigh_ifinfo->bat_v.last_seqno = ntohl(ogm2->seqno);
444 neigh_ifinfo->last_ttl = ogm2->ttl;
445
446 if (seq_diff > 0 || protection_started)
447 ret = 1;
448 else
449 ret = 0;
450out:
451 if (orig_ifinfo)
452 batadv_orig_ifinfo_put(orig_ifinfo);
453 if (neigh_ifinfo)
454 batadv_neigh_ifinfo_put(neigh_ifinfo);
455
456 return ret;
457}
458
459/**
460 * batadv_v_ogm_route_update - update routes based on OGM
461 * @bat_priv: the bat priv with all the soft interface information
462 * @ethhdr: the Ethernet header of the OGM2
463 * @ogm2: OGM2 structure
464 * @orig_node: Originator structure for which the OGM has been received
465 * @neigh_node: the neigh_node through with the OGM has been received
466 * @if_incoming: the interface where this packet was received
467 * @if_outgoing: the interface for which the packet should be considered
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100468 *
469 * Return: true if the packet should be forwarded, false otherwise
Antonio Quartulli93231582016-01-16 16:40:13 +0800470 */
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100471static bool batadv_v_ogm_route_update(struct batadv_priv *bat_priv,
Antonio Quartulli93231582016-01-16 16:40:13 +0800472 const struct ethhdr *ethhdr,
473 const struct batadv_ogm2_packet *ogm2,
474 struct batadv_orig_node *orig_node,
475 struct batadv_neigh_node *neigh_node,
476 struct batadv_hard_iface *if_incoming,
477 struct batadv_hard_iface *if_outgoing)
478{
479 struct batadv_neigh_node *router = NULL;
Antonio Quartulli93231582016-01-16 16:40:13 +0800480 struct batadv_orig_node *orig_neigh_node = NULL;
Antonio Quartulli93231582016-01-16 16:40:13 +0800481 struct batadv_neigh_node *orig_neigh_router = NULL;
Simon Wunderlich86de37c2016-02-01 15:21:38 +0100482 struct batadv_neigh_ifinfo *router_ifinfo = NULL, *neigh_ifinfo = NULL;
483 u32 router_throughput, neigh_throughput;
484 u32 router_last_seqno;
485 u32 neigh_last_seqno;
486 s32 neigh_seq_diff;
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100487 bool forward = false;
Antonio Quartulli93231582016-01-16 16:40:13 +0800488
489 orig_neigh_node = batadv_v_ogm_orig_get(bat_priv, ethhdr->h_source);
490 if (!orig_neigh_node)
491 goto out;
492
493 orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
494 if_outgoing);
495
496 /* drop packet if sender is not a direct neighbor and if we
497 * don't route towards it
498 */
499 router = batadv_orig_router_get(orig_node, if_outgoing);
500 if (router && router->orig_node != orig_node && !orig_neigh_router) {
501 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
502 "Drop packet: OGM via unknown neighbor!\n");
503 goto out;
504 }
505
Simon Wunderlich86de37c2016-02-01 15:21:38 +0100506 /* Mark the OGM to be considered for forwarding, and update routes
507 * if needed.
508 */
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100509 forward = true;
Simon Wunderlich86de37c2016-02-01 15:21:38 +0100510
511 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
512 "Searching and updating originator entry of received packet\n");
513
514 /* if this neighbor already is our next hop there is nothing
515 * to change
516 */
517 if (router == neigh_node)
518 goto out;
519
520 /* don't consider neighbours with worse throughput.
521 * also switch route if this seqno is BATADV_V_MAX_ORIGDIFF newer than
522 * the last received seqno from our best next hop.
523 */
524 if (router) {
525 router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
526 neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
527
528 /* if these are not allocated, something is wrong. */
529 if (!router_ifinfo || !neigh_ifinfo)
530 goto out;
531
532 neigh_last_seqno = neigh_ifinfo->bat_v.last_seqno;
533 router_last_seqno = router_ifinfo->bat_v.last_seqno;
534 neigh_seq_diff = neigh_last_seqno - router_last_seqno;
535 router_throughput = router_ifinfo->bat_v.throughput;
536 neigh_throughput = neigh_ifinfo->bat_v.throughput;
537
538 if ((neigh_seq_diff < BATADV_OGM_MAX_ORIGDIFF) &&
539 (router_throughput >= neigh_throughput))
540 goto out;
541 }
542
543 batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
Antonio Quartulli93231582016-01-16 16:40:13 +0800544out:
Antonio Quartulli93231582016-01-16 16:40:13 +0800545 if (router)
546 batadv_neigh_node_put(router);
547 if (orig_neigh_router)
548 batadv_neigh_node_put(orig_neigh_router);
549 if (orig_neigh_node)
550 batadv_orig_node_put(orig_neigh_node);
Simon Wunderlich86de37c2016-02-01 15:21:38 +0100551 if (router_ifinfo)
552 batadv_neigh_ifinfo_put(router_ifinfo);
553 if (neigh_ifinfo)
554 batadv_neigh_ifinfo_put(neigh_ifinfo);
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100555
556 return forward;
Antonio Quartulli93231582016-01-16 16:40:13 +0800557}
558
559/**
560 * batadv_v_ogm_process_per_outif - process a batman v OGM for an outgoing if
561 * @bat_priv: the bat priv with all the soft interface information
562 * @ethhdr: the Ethernet header of the OGM2
563 * @ogm2: OGM2 structure
564 * @orig_node: Originator structure for which the OGM has been received
565 * @neigh_node: the neigh_node through with the OGM has been received
566 * @if_incoming: the interface where this packet was received
567 * @if_outgoing: the interface for which the packet should be considered
568 */
569static void
570batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
571 const struct ethhdr *ethhdr,
572 const struct batadv_ogm2_packet *ogm2,
573 struct batadv_orig_node *orig_node,
574 struct batadv_neigh_node *neigh_node,
575 struct batadv_hard_iface *if_incoming,
576 struct batadv_hard_iface *if_outgoing)
577{
578 int seqno_age;
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100579 bool forward;
Antonio Quartulli93231582016-01-16 16:40:13 +0800580
581 /* first, update the metric with according sanity checks */
582 seqno_age = batadv_v_ogm_metric_update(bat_priv, ogm2, orig_node,
583 neigh_node, if_incoming,
584 if_outgoing);
585
586 /* outdated sequence numbers are to be discarded */
587 if (seqno_age < 0)
588 return;
589
590 /* only unknown & newer OGMs contain TVLVs we are interested in */
591 if ((seqno_age > 0) && (if_outgoing == BATADV_IF_DEFAULT))
592 batadv_tvlv_containers_process(bat_priv, true, orig_node,
593 NULL, NULL,
594 (unsigned char *)(ogm2 + 1),
595 ntohs(ogm2->tvlv_len));
596
597 /* if the metric update went through, update routes if needed */
Simon Wunderlichefcc9d32016-02-01 15:21:37 +0100598 forward = batadv_v_ogm_route_update(bat_priv, ethhdr, ogm2, orig_node,
599 neigh_node, if_incoming,
600 if_outgoing);
601
602 /* if the routes have been processed correctly, check and forward */
603 if (forward)
604 batadv_v_ogm_forward(bat_priv, ogm2, orig_node, neigh_node,
605 if_incoming, if_outgoing);
Antonio Quartulli93231582016-01-16 16:40:13 +0800606}
607
608/**
609 * batadv_v_ogm_aggr_packet - checks if there is another OGM aggregated
610 * @buff_pos: current position in the skb
611 * @packet_len: total length of the skb
612 * @tvlv_len: tvlv length of the previously considered OGM
613 *
614 * Return: true if there is enough space for another OGM, false otherwise.
615 */
616static bool batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
617 __be16 tvlv_len)
618{
619 int next_buff_pos = 0;
620
621 next_buff_pos += buff_pos + BATADV_OGM2_HLEN;
622 next_buff_pos += ntohs(tvlv_len);
623
624 return (next_buff_pos <= packet_len) &&
625 (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
626}
627
628/**
629 * batadv_v_ogm_process - process an incoming batman v OGM
630 * @skb: the skb containing the OGM
631 * @ogm_offset: offset to the OGM which should be processed (for aggregates)
632 * @if_incoming: the interface where this packet was receved
633 */
634static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
635 struct batadv_hard_iface *if_incoming)
636{
637 struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
638 struct ethhdr *ethhdr;
639 struct batadv_orig_node *orig_node = NULL;
640 struct batadv_hardif_neigh_node *hardif_neigh = NULL;
641 struct batadv_neigh_node *neigh_node = NULL;
642 struct batadv_hard_iface *hard_iface;
643 struct batadv_ogm2_packet *ogm_packet;
644 u32 ogm_throughput, link_throughput, path_throughput;
645
646 ethhdr = eth_hdr(skb);
647 ogm_packet = (struct batadv_ogm2_packet *)(skb->data + ogm_offset);
648
649 ogm_throughput = ntohl(ogm_packet->throughput);
650
651 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
652 "Received OGM2 packet via NB: %pM, IF: %s [%pM] (from OG: %pM, seqno %u, troughput %u, TTL %u, V %u, tvlv_len %u)\n",
653 ethhdr->h_source, if_incoming->net_dev->name,
654 if_incoming->net_dev->dev_addr, ogm_packet->orig,
655 ntohl(ogm_packet->seqno), ogm_throughput, ogm_packet->ttl,
656 ogm_packet->version, ntohs(ogm_packet->tvlv_len));
657
658 /* If the troughput metric is 0, immediately drop the packet. No need to
659 * create orig_node / neigh_node for an unusable route.
660 */
661 if (ogm_throughput == 0) {
662 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
663 "Drop packet: originator packet with troughput metric of 0\n");
664 return;
665 }
666
667 /* require ELP packets be to received from this neighbor first */
668 hardif_neigh = batadv_hardif_neigh_get(if_incoming, ethhdr->h_source);
669 if (!hardif_neigh) {
670 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
671 "Drop packet: OGM via unknown neighbor!\n");
672 goto out;
673 }
674
675 orig_node = batadv_v_ogm_orig_get(bat_priv, ogm_packet->orig);
676 if (!orig_node)
677 return;
678
679 neigh_node = batadv_neigh_node_new(orig_node, if_incoming,
680 ethhdr->h_source);
681 if (!neigh_node)
682 goto out;
683
684 /* Update the received throughput metric to match the link
685 * characteristic:
686 * - If this OGM traveled one hop so far (emitted by single hop
687 * neighbor) the path throughput metric equals the link throughput.
688 * - For OGMs traversing more than hop the path throughput metric is
689 * the smaller of the path throughput and the link throughput.
690 */
691 link_throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
692 path_throughput = min_t(u32, link_throughput, ogm_throughput);
693 ogm_packet->throughput = htonl(path_throughput);
694
695 batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, orig_node,
696 neigh_node, if_incoming,
697 BATADV_IF_DEFAULT);
698
699 rcu_read_lock();
700 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
701 if (hard_iface->if_status != BATADV_IF_ACTIVE)
702 continue;
703
704 if (hard_iface->soft_iface != bat_priv->soft_iface)
705 continue;
706
707 batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet,
708 orig_node, neigh_node,
709 if_incoming, hard_iface);
710 }
711 rcu_read_unlock();
712out:
713 if (orig_node)
714 batadv_orig_node_put(orig_node);
715 if (neigh_node)
716 batadv_neigh_node_put(neigh_node);
717 if (hardif_neigh)
718 batadv_hardif_neigh_put(hardif_neigh);
719}
720
721/**
Antonio Quartulli0da00352016-01-16 16:40:12 +0800722 * batadv_v_ogm_packet_recv - OGM2 receiving handler
723 * @skb: the received OGM
724 * @if_incoming: the interface where this OGM has been received
725 *
726 * Return: NET_RX_SUCCESS and consume the skb on success or returns NET_RX_DROP
727 * (without freeing the skb) on failure
728 */
729int batadv_v_ogm_packet_recv(struct sk_buff *skb,
730 struct batadv_hard_iface *if_incoming)
731{
732 struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
733 struct batadv_ogm2_packet *ogm_packet;
734 struct ethhdr *ethhdr = eth_hdr(skb);
Antonio Quartulli93231582016-01-16 16:40:13 +0800735 int ogm_offset;
736 u8 *packet_pos;
737 int ret = NET_RX_DROP;
Antonio Quartulli0da00352016-01-16 16:40:12 +0800738
739 /* did we receive a OGM2 packet on an interface that does not have
740 * B.A.T.M.A.N. V enabled ?
741 */
742 if (strcmp(bat_priv->bat_algo_ops->name, "BATMAN_V") != 0)
743 return NET_RX_DROP;
744
745 if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
746 return NET_RX_DROP;
747
748 if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
749 return NET_RX_DROP;
750
751 ogm_packet = (struct batadv_ogm2_packet *)skb->data;
752
753 if (batadv_is_my_mac(bat_priv, ogm_packet->orig))
754 return NET_RX_DROP;
755
756 batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
757 batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
758 skb->len + ETH_HLEN);
759
Antonio Quartulli93231582016-01-16 16:40:13 +0800760 ogm_offset = 0;
761 ogm_packet = (struct batadv_ogm2_packet *)skb->data;
762
763 while (batadv_v_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
764 ogm_packet->tvlv_len)) {
765 batadv_v_ogm_process(skb, ogm_offset, if_incoming);
766
767 ogm_offset += BATADV_OGM2_HLEN;
768 ogm_offset += ntohs(ogm_packet->tvlv_len);
769
770 packet_pos = skb->data + ogm_offset;
771 ogm_packet = (struct batadv_ogm2_packet *)packet_pos;
772 }
773
774 ret = NET_RX_SUCCESS;
Antonio Quartulli0da00352016-01-16 16:40:12 +0800775 consume_skb(skb);
Antonio Quartulli93231582016-01-16 16:40:13 +0800776
777 return ret;
Antonio Quartulli0da00352016-01-16 16:40:12 +0800778}
779
780/**
781 * batadv_v_ogm_init - initialise the OGM2 engine
782 * @bat_priv: the bat priv with all the soft interface information
783 *
784 * Return: 0 on success or a negative error code in case of failure
785 */
786int batadv_v_ogm_init(struct batadv_priv *bat_priv)
787{
788 struct batadv_ogm2_packet *ogm_packet;
789 unsigned char *ogm_buff;
790 u32 random_seqno;
791
792 bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
793 ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
794 if (!ogm_buff)
795 return -ENOMEM;
796
797 bat_priv->bat_v.ogm_buff = ogm_buff;
798 ogm_packet = (struct batadv_ogm2_packet *)ogm_buff;
799 ogm_packet->packet_type = BATADV_OGM2;
800 ogm_packet->version = BATADV_COMPAT_VERSION;
801 ogm_packet->ttl = BATADV_TTL;
802 ogm_packet->flags = BATADV_NO_FLAGS;
803 ogm_packet->throughput = htonl(BATADV_THROUGHPUT_MAX_VALUE);
804
805 /* randomize initial seqno to avoid collision */
806 get_random_bytes(&random_seqno, sizeof(random_seqno));
807 atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
808 INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
809
810 return 0;
811}
812
813/**
814 * batadv_v_ogm_free - free OGM private resources
815 * @bat_priv: the bat priv with all the soft interface information
816 */
817void batadv_v_ogm_free(struct batadv_priv *bat_priv)
818{
819 cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
820
821 kfree(bat_priv->bat_v.ogm_buff);
822 bat_priv->bat_v.ogm_buff = NULL;
823 bat_priv->bat_v.ogm_buff_len = 0;
824}