main.c 17.5 KB
Newer Older
1
/* Copyright (C) 2007-2016  B.A.T.M.A.N. contributors:
2 3 4 5 6 7 8 9 10 11 12 13 14
 *
 * 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
15
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 17
 */

18 19 20 21 22
#include "main.h"

#include <linux/atomic.h>
#include <linux/bug.h>
#include <linux/byteorder/generic.h>
23
#include <linux/crc32c.h>
24 25 26
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/if_ether.h>
27
#include <linux/if_vlan.h>
28 29 30 31
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kernel.h>
32
#include <linux/kref.h>
33 34 35
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
36
#include <linux/printk.h>
37 38 39 40 41 42 43 44
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/workqueue.h>
45
#include <net/dsfield.h>
46 47 48
#include <net/rtnetlink.h>

#include "bat_algo.h"
49 50
#include "bat_iv_ogm.h"
#include "bat_v.h"
51
#include "bridge_loop_avoidance.h"
52
#include "debugfs.h"
53 54 55 56 57
#include "distributed-arp-table.h"
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
#include "icmp_socket.h"
58
#include "log.h"
59
#include "multicast.h"
60
#include "netlink.h"
61 62 63
#include "network-coding.h"
#include "originator.h"
#include "packet.h"
64 65 66
#include "routing.h"
#include "send.h"
#include "soft-interface.h"
67
#include "tp_meter.h"
68 69
#include "translation-table.h"

70
/* List manipulations on hardif_list have to be rtnl_lock()'ed,
71 72
 * list traversals just rcu-locked
 */
73
struct list_head batadv_hardif_list;
74
static int (*batadv_rx_handler[256])(struct sk_buff *,
75
				     struct batadv_hard_iface *);
76

77
unsigned char batadv_broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
78

79
struct workqueue_struct *batadv_event_workqueue;
80

81
static void batadv_recv_handler_init(void);
82

83
static int __init batadv_init(void)
84
{
85 86 87 88 89 90
	int ret;

	ret = batadv_tt_cache_init();
	if (ret < 0)
		return ret;

91
	INIT_LIST_HEAD(&batadv_hardif_list);
92
	batadv_algo_init();
93

94
	batadv_recv_handler_init();
95

96
	batadv_v_init();
97
	batadv_iv_init();
98
	batadv_nc_init();
99
	batadv_tp_meter_init();
100

101 102
	batadv_event_workqueue = create_singlethread_workqueue("bat_events");
	if (!batadv_event_workqueue)
103
		goto err_create_wq;
104

105
	batadv_socket_init();
106
	batadv_debugfs_init();
107

108
	register_netdevice_notifier(&batadv_hard_if_notifier);
109
	rtnl_link_register(&batadv_link_ops);
110
	batadv_netlink_register();
111

112
	pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
113
		BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION);
114 115

	return 0;
116 117 118 119 120

err_create_wq:
	batadv_tt_cache_destroy();

	return -ENOMEM;
121 122
}

123
static void __exit batadv_exit(void)
124
{
125
	batadv_debugfs_destroy();
126
	batadv_netlink_unregister();
127
	rtnl_link_unregister(&batadv_link_ops);
128 129
	unregister_netdevice_notifier(&batadv_hard_if_notifier);
	batadv_hardif_remove_interfaces();
130

131 132 133
	flush_workqueue(batadv_event_workqueue);
	destroy_workqueue(batadv_event_workqueue);
	batadv_event_workqueue = NULL;
134 135

	rcu_barrier();
136 137

	batadv_tt_cache_destroy();
138 139
}

