581dcc40d85cca5df651b6d6bc3305fcaf38fd75
[olsrd.git] / src / lq_packet.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2003, Andreas T√łnnesen (andreto@olsr.org)
4  *               2004, Thomas Lopatic (thomas@lopatic.de)
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  * $Id: lq_packet.c,v 1.9 2005/01/16 19:49:28 kattemat Exp $
41  */
42
43 #include "olsr_protocol.h"
44 #include "defs.h"
45 #include "interfaces.h"
46 #include "link_set.h"
47 #include "neighbor_table.h"
48 #include "mpr_selector_set.h"
49 #include "mid_set.h"
50 #include "mantissa.h"
51 #include "process_package.h" // XXX - remove
52 #include "two_hop_neighbor_table.h"
53 #include "hysteresis.h"
54
55 static unsigned char msg_buffer[MAXMESSAGESIZE - OLSR_HEADERSIZE];
56
57 static void
58 create_lq_hello(struct lq_hello_message *lq_hello, struct interface *outif)
59 {
60   struct lq_hello_neighbor *neigh;
61   struct link_entry *walker;
62
63   // initialize the static fields
64
65   lq_hello->comm.type = LQ_HELLO_MESSAGE;
66   lq_hello->comm.vtime = me_to_double(outif->valtimes.hello);
67   lq_hello->comm.size = 0;
68
69   COPY_IP(&lq_hello->comm.orig, &main_addr);
70
71   lq_hello->comm.ttl = 1;
72   lq_hello->comm.hops = 0;
73   lq_hello->comm.seqno = get_msg_seqno();
74
75   lq_hello->htime = me_to_double(outif->hello_etime);
76   lq_hello->will = olsr_cnf->willingness;
77
78   lq_hello->neigh = NULL;
79   
80   // loop through the link set
81
82   for (walker = link_set; walker != NULL; walker = walker->next)
83     {
84       // allocate a neighbour entry
85
86       neigh = olsr_malloc(sizeof (struct lq_hello_neighbor), "Build LQ_HELLO");
87       
88       // a) this neighbor interface IS NOT visible via the output interface
89
90       if(!COMP_IP(&walker->local_iface_addr, &outif->ip_addr))
91         neigh->link_type = UNSPEC_LINK;
92       
93       // b) this neighbor interface IS visible via the output interface
94
95       else
96         neigh->link_type = lookup_link_status(walker);
97
98       // set the entry's link quality
99
100       neigh->link_quality = walker->loss_link_quality;
101       neigh->neigh_link_quality = walker->neigh_link_quality;
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->status == SYM)
109         neigh->neigh_type = SYM_NEIGH;
110
111       else if (walker->neighbor->status == NOT_SYM)
112         neigh->neigh_type = NOT_NEIGH;
113   
114       // set the entry's neighbour interface address
115
116       COPY_IP(&neigh->addr, &walker->neighbor_iface_addr);
117       
118       // queue the neighbour entry
119
120       neigh->next = lq_hello->neigh;
121       lq_hello->neigh = neigh;
122     }
123 }
124
125 static void
126 destroy_lq_hello(struct lq_hello_message *lq_hello)
127 {
128   struct lq_hello_neighbor *walker, *aux;
129
130   // loop through the queued neighbour entries and free them
131
132   for (walker = lq_hello->neigh; walker != NULL; walker = aux)
133     {
134       aux = walker->next;
135       free(walker);
136     }
137
138   lq_hello->neigh = NULL;
139 }
140
141 static void
142 create_lq_tc(struct lq_tc_message *lq_tc, struct interface *outif)
143 {
144   struct lq_tc_neighbor *neigh;
145   int i;
146   struct neighbor_entry *walker;
147   struct link_entry *link;
148
149   // initialize the static fields
150
151   lq_tc->comm.type = LQ_TC_MESSAGE;
152   lq_tc->comm.vtime = me_to_double(outif->valtimes.tc);
153   lq_tc->comm.size = 0;
154
155   COPY_IP(&lq_tc->comm.orig, &main_addr);
156
157   lq_tc->comm.ttl = MAX_TTL;
158   lq_tc->comm.hops = 0;
159   lq_tc->comm.seqno = get_msg_seqno();
160
161   COPY_IP(&lq_tc->from, &main_addr);
162
163   lq_tc->ansn = ansn;
164
165   lq_tc->neigh = NULL;
166  
167   // loop through all neighbours
168   
169   for(i = 0; i < HASHSIZE; i++)
170     {
171       for(walker = neighbortable[i].next; walker != &neighbortable[i];
172           walker = walker->next)
173         {
174           // only consider symmetric neighbours
175
176           if(walker->status != SYM)
177             continue;
178
179           // TC redundancy == 1: only consider MPRs and MPR selectors
180
181           if (olsr_cnf->tc_redundancy == 1 && !walker->is_mpr &&
182               olsr_lookup_mprs_set(&walker->neighbor_main_addr) == NULL)
183             continue;
184
185           // TC redundancy == 0: only consider MPR selectors
186
187           else if (olsr_cnf->tc_redundancy == 0 &&
188                    olsr_lookup_mprs_set(&walker->neighbor_main_addr) == NULL)
189             continue;
190
191           // allocate a neighbour entry
192           
193           neigh = olsr_malloc(sizeof (struct lq_tc_neighbor), "Build LQ_TC");
194                 
195           // set the entry's main address
196
197           COPY_IP(&neigh->main, &walker->neighbor_main_addr);
198
199           // set the entry's link quality
200
201           link = olsr_neighbor_best_link(&neigh->main);
202
203           neigh->link_quality = link->loss_link_quality;
204           neigh->neigh_link_quality = link->neigh_link_quality;
205
206           // queue the neighbour entry
207
208           neigh->next = lq_tc->neigh;
209           lq_tc->neigh = neigh;
210         }
211     }
212 }
213
214 static void
215 destroy_lq_tc(struct lq_tc_message *lq_tc)
216 {
217   struct lq_tc_neighbor *walker, *aux;
218
219   // loop through the queued neighbour entries and free them
220
221   for (walker = lq_tc->neigh; walker != NULL; walker = aux)
222     {
223       aux = walker->next;
224       free(walker);
225     }
226 }
227
228 static int common_size(void)
229 {
230   // return the size of the header shared by all OLSR messages
231
232   return (olsr_cnf->ip_version == AF_INET) ?
233     sizeof (struct olsr_header_v4) : sizeof (struct olsr_header_v6);
234 }
235
236 static void serialize_common(struct olsr_common *comm)
237 {
238   struct olsr_header_v4 *olsr_head_v4;
239   struct olsr_header_v6 *olsr_head_v6;
240
241   // serialize an IPv4 OLSR message header
242
243   if (olsr_cnf->ip_version == AF_INET)
244     {
245       olsr_head_v4 = (struct olsr_header_v4 *)msg_buffer;
246
247       olsr_head_v4->type = comm->type;
248       olsr_head_v4->vtime = double_to_me(comm->vtime);
249       olsr_head_v4->size = htons(comm->size);
250
251       COPY_IP(&olsr_head_v4->orig, &comm->orig);
252
253       olsr_head_v4->ttl = comm->ttl;
254       olsr_head_v4->hops = comm->hops;
255       olsr_head_v4->seqno = htons(comm->seqno);
256
257       return;
258     }
259
260   // serialize an IPv6 OLSR message header
261
262   olsr_head_v6 = (struct olsr_header_v6 *)msg_buffer;
263
264   olsr_head_v6->type = comm->type;
265   olsr_head_v6->vtime = double_to_me(comm->vtime);
266   olsr_head_v6->size = htons(comm->size);
267
268   COPY_IP(&olsr_head_v6->orig, &comm->orig);
269
270   olsr_head_v6->ttl = comm->ttl;
271   olsr_head_v6->hops = comm->hops;
272   olsr_head_v6->seqno = htons(comm->seqno);
273 }
274
275 static void
276 serialize_lq_hello(struct lq_hello_message *lq_hello, struct interface *outif)
277 {
278   int off, rem, size, req;
279   struct lq_hello_header *head;
280   struct lq_hello_info_header *info_head;
281   struct lq_hello_neighbor *neigh;
282   unsigned char *buff;
283   int is_first;
284   int i, j;
285
286   if (lq_hello == NULL || outif == NULL)
287     return;
288
289   // leave space for the OLSR header
290
291   off = common_size();
292
293   // initialize the LQ_HELLO header
294
295   head = (struct lq_hello_header *)(msg_buffer + off);
296
297   head->reserved = 0;
298   head->htime = double_to_me(lq_hello->htime);
299   head->will = lq_hello->will; 
300
301   // 'off' is the offset of the byte following the LQ_HELLO header
302
303   off += sizeof (struct lq_hello_header);
304
305   // our work buffer starts at 'off'...
306
307   buff = msg_buffer + off;
308
309   // ... that's why we start with a 'size' of 0 and subtract 'off' from
310   // the remaining bytes in the output buffer
311
312   size = 0;
313   rem = net_outbuffer_bytes_left(outif) - off;
314
315   // initially, we want to put at least an info header, an IP address,
316   // and the corresponding link quality into the message
317
318   if (rem < sizeof (struct lq_hello_info_header) + ipsize + 4)
319   {
320     net_output(outif);
321
322     rem = net_outbuffer_bytes_left(outif) - off;
323   }
324
325   info_head = NULL;
326
327   // iterate through all neighbor types ('i') and all link types ('j')
328
329   for (i = 0; i <= MAX_NEIGH; i++) 
330     {
331       for(j = 0; j <= MAX_LINK; j++)
332         {
333           if(j == HIDE_LINK)
334             continue;
335
336           is_first = 1;
337
338           // loop through neighbors
339
340           for (neigh = lq_hello->neigh; neigh != NULL; neigh = neigh->next)
341             {  
342               if (neigh->neigh_type != i || neigh->link_type != j)
343                 continue;
344
345               // we need space for an IP address plus link quality
346               // information
347
348               req = ipsize + 4;
349
350               // no, we also need space for an info header, as this is the
351               // first neighbor with the current neighor type and link type
352
353               if (is_first != 0)
354                 req += sizeof (struct lq_hello_info_header);
355
356               // we do not have enough space left
357
358               if (size + req > rem)
359                 {
360                   // finalize the OLSR header
361
362                   lq_hello->comm.size = size + off;
363
364                   serialize_common((struct olsr_common *)lq_hello);
365
366                   // finalize the info header
367
368                   info_head->size =
369                     ntohs(buff + size - (unsigned char *)info_head);
370                               
371                   // output packet
372
373                   net_outbuffer_push(outif, msg_buffer, size + off);
374
375                   net_output(outif);
376
377                   // move to the beginning of the buffer
378
379                   size = 0;
380                   rem = net_outbuffer_bytes_left(outif) - off;
381
382                   // we need a new info header
383
384                   is_first = 1;
385                 }
386
387               // create a new info header
388
389               if (is_first != 0)
390                 {
391                   info_head = (struct lq_hello_info_header *)(buff + size);
392                   size += sizeof (struct lq_hello_info_header);
393
394                   info_head->reserved = 0;
395                   info_head->link_code = CREATE_LINK_CODE(i, j);
396                 }
397
398               // add the current neighbor's IP address
399
400               COPY_IP(buff + size, &neigh->addr);
401               size += ipsize;
402
403               // add the corresponding link quality
404
405               buff[size++] = (unsigned char)(neigh->link_quality * 255);
406               buff[size++] = (unsigned char)(neigh->neigh_link_quality * 255);
407
408               // pad
409
410               buff[size++] = 0;
411               buff[size++] = 0;
412
413               is_first = 0;
414             }
415
416           // finalize the info header, if there are any neighbors with the
417           // current neighbor type and link type
418
419           if (is_first == 0)
420             info_head->size = ntohs(buff + size - (unsigned char *)info_head);
421         }
422     }
423
424   // finalize the OLSR header
425
426   lq_hello->comm.size = size + off;
427
428   serialize_common((struct olsr_common *)lq_hello);
429
430   // move the message to the output buffer
431
432   net_outbuffer_push(outif, msg_buffer, size + off);
433 }
434
435 static void
436 serialize_lq_tc(struct lq_tc_message *lq_tc, struct interface *outif)
437 {
438   int off, rem, size;
439   struct lq_tc_header *head;
440   struct lq_tc_neighbor *neigh;
441   unsigned char *buff;
442
443   if (lq_tc == NULL || outif == NULL)
444     return;
445
446   // leave space for the OLSR header
447
448   off = common_size();
449
450   // initialize the LQ_TC header
451
452   head = (struct lq_tc_header *)(msg_buffer + off);
453
454   head->ansn = htons(lq_tc->ansn);
455   head->reserved = 0;
456
457   // 'off' is the offset of the byte following the LQ_TC header
458
459   off += sizeof (struct lq_tc_header);
460
461   // our work buffer starts at 'off'...
462
463   buff = msg_buffer + off;
464
465   // ... that's why we start with a 'size' of 0 and subtract 'off' from
466   // the remaining bytes in the output buffer
467
468   size = 0;
469   rem = net_outbuffer_bytes_left(outif) - off;
470
471   // initially, we want to put at least an IP address and the corresponding
472   // link quality into the message
473
474   if (rem < ipsize + 4)
475   {
476     net_output(outif);
477
478     rem = net_outbuffer_bytes_left(outif) - off;
479   }
480
481   // loop through neighbors
482
483   for (neigh = lq_tc->neigh; neigh != NULL; neigh = neigh->next)
484     {  
485       // we need space for an IP address plus link quality
486       // information
487
488       if (size + ipsize + 4 > rem)
489         {
490           // finalize the OLSR header
491
492           lq_tc->comm.size = size + off;
493
494           serialize_common((struct olsr_common *)lq_tc);
495
496           // output packet
497
498           net_outbuffer_push(outif, msg_buffer, size + off);
499
500           net_output(outif);
501
502           // move to the beginning of the buffer
503
504           size = 0;
505           rem = net_outbuffer_bytes_left(outif) - off;
506         }
507
508       // add the current neighbor's IP address
509
510       COPY_IP(buff + size, &neigh->main);
511       size += ipsize;
512
513       // add the corresponding link quality
514
515       buff[size++] = (unsigned char)(neigh->link_quality * 255);
516       buff[size++] = (unsigned char)(neigh->neigh_link_quality * 255);
517
518       // pad
519
520       buff[size++] = 0;
521       buff[size++] = 0;
522     }
523
524   // finalize the OLSR header
525
526   lq_tc->comm.size = size + off;
527
528   serialize_common((struct olsr_common *)lq_tc);
529
530   net_outbuffer_push(outif, msg_buffer, size + off);
531 }
532
533 static void *deserialize_common(struct olsr_common *comm, void *ser)
534 {
535   struct olsr_header_v4 *olsr_head_v4;
536   struct olsr_header_v6 *olsr_head_v6;
537
538   // deserialize an IPv4 OLSR message header
539
540   if (olsr_cnf->ip_version == AF_INET)
541     {
542       olsr_head_v4 = (struct olsr_header_v4 *)ser;
543
544       comm->type = olsr_head_v4->type;
545       comm->vtime = me_to_double(olsr_head_v4->vtime);
546       comm->size = ntohs(olsr_head_v4->size);
547
548       COPY_IP(&comm->orig, &olsr_head_v4->orig);
549
550       comm->ttl = olsr_head_v4->ttl;
551       comm->hops = olsr_head_v4->hops;
552       comm->seqno = ntohs(olsr_head_v4->seqno);
553
554       return (void *)(olsr_head_v4 + 1);
555     }
556
557   // deserialize an IPv6 OLSR message header
558
559   olsr_head_v6 = (struct olsr_header_v6 *)ser;
560
561   comm->type = olsr_head_v6->type;
562   comm->vtime = me_to_double(olsr_head_v6->vtime);
563   comm->size = ntohs(olsr_head_v6->size);
564
565   COPY_IP(&comm->orig, &olsr_head_v6->orig);
566
567   comm->ttl = olsr_head_v6->ttl;
568   comm->hops = olsr_head_v6->hops;
569   comm->seqno = ntohs(olsr_head_v6->seqno);
570
571   return (void *)(olsr_head_v6 + 1);
572 }
573
574 static void
575 deserialize_lq_hello(struct lq_hello_message *lq_hello, void *ser)
576 {
577   struct lq_hello_header *head;
578   struct lq_hello_info_header *info_head;
579   unsigned char *curr, *limit, *limit2;
580   struct lq_hello_neighbor *neigh;
581   
582   lq_hello->neigh = NULL;
583
584   if (ser == NULL)
585     return;
586
587   head = (struct lq_hello_header *)
588     deserialize_common((struct olsr_common *)lq_hello, ser);
589
590   if (lq_hello->comm.type != LQ_HELLO_MESSAGE)
591     return;
592
593   limit = ((unsigned char *)ser) + lq_hello->comm.size;
594
595   lq_hello->htime = me_to_double(head->htime);
596   lq_hello->will = head->will;
597
598   lq_hello->neigh = NULL;
599
600   curr = (unsigned char *)(head + 1);
601
602   while (curr < limit)
603     {
604       info_head = (struct lq_hello_info_header *)curr;
605
606       limit2 = curr + ntohs(info_head->size);
607
608       curr = (unsigned char *)(info_head + 1);
609       
610       while (curr < limit2)
611         {
612           neigh = olsr_malloc(sizeof (struct lq_hello_neighbor),
613                               "LQ_HELLO deserialization");
614
615           COPY_IP(&neigh->addr, curr);
616           curr += ipsize;
617
618           neigh->link_quality = (double)*curr++ / 255.0;
619           neigh->neigh_link_quality = (double)*curr++ / 255.0;
620
621           curr += 2;
622
623           neigh->link_type = EXTRACT_LINK(info_head->link_code);
624           neigh->neigh_type = EXTRACT_STATUS(info_head->link_code);
625
626           neigh->next = lq_hello->neigh;
627           lq_hello->neigh = neigh;
628         }
629     }
630 }
631
632 static void
633 deserialize_lq_tc(struct lq_tc_message *lq_tc, void *ser,
634                   union olsr_ip_addr *from)
635 {
636   struct lq_tc_header *head;
637   union olsr_ip_addr *addr;
638   unsigned char *curr, *limit;
639   struct lq_tc_neighbor *neigh;
640
641   lq_tc->neigh = NULL;
642
643   if (ser == NULL)
644     return;
645
646   head = (struct lq_tc_header *)
647     deserialize_common((struct olsr_common *)lq_tc, ser);
648
649   if (lq_tc->comm.type != LQ_TC_MESSAGE)
650     return;
651
652   limit = ((unsigned char *)ser) + lq_tc->comm.size;
653
654   addr = mid_lookup_main_addr(from);
655
656   if (addr == 0)
657     COPY_IP(&lq_tc->from, from);
658
659   else
660     COPY_IP(&lq_tc->from, addr);
661
662   lq_tc->ansn =  ntohs(head->ansn);
663
664   lq_tc->neigh = NULL;
665
666   curr = (unsigned char *)(head + 1);
667
668   while (curr < limit)
669     {
670       neigh = olsr_malloc(sizeof (struct lq_tc_neighbor),
671                           "LQ_TC deserialization");
672
673       COPY_IP(&neigh->main, curr);
674       curr += ipsize;
675
676       neigh->link_quality = (double)*curr++ / 255.0;
677       neigh->neigh_link_quality = (double)*curr++ / 255.0;
678
679       curr += 2;
680
681       neigh->next = lq_tc->neigh;
682       lq_tc->neigh = neigh;
683     }
684 }
685
686 void
687 olsr_output_lq_hello(void *para)
688 {
689   struct lq_hello_message lq_hello;
690   struct interface *outif = (struct interface *)para;
691
692   // create LQ_HELLO in internal format
693
694   create_lq_hello(&lq_hello, outif);
695
696   // convert internal format into transmission format, send it
697
698   serialize_lq_hello(&lq_hello, outif);
699
700   // destroy internal format
701
702   destroy_lq_hello(&lq_hello);
703
704   if(net_output_pending(outif))
705     net_output(outif);
706 }
707
708 void
709 olsr_output_lq_tc(void *para)
710 {
711   static int prev_empty = 1;
712   struct lq_tc_message lq_tc;
713   struct interface *outif = (struct interface *)para;
714
715   // create LQ_TC in internal format
716
717   create_lq_tc(&lq_tc, outif);
718
719   // a) the message is not empty
720
721   if (lq_tc.neigh != NULL)
722     {
723       prev_empty = 0;
724
725       // convert internal format into transmission format, send it
726
727       serialize_lq_tc(&lq_tc, outif);
728     }
729
730   // b) this is the first empty message
731
732   else if (prev_empty == 0)
733     {
734       // initialize timer
735
736       send_empty_tc = GET_TIMESTAMP((max_tc_vtime * 3) * 1000);
737
738       prev_empty = 1;
739
740       // convert internal format into transmission format, send it
741
742       serialize_lq_tc(&lq_tc, outif);
743     }
744
745   // c) this is not the first empty message, send if timer hasn't fired
746
747   else if (!TIMED_OUT(send_empty_tc))
748     serialize_lq_tc(&lq_tc, outif);
749
750   // destroy internal format
751
752   destroy_lq_tc(&lq_tc);
753
754   if(net_output_pending(outif) && TIMED_OUT(fwdtimer[outif->if_nr]))
755     set_buffer_timer(outif);
756 }
757
758 static void
759 process_lq_hello(struct lq_hello_message *lq_hello, struct interface *inif,
760                  union olsr_ip_addr *from)
761 {
762   struct hello_message hello;
763   struct lq_hello_neighbor *neigh;
764   struct hello_neighbor *new_neigh;
765
766   // XXX - translation is ugly; everybody should use lq_hello_message :-)
767
768   // move the static fields from LQ_HELLO to HELLO
769
770   hello.vtime = lq_hello->comm.vtime;
771   hello.htime = lq_hello->htime;
772
773   COPY_IP(&hello.source_addr, &lq_hello->comm.orig);
774
775   hello.packet_seq_number = lq_hello->comm.seqno;
776   hello.hop_count = lq_hello->comm.hops;
777   hello.ttl = lq_hello->comm.ttl;
778   hello.willingness = lq_hello->will;
779
780   hello.neighbors = NULL;
781
782   // move all LQ_HELLO neighbours to HELLO
783
784   for (neigh = lq_hello->neigh; neigh != NULL; neigh = neigh->next)
785     {
786       // allocate HELLO neighbour
787
788       new_neigh = olsr_malloc(sizeof (struct hello_neighbor),
789                               "LQ_HELLO translation");
790
791       // copy fields
792
793       new_neigh->status = neigh->neigh_type;
794       new_neigh->link = neigh->link_type;
795       new_neigh->link_quality = neigh->link_quality;
796       new_neigh->neigh_link_quality = neigh->neigh_link_quality;
797
798       COPY_IP(&new_neigh->address, &neigh->addr);
799
800       // queue HELLO neighbour
801
802       new_neigh->next = hello.neighbors;
803       hello.neighbors = new_neigh;
804     }
805
806   olsr_hello_tap(&hello, inif, from);
807 }
808
809 static void
810 process_lq_tc(struct lq_tc_message *lq_tc, struct interface *inif,
811               union olsr_ip_addr *from, union olsr_message *ser)
812 {
813   struct tc_message tc;
814   struct lq_tc_neighbor *neigh;
815   struct tc_mpr_addr *new_neigh;
816
817   // XXX - translation is ugly; everybody should use lq_tc_message :-)
818
819   // move the static fields from LQ_TC to TC
820
821   tc.vtime = lq_tc->comm.vtime;
822
823   COPY_IP(&tc.source_addr, &lq_tc->from);
824   COPY_IP(&tc.originator, &lq_tc->comm.orig);
825
826   tc.packet_seq_number = lq_tc->comm.seqno;
827   tc.hop_count = lq_tc->comm.hops;
828   tc.ttl = lq_tc->comm.ttl;
829   tc.ansn = lq_tc->ansn;
830
831   tc.multipoint_relay_selector_address = NULL;
832
833   // move all LQ_TC neighbours to TC
834
835   for (neigh = lq_tc->neigh; neigh != NULL; neigh = neigh->next)
836     {
837       // allocate TC neighbour
838
839       new_neigh = olsr_malloc(sizeof (struct tc_mpr_addr),
840                               "LQ_TC translation");
841
842       // copy fields
843
844       new_neigh->link_quality = neigh->link_quality;
845       new_neigh->neigh_link_quality = neigh->neigh_link_quality;
846
847       COPY_IP(&new_neigh->address, &neigh->main);
848
849       // queue TC neighbour
850
851       new_neigh->next = tc.multipoint_relay_selector_address;
852       tc.multipoint_relay_selector_address = new_neigh;
853     }
854
855   olsr_tc_tap(&tc, inif, from, ser);
856 }
857
858 void
859 olsr_input_lq_hello(union olsr_message *ser,
860                     struct interface *inif,
861                     union olsr_ip_addr *from)
862 {
863   struct lq_hello_message lq_hello;
864
865   // convert received packet from transmission format into internal format
866
867   deserialize_lq_hello(&lq_hello, ser);
868
869   // process internal format
870
871   process_lq_hello(&lq_hello, inif, from);
872
873   // destroy internal format
874
875   destroy_lq_hello(&lq_hello);
876 }
877
878 void
879 olsr_input_lq_tc(union olsr_message *ser, struct interface *inif,
880                  union olsr_ip_addr *from)
881 {
882   struct lq_tc_message lq_tc;
883   
884   // convert received packet from transmission format into internal format
885
886   deserialize_lq_tc(&lq_tc, ser, from);
887
888   // process internal format
889
890   process_lq_tc(&lq_tc, inif, from, ser);
891
892   // destroy internal format
893
894   destroy_lq_tc(&lq_tc);
895 }