static void _send_to_iface(kernel_pid_t iface, gnrc_pktsnip_t *pkt) { ((gnrc_netif_hdr_t *)pkt->data)->if_pid = iface; gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface); assert(if_entry != NULL); if (gnrc_pkt_len(pkt->next) > if_entry->mtu) { DEBUG("ipv6: packet too big\n"); gnrc_pktbuf_release(pkt); return; } #ifdef MODULE_NETSTATS_IPV6 if_entry->stats.tx_success++; if_entry->stats.tx_bytes += gnrc_pkt_len(pkt->next); #endif #ifdef MODULE_GNRC_SIXLOWPAN if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { DEBUG("ipv6: send to 6LoWPAN instead\n"); if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_SIXLOWPAN, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("ipv6: no 6LoWPAN thread found"); gnrc_pktbuf_release(pkt); } return; } #endif if (gnrc_netapi_send(iface, pkt) < 1) { DEBUG("ipv6: unable to send packet\n"); gnrc_pktbuf_release(pkt); } }
/* shell commands */ int _netif_send(int argc, char **argv) { kernel_pid_t dev; uint8_t addr[MAX_ADDR_LEN]; size_t addr_len; gnrc_pktsnip_t *pkt, *hdr; gnrc_netif_hdr_t *nethdr; uint8_t flags = 0x00; if (argc < 4) { printf("usage: %s <if> [<L2 addr>|bcast] <data>\n", argv[0]); return 1; } /* parse interface */ dev = atoi(argv[1]); if (!_is_iface(dev)) { puts("error: invalid interface given"); return 1; } /* parse address */ addr_len = gnrc_netif_addr_from_str(addr, sizeof(addr), argv[2]); if (addr_len == 0) { if (strcmp(argv[2], "bcast") == 0) { flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST; } else { puts("error: invalid address given"); return 1; } } /* put packet together */ pkt = gnrc_pktbuf_add(NULL, argv[3], strlen(argv[3]), GNRC_NETTYPE_UNDEF); if (pkt == NULL) { puts("error: packet buffer full"); return 1; } hdr = gnrc_netif_hdr_build(NULL, 0, addr, addr_len); if (hdr == NULL) { puts("error: packet buffer full"); gnrc_pktbuf_release(pkt); return 1; } LL_PREPEND(pkt, hdr); nethdr = (gnrc_netif_hdr_t *)hdr->data; nethdr->flags = flags; /* and send it */ if (gnrc_netapi_send(dev, pkt) < 1) { puts("error: unable to send"); gnrc_pktbuf_release(pkt); return 1; } return 0; }
static uint16_t _send_1st_fragment(gnrc_netif_t *iface, gnrc_pktsnip_t *pkt, size_t payload_len, size_t datagram_size) { gnrc_pktsnip_t *frag; uint16_t local_offset = 0; /* payload_len: actual size of the packet vs * datagram_size: size of the uncompressed IPv6 packet */ int payload_diff = (datagram_size - payload_len); /* virtually add payload_diff to flooring to account for offset (must be divisable by 8) * in uncompressed datagram */ uint16_t max_frag_size = _floor8(iface->sixlo.max_frag_size + payload_diff - sizeof(sixlowpan_frag_t)) - payload_diff; sixlowpan_frag_t *hdr; uint8_t *data; DEBUG("6lo frag: determined max_frag_size = %" PRIu16 "\n", max_frag_size); frag = _build_frag_pkt(pkt, payload_len, max_frag_size + sizeof(sixlowpan_frag_t)); if (frag == NULL) { return 0; } hdr = frag->next->data; data = (uint8_t *)(hdr + 1); hdr->disp_size = byteorder_htons((uint16_t)datagram_size); hdr->disp_size.u8[0] |= SIXLOWPAN_FRAG_1_DISP; hdr->tag = byteorder_htons(_tag); pkt = pkt->next; /* don't copy netif header */ while (pkt != NULL) { size_t clen = _min(max_frag_size - local_offset, pkt->size); memcpy(data + local_offset, pkt->data, clen); local_offset += clen; if (local_offset >= max_frag_size) { break; } pkt = pkt->next; } DEBUG("6lo frag: send first fragment (datagram size: %u, " "datagram tag: %" PRIu16 ", fragment size: %" PRIu16 ")\n", (unsigned int)datagram_size, _tag, local_offset); if (gnrc_netapi_send(iface->pid, frag) < 1) { DEBUG("6lo frag: unable to send first fragment\n"); gnrc_pktbuf_release(frag); } return local_offset; }
static void _send(void *data, size_t len, char *dest, size_t *dest_len) { gnrc_pktsnip_t *payload = gnrc_pktbuf_add(NULL, data, len, GNRC_NETTYPE_UNDEF); gnrc_netapi_send(_kiss_pid, payload); // force an ack using gnrc_netapi_get gnrc_netapi_get(_kiss_pid, 0, 0, NULL, 0); // read back from the file *dest_len = (size_t) ftell(_kiss_file); fseek(_kiss_file, 0, SEEK_SET); fread(dest, 1, *dest_len, _kiss_file); }
/* shell commands */ int _netif_send(int argc, char **argv) { kernel_pid_t dev; uint8_t addr[MAX_ADDR_LEN]; size_t addr_len; gnrc_pktsnip_t *pkt; gnrc_netif_hdr_t *nethdr; uint8_t flags = 0x00; if (argc < 4) { printf("usage: %s <if> [<addr>|bcast] <data>\n", argv[0]); return 1; } /* parse interface */ dev = (kernel_pid_t)atoi(argv[1]); if (!_is_iface(dev)) { puts("error: invalid interface given"); return 1; } /* parse address */ addr_len = gnrc_netif_addr_from_str(addr, sizeof(addr), argv[2]); if (addr_len == 0) { if (strcmp(argv[2], "bcast") == 0) { flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST; } else { puts("error: invalid address given"); return 1; } } /* put packet together */ pkt = gnrc_pktbuf_add(NULL, argv[3], strlen(argv[3]), GNRC_NETTYPE_UNDEF); pkt = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_netif_hdr_t) + addr_len, GNRC_NETTYPE_NETIF); nethdr = (gnrc_netif_hdr_t *)pkt->data; gnrc_netif_hdr_init(nethdr, 0, addr_len); gnrc_netif_hdr_set_dst_addr(nethdr, addr, addr_len); nethdr->flags = flags; /* and send it */ gnrc_netapi_send(dev, pkt); return 0; }
void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_addr_t *dst) { gnrc_pktsnip_t *hdr, *pkt = NULL; ipv6_addr_t *src = NULL; DEBUG("ndp internal: send neighbor solicitation (iface: %" PRIkernel_pid ", tgt: %s, ", iface, ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str))); DEBUG("dst: %s)\n", ipv6_addr_to_str(addr_str, dst, sizeof(addr_str))); /* check if there is a fitting source address to target */ if ((src = gnrc_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) { uint8_t l2src[8]; size_t l2src_len; l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add source address link-layer address option */ pkt = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, NULL); if (pkt == NULL) { DEBUG("ndp internal: error allocating Source Link-layer address option.\n"); gnrc_pktbuf_release(pkt); return; } } } hdr = gnrc_ndp_nbr_sol_build(tgt, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating Neighbor solicitation.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = _build_headers(iface, pkt, dst, src); if (hdr == NULL) { DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } gnrc_netapi_send(gnrc_ipv6_pid, hdr); }
void gnrc_ndp_internal_send_rtr_sol(kernel_pid_t iface, ipv6_addr_t *dst) { gnrc_pktsnip_t *hdr, *pkt = NULL; ipv6_addr_t *src = NULL, all_routers = IPV6_ADDR_ALL_ROUTERS_LINK_LOCAL; DEBUG("ndp internal: send router solicitation (iface: %" PRIkernel_pid ", dst: ff02::2)\n", iface); if (dst == NULL) { dst = &all_routers; } /* check if there is a fitting source address to target */ if ((src = gnrc_ipv6_netif_find_best_src_addr(iface, dst)) != NULL) { uint8_t l2src[8]; size_t l2src_len; l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add source address link-layer address option */ pkt = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, NULL); if (pkt == NULL) { DEBUG("ndp internal: error allocating Source Link-layer address option.\n"); gnrc_pktbuf_release(pkt); return; } } } hdr = gnrc_ndp_rtr_sol_build(pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating router solicitation.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = _build_headers(iface, pkt, dst, src); if (hdr == NULL) { DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) { DEBUG("ndp internal: unable to send router solicitation\n"); gnrc_pktbuf_release(hdr); } }
/* tests sending */ static int test_send(void) { ethernet_hdr_t *exp_mac = (ethernet_hdr_t *)_tmp; uint8_t *exp_payload = _tmp + sizeof(ethernet_hdr_t); gnrc_pktsnip_t *pkt, *hdr; msg_t msg; /* prepare packet for sending */ pkt = gnrc_pktbuf_add(NULL, _TEST_PAYLOAD1, sizeof(_TEST_PAYLOAD1) - 1, GNRC_NETTYPE_UNDEF); if (pkt == NULL) { puts("Could not allocate send payload"); return 0; } hdr = gnrc_netif_hdr_build(NULL, 0, (uint8_t *)_test_dst, sizeof(_test_dst)); if (hdr == NULL) { gnrc_pktbuf_release(pkt); puts("Could not allocate send header"); return 0; } LL_PREPEND(pkt, hdr); /* prepare expected data */ memcpy(exp_mac->dst, _test_dst, sizeof(_test_dst)); memcpy(exp_mac->src, _dev_addr, sizeof(_dev_addr)); exp_mac->type = byteorder_htons(ETHERTYPE_UNKNOWN); memcpy(exp_payload, _TEST_PAYLOAD1, sizeof(_TEST_PAYLOAD1) - 1); _tmp_len = sizeof(_TEST_PAYLOAD1) + sizeof(ethernet_hdr_t) - 1; /* register for returned packet status */ if (gnrc_neterr_reg(pkt) != 0) { puts("Can not register for error reporting"); return 0; } /* send packet to MAC layer */ gnrc_netapi_send(_mac_pid, pkt); /* wait for packet status and check */ msg_receive(&msg); if ((msg.type != GNRC_NETERR_MSG_TYPE) || (msg.content.value != GNRC_NETERR_SUCCESS)) { puts("Error sending packet"); return 0; } return 1; }
static int _send(int argc, char **argv) { (void) argc; (void) argv; gnrc_pktsnip_t *pkt, *hdr; gnrc_netif_hdr_t *nethdr; uint8_t addr[8]; size_t addr_len = 0; uint8_t flags = 0x00; kernel_pid_t ifs[GNRC_NETIF_NUMOF]; size_t numof = gnrc_netif_get(ifs); for (size_t i = 0; i < numof && i < GNRC_NETIF_NUMOF; i++) { flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST; /* put packet together */ conn_test_payload_t payload; payload.id = conn_test_id; // memcpy(payload.txt, CONN_TEST_PAYLOAD, sizeof(CONN_TEST_PAYLOAD)); pkt = gnrc_pktbuf_add(NULL, &payload, sizeof(payload), GNRC_NETTYPE_UNDEF); hdr = gnrc_netif_hdr_build(NULL, 0, addr, addr_len); LL_PREPEND(pkt, hdr); nethdr = (gnrc_netif_hdr_t *)hdr->data; nethdr->flags = flags; /* and send it */ if (gnrc_netapi_send(ifs[i], pkt) < 1) { puts("error: unable to send\n"); gnrc_pktbuf_release(pkt); } } return 0; }
void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst, bool fin) { gnrc_pktsnip_t *hdr, *pkt = NULL; ipv6_addr_t all_nodes = IPV6_ADDR_ALL_NODES_LINK_LOCAL; gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface); uint32_t reach_time = 0, retrans_timer = 0; uint16_t adv_ltime = 0; uint8_t cur_hl = 0; if (dst == NULL) { dst = &all_nodes; } DEBUG("ndp internal: send router advertisement (iface: %" PRIkernel_pid ", dst: %s%s\n", iface, ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), fin ? ", final" : ""); mutex_lock(&ipv6_iface->mutex); #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { #endif hdr = _add_pios(ipv6_iface, pkt); if (hdr == NULL) { /* pkt already released in _add_pios */ mutex_unlock(&ipv6_iface->mutex); return; } pkt = hdr; #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER } else { gnrc_sixlowpan_nd_router_abr_t *abr = gnrc_sixlowpan_nd_router_abr_get(); if (abr != NULL) { gnrc_sixlowpan_nd_router_prf_t *prf = abr->prfs; /* add prefixes from border router */ while (prf) { bool processed_before = false; /* skip if prefix does not belong to iface */ if (prf->iface != ipv6_iface) { prf = prf->next; continue; } /* skip if prefix has been processed already */ for (gnrc_sixlowpan_nd_router_prf_t *tmp = abr->prfs; tmp != prf; tmp = tmp->next) { if ((processed_before = _check_prefixes(prf->prefix, tmp->prefix))) { break; } } if (processed_before) { prf = prf->next; continue; } if (_pio_from_iface_addr(&hdr, prf->prefix, pkt)) { if (hdr != NULL) { pkt = hdr; } else { DEBUG("ndp rtr: error allocating PIO\n"); gnrc_pktbuf_release(pkt); return; } } prf = prf->next; } for (unsigned int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) { gnrc_sixlowpan_ctx_t *ctx; if (!bf_isset(abr->ctxs, i)) { continue; } ctx = gnrc_sixlowpan_ctx_lookup_id(i); hdr = gnrc_sixlowpan_nd_opt_6ctx_build(ctx->prefix_len, ctx->flags_id, ctx->ltime, &ctx->prefix, pkt); if (hdr == NULL) { DEBUG("ndp rtr: error allocating 6CO\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; } hdr = gnrc_sixlowpan_nd_opt_abr_build(abr->version, abr->ltime, &abr->addr, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating ABRO.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; } } #endif /* MODULE_GNRC_SIXLOWPAN_ND_ROUTER */ if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_MTU) { if ((hdr = gnrc_ndp_opt_mtu_build(ipv6_iface->mtu, pkt)) == NULL) { DEBUG("ndp rtr: no space left in packet buffer\n"); mutex_unlock(&ipv6_iface->mutex); gnrc_pktbuf_release(pkt); return; } pkt = hdr; } if (src == NULL) { mutex_unlock(&ipv6_iface->mutex); /* get address from source selection algorithm */ src = gnrc_ipv6_netif_find_best_src_addr(iface, dst); mutex_lock(&ipv6_iface->mutex); } /* add SL2A for source address */ if (src != NULL) { DEBUG(" - SL2A\n"); uint8_t l2src[8]; size_t l2src_len; /* optimization note: MAY also be omitted to facilitate in-bound load balancing over * replicated interfaces. * source: https://tools.ietf.org/html/rfc4861#section-6.2.3 */ l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add source address link-layer address option */ hdr = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating Source Link-layer address option.\n"); mutex_unlock(&ipv6_iface->mutex); gnrc_pktbuf_release(pkt); return; } pkt = hdr; } } if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_CUR_HL) { cur_hl = ipv6_iface->cur_hl; } if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_REACH_TIME) { if (ipv6_iface->reach_time > (3600 * SEC_IN_USEC)) { /* reach_time > 1 hour */ reach_time = (3600 * SEC_IN_MS); } else { reach_time = ipv6_iface->reach_time / MS_IN_USEC; } } if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_RETRANS_TIMER) { retrans_timer = ipv6_iface->retrans_timer / MS_IN_USEC; } if (!fin) { adv_ltime = ipv6_iface->adv_ltime; } mutex_unlock(&ipv6_iface->mutex); hdr = gnrc_ndp_rtr_adv_build(cur_hl, (ipv6_iface->flags & (GNRC_IPV6_NETIF_FLAGS_OTHER_CONF | GNRC_IPV6_NETIF_FLAGS_MANAGED)) >> 8, adv_ltime, reach_time, retrans_timer, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating router advertisement.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = _build_headers(iface, pkt, dst, src); if (hdr == NULL) { DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) { DEBUG("ndp internal: unable to send router advertisement\n"); gnrc_pktbuf_release(hdr); } }
void gnrc_ndp_internal_send_nbr_sol(kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *tgt, ipv6_addr_t *dst) { #ifdef MODULE_GNRC_SIXLOWPAN_ND gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface); assert(ipv6_iface != NULL); #endif gnrc_pktsnip_t *hdr, *pkt = NULL; /* both suppressions, since they are needed in the MODULE_GNRC_SIXLOWPAN_ND branch */ /* cppcheck-suppress variableScope */ uint8_t l2src[8]; /* cppcheck-suppress variableScope */ size_t l2src_len = 0; DEBUG("ndp internal: send neighbor solicitation (iface: %" PRIkernel_pid ", src: %s, ", iface, ipv6_addr_to_str(addr_str, src, sizeof(addr_str))); DEBUG(" tgt: %s, ", ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str))); DEBUG("dst: %s)\n", ipv6_addr_to_str(addr_str, dst, sizeof(addr_str))); /* check if there is a fitting source address to target */ if (src == NULL) { src = gnrc_ipv6_netif_find_best_src_addr(iface, tgt); } if (src != NULL) { l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add source address link-layer address option */ pkt = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, NULL); if (pkt == NULL) { DEBUG("ndp internal: error allocating Source Link-layer address option.\n"); gnrc_pktbuf_release(pkt); return; } } } #ifdef MODULE_GNRC_SIXLOWPAN_ND if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) { if (l2src_len != sizeof(eui64_t)) { l2src_len = (uint16_t)gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, l2src, sizeof(l2src)); if (l2src_len != sizeof(eui64_t)) { DEBUG("ndp internal: can't get EUI-64 of the interface\n"); gnrc_pktbuf_release(pkt); return; } } hdr = gnrc_sixlowpan_nd_opt_ar_build(0, GNRC_SIXLOWPAN_ND_AR_LTIME, (eui64_t *)l2src, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocatin Address Registration option.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; } #endif hdr = gnrc_ndp_nbr_sol_build(tgt, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating Neighbor solicitation.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = _build_headers(iface, pkt, dst, src); if (hdr == NULL) { DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) { DEBUG("ndp internal: unable to send neighbor solicitation\n"); gnrc_pktbuf_release(hdr); } }
void gnrc_ndp_internal_send_nbr_adv(kernel_pid_t iface, ipv6_addr_t *tgt, ipv6_addr_t *dst, bool supply_tl2a, gnrc_pktsnip_t *ext_opts) { gnrc_pktsnip_t *hdr, *pkt = ext_opts; uint8_t adv_flags = 0; DEBUG("ndp internal: send neighbor advertisement (iface: %" PRIkernel_pid ", tgt: %s, ", iface, ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str))); DEBUG("dst: %s, supply_tl2a: %d)\n", ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), supply_tl2a); if ((gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) && (gnrc_ipv6_netif_get(iface)->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV)) { adv_flags |= NDP_NBR_ADV_FLAGS_R; } if (ipv6_addr_is_unspecified(dst)) { ipv6_addr_set_all_nodes_multicast(dst, IPV6_ADDR_MCAST_SCP_LINK_LOCAL); } else { adv_flags |= NDP_NBR_ADV_FLAGS_S; } if (supply_tl2a) { uint8_t l2src[8]; size_t l2src_len; /* we previously checked if we are the target, so we can take our L2src */ l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add target address link-layer address option */ pkt = gnrc_ndp_opt_tl2a_build(l2src, l2src_len, pkt); if (pkt == NULL) { DEBUG("ndp internal: error allocating Target Link-layer address option.\n"); gnrc_pktbuf_release(ext_opts); return; } } } /* TODO: also check if the node provides proxy servies for tgt */ if ((pkt != NULL) && !gnrc_ipv6_netif_addr_is_non_unicast(tgt)) { /* TL2A is not supplied and tgt is not anycast */ adv_flags |= NDP_NBR_ADV_FLAGS_O; } hdr = gnrc_ndp_nbr_adv_build(adv_flags, tgt, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating Neighbor advertisement.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = _build_headers(iface, pkt, dst, NULL); if (hdr == NULL) { DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } if (gnrc_ipv6_netif_addr_is_non_unicast(tgt)) { /* avoid collision for anycast addresses * (see https://tools.ietf.org/html/rfc4861#section-7.2.7) */ uint32_t delay = genrand_uint32_range(0, GNRC_NDP_MAX_AC_TGT_DELAY * SEC_IN_USEC); gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, dst); DEBUG("ndp internal: delay neighbor advertisement for %" PRIu32 " sec.", (delay / SEC_IN_USEC)); /* nc_entry must be set so no need to check it */ assert(nc_entry); _send_delayed(&nc_entry->nbr_adv_timer, &nc_entry->nbr_adv_msg, delay, hdr); } else if (gnrc_netapi_send(gnrc_ipv6_pid, hdr) < 1) { DEBUG("ndp internal: unable to send neighbor advertisement\n"); gnrc_pktbuf_release(hdr); } }
void gnrc_icmpv6_echo_req_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6_hdr, icmpv6_echo_t *echo, uint16_t len) { uint8_t *payload = ((uint8_t *)echo) + sizeof(icmpv6_echo_t); gnrc_pktsnip_t *hdr, *pkt; gnrc_netreg_entry_t *sendto = NULL; if ((echo == NULL) || (len < sizeof(icmpv6_echo_t))) { DEBUG("icmpv6_echo: echo was NULL or len (%" PRIu16 ") was < sizeof(icmpv6_echo_t)\n", len); return; } pkt = gnrc_icmpv6_echo_build(ICMPV6_ECHO_REP, byteorder_ntohs(echo->id), byteorder_ntohs(echo->seq), payload, len - sizeof(icmpv6_echo_t)); if (pkt == NULL) { DEBUG("icmpv6_echo: no space left in packet buffer\n"); return; } if (ipv6_addr_is_multicast(&ipv6_hdr->dst)) { hdr = gnrc_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)&ipv6_hdr->src, sizeof(ipv6_addr_t)); } else { hdr = gnrc_ipv6_hdr_build(pkt, (uint8_t *)&ipv6_hdr->dst, sizeof(ipv6_addr_t), (uint8_t *)&ipv6_hdr->src, sizeof(ipv6_addr_t)); } if (hdr == NULL) { DEBUG("icmpv6_echo: no space left in packet buffer\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0); ((gnrc_netif_hdr_t *)hdr->data)->if_pid = iface; LL_PREPEND(pkt, hdr); sendto = gnrc_netreg_lookup(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL); if (sendto == NULL) { DEBUG("icmpv6_echo: no receivers for IPv6 packets\n"); gnrc_pktbuf_release(pkt); return; } /* ICMPv6 is not interested anymore so `- 1` */ gnrc_pktbuf_hold(pkt, gnrc_netreg_num(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { if (gnrc_netapi_send(sendto->pid, pkt) < 1) { DEBUG("icmpv6_echo: unable to send packet\n"); gnrc_pktbuf_release(pkt); } sendto = gnrc_netreg_getnext(sendto); } }
static void _send(gnrc_pktsnip_t *pkt) { gnrc_netif_hdr_t *hdr; gnrc_pktsnip_t *pkt2; gnrc_netif_t *iface; /* datagram_size: pure IPv6 packet without 6LoWPAN dispatches or compression */ size_t datagram_size; if ((pkt == NULL) || (pkt->size < sizeof(gnrc_netif_hdr_t))) { DEBUG("6lo: Sending packet has no netif header\n"); gnrc_pktbuf_release(pkt); return; } if ((pkt->next == NULL) || (pkt->next->type != GNRC_NETTYPE_IPV6)) { DEBUG("6lo: Sending packet has no IPv6 header\n"); gnrc_pktbuf_release(pkt); return; } pkt2 = gnrc_pktbuf_start_write(pkt); if (pkt2 == NULL) { DEBUG("6lo: no space left in packet buffer\n"); gnrc_pktbuf_release(pkt); return; } hdr = pkt2->data; iface = gnrc_netif_get_by_pid(hdr->if_pid); datagram_size = gnrc_pkt_len(pkt2->next); if (iface == NULL) { DEBUG("6lo: Can not get 6LoWPAN specific interface information.\n"); gnrc_pktbuf_release(pkt); return; } #ifdef MODULE_GNRC_SIXLOWPAN_IPHC if (iface->flags & GNRC_NETIF_FLAGS_6LO_HC) { if (!gnrc_sixlowpan_iphc_encode(pkt2)) { DEBUG("6lo: error on IPHC encoding\n"); gnrc_pktbuf_release(pkt2); return; } /* IPHC dispatch does not count on dispatch length since it _shortens_ * the datagram */ } else { if (!_add_uncompr_disp(pkt2)) { /* adding uncompressed dispatch failed */ DEBUG("6lo: no space left in packet buffer\n"); gnrc_pktbuf_release(pkt2); return; } } #else /* suppress clang-analyzer report about iface being not read */ (void) iface; if (!_add_uncompr_disp(pkt2)) { /* adding uncompressed dispatch failed */ DEBUG("6lo: no space left in packet buffer\n"); gnrc_pktbuf_release(pkt2); return; } #endif DEBUG("6lo: iface->sixlo.max_frag_size = %" PRIu16 " for interface %" PRIkernel_pid "\n", iface->sixlo.max_frag_size, hdr->if_pid); /* IP should not send anything here if it is not a 6LoWPAN interface, * so we don't need to check for NULL pointers. * Note, that datagram_size cannot be used here, because the header size * might be changed by IPHC. */ if (gnrc_pkt_len(pkt2->next) <= iface->sixlo.max_frag_size) { DEBUG("6lo: Send SND command for %p to %" PRIu16 "\n", (void *)pkt2, hdr->if_pid); if (gnrc_netapi_send(hdr->if_pid, pkt2) < 1) { DEBUG("6lo: unable to send %p over %" PRIu16 "\n", (void *)pkt, hdr->if_pid); gnrc_pktbuf_release(pkt2); } return; } #ifdef MODULE_GNRC_SIXLOWPAN_FRAG else if (fragment_msg.pkt != NULL) { DEBUG("6lo: Fragmentation already ongoing. Dropping packet\n"); gnrc_pktbuf_release(pkt2); return; } else if (datagram_size <= SIXLOWPAN_FRAG_MAX_LEN) { DEBUG("6lo: Send fragmented (%u > %" PRIu16 ")\n", (unsigned int)datagram_size, iface->max_frag_size); msg_t msg; fragment_msg.pid = hdr->if_pid; fragment_msg.pkt = pkt2; fragment_msg.datagram_size = datagram_size; /* Sending the first fragment has an offset==0 */ fragment_msg.offset = 0; /* set the outgoing message's fields */ msg.type = GNRC_SIXLOWPAN_MSG_FRAG_SND; msg.content.ptr = &fragment_msg; /* send message to self */ msg_send_to_self(&msg); } else { DEBUG("6lo: packet too big (%u > %" PRIu16 ")\n", (unsigned int)datagram_size, (uint16_t)SIXLOWPAN_FRAG_MAX_LEN); gnrc_pktbuf_release(pkt2); } #else (void) datagram_size; DEBUG("6lo: packet too big (%u > %" PRIu16 ")\n", (unsigned int)datagram_size, iface->max_frag_size); gnrc_pktbuf_release(pkt2); #endif }
void gnrc_ndp_internal_send_rtr_adv(kernel_pid_t iface, ipv6_addr_t *src, ipv6_addr_t *dst, bool fin) { gnrc_pktsnip_t *hdr, *pkt = NULL; ipv6_addr_t all_nodes = IPV6_ADDR_ALL_NODES_LINK_LOCAL; gnrc_ipv6_netif_t *ipv6_iface = gnrc_ipv6_netif_get(iface); uint32_t reach_time = 0, retrans_timer = 0; uint16_t adv_ltime = 0; uint8_t cur_hl = 0; if (dst == NULL) { dst = &all_nodes; } DEBUG("ndp internal: send router advertisement (iface: %" PRIkernel_pid ", dst: %s%s\n", iface, ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), fin ? ", final" : ""); mutex_lock(&ipv6_iface->mutex); hdr = _add_pios(ipv6_iface, pkt); if (hdr == NULL) { /* pkt already released in _add_pios */ mutex_unlock(&ipv6_iface->mutex); return; } pkt = hdr; if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_MTU) { if ((hdr = gnrc_ndp_opt_mtu_build(ipv6_iface->mtu, pkt)) == NULL) { DEBUG("ndp rtr: no space left in packet buffer\n"); mutex_unlock(&ipv6_iface->mutex); gnrc_pktbuf_release(pkt); return; } pkt = hdr; } if (src == NULL) { /* get address from source selection algorithm */ src = gnrc_ipv6_netif_find_best_src_addr(iface, dst); } /* add SL2A for source address */ if (src != NULL) { DEBUG(" - SL2A\n"); uint8_t l2src[8]; size_t l2src_len; /* optimization note: MAY also be omitted to facilitate in-bound load balancing over * replicated interfaces. * source: https://tools.ietf.org/html/rfc4861#section-6.2.3 */ l2src_len = _get_l2src(iface, l2src, sizeof(l2src)); if (l2src_len > 0) { /* add source address link-layer address option */ hdr = gnrc_ndp_opt_sl2a_build(l2src, l2src_len, NULL); if (hdr == NULL) { DEBUG("ndp internal: error allocating Source Link-layer address option.\n"); mutex_unlock(&ipv6_iface->mutex); gnrc_pktbuf_release(pkt); return; } pkt = hdr; } } if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_CUR_HL) { cur_hl = ipv6_iface->cur_hl; } if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_REACH_TIME) { uint64_t tmp = timex_uint64(ipv6_iface->reach_time) / MS_IN_USEC; if (tmp > (3600 * SEC_IN_MS)) { /* tmp > 1 hour */ tmp = (3600 * SEC_IN_MS); } reach_time = (uint32_t)tmp; } if (ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ADV_RETRANS_TIMER) { uint64_t tmp = timex_uint64(ipv6_iface->retrans_timer) / MS_IN_USEC; if (tmp > UINT32_MAX) { tmp = UINT32_MAX; } retrans_timer = (uint32_t)tmp; } if (!fin) { adv_ltime = ipv6_iface->adv_ltime; } mutex_unlock(&ipv6_iface->mutex); hdr = gnrc_ndp_rtr_adv_build(cur_hl, (ipv6_iface->flags & (GNRC_IPV6_NETIF_FLAGS_OTHER_CONF | GNRC_IPV6_NETIF_FLAGS_MANAGED)) >> 8, adv_ltime, reach_time, retrans_timer, pkt); if (hdr == NULL) { DEBUG("ndp internal: error allocating router advertisement.\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = _build_headers(iface, pkt, dst, src); if (hdr == NULL) { DEBUG("ndp internal: error adding lower-layer headers.\n"); gnrc_pktbuf_release(pkt); return; } gnrc_netapi_send(gnrc_ipv6_pid, hdr); }
static uint16_t _send_nth_fragment(gnrc_sixlowpan_netif_t *iface, gnrc_pktsnip_t *pkt, size_t payload_len, size_t datagram_size, uint16_t offset) { gnrc_pktsnip_t *frag; /* since dispatches aren't supposed to go into subsequent fragments, we need not account * for payload difference as for the first fragment */ uint16_t max_frag_size = _floor8(iface->max_frag_size - sizeof(sixlowpan_frag_n_t)); uint16_t local_offset = 0, offset_count = 0; sixlowpan_frag_n_t *hdr; uint8_t *data; DEBUG("6lo frag: determined max_frag_size = %" PRIu16 "\n", max_frag_size); frag = _build_frag_pkt(pkt, payload_len - offset + sizeof(sixlowpan_frag_n_t), max_frag_size + sizeof(sixlowpan_frag_n_t)); if (frag == NULL) { return 0; } hdr = frag->next->data; data = (uint8_t *)(hdr + 1); /* XXX: truncation of datagram_size > 4095 may happen here */ hdr->disp_size = byteorder_htons((uint16_t)datagram_size); hdr->disp_size.u8[0] |= SIXLOWPAN_FRAG_N_DISP; hdr->tag = byteorder_htons(_tag); /* don't mention payload diff in offset */ hdr->offset = (uint8_t)((offset + (datagram_size - payload_len)) >> 3); pkt = pkt->next; /* don't copy netif header */ while ((pkt != NULL) && (offset_count != offset)) { /* go to offset */ offset_count += (uint16_t)pkt->size; if (offset_count > offset) { /* we overshot */ /* => copy rest of partly send packet snip */ uint16_t pkt_offset = offset - (offset_count - ((uint16_t)pkt->size)); size_t clen = _min(max_frag_size, pkt->size - pkt_offset); memcpy(data, ((uint8_t *)pkt->data) + pkt_offset, clen); local_offset = clen; pkt = pkt->next; break; } pkt = pkt->next; } if (local_offset < max_frag_size) { /* copy other packet snips */ while (pkt != NULL) { size_t clen = _min(max_frag_size - local_offset, pkt->size); memcpy(data + local_offset, pkt->data, clen); local_offset += clen; if (local_offset == max_frag_size) { break; } pkt = pkt->next; } } DEBUG("6lo frag: send subsequent fragment (datagram size: %u, " "datagram tag: %" PRIu16 ", offset: %" PRIu8 " (%u bytes), " "fragment size: %" PRIu16 ")\n", (unsigned int)datagram_size, _tag, hdr->offset, hdr->offset << 3, local_offset); gnrc_netapi_send(iface->pid, frag); return local_offset; }
void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, ndp_nbr_adv_t *nbr_adv, size_t icmpv6_size) { uint16_t opt_offset = 0; uint8_t *buf = ((uint8_t *)nbr_adv) + sizeof(ndp_nbr_adv_t); int l2tgt_len = 0; uint8_t l2tgt[GNRC_IPV6_NC_L2_ADDR_MAX]; int sicmpv6_size = (int)icmpv6_size; gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &nbr_adv->tgt); gnrc_pktsnip_t *netif; gnrc_netif_hdr_t *netif_hdr = NULL; DEBUG("ndp: received neighbor advertisement (src: %s, ", ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str))); DEBUG("dst: %s, ", ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str))); DEBUG("tgt: %s)\n", ipv6_addr_to_str(addr_str, &nbr_adv->tgt, sizeof(addr_str))); /* check validity */ if ((ipv6->hl != 255) || (nbr_adv->code != 0) || (icmpv6_size < sizeof(ndp_nbr_adv_t)) || ipv6_addr_is_multicast(&nbr_adv->tgt)) { DEBUG("ndp: neighbor advertisement was invalid.\n"); /* ipv6 releases */ return; } if (nc_entry == NULL) { /* see https://tools.ietf.org/html/rfc4861#section-7.2.5 */ DEBUG("ndp: no neighbor cache entry found for advertisement's target\n"); /* ipv6 releases */ return; } sicmpv6_size -= sizeof(ndp_nbr_adv_t); while (sicmpv6_size > 0) { ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NDP_OPT_TL2A: if ((l2tgt_len = gnrc_ndp_internal_tl2a_opt_handle(pkt, ipv6, nbr_adv->type, opt, l2tgt)) < 0) { /* invalid target link-layer address option */ return; } break; #ifdef MODULE_GNRC_SIXLOWPAN_ND case NDP_OPT_AR: /* address registration option is always ignored when invalid */ gnrc_sixlowpan_nd_opt_ar_handle(iface, ipv6, nbr_adv->type, &nbr_adv->tgt, (sixlowpan_nd_opt_ar_t *)opt, NULL, 0); break; #endif default: /* silently discard all other options */ break; } opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); #if ENABLE_DEBUG if (sicmpv6_size < 0) { DEBUG("ndp: Option parsing out of sync.\n"); } #endif } LL_SEARCH_SCALAR(pkt, netif, type, GNRC_NETTYPE_NETIF); if (netif != NULL) { netif_hdr = netif->data; } if (l2tgt_len != -ENOTSUP) { #ifdef MODULE_GNRC_SIXLOWPAN_ND /* check if entry wasn't removed by ARO, ideally there should not be any TL2A in here */ nc_entry = gnrc_ipv6_nc_get(iface, &nbr_adv->tgt); if (nc_entry == NULL) { return; } #endif if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) { if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) { /* link-layer has addresses, but no TLLAO supplied: discard silently * (see https://tools.ietf.org/html/rfc4861#section-7.2.5) */ return; } nc_entry->iface = iface; nc_entry->l2_addr_len = l2tgt_len; memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len); if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE); } else { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE); } if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_R) { nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER; } else { nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER; /* TODO: update state of neighbor as router in FIB? */ } #ifdef MODULE_GNRC_NDP_NODE gnrc_pktqueue_t *queued_pkt; while ((queued_pkt = gnrc_pktqueue_remove_head(&nc_entry->pkts)) != NULL) { if (gnrc_netapi_send(gnrc_ipv6_pid, queued_pkt->pkt) < 1) { DEBUG("ndp: unable to send queued packet\n"); gnrc_pktbuf_release(queued_pkt->pkt); } queued_pkt->pkt = NULL; } #endif } else { /* first or-term: no link-layer, but nc_entry has l2addr, * second or-term: different l2addr cached */ bool l2tgt_changed = false; if ((!_pkt_has_l2addr(netif_hdr)) && (l2tgt_len == 0)) { /* there was previously a L2 address registered */ l2tgt_changed = (nc_entry->l2_addr_len != 0); } /* link-layer has addresses and TLLAO with different address */ else if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len != 0)) { l2tgt_changed = (!(l2tgt_len == nc_entry->l2_addr_len)) && (memcmp(nc_entry->l2_addr, l2tgt, l2tgt_len) == 0); } if ((nbr_adv->flags & NDP_NBR_ADV_FLAGS_O) || !l2tgt_changed || (l2tgt_len == 0)) { if (l2tgt_len != 0) { nc_entry->iface = iface; nc_entry->l2_addr_len = l2tgt_len; memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len); } if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE); } else if (l2tgt_changed) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE); } if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_R) { nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER; } else { nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER; /* TODO: update state of neighbor as router in FIB? */ } } else if (l2tgt_changed && gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_REACHABLE) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE); } } } return; }
/* send a beacon */ void beaconing_send(void) { gnrc_pktsnip_t *pkt, *hdr; gnrc_netif_hdr_t *nethdr; /* put packet together */ beacon_t b = { .magic_key = BEACONING_MK, .id = dow_my_id }; pkt = gnrc_pktbuf_add(NULL, &b, sizeof(b), GNRC_NETTYPE_UNDEF); if (pkt == NULL) { puts("error: packet buffer full"); return; } hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0); if (hdr == NULL) { puts("error: packet buffer full"); gnrc_pktbuf_release(pkt); return; } LL_PREPEND(pkt, hdr); nethdr = (gnrc_netif_hdr_t *)hdr->data; nethdr->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST; /* and send it */ LOG_DEBUG("beaconing: send beacon\n"); if (gnrc_netapi_send(CCNLRIOT_NETIF, pkt) < 1) { puts("error: unable to send"); gnrc_pktbuf_release(pkt); return; } }