162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) B.A.T.M.A.N. contributors:
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Marek Lindner, Simon Wunderlich
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "main.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/atomic.h>
1062306a36Sopenharmony_ci#include <linux/build_bug.h>
1162306a36Sopenharmony_ci#include <linux/byteorder/generic.h>
1262306a36Sopenharmony_ci#include <linux/container_of.h>
1362306a36Sopenharmony_ci#include <linux/crc32c.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/errno.h>
1662306a36Sopenharmony_ci#include <linux/genetlink.h>
1762306a36Sopenharmony_ci#include <linux/gfp.h>
1862306a36Sopenharmony_ci#include <linux/if_ether.h>
1962306a36Sopenharmony_ci#include <linux/if_vlan.h>
2062306a36Sopenharmony_ci#include <linux/init.h>
2162306a36Sopenharmony_ci#include <linux/ip.h>
2262306a36Sopenharmony_ci#include <linux/ipv6.h>
2362306a36Sopenharmony_ci#include <linux/kernel.h>
2462306a36Sopenharmony_ci#include <linux/kobject.h>
2562306a36Sopenharmony_ci#include <linux/kref.h>
2662306a36Sopenharmony_ci#include <linux/list.h>
2762306a36Sopenharmony_ci#include <linux/minmax.h>
2862306a36Sopenharmony_ci#include <linux/module.h>
2962306a36Sopenharmony_ci#include <linux/netdevice.h>
3062306a36Sopenharmony_ci#include <linux/printk.h>
3162306a36Sopenharmony_ci#include <linux/rculist.h>
3262306a36Sopenharmony_ci#include <linux/rcupdate.h>
3362306a36Sopenharmony_ci#include <linux/skbuff.h>
3462306a36Sopenharmony_ci#include <linux/slab.h>
3562306a36Sopenharmony_ci#include <linux/spinlock.h>
3662306a36Sopenharmony_ci#include <linux/stddef.h>
3762306a36Sopenharmony_ci#include <linux/string.h>
3862306a36Sopenharmony_ci#include <linux/workqueue.h>
3962306a36Sopenharmony_ci#include <net/dsfield.h>
4062306a36Sopenharmony_ci#include <net/rtnetlink.h>
4162306a36Sopenharmony_ci#include <uapi/linux/batadv_packet.h>
4262306a36Sopenharmony_ci#include <uapi/linux/batman_adv.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include "bat_algo.h"
4562306a36Sopenharmony_ci#include "bat_iv_ogm.h"
4662306a36Sopenharmony_ci#include "bat_v.h"
4762306a36Sopenharmony_ci#include "bridge_loop_avoidance.h"
4862306a36Sopenharmony_ci#include "distributed-arp-table.h"
4962306a36Sopenharmony_ci#include "gateway_client.h"
5062306a36Sopenharmony_ci#include "gateway_common.h"
5162306a36Sopenharmony_ci#include "hard-interface.h"
5262306a36Sopenharmony_ci#include "log.h"
5362306a36Sopenharmony_ci#include "multicast.h"
5462306a36Sopenharmony_ci#include "netlink.h"
5562306a36Sopenharmony_ci#include "network-coding.h"
5662306a36Sopenharmony_ci#include "originator.h"
5762306a36Sopenharmony_ci#include "routing.h"
5862306a36Sopenharmony_ci#include "send.h"
5962306a36Sopenharmony_ci#include "soft-interface.h"
6062306a36Sopenharmony_ci#include "tp_meter.h"
6162306a36Sopenharmony_ci#include "translation-table.h"
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/* List manipulations on hardif_list have to be rtnl_lock()'ed,
6462306a36Sopenharmony_ci * list traversals just rcu-locked
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_cistruct list_head batadv_hardif_list;
6762306a36Sopenharmony_ciunsigned int batadv_hardif_generation;
6862306a36Sopenharmony_cistatic int (*batadv_rx_handler[256])(struct sk_buff *skb,
6962306a36Sopenharmony_ci				     struct batadv_hard_iface *recv_if);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ciunsigned char batadv_broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct workqueue_struct *batadv_event_workqueue;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void batadv_recv_handler_init(void);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define BATADV_UEV_TYPE_VAR	"BATTYPE="
7862306a36Sopenharmony_ci#define BATADV_UEV_ACTION_VAR	"BATACTION="
7962306a36Sopenharmony_ci#define BATADV_UEV_DATA_VAR	"BATDATA="
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic char *batadv_uev_action_str[] = {
8262306a36Sopenharmony_ci	"add",
8362306a36Sopenharmony_ci	"del",
8462306a36Sopenharmony_ci	"change",
8562306a36Sopenharmony_ci	"loopdetect",
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic char *batadv_uev_type_str[] = {
8962306a36Sopenharmony_ci	"gw",
9062306a36Sopenharmony_ci	"bla",
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int __init batadv_init(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	int ret;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ret = batadv_tt_cache_init();
9862306a36Sopenharmony_ci	if (ret < 0)
9962306a36Sopenharmony_ci		return ret;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	INIT_LIST_HEAD(&batadv_hardif_list);
10262306a36Sopenharmony_ci	batadv_algo_init();
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	batadv_recv_handler_init();
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	batadv_v_init();
10762306a36Sopenharmony_ci	batadv_iv_init();
10862306a36Sopenharmony_ci	batadv_nc_init();
10962306a36Sopenharmony_ci	batadv_tp_meter_init();
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	batadv_event_workqueue = create_singlethread_workqueue("bat_events");
11262306a36Sopenharmony_ci	if (!batadv_event_workqueue)
11362306a36Sopenharmony_ci		goto err_create_wq;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	register_netdevice_notifier(&batadv_hard_if_notifier);
11662306a36Sopenharmony_ci	rtnl_link_register(&batadv_link_ops);
11762306a36Sopenharmony_ci	batadv_netlink_register();
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
12062306a36Sopenharmony_ci		BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return 0;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cierr_create_wq:
12562306a36Sopenharmony_ci	batadv_tt_cache_destroy();
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return -ENOMEM;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic void __exit batadv_exit(void)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	batadv_netlink_unregister();
13362306a36Sopenharmony_ci	rtnl_link_unregister(&batadv_link_ops);
13462306a36Sopenharmony_ci	unregister_netdevice_notifier(&batadv_hard_if_notifier);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	destroy_workqueue(batadv_event_workqueue);
13762306a36Sopenharmony_ci	batadv_event_workqueue = NULL;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	rcu_barrier();
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	batadv_tt_cache_destroy();
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/**
14562306a36Sopenharmony_ci * batadv_mesh_init() - Initialize soft interface
14662306a36Sopenharmony_ci * @soft_iface: netdev struct of the soft interface
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_ciint batadv_mesh_init(struct net_device *soft_iface)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
15362306a36Sopenharmony_ci	int ret;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	spin_lock_init(&bat_priv->forw_bat_list_lock);
15662306a36Sopenharmony_ci	spin_lock_init(&bat_priv->forw_bcast_list_lock);
15762306a36Sopenharmony_ci	spin_lock_init(&bat_priv->tt.changes_list_lock);
15862306a36Sopenharmony_ci	spin_lock_init(&bat_priv->tt.req_list_lock);
15962306a36Sopenharmony_ci	spin_lock_init(&bat_priv->tt.roam_list_lock);
16062306a36Sopenharmony_ci	spin_lock_init(&bat_priv->tt.last_changeset_lock);
16162306a36Sopenharmony_ci	spin_lock_init(&bat_priv->tt.commit_lock);
16262306a36Sopenharmony_ci	spin_lock_init(&bat_priv->gw.list_lock);
16362306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_MCAST
16462306a36Sopenharmony_ci	spin_lock_init(&bat_priv->mcast.mla_lock);
16562306a36Sopenharmony_ci	spin_lock_init(&bat_priv->mcast.want_lists_lock);
16662306a36Sopenharmony_ci#endif
16762306a36Sopenharmony_ci	spin_lock_init(&bat_priv->tvlv.container_list_lock);
16862306a36Sopenharmony_ci	spin_lock_init(&bat_priv->tvlv.handler_list_lock);
16962306a36Sopenharmony_ci	spin_lock_init(&bat_priv->softif_vlan_list_lock);
17062306a36Sopenharmony_ci	spin_lock_init(&bat_priv->tp_list_lock);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
17362306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
17462306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->gw.gateway_list);
17562306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_MCAST
17662306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_unsnoopables_list);
17762306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv4_list);
17862306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv6_list);
17962306a36Sopenharmony_ci#endif
18062306a36Sopenharmony_ci	INIT_LIST_HEAD(&bat_priv->tt.changes_list);
18162306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->tt.req_list);
18262306a36Sopenharmony_ci	INIT_LIST_HEAD(&bat_priv->tt.roam_list);
18362306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_MCAST
18462306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->mcast.mla_list);
18562306a36Sopenharmony_ci#endif
18662306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
18762306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
18862306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
18962306a36Sopenharmony_ci	INIT_HLIST_HEAD(&bat_priv->tp_list);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	bat_priv->gw.generation = 0;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	ret = batadv_originator_init(bat_priv);
19462306a36Sopenharmony_ci	if (ret < 0) {
19562306a36Sopenharmony_ci		atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
19662306a36Sopenharmony_ci		goto err_orig;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	ret = batadv_tt_init(bat_priv);
20062306a36Sopenharmony_ci	if (ret < 0) {
20162306a36Sopenharmony_ci		atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
20262306a36Sopenharmony_ci		goto err_tt;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	ret = batadv_v_mesh_init(bat_priv);
20662306a36Sopenharmony_ci	if (ret < 0) {
20762306a36Sopenharmony_ci		atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
20862306a36Sopenharmony_ci		goto err_v;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	ret = batadv_bla_init(bat_priv);
21262306a36Sopenharmony_ci	if (ret < 0) {
21362306a36Sopenharmony_ci		atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
21462306a36Sopenharmony_ci		goto err_bla;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	ret = batadv_dat_init(bat_priv);
21862306a36Sopenharmony_ci	if (ret < 0) {
21962306a36Sopenharmony_ci		atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
22062306a36Sopenharmony_ci		goto err_dat;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	ret = batadv_nc_mesh_init(bat_priv);
22462306a36Sopenharmony_ci	if (ret < 0) {
22562306a36Sopenharmony_ci		atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
22662306a36Sopenharmony_ci		goto err_nc;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	batadv_gw_init(bat_priv);
23062306a36Sopenharmony_ci	batadv_mcast_init(bat_priv);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	atomic_set(&bat_priv->gw.reselect, 0);
23362306a36Sopenharmony_ci	atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return 0;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cierr_nc:
23862306a36Sopenharmony_ci	batadv_dat_free(bat_priv);
23962306a36Sopenharmony_cierr_dat:
24062306a36Sopenharmony_ci	batadv_bla_free(bat_priv);
24162306a36Sopenharmony_cierr_bla:
24262306a36Sopenharmony_ci	batadv_v_mesh_free(bat_priv);
24362306a36Sopenharmony_cierr_v:
24462306a36Sopenharmony_ci	batadv_tt_free(bat_priv);
24562306a36Sopenharmony_cierr_tt:
24662306a36Sopenharmony_ci	batadv_originator_free(bat_priv);
24762306a36Sopenharmony_cierr_orig:
24862306a36Sopenharmony_ci	batadv_purge_outstanding_packets(bat_priv, NULL);
24962306a36Sopenharmony_ci	atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return ret;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/**
25562306a36Sopenharmony_ci * batadv_mesh_free() - Deinitialize soft interface
25662306a36Sopenharmony_ci * @soft_iface: netdev struct of the soft interface
25762306a36Sopenharmony_ci */
25862306a36Sopenharmony_civoid batadv_mesh_free(struct net_device *soft_iface)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	batadv_purge_outstanding_packets(bat_priv, NULL);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	batadv_gw_node_free(bat_priv);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	batadv_v_mesh_free(bat_priv);
26962306a36Sopenharmony_ci	batadv_nc_mesh_free(bat_priv);
27062306a36Sopenharmony_ci	batadv_dat_free(bat_priv);
27162306a36Sopenharmony_ci	batadv_bla_free(bat_priv);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	batadv_mcast_free(bat_priv);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Free the TT and the originator tables only after having terminated
27662306a36Sopenharmony_ci	 * all the other depending components which may use these structures for
27762306a36Sopenharmony_ci	 * their purposes.
27862306a36Sopenharmony_ci	 */
27962306a36Sopenharmony_ci	batadv_tt_free(bat_priv);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* Since the originator table clean up routine is accessing the TT
28262306a36Sopenharmony_ci	 * tables as well, it has to be invoked after the TT tables have been
28362306a36Sopenharmony_ci	 * freed and marked as empty. This ensures that no cleanup RCU callbacks
28462306a36Sopenharmony_ci	 * accessing the TT data are scheduled for later execution.
28562306a36Sopenharmony_ci	 */
28662306a36Sopenharmony_ci	batadv_originator_free(bat_priv);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	batadv_gw_free(bat_priv);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	free_percpu(bat_priv->bat_counters);
29162306a36Sopenharmony_ci	bat_priv->bat_counters = NULL;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci/**
29762306a36Sopenharmony_ci * batadv_is_my_mac() - check if the given mac address belongs to any of the
29862306a36Sopenharmony_ci *  real interfaces in the current mesh
29962306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
30062306a36Sopenharmony_ci * @addr: the address to check
30162306a36Sopenharmony_ci *
30262306a36Sopenharmony_ci * Return: 'true' if the mac address was found, false otherwise.
30362306a36Sopenharmony_ci */
30462306a36Sopenharmony_cibool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	const struct batadv_hard_iface *hard_iface;
30762306a36Sopenharmony_ci	bool is_my_mac = false;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	rcu_read_lock();
31062306a36Sopenharmony_ci	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
31162306a36Sopenharmony_ci		if (hard_iface->if_status != BATADV_IF_ACTIVE)
31262306a36Sopenharmony_ci			continue;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		if (hard_iface->soft_iface != bat_priv->soft_iface)
31562306a36Sopenharmony_ci			continue;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) {
31862306a36Sopenharmony_ci			is_my_mac = true;
31962306a36Sopenharmony_ci			break;
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci	rcu_read_unlock();
32362306a36Sopenharmony_ci	return is_my_mac;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/**
32762306a36Sopenharmony_ci * batadv_max_header_len() - calculate maximum encapsulation overhead for a
32862306a36Sopenharmony_ci *  payload packet
32962306a36Sopenharmony_ci *
33062306a36Sopenharmony_ci * Return: the maximum encapsulation overhead in bytes.
33162306a36Sopenharmony_ci */
33262306a36Sopenharmony_ciint batadv_max_header_len(void)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	int header_len = 0;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	header_len = max_t(int, header_len,
33762306a36Sopenharmony_ci			   sizeof(struct batadv_unicast_packet));
33862306a36Sopenharmony_ci	header_len = max_t(int, header_len,
33962306a36Sopenharmony_ci			   sizeof(struct batadv_unicast_4addr_packet));
34062306a36Sopenharmony_ci	header_len = max_t(int, header_len,
34162306a36Sopenharmony_ci			   sizeof(struct batadv_bcast_packet));
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_NC
34462306a36Sopenharmony_ci	header_len = max_t(int, header_len,
34562306a36Sopenharmony_ci			   sizeof(struct batadv_coded_packet));
34662306a36Sopenharmony_ci#endif
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return header_len + ETH_HLEN;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/**
35262306a36Sopenharmony_ci * batadv_skb_set_priority() - sets skb priority according to packet content
35362306a36Sopenharmony_ci * @skb: the packet to be sent
35462306a36Sopenharmony_ci * @offset: offset to the packet content
35562306a36Sopenharmony_ci *
35662306a36Sopenharmony_ci * This function sets a value between 256 and 263 (802.1d priority), which
35762306a36Sopenharmony_ci * can be interpreted by the cfg80211 or other drivers.
35862306a36Sopenharmony_ci */
35962306a36Sopenharmony_civoid batadv_skb_set_priority(struct sk_buff *skb, int offset)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct iphdr ip_hdr_tmp, *ip_hdr;
36262306a36Sopenharmony_ci	struct ipv6hdr ip6_hdr_tmp, *ip6_hdr;
36362306a36Sopenharmony_ci	struct ethhdr ethhdr_tmp, *ethhdr;
36462306a36Sopenharmony_ci	struct vlan_ethhdr *vhdr, vhdr_tmp;
36562306a36Sopenharmony_ci	u32 prio;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* already set, do nothing */
36862306a36Sopenharmony_ci	if (skb->priority >= 256 && skb->priority <= 263)
36962306a36Sopenharmony_ci		return;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	ethhdr = skb_header_pointer(skb, offset, sizeof(*ethhdr), &ethhdr_tmp);
37262306a36Sopenharmony_ci	if (!ethhdr)
37362306a36Sopenharmony_ci		return;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	switch (ethhdr->h_proto) {
37662306a36Sopenharmony_ci	case htons(ETH_P_8021Q):
37762306a36Sopenharmony_ci		vhdr = skb_header_pointer(skb, offset + sizeof(*vhdr),
37862306a36Sopenharmony_ci					  sizeof(*vhdr), &vhdr_tmp);
37962306a36Sopenharmony_ci		if (!vhdr)
38062306a36Sopenharmony_ci			return;
38162306a36Sopenharmony_ci		prio = ntohs(vhdr->h_vlan_TCI) & VLAN_PRIO_MASK;
38262306a36Sopenharmony_ci		prio = prio >> VLAN_PRIO_SHIFT;
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci	case htons(ETH_P_IP):
38562306a36Sopenharmony_ci		ip_hdr = skb_header_pointer(skb, offset + sizeof(*ethhdr),
38662306a36Sopenharmony_ci					    sizeof(*ip_hdr), &ip_hdr_tmp);
38762306a36Sopenharmony_ci		if (!ip_hdr)
38862306a36Sopenharmony_ci			return;
38962306a36Sopenharmony_ci		prio = (ipv4_get_dsfield(ip_hdr) & 0xfc) >> 5;
39062306a36Sopenharmony_ci		break;
39162306a36Sopenharmony_ci	case htons(ETH_P_IPV6):
39262306a36Sopenharmony_ci		ip6_hdr = skb_header_pointer(skb, offset + sizeof(*ethhdr),
39362306a36Sopenharmony_ci					     sizeof(*ip6_hdr), &ip6_hdr_tmp);
39462306a36Sopenharmony_ci		if (!ip6_hdr)
39562306a36Sopenharmony_ci			return;
39662306a36Sopenharmony_ci		prio = (ipv6_get_dsfield(ip6_hdr) & 0xfc) >> 5;
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	default:
39962306a36Sopenharmony_ci		return;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	skb->priority = prio + 256;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic int batadv_recv_unhandled_packet(struct sk_buff *skb,
40662306a36Sopenharmony_ci					struct batadv_hard_iface *recv_if)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	kfree_skb(skb);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	return NET_RX_DROP;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/* incoming packets with the batman ethertype received on any active hard
41462306a36Sopenharmony_ci * interface
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/**
41862306a36Sopenharmony_ci * batadv_batman_skb_recv() - Handle incoming message from an hard interface
41962306a36Sopenharmony_ci * @skb: the received packet
42062306a36Sopenharmony_ci * @dev: the net device that the packet was received on
42162306a36Sopenharmony_ci * @ptype: packet type of incoming packet (ETH_P_BATMAN)
42262306a36Sopenharmony_ci * @orig_dev: the original receive net device (e.g. bonded device)
42362306a36Sopenharmony_ci *
42462306a36Sopenharmony_ci * Return: NET_RX_SUCCESS on success or NET_RX_DROP in case of failure
42562306a36Sopenharmony_ci */
42662306a36Sopenharmony_ciint batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
42762306a36Sopenharmony_ci			   struct packet_type *ptype,
42862306a36Sopenharmony_ci			   struct net_device *orig_dev)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct batadv_priv *bat_priv;
43162306a36Sopenharmony_ci	struct batadv_ogm_packet *batadv_ogm_packet;
43262306a36Sopenharmony_ci	struct batadv_hard_iface *hard_iface;
43362306a36Sopenharmony_ci	u8 idx;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	hard_iface = container_of(ptype, struct batadv_hard_iface,
43662306a36Sopenharmony_ci				  batman_adv_ptype);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* Prevent processing a packet received on an interface which is getting
43962306a36Sopenharmony_ci	 * shut down otherwise the packet may trigger de-reference errors
44062306a36Sopenharmony_ci	 * further down in the receive path.
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci	if (!kref_get_unless_zero(&hard_iface->refcount))
44362306a36Sopenharmony_ci		goto err_out;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	skb = skb_share_check(skb, GFP_ATOMIC);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* skb was released by skb_share_check() */
44862306a36Sopenharmony_ci	if (!skb)
44962306a36Sopenharmony_ci		goto err_put;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/* packet should hold at least type and version */
45262306a36Sopenharmony_ci	if (unlikely(!pskb_may_pull(skb, 2)))
45362306a36Sopenharmony_ci		goto err_free;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* expect a valid ethernet header here. */
45662306a36Sopenharmony_ci	if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb)))
45762306a36Sopenharmony_ci		goto err_free;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (!hard_iface->soft_iface)
46062306a36Sopenharmony_ci		goto err_free;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	bat_priv = netdev_priv(hard_iface->soft_iface);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
46562306a36Sopenharmony_ci		goto err_free;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/* discard frames on not active interfaces */
46862306a36Sopenharmony_ci	if (hard_iface->if_status != BATADV_IF_ACTIVE)
46962306a36Sopenharmony_ci		goto err_free;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (batadv_ogm_packet->version != BATADV_COMPAT_VERSION) {
47462306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
47562306a36Sopenharmony_ci			   "Drop packet: incompatible batman version (%i)\n",
47662306a36Sopenharmony_ci			   batadv_ogm_packet->version);
47762306a36Sopenharmony_ci		goto err_free;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* reset control block to avoid left overs from previous users */
48162306a36Sopenharmony_ci	memset(skb->cb, 0, sizeof(struct batadv_skb_cb));
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	idx = batadv_ogm_packet->packet_type;
48462306a36Sopenharmony_ci	(*batadv_rx_handler[idx])(skb, hard_iface);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	batadv_hardif_put(hard_iface);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* return NET_RX_SUCCESS in any case as we
48962306a36Sopenharmony_ci	 * most probably dropped the packet for
49062306a36Sopenharmony_ci	 * routing-logical reasons.
49162306a36Sopenharmony_ci	 */
49262306a36Sopenharmony_ci	return NET_RX_SUCCESS;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cierr_free:
49562306a36Sopenharmony_ci	kfree_skb(skb);
49662306a36Sopenharmony_cierr_put:
49762306a36Sopenharmony_ci	batadv_hardif_put(hard_iface);
49862306a36Sopenharmony_cierr_out:
49962306a36Sopenharmony_ci	return NET_RX_DROP;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic void batadv_recv_handler_init(void)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	int i;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++)
50762306a36Sopenharmony_ci		batadv_rx_handler[i] = batadv_recv_unhandled_packet;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++)
51062306a36Sopenharmony_ci		batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* compile time checks for sizes */
51362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_bla_claim_dst) != 6);
51462306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_ogm_packet) != 24);
51562306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_icmp_header) != 20);
51662306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_icmp_packet) != 20);
51762306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_icmp_packet_rr) != 116);
51862306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10);
51962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18);
52062306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20);
52162306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_bcast_packet) != 14);
52262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_coded_packet) != 46);
52362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_unicast_tvlv_packet) != 20);
52462306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_tvlv_hdr) != 4);
52562306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_tvlv_gateway_data) != 8);
52662306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_vlan_data) != 8);
52762306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12);
52862306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	i = sizeof_field(struct sk_buff, cb);
53162306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct batadv_skb_cb) > i);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* broadcast packet */
53462306a36Sopenharmony_ci	batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* unicast packets ... */
53762306a36Sopenharmony_ci	/* unicast with 4 addresses packet */
53862306a36Sopenharmony_ci	batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet;
53962306a36Sopenharmony_ci	/* unicast packet */
54062306a36Sopenharmony_ci	batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet;
54162306a36Sopenharmony_ci	/* unicast tvlv packet */
54262306a36Sopenharmony_ci	batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv;
54362306a36Sopenharmony_ci	/* batman icmp packet */
54462306a36Sopenharmony_ci	batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet;
54562306a36Sopenharmony_ci	/* Fragmented packets */
54662306a36Sopenharmony_ci	batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_frag_packet;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/**
55062306a36Sopenharmony_ci * batadv_recv_handler_register() - Register handler for batman-adv packet type
55162306a36Sopenharmony_ci * @packet_type: batadv_packettype which should be handled
55262306a36Sopenharmony_ci * @recv_handler: receive handler for the packet type
55362306a36Sopenharmony_ci *
55462306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure
55562306a36Sopenharmony_ci */
55662306a36Sopenharmony_ciint
55762306a36Sopenharmony_cibatadv_recv_handler_register(u8 packet_type,
55862306a36Sopenharmony_ci			     int (*recv_handler)(struct sk_buff *,
55962306a36Sopenharmony_ci						 struct batadv_hard_iface *))
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	int (*curr)(struct sk_buff *skb,
56262306a36Sopenharmony_ci		    struct batadv_hard_iface *recv_if);
56362306a36Sopenharmony_ci	curr = batadv_rx_handler[packet_type];
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	if (curr != batadv_recv_unhandled_packet &&
56662306a36Sopenharmony_ci	    curr != batadv_recv_unhandled_unicast_packet)
56762306a36Sopenharmony_ci		return -EBUSY;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	batadv_rx_handler[packet_type] = recv_handler;
57062306a36Sopenharmony_ci	return 0;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/**
57462306a36Sopenharmony_ci * batadv_recv_handler_unregister() - Unregister handler for packet type
57562306a36Sopenharmony_ci * @packet_type: batadv_packettype which should no longer be handled
57662306a36Sopenharmony_ci */
57762306a36Sopenharmony_civoid batadv_recv_handler_unregister(u8 packet_type)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	batadv_rx_handler[packet_type] = batadv_recv_unhandled_packet;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci/**
58362306a36Sopenharmony_ci * batadv_skb_crc32() - calculate CRC32 of the whole packet and skip bytes in
58462306a36Sopenharmony_ci *  the header
58562306a36Sopenharmony_ci * @skb: skb pointing to fragmented socket buffers
58662306a36Sopenharmony_ci * @payload_ptr: Pointer to position inside the head buffer of the skb
58762306a36Sopenharmony_ci *  marking the start of the data to be CRC'ed
58862306a36Sopenharmony_ci *
58962306a36Sopenharmony_ci * payload_ptr must always point to an address in the skb head buffer and not to
59062306a36Sopenharmony_ci * a fragment.
59162306a36Sopenharmony_ci *
59262306a36Sopenharmony_ci * Return: big endian crc32c of the checksummed data
59362306a36Sopenharmony_ci */
59462306a36Sopenharmony_ci__be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	u32 crc = 0;
59762306a36Sopenharmony_ci	unsigned int from;
59862306a36Sopenharmony_ci	unsigned int to = skb->len;
59962306a36Sopenharmony_ci	struct skb_seq_state st;
60062306a36Sopenharmony_ci	const u8 *data;
60162306a36Sopenharmony_ci	unsigned int len;
60262306a36Sopenharmony_ci	unsigned int consumed = 0;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	from = (unsigned int)(payload_ptr - skb->data);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	skb_prepare_seq_read(skb, from, to, &st);
60762306a36Sopenharmony_ci	while ((len = skb_seq_read(consumed, &data, &st)) != 0) {
60862306a36Sopenharmony_ci		crc = crc32c(crc, data, len);
60962306a36Sopenharmony_ci		consumed += len;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return htonl(crc);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci/**
61662306a36Sopenharmony_ci * batadv_get_vid() - extract the VLAN identifier from skb if any
61762306a36Sopenharmony_ci * @skb: the buffer containing the packet
61862306a36Sopenharmony_ci * @header_len: length of the batman header preceding the ethernet header
61962306a36Sopenharmony_ci *
62062306a36Sopenharmony_ci * Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the
62162306a36Sopenharmony_ci * skb is vlan tagged. Otherwise BATADV_NO_FLAGS.
62262306a36Sopenharmony_ci */
62362306a36Sopenharmony_ciunsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct ethhdr *ethhdr = (struct ethhdr *)(skb->data + header_len);
62662306a36Sopenharmony_ci	struct vlan_ethhdr *vhdr;
62762306a36Sopenharmony_ci	unsigned short vid;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if (ethhdr->h_proto != htons(ETH_P_8021Q))
63062306a36Sopenharmony_ci		return BATADV_NO_FLAGS;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (!pskb_may_pull(skb, header_len + VLAN_ETH_HLEN))
63362306a36Sopenharmony_ci		return BATADV_NO_FLAGS;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	vhdr = (struct vlan_ethhdr *)(skb->data + header_len);
63662306a36Sopenharmony_ci	vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
63762306a36Sopenharmony_ci	vid |= BATADV_VLAN_HAS_TAG;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return vid;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci/**
64362306a36Sopenharmony_ci * batadv_vlan_ap_isola_get() - return AP isolation status for the given vlan
64462306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
64562306a36Sopenharmony_ci * @vid: the VLAN identifier for which the AP isolation attributed as to be
64662306a36Sopenharmony_ci *  looked up
64762306a36Sopenharmony_ci *
64862306a36Sopenharmony_ci * Return: true if AP isolation is on for the VLAN identified by vid, false
64962306a36Sopenharmony_ci * otherwise
65062306a36Sopenharmony_ci */
65162306a36Sopenharmony_cibool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	bool ap_isolation_enabled = false;
65462306a36Sopenharmony_ci	struct batadv_softif_vlan *vlan;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/* if the AP isolation is requested on a VLAN, then check for its
65762306a36Sopenharmony_ci	 * setting in the proper VLAN private data structure
65862306a36Sopenharmony_ci	 */
65962306a36Sopenharmony_ci	vlan = batadv_softif_vlan_get(bat_priv, vid);
66062306a36Sopenharmony_ci	if (vlan) {
66162306a36Sopenharmony_ci		ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
66262306a36Sopenharmony_ci		batadv_softif_vlan_put(vlan);
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	return ap_isolation_enabled;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci/**
66962306a36Sopenharmony_ci * batadv_throw_uevent() - Send an uevent with batman-adv specific env data
67062306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
67162306a36Sopenharmony_ci * @type: subsystem type of event. Stored in uevent's BATTYPE
67262306a36Sopenharmony_ci * @action: action type of event. Stored in uevent's BATACTION
67362306a36Sopenharmony_ci * @data: string with additional information to the event (ignored for
67462306a36Sopenharmony_ci *  BATADV_UEV_DEL). Stored in uevent's BATDATA
67562306a36Sopenharmony_ci *
67662306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure
67762306a36Sopenharmony_ci */
67862306a36Sopenharmony_ciint batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type,
67962306a36Sopenharmony_ci			enum batadv_uev_action action, const char *data)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	int ret = -ENOMEM;
68262306a36Sopenharmony_ci	struct kobject *bat_kobj;
68362306a36Sopenharmony_ci	char *uevent_env[4] = { NULL, NULL, NULL, NULL };
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	bat_kobj = &bat_priv->soft_iface->dev.kobj;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	uevent_env[0] = kasprintf(GFP_ATOMIC,
68862306a36Sopenharmony_ci				  "%s%s", BATADV_UEV_TYPE_VAR,
68962306a36Sopenharmony_ci				  batadv_uev_type_str[type]);
69062306a36Sopenharmony_ci	if (!uevent_env[0])
69162306a36Sopenharmony_ci		goto out;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	uevent_env[1] = kasprintf(GFP_ATOMIC,
69462306a36Sopenharmony_ci				  "%s%s", BATADV_UEV_ACTION_VAR,
69562306a36Sopenharmony_ci				  batadv_uev_action_str[action]);
69662306a36Sopenharmony_ci	if (!uevent_env[1])
69762306a36Sopenharmony_ci		goto out;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/* If the event is DEL, ignore the data field */
70062306a36Sopenharmony_ci	if (action != BATADV_UEV_DEL) {
70162306a36Sopenharmony_ci		uevent_env[2] = kasprintf(GFP_ATOMIC,
70262306a36Sopenharmony_ci					  "%s%s", BATADV_UEV_DATA_VAR, data);
70362306a36Sopenharmony_ci		if (!uevent_env[2])
70462306a36Sopenharmony_ci			goto out;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
70862306a36Sopenharmony_ciout:
70962306a36Sopenharmony_ci	kfree(uevent_env[0]);
71062306a36Sopenharmony_ci	kfree(uevent_env[1]);
71162306a36Sopenharmony_ci	kfree(uevent_env[2]);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (ret)
71462306a36Sopenharmony_ci		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
71562306a36Sopenharmony_ci			   "Impossible to send uevent for (%s,%s,%s) event (err: %d)\n",
71662306a36Sopenharmony_ci			   batadv_uev_type_str[type],
71762306a36Sopenharmony_ci			   batadv_uev_action_str[action],
71862306a36Sopenharmony_ci			   (action == BATADV_UEV_DEL ? "NULL" : data), ret);
71962306a36Sopenharmony_ci	return ret;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cimodule_init(batadv_init);
72362306a36Sopenharmony_cimodule_exit(batadv_exit);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ciMODULE_AUTHOR(BATADV_DRIVER_AUTHOR);
72862306a36Sopenharmony_ciMODULE_DESCRIPTION(BATADV_DRIVER_DESC);
72962306a36Sopenharmony_ciMODULE_VERSION(BATADV_SOURCE_VERSION);
73062306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("batadv");
73162306a36Sopenharmony_ciMODULE_ALIAS_GENL_FAMILY(BATADV_NL_NAME);
732