aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
authorMartin Hundebøll <martin@hundeboll.net>2013-01-25 05:12:43 -0500
committerAntonio Quartulli <ordex@autistici.org>2013-03-13 17:53:51 -0400
commit2df5278b0267c799f3e877e8eeddbb6e93cda0bb (patch)
treef6926a73b3ee324449d122cf185df0fade1bc248 /net/batman-adv
parent612d2b4fe0a1ff2f8389462a6f8be34e54124c05 (diff)
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 <martin@hundeboll.net> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/network-coding.c232
-rw-r--r--net/batman-adv/soft-interface.c4
-rw-r--r--net/batman-adv/types.h10
3 files changed, 246 insertions, 0 deletions
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
index 3d2ed2fe5421..57280797bf4e 100644
--- a/net/batman-adv/network-coding.c
+++ b/net/batman-adv/network-coding.c
@@ -25,11 +25,14 @@
25#include "send.h" 25#include "send.h"
26#include "originator.h" 26#include "originator.h"
27#include "hard-interface.h" 27#include "hard-interface.h"
28#include "routing.h"
28 29
29static struct lock_class_key batadv_nc_coding_hash_lock_class_key; 30static struct lock_class_key batadv_nc_coding_hash_lock_class_key;
30static struct lock_class_key batadv_nc_decoding_hash_lock_class_key; 31static struct lock_class_key batadv_nc_decoding_hash_lock_class_key;
31 32
32static void batadv_nc_worker(struct work_struct *work); 33static void batadv_nc_worker(struct work_struct *work);
34static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
35 struct batadv_hard_iface *recv_if);
33 36
34/** 37/**
35 * batadv_nc_start_timer - initialise the nc periodic worker 38 * batadv_nc_start_timer - initialise the nc periodic worker
@@ -67,6 +70,11 @@ int batadv_nc_init(struct batadv_priv *bat_priv)
67 batadv_hash_set_lock_class(bat_priv->nc.coding_hash, 70 batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
68 &batadv_nc_decoding_hash_lock_class_key); 71 &batadv_nc_decoding_hash_lock_class_key);
69 72
73 /* Register our packet type */
74 if (batadv_recv_handler_register(BATADV_CODED,
75 batadv_nc_recv_coded_packet) < 0)
76 goto err;
77
70 INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker); 78 INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
71 batadv_nc_start_timer(bat_priv); 79 batadv_nc_start_timer(bat_priv);
72 80
@@ -1486,11 +1494,235 @@ void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
1486} 1494}
1487 1495
1488/** 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 */
1505static struct batadv_unicast_packet *
1506batadv_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 */
1594static struct batadv_nc_packet *
1595batadv_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 */
1656static 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
1714free_nc_packet:
1715 batadv_nc_packet_free(nc_packet);
1716 return NET_RX_DROP;
1717}
1718
1719/**
1489 * batadv_nc_free - clean up network coding memory 1720 * batadv_nc_free - clean up network coding memory
1490 * @bat_priv: the bat priv with all the soft interface information 1721 * @bat_priv: the bat priv with all the soft interface information
1491 */ 1722 */
1492void batadv_nc_free(struct batadv_priv *bat_priv) 1723void batadv_nc_free(struct batadv_priv *bat_priv)
1493{ 1724{
1725 batadv_recv_handler_unregister(BATADV_CODED);
1494 cancel_delayed_work_sync(&bat_priv->nc.work); 1726 cancel_delayed_work_sync(&bat_priv->nc.work);
1495 1727
1496 batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL); 1728 batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL);
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 75204ec1eee4..f93ae42abb58 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -671,6 +671,10 @@ static const struct {
671 { "nc_recode" }, 671 { "nc_recode" },
672 { "nc_recode_bytes" }, 672 { "nc_recode_bytes" },
673 { "nc_buffer" }, 673 { "nc_buffer" },
674 { "nc_decode" },
675 { "nc_decode_bytes" },
676 { "nc_decode_failed" },
677 { "nc_sniffed" },
674#endif 678#endif
675}; 679};
676 680
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 5f3640d15dd2..aba8364c3689 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -280,6 +280,12 @@ struct batadv_bcast_duplist_entry {
280 * @BATADV_CNT_NC_RECODE: transmitted nc-recombined traffic packet counter 280 * @BATADV_CNT_NC_RECODE: transmitted nc-recombined traffic packet counter
281 * @BATADV_CNT_NC_RECODE_BYTES: transmitted nc-recombined traffic bytes counter 281 * @BATADV_CNT_NC_RECODE_BYTES: transmitted nc-recombined traffic bytes counter
282 * @BATADV_CNT_NC_BUFFER: counter for packets buffered for later nc decoding 282 * @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.
283 * @BATADV_CNT_NUM: number of traffic counters 289 * @BATADV_CNT_NUM: number of traffic counters
284 */ 290 */
285enum batadv_counters { 291enum batadv_counters {
@@ -313,6 +319,10 @@ enum batadv_counters {
313 BATADV_CNT_NC_RECODE, 319 BATADV_CNT_NC_RECODE,
314 BATADV_CNT_NC_RECODE_BYTES, 320 BATADV_CNT_NC_RECODE_BYTES,
315 BATADV_CNT_NC_BUFFER, 321 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,
316#endif 326#endif
317 BATADV_CNT_NUM, 327 BATADV_CNT_NUM,
318}; 328};