Blame view

net/batman-adv/hard-interface.c 16.5 KB
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1
  /*
64afe3539   Sven Eckelmann   batman-adv: Updat...
2
   * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   *
   * Marek Lindner, Simon Wunderlich
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   * 02110-1301, USA
   *
   */
  
  #include "main.h"
  #include "hard-interface.h"
  #include "soft-interface.h"
  #include "send.h"
  #include "translation-table.h"
  #include "routing.h"
  #include "bat_sysfs.h"
  #include "originator.h"
  #include "hash.h"
d0b9fd89c   Marek Lindner   batman-adv: move ...
31
  #include "bat_ogm.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
32
33
  
  #include <linux/if_arp.h>
fb86d7648   Sven Eckelmann   batman-adv: Remov...
34
35
36
37
38
  
  static int batman_skb_recv(struct sk_buff *skb,
  			   struct net_device *dev,
  			   struct packet_type *ptype,
  			   struct net_device *orig_dev);
ed75ccbe2   Marek Lindner   batman-adv: Corre...
39
  void hardif_free_rcu(struct rcu_head *rcu)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
40
  {
e6c10f433   Marek Lindner   batman-adv: renam...
41
  	struct hard_iface *hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
42

e6c10f433   Marek Lindner   batman-adv: renam...
43
44
45
  	hard_iface = container_of(rcu, struct hard_iface, rcu);
  	dev_put(hard_iface->net_dev);
  	kfree(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
46
  }
747e4221a   Sven Eckelmann   batman-adv: Add c...
47
  struct hard_iface *hardif_get_by_netdev(const struct net_device *net_dev)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
48
  {
e6c10f433   Marek Lindner   batman-adv: renam...
49
  	struct hard_iface *hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
50
51
  
  	rcu_read_lock();
e6c10f433   Marek Lindner   batman-adv: renam...
52
53
54
  	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
  		if (hard_iface->net_dev == net_dev &&
  		    atomic_inc_not_zero(&hard_iface->refcount))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
55
56
  			goto out;
  	}
e6c10f433   Marek Lindner   batman-adv: renam...
57
  	hard_iface = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
58
59
  
  out:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
60
  	rcu_read_unlock();
e6c10f433   Marek Lindner   batman-adv: renam...
61
  	return hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
62
  }
747e4221a   Sven Eckelmann   batman-adv: Add c...
63
  static int is_valid_iface(const struct net_device *net_dev)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
64
65
66
67
68
69
70
71
72
73
74
  {
  	if (net_dev->flags & IFF_LOOPBACK)
  		return 0;
  
  	if (net_dev->type != ARPHRD_ETHER)
  		return 0;
  
  	if (net_dev->addr_len != ETH_ALEN)
  		return 0;
  
  	/* no batman over batman */
e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
75
  	if (softif_is_valid(net_dev))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
76
  		return 0;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
77
78
79
80
81
82
83
  
  	/* Device is being bridged */
  	/* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
  		return 0; */
  
  	return 1;
  }