140
int batadv_mesh_init(struct net_device *soft_iface)
141
{
142
	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
143
	int ret;
144 145 146

	spin_lock_init(&bat_priv->forw_bat_list_lock);
	spin_lock_init(&bat_priv->forw_bcast_list_lock);
147 148 149 150
	spin_lock_init(&bat_priv->tt.changes_list_lock);
	spin_lock_init(&bat_priv->tt.req_list_lock);
	spin_lock_init(&bat_priv->tt.roam_list_lock);
	spin_lock_init(&bat_priv->tt.last_changeset_lock);
151
	spin_lock_init(&bat_priv->tt.commit_lock);
152
	spin_lock_init(&bat_priv->gw.list_lock);
153 154 155
#ifdef CONFIG_BATMAN_ADV_MCAST
	spin_lock_init(&bat_priv->mcast.want_lists_lock);
#endif
156 157
	spin_lock_init(&bat_priv->tvlv.container_list_lock);
	spin_lock_init(&bat_priv->tvlv.handler_list_lock);
158
	spin_lock_init(&bat_priv->softif_vlan_list_lock);
159
	spin_lock_init(&bat_priv->tp_list_lock);
160 161 162

	INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
	INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
163
	INIT_HLIST_HEAD(&bat_priv->gw.gateway_list);
164 165
#ifdef CONFIG_BATMAN_ADV_MCAST
	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_unsnoopables_list);
166 167
	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv4_list);
	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv6_list);
168
#endif
169
	INIT_LIST_HEAD(&bat_priv->tt.changes_list);
170
	INIT_HLIST_HEAD(&bat_priv->tt.req_list);
171
	INIT_LIST_HEAD(&bat_priv->tt.roam_list);
172 173 174
#ifdef CONFIG_BATMAN_ADV_MCAST
	INIT_HLIST_HEAD(&bat_priv->mcast.mla_list);
#endif
175 176
	INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
	INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
177
	INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
178
	INIT_HLIST_HEAD(&bat_priv->tp_list);
179

180 181 182 183
	ret = batadv_v_mesh_init(bat_priv);
	if (ret < 0)
		goto err;

184
	ret = batadv_originator_init(bat_priv);
185
	if (ret < 0)
186 187
		goto err;

188
	ret = batadv_tt_init(bat_priv);
189
	if (ret < 0)
190 191
		goto err;

192
	ret = batadv_bla_init(bat_priv);
193
	if (ret < 0)
194 195
		goto err;

196 197 198 199
	ret = batadv_dat_init(bat_priv);
	if (ret < 0)
		goto err;

200
	ret = batadv_nc_mesh_init(bat_priv);
201 202 203
	if (ret < 0)
		goto err;

204
	batadv_gw_init(bat_priv);
205
	batadv_mcast_init(bat_priv);
206

207
	atomic_set(&bat_priv->gw.reselect, 0);
208
	atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE);
209 210

	return 0;
211 212

err:
213
	batadv_mesh_free(soft_iface);
214
	return ret;
215 216
}

217
void batadv_mesh_free(struct net_device *soft_iface)
218
{
219
	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
220

221
	atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
222

223
	batadv_purge_outstanding_packets(bat_priv, NULL);
224

225
	batadv_gw_node_free(bat_priv);
226 227

	batadv_v_mesh_free(bat_priv);
228
	batadv_nc_mesh_free(bat_priv);
229 230
	batadv_dat_free(bat_priv);
	batadv_bla_free(bat_priv);
231

232 233
	batadv_mcast_free(bat_priv);

234 235 236 237
	/* Free the TT and the originator tables only after having terminated
	 * all the other depending components which may use these structures for
	 * their purposes.
	 */
238
	batadv_tt_free(bat_priv);
239

240 241 242 243 244 245
	/* Since the originator table clean up routine is accessing the TT
	 * tables as well, it has to be invoked after the TT tables have been
	 * freed and marked as empty. This ensures that no cleanup RCU callbacks
	 * accessing the TT data are scheduled for later execution.
	 */
	batadv_originator_free(bat_priv);
246

247 248
	batadv_gw_free(bat_priv);

249
	free_percpu(bat_priv->bat_counters);
250
	bat_priv->bat_counters = NULL;
251

252
	atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
253 254
}

255 256 257 258 259
/**
 * batadv_is_my_mac - check if the given mac address belongs to any of the real
 * interfaces in the current mesh
 * @bat_priv: the bat priv with all the soft interface information
 * @addr: the address to check
260
 *
261
 * Return: 'true' if the mac address was found, false otherwise.
262
 */
263
bool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr)
264
{
265
	const struct batadv_hard_iface *hard_iface;
266
	bool is_my_mac = false;
267 268

	rcu_read_lock();
269
	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
270
		if (hard_iface->if_status != BATADV_IF_ACTIVE)
271 272
			continue;

273 274 275
		if (hard_iface->soft_iface != bat_priv->soft_iface)
			continue;

276
		if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) {
277 278
			is_my_mac = true;
			break;
279 280 281
		}
	}
	rcu_read_unlock();
