Fix build without DEBUG/INFO output
[oonf.git] / src-plugins / nhdp / nhdp / nhdp_writer.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 #include "common/common_types.h"
47 #include "common/avl.h"
48 #include "common/avl_comp.h"
49 #include "core/oonf_logging.h"
50 #include "subsystems/oonf_rfc5444.h"
51
52 #include "nhdp/nhdp.h"
53 #include "nhdp/nhdp_domain.h"
54 #include "nhdp/nhdp_interfaces.h"
55 #include "nhdp/nhdp_internal.h"
56 #include "nhdp/nhdp_writer.h"
57
58 /* constants */
59 enum {
60   IDX_ADDRTLV_LOCAL_IF,
61   IDX_ADDRTLV_LINK_STATUS,
62   IDX_ADDRTLV_OTHER_NEIGHB,
63   IDX_ADDRTLV_MPR,
64 };
65
66 /* prototypes */
67 static int _cb_addMessageHeader(
68     struct rfc5444_writer *, struct rfc5444_writer_message *);
69 static void _cb_addMessageTLVs(struct rfc5444_writer *);
70 static void _cb_addAddresses(struct rfc5444_writer *);
71
72 static void _add_link_address(struct rfc5444_writer *writer,
73     struct rfc5444_writer_content_provider *prv,
74     struct nhdp_interface *interf, struct nhdp_naddr *naddr);
75 static void _add_localif_address(struct rfc5444_writer *writer,
76     struct rfc5444_writer_content_provider *prv,
77     struct nhdp_interface *interf, struct nhdp_interface_addr *addr);
78
79 static void _write_metric_tlv(struct rfc5444_writer *writer,
80     struct rfc5444_writer_address *addr,
81     struct nhdp_neighbor *neigh, struct nhdp_link *lnk,
82     struct nhdp_domain *domain);
83
84 /* definition of NHDP writer */
85 static struct rfc5444_writer_message *_nhdp_message = NULL;
86
87 static struct rfc5444_writer_content_provider _nhdp_msgcontent_provider = {
88   .msg_type = RFC6130_MSGTYPE_HELLO,
89   .addMessageTLVs = _cb_addMessageTLVs,
90   .addAddresses = _cb_addAddresses,
91 };
92
93 static struct rfc5444_writer_tlvtype _nhdp_addrtlvs[] = {
94   [IDX_ADDRTLV_LOCAL_IF] =     { .type = RFC6130_ADDRTLV_LOCAL_IF },
95   [IDX_ADDRTLV_LINK_STATUS] =  { .type = RFC6130_ADDRTLV_LINK_STATUS },
96   [IDX_ADDRTLV_OTHER_NEIGHB] = { .type = RFC6130_ADDRTLV_OTHER_NEIGHB },
97   [IDX_ADDRTLV_MPR] =          { .type = RFC7181_ADDRTLV_MPR },
98 };
99
100 static struct oonf_rfc5444_protocol *_protocol;
101
102 static bool _cleanedup = false;
103 static bool _add_mac_tlv = true;
104 static struct nhdp_interface *_nhdp_if = NULL;
105
106 /**
107  * Initialize nhdp writer
108  * @param p rfc5444 protocol
109  * @return -1 if an error happened, 0 otherwise
110  */
111 int
112 nhdp_writer_init(struct oonf_rfc5444_protocol *p) {
113   _protocol = p;
114
115   _nhdp_message = rfc5444_writer_register_message(
116       &_protocol->writer, RFC6130_MSGTYPE_HELLO, true);
117   if (_nhdp_message == NULL) {
118     OONF_WARN(LOG_NHDP_W, "Could not register NHDP Hello message");
119     return -1;
120   }
121
122   _nhdp_message->addMessageHeader = _cb_addMessageHeader;
123
124   if (rfc5444_writer_register_msgcontentprovider(
125       &_protocol->writer, &_nhdp_msgcontent_provider,
126       _nhdp_addrtlvs, ARRAYSIZE(_nhdp_addrtlvs))) {
127
128     OONF_WARN(LOG_NHDP_W, "Count not register NHDP msg contentprovider");
129     rfc5444_writer_unregister_message(&_protocol->writer, _nhdp_message);
130     return -1;
131   }
132   return 0;
133 }
134
135 /**
136  * Cleanup nhdp writer
137  */
138 void
139 nhdp_writer_cleanup(void) {
140   /* remember we already did shut down the writer */
141   _cleanedup = true;
142
143   /* remove pbb writer */
144   rfc5444_writer_unregister_content_provider(
145       &_protocol->writer, &_nhdp_msgcontent_provider,
146       _nhdp_addrtlvs, ARRAYSIZE(_nhdp_addrtlvs));
147   rfc5444_writer_unregister_message(&_protocol->writer, _nhdp_message);
148 }
149
150 /**
151  * Send a NHDP Hello through the specified interface. This might result
152  * in both an IPv4 and IPv6 message
153  * @param ninterf NHDP interface
154  */
155 void
156 nhdp_writer_send_hello(struct nhdp_interface *ninterf) {
157   enum rfc5444_result result;
158   struct os_interface_listener *interf;
159   struct netaddr_str buf;
160
161   if (_cleanedup) {
162     /* do not send more Hellos during shutdown */
163     return;
164   }
165
166   interf = nhdp_interface_get_if_listener(ninterf);
167   if (interf->data->flags.loopback) {
168     /* no NHDP on loopback interface */
169     return;
170   }
171
172   OONF_DEBUG(LOG_NHDP_W, "Sending Hello to interface %s",
173       nhdp_interface_get_name(ninterf));
174
175   /* store NHDP interface */
176   _nhdp_if = ninterf;
177
178   /* send IPv4 (if socket is active) */
179   result = oonf_rfc5444_send_if(ninterf->rfc5444_if.interface->multicast4, RFC6130_MSGTYPE_HELLO);
180   if (result < 0) {
181     OONF_WARN(LOG_NHDP_W, "Could not send NHDP message to %s: %s (%d)",
182         netaddr_to_string(&buf, &ninterf->rfc5444_if.interface->multicast4->dst), rfc5444_strerror(result), result);
183   }
184
185   /* send IPV6 (if socket is active) */
186   result = oonf_rfc5444_send_if(ninterf->rfc5444_if.interface->multicast6, RFC6130_MSGTYPE_HELLO);
187   if (result < 0) {
188     OONF_WARN(LOG_NHDP_W, "Could not send NHDP message to %s: %s (%d)",
189         netaddr_to_string(&buf, &ninterf->rfc5444_if.interface->multicast6->dst), rfc5444_strerror(result), result);
190   }
191 }
192
193
194 /**
195  * activates or deactivates the MAC_TLV in the NHDP Hello messages
196  * @param active true if MAC_TLV should be present
197  */
198 void
199 nhdp_writer_set_mac_TLV_state(bool active) {
200   _add_mac_tlv = active;
201 }
202
203 /**
204  * Callback to initialize the message header for a HELLO message
205  * @param writer
206  * @param message
207  */
208 static int
209 _cb_addMessageHeader(struct rfc5444_writer *writer,
210     struct rfc5444_writer_message *message) {
211   struct oonf_rfc5444_target *target;
212   const struct netaddr *originator;
213   struct netaddr_str buf;
214
215   if (!message->target_specific) {
216     OONF_WARN(LOG_NHDP_W, "non interface-specific NHDP message!");
217     return RFC5444_DROP_MESSAGE;
218   }
219
220   target = oonf_rfc5444_get_target_from_writer(writer);
221   if (target != target->interface->multicast6
222       && target != target->interface->multicast4) {
223     OONF_WARN(LOG_NHDP_W, "Cannot generate unicast nhdp message to %s",
224         netaddr_to_string(&buf, &target->dst));
225     return RFC5444_DROP_MESSAGE;
226   }
227
228   /* get originator */
229   if (writer->msg_addr_len == 4) {
230     originator = nhdp_get_originator(AF_INET);
231   }
232   else {
233     originator = nhdp_get_originator(AF_INET6);
234   }
235
236   OONF_DEBUG(LOG_NHDP_W, "Generate Hello on interface %s with destination %s",
237       target->interface->name, netaddr_to_string(&buf, &target->dst));
238
239   if (originator != NULL && netaddr_get_address_family(originator) != AF_UNSPEC) {
240     OONF_DEBUG(LOG_NHDP_W, "Add originator %s", netaddr_to_string(&buf, originator));
241
242     rfc5444_writer_set_msg_header(writer, message, true , false, false, false);
243     rfc5444_writer_set_msg_originator(writer, message, netaddr_get_binptr(originator));
244   }
245   else {
246     rfc5444_writer_set_msg_header(writer, message, false , false, false, false);
247   }
248   return RFC5444_OKAY;
249 }
250
251 /**
252  * Callback to add the message TLVs to a HELLO message
253  * @param writer
254  * @param prv
255  */
256 static void
257 _cb_addMessageTLVs(struct rfc5444_writer *writer) {
258   uint8_t vtime_encoded, itime_encoded;
259   struct oonf_rfc5444_target *target;
260   const struct netaddr *v4_originator;
261   struct os_interface *os_if;
262   uint8_t willingness[NHDP_MAXIMUM_DOMAINS];
263   size_t willingness_size;
264   uint8_t mprtypes[NHDP_MAXIMUM_DOMAINS];
265   uint8_t mprtypes_size;
266
267   target = oonf_rfc5444_get_target_from_writer(writer);
268
269   if (target != target->interface->multicast4
270       && target != target->interface->multicast6) {
271     struct netaddr_str buf;
272     OONF_WARN(LOG_NHDP_W, "target for NHDP is no interface multicast: %s",
273         netaddr_to_string(&buf, &target->dst));
274     assert(0);
275   }
276
277   itime_encoded = rfc5497_timetlv_encode(_nhdp_if->refresh_interval);
278   vtime_encoded = rfc5497_timetlv_encode(_nhdp_if->h_hold_time);
279
280   rfc5444_writer_add_messagetlv(writer, RFC5497_MSGTLV_INTERVAL_TIME, 0,
281       &itime_encoded, sizeof(itime_encoded));
282   rfc5444_writer_add_messagetlv(writer, RFC5497_MSGTLV_VALIDITY_TIME, 0,
283       &vtime_encoded, sizeof(vtime_encoded));
284
285   /* generate MPRtypes */
286   mprtypes_size = nhdp_domain_encode_mprtypes_tlvvalue(
287       mprtypes, sizeof(mprtypes));
288   if (mprtypes_size > 1) {
289     rfc5444_writer_add_messagetlv(writer,
290         DRAFT_MT_MSGTLV_MPR_TYPES, DRAFT_MT_MSGTLV_MPR_TYPES_EXT,
291         &mprtypes, mprtypes_size);
292   }
293
294   /* add willingness for all domains */
295   willingness_size = nhdp_domain_encode_willingness_tlvvalue(
296       willingness, sizeof(willingness));
297   rfc5444_writer_add_messagetlv(writer, RFC7181_MSGTLV_MPR_WILLING, 0,
298       &willingness, willingness_size);
299
300   /* get v6 originator (might be unspecified) */
301   v4_originator = nhdp_get_originator(AF_INET);
302
303   /* add V4 originator to V6 message if available and interface is dualstack */
304   if (writer->msg_addr_len == 16 && v4_originator != NULL
305       && netaddr_get_address_family(v4_originator) == AF_INET) {
306     rfc5444_writer_add_messagetlv(writer, NHDP_MSGTLV_IPV4ORIGINATOR, 0,
307         netaddr_get_binptr(v4_originator), netaddr_get_binlength(v4_originator));
308   }
309
310   /* add mac address of local interface */
311   os_if = nhdp_interface_get_if_listener(_nhdp_if)->data;
312
313   if (_add_mac_tlv) {
314     rfc5444_writer_add_messagetlv(writer, NHDP_MSGTLV_MAC, 0,
315         netaddr_get_binptr(&os_if->mac), netaddr_get_binlength(&os_if->mac));
316   }
317 }
318
319 /**
320  * Add a rfc5444 address with localif TLV to the stream
321  * @param writer
322  * @param prv
323  * @param interf
324  * @param addr
325  */
326 static void
327 _add_localif_address(struct rfc5444_writer *writer, struct rfc5444_writer_content_provider *prv,
328     struct nhdp_interface *interf, struct nhdp_interface_addr *addr) {
329   struct rfc5444_writer_address *address;
330   struct netaddr_str buf;
331   uint8_t value;
332   bool this_if;
333
334   /* check if address of local interface */
335   this_if = NULL != avl_find_element(
336       &interf->_if_addresses, &addr->if_addr, addr, _if_node);
337
338   OONF_DEBUG(LOG_NHDP_W, "Add %s (%s) to NHDP hello",
339       netaddr_to_string(&buf, &addr->if_addr), this_if ? "this_if" : "other_if");
340
341   /* generate RFC5444 address */
342   address = rfc5444_writer_add_address(writer, prv->creator, &addr->if_addr, true);
343   if (address == NULL) {
344     OONF_WARN(LOG_NHDP_W, "Could not add address %s to NHDP hello",
345         netaddr_to_string(&buf, &addr->if_addr));
346     return;
347   }
348
349   /* Add LOCALIF TLV */
350   if (this_if) {
351     value = RFC6130_LOCALIF_THIS_IF;
352   }
353   else {
354     value = RFC6130_LOCALIF_OTHER_IF;
355   }
356   rfc5444_writer_add_addrtlv(writer, address, &_nhdp_addrtlvs[IDX_ADDRTLV_LOCAL_IF],
357       &value, sizeof(value), true);
358 }
359
360 /**
361  * Add a rfc5444 address with link_status or other_neigh TLV to the stream
362  * @param writer
363  * @param prv
364  * @param interf
365  * @param naddr
366  */
367 static void
368 _add_link_address(struct rfc5444_writer *writer, struct rfc5444_writer_content_provider *prv,
369     struct nhdp_interface *interf, struct nhdp_naddr *naddr) {
370   struct rfc5444_writer_address *address;
371   struct nhdp_domain *domain;
372   struct nhdp_laddr *laddr;
373   struct netaddr_str buf;
374   uint8_t linkstatus, otherneigh_sym;
375   uint8_t mprvalue[NHDP_MAXIMUM_DOMAINS];
376   size_t len;
377
378   /* initialize flags for default (lost address) address */
379   linkstatus = 255;
380   otherneigh_sym = 0;
381
382   laddr = nhdp_interface_get_link_addr(interf, &naddr->neigh_addr);
383   if (!nhdp_db_neighbor_addr_is_lost(naddr)) {
384     if (laddr != NULL && laddr->link->local_if == interf
385         && laddr->link->status != NHDP_LINK_PENDING) {
386       linkstatus = laddr->link->status;
387     }
388
389     if (naddr->neigh->symmetric > 0
390         && linkstatus != NHDP_LINK_SYMMETRIC) {
391       otherneigh_sym = NHDP_LINK_SYMMETRIC;
392     }
393   }
394
395   /* generate RFC5444 address */
396   address = rfc5444_writer_add_address(writer, prv->creator, &naddr->neigh_addr, false);
397   if (address == NULL) {
398     OONF_WARN(LOG_NHDP_W, "Could not add address %s to NHDP hello",
399         netaddr_to_string(&buf, &naddr->neigh_addr));
400     return;
401   }
402
403   if (linkstatus != 255) {
404     rfc5444_writer_add_addrtlv(writer, address,
405           &_nhdp_addrtlvs[IDX_ADDRTLV_LINK_STATUS],
406           &linkstatus, sizeof(linkstatus), false);
407
408     OONF_DEBUG(LOG_NHDP_W, "Add %s (linkstatus=%d) to NHDP hello",
409         netaddr_to_string(&buf, &naddr->neigh_addr), laddr->link->status);
410   }
411
412   rfc5444_writer_add_addrtlv(writer, address,
413       &_nhdp_addrtlvs[IDX_ADDRTLV_OTHER_NEIGHB],
414       &otherneigh_sym, sizeof(otherneigh_sym), false);
415
416   OONF_DEBUG(LOG_NHDP_W, "Add %s (otherneigh=%d) to NHDP hello",
417       netaddr_to_string(&buf, &naddr->neigh_addr), otherneigh_sym);
418
419   /* add MPR tlvs */
420   if (laddr != NULL) {
421     len = nhdp_domain_encode_mpr_tlvvalue(mprvalue, sizeof(mprvalue), naddr->neigh);
422
423     if (len) {
424       rfc5444_writer_add_addrtlv(writer, address,
425           &_nhdp_addrtlvs[IDX_ADDRTLV_MPR], &mprvalue, len, false);
426     }
427   }
428
429   /* add linkcost TLVs */
430   list_for_each_element(nhdp_domain_get_list(), domain, _node) {
431     struct nhdp_link *lnk = NULL;
432     struct nhdp_neighbor *neigh = NULL;
433
434     if (linkstatus == NHDP_LINK_HEARD
435         || linkstatus == NHDP_LINK_SYMMETRIC) {
436       lnk = laddr->link;
437     }
438     if (naddr->neigh->symmetric > 0
439         && (linkstatus == NHDP_LINK_SYMMETRIC
440             || otherneigh_sym == RFC6130_OTHERNEIGHB_SYMMETRIC)) {
441       neigh = naddr->neigh;
442     }
443
444     _write_metric_tlv(writer, address, neigh, lnk, domain);
445   }
446 }
447
448 /**
449  * Write up to four metric TLVs to an address
450  * @param writer rfc5444 writer
451  * @param addr rfc5444 address
452  * @param neigh pointer to symmetric neighbor, might be NULL
453  * @param lnk pointer to symmetric link, might be NULL
454  * @param handler pointer to link metric handler
455  */
456 static void
457 _write_metric_tlv(struct rfc5444_writer *writer, struct rfc5444_writer_address *addr,
458     struct nhdp_neighbor *neigh, struct nhdp_link *lnk,
459     struct nhdp_domain *domain) {
460   static const enum rfc7181_linkmetric_flags flags[4] = {
461       RFC7181_LINKMETRIC_INCOMING_LINK,
462       RFC7181_LINKMETRIC_OUTGOING_LINK,
463       RFC7181_LINKMETRIC_INCOMING_NEIGH,
464       RFC7181_LINKMETRIC_OUTGOING_NEIGH,
465   };
466 #ifdef OONF_LOG_DEBUG_INFO
467   static const char *lq_name[4] = {
468     "l_in", "l_out", "n_in", "n_out",
469   };
470 #endif
471   struct nhdp_link_domaindata *linkdata;
472   struct nhdp_neighbor_domaindata *neighdata;
473   struct rfc7181_metric_field metric_encoded[4], tlv_value;
474   int i,j,k;
475   uint32_t metrics[4] = { 0,0,0,0 };
476
477   if (lnk == NULL && neigh == NULL) {
478     /* nothing to do */
479     return;
480   }
481
482   /* get link metrics if available */
483   if (lnk != NULL && (lnk->status == NHDP_LINK_HEARD || lnk->status == NHDP_LINK_SYMMETRIC)) {
484     linkdata = nhdp_domain_get_linkdata(domain, lnk);
485     metrics[0] = linkdata->metric.in;
486     metrics[1] = linkdata->metric.out;
487   }
488
489   /* get neighbor metrics if available */
490   if (neigh != NULL && neigh->symmetric > 0) {
491     neighdata = nhdp_domain_get_neighbordata(domain, neigh);
492     metrics[2] = neighdata->metric.in;
493     metrics[3] = neighdata->metric.out;
494   }
495
496   /* check if metric is infinite */
497   for (i=0; i<4; i++) {
498     if (metrics[i] > RFC7181_METRIC_MAX) {
499       metrics[i] = 0;
500     }
501   }
502
503   /* encode metrics */
504   for (i=0; i<4; i++) {
505     if (metrics[i] > 0) {
506       if (rfc7181_metric_encode(&metric_encoded[i], metrics[i])) {
507         OONF_WARN(LOG_NHDP_W, "Metric encoding for %u failed", metrics[i]);
508         return;
509       }
510     }
511   }
512
513   /* compress four metrics into 1-4 TLVs */
514   k = 0;
515   for (i=0; i<4; i++) {
516     /* find first metric value which still must be sent */
517     if (metrics[i] == 0) {
518       continue;
519     }
520
521     /* create value */
522     tlv_value = metric_encoded[i];
523
524     /* mark first metric value */
525     rfc7181_metric_set_flag(&tlv_value, flags[i]);
526
527     /* mark all metric pair that have the same linkmetric */
528     OONF_DEBUG(LOG_NHDP_W, "Add Metric %s (ext %u): 0x%02x%02x (%u)",
529         lq_name[i], domain->ext, tlv_value.b[0], tlv_value.b[1], metrics[i]);
530
531     for (j=3; j>i; j--) {
532       if (metrics[j] > 0 &&
533           memcmp(&metric_encoded[i], &metric_encoded[j], sizeof(metric_encoded[0])) == 0) {
534         rfc7181_metric_set_flag(&tlv_value, flags[j]);
535         metrics[j] = 0;
536
537         OONF_DEBUG(LOG_NHDP_W, "Same metrics for %s (ext %u)",
538             lq_name[j], domain->ext);
539       }
540     }
541
542     /* add to rfc5444 address */
543     rfc5444_writer_add_addrtlv(writer, addr,
544         &domain->_metric_addrtlvs[k++],
545         &tlv_value, sizeof(tlv_value), true);
546   }
547 }
548 /**
549  * Callback to add the addresses and address TLVs to a HELLO message
550  * @param writer
551  */
552 void
553 _cb_addAddresses(struct rfc5444_writer *writer) {
554   struct oonf_rfc5444_target *target;
555
556   struct nhdp_interface *interf;
557   struct nhdp_interface_addr *addr;
558   struct nhdp_naddr *naddr;
559
560   /* have already be checked for message TLVs, so they cannot be NULL */
561   target = oonf_rfc5444_get_target_from_writer(writer);
562   interf = nhdp_interface_get(target->interface->name);
563
564   /* transmit interface addresses first */
565   avl_for_each_element(nhdp_interface_get_address_tree(), addr, _global_node) {
566     if (addr->removed) {
567       continue;
568     }
569     if (netaddr_get_address_family(&addr->if_addr)
570         == netaddr_get_address_family(&target->dst)) {
571       _add_localif_address(writer, &_nhdp_msgcontent_provider, interf, addr);
572     }
573   }
574
575   /* then transmit neighbor addresses */
576   avl_for_each_element(nhdp_db_get_naddr_tree(), naddr, _global_node) {
577     if (netaddr_get_address_family(&naddr->neigh_addr)
578         == netaddr_get_address_family(&target->dst)) {
579       _add_link_address(writer, &_nhdp_msgcontent_provider, interf, naddr);
580     }
581   }
582 }