gnrc_ipv6_auto_subnets.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2021 ML!PA Consulting GmbH
3  *
4  * This file is subject to the terms and conditions of the GNU Lesser
5  * General Public License v2.1. See the file LICENSE in the top level
6  * directory for more details.
7  */
8 
102 #include "compiler_hints.h"
103 #include "macros/utils.h"
104 #include "net/gnrc/ipv6.h"
105 #include "net/gnrc/netif.h"
106 #include "net/gnrc/netif/hdr.h"
107 #include "net/gnrc/udp.h"
108 #include "net/gnrc/ipv6/nib.h"
109 #include "net/gnrc/ndp.h"
110 #include "net/gnrc/rpl.h"
111 #include "random.h"
112 #include "xtimer.h"
113 
117 #ifndef CONFIG_GNRC_IPV6_AUTO_SUBNETS_PORT
118 #define CONFIG_GNRC_IPV6_AUTO_SUBNETS_PORT (16179)
119 #endif
120 
124 #ifndef CONFIG_GNRC_IPV6_AUTO_SUBNETS_PEERS_MAX
125 #define CONFIG_GNRC_IPV6_AUTO_SUBNETS_PEERS_MAX (4)
126 #endif
127 
131 #ifndef CONFIG_GNRC_IPV6_AUTO_SUBNETS_TX_PER_PERIOD
132 #define CONFIG_GNRC_IPV6_AUTO_SUBNETS_TX_PER_PERIOD (3)
133 #endif
134 
139 #ifndef CONFIG_GNRC_IPV6_AUTO_SUBNETS_TIMEOUT_MS
140 #define CONFIG_GNRC_IPV6_AUTO_SUBNETS_TIMEOUT_MS (50)
141 #endif
142 
152 #ifndef CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_FIX_LEN
153 #define CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_FIX_LEN (0)
154 #endif
155 
160 #ifndef CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_MIN_LEN
161 #define CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_MIN_LEN (0)
162 #endif
163 
173 #ifndef CONFIG_GNRC_IPV6_AUTO_SUBNETS_NUMOF
174 #define CONFIG_GNRC_IPV6_AUTO_SUBNETS_NUMOF (1)
175 #endif
176 
185 #ifndef CONFIG_GNRC_IPV6_AUTO_SUBNETS_STATIC
186 #define CONFIG_GNRC_IPV6_AUTO_SUBNETS_STATIC (0)
187 #endif
188 
189 /* Code below should not be included by Doxygen */
190 #ifndef DOXYGEN
191 
192 #define SERVER_THREAD_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
193 #define SERVER_MSG_QUEUE_SIZE (CONFIG_GNRC_IPV6_AUTO_SUBNETS_PEERS_MAX)
194 #define SERVER_MSG_TYPE_TIMEOUT (0x8fae)
195 
196 #define ENABLE_DEBUG 0
197 #include "debug.h"
198 
199 static char addr_str[IPV6_ADDR_MAX_STR_LEN];
200 
201 #if !IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_SIMPLE)
202 
206 typedef struct __attribute__((packed)) {
207  uint8_t version;
208  uint8_t num_subnets;
209 } _auto_subnets_request_v0_t;
210 
211 /* keep a copy of PIO information in memory */
212 static gnrc_netif_t *_upstream;
214 static mutex_t _pio_cache_lock;
215 
216 static char auto_subnets_stack[SERVER_THREAD_STACKSIZE];
217 static msg_t server_queue[SERVER_MSG_QUEUE_SIZE];
218 
219 /* store neighbor routers l2 address to ignore duplicate packets */
220 static uint8_t l2addrs[CONFIG_GNRC_IPV6_AUTO_SUBNETS_PEERS_MAX]
222 
223 /* PID of the event thread */
224 static kernel_pid_t _server_pid;
225 
226 static bool _store_pio(const ndp_opt_pi_t *pio)
227 {
228  mutex_lock(&_pio_cache_lock);
229 
230  for (unsigned i = 0; i < ARRAY_SIZE(_pio_cache); ++i) {
231  if (_pio_cache[i].len == 0) {
232  _pio_cache[i] = *pio;
233 
234  mutex_unlock(&_pio_cache_lock);
235  return true;
236  }
237  }
238 
239  mutex_unlock(&_pio_cache_lock);
240  return false;
241 }
242 
243 static int _send_udp(gnrc_netif_t *netif, const ipv6_addr_t *addr,
244  uint16_t port, const void *data, size_t len)
245 {
246  gnrc_pktsnip_t *payload, *udp, *ip;
247 
248  /* allocate payload */
249  payload = gnrc_pktbuf_add(NULL, data, len, GNRC_NETTYPE_UNDEF);
250  if (payload == NULL) {
251  DEBUG("auto_subnets: unable to copy data to packet buffer\n");
252  return -ENOBUFS;
253  }
254 
255  /* allocate UDP header, set source port := destination port */
256  udp = gnrc_udp_hdr_build(payload, port, port);
257  if (udp == NULL) {
258  DEBUG("auto_subnets: unable to allocate UDP header\n");
259  gnrc_pktbuf_release(payload);
260  return -ENOBUFS;
261  }
262 
263  /* allocate IPv6 header */
264  ip = gnrc_ipv6_hdr_build(udp, NULL, addr);
265  if (ip == NULL) {
266  DEBUG("auto_subnets: unable to allocate IPv6 header\n");
267  gnrc_pktbuf_release(udp);
268  return -ENOBUFS;
269  }
270 
271  /* add netif header, if interface was given */
272  if (netif != NULL) {
273  gnrc_pktsnip_t *netif_hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
274  if (netif_hdr == NULL) {
275  DEBUG("auto_subnets: unable to allocate netif header\n");
277  return -ENOBUFS;
278  }
279 
280  gnrc_netif_hdr_set_netif(netif_hdr->data, netif);
281  ip = gnrc_pkt_prepend(ip, netif_hdr);
282  }
283 
284  /* send packet */
287  DEBUG("auto_subnets: unable to locate UDP thread\n");
289  return -ENETUNREACH;
290  }
291 
292  return 0;
293 }
294 #endif /* !IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_SIMPLE) */
295 
296 static void _init_sub_prefix(ipv6_addr_t *out,
297  const ipv6_addr_t *prefix, uint8_t bits,
298  uint8_t idx, uint8_t idx_bits)
299 {
300  uint8_t bytes = bits / 8;
301  uint8_t rem = bits % 8;
302  int8_t shift = 8 - rem - idx_bits;
303 
304  /* first copy old prefix */
305  memset(out, 0, sizeof(*out));
306  ipv6_addr_init_prefix(out, prefix, bits);
307 
308  /* if new bits are between bytes, first copy over the most significant bits */
309  if (shift < 0) {
310  out->u8[bytes] |= idx >> -shift;
311  out->u8[++bytes] = 0;
312  shift += 8;
313  }
314 
315  /* shift remaining bits at the end of the prefix */
316  out->u8[bytes] |= idx << shift;
317 }
318 
319 static uint8_t _init_sub_prefix_eui(ipv6_addr_t *out,
320  const ipv6_addr_t *prefix, uint8_t bits,
321  const uint8_t *eui, uint8_t eui_len)
322 {
323  assert(eui_len <= sizeof(uint64_t));
324 
325  /* If the EUI is too large, discard most significant bits as
326  those are typically manufacturer ID */
327  uint64_t mask = UINT64_MAX >> bits;
328 
329  union {
330  uint64_t u64;
331  uint8_t u8[8];
332  } eui64 = {};
333  uint64_t pfx = byteorder_ntohll(prefix->u64[0]);
334 
335  /* If EUI is small, we want to preserve leftover unused bits at the end */
336  uint8_t bits_total = bits + 8 * eui_len;
337  uint8_t shift = bits_total < 64
338  ? 64 - bits_total
339  : 0;
340 
341  /* treat EUI as a EUI-64 with unused bytes set to 0 */
342  memcpy(&eui64.u8[sizeof(uint64_t) - eui_len], eui, eui_len);
343  eui64.u64 = ntohll(eui64.u64) & mask;
344 
345  /* create downstream prefix from upstream prefix + masked EUI64 */
346  out->u64[0] = byteorder_htonll(pfx | (eui64.u64 << shift));
347 
348  /* we don't create prefixes that longer than 64 bits */
349  return MIN(64, bits_total);
350 }
351 
352 /* returns true if a new prefix was added, false if nothing changed */
353 static bool _remove_old_prefix(gnrc_netif_t *netif,
354  const ipv6_addr_t *pfx, uint8_t pfx_len,
355  gnrc_pktsnip_t **ext_opts)
356 {
357  gnrc_ipv6_nib_pl_t entry;
358  gnrc_pktsnip_t *tmp;
359  void *state = NULL;
360  ipv6_addr_t old_pfx;
361  uint8_t old_pfx_len = CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_FIX_LEN;
362 
363  /* iterate prefix list to see if the prefix already exists */
364  while (gnrc_ipv6_nib_pl_iter(netif->pid, &state, &entry)) {
365  uint8_t match_len = ipv6_addr_match_prefix(&entry.pfx, pfx);
366 
367  /* The prefix did not change - nothing to do here */
368  if (match_len >= pfx_len && pfx_len == entry.pfx_len) {
369  return false;
370  }
371 
372  /* find prefix that is closest to the new prefix */
373  if (match_len > old_pfx_len) {
374  old_pfx_len = entry.pfx_len;
375  old_pfx = entry.pfx;
376  }
377  }
378 
379  /* no prefix found */
381  return true;
382  }
383 
384  DEBUG("auto_subnets: remove old prefix %s/%u\n",
385  ipv6_addr_to_str(addr_str, &old_pfx, sizeof(addr_str)), old_pfx_len);
386 
387  /* invalidate old prefix in RIO */
388  tmp = gnrc_ndp_opt_ri_build(&old_pfx, old_pfx_len, 0,
389  NDP_OPT_RI_FLAGS_PRF_ZERO, *ext_opts);
390  if (tmp) {
391  *ext_opts = tmp;
392  }
393 
394  /* remove the prefix */
395  gnrc_ipv6_nib_pl_del(netif->pid, &old_pfx, old_pfx_len);
396 
397  return true;
398 }
399 
400 static void _configure_subnets(uint8_t subnets, uint8_t start_idx, gnrc_netif_t *upstream,
401  const ndp_opt_pi_t *pio, const ipv6_addr_t *src)
402 {
403  gnrc_netif_t *downstream = NULL;
404  gnrc_pktsnip_t *ext_opts = NULL;
405  const ipv6_addr_t *prefix = &pio->prefix;
406  uint32_t valid_ltime = byteorder_ntohl(pio->valid_ltime);
407  uint32_t pref_ltime = byteorder_ntohl(pio->pref_ltime);
408  const uint8_t prefix_len = pio->prefix_len;
409  uint8_t new_prefix_len, subnet_len;
410 
411  DEBUG("auto_subnets: create %u subnets, start with %u\n", subnets, start_idx);
412 
413  /* Calculate remaining prefix length.
414  * For n subnets we consume floor(log_2 n) + 1 bits.
415  * To calculate floor(log_2 n) quickly, find the position of the
416  * most significant set bit by counting leading zeros.
417  */
418  subnet_len = 32 - __builtin_clz(subnets);
419  new_prefix_len = prefix_len + subnet_len;
420 
421  if (new_prefix_len > 64) {
422  DEBUG("auto_subnets: can't split /%u into %u subnets\n", prefix_len, subnets);
423  return;
424  }
425 
428  }
429 
430  while ((downstream = gnrc_netif_iter(downstream))) {
431  gnrc_pktsnip_t *tmp;
432  ipv6_addr_t new_prefix;
433  int idx;
434 
435  if (downstream == upstream) {
436  continue;
437  }
438 
439  /* create subnet from upstream prefix */
440  if (IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_EUI)) {
441  uint8_t hwaddr[GNRC_NETIF_L2ADDR_MAXLEN];
442  int hwaddr_len = netif_get_opt(&downstream->netif, NETOPT_ADDRESS, 0,
443  hwaddr, sizeof(hwaddr));
444  if (hwaddr_len <= 0) {
445  DEBUG("auto_subnets: can't get l2 address from netif %u\n", downstream->pid);
446  continue;
447  }
448  new_prefix_len = _init_sub_prefix_eui(&new_prefix, prefix, prefix_len, hwaddr, hwaddr_len);
449  new_prefix_len = MAX(new_prefix_len, CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_MIN_LEN);
450  } else {
451  _init_sub_prefix(&new_prefix, prefix, prefix_len, ++start_idx, subnet_len);
452  }
453 
454  DEBUG("auto_subnets: configure prefix %s/%u on %u\n",
455  ipv6_addr_to_str(addr_str, &new_prefix, sizeof(addr_str)),
456  new_prefix_len, downstream->pid);
457 
458  /* first remove old prefix if the prefix changed */
459  if (_remove_old_prefix(downstream, &new_prefix, new_prefix_len, &ext_opts)) {
460 
461  /* configure subnet on downstream interface */
462  idx = gnrc_netif_ipv6_add_prefix(downstream, &new_prefix, new_prefix_len,
463  valid_ltime, pref_ltime);
464  if (idx < 0) {
465  DEBUG("auto_subnets: adding prefix to %u failed\n", downstream->pid);
466  continue;
467  }
468 
469  /* start advertising subnet */
470  gnrc_ipv6_nib_change_rtr_adv_iface(downstream, true);
471 
472  /* configure RPL root if applicable */
473  gnrc_rpl_configure_root(downstream, &downstream->ipv6.addrs[idx]);
474  }
475 
476  /* add route information option with new subnet */
477  tmp = gnrc_ndp_opt_ri_build(&new_prefix, new_prefix_len, valid_ltime,
478  NDP_OPT_RI_FLAGS_PRF_ZERO, ext_opts);
479  if (tmp == NULL) {
480  DEBUG("auto_subnets: No space left in packet buffer. Not adding RIO\n");
481  } else {
482  ext_opts = tmp;
483  }
484  }
485 
486  /* immediately send an RA with RIO */
487  if (ext_opts) {
488  gnrc_ndp_rtr_adv_send(upstream, NULL, src, true, ext_opts);
489  } else {
490  DEBUG("auto_subnets: Options empty, not sending RA\n");
491  }
492 }
493 
494 void gnrc_ipv6_nib_rtr_adv_pio_cb(gnrc_netif_t *upstream, const ndp_opt_pi_t *pio,
495  const ipv6_addr_t *src)
496 {
497  /* create a subnet for each downstream interface */
498  unsigned subnets = gnrc_netif_numof() - 1;
499 
500  if (subnets == 0) {
501  return;
502  }
503 
504  if (pio->valid_ltime.u32 == 0) {
505  return;
506  }
507 
508  /* only consider prefix meant for autonomous address configuration */
509  if (!(pio->flags & NDP_OPT_PI_FLAGS_A)) {
510  return;
511  }
512 
513 #if IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_SIMPLE)
514  /* 'don't broadcast RA if we are a 6lo node - unicast allows l2 retransmissions */
515  if (!gnrc_netif_is_6ln(upstream)) {
516  src = NULL;
517  }
518  /* if we are the only router on this bus, we can directly choose a prefix */
519  _configure_subnets(subnets, 0, upstream, pio, src);
520 #else
521  (void)src;
522 
523  /* store PIO information for later use */
524  if (!_store_pio(pio)) {
525  DEBUG("auto_subnets: no space left in PIO cache, increase CONFIG_GNRC_IPV6_AUTO_SUBNETS_NUMOF\n");
526  return;
527  }
528  _upstream = upstream;
529 
530  /* start advertising by sending timeout message to the server thread */
531  msg_t m = {
532  .type = SERVER_MSG_TYPE_TIMEOUT
533  };
534 
535  msg_send(&m, _server_pid);
536 #endif /* !IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_SIMPLE) */
537 }
538 
539 #if !IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_SIMPLE)
548 static bool _all_zero(const uint8_t *addr, size_t len)
549 {
550  for (const uint8_t *end = addr + len; addr != end; ++addr) {
551  if (*addr) {
552  return false;
553  }
554  }
555  return true;
556 }
557 
568 static int _alloc_l2addr_entry(const void *addr, size_t len)
569 {
570  int empty = -1;
571  for (unsigned i = 0; i < CONFIG_GNRC_IPV6_AUTO_SUBNETS_PEERS_MAX; ++i) {
572  if (_all_zero(l2addrs[i], len)) {
573  empty = i;
574  continue;
575  }
576  if (memcmp(addr, l2addrs[i], len) == 0) {
577  return 0;
578  }
579  }
580 
581  if (empty < 0) {
582  return -1;
583  }
584 
585  memcpy(l2addrs[empty], addr, len);
586  return 1;
587 }
588 
604 static int _get_my_l2addr_rank(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt)
605 {
606  const void *src_addr;
607  gnrc_pktsnip_t *netif_hdr;
608  gnrc_netif_hdr_t *hdr;
609 
610  if (iface == NULL) {
611  return 0;
612  }
613 
615  if (netif_hdr == NULL) {
616  return 0;
617  }
618 
619  /* ignore packet if it was received on the wrong interface */
620  hdr = netif_hdr->data;
621  if (iface->pid != hdr->if_pid) {
622  return 0;
623  }
624 
625  /* ignore packets without source address */
626  src_addr = gnrc_netif_hdr_get_src_addr(hdr);
627  if (src_addr == NULL) {
628  return 0;
629  }
630 
631  /* check if we have seen the host before */
632  if (_alloc_l2addr_entry(src_addr, iface->l2addr_len) == 0) {
633  return 0;
634  }
635 
636  return memcmp(iface->l2addr, src_addr, iface->l2addr_len);
637 }
638 
639 static void _receive_announce(gnrc_pktsnip_t *pkt, uint8_t *subnets, uint8_t *idx_start)
640 {
641  _auto_subnets_request_v0_t *request = pkt->data;
642 
643  /* Check if we already got an announcement from that host, */
644  /* in this case, res will be 0. */
645  int res = _get_my_l2addr_rank(_upstream, pkt);
646  if (res) {
647  /* calculate total number of subnets */
648  *subnets += request->num_subnets;
649 
650  DEBUG("auto_subnets: %u new remote subnets, total %u\n",
651  request->num_subnets, *subnets);
652 
653  /* If other host is before us in order of MAC addresses, add
654  * their subnets to our offset */
655  if (res > 0) {
656  *idx_start += request->num_subnets;
657  }
658  }
659 
660  gnrc_pktbuf_release(pkt);
661 }
662 
663 static void _send_announce(uint8_t local_subnets, xtimer_t *timer, msg_t *msg)
664 {
665  uint32_t timeout_us;
666  _auto_subnets_request_v0_t request = {
667  .num_subnets = local_subnets,
668  };
669 
670  /* broadcast the number of subnets we want to create */
671  _send_udp(_upstream, &ipv6_addr_all_routers_link_local,
673  &request, sizeof(request));
674 
675  /* configure timeout for resend */
676  timeout_us = random_uint32_range(
679  xtimer_set_msg(timer, timeout_us, msg, _server_pid);
680  DEBUG("auto_subnets: announce sent, next timeout in %" PRIu32 " µs\n", timeout_us);
681 }
682 
683 static void _process_pio_cache(uint8_t subnets, uint8_t idx_start, gnrc_netif_t *upstream)
684 {
685  mutex_lock(&_pio_cache_lock);
686 
687  for (unsigned i = 0; i < ARRAY_SIZE(_pio_cache); ++i) {
688  if (!_pio_cache[i].len) {
689  continue;
690  }
691 
692  /* use PIO for prefix configuration */
693  _configure_subnets(subnets, idx_start, upstream, &_pio_cache[i], NULL);
694 
695  /* invalidate entry */
696  _pio_cache[i].len = 0;
697  }
698 
699  mutex_unlock(&_pio_cache_lock);
700 }
701 
702 static void *_eventloop(void *arg)
703 {
704  (void)arg;
705 
706  xtimer_t timeout_timer;
707  msg_t msg, timeout_msg = { .type = SERVER_MSG_TYPE_TIMEOUT };
709  const uint8_t local_subnets = gnrc_netif_numof() - 1;
710  uint8_t idx_start = 0;
711  uint8_t subnets = local_subnets;
713 
714  /* only used with CONFIG_GNRC_IPV6_AUTO_SUBNETS_STATIC set */
715  uint8_t idx_old = 0;
716  uint8_t subnets_old = 0;
717 
718  DEBUG("auto_subnets: %u local subnets\n", subnets);
719 
720  if (subnets == 0) {
721  return NULL;
722  }
723 
724  /* setup the message queue */
725  msg_init_queue(server_queue, SERVER_MSG_QUEUE_SIZE);
726 
727  /* register server to receive messages from given port */
730 
731  while (1) {
732  msg_receive(&msg);
733 
734  switch (msg.type) {
736  _receive_announce(msg.content.ptr, &subnets, &idx_start);
737  break;
738  case SERVER_MSG_TYPE_TIMEOUT:
739  if (tx_period--) {
740  /* send subnet announcement */
741  _send_announce(local_subnets, &timeout_timer, &timeout_msg);
742  } else {
743 
744  /* don't re-enumerate subnets of a downstream router goes down */
746  /* If we got less subnets than before, use the old value */
747  if (subnets < subnets_old) {
748  subnets = subnets_old;
749  idx_start = idx_old;
750  }
751  /* Store subnet high water mark for later use */
752  else {
753  subnets_old = subnets;
754  idx_old = idx_start;
755  }
756  }
757 
758  /* config round done, configure subnets */
759  _process_pio_cache(subnets, idx_start, _upstream);
760 
761  /* start a new round of counting */
763  memset(l2addrs, 0, sizeof(l2addrs));
764  idx_start = 0;
765  subnets = local_subnets;
766  }
767  break;
768  }
769  }
770 
771  /* never reached */
772  return NULL;
773 }
774 
775 void gnrc_ipv6_auto_subnets_init(void)
776 {
777  /* initiate auto_subnets thread */
778  _server_pid = thread_create(auto_subnets_stack, sizeof(auto_subnets_stack),
779  THREAD_PRIORITY_MAIN - 1, 0,
780  _eventloop, NULL, "auto_subnets");
781 }
782 #endif /* !IS_USED(MODULE_GNRC_IPV6_AUTO_SUBNETS_SIMPLE) */
783 #endif /* !DOXYGEN */
#define assert(cond)
abort the program if assertion is false
Definition: assert.h:136
static uint64_t ntohll(uint64_t v)
Convert from network byte order to host byte order, 64 bit.
Definition: byteorder.h:546
static uint32_t byteorder_ntohl(network_uint32_t v)
Convert from network byte order to host byte order, 32 bit.
Definition: byteorder.h:511
static network_uint64_t byteorder_htonll(uint64_t v)
Convert from host byte order to network byte order, 64 bit.
Definition: byteorder.h:499
static uint64_t byteorder_ntohll(network_uint64_t v)
Convert from network byte order to host byte order, 64 bit.
Definition: byteorder.h:516
Common macros and compiler attributes/pragmas configuration.
static unsigned may_be_zero(unsigned n)
Wrapper function to silence "comparison is always false due to limited range of data type" t...
#define ARRAY_SIZE(a)
Calculate the number of elements in a static array.
Definition: container.h:83
Various helper macros.
#define MIN(a, b)
Get the minimum of the two parameters.
Definition: utils.h:63
#define MAX(a, b)
Get the maximum of the two parameters.
Definition: utils.h:53
Debug-header.
#define DEBUG(...)
Print debug information to stdout.
Definition: debug.h:125
Definitions for GNRC's IPv6 implementation.
GNRC-specific neighbor discovery definitions.
Definition for GNRC's network interfaces.
UDP GNRC definition.
void msg_init_queue(msg_t *array, int num)
Initialize the current thread's message queue.
int msg_send(msg_t *m, kernel_pid_t target_pid)
Send a message (blocking).
int msg_receive(msg_t *m)
Receive a message.
int16_t kernel_pid_t
Unique process identifier.
Definition: sched.h:139
#define KERNEL_PID_UNDEF
Canonical identifier for an invalid PID.
Definition: sched.h:110
void mutex_unlock(mutex_t *mutex)
Unlocks the mutex.
static void mutex_lock(mutex_t *mutex)
Locks a mutex, blocking.
Definition: mutex.h:312
kernel_pid_t thread_create(char *stack, int stacksize, uint8_t priority, int flags, thread_task_func_t task_func, void *arg, const char *name)
Creates a new thread.
static kernel_pid_t thread_getpid(void)
Returns the process ID of the currently running thread.
Definition: thread.h:393
#define ENETUNREACH
Network unreachable.
Definition: errno.h:109
#define ENOBUFS
No buffer space available.
Definition: errno.h:111
#define CONFIG_GNRC_IPV6_AUTO_SUBNETS_PEERS_MAX
Max number of other routers on the same link.
#define CONFIG_GNRC_IPV6_AUTO_SUBNETS_TIMEOUT_MS
How long to wait for other routers announcements before resending or creating subnets when the retry ...
#define CONFIG_GNRC_IPV6_AUTO_SUBNETS_STATIC
Enable this if you have a static network that might experience high packet loss under certain conditi...
#define CONFIG_GNRC_IPV6_AUTO_SUBNETS_PORT
Port for the custom UDP sync protocol.
#define CONFIG_GNRC_IPV6_AUTO_SUBNETS_TX_PER_PERIOD
How often the number subnets should be announced by the routers.
#define CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_MIN_LEN
Minimal length of a new prefix.
#define CONFIG_GNRC_IPV6_AUTO_SUBNETS_PREFIX_FIX_LEN
How many bits of a new prefix have to match the old prefix for it to be considered for replacement.
#define CONFIG_GNRC_IPV6_AUTO_SUBNETS_NUMOF
Number of subnets that can be configured.
gnrc_pktsnip_t * gnrc_ipv6_hdr_build(gnrc_pktsnip_t *payload, const ipv6_addr_t *src, const ipv6_addr_t *dst)
Builds an IPv6 header for sending and adds it to the packet buffer.
#define CONFIG_GNRC_IPV6_NIB_L2ADDR_MAX_LEN
Maximum link-layer address length (aligned)
Definition: conf.h:261
bool gnrc_ipv6_nib_pl_iter(unsigned iface, void **state, gnrc_ipv6_nib_pl_t *ple)
Iterates over all prefix list entries in the NIB.
void gnrc_ipv6_nib_pl_del(unsigned iface, const ipv6_addr_t *pfx, unsigned pfx_len)
Deletes prefix from NIB.
void gnrc_ipv6_nib_change_rtr_adv_iface(gnrc_netif_t *netif, bool enable)
Changes the state if an interface advertises itself as a router or not.
void gnrc_ndp_rtr_adv_send(gnrc_netif_t *netif, const ipv6_addr_t *src, const ipv6_addr_t *dst, bool fin, gnrc_pktsnip_t *ext_opts)
Send pre-compiled router advertisement depending on a given network interface.
gnrc_pktsnip_t * gnrc_ndp_opt_ri_build(const ipv6_addr_t *prefix, uint8_t prefix_len, uint32_t route_ltime, uint8_t flags, gnrc_pktsnip_t *next)
Builds the route information option.
static int gnrc_netapi_dispatch_send(gnrc_nettype_t type, uint32_t demux_ctx, gnrc_pktsnip_t *pkt)
Sends a GNRC_NETAPI_MSG_TYPE_SND command to all subscribers to (type, demux_ctx).
Definition: netapi.h:181
#define GNRC_NETAPI_MSG_TYPE_RCV
Messaging / IPC type for passing a Packet up the network stack
Definition: netapi.h:74
#define GNRC_NETIF_L2ADDR_MAXLEN
Maximum length of the link-layer address.
Definition: conf.h:158
gnrc_pktsnip_t * gnrc_netif_hdr_build(const uint8_t *src, uint8_t src_len, const uint8_t *dst, uint8_t dst_len)
Builds a generic network interface header for sending and adds it to the packet buffer.
static void gnrc_netif_hdr_set_netif(gnrc_netif_hdr_t *hdr, const gnrc_netif_t *netif)
Convenience function to set the interface of an interface header, given the network interface.
Definition: hdr.h:396
static uint8_t * gnrc_netif_hdr_get_src_addr(const gnrc_netif_hdr_t *hdr)
Get the source address from the given header.
Definition: hdr.h:198
unsigned gnrc_netif_numof(void)
Get number of network interfaces actually allocated.
gnrc_netif_t * gnrc_netif_iter(const gnrc_netif_t *prev)
Iterate over all network interfaces.
#define GNRC_NETREG_DEMUX_CTX_ALL
Demux context value to get all packets of a certain type.
Definition: netreg.h:80
static void gnrc_netreg_entry_init_pid(gnrc_netreg_entry_t *entry, uint32_t demux_ctx, kernel_pid_t pid)
Initializes a netreg entry dynamically with PID.
Definition: netreg.h:272
#define GNRC_NETREG_ENTRY_INIT_PID(demux_ctx, pid)
Initializes a netreg entry statically with PID.
Definition: netreg.h:101
int gnrc_netreg_register(gnrc_nettype_t type, gnrc_netreg_entry_t *entry)
Registers a thread to the registry.
@ GNRC_NETTYPE_NETIF
Protocol is as defined in gnrc_netif_hdr_t.
Definition: nettype.h:61
@ GNRC_NETTYPE_UDP
Protocol is UDP.
Definition: nettype.h:135
@ GNRC_NETTYPE_UNDEF
Protocol is undefined.
Definition: nettype.h:62
static gnrc_pktsnip_t * gnrc_pkt_prepend(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *snip)
Prepends a snip to a packet.
Definition: pkt.h:196
gnrc_pktsnip_t * gnrc_pktsnip_search_type(gnrc_pktsnip_t *pkt, gnrc_nettype_t type)
Searches the packet for a packet snip of a specific type.
gnrc_pktsnip_t * gnrc_pktbuf_add(gnrc_pktsnip_t *next, const void *data, size_t size, gnrc_nettype_t type)
Adds a new gnrc_pktsnip_t and its packet to the packet buffer.
static void gnrc_pktbuf_release(gnrc_pktsnip_t *pkt)
Decreases gnrc_pktsnip_t::users of pkt atomically and removes it if it reaches 0 and reports GNRC_NET...
Definition: pktbuf.h:196
void gnrc_rpl_configure_root(gnrc_netif_t *netif, const ipv6_addr_t *dodag_id)
Convenience function to start a RPL root using the default configuration.
gnrc_pktsnip_t * gnrc_udp_hdr_build(gnrc_pktsnip_t *payload, uint16_t src, uint16_t dst)
Allocate and initialize a fresh UDP header in the packet buffer.
const ipv6_addr_t ipv6_addr_all_routers_link_local
#define IPV6_ADDR_MAX_STR_LEN
Maximum length of an IPv6 address as string.
Definition: addr.h:53
char * ipv6_addr_to_str(char *result, const ipv6_addr_t *addr, uint8_t result_len)
Converts an IPv6 address to its string representation.
void ipv6_addr_init_prefix(ipv6_addr_t *out, const ipv6_addr_t *prefix, uint8_t bits)
Sets IPv6 address out with the first bits taken from prefix and leaves the remaining bits untouched.
uint8_t ipv6_addr_match_prefix(const ipv6_addr_t *a, const ipv6_addr_t *b)
Checks up to which bit-count two IPv6 addresses match in their prefix.
#define NDP_OPT_RI_FLAGS_PRF_ZERO
zero preference
Definition: ndp.h:114
#define NDP_OPT_PI_FLAGS_A
autonomous address configuration
Definition: ndp.h:104
int netif_get_opt(const netif_t *netif, netopt_t opt, uint16_t context, void *value, size_t max_len)
Gets option from an interface.
@ NETOPT_ADDRESS
(byte array, see below) link layer address in network byte order
Definition: netopt.h:69
uint32_t random_uint32_range(uint32_t a, uint32_t b)
generates a random number r with a <= r < b.
#define US_PER_MS
The number of microseconds per millisecond.
Definition: time_units.h:90
static void xtimer_set_msg(xtimer_t *timer, uint32_t offset, msg_t *msg, kernel_pid_t target_pid)
Set a timer that sends a message.
#define IS_USED(module)
Checks whether a module is being used or not.
Definition: modules.h:71
Generic network interface header.
NIB definitions.
Common interface to the software PRNG.
RPL header.
Prefix list entry view on NIB.
Definition: pl.h:38
uint8_t pfx_len
length of gnrc_ipv6_nib_pl_t::pfx in bits
Definition: pl.h:40
ipv6_addr_t pfx
prefix
Definition: pl.h:39
Generic network interface header.
Definition: hdr.h:126
kernel_pid_t if_pid
PID of network interface.
Definition: hdr.h:129
ipv6_addr_t addrs[CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF]
IPv6 unicast and anycast addresses of the interface.
Definition: ipv6.h:93
Representation of a network interface.
Definition: netif.h:135
netif_t netif
network interface descriptor
Definition: netif.h:136
uint8_t l2addr_len
Length in bytes of gnrc_netif_t::l2addr.
Definition: netif.h:199
kernel_pid_t pid
PID of the network interface's thread.
Definition: netif.h:226
uint8_t l2addr[GNRC_NETIF_L2ADDR_MAXLEN]
The link-layer address currently used as the source address on this interface.
Definition: netif.h:192
gnrc_netif_ipv6_t ipv6
IPv6 component.
Definition: netif.h:147
Entry to the Network protocol registry.
Definition: netreg.h:167
Type to represent parts (either headers or payload) of a packet, called snips.
Definition: pkt.h:108
void * data
pointer to the data of the snip
Definition: pkt.h:111
Describes a message object which can be sent between threads.
Definition: msg.h:196
uint16_t type
Type field.
Definition: msg.h:199
union msg_t::@1 content
Content of the message.
void * ptr
Pointer content field.
Definition: msg.h:201
Mutex structure.
Definition: mutex.h:146
Prefix information option format.
Definition: ndp.h:312
uint8_t flags
flags
Definition: ndp.h:316
uint8_t prefix_len
prefix length
Definition: ndp.h:315
network_uint32_t pref_ltime
preferred lifetime
Definition: ndp.h:318
network_uint32_t valid_ltime
valid lifetime
Definition: ndp.h:317
uint8_t len
length in units of 8 octets
Definition: ndp.h:314
ipv6_addr_t prefix
prefix
Definition: ndp.h:320
xtimer timer structure
Definition: xtimer.h:97
#define THREAD_PRIORITY_MAIN
Priority of the main thread.
uint32_t u32
32 bit representation
Definition: byteorder.h:85
Data type to represent an IPv6 address.
Definition: addr.h:72
uint8_t u8[16]
divided by 16 8-bit words.
Definition: addr.h:73
network_uint64_t u64[2]
divided by 2 64-bit words.
Definition: addr.h:76
xtimer interface definitions