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