batman-adv: rename random32() to prandom_u32()
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / batman-adv / hard-interface.c
CommitLineData
9cfc7bd6 1/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
c6c8fea2
SE
2 *
3 * Marek Lindner, Simon Wunderlich
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, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA
c6c8fea2
SE
18 */
19
20#include "main.h"
785ea114 21#include "distributed-arp-table.h"
c6c8fea2
SE
22#include "hard-interface.h"
23#include "soft-interface.h"
24#include "send.h"
25#include "translation-table.h"
26#include "routing.h"
b706b13b 27#include "sysfs.h"
c6c8fea2
SE
28#include "originator.h"
29#include "hash.h"
23721387 30#include "bridge_loop_avoidance.h"
c6c8fea2
SE
31
32#include <linux/if_arp.h>
af5d4f77 33#include <linux/if_ether.h>
c6c8fea2 34
9563877e 35void batadv_hardif_free_rcu(struct rcu_head *rcu)
c6c8fea2 36{
56303d34 37 struct batadv_hard_iface *hard_iface;
c6c8fea2 38
56303d34 39 hard_iface = container_of(rcu, struct batadv_hard_iface, rcu);
e6c10f43
ML
40 dev_put(hard_iface->net_dev);
41 kfree(hard_iface);
c6c8fea2
SE
42}
43
56303d34
SE
44struct batadv_hard_iface *
45batadv_hardif_get_by_netdev(const struct net_device *net_dev)
c6c8fea2 46{
56303d34 47 struct batadv_hard_iface *hard_iface;
c6c8fea2
SE
48
49 rcu_read_lock();
3193e8fd 50 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
e6c10f43
ML
51 if (hard_iface->net_dev == net_dev &&
52 atomic_inc_not_zero(&hard_iface->refcount))
c6c8fea2
SE
53 goto out;
54 }
55
e6c10f43 56 hard_iface = NULL;
c6c8fea2
SE
57
58out:
c6c8fea2 59 rcu_read_unlock();
e6c10f43 60 return hard_iface;
c6c8fea2
SE
61}
62
b7eddd0b
AQ
63/**
64 * batadv_is_on_batman_iface - check if a device is a batman iface descendant
65 * @net_dev: the device to check
66 *
67 * If the user creates any virtual device on top of a batman-adv interface, it
68 * is important to prevent this new interface to be used to create a new mesh
69 * network (this behaviour would lead to a batman-over-batman configuration).
70 * This function recursively checks all the fathers of the device passed as
71 * argument looking for a batman-adv soft interface.
72 *
73 * Returns true if the device is descendant of a batman-adv mesh interface (or
74 * if it is a batman-adv interface itself), false otherwise
75 */
76static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
77{
78 struct net_device *parent_dev;
79 bool ret;
80
81 /* check if this is a batman-adv mesh interface */
82 if (batadv_softif_is_valid(net_dev))
83 return true;
84
85 /* no more parents..stop recursion */
86 if (net_dev->iflink == net_dev->ifindex)
87 return false;
88
89 /* recurse over the parent device */
90 parent_dev = dev_get_by_index(&init_net, net_dev->iflink);
91 /* if we got a NULL parent_dev there is something broken.. */
92 if (WARN(!parent_dev, "Cannot find parent device"))
93 return false;
94
95 ret = batadv_is_on_batman_iface(parent_dev);
96
97 if (parent_dev)
98 dev_put(parent_dev);
99 return ret;
100}
101
18a1cb6e 102static int batadv_is_valid_iface(const struct net_device *net_dev)
c6c8fea2
SE
103{
104 if (net_dev->flags & IFF_LOOPBACK)
105 return 0;
106
107 if (net_dev->type != ARPHRD_ETHER)
108 return 0;
109
110 if (net_dev->addr_len != ETH_ALEN)
111 return 0;
112
113 /* no batman over batman */
b7eddd0b 114 if (batadv_is_on_batman_iface(net_dev))
c6c8fea2 115 return 0;
c6c8fea2 116
c6c8fea2
SE
117 return 1;
118}
119
56303d34 120static struct batadv_hard_iface *
18a1cb6e 121batadv_hardif_get_active(const struct net_device *soft_iface)
c6c8fea2 122{
56303d34 123 struct batadv_hard_iface *hard_iface;
c6c8fea2
SE
124
125 rcu_read_lock();
3193e8fd 126 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
e6c10f43 127 if (hard_iface->soft_iface != soft_iface)
c6c8fea2
SE
128 continue;
129
e9a4f295 130 if (hard_iface->if_status == BATADV_IF_ACTIVE &&
e6c10f43 131 atomic_inc_not_zero(&hard_iface->refcount))
c6c8fea2
SE
132 goto out;
133 }
134
e6c10f43 135 hard_iface = NULL;
c6c8fea2
SE
136
137out:
c6c8fea2 138 rcu_read_unlock();
e6c10f43 139 return hard_iface;
c6c8fea2
SE
140}
141
56303d34
SE
142static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv,
143 struct batadv_hard_iface *oldif)
c6c8fea2 144{
96412690 145 struct batadv_vis_packet *vis_packet;
56303d34 146 struct batadv_hard_iface *primary_if;
807736f6 147 struct sk_buff *skb;
32ae9b22 148
e5d89254 149 primary_if = batadv_primary_if_get_selected(bat_priv);
32ae9b22
ML
150 if (!primary_if)
151 goto out;
c6c8fea2 152
785ea114
AQ
153 batadv_dat_init_own_addr(bat_priv, primary_if);
154
807736f6
SE
155 skb = bat_priv->vis.my_info->skb_packet;
156 vis_packet = (struct batadv_vis_packet *)skb->data;
32ae9b22 157 memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
c6c8fea2 158 memcpy(vis_packet->sender_orig,
32ae9b22
ML
159 primary_if->net_dev->dev_addr, ETH_ALEN);
160
08adf151 161 batadv_bla_update_orig_address(bat_priv, primary_if, oldif);
32ae9b22
ML
162out:
163 if (primary_if)
e5d89254 164 batadv_hardif_free_ref(primary_if);
c6c8fea2
SE
165}
166
56303d34
SE
167static void batadv_primary_if_select(struct batadv_priv *bat_priv,
168 struct batadv_hard_iface *new_hard_iface)
c6c8fea2 169{
56303d34 170 struct batadv_hard_iface *curr_hard_iface;
c6c8fea2 171
c3caf519 172 ASSERT_RTNL();
c6c8fea2 173
32ae9b22
ML
174 if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
175 new_hard_iface = NULL;
c6c8fea2 176
728cbc6a 177 curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
32ae9b22 178 rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
c6c8fea2 179
32ae9b22 180 if (!new_hard_iface)
23721387 181 goto out;
32ae9b22 182
cd8b78e7 183 bat_priv->bat_algo_ops->bat_primary_iface_set(new_hard_iface);
18a1cb6e 184 batadv_primary_if_update_addr(bat_priv, curr_hard_iface);
23721387
SW
185
186out:
187 if (curr_hard_iface)
e5d89254 188 batadv_hardif_free_ref(curr_hard_iface);
c6c8fea2
SE
189}
190
56303d34
SE
191static bool
192batadv_hardif_is_iface_up(const struct batadv_hard_iface *hard_iface)
c6c8fea2 193{
e6c10f43 194 if (hard_iface->net_dev->flags & IFF_UP)
c6c8fea2
SE
195 return true;
196
197 return false;
198}
199
18a1cb6e 200static void batadv_check_known_mac_addr(const struct net_device *net_dev)
c6c8fea2 201{
56303d34 202 const struct batadv_hard_iface *hard_iface;
c6c8fea2
SE
203
204 rcu_read_lock();
3193e8fd 205 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
e9a4f295
SE
206 if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
207 (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
c6c8fea2
SE
208 continue;
209
e6c10f43 210 if (hard_iface->net_dev == net_dev)
c6c8fea2
SE
211 continue;
212
1eda58bf
SE
213 if (!batadv_compare_eth(hard_iface->net_dev->dev_addr,
214 net_dev->dev_addr))
c6c8fea2
SE
215 continue;
216
67969581
SE
217 pr_warn("The newly added mac address (%pM) already exists on: %s\n",
218 net_dev->dev_addr, hard_iface->net_dev->name);
219 pr_warn("It is strongly recommended to keep mac addresses unique to avoid problems!\n");
c6c8fea2
SE
220 }
221 rcu_read_unlock();
222}
223
9563877e 224int batadv_hardif_min_mtu(struct net_device *soft_iface)
c6c8fea2 225{
56303d34
SE
226 const struct batadv_priv *bat_priv = netdev_priv(soft_iface);
227 const struct batadv_hard_iface *hard_iface;
c6c8fea2 228 /* allow big frames if all devices are capable to do so
9cfc7bd6
SE
229 * (have MTU > 1500 + BAT_HEADER_LEN)
230 */
c6c8fea2
SE
231 int min_mtu = ETH_DATA_LEN;
232
233 if (atomic_read(&bat_priv->fragmentation))
234 goto out;
235
236 rcu_read_lock();
3193e8fd 237 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
e9a4f295
SE
238 if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
239 (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
c6c8fea2
SE
240 continue;
241
e6c10f43 242 if (hard_iface->soft_iface != soft_iface)
c6c8fea2
SE
243 continue;
244
c11fdfae
SE
245 min_mtu = min_t(int,
246 hard_iface->net_dev->mtu - BATADV_HEADER_LEN,
c6c8fea2
SE
247 min_mtu);
248 }
249 rcu_read_unlock();
250out:
251 return min_mtu;
252}
253
254/* adjusts the MTU if a new interface with a smaller MTU appeared. */
9563877e 255void batadv_update_min_mtu(struct net_device *soft_iface)
c6c8fea2
SE
256{
257 int min_mtu;
258
9563877e 259 min_mtu = batadv_hardif_min_mtu(soft_iface);
c6c8fea2
SE
260 if (soft_iface->mtu != min_mtu)
261 soft_iface->mtu = min_mtu;
262}
263
56303d34
SE
264static void
265batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
c6c8fea2 266{
56303d34
SE
267 struct batadv_priv *bat_priv;
268 struct batadv_hard_iface *primary_if = NULL;
c6c8fea2 269
e9a4f295 270 if (hard_iface->if_status != BATADV_IF_INACTIVE)
32ae9b22 271 goto out;
c6c8fea2 272
e6c10f43 273 bat_priv = netdev_priv(hard_iface->soft_iface);
c6c8fea2 274
c3229398 275 bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
e9a4f295 276 hard_iface->if_status = BATADV_IF_TO_BE_ACTIVATED;
c6c8fea2 277
9cfc7bd6 278 /* the first active interface becomes our primary interface or
015758d0 279 * the next active interface after the old primary interface was removed
c6c8fea2 280 */
e5d89254 281 primary_if = batadv_primary_if_get_selected(bat_priv);
32ae9b22 282 if (!primary_if)
18a1cb6e 283 batadv_primary_if_select(bat_priv, hard_iface);
c6c8fea2 284
3e34819e
SE
285 batadv_info(hard_iface->soft_iface, "Interface activated: %s\n",
286 hard_iface->net_dev->name);
c6c8fea2 287
9563877e 288 batadv_update_min_mtu(hard_iface->soft_iface);
32ae9b22
ML
289
290out:
291 if (primary_if)
e5d89254 292 batadv_hardif_free_ref(primary_if);
c6c8fea2
SE
293}
294
56303d34
SE
295static void
296batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
c6c8fea2 297{
e9a4f295
SE
298 if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
299 (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
c6c8fea2
SE
300 return;
301
e9a4f295 302 hard_iface->if_status = BATADV_IF_INACTIVE;
c6c8fea2 303
3e34819e
SE
304 batadv_info(hard_iface->soft_iface, "Interface deactivated: %s\n",
305 hard_iface->net_dev->name);
c6c8fea2 306
9563877e 307 batadv_update_min_mtu(hard_iface->soft_iface);
c6c8fea2
SE
308}
309
56303d34 310int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
9563877e 311 const char *iface_name)
c6c8fea2 312{
56303d34 313 struct batadv_priv *bat_priv;
e44d8fe2 314 struct net_device *soft_iface;
af5d4f77 315 __be16 ethertype = __constant_htons(ETH_P_BATMAN);
e44d8fe2 316 int ret;
c6c8fea2 317
e9a4f295 318 if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
c6c8fea2
SE
319 goto out;
320
e6c10f43 321 if (!atomic_inc_not_zero(&hard_iface->refcount))
ed75ccbe
ML
322 goto out;
323
6e242f90
ML
324 /* hard-interface is part of a bridge */
325 if (hard_iface->net_dev->priv_flags & IFF_BRIDGE_PORT)
86ceb360 326 pr_err("You are about to enable batman-adv on '%s' which already is part of a bridge. Unless you know exactly what you are doing this is probably wrong and won't work the way you think it would.\n",
6e242f90
ML
327 hard_iface->net_dev->name);
328
e44d8fe2 329 soft_iface = dev_get_by_name(&init_net, iface_name);
c6c8fea2 330
e44d8fe2 331 if (!soft_iface) {
04b482a2 332 soft_iface = batadv_softif_create(iface_name);
c6c8fea2 333
e44d8fe2
SE
334 if (!soft_iface) {
335 ret = -ENOMEM;
c6c8fea2 336 goto err;
e44d8fe2 337 }
c6c8fea2
SE
338
339 /* dev_get_by_name() increases the reference counter for us */
e44d8fe2
SE
340 dev_hold(soft_iface);
341 }
342
04b482a2 343 if (!batadv_softif_is_valid(soft_iface)) {
86ceb360 344 pr_err("Can't create batman mesh interface %s: already exists as regular interface\n",
e44d8fe2 345 soft_iface->name);
e44d8fe2 346 ret = -EINVAL;
77af7575 347 goto err_dev;
c6c8fea2
SE
348 }
349
e44d8fe2 350 hard_iface->soft_iface = soft_iface;
e6c10f43 351 bat_priv = netdev_priv(hard_iface->soft_iface);
d0b9fd89 352
77af7575 353 ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
5346c35e 354 if (ret < 0)
77af7575 355 goto err_dev;
c6c8fea2 356
e6c10f43 357 hard_iface->if_num = bat_priv->num_ifaces;
c6c8fea2 358 bat_priv->num_ifaces++;
e9a4f295 359 hard_iface->if_status = BATADV_IF_INACTIVE;
62446307
SW
360 ret = batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
361 if (ret < 0) {
362 bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
363 bat_priv->num_ifaces--;
364 hard_iface->if_status = BATADV_IF_NOT_IN_USE;
365 goto err_dev;
366 }
c6c8fea2 367
7e071c79 368 hard_iface->batman_adv_ptype.type = ethertype;
3193e8fd 369 hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
e6c10f43
ML
370 hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
371 dev_add_pack(&hard_iface->batman_adv_ptype);
c6c8fea2 372
e6c10f43 373 atomic_set(&hard_iface->frag_seqno, 1);
3e34819e
SE
374 batadv_info(hard_iface->soft_iface, "Adding interface: %s\n",
375 hard_iface->net_dev->name);
c6c8fea2 376
0aca2369
SE
377 if (atomic_read(&bat_priv->fragmentation) &&
378 hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
3e34819e
SE
379 batadv_info(hard_iface->soft_iface,
380 "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.\n",
381 hard_iface->net_dev->name, hard_iface->net_dev->mtu,
c11fdfae 382 ETH_DATA_LEN + BATADV_HEADER_LEN);
c6c8fea2 383
0aca2369
SE
384 if (!atomic_read(&bat_priv->fragmentation) &&
385 hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
3e34819e
SE
386 batadv_info(hard_iface->soft_iface,
387 "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.\n",
388 hard_iface->net_dev->name, hard_iface->net_dev->mtu,
c11fdfae 389 ETH_DATA_LEN + BATADV_HEADER_LEN);
c6c8fea2 390
18a1cb6e
SE
391 if (batadv_hardif_is_iface_up(hard_iface))
392 batadv_hardif_activate_interface(hard_iface);
c6c8fea2 393 else
3e34819e
SE
394 batadv_err(hard_iface->soft_iface,
395 "Not using interface %s (retrying later): interface not active\n",
396 hard_iface->net_dev->name);
c6c8fea2
SE
397
398 /* begin scheduling originator messages on that interface */
9455e34c 399 batadv_schedule_bat_ogm(hard_iface);
c6c8fea2
SE
400
401out:
402 return 0;
403
77af7575
ML
404err_dev:
405 dev_put(soft_iface);
c6c8fea2 406err:
e5d89254 407 batadv_hardif_free_ref(hard_iface);
e44d8fe2 408 return ret;
c6c8fea2
SE
409}
410
56303d34 411void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
c6c8fea2 412{
56303d34
SE
413 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
414 struct batadv_hard_iface *primary_if = NULL;
c6c8fea2 415
e9a4f295 416 if (hard_iface->if_status == BATADV_IF_ACTIVE)
18a1cb6e 417 batadv_hardif_deactivate_interface(hard_iface);
c6c8fea2 418
e9a4f295 419 if (hard_iface->if_status != BATADV_IF_INACTIVE)
32ae9b22 420 goto out;
c6c8fea2 421
3e34819e
SE
422 batadv_info(hard_iface->soft_iface, "Removing interface: %s\n",
423 hard_iface->net_dev->name);
e6c10f43 424 dev_remove_pack(&hard_iface->batman_adv_ptype);
c6c8fea2
SE
425
426 bat_priv->num_ifaces--;
7d211efc 427 batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
c6c8fea2 428
e5d89254 429 primary_if = batadv_primary_if_get_selected(bat_priv);
32ae9b22 430 if (hard_iface == primary_if) {
56303d34 431 struct batadv_hard_iface *new_if;
c6c8fea2 432
18a1cb6e
SE
433 new_if = batadv_hardif_get_active(hard_iface->soft_iface);
434 batadv_primary_if_select(bat_priv, new_if);
c6c8fea2
SE
435
436 if (new_if)
e5d89254 437 batadv_hardif_free_ref(new_if);
c6c8fea2
SE
438 }
439
00a50076 440 bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
e9a4f295 441 hard_iface->if_status = BATADV_IF_NOT_IN_USE;
c6c8fea2 442
e6c10f43 443 /* delete all references to this hard_iface */
7d211efc 444 batadv_purge_orig_ref(bat_priv);
9455e34c 445 batadv_purge_outstanding_packets(bat_priv, hard_iface);
e6c10f43 446 dev_put(hard_iface->soft_iface);
c6c8fea2
SE
447
448 /* nobody uses this interface anymore */
449 if (!bat_priv->num_ifaces)
04b482a2 450 batadv_softif_destroy(hard_iface->soft_iface);
c6c8fea2 451
e6c10f43 452 hard_iface->soft_iface = NULL;
e5d89254 453 batadv_hardif_free_ref(hard_iface);
32ae9b22
ML
454
455out:
456 if (primary_if)
e5d89254 457 batadv_hardif_free_ref(primary_if);
c6c8fea2
SE
458}
459
56303d34 460static struct batadv_hard_iface *
18a1cb6e 461batadv_hardif_add_interface(struct net_device *net_dev)
c6c8fea2 462{
56303d34 463 struct batadv_hard_iface *hard_iface;
c6c8fea2
SE
464 int ret;
465
c3caf519
SE
466 ASSERT_RTNL();
467
18a1cb6e 468 ret = batadv_is_valid_iface(net_dev);
c6c8fea2
SE
469 if (ret != 1)
470 goto out;
471
472 dev_hold(net_dev);
473
704509b8 474 hard_iface = kmalloc(sizeof(*hard_iface), GFP_ATOMIC);
320f422f 475 if (!hard_iface)
c6c8fea2 476 goto release_dev;
c6c8fea2 477
5853e22c 478 ret = batadv_sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
c6c8fea2
SE
479 if (ret)
480 goto free_if;
481
e6c10f43
ML
482 hard_iface->if_num = -1;
483 hard_iface->net_dev = net_dev;
484 hard_iface->soft_iface = NULL;
e9a4f295 485 hard_iface->if_status = BATADV_IF_NOT_IN_USE;
e6c10f43 486 INIT_LIST_HEAD(&hard_iface->list);
ed75ccbe 487 /* extra reference for return */
e6c10f43 488 atomic_set(&hard_iface->refcount, 2);
c6c8fea2 489
18a1cb6e 490 batadv_check_known_mac_addr(hard_iface->net_dev);
3193e8fd 491 list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
c6c8fea2 492
9cfc7bd6 493 /* This can't be called via a bat_priv callback because
8140625e
ML
494 * we have no bat_priv yet.
495 */
14511519
ML
496 atomic_set(&hard_iface->bat_iv.ogm_seqno, 1);
497 hard_iface->bat_iv.ogm_buff = NULL;
8140625e 498
e6c10f43 499 return hard_iface;
c6c8fea2
SE
500
501free_if:
e6c10f43 502 kfree(hard_iface);
c6c8fea2
SE
503release_dev:
504 dev_put(net_dev);
505out:
506 return NULL;
507}
508
56303d34 509static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
c6c8fea2 510{
c3caf519
SE
511 ASSERT_RTNL();
512
c6c8fea2 513 /* first deactivate interface */
e9a4f295 514 if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
9563877e 515 batadv_hardif_disable_interface(hard_iface);
c6c8fea2 516
e9a4f295 517 if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
c6c8fea2
SE
518 return;
519
e9a4f295 520 hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
5853e22c 521 batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
e5d89254 522 batadv_hardif_free_ref(hard_iface);
c6c8fea2
SE
523}
524
9563877e 525void batadv_hardif_remove_interfaces(void)
c6c8fea2 526{
56303d34 527 struct batadv_hard_iface *hard_iface, *hard_iface_tmp;
c6c8fea2 528
c3caf519 529 rtnl_lock();
e6c10f43 530 list_for_each_entry_safe(hard_iface, hard_iface_tmp,
3193e8fd 531 &batadv_hardif_list, list) {
e6c10f43 532 list_del_rcu(&hard_iface->list);
18a1cb6e 533 batadv_hardif_remove_interface(hard_iface);
c6c8fea2
SE
534 }
535 rtnl_unlock();
536}
537
18a1cb6e
SE
538static int batadv_hard_if_event(struct notifier_block *this,
539 unsigned long event, void *ptr)
c6c8fea2 540{
5f718c20 541 struct net_device *net_dev = ptr;
56303d34
SE
542 struct batadv_hard_iface *hard_iface;
543 struct batadv_hard_iface *primary_if = NULL;
544 struct batadv_priv *bat_priv;
c6c8fea2 545
56303d34 546 hard_iface = batadv_hardif_get_by_netdev(net_dev);
e6c10f43 547 if (!hard_iface && event == NETDEV_REGISTER)
18a1cb6e 548 hard_iface = batadv_hardif_add_interface(net_dev);
c6c8fea2 549
e6c10f43 550 if (!hard_iface)
c6c8fea2
SE
551 goto out;
552
553 switch (event) {
554 case NETDEV_UP:
18a1cb6e 555 batadv_hardif_activate_interface(hard_iface);
c6c8fea2
SE
556 break;
557 case NETDEV_GOING_DOWN:
558 case NETDEV_DOWN:
18a1cb6e 559 batadv_hardif_deactivate_interface(hard_iface);
c6c8fea2
SE
560 break;
561 case NETDEV_UNREGISTER:
e6c10f43 562 list_del_rcu(&hard_iface->list);
c6c8fea2 563
18a1cb6e 564 batadv_hardif_remove_interface(hard_iface);
c6c8fea2
SE
565 break;
566 case NETDEV_CHANGEMTU:
e6c10f43 567 if (hard_iface->soft_iface)
9563877e 568 batadv_update_min_mtu(hard_iface->soft_iface);
c6c8fea2
SE
569 break;
570 case NETDEV_CHANGEADDR:
e9a4f295 571 if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
c6c8fea2
SE
572 goto hardif_put;
573
18a1cb6e 574 batadv_check_known_mac_addr(hard_iface->net_dev);
c6c8fea2 575
e6c10f43 576 bat_priv = netdev_priv(hard_iface->soft_iface);
c3229398 577 bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
01c4224b 578
e5d89254 579 primary_if = batadv_primary_if_get_selected(bat_priv);
32ae9b22
ML
580 if (!primary_if)
581 goto hardif_put;
582
583 if (hard_iface == primary_if)
18a1cb6e 584 batadv_primary_if_update_addr(bat_priv, NULL);
c6c8fea2
SE
585 break;
586 default:
587 break;
f81c6224 588 }
c6c8fea2
SE
589
590hardif_put:
e5d89254 591 batadv_hardif_free_ref(hard_iface);
c6c8fea2 592out:
32ae9b22 593 if (primary_if)
e5d89254 594 batadv_hardif_free_ref(primary_if);
c6c8fea2
SE
595 return NOTIFY_DONE;
596}
597
bc279080 598/* This function returns true if the interface represented by ifindex is a
9cfc7bd6
SE
599 * 802.11 wireless device
600 */
9563877e 601bool batadv_is_wifi_iface(int ifindex)
bc279080
AQ
602{
603 struct net_device *net_device = NULL;
604 bool ret = false;
605
42d0b044 606 if (ifindex == BATADV_NULL_IFINDEX)
bc279080
AQ
607 goto out;
608
609 net_device = dev_get_by_index(&init_net, ifindex);
610 if (!net_device)
611 goto out;
612
613#ifdef CONFIG_WIRELESS_EXT
614 /* pre-cfg80211 drivers have to implement WEXT, so it is possible to
9cfc7bd6
SE
615 * check for wireless_handlers != NULL
616 */
bc279080
AQ
617 if (net_device->wireless_handlers)
618 ret = true;
619 else
620#endif
621 /* cfg80211 drivers have to set ieee80211_ptr */
622 if (net_device->ieee80211_ptr)
623 ret = true;
624out:
625 if (net_device)
626 dev_put(net_device);
627 return ret;
628}
629
9563877e 630struct notifier_block batadv_hard_if_notifier = {
18a1cb6e 631 .notifier_call = batadv_hard_if_event,
c6c8fea2 632};