~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/batman-adv/bat_v_ogm.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (C) B.A.T.M.A.N. contributors:
  3  *
  4  * Antonio Quartulli
  5  */
  6 
  7 #include "bat_v_ogm.h"
  8 #include "main.h"
  9 
 10 #include <linux/atomic.h>
 11 #include <linux/byteorder/generic.h>
 12 #include <linux/container_of.h>
 13 #include <linux/errno.h>
 14 #include <linux/etherdevice.h>
 15 #include <linux/gfp.h>
 16 #include <linux/if_ether.h>
 17 #include <linux/jiffies.h>
 18 #include <linux/kref.h>
 19 #include <linux/list.h>
 20 #include <linux/lockdep.h>
 21 #include <linux/minmax.h>
 22 #include <linux/mutex.h>
 23 #include <linux/netdevice.h>
 24 #include <linux/random.h>
 25 #include <linux/rculist.h>
 26 #include <linux/rcupdate.h>
 27 #include <linux/skbuff.h>
 28 #include <linux/slab.h>
 29 #include <linux/spinlock.h>
 30 #include <linux/stddef.h>
 31 #include <linux/string.h>
 32 #include <linux/types.h>
 33 #include <linux/workqueue.h>
 34 #include <uapi/linux/batadv_packet.h>
 35 
 36 #include "bat_algo.h"
 37 #include "hard-interface.h"
 38 #include "hash.h"
 39 #include "log.h"
 40 #include "originator.h"
 41 #include "routing.h"
 42 #include "send.h"
 43 #include "translation-table.h"
 44 #include "tvlv.h"
 45 
 46 /**
 47  * batadv_v_ogm_orig_get() - retrieve and possibly create an originator node
 48  * @bat_priv: the bat priv with all the soft interface information
 49  * @addr: the address of the originator
 50  *
 51  * Return: the orig_node corresponding to the specified address. If such an
 52  * object does not exist, it is allocated here. In case of allocation failure
 53  * returns NULL.
 54  */
 55 struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
 56                                                const u8 *addr)
 57 {
 58         struct batadv_orig_node *orig_node;
 59         int hash_added;
 60 
 61         orig_node = batadv_orig_hash_find(bat_priv, addr);
 62         if (orig_node)
 63                 return orig_node;
 64 
 65         orig_node = batadv_orig_node_new(bat_priv, addr);
 66         if (!orig_node)
 67                 return NULL;
 68 
 69         kref_get(&orig_node->refcount);
 70         hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
 71                                      batadv_choose_orig, orig_node,
 72                                      &orig_node->hash_entry);
 73         if (hash_added != 0) {
 74                 /* remove refcnt for newly created orig_node and hash entry */
 75                 batadv_orig_node_put(orig_node);
 76                 batadv_orig_node_put(orig_node);
 77                 orig_node = NULL;
 78         }
 79 
 80         return orig_node;
 81 }
 82 
 83 /**
 84  * batadv_v_ogm_start_queue_timer() - restart the OGM aggregation timer
 85  * @hard_iface: the interface to use to send the OGM
 86  */
 87 static void batadv_v_ogm_start_queue_timer(struct batadv_hard_iface *hard_iface)
 88 {
 89         unsigned int msecs = BATADV_MAX_AGGREGATION_MS * 1000;
 90 
 91         /* msecs * [0.9, 1.1] */
 92         msecs += get_random_u32_below(msecs / 5) - (msecs / 10);
 93         queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.aggr_wq,
 94                            msecs_to_jiffies(msecs / 1000));
 95 }
 96 
 97 /**
 98  * batadv_v_ogm_start_timer() - restart the OGM sending timer
 99  * @bat_priv: the bat priv with all the soft interface information
100  */
101 static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
102 {
103         unsigned long msecs;
104         /* this function may be invoked in different contexts (ogm rescheduling
105          * or hard_iface activation), but the work timer should not be reset
106          */
107         if (delayed_work_pending(&bat_priv->bat_v.ogm_wq))
108                 return;
109 
110         msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
111         msecs += get_random_u32_below(2 * BATADV_JITTER);
112         queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq,
113                            msecs_to_jiffies(msecs));
114 }
115 
116 /**
117  * batadv_v_ogm_send_to_if() - send a batman ogm using a given interface
118  * @skb: the OGM to send
119  * @hard_iface: the interface to use to send the OGM
120  */
121 static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
122                                     struct batadv_hard_iface *hard_iface)
123 {
124         struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
125 
126         if (hard_iface->if_status != BATADV_IF_ACTIVE) {
127                 kfree_skb(skb);
128                 return;
129         }
130 
131         batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
132         batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
133                            skb->len + ETH_HLEN);
134 
135         batadv_send_broadcast_skb(skb, hard_iface);
136 }
137 
138 /**
139  * batadv_v_ogm_len() - OGMv2 packet length
140  * @skb: the OGM to check
141  *
142  * Return: Length of the given OGMv2 packet, including tvlv length, excluding
143  * ethernet header length.
144  */
145 static unsigned int batadv_v_ogm_len(struct sk_buff *skb)
146 {
147         struct batadv_ogm2_packet *ogm_packet;
148 
149         ogm_packet = (struct batadv_ogm2_packet *)skb->data;
150         return BATADV_OGM2_HLEN + ntohs(ogm_packet->tvlv_len);
151 }
152 
153 /**
154  * batadv_v_ogm_queue_left() - check if given OGM still fits aggregation queue
155  * @skb: the OGM to check
156  * @hard_iface: the interface to use to send the OGM
157  *
158  * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
159  *
160  * Return: True, if the given OGMv2 packet still fits, false otherwise.
161  */
162 static bool batadv_v_ogm_queue_left(struct sk_buff *skb,
163                                     struct batadv_hard_iface *hard_iface)
164 {
165         unsigned int max = min_t(unsigned int, hard_iface->net_dev->mtu,
166                                  BATADV_MAX_AGGREGATION_BYTES);
167         unsigned int ogm_len = batadv_v_ogm_len(skb);
168 
169         lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
170 
171         return hard_iface->bat_v.aggr_len + ogm_len <= max;
172 }
173 
174 /**
175  * batadv_v_ogm_aggr_list_free - free all elements in an aggregation queue
176  * @hard_iface: the interface holding the aggregation queue
177  *
178  * Empties the OGMv2 aggregation queue and frees all the skbs it contains.
179  *
180  * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
181  */
182 static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
183 {
184         lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
185 
186         __skb_queue_purge(&hard_iface->bat_v.aggr_list);
187         hard_iface->bat_v.aggr_len = 0;
188 }
189 
190 /**
191  * batadv_v_ogm_aggr_send() - flush & send aggregation queue
192  * @hard_iface: the interface with the aggregation queue to flush
193  *
194  * Aggregates all OGMv2 packets currently in the aggregation queue into a
195  * single OGMv2 packet and transmits this aggregate.
196  *
197  * The aggregation queue is empty after this call.
198  *
199  * Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
200  */
201 static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
202 {
203         unsigned int aggr_len = hard_iface->bat_v.aggr_len;
204         struct sk_buff *skb_aggr;
205         unsigned int ogm_len;
206         struct sk_buff *skb;
207 
208         lockdep_assert_held(&hard_iface->bat_v.aggr_list.lock);
209 
210         if (!aggr_len)
211                 return;
212 
213         skb_aggr = dev_alloc_skb(aggr_len + ETH_HLEN + NET_IP_ALIGN);
214         if (!skb_aggr) {
215                 batadv_v_ogm_aggr_list_free(hard_iface);
216                 return;
217         }
218 
219         skb_reserve(skb_aggr, ETH_HLEN + NET_IP_ALIGN);
220         skb_reset_network_header(skb_aggr);
221 
222         while ((skb = __skb_dequeue(&hard_iface->bat_v.aggr_list))) {
223                 hard_iface->bat_v.aggr_len -= batadv_v_ogm_len(skb);
224 
225                 ogm_len = batadv_v_ogm_len(skb);
226                 skb_put_data(skb_aggr, skb->data, ogm_len);
227 
228                 consume_skb(skb);
229         }
230 
231         batadv_v_ogm_send_to_if(skb_aggr, hard_iface);
232 }
233 
234 /**
235  * batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface
236  * @skb: the OGM to queue
237  * @hard_iface: the interface to queue the OGM on
238  */
239 static void batadv_v_ogm_queue_on_if(struct sk_buff *skb,
240                                      struct batadv_hard_iface *hard_iface)
241 {
242         struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
243 
244         if (!atomic_read(&bat_priv->aggregated_ogms)) {
245                 batadv_v_ogm_send_to_if(skb, hard_iface);
246                 return;
247         }
248 
249         spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
250         if (!batadv_v_ogm_queue_left(skb, hard_iface))
251                 batadv_v_ogm_aggr_send(hard_iface);
252 
253         hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb);
254         __skb_queue_tail(&hard_iface->bat_v.aggr_list, skb);
255         spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
256 }
257 
258 /**
259  * batadv_v_ogm_send_softif() - periodic worker broadcasting the own OGM
260  * @bat_priv: the bat priv with all the soft interface information
261  */
262 static void batadv_v_ogm_send_softif(struct batadv_priv *bat_priv)
263 {
264         struct batadv_hard_iface *hard_iface;
265         struct batadv_ogm2_packet *ogm_packet;
266         struct sk_buff *skb, *skb_tmp;
267         unsigned char *ogm_buff;
268         int ogm_buff_len;
269         u16 tvlv_len = 0;
270         int ret;
271 
272         lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex);
273 
274         if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
275                 goto out;
276 
277         ogm_buff = bat_priv->bat_v.ogm_buff;
278         ogm_buff_len = bat_priv->bat_v.ogm_buff_len;
279         /* tt changes have to be committed before the tvlv data is
280          * appended as it may alter the tt tvlv container
281          */
282         batadv_tt_local_commit_changes(bat_priv);
283         tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
284                                                     &ogm_buff_len,
285                                                     BATADV_OGM2_HLEN);
286 
287         bat_priv->bat_v.ogm_buff = ogm_buff;
288         bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
289 
290         skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
291         if (!skb)
292                 goto reschedule;
293 
294         skb_reserve(skb, ETH_HLEN);
295         skb_put_data(skb, ogm_buff, ogm_buff_len);
296 
297         ogm_packet = (struct batadv_ogm2_packet *)skb->data;
298         ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
299         atomic_inc(&bat_priv->bat_v.ogm_seqno);
300         ogm_packet->tvlv_len = htons(tvlv_len);
301 
302         /* broadcast on every interface */
303         rcu_read_lock();
304         list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
305                 if (hard_iface->soft_iface != bat_priv->soft_iface)
306                         continue;
307 
308                 if (!kref_get_unless_zero(&hard_iface->refcount))
309                         continue;
310 
311                 ret = batadv_hardif_no_broadcast(hard_iface, NULL, NULL);
312                 if (ret) {
313                         char *type;
314 
315                         switch (ret) {
316                         case BATADV_HARDIF_BCAST_NORECIPIENT:
317                                 type = "no neighbor";
318                                 break;
319                         case BATADV_HARDIF_BCAST_DUPFWD:
320                                 type = "single neighbor is source";
321                                 break;
322                         case BATADV_HARDIF_BCAST_DUPORIG:
323                                 type = "single neighbor is originator";
324                                 break;
325                         default:
326                                 type = "unknown";
327                         }
328 
329                         batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 from ourselves on %s suppressed: %s\n",
330                                    hard_iface->net_dev->name, type);
331 
332                         batadv_hardif_put(hard_iface);
333                         continue;
334                 }
335 
336                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
337                            "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
338                            ogm_packet->orig, ntohl(ogm_packet->seqno),
339                            ntohl(ogm_packet->throughput), ogm_packet->ttl,
340                            hard_iface->net_dev->name,
341                            hard_iface->net_dev->dev_addr);
342 
343                 /* this skb gets consumed by batadv_v_ogm_send_to_if() */
344                 skb_tmp = skb_clone(skb, GFP_ATOMIC);
345                 if (!skb_tmp) {
346                         batadv_hardif_put(hard_iface);
347                         break;
348                 }
349 
350                 batadv_v_ogm_queue_on_if(skb_tmp, hard_iface);
351                 batadv_hardif_put(hard_iface);
352         }
353         rcu_read_unlock();
354 
355         consume_skb(skb);
356 
357 reschedule:
358         batadv_v_ogm_start_timer(bat_priv);
359 out:
360         return;
361 }
362 
363 /**
364  * batadv_v_ogm_send() - periodic worker broadcasting the own OGM
365  * @work: work queue item
366  */
367 static void batadv_v_ogm_send(struct work_struct *work)
368 {
369         struct batadv_priv_bat_v *bat_v;
370         struct batadv_priv *bat_priv;
371 
372         bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
373         bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
374 
375         mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
376         batadv_v_ogm_send_softif(bat_priv);
377         mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
378 }
379 
380 /**
381  * batadv_v_ogm_aggr_work() - OGM queue periodic task per interface
382  * @work: work queue item
383  *
384  * Emits aggregated OGM messages in regular intervals.
385  */
386 void batadv_v_ogm_aggr_work(struct work_struct *work)
387 {
388         struct batadv_hard_iface_bat_v *batv;
389         struct batadv_hard_iface *hard_iface;
390 
391         batv = container_of(work, struct batadv_hard_iface_bat_v, aggr_wq.work);
392         hard_iface = container_of(batv, struct batadv_hard_iface, bat_v);
393 
394         spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
395         batadv_v_ogm_aggr_send(hard_iface);
396         spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
397 
398         batadv_v_ogm_start_queue_timer(hard_iface);
399 }
400 
401 /**
402  * batadv_v_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. V
403  * @hard_iface: the interface to prepare
404  *
405  * Takes care of scheduling its own OGM sending routine for this interface.
406  *
407  * Return: 0 on success or a negative error code otherwise
408  */
409 int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
410 {
411         struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
412 
413         batadv_v_ogm_start_queue_timer(hard_iface);
414         batadv_v_ogm_start_timer(bat_priv);
415 
416         return 0;
417 }
418 
419 /**
420  * batadv_v_ogm_iface_disable() - release OGM interface private resources
421  * @hard_iface: interface for which the resources have to be released
422  */
423 void batadv_v_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
424 {
425         cancel_delayed_work_sync(&hard_iface->bat_v.aggr_wq);
426 
427         spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
428         batadv_v_ogm_aggr_list_free(hard_iface);
429         spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
430 }
431 
432 /**
433  * batadv_v_ogm_primary_iface_set() - set a new primary interface
434  * @primary_iface: the new primary interface
435  */
436 void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface)
437 {
438         struct batadv_priv *bat_priv = netdev_priv(primary_iface->soft_iface);
439         struct batadv_ogm2_packet *ogm_packet;
440 
441         mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
442         if (!bat_priv->bat_v.ogm_buff)
443                 goto unlock;
444 
445         ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
446         ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
447 
448 unlock:
449         mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
450 }
451 
452 /**
453  * batadv_v_forward_penalty() - apply a penalty to the throughput metric
454  *  forwarded with B.A.T.M.A.N. V OGMs
455  * @bat_priv: the bat priv with all the soft interface information
456  * @if_incoming: the interface where the OGM has been received
457  * @if_outgoing: the interface where the OGM has to be forwarded to
458  * @throughput: the current throughput
459  *
460  * Apply a penalty on the current throughput metric value based on the
461  * characteristic of the interface where the OGM has been received.
462  *
463  * Initially the per hardif hop penalty is applied to the throughput. After
464  * that the return value is then computed as follows:
465  * - throughput * 50%          if the incoming and outgoing interface are the
466  *                             same WiFi interface and the throughput is above
467  *                             1MBit/s
468  * - throughput                if the outgoing interface is the default
469  *                             interface (i.e. this OGM is processed for the
470  *                             internal table and not forwarded)
471  * - throughput * node hop penalty  otherwise
472  *
473  * Return: the penalised throughput metric.
474  */
475 static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv,
476                                     struct batadv_hard_iface *if_incoming,
477                                     struct batadv_hard_iface *if_outgoing,
478                                     u32 throughput)
479 {
480         int if_hop_penalty = atomic_read(&if_incoming->hop_penalty);
481         int hop_penalty = atomic_read(&bat_priv->hop_penalty);
482         int hop_penalty_max = BATADV_TQ_MAX_VALUE;
483 
484         /* Apply per hardif hop penalty */
485         throughput = throughput * (hop_penalty_max - if_hop_penalty) /
486                      hop_penalty_max;
487 
488         /* Don't apply hop penalty in default originator table. */
489         if (if_outgoing == BATADV_IF_DEFAULT)
490                 return throughput;
491 
492         /* Forwarding on the same WiFi interface cuts the throughput in half
493          * due to the store & forward characteristics of WIFI.
494          * Very low throughput values are the exception.
495          */
496         if (throughput > 10 &&
497             if_incoming == if_outgoing &&
498             !(if_incoming->bat_v.flags & BATADV_FULL_DUPLEX))
499                 return throughput / 2;
500 
501         /* hop penalty of 255 equals 100% */
502         return throughput * (hop_penalty_max - hop_penalty) / hop_penalty_max;
503 }
504 
505 /**
506  * batadv_v_ogm_forward() - check conditions and forward an OGM to the given
507  *  outgoing interface
508  * @bat_priv: the bat priv with all the soft interface information
509  * @ogm_received: previously received OGM to be forwarded
510  * @orig_node: the originator which has been updated
511  * @neigh_node: the neigh_node through with the OGM has been received
512  * @if_incoming: the interface on which this OGM was received on
513  * @if_outgoing: the interface to which the OGM has to be forwarded to
514  *
515  * Forward an OGM to an interface after having altered the throughput metric and
516  * the TTL value contained in it. The original OGM isn't modified.
517  */
518 static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
519                                  const struct batadv_ogm2_packet *ogm_received,
520                                  struct batadv_orig_node *orig_node,
521                                  struct batadv_neigh_node *neigh_node,
522                                  struct batadv_hard_iface *if_incoming,
523                                  struct batadv_hard_iface *if_outgoing)
524 {
525         struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
526         struct batadv_orig_ifinfo *orig_ifinfo = NULL;
527         struct batadv_neigh_node *router = NULL;
528         struct batadv_ogm2_packet *ogm_forward;
529         unsigned char *skb_buff;
530         struct sk_buff *skb;
531         size_t packet_len;
532         u16 tvlv_len;
533 
534         /* only forward for specific interfaces, not for the default one. */
535         if (if_outgoing == BATADV_IF_DEFAULT)
536                 goto out;
537 
538         orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
539         if (!orig_ifinfo)
540                 goto out;
541 
542         /* acquire possibly updated router */
543         router = batadv_orig_router_get(orig_node, if_outgoing);
544 
545         /* strict rule: forward packets coming from the best next hop only */
546         if (neigh_node != router)
547                 goto out;
548 
549         /* don't forward the same seqno twice on one interface */
550         if (orig_ifinfo->last_seqno_forwarded == ntohl(ogm_received->seqno))
551                 goto out;
552 
553         orig_ifinfo->last_seqno_forwarded = ntohl(ogm_received->seqno);
554 
555         if (ogm_received->ttl <= 1) {
556                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n");
557                 goto out;
558         }
559 
560         neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
561         if (!neigh_ifinfo)
562                 goto out;
563 
564         tvlv_len = ntohs(ogm_received->tvlv_len);
565 
566         packet_len = BATADV_OGM2_HLEN + tvlv_len;
567         skb = netdev_alloc_skb_ip_align(if_outgoing->net_dev,
568                                         ETH_HLEN + packet_len);
569         if (!skb)
570                 goto out;
571 
572         skb_reserve(skb, ETH_HLEN);
573         skb_buff = skb_put_data(skb, ogm_received, packet_len);
574 
575         /* apply forward penalty */
576         ogm_forward = (struct batadv_ogm2_packet *)skb_buff;
577         ogm_forward->throughput = htonl(neigh_ifinfo->bat_v.throughput);
578         ogm_forward->ttl--;
579 
580         batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
581                    "Forwarding OGM2 packet on %s: throughput %u, ttl %u, received via %s\n",
582                    if_outgoing->net_dev->name, ntohl(ogm_forward->throughput),
583                    ogm_forward->ttl, if_incoming->net_dev->name);
584 
585         batadv_v_ogm_queue_on_if(skb, if_outgoing);
586 
587 out:
588         batadv_orig_ifinfo_put(orig_ifinfo);
589         batadv_neigh_node_put(router);
590         batadv_neigh_ifinfo_put(neigh_ifinfo);
591 }
592 
593 /**
594  * batadv_v_ogm_metric_update() - update route metric based on OGM
595  * @bat_priv: the bat priv with all the soft interface information
596  * @ogm2: OGM2 structure
597  * @orig_node: Originator structure for which the OGM has been received
598  * @neigh_node: the neigh_node through with the OGM has been received
599  * @if_incoming: the interface where this packet was received
600  * @if_outgoing: the interface for which the packet should be considered
601  *
602  * Return:
603  *  1  if the OGM is new,
604  *  0  if it is not new but valid,
605  *  <0 on error (e.g. old OGM)
606  */
607 static int batadv_v_ogm_metric_update(struct batadv_priv *bat_priv,
608                                       const struct batadv_ogm2_packet *ogm2,
609                                       struct batadv_orig_node *orig_node,
610                                       struct batadv_neigh_node *neigh_node,
611                                       struct batadv_hard_iface *if_incoming,
612                                       struct batadv_hard_iface *if_outgoing)
613 {
614         struct batadv_orig_ifinfo *orig_ifinfo;
615         struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
616         bool protection_started = false;
617         int ret = -EINVAL;
618         u32 path_throughput;
619         s32 seq_diff;
620 
621         orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
622         if (!orig_ifinfo)
623                 goto out;
624 
625         seq_diff = ntohl(ogm2->seqno) - orig_ifinfo->last_real_seqno;
626 
627         if (!hlist_empty(&orig_node->neigh_list) &&
628             batadv_window_protected(bat_priv, seq_diff,
629                                     BATADV_OGM_MAX_AGE,
630                                     &orig_ifinfo->batman_seqno_reset,
631                                     &protection_started)) {
632                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
633                            "Drop packet: packet within window protection time from %pM\n",
634                            ogm2->orig);
635                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
636                            "Last reset: %ld, %ld\n",
637                            orig_ifinfo->batman_seqno_reset, jiffies);
638                 goto out;
639         }
640 
641         /* drop packets with old seqnos, however accept the first packet after
642          * a host has been rebooted.
643          */
644         if (seq_diff < 0 && !protection_started)
645                 goto out;
646 
647         neigh_node->last_seen = jiffies;
648 
649         orig_node->last_seen = jiffies;
650 
651         orig_ifinfo->last_real_seqno = ntohl(ogm2->seqno);
652         orig_ifinfo->last_ttl = ogm2->ttl;
653 
654         neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
655         if (!neigh_ifinfo)
656                 goto out;
657 
658         path_throughput = batadv_v_forward_penalty(bat_priv, if_incoming,
659                                                    if_outgoing,
660                                                    ntohl(ogm2->throughput));
661         neigh_ifinfo->bat_v.throughput = path_throughput;
662         neigh_ifinfo->bat_v.last_seqno = ntohl(ogm2->seqno);
663         neigh_ifinfo->last_ttl = ogm2->ttl;
664 
665         if (seq_diff > 0 || protection_started)
666                 ret = 1;
667         else
668                 ret = 0;
669 out:
670         batadv_orig_ifinfo_put(orig_ifinfo);
671         batadv_neigh_ifinfo_put(neigh_ifinfo);
672 
673         return ret;
674 }
675 
676 /**
677  * batadv_v_ogm_route_update() - update routes based on OGM
678  * @bat_priv: the bat priv with all the soft interface information
679  * @ethhdr: the Ethernet header of the OGM2
680  * @ogm2: OGM2 structure
681  * @orig_node: Originator structure for which the OGM has been received
682  * @neigh_node: the neigh_node through with the OGM has been received
683  * @if_incoming: the interface where this packet was received
684  * @if_outgoing: the interface for which the packet should be considered
685  *
686  * Return: true if the packet should be forwarded, false otherwise
687  */
688 static bool batadv_v_ogm_route_update(struct batadv_priv *bat_priv,
689                                       const struct ethhdr *ethhdr,
690                                       const struct batadv_ogm2_packet *ogm2,
691                                       struct batadv_orig_node *orig_node,
692                                       struct batadv_neigh_node *neigh_node,
693                                       struct batadv_hard_iface *if_incoming,
694                                       struct batadv_hard_iface *if_outgoing)
695 {
696         struct batadv_neigh_node *router = NULL;
697         struct batadv_orig_node *orig_neigh_node;
698         struct batadv_neigh_node *orig_neigh_router = NULL;
699         struct batadv_neigh_ifinfo *router_ifinfo = NULL, *neigh_ifinfo = NULL;
700         u32 router_throughput, neigh_throughput;
701         u32 router_last_seqno;
702         u32 neigh_last_seqno;
703         s32 neigh_seq_diff;
704         bool forward = false;
705 
706         orig_neigh_node = batadv_v_ogm_orig_get(bat_priv, ethhdr->h_source);
707         if (!orig_neigh_node)
708                 goto out;
709 
710         orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
711                                                    if_outgoing);
712 
713         /* drop packet if sender is not a direct neighbor and if we
714          * don't route towards it
715          */
716         router = batadv_orig_router_get(orig_node, if_outgoing);
717         if (router && router->orig_node != orig_node && !orig_neigh_router) {
718                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
719                            "Drop packet: OGM via unknown neighbor!\n");
720                 goto out;
721         }
722 
723         /* Mark the OGM to be considered for forwarding, and update routes
724          * if needed.
725          */
726         forward = true;
727 
728         batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
729                    "Searching and updating originator entry of received packet\n");
730 
731         /* if this neighbor already is our next hop there is nothing
732          * to change
733          */
734         if (router == neigh_node)
735                 goto out;
736 
737         /* don't consider neighbours with worse throughput.
738          * also switch route if this seqno is BATADV_V_MAX_ORIGDIFF newer than
739          * the last received seqno from our best next hop.
740          */
741         if (router) {
742                 router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
743                 neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
744 
745                 /* if these are not allocated, something is wrong. */
746                 if (!router_ifinfo || !neigh_ifinfo)
747                         goto out;
748 
749                 neigh_last_seqno = neigh_ifinfo->bat_v.last_seqno;
750                 router_last_seqno = router_ifinfo->bat_v.last_seqno;
751                 neigh_seq_diff = neigh_last_seqno - router_last_seqno;
752                 router_throughput = router_ifinfo->bat_v.throughput;
753                 neigh_throughput = neigh_ifinfo->bat_v.throughput;
754 
755                 if (neigh_seq_diff < BATADV_OGM_MAX_ORIGDIFF &&
756                     router_throughput >= neigh_throughput)
757                         goto out;
758         }
759 
760         batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
761 out:
762         batadv_neigh_node_put(router);
763         batadv_neigh_node_put(orig_neigh_router);
764         batadv_orig_node_put(orig_neigh_node);
765         batadv_neigh_ifinfo_put(router_ifinfo);
766         batadv_neigh_ifinfo_put(neigh_ifinfo);
767 
768         return forward;
769 }
770 
771 /**
772  * batadv_v_ogm_process_per_outif() - process a batman v OGM for an outgoing if
773  * @bat_priv: the bat priv with all the soft interface information
774  * @ethhdr: the Ethernet header of the OGM2
775  * @ogm2: OGM2 structure
776  * @orig_node: Originator structure for which the OGM has been received
777  * @neigh_node: the neigh_node through with the OGM has been received
778  * @if_incoming: the interface where this packet was received
779  * @if_outgoing: the interface for which the packet should be considered
780  */
781 static void
782 batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
783                                const struct ethhdr *ethhdr,
784                                const struct batadv_ogm2_packet *ogm2,
785                                struct batadv_orig_node *orig_node,
786                                struct batadv_neigh_node *neigh_node,
787                                struct batadv_hard_iface *if_incoming,
788                                struct batadv_hard_iface *if_outgoing)
789 {
790         int seqno_age;
791         bool forward;
792 
793         /* first, update the metric with according sanity checks */
794         seqno_age = batadv_v_ogm_metric_update(bat_priv, ogm2, orig_node,
795                                                neigh_node, if_incoming,
796                                                if_outgoing);
797 
798         /* outdated sequence numbers are to be discarded */
799         if (seqno_age < 0)
800                 return;
801 
802         /* only unknown & newer OGMs contain TVLVs we are interested in */
803         if (seqno_age > 0 && if_outgoing == BATADV_IF_DEFAULT)
804                 batadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
805                                                NULL,
806                                                (unsigned char *)(ogm2 + 1),
807                                                ntohs(ogm2->tvlv_len));
808 
809         /* if the metric update went through, update routes if needed */
810         forward = batadv_v_ogm_route_update(bat_priv, ethhdr, ogm2, orig_node,
811                                             neigh_node, if_incoming,
812                                             if_outgoing);
813 
814         /* if the routes have been processed correctly, check and forward */
815         if (forward)
816                 batadv_v_ogm_forward(bat_priv, ogm2, orig_node, neigh_node,
817                                      if_incoming, if_outgoing);
818 }
819 
820 /**
821  * batadv_v_ogm_aggr_packet() - checks if there is another OGM aggregated
822  * @buff_pos: current position in the skb
823  * @packet_len: total length of the skb
824  * @ogm2_packet: potential OGM2 in buffer
825  *
826  * Return: true if there is enough space for another OGM, false otherwise.
827  */
828 static bool
829 batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
830                          const struct batadv_ogm2_packet *ogm2_packet)
831 {
832         int next_buff_pos = 0;
833 
834         /* check if there is enough space for the header */
835         next_buff_pos += buff_pos + sizeof(*ogm2_packet);
836         if (next_buff_pos > packet_len)
837                 return false;
838 
839         /* check if there is enough space for the optional TVLV */
840         next_buff_pos += ntohs(ogm2_packet->tvlv_len);
841 
842         return (next_buff_pos <= packet_len) &&
843                (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
844 }
845 
846 /**
847  * batadv_v_ogm_process() - process an incoming batman v OGM
848  * @skb: the skb containing the OGM
849  * @ogm_offset: offset to the OGM which should be processed (for aggregates)
850  * @if_incoming: the interface where this packet was received
851  */
852 static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
853                                  struct batadv_hard_iface *if_incoming)
854 {
855         struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
856         struct ethhdr *ethhdr;
857         struct batadv_orig_node *orig_node = NULL;
858         struct batadv_hardif_neigh_node *hardif_neigh = NULL;
859         struct batadv_neigh_node *neigh_node = NULL;
860         struct batadv_hard_iface *hard_iface;
861         struct batadv_ogm2_packet *ogm_packet;
862         u32 ogm_throughput, link_throughput, path_throughput;
863         int ret;
864 
865         ethhdr = eth_hdr(skb);
866         ogm_packet = (struct batadv_ogm2_packet *)(skb->data + ogm_offset);
867 
868         ogm_throughput = ntohl(ogm_packet->throughput);
869 
870         batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
871                    "Received OGM2 packet via NB: %pM, IF: %s [%pM] (from OG: %pM, seqno %u, throughput %u, TTL %u, V %u, tvlv_len %u)\n",
872                    ethhdr->h_source, if_incoming->net_dev->name,
873                    if_incoming->net_dev->dev_addr, ogm_packet->orig,
874                    ntohl(ogm_packet->seqno), ogm_throughput, ogm_packet->ttl,
875                    ogm_packet->version, ntohs(ogm_packet->tvlv_len));
876 
877         if (batadv_is_my_mac(bat_priv, ogm_packet->orig)) {
878                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
879                            "Drop packet: originator packet from ourself\n");
880                 return;
881         }
882 
883         /* If the throughput metric is 0, immediately drop the packet. No need
884          * to create orig_node / neigh_node for an unusable route.
885          */
886         if (ogm_throughput == 0) {
887                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
888                            "Drop packet: originator packet with throughput metric of 0\n");
889                 return;
890         }
891 
892         /* require ELP packets be to received from this neighbor first */
893         hardif_neigh = batadv_hardif_neigh_get(if_incoming, ethhdr->h_source);
894         if (!hardif_neigh) {
895                 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
896                            "Drop packet: OGM via unknown neighbor!\n");
897                 goto out;
898         }
899 
900         orig_node = batadv_v_ogm_orig_get(bat_priv, ogm_packet->orig);
901         if (!orig_node)
902                 goto out;
903 
904         neigh_node = batadv_neigh_node_get_or_create(orig_node, if_incoming,
905                                                      ethhdr->h_source);
906         if (!neigh_node)
907                 goto out;
908 
909         /* Update the received throughput metric to match the link
910          * characteristic:
911          *  - If this OGM traveled one hop so far (emitted by single hop
912          *    neighbor) the path throughput metric equals the link throughput.
913          *  - For OGMs traversing more than hop the path throughput metric is
914          *    the smaller of the path throughput and the link throughput.
915          */
916         link_throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
917         path_throughput = min_t(u32, link_throughput, ogm_throughput);
918         ogm_packet->throughput = htonl(path_throughput);
919 
920         batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, orig_node,
921                                        neigh_node, if_incoming,
922                                        BATADV_IF_DEFAULT);
923 
924         rcu_read_lock();
925         list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
926                 if (hard_iface->if_status != BATADV_IF_ACTIVE)
927                         continue;
928 
929                 if (hard_iface->soft_iface != bat_priv->soft_iface)
930                         continue;
931 
932                 if (!kref_get_unless_zero(&hard_iface->refcount))
933                         continue;
934 
935                 ret = batadv_hardif_no_broadcast(hard_iface,
936                                                  ogm_packet->orig,
937                                                  hardif_neigh->orig);
938 
939                 if (ret) {
940                         char *type;
941 
942                         switch (ret) {
943                         case BATADV_HARDIF_BCAST_NORECIPIENT:
944                                 type = "no neighbor";
945                                 break;
946                         case BATADV_HARDIF_BCAST_DUPFWD:
947                                 type = "single neighbor is source";
948                                 break;
949                         case BATADV_HARDIF_BCAST_DUPORIG:
950                                 type = "single neighbor is originator";
951                                 break;
952                         default:
953                                 type = "unknown";
954                         }
955 
956                         batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 packet from %pM on %s suppressed: %s\n",
957                                    ogm_packet->orig, hard_iface->net_dev->name,
958                                    type);
959 
960                         batadv_hardif_put(hard_iface);
961                         continue;
962                 }
963 
964                 batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet,
965                                                orig_node, neigh_node,
966                                                if_incoming, hard_iface);
967 
968                 batadv_hardif_put(hard_iface);
969         }
970         rcu_read_unlock();
971 out:
972         batadv_orig_node_put(orig_node);
973         batadv_neigh_node_put(neigh_node);
974         batadv_hardif_neigh_put(hardif_neigh);
975 }
976 
977 /**
978  * batadv_v_ogm_packet_recv() - OGM2 receiving handler
979  * @skb: the received OGM
980  * @if_incoming: the interface where this OGM has been received
981  *
982  * Return: NET_RX_SUCCESS and consume the skb on success or returns NET_RX_DROP
983  * (without freeing the skb) on failure
984  */
985 int batadv_v_ogm_packet_recv(struct sk_buff *skb,
986                              struct batadv_hard_iface *if_incoming)
987 {
988         struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
989         struct batadv_ogm2_packet *ogm_packet;
990         struct ethhdr *ethhdr;
991         int ogm_offset;
992         u8 *packet_pos;
993         int ret = NET_RX_DROP;
994 
995         /* did we receive a OGM2 packet on an interface that does not have
996          * B.A.T.M.A.N. V enabled ?
997          */
998         if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0)
999                 goto free_skb;
1000 
1001         if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
1002                 goto free_skb;
1003 
1004         ethhdr = eth_hdr(skb);
1005         if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
1006                 goto free_skb;
1007 
1008         batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
1009         batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
1010                            skb->len + ETH_HLEN);
1011 
1012         ogm_offset = 0;
1013         ogm_packet = (struct batadv_ogm2_packet *)skb->data;
1014 
1015         while (batadv_v_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
1016                                         ogm_packet)) {
1017                 batadv_v_ogm_process(skb, ogm_offset, if_incoming);
1018 
1019                 ogm_offset += BATADV_OGM2_HLEN;
1020                 ogm_offset += ntohs(ogm_packet->tvlv_len);
1021 
1022                 packet_pos = skb->data + ogm_offset;
1023                 ogm_packet = (struct batadv_ogm2_packet *)packet_pos;
1024         }
1025 
1026         ret = NET_RX_SUCCESS;
1027 
1028 free_skb:
1029         if (ret == NET_RX_SUCCESS)
1030                 consume_skb(skb);
1031         else
1032                 kfree_skb(skb);
1033 
1034         return ret;
1035 }
1036 
1037 /**
1038  * batadv_v_ogm_init() - initialise the OGM2 engine
1039  * @bat_priv: the bat priv with all the soft interface information
1040  *
1041  * Return: 0 on success or a negative error code in case of failure
1042  */
1043 int batadv_v_ogm_init(struct batadv_priv *bat_priv)
1044 {
1045         struct batadv_ogm2_packet *ogm_packet;
1046         unsigned char *ogm_buff;
1047         u32 random_seqno;
1048 
1049         bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
1050         ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
1051         if (!ogm_buff)
1052                 return -ENOMEM;
1053 
1054         bat_priv->bat_v.ogm_buff = ogm_buff;
1055         ogm_packet = (struct batadv_ogm2_packet *)ogm_buff;
1056         ogm_packet->packet_type = BATADV_OGM2;
1057         ogm_packet->version = BATADV_COMPAT_VERSION;
1058         ogm_packet->ttl = BATADV_TTL;
1059         ogm_packet->flags = BATADV_NO_FLAGS;
1060         ogm_packet->throughput = htonl(BATADV_THROUGHPUT_MAX_VALUE);
1061 
1062         /* randomize initial seqno to avoid collision */
1063         get_random_bytes(&random_seqno, sizeof(random_seqno));
1064         atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
1065         INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
1066 
1067         mutex_init(&bat_priv->bat_v.ogm_buff_mutex);
1068 
1069         return 0;
1070 }
1071 
1072 /**
1073  * batadv_v_ogm_free() - free OGM private resources
1074  * @bat_priv: the bat priv with all the soft interface information
1075  */
1076 void batadv_v_ogm_free(struct batadv_priv *bat_priv)
1077 {
1078         cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
1079 
1080         mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
1081 
1082         kfree(bat_priv->bat_v.ogm_buff);
1083         bat_priv->bat_v.ogm_buff = NULL;
1084         bat_priv->bat_v.ogm_buff_len = 0;
1085 
1086         mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
1087 }
1088 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php