282
	return is_my_mac;
283 284
}

285
#ifdef CONFIG_BATMAN_ADV_DEBUGFS
286 287 288 289 290
/**
 * batadv_seq_print_text_primary_if_get - called from debugfs table printing
 *  function that requires the primary interface
 * @seq: debugfs table seq_file struct
 *
291
 * Return: primary interface if found or NULL otherwise.
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
 */
struct batadv_hard_iface *
batadv_seq_print_text_primary_if_get(struct seq_file *seq)
{
	struct net_device *net_dev = (struct net_device *)seq->private;
	struct batadv_priv *bat_priv = netdev_priv(net_dev);
	struct batadv_hard_iface *primary_if;

	primary_if = batadv_primary_if_get_selected(bat_priv);

	if (!primary_if) {
		seq_printf(seq,
			   "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
			   net_dev->name);
		goto out;
	}

	if (primary_if->if_status == BATADV_IF_ACTIVE)
		goto out;

	seq_printf(seq,
		   "BATMAN mesh %s disabled - primary interface not active\n",
		   net_dev->name);
315
	batadv_hardif_put(primary_if);
316 317 318 319 320
	primary_if = NULL;

out:
	return primary_if;
}
321
#endif
322

323 324 325 326
/**
 * batadv_max_header_len - calculate maximum encapsulation overhead for a
 *  payload packet
 *
327
 * Return: the maximum encapsulation overhead in bytes.
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
 */
int batadv_max_header_len(void)
{
	int header_len = 0;

	header_len = max_t(int, header_len,
			   sizeof(struct batadv_unicast_packet));
	header_len = max_t(int, header_len,
			   sizeof(struct batadv_unicast_4addr_packet));
	header_len = max_t(int, header_len,
			   sizeof(struct batadv_bcast_packet));

#ifdef CONFIG_BATMAN_ADV_NC
	header_len = max_t(int, header_len,
			   sizeof(struct batadv_coded_packet));
#endif

345
	return header_len + ETH_HLEN;
346 347
}

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
/**
 * batadv_skb_set_priority - sets skb priority according to packet content
 * @skb: the packet to be sent
 * @offset: offset to the packet content
 *
 * This function sets a value between 256 and 263 (802.1d priority), which
 * can be interpreted by the cfg80211 or other drivers.
 */
void batadv_skb_set_priority(struct sk_buff *skb, int offset)
{
	struct iphdr ip_hdr_tmp, *ip_hdr;
	struct ipv6hdr ip6_hdr_tmp, *ip6_hdr;
	struct ethhdr ethhdr_tmp, *ethhdr;
	struct vlan_ethhdr *vhdr, vhdr_tmp;
	u32 prio;

	/* already set, do nothing */
	if (skb->priority >= 256 && skb->priority <= 263)
		return;

	ethhdr = skb_header_pointer(skb, offset, sizeof(*ethhdr), &ethhdr_tmp);
	if (!ethhdr)
		return;

	switch (ethhdr->h_proto) {
	case htons(ETH_P_8021Q):
		vhdr = skb_header_pointer(skb, offset + sizeof(*vhdr),
					  sizeof(*vhdr), &vhdr_tmp);
		if (!vhdr)
			return;
		prio = ntohs(vhdr->h_vlan_TCI) & VLAN_PRIO_MASK;
		prio = prio >> VLAN_PRIO_SHIFT;
		break;
	case htons(ETH_P_IP):
		ip_hdr = skb_header_pointer(skb, offset + sizeof(*ethhdr),
					    sizeof(*ip_hdr), &ip_hdr_tmp);
		if (!ip_hdr)
			return;
		prio = (ipv4_get_dsfield(ip_hdr) & 0xfc) >> 5;
		break;
	case htons(ETH_P_IPV6):
		ip6_hdr = skb_header_pointer(skb, offset + sizeof(*ethhdr),
					     sizeof(*ip6_hdr), &ip6_hdr_tmp);
		if (!ip6_hdr)
			return;
		prio = (ipv6_get_dsfield(ip6_hdr) & 0xfc) >> 5;
		break;
	default:
		return;
	}

	skb->priority = prio + 256;
}

