@@ -27,9 +27,11 @@
#define BAT_PACKET 0x01
#define BAT_ICMP 0x02
#define BAT_UNICAST 0x03
-#define BAT_BCAST 0x04
#define BAT_VIS 0x05
#define BAT_UNICAST_FRAG 0x06
+#define BAT_MCAST 0x07
+#define BAT_MCAST_DISC 0x08
+#define BAT_HNA 0x09
/* this file is included by batctl which needs these defines */
#define COMPAT_VERSION 12
@@ -112,7 +114,7 @@
uint16_t seqno;
} __attribute__((packed));
-struct bcast_packet {
+struct mcast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t orig[6];
@@ -133,4 +135,13 @@
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __attribute__((packed));
+struct mcastd_packet {
+ uint8_t packet_type;
+ uint8_t version; /* batman version field */
+ uint8_t orig[6];
+ uint32_t seqno;
+ uint8_t ttl;
+ uint8_t num_dest;
+} __attribute__((packed));
+
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
@@ -28,6 +28,7 @@
#include "bat_sysfs.h"
#include "originator.h"
#include "hash.h"
+#include "multicast.h"
#include <linux/if_arp.h>
@@ -158,7 +159,7 @@
* hacky trick to make sure that we send the HNA information via
* our new primary interface
*/
- atomic_set(&bat_priv->hna_local_changed, 1);
+ send_hna_packet(bat_priv);
}
static bool hardif_is_iface_up(struct batman_if *batman_if)
@@ -612,9 +613,17 @@
ret = recv_ucast_frag_packet(skb, batman_if);
break;
- /* broadcast packet */
- case BAT_BCAST:
- ret = recv_bcast_packet(skb, batman_if);
+ /* multicast/broadcast packets */
+ case BAT_MCAST:
+ ret = recv_mcast_packet(skb, batman_if);
+ break;
+
+ case BAT_MCAST_DISC:
+ ret = recv_mcastd_packet(skb, batman_if);
+ break;
+
+ case BAT_HNA:
+ ret = recv_mcast_packet(skb, batman_if);
break;
/* vis packet */
@@ -83,7 +83,6 @@
spin_lock_init(&bat_priv->orig_hash_lock);
spin_lock_init(&bat_priv->forw_bat_list_lock);
- spin_lock_init(&bat_priv->forw_bcast_list_lock);
spin_lock_init(&bat_priv->hna_lhash_lock);
spin_lock_init(&bat_priv->hna_ghash_lock);
spin_lock_init(&bat_priv->gw_list_lock);
@@ -92,7 +91,6 @@
spin_lock_init(&bat_priv->softif_neigh_lock);
INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
- INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
INIT_HLIST_HEAD(&bat_priv->gw_list);
INIT_HLIST_HEAD(&bat_priv->softif_neigh_list);
@@ -82,7 +82,6 @@
#define MESH_ACTIVE 1
#define MESH_DEACTIVATING 2
-#define BCAST_QUEUE_LEN 256
#define BATMAN_QUEUE_LEN 256
/*
@@ -32,4 +32,4 @@
endif
obj-m += batman-adv.o
-batman-adv-y := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o gateway_common.o gateway_client.o unicast.o $(shell [ "2" -eq "$(VERSION)" ] 2>&- && [ "6" -eq "$(PATCHLEVEL)" ] 2>&- && [ "$(SUBLEVEL)" -le "28" ] 2>&- && echo bat_printk.o)
+batman-adv-y := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o gateway_common.o gateway_client.o unicast.o multicast.o $(shell [ "2" -eq "$(VERSION)" ] 2>&- && [ "6" -eq "$(PATCHLEVEL)" ] 2>&- && [ "$(SUBLEVEL)" -le "28" ] 2>&- && echo bat_printk.o)
@@ -32,4 +32,4 @@
endif
obj-m += batman-adv.o
-batman-adv-y := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o gateway_common.o gateway_client.o unicast.o $(shell [ "2" -eq "$(VERSION)" ] 2>&- && [ "6" -eq "$(PATCHLEVEL)" ] 2>&- && [ "$(SUBLEVEL)" -le "28" ] 2>&- && echo bat_printk.o)
+batman-adv-y := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o gateway_common.o gateway_client.o unicast.o multicast.o $(shell [ "2" -eq "$(VERSION)" ] 2>&- && [ "6" -eq "$(PATCHLEVEL)" ] 2>&- && [ "$(SUBLEVEL)" -le "28" ] 2>&- && echo bat_printk.o)
@@ -0,0 +1,630 @@
+/*
+ * Copyright (C) 2010 B.A.T.M.A.N. contributors:
+ *
+ * Andreas Langer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+#include "multicast.h"
+#include "send.h"
+#include "soft-interface.h"
+#include "gateway_client.h"
+#include "hash.h"
+#include "translation-table.h"
+#include "routing.h"
+#include "hard-interface.h"
+
+static void free_mcast_dest(void *data, void *arg)
+{
+ struct mcast_dest_entry *mcast_dest_entry =
+ (struct mcast_dest_entry *)data;
+ kfree(mcast_dest_entry);
+}
+
+void free_mcast_router(void *data, void *arg)
+{
+ struct mcast_router_entry *mcast_router_entry =
+ (struct mcast_router_entry *)data;
+ struct bat_priv *bat_priv = (struct bat_priv *)arg;
+ if (mcast_router_entry->mcast_dest_hash)
+ hash_delete(mcast_router_entry->mcast_dest_hash,
+ free_mcast_dest, bat_priv);
+ kfree(mcast_router_entry);
+}
+
+void send_hna_packet(struct bat_priv *bat_priv)
+{
+ struct sk_buff *skb;
+ unsigned char *skb_buff;
+ struct mcast_packet *mcast_packet;
+ uint16_t *num_hna;
+
+ if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
+ return;
+
+ if (!bat_priv->num_local_hna)
+ return;
+
+ if (!bat_priv->primary_if)
+ return;
+
+ skb = dev_alloc_skb((bat_priv->num_local_hna * ETH_ALEN) +
+ sizeof(struct mcast_packet) + sizeof(struct ethhdr) + 2);
+
+ if (!skb)
+ return;
+
+ skb_reserve(skb, sizeof(struct ethhdr));
+
+ skb_buff = skb_put(skb, sizeof(struct mcast_packet) +
+ (bat_priv->num_local_hna * ETH_ALEN) + 2);
+ mcast_packet = (struct mcast_packet *)skb->data;
+ num_hna = (uint16_t *)((void *)skb->data + sizeof(struct mcast_packet));
+ mcast_packet->version = COMPAT_VERSION;
+ mcast_packet->ttl = TTL;
+ mcast_packet->packet_type = BAT_HNA;
+ memcpy(mcast_packet->orig,
+ bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ /* set broadcast sequence number */
+ mcast_packet->seqno =
+ htonl(atomic_inc_return(&bat_priv->mcast_seqno));
+ *num_hna = hna_local_fill_buffer(bat_priv,
+ (void *)((void *)skb->data +
+ sizeof(struct mcast_packet) + 2),
+ bat_priv->num_local_hna * ETH_ALEN);
+
+ send_mcast_packet(bat_priv, skb, NULL);
+ bat_priv->hna_timer = jiffies + msecs_to_jiffies(5000);
+ kfree_skb(skb);
+}
+
+void send_mcastd_packet(struct bat_priv *bat_priv, struct hashtable_t *hash,
+ uint8_t *addr, uint32_t seqno)
+{
+ HASHIT(hashit);
+ HASHIT(_hashit);
+ struct sk_buff *skb;
+ unsigned char *skb_buff;
+ struct mcastd_packet *mcastd_packet;
+ struct mcast_router_entry *mcast_router_entry;
+ struct mcast_dest_entry *mcast_dest_entry;
+ struct batman_if *batman_if;
+ uint8_t mcast_info[1410];
+ uint8_t *mi;
+
+ while (hash_iterate(hash, &hashit)) {
+ mcast_router_entry = hashit.bucket->data;
+
+ skb = dev_alloc_skb(1410 +
+ sizeof(struct mcastd_packet) +
+ sizeof(struct ethhdr));
+
+ if (!skb)
+ continue;
+
+ skb_reserve(skb, sizeof(struct ethhdr));
+
+ batman_if = mcast_router_entry->batman_if;
+ _hashit.index = -1;
+ _hashit.bucket = NULL;
+ mi = mcast_info;
+ while (hash_iterate(mcast_router_entry->mcast_dest_hash,
+ &_hashit)) {
+ mcast_dest_entry = _hashit.bucket->data;
+ memcpy(mi, mcast_dest_entry->addr, ETH_ALEN);
+ mi += ETH_ALEN;
+ }
+ skb_buff = skb_put(skb, sizeof(struct mcastd_packet) +
+ (mcast_router_entry->num_dest * ETH_ALEN));
+ mcastd_packet = (struct mcastd_packet *)skb->data;
+ mcastd_packet->packet_type = BAT_MCAST_DISC;
+ mcastd_packet->version = COMPAT_VERSION;
+ mcastd_packet->ttl = 50;
+ mcastd_packet->num_dest = mcast_router_entry->num_dest;
+ mcastd_packet->seqno = seqno;
+ if (addr == NULL) {
+ memcpy(mcastd_packet->orig,
+ bat_priv->primary_if->net_dev->dev_addr,
+ ETH_ALEN);
+ } else {
+ memcpy(mcastd_packet->orig, addr, ETH_ALEN);
+ }
+
+ memcpy(((void *)skb->data + sizeof(struct mcastd_packet)),
+ (void *)mcast_info,
+ mcast_router_entry->num_dest * ETH_ALEN);
+
+ send_skb_packet(skb, batman_if, mcast_router_entry->router);
+ }
+}
+
+static void send_mcastd_packets(struct bat_priv *bat_priv)
+{
+ HASHIT(hashit);
+ struct orig_node *orig_node;
+ struct neigh_node *router;
+ struct mcast_router_entry *mcast_router_entry;
+ struct mcast_dest_entry *mcast_dest_entry;
+ uint32_t seqno;
+
+ if (bat_priv->mcast_router_hash)
+ hash_delete(bat_priv->mcast_router_hash, free_mcast_router, bat_priv);
+
+ bat_priv->mcast_router_hash = hash_new(128, compare_orig, choose_orig);
+
+ if (!bat_priv->mcast_router_hash) {
+ goto out;
+ }
+
+ while (hash_iterate(bat_priv->orig_hash, &hashit)) {
+ orig_node = hashit.bucket->data;
+
+ router = find_router(orig_node, NULL);
+
+ /* If we don't have a route skip */
+ if (!router) {
+ continue;
+ }
+
+ if (router->tq_avg <= TQ_TOTAL_BIDRECT_LIMIT)
+ continue;
+
+ mcast_router_entry = ((struct mcast_router_entry *)
+ hash_find(bat_priv->mcast_router_hash,
+ router->orig_node->primary_addr));
+
+ if (!mcast_router_entry) {
+ mcast_router_entry =
+ kmalloc(sizeof(struct mcast_router_entry),
+ GFP_ATOMIC);
+ mcast_router_entry->num_dest = 0;
+ mcast_router_entry->batman_if = router->if_incoming;
+ mcast_router_entry->tq = router->tq_avg;
+ mcast_router_entry->mcast_dest_hash =
+ hash_new(128, compare_orig, choose_orig);
+ memcpy(mcast_router_entry->router, router->addr,
+ ETH_ALEN);
+ memcpy(mcast_router_entry->primary,
+ router->orig_node->primary_addr, ETH_ALEN);
+ hash_add(bat_priv->mcast_router_hash,
+ mcast_router_entry);
+ }
+
+ if (mcast_router_entry->num_dest < 235) {
+ mcast_router_entry->num_dest++;
+ mcast_dest_entry =
+ kmalloc(sizeof(struct mcast_dest_entry),
+ GFP_ATOMIC);
+ memcpy(mcast_dest_entry->addr, orig_node->orig,
+ ETH_ALEN);
+ hash_add(mcast_router_entry->mcast_dest_hash,
+ mcast_dest_entry);
+
+ if (!compare_orig(mcast_router_entry->router, router->addr) &&
+ router->tq_avg > mcast_router_entry->tq) {
+ mcast_router_entry->batman_if = router->if_incoming;
+ mcast_router_entry->tq = router->tq_avg;
+ memcpy(mcast_router_entry->router, router->addr, ETH_ALEN);
+ }
+ }
+ }
+
+ /* set sequence number */
+ seqno = htonl(atomic_inc_return(&bat_priv->mcast_disc_seqno));
+ send_mcastd_packet(bat_priv, bat_priv->mcast_router_hash,
+ NULL, seqno);
+
+out:
+ bat_priv->mcast_disc_timer = jiffies + msecs_to_jiffies(1000);
+}
+
+int send_mcast_packet(struct bat_priv *bat_priv, struct sk_buff *skb, struct ethhdr *ethhdr)
+{
+ HASHIT(hashit);
+ struct mcast_packet *mcast_packet;
+ struct orig_node *orig_node = NULL;
+ struct mcast_router_entry *mcast_router_entry;
+ struct sk_buff *skb1;
+ struct batman_if *batman_if;
+
+ if (!bat_priv->primary_if)
+ goto out;
+
+ if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
+ goto out;
+
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ goto out;
+
+ /* as we have a copy now, it is safe to decrease the TTL */
+ mcast_packet = (struct mcast_packet *)skb->data;
+ mcast_packet->ttl--;
+
+ spin_lock_bh(&bat_priv->orig_hash_lock);
+
+ if (!ethhdr) {
+ if (!bat_priv->mcast_router_hash)
+ goto free;
+ if (time_after(jiffies, bat_priv->mcast_disc_timer))
+ send_mcastd_packets(bat_priv);
+ while (hash_iterate(bat_priv->mcast_router_hash, &hashit)) {
+ mcast_router_entry = hashit.bucket->data;
+ batman_if = mcast_router_entry->batman_if;
+ skb1 = skb_copy(skb, GFP_ATOMIC);
+ if (!skb1)
+ continue;
+
+ skb_reset_mac_header(skb1);
+ send_skb_packet(skb1, batman_if,
+ mcast_router_entry->router);
+ }
+ } else {
+ /* Here we consult the orig mcast table to see
+ * who we need to forward to
+ */
+ orig_node = ((struct orig_node *)
+ hash_find(bat_priv->orig_hash, mcast_packet->orig));
+ if (!orig_node)
+ goto free;
+
+ while (hash_iterate(orig_node->mcast_router_hash, &hashit)) {
+ mcast_router_entry = hashit.bucket->data;
+ batman_if = mcast_router_entry->batman_if;
+ skb1 = skb_copy(skb, GFP_ATOMIC);
+ if (!skb1)
+ continue;
+
+ send_skb_packet(skb1, batman_if,
+ mcast_router_entry->router);
+ }
+ }
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+
+free:
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ kfree_skb(skb);
+out:
+ return NETDEV_TX_BUSY;
+}
+
+int mcast_data_print_text(struct seq_file *seq, void *offset)
+{
+ HASHIT(hashit);
+ HASHIT(_hashit);
+ struct net_device *net_dev = (struct net_device *)seq->private;
+ struct bat_priv *bat_priv = netdev_priv(net_dev);
+ struct orig_node *orig_node;
+ struct mcast_router_entry *mcast_router_entry;
+ int i;
+
+ if ((!bat_priv->primary_if) ||
+ (bat_priv->primary_if->if_status != IF_ACTIVE)) {
+ if (!bat_priv->primary_if)
+ return seq_printf(seq, "BATMAN mesh %s disabled - "
+ "please specify interfaces to enable it\n",
+ net_dev->name);
+
+ return seq_printf(seq, "BATMAN mesh %s "
+ "disabled - primary interface not active\n",
+ net_dev->name);
+ }
+
+ seq_printf(seq, "Mcast sent locally\n");
+
+ spin_lock_bh(&bat_priv->orig_hash_lock);
+
+ if (bat_priv->mcast_router_hash) {
+ while (hash_iterate(bat_priv->mcast_router_hash, &hashit)) {
+ mcast_router_entry = hashit.bucket->data;
+ seq_printf(seq, " * %pM [%pM]\n",
+ mcast_router_entry->primary,
+ mcast_router_entry->router);
+ }
+ }
+
+ hashit.index = -1;
+ hashit.bucket = NULL;
+
+ while (hash_iterate(bat_priv->orig_hash, &hashit)) {
+ orig_node = hashit.bucket->data;
+ _hashit.index = -1;
+ _hashit.bucket = NULL;
+ i = 0;
+ seq_printf(seq, "Mcast forwarded from Originator %pM\n",
+ orig_node->orig);
+ while (hash_iterate(orig_node->mcast_router_hash, &_hashit)) {
+ mcast_router_entry = _hashit.bucket->data;
+ seq_printf(seq, " * %pM - [%10s]\n",
+ mcast_router_entry->router,
+ mcast_router_entry->batman_if->net_dev->name);
+ }
+ }
+
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+
+ return 0;
+}
+
+static void mcast_update_orig_routes(struct bat_priv *bat_priv,
+ struct orig_node *orig_node, struct sk_buff *skb,
+ uint8_t is_duplicate, struct batman_if *recv_if)
+{
+ struct ethhdr *ethhdr;
+ struct mcastd_packet *mcastd_packet;
+ uint8_t *dest_addr;
+ struct neigh_node *router;
+ int i;
+ struct mcast_router_entry *mcast_router_entry;
+ struct mcast_dest_entry *mcast_dest_entry;
+ uint8_t new_entries = 0;
+ struct orig_node *router_node;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+ mcastd_packet = (struct mcastd_packet *)skb->data;
+
+ if (!is_duplicate) {
+ if (orig_node->mcast_router_hash)
+ hash_delete(orig_node->mcast_router_hash,
+ free_mcast_router, bat_priv);
+
+ orig_node->mcast_router_hash =
+ hash_new(1024, compare_orig, choose_orig);
+ }
+
+ if (!orig_node->mcast_router_hash)
+ orig_node->mcast_router_hash =
+ hash_new(1024, compare_orig, choose_orig);
+
+ if (!orig_node->mcast_router_hash) {
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ return;
+ }
+
+ skb->data += sizeof(struct mcastd_packet);
+ for (i = 0; i < mcastd_packet->num_dest; i++, skb->data += ETH_ALEN) {
+ dest_addr = (uint8_t *)skb->data;
+
+ if (is_my_mac(dest_addr))
+ continue;
+
+ router_node = ((struct orig_node *)
+ hash_find(bat_priv->orig_hash, dest_addr));
+
+ if (!router_node)
+ continue;
+
+ router = find_router(router_node, recv_if);
+
+ if (router->tq_avg <= TQ_TOTAL_BIDRECT_LIMIT)
+ continue;
+
+ if (compare_orig(router->orig_node->primary_addr,
+ orig_node->primary_addr))
+ continue;
+
+ mcast_router_entry = ((struct mcast_router_entry *)
+ hash_find(orig_node->mcast_router_hash,
+ router->orig_node->primary_addr));
+
+ if (!mcast_router_entry) {
+ mcast_router_entry =
+ kmalloc(sizeof(struct mcast_router_entry),
+ GFP_ATOMIC);
+ mcast_router_entry->num_dest = 0;
+ mcast_router_entry->batman_if = router->if_incoming;
+ mcast_router_entry->tq = router->tq_avg;
+ mcast_router_entry->mcast_dest_hash =
+ hash_new(128, compare_orig, choose_orig);
+ memcpy(mcast_router_entry->router, router->addr,
+ ETH_ALEN);
+ memcpy(mcast_router_entry->primary,
+ router->orig_node->primary_addr, ETH_ALEN);
+ hash_add(orig_node->mcast_router_hash,
+ mcast_router_entry);
+ }
+
+ mcast_dest_entry = ((struct mcast_dest_entry *)
+ hash_find(mcast_router_entry->mcast_dest_hash, dest_addr));
+
+ if (mcast_router_entry->num_dest < 235 && !mcast_dest_entry) {
+ mcast_router_entry->num_dest++;
+ new_entries++;
+ mcast_dest_entry =
+ kmalloc(sizeof(struct mcast_dest_entry),
+ GFP_ATOMIC);
+ memcpy(mcast_dest_entry->addr, dest_addr, ETH_ALEN);
+ memcpy(mcast_dest_entry->dest_addr, ethhdr->h_dest,
+ ETH_ALEN);
+ hash_add(mcast_router_entry->mcast_dest_hash,
+ mcast_dest_entry);
+ if (!compare_orig(mcast_router_entry->router, router->addr) &&
+ router->tq_avg > mcast_router_entry->tq) {
+ mcast_router_entry->batman_if = router->if_incoming;
+ mcast_router_entry->tq = router->tq_avg;
+ memcpy(mcast_router_entry->router, router->addr, ETH_ALEN);
+ }
+ }
+ }
+
+ if (new_entries)
+ send_mcastd_packet(bat_priv, orig_node->mcast_router_hash,
+ orig_node->orig, mcastd_packet->seqno);
+}
+
+int recv_mcastd_packet(struct sk_buff *skb, struct batman_if *recv_if)
+{
+ struct ethhdr *ethhdr;
+ struct mcastd_packet *mcastd_packet;
+ int hdr_size = sizeof(struct mcastd_packet);
+ struct orig_node *orig_node;
+ uint8_t is_duplicate = 0;
+ int32_t seq_diff;
+ struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
+
+
+ /* drop packet if it has not necessary minimum size */
+ if (unlikely(!pskb_may_pull(skb, hdr_size)))
+ return NET_RX_DROP;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* not for me */
+ if (!is_my_mac(ethhdr->h_dest))
+ return NET_RX_DROP;
+
+ /* ignore discovery packets sent by myself */
+ if (is_my_mac(ethhdr->h_source))
+ return NET_RX_DROP;
+
+ mcastd_packet = (struct mcastd_packet *)skb->data;
+
+ if (is_my_mac(mcastd_packet->orig))
+ return NET_RX_DROP;
+
+ spin_lock_bh(&bat_priv->orig_hash_lock);
+ orig_node = ((struct orig_node *)
+ hash_find(bat_priv->orig_hash, mcastd_packet->orig));
+
+ if (!orig_node) {
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ return NET_RX_DROP;
+ }
+
+ /* check whether the packet is a duplicate */
+ if (get_bit_status(orig_node->mcast_disc_bits,
+ orig_node->last_mcast_disc_seqno,
+ ntohl(mcastd_packet->seqno))) {
+ is_duplicate = 1;
+ }
+
+ seq_diff = ntohl(mcastd_packet->seqno) -
+ orig_node->last_mcast_disc_seqno;
+
+ /* check whether the packet is old and the host just restarted. */
+ if (window_protected(bat_priv, seq_diff,
+ &orig_node->mcast_disc_seqno_reset)) {
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ return NET_RX_DROP;
+ }
+
+ /* mark multicast in flood history, update window position
+ * if required. */
+ if (bit_get_packet(bat_priv, orig_node->mcast_disc_bits, seq_diff, 1))
+ orig_node->last_mcast_disc_seqno =
+ ntohl(mcastd_packet->seqno);
+
+ if (seq_diff < 0) {
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ return NET_RX_DROP;
+ }
+
+ mcast_update_orig_routes(bat_priv, orig_node, skb, is_duplicate,
+ recv_if);
+
+ kfree_skb(skb);
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ return NET_RX_SUCCESS;
+}
+
+int recv_mcast_packet(struct sk_buff *skb, struct batman_if *recv_if)
+{
+ struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
+ struct orig_node *orig_node;
+ struct mcast_packet *mcast_packet;
+ struct ethhdr *ethhdr;
+ int hdr_size = sizeof(struct mcast_packet);
+ int32_t seq_diff;
+ short *num_hna;
+ int hna_buff_len;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* ignore broadcasts sent by myself */
+ if (is_my_mac(ethhdr->h_source))
+ return NET_RX_DROP;
+
+ mcast_packet = (struct mcast_packet *)skb->data;
+
+ /* ignore broadcasts originated by myself */
+ if (is_my_mac(mcast_packet->orig))
+ return NET_RX_DROP;
+
+ if (mcast_packet->ttl < 2)
+ return NET_RX_DROP;
+
+ spin_lock_bh(&bat_priv->orig_hash_lock);
+ orig_node = ((struct orig_node *)
+ hash_find(bat_priv->orig_hash, mcast_packet->orig));
+
+ if (orig_node == NULL) {
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ return NET_RX_DROP;
+ }
+
+ /* check whether the packet is a duplicate */
+ if (get_bit_status(orig_node->mcast_bits,
+ orig_node->last_mcast_seqno,
+ ntohl(mcast_packet->seqno))) {
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ return NET_RX_DROP;
+ }
+
+ seq_diff = ntohl(mcast_packet->seqno) - orig_node->last_mcast_seqno;
+
+ if (seq_diff > 1)
+ printk("dropped %i packet\n", seq_diff);
+
+ /* check whether the packet is old and the host just restarted. */
+ if (window_protected(bat_priv, seq_diff,
+ &orig_node->mcast_seqno_reset)) {
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+ return NET_RX_DROP;
+ }
+
+ /* mark broadcast in flood history, update window position
+ * if required. */
+ if (bit_get_packet(bat_priv, orig_node->mcast_bits, seq_diff, 1))
+ orig_node->last_mcast_seqno = ntohl(mcast_packet->seqno);
+
+ if (mcast_packet->packet_type == BAT_HNA){
+ num_hna = (uint16_t *)((void *)mcast_packet +
+ sizeof(struct mcast_packet));
+ hna_buff_len = *num_hna * ETH_ALEN;
+ update_HNA(bat_priv, orig_node,
+ (unsigned char *)((void *)mcast_packet +
+ sizeof(struct mcast_packet) + 2),
+ hna_buff_len);
+ }
+
+ spin_unlock_bh(&bat_priv->orig_hash_lock);
+
+ send_mcast_packet(bat_priv, skb, ethhdr);
+
+ /* multicast for me */
+ if (mcast_packet->packet_type != BAT_HNA) {
+ interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
+ } else {
+ kfree_skb(skb);
+ }
+
+ return NET_RX_SUCCESS;
+}
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 B.A.T.M.A.N. contributors:
+ *
+ * Andreas Langer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#ifndef _NET_BATMAN_ADV_MULTICAST_H_
+#define _NET_BATMAN_ADV_MULTICAST_H_
+
+void free_mcast_router(void *data, void *arg);
+void send_mcastd_packet(struct bat_priv *bat_priv, struct hashtable_t *hash,
+ uint8_t *addr, uint32_t seqno);
+void send_hna_packet(struct bat_priv *bat_priv);
+int send_mcast_packet(struct bat_priv *bat_priv, struct sk_buff *skb,
+ struct ethhdr *ethhdr);
+int recv_mcastd_packet(struct sk_buff *skb, struct batman_if *recv_if);
+int recv_mcast_packet(struct sk_buff *skb, struct batman_if *recv_if);
+int mcast_data_print_text(struct seq_file *seq, void *offset);
+
+#endif /* _NET_BATMAN_ADV_MULTICAST_H_ */
@@ -31,6 +31,7 @@
#include "hard-interface.h"
#include "unicast.h"
#include "soft-interface.h"
+#include "multicast.h"
static void purge_orig(struct work_struct *work);
@@ -52,6 +53,11 @@
if (!bat_priv->orig_hash)
goto err;
+ bat_priv->mcast_router_hash = hash_new(1024, compare_orig, choose_orig);
+
+ if (!bat_priv->mcast_router_hash)
+ goto err;
+
spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
start_purge_timer(bat_priv);
return 1;
@@ -92,6 +98,10 @@
struct orig_node *orig_node = (struct orig_node *)data;
struct bat_priv *bat_priv = (struct bat_priv *)arg;
+ if (orig_node->mcast_router_hash)
+ hash_delete(orig_node->mcast_router_hash, free_mcast_router,
+ bat_priv);
+
/* for all neighbors towards this originator ... */
list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
neigh_node = list_entry(list_pos, struct neigh_node, list);
@@ -148,7 +158,9 @@
memcpy(orig_node->orig, addr, ETH_ALEN);
orig_node->router = NULL;
orig_node->hna_buff = NULL;
- orig_node->bcast_seqno_reset = jiffies - 1
+ orig_node->mcast_seqno_reset = jiffies - 1
+ - msecs_to_jiffies(RESET_PROTECTION_MS);
+ orig_node->mcast_disc_seqno_reset = jiffies - 1
- msecs_to_jiffies(RESET_PROTECTION_MS);
orig_node->batman_seqno_reset = jiffies - 1
- msecs_to_jiffies(RESET_PROTECTION_MS);
@@ -182,6 +194,7 @@
bat_priv->orig_hash = swaphash;
}
+ send_hna_packet(bat_priv);
return orig_node;
free_bcast_own_sum:
kfree(orig_node->bcast_own_sum);
@@ -27,9 +27,11 @@
#define BAT_PACKET 0x01
#define BAT_ICMP 0x02
#define BAT_UNICAST 0x03
-#define BAT_BCAST 0x04
#define BAT_VIS 0x05
#define BAT_UNICAST_FRAG 0x06
+#define BAT_MCAST 0x07
+#define BAT_MCAST_DISC 0x08
+#define BAT_HNA 0x09
/* this file is included by batctl which needs these defines */
#define COMPAT_VERSION 12
@@ -112,7 +114,7 @@
uint16_t seqno;
} __attribute__((packed));
-struct bcast_packet {
+struct mcast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t orig[6];
@@ -133,4 +135,13 @@
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __attribute__((packed));
+struct mcastd_packet {
+ uint8_t packet_type;
+ uint8_t version; /* batman version field */
+ uint8_t orig[6];
+ uint32_t seqno;
+ uint8_t ttl;
+ uint8_t num_dest;
+} __attribute__((packed));
+
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
@@ -58,7 +58,7 @@
spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
}
-static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node,
+void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node,
unsigned char *hna_buff, int hna_buff_len)
{
if ((hna_buff_len != orig_node->hna_buff_len) ||
@@ -122,9 +122,6 @@
if (orig_node->router != neigh_node)
update_route(bat_priv, orig_node, neigh_node,
hna_buff, hna_buff_len);
- /* may be just HNA changed */
- else
- update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len);
}
static int is_bidirectional_neigh(struct orig_node *orig_node,
@@ -339,7 +336,7 @@
* 0 if the packet is to be accepted
* 1 if the packet is to be ignored.
*/
-static int window_protected(struct bat_priv *bat_priv,
+int window_protected(struct bat_priv *bat_priv,
int32_t seq_num_diff,
unsigned long *last_reset)
{
@@ -1266,85 +1263,6 @@
return route_unicast_packet(skb, recv_if, hdr_size);
}
-
-int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if)
-{
- struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
- struct orig_node *orig_node;
- struct bcast_packet *bcast_packet;
- struct ethhdr *ethhdr;
- int hdr_size = sizeof(struct bcast_packet);
- int32_t seq_diff;
- unsigned long flags;
-
- /* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, hdr_size)))
- return NET_RX_DROP;
-
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
-
- /* packet with broadcast indication but unicast recipient */
- if (!is_bcast(ethhdr->h_dest))
- return NET_RX_DROP;
-
- /* packet with broadcast sender address */
- if (is_bcast(ethhdr->h_source))
- return NET_RX_DROP;
-
- /* ignore broadcasts sent by myself */
- if (is_my_mac(ethhdr->h_source))
- return NET_RX_DROP;
-
- bcast_packet = (struct bcast_packet *)skb->data;
-
- /* ignore broadcasts originated by myself */
- if (is_my_mac(bcast_packet->orig))
- return NET_RX_DROP;
-
- if (bcast_packet->ttl < 2)
- return NET_RX_DROP;
-
- spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
- orig_node = ((struct orig_node *)
- hash_find(bat_priv->orig_hash, bcast_packet->orig));
-
- if (orig_node == NULL) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return NET_RX_DROP;
- }
-
- /* check whether the packet is a duplicate */
- if (get_bit_status(orig_node->bcast_bits,
- orig_node->last_bcast_seqno,
- ntohl(bcast_packet->seqno))) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return NET_RX_DROP;
- }
-
- seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
-
- /* check whether the packet is old and the host just restarted. */
- if (window_protected(bat_priv, seq_diff,
- &orig_node->bcast_seqno_reset)) {
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- return NET_RX_DROP;
- }
-
- /* mark broadcast in flood history, update window position
- * if required. */
- if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
- orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
-
- spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
- /* rebroadcast packet */
- add_bcast_packet_to_list(bat_priv, skb);
-
- /* broadcast for me */
- interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
-
- return NET_RX_SUCCESS;
-}
-
int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if)
{
struct vis_packet *vis_packet;
@@ -44,5 +44,9 @@
struct batman_if *recv_if);
void update_bonding_candidates(struct bat_priv *bat_priv,
struct orig_node *orig_node);
+void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ unsigned char *hna_buff, int hna_buff_len);
+int window_protected(struct bat_priv *bat_priv,
+ int32_t seq_num_diff, unsigned long *last_reset);
#endif /* _NET_BATMAN_ADV_ROUTING_H_ */
@@ -29,11 +29,10 @@
#include "vis.h"
#include "aggregation.h"
#include "gateway_common.h"
+#include "multicast.h"
#include "compat.h"
-static void send_outstanding_bcast_packet(struct work_struct *work);
-
/* apply hop penalty for a normal link */
static uint8_t hop_penalty(const uint8_t tq)
{
@@ -214,33 +213,6 @@
rcu_read_unlock();
}
-static void rebuild_batman_packet(struct bat_priv *bat_priv,
- struct batman_if *batman_if)
-{
- int new_len;
- unsigned char *new_buff;
- struct batman_packet *batman_packet;
-
- new_len = sizeof(struct batman_packet) +
- (bat_priv->num_local_hna * ETH_ALEN);
- new_buff = kmalloc(new_len, GFP_ATOMIC);
-
- /* keep old buffer if kmalloc should fail */
- if (new_buff) {
- memcpy(new_buff, batman_if->packet_buff,
- sizeof(struct batman_packet));
- batman_packet = (struct batman_packet *)new_buff;
-
- batman_packet->num_hna = hna_local_fill_buffer(bat_priv,
- new_buff + sizeof(struct batman_packet),
- new_len - sizeof(struct batman_packet));
-
- kfree(batman_if->packet_buff);
- batman_if->packet_buff = new_buff;
- batman_if->packet_len = new_len;
- }
-}
-
void schedule_own_packet(struct batman_if *batman_if)
{
struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
@@ -265,9 +237,10 @@
batman_if->if_status = IF_ACTIVE;
/* if local hna has changed and interface is a primary interface */
- if ((atomic_read(&bat_priv->hna_local_changed)) &&
- (batman_if == bat_priv->primary_if))
- rebuild_batman_packet(bat_priv, batman_if);
+ if (((atomic_read(&bat_priv->hna_local_changed)) &&
+ (batman_if == bat_priv->primary_if)) ||
+ (time_after(jiffies, bat_priv->hna_timer)))
+ send_hna_packet(bat_priv);
/**
* NOTE: packet_buff might just have been re-allocated in
@@ -370,124 +343,7 @@
kfree(forw_packet);
}
-static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
- struct forw_packet *forw_packet,
- unsigned long send_time)
-{
- unsigned long flags;
- INIT_HLIST_NODE(&forw_packet->list);
-
- /* add new packet to packet list */
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags);
- hlist_add_head(&forw_packet->list, &bat_priv->forw_bcast_list);
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags);
-
- /* start timer for this packet */
- INIT_DELAYED_WORK(&forw_packet->delayed_work,
- send_outstanding_bcast_packet);
- queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work,
- send_time);
-}
-
#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
-/* add a broadcast packet to the queue and setup timers. broadcast packets
- * are sent multiple times to increase probability for beeing received.
- *
- * This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on
- * errors.
- *
- * The skb is not consumed, so the caller should make sure that the
- * skb is freed. */
-int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
-{
- struct forw_packet *forw_packet;
- struct bcast_packet *bcast_packet;
-
- if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) {
- bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n");
- goto out;
- }
-
- if (!bat_priv->primary_if)
- goto out;
-
- forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
-
- if (!forw_packet)
- goto out_and_inc;
-
- skb = skb_copy(skb, GFP_ATOMIC);
- if (!skb)
- goto packet_free;
-
- /* as we have a copy now, it is safe to decrease the TTL */
- bcast_packet = (struct bcast_packet *)skb->data;
- bcast_packet->ttl--;
-
- skb_reset_mac_header(skb);
-
- forw_packet->skb = skb;
- forw_packet->if_incoming = bat_priv->primary_if;
-
- /* how often did we send the bcast packet ? */
- forw_packet->num_packets = 0;
-
- _add_bcast_packet_to_list(bat_priv, forw_packet, 1);
- return NETDEV_TX_OK;
-
-packet_free:
- kfree(forw_packet);
-out_and_inc:
- atomic_inc(&bat_priv->bcast_queue_left);
-out:
- return NETDEV_TX_BUSY;
-}
-
-static void send_outstanding_bcast_packet(struct work_struct *work)
-{
- struct batman_if *batman_if;
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct forw_packet *forw_packet =
- container_of(delayed_work, struct forw_packet, delayed_work);
- unsigned long flags;
- struct sk_buff *skb1;
- struct net_device *soft_iface = forw_packet->if_incoming->soft_iface;
- struct bat_priv *bat_priv = netdev_priv(soft_iface);
-
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags);
- hlist_del(&forw_packet->list);
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags);
-
- if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING)
- goto out;
-
- /* rebroadcast packet */
- rcu_read_lock();
- list_for_each_entry_rcu(batman_if, &if_list, list) {
- if (batman_if->soft_iface != soft_iface)
- continue;
-
- /* send a copy of the saved skb */
- skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
- if (skb1)
- send_skb_packet(skb1, batman_if, broadcast_addr);
- }
- rcu_read_unlock();
-
- forw_packet->num_packets++;
-
- /* if we still have some more bcasts to send */
- if (forw_packet->num_packets < 3) {
- _add_bcast_packet_to_list(bat_priv, forw_packet,
- ((5 * HZ) / 1000));
- return;
- }
-
-out:
- forw_packet_free(forw_packet);
- atomic_inc(&bat_priv->bcast_queue_left);
-}
void send_outstanding_bat_packet(struct work_struct *work)
{
@@ -539,30 +395,6 @@
bat_dbg(DBG_BATMAN, bat_priv,
"purge_outstanding_packets()\n");
- /* free bcast list */
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags);
- hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
- &bat_priv->forw_bcast_list, list) {
-
- /**
- * if purge_outstanding_packets() was called with an argmument
- * we delete only packets belonging to the given interface
- */
- if ((batman_if) &&
- (forw_packet->if_incoming != batman_if))
- continue;
-
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags);
-
- /**
- * send_outstanding_bcast_packet() will lock the list to
- * delete the item from the list
- */
- cancel_delayed_work_sync(&forw_packet->delayed_work);
- spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags);
- }
- spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags);
-
/* free batman packet list */
spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags);
hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node,
@@ -33,7 +33,6 @@
struct batman_packet *batman_packet,
uint8_t directlink, int hna_buff_len,
struct batman_if *if_outgoing);
-int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb);
void send_outstanding_bat_packet(struct work_struct *work);
void purge_outstanding_packets(struct bat_priv *bat_priv,
struct batman_if *batman_if);
@@ -39,7 +39,7 @@
#include "compat.h"
#include "unicast.h"
#include "routing.h"
-
+#include "multicast.h"
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
static void bat_get_drvinfo(struct net_device *dev,
@@ -347,11 +347,11 @@
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *bat_priv = netdev_priv(soft_iface);
- struct bcast_packet *bcast_packet;
+ struct mcast_packet *mcast_packet;
struct vlan_ethhdr *vhdr;
int data_len = skb->len, ret;
short vid = -1;
- bool bcast_dst = false, do_bcast = true;
+ bool mcast_dst = false, do_mcast = true;
if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
goto dropped;
@@ -383,39 +383,37 @@
hna_local_add(soft_iface, ethhdr->h_source);
if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest))
- bcast_dst = true;
+ mcast_dst = true;
- if ((bcast_dst) && gw_is_target(bat_priv, skb))
- do_bcast = false;
+ if ((mcast_dst) && gw_is_target(bat_priv, skb))
+ do_mcast = false;
/* ethernet packet should be broadcasted */
- if (bcast_dst && do_bcast) {
+ if (mcast_dst && do_mcast) {
if (!bat_priv->primary_if)
goto dropped;
- if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
+ if (my_skb_head_push(skb, sizeof(struct mcast_packet)) < 0)
goto dropped;
- bcast_packet = (struct bcast_packet *)skb->data;
- bcast_packet->version = COMPAT_VERSION;
- bcast_packet->ttl = TTL;
+ mcast_packet = (struct mcast_packet *)skb->data;
+ mcast_packet->version = COMPAT_VERSION;
+ mcast_packet->ttl = TTL;
/* batman packet type: broadcast */
- bcast_packet->packet_type = BAT_BCAST;
+ mcast_packet->packet_type = BAT_MCAST;
/* hw address of first interface is the orig mac because only
* this mac is known throughout the mesh */
- memcpy(bcast_packet->orig,
+ memcpy(mcast_packet->orig,
bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
/* set broadcast sequence number */
- bcast_packet->seqno =
- htonl(atomic_inc_return(&bat_priv->bcast_seqno));
+ mcast_packet->seqno =
+ htonl(atomic_inc_return(&bat_priv->mcast_seqno));
- add_bcast_packet_to_list(bat_priv, skb);
+ send_mcast_packet(bat_priv, skb, NULL);
- /* a copy is stored in the bcast list, therefore removing
- * the original skb. */
kfree_skb(skb);
/* unicast packet */
@@ -595,16 +593,17 @@
atomic_set(&bat_priv->orig_interval, 1000);
atomic_set(&bat_priv->log_level, 0);
atomic_set(&bat_priv->frag_enabled, 1);
- atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN);
atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN);
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
- atomic_set(&bat_priv->bcast_seqno, 1);
- atomic_set(&bat_priv->hna_local_changed, 0);
+ atomic_set(&bat_priv->mcast_seqno, 1);
+ atomic_set(&bat_priv->mcast_disc_seqno, 1);
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
bat_priv->softif_neigh = NULL;
+ bat_priv->mcast_disc_timer = jiffies;
+ bat_priv->hna_timer = jiffies + msecs_to_jiffies(5000);
ret = sysfs_add_meshif(soft_iface);
if (ret < 0)
@@ -24,6 +24,7 @@
#include "soft-interface.h"
#include "types.h"
#include "hash.h"
+#include "multicast.h"
#include "compat.h"
static void hna_local_purge(struct work_struct *work);
@@ -47,7 +48,6 @@
if (!bat_priv->hna_local_hash)
return 0;
- atomic_set(&bat_priv->hna_local_changed, 0);
hna_local_start_timer(bat_priv);
return 1;
@@ -105,7 +105,6 @@
hash_add(bat_priv->hna_local_hash, hna_local_entry);
bat_priv->num_local_hna++;
- atomic_set(&bat_priv->hna_local_changed, 1);
if (bat_priv->hna_local_hash->elements * 4 >
bat_priv->hna_local_hash->size) {
@@ -120,6 +119,8 @@
spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags);
+ send_hna_packet(bat_priv);
+
/* remove address from global hash if present */
spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags);
@@ -28,9 +28,9 @@
#include "bitarray.h"
#define BAT_HEADER_LEN (sizeof(struct ethhdr) + \
- ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? \
+ ((sizeof(struct unicast_packet) > sizeof(struct mcast_packet) ? \
sizeof(struct unicast_packet) : \
- sizeof(struct bcast_packet))))
+ sizeof(struct mcast_packet))))
struct batman_if {
@@ -54,13 +54,13 @@
* orig_node - structure for orig_list maintaining nodes of mesh
* @primary_addr: hosts primary interface address
* @last_valid: when last packet from this node was received
- * @bcast_seqno_reset: time when the broadcast seqno window was reset
+ * @mcast_seqno_reset: time when the broadcast seqno window was reset
* @batman_seqno_reset: time when the batman seqno window was reset
* @gw_flags: flags related to gateway class
* @flags: for now only VIS_SERVER flag
* @last_real_seqno: last and best known squence number
* @last_ttl: ttl of last received packet
- * @last_bcast_seqno: last broadcast sequence number received by this host
+ * @last_mcast_seqno: last broadcast sequence number received by this host
*
* @candidates: how many candidates are available
* @selected: next bonding candidate
@@ -74,7 +74,8 @@
uint8_t tq_own;
int tq_asym_penalty;
unsigned long last_valid;
- unsigned long bcast_seqno_reset;
+ unsigned long mcast_seqno_reset;
+ unsigned long mcast_disc_seqno_reset;
unsigned long batman_seqno_reset;
uint8_t gw_flags;
uint8_t flags;
@@ -82,8 +83,10 @@
int16_t hna_buff_len;
uint32_t last_real_seqno;
uint8_t last_ttl;
- TYPE_OF_WORD bcast_bits[NUM_WORDS];
- uint32_t last_bcast_seqno;
+ TYPE_OF_WORD mcast_bits[NUM_WORDS];
+ TYPE_OF_WORD mcast_disc_bits[NUM_WORDS];
+ uint32_t last_mcast_seqno;
+ uint32_t last_mcast_disc_seqno;
struct list_head neigh_list;
struct list_head frag_list;
unsigned long last_frag_packet;
@@ -91,6 +94,7 @@
uint8_t candidates;
struct neigh_node *selected;
} bond;
+ struct hashtable_t *mcast_router_hash;
};
struct gw_node {
@@ -132,8 +136,8 @@
atomic_t gw_class;
atomic_t orig_interval;
atomic_t log_level;
- atomic_t bcast_seqno;
- atomic_t bcast_queue_left;
+ atomic_t mcast_seqno;
+ atomic_t mcast_disc_seqno;
atomic_t batman_queue_left;
char num_ifaces;
struct hlist_head softif_neigh_list;
@@ -143,22 +147,23 @@
struct kobject *mesh_obj;
struct dentry *debug_dir;
struct hlist_head forw_bat_list;
- struct hlist_head forw_bcast_list;
struct hlist_head gw_list;
struct list_head vis_send_list;
struct hashtable_t *orig_hash;
struct hashtable_t *hna_local_hash;
struct hashtable_t *hna_global_hash;
struct hashtable_t *vis_hash;
+ struct hashtable_t *mcast_router_hash;
spinlock_t orig_hash_lock; /* protects orig_hash */
spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
- spinlock_t forw_bcast_list_lock; /* protects */
spinlock_t hna_lhash_lock; /* protects hna_local_hash */
spinlock_t hna_ghash_lock; /* protects hna_global_hash */
spinlock_t gw_list_lock; /* protects gw_list */
spinlock_t vis_hash_lock; /* protects vis_hash */
spinlock_t vis_list_lock; /* protects vis_info::recv_list */
spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */
+ unsigned long mcast_disc_timer;
+ unsigned long hna_timer;
int16_t num_local_hna;
atomic_t hna_local_changed;
struct delayed_work hna_work;
@@ -267,4 +272,17 @@
struct rcu_head rcu;
};
+struct mcast_router_entry {
+ uint8_t primary[ETH_ALEN];
+ uint8_t router[ETH_ALEN];
+ uint8_t tq;
+ struct batman_if *batman_if;
+ uint32_t num_dest;
+ struct hashtable_t *mcast_dest_hash;
+};
+
+struct mcast_dest_entry {
+ uint8_t addr[ETH_ALEN];
+ uint8_t dest_addr[ETH_ALEN];
+};
#endif /* _NET_BATMAN_ADV_TYPES_H_ */