Commit ef261577 authored by Marek Lindner's avatar Marek Lindner Committed by Antonio Quartulli

batman-adv: tvlv - basic infrastructure

The goal is to provide the infrastructure for sending, receiving and
parsing information 'containers' while preserving backward
compatibility. TVLV (based on the commonly known Type Length Value
technique) was chosen as the format for those containers. Even if a
node does not know the tvlv type of a certain container it can simply
skip the current container and proceed with the next. Past experience
has shown features evolve over time, so a 'version' field was added
right from the start to allow differentiating between feature
variants - hence the name: T(ype) V(ersion) L(ength) V(alue).

This patch introduces the basic TVLV infrastructure:
 * register / unregister tvlv containers to be sent with each OGM
   (on primary interfaces only)
 * register / unregister callback handlers to be called upon
   finding the corresponding tvlv type in a tvlv buffer
 * unicast tvlv send / receive API calls
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
Signed-off-by: default avatarSpyros Gasteratos <morfeas3000@gmail.com>
Signed-off-by: default avatarAntonio Quartulli <antonio@meshcoding.com>
parent 60cf7981
......@@ -207,12 +207,12 @@ static uint8_t batadv_hop_penalty(uint8_t tq,
/* is there another aggregated packet here? */
static int batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
int tt_num_changes)
__be16 tvlv_len)
{
int next_buff_pos = 0;
next_buff_pos += buff_pos + BATADV_OGM_HLEN;
next_buff_pos += batadv_tt_len(tt_num_changes);
next_buff_pos += ntohs(tvlv_len);
return (next_buff_pos <= packet_len) &&
(next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
......@@ -240,7 +240,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
/* adjust all flags and log packets */
while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
batadv_ogm_packet->tt_num_changes)) {
batadv_ogm_packet->tvlv_len)) {
/* we might have aggregated direct link packets with an
* ordinary base packet
*/
......@@ -267,7 +267,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
hard_iface->net_dev->dev_addr);
buff_pos += BATADV_OGM_HLEN;
buff_pos += batadv_tt_len(batadv_ogm_packet->tt_num_changes);
buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
packet_num++;
packet_pos = forw_packet->skb->data + buff_pos;
batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
......@@ -601,7 +601,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_incoming)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
uint8_t tt_num_changes;
uint16_t tvlv_len;
if (batadv_ogm_packet->header.ttl <= 1) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n");
......@@ -621,7 +621,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
return;
}
tt_num_changes = batadv_ogm_packet->tt_num_changes;
tvlv_len = ntohs(batadv_ogm_packet->tvlv_len);
batadv_ogm_packet->header.ttl--;
memcpy(batadv_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
......@@ -642,7 +642,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK;
batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet,
BATADV_OGM_HLEN + batadv_tt_len(tt_num_changes),
BATADV_OGM_HLEN + tvlv_len,
if_incoming, 0, batadv_iv_ogm_fwd_send_time());
}
......@@ -691,16 +691,18 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
int vis_server, tt_num_changes = 0;
uint32_t seqno;
uint8_t bandwidth;
uint16_t tvlv_len = 0;
vis_server = atomic_read(&bat_priv->vis_mode);
primary_if = batadv_primary_if_get_selected(bat_priv);
if (hard_iface == primary_if)
tt_num_changes = batadv_tt_append_diff(bat_priv, ogm_buff,
ogm_buff_len,
BATADV_OGM_HLEN);
tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
ogm_buff_len,
BATADV_OGM_HLEN);
batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff);
batadv_ogm_packet->tvlv_len = htons(tvlv_len);
/* change sequence number to network order */
seqno = (uint32_t)atomic_read(&hard_iface->bat_iv.ogm_seqno);
......@@ -1254,6 +1256,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
goto out;
}
batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node);
/* if sender is a direct neighbor the sender mac equals
* originator mac
*/
......@@ -1350,9 +1354,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
struct batadv_ogm_packet *batadv_ogm_packet;
struct ethhdr *ethhdr;
int buff_pos = 0, packet_len;
unsigned char *tt_buff, *packet_buff;
bool ret;
unsigned char *tvlv_buff, *packet_buff;
uint8_t *packet_pos;
bool ret;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN);
if (!ret)
......@@ -1375,14 +1379,14 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
/* unpack the aggregated packets and process them one by one */
while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len,
batadv_ogm_packet->tt_num_changes)) {
tt_buff = packet_buff + buff_pos + BATADV_OGM_HLEN;
batadv_ogm_packet->tvlv_len)) {
tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN;
batadv_iv_ogm_process(ethhdr, batadv_ogm_packet, tt_buff,
if_incoming);
batadv_iv_ogm_process(ethhdr, batadv_ogm_packet,
tvlv_buff, if_incoming);
buff_pos += BATADV_OGM_HLEN;
buff_pos += batadv_tt_len(batadv_ogm_packet->tt_num_changes);
buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
packet_pos = packet_buff + buff_pos;
batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
......
This diff is collapsed.
......@@ -326,4 +326,39 @@ static inline uint64_t batadv_sum_counter(struct batadv_priv *bat_priv,
*/
#define BATADV_SKB_CB(__skb) ((struct batadv_skb_cb *)&((__skb)->cb[0]))
void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
uint8_t type, uint8_t version,
void *tvlv_value, uint16_t tvlv_value_len);
uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
unsigned char **packet_buff,
int *packet_buff_len,
int packet_min_len);
void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv,
struct batadv_ogm_packet *batadv_ogm_packet,
struct batadv_orig_node *orig_node);
void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv,
uint8_t type, uint8_t version);
void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
void (*optr)(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig,
uint8_t flags,
void *tvlv_value,
uint16_t tvlv_value_len),
int (*uptr)(struct batadv_priv *bat_priv,
uint8_t *src, uint8_t *dst,
void *tvlv_value,
uint16_t tvlv_value_len),
uint8_t type, uint8_t version, uint8_t flags);
void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv,
uint8_t type, uint8_t version);
int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
bool ogm_source,
struct batadv_orig_node *orig_node,
uint8_t *src, uint8_t *dst,
void *tvlv_buff, uint16_t tvlv_buff_len);
void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src,
uint8_t *dst, uint8_t type, uint8_t version,
void *tvlv_value, uint16_t tvlv_value_len);
#endif /* _NET_BATMAN_ADV_MAIN_H_ */
......@@ -20,6 +20,10 @@
#ifndef _NET_BATMAN_ADV_PACKET_H_
#define _NET_BATMAN_ADV_PACKET_H_
/**
* enum batadv_packettype - types for batman-adv encapsulated packets
* @BATADV_UNICAST_TVLV: unicast packet carrying TVLV containers
*/
enum batadv_packettype {
BATADV_IV_OGM = 0x01,
BATADV_ICMP = 0x02,
......@@ -31,6 +35,7 @@ enum batadv_packettype {
BATADV_ROAM_ADV = 0x08,
BATADV_UNICAST_4ADDR = 0x09,
BATADV_CODED = 0x0a,
BATADV_UNICAST_TVLV = 0x0b,
};
/**
......@@ -131,6 +136,11 @@ struct batadv_header {
*/
};
/**
* struct batadv_ogm_packet - ogm (routing protocol) packet
* @header: common batman packet header
* @tvlv_len: length of tvlv data following the ogm header
*/
struct batadv_ogm_packet {
struct batadv_header header;
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
......@@ -142,6 +152,7 @@ struct batadv_ogm_packet {
uint8_t tt_num_changes;
uint8_t ttvn; /* translation table version number */
__be16 tt_crc;
__be16 tvlv_len;
} __packed;
#define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet)
......@@ -311,4 +322,34 @@ struct batadv_coded_packet {
__be16 coded_len;
};
/**
* struct batadv_unicast_tvlv - generic unicast packet with tvlv payload
* @header: common batman packet header
* @reserved: reserved field (for packet alignment)
* @src: address of the source
* @dst: address of the destination
* @tvlv_len: length of tvlv data following the unicast tvlv header
* @align: 2 bytes to align the header to a 4 byte boundry
*/
struct batadv_unicast_tvlv_packet {
struct batadv_header header;
uint8_t reserved;
uint8_t dst[ETH_ALEN];
uint8_t src[ETH_ALEN];
__be16 tvlv_len;
uint16_t align;
};
/**
* struct batadv_tvlv_hdr - base tvlv header struct
* @type: tvlv container type (see batadv_tvlv_type)
* @version: tvlv container version
* @len: tvlv container length
*/
struct batadv_tvlv_hdr {
uint8_t type;
uint8_t version;
__be16 len;
};
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
......@@ -1139,6 +1139,54 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
return batadv_route_unicast_packet(skb, recv_if);
}
/**
* batadv_recv_unicast_tvlv - receive and process unicast tvlv packets
* @skb: unicast tvlv packet to process
* @recv_if: pointer to interface this packet was received on
* @dst_addr: the payload destination
*
* Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
* otherwise.
*/
int batadv_recv_unicast_tvlv(struct sk_buff *skb,
struct batadv_hard_iface *recv_if)
{
struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct batadv_unicast_tvlv_packet *unicast_tvlv_packet;
unsigned char *tvlv_buff;
uint16_t tvlv_buff_len;
int hdr_size = sizeof(*unicast_tvlv_packet);
int ret = NET_RX_DROP;
if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0)
return NET_RX_DROP;
/* the header is likely to be modified while forwarding */
if (skb_cow(skb, hdr_size) < 0)
return NET_RX_DROP;
/* packet needs to be linearized to access the tvlv content */
if (skb_linearize(skb) < 0)
return NET_RX_DROP;
unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)skb->data;
tvlv_buff = (unsigned char *)(skb->data + hdr_size);
tvlv_buff_len = ntohs(unicast_tvlv_packet->tvlv_len);
if (tvlv_buff_len > skb->len - hdr_size)
return NET_RX_DROP;
ret = batadv_tvlv_containers_process(bat_priv, false, NULL,
unicast_tvlv_packet->src,
unicast_tvlv_packet->dst,
tvlv_buff, tvlv_buff_len);
if (ret != NET_RX_SUCCESS)
ret = batadv_route_unicast_packet(skb, recv_if);
return ret;
}
int batadv_recv_bcast_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if)
......
......@@ -40,6 +40,8 @@ int batadv_recv_tt_query(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
int batadv_recv_roam_adv(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
int batadv_recv_unicast_tvlv(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
struct batadv_neigh_node *
batadv_find_router(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
......
......@@ -429,6 +429,20 @@ struct batadv_priv_gw {
atomic_t reselect;
};
/**
* struct batadv_priv_tvlv - per mesh interface tvlv data
* @container_list: list of registered tvlv containers to be sent with each OGM
* @handler_list: list of the various tvlv content handlers
* @container_list_lock: protects tvlv container list access
* @handler_list_lock: protects handler list access
*/
struct batadv_priv_tvlv {
struct hlist_head container_list;
struct hlist_head handler_list;
spinlock_t container_list_lock; /* protects container_list */
spinlock_t handler_list_lock; /* protects handler_list */
};
/**
* struct batadv_priv_vis - per mesh interface vis data
* @send_list: list of batadv_vis_info packets to sent
......@@ -531,6 +545,7 @@ struct batadv_priv_nc {
* @debug_log: holding debug logging relevant data
* @gw: gateway data
* @tt: translation table data
* @tvlv: type-version-length-value data
* @vis: vis data
* @dat: distributed arp table data
* @network_coding: bool indicating whether network coding is enabled
......@@ -583,6 +598,7 @@ struct batadv_priv {
#endif
struct batadv_priv_gw gw;
struct batadv_priv_tt tt;
struct batadv_priv_tvlv tvlv;
struct batadv_priv_vis vis;
#ifdef CONFIG_BATMAN_ADV_DAT
struct batadv_priv_dat dat;
......@@ -992,4 +1008,60 @@ struct batadv_dat_candidate {
struct batadv_orig_node *orig_node;
};
/**
* struct batadv_tvlv_container - container for tvlv appended to OGMs
* @list: hlist node for batadv_priv_tvlv::container_list
* @tvlv_hdr: tvlv header information needed to construct the tvlv
* @value_len: length of the buffer following this struct which contains
* the actual tvlv payload
* @refcount: number of contexts the object is used
*/
struct batadv_tvlv_container {
struct hlist_node list;
struct batadv_tvlv_hdr tvlv_hdr;
atomic_t refcount;
};
/**
* struct batadv_tvlv_handler - handler for specific tvlv type and version
* @list: hlist node for batadv_priv_tvlv::handler_list
* @ogm_handler: handler callback which is given the tvlv payload to process on
* incoming OGM packets
* @unicast_handler: handler callback which is given the tvlv payload to process
* on incoming unicast tvlv packets
* @type: tvlv type this handler feels responsible for
* @version: tvlv version this handler feels responsible for
* @flags: tvlv handler flags
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner
*/
struct batadv_tvlv_handler {
struct hlist_node list;
void (*ogm_handler)(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig,
uint8_t flags,
void *tvlv_value, uint16_t tvlv_value_len);
int (*unicast_handler)(struct batadv_priv *bat_priv,
uint8_t *src, uint8_t *dst,
void *tvlv_value, uint16_t tvlv_value_len);
uint8_t type;
uint8_t version;
uint8_t flags;
atomic_t refcount;
struct rcu_head rcu;
};
/**
* enum batadv_tvlv_handler_flags - tvlv handler flags definitions
* @BATADV_TVLV_HANDLER_OGM_CIFNOTFND: tvlv ogm processing function will call
* this handler even if its type was not found (with no data)
* @BATADV_TVLV_HANDLER_OGM_CALLED: interval tvlv handling flag - the API marks
* a handler as being called, so it won't be called if the
* BATADV_TVLV_HANDLER_OGM_CIFNOTFND flag was set
*/
enum batadv_tvlv_handler_flags {
BATADV_TVLV_HANDLER_OGM_CIFNOTFND = BIT(1),
BATADV_TVLV_HANDLER_OGM_CALLED = BIT(2),
};
#endif /* _NET_BATMAN_ADV_TYPES_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment