Fix MPR calculation... at least make it possible to work in theory.
[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,
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   struct link_entry *lnk;
72   union olsr_ip_addr *neigh_addr;
73   struct nbr_con *connector;
74
75   lnk = get_best_link_to_neighbor(neighbor);
76
77   /*
78    * Walk our 2-hop neighbors.
79    */
80   for (message_neighbors = message->neigh; message_neighbors; message_neighbors = message_neighbors->next) {
81     /*
82      * We are only interested in symmetrical or MPR neighbors.
83      */
84     if (message_neighbors->neigh_type != SYM_NEIGH && message_neighbors->neigh_type != MPR_NEIGH) {
85       continue;
86     }
87
88     /*
89      * Check all interfaces such that we don't add ourselves to the 2 hop list.
90      * IMPORTANT!
91      */
92     if (if_ifwithaddr(&message_neighbors->addr) != NULL) {
93       continue;
94     }
95
96     /* Get the main address */
97     neigh_addr = olsr_lookup_main_addr_by_alias(&message_neighbors->addr);
98     if (neigh_addr == NULL) {
99       neigh_addr = &message_neighbors->addr;
100     }
101
102     olsr_link_nbr_nbr2(neighbor, neigh_addr, message->comm->vtime);
103
104     if (lnk) {
105       connector = olsr_lookup_nbr_con_entry(neighbor, neigh_addr);
106
107       connector->second_hop_linkcost = message_neighbors->cost;
108       connector->path_linkcost = lnk->linkcost + message_neighbors->cost;
109
110       changes_neighborhood = true;
111     }
112   }
113 }
114
115
116 /**
117  * Check if a hello message states this node as a MPR.
118  *
119  * @param message the message to check
120  * @param n_link the buffer to put the link status in
121  *
122  * @return 1 if we are selected as MPR 0 if not
123  */
124 static bool
125 lookup_mpr_status(const struct lq_hello_message *message, const struct interface *in_if)
126 {
127   struct lq_hello_neighbor *neighbors;
128
129   for (neighbors = message->neigh; neighbors; neighbors = neighbors->next) {
130     if ( neighbors->link_type != UNSPEC_LINK
131         && olsr_ipcmp(&neighbors->addr, &in_if->ip_addr) == 0) {
132       return neighbors->link_type == SYM_LINK && neighbors->neigh_type == MPR_NEIGH ? true : false;
133     }
134   }
135   /* Not found */
136   return false;
137 }
138
139 /**
140  * Initializing the parser functions we are using
141  * For downwards compatibility reasons we also understand the non-LQ messages.
142  */
143 void
144 olsr_init_package_process(void)
145 {
146   olsr_parser_add_function(&olsr_input_hello, olsr_get_Hello_MessageId());
147   olsr_parser_add_function(&olsr_input_tc, olsr_get_TC_MessageId());
148   olsr_parser_add_function(&olsr_input_mid, MID_MESSAGE);
149   olsr_parser_add_function(&olsr_input_hna, HNA_MESSAGE);
150 }
151
152 void
153 olsr_deinit_package_process(void)
154 {
155   olsr_parser_remove_function(&olsr_input_hello);
156   olsr_parser_remove_function(&olsr_input_tc);
157   olsr_parser_remove_function(&olsr_input_mid);
158   olsr_parser_remove_function(&olsr_input_hna);
159 }
160
161 static bool
162 deserialize_hello(struct lq_hello_message *hello, struct olsr_message *msg)
163 {
164   const uint8_t *curr = msg->payload;
165   hello->comm = msg;
166
167   /* parse HELLO specific header */
168   pkt_ignore_u16(&curr);
169   pkt_get_reltime(&curr, &hello->htime);
170   pkt_get_u8(&curr, &hello->will);
171
172   hello->neigh = NULL;
173   while (curr < msg->end) {
174     const uint8_t *ptr, *limit2;
175     uint8_t link_code;
176     uint16_t size;
177
178     ptr = curr;
179     pkt_get_u8(&curr, &link_code);
180     pkt_ignore_u8(&curr);
181     pkt_get_u16(&curr, &size);
182
183     limit2 = ptr + size;
184     while (curr + olsr_cnf->ipsize + olsr_sizeof_HelloLQ() <= limit2) {
185       struct lq_hello_neighbor *neigh = olsr_malloc_lq_hello_neighbor();
186       pkt_get_ipaddress(&curr, &neigh->addr);
187
188       olsr_deserialize_hello_lq_pair(&curr, neigh);
189       if (is_lost_interface_ip(&neigh->addr)) {
190         /* this is a lost interface IP of this node... ignore it */
191         olsr_free_lq_hello_neighbor(neigh);
192         continue;
193       }
194
195       neigh->link_type = EXTRACT_LINK(link_code);
196       neigh->neigh_type = EXTRACT_STATUS(link_code);
197
198       neigh->next = hello->neigh;
199       hello->neigh = neigh;
200     }
201   }
202   return false;
203 }
204
205
206 static void olsr_update_mprs_set(struct lq_hello_message *message, struct link_entry *link) {
207   bool new_mprs_status;
208
209   new_mprs_status = lookup_mpr_status(message, link->inter);
210
211   if (new_mprs_status && !link->is_mprs) {
212     link->neighbor->mprs_count++;
213   }
214   if (!new_mprs_status && link->is_mprs) {
215     link->neighbor->mprs_count--;
216   }
217
218   link->is_mprs = new_mprs_status;
219 }
220
221 static void
222 hello_tap(struct lq_hello_message *message, struct interface *in_if, const union olsr_ip_addr *from_addr)
223 {
224   /*
225    * Update link status
226    */
227   struct link_entry *lnk = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
228   struct lq_hello_neighbor *walker;
229   /* just in case our neighbor has changed its HELLO interval */
230   olsr_update_packet_loss_hello_int(lnk, message->htime);
231
232   /* find the input interface in the list of neighbor interfaces */
233   for (walker = message->neigh; walker != NULL; walker = walker->next) {
234     if (walker->link_type != UNSPEC_LINK && olsr_ipcmp(&walker->addr, &in_if->ip_addr) == 0) {
235       break;
236     }
237   }
238
239   olsr_update_mprs_set(message, lnk);
240
241   /*
242    * memorize our neighbour's idea of the link quality, so that we
243    * know the link quality in both directions
244    *
245    * walker is NULL if there the current interface was not included in
246    * the message (or was included as an UNSPEC_LINK)
247    */
248   olsr_memorize_foreign_hello_lq(lnk, walker);
249
250   /* update packet loss for link quality calculation */
251   olsr_update_packet_loss(lnk);
252
253   /* Check willingness */
254   if (lnk->neighbor->willingness != message->will) {
255 #if !defined REMOVE_LOG_DEBUG
256     struct ipaddr_str buf;
257 #endif
258     OLSR_DEBUG(LOG_LINKS, "Willingness for %s changed from %d to %d - UPDATING\n",
259                olsr_ip_to_string(&buf, &lnk->neighbor->nbr_addr), lnk->neighbor->willingness, message->will);
260     /*
261      *If willingness changed - recalculate
262      */
263     lnk->neighbor->willingness = message->will;
264     changes_neighborhood = true;
265     changes_topology = true;
266   }
267
268   /* Don't register neighbors of neighbors that announces WILL_NEVER */
269   if (lnk->neighbor->willingness != WILL_NEVER) {
270     process_message_neighbors(lnk->neighbor, message);
271   }
272
273   /* Process changes immedeatly in case of MPR updates */
274   olsr_process_changes();
275
276   destroy_lq_hello(message);
277 }
278
279 static void
280 olsr_input_hello(struct olsr_message *msg, struct interface *inif, union olsr_ip_addr *from,
281     enum duplicate_status status __attribute__ ((unused)))
282 {
283   struct lq_hello_message hello;
284   if (!deserialize_hello(&hello, msg)) {
285     hello_tap(&hello, inif, from);
286   }
287 }
288
289 /*
290  * Local Variables:
291  * c-basic-offset: 2
292  * indent-tabs-mode: nil
293  * End:
294  */