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), ðhdr_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