void gnrc_netif_ipv6_group_leave_internal(gnrc_netif_t *netif, const ipv6_addr_t *addr) { int idx; assert((netif != NULL) && (addr != NULL)); gnrc_netif_acquire(netif); idx = _group_idx(netif, addr); if (idx >= 0) { ipv6_addr_set_unspecified(&netif->ipv6.groups[idx]); /* TODO: * - MLD action */ } gnrc_netif_release(netif); }
ipv6_addr_t *gnrc_netif_ipv6_addr_best_src(gnrc_netif_t *netif, const ipv6_addr_t *dst, bool ll_only) { ipv6_addr_t *best_src = NULL; BITFIELD(candidate_set, GNRC_NETIF_IPV6_ADDRS_NUMOF); assert((netif != NULL) && (dst != NULL)); memset(candidate_set, 0, sizeof(candidate_set)); gnrc_netif_acquire(netif); int first_candidate = _create_candidate_set(netif, dst, ll_only, candidate_set); if (first_candidate >= 0) { best_src = _src_addr_selection(netif, dst, candidate_set); if (best_src == NULL) { best_src = &(netif->ipv6.addrs[first_candidate]); } } gnrc_netif_release(netif); return best_src; }
int gnrc_netif_get_from_netdev(gnrc_netif_t *netif, gnrc_netapi_opt_t *opt) { int res = -ENOTSUP; gnrc_netif_acquire(netif); switch (opt->opt) { case NETOPT_HOP_LIMIT: assert(opt->data_len == sizeof(uint8_t)); *((uint8_t *)opt->data) = netif->cur_hl; res = sizeof(uint8_t); break; case NETOPT_STATS: /* XXX discussed this with Oleg, it's supposed to be a pointer */ switch ((int16_t)opt->context) { #if defined(MODULE_NETSTATS_IPV6) && defined(MODULE_GNRC_IPV6) case NETSTATS_IPV6: assert(opt->data_len == sizeof(netstats_t *)); *((netstats_t **)opt->data) = &netif->ipv6.stats; res = sizeof(&netif->ipv6.stats); break; #endif default: /* take from device */ break; } break; #ifdef MODULE_GNRC_IPV6 case NETOPT_IPV6_ADDR: { assert(opt->data_len >= sizeof(ipv6_addr_t)); ipv6_addr_t *tgt = opt->data; res = 0; for (unsigned i = 0; (res < (int)opt->data_len) && (i < GNRC_NETIF_IPV6_ADDRS_NUMOF); i++) { if (netif->ipv6.addrs_flags[i] != 0) { memcpy(tgt, &netif->ipv6.addrs[i], sizeof(ipv6_addr_t)); res += sizeof(ipv6_addr_t); tgt++; } } } break; case NETOPT_IPV6_ADDR_FLAGS: { assert(opt->data_len >= sizeof(uint8_t)); uint8_t *tgt = opt->data; res = 0; for (unsigned i = 0; (res < (int)opt->data_len) && (i < GNRC_NETIF_IPV6_ADDRS_NUMOF); i++) { if (netif->ipv6.addrs_flags[i] != 0) { *tgt = netif->ipv6.addrs_flags[i]; res += sizeof(uint8_t); tgt++; } } } break; case NETOPT_IPV6_GROUP: { assert(opt->data_len >= sizeof(ipv6_addr_t)); ipv6_addr_t *tgt = opt->data; res = 0; for (unsigned i = 0; (res < (int)opt->data_len) && (i < GNRC_NETIF_IPV6_GROUPS_NUMOF); i++) { if (!ipv6_addr_is_unspecified(&netif->ipv6.groups[i])) { memcpy(tgt, &netif->ipv6.groups[i], sizeof(ipv6_addr_t)); res += sizeof(ipv6_addr_t); tgt++; } } } break; case NETOPT_IPV6_IID: assert(opt->data_len >= sizeof(eui64_t)); if (gnrc_netif_ipv6_get_iid(netif, opt->data) == 0) { res = sizeof(eui64_t); } break; case NETOPT_MAX_PACKET_SIZE: if (opt->context == GNRC_NETTYPE_IPV6) { assert(opt->data_len == sizeof(uint16_t)); *((uint16_t *)opt->data) = netif->ipv6.mtu; res = sizeof(uint16_t); } /* else ask device */ break; #if GNRC_IPV6_NIB_CONF_ROUTER case NETOPT_IPV6_FORWARDING: assert(opt->data_len == sizeof(netopt_enable_t)); *((netopt_enable_t *)opt->data) = (gnrc_netif_is_rtr(netif)) ? NETOPT_ENABLE : NETOPT_DISABLE; res = sizeof(netopt_enable_t); break; case NETOPT_IPV6_SND_RTR_ADV: assert(opt->data_len == sizeof(netopt_enable_t)); *((netopt_enable_t *)opt->data) = (gnrc_netif_is_rtr_adv(netif)) ? NETOPT_ENABLE : NETOPT_DISABLE; res = sizeof(netopt_enable_t); break; #endif /* GNRC_IPV6_NIB_CONF_ROUTER */ #endif /* MODULE_GNRC_IPV6 */ #ifdef MODULE_GNRC_SIXLOWPAN_IPHC case NETOPT_6LO_IPHC: assert(opt->data_len == sizeof(netopt_enable_t)); *((netopt_enable_t *)opt->data) = (netif->flags & GNRC_NETIF_FLAGS_6LO_HC) ? NETOPT_ENABLE : NETOPT_DISABLE; res = sizeof(netopt_enable_t); break; #endif /* MODULE_GNRC_SIXLOWPAN_IPHC */ default: break; } if (res == -ENOTSUP) { res = netif->dev->driver->get(netif->dev, opt->opt, opt->data, opt->data_len); } gnrc_netif_release(netif); return res; }
int gnrc_netif_ipv6_addr_add_internal(gnrc_netif_t *netif, const ipv6_addr_t *addr, unsigned pfx_len, uint8_t flags) { unsigned idx = UINT_MAX; assert((netif != NULL) && (addr != NULL)); assert(!(ipv6_addr_is_multicast(addr) || ipv6_addr_is_unspecified(addr) || ipv6_addr_is_loopback(addr))); assert((pfx_len > 0) && (pfx_len <= 128)); gnrc_netif_acquire(netif); if ((flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK) == GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE) { /* set to first retransmission */ flags &= ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE; flags |= 0x1; } for (unsigned i = 0; i < GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { if (ipv6_addr_equal(&netif->ipv6.addrs[i], addr)) { gnrc_netif_release(netif); return i; } if ((idx == UINT_MAX) && (netif->ipv6.addrs_flags[i] == 0)) { idx = i; } } if (idx == UINT_MAX) { gnrc_netif_release(netif); return -ENOMEM; } netif->ipv6.addrs_flags[idx] = flags; memcpy(&netif->ipv6.addrs[idx], addr, sizeof(netif->ipv6.addrs[idx])); #ifdef MODULE_GNRC_IPV6_NIB #if GNRC_IPV6_NIB_CONF_ARSM ipv6_addr_t sol_nodes; int res; /* TODO: SHOULD delay join between 0 and MAX_RTR_SOLICITATION_DELAY * for SLAAC */ ipv6_addr_set_solicited_nodes(&sol_nodes, addr); res = gnrc_netif_ipv6_group_join_internal(netif, &sol_nodes); if (res < 0) { DEBUG("nib: Can't join solicited-nodes of %s on interface %u\n", ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), netif->pid); } #endif /* GNRC_IPV6_NIB_CONF_ARSM */ if (_get_state(netif, idx) == GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID) { void *state = NULL; gnrc_ipv6_nib_pl_t ple; bool in_pl = false; while (gnrc_ipv6_nib_pl_iter(netif->pid, &state, &ple)) { if (ipv6_addr_match_prefix(&ple.pfx, addr) >= pfx_len) { in_pl = true; } } if (!in_pl) { gnrc_ipv6_nib_pl_set(netif->pid, addr, pfx_len, UINT32_MAX, UINT32_MAX); } } #if GNRC_IPV6_NIB_CONF_SLAAC else { /* TODO: send out NS to solicited nodes for DAD probing */ } #endif #else (void)pfx_len; #endif gnrc_netif_release(netif); return idx; }
int gnrc_netif_set_from_netdev(gnrc_netif_t *netif, const gnrc_netapi_opt_t *opt) { int res = -ENOTSUP; gnrc_netif_acquire(netif); switch (opt->opt) { case NETOPT_HOP_LIMIT: assert(opt->data_len == sizeof(uint8_t)); netif->cur_hl = *((uint8_t *)opt->data); res = sizeof(uint8_t); break; #ifdef MODULE_GNRC_IPV6 case NETOPT_IPV6_ADDR: { assert(opt->data_len == sizeof(ipv6_addr_t)); /* always assume manually added */ uint8_t flags = ((((uint8_t)opt->context & 0xff) & ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK) | GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID); uint8_t pfx_len = (uint8_t)(opt->context >> 8U); /* acquire locks a recursive mutex so we are safe calling this * public function */ res = gnrc_netif_ipv6_addr_add_internal(netif, opt->data, pfx_len, flags); if (res >= 0) { res = sizeof(ipv6_addr_t); } } break; case NETOPT_IPV6_ADDR_REMOVE: assert(opt->data_len == sizeof(ipv6_addr_t)); /* acquire locks a recursive mutex so we are safe calling this * public function */ gnrc_netif_ipv6_addr_remove_internal(netif, opt->data); res = sizeof(ipv6_addr_t); break; case NETOPT_IPV6_GROUP: assert(opt->data_len == sizeof(ipv6_addr_t)); /* acquire locks a recursive mutex so we are safe calling this * public function */ res = gnrc_netif_ipv6_group_join_internal(netif, opt->data); if (res >= 0) { res = sizeof(ipv6_addr_t); } break; case NETOPT_IPV6_GROUP_LEAVE: assert(opt->data_len == sizeof(ipv6_addr_t)); /* acquire locks a recursive mutex so we are safe calling this * public function */ gnrc_netif_ipv6_group_leave_internal(netif, opt->data); res = sizeof(ipv6_addr_t); break; case NETOPT_MAX_PACKET_SIZE: if (opt->context == GNRC_NETTYPE_IPV6) { assert(opt->data_len == sizeof(uint16_t)); netif->ipv6.mtu = *((uint16_t *)opt->data); res = sizeof(uint16_t); } /* else set device */ break; #if GNRC_IPV6_NIB_CONF_ROUTER case NETOPT_IPV6_FORWARDING: assert(opt->data_len == sizeof(netopt_enable_t)); if (*(((netopt_enable_t *)opt->data)) == NETOPT_ENABLE) { netif->flags |= GNRC_NETIF_FLAGS_IPV6_FORWARDING; } else { if (gnrc_netif_is_rtr_adv(netif)) { gnrc_ipv6_nib_change_rtr_adv_iface(netif, false); } netif->flags &= ~GNRC_NETIF_FLAGS_IPV6_FORWARDING; } res = sizeof(netopt_enable_t); break; case NETOPT_IPV6_SND_RTR_ADV: assert(opt->data_len == sizeof(netopt_enable_t)); gnrc_ipv6_nib_change_rtr_adv_iface(netif, (*(((netopt_enable_t *)opt->data)) == NETOPT_ENABLE)); res = sizeof(netopt_enable_t); break; #endif /* GNRC_IPV6_NIB_CONF_ROUTER */ #endif /* MODULE_GNRC_IPV6 */ #ifdef MODULE_GNRC_SIXLOWPAN_IPHC case NETOPT_6LO_IPHC: assert(opt->data_len == sizeof(netopt_enable_t)); if (*(((netopt_enable_t *)opt->data)) == NETOPT_ENABLE) { netif->flags |= GNRC_NETIF_FLAGS_6LO_HC; } else { netif->flags &= ~GNRC_NETIF_FLAGS_6LO_HC; } res = sizeof(netopt_enable_t); break; #endif /* MODULE_GNRC_SIXLOWPAN_IPHC */ default: break; } if (res == -ENOTSUP) { res = netif->dev->driver->set(netif->dev, opt->opt, opt->data, opt->data_len); if (res > 0) { switch (opt->opt) { case NETOPT_ADDRESS: case NETOPT_ADDRESS_LONG: case NETOPT_ADDR_LEN: case NETOPT_SRC_LEN: _update_l2addr_from_dev(netif); break; default: break; } } } gnrc_netif_release(netif); return res; }
static void *_gnrc_netif_thread(void *args) { gnrc_netapi_opt_t *opt; gnrc_netif_t *netif; netdev_t *dev; int res; msg_t reply = { .type = GNRC_NETAPI_MSG_TYPE_ACK }; msg_t msg, msg_queue[_NETIF_NETAPI_MSG_QUEUE_SIZE]; DEBUG("gnrc_netif: starting thread %i\n", sched_active_pid); netif = args; gnrc_netif_acquire(netif); dev = netif->dev; netif->pid = sched_active_pid; /* setup the link-layer's message queue */ msg_init_queue(msg_queue, _NETIF_NETAPI_MSG_QUEUE_SIZE); /* register the event callback with the device driver */ dev->event_callback = _event_cb; dev->context = netif; /* initialize low-level driver */ dev->driver->init(dev); _init_from_device(netif); netif->cur_hl = GNRC_NETIF_DEFAULT_HL; #ifdef MODULE_GNRC_IPV6_NIB gnrc_ipv6_nib_init_iface(netif); #endif if (netif->ops->init) { netif->ops->init(netif); } /* now let rest of GNRC use the interface */ gnrc_netif_release(netif); while (1) { DEBUG("gnrc_netif: waiting for incoming messages\n"); msg_receive(&msg); /* dispatch netdev, MAC and gnrc_netapi messages */ switch (msg.type) { case NETDEV_MSG_TYPE_EVENT: DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_EVENT received\n"); dev->driver->isr(dev); break; case GNRC_NETAPI_MSG_TYPE_SND: DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_SND received\n"); res = netif->ops->send(netif, msg.content.ptr); if (res < 0) { DEBUG("gnrc_netif: error sending packet %p (code: %u)\n", msg.content.ptr, res); } break; case GNRC_NETAPI_MSG_TYPE_SET: opt = msg.content.ptr; #ifdef MODULE_NETOPT DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_SET received. opt=%s\n", netopt2str(opt->opt)); #else DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_SET received. opt=%d\n", opt->opt); #endif /* set option for device driver */ res = netif->ops->set(netif, opt); DEBUG("gnrc_netif: response of netif->ops->set(): %i\n", res); reply.content.value = (uint32_t)res; msg_reply(&msg, &reply); break; case GNRC_NETAPI_MSG_TYPE_GET: opt = msg.content.ptr; #ifdef MODULE_NETOPT DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_GET received. opt=%s\n", netopt2str(opt->opt)); #else DEBUG("gnrc_netif: GNRC_NETAPI_MSG_TYPE_GET received. opt=%d\n", opt->opt); #endif /* get option from device driver */ res = netif->ops->get(netif, opt); DEBUG("gnrc_netif: response of netif->ops->get(): %i\n", res); reply.content.value = (uint32_t)res; msg_reply(&msg, &reply); break; default: if (netif->ops->msg_handler) { DEBUG("gnrc_netif: delegate message of type 0x%04x to " "netif->ops->msg_handler()\n", msg.type); netif->ops->msg_handler(netif, &msg); } else { DEBUG("gnrc_netif: unknown message type 0x%04x" "(no message handler defined)\n", msg.type); } break; } } /* never reached */ return NULL; }