move ansn handling into tc_set.c
[olsrd.git] / src / lq_packet.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 "ipcalc.h"
43 #include "olsr_protocol.h"
44 #include "defs.h"
45 #include "lq_packet.h"
46 #include "interfaces.h"
47 #include "link_set.h"
48 #include "neighbor_table.h"
49 #include "mid_set.h"
50 #include "olsr_time.h"
51 #include "process_package.h"    // XXX - remove
52 #include "olsr.h"
53 #include "net_olsr.h"
54 #include "lq_plugin.h"
55 #include "olsr_logging.h"
56
57 #include <stdlib.h>
58
59 bool lq_tc_pending = false;
60
61 static unsigned char msg_buffer[MAXMESSAGESIZE - OLSR_HEADERSIZE];
62
63 static void
64 create_lq_hello(struct lq_hello_message *lq_hello, struct interface *outif)
65 {
66   struct link_entry *walker;
67
68   // initialize the static fields
69
70   lq_hello->comm.type = olsr_get_Hello_MessageId();
71   lq_hello->comm.vtime = outif->hello_validity;
72   lq_hello->comm.size = 0;
73
74   lq_hello->comm.orig = olsr_cnf->router_id;
75
76   lq_hello->comm.ttl = 1;
77   lq_hello->comm.hops = 0;
78
79   lq_hello->htime = outif->hello_interval;
80   lq_hello->will = olsr_cnf->willingness;
81
82   lq_hello->neigh = NULL;
83
84   // loop through the link set
85
86   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
87
88     // allocate a neighbour entry
89     struct lq_hello_neighbor *neigh = olsr_malloc_lq_hello_neighbor();
90
91     // a) this neighbor interface IS NOT visible via the output interface
92     if (olsr_ipcmp(&walker->local_iface_addr, &outif->ip_addr) != 0)
93       neigh->link_type = UNSPEC_LINK;
94
95     // b) this neighbor interface IS visible via the output interface
96
97     else
98       neigh->link_type = lookup_link_status(walker);
99
100     // set the entry's link quality
101     olsr_copy_hello_lq(neigh, walker);
102
103     // set the entry's neighbour type
104
105     if (walker->neighbor->is_mpr)
106       neigh->neigh_type = MPR_NEIGH;
107
108     else if (walker->neighbor->is_sym)
109       neigh->neigh_type = SYM_NEIGH;
110
111     else
112       neigh->neigh_type = NOT_NEIGH;
113
114     // set the entry's neighbour interface address
115
116     neigh->addr = walker->neighbor_iface_addr;
117
118     // queue the neighbour entry
119     neigh->next = lq_hello->neigh;
120     lq_hello->neigh = neigh;
121
122   }
123   OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
124 }
125
126 void
127 destroy_lq_hello(struct lq_hello_message *lq_hello)
128 {
129   struct lq_hello_neighbor *walker, *aux;
130
131   // loop through the queued neighbour entries and free them
132
133   for (walker = lq_hello->neigh; walker != NULL; walker = aux) {
134     aux = walker->next;
135     olsr_free_lq_hello_neighbor(walker);
136   }
137
138   lq_hello->neigh = NULL;
139 }
140
141 static int
142 common_size(void)
143 {
144   // return the size of the header shared by all OLSR messages
145
146   return (olsr_cnf->ip_version == AF_INET) ? sizeof(struct olsr_header_v4) : sizeof(struct olsr_header_v6);
147 }
148
149 static void
150 serialize_common(struct olsr_common *comm)
151 {
152   if (olsr_cnf->ip_version == AF_INET) {
153     // serialize an IPv4 OLSR message header
154     struct olsr_header_v4 *olsr_head_v4 = (struct olsr_header_v4 *)msg_buffer;
155
156     olsr_head_v4->type = comm->type;
157     olsr_head_v4->vtime = reltime_to_me(comm->vtime);
158     olsr_head_v4->size = htons(comm->size);
159
160     olsr_head_v4->orig = comm->orig.v4.s_addr;
161
162     olsr_head_v4->ttl = comm->ttl;
163     olsr_head_v4->hops = comm->hops;
164     olsr_head_v4->seqno = htons(get_msg_seqno());
165   } else {
166     // serialize an IPv6 OLSR message header
167     struct olsr_header_v6 *olsr_head_v6 = (struct olsr_header_v6 *)msg_buffer;
168
169     olsr_head_v6->type = comm->type;
170     olsr_head_v6->vtime = reltime_to_me(comm->vtime);
171     olsr_head_v6->size = htons(comm->size);
172
173     memcpy(&olsr_head_v6->orig, &comm->orig.v6.s6_addr, sizeof(olsr_head_v6->orig));
174
175     olsr_head_v6->ttl = comm->ttl;
176     olsr_head_v6->hops = comm->hops;
177     olsr_head_v6->seqno = htons(get_msg_seqno());
178   }
179 }
180
181 static void
182 serialize_lq_hello(struct lq_hello_message *lq_hello, struct interface *outif)
183 {
184   static const int LINK_ORDER[] = { SYM_LINK, UNSPEC_LINK, ASYM_LINK, LOST_LINK };
185   int rem, size, req, expected_size = 0;
186   struct lq_hello_info_header *info_head;
187   struct lq_hello_neighbor *neigh;
188   unsigned char *buff;
189   bool is_first;
190   int i;
191
192   // leave space for the OLSR header
193   int off = common_size();
194
195   // initialize the LQ_HELLO header
196
197   struct lq_hello_header *head = (struct lq_hello_header *)(msg_buffer + off);
198
199   head->reserved = 0;
200   head->htime = reltime_to_me(lq_hello->htime);
201   head->will = lq_hello->will;
202
203   // 'off' is the offset of the byte following the LQ_HELLO header
204
205   off += sizeof(struct lq_hello_header);
206
207   // our work buffer starts at 'off'...
208
209   buff = msg_buffer + off;
210
211   // ... that's why we start with a 'size' of 0 and subtract 'off' from
212   // the remaining bytes in the output buffer
213
214   size = 0;
215   rem = net_outbuffer_bytes_left(outif) - off;
216
217   /*
218    * Initially, we want to put the complete lq_hello into the message.
219    * For this flush the output buffer (if there are some bytes in).
220    * This is a hack/fix, which prevents message fragementation resulting
221    * in instable links. The ugly lq/genmsg code should be reworked anyhow.
222    */
223   if (0 < net_output_pending(outif)) {
224     for (i = 0; i <= MAX_NEIGH; i++) {
225       unsigned int j;
226       for (j = 0; j < ARRAYSIZE(LINK_ORDER); j++) {
227         is_first = true;
228         for (neigh = lq_hello->neigh; neigh != NULL; neigh = neigh->next) {
229           if (0 == i && 0 == j)
230             expected_size += olsr_cnf->ipsize + olsr_sizeof_TCLQ();
231           if (neigh->neigh_type == i && neigh->link_type == LINK_ORDER[j]) {
232             if (is_first) {
233               expected_size += sizeof(struct lq_hello_info_header);
234               is_first = false;
235             }
236           }
237         }
238       }
239     }
240   }
241
242   if (rem < expected_size) {
243     net_output(outif);
244     rem = net_outbuffer_bytes_left(outif) - off;
245   }
246
247   info_head = NULL;
248
249   // iterate through all neighbor types ('i') and all link types ('j')
250
251   for (i = 0; i <= MAX_NEIGH; i++) {
252     unsigned int j;
253     for (j = 0; j < ARRAYSIZE(LINK_ORDER); j++) {
254       is_first = true;
255
256       // loop through neighbors
257
258       for (neigh = lq_hello->neigh; neigh != NULL; neigh = neigh->next) {
259         if (neigh->neigh_type != i || neigh->link_type != LINK_ORDER[j])
260           continue;
261
262         // we need space for an IP address plus link quality
263         // information
264
265         req = olsr_cnf->ipsize + 4;
266
267         // no, we also need space for an info header, as this is the
268         // first neighbor with the current neighor type and link type
269
270         if (is_first)
271           req += sizeof(struct lq_hello_info_header);
272
273         // we do not have enough space left
274
275         // force signed comparison
276
277         if ((int)(size + req) > rem) {
278           // finalize the OLSR header
279
280           lq_hello->comm.size = size + off;
281
282           serialize_common(&lq_hello->comm);
283
284           // finalize the info header
285
286           info_head->size = ntohs(buff + size - (unsigned char *)info_head);
287
288           // output packet
289
290           net_outbuffer_push(outif, msg_buffer, size + off);
291
292           net_output(outif);
293
294           // move to the beginning of the buffer
295
296           size = 0;
297           rem = net_outbuffer_bytes_left(outif) - off;
298
299           // we need a new info header
300
301           is_first = true;
302         }
303         // create a new info header
304
305         if (is_first) {
306           info_head = (struct lq_hello_info_header *)(buff + size);
307           size += sizeof(struct lq_hello_info_header);
308
309           info_head->reserved = 0;
310           info_head->link_code = CREATE_LINK_CODE(i, LINK_ORDER[j]);
311         }
312         // add the current neighbor's IP address
313
314         genipcopy(buff + size, &neigh->addr);
315         size += olsr_cnf->ipsize;
316
317         // add the corresponding link quality
318         size += olsr_serialize_hello_lq_pair(&buff[size], neigh);
319
320         is_first = false;
321       }
322
323       // finalize the info header, if there are any neighbors with the
324       // current neighbor type and link type
325
326       if (!is_first)
327         info_head->size = ntohs(buff + size - (unsigned char *)info_head);
328     }
329   }
330
331   // finalize the OLSR header
332
333   lq_hello->comm.size = size + off;
334
335   serialize_common((struct olsr_common *)lq_hello);
336
337   // move the message to the output buffer
338
339   net_outbuffer_push(outif, msg_buffer, size + off);
340 }
341
342 void
343 olsr_output_lq_hello(void *para)
344 {
345   struct lq_hello_message lq_hello;
346   struct interface *outif = para;
347
348   if (outif == NULL) {
349     return;
350   }
351   // create LQ_HELLO in internal format
352   create_lq_hello(&lq_hello, outif);
353
354   // convert internal format into transmission format, send it
355   serialize_lq_hello(&lq_hello, outif);
356
357   // destroy internal format
358   destroy_lq_hello(&lq_hello);
359
360   if (net_output_pending(outif)) {
361     if (outif->immediate_send_tc) {
362       set_buffer_timer(outif);
363     } else {
364       net_output(outif);
365     }
366   }
367 }
368 /*
369  * Local Variables:
370  * c-basic-offset: 2
371  * indent-tabs-mode: nil
372  * End:
373  */