Example #1
0
static int _fill_ipv6_hdr(kernel_pid_t iface, gnrc_pktsnip_t *ipv6,
                          gnrc_pktsnip_t *payload)
{
    int res;
    ipv6_hdr_t *hdr = ipv6->data;

    hdr->len = byteorder_htons(gnrc_pkt_len(payload));
    DEBUG("ipv6: set payload length to %u (network byteorder %04" PRIx16 ")\n",
          (unsigned) gnrc_pkt_len(payload), hdr->len.u16);

    /* check if e.g. extension header was not already marked */
    if (hdr->nh == PROTNUM_RESERVED) {
        hdr->nh = gnrc_nettype_to_protnum(payload->type);

        /* if still reserved: mark no next header */
        if (hdr->nh == PROTNUM_RESERVED) {
            hdr->nh = PROTNUM_IPV6_NONXT;
        }
    }

    DEBUG("ipv6: set next header to %u\n", hdr->nh);

    if (hdr->hl == 0) {
        if (iface == KERNEL_PID_UNDEF) {
            hdr->hl = GNRC_IPV6_NETIF_DEFAULT_HL;
        }
        else {
            hdr->hl = gnrc_ipv6_netif_get(iface)->cur_hl;
        }
    }

    if (ipv6_addr_is_unspecified(&hdr->src)) {
        if (ipv6_addr_is_loopback(&hdr->dst)) {
            ipv6_addr_set_loopback(&hdr->src);
        }
        else {
            ipv6_addr_t *src = gnrc_ipv6_netif_find_best_src_addr(iface, &hdr->dst, false);

            if (src != NULL) {
                DEBUG("ipv6: set packet source to %s\n",
                      ipv6_addr_to_str(addr_str, src, sizeof(addr_str)));
                memcpy(&hdr->src, src, sizeof(ipv6_addr_t));
            }
            /* Otherwise leave unspecified */
        }
    }

    DEBUG("ipv6: calculate checksum for upper header.\n");

    if ((res = gnrc_netreg_calc_csum(payload, ipv6)) < 0) {
        if (res != -ENOENT) {   /* if there is no checksum we are okay */
            DEBUG("ipv6: checksum calculation failed.\n");
            return res;
        }
    }

    return 0;
}
Example #2
0
void _gnrc_rpl_send(gnrc_pktsnip_t *pkt, ipv6_addr_t *src, ipv6_addr_t *dst,
        ipv6_addr_t *dodag_id)
{
    gnrc_pktsnip_t *hdr;
    ipv6_addr_t all_RPL_nodes = GNRC_RPL_ALL_NODES_ADDR, ll_addr;
    kernel_pid_t iface = gnrc_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
    if (iface == KERNEL_PID_UNDEF) {
        DEBUG("RPL: no suitable interface found for this destination address\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    if (src == NULL) {
        ipv6_addr_t *tmp = NULL;
        if (dodag_id != NULL) {
            tmp = gnrc_ipv6_netif_match_prefix(iface, dodag_id);
        }
        else if (dodag_id == NULL) {
            tmp = gnrc_ipv6_netif_find_best_src_addr(iface, &all_RPL_nodes);
        }

        if (tmp == NULL) {
            DEBUG("RPL: no suitable src address found\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        memcpy(&ll_addr, tmp, sizeof(ll_addr));
        ipv6_addr_set_link_local_prefix(&ll_addr);
        src = &ll_addr;
    }

    if (dst == NULL) {
        dst = &all_RPL_nodes;
    }

    hdr = gnrc_ipv6_hdr_build(pkt, (uint8_t *)src, sizeof(ipv6_addr_t), (uint8_t *)dst,
                            sizeof(ipv6_addr_t));

    if (hdr == NULL) {
        DEBUG("RPL: Send - no space left in packet buffer\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL,hdr)) {
        DEBUG("RPL: cannot send packet: no subscribers found.\n");
        gnrc_pktbuf_release(hdr);
    }

}
Example #3
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);
}
Example #4
0
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);
    }
}
Example #5
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);
    }
}
Example #6
0
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);
    }
}
Example #7
0
static int _fill_ipv6_hdr(kernel_pid_t iface, gnrc_pktsnip_t *ipv6,
                          gnrc_pktsnip_t *payload)
{
    int res;
    ipv6_hdr_t *hdr = ipv6->data;

    hdr->len = byteorder_htons(gnrc_pkt_len(payload));
    DEBUG("ipv6: set payload length to %zu (network byteorder %04" PRIx16 ")\n",
          gnrc_pkt_len(payload), hdr->len.u16);

    /* check if e.g. extension header was not already marked */
    if (hdr->nh == PROTNUM_RESERVED) {
        hdr->nh = gnrc_nettype_to_protnum(payload->type);

        /* if still reserved: mark no next header */
        if (hdr->nh == PROTNUM_RESERVED) {
            hdr->nh = PROTNUM_IPV6_NONXT;
        }
    }

    DEBUG("ipv6: set next header to %" PRIu8 "\n", hdr->nh);

    if (hdr->hl == 0) {
        if (iface == KERNEL_PID_UNDEF) {
            hdr->hl = GNRC_IPV6_NETIF_DEFAULT_HL;
        }
        else {
            hdr->hl = gnrc_ipv6_netif_get(iface)->cur_hl;
        }
    }

    if (ipv6_addr_is_unspecified(&hdr->src)) {
        if (ipv6_addr_is_loopback(&hdr->dst)) {
            ipv6_addr_set_loopback(&hdr->src);
        }
        else {
            ipv6_addr_t *src = gnrc_ipv6_netif_find_best_src_addr(iface, &hdr->dst);

            if (src != NULL) {
                DEBUG("ipv6: set packet source to %s\n",
                      ipv6_addr_to_str(addr_str, src, sizeof(addr_str)));
                memcpy(&hdr->src, src, sizeof(ipv6_addr_t));
            }
            /* Otherwise leave unspecified */
        }
    }

    DEBUG("ipv6: calculate checksum for upper header.\n");

#if GNRC_NETIF_NUMOF > 1
    if (payload->users > 1) {
        gnrc_pktsnip_t *ptr = ipv6;

        /* We deal with multiple interfaces here (multicast) => possible
         * different source addresses => duplication of payload needed */
        while (ptr != payload->next) {
            gnrc_pktsnip_t *old = ptr->next;
            /* duplicate everything including payload */
            ptr->next = gnrc_pktbuf_start_write(ptr->next);

            if (ptr->next == NULL) {
                DEBUG("ipv6: unable to get write access to payload, drop it\n");
                return -ENOBUFS;
            }

            ptr = old;
        }
    }
#endif /* GNRC_NETIF_NUMOF */

    if ((res = gnrc_netreg_calc_csum(payload, ipv6)) < 0) {
        if (res != -ENOENT) {   /* if there is no checksum we are okay */
            DEBUG("ipv6: checksum calculation failed.\n");
            return res;
        }
    }

    return 0;
}
Example #8
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);
    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);
}