lq_packet: do not report duplicate neighbours in HELLO messages
authorIwan G. Flameling <iwanovich@gmail.com>
Fri, 3 Feb 2017 13:17:51 +0000 (14:17 +0100)
committerFerry Huberts <ferry.huberts@pelagic.nl>
Tue, 7 Feb 2017 12:37:58 +0000 (13:37 +0100)
See the explanations in the descriptions of commits 2f38613 and
5089a79.

To fix the issue more thoroughly we need to ensure that no duplicate
neighbours are sent or received because that confuses the receiver.
This is especially true when the HELLO messages are fragmented, and
even more so when the fragments have some delay between them since
that causes link instability.

This commit fixes that for the sending side.

Signed-off-by: Iwan G. Flameling <iwanovich@gmail.com>
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
src/lq_packet.c

index 5364f8b..97b0842 100644 (file)
@@ -68,6 +68,21 @@ bool lq_tc_pending = false;
 static uint32_t msg_buffer_aligned[(MAXMESSAGESIZE - OLSR_HEADERSIZE) / sizeof(uint32_t) + 1];
 static unsigned char *const msg_buffer = (unsigned char *)msg_buffer_aligned;
 
+static struct lq_hello_neighbor *neigh_find(struct lq_hello_message *lq_hello, struct link_entry *walker) {
+  struct lq_hello_neighbor *neigh;
+
+  assert(lq_hello);
+  assert(walker);
+
+  for (neigh = lq_hello->neigh; neigh; neigh = neigh->next) {
+    if (ipequal(&neigh->addr, &walker->neighbor_iface_addr)) {
+      return neigh;
+    }
+  }
+
+  return NULL;
+}
+
 static void
 create_lq_hello(struct lq_hello_message *lq_hello, struct interface_olsr *outif)
 {
@@ -92,46 +107,59 @@ create_lq_hello(struct lq_hello_message *lq_hello, struct interface_olsr *outif)
   // loop through the link set
 
   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
+    struct lq_hello_neighbor *neigh;
+    bool neigh_is_new = false;
+    uint8_t link_type;
 
     // allocate a neighbour entry
-    struct lq_hello_neighbor *neigh = olsr_malloc_lq_hello_neighbor("Build LQ_HELLO");
+    neigh = neigh_find(lq_hello, walker);
+    if (!neigh) {
+      neigh = olsr_malloc_lq_hello_neighbor("Build LQ_HELLO");
+      neigh_is_new = true;
+    }
 
     // a) this neighbor interface IS NOT visible via the output interface
     if (!ipequal(&walker->local_iface_addr, &outif->ip_addr))
-      neigh->link_type = UNSPEC_LINK;
+      link_type = UNSPEC_LINK;
 
     // b) this neighbor interface IS visible via the output interface
 
     else
-      neigh->link_type = lookup_link_status(walker);
+      link_type = lookup_link_status(walker);
 
-    // set the entry's link quality
-    olsr_copy_hello_lq(neigh, walker);
+    if (neigh_is_new || ((neigh->link_type == UNSPEC_LINK) && (link_type != UNSPEC_LINK))) {
+      neigh->link_type = link_type;
 
-    // set the entry's neighbour type
+      // set the entry's link quality
+      olsr_copy_hello_lq(neigh, walker);
 
-    if (walker->neighbor->is_mpr)
-      neigh->neigh_type = MPR_NEIGH;
+      // set the entry's neighbour type
 
-    else if (walker->neighbor->status == SYM)
-      neigh->neigh_type = SYM_NEIGH;
+      if (walker->neighbor->is_mpr)
+        neigh->neigh_type = MPR_NEIGH;
 
-    else if (walker->neighbor->status == NOT_SYM)
-      neigh->neigh_type = NOT_NEIGH;
+      else if (walker->neighbor->status == SYM)
+        neigh->neigh_type = SYM_NEIGH;
 
-    else {
-      OLSR_PRINTF(0, "Error: neigh_type undefined");
-      neigh->neigh_type = NOT_NEIGH;
-    }
+      else if (walker->neighbor->status == NOT_SYM)
+        neigh->neigh_type = NOT_NEIGH;
 
-    // set the entry's neighbour interface address
+      else {
+        OLSR_PRINTF(0, "Error: neigh_type undefined");
+        neigh->neigh_type = NOT_NEIGH;
+      }
 
-    neigh->addr = walker->neighbor_iface_addr;
+      // set the entry's neighbour interface address
 
-    // queue the neighbour entry
-    neigh->next = lq_hello->neigh;
-    lq_hello->neigh = neigh;
+      neigh->addr = walker->neighbor_iface_addr;
 
+      if (neigh_is_new) {
+        // queue the neighbour entry
+        neigh->next = lq_hello->neigh;
+        lq_hello->neigh = neigh;
+
+      }
+    }
   }
   OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
 }