blob: bc6e046c614c65fa55ee4358a6ef18538023d957 [file] [log] [blame]
Linus Luessingd6f94d92016-01-16 16:40:09 +08001/* Copyright (C) 2011-2016 B.A.T.M.A.N. contributors:
2 *
3 * Linus Lüssing, Marek Lindner
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_elp.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/stddef.h>
35#include <linux/string.h>
36#include <linux/types.h>
37#include <linux/workqueue.h>
38
39#include "bat_algo.h"
40#include "hard-interface.h"
41#include "packet.h"
42#include "send.h"
43
44/**
45 * batadv_v_elp_start_timer - restart timer for ELP periodic work
46 * @hard_iface: the interface for which the timer has to be reset
47 */
48static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
49{
50 unsigned int msecs;
51
52 msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER;
53 msecs += prandom_u32() % (2 * BATADV_JITTER);
54
55 queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq,
56 msecs_to_jiffies(msecs));
57}
58
59/**
60 * batadv_v_elp_periodic_work - ELP periodic task per interface
61 * @work: work queue item
62 *
63 * Emits broadcast ELP message in regular intervals.
64 */
65static void batadv_v_elp_periodic_work(struct work_struct *work)
66{
67 struct batadv_hard_iface *hard_iface;
68 struct batadv_hard_iface_bat_v *bat_v;
69 struct batadv_elp_packet *elp_packet;
70 struct batadv_priv *bat_priv;
71 struct sk_buff *skb;
72 u32 elp_interval;
73
74 bat_v = container_of(work, struct batadv_hard_iface_bat_v, elp_wq.work);
75 hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v);
76 bat_priv = netdev_priv(hard_iface->soft_iface);
77
78 if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
79 goto out;
80
81 /* we are in the process of shutting this interface down */
82 if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) ||
83 (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED))
84 goto out;
85
86 /* the interface was enabled but may not be ready yet */
87 if (hard_iface->if_status != BATADV_IF_ACTIVE)
88 goto restart_timer;
89
90 skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
91 if (!skb)
92 goto restart_timer;
93
94 elp_packet = (struct batadv_elp_packet *)skb->data;
95 elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno));
96 elp_interval = atomic_read(&hard_iface->bat_v.elp_interval);
97 elp_packet->elp_interval = htonl(elp_interval);
98
99 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
100 "Sending broadcast ELP packet on interface %s, seqno %u\n",
101 hard_iface->net_dev->name,
102 atomic_read(&hard_iface->bat_v.elp_seqno));
103
104 batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
105
106 atomic_inc(&hard_iface->bat_v.elp_seqno);
107
108restart_timer:
109 batadv_v_elp_start_timer(hard_iface);
110out:
111 return;
112}
113
114/**
115 * batadv_v_elp_iface_enable - setup the ELP interface private resources
116 * @hard_iface: interface for which the data has to be prepared
117 *
118 * Return: 0 on success or a -ENOMEM in case of failure.
119 */
120int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
121{
122 struct batadv_elp_packet *elp_packet;
123 unsigned char *elp_buff;
124 u32 random_seqno;
125 size_t size;
126 int res = -ENOMEM;
127
128 size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN;
129 hard_iface->bat_v.elp_skb = dev_alloc_skb(size);
130 if (!hard_iface->bat_v.elp_skb)
131 goto out;
132
133 skb_reserve(hard_iface->bat_v.elp_skb, ETH_HLEN + NET_IP_ALIGN);
134 elp_buff = skb_push(hard_iface->bat_v.elp_skb, BATADV_ELP_HLEN);
135 elp_packet = (struct batadv_elp_packet *)elp_buff;
136 memset(elp_packet, 0, BATADV_ELP_HLEN);
137
138 elp_packet->packet_type = BATADV_ELP;
139 elp_packet->version = BATADV_COMPAT_VERSION;
140
141 /* randomize initial seqno to avoid collision */
142 get_random_bytes(&random_seqno, sizeof(random_seqno));
143 atomic_set(&hard_iface->bat_v.elp_seqno, random_seqno);
144 atomic_set(&hard_iface->bat_v.elp_interval, 500);
145
146 INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
147 batadv_v_elp_periodic_work);
148 batadv_v_elp_start_timer(hard_iface);
149 res = 0;
150
151out:
152 return res;
153}
154
155/**
156 * batadv_v_elp_iface_disable - release ELP interface private resources
157 * @hard_iface: interface for which the resources have to be released
158 */
159void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
160{
161 cancel_delayed_work_sync(&hard_iface->bat_v.elp_wq);
162
163 dev_kfree_skb(hard_iface->bat_v.elp_skb);
164 hard_iface->bat_v.elp_skb = NULL;
165}
166
167/**
168 * batadv_v_elp_primary_iface_set - change internal data to reflect the new
169 * primary interface
170 * @primary_iface: the new primary interface
171 */
172void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface)
173{
174 struct batadv_hard_iface *hard_iface;
175 struct batadv_elp_packet *elp_packet;
176 struct sk_buff *skb;
177
178 /* update orig field of every elp iface belonging to this mesh */
179 rcu_read_lock();
180 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
181 if (primary_iface->soft_iface != hard_iface->soft_iface)
182 continue;
183
184 if (!hard_iface->bat_v.elp_skb)
185 continue;
186
187 skb = hard_iface->bat_v.elp_skb;
188 elp_packet = (struct batadv_elp_packet *)skb->data;
189 ether_addr_copy(elp_packet->orig,
190 primary_iface->net_dev->dev_addr);
191 }
192 rcu_read_unlock();
193}