1 /* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
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.
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.
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/>.
18 #include "bat_v_ogm.h"
21 #include <linux/atomic.h>
22 #include <linux/byteorder/generic.h>
23 #include <linux/errno.h>
24 #include <linux/etherdevice.h>
26 #include <linux/if_ether.h>
27 #include <linux/jiffies.h>
28 #include <linux/kernel.h>
29 #include <linux/netdevice.h>
30 #include <linux/random.h>
31 #include <linux/rculist.h>
32 #include <linux/rcupdate.h>
33 #include <linux/skbuff.h>
34 #include <linux/slab.h>
35 #include <linux/stddef.h>
36 #include <linux/string.h>
37 #include <linux/types.h>
38 #include <linux/workqueue.h>
40 #include "hard-interface.h"
44 #include "translation-table.h"
47 * batadv_v_ogm_start_timer - restart the OGM sending timer
48 * @bat_priv: the bat priv with all the soft interface information
50 static void batadv_v_ogm_start_timer(struct batadv_priv
*bat_priv
)
53 /* this function may be invoked in different contexts (ogm rescheduling
54 * or hard_iface activation), but the work timer should not be reset
56 if (delayed_work_pending(&bat_priv
->bat_v
.ogm_wq
))
59 msecs
= atomic_read(&bat_priv
->orig_interval
) - BATADV_JITTER
;
60 msecs
+= prandom_u32() % (2 * BATADV_JITTER
);
61 queue_delayed_work(batadv_event_workqueue
, &bat_priv
->bat_v
.ogm_wq
,
62 msecs_to_jiffies(msecs
));
66 * batadv_v_ogm_send_to_if - send a batman ogm using a given interface
67 * @skb: the OGM to send
68 * @hard_iface: the interface to use to send the OGM
70 static void batadv_v_ogm_send_to_if(struct sk_buff
*skb
,
71 struct batadv_hard_iface
*hard_iface
)
73 struct batadv_priv
*bat_priv
= netdev_priv(hard_iface
->soft_iface
);
75 if (hard_iface
->if_status
!= BATADV_IF_ACTIVE
)
78 batadv_inc_counter(bat_priv
, BATADV_CNT_MGMT_TX
);
79 batadv_add_counter(bat_priv
, BATADV_CNT_MGMT_TX_BYTES
,
82 batadv_send_skb_packet(skb
, hard_iface
, batadv_broadcast_addr
);
86 * batadv_v_ogm_send - periodic worker broadcasting the own OGM
87 * @work: work queue item
89 static void batadv_v_ogm_send(struct work_struct
*work
)
91 struct batadv_hard_iface
*hard_iface
;
92 struct batadv_priv_bat_v
*bat_v
;
93 struct batadv_priv
*bat_priv
;
94 struct batadv_ogm2_packet
*ogm_packet
;
95 struct sk_buff
*skb
, *skb_tmp
;
96 unsigned char *ogm_buff
, *pkt_buff
;
100 bat_v
= container_of(work
, struct batadv_priv_bat_v
, ogm_wq
.work
);
101 bat_priv
= container_of(bat_v
, struct batadv_priv
, bat_v
);
103 if (atomic_read(&bat_priv
->mesh_state
) == BATADV_MESH_DEACTIVATING
)
106 ogm_buff
= bat_priv
->bat_v
.ogm_buff
;
107 ogm_buff_len
= bat_priv
->bat_v
.ogm_buff_len
;
108 /* tt changes have to be committed before the tvlv data is
109 * appended as it may alter the tt tvlv container
111 batadv_tt_local_commit_changes(bat_priv
);
112 tvlv_len
= batadv_tvlv_container_ogm_append(bat_priv
, &ogm_buff
,
116 bat_priv
->bat_v
.ogm_buff
= ogm_buff
;
117 bat_priv
->bat_v
.ogm_buff_len
= ogm_buff_len
;
119 skb
= netdev_alloc_skb_ip_align(NULL
, ETH_HLEN
+ ogm_buff_len
);
123 skb_reserve(skb
, ETH_HLEN
);
124 pkt_buff
= skb_put(skb
, ogm_buff_len
);
125 memcpy(pkt_buff
, ogm_buff
, ogm_buff_len
);
127 ogm_packet
= (struct batadv_ogm2_packet
*)skb
->data
;
128 ogm_packet
->seqno
= htonl(atomic_read(&bat_priv
->bat_v
.ogm_seqno
));
129 atomic_inc(&bat_priv
->bat_v
.ogm_seqno
);
130 ogm_packet
->tvlv_len
= htons(tvlv_len
);
132 /* broadcast on every interface */
134 list_for_each_entry_rcu(hard_iface
, &batadv_hardif_list
, list
) {
135 if (hard_iface
->soft_iface
!= bat_priv
->soft_iface
)
138 batadv_dbg(BATADV_DBG_BATMAN
, bat_priv
,
139 "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
140 ogm_packet
->orig
, ntohl(ogm_packet
->seqno
),
141 ntohl(ogm_packet
->throughput
), ogm_packet
->ttl
,
142 hard_iface
->net_dev
->name
,
143 hard_iface
->net_dev
->dev_addr
);
145 /* this skb gets consumed by batadv_v_ogm_send_to_if() */
146 skb_tmp
= skb_clone(skb
, GFP_ATOMIC
);
150 batadv_v_ogm_send_to_if(skb_tmp
, hard_iface
);
157 batadv_v_ogm_start_timer(bat_priv
);
163 * batadv_v_ogm_iface_enable - prepare an interface for B.A.T.M.A.N. V
164 * @hard_iface: the interface to prepare
166 * Takes care of scheduling own OGM sending routine for this interface.
168 * Return: 0 on success or a negative error code otherwise
170 int batadv_v_ogm_iface_enable(struct batadv_hard_iface
*hard_iface
)
172 struct batadv_priv
*bat_priv
= netdev_priv(hard_iface
->soft_iface
);
174 batadv_v_ogm_start_timer(bat_priv
);
180 * batadv_v_ogm_primary_iface_set - set a new primary interface
181 * @primary_iface: the new primary interface
183 void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface
*primary_iface
)
185 struct batadv_priv
*bat_priv
= netdev_priv(primary_iface
->soft_iface
);
186 struct batadv_ogm2_packet
*ogm_packet
;
188 if (!bat_priv
->bat_v
.ogm_buff
)
191 ogm_packet
= (struct batadv_ogm2_packet
*)bat_priv
->bat_v
.ogm_buff
;
192 ether_addr_copy(ogm_packet
->orig
, primary_iface
->net_dev
->dev_addr
);
196 * batadv_v_ogm_packet_recv - OGM2 receiving handler
197 * @skb: the received OGM
198 * @if_incoming: the interface where this OGM has been received
200 * Return: NET_RX_SUCCESS and consume the skb on success or returns NET_RX_DROP
201 * (without freeing the skb) on failure
203 int batadv_v_ogm_packet_recv(struct sk_buff
*skb
,
204 struct batadv_hard_iface
*if_incoming
)
206 struct batadv_priv
*bat_priv
= netdev_priv(if_incoming
->soft_iface
);
207 struct batadv_ogm2_packet
*ogm_packet
;
208 struct ethhdr
*ethhdr
= eth_hdr(skb
);
210 /* did we receive a OGM2 packet on an interface that does not have
211 * B.A.T.M.A.N. V enabled ?
213 if (strcmp(bat_priv
->bat_algo_ops
->name
, "BATMAN_V") != 0)
216 if (!batadv_check_management_packet(skb
, if_incoming
, BATADV_OGM2_HLEN
))
219 if (batadv_is_my_mac(bat_priv
, ethhdr
->h_source
))
222 ogm_packet
= (struct batadv_ogm2_packet
*)skb
->data
;
224 if (batadv_is_my_mac(bat_priv
, ogm_packet
->orig
))
227 batadv_inc_counter(bat_priv
, BATADV_CNT_MGMT_RX
);
228 batadv_add_counter(bat_priv
, BATADV_CNT_MGMT_RX_BYTES
,
229 skb
->len
+ ETH_HLEN
);
232 return NET_RX_SUCCESS
;
236 * batadv_v_ogm_init - initialise the OGM2 engine
237 * @bat_priv: the bat priv with all the soft interface information
239 * Return: 0 on success or a negative error code in case of failure
241 int batadv_v_ogm_init(struct batadv_priv
*bat_priv
)
243 struct batadv_ogm2_packet
*ogm_packet
;
244 unsigned char *ogm_buff
;
247 bat_priv
->bat_v
.ogm_buff_len
= BATADV_OGM2_HLEN
;
248 ogm_buff
= kzalloc(bat_priv
->bat_v
.ogm_buff_len
, GFP_ATOMIC
);
252 bat_priv
->bat_v
.ogm_buff
= ogm_buff
;
253 ogm_packet
= (struct batadv_ogm2_packet
*)ogm_buff
;
254 ogm_packet
->packet_type
= BATADV_OGM2
;
255 ogm_packet
->version
= BATADV_COMPAT_VERSION
;
256 ogm_packet
->ttl
= BATADV_TTL
;
257 ogm_packet
->flags
= BATADV_NO_FLAGS
;
258 ogm_packet
->throughput
= htonl(BATADV_THROUGHPUT_MAX_VALUE
);
260 /* randomize initial seqno to avoid collision */
261 get_random_bytes(&random_seqno
, sizeof(random_seqno
));
262 atomic_set(&bat_priv
->bat_v
.ogm_seqno
, random_seqno
);
263 INIT_DELAYED_WORK(&bat_priv
->bat_v
.ogm_wq
, batadv_v_ogm_send
);
269 * batadv_v_ogm_free - free OGM private resources
270 * @bat_priv: the bat priv with all the soft interface information
272 void batadv_v_ogm_free(struct batadv_priv
*bat_priv
)
274 cancel_delayed_work_sync(&bat_priv
->bat_v
.ogm_wq
);
276 kfree(bat_priv
->bat_v
.ogm_buff
);
277 bat_priv
->bat_v
.ogm_buff
= NULL
;
278 bat_priv
->bat_v
.ogm_buff_len
= 0;