162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (C) B.A.T.M.A.N. contributors: 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Matthias Schiffer 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "netlink.h" 862306a36Sopenharmony_ci#include "main.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/atomic.h> 1162306a36Sopenharmony_ci#include <linux/bitops.h> 1262306a36Sopenharmony_ci#include <linux/bug.h> 1362306a36Sopenharmony_ci#include <linux/byteorder/generic.h> 1462306a36Sopenharmony_ci#include <linux/cache.h> 1562306a36Sopenharmony_ci#include <linux/err.h> 1662306a36Sopenharmony_ci#include <linux/errno.h> 1762306a36Sopenharmony_ci#include <linux/export.h> 1862306a36Sopenharmony_ci#include <linux/genetlink.h> 1962306a36Sopenharmony_ci#include <linux/gfp.h> 2062306a36Sopenharmony_ci#include <linux/if_ether.h> 2162306a36Sopenharmony_ci#include <linux/if_vlan.h> 2262306a36Sopenharmony_ci#include <linux/init.h> 2362306a36Sopenharmony_ci#include <linux/kernel.h> 2462306a36Sopenharmony_ci#include <linux/limits.h> 2562306a36Sopenharmony_ci#include <linux/list.h> 2662306a36Sopenharmony_ci#include <linux/minmax.h> 2762306a36Sopenharmony_ci#include <linux/netdevice.h> 2862306a36Sopenharmony_ci#include <linux/netlink.h> 2962306a36Sopenharmony_ci#include <linux/printk.h> 3062306a36Sopenharmony_ci#include <linux/rtnetlink.h> 3162306a36Sopenharmony_ci#include <linux/skbuff.h> 3262306a36Sopenharmony_ci#include <linux/stddef.h> 3362306a36Sopenharmony_ci#include <linux/types.h> 3462306a36Sopenharmony_ci#include <net/genetlink.h> 3562306a36Sopenharmony_ci#include <net/net_namespace.h> 3662306a36Sopenharmony_ci#include <net/netlink.h> 3762306a36Sopenharmony_ci#include <net/sock.h> 3862306a36Sopenharmony_ci#include <uapi/linux/batadv_packet.h> 3962306a36Sopenharmony_ci#include <uapi/linux/batman_adv.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "bat_algo.h" 4262306a36Sopenharmony_ci#include "bridge_loop_avoidance.h" 4362306a36Sopenharmony_ci#include "distributed-arp-table.h" 4462306a36Sopenharmony_ci#include "gateway_client.h" 4562306a36Sopenharmony_ci#include "gateway_common.h" 4662306a36Sopenharmony_ci#include "hard-interface.h" 4762306a36Sopenharmony_ci#include "log.h" 4862306a36Sopenharmony_ci#include "multicast.h" 4962306a36Sopenharmony_ci#include "network-coding.h" 5062306a36Sopenharmony_ci#include "originator.h" 5162306a36Sopenharmony_ci#include "soft-interface.h" 5262306a36Sopenharmony_ci#include "tp_meter.h" 5362306a36Sopenharmony_ci#include "translation-table.h" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct genl_family batadv_netlink_family; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* multicast groups */ 5862306a36Sopenharmony_cienum batadv_netlink_multicast_groups { 5962306a36Sopenharmony_ci BATADV_NL_MCGRP_CONFIG, 6062306a36Sopenharmony_ci BATADV_NL_MCGRP_TPMETER, 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/** 6462306a36Sopenharmony_ci * enum batadv_genl_ops_flags - flags for genl_ops's internal_flags 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cienum batadv_genl_ops_flags { 6762306a36Sopenharmony_ci /** 6862306a36Sopenharmony_ci * @BATADV_FLAG_NEED_MESH: request requires valid soft interface in 6962306a36Sopenharmony_ci * attribute BATADV_ATTR_MESH_IFINDEX and expects a pointer to it to be 7062306a36Sopenharmony_ci * saved in info->user_ptr[0] 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci BATADV_FLAG_NEED_MESH = BIT(0), 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /** 7562306a36Sopenharmony_ci * @BATADV_FLAG_NEED_HARDIF: request requires valid hard interface in 7662306a36Sopenharmony_ci * attribute BATADV_ATTR_HARD_IFINDEX and expects a pointer to it to be 7762306a36Sopenharmony_ci * saved in info->user_ptr[1] 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci BATADV_FLAG_NEED_HARDIF = BIT(1), 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /** 8262306a36Sopenharmony_ci * @BATADV_FLAG_NEED_VLAN: request requires valid vlan in 8362306a36Sopenharmony_ci * attribute BATADV_ATTR_VLANID and expects a pointer to it to be 8462306a36Sopenharmony_ci * saved in info->user_ptr[1] 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci BATADV_FLAG_NEED_VLAN = BIT(2), 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const struct genl_multicast_group batadv_netlink_mcgrps[] = { 9062306a36Sopenharmony_ci [BATADV_NL_MCGRP_CONFIG] = { .name = BATADV_NL_MCAST_GROUP_CONFIG }, 9162306a36Sopenharmony_ci [BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER }, 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { 9562306a36Sopenharmony_ci [BATADV_ATTR_VERSION] = { .type = NLA_STRING }, 9662306a36Sopenharmony_ci [BATADV_ATTR_ALGO_NAME] = { .type = NLA_STRING }, 9762306a36Sopenharmony_ci [BATADV_ATTR_MESH_IFINDEX] = { .type = NLA_U32 }, 9862306a36Sopenharmony_ci [BATADV_ATTR_MESH_IFNAME] = { .type = NLA_STRING }, 9962306a36Sopenharmony_ci [BATADV_ATTR_MESH_ADDRESS] = { .len = ETH_ALEN }, 10062306a36Sopenharmony_ci [BATADV_ATTR_HARD_IFINDEX] = { .type = NLA_U32 }, 10162306a36Sopenharmony_ci [BATADV_ATTR_HARD_IFNAME] = { .type = NLA_STRING }, 10262306a36Sopenharmony_ci [BATADV_ATTR_HARD_ADDRESS] = { .len = ETH_ALEN }, 10362306a36Sopenharmony_ci [BATADV_ATTR_ORIG_ADDRESS] = { .len = ETH_ALEN }, 10462306a36Sopenharmony_ci [BATADV_ATTR_TPMETER_RESULT] = { .type = NLA_U8 }, 10562306a36Sopenharmony_ci [BATADV_ATTR_TPMETER_TEST_TIME] = { .type = NLA_U32 }, 10662306a36Sopenharmony_ci [BATADV_ATTR_TPMETER_BYTES] = { .type = NLA_U64 }, 10762306a36Sopenharmony_ci [BATADV_ATTR_TPMETER_COOKIE] = { .type = NLA_U32 }, 10862306a36Sopenharmony_ci [BATADV_ATTR_ACTIVE] = { .type = NLA_FLAG }, 10962306a36Sopenharmony_ci [BATADV_ATTR_TT_ADDRESS] = { .len = ETH_ALEN }, 11062306a36Sopenharmony_ci [BATADV_ATTR_TT_TTVN] = { .type = NLA_U8 }, 11162306a36Sopenharmony_ci [BATADV_ATTR_TT_LAST_TTVN] = { .type = NLA_U8 }, 11262306a36Sopenharmony_ci [BATADV_ATTR_TT_CRC32] = { .type = NLA_U32 }, 11362306a36Sopenharmony_ci [BATADV_ATTR_TT_VID] = { .type = NLA_U16 }, 11462306a36Sopenharmony_ci [BATADV_ATTR_TT_FLAGS] = { .type = NLA_U32 }, 11562306a36Sopenharmony_ci [BATADV_ATTR_FLAG_BEST] = { .type = NLA_FLAG }, 11662306a36Sopenharmony_ci [BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NLA_U32 }, 11762306a36Sopenharmony_ci [BATADV_ATTR_NEIGH_ADDRESS] = { .len = ETH_ALEN }, 11862306a36Sopenharmony_ci [BATADV_ATTR_TQ] = { .type = NLA_U8 }, 11962306a36Sopenharmony_ci [BATADV_ATTR_THROUGHPUT] = { .type = NLA_U32 }, 12062306a36Sopenharmony_ci [BATADV_ATTR_BANDWIDTH_UP] = { .type = NLA_U32 }, 12162306a36Sopenharmony_ci [BATADV_ATTR_BANDWIDTH_DOWN] = { .type = NLA_U32 }, 12262306a36Sopenharmony_ci [BATADV_ATTR_ROUTER] = { .len = ETH_ALEN }, 12362306a36Sopenharmony_ci [BATADV_ATTR_BLA_OWN] = { .type = NLA_FLAG }, 12462306a36Sopenharmony_ci [BATADV_ATTR_BLA_ADDRESS] = { .len = ETH_ALEN }, 12562306a36Sopenharmony_ci [BATADV_ATTR_BLA_VID] = { .type = NLA_U16 }, 12662306a36Sopenharmony_ci [BATADV_ATTR_BLA_BACKBONE] = { .len = ETH_ALEN }, 12762306a36Sopenharmony_ci [BATADV_ATTR_BLA_CRC] = { .type = NLA_U16 }, 12862306a36Sopenharmony_ci [BATADV_ATTR_DAT_CACHE_IP4ADDRESS] = { .type = NLA_U32 }, 12962306a36Sopenharmony_ci [BATADV_ATTR_DAT_CACHE_HWADDRESS] = { .len = ETH_ALEN }, 13062306a36Sopenharmony_ci [BATADV_ATTR_DAT_CACHE_VID] = { .type = NLA_U16 }, 13162306a36Sopenharmony_ci [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 }, 13262306a36Sopenharmony_ci [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 }, 13362306a36Sopenharmony_ci [BATADV_ATTR_VLANID] = { .type = NLA_U16 }, 13462306a36Sopenharmony_ci [BATADV_ATTR_AGGREGATED_OGMS_ENABLED] = { .type = NLA_U8 }, 13562306a36Sopenharmony_ci [BATADV_ATTR_AP_ISOLATION_ENABLED] = { .type = NLA_U8 }, 13662306a36Sopenharmony_ci [BATADV_ATTR_ISOLATION_MARK] = { .type = NLA_U32 }, 13762306a36Sopenharmony_ci [BATADV_ATTR_ISOLATION_MASK] = { .type = NLA_U32 }, 13862306a36Sopenharmony_ci [BATADV_ATTR_BONDING_ENABLED] = { .type = NLA_U8 }, 13962306a36Sopenharmony_ci [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED] = { .type = NLA_U8 }, 14062306a36Sopenharmony_ci [BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED] = { .type = NLA_U8 }, 14162306a36Sopenharmony_ci [BATADV_ATTR_FRAGMENTATION_ENABLED] = { .type = NLA_U8 }, 14262306a36Sopenharmony_ci [BATADV_ATTR_GW_BANDWIDTH_DOWN] = { .type = NLA_U32 }, 14362306a36Sopenharmony_ci [BATADV_ATTR_GW_BANDWIDTH_UP] = { .type = NLA_U32 }, 14462306a36Sopenharmony_ci [BATADV_ATTR_GW_MODE] = { .type = NLA_U8 }, 14562306a36Sopenharmony_ci [BATADV_ATTR_GW_SEL_CLASS] = { .type = NLA_U32 }, 14662306a36Sopenharmony_ci [BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 }, 14762306a36Sopenharmony_ci [BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 }, 14862306a36Sopenharmony_ci [BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED] = { .type = NLA_U8 }, 14962306a36Sopenharmony_ci [BATADV_ATTR_MULTICAST_FANOUT] = { .type = NLA_U32 }, 15062306a36Sopenharmony_ci [BATADV_ATTR_NETWORK_CODING_ENABLED] = { .type = NLA_U8 }, 15162306a36Sopenharmony_ci [BATADV_ATTR_ORIG_INTERVAL] = { .type = NLA_U32 }, 15262306a36Sopenharmony_ci [BATADV_ATTR_ELP_INTERVAL] = { .type = NLA_U32 }, 15362306a36Sopenharmony_ci [BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NLA_U32 }, 15462306a36Sopenharmony_ci}; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/** 15762306a36Sopenharmony_ci * batadv_netlink_get_ifindex() - Extract an interface index from a message 15862306a36Sopenharmony_ci * @nlh: Message header 15962306a36Sopenharmony_ci * @attrtype: Attribute which holds an interface index 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * Return: interface index, or 0. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ciint 16462306a36Sopenharmony_cibatadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct nlattr *attr = nlmsg_find_attr(nlh, GENL_HDRLEN, attrtype); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return (attr && nla_len(attr) == sizeof(u32)) ? nla_get_u32(attr) : 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * batadv_netlink_mesh_fill_ap_isolation() - Add ap_isolation softif attribute 17362306a36Sopenharmony_ci * @msg: Netlink message to dump into 17462306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_cistatic int batadv_netlink_mesh_fill_ap_isolation(struct sk_buff *msg, 17962306a36Sopenharmony_ci struct batadv_priv *bat_priv) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct batadv_softif_vlan *vlan; 18262306a36Sopenharmony_ci u8 ap_isolation; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); 18562306a36Sopenharmony_ci if (!vlan) 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ap_isolation = atomic_read(&vlan->ap_isolation); 18962306a36Sopenharmony_ci batadv_softif_vlan_put(vlan); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION_ENABLED, 19262306a36Sopenharmony_ci !!ap_isolation); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/** 19662306a36Sopenharmony_ci * batadv_netlink_set_mesh_ap_isolation() - Set ap_isolation from genl msg 19762306a36Sopenharmony_ci * @attr: parsed BATADV_ATTR_AP_ISOLATION_ENABLED attribute 19862306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic int batadv_netlink_set_mesh_ap_isolation(struct nlattr *attr, 20362306a36Sopenharmony_ci struct batadv_priv *bat_priv) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct batadv_softif_vlan *vlan; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); 20862306a36Sopenharmony_ci if (!vlan) 20962306a36Sopenharmony_ci return -ENOENT; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr)); 21262306a36Sopenharmony_ci batadv_softif_vlan_put(vlan); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/** 21862306a36Sopenharmony_ci * batadv_netlink_mesh_fill() - Fill message with mesh attributes 21962306a36Sopenharmony_ci * @msg: Netlink message to dump into 22062306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 22162306a36Sopenharmony_ci * @cmd: type of message to generate 22262306a36Sopenharmony_ci * @portid: Port making netlink request 22362306a36Sopenharmony_ci * @seq: sequence number for message 22462306a36Sopenharmony_ci * @flags: Additional flags for message 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_cistatic int batadv_netlink_mesh_fill(struct sk_buff *msg, 22962306a36Sopenharmony_ci struct batadv_priv *bat_priv, 23062306a36Sopenharmony_ci enum batadv_nl_commands cmd, 23162306a36Sopenharmony_ci u32 portid, u32 seq, int flags) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct net_device *soft_iface = bat_priv->soft_iface; 23462306a36Sopenharmony_ci struct batadv_hard_iface *primary_if = NULL; 23562306a36Sopenharmony_ci struct net_device *hard_iface; 23662306a36Sopenharmony_ci void *hdr; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd); 23962306a36Sopenharmony_ci if (!hdr) 24062306a36Sopenharmony_ci return -ENOBUFS; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) || 24362306a36Sopenharmony_ci nla_put_string(msg, BATADV_ATTR_ALGO_NAME, 24462306a36Sopenharmony_ci bat_priv->algo_ops->name) || 24562306a36Sopenharmony_ci nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, soft_iface->ifindex) || 24662306a36Sopenharmony_ci nla_put_string(msg, BATADV_ATTR_MESH_IFNAME, soft_iface->name) || 24762306a36Sopenharmony_ci nla_put(msg, BATADV_ATTR_MESH_ADDRESS, ETH_ALEN, 24862306a36Sopenharmony_ci soft_iface->dev_addr) || 24962306a36Sopenharmony_ci nla_put_u8(msg, BATADV_ATTR_TT_TTVN, 25062306a36Sopenharmony_ci (u8)atomic_read(&bat_priv->tt.vn))) 25162306a36Sopenharmony_ci goto nla_put_failure; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BLA 25462306a36Sopenharmony_ci if (nla_put_u16(msg, BATADV_ATTR_BLA_CRC, 25562306a36Sopenharmony_ci ntohs(bat_priv->bla.claim_dest.group))) 25662306a36Sopenharmony_ci goto nla_put_failure; 25762306a36Sopenharmony_ci#endif 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (batadv_mcast_mesh_info_put(msg, bat_priv)) 26062306a36Sopenharmony_ci goto nla_put_failure; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci primary_if = batadv_primary_if_get_selected(bat_priv); 26362306a36Sopenharmony_ci if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) { 26462306a36Sopenharmony_ci hard_iface = primary_if->net_dev; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, 26762306a36Sopenharmony_ci hard_iface->ifindex) || 26862306a36Sopenharmony_ci nla_put_string(msg, BATADV_ATTR_HARD_IFNAME, 26962306a36Sopenharmony_ci hard_iface->name) || 27062306a36Sopenharmony_ci nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN, 27162306a36Sopenharmony_ci hard_iface->dev_addr)) 27262306a36Sopenharmony_ci goto nla_put_failure; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_AGGREGATED_OGMS_ENABLED, 27662306a36Sopenharmony_ci !!atomic_read(&bat_priv->aggregated_ogms))) 27762306a36Sopenharmony_ci goto nla_put_failure; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (batadv_netlink_mesh_fill_ap_isolation(msg, bat_priv)) 28062306a36Sopenharmony_ci goto nla_put_failure; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_ISOLATION_MARK, 28362306a36Sopenharmony_ci bat_priv->isolation_mark)) 28462306a36Sopenharmony_ci goto nla_put_failure; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_ISOLATION_MASK, 28762306a36Sopenharmony_ci bat_priv->isolation_mark_mask)) 28862306a36Sopenharmony_ci goto nla_put_failure; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_BONDING_ENABLED, 29162306a36Sopenharmony_ci !!atomic_read(&bat_priv->bonding))) 29262306a36Sopenharmony_ci goto nla_put_failure; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BLA 29562306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED, 29662306a36Sopenharmony_ci !!atomic_read(&bat_priv->bridge_loop_avoidance))) 29762306a36Sopenharmony_ci goto nla_put_failure; 29862306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_BLA */ 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DAT 30162306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED, 30262306a36Sopenharmony_ci !!atomic_read(&bat_priv->distributed_arp_table))) 30362306a36Sopenharmony_ci goto nla_put_failure; 30462306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_DAT */ 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_FRAGMENTATION_ENABLED, 30762306a36Sopenharmony_ci !!atomic_read(&bat_priv->fragmentation))) 30862306a36Sopenharmony_ci goto nla_put_failure; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_DOWN, 31162306a36Sopenharmony_ci atomic_read(&bat_priv->gw.bandwidth_down))) 31262306a36Sopenharmony_ci goto nla_put_failure; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_UP, 31562306a36Sopenharmony_ci atomic_read(&bat_priv->gw.bandwidth_up))) 31662306a36Sopenharmony_ci goto nla_put_failure; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_GW_MODE, 31962306a36Sopenharmony_ci atomic_read(&bat_priv->gw.mode))) 32062306a36Sopenharmony_ci goto nla_put_failure; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (bat_priv->algo_ops->gw.get_best_gw_node && 32362306a36Sopenharmony_ci bat_priv->algo_ops->gw.is_eligible) { 32462306a36Sopenharmony_ci /* GW selection class is not available if the routing algorithm 32562306a36Sopenharmony_ci * in use does not implement the GW API 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_GW_SEL_CLASS, 32862306a36Sopenharmony_ci atomic_read(&bat_priv->gw.sel_class))) 32962306a36Sopenharmony_ci goto nla_put_failure; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY, 33362306a36Sopenharmony_ci atomic_read(&bat_priv->hop_penalty))) 33462306a36Sopenharmony_ci goto nla_put_failure; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUG 33762306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL, 33862306a36Sopenharmony_ci atomic_read(&bat_priv->log_level))) 33962306a36Sopenharmony_ci goto nla_put_failure; 34062306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_DEBUG */ 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_MCAST 34362306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED, 34462306a36Sopenharmony_ci !atomic_read(&bat_priv->multicast_mode))) 34562306a36Sopenharmony_ci goto nla_put_failure; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_MULTICAST_FANOUT, 34862306a36Sopenharmony_ci atomic_read(&bat_priv->multicast_fanout))) 34962306a36Sopenharmony_ci goto nla_put_failure; 35062306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_MCAST */ 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_NC 35362306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_NETWORK_CODING_ENABLED, 35462306a36Sopenharmony_ci !!atomic_read(&bat_priv->network_coding))) 35562306a36Sopenharmony_ci goto nla_put_failure; 35662306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_NC */ 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_ORIG_INTERVAL, 35962306a36Sopenharmony_ci atomic_read(&bat_priv->orig_interval))) 36062306a36Sopenharmony_ci goto nla_put_failure; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci batadv_hardif_put(primary_if); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci genlmsg_end(msg, hdr); 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cinla_put_failure: 36862306a36Sopenharmony_ci batadv_hardif_put(primary_if); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci genlmsg_cancel(msg, hdr); 37162306a36Sopenharmony_ci return -EMSGSIZE; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/** 37562306a36Sopenharmony_ci * batadv_netlink_notify_mesh() - send softif attributes to listener 37662306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * Return: 0 on success, < 0 on error 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_cistatic int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct sk_buff *msg; 38362306a36Sopenharmony_ci int ret; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 38662306a36Sopenharmony_ci if (!msg) 38762306a36Sopenharmony_ci return -ENOMEM; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ret = batadv_netlink_mesh_fill(msg, bat_priv, BATADV_CMD_SET_MESH, 39062306a36Sopenharmony_ci 0, 0, 0); 39162306a36Sopenharmony_ci if (ret < 0) { 39262306a36Sopenharmony_ci nlmsg_free(msg); 39362306a36Sopenharmony_ci return ret; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci genlmsg_multicast_netns(&batadv_netlink_family, 39762306a36Sopenharmony_ci dev_net(bat_priv->soft_iface), msg, 0, 39862306a36Sopenharmony_ci BATADV_NL_MCGRP_CONFIG, GFP_KERNEL); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/** 40462306a36Sopenharmony_ci * batadv_netlink_get_mesh() - Get softif attributes 40562306a36Sopenharmony_ci * @skb: Netlink message with request data 40662306a36Sopenharmony_ci * @info: receiver information 40762306a36Sopenharmony_ci * 40862306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_cistatic int batadv_netlink_get_mesh(struct sk_buff *skb, struct genl_info *info) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct batadv_priv *bat_priv = info->user_ptr[0]; 41362306a36Sopenharmony_ci struct sk_buff *msg; 41462306a36Sopenharmony_ci int ret; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 41762306a36Sopenharmony_ci if (!msg) 41862306a36Sopenharmony_ci return -ENOMEM; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci ret = batadv_netlink_mesh_fill(msg, bat_priv, BATADV_CMD_GET_MESH, 42162306a36Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 42262306a36Sopenharmony_ci if (ret < 0) { 42362306a36Sopenharmony_ci nlmsg_free(msg); 42462306a36Sopenharmony_ci return ret; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci ret = genlmsg_reply(msg, info); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return ret; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci/** 43362306a36Sopenharmony_ci * batadv_netlink_set_mesh() - Set softif attributes 43462306a36Sopenharmony_ci * @skb: Netlink message with request data 43562306a36Sopenharmony_ci * @info: receiver information 43662306a36Sopenharmony_ci * 43762306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_cistatic int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct batadv_priv *bat_priv = info->user_ptr[0]; 44262306a36Sopenharmony_ci struct nlattr *attr; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_AGGREGATED_OGMS_ENABLED]) { 44562306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_AGGREGATED_OGMS_ENABLED]; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci atomic_set(&bat_priv->aggregated_ogms, !!nla_get_u8(attr)); 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]) { 45162306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci batadv_netlink_set_mesh_ap_isolation(attr, bat_priv); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_ISOLATION_MARK]) { 45762306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_ISOLATION_MARK]; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci bat_priv->isolation_mark = nla_get_u32(attr); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_ISOLATION_MASK]) { 46362306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_ISOLATION_MASK]; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci bat_priv->isolation_mark_mask = nla_get_u32(attr); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_BONDING_ENABLED]) { 46962306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_BONDING_ENABLED]; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci atomic_set(&bat_priv->bonding, !!nla_get_u8(attr)); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BLA 47562306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]) { 47662306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci atomic_set(&bat_priv->bridge_loop_avoidance, 47962306a36Sopenharmony_ci !!nla_get_u8(attr)); 48062306a36Sopenharmony_ci batadv_bla_status_update(bat_priv->soft_iface); 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_BLA */ 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DAT 48562306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]) { 48662306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci atomic_set(&bat_priv->distributed_arp_table, 48962306a36Sopenharmony_ci !!nla_get_u8(attr)); 49062306a36Sopenharmony_ci batadv_dat_status_update(bat_priv->soft_iface); 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_DAT */ 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_FRAGMENTATION_ENABLED]) { 49562306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_FRAGMENTATION_ENABLED]; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci atomic_set(&bat_priv->fragmentation, !!nla_get_u8(attr)); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci rtnl_lock(); 50062306a36Sopenharmony_ci batadv_update_min_mtu(bat_priv->soft_iface); 50162306a36Sopenharmony_ci rtnl_unlock(); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]) { 50562306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci atomic_set(&bat_priv->gw.bandwidth_down, nla_get_u32(attr)); 50862306a36Sopenharmony_ci batadv_gw_tvlv_container_update(bat_priv); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]) { 51262306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci atomic_set(&bat_priv->gw.bandwidth_up, nla_get_u32(attr)); 51562306a36Sopenharmony_ci batadv_gw_tvlv_container_update(bat_priv); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_GW_MODE]) { 51962306a36Sopenharmony_ci u8 gw_mode; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_GW_MODE]; 52262306a36Sopenharmony_ci gw_mode = nla_get_u8(attr); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (gw_mode <= BATADV_GW_MODE_SERVER) { 52562306a36Sopenharmony_ci /* Invoking batadv_gw_reselect() is not enough to really 52662306a36Sopenharmony_ci * de-select the current GW. It will only instruct the 52762306a36Sopenharmony_ci * gateway client code to perform a re-election the next 52862306a36Sopenharmony_ci * time that this is needed. 52962306a36Sopenharmony_ci * 53062306a36Sopenharmony_ci * When gw client mode is being switched off the current 53162306a36Sopenharmony_ci * GW must be de-selected explicitly otherwise no GW_ADD 53262306a36Sopenharmony_ci * uevent is thrown on client mode re-activation. This 53362306a36Sopenharmony_ci * is operation is performed in 53462306a36Sopenharmony_ci * batadv_gw_check_client_stop(). 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_ci batadv_gw_reselect(bat_priv); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* always call batadv_gw_check_client_stop() before 53962306a36Sopenharmony_ci * changing the gateway state 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ci batadv_gw_check_client_stop(bat_priv); 54262306a36Sopenharmony_ci atomic_set(&bat_priv->gw.mode, gw_mode); 54362306a36Sopenharmony_ci batadv_gw_tvlv_container_update(bat_priv); 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_GW_SEL_CLASS] && 54862306a36Sopenharmony_ci bat_priv->algo_ops->gw.get_best_gw_node && 54962306a36Sopenharmony_ci bat_priv->algo_ops->gw.is_eligible) { 55062306a36Sopenharmony_ci /* setting the GW selection class is allowed only if the routing 55162306a36Sopenharmony_ci * algorithm in use implements the GW API 55262306a36Sopenharmony_ci */ 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci u32 sel_class_max = bat_priv->algo_ops->gw.sel_class_max; 55562306a36Sopenharmony_ci u32 sel_class; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_GW_SEL_CLASS]; 55862306a36Sopenharmony_ci sel_class = nla_get_u32(attr); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (sel_class >= 1 && sel_class <= sel_class_max) { 56162306a36Sopenharmony_ci atomic_set(&bat_priv->gw.sel_class, sel_class); 56262306a36Sopenharmony_ci batadv_gw_reselect(bat_priv); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_HOP_PENALTY]) { 56762306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_HOP_PENALTY]; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci atomic_set(&bat_priv->hop_penalty, nla_get_u8(attr)); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUG 57362306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_LOG_LEVEL]) { 57462306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_LOG_LEVEL]; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci atomic_set(&bat_priv->log_level, 57762306a36Sopenharmony_ci nla_get_u32(attr) & BATADV_DBG_ALL); 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_DEBUG */ 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_MCAST 58262306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]) { 58362306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci atomic_set(&bat_priv->multicast_mode, !nla_get_u8(attr)); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_MULTICAST_FANOUT]) { 58962306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_MULTICAST_FANOUT]; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci atomic_set(&bat_priv->multicast_fanout, nla_get_u32(attr)); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_MCAST */ 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_NC 59662306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_NETWORK_CODING_ENABLED]) { 59762306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_NETWORK_CODING_ENABLED]; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci atomic_set(&bat_priv->network_coding, !!nla_get_u8(attr)); 60062306a36Sopenharmony_ci batadv_nc_status_update(bat_priv->soft_iface); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_NC */ 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_ORIG_INTERVAL]) { 60562306a36Sopenharmony_ci u32 orig_interval; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_ORIG_INTERVAL]; 60862306a36Sopenharmony_ci orig_interval = nla_get_u32(attr); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci orig_interval = min_t(u32, orig_interval, INT_MAX); 61162306a36Sopenharmony_ci orig_interval = max_t(u32, orig_interval, 2 * BATADV_JITTER); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci atomic_set(&bat_priv->orig_interval, orig_interval); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci batadv_netlink_notify_mesh(bat_priv); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci/** 62262306a36Sopenharmony_ci * batadv_netlink_tp_meter_put() - Fill information of started tp_meter session 62362306a36Sopenharmony_ci * @msg: netlink message to be sent back 62462306a36Sopenharmony_ci * @cookie: tp meter session cookie 62562306a36Sopenharmony_ci * 62662306a36Sopenharmony_ci * Return: 0 on success, < 0 on error 62762306a36Sopenharmony_ci */ 62862306a36Sopenharmony_cistatic int 62962306a36Sopenharmony_cibatadv_netlink_tp_meter_put(struct sk_buff *msg, u32 cookie) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_TPMETER_COOKIE, cookie)) 63262306a36Sopenharmony_ci return -ENOBUFS; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci return 0; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/** 63862306a36Sopenharmony_ci * batadv_netlink_tpmeter_notify() - send tp_meter result via netlink to client 63962306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 64062306a36Sopenharmony_ci * @dst: destination of tp_meter session 64162306a36Sopenharmony_ci * @result: reason for tp meter session stop 64262306a36Sopenharmony_ci * @test_time: total time of the tp_meter session 64362306a36Sopenharmony_ci * @total_bytes: bytes acked to the receiver 64462306a36Sopenharmony_ci * @cookie: cookie of tp_meter session 64562306a36Sopenharmony_ci * 64662306a36Sopenharmony_ci * Return: 0 on success, < 0 on error 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_ciint batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst, 64962306a36Sopenharmony_ci u8 result, u32 test_time, u64 total_bytes, 65062306a36Sopenharmony_ci u32 cookie) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct sk_buff *msg; 65362306a36Sopenharmony_ci void *hdr; 65462306a36Sopenharmony_ci int ret; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 65762306a36Sopenharmony_ci if (!msg) 65862306a36Sopenharmony_ci return -ENOMEM; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci hdr = genlmsg_put(msg, 0, 0, &batadv_netlink_family, 0, 66162306a36Sopenharmony_ci BATADV_CMD_TP_METER); 66262306a36Sopenharmony_ci if (!hdr) { 66362306a36Sopenharmony_ci ret = -ENOBUFS; 66462306a36Sopenharmony_ci goto err_genlmsg; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_TPMETER_COOKIE, cookie)) 66862306a36Sopenharmony_ci goto nla_put_failure; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_TPMETER_TEST_TIME, test_time)) 67162306a36Sopenharmony_ci goto nla_put_failure; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, BATADV_ATTR_TPMETER_BYTES, total_bytes, 67462306a36Sopenharmony_ci BATADV_ATTR_PAD)) 67562306a36Sopenharmony_ci goto nla_put_failure; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_TPMETER_RESULT, result)) 67862306a36Sopenharmony_ci goto nla_put_failure; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, dst)) 68162306a36Sopenharmony_ci goto nla_put_failure; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci genlmsg_end(msg, hdr); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci genlmsg_multicast_netns(&batadv_netlink_family, 68662306a36Sopenharmony_ci dev_net(bat_priv->soft_iface), msg, 0, 68762306a36Sopenharmony_ci BATADV_NL_MCGRP_TPMETER, GFP_KERNEL); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cinla_put_failure: 69262306a36Sopenharmony_ci genlmsg_cancel(msg, hdr); 69362306a36Sopenharmony_ci ret = -EMSGSIZE; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cierr_genlmsg: 69662306a36Sopenharmony_ci nlmsg_free(msg); 69762306a36Sopenharmony_ci return ret; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci/** 70162306a36Sopenharmony_ci * batadv_netlink_tp_meter_start() - Start a new tp_meter session 70262306a36Sopenharmony_ci * @skb: received netlink message 70362306a36Sopenharmony_ci * @info: receiver information 70462306a36Sopenharmony_ci * 70562306a36Sopenharmony_ci * Return: 0 on success, < 0 on error 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_cistatic int 70862306a36Sopenharmony_cibatadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci struct batadv_priv *bat_priv = info->user_ptr[0]; 71162306a36Sopenharmony_ci struct sk_buff *msg = NULL; 71262306a36Sopenharmony_ci u32 test_length; 71362306a36Sopenharmony_ci void *msg_head; 71462306a36Sopenharmony_ci u32 cookie; 71562306a36Sopenharmony_ci u8 *dst; 71662306a36Sopenharmony_ci int ret; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS]) 71962306a36Sopenharmony_ci return -EINVAL; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (!info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]) 72262306a36Sopenharmony_ci return -EINVAL; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci test_length = nla_get_u32(info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 72962306a36Sopenharmony_ci if (!msg) { 73062306a36Sopenharmony_ci ret = -ENOMEM; 73162306a36Sopenharmony_ci goto out; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci msg_head = genlmsg_put(msg, info->snd_portid, info->snd_seq, 73562306a36Sopenharmony_ci &batadv_netlink_family, 0, 73662306a36Sopenharmony_ci BATADV_CMD_TP_METER); 73762306a36Sopenharmony_ci if (!msg_head) { 73862306a36Sopenharmony_ci ret = -ENOBUFS; 73962306a36Sopenharmony_ci goto out; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci batadv_tp_start(bat_priv, dst, test_length, &cookie); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci ret = batadv_netlink_tp_meter_put(msg, cookie); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci out: 74762306a36Sopenharmony_ci if (ret) { 74862306a36Sopenharmony_ci if (msg) 74962306a36Sopenharmony_ci nlmsg_free(msg); 75062306a36Sopenharmony_ci return ret; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci genlmsg_end(msg, msg_head); 75462306a36Sopenharmony_ci return genlmsg_reply(msg, info); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci/** 75862306a36Sopenharmony_ci * batadv_netlink_tp_meter_cancel() - Cancel a running tp_meter session 75962306a36Sopenharmony_ci * @skb: received netlink message 76062306a36Sopenharmony_ci * @info: receiver information 76162306a36Sopenharmony_ci * 76262306a36Sopenharmony_ci * Return: 0 on success, < 0 on error 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_cistatic int 76562306a36Sopenharmony_cibatadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct batadv_priv *bat_priv = info->user_ptr[0]; 76862306a36Sopenharmony_ci u8 *dst; 76962306a36Sopenharmony_ci int ret = 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS]) 77262306a36Sopenharmony_ci return -EINVAL; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci batadv_tp_stop(bat_priv, dst, BATADV_TP_REASON_CANCEL); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return ret; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci/** 78262306a36Sopenharmony_ci * batadv_netlink_hardif_fill() - Fill message with hardif attributes 78362306a36Sopenharmony_ci * @msg: Netlink message to dump into 78462306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 78562306a36Sopenharmony_ci * @hard_iface: hard interface which was modified 78662306a36Sopenharmony_ci * @cmd: type of message to generate 78762306a36Sopenharmony_ci * @portid: Port making netlink request 78862306a36Sopenharmony_ci * @seq: sequence number for message 78962306a36Sopenharmony_ci * @flags: Additional flags for message 79062306a36Sopenharmony_ci * @cb: Control block containing additional options 79162306a36Sopenharmony_ci * 79262306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_cistatic int batadv_netlink_hardif_fill(struct sk_buff *msg, 79562306a36Sopenharmony_ci struct batadv_priv *bat_priv, 79662306a36Sopenharmony_ci struct batadv_hard_iface *hard_iface, 79762306a36Sopenharmony_ci enum batadv_nl_commands cmd, 79862306a36Sopenharmony_ci u32 portid, u32 seq, int flags, 79962306a36Sopenharmony_ci struct netlink_callback *cb) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct net_device *net_dev = hard_iface->net_dev; 80262306a36Sopenharmony_ci void *hdr; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd); 80562306a36Sopenharmony_ci if (!hdr) 80662306a36Sopenharmony_ci return -ENOBUFS; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (cb) 80962306a36Sopenharmony_ci genl_dump_check_consistent(cb, hdr); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, 81262306a36Sopenharmony_ci bat_priv->soft_iface->ifindex)) 81362306a36Sopenharmony_ci goto nla_put_failure; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (nla_put_string(msg, BATADV_ATTR_MESH_IFNAME, 81662306a36Sopenharmony_ci bat_priv->soft_iface->name)) 81762306a36Sopenharmony_ci goto nla_put_failure; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, 82062306a36Sopenharmony_ci net_dev->ifindex) || 82162306a36Sopenharmony_ci nla_put_string(msg, BATADV_ATTR_HARD_IFNAME, 82262306a36Sopenharmony_ci net_dev->name) || 82362306a36Sopenharmony_ci nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN, 82462306a36Sopenharmony_ci net_dev->dev_addr)) 82562306a36Sopenharmony_ci goto nla_put_failure; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (hard_iface->if_status == BATADV_IF_ACTIVE) { 82862306a36Sopenharmony_ci if (nla_put_flag(msg, BATADV_ATTR_ACTIVE)) 82962306a36Sopenharmony_ci goto nla_put_failure; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY, 83362306a36Sopenharmony_ci atomic_read(&hard_iface->hop_penalty))) 83462306a36Sopenharmony_ci goto nla_put_failure; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BATMAN_V 83762306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_ELP_INTERVAL, 83862306a36Sopenharmony_ci atomic_read(&hard_iface->bat_v.elp_interval))) 83962306a36Sopenharmony_ci goto nla_put_failure; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT_OVERRIDE, 84262306a36Sopenharmony_ci atomic_read(&hard_iface->bat_v.throughput_override))) 84362306a36Sopenharmony_ci goto nla_put_failure; 84462306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_BATMAN_V */ 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci genlmsg_end(msg, hdr); 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cinla_put_failure: 85062306a36Sopenharmony_ci genlmsg_cancel(msg, hdr); 85162306a36Sopenharmony_ci return -EMSGSIZE; 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci/** 85562306a36Sopenharmony_ci * batadv_netlink_notify_hardif() - send hardif attributes to listener 85662306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 85762306a36Sopenharmony_ci * @hard_iface: hard interface which was modified 85862306a36Sopenharmony_ci * 85962306a36Sopenharmony_ci * Return: 0 on success, < 0 on error 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_cistatic int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv, 86262306a36Sopenharmony_ci struct batadv_hard_iface *hard_iface) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct sk_buff *msg; 86562306a36Sopenharmony_ci int ret; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 86862306a36Sopenharmony_ci if (!msg) 86962306a36Sopenharmony_ci return -ENOMEM; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci ret = batadv_netlink_hardif_fill(msg, bat_priv, hard_iface, 87262306a36Sopenharmony_ci BATADV_CMD_SET_HARDIF, 0, 0, 0, NULL); 87362306a36Sopenharmony_ci if (ret < 0) { 87462306a36Sopenharmony_ci nlmsg_free(msg); 87562306a36Sopenharmony_ci return ret; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci genlmsg_multicast_netns(&batadv_netlink_family, 87962306a36Sopenharmony_ci dev_net(bat_priv->soft_iface), msg, 0, 88062306a36Sopenharmony_ci BATADV_NL_MCGRP_CONFIG, GFP_KERNEL); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci/** 88662306a36Sopenharmony_ci * batadv_netlink_get_hardif() - Get hardif attributes 88762306a36Sopenharmony_ci * @skb: Netlink message with request data 88862306a36Sopenharmony_ci * @info: receiver information 88962306a36Sopenharmony_ci * 89062306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_cistatic int batadv_netlink_get_hardif(struct sk_buff *skb, 89362306a36Sopenharmony_ci struct genl_info *info) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct batadv_hard_iface *hard_iface = info->user_ptr[1]; 89662306a36Sopenharmony_ci struct batadv_priv *bat_priv = info->user_ptr[0]; 89762306a36Sopenharmony_ci struct sk_buff *msg; 89862306a36Sopenharmony_ci int ret; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 90162306a36Sopenharmony_ci if (!msg) 90262306a36Sopenharmony_ci return -ENOMEM; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci ret = batadv_netlink_hardif_fill(msg, bat_priv, hard_iface, 90562306a36Sopenharmony_ci BATADV_CMD_GET_HARDIF, 90662306a36Sopenharmony_ci info->snd_portid, info->snd_seq, 0, 90762306a36Sopenharmony_ci NULL); 90862306a36Sopenharmony_ci if (ret < 0) { 90962306a36Sopenharmony_ci nlmsg_free(msg); 91062306a36Sopenharmony_ci return ret; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci ret = genlmsg_reply(msg, info); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return ret; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci/** 91962306a36Sopenharmony_ci * batadv_netlink_set_hardif() - Set hardif attributes 92062306a36Sopenharmony_ci * @skb: Netlink message with request data 92162306a36Sopenharmony_ci * @info: receiver information 92262306a36Sopenharmony_ci * 92362306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_cistatic int batadv_netlink_set_hardif(struct sk_buff *skb, 92662306a36Sopenharmony_ci struct genl_info *info) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci struct batadv_hard_iface *hard_iface = info->user_ptr[1]; 92962306a36Sopenharmony_ci struct batadv_priv *bat_priv = info->user_ptr[0]; 93062306a36Sopenharmony_ci struct nlattr *attr; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_HOP_PENALTY]) { 93362306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_HOP_PENALTY]; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci atomic_set(&hard_iface->hop_penalty, nla_get_u8(attr)); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_BATMAN_V 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_ELP_INTERVAL]) { 94162306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_ELP_INTERVAL]; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci atomic_set(&hard_iface->bat_v.elp_interval, nla_get_u32(attr)); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) { 94762306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci atomic_set(&hard_iface->bat_v.throughput_override, 95062306a36Sopenharmony_ci nla_get_u32(attr)); 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_BATMAN_V */ 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci batadv_netlink_notify_hardif(bat_priv, hard_iface); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/** 96062306a36Sopenharmony_ci * batadv_netlink_dump_hardif() - Dump all hard interface into a messages 96162306a36Sopenharmony_ci * @msg: Netlink message to dump into 96262306a36Sopenharmony_ci * @cb: Parameters from query 96362306a36Sopenharmony_ci * 96462306a36Sopenharmony_ci * Return: error code, or length of reply message on success 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_cistatic int 96762306a36Sopenharmony_cibatadv_netlink_dump_hardif(struct sk_buff *msg, struct netlink_callback *cb) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci struct net *net = sock_net(cb->skb->sk); 97062306a36Sopenharmony_ci struct net_device *soft_iface; 97162306a36Sopenharmony_ci struct batadv_hard_iface *hard_iface; 97262306a36Sopenharmony_ci struct batadv_priv *bat_priv; 97362306a36Sopenharmony_ci int ifindex; 97462306a36Sopenharmony_ci int portid = NETLINK_CB(cb->skb).portid; 97562306a36Sopenharmony_ci int skip = cb->args[0]; 97662306a36Sopenharmony_ci int i = 0; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci ifindex = batadv_netlink_get_ifindex(cb->nlh, 97962306a36Sopenharmony_ci BATADV_ATTR_MESH_IFINDEX); 98062306a36Sopenharmony_ci if (!ifindex) 98162306a36Sopenharmony_ci return -EINVAL; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci soft_iface = dev_get_by_index(net, ifindex); 98462306a36Sopenharmony_ci if (!soft_iface) 98562306a36Sopenharmony_ci return -ENODEV; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (!batadv_softif_is_valid(soft_iface)) { 98862306a36Sopenharmony_ci dev_put(soft_iface); 98962306a36Sopenharmony_ci return -ENODEV; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci bat_priv = netdev_priv(soft_iface); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci rtnl_lock(); 99562306a36Sopenharmony_ci cb->seq = batadv_hardif_generation << 1 | 1; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci list_for_each_entry(hard_iface, &batadv_hardif_list, list) { 99862306a36Sopenharmony_ci if (hard_iface->soft_iface != soft_iface) 99962306a36Sopenharmony_ci continue; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (i++ < skip) 100262306a36Sopenharmony_ci continue; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (batadv_netlink_hardif_fill(msg, bat_priv, hard_iface, 100562306a36Sopenharmony_ci BATADV_CMD_GET_HARDIF, 100662306a36Sopenharmony_ci portid, cb->nlh->nlmsg_seq, 100762306a36Sopenharmony_ci NLM_F_MULTI, cb)) { 100862306a36Sopenharmony_ci i--; 100962306a36Sopenharmony_ci break; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci rtnl_unlock(); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci dev_put(soft_iface); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci cb->args[0] = i; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci return msg->len; 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci/** 102362306a36Sopenharmony_ci * batadv_netlink_vlan_fill() - Fill message with vlan attributes 102462306a36Sopenharmony_ci * @msg: Netlink message to dump into 102562306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 102662306a36Sopenharmony_ci * @vlan: vlan which was modified 102762306a36Sopenharmony_ci * @cmd: type of message to generate 102862306a36Sopenharmony_ci * @portid: Port making netlink request 102962306a36Sopenharmony_ci * @seq: sequence number for message 103062306a36Sopenharmony_ci * @flags: Additional flags for message 103162306a36Sopenharmony_ci * 103262306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 103362306a36Sopenharmony_ci */ 103462306a36Sopenharmony_cistatic int batadv_netlink_vlan_fill(struct sk_buff *msg, 103562306a36Sopenharmony_ci struct batadv_priv *bat_priv, 103662306a36Sopenharmony_ci struct batadv_softif_vlan *vlan, 103762306a36Sopenharmony_ci enum batadv_nl_commands cmd, 103862306a36Sopenharmony_ci u32 portid, u32 seq, int flags) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci void *hdr; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd); 104362306a36Sopenharmony_ci if (!hdr) 104462306a36Sopenharmony_ci return -ENOBUFS; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, 104762306a36Sopenharmony_ci bat_priv->soft_iface->ifindex)) 104862306a36Sopenharmony_ci goto nla_put_failure; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (nla_put_string(msg, BATADV_ATTR_MESH_IFNAME, 105162306a36Sopenharmony_ci bat_priv->soft_iface->name)) 105262306a36Sopenharmony_ci goto nla_put_failure; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (nla_put_u32(msg, BATADV_ATTR_VLANID, vlan->vid & VLAN_VID_MASK)) 105562306a36Sopenharmony_ci goto nla_put_failure; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION_ENABLED, 105862306a36Sopenharmony_ci !!atomic_read(&vlan->ap_isolation))) 105962306a36Sopenharmony_ci goto nla_put_failure; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci genlmsg_end(msg, hdr); 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cinla_put_failure: 106562306a36Sopenharmony_ci genlmsg_cancel(msg, hdr); 106662306a36Sopenharmony_ci return -EMSGSIZE; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci/** 107062306a36Sopenharmony_ci * batadv_netlink_notify_vlan() - send vlan attributes to listener 107162306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 107262306a36Sopenharmony_ci * @vlan: vlan which was modified 107362306a36Sopenharmony_ci * 107462306a36Sopenharmony_ci * Return: 0 on success, < 0 on error 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_cistatic int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv, 107762306a36Sopenharmony_ci struct batadv_softif_vlan *vlan) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci struct sk_buff *msg; 108062306a36Sopenharmony_ci int ret; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 108362306a36Sopenharmony_ci if (!msg) 108462306a36Sopenharmony_ci return -ENOMEM; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci ret = batadv_netlink_vlan_fill(msg, bat_priv, vlan, 108762306a36Sopenharmony_ci BATADV_CMD_SET_VLAN, 0, 0, 0); 108862306a36Sopenharmony_ci if (ret < 0) { 108962306a36Sopenharmony_ci nlmsg_free(msg); 109062306a36Sopenharmony_ci return ret; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci genlmsg_multicast_netns(&batadv_netlink_family, 109462306a36Sopenharmony_ci dev_net(bat_priv->soft_iface), msg, 0, 109562306a36Sopenharmony_ci BATADV_NL_MCGRP_CONFIG, GFP_KERNEL); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return 0; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci/** 110162306a36Sopenharmony_ci * batadv_netlink_get_vlan() - Get vlan attributes 110262306a36Sopenharmony_ci * @skb: Netlink message with request data 110362306a36Sopenharmony_ci * @info: receiver information 110462306a36Sopenharmony_ci * 110562306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_cistatic int batadv_netlink_get_vlan(struct sk_buff *skb, struct genl_info *info) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci struct batadv_softif_vlan *vlan = info->user_ptr[1]; 111062306a36Sopenharmony_ci struct batadv_priv *bat_priv = info->user_ptr[0]; 111162306a36Sopenharmony_ci struct sk_buff *msg; 111262306a36Sopenharmony_ci int ret; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 111562306a36Sopenharmony_ci if (!msg) 111662306a36Sopenharmony_ci return -ENOMEM; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci ret = batadv_netlink_vlan_fill(msg, bat_priv, vlan, BATADV_CMD_GET_VLAN, 111962306a36Sopenharmony_ci info->snd_portid, info->snd_seq, 0); 112062306a36Sopenharmony_ci if (ret < 0) { 112162306a36Sopenharmony_ci nlmsg_free(msg); 112262306a36Sopenharmony_ci return ret; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci ret = genlmsg_reply(msg, info); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci return ret; 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci/** 113162306a36Sopenharmony_ci * batadv_netlink_set_vlan() - Get vlan attributes 113262306a36Sopenharmony_ci * @skb: Netlink message with request data 113362306a36Sopenharmony_ci * @info: receiver information 113462306a36Sopenharmony_ci * 113562306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 113662306a36Sopenharmony_ci */ 113762306a36Sopenharmony_cistatic int batadv_netlink_set_vlan(struct sk_buff *skb, struct genl_info *info) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci struct batadv_softif_vlan *vlan = info->user_ptr[1]; 114062306a36Sopenharmony_ci struct batadv_priv *bat_priv = info->user_ptr[0]; 114162306a36Sopenharmony_ci struct nlattr *attr; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci if (info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]) { 114462306a36Sopenharmony_ci attr = info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr)); 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci batadv_netlink_notify_vlan(bat_priv, vlan); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci return 0; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci/** 115562306a36Sopenharmony_ci * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes 115662306a36Sopenharmony_ci * @net: the applicable net namespace 115762306a36Sopenharmony_ci * @info: receiver information 115862306a36Sopenharmony_ci * 115962306a36Sopenharmony_ci * Return: Pointer to soft interface (with increased refcnt) on success, error 116062306a36Sopenharmony_ci * pointer on error 116162306a36Sopenharmony_ci */ 116262306a36Sopenharmony_cistatic struct net_device * 116362306a36Sopenharmony_cibatadv_get_softif_from_info(struct net *net, struct genl_info *info) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci struct net_device *soft_iface; 116662306a36Sopenharmony_ci int ifindex; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) 116962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci soft_iface = dev_get_by_index(net, ifindex); 117462306a36Sopenharmony_ci if (!soft_iface) 117562306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (!batadv_softif_is_valid(soft_iface)) 117862306a36Sopenharmony_ci goto err_put_softif; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci return soft_iface; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_cierr_put_softif: 118362306a36Sopenharmony_ci dev_put(soft_iface); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci/** 118962306a36Sopenharmony_ci * batadv_get_hardif_from_info() - Retrieve hardif from genl attributes 119062306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 119162306a36Sopenharmony_ci * @net: the applicable net namespace 119262306a36Sopenharmony_ci * @info: receiver information 119362306a36Sopenharmony_ci * 119462306a36Sopenharmony_ci * Return: Pointer to hard interface (with increased refcnt) on success, error 119562306a36Sopenharmony_ci * pointer on error 119662306a36Sopenharmony_ci */ 119762306a36Sopenharmony_cistatic struct batadv_hard_iface * 119862306a36Sopenharmony_cibatadv_get_hardif_from_info(struct batadv_priv *bat_priv, struct net *net, 119962306a36Sopenharmony_ci struct genl_info *info) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci struct batadv_hard_iface *hard_iface; 120262306a36Sopenharmony_ci struct net_device *hard_dev; 120362306a36Sopenharmony_ci unsigned int hardif_index; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (!info->attrs[BATADV_ATTR_HARD_IFINDEX]) 120662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci hardif_index = nla_get_u32(info->attrs[BATADV_ATTR_HARD_IFINDEX]); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci hard_dev = dev_get_by_index(net, hardif_index); 121162306a36Sopenharmony_ci if (!hard_dev) 121262306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci hard_iface = batadv_hardif_get_by_netdev(hard_dev); 121562306a36Sopenharmony_ci if (!hard_iface) 121662306a36Sopenharmony_ci goto err_put_harddev; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci if (hard_iface->soft_iface != bat_priv->soft_iface) 121962306a36Sopenharmony_ci goto err_put_hardif; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci /* hard_dev is referenced by hard_iface and not needed here */ 122262306a36Sopenharmony_ci dev_put(hard_dev); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci return hard_iface; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_cierr_put_hardif: 122762306a36Sopenharmony_ci batadv_hardif_put(hard_iface); 122862306a36Sopenharmony_cierr_put_harddev: 122962306a36Sopenharmony_ci dev_put(hard_dev); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 123262306a36Sopenharmony_ci} 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci/** 123562306a36Sopenharmony_ci * batadv_get_vlan_from_info() - Retrieve vlan from genl attributes 123662306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 123762306a36Sopenharmony_ci * @net: the applicable net namespace 123862306a36Sopenharmony_ci * @info: receiver information 123962306a36Sopenharmony_ci * 124062306a36Sopenharmony_ci * Return: Pointer to vlan on success (with increased refcnt), error pointer 124162306a36Sopenharmony_ci * on error 124262306a36Sopenharmony_ci */ 124362306a36Sopenharmony_cistatic struct batadv_softif_vlan * 124462306a36Sopenharmony_cibatadv_get_vlan_from_info(struct batadv_priv *bat_priv, struct net *net, 124562306a36Sopenharmony_ci struct genl_info *info) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci struct batadv_softif_vlan *vlan; 124862306a36Sopenharmony_ci u16 vid; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci if (!info->attrs[BATADV_ATTR_VLANID]) 125162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci vid = nla_get_u16(info->attrs[BATADV_ATTR_VLANID]); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG); 125662306a36Sopenharmony_ci if (!vlan) 125762306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci return vlan; 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci/** 126362306a36Sopenharmony_ci * batadv_pre_doit() - Prepare batman-adv genl doit request 126462306a36Sopenharmony_ci * @ops: requested netlink operation 126562306a36Sopenharmony_ci * @skb: Netlink message with request data 126662306a36Sopenharmony_ci * @info: receiver information 126762306a36Sopenharmony_ci * 126862306a36Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_cistatic int batadv_pre_doit(const struct genl_split_ops *ops, 127162306a36Sopenharmony_ci struct sk_buff *skb, 127262306a36Sopenharmony_ci struct genl_info *info) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci struct net *net = genl_info_net(info); 127562306a36Sopenharmony_ci struct batadv_hard_iface *hard_iface; 127662306a36Sopenharmony_ci struct batadv_priv *bat_priv = NULL; 127762306a36Sopenharmony_ci struct batadv_softif_vlan *vlan; 127862306a36Sopenharmony_ci struct net_device *soft_iface; 127962306a36Sopenharmony_ci u8 user_ptr1_flags; 128062306a36Sopenharmony_ci u8 mesh_dep_flags; 128162306a36Sopenharmony_ci int ret; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci user_ptr1_flags = BATADV_FLAG_NEED_HARDIF | BATADV_FLAG_NEED_VLAN; 128462306a36Sopenharmony_ci if (WARN_ON(hweight8(ops->internal_flags & user_ptr1_flags) > 1)) 128562306a36Sopenharmony_ci return -EINVAL; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci mesh_dep_flags = BATADV_FLAG_NEED_HARDIF | BATADV_FLAG_NEED_VLAN; 128862306a36Sopenharmony_ci if (WARN_ON((ops->internal_flags & mesh_dep_flags) && 128962306a36Sopenharmony_ci (~ops->internal_flags & BATADV_FLAG_NEED_MESH))) 129062306a36Sopenharmony_ci return -EINVAL; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (ops->internal_flags & BATADV_FLAG_NEED_MESH) { 129362306a36Sopenharmony_ci soft_iface = batadv_get_softif_from_info(net, info); 129462306a36Sopenharmony_ci if (IS_ERR(soft_iface)) 129562306a36Sopenharmony_ci return PTR_ERR(soft_iface); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci bat_priv = netdev_priv(soft_iface); 129862306a36Sopenharmony_ci info->user_ptr[0] = bat_priv; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF) { 130262306a36Sopenharmony_ci hard_iface = batadv_get_hardif_from_info(bat_priv, net, info); 130362306a36Sopenharmony_ci if (IS_ERR(hard_iface)) { 130462306a36Sopenharmony_ci ret = PTR_ERR(hard_iface); 130562306a36Sopenharmony_ci goto err_put_softif; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci info->user_ptr[1] = hard_iface; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (ops->internal_flags & BATADV_FLAG_NEED_VLAN) { 131262306a36Sopenharmony_ci vlan = batadv_get_vlan_from_info(bat_priv, net, info); 131362306a36Sopenharmony_ci if (IS_ERR(vlan)) { 131462306a36Sopenharmony_ci ret = PTR_ERR(vlan); 131562306a36Sopenharmony_ci goto err_put_softif; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci info->user_ptr[1] = vlan; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci return 0; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cierr_put_softif: 132462306a36Sopenharmony_ci if (bat_priv) 132562306a36Sopenharmony_ci dev_put(bat_priv->soft_iface); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci return ret; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci/** 133162306a36Sopenharmony_ci * batadv_post_doit() - End batman-adv genl doit request 133262306a36Sopenharmony_ci * @ops: requested netlink operation 133362306a36Sopenharmony_ci * @skb: Netlink message with request data 133462306a36Sopenharmony_ci * @info: receiver information 133562306a36Sopenharmony_ci */ 133662306a36Sopenharmony_cistatic void batadv_post_doit(const struct genl_split_ops *ops, 133762306a36Sopenharmony_ci struct sk_buff *skb, 133862306a36Sopenharmony_ci struct genl_info *info) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci struct batadv_hard_iface *hard_iface; 134162306a36Sopenharmony_ci struct batadv_softif_vlan *vlan; 134262306a36Sopenharmony_ci struct batadv_priv *bat_priv; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF && 134562306a36Sopenharmony_ci info->user_ptr[1]) { 134662306a36Sopenharmony_ci hard_iface = info->user_ptr[1]; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci batadv_hardif_put(hard_iface); 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci if (ops->internal_flags & BATADV_FLAG_NEED_VLAN && info->user_ptr[1]) { 135262306a36Sopenharmony_ci vlan = info->user_ptr[1]; 135362306a36Sopenharmony_ci batadv_softif_vlan_put(vlan); 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) { 135762306a36Sopenharmony_ci bat_priv = info->user_ptr[0]; 135862306a36Sopenharmony_ci dev_put(bat_priv->soft_iface); 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci} 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_cistatic const struct genl_small_ops batadv_netlink_ops[] = { 136362306a36Sopenharmony_ci { 136462306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_MESH, 136562306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 136662306a36Sopenharmony_ci /* can be retrieved by unprivileged users */ 136762306a36Sopenharmony_ci .doit = batadv_netlink_get_mesh, 136862306a36Sopenharmony_ci .internal_flags = BATADV_FLAG_NEED_MESH, 136962306a36Sopenharmony_ci }, 137062306a36Sopenharmony_ci { 137162306a36Sopenharmony_ci .cmd = BATADV_CMD_TP_METER, 137262306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 137362306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 137462306a36Sopenharmony_ci .doit = batadv_netlink_tp_meter_start, 137562306a36Sopenharmony_ci .internal_flags = BATADV_FLAG_NEED_MESH, 137662306a36Sopenharmony_ci }, 137762306a36Sopenharmony_ci { 137862306a36Sopenharmony_ci .cmd = BATADV_CMD_TP_METER_CANCEL, 137962306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 138062306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 138162306a36Sopenharmony_ci .doit = batadv_netlink_tp_meter_cancel, 138262306a36Sopenharmony_ci .internal_flags = BATADV_FLAG_NEED_MESH, 138362306a36Sopenharmony_ci }, 138462306a36Sopenharmony_ci { 138562306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_ROUTING_ALGOS, 138662306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 138762306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 138862306a36Sopenharmony_ci .dumpit = batadv_algo_dump, 138962306a36Sopenharmony_ci }, 139062306a36Sopenharmony_ci { 139162306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_HARDIF, 139262306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 139362306a36Sopenharmony_ci /* can be retrieved by unprivileged users */ 139462306a36Sopenharmony_ci .dumpit = batadv_netlink_dump_hardif, 139562306a36Sopenharmony_ci .doit = batadv_netlink_get_hardif, 139662306a36Sopenharmony_ci .internal_flags = BATADV_FLAG_NEED_MESH | 139762306a36Sopenharmony_ci BATADV_FLAG_NEED_HARDIF, 139862306a36Sopenharmony_ci }, 139962306a36Sopenharmony_ci { 140062306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL, 140162306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 140262306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 140362306a36Sopenharmony_ci .dumpit = batadv_tt_local_dump, 140462306a36Sopenharmony_ci }, 140562306a36Sopenharmony_ci { 140662306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL, 140762306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 140862306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 140962306a36Sopenharmony_ci .dumpit = batadv_tt_global_dump, 141062306a36Sopenharmony_ci }, 141162306a36Sopenharmony_ci { 141262306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_ORIGINATORS, 141362306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 141462306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 141562306a36Sopenharmony_ci .dumpit = batadv_orig_dump, 141662306a36Sopenharmony_ci }, 141762306a36Sopenharmony_ci { 141862306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_NEIGHBORS, 141962306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 142062306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 142162306a36Sopenharmony_ci .dumpit = batadv_hardif_neigh_dump, 142262306a36Sopenharmony_ci }, 142362306a36Sopenharmony_ci { 142462306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_GATEWAYS, 142562306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 142662306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 142762306a36Sopenharmony_ci .dumpit = batadv_gw_dump, 142862306a36Sopenharmony_ci }, 142962306a36Sopenharmony_ci { 143062306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_BLA_CLAIM, 143162306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 143262306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 143362306a36Sopenharmony_ci .dumpit = batadv_bla_claim_dump, 143462306a36Sopenharmony_ci }, 143562306a36Sopenharmony_ci { 143662306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_BLA_BACKBONE, 143762306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 143862306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 143962306a36Sopenharmony_ci .dumpit = batadv_bla_backbone_dump, 144062306a36Sopenharmony_ci }, 144162306a36Sopenharmony_ci { 144262306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_DAT_CACHE, 144362306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 144462306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 144562306a36Sopenharmony_ci .dumpit = batadv_dat_cache_dump, 144662306a36Sopenharmony_ci }, 144762306a36Sopenharmony_ci { 144862306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_MCAST_FLAGS, 144962306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 145062306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 145162306a36Sopenharmony_ci .dumpit = batadv_mcast_flags_dump, 145262306a36Sopenharmony_ci }, 145362306a36Sopenharmony_ci { 145462306a36Sopenharmony_ci .cmd = BATADV_CMD_SET_MESH, 145562306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 145662306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 145762306a36Sopenharmony_ci .doit = batadv_netlink_set_mesh, 145862306a36Sopenharmony_ci .internal_flags = BATADV_FLAG_NEED_MESH, 145962306a36Sopenharmony_ci }, 146062306a36Sopenharmony_ci { 146162306a36Sopenharmony_ci .cmd = BATADV_CMD_SET_HARDIF, 146262306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 146362306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 146462306a36Sopenharmony_ci .doit = batadv_netlink_set_hardif, 146562306a36Sopenharmony_ci .internal_flags = BATADV_FLAG_NEED_MESH | 146662306a36Sopenharmony_ci BATADV_FLAG_NEED_HARDIF, 146762306a36Sopenharmony_ci }, 146862306a36Sopenharmony_ci { 146962306a36Sopenharmony_ci .cmd = BATADV_CMD_GET_VLAN, 147062306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 147162306a36Sopenharmony_ci /* can be retrieved by unprivileged users */ 147262306a36Sopenharmony_ci .doit = batadv_netlink_get_vlan, 147362306a36Sopenharmony_ci .internal_flags = BATADV_FLAG_NEED_MESH | 147462306a36Sopenharmony_ci BATADV_FLAG_NEED_VLAN, 147562306a36Sopenharmony_ci }, 147662306a36Sopenharmony_ci { 147762306a36Sopenharmony_ci .cmd = BATADV_CMD_SET_VLAN, 147862306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 147962306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 148062306a36Sopenharmony_ci .doit = batadv_netlink_set_vlan, 148162306a36Sopenharmony_ci .internal_flags = BATADV_FLAG_NEED_MESH | 148262306a36Sopenharmony_ci BATADV_FLAG_NEED_VLAN, 148362306a36Sopenharmony_ci }, 148462306a36Sopenharmony_ci}; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_cistruct genl_family batadv_netlink_family __ro_after_init = { 148762306a36Sopenharmony_ci .hdrsize = 0, 148862306a36Sopenharmony_ci .name = BATADV_NL_NAME, 148962306a36Sopenharmony_ci .version = 1, 149062306a36Sopenharmony_ci .maxattr = BATADV_ATTR_MAX, 149162306a36Sopenharmony_ci .policy = batadv_netlink_policy, 149262306a36Sopenharmony_ci .netnsok = true, 149362306a36Sopenharmony_ci .pre_doit = batadv_pre_doit, 149462306a36Sopenharmony_ci .post_doit = batadv_post_doit, 149562306a36Sopenharmony_ci .module = THIS_MODULE, 149662306a36Sopenharmony_ci .small_ops = batadv_netlink_ops, 149762306a36Sopenharmony_ci .n_small_ops = ARRAY_SIZE(batadv_netlink_ops), 149862306a36Sopenharmony_ci .resv_start_op = BATADV_CMD_SET_VLAN + 1, 149962306a36Sopenharmony_ci .mcgrps = batadv_netlink_mcgrps, 150062306a36Sopenharmony_ci .n_mcgrps = ARRAY_SIZE(batadv_netlink_mcgrps), 150162306a36Sopenharmony_ci}; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci/** 150462306a36Sopenharmony_ci * batadv_netlink_register() - register batadv genl netlink family 150562306a36Sopenharmony_ci */ 150662306a36Sopenharmony_civoid __init batadv_netlink_register(void) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci int ret; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci ret = genl_register_family(&batadv_netlink_family); 151162306a36Sopenharmony_ci if (ret) 151262306a36Sopenharmony_ci pr_warn("unable to register netlink family"); 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci/** 151662306a36Sopenharmony_ci * batadv_netlink_unregister() - unregister batadv genl netlink family 151762306a36Sopenharmony_ci */ 151862306a36Sopenharmony_civoid batadv_netlink_unregister(void) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci genl_unregister_family(&batadv_netlink_family); 152162306a36Sopenharmony_ci} 1522