2bc0da7a6441899fefa013f2ed7a8157bbb924fc
[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 "mpr_selector_set.h"
47 #include "mid_set.h"
48 #include "olsr.h"
49 #include "parser.h"
50 #include "olsr_logging.h"
51
52 static bool olsr_input_hello(union olsr_message *ser, struct interface *inif, union olsr_ip_addr *from);
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, HELLO_MESSAGE);
193   olsr_parser_add_function(&olsr_input_hello, LQ_HELLO_MESSAGE);
194   olsr_parser_add_function(&olsr_input_tc, TC_MESSAGE);
195   olsr_parser_add_function(&olsr_input_tc, LQ_TC_MESSAGE);
196   olsr_parser_add_function(&olsr_input_mid, MID_MESSAGE);
197   olsr_parser_add_function(&olsr_input_hna, HNA_MESSAGE);
198 }
199
200 void
201 olsr_deinit_package_process(void)
202 {
203   olsr_parser_remove_function(&olsr_input_hello, HELLO_MESSAGE);
204   olsr_parser_remove_function(&olsr_input_hello, LQ_HELLO_MESSAGE);
205   olsr_parser_remove_function(&olsr_input_tc, TC_MESSAGE);
206   olsr_parser_remove_function(&olsr_input_tc, LQ_TC_MESSAGE);
207   olsr_parser_remove_function(&olsr_input_mid, MID_MESSAGE);
208   olsr_parser_remove_function(&olsr_input_hna, HNA_MESSAGE);
209 }
210
211 static int
212 deserialize_hello(struct lq_hello_message *hello, const void *ser)
213 {
214   const unsigned char *limit;
215   uint8_t type;
216   uint16_t size;
217
218   const unsigned char *curr = ser;
219   pkt_get_u8(&curr, &type);
220   if (type != HELLO_MESSAGE && type != LQ_HELLO_MESSAGE) {
221     /* No need to do anything more */
222     return 1;
223   }
224   pkt_get_reltime(&curr, &hello->comm.vtime);
225   pkt_get_u16(&curr, &size);
226   pkt_get_ipaddress(&curr, &hello->comm.orig);
227
228   pkt_get_u8(&curr, &hello->comm.ttl);
229   pkt_get_u8(&curr, &hello->comm.hops);
230   pkt_get_u16(&curr, &hello->comm.seqno);
231   pkt_ignore_u16(&curr);
232
233   pkt_get_reltime(&curr, &hello->htime);
234   pkt_get_u8(&curr, &hello->will);
235
236   hello->neigh = NULL;
237   limit = ((const unsigned char *)ser) + size;
238   while (curr < limit) {
239     const struct lq_hello_info_header *info_head = (const struct lq_hello_info_header *)curr;
240     const unsigned char *limit2 = curr + ntohs(info_head->size);
241
242     curr = (const unsigned char *)(info_head + 1);
243     while (curr < limit2) {
244       struct lq_hello_neighbor *neigh = olsr_malloc_lq_hello_neighbor();
245       pkt_get_ipaddress(&curr, &neigh->addr);
246
247       olsr_deserialize_hello_lq_pair(&curr, neigh);
248       neigh->link_type = EXTRACT_LINK(info_head->link_code);
249       neigh->neigh_type = EXTRACT_STATUS(info_head->link_code);
250
251       neigh->next = hello->neigh;
252       hello->neigh = neigh;
253     }
254   }
255   return 0;
256 }
257
258
259 static void
260 hello_tap(struct lq_hello_message *message, struct interface *in_if, const union olsr_ip_addr *from_addr)
261 {
262   /*
263    * Update link status
264    */
265   struct link_entry *lnk = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
266   struct lq_hello_neighbor *walker;
267   /* just in case our neighbor has changed its HELLO interval */
268   olsr_update_packet_loss_hello_int(lnk, message->htime);
269
270   /* find the input interface in the list of neighbor interfaces */
271   for (walker = message->neigh; walker != NULL; walker = walker->next) {
272     if (walker->link_type != UNSPEC_LINK && olsr_ipcmp(&walker->addr, &in_if->ip_addr) == 0) {
273       break;
274     }
275   }
276
277   /*
278    * memorize our neighbour's idea of the link quality, so that we
279    * know the link quality in both directions
280    *
281    * walker is NULL if there the current interface was not included in
282    * the message (or was included as an UNSPEC_LINK)
283    */
284   olsr_memorize_foreign_hello_lq(lnk, walker);
285
286   /* update packet loss for link quality calculation */
287   olsr_update_packet_loss(lnk);
288
289   /* Check if we are chosen as MPR */
290   if (lookup_mpr_status(message, in_if)) {
291     /* source_addr is always the main addr of a node! */
292     olsr_update_mprs_set(&message->comm.orig, message->comm.vtime);
293   }
294
295   /* Check willingness */
296   if (lnk->neighbor->willingness != message->will) {
297 #if !defined REMOVE_LOG_DEBUG
298     struct ipaddr_str buf;
299 #endif
300     OLSR_DEBUG(LOG_LINKS, "Willingness for %s changed from %d to %d - UPDATING\n",
301                olsr_ip_to_string(&buf, &lnk->neighbor->nbr_addr), lnk->neighbor->willingness, message->will);
302     /*
303      *If willingness changed - recalculate
304      */
305     lnk->neighbor->willingness = message->will;
306     changes_neighborhood = true;
307     changes_topology = true;
308   }
309
310   /* Don't register neighbors of neighbors that announces WILL_NEVER */
311   if (lnk->neighbor->willingness != WILL_NEVER) {
312     process_message_neighbors(lnk->neighbor, message);
313   }
314
315   /* Process changes immedeatly in case of MPR updates */
316   olsr_process_changes();
317
318   destroy_lq_hello(message);
319 }
320
321 static bool
322 olsr_input_hello(union olsr_message *msg, struct interface *inif, union olsr_ip_addr *from)
323 {
324   struct lq_hello_message hello;
325
326   if (msg == NULL) {
327     return false;
328   }
329   if (deserialize_hello(&hello, msg) != 0) {
330     return false;
331   }
332   hello_tap(&hello, inif, from);
333
334   /* Do not forward hello messages */
335   return false;
336 }
337
338 /*
339  * Local Variables:
340  * c-basic-offset: 2
341  * indent-tabs-mode: nil
342  * End:
343  */