7a9a5ae5670fea574c0b98343e8b19a47e99bdf7
[olsrd.git] / src / hna_set.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 "hna_set.h"
43 #include "ipcalc.h"
44 #include "defs.h"
45 #include "parser.h"
46 #include "olsr.h"
47 #include "scheduler.h"
48 #include "net_olsr.h"
49 #include "tc_set.h"
50 #include "olsr_ip_prefix_list.h"
51 #include "olsr_logging.h"
52
53 /* Some cookies for stats keeping */
54 static struct olsr_cookie_info *hna_net_timer_cookie = NULL;
55 static struct olsr_cookie_info *hna_net_mem_cookie = NULL;
56
57 /**
58  * Initialize the HNA set
59  */
60 void
61 olsr_init_hna_set(void)
62 {
63   OLSR_INFO(LOG_HNA, "Initialize HNA set...\n");
64
65   hna_net_timer_cookie = olsr_alloc_cookie("HNA Network", OLSR_COOKIE_TYPE_TIMER);
66
67   hna_net_mem_cookie = olsr_alloc_cookie("hna_net", OLSR_COOKIE_TYPE_MEMORY);
68   olsr_cookie_set_memory_size(hna_net_mem_cookie, sizeof(struct hna_net));
69 }
70
71 /**
72  * Lookup a network entry in the HNA subtree.
73  *
74  * @param tc the HNA hookup point
75  * @param prefic the prefix to look for
76  *
77  * @return the localized entry or NULL of not found
78  */
79 static struct hna_net *
80 olsr_lookup_hna_net(struct tc_entry *tc, const struct olsr_ip_prefix *prefix)
81 {
82   return (hna_tc_tree2hna(avl_find(&tc->hna_tree, prefix)));
83 }
84
85 /**
86  * Adds a network entry to a HNA gateway.
87  *
88  * @param tc the gateway entry to add the network to
89  * @param net the nework prefix to add
90  * @param prefixlen the prefix length
91  *
92  * @return the newly created entry
93  */
94 static struct hna_net *
95 olsr_add_hna_net(struct tc_entry *tc, const struct olsr_ip_prefix *prefix)
96 {
97   /* Add the net */
98   struct hna_net *new_net = olsr_cookie_malloc(hna_net_mem_cookie);
99
100   /* Fill struct */
101   new_net->hna_prefix = *prefix;
102
103   /* Set backpointer */
104   new_net->hna_tc = tc;
105   olsr_lock_tc_entry(tc);
106
107   /*
108    * Insert into the per-tc hna subtree.
109    */
110   new_net->hna_tc_node.key = &new_net->hna_prefix;
111   avl_insert(&tc->hna_tree, &new_net->hna_tc_node, AVL_DUP_NO);
112
113   return new_net;
114 }
115
116 /**
117  * Delete a single HNA network.
118  *
119  * @param hna_net the hna_net to delete.
120  */
121 static void
122 olsr_delete_hna_net(struct hna_net *hna_net)
123 {
124   struct tc_entry *tc = hna_net->hna_tc;
125
126   /*
127    * Delete the rt_path for the hna_net.
128    */
129   olsr_delete_routing_table(&hna_net->hna_prefix.prefix, hna_net->hna_prefix.prefix_len, &tc->addr, OLSR_RT_ORIGIN_HNA);
130
131   /*
132    * Remove from the per-tc tree.
133    */
134   avl_delete(&tc->hna_tree, &hna_net->hna_tc_node);
135
136   /*
137    * Unlock and free.
138    */
139   olsr_unlock_tc_entry(tc);
140   olsr_cookie_free(hna_net_mem_cookie, hna_net);
141 }
142
143 /**
144  * Delete all the HNA nets hanging off a tc entry.
145  *
146  * @param entry the tc entry holding the HNA networks.
147  */
148 void
149 olsr_flush_hna_nets(struct tc_entry *tc)
150 {
151   struct hna_net *hna_net;
152
153   OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, hna_net) {
154     olsr_delete_hna_net(hna_net);
155   } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, hna_net);
156 }
157
158 /**
159  * Callback for the hna_net timer.
160  */
161 static void
162 olsr_expire_hna_net_entry(void *context)
163 {
164   struct hna_net *hna_net = context;
165 #if !defined REMOVE_LOG_DEBUG
166   struct ipaddr_str buf;
167   struct ipprefix_str prefixstr;
168 #endif
169
170   OLSR_DEBUG(5, "HNA: timeout %s via hna-gw %s\n",
171              olsr_ip_prefix_to_string(&prefixstr, &hna_net->hna_prefix), olsr_ip_to_string(&buf, &hna_net->hna_tc->addr));
172
173   hna_net->hna_net_timer = NULL;        /* be pedandic */
174
175   olsr_delete_hna_net(hna_net);
176 }
177
178 /**
179  * Update a HNA entry. If it does not exist it
180  * is created.
181  * This is the only function that should be called
182  * from outside concerning creation of HNA entries.
183  *
184  *@param gw address of the gateway
185  *@param net address of the network
186  *@param mask the netmask
187  *@param vtime the validitytime of the entry
188  *
189  *@return nada
190  */
191 static void
192 olsr_update_hna_entry(const union olsr_ip_addr *gw, const struct olsr_ip_prefix *prefix, uint32_t vtime,
193     uint16_t msg_seq)
194 {
195   struct tc_entry *tc = olsr_locate_tc_entry(gw);
196   struct hna_net *net_entry = olsr_lookup_hna_net(tc, prefix);
197
198   if (net_entry == NULL) {
199     /* Need to add the net */
200     net_entry = olsr_add_hna_net(tc, prefix);
201     changes_hna = true;
202   }
203
204   net_entry->tc_entry_seqno = msg_seq;
205
206   /*
207    * Add the rt_path for the entry.
208    */
209   olsr_insert_routing_table(&net_entry->hna_prefix.prefix, net_entry->hna_prefix.prefix_len, &tc->addr, OLSR_RT_ORIGIN_HNA);
210
211   /*
212    * Start, or refresh the timer, whatever is appropriate.
213    */
214   olsr_set_timer(&net_entry->hna_net_timer, vtime,
215                  OLSR_HNA_NET_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_hna_net_entry, net_entry, hna_net_timer_cookie);
216 }
217
218 /**
219  * Print all HNA entries.
220  *
221  *@return nada
222  */
223 void
224 olsr_print_hna_set(void)
225 {
226   /* The whole function doesn't do anything else. */
227 #if !defined REMOVE_LOG_INFO
228   struct tc_entry *tc;
229   struct ipaddr_str buf;
230   struct ipprefix_str prefixstr;
231   struct hna_net *hna_net;
232
233   OLSR_INFO(LOG_HNA, "\n--- %s ------------------------------------------------- HNA\n\n", olsr_wallclock_string());
234
235   OLSR_FOR_ALL_TC_ENTRIES(tc) {
236     OLSR_INFO_NH(LOG_HNA, "HNA-gw %s:\n", olsr_ip_to_string(&buf, &tc->addr));
237
238     OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, hna_net) {
239       OLSR_INFO_NH(LOG_HNA, "\t%-27s\n", olsr_ip_prefix_to_string(&prefixstr, &hna_net->hna_prefix));
240     } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, hna_net);
241   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
242 #endif
243 }
244
245 static void
246 olsr_prune_hna_entries(struct tc_entry *tc)
247 {
248   struct hna_net *hna_net;
249
250   OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, hna_net) {
251     if (hna_net->tc_entry_seqno != tc->hna_seq) {
252       olsr_delete_hna_net(hna_net);
253     }
254   } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, hna_net);
255 }
256
257 /**
258  * Process incoming HNA message.
259  * Forwards the message if that is to be done.
260  */
261 void
262 olsr_input_hna(union olsr_message *msg, struct interface *in_if __attribute__ ((unused)),
263     union olsr_ip_addr *from_addr, enum duplicate_status status)
264 {
265   uint16_t msg_size, msg_seq;
266   uint8_t type, ttl, msg_hops;
267   uint32_t vtime;
268   union olsr_ip_addr originator;
269   struct tc_entry *tc;
270   struct olsr_ip_prefix prefix;
271   const uint8_t *curr, *curr_end;
272 #if !defined REMOVE_LOG_DEBUG
273   struct ipaddr_str buf;
274 #endif
275
276   curr = (void *)msg;
277
278   /* We are only interested in MID message types. */
279   pkt_get_u8(&curr, &type);
280   if (type != HNA_MESSAGE) {
281     return;
282   }
283
284   pkt_get_reltime(&curr, &vtime);
285   pkt_get_u16(&curr, &msg_size);
286
287   pkt_get_ipaddress(&curr, &originator);
288
289   /* Copy header values */
290   pkt_get_u8(&curr, &ttl);
291   pkt_get_u8(&curr, &msg_hops);
292   pkt_get_u16(&curr, &msg_seq);
293
294   if (!olsr_validate_address(&originator)) {
295     return;
296   }
297
298   /*
299    * If the sender interface (NB: not originator) of this message
300    * is not in the symmetric 1-hop neighborhood of this node, the
301    * message MUST be discarded.
302    */
303   if (check_neighbor_link(from_addr) != SYM_LINK) {
304     OLSR_DEBUG(LOG_HNA, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
305     return;
306   }
307
308   tc = olsr_locate_tc_entry(&originator);
309   if (status != RESET_SEQNO_OLSR_MESSAGE && olsr_seqno_diff(msg_seq, tc->mid_seq) <= 0) {
310     /* this HNA is too old, discard it */
311     return;
312   }
313   tc->hna_seq = msg_seq;
314
315   OLSR_DEBUG(LOG_HNA, "Processing HNA from %s, seq 0x%04x\n", olsr_ip_to_string(&buf, &originator), msg_seq);
316
317   /*
318    * Now walk the list of HNA advertisements.
319    */
320   curr_end = (uint8_t *)msg + msg_size;
321
322   while (curr + 2*olsr_cnf->ipsize <= curr_end) {
323
324     pkt_get_ipaddress(&curr, &prefix.prefix);
325     pkt_get_prefixlen(&curr, &prefix.prefix_len);
326
327     if (!ip_prefix_list_find(&olsr_cnf->hna_entries, &prefix.prefix, prefix.prefix_len, olsr_cnf->ip_version)) {
328       /*
329        * Only update if it's not from us.
330        */
331       olsr_update_hna_entry(&originator, &prefix, vtime, msg_seq);
332     }
333   }
334
335   /*
336    * Prune the HNAs that did not get refreshed by this advertisment.
337    */
338   olsr_prune_hna_entries(tc);
339
340 }
341
342 /*
343  * Local Variables:
344  * c-basic-offset: 2
345  * indent-tabs-mode: nil
346  * End:
347  */