747e4221a   Sven Eckelmann   batman-adv: Add c...
84
  static struct hard_iface *hardif_get_active(const struct net_device *soft_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
85
  {
e6c10f433   Marek Lindner   batman-adv: renam...
86
  	struct hard_iface *hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
87
88
  
  	rcu_read_lock();
e6c10f433   Marek Lindner   batman-adv: renam...
89
90
  	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
  		if (hard_iface->soft_iface != soft_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
91
  			continue;
e6c10f433   Marek Lindner   batman-adv: renam...
92
93
  		if (hard_iface->if_status == IF_ACTIVE &&
  		    atomic_inc_not_zero(&hard_iface->refcount))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
94
95
  			goto out;
  	}
e6c10f433   Marek Lindner   batman-adv: renam...
96
  	hard_iface = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
97
98
  
  out:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
99
  	rcu_read_unlock();
e6c10f433   Marek Lindner   batman-adv: renam...
100
  	return hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
101
  }
32ae9b221   Marek Lindner   batman-adv: Make ...
102
  static void primary_if_update_addr(struct bat_priv *bat_priv)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
103
104
  {
  	struct vis_packet *vis_packet;
32ae9b221   Marek Lindner   batman-adv: Make ...
105
106
107
108
109
  	struct hard_iface *primary_if;
  
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
110
111
112
  
  	vis_packet = (struct vis_packet *)
  				bat_priv->my_vis_info->skb_packet->data;
32ae9b221   Marek Lindner   batman-adv: Make ...
113
  	memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
114
  	memcpy(vis_packet->sender_orig,
32ae9b221   Marek Lindner   batman-adv: Make ...
115
116
117
118
119
  	       primary_if->net_dev->dev_addr, ETH_ALEN);
  
  out:
  	if (primary_if)
  		hardif_free_ref(primary_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
120
  }
32ae9b221   Marek Lindner   batman-adv: Make ...
121
122
  static void primary_if_select(struct bat_priv *bat_priv,
  			      struct hard_iface *new_hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
123
  {
32ae9b221   Marek Lindner   batman-adv: Make ...
124
  	struct hard_iface *curr_hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
125

c3caf5196   Sven Eckelmann   batman-adv: Remov...
126
  	ASSERT_RTNL();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
127

32ae9b221   Marek Lindner   batman-adv: Make ...
128
129
  	if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
  		new_hard_iface = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
130

728cbc6ac   Sven Eckelmann   batman-adv: Use r...
131
  	curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
32ae9b221   Marek Lindner   batman-adv: Make ...
132
  	rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
133

32ae9b221   Marek Lindner   batman-adv: Make ...
134
135
  	if (curr_hard_iface)
  		hardif_free_ref(curr_hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
136

32ae9b221   Marek Lindner   batman-adv: Make ...
137
  	if (!new_hard_iface)
c3caf5196   Sven Eckelmann   batman-adv: Remov...
138
  		return;
32ae9b221   Marek Lindner   batman-adv: Make ...
139

d0b9fd89c   Marek Lindner   batman-adv: move ...
140
  	bat_ogm_init_primary(new_hard_iface);
32ae9b221   Marek Lindner   batman-adv: Make ...
141
  	primary_if_update_addr(bat_priv);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
142
  }
747e4221a   Sven Eckelmann   batman-adv: Add c...
143
  static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
144
  {
e6c10f433   Marek Lindner   batman-adv: renam...
145
  	if (hard_iface->net_dev->flags & IFF_UP)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
146
147
148
149
  		return true;
  
  	return false;
  }
747e4221a   Sven Eckelmann   batman-adv: Add c...
150
  static void check_known_mac_addr(const struct net_device *net_dev)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
151
  {
747e4221a   Sven Eckelmann   batman-adv: Add c...
152
  	const struct hard_iface *hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
153
154
  
  	rcu_read_lock();
e6c10f433   Marek Lindner   batman-adv: renam...
155
156
157
  	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
  		if ((hard_iface->if_status != IF_ACTIVE) &&
  		    (hard_iface->if_status != IF_TO_BE_ACTIVATED))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
158
  			continue;
e6c10f433   Marek Lindner   batman-adv: renam...
159
  		if (hard_iface->net_dev == net_dev)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
160
  			continue;
e6c10f433   Marek Lindner   batman-adv: renam...
161
162
  		if (!compare_eth(hard_iface->net_dev->dev_addr,
  				 net_dev->dev_addr))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
163
164
165
166
167
  			continue;
  
  		pr_warning("The newly added mac address (%pM) already exists "
  			   "on: %s
  ", net_dev->dev_addr,
e6c10f433   Marek Lindner   batman-adv: renam...
168
  			   hard_iface->net_dev->name);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
169
170
171
172
173
174
175
176
177
  		pr_warning("It is strongly recommended to keep mac addresses "
  			   "unique to avoid problems!
  ");
  	}
  	rcu_read_unlock();
  }
  
  int hardif_min_mtu(struct net_device *soft_iface)
  {
747e4221a   Sven Eckelmann   batman-adv: Add c...
178
179
  	const struct bat_priv *bat_priv = netdev_priv(soft_iface);
  	const struct hard_iface *hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
180
181
182
183
184
185
186
187
  	/* allow big frames if all devices are capable to do so
  	 * (have MTU > 1500 + BAT_HEADER_LEN) */
  	int min_mtu = ETH_DATA_LEN;
  
  	if (atomic_read(&bat_priv->fragmentation))
  		goto out;
  
  	rcu_read_lock();
e6c10f433   Marek Lindner   batman-adv: renam...
188
189
190
  	list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
  		if ((hard_iface->if_status != IF_ACTIVE) &&
  		    (hard_iface->if_status != IF_TO_BE_ACTIVATED))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
191
  			continue;
e6c10f433   Marek Lindner   batman-adv: renam...
192
  		if (hard_iface->soft_iface != soft_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
193
  			continue;
e6c10f433   Marek Lindner   batman-adv: renam...
194
  		min_mtu = min_t(int, hard_iface->net_dev->mtu - BAT_HEADER_LEN,
c6c8fea29   Sven Eckelmann   net: Add batman-a...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  				min_mtu);
  	}
  	rcu_read_unlock();
  out:
  	return min_mtu;
  }
  
  /* adjusts the MTU if a new interface with a smaller MTU appeared. */
  void update_min_mtu(struct net_device *soft_iface)
  {
  	int min_mtu;
  
  	min_mtu = hardif_min_mtu(soft_iface);
  	if (soft_iface->mtu != min_mtu)
  		soft_iface->mtu = min_mtu;
  }
e6c10f433   Marek Lindner   batman-adv: renam...
211
  static void hardif_activate_interface(struct hard_iface *hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
212
213
  {
  	struct bat_priv *bat_priv;
32ae9b221   Marek Lindner   batman-adv: Make ...
214
  	struct hard_iface *primary_if = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
215

e6c10f433   Marek Lindner   batman-adv: renam...
216
  	if (hard_iface->if_status != IF_INACTIVE)
32ae9b221   Marek Lindner   batman-adv: Make ...
217
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
218

e6c10f433   Marek Lindner   batman-adv: renam...
219
  	bat_priv = netdev_priv(hard_iface->soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
220

d0b9fd89c   Marek Lindner   batman-adv: move ...
221
  	bat_ogm_update_mac(hard_iface);
e6c10f433   Marek Lindner   batman-adv: renam...
222
  	hard_iface->if_status = IF_TO_BE_ACTIVATED;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
223
224
225
  
  	/**
  	 * the first active interface becomes our primary interface or
015758d00   Antonio Quartulli   batman-adv: corre...
226
  	 * the next active interface after the old primary interface was removed
c6c8fea29   Sven Eckelmann   net: Add batman-a...
227
  	 */
32ae9b221   Marek Lindner   batman-adv: Make ...
228
229
230
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		primary_if_select(bat_priv, hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
231

e6c10f433   Marek Lindner   batman-adv: renam...
232
233
234
  	bat_info(hard_iface->soft_iface, "Interface activated: %s
  ",
  		 hard_iface->net_dev->name);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
235

e6c10f433   Marek Lindner   batman-adv: renam...
236
  	update_min_mtu(hard_iface->soft_iface);
32ae9b221   Marek Lindner   batman-adv: Make ...
237
238
239
240
  
  out:
  	if (primary_if)
  		hardif_free_ref(primary_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
241
  }
e6c10f433   Marek Lindner   batman-adv: renam...
242
  static void hardif_deactivate_interface(struct hard_iface *hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
243
  {
e6c10f433   Marek Lindner   batman-adv: renam...
244
245
  	if ((hard_iface->if_status != IF_ACTIVE) &&
  	    (hard_iface->if_status != IF_TO_BE_ACTIVATED))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
246
  		return;
e6c10f433   Marek Lindner   batman-adv: renam...
247
  	hard_iface->if_status = IF_INACTIVE;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
248

e6c10f433   Marek Lindner   batman-adv: renam...
249
250
251
  	bat_info(hard_iface->soft_iface, "Interface deactivated: %s
  ",
  		 hard_iface->net_dev->name);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
252

e6c10f433   Marek Lindner   batman-adv: renam...
253
  	update_min_mtu(hard_iface->soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
254
  }
747e4221a   Sven Eckelmann   batman-adv: Add c...
255
256
  int hardif_enable_interface(struct hard_iface *hard_iface,
  			    const char *iface_name)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
257
258
  {
  	struct bat_priv *bat_priv;
e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
259
260
  	struct net_device *soft_iface;
  	int ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
261

e6c10f433   Marek Lindner   batman-adv: renam...
262
  	if (hard_iface->if_status != IF_NOT_IN_USE)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
263
  		goto out;
e6c10f433   Marek Lindner   batman-adv: renam...
264
  	if (!atomic_inc_not_zero(&hard_iface->refcount))
ed75ccbe2   Marek Lindner   batman-adv: Corre...
265
  		goto out;
e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
266
  	soft_iface = dev_get_by_name(&init_net, iface_name);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
267

e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
268
269
  	if (!soft_iface) {
  		soft_iface = softif_create(iface_name);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
270

e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
271
272
  		if (!soft_iface) {
  			ret = -ENOMEM;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
273
  			goto err;
e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
274
  		}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
275
276
  
  		/* dev_get_by_name() increases the reference counter for us */
e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
277
278
279
280
281
282
283
284
285
286
287
  		dev_hold(soft_iface);
  	}
  
  	if (!softif_is_valid(soft_iface)) {
  		pr_err("Can't create batman mesh interface %s: "
  		       "already exists as regular interface
  ",
  		       soft_iface->name);
  		dev_put(soft_iface);
  		ret = -EINVAL;
  		goto err;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
288
  	}
e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
289
  	hard_iface->soft_iface = soft_iface;
e6c10f433   Marek Lindner   batman-adv: renam...
290
  	bat_priv = netdev_priv(hard_iface->soft_iface);
d0b9fd89c   Marek Lindner   batman-adv: move ...
291
292
  
  	bat_ogm_init(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
293

e6c10f433   Marek Lindner   batman-adv: renam...
294
295
296
297
  	if (!hard_iface->packet_buff) {
  		bat_err(hard_iface->soft_iface, "Can't add interface packet "
  			"(%s): out of memory
  ", hard_iface->net_dev->name);
e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
298
  		ret = -ENOMEM;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
299
300
  		goto err;
  	}
e6c10f433   Marek Lindner   batman-adv: renam...
301
  	hard_iface->if_num = bat_priv->num_ifaces;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
302
  	bat_priv->num_ifaces++;
e6c10f433   Marek Lindner   batman-adv: renam...
303
304
  	hard_iface->if_status = IF_INACTIVE;
  	orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
305

e6c10f433   Marek Lindner   batman-adv: renam...
306
307
308
309
  	hard_iface->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN);
  	hard_iface->batman_adv_ptype.func = batman_skb_recv;
  	hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
  	dev_add_pack(&hard_iface->batman_adv_ptype);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
310

e6c10f433   Marek Lindner   batman-adv: renam...
311
312
313
314
315
  	atomic_set(&hard_iface->seqno, 1);
  	atomic_set(&hard_iface->frag_seqno, 1);
  	bat_info(hard_iface->soft_iface, "Adding interface: %s
  ",
  		 hard_iface->net_dev->name);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
316

e6c10f433   Marek Lindner   batman-adv: renam...
317
  	if (atomic_read(&bat_priv->fragmentation) && hard_iface->net_dev->mtu <
c6c8fea29   Sven Eckelmann   net: Add batman-a...
318
  		ETH_DATA_LEN + BAT_HEADER_LEN)
e6c10f433   Marek Lindner   batman-adv: renam...
319
  		bat_info(hard_iface->soft_iface,
c6c8fea29   Sven Eckelmann   net: Add batman-a...
320
321
322
323
324
325
  			"The MTU of interface %s is too small (%i) to handle "
  			"the transport of batman-adv packets. Packets going "
  			"over this interface will be fragmented on layer2 "
  			"which could impact the performance. Setting the MTU "
  			"to %zi would solve the problem.
  ",
e6c10f433   Marek Lindner   batman-adv: renam...
326
  			hard_iface->net_dev->name, hard_iface->net_dev->mtu,
c6c8fea29   Sven Eckelmann   net: Add batman-a...
327
  			ETH_DATA_LEN + BAT_HEADER_LEN);
e6c10f433   Marek Lindner   batman-adv: renam...
328
  	if (!atomic_read(&bat_priv->fragmentation) && hard_iface->net_dev->mtu <
c6c8fea29   Sven Eckelmann   net: Add batman-a...
329
  		ETH_DATA_LEN + BAT_HEADER_LEN)
e6c10f433   Marek Lindner   batman-adv: renam...
330
  		bat_info(hard_iface->soft_iface,
c6c8fea29   Sven Eckelmann   net: Add batman-a...
331
332
333
334
335
  			"The MTU of interface %s is too small (%i) to handle "
  			"the transport of batman-adv packets. If you experience"
  			" problems getting traffic through try increasing the "
  			"MTU to %zi.
  ",
e6c10f433   Marek Lindner   batman-adv: renam...
336
  			hard_iface->net_dev->name, hard_iface->net_dev->mtu,
c6c8fea29   Sven Eckelmann   net: Add batman-a...
337
  			ETH_DATA_LEN + BAT_HEADER_LEN);
e6c10f433   Marek Lindner   batman-adv: renam...
338
339
  	if (hardif_is_iface_up(hard_iface))
  		hardif_activate_interface(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
340
  	else
e6c10f433   Marek Lindner   batman-adv: renam...
341
  		bat_err(hard_iface->soft_iface, "Not using interface %s "
c6c8fea29   Sven Eckelmann   net: Add batman-a...
342
343
  			"(retrying later): interface not active
  ",
e6c10f433   Marek Lindner   batman-adv: renam...
344
  			hard_iface->net_dev->name);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
345
346
  
  	/* begin scheduling originator messages on that interface */
b9dacc521   Marek Lindner   batman-adv: agglo...
347
  	schedule_bat_ogm(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
348
349
350
351
352
  
  out:
  	return 0;
  
  err:
e6c10f433   Marek Lindner   batman-adv: renam...
353
  	hardif_free_ref(hard_iface);
e44d8fe2b   Sven Eckelmann   batman-adv: Disal...
354
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
355
  }
e6c10f433   Marek Lindner   batman-adv: renam...
356
  void hardif_disable_interface(struct hard_iface *hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
357
  {
e6c10f433   Marek Lindner   batman-adv: renam...
358
  	struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
32ae9b221   Marek Lindner   batman-adv: Make ...
359
  	struct hard_iface *primary_if = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
360

e6c10f433   Marek Lindner   batman-adv: renam...
361
362
  	if (hard_iface->if_status == IF_ACTIVE)
  		hardif_deactivate_interface(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
363

e6c10f433   Marek Lindner   batman-adv: renam...
364
  	if (hard_iface->if_status != IF_INACTIVE)
32ae9b221   Marek Lindner   batman-adv: Make ...
365
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
366

e6c10f433   Marek Lindner   batman-adv: renam...
367
368
369
370
  	bat_info(hard_iface->soft_iface, "Removing interface: %s
  ",
  		 hard_iface->net_dev->name);
  	dev_remove_pack(&hard_iface->batman_adv_ptype);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
371
372
  
  	bat_priv->num_ifaces--;
e6c10f433   Marek Lindner   batman-adv: renam...
373
  	orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
374

32ae9b221   Marek Lindner   batman-adv: Make ...
375
376
  	primary_if = primary_if_get_selected(bat_priv);
  	if (hard_iface == primary_if) {
e6c10f433   Marek Lindner   batman-adv: renam...
377
  		struct hard_iface *new_if;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
378

e6c10f433   Marek Lindner   batman-adv: renam...
379
  		new_if = hardif_get_active(hard_iface->soft_iface);
32ae9b221   Marek Lindner   batman-adv: Make ...
380
  		primary_if_select(bat_priv, new_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
381
382
  
  		if (new_if)
ed75ccbe2   Marek Lindner   batman-adv: Corre...
383
  			hardif_free_ref(new_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
384
  	}
e6c10f433   Marek Lindner   batman-adv: renam...
385
386
387
  	kfree(hard_iface->packet_buff);
  	hard_iface->packet_buff = NULL;
  	hard_iface->if_status = IF_NOT_IN_USE;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
388

e6c10f433   Marek Lindner   batman-adv: renam...
389
  	/* delete all references to this hard_iface */
c6c8fea29   Sven Eckelmann   net: Add batman-a...
390
  	purge_orig_ref(bat_priv);
e6c10f433   Marek Lindner   batman-adv: renam...
391
392
  	purge_outstanding_packets(bat_priv, hard_iface);
  	dev_put(hard_iface->soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
393
394
395
  
  	/* nobody uses this interface anymore */
  	if (!bat_priv->num_ifaces)
e6c10f433   Marek Lindner   batman-adv: renam...
396
  		softif_destroy(hard_iface->soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
397

e6c10f433   Marek Lindner   batman-adv: renam...
398
399
  	hard_iface->soft_iface = NULL;
  	hardif_free_ref(hard_iface);
32ae9b221   Marek Lindner   batman-adv: Make ...
400
401
402
403
  
  out:
  	if (primary_if)
  		hardif_free_ref(primary_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
404
  }
e6c10f433   Marek Lindner   batman-adv: renam...
405
  static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
406
  {
e6c10f433   Marek Lindner   batman-adv: renam...
407
  	struct hard_iface *hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
408
  	int ret;
c3caf5196   Sven Eckelmann   batman-adv: Remov...
409
  	ASSERT_RTNL();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
410
411
412
413
414
  	ret = is_valid_iface(net_dev);
  	if (ret != 1)
  		goto out;
  
  	dev_hold(net_dev);
704509b8d   Sven Eckelmann   batman-adv: Calcu...
415
  	hard_iface = kmalloc(sizeof(*hard_iface), GFP_ATOMIC);
320f422f6   Joe Perches   batman-adv: Remov...
416
  	if (!hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
417
  		goto release_dev;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
418

e6c10f433   Marek Lindner   batman-adv: renam...
419
  	ret = sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
420
421
  	if (ret)
  		goto free_if;
e6c10f433   Marek Lindner   batman-adv: renam...
422
423
424
425
426
  	hard_iface->if_num = -1;
  	hard_iface->net_dev = net_dev;
  	hard_iface->soft_iface = NULL;
  	hard_iface->if_status = IF_NOT_IN_USE;
  	INIT_LIST_HEAD(&hard_iface->list);
ed75ccbe2   Marek Lindner   batman-adv: Corre...
427
  	/* extra reference for return */
e6c10f433   Marek Lindner   batman-adv: renam...
428
  	atomic_set(&hard_iface->refcount, 2);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
429

e6c10f433   Marek Lindner   batman-adv: renam...
430
  	check_known_mac_addr(hard_iface->net_dev);
e6c10f433   Marek Lindner   batman-adv: renam...
431
  	list_add_tail_rcu(&hard_iface->list, &hardif_list);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
432

e6c10f433   Marek Lindner   batman-adv: renam...
433
  	return hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
434
435
  
  free_if:
e6c10f433   Marek Lindner   batman-adv: renam...
436
  	kfree(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
437
438
439
440
441
  release_dev:
  	dev_put(net_dev);
  out:
  	return NULL;
  }
e6c10f433   Marek Lindner   batman-adv: renam...
442
  static void hardif_remove_interface(struct hard_iface *hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
443
  {
c3caf5196   Sven Eckelmann   batman-adv: Remov...
444
  	ASSERT_RTNL();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
445
  	/* first deactivate interface */
e6c10f433   Marek Lindner   batman-adv: renam...
446
447
  	if (hard_iface->if_status != IF_NOT_IN_USE)
  		hardif_disable_interface(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
448

e6c10f433   Marek Lindner   batman-adv: renam...
449
  	if (hard_iface->if_status != IF_NOT_IN_USE)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
450
  		return;
e6c10f433   Marek Lindner   batman-adv: renam...
451
452
453
  	hard_iface->if_status = IF_TO_BE_REMOVED;
  	sysfs_del_hardif(&hard_iface->hardif_obj);
  	hardif_free_ref(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
454
455
456
457
  }
  
  void hardif_remove_interfaces(void)
  {
e6c10f433   Marek Lindner   batman-adv: renam...
458
  	struct hard_iface *hard_iface, *hard_iface_tmp;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
459

c3caf5196   Sven Eckelmann   batman-adv: Remov...
460
  	rtnl_lock();
e6c10f433   Marek Lindner   batman-adv: renam...
461
462
463
  	list_for_each_entry_safe(hard_iface, hard_iface_tmp,
  				 &hardif_list, list) {
  		list_del_rcu(&hard_iface->list);
e6c10f433   Marek Lindner   batman-adv: renam...
464
  		hardif_remove_interface(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
465
466
467
468
469
470
471
  	}
  	rtnl_unlock();
  }
  
  static int hard_if_event(struct notifier_block *this,
  			 unsigned long event, void *ptr)
  {
5f718c200   Sven Eckelmann   batman-adv: Remov...
472
  	struct net_device *net_dev = ptr;
e6c10f433   Marek Lindner   batman-adv: renam...
473
  	struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
32ae9b221   Marek Lindner   batman-adv: Make ...
474
  	struct hard_iface *primary_if = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
475
  	struct bat_priv *bat_priv;
e6c10f433   Marek Lindner   batman-adv: renam...
476
477
  	if (!hard_iface && event == NETDEV_REGISTER)
  		hard_iface = hardif_add_interface(net_dev);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
478

e6c10f433   Marek Lindner   batman-adv: renam...
479
  	if (!hard_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
480
481
482
483
  		goto out;
  
  	switch (event) {
  	case NETDEV_UP:
e6c10f433   Marek Lindner   batman-adv: renam...
484
  		hardif_activate_interface(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
485
486
487
  		break;
  	case NETDEV_GOING_DOWN:
  	case NETDEV_DOWN:
e6c10f433   Marek Lindner   batman-adv: renam...
488
  		hardif_deactivate_interface(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
489
490
  		break;
  	case NETDEV_UNREGISTER:
e6c10f433   Marek Lindner   batman-adv: renam...
491
  		list_del_rcu(&hard_iface->list);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
492

e6c10f433   Marek Lindner   batman-adv: renam...
493
  		hardif_remove_interface(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
494
495
  		break;
  	case NETDEV_CHANGEMTU:
e6c10f433   Marek Lindner   batman-adv: renam...
496
497
  		if (hard_iface->soft_iface)
  			update_min_mtu(hard_iface->soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
498
499
  		break;
  	case NETDEV_CHANGEADDR:
e6c10f433   Marek Lindner   batman-adv: renam...
500
  		if (hard_iface->if_status == IF_NOT_IN_USE)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
501
  			goto hardif_put;
e6c10f433   Marek Lindner   batman-adv: renam...
502
  		check_known_mac_addr(hard_iface->net_dev);
d0b9fd89c   Marek Lindner   batman-adv: move ...
503
  		bat_ogm_update_mac(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
504

e6c10f433   Marek Lindner   batman-adv: renam...
505
  		bat_priv = netdev_priv(hard_iface->soft_iface);
32ae9b221   Marek Lindner   batman-adv: Make ...
506
507
508
509
510
511
  		primary_if = primary_if_get_selected(bat_priv);
  		if (!primary_if)
  			goto hardif_put;
  
  		if (hard_iface == primary_if)
  			primary_if_update_addr(bat_priv);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
512
513
514
  		break;
  	default:
  		break;
f81c62242   Joe Perches   net: Remove unnec...
515
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
516
517
  
  hardif_put:
e6c10f433   Marek Lindner   batman-adv: renam...
518
  	hardif_free_ref(hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
519
  out:
32ae9b221   Marek Lindner   batman-adv: Make ...
520
521
  	if (primary_if)
  		hardif_free_ref(primary_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
522
523
  	return NOTIFY_DONE;
  }
015758d00   Antonio Quartulli   batman-adv: corre...
524
  /* incoming packets with the batman ethertype received on any active hard
c6c8fea29   Sven Eckelmann   net: Add batman-a...
525
   * interface */
fb86d7648   Sven Eckelmann   batman-adv: Remov...
526
527
528
  static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
  			   struct packet_type *ptype,
  			   struct net_device *orig_dev)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
529
530
  {
  	struct bat_priv *bat_priv;
b6da4bf5d   Marek Lindner   batman-adv: renam...
531
  	struct batman_ogm_packet *batman_ogm_packet;
e6c10f433   Marek Lindner   batman-adv: renam...
532
  	struct hard_iface *hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
533
  	int ret;
e6c10f433   Marek Lindner   batman-adv: renam...
534
  	hard_iface = container_of(ptype, struct hard_iface, batman_adv_ptype);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
  	skb = skb_share_check(skb, GFP_ATOMIC);
  
  	/* skb was released by skb_share_check() */
  	if (!skb)
  		goto err_out;
  
  	/* packet should hold at least type and version */
  	if (unlikely(!pskb_may_pull(skb, 2)))
  		goto err_free;
  
  	/* expect a valid ethernet header here. */
  	if (unlikely(skb->mac_len != sizeof(struct ethhdr)
  				|| !skb_mac_header(skb)))
  		goto err_free;
e6c10f433   Marek Lindner   batman-adv: renam...
549
  	if (!hard_iface->soft_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
550
  		goto err_free;
e6c10f433   Marek Lindner   batman-adv: renam...
551
  	bat_priv = netdev_priv(hard_iface->soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
552
553
554
555
556
  
  	if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
  		goto err_free;
  
  	/* discard frames on not active interfaces */
e6c10f433   Marek Lindner   batman-adv: renam...
557
  	if (hard_iface->if_status != IF_ACTIVE)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
558
  		goto err_free;
b6da4bf5d   Marek Lindner   batman-adv: renam...
559
  	batman_ogm_packet = (struct batman_ogm_packet *)skb->data;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
560

b6da4bf5d   Marek Lindner   batman-adv: renam...
561
  	if (batman_ogm_packet->version != COMPAT_VERSION) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
562
563
564
  		bat_dbg(DBG_BATMAN, bat_priv,
  			"Drop packet: incompatible batman version (%i)
  ",
b6da4bf5d   Marek Lindner   batman-adv: renam...
565
  			batman_ogm_packet->version);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
566
567
568
569
570
  		goto err_free;
  	}
  
  	/* all receive handlers return whether they received or reused
  	 * the supplied skb. if not, we have to free the skb. */
b6da4bf5d   Marek Lindner   batman-adv: renam...
571
  	switch (batman_ogm_packet->packet_type) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
572
  		/* batman originator packet */
b6da4bf5d   Marek Lindner   batman-adv: renam...
573
  	case BAT_OGM:
fc9572756   Marek Lindner   batman-adv: agglo...
574
  		ret = recv_bat_ogm_packet(skb, hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
575
576
577
578
  		break;
  
  		/* batman icmp packet */
  	case BAT_ICMP:
e6c10f433   Marek Lindner   batman-adv: renam...
579
  		ret = recv_icmp_packet(skb, hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
580
581
582
583
  		break;
  
  		/* unicast packet */
  	case BAT_UNICAST:
e6c10f433   Marek Lindner   batman-adv: renam...
584
  		ret = recv_unicast_packet(skb, hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
585
586
587
588
  		break;
  
  		/* fragmented unicast packet */
  	case BAT_UNICAST_FRAG:
e6c10f433   Marek Lindner   batman-adv: renam...
589
  		ret = recv_ucast_frag_packet(skb, hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
590
591
592
593
  		break;
  
  		/* broadcast packet */
  	case BAT_BCAST:
e6c10f433   Marek Lindner   batman-adv: renam...
594
  		ret = recv_bcast_packet(skb, hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
595
596
597
598
  		break;
  
  		/* vis packet */
  	case BAT_VIS:
e6c10f433   Marek Lindner   batman-adv: renam...
599
  		ret = recv_vis_packet(skb, hard_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
600
  		break;
a73105b8d   Antonio Quartulli   batman-adv: impro...
601
602
603
604
  		/* Translation table query (request or response) */
  	case BAT_TT_QUERY:
  		ret = recv_tt_query(skb, hard_iface);
  		break;
cc47f66e6   Antonio Quartulli   batman-adv: impro...
605
606
607
608
  		/* Roaming advertisement */
  	case BAT_ROAM_ADV:
  		ret = recv_roam_adv(skb, hard_iface);
  		break;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  	default:
  		ret = NET_RX_DROP;
  	}
  
  	if (ret == NET_RX_DROP)
  		kfree_skb(skb);
  
  	/* return NET_RX_SUCCESS in any case as we
  	 * most probably dropped the packet for
  	 * routing-logical reasons. */
  
  	return NET_RX_SUCCESS;
  
  err_free:
  	kfree_skb(skb);
  err_out:
  	return NET_RX_DROP;
  }
bc2790808   Antonio Quartulli   batman-adv: detec...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
  /* This function returns true if the interface represented by ifindex is a
   * 802.11 wireless device */
  bool is_wifi_iface(int ifindex)
  {
  	struct net_device *net_device = NULL;
  	bool ret = false;
  
  	if (ifindex == NULL_IFINDEX)
  		goto out;
  
  	net_device = dev_get_by_index(&init_net, ifindex);
  	if (!net_device)
  		goto out;
  
  #ifdef CONFIG_WIRELESS_EXT
  	/* pre-cfg80211 drivers have to implement WEXT, so it is possible to
  	 * check for wireless_handlers != NULL */
  	if (net_device->wireless_handlers)
  		ret = true;
  	else
  #endif
  		/* cfg80211 drivers have to set ieee80211_ptr */
  		if (net_device->ieee80211_ptr)
  			ret = true;
  out:
  	if (net_device)
  		dev_put(net_device);
  	return ret;
  }
c6c8fea29   Sven Eckelmann   net: Add batman-a...
656
657
658
  struct notifier_block hard_if_notifier = {
  	.notifier_call = hard_if_event,
  };