Skip to content

Commit 2df5278

Browse files
hundebollAntonio Quartulli
authored andcommitted
batman-adv: network coding - receive coded packets and decode them
When receiving a network coded packet, the decoding buffer is searched for a packet to use for decoding. The source, destination, and crc32 from the coded packet is used to identify the wanted packet. The decoded packet is passed to the usual unicast receiver function, as had it never been network coded. Signed-off-by: Martin Hundebøll <[email protected]> Signed-off-by: Marek Lindner <[email protected]> Signed-off-by: Antonio Quartulli <[email protected]>
1 parent 612d2b4 commit 2df5278

File tree

3 files changed

+246
-0
lines changed

3 files changed

+246
-0
lines changed

net/batman-adv/network-coding.c

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@
2525
#include "send.h"
2626
#include "originator.h"
2727
#include "hard-interface.h"
28+
#include "routing.h"
2829

2930
static struct lock_class_key batadv_nc_coding_hash_lock_class_key;
3031
static struct lock_class_key batadv_nc_decoding_hash_lock_class_key;
3132

3233
static void batadv_nc_worker(struct work_struct *work);
34+
static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
35+
struct batadv_hard_iface *recv_if);
3336

3437
/**
3538
* batadv_nc_start_timer - initialise the nc periodic worker
@@ -67,6 +70,11 @@ int batadv_nc_init(struct batadv_priv *bat_priv)
6770
batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
6871
&batadv_nc_decoding_hash_lock_class_key);
6972

73+
/* Register our packet type */
74+
if (batadv_recv_handler_register(BATADV_CODED,
75+
batadv_nc_recv_coded_packet) < 0)
76+
goto err;
77+
7078
INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
7179
batadv_nc_start_timer(bat_priv);
7280

@@ -1485,12 +1493,236 @@ void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
14851493
batadv_nc_skb_store_for_decoding(bat_priv, skb);
14861494
}
14871495

