get_random_bytes(&random_seqno, sizeof(random_seqno));
atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
- hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN;
- ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC);
+ hard_iface->bat_iv.ogm_buff.len = BATADV_OGM_HLEN;
+ hard_iface->bat_iv.ogm_buff.capacity = BATADV_OGM_HLEN;
+ hard_iface->bat_iv.ogm_buff.header_length = BATADV_OGM_HLEN;
+
+ ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff.capacity, GFP_ATOMIC);
if (!ogm_buff) {
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
return -ENOMEM;
}
- hard_iface->bat_iv.ogm_buff = ogm_buff;
+ hard_iface->bat_iv.ogm_buff.buf = ogm_buff;
batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
batadv_ogm_packet->packet_type = BATADV_IV_OGM;
{
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
- kfree(hard_iface->bat_iv.ogm_buff);
- hard_iface->bat_iv.ogm_buff = NULL;
+ kfree(hard_iface->bat_iv.ogm_buff.buf);
+ memset(&hard_iface->bat_iv.ogm_buff, 0,
+ sizeof(hard_iface->bat_iv.ogm_buff));
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
- ogm_buff = hard_iface->bat_iv.ogm_buff;
+ ogm_buff = hard_iface->bat_iv.ogm_buff.buf;
if (!ogm_buff)
goto unlock;
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
- ogm_buff = hard_iface->bat_iv.ogm_buff;
+ ogm_buff = hard_iface->bat_iv.ogm_buff.buf;
if (!ogm_buff)
goto unlock;
static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
- unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
+ struct batadv_ogm_buf *ogm_buff = &hard_iface->bat_iv.ogm_buff;
struct batadv_ogm_packet *batadv_ogm_packet;
struct batadv_hard_iface *primary_if, *tmp_hard_iface;
- int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len;
struct list_head *iter;
u32 seqno;
u16 tvlv_len = 0;
lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
/* interface already disabled by batadv_iv_ogm_iface_disable */
- if (!*ogm_buff)
+ if (!ogm_buff->buf)
return;
/* the interface gets activated here to avoid race conditions between
* appended as it may alter the tt tvlv container
*/
batadv_tt_local_commit_changes(bat_priv);
- ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
- ogm_buff_len,
- BATADV_OGM_HLEN);
+ ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff);
if (ret < 0) {
reschedule = true;
goto out;
tvlv_len = ret;
}
- batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff);
+ batadv_ogm_packet = ogm_buff->buf;
batadv_ogm_packet->tvlv_len = htons(tvlv_len);
/* change sequence number to network order */
/* OGMs from secondary interfaces are only scheduled on their
* respective interfaces.
*/
- scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
+ scheduled = batadv_iv_ogm_queue_add(bat_priv, ogm_buff->buf, ogm_buff->len,
hard_iface, hard_iface, 1, send_time);
if (!scheduled)
reschedule = true;
if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
continue;
- scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
- *ogm_buff_len, hard_iface,
+ scheduled = batadv_iv_ogm_queue_add(bat_priv, ogm_buff->buf,
+ ogm_buff->len, hard_iface,
tmp_hard_iface, 1, send_time);
batadv_hardif_put(tmp_hard_iface);
{
struct batadv_hard_iface *hard_iface;
struct batadv_ogm2_packet *ogm_packet;
+ struct batadv_ogm_buf *ogm_buff;
struct sk_buff *skb, *skb_tmp;
- unsigned char **ogm_buff;
struct list_head *iter;
- int *ogm_buff_len;
u16 tvlv_len;
int ret;
goto out;
ogm_buff = &bat_priv->bat_v.ogm_buff;
- ogm_buff_len = &bat_priv->bat_v.ogm_buff_len;
/* tt changes have to be committed before the tvlv data is
* appended as it may alter the tt tvlv container
*/
batadv_tt_local_commit_changes(bat_priv);
- ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
- ogm_buff_len,
- BATADV_OGM2_HLEN);
+ ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff);
if (ret < 0)
goto reschedule;
tvlv_len = ret;
- skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + *ogm_buff_len);
+ skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff->len);
if (!skb)
goto reschedule;
skb_reserve(skb, ETH_HLEN);
- skb_put_data(skb, *ogm_buff, *ogm_buff_len);
+ skb_put_data(skb, ogm_buff->buf, ogm_buff->len);
ogm_packet = (struct batadv_ogm2_packet *)skb->data;
ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
struct batadv_ogm2_packet *ogm_packet;
mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
- if (!bat_priv->bat_v.ogm_buff)
+ if (!bat_priv->bat_v.ogm_buff.buf)
goto unlock;
- ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
+ ogm_packet = bat_priv->bat_v.ogm_buff.buf;
ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
unlock:
unsigned char *ogm_buff;
u32 random_seqno;
- bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
- ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
+ bat_priv->bat_v.ogm_buff.len = BATADV_OGM2_HLEN;
+ bat_priv->bat_v.ogm_buff.capacity = BATADV_OGM2_HLEN;
+ bat_priv->bat_v.ogm_buff.header_length = BATADV_OGM2_HLEN;
+
+ ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff.capacity, GFP_ATOMIC);
if (!ogm_buff)
return -ENOMEM;
- bat_priv->bat_v.ogm_buff = ogm_buff;
+ bat_priv->bat_v.ogm_buff.buf = ogm_buff;
ogm_packet = (struct batadv_ogm2_packet *)ogm_buff;
ogm_packet->packet_type = BATADV_OGM2;
ogm_packet->version = BATADV_COMPAT_VERSION;
mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
- kfree(bat_priv->bat_v.ogm_buff);
- bat_priv->bat_v.ogm_buff = NULL;
- bat_priv->bat_v.ogm_buff_len = 0;
+ kfree(bat_priv->bat_v.ogm_buff.buf);
+ memset(&bat_priv->bat_v.ogm_buff, 0, sizeof(bat_priv->bat_v.ogm_buff));
mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
}
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/lockdep.h>
+#include <linux/log2.h>
#include <linux/netdevice.h>
#include <linux/pkt_sched.h>
#include <linux/rculist.h>
/**
* batadv_tvlv_realloc_packet_buff() - reallocate packet buffer to accommodate
* requested packet size
- * @packet_buff: packet buffer
- * @packet_buff_len: packet buffer size
- * @min_packet_len: requested packet minimum size
+ * @ogm_buff: ogm packet buffer
* @additional_packet_len: requested additional packet size on top of minimum
* size
*
* Return: true of the packet buffer could be changed to the requested size,
* false otherwise.
*/
-static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff,
- int *packet_buff_len,
- int min_packet_len,
- int additional_packet_len)
+static bool batadv_tvlv_realloc_packet_buff(struct batadv_ogm_buf *ogm_buff,
+ size_t additional_packet_len)
{
unsigned char *new_buff;
+ size_t newcapacity;
+ size_t newlen;
- new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC);
+ newlen = ogm_buff->header_length + additional_packet_len;
+ newcapacity = roundup_pow_of_two(newlen);
+
+ /* nothing to reallocate */
+ if (newcapacity == ogm_buff->capacity) {
+ ogm_buff->len = newlen;
+ return true;
+ }
+
+ new_buff = kmalloc(newcapacity, GFP_ATOMIC);
/* keep old buffer if kmalloc should fail */
- if (!new_buff)
+ if (!new_buff) {
+ /* continue to use oversize buffer if new data fits */
+ if (newlen <= ogm_buff->capacity) {
+ ogm_buff->len = newlen;
+ return true;
+ }
+
return false;
+ }
+
+ memcpy(new_buff, ogm_buff->buf, ogm_buff->header_length);
+ kfree(ogm_buff->buf);
- memcpy(new_buff, *packet_buff, min_packet_len);
- kfree(*packet_buff);
- *packet_buff = new_buff;
- *packet_buff_len = min_packet_len + additional_packet_len;
+ ogm_buff->buf = new_buff;
+ ogm_buff->len = newlen;
+ ogm_buff->capacity = newcapacity;
return true;
}
* batadv_tvlv_container_ogm_append() - append tvlv container content to given
* OGM packet buffer
* @bat_priv: the bat priv with all the mesh interface information
- * @packet_buff: ogm packet buffer
- * @packet_buff_len: ogm packet buffer size including ogm header and tvlv
- * content
- * @packet_min_len: ogm header size to be preserved for the OGM itself
+ * @ogm_buff: ogm packet buffer
*
* The ogm packet might be enlarged or shrunk depending on the current size
* and the size of the to-be-appended tvlv containers.
* if operation failed
*/
int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
- unsigned char **packet_buff,
- int *packet_buff_len, int packet_min_len)
+ struct batadv_ogm_buf *ogm_buff)
{
struct batadv_tvlv_container *tvlv;
struct batadv_tvlv_hdr *tvlv_hdr;
goto end;
}
- ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len,
- packet_min_len, tvlv_value_len);
+ ret = batadv_tvlv_realloc_packet_buff(ogm_buff, tvlv_value_len);
if (!ret) {
tvlv_len_ret = -ENOMEM;
goto end;
if (!tvlv_value_len)
goto end;
- tvlv_value = (*packet_buff) + packet_min_len;
+ tvlv_value = (u8 *)ogm_buff->buf + ogm_buff->header_length;
hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) {
tvlv_hdr = tvlv_value;
u8 type, u8 version,
void *tvlv_value, u16 tvlv_value_len);
int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
- unsigned char **packet_buff,
- int *packet_buff_len, int packet_min_len);
+ struct batadv_ogm_buf *ogm_buff);
void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv,
struct batadv_ogm_packet *batadv_ogm_packet,
struct batadv_orig_node *orig_node);
*/
#define BATADV_TT_SYNC_MASK 0x00F0
+/**
+ * struct batadv_ogm_buf - Buffer to construct an OGM with TVLV
+ */
+struct batadv_ogm_buf {
+ /** @buf: buffer holding the OGM packet */
+ void *buf;
+
+ /** @len: length of the OGM packet buffer data */
+ size_t len;
+
+ /** @capacity: size of allocated buf */
+ size_t capacity;
+
+ /** @header_length: fixed size header length (must be <= len) */
+ size_t header_length;
+};
+
/**
* struct batadv_hard_iface_bat_iv - per hard-interface B.A.T.M.A.N. IV data
*/
struct batadv_hard_iface_bat_iv {
/** @ogm_buff: buffer holding the OGM packet */
- unsigned char *ogm_buff;
-
- /** @ogm_buff_len: length of the OGM packet buffer */
- int ogm_buff_len;
+ struct batadv_ogm_buf ogm_buff;
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
atomic_t ogm_seqno;
/** @reschedule_work: recover OGM schedule after schedule error */
struct delayed_work reschedule_work;
- /** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */
+ /** @ogm_buff_mutex: lock protecting ogm_buff */
struct mutex ogm_buff_mutex;
};
*/
struct batadv_priv_bat_v {
/** @ogm_buff: buffer holding the OGM packet */
- unsigned char *ogm_buff;
-
- /** @ogm_buff_len: length of the OGM packet buffer */
- int ogm_buff_len;
+ struct batadv_ogm_buf ogm_buff;
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
atomic_t ogm_seqno;
- /** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */
+ /** @ogm_buff_mutex: lock protecting ogm_buff */
struct mutex ogm_buff_mutex;
/** @ogm_wq: workqueue used to schedule OGM transmissions */