New feature: support for Linux NL802.11 wireless link information in cost calculation.
[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 #include "lq_plugin_ffeth_nl80211.h"
44 #include "tc_set.h"
45 #include "link_set.h"
46 #include "lq_plugin.h"
47 #include "olsr_spf.h"
48 #include "lq_packet.h"
49 #include "packet.h"
50 #include "olsr.h"
51 #include "parser.h"
52 #include "fpm.h"
53 #include "mid_set.h"
54 #include "scheduler.h"
55 #include "log.h"
56
57 #ifdef LINUX_NL80211
58 #include "nl80211_link_info.h"
59 #define WEIGHT_ETX                      50
60 #define WEIGHT_BANDWIDTH        50
61 #endif
62
63 #define LQ_PLUGIN_LC_MULTIPLIER 1024
64 #define LQ_PLUGIN_RELEVANT_COSTCHANGE_FF 16
65
66 static void lq_initialize_ffeth_nl80211(void);
67
68 static olsr_linkcost lq_calc_cost_ffeth_nl80211(const void *lq);
69
70 static void lq_packet_loss_worker_ffeth_nl80211(struct link_entry *link, void *lq, bool lost);
71 static void lq_memorize_foreign_hello_ffeth_nl80211(void *local, void *foreign);
72
73 static int lq_serialize_hello_lq_pair_ffeth_nl80211(unsigned char *buff, void *lq);
74 static void lq_deserialize_hello_lq_pair_ffeth_nl80211(const uint8_t ** curr, void *lq);
75 static int lq_serialize_tc_lq_pair_ffeth_nl80211(unsigned char *buff, void *lq);
76 static void lq_deserialize_tc_lq_pair_ffeth_nl80211(const uint8_t ** curr, void *lq);
77
78 static void lq_copy_link2neigh_ffeth_nl80211(void *t, void *s);
79 static void lq_copy_link2tc_ffeth_nl80211(void *target, void *source);
80 static void lq_clear_ffeth_nl80211(void *target);
81 static void lq_clear_ffeth_nl80211_hello(void *target);
82
83 static const char *lq_print_ffeth_nl80211(void *ptr, char separator, struct lqtextbuffer *buffer);
84 static const char *lq_print_cost_ffeth_nl80211(olsr_linkcost cost, struct lqtextbuffer *buffer);
85
86 /* etx lq plugin (freifunk fpm version) settings */
87 struct lq_handler lq_etx_ffeth_nl80211_handler = {
88   &lq_initialize_ffeth_nl80211,
89   &lq_calc_cost_ffeth_nl80211,
90   &lq_calc_cost_ffeth_nl80211,
91
92   &lq_packet_loss_worker_ffeth_nl80211,
93
94   &lq_memorize_foreign_hello_ffeth_nl80211,
95   &lq_copy_link2neigh_ffeth_nl80211,
96   &lq_copy_link2tc_ffeth_nl80211,
97   &lq_clear_ffeth_nl80211_hello,
98   &lq_clear_ffeth_nl80211,
99
100   &lq_serialize_hello_lq_pair_ffeth_nl80211,
101   &lq_serialize_tc_lq_pair_ffeth_nl80211,
102   &lq_deserialize_hello_lq_pair_ffeth_nl80211,
103   &lq_deserialize_tc_lq_pair_ffeth_nl80211,
104
105   &lq_print_ffeth_nl80211,
106   &lq_print_ffeth_nl80211,
107   &lq_print_cost_ffeth_nl80211,
108
109   sizeof(struct lq_ffeth_hello),
110   sizeof(struct lq_ffeth),
111   4,
112   4
113 };
114
115 static void
116 lq_ffeth_nl80211_handle_lqchange(void) {
117   struct lq_ffeth_hello *lq;
118   struct ipaddr_str buf;
119   struct link_entry *link;
120
121   bool triggered = false;
122
123   OLSR_FOR_ALL_LINK_ENTRIES(link) {
124     bool relevant = false;
125     lq = (struct lq_ffeth_hello *)link->linkquality;
126
127 #if 0
128   fprintf(stderr, "%s: old = %u/%u   new = %u/%u\n", olsr_ip_to_string(&buf, &link->neighbor_iface_addr),
129       lq->smoothed_lq.valueLq, lq->smoothed_lq.valueNlq,
130       lq->lq.valueLq, lq->lq.valueNlq);
131 #endif
132
133     if (lq->smoothed_lq.valueLq < lq->lq.valueLq) {
134       if (lq->lq.valueLq >= 254 || lq->lq.valueLq - lq->smoothed_lq.valueLq > lq->smoothed_lq.valueLq/10) {
135         relevant = true;
136       }
137     }
138     else if (lq->smoothed_lq.valueLq > lq->lq.valueLq) {
139       if (lq->smoothed_lq.valueLq - lq->lq.valueLq > lq->smoothed_lq.valueLq/10) {
140         relevant = true;
141       }
142     }
143     if (lq->smoothed_lq.valueNlq < lq->lq.valueNlq) {
144       if (lq->lq.valueNlq >= 254 || lq->lq.valueNlq - lq->smoothed_lq.valueNlq > lq->smoothed_lq.valueNlq/10) {
145         relevant = true;
146       }
147     }
148     else if (lq->smoothed_lq.valueNlq > lq->lq.valueNlq) {
149       if (lq->smoothed_lq.valueNlq - lq->lq.valueNlq > lq->smoothed_lq.valueNlq/10) {
150         relevant = true;
151       }
152     }
153
154     if (relevant) {
155       memcpy(&lq->smoothed_lq, &lq->lq, sizeof(struct lq_ffeth));
156       link->linkcost = lq_calc_cost_ffeth_nl80211(&lq->smoothed_lq);
157       triggered = true;
158     }
159   } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
160
161   if (!triggered) {
162     return;
163   }
164
165   OLSR_FOR_ALL_LINK_ENTRIES(link) {
166     lq = (struct lq_ffeth_hello *)link->linkquality;
167
168     if (lq->smoothed_lq.valueLq >= 254 && lq->smoothed_lq.valueNlq >= 254) {
169       continue;
170     }
171
172     if (lq->smoothed_lq.valueLq == lq->lq.valueLq && lq->smoothed_lq.valueNlq == lq->lq.valueNlq) {
173       continue;
174     }
175
176     memcpy(&lq->smoothed_lq, &lq->lq, sizeof(struct lq_ffeth));
177     link->linkcost = lq_calc_cost_ffeth_nl80211(&lq->smoothed_lq);
178   } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
179
180   olsr_relevant_linkcost_change();
181 }
182
183 static void
184 lq_parser_ffeth_nl80211(struct olsr *olsr, struct interface *in_if, union olsr_ip_addr *from_addr)
185 {
186   const union olsr_ip_addr *main_addr;
187   struct link_entry *lnk;
188   struct lq_ffeth_hello *lq;
189   uint32_t seq_diff;
190
191   /* Find main address */
192   main_addr = mid_lookup_main_addr(from_addr);
193
194   /* Loopup link entry */
195   lnk = lookup_link_entry(from_addr, main_addr, in_if);
196   if (lnk == NULL) {
197     return;
198   }
199
200   lq = (struct lq_ffeth_hello *)lnk->linkquality;
201
202   /* ignore double package */
203   if (lq->last_seq_nr == olsr->olsr_seqno) {
204     struct ipaddr_str buf;
205     olsr_syslog(OLSR_LOG_INFO, "detected duplicate packet with seqnr %d from %s on %s (%d Bytes)",
206                 olsr->olsr_seqno,olsr_ip_to_string(&buf, from_addr),in_if->int_name,ntohs(olsr->olsr_packlen));
207     return;
208   }
209
210   if (lq->last_seq_nr > olsr->olsr_seqno) {
211     seq_diff = (uint32_t) olsr->olsr_seqno + 65536 - lq->last_seq_nr;
212   } else {
213     seq_diff = olsr->olsr_seqno - lq->last_seq_nr;
214   }
215
216   /* Jump in sequence numbers ? */
217   if (seq_diff > 256) {
218     seq_diff = 1;
219   }
220
221   lq->received[lq->activePtr]++;
222   lq->total[lq->activePtr] += seq_diff;
223
224   lq->last_seq_nr = olsr->olsr_seqno;
225   lq->missed_hellos = 0;
226 }
227
228 static void
229 lq_ffeth_nl80211_timer(void __attribute__ ((unused)) * context)
230 {
231   struct link_entry *link;
232
233 #ifdef LINUX_NL80211
234         nl80211_link_info_get();
235 #endif
236
237   OLSR_FOR_ALL_LINK_ENTRIES(link) {
238     struct lq_ffeth_hello *tlq = (struct lq_ffeth_hello *)link->linkquality;
239     fpm ratio;
240     int i, received, total;
241
242     received = 0;
243     total = 0;
244
245     /* enlarge window if still in quickstart phase */
246     if (tlq->windowSize < LQ_FFETH_WINDOW) {
247       tlq->windowSize++;
248     }
249     for (i = 0; i < tlq->windowSize; i++) {
250       received += tlq->received[i];
251       total += tlq->total[i];
252     }
253
254     /* calculate link quality */
255     if (total == 0) {
256       tlq->lq.valueLq = 0;
257     } else {
258       // start with link-loss-factor
259       ratio = fpmidiv(itofpm(link->loss_link_multiplier), LINK_LOSS_MULTIPLIER);
260
261       /* keep missed hello periods in mind (round up hello interval to seconds) */
262       if (tlq->missed_hellos > 1) {
263         received = received - received * tlq->missed_hellos * link->inter->hello_etime/1000 / LQ_FFETH_WINDOW;
264       }
265
266       // calculate received/total factor
267       ratio = fpmmuli(ratio, received);
268       ratio = fpmidiv(ratio, total);
269       ratio = fpmmuli(ratio, 255);
270
271       tlq->lq.valueLq = (uint8_t) (fpmtoi(ratio));
272     }
273
274     /* ethernet booster */
275     if (link->inter->mode == IF_MODE_ETHER) {
276       if (tlq->lq.valueLq > (uint8_t)(0.95 * 255)) {
277         tlq->perfect_eth = true;
278       }
279       else if (tlq->lq.valueLq > (uint8_t)(0.90 * 255)) {
280         tlq->perfect_eth = false;
281       }
282
283       if (tlq->perfect_eth) {
284         tlq->lq.valueLq = 255;
285       }
286     }
287     else if (link->inter->mode != IF_MODE_ETHER && tlq->lq.valueLq > 0) {
288       tlq->lq.valueLq--;
289     }
290
291     // shift buffer
292     tlq->activePtr = (tlq->activePtr + 1) % LQ_FFETH_WINDOW;
293     tlq->total[tlq->activePtr] = 0;
294     tlq->received[tlq->activePtr] = 0;
295
296   } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
297
298   lq_ffeth_nl80211_handle_lqchange();
299 }
300
301 static void
302 lq_initialize_ffeth_nl80211(void)
303 {
304   if (olsr_cnf->lq_nat_thresh < 1.0) {
305     fprintf(stderr, "Warning, nat_treshold < 1.0 is more likely to produce loops with etx_ffeth\n");
306   }
307   olsr_packetparser_add_function(&lq_parser_ffeth_nl80211);
308   olsr_start_timer(1000, 0, OLSR_TIMER_PERIODIC, &lq_ffeth_nl80211_timer, NULL, 0);
309
310 #ifdef LINUX_NL80211
311   nl80211_link_info_init();
312 #endif
313 }
314
315 static olsr_linkcost
316 lq_calc_cost_ffeth_nl80211(const void *ptr)
317 {
318   const struct lq_ffeth *lq = ptr;
319   olsr_linkcost cost;
320   bool ether;
321   int lq_int, nlq_int;
322 #ifdef LINUX_NL80211
323   fpm nl80211 = itofpm((int) lq->valueBandwidth + lq->valueRSSI);
324 #endif
325
326   // MINIMAL_USEFUL_LQ is a float, multiplying by 255 converts it to uint8_t
327   if (lq->valueLq < (unsigned int)(255 * MINIMAL_USEFUL_LQ) || lq->valueNlq < (unsigned int)(255 * MINIMAL_USEFUL_LQ)) {
328     return LINK_COST_BROKEN;
329   }
330
331   ether = lq->valueLq == 255 && lq->valueNlq == 255;
332
333   lq_int = (int)lq->valueLq;
334   if (lq_int > 0 && lq_int < 255) {
335     lq_int++;
336   }
337
338   nlq_int = (int)lq->valueNlq;
339   if (nlq_int > 0 && nlq_int < 255) {
340     nlq_int++;
341   }
342
343 #ifdef LINUX_NL80211
344   nl80211 = fpmidiv(nl80211, 255);
345   cost = fpmidiv(itofpm(255 * 255), lq_int * nlq_int); // 1 / (LQ * NLQ)
346   cost = fpmadd(cost, nl80211);
347 #else
348   cost = fpmidiv(itofpm(255 * 255), lq_int * nlq_int); // 1 / (LQ * NLQ)
349 #endif
350   if (ether) {
351     /* ethernet boost */
352     cost /= 10;
353   }
354
355   if (cost > LINK_COST_BROKEN)
356     return LINK_COST_BROKEN;
357   if (cost == 0)
358     return 1;
359   return cost;
360 }
361
362 static int
363 lq_serialize_hello_lq_pair_ffeth_nl80211(unsigned char *buff, void *ptr)
364 {
365   struct lq_ffeth *lq = ptr;
366
367 #ifdef LINUX_NL80211
368   buff[0] = lq->valueBandwidth;
369   buff[1] = lq->valueRSSI;
370 #else
371   buff[0] = (unsigned char)(0);
372   buff[1] = (unsigned char)(0);
373 #endif
374   buff[2] = (unsigned char)lq->valueLq;
375   buff[3] = (unsigned char)lq->valueNlq;
376
377   return 4;
378 }
379
380 static void
381 lq_deserialize_hello_lq_pair_ffeth_nl80211(const uint8_t ** curr, void *ptr)
382 {
383   struct lq_ffeth *lq = ptr;
384
385 #ifdef LINUX_NL80211
386   pkt_get_u8(curr, &lq->valueBandwidth);
387   pkt_get_u8(curr, &lq->valueRSSI);
388 #else
389   pkt_ignore_u16(curr);
390 #endif
391   pkt_get_u8(curr, &lq->valueLq);
392   pkt_get_u8(curr, &lq->valueNlq);
393 }
394
395 static int
396 lq_serialize_tc_lq_pair_ffeth_nl80211(unsigned char *buff, void *ptr)
397 {
398   struct lq_ffeth *lq = ptr;
399
400 #ifdef LINUX_NL80211
401   buff[0] = lq->valueBandwidth;
402   buff[1] = lq->valueRSSI;
403 #else
404   buff[0] = (unsigned char)(0);
405   buff[1] = (unsigned char)(0);
406 #endif
407   buff[2] = (unsigned char)lq->valueLq;
408   buff[3] = (unsigned char)lq->valueNlq;
409
410   return 4;
411 }
412
413 static void
414 lq_deserialize_tc_lq_pair_ffeth_nl80211(const uint8_t ** curr, void *ptr)
415 {
416   struct lq_ffeth *lq = ptr;
417
418 #ifdef LINUX_NL80211
419   pkt_get_u8(curr, &lq->valueBandwidth);
420   pkt_get_u8(curr, &lq->valueRSSI);
421 #else
422   pkt_ignore_u16(curr);
423 #endif
424   pkt_get_u8(curr, &lq->valueLq);
425   pkt_get_u8(curr, &lq->valueNlq);
426 }
427
428 static void
429 lq_packet_loss_worker_ffeth_nl80211(struct link_entry *link,
430     void __attribute__ ((unused)) *ptr, bool lost)
431 {
432   struct lq_ffeth_hello *tlq = (struct lq_ffeth_hello *)link->linkquality;
433
434   if (lost) {
435     tlq->missed_hellos++;
436   }
437   return;
438 }
439
440 static void
441 lq_memorize_foreign_hello_ffeth_nl80211(void *ptrLocal, void *ptrForeign)
442 {
443   struct lq_ffeth_hello *local = ptrLocal;
444   struct lq_ffeth *foreign = ptrForeign;
445
446   if (foreign) {
447     local->lq.valueNlq = foreign->valueLq;
448   } else {
449     local->lq.valueNlq = 0;
450   }
451 }
452
453 static void
454 lq_copy_link2neigh_ffeth_nl80211(void *t, void *s)
455 {
456   struct lq_ffeth *target = t;
457   struct lq_ffeth_hello *source = s;
458   *target = source->smoothed_lq;
459 }
460
461 static void
462 lq_copy_link2tc_ffeth_nl80211(void *t, void *s)
463 {
464   struct lq_ffeth *target = t;
465   struct lq_ffeth_hello *source = s;
466   *target = source->smoothed_lq;
467 }
468
469 static void
470 lq_clear_ffeth_nl80211(void *target)
471 {
472   memset(target, 0, sizeof(struct lq_ffeth));
473 }
474
475 static void
476 lq_clear_ffeth_nl80211_hello(void *target)
477 {
478   struct lq_ffeth_hello *local = target;
479   int i;
480
481   lq_clear_ffeth_nl80211(&local->lq);
482   lq_clear_ffeth_nl80211(&local->smoothed_lq);
483   local->windowSize = LQ_FFETH_QUICKSTART_INIT;
484   for (i = 0; i < LQ_FFETH_WINDOW; i++) {
485     local->total[i] = 3;
486   }
487 }
488
489 static const char *
490 lq_print_ffeth_nl80211(void *ptr, char separator, struct lqtextbuffer *buffer)
491 {
492   struct lq_ffeth *lq = ptr;
493   int lq_int, nlq_int;
494
495   lq_int = (int)lq->valueLq;
496   if (lq_int > 0 && lq_int < 255) {
497     lq_int++;
498   }
499
500   nlq_int = (int)lq->valueNlq;
501   if (nlq_int > 0 && nlq_int < 255) {
502     nlq_int++;
503   }
504
505   snprintf(buffer->buf, sizeof(buffer->buf), "%s%c%s", fpmtoa(fpmidiv(itofpm(lq_int), 255)), separator,
506            fpmtoa(fpmidiv(itofpm(nlq_int), 255)));
507   return buffer->buf;
508 }
509
510 static const char *
511 lq_print_cost_ffeth_nl80211(olsr_linkcost cost, struct lqtextbuffer *buffer)
512 {
513   snprintf(buffer->buf, sizeof(buffer->buf), "%s", fpmtoa(cost));
514   return buffer->buf;
515 }
516
517 /*
518  * Local Variables:
519  * c-basic-offset: 2
520  * indent-tabs-mode: nil
521  * End:
522  */