Fix os_interface behavior for p2p interfaces with peer addresses.
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Thu, 23 Feb 2017 08:11:33 +0000 (09:11 +0100)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Thu, 23 Feb 2017 08:11:33 +0000 (09:11 +0100)
Fix nhdp_writer behavior for interfaces without MAC address (e.g. PPP tunnel).

src-plugins/nhdp/nhdp/nhdp_writer.c
src-plugins/subsystems/os_interface.h
src-plugins/subsystems/os_linux/os_interface_linux.c

index 31c25ea..0c959fd 100644 (file)
@@ -312,7 +312,7 @@ _cb_addMessageTLVs(struct rfc5444_writer *writer) {
   /* add mac address of local interface */
   os_if = nhdp_interface_get_if_listener(_nhdp_if)->data;
 
-  if (_add_mac_tlv) {
+  if (_add_mac_tlv && netaddr_get_address_family(&os_if->mac) == AF_MAC48) {
     rfc5444_writer_add_messagetlv(writer, NHDP_MSGTLV_MAC, 0,
         netaddr_get_binptr(&os_if->mac), netaddr_get_binlength(&os_if->mac));
   }
index d322f84..39fc131 100644 (file)
@@ -173,6 +173,9 @@ struct os_interface {
   /*! tree of all addresses/prefixes of this interface */
   struct avl_tree addresses;
 
+  /*! tree of all peer addresses/prefixes of this interface */
+  struct avl_tree peers;
+
   /*! listeners to be informed when an interface changes */
   struct list_entity _listeners;
 
index 0eb89ef..e5d6898 100644 (file)
@@ -614,6 +614,10 @@ _remove_interface(struct os_interface *data) {
     avl_remove(&data->addresses, &ip->_node);
     oonf_class_free(&_interface_ip_class, ip);
   }
+  avl_for_each_element_safe(&data->peers, ip, _node, ip_iter) {
+    avl_remove(&data->peers, &ip->_node);
+    oonf_class_free(&_interface_ip_class, ip);
+  }
 
   /* stop change timer */
   oonf_timer_stop(&data->_change_timer);
@@ -1101,15 +1105,19 @@ _update_address_shortcuts(struct os_interface *os_if) {
  * Add an IP address/prefix to a network interface
  * @param os_if network interface
  * @param prefixed_addr full IP address with prefix length
+ * @param address true if this is a peer address, false otherwise
  */
 static void
-_add_address(struct os_interface *os_if, struct netaddr *prefixed_addr) {
+_add_address(struct os_interface *os_if, struct netaddr *prefixed_addr, bool peer) {
   struct os_interface_ip *ip;
+  struct avl_tree *tree;
 #if defined(OONF_LOG_INFO)
   struct netaddr_str nbuf;
 #endif
 
-  ip = avl_find_element(&os_if->addresses, prefixed_addr, ip, _node);
+  tree = peer ? &os_if->peers : &os_if->addresses;
+
+  ip = avl_find_element(tree, prefixed_addr, ip, _node);
   if (!ip) {
     ip = oonf_class_malloc(&_interface_ip_class);
     if (!ip) {
@@ -1119,14 +1127,15 @@ _add_address(struct os_interface *os_if, struct netaddr *prefixed_addr) {
     /* establish key and add to tree */
     memcpy(&ip->prefixed_addr, prefixed_addr, sizeof(*prefixed_addr));
     ip->_node.key = &ip->prefixed_addr;
-    avl_insert(&os_if->addresses, &ip->_node);
+    avl_insert(tree, &ip->_node);
 
     /* add back pointer */
     ip->interf = os_if;
   }
 
-  OONF_INFO(LOG_OS_INTERFACE, "Add address to %s: %s",
-      os_if->name, netaddr_to_string(&nbuf, prefixed_addr));
+  OONF_INFO(LOG_OS_INTERFACE, "Add address to %s%s: %s",
+      os_if->name, peer ? " (peer)" : "",
+      netaddr_to_string(&nbuf, prefixed_addr));
 
   /* copy sanitized addresses */
   memcpy(&ip->address, prefixed_addr, sizeof(*prefixed_addr));
@@ -1138,23 +1147,27 @@ _add_address(struct os_interface *os_if, struct netaddr *prefixed_addr) {
  * Remove an IP address/prefix from a network interface
  * @param os_if network interface
  * @param prefixed_addr full IP address with prefix length
+ * @param address true if this is a peer address, false otherwise
  */
 static void
-_remove_address(struct os_interface *os_if, struct netaddr *prefixed_addr) {
+_remove_address(struct os_interface *os_if, struct netaddr *prefixed_addr, bool peer) {
   struct os_interface_ip *ip;
+  struct avl_tree *tree;
 #if defined(OONF_LOG_INFO)
   struct netaddr_str nbuf;
 #endif
 
-  ip = avl_find_element(&os_if->addresses, prefixed_addr, ip, _node);
+  tree = peer ? &os_if->peers : &os_if->addresses;
+  ip = avl_find_element(tree, prefixed_addr, ip, _node);
   if (!ip) {
     return;
   }
 
-  OONF_INFO(LOG_OS_INTERFACE, "Remove address from %s: %s",
-      os_if->name, netaddr_to_string(&nbuf, prefixed_addr));
+  OONF_INFO(LOG_OS_INTERFACE, "Remove address from %s%s: %s",
+      os_if->name, peer ? " (peer)" : "",
+      netaddr_to_string(&nbuf, prefixed_addr));
 
-  avl_remove(&os_if->addresses, &ip->_node);
+  avl_remove(tree, &ip->_node);
   oonf_class_free(&_interface_ip_class, ip);
 }
 
@@ -1169,7 +1182,7 @@ _address_parse_nlmsg(const char *ifname, struct nlmsghdr *msg) {
   struct rtattr *ifa_attr;
   int ifa_len;
   struct os_interface *ifdata;
-  struct netaddr addr;
+  struct netaddr ifa_local, ifa_address;
   bool update;
 
   ifa_msg = NLMSG_DATA(msg);
@@ -1185,18 +1198,26 @@ _address_parse_nlmsg(const char *ifname, struct nlmsghdr *msg) {
       ifname, ifa_msg->ifa_index, ifa_len);
 
   update = false;
+  netaddr_invalidate(&ifa_local);
+  netaddr_invalidate(&ifa_address);
+
   for(; RTA_OK(ifa_attr, ifa_len); ifa_attr = RTA_NEXT(ifa_attr,ifa_len)) {
     switch(ifa_attr->rta_type) {
       case IFA_ADDRESS:
-        netaddr_from_binary_prefix(&addr, RTA_DATA(ifa_attr), RTA_PAYLOAD(ifa_attr), 0,
-            ifa_msg->ifa_prefixlen);
-        if (msg->nlmsg_type == RTM_NEWADDR) {
-          _add_address(ifdata, &addr);
+        netaddr_from_binary_prefix(&ifa_address,
+            RTA_DATA(ifa_attr), RTA_PAYLOAD(ifa_attr), 0,
+                ifa_msg->ifa_prefixlen);
+        if (netaddr_is_unspec(&ifa_local)) {
+          memcpy(&ifa_local, &ifa_address, sizeof(ifa_local));
         }
-        else {
-          _remove_address(ifdata, &addr);
+        break;
+      case IFA_LOCAL:
+        netaddr_from_binary_prefix(&ifa_local,
+            RTA_DATA(ifa_attr), RTA_PAYLOAD(ifa_attr), 0,
+                ifa_msg->ifa_prefixlen);
+        if (netaddr_is_unspec(&ifa_address)) {
+          memcpy(&ifa_address, &ifa_local, sizeof(ifa_address));
         }
-        update = true;
         break;
       default:
         OONF_DEBUG(LOG_OS_INTERFACE, "ifa_attr_type: %u", ifa_attr->rta_type);
@@ -1204,16 +1225,37 @@ _address_parse_nlmsg(const char *ifname, struct nlmsghdr *msg) {
     }
   }
 
-  if (update) {
+  if (!netaddr_is_unspec(&ifa_local)) {
+    if (msg->nlmsg_type == RTM_NEWADDR) {
+      _add_address(ifdata, &ifa_local, false);
+    }
+    else {
+      _remove_address(ifdata, &ifa_local, false);
+    }
+
     _update_address_shortcuts(ifdata);
+    update = true;
+  }
+
+  if (netaddr_cmp(&ifa_local, &ifa_address)) {
+    if (msg->nlmsg_type == RTM_NEWADDR) {
+      _add_address(ifdata, &ifa_address, true);
+    }
+    else {
+      _remove_address(ifdata, &ifa_address, true);
+    }
+
+    update = true;
+  }
+
+  if (update) {
     if (!ifdata->_addr_initialized) {
       ifdata->_addr_initialized = true;
       OONF_INFO(LOG_OS_INTERFACE, "Interface %s address data initialized",
           ifdata->name);
     }
+    _trigger_if_change_including_any(ifdata);
   }
-
-  _trigger_if_change_including_any(ifdata);
 }
 
 /**