402
static int batadv_recv_unhandled_packet(struct sk_buff *skb,
403
					struct batadv_hard_iface *recv_if)
404
{
405 406
	kfree_skb(skb);

407 408 409 410 411 412
	return NET_RX_DROP;
}

/* incoming packets with the batman ethertype received on any active hard
 * interface
 */
413 414 415
int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
			   struct packet_type *ptype,
			   struct net_device *orig_dev)
416
{
417
	struct batadv_priv *bat_priv;
418
	struct batadv_ogm_packet *batadv_ogm_packet;
419
	struct batadv_hard_iface *hard_iface;
420
	u8 idx;
421

422 423
	hard_iface = container_of(ptype, struct batadv_hard_iface,
				  batman_adv_ptype);
424 425 426 427 428 429 430 431

	/* Prevent processing a packet received on an interface which is getting
	 * shut down otherwise the packet may trigger de-reference errors
	 * further down in the receive path.
	 */
	if (!kref_get_unless_zero(&hard_iface->refcount))
		goto err_out;

432 433 434 435
	skb = skb_share_check(skb, GFP_ATOMIC);

	/* skb was released by skb_share_check() */
	if (!skb)
436
		goto err_put;
437 438 439 440 441 442 443 444 445 446 447 448 449 450

	/* 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 != ETH_HLEN || !skb_mac_header(skb)))
		goto err_free;

	if (!hard_iface->soft_iface)
		goto err_free;

	bat_priv = netdev_priv(hard_iface->soft_iface);

451
	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
452 453 454
		goto err_free;

	/* discard frames on not active interfaces */
455
	if (hard_iface->if_status != BATADV_IF_ACTIVE)
456 457
		goto err_free;

458
	batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data;
459

460
	if (batadv_ogm_packet->version != BATADV_COMPAT_VERSION) {
461
		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
462
			   "Drop packet: incompatible batman version (%i)\n",
463
			   batadv_ogm_packet->version);
464 465 466
		goto err_free;
	}

467 468 469
	/* reset control block to avoid left overs from previous users */
	memset(skb->cb, 0, sizeof(struct batadv_skb_cb));

470
	idx = batadv_ogm_packet->packet_type;
471
	(*batadv_rx_handler[idx])(skb, hard_iface);
472

473 474
	batadv_hardif_put(hard_iface);

475 476 477 478 479 480 481 482
	/* 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);
483 484
err_put:
	batadv_hardif_put(hard_iface);
485 486 487 488
err_out:
	return NET_RX_DROP;
}

489
static void batadv_recv_handler_init(void)
490 491 492
{
	int i;

493 494
	for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++)
		batadv_rx_handler[i] = batadv_recv_unhandled_packet;
495

496 497 498
	for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++)
		batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet;

499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
	/* compile time checks for sizes */
	BUILD_BUG_ON(sizeof(struct batadv_bla_claim_dst) != 6);
	BUILD_BUG_ON(sizeof(struct batadv_ogm_packet) != 24);
	BUILD_BUG_ON(sizeof(struct batadv_icmp_header) != 20);
	BUILD_BUG_ON(sizeof(struct batadv_icmp_packet) != 20);
	BUILD_BUG_ON(sizeof(struct batadv_icmp_packet_rr) != 116);
	BUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10);
	BUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18);
	BUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20);
	BUILD_BUG_ON(sizeof(struct batadv_bcast_packet) != 14);
	BUILD_BUG_ON(sizeof(struct batadv_coded_packet) != 46);
	BUILD_BUG_ON(sizeof(struct batadv_unicast_tvlv_packet) != 20);
	BUILD_BUG_ON(sizeof(struct batadv_tvlv_hdr) != 4);
	BUILD_BUG_ON(sizeof(struct batadv_tvlv_gateway_data) != 8);
	BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_vlan_data) != 8);
	BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12);
	BUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8);
516

517 518 519 520
	/* broadcast packet */
	batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;

	/* unicast packets ... */
521 522
	/* unicast with 4 addresses packet */
	batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet;
523
	/* unicast packet */
524
	batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet;
525 526
	/* unicast tvlv packet */
	batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv;
527 528
	/* batman icmp packet */
	batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet;
