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