Add OLSR support for NIIT (IP 4to6 tunnel device)
[olsrd.git] / src / hna_set.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
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 "ipcalc.h"
43 #include "defs.h"
44 #include "olsr.h"
45 #include "scheduler.h"
46 #include "net_olsr.h"
47 #include "tc_set.h"
48 #include "parser.h"
49 #include "duplicate_handler.h"
50
51 struct hna_entry hna_set[HASHSIZE];
52 struct olsr_cookie_info *hna_net_timer_cookie = NULL;
53 struct olsr_cookie_info *hna_entry_mem_cookie = NULL;
54 struct olsr_cookie_info *hna_net_mem_cookie = NULL;
55
56 static bool olsr_delete_hna_net_entry(struct hna_net *net_to_delete);
57
58 /**
59  * Initialize the HNA set
60  */
61 int
62 olsr_init_hna_set(void)
63 {
64   int idx;
65
66   for (idx = 0; idx < HASHSIZE; idx++) {
67     hna_set[idx].next = &hna_set[idx];
68     hna_set[idx].prev = &hna_set[idx];
69   }
70
71   hna_net_timer_cookie = olsr_alloc_cookie("HNA Network", OLSR_COOKIE_TYPE_TIMER);
72
73   hna_net_mem_cookie = olsr_alloc_cookie("hna_net", OLSR_COOKIE_TYPE_MEMORY);
74   olsr_cookie_set_memory_size(hna_net_mem_cookie, sizeof(struct hna_net));
75
76   hna_entry_mem_cookie = olsr_alloc_cookie("hna_entry", OLSR_COOKIE_TYPE_MEMORY);
77   olsr_cookie_set_memory_size(hna_entry_mem_cookie, sizeof(struct hna_entry));
78
79   return 1;
80 }
81
82 void
83 olsr_cleanup_hna(union olsr_ip_addr *orig) {
84   struct hna_entry *hna;
85
86   OLSR_FOR_ALL_HNA_ENTRIES(hna) {
87     if (hna->networks.next != &hna->networks && ipequal(&hna->A_gateway_addr, orig)) {
88       while (!olsr_delete_hna_net_entry(hna->networks.next));
89     }
90   } OLSR_FOR_ALL_HNA_ENTRIES_END(hna)
91 }
92
93 /**
94  * Lookup a network entry in a networkentry list.
95  *
96  * @param nets the network list to look in
97  * @param net the network to look for
98  * @param mask the netmask to look for
99  *
100  * @return the localized entry or NULL of not found
101  */
102 struct hna_net *
103 olsr_lookup_hna_net(const struct hna_net *nets, const union olsr_ip_addr *net, uint8_t prefixlen)
104 {
105   struct hna_net *tmp;
106
107   /* Loop trough entrys */
108   for (tmp = nets->next; tmp != nets; tmp = tmp->next) {
109     if (tmp->prefixlen == prefixlen && ipequal(&tmp->A_network_addr, net)) {
110       return tmp;
111     }
112   }
113
114   /* Not found */
115   return NULL;
116 }
117
118 /**
119  * Lookup a gateway entry
120  *
121  * @param gw the address of the gateway
122  * @return the located entry or NULL if not found
123  */
124 struct hna_entry *
125 olsr_lookup_hna_gw(const union olsr_ip_addr *gw)
126 {
127   struct hna_entry *tmp_hna;
128   uint32_t hash = olsr_ip_hashing(gw);
129
130 #if 0
131   OLSR_PRINTF(5, "HNA: lookup entry\n");
132 #endif
133   /* Check for registered entry */
134
135   for (tmp_hna = hna_set[hash].next; tmp_hna != &hna_set[hash]; tmp_hna = tmp_hna->next) {
136     if (ipequal(&tmp_hna->A_gateway_addr, gw)) {
137       return tmp_hna;
138     }
139   }
140
141   /* Not found */
142   return NULL;
143 }
144
145 /**
146  *Add a gatewayentry to the HNA set
147  *
148  *@param addr the address of the gateway
149  *
150  *@return the created entry
151  */
152 struct hna_entry *
153 olsr_add_hna_entry(const union olsr_ip_addr *addr)
154 {
155   struct hna_entry *new_entry;
156   uint32_t hash;
157
158   new_entry = olsr_cookie_malloc(hna_entry_mem_cookie);
159
160   /* Fill struct */
161   new_entry->A_gateway_addr = *addr;
162
163   /* Link nets */
164   new_entry->networks.next = &new_entry->networks;
165   new_entry->networks.prev = &new_entry->networks;
166
167   /* queue */
168   hash = olsr_ip_hashing(addr);
169
170   hna_set[hash].next->prev = new_entry;
171   new_entry->next = hna_set[hash].next;
172   hna_set[hash].next = new_entry;
173   new_entry->prev = &hna_set[hash];
174
175   return new_entry;
176 }
177
178 /**
179  * Adds a network entry to a HNA gateway.
180  *
181  * @param hna_gw the gateway entry to add the network to
182  * @param net the networkaddress to add
183  * @param mask the netmask
184  *
185  * @return the newly created entry
186  */
187 struct hna_net *
188 olsr_add_hna_net(struct hna_entry *hna_gw, const union olsr_ip_addr *net, uint8_t prefixlen)
189 {
190   /* Add the net */
191   struct hna_net *new_net = olsr_cookie_malloc(hna_net_mem_cookie);
192
193   /* Fill struct */
194   memset(new_net, 0, sizeof(struct hna_net));
195   new_net->A_network_addr = *net;
196   new_net->prefixlen = prefixlen;
197
198   /* Set backpointer */
199   new_net->hna_gw = hna_gw;
200
201   /* Queue */
202   hna_gw->networks.next->prev = new_net;
203   new_net->next = hna_gw->networks.next;
204   hna_gw->networks.next = new_net;
205   new_net->prev = &hna_gw->networks;
206
207   return new_net;
208 }
209
210 static bool
211 olsr_delete_hna_net_entry(struct hna_net *net_to_delete) {
212 #ifdef DEBUG
213   struct ipaddr_str buf1, buf2;
214 #endif
215   struct hna_entry *hna_gw;
216   bool removed_entry = false;
217
218   olsr_stop_timer(net_to_delete->hna_net_timer);
219   net_to_delete->hna_net_timer = NULL;  /* be pedandic */
220   hna_gw = net_to_delete->hna_gw;
221
222 #ifdef DEBUG
223   OLSR_PRINTF(5, "HNA: timeout %s/%u via hna-gw %s\n", olsr_ip_to_string(&buf1, &net_to_delete->A_network_addr),
224               net_to_delete->prefixlen, olsr_ip_to_string(&buf2, &hna_gw->A_gateway_addr));
225 #endif
226
227   /*
228    * Delete the rt_path for the entry.
229    */
230   olsr_delete_routing_table(&net_to_delete->A_network_addr, net_to_delete->prefixlen, &hna_gw->A_gateway_addr);
231
232   DEQUEUE_ELEM(net_to_delete);
233
234   /* Delete hna_gw if empty */
235   if (hna_gw->networks.next == &hna_gw->networks) {
236     DEQUEUE_ELEM(hna_gw);
237     olsr_cookie_free(hna_entry_mem_cookie, hna_gw);
238     removed_entry = true;
239   }
240
241   olsr_cookie_free(hna_net_mem_cookie, net_to_delete);
242   return removed_entry;
243 }
244
245 /**
246  * Callback for the hna_net timer.
247  */
248 static void
249 olsr_expire_hna_net_entry(void *context)
250 {
251   olsr_delete_hna_net_entry(context);
252 }
253
254 /**
255  * Update a HNA entry. If it does not exist it
256  * is created.
257  * This is the only function that should be called
258  * from outside concerning creation of HNA entries.
259  *
260  *@param gw address of the gateway
261  *@param net address of the network
262  *@param mask the netmask
263  *@param vtime the validitytime of the entry
264  *
265  *@return nada
266  */
267 void
268 olsr_update_hna_entry(const union olsr_ip_addr *gw, const union olsr_ip_addr *net, uint8_t prefixlen, olsr_reltime vtime)
269 {
270   struct hna_entry *gw_entry;
271   struct hna_net *net_entry;
272
273   gw_entry = olsr_lookup_hna_gw(gw);
274   if (!gw_entry) {
275
276     /* Need to add the entry */
277     gw_entry = olsr_add_hna_entry(gw);
278   }
279
280   net_entry = olsr_lookup_hna_net(&gw_entry->networks, net, prefixlen);
281   if (net_entry == NULL) {
282
283     /* Need to add the net */
284     net_entry = olsr_add_hna_net(gw_entry, net, prefixlen);
285     changes_hna = true;
286   }
287
288   /*
289    * Add the rt_path for the entry.
290    */
291   olsr_insert_routing_table(&net_entry->A_network_addr, net_entry->prefixlen, &gw_entry->A_gateway_addr, OLSR_RT_ORIGIN_HNA);
292
293   /*
294    * Start, or refresh the timer, whatever is appropriate.
295    */
296   olsr_set_timer(&net_entry->hna_net_timer, vtime, OLSR_HNA_NET_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_hna_net_entry, net_entry,
297                  hna_net_timer_cookie->ci_id);
298 }
299
300 /**
301  * Print all HNA entries.
302  *
303  *@return nada
304  */
305 void
306 olsr_print_hna_set(void)
307 {
308 #ifdef NODEBUG
309   /* The whole function doesn't do anything else. */
310   int idx;
311
312   OLSR_PRINTF(1, "\n--- %02d:%02d:%02d.%02d ------------------------------------------------- HNA SET\n\n", nowtm->tm_hour,
313               nowtm->tm_min, nowtm->tm_sec, (int)now.tv_usec / 10000);
314
315   if (olsr_cnf->ip_version == AF_INET)
316     OLSR_PRINTF(1, "IP net          netmask         GW IP\n");
317   else
318     OLSR_PRINTF(1, "IP net/prefixlen               GW IP\n");
319
320   for (idx = 0; idx < HASHSIZE; idx++) {
321     struct hna_entry *tmp_hna = hna_set[idx].next;
322     /* Check all entrys */
323     while (tmp_hna != &hna_set[idx]) {
324       /* Check all networks */
325       struct hna_net *tmp_net = tmp_hna->networks.next;
326
327       while (tmp_net != &tmp_hna->networks) {
328         if (olsr_cnf->ip_version == AF_INET) {
329           struct ipaddr_str buf;
330           OLSR_PRINTF(1, "%-15s ", olsr_ip_to_string(&buf, &tmp_net->A_network_addr));
331           OLSR_PRINTF(1, "%-15d ", tmp_net->prefix_len);
332           OLSR_PRINTF(1, "%-15s\n", olsr_ip_to_string(&buf, &tmp_hna->A_gateway_addr));
333         } else {
334           struct ipaddr_str buf;
335           OLSR_PRINTF(1, "%-27s/%d", olsr_ip_to_string(&buf, &tmp_net->A_network_addr), tmp_net->A_netmask.v6);
336           OLSR_PRINTF(1, "%s\n", olsr_ip_to_string(&buf, &tmp_hna->A_gateway_addr));
337         }
338
339         tmp_net = tmp_net->next;
340       }
341       tmp_hna = tmp_hna->next;
342     }
343   }
344 #endif
345 }
346
347 /**
348  *Process incoming HNA message.
349  *Forwards the message if that is to be done.
350  *
351  *@param m the incoming OLSR message
352  *the OLSR message.
353  *@return 1 on success
354  */
355
356 bool
357 olsr_input_hna(union olsr_message *m, struct interface *in_if __attribute__ ((unused)), union olsr_ip_addr *from_addr)
358 {
359
360   uint8_t olsr_msgtype;
361   olsr_reltime vtime;
362   uint16_t olsr_msgsize;
363   union olsr_ip_addr originator;
364   uint8_t hop_count;
365   uint16_t packet_seq_number;
366
367   int hnasize;
368   const uint8_t *curr, *curr_end;
369
370   struct ipaddr_str buf;
371 #ifdef DEBUG
372   OLSR_PRINTF(5, "Processing HNA\n");
373 #endif
374
375   /* Check if everyting is ok */
376   if (!m) {
377     return false;
378   }
379   curr = (const uint8_t *)m;
380
381   /* olsr_msgtype */
382   pkt_get_u8(&curr, &olsr_msgtype);
383   if (olsr_msgtype != HNA_MESSAGE) {
384     OLSR_PRINTF(1, "not a HNA message!\n");
385     return false;
386   }
387   /* Get vtime */
388   pkt_get_reltime(&curr, &vtime);
389
390   /* olsr_msgsize */
391   pkt_get_u16(&curr, &olsr_msgsize);
392
393   if (olsr_msgsize < 8 + olsr_cnf->ipsize) {
394 #ifndef WIN32
395     OLSR_PRINTF(1, "HNA message size %d too small (at least %zu)!\n", olsr_msgsize,
396                 8 + olsr_cnf->ipsize);
397 #endif
398     return false;
399   }
400
401   hnasize = olsr_msgsize - 8 - olsr_cnf->ipsize;
402   curr_end = (const uint8_t *)m + olsr_msgsize;
403
404   /* validate originator */
405   pkt_get_ipaddress(&curr, &originator);
406   /*printf("HNA from %s\n\n", olsr_ip_to_string(&buf, &originator)); */
407
408   /* ttl */
409   pkt_ignore_u8(&curr);
410
411   /* hopcnt */
412   pkt_get_u8(&curr, &hop_count);
413
414   /* seqno */
415   pkt_get_u16(&curr, &packet_seq_number);
416
417   if ((hnasize % (2 * olsr_cnf->ipsize)) != 0) {
418     OLSR_PRINTF(1, "Illegal HNA message from %s with size %d!\n",
419         olsr_ip_to_string(&buf, &originator), olsr_msgsize);
420     return false;
421   }
422
423   /*
424    *      If the sender interface (NB: not originator) of this message
425    *      is not in the symmetric 1-hop neighborhood of this node, the
426    *      message MUST be discarded.
427    */
428   if (check_neighbor_link(from_addr) != SYM_LINK) {
429     OLSR_PRINTF(2, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
430     return false;
431   }
432   while (curr < curr_end) {
433     union olsr_ip_addr net;
434     uint8_t prefixlen;
435     struct ip_prefix_list *entry;
436     struct interface *ifs;
437     bool stop = false;
438
439     pkt_get_ipaddress(&curr, &net);
440     pkt_get_prefixlen(&curr, &prefixlen);
441
442 #ifndef NO_DUPLICATE_DETECTION_HANDLER
443     for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
444       if (ipequal(&ifs->ip_addr, &net)) {
445       /* ignore your own main IP as an incoming MID */
446         olsr_handle_hna_collision(&net, &originator);
447         stop = true;
448         break;
449       }
450     }
451     if (stop) {
452       continue;
453     }
454 #endif
455     entry = ip_prefix_list_find(olsr_cnf->hna_entries, &net, prefixlen);
456     if (entry == NULL) {
457       /* only update if it's not from us */
458       olsr_update_hna_entry(&originator, &net, prefixlen, vtime);
459     }
460   }
461   /* Forward the message */
462   return true;
463 }
464
465 /*
466  * Local Variables:
467  * c-basic-offset: 2
468  * indent-tabs-mode: nil
469  * End:
470  */