1496+
/**
1497+
* batadv_nc_skb_decode_packet - decode given skb using the decode data stored
1498+
* in nc_packet
1499+
* @skb: unicast skb to decode
1500+
* @nc_packet: decode data needed to decode the skb
1501+
*
1502+
* Returns pointer to decoded unicast packet if the packet was decoded or NULL
1503+
* in case of an error.
1504+
*/
1505+
static struct batadv_unicast_packet *
1506+
batadv_nc_skb_decode_packet(struct sk_buff *skb,
1507+
struct batadv_nc_packet *nc_packet)
1508+
{
1509+
const int h_size = sizeof(struct batadv_unicast_packet);
1510+
const int h_diff = sizeof(struct batadv_coded_packet) - h_size;
1511+
struct batadv_unicast_packet *unicast_packet;
1512+
struct batadv_coded_packet coded_packet_tmp;
1513+
struct ethhdr *ethhdr, ethhdr_tmp;
1514+
uint8_t *orig_dest, ttl, ttvn;
1515+
unsigned int coding_len;
1516+
1517+
/* Save headers temporarily */
1518+
memcpy(&coded_packet_tmp, skb->data, sizeof(coded_packet_tmp));
1519+
memcpy(&ethhdr_tmp, skb_mac_header(skb), sizeof(ethhdr_tmp));
1520+
1521+
if (skb_cow(skb, 0) < 0)
1522+
return NULL;
1523+
1524+
if (unlikely(!skb_pull_rcsum(skb, h_diff)))
1525+
return NULL;
1526+
1527+
/* Data points to batman header, so set mac header 14 bytes before
1528+
* and network to data
1529+
*/
1530+
skb_set_mac_header(skb, -ETH_HLEN);
1531+
skb_reset_network_header(skb);
1532+
1533+
/* Reconstruct original mac header */
1534+
ethhdr = (struct ethhdr *)skb_mac_header(skb);
1535+
memcpy(ethhdr, &ethhdr_tmp, sizeof(*ethhdr));
1536+
1537+
/* Select the correct unicast header information based on the location
1538+
* of our mac address in the coded_packet header
1539+
*/
1540+
if (batadv_is_my_mac(coded_packet_tmp.second_dest)) {
1541+
/* If we are the second destination the packet was overheard,
1542+
* so the Ethernet address must be copied to h_dest and
1543+
* pkt_type changed from PACKET_OTHERHOST to PACKET_HOST
1544+
*/
1545+
memcpy(ethhdr->h_dest, coded_packet_tmp.second_dest, ETH_ALEN);
1546+
skb->pkt_type = PACKET_HOST;
1547+
1548+
orig_dest = coded_packet_tmp.second_orig_dest;
1549+
ttl = coded_packet_tmp.second_ttl;
1550+
ttvn = coded_packet_tmp.second_ttvn;
1551+
} else {
1552+
orig_dest = coded_packet_tmp.first_orig_dest;
1553+
ttl = coded_packet_tmp.header.ttl;
1554+
ttvn = coded_packet_tmp.first_ttvn;
1555+
}
1556+
1557+
coding_len = ntohs(coded_packet_tmp.coded_len);
1558+
1559+
if (coding_len > skb->len)
1560+
return NULL;
1561+
1562+
/* Here the magic is reversed:
1563+
* extract the missing packet from the received coded packet
1564+
*/
1565+
batadv_nc_memxor(skb->data + h_size,
1566+
nc_packet->skb->data + h_size,
1567+
coding_len);
1568+
1569+
/* Resize decoded skb if decoded with larger packet */
1570+
if (nc_packet->skb->len > coding_len + h_size)
1571+
pskb_trim_rcsum(skb, coding_len + h_size);
1572+
1573+
/* Create decoded unicast packet */
1574+
unicast_packet = (struct batadv_unicast_packet *)skb->data;
1575+
unicast_packet->header.packet_type = BATADV_UNICAST;
1576+
unicast_packet->header.version = BATADV_COMPAT_VERSION;
1577+
unicast_packet->header.ttl = ttl;
1578+
memcpy(unicast_packet->dest, orig_dest, ETH_ALEN);
1579+
unicast_packet->ttvn = ttvn;
1580+
1581+
batadv_nc_packet_free(nc_packet);
1582+
return unicast_packet;
1583+
}
1584+
1585+
/**
1586+
* batadv_nc_find_decoding_packet - search through buffered decoding data to
1587+
* find the data needed to decode the coded packet
1588+
* @bat_priv: the bat priv with all the soft interface information
1589+
* @ethhdr: pointer to the ethernet header inside the coded packet
1590+
* @coded: coded packet we try to find decode data for
1591+
*
1592+
* Returns pointer to nc packet if the needed data was found or NULL otherwise.
1593+
*/
1594+
static struct batadv_nc_packet *
1595+
batadv_nc_find_decoding_packet(struct batadv_priv *bat_priv,
1596+
struct ethhdr *ethhdr,
1597+
struct batadv_coded_packet *coded)
1598+
{
1599+
struct batadv_hashtable *hash = bat_priv->nc.decoding_hash;
1600+
struct batadv_nc_packet *tmp_nc_packet, *nc_packet = NULL;
1601+
struct batadv_nc_path *nc_path, nc_path_key;
1602+
uint8_t *dest, *source;
1603+
__be32 packet_id;
1604+
int index;
1605+
1606+
if (!hash)
1607+
return NULL;
1608+
1609+
/* Select the correct packet id based on the location of our mac-addr */
1610+
dest = ethhdr->h_source;
1611+
if (!batadv_is_my_mac(coded->second_dest)) {
1612+
source = coded->second_source;
1613+
packet_id = coded->second_crc;
1614+
} else {
1615+
source = coded->first_source;
1616+
packet_id = coded->first_crc;
1617+
}
1618+
1619+
batadv_nc_hash_key_gen(&nc_path_key, source, dest);
1620+
index = batadv_nc_hash_choose(&nc_path_key, hash->size);
1621+
1622+
/* Search for matching coding path */
1623+
rcu_read_lock();
1624+
hlist_for_each_entry_rcu(nc_path, &hash->table[index], hash_entry) {
1625+
/* Find matching nc_packet */
1626+
spin_lock_bh(&nc_path->packet_list_lock);
1627+
list_for_each_entry(tmp_nc_packet,
1628+
&nc_path->packet_list, list) {
1629+
if (packet_id == tmp_nc_packet->packet_id) {
1630+
list_del(&tmp_nc_packet->list);
1631+
1632+
nc_packet = tmp_nc_packet;
1633+
break;
1634+
}
1635+
}
1636+
spin_unlock_bh(&nc_path->packet_list_lock);
1637+
1638+
if (nc_packet)
1639+
break;
1640+
}
1641+
rcu_read_unlock();
1642+
1643+
if (!nc_packet)
1644+
batadv_dbg(BATADV_DBG_NC, bat_priv,
1645+
"No decoding packet found for %u\n", packet_id);
1646+
1647+
return nc_packet;
1648+
}
1649+
1650+
/**
1651+
* batadv_nc_recv_coded_packet - try to decode coded packet and enqueue the
1652+
* resulting unicast packet
1653+
* @skb: incoming coded packet
1654+
* @recv_if: pointer to interface this packet was received on
1655+
*/
1656+
static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
1657+
struct batadv_hard_iface *recv_if)
1658+
{
1659+
struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1660+
struct batadv_unicast_packet *unicast_packet;
1661+
struct batadv_coded_packet *coded_packet;
1662+
struct batadv_nc_packet *nc_packet;
1663+
struct ethhdr *ethhdr;
1664+
int hdr_size = sizeof(*coded_packet);
1665+
1666+
/* Check if network coding is enabled */
1667+
if (!atomic_read(&bat_priv->network_coding))
1668+
return NET_RX_DROP;
1669+
1670+
/* Make sure we can access (and remove) header */
1671+
if (unlikely(!pskb_may_pull(skb, hdr_size)))
1672+
return NET_RX_DROP;
1673+
1674+
coded_packet = (struct batadv_coded_packet *)skb->data;
1675+
ethhdr = (struct ethhdr *)skb_mac_header(skb);
1676+
1677+
/* Verify frame is destined for us */
1678+
if (!batadv_is_my_mac(ethhdr->h_dest) &&
1679+
!batadv_is_my_mac(coded_packet->second_dest))
1680+
return NET_RX_DROP;
1681+
1682+
/* Update stat counter */
1683+
if (batadv_is_my_mac(coded_packet->second_dest))
1684+
batadv_inc_counter(bat_priv, BATADV_CNT_NC_SNIFFED);
1685+
1686+
nc_packet = batadv_nc_find_decoding_packet(bat_priv, ethhdr,
1687+
coded_packet);
1688+
if (!nc_packet) {
1689+
batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE_FAILED);
1690+
return NET_RX_DROP;
1691+
}
1692+
1693+
/* Make skb's linear, because decoding accesses the entire buffer */
1694+
if (skb_linearize(skb) < 0)
1695+
goto free_nc_packet;
1696+
1697+
if (skb_linearize(nc_packet->skb) < 0)
1698+
goto free_nc_packet;
1699+
1700+
/* Decode the packet */
1701+
unicast_packet = batadv_nc_skb_decode_packet(skb, nc_packet);
1702+
if (!unicast_packet) {
1703+
batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE_FAILED);
1704+
goto free_nc_packet;
1705+
}
1706+
1707+
/* Mark packet as decoded to do correct recoding when forwarding */
1708+
BATADV_SKB_CB(skb)->decoded = true;
1709+
batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE);
1710+
batadv_add_counter(bat_priv, BATADV_CNT_NC_DECODE_BYTES,
1711+
skb->len + ETH_HLEN);
1712+
return batadv_recv_unicast_packet(skb, recv_if);
1713+
1714+
free_nc_packet:
1715+
batadv_nc_packet_free(nc_packet);
1716+
return NET_RX_DROP;
1717+
}
1718+
14881719
/**
14891720
* batadv_nc_free - clean up network coding memory
14901721
* @bat_priv: the bat priv with all the soft interface information
14911722
*/
14921723
void batadv_nc_free(struct batadv_priv *bat_priv)
14931724
{
1725+
batadv_recv_handler_unregister(BATADV_CODED);
14941726
cancel_delayed_work_sync(&bat_priv->nc.work);
14951727

14961728
batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL);

