3 * The olsr.org Optimized Link-State Routing daemon(olsrd)
4 * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 * Visit http://www.olsr.org for more information.
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.
43 * Link sensing database for the OLSR routing daemon
49 #include "neighbor_table.h"
51 #include "scheduler.h"
55 #include "lq_plugin.h"
56 #include "common/string.h"
57 #include "olsr_logging.h"
59 /* head node for all link sets */
60 struct list_node link_entry_head;
62 static struct olsr_cookie_info *link_dead_timer_cookie = NULL;
63 static struct olsr_cookie_info *link_loss_timer_cookie = NULL;
64 static struct olsr_cookie_info *link_sym_timer_cookie = NULL;
66 bool link_changes; /* is set if changes occur in MPRS set */
69 signal_link_changes(bool val)
75 static int check_link_status(const struct lq_hello_message *message, const struct interface *in_if);
76 static struct link_entry *add_link_entry(const union olsr_ip_addr *,
77 const union olsr_ip_addr *,
78 union olsr_ip_addr *, uint32_t, uint32_t, struct interface *);
79 static bool get_neighbor_status(const union olsr_ip_addr *);
82 olsr_init_link_set(void)
84 OLSR_INFO(LOG_LINKS, "Initialize linkset...\n");
87 list_head_init(&link_entry_head);
89 link_dead_timer_cookie = olsr_alloc_cookie("Link dead", OLSR_COOKIE_TYPE_TIMER);
90 link_loss_timer_cookie = olsr_alloc_cookie("Link loss", OLSR_COOKIE_TYPE_TIMER);
91 link_sym_timer_cookie = olsr_alloc_cookie("Link SYM", OLSR_COOKIE_TYPE_TIMER);
97 * Get the status of a link. The status is based upon different
98 * timeouts in the link entry.
100 * @param remote address of the remote interface
101 * @return the link status of the link
104 lookup_link_status(const struct link_entry *entry)
107 if (entry == NULL || list_is_empty(&link_entry_head)) {
114 if (entry->link_sym_timer) {
118 if (!TIMED_OUT(entry->ASYM_time)) {
127 * Find the "best" link status to a neighbor
129 * @param address the address to check for
130 * @return true if a symmetric link exists false if not
133 get_neighbor_status(const union olsr_ip_addr *address)
135 const union olsr_ip_addr *main_addr;
136 struct interface *ifs;
139 /* Find main address */
140 if (!(main_addr = olsr_lookup_main_addr_by_alias(address)))
144 * Locate the hookup point.
146 tc = olsr_locate_tc_entry(main_addr);
148 /* Loop trough local interfaces to check all possebilities */
149 OLSR_FOR_ALL_INTERFACES(ifs) {
151 struct mid_entry *aliases;
152 struct link_entry *lnk = lookup_link_entry(main_addr, NULL, ifs);
155 if (lookup_link_status(lnk) == SYM_LINK)
159 /* Walk the aliases */
160 OLSR_FOR_ALL_TC_MID_ENTRIES(tc, aliases) {
162 lnk = lookup_link_entry(&aliases->mid_alias_addr, NULL, ifs);
163 if (lnk && (lookup_link_status(lnk) == SYM_LINK)) {
167 OLSR_FOR_ALL_TC_MID_ENTRIES_END(tc, aliases);
169 OLSR_FOR_ALL_INTERFACES_END(ifs);
175 * Find best link to a neighbor
178 get_best_link_to_neighbor(const union olsr_ip_addr *remote)
180 const union olsr_ip_addr *main_addr;
181 struct link_entry *walker, *good_link, *backup_link;
182 olsr_linkcost curr_lcost = LINK_COST_BROKEN;
183 olsr_linkcost tmp_lc;
185 /* main address lookup */
186 main_addr = olsr_lookup_main_addr_by_alias(remote);
188 /* "remote" *already is* the main address */
193 /* we haven't selected any links, yet */
197 /* loop through all links that we have */
198 OLSR_FOR_ALL_LINK_ENTRIES(walker) {
200 /* if this is not a link to the neighour in question, skip */
201 if (olsr_ipcmp(&walker->neighbor->nbr_addr, main_addr) != 0)
204 /* get the link cost */
205 tmp_lc = walker->linkcost;
208 * is this link better than anything we had before ?
209 * use the requested remote interface address as a tie-breaker.
211 if ((tmp_lc < curr_lcost) || ((tmp_lc == curr_lcost) && olsr_ipcmp(&walker->local_iface_addr, remote) == 0)) {
213 /* memorize the link quality */
216 /* prefer symmetric links over asymmetric links */
217 if (lookup_link_status(walker) == SYM_LINK) {
220 backup_link = walker;
224 OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
227 * if we haven't found any symmetric links, try to return an asymmetric link.
229 return good_link ? good_link : backup_link;
233 set_loss_link_multiplier(struct link_entry *entry)
235 struct interface *inter;
236 struct olsr_if_config *cfg_inter;
237 struct olsr_lq_mult *mult;
240 /* find the interface for the link */
241 inter = if_ifwithaddr(&entry->local_iface_addr);
243 /* find the interface configuration for the interface */
244 for (cfg_inter = olsr_cnf->if_configs; cfg_inter; cfg_inter = cfg_inter->next) {
245 if (cfg_inter->interf == inter) {
250 /* loop through the multiplier entries */
251 for (mult = cfg_inter->cnf->lq_mult; mult != NULL; mult = mult->next) {
253 * use the default multiplier only if there isn't any entry that
254 * has a matching IP address.
256 if ((val == 0 && olsr_ipcmp(&mult->addr, &all_zero) == 0) || olsr_ipcmp(&mult->addr, &entry->neighbor_iface_addr) == 0) {
261 /* if we have not found an entry, then use the default multiplier */
263 val = LINK_LOSS_MULTIPLIER;
266 /* store the multiplier */
267 entry->loss_link_multiplier = val;
271 * Delete, unlink and free a link entry.
274 olsr_delete_link_entry(struct link_entry *link)
278 * Delete the corresponding tc-edge for that link.
280 if (link->link_tc_edge) {
281 olsr_delete_tc_edge_entry(link->link_tc_edge);
282 link->link_tc_edge = NULL;
284 changes_topology = true;
288 * Delete the rt_path for the link-end.
290 olsr_delete_routing_table(&link->neighbor_iface_addr, 8 * olsr_cnf->ipsize,
291 &link->neighbor->nbr_addr, OLSR_RT_ORIGIN_LINK);
293 /* Delete neighbor entry */
294 if (link->neighbor->linkcount == 1) {
295 olsr_delete_nbr_entry(link->neighbor);
297 link->neighbor->linkcount--;
300 link->neighbor->mprs_count --;
304 /* Kill running timers */
305 olsr_stop_timer(link->link_timer);
306 link->link_timer = NULL;
307 olsr_stop_timer(link->link_sym_timer);
308 link->link_sym_timer = NULL;
309 olsr_stop_timer(link->link_loss_timer);
310 link->link_loss_timer = NULL;
312 list_remove(&link->link_list);
314 /* Unlink Interfaces */
315 unlock_interface(link->inter);
319 olsr_free_link_entry(link);
321 changes_neighborhood = true;
325 * Delete all link entries matching a given interface id
328 olsr_delete_link_entry_by_if(const struct interface *ifp)
330 struct link_entry *link;
331 #if !defined REMOVE_LOG_DEBUG
332 struct ipaddr_str buf;
335 OLSR_FOR_ALL_LINK_ENTRIES(link) {
336 if (ifp == link->inter) {
337 OLSR_DEBUG(LOG_LINKS, "Removing link %s of interface %s\n",
338 olsr_ip_to_string(&buf, &link->neighbor_iface_addr), ifp->int_name);
339 olsr_delete_link_entry(link);
342 OLSR_FOR_ALL_LINK_ENTRIES_END(link);
346 * Callback for the link loss timer.
349 olsr_expire_link_loss_timer(void *context)
351 struct link_entry *link;
353 link = (struct link_entry *)context;
355 /* count the lost packet */
356 olsr_update_packet_loss_worker(link, true);
358 /* next timeout in 1.0 x htime */
359 olsr_change_timer(link->link_loss_timer, link->loss_helloint, OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC);
363 * Callback for the link SYM timer.
366 olsr_expire_link_sym_timer(void *context)
368 struct link_entry *link;
370 link = (struct link_entry *)context;
371 link->link_sym_timer = NULL; /* be pedandic */
373 if (link->status != SYM_LINK) {
377 link->status = lookup_link_status(link);
378 olsr_update_nbr_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
379 changes_neighborhood = true;
383 * Callback for the link_hello timer.
386 olsr_expire_link_hello_timer(void *context)
388 struct link_entry *link;
390 link = (struct link_entry *)context;
392 /* update neighbor status */
393 olsr_update_nbr_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
397 * Callback for the link timer.
400 olsr_expire_link_entry(void *context)
402 struct link_entry *link;
404 link = (struct link_entry *)context;
405 link->link_timer = NULL; /* be pedandic */
407 olsr_delete_link_entry(link);
411 * Set the link expiration timer.
414 olsr_set_link_timer(struct link_entry *link, unsigned int rel_timer)
416 olsr_set_timer(&link->link_timer, rel_timer, OLSR_LINK_JITTER,
417 OLSR_TIMER_ONESHOT, &olsr_expire_link_entry, link, link_dead_timer_cookie);
421 * Nothing mysterious here.
422 * Adding a new link entry to the link set.
424 * @param local the local IP address
425 * @param remote the remote IP address
426 * @param remote_main the remote nodes main address
427 * @param vtime the validity time of the entry
428 * @param htime the HELLO interval of the remote node
429 * @param local_if the local interface
430 * @return the new (or already existing) link_entry
432 static struct link_entry *
433 add_link_entry(const union olsr_ip_addr *local,
434 const union olsr_ip_addr *remote,
435 union olsr_ip_addr *remote_main, uint32_t vtime, uint32_t htime, struct interface *local_if)
437 struct link_entry *link;
438 struct nbr_entry *neighbor;
439 #if !defined REMOVE_LOG_DEBUG
440 struct ipaddr_str localbuf, rembuf;
443 link = lookup_link_entry(remote, remote_main, local_if);
446 * Link exists. Update tc_edge LQ and exit.
448 olsr_copylq_link_entry_2_tc_edge_entry(link->link_tc_edge, link);
449 changes_neighborhood = olsr_calc_tc_edge_entry_etx(link->link_tc_edge);
454 * if there exists no link tuple with
455 * L_neighbor_iface_addr == Source Address
458 OLSR_DEBUG(LOG_LINKS, "Adding %s=>%s to link set\n", olsr_ip_to_string(&localbuf, local), olsr_ip_to_string(&rembuf, remote));
460 /* a new tuple is created with... */
461 link = olsr_malloc_link_entry();
463 /* copy if_name, if it is defined */
464 if (local_if->int_name) {
465 size_t name_size = strlen(local_if->int_name) + 1;
466 link->if_name = olsr_malloc(name_size, "target of if_name in new link entry");
467 strscpy(link->if_name, local_if->int_name, name_size);
469 link->if_name = NULL;
471 /* shortcut to interface. */
472 link->inter = local_if;
473 lock_interface(local_if);
476 * L_local_iface_addr = Address of the interface
477 * which received the HELLO message
479 link->local_iface_addr = *local;
481 /* L_neighbor_iface_addr = Source Address */
482 link->neighbor_iface_addr = *remote;
484 /* L_time = current time + validity time */
485 olsr_set_link_timer(link, vtime);
487 link->status = ASYM_LINK;
489 link->loss_helloint = htime;
491 olsr_set_timer(&link->link_loss_timer, htime + htime / 2,
492 OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC, &olsr_expire_link_loss_timer, link, link_loss_timer_cookie);
494 set_loss_link_multiplier(link);
496 link->linkcost = LINK_COST_BROKEN;
498 link->is_mprs = false;
501 list_add_before(&link_entry_head, &link->link_list);
505 * Create the neighbor entry
508 /* Neighbor MUST exist! */
509 neighbor = olsr_lookup_nbr_entry(remote_main, true);
511 OLSR_DEBUG(LOG_LINKS, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(&rembuf, remote_main));
512 neighbor = olsr_add_nbr_entry(remote_main);
515 neighbor->linkcount++;
516 link->neighbor = neighbor;
519 * Now create a tc-edge for that link.
521 olsr_change_myself_tc();
523 link->link_tc_edge = olsr_lookup_tc_edge(tc_myself, remote_main);
524 if (link->link_tc_edge == NULL) {
525 link->link_tc_edge = olsr_add_tc_edge_entry(tc_myself, remote_main, 0);
529 * Add the rt_path for the link-end. This is an optimization
530 * that lets us install > 1 hop routes prior to receiving
531 * the MID entry for the 1 hop neighbor.
533 olsr_insert_routing_table(remote, 8 * olsr_cnf->ipsize, remote_main, OLSR_RT_ORIGIN_LINK);
535 changes_neighborhood = true;
541 * Lookup the status of a link.
543 * @param int_addr address of the remote interface
544 * @return 1 of the link is symmertic 0 if not
547 check_neighbor_link(const union olsr_ip_addr *int_addr)
549 struct link_entry *link;
551 OLSR_FOR_ALL_LINK_ENTRIES(link) {
552 if (olsr_ipcmp(int_addr, &link->neighbor_iface_addr) == 0) {
553 return lookup_link_status(link);
556 OLSR_FOR_ALL_LINK_ENTRIES_END(link);
562 * Lookup a link entry
564 * @param remote the remote interface address
565 * @param remote_main the remote nodes main address
566 * @param local the local interface address
567 * @return the link entry if found, NULL if not
570 lookup_link_entry(const union olsr_ip_addr *remote, const union olsr_ip_addr *remote_main, const struct interface *local)
572 struct link_entry *link;
574 OLSR_FOR_ALL_LINK_ENTRIES(link) {
575 if (olsr_ipcmp(remote, &link->neighbor_iface_addr) == 0 && (link->if_name ? !strcmp(link->if_name, local->int_name)
576 : olsr_ipcmp(&local->ip_addr, &link->local_iface_addr) == 0)) {
577 /* check the remote-main address only if there is one given */
578 if (NULL != remote_main && olsr_ipcmp(remote_main, &link->neighbor->nbr_addr) != 0) {
579 /* Neighbor has changed it's main_addr, update */
580 #if !defined REMOVE_LOG_DEBUG
581 struct ipaddr_str oldbuf, newbuf;
583 OLSR_DEBUG(LOG_LINKS, "Neighbor changed main_ip, updating %s -> %s\n",
584 olsr_ip_to_string(&oldbuf, &link->neighbor->nbr_addr), olsr_ip_to_string(&newbuf, remote_main));
585 link->neighbor->nbr_addr = *remote_main;
590 OLSR_FOR_ALL_LINK_ENTRIES_END(link);
596 * Update a link entry. This is the "main entrypoint" in
597 * the link-sensing. This function is called from the HELLO
598 * parser function. It makes sure a entry is updated or created.
600 * @param local the local IP address
601 * @param remote the remote IP address
602 * @param message the HELLO message
603 * @param in_if the interface on which this HELLO was received
604 * @return the link_entry struct describing this link entry
607 update_link_entry(const union olsr_ip_addr *local,
608 const union olsr_ip_addr *remote, struct lq_hello_message *message, struct interface *in_if)
610 struct link_entry *entry;
612 /* Add if not registered */
613 entry = add_link_entry(local, remote, &message->comm->originator, message->comm->vtime, message->htime, in_if);
615 /* Update ASYM_time */
616 entry->vtime = message->comm->vtime;
617 entry->ASYM_time = GET_TIMESTAMP(message->comm->vtime);
619 entry->status = check_link_status(message, in_if);
621 switch (entry->status) {
623 olsr_stop_timer(entry->link_sym_timer);
624 entry->link_sym_timer = NULL;
629 /* L_SYM_time = current time + validity time */
630 olsr_set_timer(&entry->link_sym_timer, message->comm->vtime,
631 OLSR_LINK_SYM_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_link_sym_timer, entry, link_sym_timer_cookie);
633 /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
634 olsr_set_link_timer(entry, message->comm->vtime + NEIGHB_HOLD_TIME);
639 /* L_time = max(L_time, L_ASYM_time) */
640 if (entry->link_timer && (entry->link_timer->timer_clock < entry->ASYM_time)) {
641 olsr_set_link_timer(entry, TIME_DUE(entry->ASYM_time));
644 /* Update neighbor */
645 olsr_update_nbr_status(entry->neighbor, get_neighbor_status(remote));
652 * Function that updates all registered pointers to
653 * one neighbor entry with another pointer
654 * Used by MID updates.
656 * @old the pointer to replace
657 * @new the pointer to use instead of "old"
658 * @return the number of entries updated
661 replace_neighbor_link_set(const struct nbr_entry *old, struct nbr_entry *new)
663 struct link_entry *link;
666 if (list_is_empty(&link_entry_head)) {
670 OLSR_FOR_ALL_LINK_ENTRIES(link) {
672 if (link->neighbor == old) {
673 link->neighbor = new;
677 OLSR_FOR_ALL_LINK_ENTRIES_END(link);
684 *Checks the link status to a neighbor by
685 *looking in a received HELLO message.
687 *@param message the HELLO message to check
689 *@return the link status
692 check_link_status(const struct lq_hello_message *message, const struct interface *in_if)
694 int ret = UNSPEC_LINK;
695 struct lq_hello_neighbor *neighbors;
697 neighbors = message->neigh;
701 * Note: If a neigh has 2 cards we can reach, the neigh
702 * will send a Hello with the same IP mentined twice
704 if (olsr_ipcmp(&neighbors->addr, &in_if->ip_addr) == 0
705 && neighbors->link_type != UNSPEC_LINK) {
706 ret = neighbors->link_type;
707 if (SYM_LINK == ret) {
711 neighbors = neighbors->next;
718 olsr_print_link_set(void)
720 #if !defined REMOVE_LOG_INFO
721 /* The whole function makes no sense without it. */
722 struct link_entry *walker;
726 size_t i, j, length, max, totaltxt_len;
727 addrsize = olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
729 /* generate LQ headline */
732 for (i=1; i<olsr_get_linklabel_count(); i++) {
733 txt = olsr_get_linklabel(i);
734 max = olsr_get_linklabel_maxlength(i);
736 length = strlen(txt);
740 totaltxt[totaltxt_len++] = '/';
743 /* reserve space for label */
745 for (j=0; j<max; j++) {
746 totaltxt[totaltxt_len + j] = '-';
751 strncpy(&totaltxt[totaltxt_len + max/2 - length/2], txt, length);
754 totaltxt[totaltxt_len] = 0;
756 OLSR_INFO(LOG_LINKS, "\n--- %s ---------------------------------------------------- LINKS\n\n", olsr_wallclock_string());
757 OLSR_INFO_NH(LOG_LINKS, "%-*s %-6s %s %s\n", addrsize, "IP address", "hyst", totaltxt , olsr_get_linklabel(0));
759 OLSR_FOR_ALL_LINK_ENTRIES(walker) {
760 struct ipaddr_str buf;
761 char lqbuffer[LQTEXT_MAXLENGTH];
763 /* generate LQ headline */
766 for (i=1; i<olsr_get_linklabel_count(); i++) {
767 txt = olsr_get_linkdata_text(walker, i, lqbuffer, sizeof(lqbuffer));
768 max = olsr_get_linklabel_maxlength(i);
770 length = strlen(txt);
774 totaltxt[totaltxt_len++] = '/';
777 /* reserve space for label */
779 for (j=0; j<max; j++) {
780 totaltxt[totaltxt_len + j] = ' ';
785 strncpy(&totaltxt[totaltxt_len + max/2 - length/2], txt, length);
788 totaltxt[totaltxt_len] = 0;
789 OLSR_INFO_NH(LOG_LINKS, "%-*s %s %s\n",
790 addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
791 totaltxt, olsr_get_linkcost_text(walker->linkcost, false, lqbuffer, sizeof(lqbuffer)));
792 } OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
797 * called for every LQ HELLO message.
798 * update the timeout with the htime value from the message
801 olsr_update_packet_loss_hello_int(struct link_entry *entry, uint32_t loss_hello_int)
803 entry->loss_helloint = loss_hello_int;
807 olsr_update_packet_loss(struct link_entry *entry)
809 olsr_update_packet_loss_worker(entry, false);
811 /* timeout for the first lost packet is 1.5 x htime */
812 olsr_set_timer(&entry->link_loss_timer, entry->loss_helloint + entry->loss_helloint / 2,
813 OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC, &olsr_expire_link_loss_timer, entry, link_loss_timer_cookie);
817 generate_hello(void *p) {
818 struct interface *ifp = p;
819 uint8_t msg_buffer[MAXMESSAGESIZE - OLSR_HEADERSIZE] __attribute__ ((aligned));
820 struct olsr_message msg;
821 uint8_t *curr = msg_buffer;
822 uint8_t *length_field, *last;
823 struct link_entry *link;
824 uint8_t writeLinkType, writeNeighType;
825 OLSR_INFO(LOG_PACKET_CREATION, "Building Hello for %s\n-------------------\n", ifp->int_name);
827 msg.type = olsr_get_Hello_MessageId();
828 msg.vtime = ifp->hello_validity;
829 msg.size = 0; /* fill in later */
830 msg.originator = olsr_cnf->router_id;
833 msg.seqno = get_msg_seqno();
835 length_field = olsr_put_msg_hdr(&curr, &msg);
837 pkt_put_u16(&curr, 0);
838 pkt_put_reltime(&curr, ifp->hello_interval);
839 pkt_put_u8(&curr, olsr_cnf->willingness);
841 last = msg_buffer + sizeof(msg_buffer) - olsr_cnf->ipsize;
843 /* first calculate local link status */
844 OLSR_FOR_ALL_LINK_ENTRIES(link) {
845 if (olsr_ipcmp(&link->local_iface_addr, &ifp->ip_addr) != 0) {
846 link->iflocal_link_status = UNSPEC_LINK;
849 link->iflocal_link_status = lookup_link_status(link);
852 if (link->neighbor->is_mpr) {
853 link->iflocal_neigh_status = MPR_NEIGH;
855 else if (link->neighbor->is_sym) {
856 link->iflocal_neigh_status = SYM_NEIGH;
859 link->iflocal_neigh_status = NOT_NEIGH;
861 } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
863 for (writeNeighType = 0; writeNeighType < COUNT_NEIGH_TYPES; writeNeighType++) {
864 for (writeLinkType = 0; writeLinkType < COUNT_LINK_TYPES; writeLinkType++) {
866 uint8_t *linkstart = NULL;
868 OLSR_FOR_ALL_LINK_ENTRIES(link) {
869 if (link->iflocal_link_status != writeLinkType
870 || link->iflocal_neigh_status != writeNeighType) {
875 pkt_put_u8(&curr, CREATE_LINK_CODE(writeNeighType, writeLinkType));
876 pkt_put_u8(&curr, 0);
879 /* put in dummy length */
881 pkt_put_u16(&curr, 0);
884 pkt_put_ipaddress(&curr, &link->neighbor_iface_addr);
885 olsr_serialize_hello_lq_pair(&curr, link);
886 } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
888 /* fix length field of hello block */
889 if (linkstart != NULL) {
890 pkt_put_u16(&linkstart, (uint16_t)(curr + 2 - linkstart));
895 /* fix length field of message */
896 pkt_put_u16(&length_field, curr - msg_buffer);
898 /* send hello immediately */
899 if (net_outbuffer_bytes_left(ifp) < curr - msg_buffer) {
902 net_outbuffer_push(ifp, msg_buffer, curr - msg_buffer);
908 * indent-tabs-mode: nil