sgw: send sgw HNAs with zero bandwidth after local gw has gone away
[olsrd.git] / src / build_msg.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 "build_msg.h"
43 #include "ipcalc.h"
44 #include "olsr.h"
45 #include "log.h"
46 #include "mantissa.h"
47 #include "net_olsr.h"
48 #include "gateway.h"
49
50 #define BMSG_DBGLVL 5
51
52 #define OLSR_IPV4_HDRSIZE          12
53 #define OLSR_IPV6_HDRSIZE          24
54
55 #define OLSR_HELLO_IPV4_HDRSIZE    (OLSR_IPV4_HDRSIZE + 4)
56 #define OLSR_HELLO_IPV6_HDRSIZE    (OLSR_IPV6_HDRSIZE + 4)
57 #define OLSR_TC_IPV4_HDRSIZE       (OLSR_IPV4_HDRSIZE + 4)
58 #define OLSR_TC_IPV6_HDRSIZE       (OLSR_IPV6_HDRSIZE + 4)
59 #define OLSR_MID_IPV4_HDRSIZE      OLSR_IPV4_HDRSIZE
60 #define OLSR_MID_IPV6_HDRSIZE      OLSR_IPV6_HDRSIZE
61 #define OLSR_HNA_IPV4_HDRSIZE      OLSR_IPV4_HDRSIZE
62 #define OLSR_HNA_IPV6_HDRSIZE      OLSR_IPV6_HDRSIZE
63
64 static void check_buffspace(int msgsize, int buffsize, const char *type);
65
66 /* All these functions share this buffer */
67
68 static uint32_t msg_buffer_align[(MAXMESSAGESIZE - OLSR_HEADERSIZE)/sizeof(uint32_t) + 1];
69 static uint8_t *msg_buffer = (uint8_t *)msg_buffer_align;
70
71 static uint32_t send_empty_tc;          /* TC empty message sending */
72
73 /* Prototypes for internal functions */
74
75 /* IPv4 */
76
77 static bool serialize_hello4(struct hello_message *, struct interface_olsr *);
78
79 static bool serialize_tc4(struct tc_message *, struct interface_olsr *);
80
81 static bool serialize_mid4(struct interface_olsr *);
82
83 static bool serialize_hna4(struct ip_prefix_list *h, struct interface_olsr *, bool is_zero_bw);
84
85 /* IPv6 */
86
87 static bool serialize_hello6(struct hello_message *, struct interface_olsr *);
88
89 static bool serialize_tc6(struct tc_message *, struct interface_olsr *);
90
91 static bool serialize_mid6(struct interface_olsr *);
92
93 static bool serialize_hna6(struct ip_prefix_list *h, struct interface_olsr *, bool is_zero_bw);
94
95 /**
96  * Set the timer that controls the generation of
97  * empty TC messages
98  */
99 void
100 set_empty_tc_timer(uint32_t empty_tc_new)
101 {
102   send_empty_tc = empty_tc_new;
103 }
104
105 /**
106  * Get the timer that controls the generation of
107  * empty TC messages
108  */
109 uint32_t
110 get_empty_tc_timer(void)
111 {
112   return send_empty_tc;
113 }
114
115 /**
116  * Generate HELLO packet with the contents of the parameter "message".
117  * If this won't fit in one packet, chop it up into several.
118  * Send the packet if the size of the data contained in the output buffer
119  * reach maxmessagesize. Can generate an empty HELLO packet if the
120  * neighbor table is empty.
121  *
122  *
123  *@param message the hello_message struct containing the info
124  *to build the hello message from.
125  *@param ifp the interface to send the message on
126  *
127  *@return nada
128  */
129
130 bool
131 queue_hello(struct hello_message * message, struct interface_olsr * ifp)
132 {
133 #ifdef DEBUG
134   OLSR_PRINTF(BMSG_DBGLVL, "Building HELLO on %s\n-------------------\n", ifp->int_name);
135 #endif /* DEBUG */
136
137   switch (olsr_cnf->ip_version) {
138   case (AF_INET6):
139     return serialize_hello6(message, ifp);
140   case (AF_INET):
141   default:
142     return serialize_hello4(message, ifp);
143   }
144   return false;
145 }
146
147 /*
148  * Generate TC packet with the contents of the parameter "message".
149  * If this won't fit in one packet, chop it up into several.
150  * Send the packet if the size of the data contained in the output buffer
151  * reach maxmessagesize.
152  *
153  *@param message the tc_message struct containing the info
154  *to send
155  *@param ifp the interface to send the message on
156  *
157  *@return nada
158  */
159
160 bool
161 queue_tc(struct tc_message * message, struct interface_olsr * ifp)
162 {
163 #ifdef DEBUG
164   OLSR_PRINTF(BMSG_DBGLVL, "Building TC on %s\n-------------------\n", ifp->int_name);
165 #endif /* DEBUG */
166
167   switch (olsr_cnf->ip_version) {
168   case (AF_INET6):
169     return serialize_tc6(message, ifp);
170   case (AF_INET):
171   default:
172     return serialize_tc4(message, ifp);
173   }
174   return false;
175 }
176
177 /**
178  *Build a MID message to the outputbuffer
179  *
180  *<b>NO INTERNAL BUFFER</b>
181  *@param ifp a pointer to the interface with the main address
182  *@return 1 on success
183  */
184
185 bool
186 queue_mid(struct interface_olsr * ifp)
187 {
188 #ifdef DEBUG
189   OLSR_PRINTF(BMSG_DBGLVL, "Building MID on %s\n-------------------\n", ifp->int_name);
190 #endif /* DEBUG */
191
192   switch (olsr_cnf->ip_version) {
193   case (AF_INET6):
194     return serialize_mid6(ifp);
195   case (AF_INET):
196   default:
197     return serialize_mid4(ifp);
198   }
199   return false;
200 }
201
202 /**
203  *Builds a HNA message in the outputbuffer
204  *<b>NB! Not internal packetformat!</b>
205  *
206  *@param ifp the interface to send on
207  *@return nada
208  */
209 bool
210 queue_hna(struct interface_olsr * ifp)
211 {
212 #ifdef DEBUG
213   OLSR_PRINTF(BMSG_DBGLVL, "Building HNA on %s\n-------------------\n", ifp->int_name);
214 #endif /* DEBUG */
215
216   switch (olsr_cnf->ip_version) {
217   case (AF_INET6):
218     return serialize_hna6(olsr_cnf->hna_entries, ifp, false);
219   case (AF_INET):
220   default:
221     return serialize_hna4(olsr_cnf->hna_entries, ifp, false);
222   }
223   return false;
224 }
225
226 /*
227  * Protocol specific versions
228  */
229
230 static void
231 check_buffspace(int msgsize, int buffsize, const char *type)
232 {
233   if (msgsize > buffsize) {
234     OLSR_PRINTF(1, "%s build, outputbuffer to small(%d/%u)!\n", type, msgsize, buffsize);
235     olsr_syslog(OLSR_LOG_ERR, "%s build, outputbuffer to small(%d/%u)!\n", type, msgsize, buffsize);
236     olsr_exit(__func__, EXIT_FAILURE);
237   }
238 }
239
240 /**
241  * IP version 4
242  *
243  *@param message the hello_message struct containing the info
244  *to build the hello message from.
245  *@param ifp the interface to send the message on
246  *
247  *@return nada
248  */
249
250 static bool
251 serialize_hello4(struct hello_message *message, struct interface_olsr *ifp)
252 {
253   uint16_t remainsize, curr_size;
254   struct hello_neighbor *nb;
255   union olsr_message *m;
256   struct hellomsg *h;
257   struct hellinfo *hinfo;
258   char *haddr;
259   int i, j;
260   bool first_entry;
261
262   if ((!message) || (!ifp) || (olsr_cnf->ip_version != AF_INET))
263     return false;
264
265   remainsize = net_outbuffer_bytes_left(ifp);
266
267   m = (union olsr_message *)msg_buffer;
268
269   curr_size = OLSR_HELLO_IPV4_HDRSIZE;
270
271   /* Send pending packet if not room in buffer */
272   if (curr_size > remainsize) {
273     net_output(ifp);
274     remainsize = net_outbuffer_bytes_left(ifp);
275   }
276   /* Sanity check */
277   check_buffspace(curr_size, remainsize, "HELLO");
278
279   h = &m->v4.message.hello;
280   hinfo = h->hell_info;
281   haddr = (char *)hinfo->neigh_addr;
282
283   /* Fill message header */
284   m->v4.ttl = message->ttl;
285   m->v4.hopcnt = 0;
286   m->v4.olsr_msgtype = HELLO_MESSAGE;
287   /* Set source(main) addr */
288   m->v4.originator = olsr_cnf->main_addr.v4.s_addr;
289
290   m->v4.olsr_vtime = ifp->valtimes.hello;
291
292   /* Fill HELLO header */
293   h->willingness = message->willingness;
294   h->htime = reltime_to_me(ifp->hello_etime);
295
296   memset(&h->reserved, 0, sizeof(uint16_t));
297
298   /*
299    *Loops trough all possible neighbor statuses
300    *The neighbor list is grouped by status
301    *
302    */
303   /* Neighbor statuses */
304   for (i = 0; i <= MAX_NEIGH; i++) {
305     /* Link statuses */
306     for (j = 0; j <= MAX_LINK; j++) {
307 #ifdef DEBUG
308       struct ipaddr_str buf;
309 #endif /* DEBUG */
310
311       /* HYSTERESIS - Not adding neighbors with link type HIDE */
312
313       if (j == HIDE_LINK)
314         continue;
315
316       first_entry = true;
317
318       /* Looping trough neighbors */
319       for (nb = message->neighbors; nb != NULL; nb = nb->next) {
320         if ((nb->status != i) || (nb->link != j))
321           continue;
322
323
324 #ifdef DEBUG
325         OLSR_PRINTF(BMSG_DBGLVL, "\t%s - ", olsr_ip_to_string(&buf, &nb->address));
326         OLSR_PRINTF(BMSG_DBGLVL, "L:%d N:%d\n", j, i);
327 #endif /* DEBUG */
328         /*
329          * If there is not enough room left
330          * for the data in the outputbuffer
331          * we must send a partial HELLO and
332          * continue building the rest of the
333          * data in a new HELLO message
334          *
335          * If this is the first neighbor in
336          * a group, we must check for an extra
337          * 4 bytes
338          */
339         if ((curr_size + olsr_cnf->ipsize + (first_entry ? 4 : 0)) > remainsize) {
340           /* Only send partial HELLO if it contains data */
341           if (curr_size > OLSR_HELLO_IPV4_HDRSIZE) {
342 #ifdef DEBUG
343             OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize);
344 #endif /* DEBUG */
345             /* Complete the headers */
346             m->v4.seqno = htons(get_msg_seqno());
347             m->v4.olsr_msgsize = htons(curr_size);
348
349             hinfo->size = htons((char *)haddr - (char *)hinfo);
350
351             /* Send partial packet */
352             net_outbuffer_push(ifp, msg_buffer, curr_size);
353
354             curr_size = OLSR_HELLO_IPV4_HDRSIZE;
355
356             h = &m->v4.message.hello;
357             hinfo = h->hell_info;
358             haddr = (char *)hinfo->neigh_addr;
359             /* Make sure typeheader is added */
360             first_entry = true;
361           }
362
363           net_output(ifp);
364           /* Reset size and pointers */
365           remainsize = net_outbuffer_bytes_left(ifp);
366
367           /* Sanity check */
368           check_buffspace(curr_size + olsr_cnf->ipsize + 4, remainsize, "HELLO2");
369         }
370
371         if (first_entry) {
372           memset(&hinfo->reserved, 0, sizeof(uint8_t));
373           /* Set link and status for this group of neighbors (this is the first) */
374           hinfo->link_code = CREATE_LINK_CODE(i, j);
375           curr_size += 4;       /* HELLO type section header */
376         }
377
378         memcpy(haddr, &nb->address, sizeof(union olsr_ip_addr));
379
380         /* Point to next address */
381         haddr += olsr_cnf->ipsize;
382         curr_size += olsr_cnf->ipsize;  /* IP address added */
383
384         first_entry = false;
385       }
386
387       if (!first_entry) {
388         hinfo->size = htons((char *)haddr - (char *)hinfo);
389
390         hinfo = (struct hellinfo *)((char *)haddr);
391         haddr = (char *)hinfo->neigh_addr;
392
393       }
394     }                           /* for j */
395   }                             /* for i */
396
397   m->v4.seqno = htons(get_msg_seqno());
398   m->v4.olsr_msgsize = htons(curr_size);
399
400   net_outbuffer_push(ifp, msg_buffer, curr_size);
401
402   /* HELLO will always be generated */
403   return true;
404 }
405
406 /**
407  * IP version 6
408  *
409  *@param message the hello_message struct containing the info
410  *to build the hello message from.
411  *@param ifp the interface to send the message on
412  *
413  *@return nada
414  */
415
416 static bool
417 serialize_hello6(struct hello_message *message, struct interface_olsr *ifp)
418 {
419   uint16_t remainsize, curr_size;
420   struct hello_neighbor *nb;
421   union olsr_message *m;
422   struct hellomsg6 *h6;
423   struct hellinfo6 *hinfo6;
424   union olsr_ip_addr *haddr;
425   int i, j;
426   bool first_entry;
427
428   if ((!message) || (!ifp) || (olsr_cnf->ip_version != AF_INET6))
429     return false;
430
431   remainsize = net_outbuffer_bytes_left(ifp);
432   m = (union olsr_message *)msg_buffer;
433
434   curr_size = OLSR_HELLO_IPV6_HDRSIZE;  /* OLSR message header */
435
436   /* Send pending packet if not room in buffer */
437   if (curr_size > remainsize) {
438     net_output(ifp);
439     remainsize = net_outbuffer_bytes_left(ifp);
440   }
441   check_buffspace(curr_size + olsr_cnf->ipsize + 4, remainsize, "HELLO");
442
443   h6 = &m->v6.message.hello;
444   hinfo6 = h6->hell_info;
445   haddr = (union olsr_ip_addr *)hinfo6->neigh_addr;
446
447   /* Fill message header */
448   m->v6.ttl = message->ttl;
449   m->v6.hopcnt = 0;
450   /* Set source(main) addr */
451   m->v6.originator = olsr_cnf->main_addr.v6;
452   m->v6.olsr_msgtype = HELLO_MESSAGE;
453
454   m->v6.olsr_vtime = ifp->valtimes.hello;
455
456   /* Fill packet header */
457   h6->willingness = message->willingness;
458   h6->htime = reltime_to_me(ifp->hello_etime);
459   memset(&h6->reserved, 0, sizeof(uint16_t));
460
461   /*
462    *Loops trough all possible neighbor statuses
463    *The negbor list is grouped by status
464    */
465
466   for (i = 0; i <= MAX_NEIGH; i++) {
467     for (j = 0; j <= MAX_LINK; j++) {
468 #ifdef DEBUG
469       struct ipaddr_str buf;
470 #endif /* DEBUG */
471       first_entry = true;
472
473       /*
474        *Looping trough neighbors
475        */
476       for (nb = message->neighbors; nb != NULL; nb = nb->next) {
477         if ((nb->status != i) || (nb->link != j))
478           continue;
479
480 #ifdef DEBUG
481         OLSR_PRINTF(BMSG_DBGLVL, "\t%s - ", olsr_ip_to_string(&buf, &nb->address));
482         OLSR_PRINTF(BMSG_DBGLVL, "L:%d N:%d\n", j, i);
483 #endif /* DEBUG */
484
485         /*
486          * If there is not enough room left
487          * for the data in the outputbuffer
488          * we must send a partial HELLO and
489          * continue building the rest of the
490          * data in a new HELLO message
491          *
492          * If this is the first neighbor in
493          * a group, we must check for an extra
494          * 4 bytes
495          */
496         if ((curr_size + olsr_cnf->ipsize + (first_entry ? 4 : 0)) > remainsize) {
497           /* Only send partial HELLO if it contains data */
498           if (curr_size > OLSR_HELLO_IPV6_HDRSIZE) {
499 #ifdef DEBUG
500             OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize);
501 #endif /* DEBUG */
502             /* Complete the headers */
503             m->v6.seqno = htons(get_msg_seqno());
504             m->v6.olsr_msgsize = htons(curr_size);
505
506             hinfo6->size = (char *)haddr - (char *)hinfo6;
507             hinfo6->size = htons(hinfo6->size);
508
509             /* Send partial packet */
510             net_outbuffer_push(ifp, msg_buffer, curr_size);
511             curr_size = OLSR_HELLO_IPV6_HDRSIZE;
512
513             h6 = &m->v6.message.hello;
514             hinfo6 = h6->hell_info;
515             haddr = (union olsr_ip_addr *)hinfo6->neigh_addr;
516             /* Make sure typeheader is added */
517             first_entry = true;
518           }
519           net_output(ifp);
520           /* Reset size and pointers */
521           remainsize = net_outbuffer_bytes_left(ifp);
522
523           check_buffspace(curr_size + olsr_cnf->ipsize + 4, remainsize, "HELLO2");
524
525         }
526
527         if (first_entry) {
528           memset(&hinfo6->reserved, 0, sizeof(uint8_t));
529           /* Set link and status for this group of neighbors (this is the first) */
530           hinfo6->link_code = CREATE_LINK_CODE(i, j);
531           curr_size += 4;       /* HELLO type section header */
532         }
533
534         *haddr = nb->address;
535
536         /* Point to next address */
537         haddr++;
538         curr_size += olsr_cnf->ipsize;  /* IP address added */
539
540         first_entry = false;
541       }                         /* looping trough neighbors */
542
543       if (!first_entry) {
544         hinfo6->size = htons((char *)haddr - (char *)hinfo6);
545         hinfo6 = (struct hellinfo6 *)((char *)haddr);
546         haddr = (union olsr_ip_addr *)&hinfo6->neigh_addr;
547       }
548
549     }                           /* for j */
550   }                             /* for i */
551
552   m->v6.seqno = htons(get_msg_seqno());
553   m->v6.olsr_msgsize = htons(curr_size);
554
555   net_outbuffer_push(ifp, msg_buffer, curr_size);
556
557   /* HELLO is always buildt */
558   return true;
559 }
560
561 /**
562  *IP version 4
563  *
564  *@param message the tc_message struct containing the info
565  *to send
566  *@param ifp the interface to send the message on
567  *
568  *@return nada
569  */
570
571 static bool
572 serialize_tc4(struct tc_message *message, struct interface_olsr *ifp)
573 {
574 #ifdef DEBUG
575   struct ipaddr_str buf;
576 #endif /* DEBUG */
577   uint16_t remainsize, curr_size;
578   struct tc_mpr_addr *mprs;
579   union olsr_message *m;
580   struct olsr_tcmsg *tc;
581   struct neigh_info *mprsaddr;
582   bool found = false, partial_sent = false;
583
584   if ((!message) || (!ifp) || (olsr_cnf->ip_version != AF_INET))
585     return false;
586
587   remainsize = net_outbuffer_bytes_left(ifp);
588
589   m = (union olsr_message *)msg_buffer;
590
591   tc = &m->v4.message.tc;
592
593   mprsaddr = tc->neigh;
594   curr_size = OLSR_TC_IPV4_HDRSIZE;
595
596   /* Send pending packet if not room in buffer */
597   if (curr_size > remainsize) {
598     net_output(ifp);
599     remainsize = net_outbuffer_bytes_left(ifp);
600   }
601   check_buffspace(curr_size, remainsize, "TC");
602
603   /* Fill header */
604   m->v4.olsr_vtime = ifp->valtimes.tc;
605   m->v4.olsr_msgtype = TC_MESSAGE;
606   m->v4.hopcnt = message->hop_count;
607   m->v4.ttl = message->ttl;
608   m->v4.originator = message->originator.v4.s_addr;
609
610   /* Fill TC header */
611   tc->ansn = htons(message->ansn);
612   tc->reserved = 0;
613
614   /*Looping trough MPR selectors */
615   for (mprs = message->multipoint_relay_selector_address; mprs != NULL; mprs = mprs->next) {
616     /*If packet is to be chomped */
617     if ((curr_size + olsr_cnf->ipsize) > remainsize) {
618
619       /* Only add TC message if it contains data */
620       if (curr_size > OLSR_TC_IPV4_HDRSIZE) {
621 #ifdef DEBUG
622         OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize);
623 #endif /* DEBUG */
624
625         m->v4.olsr_msgsize = htons(curr_size);
626         m->v4.seqno = htons(get_msg_seqno());
627
628         net_outbuffer_push(ifp, msg_buffer, curr_size);
629
630         /* Reset stuff */
631         mprsaddr = tc->neigh;
632         curr_size = OLSR_TC_IPV4_HDRSIZE;
633         found = false;
634         partial_sent = true;
635       }
636
637       net_output(ifp);
638       remainsize = net_outbuffer_bytes_left(ifp);
639       check_buffspace(curr_size + olsr_cnf->ipsize, remainsize, "TC2");
640
641     }
642     found = true;
643 #ifdef DEBUG
644     OLSR_PRINTF(BMSG_DBGLVL, "\t%s\n", olsr_ip_to_string(&buf, &mprs->address));
645 #endif /* DEBUG */
646     mprsaddr->addr = mprs->address.v4.s_addr;
647     curr_size += olsr_cnf->ipsize;
648     mprsaddr++;
649   }
650
651   if (found) {
652
653     m->v4.olsr_msgsize = htons(curr_size);
654     m->v4.seqno = htons(get_msg_seqno());
655
656     net_outbuffer_push(ifp, msg_buffer, curr_size);
657
658   } else {
659     if ((!partial_sent) && (!TIMED_OUT(send_empty_tc))) {
660       if (!TIMED_OUT(send_empty_tc))
661         OLSR_PRINTF(1, "TC: Sending empty package - (%d/%d/%d/%d)\n", partial_sent, (int)send_empty_tc, (int)now_times,
662                     (int)((send_empty_tc) - now_times));
663
664       m->v4.olsr_msgsize = htons(curr_size);
665       m->v4.seqno = htons(get_msg_seqno());
666
667       net_outbuffer_push(ifp, msg_buffer, curr_size);
668
669       found = true;
670     }
671   }
672
673   return found;
674 }
675
676 /**
677  *IP version 6
678  *
679  *@param message the tc_message struct containing the info
680  *to send
681  *@param ifp the interface to send the message on
682  *
683  *@return nada
684  */
685
686 static bool
687 serialize_tc6(struct tc_message *message, struct interface_olsr *ifp)
688 {
689 #ifdef DEBUG
690   struct ipaddr_str buf;
691 #endif /* DEBUG */
692   uint16_t remainsize, curr_size;
693   struct tc_mpr_addr *mprs;
694   union olsr_message *m;
695   struct olsr_tcmsg6 *tc6;
696   struct neigh_info6 *mprsaddr6;
697   bool found = false, partial_sent = false;
698
699   if ((!message) || (!ifp) || (olsr_cnf->ip_version != AF_INET6))
700     return false;
701
702   remainsize = net_outbuffer_bytes_left(ifp);
703
704   m = (union olsr_message *)msg_buffer;
705
706   tc6 = &m->v6.message.tc;
707
708   mprsaddr6 = tc6->neigh;
709   curr_size = OLSR_TC_IPV6_HDRSIZE;
710
711   /* Send pending packet if not room in buffer */
712   if (curr_size > remainsize) {
713     net_output(ifp);
714     remainsize = net_outbuffer_bytes_left(ifp);
715   }
716   check_buffspace(curr_size, remainsize, "TC");
717
718   /* Fill header */
719   m->v6.olsr_vtime = ifp->valtimes.tc;
720   m->v6.olsr_msgtype = TC_MESSAGE;
721   m->v6.hopcnt = message->hop_count;
722   m->v6.ttl = message->ttl;
723   m->v6.originator = message->originator.v6;
724
725   /* Fill TC header */
726   tc6->ansn = htons(message->ansn);
727   tc6->reserved = 0;
728
729   /*Looping trough MPR selectors */
730   for (mprs = message->multipoint_relay_selector_address; mprs != NULL; mprs = mprs->next) {
731
732     /*If packet is to be chomped */
733     if ((curr_size + olsr_cnf->ipsize) > remainsize) {
734       /* Only add TC message if it contains data */
735       if (curr_size > OLSR_TC_IPV6_HDRSIZE) {
736 #ifdef DEBUG
737         OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize);
738 #endif /* DEBUG */
739         m->v6.olsr_msgsize = htons(curr_size);
740         m->v6.seqno = htons(get_msg_seqno());
741
742         net_outbuffer_push(ifp, msg_buffer, curr_size);
743         mprsaddr6 = tc6->neigh;
744         curr_size = OLSR_TC_IPV6_HDRSIZE;
745         found = false;
746         partial_sent = true;
747       }
748       net_output(ifp);
749       remainsize = net_outbuffer_bytes_left(ifp);
750       check_buffspace(curr_size + olsr_cnf->ipsize, remainsize, "TC2");
751
752     }
753     found = true;
754 #ifdef DEBUG
755     OLSR_PRINTF(BMSG_DBGLVL, "\t%s\n", olsr_ip_to_string(&buf, &mprs->address));
756 #endif /* DEBUG */
757     mprsaddr6->addr = mprs->address.v6;
758     curr_size += olsr_cnf->ipsize;
759
760     mprsaddr6++;
761   }
762
763   if (found) {
764     m->v6.olsr_msgsize = htons(curr_size);
765     m->v6.seqno = htons(get_msg_seqno());
766
767     net_outbuffer_push(ifp, msg_buffer, curr_size);
768
769   } else {
770     if ((!partial_sent) && (!TIMED_OUT(send_empty_tc))) {
771       OLSR_PRINTF(1, "TC: Sending empty package\n");
772
773       m->v6.olsr_msgsize = htons(curr_size);
774       m->v6.seqno = htons(get_msg_seqno());
775
776       net_outbuffer_push(ifp, msg_buffer, curr_size);
777
778       found = true;
779     }
780   }
781
782   return found;
783 }
784
785 /**
786  *IP version 4
787  *
788  *<b>NO INTERNAL BUFFER</b>
789  *@param ifp use this interfaces address as main address
790  *@return 1 on success
791  */
792
793 static bool
794 serialize_mid4(struct interface_olsr *ifp)
795 {
796   uint16_t remainsize, curr_size, needsize;
797   /* preserve existing data in output buffer */
798   union olsr_message *m;
799   struct midaddr *addrs;
800   struct interface_olsr *ifs;
801
802   if ((olsr_cnf->ip_version != AF_INET) || (!ifp) || (ifnet == NULL) || ((ifnet->int_next == NULL) && (ipequal(&olsr_cnf->main_addr, &ifnet->ip_addr))))
803     return false;
804
805   remainsize = net_outbuffer_bytes_left(ifp);
806
807   m = (union olsr_message *)msg_buffer;
808
809   curr_size = OLSR_MID_IPV4_HDRSIZE;
810
811   /* calculate size needed for HNA */
812   needsize = curr_size;
813   for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
814     needsize += olsr_cnf->ipsize*2;
815   }
816
817   /* Send pending packet if not room in buffer */
818   if (needsize > remainsize) {
819     net_output(ifp);
820     remainsize = net_outbuffer_bytes_left(ifp);
821   }
822   check_buffspace(curr_size, remainsize, "MID");
823
824   /* Fill header */
825   m->v4.hopcnt = 0;
826   m->v4.ttl = MAX_TTL;
827   /* Set main(first) address */
828   m->v4.originator = olsr_cnf->main_addr.v4.s_addr;
829   m->v4.olsr_msgtype = MID_MESSAGE;
830   m->v4.olsr_vtime = ifp->valtimes.mid;
831
832   addrs = m->v4.message.mid.mid_addr;
833
834   /* Don't add the main address... it's already there */
835   for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
836     if (!ipequal(&olsr_cnf->main_addr, &ifs->ip_addr)) {
837 #ifdef DEBUG
838       struct ipaddr_str buf;
839 #endif /* DEBUG */
840
841       if ((curr_size + olsr_cnf->ipsize) > remainsize) {
842         /* Only add MID message if it contains data */
843         if (curr_size > OLSR_MID_IPV4_HDRSIZE) {
844 #ifdef DEBUG
845           OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize);
846 #endif /* DEBUG */
847           /* set size */
848           m->v4.olsr_msgsize = htons(curr_size);
849           m->v4.seqno = htons(get_msg_seqno()); /* seqnumber */
850
851           net_outbuffer_push(ifp, msg_buffer, curr_size);
852           curr_size = OLSR_MID_IPV4_HDRSIZE;
853           addrs = m->v4.message.mid.mid_addr;
854         }
855         net_output(ifp);
856         remainsize = net_outbuffer_bytes_left(ifp);
857         check_buffspace(curr_size, remainsize, "MID2");
858       }
859 #ifdef DEBUG
860       OLSR_PRINTF(BMSG_DBGLVL, "\t%s(%s)\n", olsr_ip_to_string(&buf, &ifs->ip_addr), ifs->int_name);
861 #endif /* DEBUG */
862
863       addrs->addr = ifs->ip_addr.v4.s_addr;
864       addrs++;
865       curr_size += olsr_cnf->ipsize;
866     }
867   }
868
869   m->v4.seqno = htons(get_msg_seqno()); /* seqnumber */
870   m->v4.olsr_msgsize = htons(curr_size);
871
872   //printf("Sending MID (%d bytes)...\n", outputsize);
873   if (curr_size > OLSR_MID_IPV4_HDRSIZE)
874     net_outbuffer_push(ifp, msg_buffer, curr_size);
875
876   return true;
877 }
878
879 /**
880  *IP version 6
881  *
882  *<b>NO INTERNAL BUFFER</b>
883  *@param ifp use this interfaces address as main address
884  *@return 1 on success
885  */
886
887 static bool
888 serialize_mid6(struct interface_olsr *ifp)
889 {
890   uint16_t remainsize, curr_size, needsize;
891   /* preserve existing data in output buffer */
892   union olsr_message *m;
893   struct midaddr6 *addrs6;
894   struct interface_olsr *ifs;
895
896   //printf("\t\tGenerating mid on %s\n", ifn->int_name);
897
898   if ((olsr_cnf->ip_version != AF_INET6) || (!ifp) || (ifnet == NULL) || ((ifnet->int_next == NULL) && (ipequal(&olsr_cnf->main_addr, &ifnet->ip_addr))))
899     return false;
900
901   remainsize = net_outbuffer_bytes_left(ifp);
902
903   curr_size = OLSR_MID_IPV6_HDRSIZE;
904
905   /* calculate size needed for HNA */
906   needsize = curr_size;
907   for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
908     needsize += olsr_cnf->ipsize*2;
909   }
910
911   /* Send pending packet if not room in buffer */
912   if (needsize > remainsize) {
913     net_output(ifp);
914     remainsize = net_outbuffer_bytes_left(ifp);
915   }
916   check_buffspace(curr_size, remainsize, "MID");
917
918   m = (union olsr_message *)msg_buffer;
919
920   /* Build header */
921   m->v6.hopcnt = 0;
922   m->v6.ttl = MAX_TTL;
923   m->v6.olsr_msgtype = MID_MESSAGE;
924   m->v6.olsr_vtime = ifp->valtimes.mid;
925   /* Set main(first) address */
926   m->v6.originator = olsr_cnf->main_addr.v6;
927
928   addrs6 = m->v6.message.mid.mid_addr;
929
930   /* Don't add the main address... it's already there */
931   for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
932     if (!ipequal(&olsr_cnf->main_addr, &ifs->ip_addr)) {
933 #ifdef DEBUG
934       struct ipaddr_str buf;
935 #endif /* DEBUG */
936       if ((curr_size + olsr_cnf->ipsize) > remainsize) {
937         /* Only add MID message if it contains data */
938         if (curr_size > OLSR_MID_IPV6_HDRSIZE) {
939 #ifdef DEBUG
940           OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize);
941 #endif /* DEBUG */
942           /* set size */
943           m->v6.olsr_msgsize = htons(curr_size);
944           m->v6.seqno = htons(get_msg_seqno()); /* seqnumber */
945
946           net_outbuffer_push(ifp, msg_buffer, curr_size);
947           curr_size = OLSR_MID_IPV6_HDRSIZE;
948           addrs6 = m->v6.message.mid.mid_addr;
949         }
950         net_output(ifp);
951         remainsize = net_outbuffer_bytes_left(ifp);
952         check_buffspace(curr_size + olsr_cnf->ipsize, remainsize, "MID2");
953       }
954 #ifdef DEBUG
955       OLSR_PRINTF(BMSG_DBGLVL, "\t%s(%s)\n", olsr_ip_to_string(&buf, &ifs->ip_addr), ifs->int_name);
956 #endif /* DEBUG */
957
958       addrs6->addr = ifs->ip_addr.v6;
959       addrs6++;
960       curr_size += olsr_cnf->ipsize;
961     }
962   }
963
964   m->v6.olsr_msgsize = htons(curr_size);
965   m->v6.seqno = htons(get_msg_seqno()); /* seqnumber */
966
967   //printf("Sending MID (%d bytes)...\n", outputsize);
968   if (curr_size > OLSR_MID_IPV6_HDRSIZE)
969     net_outbuffer_push(ifp, msg_buffer, curr_size);
970
971   return true;
972 }
973
974 static void appendHNAEntry(struct interface_olsr *ifp, struct ip_prefix_list *h, uint16_t * remainsize, uint16_t * curr_size,
975     union olsr_message *m, struct hnapair **pair, bool zero
976 #ifndef __linux__
977 __attribute__((unused))
978 #endif
979   , bool * sgw_set
980 #ifndef __linux__
981 __attribute__((unused))
982 #endif
983   ) {
984   union olsr_ip_addr ip_addr;
985 #ifdef __linux__
986   bool is_def_route = is_prefix_inetgw(&h->net);
987 #endif
988
989   if ((*curr_size + (2 * olsr_cnf->ipsize)) > *remainsize) {
990     /* Only add HNA message if it contains data */
991     if (*curr_size > OLSR_HNA_IPV4_HDRSIZE) {
992 #ifdef DEBUG
993       OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", *curr_size, *remainsize);
994 #endif /* DEBUG */
995       m->v4.olsr_msgsize = htons(*curr_size);
996       m->v4.seqno = htons(get_msg_seqno());
997       net_outbuffer_push(ifp, msg_buffer, *curr_size);
998       *curr_size = OLSR_HNA_IPV4_HDRSIZE;
999       *pair = m->v4.message.hna.hna_net;
1000     }
1001     net_output(ifp);
1002     *remainsize = net_outbuffer_bytes_left(ifp);
1003     check_buffspace(*curr_size + (2 * olsr_cnf->ipsize), *remainsize, "HNA2");
1004   }
1005 #ifdef DEBUG
1006   OLSR_PRINTF(BMSG_DBGLVL, "\tNet: %s\n", olsr_ip_prefix_to_string(&h->net));
1007 #endif /* DEBUG */
1008
1009   olsr_prefix_to_netmask(&ip_addr, h->net.prefix_len);
1010 #ifdef __linux__
1011   if (olsr_cnf->smart_gw_active && is_def_route) {
1012     /* this is the default route, overwrite it with the smart gateway */
1013     olsr_modifiy_inetgw_netmask(&ip_addr, h->net.prefix_len, zero);
1014     *sgw_set = true;
1015   }
1016 #endif /* __linux__ */
1017   (*pair)->addr = h->net.prefix.v4.s_addr;
1018   (*pair)->netmask = ip_addr.v4.s_addr;
1019   *pair = &(*pair)[1];
1020   *curr_size += (2 * olsr_cnf->ipsize);
1021 }
1022
1023 /**
1024  *IP version 4
1025  *
1026  *@param ifp the interface to send on
1027  *@return nada
1028  */
1029 static bool
1030 serialize_hna4(struct ip_prefix_list *h, struct interface_olsr *ifp, bool is_zero_bw)
1031 {
1032   uint16_t remainsize, curr_size, needsize;
1033   /* preserve existing data in output buffer */
1034   union olsr_message *m;
1035   struct hnapair *pair;
1036   bool h_empty = !h;
1037   bool sgw_set = false;
1038
1039   if (ifp == NULL) {
1040     return false;
1041   }
1042
1043   if (olsr_cnf->ip_version != AF_INET) {
1044     return false;
1045   }
1046
1047   if (h_empty && !ifp->sgw_sgw_zero_bw_timeout) {
1048     return false;
1049   }
1050
1051   remainsize = net_outbuffer_bytes_left(ifp);
1052
1053   curr_size = OLSR_HNA_IPV4_HDRSIZE;
1054
1055   needsize = curr_size;
1056
1057   if (!h_empty) {
1058     /* calculate size needed for HNA */
1059     struct ip_prefix_list *h_tmp = h;
1060     while (h_tmp) {
1061       needsize += olsr_cnf->ipsize*2;
1062       h_tmp = h_tmp->next;
1063     }
1064
1065     /* Send pending packet if not room in buffer */
1066     if (needsize > remainsize) {
1067       net_output(ifp);
1068       remainsize = net_outbuffer_bytes_left(ifp);
1069     }
1070     check_buffspace(curr_size, remainsize, "HNA");
1071
1072     m = (union olsr_message *)msg_buffer;
1073
1074     /* Fill header */
1075     m->v4.olsr_msgtype = HNA_MESSAGE;
1076     m->v4.olsr_vtime = is_zero_bw ? reltime_to_me(ifp->sgw_sgw_zero_bw_timeout) : ifp->valtimes.hna;
1077     // olsr_msgsize
1078     m->v4.originator = olsr_cnf->main_addr.v4.s_addr;
1079     m->v4.ttl = MAX_TTL;
1080     m->v4.hopcnt = 0;
1081     // seqno
1082
1083     pair = m->v4.message.hna.hna_net;
1084
1085     for (; h != NULL; h = h->next) {
1086       appendHNAEntry(ifp, h, &remainsize, &curr_size, m, &pair, is_zero_bw, &sgw_set);
1087     }
1088
1089     m->v4.olsr_msgsize = htons(curr_size);
1090     m->v4.seqno = htons(get_msg_seqno());
1091
1092     net_outbuffer_push(ifp, msg_buffer, curr_size);
1093
1094 #ifdef __linux__
1095     if (sgw_set && !is_zero_bw) {
1096       /* (re)set zero bandwidth sgw HNAs timeout */
1097       ifp->sgw_sgw_zero_bw_timeout = ifp->valtimes.hna_reltime;
1098     }
1099 #endif
1100   }
1101
1102 #ifdef __linux__
1103   if (olsr_cnf->smart_gw_active /* sgw is active */
1104       && (h_empty || !sgw_set) /* there are no HNAs at all or no sgw HNA */
1105       && ifp->sgw_sgw_zero_bw_timeout /* the zero bandwidth sgw HNA window is still valid */
1106       && !is_zero_bw /* prevent infinite recursion */
1107       ) {
1108     struct ip_prefix_list h_zero;
1109
1110     memset(&h_zero, 0, sizeof(h_zero));
1111     serialize_hna4(&h_zero, ifp, true);
1112
1113     /* decrement the window validity time */
1114     {
1115       unsigned int hna_period = ifp->hna_gen_timer->timer_period;
1116       if (ifp->sgw_sgw_zero_bw_timeout <= hna_period) {
1117         ifp->sgw_sgw_zero_bw_timeout = 0;
1118       } else {
1119         ifp->sgw_sgw_zero_bw_timeout -= hna_period;
1120       }
1121     }
1122   }
1123 #endif /* __linux__ */
1124
1125   //printf("Sending HNA (%d bytes)...\n", outputsize);
1126   return false;
1127 }
1128
1129 static void appendHNA6Entry(struct interface_olsr *ifp, struct ip_prefix_list *h, uint16_t * remainsize, uint16_t * curr_size,
1130     union olsr_message *m, struct hnapair6 **pair, bool zero
1131 #ifndef __linux__
1132 __attribute__((unused))
1133 #endif
1134   , bool * sgw_set
1135 #ifndef __linux__
1136 __attribute__((unused))
1137 #endif
1138   ) {
1139   union olsr_ip_addr ip_addr;
1140 #ifdef __linux__
1141   bool is_def_route = is_prefix_inetgw(&h->net);
1142 #endif
1143
1144   if ((*curr_size + (2 * olsr_cnf->ipsize)) > *remainsize) {
1145     /* Only add HNA message if it contains data */
1146     if (*curr_size > OLSR_HNA_IPV6_HDRSIZE) {
1147 #ifdef DEBUG
1148       OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", *curr_size, *remainsize);
1149 #endif /* DEBUG */
1150       m->v6.olsr_msgsize = htons(*curr_size);
1151       m->v6.seqno = htons(get_msg_seqno());
1152       net_outbuffer_push(ifp, msg_buffer, *curr_size);
1153       *curr_size = OLSR_HNA_IPV6_HDRSIZE;
1154       *pair = m->v6.message.hna.hna_net;
1155     }
1156     net_output(ifp);
1157     *remainsize = net_outbuffer_bytes_left(ifp);
1158     check_buffspace(*curr_size + (2 * olsr_cnf->ipsize), *remainsize, "HNA2");
1159   }
1160 #ifdef DEBUG
1161   OLSR_PRINTF(BMSG_DBGLVL, "\tNet: %s\n", olsr_ip_prefix_to_string(&h->net));
1162 #endif /* DEBUG */
1163
1164   olsr_prefix_to_netmask(&ip_addr, h->net.prefix_len);
1165 #ifdef __linux__
1166   if (olsr_cnf->smart_gw_active && is_def_route) {
1167     /* this is the default route, overwrite it with the smart gateway */
1168     olsr_modifiy_inetgw_netmask(&ip_addr, h->net.prefix_len, zero);
1169     *sgw_set = true;
1170   }
1171 #endif /* __linux__ */
1172   (*pair)->addr = h->net.prefix.v6;
1173   (*pair)->netmask = ip_addr.v6;
1174   *pair = &(*pair)[1];
1175   *curr_size += (2 * olsr_cnf->ipsize);
1176 }
1177
1178 /**
1179  *IP version 6
1180  *
1181  *@param ifp the interface to send on
1182  *@return nada
1183  */
1184 static bool
1185 serialize_hna6(struct ip_prefix_list *h, struct interface_olsr *ifp, bool is_zero_bw)
1186 {
1187   uint16_t remainsize, curr_size, needsize;
1188   /* preserve existing data in output buffer */
1189   union olsr_message *m;
1190   struct hnapair6 *pair;
1191   bool h_empty = !h;
1192   bool sgw_set = false;
1193
1194   if (ifp == NULL) {
1195     return false;
1196   }
1197
1198   if (olsr_cnf->ip_version != AF_INET6) {
1199     return false;
1200   }
1201
1202   if (h_empty && !ifp->sgw_sgw_zero_bw_timeout) {
1203     return false;
1204   }
1205
1206   remainsize = net_outbuffer_bytes_left(ifp);
1207
1208   curr_size = OLSR_HNA_IPV6_HDRSIZE;
1209
1210   needsize = curr_size;
1211
1212   if (!h_empty) {
1213     /* calculate size needed for HNA */
1214     struct ip_prefix_list *h_tmp = h;
1215     while (h_tmp) {
1216       needsize += olsr_cnf->ipsize*2;
1217       h_tmp = h_tmp->next;
1218     }
1219
1220     /* Send pending packet if not room in buffer */
1221     if (needsize > remainsize) {
1222       net_output(ifp);
1223       remainsize = net_outbuffer_bytes_left(ifp);
1224     }
1225     check_buffspace(curr_size, remainsize, "HNA");
1226
1227     m = (union olsr_message *)msg_buffer;
1228
1229     /* Fill header */
1230     m->v6.olsr_msgtype = HNA_MESSAGE;
1231     m->v6.olsr_vtime = is_zero_bw ? reltime_to_me(ifp->sgw_sgw_zero_bw_timeout) : ifp->valtimes.hna;
1232     // olsr_msgsize
1233     m->v6.originator = olsr_cnf->main_addr.v6;
1234     m->v6.ttl = MAX_TTL;
1235     m->v6.hopcnt = 0;
1236     // seqno
1237
1238     pair = m->v6.message.hna.hna_net;
1239
1240     for (; h != NULL; h = h->next) {
1241       appendHNA6Entry(ifp, h, &remainsize, &curr_size, m, &pair, is_zero_bw, &sgw_set);
1242     }
1243
1244     m->v6.olsr_msgsize = htons(curr_size);
1245     m->v6.seqno = htons(get_msg_seqno());
1246
1247     net_outbuffer_push(ifp, msg_buffer, curr_size);
1248
1249 #ifdef __linux__
1250     if (sgw_set && !is_zero_bw) {
1251       /* (re)set zero bandwidth sgw HNAs timeout */
1252       ifp->sgw_sgw_zero_bw_timeout = ifp->valtimes.hna_reltime;
1253     }
1254 #endif
1255   }
1256
1257 #ifdef __linux__
1258   if (olsr_cnf->smart_gw_active /* sgw is active */
1259       && (h_empty || !sgw_set) /* there are no HNAs at all or no sgw HNA */
1260       && ifp->sgw_sgw_zero_bw_timeout /* the zero bandwidth sgw HNA window is still valid */
1261       && !is_zero_bw /* prevent infinite recursion */
1262       ) {
1263     struct ip_prefix_list h_zero;
1264
1265     memset(&h_zero, 0, sizeof(h_zero));
1266     serialize_hna6(&h_zero, ifp, true);
1267
1268     /* decrement the window validity time */
1269     {
1270       unsigned int hna_period = ifp->hna_gen_timer->timer_period;
1271       if (ifp->sgw_sgw_zero_bw_timeout <= hna_period) {
1272         ifp->sgw_sgw_zero_bw_timeout = 0;
1273       } else {
1274         ifp->sgw_sgw_zero_bw_timeout -= hna_period;
1275       }
1276     }
1277   }
1278 #endif /* __linux__ */
1279
1280   //printf("Sending HNA (%d bytes)...\n", outputsize);
1281   return false;
1282 }
1283
1284 /*
1285  * Local Variables:
1286  * c-basic-offset: 2
1287  * indent-tabs-mode: nil
1288  * End:
1289  */