529 530
	/* Fragmented packets */
	batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_frag_packet;
531 532
}

533
int
534
batadv_recv_handler_register(u8 packet_type,
535 536
			     int (*recv_handler)(struct sk_buff *,
						 struct batadv_hard_iface *))
537
{
538 539 540 541 542 543
	int (*curr)(struct sk_buff *,
		    struct batadv_hard_iface *);
	curr = batadv_rx_handler[packet_type];

	if ((curr != batadv_recv_unhandled_packet) &&
	    (curr != batadv_recv_unhandled_unicast_packet))
544 545
		return -EBUSY;

546
	batadv_rx_handler[packet_type] = recv_handler;
547 548 549
	return 0;
}

550
void batadv_recv_handler_unregister(u8 packet_type)
551
{
552
	batadv_rx_handler[packet_type] = batadv_recv_unhandled_packet;
553 554
}

555 556 557 558 559 560 561 562 563
/**
 * batadv_skb_crc32 - calculate CRC32 of the whole packet and skip bytes in
 *  the header
 * @skb: skb pointing to fragmented socket buffers
 * @payload_ptr: Pointer to position inside the head buffer of the skb
 *  marking the start of the data to be CRC'ed
 *
 * payload_ptr must always point to an address in the skb head buffer and not to
 * a fragment.
564 565
 *
 * Return: big endian crc32c of the checksummed data
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
 */
__be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr)
{
	u32 crc = 0;
	unsigned int from;
	unsigned int to = skb->len;
	struct skb_seq_state st;
	const u8 *data;
	unsigned int len;
	unsigned int consumed = 0;

	from = (unsigned int)(payload_ptr - skb->data);

	skb_prepare_seq_read(skb, from, to, &st);
	while ((len = skb_seq_read(consumed, &data, &st)) != 0) {
		crc = crc32c(crc, data, len);
		consumed += len;
	}

	return htonl(crc);
}

588 589 590 591 592
/**
 * batadv_get_vid - extract the VLAN identifier from skb if any
 * @skb: the buffer containing the packet
 * @header_len: length of the batman header preceding the ethernet header
 *
593 594
 * Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the
 * skb is vlan tagged. Otherwise BATADV_NO_FLAGS.
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
 */
unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
{
	struct ethhdr *ethhdr = (struct ethhdr *)(skb->data + header_len);
	struct vlan_ethhdr *vhdr;
	unsigned short vid;

	if (ethhdr->h_proto != htons(ETH_P_8021Q))
		return BATADV_NO_FLAGS;

	if (!pskb_may_pull(skb, header_len + VLAN_ETH_HLEN))
		return BATADV_NO_FLAGS;

	vhdr = (struct vlan_ethhdr *)(skb->data + header_len);
	vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
	vid |= BATADV_VLAN_HAS_TAG;

	return vid;
}

615 616 617 618 619 620
/**
 * batadv_vlan_ap_isola_get - return the AP isolation status for the given vlan
 * @bat_priv: the bat priv with all the soft interface information
 * @vid: the VLAN identifier for which the AP isolation attributed as to be
 *  looked up
 *
621
 * Return: true if AP isolation is on for the VLAN idenfied by vid, false
622 623 624 625 626 627 628 629 630 631 632 633 634
 * otherwise
 */
bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
{
	bool ap_isolation_enabled = false;
	struct batadv_softif_vlan *vlan;

	/* if the AP isolation is requested on a VLAN, then check for its
	 * setting in the proper VLAN private data structure
	 */
	vlan = batadv_softif_vlan_get(bat_priv, vid);
	if (vlan) {
		ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
635
		batadv_softif_vlan_put(vlan);
636 637 638 639 640
	}

	return ap_isolation_enabled;
}

641 642
module_init(batadv_init);
module_exit(batadv_exit);
643 644 645

MODULE_LICENSE("GPL");

646 647 648 649
MODULE_AUTHOR(BATADV_DRIVER_AUTHOR);
MODULE_DESCRIPTION(BATADV_DRIVER_DESC);
MODULE_SUPPORTED_DEVICE(BATADV_DRIVER_DEVICE);
MODULE_VERSION(BATADV_SOURCE_VERSION);
650
MODULE_ALIAS_RTNL_LINK("batadv");