linux: put #ifdef __linux__ around code
[olsrd.git] / src / linux / lq_plugin_ffeth_nl80211.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2008 Henning Rogge <rogge@fgan.de>
5  * Copyright (c) 2012 Fox-IT B.V. <opensource@fox-it.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  * * Neither the name of olsr.org, olsrd nor the names of its
19  *   contributors may be used to endorse or promote products derived
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Visit http://www.olsr.org for more information.
36  *
37  * If you find this software useful feel free to make a donation
38  * to the project. For more information see the website or contact
39  * the copyright holders.
40  *
41  */
42
43 #ifdef __linux__
44 #ifdef LINUX_NL80211 /* Optional - not supported on all platforms */
45
46 #include "lq_plugin_ffeth_nl80211.h"
47 #include "tc_set.h"
48 #include "link_set.h"
49 #include "lq_plugin.h"
50 #include "olsr_spf.h"
51 #include "lq_packet.h"
52 #include "packet.h"
53 #include "olsr.h"
54 #include "parser.h"
55 #include "fpm.h"
56 #include "mid_set.h"
57 #include "scheduler.h"
58 #include "log.h"
59
60 #ifdef LINUX_NL80211
61 #include "nl80211_link_info.h"
62 #define WEIGHT_ETX                      50
63 #define WEIGHT_BANDWIDTH        50
64 #endif
65
66 #define LQ_PLUGIN_LC_MULTIPLIER 1024
67 #define LQ_PLUGIN_RELEVANT_COSTCHANGE_FF 16
68
69 static void lq_initialize_ffeth_nl80211(void);
70
71 static olsr_linkcost lq_calc_cost_ffeth_nl80211(const void *lq);
72
73 static void lq_packet_loss_worker_ffeth_nl80211(struct link_entry *link, void *lq, bool lost);
74 static void lq_memorize_foreign_hello_ffeth_nl80211(void *local, void *foreign);
75
76 static int lq_serialize_hello_lq_pair_ffeth_nl80211(unsigned char *buff, void *lq);
77 static void lq_deserialize_hello_lq_pair_ffeth_nl80211(const uint8_t ** curr, void *lq);
78 static int lq_serialize_tc_lq_pair_ffeth_nl80211(unsigned char *buff, void *lq);
79 static void lq_deserialize_tc_lq_pair_ffeth_nl80211(const uint8_t ** curr, void *lq);
80
81 static void lq_copy_link2neigh_ffeth_nl80211(void *t, void *s);
82 static void lq_copy_link2tc_ffeth_nl80211(void *target, void *source);
83 static void lq_clear_ffeth_nl80211(void *target);
84 static void lq_clear_ffeth_nl80211_hello(void *target);
85
86 static const char *lq_print_ffeth_nl80211(void *ptr, char separator, struct lqtextbuffer *buffer);
87 static const char *lq_print_cost_ffeth_nl80211(olsr_linkcost cost, struct lqtextbuffer *buffer);
88
89 /* etx lq plugin (freifunk fpm version) settings */
90 struct lq_handler lq_etx_ffeth_nl80211_handler = {
91   &lq_initialize_ffeth_nl80211,
92   &lq_calc_cost_ffeth_nl80211,
93   &lq_calc_cost_ffeth_nl80211,
94
95   &lq_packet_loss_worker_ffeth_nl80211,
96
97   &lq_memorize_foreign_hello_ffeth_nl80211,
98   &lq_copy_link2neigh_ffeth_nl80211,
99   &lq_copy_link2tc_ffeth_nl80211,
100   &lq_clear_ffeth_nl80211_hello,
101   &lq_clear_ffeth_nl80211,
102
103   &lq_serialize_hello_lq_pair_ffeth_nl80211,
104   &lq_serialize_tc_lq_pair_ffeth_nl80211,
105   &lq_deserialize_hello_lq_pair_ffeth_nl80211,
106   &lq_deserialize_tc_lq_pair_ffeth_nl80211,
107
108   &lq_print_ffeth_nl80211,
109   &lq_print_ffeth_nl80211,
110   &lq_print_cost_ffeth_nl80211,
111
112   sizeof(struct lq_ffeth_hello),
113   sizeof(struct lq_ffeth),
114   4,
115   4
116 };
117
118 static void
119 lq_ffeth_nl80211_handle_lqchange(void) {
120   struct lq_ffeth_hello *lq;
121   struct ipaddr_str buf;
122   struct link_entry *link;
123
124   bool triggered = false;
125
126   OLSR_FOR_ALL_LINK_ENTRIES(link) {
127     bool relevant = false;
128     lq = (struct lq_ffeth_hello *)link->linkquality;
129
130 #if 0
131   fprintf(stderr, "%s: old = %u/%u   new = %u/%u\n", olsr_ip_to_string(&buf, &link->neighbor_iface_addr),
132       lq->smoothed_lq.valueLq, lq->smoothed_lq.valueNlq,
133       lq->lq.valueLq, lq->lq.valueNlq);
134 #endif
135
136     if (lq->smoothed_lq.valueLq < lq->lq.valueLq) {
137       if (lq->lq.valueLq >= 254 || lq->lq.valueLq - lq->smoothed_lq.valueLq > lq->smoothed_lq.valueLq/10) {
138         relevant = true;
139       }
140     }
141     else if (lq->smoothed_lq.valueLq > lq->lq.valueLq) {
142       if (lq->smoothed_lq.valueLq - lq->lq.valueLq > lq->smoothed_lq.valueLq/10) {
143         relevant = true;
144       }
145     }
146     if (lq->smoothed_lq.valueNlq < lq->lq.valueNlq) {
147       if (lq->lq.valueNlq >= 254 || lq->lq.valueNlq - lq->smoothed_lq.valueNlq > lq->smoothed_lq.valueNlq/10) {
148         relevant = true;
149       }
150     }
151     else if (lq->smoothed_lq.valueNlq > lq->lq.valueNlq) {
152       if (lq->smoothed_lq.valueNlq - lq->lq.valueNlq > lq->smoothed_lq.valueNlq/10) {
153         relevant = true;
154       }
155     }
156
157     if (relevant) {
158       memcpy(&lq->smoothed_lq, &lq->lq, sizeof(struct lq_ffeth));
159       link->linkcost = lq_calc_cost_ffeth_nl80211(&lq->smoothed_lq);
160       triggered = true;
161     }
162   } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
163
164   if (!triggered) {
165     return;
166   }
167
168   OLSR_FOR_ALL_LINK_ENTRIES(link) {
169     lq = (struct lq_ffeth_hello *)link->linkquality;
170
171     if (lq->smoothed_lq.valueLq >= 254 && lq->smoothed_lq.valueNlq >= 254) {
172       continue;
173     }
174
175     if (lq->smoothed_lq.valueLq == lq->lq.valueLq && lq->smoothed_lq.valueNlq == lq->lq.valueNlq) {
176       continue;
177     }
178
179     memcpy(&lq->smoothed_lq, &lq->lq, sizeof(struct lq_ffeth));
180     link->linkcost = lq_calc_cost_ffeth_nl80211(&lq->smoothed_lq);
181   } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
182
183   olsr_relevant_linkcost_change();
184 }
185
186 static void
187 lq_parser_ffeth_nl80211(struct olsr *olsr, struct interface *in_if, union olsr_ip_addr *from_addr)
188 {
189   const union olsr_ip_addr *main_addr;
190   struct link_entry *lnk;
191   struct lq_ffeth_hello *lq;
192   uint32_t seq_diff;
193
194   /* Find main address */
195   main_addr = mid_lookup_main_addr(from_addr);
196
197   /* Loopup link entry */
198   lnk = lookup_link_entry(from_addr, main_addr, in_if);
199   if (lnk == NULL) {
200     return;
201   }
202
203   lq = (struct lq_ffeth_hello *)lnk->linkquality;
204
205   /* ignore double package */
206   if (lq->last_seq_nr == olsr->olsr_seqno) {
207     struct ipaddr_str buf;
208     olsr_syslog(OLSR_LOG_INFO, "detected duplicate packet with seqnr %d from %s on %s (%d Bytes)",
209                 olsr->olsr_seqno,olsr_ip_to_string(&buf, from_addr),in_if->int_name,ntohs(olsr->olsr_packlen));
210     return;
211   }
212
213   if (lq->last_seq_nr > olsr->olsr_seqno) {
214     seq_diff = (uint32_t) olsr->olsr_seqno + 65536 - lq->last_seq_nr;
215   } else {
216     seq_diff = olsr->olsr_seqno - lq->last_seq_nr;
217   }
218
219   /* Jump in sequence numbers ? */
220   if (seq_diff > 256) {
221     seq_diff = 1;
222   }
223
224   lq->received[lq->activePtr]++;
225   lq->total[lq->activePtr] += seq_diff;
226
227   lq->last_seq_nr = olsr->olsr_seqno;
228   lq->missed_hellos = 0;
229 }
230
231 static void
232 lq_ffeth_nl80211_timer(void __attribute__ ((unused)) * context)
233 {
234   struct link_entry *link;
235
236 #ifdef LINUX_NL80211
237         nl80211_link_info_get();
238 #endif
239
240   OLSR_FOR_ALL_LINK_ENTRIES(link) {
241     struct lq_ffeth_hello *tlq = (struct lq_ffeth_hello *)link->linkquality;
242     fpm ratio;
243     int i, received, total;
244
245     received = 0;
246     total = 0;
247
248     /* enlarge window if still in quickstart phase */
249     if (tlq->windowSize < LQ_FFETH_WINDOW) {
250       tlq->windowSize++;
251     }
252     for (i = 0; i < tlq->windowSize; i++) {
253       received += tlq->received[i];
254       total += tlq->total[i];
255     }
256
257     /* calculate link quality */
258     if (total == 0) {
259       tlq->lq.valueLq = 0;
260     } else {
261       // start with link-loss-factor
262       ratio = fpmidiv(itofpm(link->loss_link_multiplier), LINK_LOSS_MULTIPLIER);
263
264       /* keep missed hello periods in mind (round up hello interval to seconds) */
265       if (tlq->missed_hellos > 1) {
266         received = received - received * tlq->missed_hellos * link->inter->hello_etime/1000 / LQ_FFETH_WINDOW;
267       }
268
269       // calculate received/total factor
270       ratio = fpmmuli(ratio, received);
271       ratio = fpmidiv(ratio, total);
272       ratio = fpmmuli(ratio, 255);
273
274       tlq->lq.valueLq = (uint8_t) (fpmtoi(ratio));
275     }
276
277     /* ethernet booster */
278     if (link->inter->mode == IF_MODE_ETHER) {
279       if (tlq->lq.valueLq > (uint8_t)(0.95 * 255)) {
280         tlq->perfect_eth = true;
281       }
282       else if (tlq->lq.valueLq > (uint8_t)(0.90 * 255)) {
283         tlq->perfect_eth = false;
284       }
285
286       if (tlq->perfect_eth) {
287         tlq->lq.valueLq = 255;
288       }
289     }
290     else if (link->inter->mode != IF_MODE_ETHER && tlq->lq.valueLq > 0) {
291       tlq->lq.valueLq--;
292     }
293
294     // shift buffer
295     tlq->activePtr = (tlq->activePtr + 1) % LQ_FFETH_WINDOW;
296     tlq->total[tlq->activePtr] = 0;
297     tlq->received[tlq->activePtr] = 0;
298
299   } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
300
301   lq_ffeth_nl80211_handle_lqchange();
302 }
303
304 static void
305 lq_initialize_ffeth_nl80211(void)
306 {
307   if (olsr_cnf->lq_nat_thresh < 1.0f) {
308     fprintf(stderr, "Warning, nat_treshold < 1.0 is more likely to produce loops with etx_ffeth\n");
309   }
310   olsr_packetparser_add_function(&lq_parser_ffeth_nl80211);
311   olsr_start_timer(1000, 0, OLSR_TIMER_PERIODIC, &lq_ffeth_nl80211_timer, NULL, 0);
312
313 #ifdef LINUX_NL80211
314   nl80211_link_info_init();
315 #endif
316 }
317
318 static olsr_linkcost
319 lq_calc_cost_ffeth_nl80211(const void *ptr)
320 {
321   const struct lq_ffeth *lq = ptr;
322   olsr_linkcost cost;
323   bool ether;
324   int lq_int, nlq_int;
325 #ifdef LINUX_NL80211
326   fpm nl80211 = itofpm((int) lq->valueBandwidth + lq->valueRSSI);
327 #endif
328
329   // MINIMAL_USEFUL_LQ is a float, multiplying by 255 converts it to uint8_t
330   if (lq->valueLq < (unsigned int)(255 * MINIMAL_USEFUL_LQ) || lq->valueNlq < (unsigned int)(255 * MINIMAL_USEFUL_LQ)) {
331     return LINK_COST_BROKEN;
332   }
333
334   ether = lq->valueLq == 255 && lq->valueNlq == 255;
335
336   lq_int = (int)lq->valueLq;
337   if (lq_int > 0 && lq_int < 255) {
338     lq_int++;
339   }
340
341   nlq_int = (int)lq->valueNlq;
342   if (nlq_int > 0 && nlq_int < 255) {
343     nlq_int++;
344   }
345
346 #ifdef LINUX_NL80211
347   nl80211 = fpmidiv(nl80211, 255);
348   cost = fpmidiv(itofpm(255 * 255), lq_int * nlq_int); // 1 / (LQ * NLQ)
349   cost = fpmadd(cost, nl80211);
350 #else
351   cost = fpmidiv(itofpm(255 * 255), lq_int * nlq_int); // 1 / (LQ * NLQ)
352 #endif
353   if (ether) {
354     /* ethernet boost */
355     cost /= 10;
356   }
357
358   if (cost > LINK_COST_BROKEN)
359     return LINK_COST_BROKEN;
360   if (cost == 0)
361     return 1;
362   return cost;
363 }
364
365 static int
366 lq_serialize_hello_lq_pair_ffeth_nl80211(unsigned char *buff, void *ptr)
367 {
368   struct lq_ffeth *lq = ptr;
369
370 #ifdef LINUX_NL80211
371   buff[0] = lq->valueBandwidth;
372   buff[1] = lq->valueRSSI;
373 #else
374   buff[0] = (unsigned char)(0);
375   buff[1] = (unsigned char)(0);
376 #endif
377   buff[2] = (unsigned char)lq->valueLq;
378   buff[3] = (unsigned char)lq->valueNlq;
379
380   return 4;
381 }
382
383 static void
384 lq_deserialize_hello_lq_pair_ffeth_nl80211(const uint8_t ** curr, void *ptr)
385 {
386   struct lq_ffeth *lq = ptr;
387
388 #ifdef LINUX_NL80211
389   pkt_get_u8(curr, &lq->valueBandwidth);
390   pkt_get_u8(curr, &lq->valueRSSI);
391 #else
392   pkt_ignore_u16(curr);
393 #endif
394   pkt_get_u8(curr, &lq->valueLq);
395   pkt_get_u8(curr, &lq->valueNlq);
396 }
397
398 static int
399 lq_serialize_tc_lq_pair_ffeth_nl80211(unsigned char *buff, void *ptr)
400 {
401   struct lq_ffeth *lq = ptr;
402
403 #ifdef LINUX_NL80211
404   buff[0] = lq->valueBandwidth;
405   buff[1] = lq->valueRSSI;
406 #else
407   buff[0] = (unsigned char)(0);
408   buff[1] = (unsigned char)(0);
409 #endif
410   buff[2] = (unsigned char)lq->valueLq;
411   buff[3] = (unsigned char)lq->valueNlq;
412
413   return 4;
414 }
415
416 static void
417 lq_deserialize_tc_lq_pair_ffeth_nl80211(const uint8_t ** curr, void *ptr)
418 {
419   struct lq_ffeth *lq = ptr;
420
421 #ifdef LINUX_NL80211
422   pkt_get_u8(curr, &lq->valueBandwidth);
423   pkt_get_u8(curr, &lq->valueRSSI);
424 #else
425   pkt_ignore_u16(curr);
426 #endif
427   pkt_get_u8(curr, &lq->valueLq);
428   pkt_get_u8(curr, &lq->valueNlq);
429 }
430
431 static void
432 lq_packet_loss_worker_ffeth_nl80211(struct link_entry *link,
433     void __attribute__ ((unused)) *ptr, bool lost)
434 {
435   struct lq_ffeth_hello *tlq = (struct lq_ffeth_hello *)link->linkquality;
436
437   if (lost) {
438     tlq->missed_hellos++;
439   }
440   return;
441 }
442
443 static void
444 lq_memorize_foreign_hello_ffeth_nl80211(void *ptrLocal, void *ptrForeign)
445 {
446   struct lq_ffeth_hello *local = ptrLocal;
447   struct lq_ffeth *foreign = ptrForeign;
448
449   if (foreign) {
450     local->lq.valueNlq = foreign->valueLq;
451   } else {
452     local->lq.valueNlq = 0;
453   }
454 }
455
456 static void
457 lq_copy_link2neigh_ffeth_nl80211(void *t, void *s)
458 {
459   struct lq_ffeth *target = t;
460   struct lq_ffeth_hello *source = s;
461   *target = source->smoothed_lq;
462 }
463
464 static void
465 lq_copy_link2tc_ffeth_nl80211(void *t, void *s)
466 {
467   struct lq_ffeth *target = t;
468   struct lq_ffeth_hello *source = s;
469   *target = source->smoothed_lq;
470 }
471
472 static void
473 lq_clear_ffeth_nl80211(void *target)
474 {
475   memset(target, 0, sizeof(struct lq_ffeth));
476 }
477
478 static void
479 lq_clear_ffeth_nl80211_hello(void *target)
480 {
481   struct lq_ffeth_hello *local = target;
482   int i;
483
484   lq_clear_ffeth_nl80211(&local->lq);
485   lq_clear_ffeth_nl80211(&local->smoothed_lq);
486   local->windowSize = LQ_FFETH_QUICKSTART_INIT;
487   for (i = 0; i < LQ_FFETH_WINDOW; i++) {
488     local->total[i] = 3;
489   }
490 }
491
492 static const char *
493 lq_print_ffeth_nl80211(void *ptr, char separator, struct lqtextbuffer *buffer)
494 {
495   struct lq_ffeth *lq = ptr;
496   int lq_int, nlq_int;
497
498   lq_int = (int)lq->valueLq;
499   if (lq_int > 0 && lq_int < 255) {
500     lq_int++;
501   }
502
503   nlq_int = (int)lq->valueNlq;
504   if (nlq_int > 0 && nlq_int < 255) {
505     nlq_int++;
506   }
507
508   snprintf(buffer->buf, sizeof(buffer->buf), "%s%c%s", fpmtoa(fpmidiv(itofpm(lq_int), 255)), separator,
509            fpmtoa(fpmidiv(itofpm(nlq_int), 255)));
510   return buffer->buf;
511 }
512
513 static const char *
514 lq_print_cost_ffeth_nl80211(olsr_linkcost cost, struct lqtextbuffer *buffer)
515 {
516   snprintf(buffer->buf, sizeof(buffer->buf), "%s", fpmtoa(cost));
517   return buffer->buf;
518 }
519
520 #endif /* LINUX_NL80211 */
521 #endif /* __linux__ */
522
523 /*
524  * Local Variables:
525  * c-basic-offset: 2
526  * indent-tabs-mode: nil
527  * End:
528  */