Merge pull request #19 in FKIEA/oonf-os from develop to master
[oonf.git] / src / generic / dlep / ext_base_ip / ip.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, 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 /**
43  * @file
44  */
45
46 #include <oonf/libcommon/autobuf.h>
47 #include <oonf/libcommon/avl.h>
48 #include <oonf/oonf.h>
49 #include <oonf/base/oonf_layer2.h>
50 #include <oonf/base/oonf_timer.h>
51
52 #include <oonf/generic/dlep/dlep_extension.h>
53 #include <oonf/generic/dlep/dlep_iana.h>
54 #include <oonf/generic/dlep/dlep_interface.h>
55 #include <oonf/generic/dlep/dlep_reader.h>
56 #include <oonf/generic/dlep/dlep_writer.h>
57 #include <oonf/generic/dlep/radio/dlep_radio_interface.h>
58 #include <oonf/generic/dlep/radio/dlep_radio_session.h>
59
60 #include <oonf/generic/dlep/ext_base_ip/ip.h>
61
62 struct _prefix_storage {
63   struct netaddr prefix;
64
65   struct avl_node _node;
66 };
67
68 static void _cb_session_init(struct dlep_session *session);
69 static void _cb_session_cleanup(struct dlep_session *session);
70 static int _radio_write_session_update(
71   struct dlep_extension *ext, struct dlep_session *session, const struct oonf_layer2_neigh_key *neigh);
72 static int _radio_write_destination_update(
73   struct dlep_extension *ext, struct dlep_session *session, const struct oonf_layer2_neigh_key *neigh);
74 static enum dlep_parser_error _router_process_session_update(struct dlep_extension *ext, struct dlep_session *session);
75 static enum dlep_parser_error _router_process_destination_update(
76   struct dlep_extension *ext, struct dlep_session *session);
77 static void _add_prefix(struct avl_tree *tree, struct netaddr *addr);
78
79 /* peer initialization ack/peer update/destination update */
80 static const uint16_t _ip_tlvs[] = {
81   DLEP_IPV4_ADDRESS_TLV,
82   DLEP_IPV4_SUBNET_TLV,
83   DLEP_IPV6_ADDRESS_TLV,
84   DLEP_IPV6_SUBNET_TLV,
85 };
86
87 static const uint16_t _ip_duplicate_tlvs[] = {
88   DLEP_IPV4_ADDRESS_TLV,
89   DLEP_IPV4_SUBNET_TLV,
90   DLEP_IPV6_ADDRESS_TLV,
91   DLEP_IPV6_SUBNET_TLV,
92 };
93
94 /* supported signals of this extension */
95 static struct dlep_extension_signal _signals[] = {
96   {
97     .id = DLEP_SESSION_INITIALIZATION_ACK,
98     .supported_tlvs = _ip_tlvs,
99     .supported_tlv_count = ARRAYSIZE(_ip_tlvs),
100     .duplicate_tlvs = _ip_duplicate_tlvs,
101     .duplicate_tlv_count = ARRAYSIZE(_ip_duplicate_tlvs),
102     .add_radio_tlvs = _radio_write_session_update,
103     .process_router = _router_process_session_update,
104   },
105   {
106     .id = DLEP_SESSION_UPDATE,
107     .supported_tlvs = _ip_tlvs,
108     .supported_tlv_count = ARRAYSIZE(_ip_tlvs),
109     .duplicate_tlvs = _ip_duplicate_tlvs,
110     .duplicate_tlv_count = ARRAYSIZE(_ip_duplicate_tlvs),
111     .add_radio_tlvs = _radio_write_session_update,
112     .process_router = _router_process_session_update,
113   },
114   {
115     .id = DLEP_DESTINATION_UP,
116     .supported_tlvs = _ip_tlvs,
117     .supported_tlv_count = ARRAYSIZE(_ip_tlvs),
118     .duplicate_tlvs = _ip_duplicate_tlvs,
119     .duplicate_tlv_count = ARRAYSIZE(_ip_duplicate_tlvs),
120     .add_radio_tlvs = _radio_write_destination_update,
121     .process_router = _router_process_destination_update,
122   },
123   {
124     .id = DLEP_DESTINATION_UPDATE,
125     .supported_tlvs = _ip_tlvs,
126     .supported_tlv_count = ARRAYSIZE(_ip_tlvs),
127     .duplicate_tlvs = _ip_duplicate_tlvs,
128     .duplicate_tlv_count = ARRAYSIZE(_ip_duplicate_tlvs),
129     .add_radio_tlvs = _radio_write_destination_update,
130     .process_router = _router_process_destination_update,
131   },
132 };
133
134 /* supported TLVs of this extension */
135 static struct dlep_extension_tlv _tlvs[] = {
136   { DLEP_MAC_ADDRESS_TLV, 6, 8 },
137   { DLEP_IPV4_ADDRESS_TLV, 5, 5 },
138   { DLEP_IPV4_SUBNET_TLV, 6, 6 },
139   { DLEP_IPV6_ADDRESS_TLV, 17, 17 },
140   { DLEP_IPV6_SUBNET_TLV, 18, 18 },
141 };
142
143 /* DLEP base extension, radio side */
144 static struct dlep_extension _base_ip = {
145   .id = DLEP_EXTENSION_BASE_IP,
146   .name = "base metric",
147
148   .signals = _signals,
149   .signal_count = ARRAYSIZE(_signals),
150   .tlvs = _tlvs,
151   .tlv_count = ARRAYSIZE(_tlvs),
152
153   .cb_session_init_radio = _cb_session_init,
154   .cb_session_init_router = _cb_session_init,
155
156   .cb_session_cleanup_radio = _cb_session_cleanup,
157   .cb_session_cleanup_router = _cb_session_cleanup,
158 };
159
160 static struct oonf_class _prefix_class = {
161   .name = "dlep ip prefix",
162   .size = sizeof(struct _prefix_storage),
163 };
164
165 /**
166  * Initialize the base metric DLEP extension
167  * @return this extension
168  */
169 struct dlep_extension *
170 dlep_base_ip_init(void) {
171   dlep_extension_add(&_base_ip);
172   oonf_class_add(&_prefix_class);
173
174   return &_base_ip;
175 }
176
177 void
178 dlep_base_ip_cleanup(void) {
179   oonf_class_remove(&_prefix_class);
180 }
181
182 static void
183 _cb_session_init(struct dlep_session *session __attribute__((unused))) {
184 }
185
186 static void
187 _cb_session_cleanup(struct dlep_session *session) {
188   struct dlep_local_neighbor *l2neigh;
189   struct _prefix_storage *storage, *storage_it;
190
191   /* remove all stored changes for neighbors */
192   avl_for_each_element(&session->local_neighbor_tree, l2neigh, _node) {
193     avl_for_each_element_safe(&l2neigh->_ip_prefix_modification, storage, _node, storage_it) {
194       avl_remove(&l2neigh->_ip_prefix_modification, &storage->_node);
195       oonf_class_free(&_prefix_class, storage);
196     }
197   }
198
199   /* remove all stored changes for the local peer */
200   avl_for_each_element_safe(&session->_ext_ip.prefix_modification, storage, _node, storage_it) {
201     avl_remove(&session->_ext_ip.prefix_modification, &storage->_node);
202     oonf_class_free(&_prefix_class, storage);
203   }
204 }
205
206 static void
207 _handle_if_ip(struct dlep_session *session, struct netaddr *last_session_if_ip,
208     const struct netaddr *first_if_ip, const struct netaddr *second_if_ip) {
209   const struct netaddr *if_ip;
210
211   if_ip = netaddr_is_unspec(first_if_ip) ? second_if_ip : first_if_ip;
212
213   if (netaddr_cmp(last_session_if_ip, if_ip) == 0) {
214     return;
215   }
216
217   if (!netaddr_is_unspec(last_session_if_ip)) {
218     dlep_writer_add_ip_tlv(&session->writer, last_session_if_ip, false);
219   }
220   if (!netaddr_is_unspec(if_ip)) {
221     dlep_writer_add_ip_tlv(&session->writer, if_ip, true);
222   }
223   memcpy(last_session_if_ip, if_ip, sizeof(*if_ip));
224 }
225
226 static int
227 _radio_write_session_update(struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session,
228   const struct oonf_layer2_neigh_key *neigh __attribute__((unused))) {
229   struct _prefix_storage *storage, *storage_it;
230   struct dlep_radio_session *radio_session;
231   struct oonf_layer2_peer_address *peer_ip;
232   struct oonf_layer2_net *l2net;
233   struct os_interface *os_if;
234   struct netaddr_str nbuf;
235
236   /* first make sure defaults are set correctly */
237   l2net = oonf_layer2_net_get(session->l2_listener.name);
238
239   /* announce newly added interface prefixes */
240   if (l2net) {
241     avl_for_each_element(&l2net->local_peer_ips, peer_ip, _net_node) {
242       if (avl_find(&session->_ext_ip.prefix_modification, &peer_ip->ip)) {
243         /* prefix already known to session */
244         continue;
245       }
246
247       OONF_INFO(session->log_source, "New prefix '%s' for session update",
248                 netaddr_to_string(&nbuf, &peer_ip->ip));
249
250       if (dlep_writer_add_ip_tlv(&session->writer, &peer_ip->ip, true)) {
251         OONF_WARN(session->log_source, "Cannot add TLV for '%s' to session update",
252           netaddr_to_string(&nbuf, &peer_ip->ip));
253         return -1;
254       }
255
256       _add_prefix(&session->_ext_ip.prefix_modification, &peer_ip->ip);
257     }
258   }
259
260   /* remove missing interface prefixes */
261   avl_for_each_element_safe(&session->_ext_ip.prefix_modification, storage, _node, storage_it) {
262     if (l2net && avl_find(&l2net->local_peer_ips, &storage->prefix)) {
263       /* prefix is still on interface */
264       continue;
265     }
266
267     OONF_INFO(session->log_source, "Removed prefix '%s' for session update",
268               netaddr_to_string(&nbuf, &storage->prefix));
269
270     if (dlep_writer_add_ip_tlv(&session->writer, &storage->prefix, false)) {
271       OONF_WARN(session->log_source, "Cannot add TLV for '%s' to session update",
272         netaddr_to_string(&nbuf, &storage->prefix));
273       return -1;
274     }
275
276     avl_remove(&session->_ext_ip.prefix_modification, &storage->_node);
277     oonf_class_free(&_prefix_class, storage);
278   }
279
280   /* also transmit IP interface addresses */
281   radio_session = dlep_radio_get_session(session);
282   if (radio_session) {
283     os_if = radio_session->interface->interf.udp._if_listener.data;
284     _handle_if_ip(session, &session->_ext_ip.if_ip_v4, os_if->if_linklocal_v4, os_if->if_v4);
285     _handle_if_ip(session, &session->_ext_ip.if_ip_v6, os_if->if_linklocal_v6, os_if->if_v6);
286   }
287   return 0;
288 }
289
290 static int
291 _radio_write_destination_update(struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session,
292     const struct oonf_layer2_neigh_key *neigh) {
293   struct dlep_local_neighbor *dlep_neigh;
294   struct oonf_layer2_neigh *l2neigh;
295   struct oonf_layer2_neighbor_address *l2neigh_ip;
296
297   struct _prefix_storage *storage, *storage_it;
298
299   union oonf_layer2_neigh_key_str nkbuf;
300   struct netaddr_str nbuf1;
301
302   dlep_neigh = dlep_session_get_local_neighbor(session, neigh);
303   if (!dlep_neigh) {
304     OONF_WARN(session->log_source,
305       "Could not find dlep_neighbor for neighbor %s",
306       oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true));
307     return -1;
308   }
309
310   l2neigh = dlep_session_get_l2_from_neighbor(dlep_neigh);
311
312   /* send every attached IP towards the router */
313 //  avl_for_each_element(&dlep_neigh->_ip_prefix_modification, storage, _node) {
314   /* announce newly added interface prefixes */
315   if (l2neigh) {
316     avl_for_each_element(&l2neigh->remote_neighbor_ips, l2neigh_ip, _neigh_node) {
317       if (avl_find(&dlep_neigh->_ip_prefix_modification, &l2neigh_ip->ip)) {
318         /* prefix already known to neighbor */
319         continue;
320       }
321
322       OONF_INFO(session->log_source, "New prefix '%s' for neighbor %s update",
323                 netaddr_to_string(&nbuf1, &l2neigh_ip->ip),
324                 oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true)
325                );
326
327       if (dlep_writer_add_ip_tlv(&session->writer, &l2neigh_ip->ip, true)) {
328         OONF_WARN(session->log_source, "Cannot add TLV for '%s' to neighbor update",
329           netaddr_to_string(&nbuf1, &l2neigh_ip->ip));
330         return -1;
331       }
332
333       _add_prefix(&dlep_neigh->_ip_prefix_modification, &l2neigh_ip->ip);
334     }
335   }
336
337   /* remove missing interface prefixes */
338   avl_for_each_element_safe(&dlep_neigh->_ip_prefix_modification, storage, _node, storage_it) {
339     if (l2neigh && avl_find(&l2neigh->remote_neighbor_ips, &storage->prefix)) {
340       /* prefix is still on neighbor */
341       continue;
342     }
343
344     OONF_INFO(session->log_source, "Removed prefix '%s' for neighbor %s update",
345               netaddr_to_string(&nbuf1, &storage->prefix),
346               oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true)
347              );
348
349     if (dlep_writer_add_ip_tlv(&session->writer, &storage->prefix, false)) {
350       OONF_WARN(session->log_source, "Cannot add TLV for '%s' to neighbor update",
351         netaddr_to_string(&nbuf1, &storage->prefix));
352       return -1;
353     }
354
355     avl_remove(&dlep_neigh->_ip_prefix_modification, &storage->_node);
356     oonf_class_free(&_prefix_class, storage);
357   }
358   return 0;
359 }
360
361 static void
362 _process_session_ip_tlvs(
363   const struct oonf_layer2_origin *origin, struct oonf_layer2_net *l2net, struct netaddr *ip, bool add) {
364   struct oonf_layer2_peer_address *l2addr;
365
366   if (add) {
367     oonf_layer2_net_add_ip(l2net, origin, ip);
368   }
369   else if ((l2addr = oonf_layer2_net_get_local_ip(l2net, ip))) {
370     oonf_layer2_net_remove_ip(l2addr, origin);
371   }
372 }
373
374 static enum dlep_parser_error
375 _router_process_session_update(struct dlep_extension *ext __attribute((unused)), struct dlep_session *session) {
376   struct oonf_layer2_net *l2net;
377   struct netaddr ip;
378   struct dlep_parser_value *value;
379   bool add_ip;
380
381   l2net = oonf_layer2_net_get(session->l2_listener.name);
382   if (!l2net) {
383     return 0;
384   }
385
386   /* ipv4 address */
387   value = dlep_session_get_tlv_value(session, DLEP_IPV4_ADDRESS_TLV);
388   while (value) {
389     if (dlep_reader_ipv4_tlv(&ip, &add_ip, session, value)) {
390       return -1;
391     }
392     _process_session_ip_tlvs(session->l2_origin, l2net, &ip, add_ip);
393     value = dlep_session_get_next_tlv_value(session, value);
394   }
395
396   /* ipv6 address */
397   value = dlep_session_get_tlv_value(session, DLEP_IPV6_ADDRESS_TLV);
398   while (value) {
399     if (dlep_reader_ipv6_tlv(&ip, &add_ip, session, value)) {
400       return -1;
401     }
402     _process_session_ip_tlvs(session->l2_origin, l2net, &ip, add_ip);
403     value = dlep_session_get_next_tlv_value(session, value);
404   }
405
406   /* ipv4 subnet */
407   value = dlep_session_get_tlv_value(session, DLEP_IPV4_SUBNET_TLV);
408   while (value) {
409     if (dlep_reader_ipv4_subnet_tlv(&ip, &add_ip, session, value)) {
410       return -1;
411     }
412     _process_session_ip_tlvs(session->l2_origin, l2net, &ip, add_ip);
413     value = dlep_session_get_next_tlv_value(session, value);
414   }
415
416   /* ipv6 subnet */
417   value = dlep_session_get_tlv_value(session, DLEP_IPV6_SUBNET_TLV);
418   while (value) {
419     if (dlep_reader_ipv6_subnet_tlv(&ip, &add_ip, session, value)) {
420       return -1;
421     }
422     _process_session_ip_tlvs(session->l2_origin, l2net, &ip, add_ip);
423     value = dlep_session_get_next_tlv_value(session, value);
424   }
425   return 0;
426 }
427
428 static void
429 _process_destination_ip_tlv(
430   const struct oonf_layer2_origin *origin, struct oonf_layer2_neigh *l2neigh, struct netaddr *ip, bool add) {
431   struct oonf_layer2_neighbor_address *l2addr;
432   struct oonf_layer2_peer_address *peer_ip;
433   int af;
434
435   af = netaddr_get_address_family(ip);
436   if (add) {
437     if (!oonf_layer2_neigh_has_nexthop(l2neigh, af)) {
438       avl_for_each_element(&l2neigh->network->local_peer_ips, peer_ip, _net_node) {
439         if (netaddr_get_address_family(&peer_ip->ip) == af
440             && netaddr_get_prefix_length(&peer_ip->ip) == netaddr_get_af_maxprefix(af)) {
441           oonf_layer2_neigh_set_nexthop(l2neigh, &peer_ip->ip);
442           break;
443         }
444       }
445     }
446     oonf_layer2_neigh_add_ip(l2neigh, origin, ip);
447   }
448   else if ((l2addr = oonf_layer2_neigh_get_remote_ip(l2neigh, ip))) {
449     oonf_layer2_neigh_remove_ip(l2addr, origin);
450   }
451 }
452
453 static enum dlep_parser_error
454 _router_process_destination_update(struct dlep_extension *ext __attribute((unused)), struct dlep_session *session) {
455   struct oonf_layer2_neigh *l2neigh;
456   struct netaddr ip;
457   struct dlep_parser_value *value;
458   bool add_ip;
459
460   l2neigh = dlep_extension_get_l2_neighbor(session);
461   if (!l2neigh) {
462     return 0;
463   }
464
465   /* ipv4 address */
466   value = dlep_session_get_tlv_value(session, DLEP_IPV4_ADDRESS_TLV);
467   while (value) {
468     if (dlep_reader_ipv4_tlv(&ip, &add_ip, session, value)) {
469       return -1;
470     }
471     _process_destination_ip_tlv(session->l2_origin, l2neigh, &ip, add_ip);
472     value = dlep_session_get_next_tlv_value(session, value);
473   }
474
475   /* ipv6 address */
476   value = dlep_session_get_tlv_value(session, DLEP_IPV6_ADDRESS_TLV);
477   while (value) {
478     if (dlep_reader_ipv6_tlv(&ip, &add_ip, session, value)) {
479       return -1;
480     }
481     _process_destination_ip_tlv(session->l2_origin, l2neigh, &ip, add_ip);
482     value = dlep_session_get_next_tlv_value(session, value);
483   }
484
485   /* ipv4 subnet */
486   value = dlep_session_get_tlv_value(session, DLEP_IPV4_SUBNET_TLV);
487   while (value) {
488     if (dlep_reader_ipv4_subnet_tlv(&ip, &add_ip, session, value)) {
489       return -1;
490     }
491     _process_destination_ip_tlv(session->l2_origin, l2neigh, &ip, add_ip);
492     value = dlep_session_get_next_tlv_value(session, value);
493   }
494
495   /* ipv6 subnet */
496   value = dlep_session_get_tlv_value(session, DLEP_IPV6_SUBNET_TLV);
497   while (value) {
498     if (dlep_reader_ipv6_subnet_tlv(&ip, &add_ip, session, value)) {
499       return -1;
500     }
501     _process_destination_ip_tlv(session->l2_origin, l2neigh, &ip, add_ip);
502     value = dlep_session_get_next_tlv_value(session, value);
503   }
504   return 0;
505 }
506
507 static void
508 _add_prefix(struct avl_tree *tree, struct netaddr *addr) {
509   struct _prefix_storage *storage;
510
511   storage = avl_find_element(tree, addr, storage, _node);
512   if (storage) {
513     return;
514   }
515
516   storage = oonf_class_malloc(&_prefix_class);
517   if (!storage) {
518     return;
519   }
520
521   /* copy key and put into tree */
522   memcpy(&storage->prefix, addr, sizeof(*addr));
523   storage->_node.key = &storage->prefix;
524   avl_insert(tree, &storage->_node);
525 }