|
25 | 25 | #include "send.h" |
26 | 26 | #include "originator.h" |
27 | 27 | #include "hard-interface.h" |
| 28 | +#include "routing.h" |
28 | 29 |
|
29 | 30 | static struct lock_class_key batadv_nc_coding_hash_lock_class_key; |
30 | 31 | static struct lock_class_key batadv_nc_decoding_hash_lock_class_key; |
31 | 32 |
|
32 | 33 | 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); |
33 | 36 |
|
34 | 37 | /** |
35 | 38 | * batadv_nc_start_timer - initialise the nc periodic worker |
@@ -67,6 +70,11 @@ int batadv_nc_init(struct batadv_priv *bat_priv) |
67 | 70 | batadv_hash_set_lock_class(bat_priv->nc.coding_hash, |
68 | 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 | 78 | INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker); |
71 | 79 | batadv_nc_start_timer(bat_priv); |
72 | 80 |
|
@@ -1485,12 +1493,236 @@ void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv, |
1485 | 1493 | batadv_nc_skb_store_for_decoding(bat_priv, skb); |
1486 | 1494 | } |
1487 | 1495 |
|
| 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(ðhdr_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, ðhdr_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 | + |
1488 | 1719 | /** |
1489 | 1720 | * batadv_nc_free - clean up network coding memory |
1490 | 1721 | * @bat_priv: the bat priv with all the soft interface information |
1491 | 1722 | */ |
1492 | 1723 | void batadv_nc_free(struct batadv_priv *bat_priv) |
1493 | 1724 | { |
| 1725 | + batadv_recv_handler_unregister(BATADV_CODED); |
1494 | 1726 | cancel_delayed_work_sync(&bat_priv->nc.work); |
1495 | 1727 |
|
1496 | 1728 | batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL); |
|
0 commit comments