xref: /kernel/linux/linux-5.10/net/batman-adv/tvlv.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (C) 2007-2020  B.A.T.M.A.N. contributors:
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Marek Lindner, Simon Wunderlich
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "main.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h>
108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
118c2ecf20Sopenharmony_ci#include <linux/gfp.h>
128c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/kref.h>
158c2ecf20Sopenharmony_ci#include <linux/list.h>
168c2ecf20Sopenharmony_ci#include <linux/lockdep.h>
178c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
188c2ecf20Sopenharmony_ci#include <linux/pkt_sched.h>
198c2ecf20Sopenharmony_ci#include <linux/rculist.h>
208c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
218c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
248c2ecf20Sopenharmony_ci#include <linux/stddef.h>
258c2ecf20Sopenharmony_ci#include <linux/string.h>
268c2ecf20Sopenharmony_ci#include <linux/types.h>
278c2ecf20Sopenharmony_ci#include <uapi/linux/batadv_packet.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include "originator.h"
308c2ecf20Sopenharmony_ci#include "send.h"
318c2ecf20Sopenharmony_ci#include "tvlv.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/**
348c2ecf20Sopenharmony_ci * batadv_tvlv_handler_release() - release tvlv handler from lists and queue for
358c2ecf20Sopenharmony_ci *  free after rcu grace period
368c2ecf20Sopenharmony_ci * @ref: kref pointer of the tvlv
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_cistatic void batadv_tvlv_handler_release(struct kref *ref)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct batadv_tvlv_handler *tvlv_handler;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	tvlv_handler = container_of(ref, struct batadv_tvlv_handler, refcount);
438c2ecf20Sopenharmony_ci	kfree_rcu(tvlv_handler, rcu);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/**
478c2ecf20Sopenharmony_ci * batadv_tvlv_handler_put() - decrement the tvlv container refcounter and
488c2ecf20Sopenharmony_ci *  possibly release it
498c2ecf20Sopenharmony_ci * @tvlv_handler: the tvlv handler to free
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_cistatic void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	if (!tvlv_handler)
548c2ecf20Sopenharmony_ci		return;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/**
608c2ecf20Sopenharmony_ci * batadv_tvlv_handler_get() - retrieve tvlv handler from the tvlv handler list
618c2ecf20Sopenharmony_ci *  based on the provided type and version (both need to match)
628c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
638c2ecf20Sopenharmony_ci * @type: tvlv handler type to look for
648c2ecf20Sopenharmony_ci * @version: tvlv handler version to look for
658c2ecf20Sopenharmony_ci *
668c2ecf20Sopenharmony_ci * Return: tvlv handler if found or NULL otherwise.
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_cistatic struct batadv_tvlv_handler *
698c2ecf20Sopenharmony_cibatadv_tvlv_handler_get(struct batadv_priv *bat_priv, u8 type, u8 version)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct batadv_tvlv_handler *tvlv_handler_tmp, *tvlv_handler = NULL;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	rcu_read_lock();
748c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tvlv_handler_tmp,
758c2ecf20Sopenharmony_ci				 &bat_priv->tvlv.handler_list, list) {
768c2ecf20Sopenharmony_ci		if (tvlv_handler_tmp->type != type)
778c2ecf20Sopenharmony_ci			continue;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci		if (tvlv_handler_tmp->version != version)
808c2ecf20Sopenharmony_ci			continue;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&tvlv_handler_tmp->refcount))
838c2ecf20Sopenharmony_ci			continue;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		tvlv_handler = tvlv_handler_tmp;
868c2ecf20Sopenharmony_ci		break;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci	rcu_read_unlock();
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return tvlv_handler;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/**
948c2ecf20Sopenharmony_ci * batadv_tvlv_container_release() - release tvlv from lists and free
958c2ecf20Sopenharmony_ci * @ref: kref pointer of the tvlv
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_cistatic void batadv_tvlv_container_release(struct kref *ref)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct batadv_tvlv_container *tvlv;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	tvlv = container_of(ref, struct batadv_tvlv_container, refcount);
1028c2ecf20Sopenharmony_ci	kfree(tvlv);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/**
1068c2ecf20Sopenharmony_ci * batadv_tvlv_container_put() - decrement the tvlv container refcounter and
1078c2ecf20Sopenharmony_ci *  possibly release it
1088c2ecf20Sopenharmony_ci * @tvlv: the tvlv container to free
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_cistatic void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	if (!tvlv)
1138c2ecf20Sopenharmony_ci		return;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	kref_put(&tvlv->refcount, batadv_tvlv_container_release);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/**
1198c2ecf20Sopenharmony_ci * batadv_tvlv_container_get() - retrieve tvlv container from the tvlv container
1208c2ecf20Sopenharmony_ci *  list based on the provided type and version (both need to match)
1218c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
1228c2ecf20Sopenharmony_ci * @type: tvlv container type to look for
1238c2ecf20Sopenharmony_ci * @version: tvlv container version to look for
1248c2ecf20Sopenharmony_ci *
1258c2ecf20Sopenharmony_ci * Has to be called with the appropriate locks being acquired
1268c2ecf20Sopenharmony_ci * (tvlv.container_list_lock).
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * Return: tvlv container if found or NULL otherwise.
1298c2ecf20Sopenharmony_ci */
1308c2ecf20Sopenharmony_cistatic struct batadv_tvlv_container *
1318c2ecf20Sopenharmony_cibatadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	hlist_for_each_entry(tvlv_tmp, &bat_priv->tvlv.container_list, list) {
1388c2ecf20Sopenharmony_ci		if (tvlv_tmp->tvlv_hdr.type != type)
1398c2ecf20Sopenharmony_ci			continue;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		if (tvlv_tmp->tvlv_hdr.version != version)
1428c2ecf20Sopenharmony_ci			continue;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		kref_get(&tvlv_tmp->refcount);
1458c2ecf20Sopenharmony_ci		tvlv = tvlv_tmp;
1468c2ecf20Sopenharmony_ci		break;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return tvlv;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/**
1538c2ecf20Sopenharmony_ci * batadv_tvlv_container_list_size() - calculate the size of the tvlv container
1548c2ecf20Sopenharmony_ci *  list entries
1558c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
1568c2ecf20Sopenharmony_ci *
1578c2ecf20Sopenharmony_ci * Has to be called with the appropriate locks being acquired
1588c2ecf20Sopenharmony_ci * (tvlv.container_list_lock).
1598c2ecf20Sopenharmony_ci *
1608c2ecf20Sopenharmony_ci * Return: size of all currently registered tvlv containers in bytes.
1618c2ecf20Sopenharmony_ci */
1628c2ecf20Sopenharmony_cistatic u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct batadv_tvlv_container *tvlv;
1658c2ecf20Sopenharmony_ci	u16 tvlv_len = 0;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) {
1708c2ecf20Sopenharmony_ci		tvlv_len += sizeof(struct batadv_tvlv_hdr);
1718c2ecf20Sopenharmony_ci		tvlv_len += ntohs(tvlv->tvlv_hdr.len);
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	return tvlv_len;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci/**
1788c2ecf20Sopenharmony_ci * batadv_tvlv_container_remove() - remove tvlv container from the tvlv
1798c2ecf20Sopenharmony_ci *  container list
1808c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
1818c2ecf20Sopenharmony_ci * @tvlv: the to be removed tvlv container
1828c2ecf20Sopenharmony_ci *
1838c2ecf20Sopenharmony_ci * Has to be called with the appropriate locks being acquired
1848c2ecf20Sopenharmony_ci * (tvlv.container_list_lock).
1858c2ecf20Sopenharmony_ci */
1868c2ecf20Sopenharmony_cistatic void batadv_tvlv_container_remove(struct batadv_priv *bat_priv,
1878c2ecf20Sopenharmony_ci					 struct batadv_tvlv_container *tvlv)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (!tvlv)
1928c2ecf20Sopenharmony_ci		return;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	hlist_del(&tvlv->list);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	/* first call to decrement the counter, second call to free */
1978c2ecf20Sopenharmony_ci	batadv_tvlv_container_put(tvlv);
1988c2ecf20Sopenharmony_ci	batadv_tvlv_container_put(tvlv);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/**
2028c2ecf20Sopenharmony_ci * batadv_tvlv_container_unregister() - unregister tvlv container based on the
2038c2ecf20Sopenharmony_ci *  provided type and version (both need to match)
2048c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
2058c2ecf20Sopenharmony_ci * @type: tvlv container type to unregister
2068c2ecf20Sopenharmony_ci * @version: tvlv container type to unregister
2078c2ecf20Sopenharmony_ci */
2088c2ecf20Sopenharmony_civoid batadv_tvlv_container_unregister(struct batadv_priv *bat_priv,
2098c2ecf20Sopenharmony_ci				      u8 type, u8 version)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct batadv_tvlv_container *tvlv;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tvlv.container_list_lock);
2148c2ecf20Sopenharmony_ci	tvlv = batadv_tvlv_container_get(bat_priv, type, version);
2158c2ecf20Sopenharmony_ci	batadv_tvlv_container_remove(bat_priv, tvlv);
2168c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tvlv.container_list_lock);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci/**
2208c2ecf20Sopenharmony_ci * batadv_tvlv_container_register() - register tvlv type, version and content
2218c2ecf20Sopenharmony_ci *  to be propagated with each (primary interface) OGM
2228c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
2238c2ecf20Sopenharmony_ci * @type: tvlv container type
2248c2ecf20Sopenharmony_ci * @version: tvlv container version
2258c2ecf20Sopenharmony_ci * @tvlv_value: tvlv container content
2268c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv container content length
2278c2ecf20Sopenharmony_ci *
2288c2ecf20Sopenharmony_ci * If a container of the same type and version was already registered the new
2298c2ecf20Sopenharmony_ci * content is going to replace the old one.
2308c2ecf20Sopenharmony_ci */
2318c2ecf20Sopenharmony_civoid batadv_tvlv_container_register(struct batadv_priv *bat_priv,
2328c2ecf20Sopenharmony_ci				    u8 type, u8 version,
2338c2ecf20Sopenharmony_ci				    void *tvlv_value, u16 tvlv_value_len)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct batadv_tvlv_container *tvlv_old, *tvlv_new;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if (!tvlv_value)
2388c2ecf20Sopenharmony_ci		tvlv_value_len = 0;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	tvlv_new = kzalloc(sizeof(*tvlv_new) + tvlv_value_len, GFP_ATOMIC);
2418c2ecf20Sopenharmony_ci	if (!tvlv_new)
2428c2ecf20Sopenharmony_ci		return;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	tvlv_new->tvlv_hdr.version = version;
2458c2ecf20Sopenharmony_ci	tvlv_new->tvlv_hdr.type = type;
2468c2ecf20Sopenharmony_ci	tvlv_new->tvlv_hdr.len = htons(tvlv_value_len);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	memcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.len));
2498c2ecf20Sopenharmony_ci	INIT_HLIST_NODE(&tvlv_new->list);
2508c2ecf20Sopenharmony_ci	kref_init(&tvlv_new->refcount);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tvlv.container_list_lock);
2538c2ecf20Sopenharmony_ci	tvlv_old = batadv_tvlv_container_get(bat_priv, type, version);
2548c2ecf20Sopenharmony_ci	batadv_tvlv_container_remove(bat_priv, tvlv_old);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	kref_get(&tvlv_new->refcount);
2578c2ecf20Sopenharmony_ci	hlist_add_head(&tvlv_new->list, &bat_priv->tvlv.container_list);
2588c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tvlv.container_list_lock);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* don't return reference to new tvlv_container */
2618c2ecf20Sopenharmony_ci	batadv_tvlv_container_put(tvlv_new);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/**
2658c2ecf20Sopenharmony_ci * batadv_tvlv_realloc_packet_buff() - reallocate packet buffer to accommodate
2668c2ecf20Sopenharmony_ci *  requested packet size
2678c2ecf20Sopenharmony_ci * @packet_buff: packet buffer
2688c2ecf20Sopenharmony_ci * @packet_buff_len: packet buffer size
2698c2ecf20Sopenharmony_ci * @min_packet_len: requested packet minimum size
2708c2ecf20Sopenharmony_ci * @additional_packet_len: requested additional packet size on top of minimum
2718c2ecf20Sopenharmony_ci *  size
2728c2ecf20Sopenharmony_ci *
2738c2ecf20Sopenharmony_ci * Return: true of the packet buffer could be changed to the requested size,
2748c2ecf20Sopenharmony_ci * false otherwise.
2758c2ecf20Sopenharmony_ci */
2768c2ecf20Sopenharmony_cistatic bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff,
2778c2ecf20Sopenharmony_ci					    int *packet_buff_len,
2788c2ecf20Sopenharmony_ci					    int min_packet_len,
2798c2ecf20Sopenharmony_ci					    int additional_packet_len)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	unsigned char *new_buff;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* keep old buffer if kmalloc should fail */
2868c2ecf20Sopenharmony_ci	if (!new_buff)
2878c2ecf20Sopenharmony_ci		return false;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	memcpy(new_buff, *packet_buff, min_packet_len);
2908c2ecf20Sopenharmony_ci	kfree(*packet_buff);
2918c2ecf20Sopenharmony_ci	*packet_buff = new_buff;
2928c2ecf20Sopenharmony_ci	*packet_buff_len = min_packet_len + additional_packet_len;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	return true;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci/**
2988c2ecf20Sopenharmony_ci * batadv_tvlv_container_ogm_append() - append tvlv container content to given
2998c2ecf20Sopenharmony_ci *  OGM packet buffer
3008c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
3018c2ecf20Sopenharmony_ci * @packet_buff: ogm packet buffer
3028c2ecf20Sopenharmony_ci * @packet_buff_len: ogm packet buffer size including ogm header and tvlv
3038c2ecf20Sopenharmony_ci *  content
3048c2ecf20Sopenharmony_ci * @packet_min_len: ogm header size to be preserved for the OGM itself
3058c2ecf20Sopenharmony_ci *
3068c2ecf20Sopenharmony_ci * The ogm packet might be enlarged or shrunk depending on the current size
3078c2ecf20Sopenharmony_ci * and the size of the to-be-appended tvlv containers.
3088c2ecf20Sopenharmony_ci *
3098c2ecf20Sopenharmony_ci * Return: size of all appended tvlv containers in bytes.
3108c2ecf20Sopenharmony_ci */
3118c2ecf20Sopenharmony_ciu16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
3128c2ecf20Sopenharmony_ci				     unsigned char **packet_buff,
3138c2ecf20Sopenharmony_ci				     int *packet_buff_len, int packet_min_len)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	struct batadv_tvlv_container *tvlv;
3168c2ecf20Sopenharmony_ci	struct batadv_tvlv_hdr *tvlv_hdr;
3178c2ecf20Sopenharmony_ci	u16 tvlv_value_len;
3188c2ecf20Sopenharmony_ci	void *tvlv_value;
3198c2ecf20Sopenharmony_ci	bool ret;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tvlv.container_list_lock);
3228c2ecf20Sopenharmony_ci	tvlv_value_len = batadv_tvlv_container_list_size(bat_priv);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len,
3258c2ecf20Sopenharmony_ci					      packet_min_len, tvlv_value_len);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (!ret)
3288c2ecf20Sopenharmony_ci		goto end;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (!tvlv_value_len)
3318c2ecf20Sopenharmony_ci		goto end;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	tvlv_value = (*packet_buff) + packet_min_len;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) {
3368c2ecf20Sopenharmony_ci		tvlv_hdr = tvlv_value;
3378c2ecf20Sopenharmony_ci		tvlv_hdr->type = tvlv->tvlv_hdr.type;
3388c2ecf20Sopenharmony_ci		tvlv_hdr->version = tvlv->tvlv_hdr.version;
3398c2ecf20Sopenharmony_ci		tvlv_hdr->len = tvlv->tvlv_hdr.len;
3408c2ecf20Sopenharmony_ci		tvlv_value = tvlv_hdr + 1;
3418c2ecf20Sopenharmony_ci		memcpy(tvlv_value, tvlv + 1, ntohs(tvlv->tvlv_hdr.len));
3428c2ecf20Sopenharmony_ci		tvlv_value = (u8 *)tvlv_value + ntohs(tvlv->tvlv_hdr.len);
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ciend:
3468c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tvlv.container_list_lock);
3478c2ecf20Sopenharmony_ci	return tvlv_value_len;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci/**
3518c2ecf20Sopenharmony_ci * batadv_tvlv_call_handler() - parse the given tvlv buffer to call the
3528c2ecf20Sopenharmony_ci *  appropriate handlers
3538c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
3548c2ecf20Sopenharmony_ci * @tvlv_handler: tvlv callback function handling the tvlv content
3558c2ecf20Sopenharmony_ci * @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet
3568c2ecf20Sopenharmony_ci * @orig_node: orig node emitting the ogm packet
3578c2ecf20Sopenharmony_ci * @src: source mac address of the unicast packet
3588c2ecf20Sopenharmony_ci * @dst: destination mac address of the unicast packet
3598c2ecf20Sopenharmony_ci * @tvlv_value: tvlv content
3608c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv content length
3618c2ecf20Sopenharmony_ci *
3628c2ecf20Sopenharmony_ci * Return: success if the handler was not found or the return value of the
3638c2ecf20Sopenharmony_ci * handler callback.
3648c2ecf20Sopenharmony_ci */
3658c2ecf20Sopenharmony_cistatic int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
3668c2ecf20Sopenharmony_ci				    struct batadv_tvlv_handler *tvlv_handler,
3678c2ecf20Sopenharmony_ci				    bool ogm_source,
3688c2ecf20Sopenharmony_ci				    struct batadv_orig_node *orig_node,
3698c2ecf20Sopenharmony_ci				    u8 *src, u8 *dst,
3708c2ecf20Sopenharmony_ci				    void *tvlv_value, u16 tvlv_value_len)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	if (!tvlv_handler)
3738c2ecf20Sopenharmony_ci		return NET_RX_SUCCESS;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (ogm_source) {
3768c2ecf20Sopenharmony_ci		if (!tvlv_handler->ogm_handler)
3778c2ecf20Sopenharmony_ci			return NET_RX_SUCCESS;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci		if (!orig_node)
3808c2ecf20Sopenharmony_ci			return NET_RX_SUCCESS;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		tvlv_handler->ogm_handler(bat_priv, orig_node,
3838c2ecf20Sopenharmony_ci					  BATADV_NO_FLAGS,
3848c2ecf20Sopenharmony_ci					  tvlv_value, tvlv_value_len);
3858c2ecf20Sopenharmony_ci		tvlv_handler->flags |= BATADV_TVLV_HANDLER_OGM_CALLED;
3868c2ecf20Sopenharmony_ci	} else {
3878c2ecf20Sopenharmony_ci		if (!src)
3888c2ecf20Sopenharmony_ci			return NET_RX_SUCCESS;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		if (!dst)
3918c2ecf20Sopenharmony_ci			return NET_RX_SUCCESS;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		if (!tvlv_handler->unicast_handler)
3948c2ecf20Sopenharmony_ci			return NET_RX_SUCCESS;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci		return tvlv_handler->unicast_handler(bat_priv, src,
3978c2ecf20Sopenharmony_ci						     dst, tvlv_value,
3988c2ecf20Sopenharmony_ci						     tvlv_value_len);
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	return NET_RX_SUCCESS;
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci/**
4058c2ecf20Sopenharmony_ci * batadv_tvlv_containers_process() - parse the given tvlv buffer to call the
4068c2ecf20Sopenharmony_ci *  appropriate handlers
4078c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
4088c2ecf20Sopenharmony_ci * @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet
4098c2ecf20Sopenharmony_ci * @orig_node: orig node emitting the ogm packet
4108c2ecf20Sopenharmony_ci * @src: source mac address of the unicast packet
4118c2ecf20Sopenharmony_ci * @dst: destination mac address of the unicast packet
4128c2ecf20Sopenharmony_ci * @tvlv_value: tvlv content
4138c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv content length
4148c2ecf20Sopenharmony_ci *
4158c2ecf20Sopenharmony_ci * Return: success when processing an OGM or the return value of all called
4168c2ecf20Sopenharmony_ci * handler callbacks.
4178c2ecf20Sopenharmony_ci */
4188c2ecf20Sopenharmony_ciint batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
4198c2ecf20Sopenharmony_ci				   bool ogm_source,
4208c2ecf20Sopenharmony_ci				   struct batadv_orig_node *orig_node,
4218c2ecf20Sopenharmony_ci				   u8 *src, u8 *dst,
4228c2ecf20Sopenharmony_ci				   void *tvlv_value, u16 tvlv_value_len)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct batadv_tvlv_handler *tvlv_handler;
4258c2ecf20Sopenharmony_ci	struct batadv_tvlv_hdr *tvlv_hdr;
4268c2ecf20Sopenharmony_ci	u16 tvlv_value_cont_len;
4278c2ecf20Sopenharmony_ci	u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND;
4288c2ecf20Sopenharmony_ci	int ret = NET_RX_SUCCESS;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	while (tvlv_value_len >= sizeof(*tvlv_hdr)) {
4318c2ecf20Sopenharmony_ci		tvlv_hdr = tvlv_value;
4328c2ecf20Sopenharmony_ci		tvlv_value_cont_len = ntohs(tvlv_hdr->len);
4338c2ecf20Sopenharmony_ci		tvlv_value = tvlv_hdr + 1;
4348c2ecf20Sopenharmony_ci		tvlv_value_len -= sizeof(*tvlv_hdr);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		if (tvlv_value_cont_len > tvlv_value_len)
4378c2ecf20Sopenharmony_ci			break;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci		tvlv_handler = batadv_tvlv_handler_get(bat_priv,
4408c2ecf20Sopenharmony_ci						       tvlv_hdr->type,
4418c2ecf20Sopenharmony_ci						       tvlv_hdr->version);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci		ret |= batadv_tvlv_call_handler(bat_priv, tvlv_handler,
4448c2ecf20Sopenharmony_ci						ogm_source, orig_node,
4458c2ecf20Sopenharmony_ci						src, dst, tvlv_value,
4468c2ecf20Sopenharmony_ci						tvlv_value_cont_len);
4478c2ecf20Sopenharmony_ci		if (tvlv_handler)
4488c2ecf20Sopenharmony_ci			batadv_tvlv_handler_put(tvlv_handler);
4498c2ecf20Sopenharmony_ci		tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
4508c2ecf20Sopenharmony_ci		tvlv_value_len -= tvlv_value_cont_len;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (!ogm_source)
4548c2ecf20Sopenharmony_ci		return ret;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	rcu_read_lock();
4578c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tvlv_handler,
4588c2ecf20Sopenharmony_ci				 &bat_priv->tvlv.handler_list, list) {
4598c2ecf20Sopenharmony_ci		if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) &&
4608c2ecf20Sopenharmony_ci		    !(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CALLED))
4618c2ecf20Sopenharmony_ci			tvlv_handler->ogm_handler(bat_priv, orig_node,
4628c2ecf20Sopenharmony_ci						  cifnotfound, NULL, 0);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci	rcu_read_unlock();
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	return NET_RX_SUCCESS;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci/**
4728c2ecf20Sopenharmony_ci * batadv_tvlv_ogm_receive() - process an incoming ogm and call the appropriate
4738c2ecf20Sopenharmony_ci *  handlers
4748c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
4758c2ecf20Sopenharmony_ci * @batadv_ogm_packet: ogm packet containing the tvlv containers
4768c2ecf20Sopenharmony_ci * @orig_node: orig node emitting the ogm packet
4778c2ecf20Sopenharmony_ci */
4788c2ecf20Sopenharmony_civoid batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv,
4798c2ecf20Sopenharmony_ci			     struct batadv_ogm_packet *batadv_ogm_packet,
4808c2ecf20Sopenharmony_ci			     struct batadv_orig_node *orig_node)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	void *tvlv_value;
4838c2ecf20Sopenharmony_ci	u16 tvlv_value_len;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (!batadv_ogm_packet)
4868c2ecf20Sopenharmony_ci		return;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	tvlv_value_len = ntohs(batadv_ogm_packet->tvlv_len);
4898c2ecf20Sopenharmony_ci	if (!tvlv_value_len)
4908c2ecf20Sopenharmony_ci		return;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	tvlv_value = batadv_ogm_packet + 1;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	batadv_tvlv_containers_process(bat_priv, true, orig_node, NULL, NULL,
4958c2ecf20Sopenharmony_ci				       tvlv_value, tvlv_value_len);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/**
4998c2ecf20Sopenharmony_ci * batadv_tvlv_handler_register() - register tvlv handler based on the provided
5008c2ecf20Sopenharmony_ci *  type and version (both need to match) for ogm tvlv payload and/or unicast
5018c2ecf20Sopenharmony_ci *  payload
5028c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
5038c2ecf20Sopenharmony_ci * @optr: ogm tvlv handler callback function. This function receives the orig
5048c2ecf20Sopenharmony_ci *  node, flags and the tvlv content as argument to process.
5058c2ecf20Sopenharmony_ci * @uptr: unicast tvlv handler callback function. This function receives the
5068c2ecf20Sopenharmony_ci *  source & destination of the unicast packet as well as the tvlv content
5078c2ecf20Sopenharmony_ci *  to process.
5088c2ecf20Sopenharmony_ci * @type: tvlv handler type to be registered
5098c2ecf20Sopenharmony_ci * @version: tvlv handler version to be registered
5108c2ecf20Sopenharmony_ci * @flags: flags to enable or disable TVLV API behavior
5118c2ecf20Sopenharmony_ci */
5128c2ecf20Sopenharmony_civoid batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
5138c2ecf20Sopenharmony_ci				  void (*optr)(struct batadv_priv *bat_priv,
5148c2ecf20Sopenharmony_ci					       struct batadv_orig_node *orig,
5158c2ecf20Sopenharmony_ci					       u8 flags,
5168c2ecf20Sopenharmony_ci					       void *tvlv_value,
5178c2ecf20Sopenharmony_ci					       u16 tvlv_value_len),
5188c2ecf20Sopenharmony_ci				  int (*uptr)(struct batadv_priv *bat_priv,
5198c2ecf20Sopenharmony_ci					      u8 *src, u8 *dst,
5208c2ecf20Sopenharmony_ci					      void *tvlv_value,
5218c2ecf20Sopenharmony_ci					      u16 tvlv_value_len),
5228c2ecf20Sopenharmony_ci				  u8 type, u8 version, u8 flags)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct batadv_tvlv_handler *tvlv_handler;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version);
5298c2ecf20Sopenharmony_ci	if (tvlv_handler) {
5308c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
5318c2ecf20Sopenharmony_ci		batadv_tvlv_handler_put(tvlv_handler);
5328c2ecf20Sopenharmony_ci		return;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	tvlv_handler = kzalloc(sizeof(*tvlv_handler), GFP_ATOMIC);
5368c2ecf20Sopenharmony_ci	if (!tvlv_handler) {
5378c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
5388c2ecf20Sopenharmony_ci		return;
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	tvlv_handler->ogm_handler = optr;
5428c2ecf20Sopenharmony_ci	tvlv_handler->unicast_handler = uptr;
5438c2ecf20Sopenharmony_ci	tvlv_handler->type = type;
5448c2ecf20Sopenharmony_ci	tvlv_handler->version = version;
5458c2ecf20Sopenharmony_ci	tvlv_handler->flags = flags;
5468c2ecf20Sopenharmony_ci	kref_init(&tvlv_handler->refcount);
5478c2ecf20Sopenharmony_ci	INIT_HLIST_NODE(&tvlv_handler->list);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	kref_get(&tvlv_handler->refcount);
5508c2ecf20Sopenharmony_ci	hlist_add_head_rcu(&tvlv_handler->list, &bat_priv->tvlv.handler_list);
5518c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/* don't return reference to new tvlv_handler */
5548c2ecf20Sopenharmony_ci	batadv_tvlv_handler_put(tvlv_handler);
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci/**
5588c2ecf20Sopenharmony_ci * batadv_tvlv_handler_unregister() - unregister tvlv handler based on the
5598c2ecf20Sopenharmony_ci *  provided type and version (both need to match)
5608c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
5618c2ecf20Sopenharmony_ci * @type: tvlv handler type to be unregistered
5628c2ecf20Sopenharmony_ci * @version: tvlv handler version to be unregistered
5638c2ecf20Sopenharmony_ci */
5648c2ecf20Sopenharmony_civoid batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv,
5658c2ecf20Sopenharmony_ci				    u8 type, u8 version)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct batadv_tvlv_handler *tvlv_handler;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version);
5708c2ecf20Sopenharmony_ci	if (!tvlv_handler)
5718c2ecf20Sopenharmony_ci		return;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	batadv_tvlv_handler_put(tvlv_handler);
5748c2ecf20Sopenharmony_ci	spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
5758c2ecf20Sopenharmony_ci	hlist_del_rcu(&tvlv_handler->list);
5768c2ecf20Sopenharmony_ci	spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
5778c2ecf20Sopenharmony_ci	batadv_tvlv_handler_put(tvlv_handler);
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci/**
5818c2ecf20Sopenharmony_ci * batadv_tvlv_unicast_send() - send a unicast packet with tvlv payload to the
5828c2ecf20Sopenharmony_ci *  specified host
5838c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
5848c2ecf20Sopenharmony_ci * @src: source mac address of the unicast packet
5858c2ecf20Sopenharmony_ci * @dst: destination mac address of the unicast packet
5868c2ecf20Sopenharmony_ci * @type: tvlv type
5878c2ecf20Sopenharmony_ci * @version: tvlv version
5888c2ecf20Sopenharmony_ci * @tvlv_value: tvlv content
5898c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv content length
5908c2ecf20Sopenharmony_ci */
5918c2ecf20Sopenharmony_civoid batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src,
5928c2ecf20Sopenharmony_ci			      u8 *dst, u8 type, u8 version,
5938c2ecf20Sopenharmony_ci			      void *tvlv_value, u16 tvlv_value_len)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	struct batadv_unicast_tvlv_packet *unicast_tvlv_packet;
5968c2ecf20Sopenharmony_ci	struct batadv_tvlv_hdr *tvlv_hdr;
5978c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
5988c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5998c2ecf20Sopenharmony_ci	unsigned char *tvlv_buff;
6008c2ecf20Sopenharmony_ci	unsigned int tvlv_len;
6018c2ecf20Sopenharmony_ci	ssize_t hdr_len = sizeof(*unicast_tvlv_packet);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	orig_node = batadv_orig_hash_find(bat_priv, dst);
6048c2ecf20Sopenharmony_ci	if (!orig_node)
6058c2ecf20Sopenharmony_ci		return;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	tvlv_len = sizeof(*tvlv_hdr) + tvlv_value_len;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + hdr_len + tvlv_len);
6108c2ecf20Sopenharmony_ci	if (!skb)
6118c2ecf20Sopenharmony_ci		goto out;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	skb->priority = TC_PRIO_CONTROL;
6148c2ecf20Sopenharmony_ci	skb_reserve(skb, ETH_HLEN);
6158c2ecf20Sopenharmony_ci	tvlv_buff = skb_put(skb, sizeof(*unicast_tvlv_packet) + tvlv_len);
6168c2ecf20Sopenharmony_ci	unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)tvlv_buff;
6178c2ecf20Sopenharmony_ci	unicast_tvlv_packet->packet_type = BATADV_UNICAST_TVLV;
6188c2ecf20Sopenharmony_ci	unicast_tvlv_packet->version = BATADV_COMPAT_VERSION;
6198c2ecf20Sopenharmony_ci	unicast_tvlv_packet->ttl = BATADV_TTL;
6208c2ecf20Sopenharmony_ci	unicast_tvlv_packet->reserved = 0;
6218c2ecf20Sopenharmony_ci	unicast_tvlv_packet->tvlv_len = htons(tvlv_len);
6228c2ecf20Sopenharmony_ci	unicast_tvlv_packet->align = 0;
6238c2ecf20Sopenharmony_ci	ether_addr_copy(unicast_tvlv_packet->src, src);
6248c2ecf20Sopenharmony_ci	ether_addr_copy(unicast_tvlv_packet->dst, dst);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	tvlv_buff = (unsigned char *)(unicast_tvlv_packet + 1);
6278c2ecf20Sopenharmony_ci	tvlv_hdr = (struct batadv_tvlv_hdr *)tvlv_buff;
6288c2ecf20Sopenharmony_ci	tvlv_hdr->version = version;
6298c2ecf20Sopenharmony_ci	tvlv_hdr->type = type;
6308c2ecf20Sopenharmony_ci	tvlv_hdr->len = htons(tvlv_value_len);
6318c2ecf20Sopenharmony_ci	tvlv_buff += sizeof(*tvlv_hdr);
6328c2ecf20Sopenharmony_ci	memcpy(tvlv_buff, tvlv_value, tvlv_value_len);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	batadv_send_skb_to_orig(skb, orig_node, NULL);
6358c2ecf20Sopenharmony_ciout:
6368c2ecf20Sopenharmony_ci	batadv_orig_node_put(orig_node);
6378c2ecf20Sopenharmony_ci}
638