Lots of work, no result
[olsrd.git] / src / process_package.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, 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 #include "process_package.h"
43 #include "link_set.h"
44 #include "hna_set.h"
45 #include "neighbor_table.h"
46 #include "mid_set.h"
47 #include "olsr.h"
48 #include "parser.h"
49 #include "olsr_logging.h"
50
51 static void olsr_input_hello(struct olsr_message *msg, const uint8_t *payload, const uint8_t *end,
52     struct interface *, union olsr_ip_addr *, enum duplicate_status);
53
54 static void process_message_neighbors(struct nbr_entry *, const struct lq_hello_message *);
55
56 static bool lookup_mpr_status(const struct lq_hello_message *, const struct interface *);
57
58 static void hello_tap(struct lq_hello_message *, struct interface *, const union olsr_ip_addr *);
59
60
61 /**
62  * Processes an list of neighbors from an incoming HELLO message.
63  * @param neighbor the neighbor who sent the message.
64  * @param message the HELLO message
65  * @return nada
66  */
67 static void
68 process_message_neighbors(struct nbr_entry *neighbor, const struct lq_hello_message *message)
69 {
70   struct lq_hello_neighbor *message_neighbors;
71   olsr_linkcost first_hop_pathcost;
72   struct link_entry *lnk;
73   union olsr_ip_addr *neigh_addr;
74   struct nbr_con *connector;
75
76   /*
77    * Walk our 2-hop neighbors.
78    */
79   for (message_neighbors = message->neigh; message_neighbors; message_neighbors = message_neighbors->next) {
80
81     /*
82      * Check all interfaces such that we don't add ourselves to the 2 hop list.
83      * IMPORTANT!
84      */
85     if (if_ifwithaddr(&message_neighbors->addr) != NULL) {
86       continue;
87     }
88
89     /* Get the main address */
90     neigh_addr = olsr_lookup_main_addr_by_alias(&message_neighbors->addr);
91     if (neigh_addr != NULL) {
92       message_neighbors->addr = *neigh_addr;
93     }
94
95     /*
96      * We are only interested in symmetrical or MPR neighbors.
97      */
98     if (message_neighbors->neigh_type != SYM_NEIGH && message_neighbors->neigh_type != MPR_NEIGH) {
99       continue;
100     }
101
102     olsr_link_nbr_nbr2(neighbor, &message_neighbors->addr, message->comm->vtime);
103   }
104
105   /* Second pass */
106   lnk = get_best_link_to_neighbor(&neighbor->nbr_addr);
107
108   if (!lnk) {
109     return;
110   }
111   /* calculate first hop path quality */
112   first_hop_pathcost = lnk->linkcost;
113   /*
114    *  Second pass : calculate the best 2-hop
115    * path costs to all the 2-hop neighbors indicated in the
116    * HELLO message. Since the same 2-hop neighbor may be listed
117    * more than once in the same HELLO message (each at a possibly
118    * different quality) we want to select only the best one, not just
119    * the last one listed in the HELLO message.
120    */
121   for (message_neighbors = message->neigh; message_neighbors != NULL; message_neighbors = message_neighbors->next) {
122     if (if_ifwithaddr(&message_neighbors->addr) != NULL) {
123       continue;
124     }
125     if (message_neighbors->neigh_type == SYM_NEIGH || message_neighbors->neigh_type == MPR_NEIGH) {
126       olsr_linkcost new_second_hop_linkcost;
127       olsr_linkcost new_path_linkcost;
128       connector = olsr_lookup_nbr_con_entry(neighbor, &message_neighbors->addr);
129
130       if (!connector) {
131         continue;
132       }
133
134       new_second_hop_linkcost = message_neighbors->cost;
135
136       // the total cost for the route
137       // "us --- 1-hop --- 2-hop"
138       new_path_linkcost = first_hop_pathcost + new_second_hop_linkcost;
139
140       // Only copy the link quality if it is better than what we have
141       // for this 2-hop neighbor
142       if (new_path_linkcost < connector->path_linkcost) {
143         connector->second_hop_linkcost = new_second_hop_linkcost;
144         connector->path_linkcost = new_path_linkcost;
145
146         if (olsr_is_relevant_costchange(new_path_linkcost, connector->saved_path_linkcost)) {
147           connector->saved_path_linkcost = new_path_linkcost;
148
149           if (olsr_cnf->lq_dlimit > 0) {
150             changes_neighborhood = true;
151             changes_topology = true;
152           }
153         }
154       }
155     }
156   }
157 }
158
159
160 /**
161  * Check if a hello message states this node as a MPR.
162  *
163  * @param message the message to check
164  * @param n_link the buffer to put the link status in
165  *
166  * @return 1 if we are selected as MPR 0 if not
167  */
168 static bool
169 lookup_mpr_status(const struct lq_hello_message *message, const struct interface *in_if)
170 {
171   struct lq_hello_neighbor *neighbors;
172
173   for (neighbors = message->neigh; neighbors; neighbors = neighbors->next) {
174     if ( neighbors->link_type != UNSPEC_LINK
175         && (olsr_cnf->ip_version == AF_INET
176             ? ip4cmp(&neighbors->addr.v4, &in_if->ip_addr.v4) == 0
177             : ip6cmp(&neighbors->addr.v6, &in_if->int6_addr.sin6_addr) == 0)) {
178       return neighbors->link_type == SYM_LINK && neighbors->neigh_type == MPR_NEIGH ? true : false;
179     }
180   }
181   /* Not found */
182   return false;
183 }
184
185 /**
186  * Initializing the parser functions we are using
187  * For downwards compatibility reasons we also understand the non-LQ messages.
188  */
189 void
190 olsr_init_package_process(void)
191 {
192   olsr_parser_add_function(&olsr_input_hello, olsr_get_Hello_MessageId());
193   olsr_parser_add_function(&olsr_input_tc, olsr_get_TC_MessageId());
194   olsr_parser_add_function(&olsr_input_mid, MID_MESSAGE);
195   olsr_parser_add_function(&olsr_input_hna, HNA_MESSAGE);
196 }
197
198 void
199 olsr_deinit_package_process(void)
200 {
201   olsr_parser_remove_function(&olsr_input_hello);
202   olsr_parser_remove_function(&olsr_input_tc);
203   olsr_parser_remove_function(&olsr_input_mid);
204   olsr_parser_remove_function(&olsr_input_hna);
205 }
206
207 static bool
208 deserialize_hello(struct lq_hello_message *hello, struct olsr_message *msg, const uint8_t *payload, const uint8_t *end)
209 {
210   const uint8_t *curr = payload;
211   hello->comm = msg;
212
213   /* parse HELLO specific header */
214   pkt_ignore_u16(&curr);
215   pkt_get_reltime(&curr, &hello->htime);
216   pkt_get_u8(&curr, &hello->will);
217
218   hello->neigh = NULL;
219   while (curr < end) {
220     const uint8_t *ptr, *limit2;
221     uint8_t link_code;
222     uint16_t size;
223
224     ptr = curr;
225     pkt_get_u8(&curr, &link_code);
226     pkt_ignore_u8(&curr);
227     pkt_get_u16(&curr, &size);
228
229     limit2 = ptr + size;
230     while (curr + olsr_cnf->ipsize + olsr_sizeof_HelloLQ() <= limit2) {
231       struct lq_hello_neighbor *neigh = olsr_malloc_lq_hello_neighbor();
232       pkt_get_ipaddress(&curr, &neigh->addr);
233
234       olsr_deserialize_hello_lq_pair(&curr, neigh);
235       if (is_lost_interface_ip(&neigh->addr)) {
236         /* this is a lost interface IP of this node... ignore it */
237         olsr_free_lq_hello_neighbor(neigh);
238         continue;
239       }
240
241       neigh->link_type = EXTRACT_LINK(link_code);
242       neigh->neigh_type = EXTRACT_STATUS(link_code);
243
244       neigh->next = hello->neigh;
245       hello->neigh = neigh;
246     }
247   }
248   return false;
249 }
250
251
252 static void olsr_update_mprs_set(struct lq_hello_message *message, struct link_entry *link) {
253   bool new_mprs_status;
254
255   new_mprs_status = lookup_mpr_status(message, link->inter);
256
257   if (new_mprs_status && !link->is_mprs) {
258     link->neighbor->mprs_count++;
259   }
260   if (!new_mprs_status && link->is_mprs) {
261     link->neighbor->mprs_count--;
262   }
263
264   link->is_mprs = new_mprs_status;
265 }
266
267 static void
268 hello_tap(struct lq_hello_message *message, struct interface *in_if, const union olsr_ip_addr *from_addr)
269 {
270   /*
271    * Update link status
272    */
273   struct link_entry *lnk = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
274   struct lq_hello_neighbor *walker;
275   /* just in case our neighbor has changed its HELLO interval */
276   olsr_update_packet_loss_hello_int(lnk, message->htime);
277
278   /* find the input interface in the list of neighbor interfaces */
279   for (walker = message->neigh; walker != NULL; walker = walker->next) {
280     if (walker->link_type != UNSPEC_LINK && olsr_ipcmp(&walker->addr, &in_if->ip_addr) == 0) {
281       break;
282     }
283   }
284
285   olsr_update_mprs_set(message, lnk);
286
287   /*
288    * memorize our neighbour's idea of the link quality, so that we
289    * know the link quality in both directions
290    *
291    * walker is NULL if there the current interface was not included in
292    * the message (or was included as an UNSPEC_LINK)
293    */
294   olsr_memorize_foreign_hello_lq(lnk, walker);
295
296   /* update packet loss for link quality calculation */
297   olsr_update_packet_loss(lnk);
298
299   /* Check willingness */
300   if (lnk->neighbor->willingness != message->will) {
301 #if !defined REMOVE_LOG_DEBUG
302     struct ipaddr_str buf;
303 #endif
304     OLSR_DEBUG(LOG_LINKS, "Willingness for %s changed from %d to %d - UPDATING\n",
305                olsr_ip_to_string(&buf, &lnk->neighbor->nbr_addr), lnk->neighbor->willingness, message->will);
306     /*
307      *If willingness changed - recalculate
308      */
309     lnk->neighbor->willingness = message->will;
310     changes_neighborhood = true;
311     changes_topology = true;
312   }
313
314   /* Don't register neighbors of neighbors that announces WILL_NEVER */
315   if (lnk->neighbor->willingness != WILL_NEVER) {
316     process_message_neighbors(lnk->neighbor, message);
317   }
318
319   /* Process changes immedeatly in case of MPR updates */
320   olsr_process_changes();
321
322   destroy_lq_hello(message);
323 }
324
325 static void
326 olsr_input_hello(struct olsr_message *msg, const uint8_t *payload, const uint8_t *end,
327     struct interface *inif, union olsr_ip_addr *from,
328     enum duplicate_status status __attribute__ ((unused)))
329 {
330   struct lq_hello_message hello;
331   if (!deserialize_hello(&hello, msg, payload, end)) {
332     hello_tap(&hello, inif, from);
333   }
334 }
335
336 /*
337  * Local Variables:
338  * c-basic-offset: 2
339  * indent-tabs-mode: nil
340  * End:
341  */