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, data: 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(kref: &orig_node->refcount); |
70 | hash_added = batadv_hash_add(hash: bat_priv->orig_hash, compare: batadv_compare_orig, |
71 | choose: batadv_choose_orig, data: orig_node, |
72 | data_node: &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(ceil: msecs / 5) - (msecs / 10); |
93 | queue_delayed_work(wq: batadv_event_workqueue, dwork: &hard_iface->bat_v.aggr_wq, |
94 | delay: msecs_to_jiffies(m: 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(v: &bat_priv->orig_interval) - BATADV_JITTER; |
111 | msecs += get_random_u32_below(ceil: 2 * BATADV_JITTER); |
112 | queue_delayed_work(wq: batadv_event_workqueue, dwork: &bat_priv->bat_v.ogm_wq, |
113 | delay: msecs_to_jiffies(m: 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(dev: 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, idx: BATADV_CNT_MGMT_TX_BYTES, |
133 | count: 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(list: &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(length: 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: skb_aggr, ETH_HLEN + NET_IP_ALIGN); |
220 | skb_reset_network_header(skb: skb_aggr); |
221 | |
222 | while ((skb = __skb_dequeue(list: &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: skb_aggr, data: skb->data, len: ogm_len); |
227 | |
228 | consume_skb(skb); |
229 | } |
230 | |
231 | batadv_v_ogm_send_to_if(skb: 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(dev: hard_iface->soft_iface); |
243 | |
244 | if (!atomic_read(v: &bat_priv->aggregated_ogms)) { |
245 | batadv_v_ogm_send_to_if(skb, hard_iface); |
246 | return; |
247 | } |
248 | |
249 | spin_lock_bh(lock: &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(list: &hard_iface->bat_v.aggr_list, newsk: skb); |
255 | spin_unlock_bh(lock: &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(v: &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, packet_buff: &ogm_buff, |
284 | packet_buff_len: &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, data: ogm_buff, len: 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(v: &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(kref: &hard_iface->refcount)) |
309 | continue; |
310 | |
311 | ret = batadv_hardif_no_broadcast(if_outgoing: 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: 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(lock: &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(lock: &hard_iface->bat_v.aggr_list.lock); |
395 | batadv_v_ogm_aggr_send(hard_iface); |
396 | spin_unlock_bh(lock: &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(dev: 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(dwork: &hard_iface->bat_v.aggr_wq); |
426 | |
427 | spin_lock_bh(lock: &hard_iface->bat_v.aggr_list.lock); |
428 | batadv_v_ogm_aggr_list_free(hard_iface); |
429 | spin_unlock_bh(lock: &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(dev: 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(dst: ogm_packet->orig, src: primary_iface->net_dev->dev_addr); |
447 | |
448 | unlock: |
449 | mutex_unlock(lock: &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(v: &if_incoming->hop_penalty); |
481 | int hop_penalty = atomic_read(v: &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: 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(dev: 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, data: ogm_received, len: 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, hard_iface: if_outgoing); |
586 | |
587 | out: |
588 | batadv_orig_ifinfo_put(orig_ifinfo); |
589 | batadv_neigh_node_put(neigh_node: 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(h: &orig_node->neigh_list) && |
628 | batadv_window_protected(bat_priv, seq_num_diff: seq_diff, |
629 | BATADV_OGM_MAX_AGE, |
630 | last_reset: &orig_ifinfo->batman_seqno_reset, |
631 | protection_started: &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: 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, addr: ethhdr->h_source); |
707 | if (!orig_neigh_node) |
708 | goto out; |
709 | |
710 | orig_neigh_router = batadv_orig_router_get(orig_node: 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(neigh: router, if_outgoing); |
743 | neigh_ifinfo = batadv_neigh_ifinfo_get(neigh: 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, recv_if: if_outgoing, neigh_node); |
761 | out: |
762 | batadv_neigh_node_put(neigh_node: router); |
763 | batadv_neigh_node_put(neigh_node: orig_neigh_router); |
764 | batadv_orig_node_put(orig_node: orig_neigh_node); |
765 | batadv_neigh_ifinfo_put(neigh_ifinfo: 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, packet_type: BATADV_OGM2, orig_node, |
805 | NULL, |
806 | tvlv_buff: (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, ogm_received: 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(dev: 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, addr: 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(hard_iface: if_incoming, neigh_addr: 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, addr: ogm_packet->orig); |
901 | if (!orig_node) |
902 | goto out; |
903 | |
904 | neigh_node = batadv_neigh_node_get_or_create(orig_node, hard_iface: if_incoming, |
905 | neigh_addr: 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(e: &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, ogm2: 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(kref: &hard_iface->refcount)) |
933 | continue; |
934 | |
935 | ret = batadv_hardif_no_broadcast(if_outgoing: hard_iface, |
936 | orig_addr: ogm_packet->orig, |
937 | orig_neigh: 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, ogm2: ogm_packet, |
965 | orig_node, neigh_node, |
966 | if_incoming, if_outgoing: 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(dev: 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, hard_iface: if_incoming, BATADV_OGM2_HLEN)) |
1002 | goto free_skb; |
1003 | |
1004 | ethhdr = eth_hdr(skb); |
1005 | if (batadv_is_my_mac(bat_priv, addr: ethhdr->h_source)) |
1006 | goto free_skb; |
1007 | |
1008 | batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX); |
1009 | batadv_add_counter(bat_priv, idx: BATADV_CNT_MGMT_RX_BYTES, |
1010 | count: 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(buff_pos: ogm_offset, packet_len: skb_headlen(skb), |
1016 | ogm2_packet: 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(size: 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(buf: &random_seqno, len: sizeof(random_seqno)); |
1064 | atomic_set(v: &bat_priv->bat_v.ogm_seqno, i: 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(dwork: &bat_priv->bat_v.ogm_wq); |
1079 | |
1080 | mutex_lock(&bat_priv->bat_v.ogm_buff_mutex); |
1081 | |
1082 | kfree(objp: 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(lock: &bat_priv->bat_v.ogm_buff_mutex); |
1087 | } |
1088 | |