batman-adv: OGMv2 - add basic infrastructure
[deliverable/linux.git] / net / batman-adv / bat_v_ogm.c
1 /* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
2 *
3 * Antonio Quartulli
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public
7 * License as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "bat_v_ogm.h"
19 #include "main.h"
20
21 #include <linux/atomic.h>
22 #include <linux/byteorder/generic.h>
23 #include <linux/errno.h>
24 #include <linux/etherdevice.h>
25 #include <linux/fs.h>
26 #include <linux/if_ether.h>
27 #include <linux/jiffies.h>
28 #include <linux/kernel.h>
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>
39
40 #include "hard-interface.h"
41 #include "packet.h"
42 #include "routing.h"
43 #include "send.h"
44 #include "translation-table.h"
45
46 /**
47 * batadv_v_ogm_start_timer - restart the OGM sending timer
48 * @bat_priv: the bat priv with all the soft interface information
49 */
50 static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
51 {
52 unsigned long msecs;
53 /* this function may be invoked in different contexts (ogm rescheduling
54 * or hard_iface activation), but the work timer should not be reset
55 */
56 if (delayed_work_pending(&bat_priv->bat_v.ogm_wq))
57 return;
58
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));
63 }
64
65 /**
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
69 */
70 static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
71 struct batadv_hard_iface *hard_iface)
72 {
73 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
74
75 if (hard_iface->if_status != BATADV_IF_ACTIVE)
76 return;
77
78 batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
79 batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
80 skb->len + ETH_HLEN);
81
82 batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
83 }
84
85 /**
86 * batadv_v_ogm_send - periodic worker broadcasting the own OGM
87 * @work: work queue item
88 */
89 static void batadv_v_ogm_send(struct work_struct *work)
90 {
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;
97 int ogm_buff_len;
98 u16 tvlv_len = 0;
99
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);
102
103 if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
104 goto out;
105
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
110 */
111 batadv_tt_local_commit_changes(bat_priv);
112 tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
113 &ogm_buff_len,
114 BATADV_OGM2_HLEN);
115
116 bat_priv->bat_v.ogm_buff = ogm_buff;
117 bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
118
119 skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
120 if (!skb)
121 goto reschedule;
122
123 skb_reserve(skb, ETH_HLEN);
124 pkt_buff = skb_put(skb, ogm_buff_len);
125 memcpy(pkt_buff, ogm_buff, ogm_buff_len);
126
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);
131
132 /* broadcast on every interface */
133 rcu_read_lock();
134 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
135 if (hard_iface->soft_iface != bat_priv->soft_iface)
136 continue;
137
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);
144
145 /* this skb gets consumed by batadv_v_ogm_send_to_if() */
146 skb_tmp = skb_clone(skb, GFP_ATOMIC);
147 if (!skb_tmp)
148 break;
149
150 batadv_v_ogm_send_to_if(skb_tmp, hard_iface);
151 }
152 rcu_read_unlock();
153
154 consume_skb(skb);
155
156 reschedule:
157 batadv_v_ogm_start_timer(bat_priv);
158 out:
159 return;
160 }
161
162 /**
163 * batadv_v_ogm_iface_enable - prepare an interface for B.A.T.M.A.N. V
164 * @hard_iface: the interface to prepare
165 *
166 * Takes care of scheduling own OGM sending routine for this interface.
167 *
168 * Return: 0 on success or a negative error code otherwise
169 */
170 int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
171 {
172 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
173
174 batadv_v_ogm_start_timer(bat_priv);
175
176 return 0;
177 }
178
179 /**
180 * batadv_v_ogm_primary_iface_set - set a new primary interface
181 * @primary_iface: the new primary interface
182 */
183 void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface)
184 {
185 struct batadv_priv *bat_priv = netdev_priv(primary_iface->soft_iface);
186 struct batadv_ogm2_packet *ogm_packet;
187
188 if (!bat_priv->bat_v.ogm_buff)
189 return;
190
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);
193 }
194
195 /**
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
199 *
200 * Return: NET_RX_SUCCESS and consume the skb on success or returns NET_RX_DROP
201 * (without freeing the skb) on failure
202 */
203 int batadv_v_ogm_packet_recv(struct sk_buff *skb,
204 struct batadv_hard_iface *if_incoming)
205 {
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);
209
210 /* did we receive a OGM2 packet on an interface that does not have
211 * B.A.T.M.A.N. V enabled ?
212 */
213 if (strcmp(bat_priv->bat_algo_ops->name, "BATMAN_V") != 0)
214 return NET_RX_DROP;
215
216 if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
217 return NET_RX_DROP;
218
219 if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
220 return NET_RX_DROP;
221
222 ogm_packet = (struct batadv_ogm2_packet *)skb->data;
223
224 if (batadv_is_my_mac(bat_priv, ogm_packet->orig))
225 return NET_RX_DROP;
226
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);
230
231 consume_skb(skb);
232 return NET_RX_SUCCESS;
233 }
234
235 /**
236 * batadv_v_ogm_init - initialise the OGM2 engine
237 * @bat_priv: the bat priv with all the soft interface information
238 *
239 * Return: 0 on success or a negative error code in case of failure
240 */
241 int batadv_v_ogm_init(struct batadv_priv *bat_priv)
242 {
243 struct batadv_ogm2_packet *ogm_packet;
244 unsigned char *ogm_buff;
245 u32 random_seqno;
246
247 bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
248 ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
249 if (!ogm_buff)
250 return -ENOMEM;
251
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);
259
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);
264
265 return 0;
266 }
267
268 /**
269 * batadv_v_ogm_free - free OGM private resources
270 * @bat_priv: the bat priv with all the soft interface information
271 */
272 void batadv_v_ogm_free(struct batadv_priv *bat_priv)
273 {
274 cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
275
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;
279 }
This page took 0.037988 seconds and 6 git commands to generate.