net/batman-adv/soft-interface.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,10 @@ static const struct {
671671
{ "nc_recode" },
672672
{ "nc_recode_bytes" },
673673
{ "nc_buffer" },
674+
{ "nc_decode" },
675+
{ "nc_decode_bytes" },
676+
{ "nc_decode_failed" },
677+
{ "nc_sniffed" },
674678
#endif
675679
};
676680

net/batman-adv/types.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ struct batadv_bcast_duplist_entry {
280280
* @BATADV_CNT_NC_RECODE: transmitted nc-recombined traffic packet counter
281281
* @BATADV_CNT_NC_RECODE_BYTES: transmitted nc-recombined traffic bytes counter
282282
* @BATADV_CNT_NC_BUFFER: counter for packets buffered for later nc decoding
283+
* @BATADV_CNT_NC_DECODE: received and nc-decoded traffic packet counter
284+
* @BATADV_CNT_NC_DECODE_BYTES: received and nc-decoded traffic bytes counter
285+
* @BATADV_CNT_NC_DECODE_FAILED: received and decode-failed traffic packet
286+
* counter
287+
* @BATADV_CNT_NC_SNIFFED: counter for nc-decoded packets received in promisc
288+
* mode.
283289
* @BATADV_CNT_NUM: number of traffic counters
284290
*/
285291
enum batadv_counters {
@@ -313,6 +319,10 @@ enum batadv_counters {
313319
BATADV_CNT_NC_RECODE,
314320
BATADV_CNT_NC_RECODE_BYTES,
315321
BATADV_CNT_NC_BUFFER,
322+
BATADV_CNT_NC_DECODE,
323+
BATADV_CNT_NC_DECODE_BYTES,
324+
BATADV_CNT_NC_DECODE_FAILED,
325+
BATADV_CNT_NC_SNIFFED,
316326
#endif
317327
BATADV_CNT_NUM,
318328
};

0 commit comments

Comments
 (0)