Exemple #1
0
static void _rx_event(ng_netdev_eth_t *netdev)
{
    dev_eth_t *dev = netdev->ethdev;
    int nread = dev->driver->recv(dev, (char*)recv_buffer, ETHERNET_MAX_LEN);

    DEBUG("ng_netdev_eth: read %d bytes\n", nread);

    if (nread > 0) {
        ethernet_hdr_t *hdr = (ethernet_hdr_t *)recv_buffer;
        ng_pktsnip_t *netif_hdr, *pkt;
        ng_nettype_t receive_type = NG_NETTYPE_UNDEF;
        size_t data_len = (nread - sizeof(ethernet_hdr_t));

        /* TODO: implement multicast groups? */

        netif_hdr = ng_pktbuf_add(NULL, NULL,
                                  sizeof(ng_netif_hdr_t) + (2 * ETHERNET_ADDR_LEN),
                                  NG_NETTYPE_NETIF);

        if (netif_hdr == NULL) {
            DEBUG("ng_netdev_eth: no space left in packet buffer\n");
            return;
        }

        ng_netif_hdr_init(netif_hdr->data, ETHERNET_ADDR_LEN, ETHERNET_ADDR_LEN);
        ng_netif_hdr_set_src_addr(netif_hdr->data, hdr->src, ETHERNET_ADDR_LEN);
        ng_netif_hdr_set_dst_addr(netif_hdr->data, hdr->dst, ETHERNET_ADDR_LEN);
        ((ng_netif_hdr_t *)netif_hdr->data)->if_pid = thread_getpid();

        receive_type = ng_nettype_from_ethertype(byteorder_ntohs(hdr->type));

        DEBUG("ng_netdev_eth: received packet from %02x:%02x:%02x:%02x:%02x:%02x "
              "of length %zu\n",
              hdr->src[0], hdr->src[1], hdr->src[2], hdr->src[3], hdr->src[4],
              hdr->src[5], data_len);
#if defined(MODULE_OD) && ENABLE_DEBUG
        od_hex_dump(hdr, nread, OD_WIDTH_DEFAULT);
#endif

        /* Mark netif header and payload for next layer */
        if ((pkt = ng_pktbuf_add(netif_hdr, recv_buffer + sizeof(ethernet_hdr_t),
                                 data_len, receive_type)) == NULL) {
            ng_pktbuf_release(netif_hdr);
            DEBUG("ng_netdev_eth: no space left in packet buffer\n");
            return;
        }

        if (netdev->event_cb != NULL) {
            netdev->event_cb(NETDEV_EVENT_RX_COMPLETE, pkt);
        }
        else {
            ng_pktbuf_release(pkt); /* netif_hdr is released automatically too */
        }
    }
    else {
        DEBUG("ng_netdev_eth: spurious _rx_event: %d\n", nread);
    }
}
Exemple #2
0
uint16_t cc2420_reg_read(const cc2420_t *dev, const uint8_t addr)
{
    network_uint16_t tmp;

    spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK);
    spi_transfer_regs(SPI_BUS, SPI_CS, (CC2420_REG_READ | addr),NULL, &tmp, 2);
    spi_release(SPI_BUS);

    return byteorder_ntohs(tmp);
}
Exemple #3
0
static void _receive(gnrc_pktsnip_t *icmpv6)
{
    gnrc_pktsnip_t *ipv6 = NULL;
    ipv6_hdr_t *ipv6_hdr = NULL;
    icmpv6_hdr_t *icmpv6_hdr = NULL;

    LL_SEARCH_SCALAR(icmpv6, ipv6, type, GNRC_NETTYPE_IPV6);

    assert(ipv6 != NULL);

    ipv6_hdr = (ipv6_hdr_t *)ipv6->data;

    icmpv6_hdr = (icmpv6_hdr_t *)icmpv6->data;
    switch (icmpv6_hdr->code) {
        case GNRC_RPL_ICMPV6_CODE_DIS:
            DEBUG("RPL: DIS received\n");
            gnrc_rpl_recv_DIS((gnrc_rpl_dis_t *)(icmpv6_hdr + 1), &ipv6_hdr->src, &ipv6_hdr->dst,
                    byteorder_ntohs(ipv6_hdr->len));
            break;
        case GNRC_RPL_ICMPV6_CODE_DIO:
            DEBUG("RPL: DIO received\n");
            gnrc_rpl_recv_DIO((gnrc_rpl_dio_t *)(icmpv6_hdr + 1), &ipv6_hdr->src,
                    byteorder_ntohs(ipv6_hdr->len));
            break;
        case GNRC_RPL_ICMPV6_CODE_DAO:
            DEBUG("RPL: DAO received\n");
            gnrc_rpl_recv_DAO((gnrc_rpl_dao_t *)(icmpv6_hdr + 1), &ipv6_hdr->src,
                    byteorder_ntohs(ipv6_hdr->len));
            break;
        case GNRC_RPL_ICMPV6_CODE_DAO_ACK:
            DEBUG("RPL: DAO-ACK received\n");
            gnrc_rpl_recv_DAO_ACK((gnrc_rpl_dao_ack_t *)(icmpv6_hdr + 1),
                    byteorder_ntohs(ipv6_hdr->len));
            break;
        default:
            DEBUG("RPL: Unknown ICMPV6 code received\n");
            break;
    }

    gnrc_pktbuf_release(icmpv6);
}
bool gnrc_sixlowpan_nd_router_abr_older(sixlowpan_nd_opt_abr_t *abr_opt)
{
    gnrc_sixlowpan_nd_router_abr_t *abr;
    uint32_t version;

    if (abr_opt->len != SIXLOWPAN_ND_OPT_ABR_LEN) {
        /* invalid option received */
        return true;
    }

    abr = _get_abr(&abr_opt->braddr);

    if (abr == NULL) {
        return false;
    }

    version = byteorder_ntohs(abr_opt->vlow);
    version |= byteorder_ntohs(abr_opt->vhigh) << 16;

    return (version < abr->version);
}
Exemple #5
0
static void _receive(ng_pktsnip_t *pkt)
{
    ng_pktsnip_t *udp, *ipv6;
    ng_udp_hdr_t *hdr;
    uint32_t port;
    ng_netreg_entry_t *sendto;

    /* mark UDP header */
    udp = ng_pktbuf_start_write(pkt);
    if (udp == NULL) {
        DEBUG("udp: unable to get write access to packet\n");
        ng_pktbuf_release(pkt);
        return;
    }
    pkt = udp;
    udp = ng_pktbuf_add(pkt, pkt->data, sizeof(ng_udp_hdr_t), NG_NETTYPE_UDP);
    if (udp == NULL) {
        DEBUG("udp: error marking UDP header, dropping packet\n");
        ng_pktbuf_release(pkt);
        return;
    }
    /* mark payload as Type: UNDEF */
    pkt->type = NG_NETTYPE_UNDEF;
    /* get explicit pointer to UDP header */
    hdr = (ng_udp_hdr_t *)udp->data;

    LL_SEARCH_SCALAR(pkt, ipv6, type, NG_NETTYPE_IPV6);

    /* validate checksum */
    if (_calc_csum(udp, ipv6, pkt)) {
        DEBUG("udp: received packet with invalid checksum, dropping it\n");
        ng_pktbuf_release(pkt);
        return;
    }

    /* get port (netreg demux context) */
    port = (uint32_t)byteorder_ntohs(hdr->dst_port);

    /* send payload to receivers */
    sendto = ng_netreg_lookup(NG_NETTYPE_UDP, port);
    if (sendto == NULL) {
        DEBUG("udp: unable to forward packet as no one is interested in it\n");
        ng_pktbuf_release(pkt);
        return;
    }
    ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_UDP, port) - 1);
    while (sendto != NULL) {
        ng_netapi_receive(sendto->pid, pkt);
        sendto = ng_netreg_getnext(sendto);
    }
}
Exemple #6
0
static void handle_reply(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data,
                         uint16_t datalen)
{
    char addr_str[IPV6_ADDR_MAX_STR_LEN];
    icmpv6_echo_t *ping = (icmpv6_echo_t *)data;

    _waiting = false;

    ipv6_addr_to_str(addr_str, (ipv6_addr_t *)source, sizeof(addr_str));

    (void)atomic_fetch_add(&received, 1); /* Ignore return value, we only want to increment the counter */
    printf("%" PRIu16 " bytes from %s: icmp_seq=%" PRIu16 " ttl=%u quota=%i/%i\n",
           datalen, addr_str, byteorder_ntohs(ping->seq), (unsigned)ttl,
           atomic_load(&received), atomic_load(&num));
}
int _option_parse(gnrc_tcp_tcb_t *tcb, tcp_hdr_t *hdr)
{
    /* Extract Offset value. Return if no options are set */
    uint8_t offset = GET_OFFSET(byteorder_ntohs(hdr->off_ctl));
    if (offset <= TCP_HDR_OFFSET_MIN) {
        return 0;
    }

    /* Get Pointer to option field and field-size */
    uint8_t *opt_ptr = (uint8_t *) hdr + sizeof(tcp_hdr_t);
    uint8_t opt_left = (offset - TCP_HDR_OFFSET_MIN) * 4;

    /* Parse Options via tcp_hdr_opt_t */
    while (opt_left > 0) {
        tcp_hdr_opt_t *option = (tcp_hdr_opt_t *) opt_ptr;

        /* Examine current option */
        switch (option->kind) {
            case TCP_OPTION_KIND_EOL:
                DEBUG("gnrc_tcp_option.c : _option_parse() : EOL option found\n");
                return 0;

            case TCP_OPTION_KIND_NOP:
                DEBUG("gnrc_tcp_option.c : _option_parse() : NOP option found\n");
                opt_ptr += 1;
                opt_left -= 1;
                continue;

            case TCP_OPTION_KIND_MSS:
                if (option->length != TCP_OPTION_LENGTH_MSS) {
                    DEBUG("gnrc_tcp_option.c : _option_parse() : invalid MSS Option length.\n");
                    return -1;
                }
                tcb->mss = (option->value[0] << 8) | option->value[1];
                DEBUG("gnrc_tcp_option.c : _option_parse() : MSS option found. MSS=%"PRIu16"\n",
                      tcb->mss);
                break;

            default:
                DEBUG("gnrc_tcp_option.c : _option_parse() : Unknown option found.\
                      KIND=%"PRIu8", LENGTH=%"PRIu8"\n", option->kind, option->length);
        }
        opt_ptr += option->length;
        opt_left -= option->length;
    }
    return 0;
}
Exemple #8
0
int gnrc_conn_recvfrom(conn_t *conn, void *data, size_t max_len, void *addr, size_t *addr_len,
                       uint16_t *port)
{
    msg_t msg;
    int timeout = 3;
    while ((timeout--) > 0) {
        gnrc_pktsnip_t *pkt, *l3hdr;
        size_t size = 0;
        msg_receive(&msg);
        switch (msg.type) {
            case GNRC_NETAPI_MSG_TYPE_RCV:
                pkt = (gnrc_pktsnip_t *)msg.content.ptr;
                if (pkt->size > max_len) {
                    return -ENOMEM;
                }
                LL_SEARCH_SCALAR(pkt, l3hdr, type, conn->l3_type);
                if (l3hdr == NULL) {
                    msg_send_to_self(&msg); /* requeue invalid messages */
                    continue;
                }
#if defined(MODULE_CONN_UDP) || defined(MODULE_CONN_TCP)
                if ((conn->l4_type != GNRC_NETTYPE_UNDEF) && (port != NULL)) {
                    gnrc_pktsnip_t *l4hdr;
                    LL_SEARCH_SCALAR(pkt, l4hdr, type, conn->l4_type);
                    if (l4hdr == NULL) {
                        msg_send_to_self(&msg); /* requeue invalid messages */
                        continue;
                    }
                    *port = byteorder_ntohs(((udp_hdr_t *)l4hdr->data)->src_port);
                }
#endif  /* defined(MODULE_CONN_UDP) */
                if (addr != NULL) {
                    memcpy(addr, &((ipv6_hdr_t *)l3hdr->data)->src, sizeof(ipv6_addr_t));
                    *addr_len = sizeof(ipv6_addr_t);
                }
                memcpy(data, pkt->data, pkt->size);
                size = pkt->size;
                gnrc_pktbuf_release(pkt);
                return (int)size;
            default:
                (void)port;
                msg_send_to_self(&msg); /* requeue invalid messages */
                break;
        }
    }
    return -ETIMEDOUT;
}
Exemple #9
0
bool gnrc_sixlowpan_nd_opt_6ctx_handle(uint8_t icmpv6_type, sixlowpan_nd_opt_6ctx_t *ctx_opt)
{
    if (((ctx_opt->ctx_len < 64) && (ctx_opt->len != 2)) ||
        ((ctx_opt->ctx_len >= 64) && (ctx_opt->len != 3))) {
        DEBUG("6lo nd: invalid 6LoWPAN context option received\n");
        return false;
    }
    if (icmpv6_type != ICMPV6_RTR_ADV) {
        /* discard silently */
        return true;
    }
    /* don't care for result */
    gnrc_sixlowpan_ctx_update(sixlowpan_nd_opt_6ctx_get_cid(ctx_opt), (ipv6_addr_t *)(ctx_opt + 1),
                              ctx_opt->ctx_len, byteorder_ntohs(ctx_opt->ltime),
                              sixlowpan_nd_opt_6ctx_is_comp(ctx_opt));
    return true;
}
Exemple #10
0
static void _dump_ipv6_hdr(ng_ipv6_hdr_t *hdr)
{
    char addr_str[NG_IPV6_ADDR_MAX_STR_LEN];

    if (ng_ipv6_hdr_is_ipv6_hdr(hdr)) {
        printf("illegal version field: %" PRIu8 "\n", ng_ipv6_hdr_get_version(hdr));
    }

    printf("traffic class: 0x%02" PRIx8 " (ECN: 0x%" PRIx8 ", DSCP: 0x%02" PRIx8 ")\n",
           ng_ipv6_hdr_get_tc(hdr), ng_ipv6_hdr_get_tc_ecn(hdr),
           ng_ipv6_hdr_get_tc_dscp(hdr));
    printf("flow label: 0x%05" PRIx32 "\n", ng_ipv6_hdr_get_fl(hdr));
    printf("length: %" PRIu16 "  next header: %" PRIu8 "  hop limit: %" PRIu8 "\n",
           byteorder_ntohs(hdr->len), hdr->nh, hdr->hl);
    printf("source address: %s\n", ng_ipv6_addr_to_str(addr_str, &hdr->src,
            sizeof(addr_str)));
    printf("destination address: %s\n", ng_ipv6_addr_to_str(addr_str, &hdr->dst,
            sizeof(addr_str)));

}
Exemple #11
0
                     /* UINT16_MAX min < UINT32_MAX ms so no risk of overflow */
                     MS_PER_SEC * SEC_PER_MIN * ltime);
    }
    return abr;
}
#endif /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */

#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
uint32_t _handle_6co(const icmpv6_hdr_t *icmpv6,
                     const sixlowpan_nd_opt_6ctx_t *sixco,
                     _nib_abr_entry_t *abr)
#else   /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
uint32_t _handle_6co(const icmpv6_hdr_t *icmpv6,
                     const sixlowpan_nd_opt_6ctx_t *sixco)
#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
{
    uint16_t ltime;

#ifdef MODULE_GNRC_SIXLOWPAN_CTX
    uint8_t cid;
#endif  /* MODULE_GNRC_SIXLOWPAN_CTX */

    if ((sixco->len != SIXLOWPAN_ND_OPT_6CTX_LEN_MIN) ||
        ((sixco->len != SIXLOWPAN_ND_OPT_6CTX_LEN_MAX) &&
         (sixco->ctx_len > 64U)) ||
        (icmpv6->type != ICMPV6_RTR_ADV)) {
        DEBUG("nib: received 6CO of invalid length (%u), must be %u "
              "or wasn't delivered by RA."
              "\n",
              sixco->len,
              (sixco->ctx_len > 64U) ? SIXLOWPAN_ND_OPT_6CTX_LEN_MAX :
                                       SIXLOWPAN_ND_OPT_6CTX_LEN_MIN);
        return UINT32_MAX;
    }
    ltime = byteorder_ntohs(sixco->ltime);
#ifdef MODULE_GNRC_SIXLOWPAN_CTX
    cid = sixlowpan_nd_opt_6ctx_get_cid(sixco);
    gnrc_sixlowpan_ctx_update(cid, (ipv6_addr_t *)(sixco + 1), sixco->ctx_len,
                              ltime, sixlowpan_nd_opt_6ctx_is_comp(sixco));
#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C
    assert(abr != NULL);    /* should have been set in _handle_abro() */
    if (ltime == 0) {
        bf_unset(abr->ctxs, cid);
    }
    else {
        bf_set(abr->ctxs, cid);
    }
#endif  /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */
#else   /* MODULE_GNRC_SIXLOWPAN_CTX */
    (void)abr;
#endif  /* MODULE_GNRC_SIXLOWPAN_CTX */
    return ltime * SEC_PER_MIN * MS_PER_SEC;
}
Exemple #12
0
int _tftp_process_data(tftp_context_t *ctxt, gnrc_pktsnip_t *buf)
{
    tftp_packet_data_t *pkt = (tftp_packet_data_t *) buf->data;

    DEBUG("tftp: processing data\n");

    uint16_t block_nr = byteorder_ntohs(pkt->block_nr);

    /* check if this is the packet we are waiting for */
    if (block_nr != (ctxt->block_nr + 1)) {
        DEBUG("tftp: not the packet we were wating for\n");
        return TS_BUSY;
    }

    /* send the user data trough to the user application */
    if (ctxt->data_cb(ctxt->block_nr * ctxt->block_size, pkt->data, buf->size - sizeof(tftp_packet_data_t)) < 0) {
        DEBUG("tftp: error in data callback\n");
        return TS_BUSY;
    }

    /* return the number of data bytes received */
    return buf->size - sizeof(tftp_packet_data_t);
}
Exemple #13
0
uint8_t gnrc_sixlowpan_nd_opt_ar_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6, uint8_t icmpv6_type,
                                        sixlowpan_nd_opt_ar_t *ar_opt, uint8_t *sl2a,
                                        size_t sl2a_len)
{
    eui64_t eui64;
    gnrc_ipv6_netif_t *ipv6_iface;
    gnrc_ipv6_nc_t *nc_entry;
    uint8_t status = 0;
    (void)sl2a;
    (void)sl2a_len;
    if (ar_opt->len != SIXLOWPAN_ND_OPT_AR_LEN) {
        /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */
        return 0;
    }
    if (gnrc_netapi_get(iface, NETOPT_ADDRESS_LONG, 0, &eui64,
                        sizeof(eui64)) < 0) {
        /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */
        return 0;
    }
    ipv6_iface = gnrc_ipv6_netif_get(iface);
    nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
    switch (icmpv6_type) {
        case ICMPV6_NBR_ADV:
            if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) {
                DEBUG("6lo nd: interface not a 6LoWPAN interface\n");
                return 0;
            }
            if (eui64.uint64.u64 != ar_opt->eui64.uint64.u64) {
                /* discard silently: see https://tools.ietf.org/html/rfc6775#section-5.5.2 */
                return 0;
            }
            switch (ar_opt->status) {
                case SIXLOWPAN_ND_STATUS_SUCCESS:
                    DEBUG("6lo nd: address registration successful\n");
                    mutex_lock(&ipv6_iface->mutex);
                    /* reschedule 1 minute before lifetime expires */
                    timex_t t = { (uint32_t)(byteorder_ntohs(ar_opt->ltime) - 1) * 60, 0 };
                    vtimer_remove(&nc_entry->nbr_sol_timer);
                    vtimer_set_msg(&nc_entry->nbr_sol_timer, t, gnrc_ipv6_pid,
                                   GNRC_NDP_MSG_NBR_SOL_RETRANS, nc_entry);
                    mutex_unlock(&ipv6_iface->mutex);
                    break;
                case SIXLOWPAN_ND_STATUS_DUP:
                    DEBUG("6lo nd: address registration determined duplicated\n");
                    /* TODO: handle DAD failed case */
                    gnrc_ipv6_netif_remove_addr(iface, &ipv6->dst);
                    /* address should not be used anymore */
                    break;
                case SIXLOWPAN_ND_STATUS_NC_FULL:
                    DEBUG("6lo nd: neighbor cache on router is full\n");
                    gnrc_ipv6_nc_remove(iface, &ipv6->src);
                    /* try to find another router */
                    gnrc_sixlowpan_nd_init(ipv6_iface);
                    break;
                default:
                    DEBUG("6lo nd: unknown status for registration received\n");
                    break;
            }
            break;
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
        case ICMPV6_NBR_SOL:
            if (!(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) &&
                !(ipv6_iface->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER)) {
                DEBUG("6lo nd: interface not a 6LoWPAN or forwarding interface\n");
                return 0;
            }
            if ((ar_opt->status != 0) ||
                ipv6_addr_is_unspecified(&ipv6->src)) {
                /* discard silently */
                return 0;
            }
            /* TODO multihop DAD */
            if ((nc_entry != NULL) &&
                ((gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_REGISTERED) ||
                 (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) &&
                ((nc_entry->eui64.uint64.u64 != 0) &&
                 (ar_opt->eui64.uint64.u64 != nc_entry->eui64.uint64.u64))) {
                /* there is already another node with this address */
                DEBUG("6lo nd: duplicate address detected\n");
                status = SIXLOWPAN_ND_STATUS_DUP;
            }
            else if ((nc_entry != NULL) && (ar_opt->ltime.u16 == 0)) {
                gnrc_ipv6_nc_remove(iface, &ipv6->src);
                /* TODO, notify routing protocol */
            }
            else if (ar_opt->ltime.u16 != 0) {
                /* TODO: multihop DAD behavior */
                uint16_t reg_ltime;
                if (nc_entry == NULL) {
                    if ((nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len,
                                                     GNRC_IPV6_NC_STATE_STALE)) == NULL) {
                        DEBUG("6lo nd: neighbor cache is full\n");
                        return SIXLOWPAN_ND_STATUS_NC_FULL;
                    }
                    nc_entry->eui64 = ar_opt->eui64;
                }
                nc_entry->flags &= ~GNRC_IPV6_NC_TYPE_MASK;
                nc_entry->flags |= GNRC_IPV6_NC_TYPE_REGISTERED;
                reg_ltime = byteorder_ntohs(ar_opt->ltime);
                /* TODO: notify routing protocol */
                vtimer_remove(&nc_entry->type_timeout);
                vtimer_set_msg(&nc_entry->type_timeout, timex_set(reg_ltime * 60, 0),
                               gnrc_ipv6_pid, GNRC_SIXLOWPAN_ND_MSG_AR_TIMEOUT, nc_entry);
            }
            break;
#endif
        default:
            break;
    }

    return status;
}
Exemple #14
0
void gnrc_ndp_rtr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6,
                             ndp_rtr_adv_t *rtr_adv, size_t icmpv6_size)
{
    uint8_t *buf = (uint8_t *)(rtr_adv + 1);
    gnrc_ipv6_nc_t *nc_entry = NULL;
    gnrc_ipv6_netif_t *if_entry = gnrc_ipv6_netif_get(iface);
    uint8_t l2src[GNRC_IPV6_NC_L2_ADDR_MAX];
#ifdef MODULE_GNRC_SIXLOWPAN_ND
    uint32_t next_rtr_sol = 0;
#endif
    int sicmpv6_size = (int)icmpv6_size, l2src_len = 0;
    uint16_t opt_offset = 0;

    if (!ipv6_addr_is_link_local(&ipv6->src) ||
        ipv6_addr_is_multicast(&ipv6->src) ||
        (ipv6->hl != 255) || (rtr_adv->code != 0) ||
        (icmpv6_size < sizeof(ndp_rtr_adv_t))) {
        DEBUG("ndp: router advertisement was invalid\n");
        /* ipv6 releases */
        return;
    }
    /* get source from default router list */
    nc_entry = gnrc_ipv6_nc_get(iface, &ipv6->src);
    if (nc_entry == NULL) { /* not in default router list */
        /* create default router list entry */
        nc_entry = gnrc_ipv6_nc_add(iface, &ipv6->src, NULL, 0,
                                    GNRC_IPV6_NC_IS_ROUTER);
        if (nc_entry == NULL) {
            DEBUG("ndp: error on default router list entry creation\n");
            return;
        }
    }
    else if ((nc_entry->flags & GNRC_IPV6_NC_IS_ROUTER) && (byteorder_ntohs(rtr_adv->ltime) == 0)) {
        nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER;
    }
    else {
        nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER;
    }
    /* set router life timer */
    if (rtr_adv->ltime.u16 != 0) {
        uint16_t ltime = byteorder_ntohs(rtr_adv->ltime);
#ifdef MODULE_GNRC_SIXLOWPAN_ND
        next_rtr_sol = ltime;
#endif
        xtimer_set_msg(&nc_entry->rtr_timeout, (ltime * SEC_IN_USEC),
                       &nc_entry->rtr_timeout_msg, thread_getpid());
    }
    /* set current hop limit from message if available */
    if (rtr_adv->cur_hl != 0) {
        if_entry->cur_hl = rtr_adv->cur_hl;
    }
    /* set flags from message */
    if_entry->flags &= ~GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK;
    if_entry->flags |= (rtr_adv->flags << GNRC_IPV6_NETIF_FLAGS_RTR_ADV_POS) &
                       GNRC_IPV6_NETIF_FLAGS_RTR_ADV_MASK;
    /* set reachable time from message if it is not the same as the random base
     * value */
    if ((rtr_adv->reach_time.u32 != 0) &&
        (if_entry->reach_time_base != byteorder_ntohl(rtr_adv->reach_time))) {
        _set_reach_time(if_entry, byteorder_ntohl(rtr_adv->reach_time));
    }
    /* set retransmission timer from message */
    if (rtr_adv->retrans_timer.u32 != 0) {
        if_entry->retrans_timer = timex_set(0, byteorder_ntohl(rtr_adv->retrans_timer));
        timex_normalize(&if_entry->retrans_timer);
    }
    mutex_unlock(&if_entry->mutex);
    sicmpv6_size -= sizeof(ndp_rtr_adv_t);
    /* parse options */
    while (sicmpv6_size > 0) {
        ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset);
        switch (opt->type) {
            case NDP_OPT_SL2A:
                if ((l2src_len = gnrc_ndp_internal_sl2a_opt_handle(pkt, ipv6, rtr_adv->type, opt,
                                                                   l2src)) < 0) {
                    /* -ENOTSUP can not happen */
                    /* invalid source link-layer address option */
                    return;
                }
                break;
            case NDP_OPT_MTU:
                if (!gnrc_ndp_internal_mtu_opt_handle(iface, rtr_adv->type, (ndp_opt_mtu_t *)opt)) {
                    /* invalid MTU option */
                    return;
                }
                break;
            case NDP_OPT_PI:
                if (!gnrc_ndp_internal_pi_opt_handle(iface, rtr_adv->type, (ndp_opt_pi_t *)opt)) {
                    /* invalid prefix information option */
                    return;
                }
#ifdef MODULE_GNRC_SIXLOWPAN_ND
                uint32_t valid_ltime = byteorder_ntohl(((ndp_opt_pi_t *)opt)->valid_ltime);
                if ((valid_ltime != 0) && (valid_ltime < next_rtr_sol)) {
                    next_rtr_sol = valid_ltime;
                }
#endif
                break;
#ifdef MODULE_GNRC_SIXLOWPAN_ND
            case NDP_OPT_6CTX:
                if (!gnrc_sixlowpan_nd_opt_6ctx_handle(rtr_adv->type,
                                                       (sixlowpan_nd_opt_6ctx_t *)opt)) {
                    /* invalid 6LoWPAN context option */
                    return;
                }
                uint16_t ltime = byteorder_ntohs(((sixlowpan_nd_opt_6ctx_t *)opt)->ltime);
                if ((ltime != 0) && (ltime < (next_rtr_sol / 60))) {
                    next_rtr_sol = ltime * 60;
                }

                break;
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER
            case NDP_OPT_ABR:
                gnrc_sixlowpan_nd_opt_abr_handle(iface, rtr_adv, icmpv6_size,
                                                 (sixlowpan_nd_opt_abr_t *)opt);
                break;
#endif
        }

        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
    }
#if ENABLE_DEBUG && defined(MODULE_GNRC_SIXLOWPAN_ND)
    if ((if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) && (l2src_len <= 0)) {
        DEBUG("ndp: Router advertisement did not contain any source address information\n");
    }
#endif
    _stale_nc(iface, &ipv6->src, l2src, l2src_len);
    /* stop multicast router solicitation retransmission timer */
    xtimer_remove(&if_entry->rtr_sol_timer);
#ifdef MODULE_GNRC_SIXLOWPAN_ND
    if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
        /* 3/4 of the time should be "well before" enough the respective timeout
         * not to run out; see https://tools.ietf.org/html/rfc6775#section-5.4.3 */
        next_rtr_sol *= 3;
        next_rtr_sol = (next_rtr_sol > 4) ? (next_rtr_sol >> 2) : 1;
        /* according to https://tools.ietf.org/html/rfc6775#section-5.3:
         * "In all cases, the RS retransmissions are terminated when an RA is
         *  received."
         *  Hence, reset router solicitation counter and reset timer. */
        if_entry->rtr_sol_count = 0;
        gnrc_sixlowpan_nd_rtr_sol_reschedule(nc_entry, next_rtr_sol);
        gnrc_ndp_internal_send_nbr_sol(nc_entry->iface, NULL, &nc_entry->ipv6_addr,
                                       &nc_entry->ipv6_addr);
        if (if_entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) {
            gnrc_ipv6_netif_set_rtr_adv(if_entry, true);
        }
    }
Exemple #15
0
void sixlowpan_print(uint8_t *data, size_t size)
{
    if (data[0] == SIXLOWPAN_UNCOMP) {
        puts("Uncompressed IPv6 packet");

        /* might just be the dispatch (or fragmented) so better check */
        if (size > sizeof(ipv6_hdr_t)) {
            ipv6_hdr_print((ipv6_hdr_t *)(data + 1));
            od_hex_dump(data + sizeof(ipv6_hdr_t) + 1,
                        size - sizeof(ipv6_hdr_t) - 1,
                        OD_WIDTH_DEFAULT);
        }
    }
    else if (sixlowpan_nalp(data[0])) {
        puts("Not a LoWPAN (NALP) frame");
        od_hex_dump(data, size, OD_WIDTH_DEFAULT);
    }
    else if ((data[0] & SIXLOWPAN_FRAG_DISP_MASK) == SIXLOWPAN_FRAG_1_DISP) {
        sixlowpan_frag_t *hdr = (sixlowpan_frag_t *)data;

        puts("Fragmentation Header (first)");
        printf("datagram size: %" PRIu16 "\n",
               byteorder_ntohs(hdr->disp_size) & SIXLOWPAN_FRAG_SIZE_MASK);
        printf("tag: 0x%" PRIu16 "\n", byteorder_ntohs(hdr->tag));

        /* Print next dispatch */
        sixlowpan_print(data + sizeof(sixlowpan_frag_t),
                           size - sizeof(sixlowpan_frag_t));
    }
    else if ((data[0] & SIXLOWPAN_FRAG_DISP_MASK) == SIXLOWPAN_FRAG_N_DISP) {
        sixlowpan_frag_n_t *hdr = (sixlowpan_frag_n_t *)data;

        puts("Fragmentation Header (subsequent)");
        printf("datagram size: %" PRIu16 "\n",
               byteorder_ntohs(hdr->disp_size) & SIXLOWPAN_FRAG_SIZE_MASK);
        printf("tag: 0x%" PRIu16 "\n", byteorder_ntohs(hdr->tag));
        printf("offset: 0x%" PRIu8 "\n", hdr->offset);

        od_hex_dump(data + sizeof(sixlowpan_frag_n_t),
                    size - sizeof(sixlowpan_frag_n_t),
                    OD_WIDTH_DEFAULT);
    }
    else if ((data[0] & SIXLOWPAN_IPHC1_DISP_MASK) == SIXLOWPAN_IPHC1_DISP) {
        uint8_t offset = SIXLOWPAN_IPHC_HDR_LEN;
        puts("IPHC dispatch");

        switch (data[0] & SIXLOWPAN_IPHC1_TF) {
            case 0x00:
                puts("TF: ECN + DSCP + Flow Label (4 bytes)");
                break;

            case 0x08:
                puts("TF: ECN + Flow Label (3 bytes)");
                break;

            case 0x10:
                puts("TF: ECN + DSCP (1 bytes)");
                break;

            case 0x18:
                puts("TF: traffic class and flow label elided");
                break;
        }

        switch (data[0] & SIXLOWPAN_IPHC1_NH) {
            case 0x00:
                puts("NH: inline");
                break;

            case 0x04:
                puts("NH: LOWPAN_NHC");
                break;
        }

        switch (data[0] & SIXLOWPAN_IPHC1_HL) {
            case 0x00:
                puts("HLIM: inline");
                break;

            case 0x01:
                puts("HLIM: 1");
                break;

            case 0x02:
                puts("HLIM: 64");
                break;

            case 0x03:
                puts("HLIM: 255");
                break;
        }

        if (data[1] & SIXLOWPAN_IPHC2_SAC) {
            printf("Stateful source address compression: ");

            switch (data[1] & SIXLOWPAN_IPHC2_SAM) {
                case 0x00:
                    puts("unspecified address (::)");
                    break;

                case 0x10:
                    puts("64 bits inline");
                    break;

                case 0x20:
                    puts("16 bits inline");
                    break;

                case 0x40:
                    puts("elided (use L2 address)");
                    break;
            }
        }
        else {
            printf("Stateless source address compression: ");

            switch (data[1] & SIXLOWPAN_IPHC2_SAM) {
                case 0x00:
                    puts("128 bits inline");
                    break;

                case 0x10:
                    puts("64 bits inline");
                    break;

                case 0x20:
                    puts("16 bits inline");
                    break;

                case 0x40:
                    puts("elided (use L2 address)");
                    break;
            }
        }

        if (data[1] & SIXLOWPAN_IPHC2_M) {
            if (data[1] & SIXLOWPAN_IPHC2_DAC) {
                puts("Stateful destinaton multicast address compression:");

                switch (data[1] & SIXLOWPAN_IPHC2_DAM) {
                    case 0x00:
                        puts("    48 bits carried inline (Unicast-Prefix-based)");
                        break;

                    case 0x01:
                    case 0x02:
                    case 0x03:
                        puts("    reserved");
                        break;
                }
            }
            else {
                puts("Stateless destinaton multicast address compression:");

                switch (data[1] & SIXLOWPAN_IPHC2_DAM) {
                    case 0x00:
                        puts("    128 bits carried inline");
                        break;

                    case 0x01:
                        puts("    48 bits carried inline");
                        break;

                    case 0x02:
                        puts("    32 bits carried inline");
                        break;

                    case 0x03:
                        puts("    8 bits carried inline");
                        break;
                }
            }
        }
        else {
            if (data[1] & SIXLOWPAN_IPHC2_DAC) {
                printf("Stateful destinaton address compression: ");

                switch (data[1] & SIXLOWPAN_IPHC2_DAM) {
                    case 0x00:
                        puts("reserved");
                        break;

                    case 0x10:
                        puts("64 bits inline");
                        break;

                    case 0x20:
                        puts("16 bits inline");
                        break;

                    case 0x40:
                        puts("elided (use L2 address)");
                        break;
                }
            }
            else {
                printf("Stateless destinaton address compression: ");

                switch (data[1] & SIXLOWPAN_IPHC2_DAM) {
                    case 0x00:
                        puts("128 bits inline");
                        break;

                    case 0x10:
                        puts("64 bits inline");
                        break;

                    case 0x20:
                        puts("16 bits inline");
                        break;

                    case 0x40:
                        puts("elided (use L2 address)");
                        break;
                }
            }
        }

        if (data[1] & SIXLOWPAN_IPHC2_CID_EXT) {
            offset += SIXLOWPAN_IPHC_CID_EXT_LEN;
            printf("SCI: 0x%" PRIx8 "; DCI: 0x%" PRIx8 "\n",
                   data[2] >> 4, data[2] & 0xf);
        }
/** @todo allow target prefixes in target options to be of variable length */
bool _parse_options(int msg_type, gnrc_rpl_dodag_t *dodag, gnrc_rpl_opt_t *opt, uint16_t len,
                    ipv6_addr_t *src)
{
    uint16_t l = 0;
    gnrc_rpl_opt_target_t *first_target = NULL;
    eui64_t iid;
    kernel_pid_t if_id = KERNEL_PID_UNDEF;

    if (!_gnrc_rpl_check_options_validity(msg_type, dodag, opt, len)) {
        return false;
    }

    while(l < len) {
        switch(opt->type) {
            case (GNRC_RPL_OPT_PAD1):
                DEBUG("RPL: PAD1 option parsed\n");
                l += 1;
                opt = (gnrc_rpl_opt_t *) (((uint8_t *) opt) + 1);
                continue;

            case (GNRC_RPL_OPT_PADN):
                DEBUG("RPL: PADN option parsed\n");
                break;

            case (GNRC_RPL_OPT_DODAG_CONF):
                DEBUG("RPL: DODAG CONF DIO option parsed\n");
                gnrc_rpl_opt_dodag_conf_t *dc = (gnrc_rpl_opt_dodag_conf_t *) opt;
                gnrc_rpl_of_t *of = gnrc_rpl_get_of_for_ocp(byteorder_ntohs(dc->ocp));
                if (of != NULL) {
                    dodag->instance->of = of;
                }
                else {
                    DEBUG("RPL: Unsupported OCP 0x%02x\n", byteorder_ntohs(dc->ocp));
                    dodag->instance->of = gnrc_rpl_get_of_for_ocp(GNRC_RPL_DEFAULT_OCP);
                }
                dodag->dio_interval_doubl = dc->dio_int_doubl;
                dodag->dio_min = dc->dio_int_min;
                dodag->dio_redun = dc->dio_redun;
                dodag->instance->max_rank_inc = byteorder_ntohs(dc->max_rank_inc);
                dodag->instance->min_hop_rank_inc = byteorder_ntohs(dc->min_hop_rank_inc);
                dodag->default_lifetime = dc->default_lifetime;
                dodag->lifetime_unit = byteorder_ntohs(dc->lifetime_unit);
                dodag->trickle.Imin = (1 << dodag->dio_min);
                dodag->trickle.Imax = dodag->dio_interval_doubl;
                dodag->trickle.k = dodag->dio_redun;
                break;

            case (GNRC_RPL_OPT_PREFIX_INFO):
                DEBUG("RPL: Prefix Information DIO option parsed\n");
                gnrc_rpl_opt_prefix_info_t *pi = (gnrc_rpl_opt_prefix_info_t *) opt;
                ipv6_addr_t all_RPL_nodes = GNRC_RPL_ALL_NODES_ADDR;
                if_id = gnrc_ipv6_netif_find_by_addr(NULL, &all_RPL_nodes);
                /* check for the auto address-configuration flag */
                if ((gnrc_netapi_get(if_id, NETOPT_IPV6_IID, 0, &iid, sizeof(eui64_t)) < 0) &&
                        !(pi->LAR_flags & GNRC_RPL_PREFIX_AUTO_ADDRESS_BIT)) {
                    break;
                }
                ipv6_addr_set_aiid(&pi->prefix, iid.uint8);
                gnrc_ipv6_netif_add_addr(if_id, &pi->prefix, pi->prefix_len, 0);

                break;

            case (GNRC_RPL_OPT_TARGET):
                DEBUG("RPL: RPL TARGET DAO option parsed\n");
                if_id = gnrc_ipv6_netif_find_by_prefix(NULL, &dodag->dodag_id);
                if (if_id == KERNEL_PID_UNDEF) {
                    DEBUG("RPL: no interface found for the configured DODAG id\n");
                    return false;
                }

                gnrc_rpl_opt_target_t *target = (gnrc_rpl_opt_target_t *) opt;
                if (first_target == NULL) {
                    first_target = target;
                }

                fib_add_entry(gnrc_ipv6_fib_table, if_id, target->target.u8,
                              sizeof(ipv6_addr_t), AF_INET6, src->u8,
                              sizeof(ipv6_addr_t), AF_INET6,
                              (dodag->default_lifetime * dodag->lifetime_unit) *
                              SEC_IN_MS);
                break;

            case (GNRC_RPL_OPT_TRANSIT):
                DEBUG("RPL: RPL TRANSIT INFO DAO option parsed\n");
                gnrc_rpl_opt_transit_t *transit = (gnrc_rpl_opt_transit_t *) opt;
                if (first_target == NULL) {
                    DEBUG("RPL: Encountered a RPL TRANSIT DAO option without \
a preceding RPL TARGET DAO option\n");
                    break;
                }

                do {
                    fib_update_entry(gnrc_ipv6_fib_table, first_target->target.u8,
                                     sizeof(ipv6_addr_t), src->u8,
                                     sizeof(ipv6_addr_t), AF_INET6,
                            (transit->path_lifetime * dodag->lifetime_unit * SEC_IN_MS));
                    first_target = (gnrc_rpl_opt_target_t *) (((uint8_t *) (first_target)) +
                        sizeof(gnrc_rpl_opt_t) + first_target->length);
                }
                while (first_target->type == GNRC_RPL_OPT_TARGET);

                first_target = NULL;
                break;

        }
        l += opt->length + sizeof(gnrc_rpl_opt_t);
        opt = (gnrc_rpl_opt_t *) (((uint8_t *) (opt + 1)) + opt->length);
    }
Exemple #17
0
void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_pktsnip_t *pkt,
              size_t frag_size, size_t offset)
{
    rbuf_t *entry;
    /* cppcheck is clearly wrong here */
    /* cppcheck-suppress variableScope */
    unsigned int data_offset = 0;
    ng_sixlowpan_frag_t *frag = pkt->data;
    rbuf_int_t *ptr;
    uint8_t *data = ((uint8_t *)pkt->data) + sizeof(ng_sixlowpan_frag_t);

    _rbuf_gc();
    entry = _rbuf_get(ng_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len,
                      ng_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len,
                      byteorder_ntohs(frag->disp_size) & NG_SIXLOWPAN_FRAG_SIZE_MASK,
                      byteorder_ntohs(frag->tag));

    if (entry == NULL) {
        DEBUG("6lo rbuf: reassembly buffer full.\n");
        return;
    }

    ptr = entry->ints;

    /* dispatches in the first fragment are ignored */
    if (offset == 0) {
        if (data[0] == NG_SIXLOWPAN_UNCOMPRESSED) {
            data++;             /* skip 6LoWPAN dispatch */
            frag_size--;
        }
#ifdef MODULE_NG_SIXLOWPAN_IPHC
        else if (ng_sixlowpan_iphc_is(data)) {
            size_t iphc_len;
            iphc_len = ng_sixlowpan_iphc_decode(entry->pkt, pkt,
                                                sizeof(ng_sixlowpan_frag_t));
            if (iphc_len == 0) {
                DEBUG("6lo rfrag: could not decode IPHC dispatch\n");
                ng_pktbuf_release(entry->pkt);
                _rbuf_rem(entry);
                return;
            }
            data += iphc_len;       /* take remaining data as data */
            frag_size -= iphc_len;  /* and reduce frag size by IPHC dispatch length */
            frag_size += sizeof(ipv6_hdr_t);    /* but add IPv6 header length */
            data_offset += sizeof(ipv6_hdr_t);  /* start copying after IPv6 header */
        }
#endif
    }
    else {
        data++; /* FRAGN header is one byte longer (offset) */
    }

    if ((offset + frag_size) > entry->pkt->size) {
        DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n");
        ng_pktbuf_release(entry->pkt);
        _rbuf_rem(entry);
        return;
    }

    while (ptr != NULL) {
        if (_rbuf_int_in(ptr, offset, offset + frag_size - 1)) {
            DEBUG("6lo rfrag: overlapping or same intervals, discarding datagram\n");
            ng_pktbuf_release(entry->pkt);
            _rbuf_rem(entry);
            return;
        }

        ptr = ptr->next;
    }

    if (_rbuf_update_ints(entry, offset, frag_size)) {
        DEBUG("6lo rbuf: add fragment data\n");
        entry->cur_size += (uint16_t)frag_size;
        memcpy(((uint8_t *)entry->pkt->data) + offset + data_offset, data,
               frag_size - data_offset);
    }

    if (entry->cur_size == entry->pkt->size) {
        kernel_pid_t iface = netif_hdr->if_pid;
        ng_pktsnip_t *netif = ng_netif_hdr_build(entry->src, entry->src_len,
                              entry->dst, entry->dst_len);

        if (netif == NULL) {
            DEBUG("6lo rbuf: error allocating netif header\n");
            ng_pktbuf_release(entry->pkt);
            _rbuf_rem(entry);
            return;
        }

        netif_hdr = netif->data;
        netif_hdr->if_pid = iface;
        LL_APPEND(entry->pkt, netif);

        if (!ng_netapi_dispatch_receive(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL,
                                        entry->pkt)) {
            DEBUG("6lo rbuf: No receivers for this packet found\n");
            ng_pktbuf_release(entry->pkt);
        }

        _rbuf_rem(entry);
    }
}
Exemple #18
0
static void _receive(gnrc_pktsnip_t *pkt)
{
    kernel_pid_t iface = KERNEL_PID_UNDEF;
    gnrc_pktsnip_t *ipv6, *netif, *first_ext;
    ipv6_hdr_t *hdr;

    assert(pkt != NULL);

    netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);

    if (netif != NULL) {
        iface = ((gnrc_netif_hdr_t *)netif->data)->if_pid;

#ifdef MODULE_NETSTATS_IPV6
        assert(iface);
        netstats_t *stats = gnrc_ipv6_netif_get_stats(iface);
        stats->rx_count++;
        stats->rx_bytes += (gnrc_pkt_len(pkt) - netif->size);
#endif
    }

    first_ext = pkt;

    for (ipv6 = pkt; ipv6 != NULL; ipv6 = ipv6->next) { /* find IPv6 header if already marked */
        if ((ipv6->type == GNRC_NETTYPE_IPV6) && (ipv6->size == sizeof(ipv6_hdr_t)) &&
            (ipv6_hdr_is(ipv6->data))) {
            break;
        }

        first_ext = ipv6;
    }

    if (ipv6 == NULL) {
        if (!ipv6_hdr_is(pkt->data)) {
            DEBUG("ipv6: Received packet was not IPv6, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
#ifdef MODULE_GNRC_IPV6_WHITELIST
        if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(pkt->data))->src)) {
            DEBUG("ipv6: Source address not whitelisted, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
#endif
#ifdef MODULE_GNRC_IPV6_BLACKLIST
        if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(pkt->data))->src)) {
            DEBUG("ipv6: Source address blacklisted, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
#endif
        /* seize ipv6 as a temporary variable */
        ipv6 = gnrc_pktbuf_start_write(pkt);

        if (ipv6 == NULL) {
            DEBUG("ipv6: unable to get write access to packet, drop it\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        pkt = ipv6;     /* reset pkt from temporary variable */

        ipv6 = gnrc_pktbuf_mark(pkt, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6);

        first_ext = pkt;
        pkt->type = GNRC_NETTYPE_UNDEF; /* snip is no longer IPv6 */

        if (ipv6 == NULL) {
            DEBUG("ipv6: error marking IPv6 header, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }
#ifdef MODULE_GNRC_IPV6_WHITELIST
    else if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(ipv6->data))->src)) {
        /* if ipv6 header already marked*/
        DEBUG("ipv6: Source address not whitelisted, dropping packet\n");
        gnrc_pktbuf_release(pkt);
        return;
    }
#endif
#ifdef MODULE_GNRC_IPV6_BLACKLIST
    else if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(ipv6->data))->src)) {
        /* if ipv6 header already marked*/
        DEBUG("ipv6: Source address blacklisted, dropping packet\n");
        gnrc_pktbuf_release(pkt);
        return;
    }
#endif

    /* extract header */
    hdr = (ipv6_hdr_t *)ipv6->data;

    /* if available, remove any padding that was added by lower layers
     * to fulfill their minimum size requirements (e.g. ethernet) */
    if (byteorder_ntohs(hdr->len) < pkt->size) {
        gnrc_pktbuf_realloc_data(pkt, byteorder_ntohs(hdr->len));
    }
    else if (byteorder_ntohs(hdr->len) >
             (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t))) {
        DEBUG("ipv6: invalid payload length: %d, actual: %d, dropping packet\n",
              (int) byteorder_ntohs(hdr->len),
              (int) (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t)));
        gnrc_pktbuf_release(pkt);
        return;
    }

    DEBUG("ipv6: Received (src = %s, ",
          ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str)));
    DEBUG("dst = %s, next header = %u, length = %" PRIu16 ")\n",
          ipv6_addr_to_str(addr_str, &(hdr->dst), sizeof(addr_str)),
          hdr->nh, byteorder_ntohs(hdr->len));

    if (_pkt_not_for_me(&iface, hdr)) { /* if packet is not for me */
        DEBUG("ipv6: packet destination not this host\n");

#ifdef MODULE_GNRC_IPV6_ROUTER    /* only routers redirect */
        /* redirect to next hop */
        DEBUG("ipv6: decrement hop limit to %u\n", (uint8_t) (hdr->hl - 1));

        /* RFC 4291, section 2.5.6 states: "Routers must not forward any
         * packets with Link-Local source or destination addresses to other
         * links."
         */
        if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) {
            DEBUG("ipv6: do not forward packets with link-local source or"
                  " destination address\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
        /* TODO: check if receiving interface is router */
        else if (--(hdr->hl) > 0) {  /* drop packets that *reach* Hop Limit 0 */
            gnrc_pktsnip_t *reversed_pkt = NULL, *ptr = pkt;

            DEBUG("ipv6: forward packet to next hop\n");

            /* pkt might not be writable yet, if header was given above */
            ipv6 = gnrc_pktbuf_start_write(ipv6);
            if (ipv6 == NULL) {
                DEBUG("ipv6: unable to get write access to packet: dropping it\n");
                gnrc_pktbuf_release(pkt);
                return;
            }

            /* remove L2 headers around IPV6 */
            netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
            if (netif != NULL) {
                gnrc_pktbuf_remove_snip(pkt, netif);
            }

            /* reverse packet snip list order */
            while (ptr != NULL) {
                gnrc_pktsnip_t *next;
                ptr = gnrc_pktbuf_start_write(ptr);     /* duplicate if not already done */
                if (ptr == NULL) {
                    DEBUG("ipv6: unable to get write access to packet: dropping it\n");
                    gnrc_pktbuf_release(reversed_pkt);
                    gnrc_pktbuf_release(pkt);
                    return;
                }
                next = ptr->next;
                ptr->next = reversed_pkt;
                reversed_pkt = ptr;
                ptr = next;
            }
            _send(reversed_pkt, false);
            return;
        }
        else {
            DEBUG("ipv6: hop limit reached 0: drop packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

#else  /* MODULE_GNRC_IPV6_ROUTER */
        DEBUG("ipv6: dropping packet\n");
        /* non rounting hosts just drop the packet */
        gnrc_pktbuf_release(pkt);
        return;
#endif /* MODULE_GNRC_IPV6_ROUTER */
    }

    /* IPv6 internal demuxing (ICMPv6, Extension headers etc.) */
    gnrc_ipv6_demux(iface, first_ext, pkt, hdr->nh);
}
Exemple #19
0
void rpl_send_DIO(rpl_dodag_t *mydodag, ipv6_addr_t *destination)
{
#if ENABLE_DEBUG

    if (destination) {
        DEBUGF("Send DIO to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
    }

#endif
    icmp_send_buf = get_rpl_send_icmpv6_buf(ipv6_ext_hdr_len);

    if (mydodag == NULL) {
        DEBUGF("Error - trying to send DIO without being part of a dodag.\n");
        return;
    }

    icmp_send_buf->type = ICMPV6_TYPE_RPL_CONTROL;
    icmp_send_buf->code = ICMP_CODE_DIO;

    rpl_send_dio_buf = get_rpl_send_dio_buf();
    memset(rpl_send_dio_buf, 0, sizeof(*rpl_send_dio_buf));

    DEBUGF("Sending DIO with ");
    rpl_send_dio_buf->rpl_instanceid = mydodag->instance->id;
    DEBUG("instance %02X ", rpl_send_dio_buf->rpl_instanceid);
    rpl_send_dio_buf->version_number = mydodag->version;
    rpl_send_dio_buf->rank = byteorder_htons(mydodag->my_rank);
    DEBUG("rank %04X\n", byteorder_ntohs(rpl_send_dio_buf->rank));
    rpl_send_dio_buf->g_mop_prf = (mydodag->grounded << RPL_GROUNDED_SHIFT) |
                                  (mydodag->mop << RPL_MOP_SHIFT) | mydodag->prf;
    rpl_send_dio_buf->dtsn = mydodag->dtsn;
    rpl_send_dio_buf->flags = 0;
    rpl_send_dio_buf->reserved = 0;
    rpl_send_dio_buf->dodagid = mydodag->dodag_id;

    int opt_hdr_len = 0;
    /* DODAG configuration option */
    rpl_send_opt_dodag_conf_buf = get_rpl_send_opt_dodag_conf_buf(DIO_BASE_LEN);
    rpl_send_opt_dodag_conf_buf->type = RPL_OPT_DODAG_CONF;
    rpl_send_opt_dodag_conf_buf->length = RPL_OPT_DODAG_CONF_LEN;
    rpl_send_opt_dodag_conf_buf->flags_a_pcs = 0;
    rpl_send_opt_dodag_conf_buf->DIOIntDoubl = mydodag->dio_interval_doubling;
    rpl_send_opt_dodag_conf_buf->DIOIntMin = mydodag->dio_min;
    rpl_send_opt_dodag_conf_buf->DIORedun = mydodag->dio_redundancy;
    rpl_send_opt_dodag_conf_buf->MaxRankIncrease = byteorder_htons(mydodag->maxrankincrease);
    rpl_send_opt_dodag_conf_buf->MinHopRankIncrease = byteorder_htons(mydodag->minhoprankincrease);
    rpl_send_opt_dodag_conf_buf->ocp = byteorder_htons(mydodag->of->ocp);
    rpl_send_opt_dodag_conf_buf->reserved = 0;
    rpl_send_opt_dodag_conf_buf->default_lifetime = mydodag->default_lifetime;
    rpl_send_opt_dodag_conf_buf->lifetime_unit = byteorder_htons(mydodag->lifetime_unit);

    opt_hdr_len += RPL_OPT_DODAG_CONF_LEN_WITH_OPT_LEN;

    if (!ipv6_addr_is_unspecified(&mydodag->prefix)) {
        rpl_send_opt_prefix_information_buf = get_rpl_send_opt_prefix_information_buf(DIO_BASE_LEN + opt_hdr_len);
        rpl_send_opt_prefix_information_buf->type = RPL_OPT_PREFIX_INFO;
        rpl_send_opt_prefix_information_buf->length = RPL_OPT_PREFIX_INFO_LEN;
        rpl_send_opt_prefix_information_buf->flags = mydodag->prefix_flags;
        rpl_send_opt_prefix_information_buf->prefix = mydodag->prefix;
        rpl_send_opt_prefix_information_buf->prefix_length = mydodag->prefix_length;
        rpl_send_opt_prefix_information_buf->preferred_lifetime = byteorder_htonl(mydodag->prefix_preferred_lifetime);
        rpl_send_opt_prefix_information_buf->valid_lifetime = byteorder_htonl(mydodag->prefix_valid_lifetime);

        opt_hdr_len += RPL_OPT_PREFIX_INFO_LEN_WITH_OPT_LEN;
    }

    uint16_t plen = ICMPV6_HDR_LEN + DIO_BASE_LEN + opt_hdr_len;
    rpl_send(destination, (uint8_t *)icmp_send_buf, plen, IPV6_PROTO_NUM_ICMPV6);
}
Exemple #20
0
static void _receive(gnrc_pktsnip_t *icmpv6)
{
    gnrc_pktsnip_t *ipv6, *netif;
    ipv6_hdr_t *ipv6_hdr;
    icmpv6_hdr_t *icmpv6_hdr;
    kernel_pid_t iface = KERNEL_PID_UNDEF;

    assert(icmpv6 != NULL);

    ipv6 = gnrc_pktsnip_search_type(icmpv6, GNRC_NETTYPE_IPV6);
    netif = gnrc_pktsnip_search_type(icmpv6, GNRC_NETTYPE_NETIF);

    assert(ipv6 != NULL);

    if (netif) {
        iface = ((gnrc_netif_hdr_t *)netif->data)->if_pid;
    }

    ipv6_hdr = (ipv6_hdr_t *)ipv6->data;

    icmpv6_hdr = (icmpv6_hdr_t *)icmpv6->data;
    switch (icmpv6_hdr->code) {
        case GNRC_RPL_ICMPV6_CODE_DIS:
            DEBUG("RPL: DIS received\n");
            gnrc_rpl_recv_DIS((gnrc_rpl_dis_t *)(icmpv6_hdr + 1), iface, &ipv6_hdr->src,
                              &ipv6_hdr->dst, byteorder_ntohs(ipv6_hdr->len));
            break;
        case GNRC_RPL_ICMPV6_CODE_DIO:
            DEBUG("RPL: DIO received\n");
            gnrc_rpl_recv_DIO((gnrc_rpl_dio_t *)(icmpv6_hdr + 1), iface, &ipv6_hdr->src,
                              &ipv6_hdr->dst, byteorder_ntohs(ipv6_hdr->len));
            break;
        case GNRC_RPL_ICMPV6_CODE_DAO:
            DEBUG("RPL: DAO received\n");
            gnrc_rpl_recv_DAO((gnrc_rpl_dao_t *)(icmpv6_hdr + 1), iface, &ipv6_hdr->src,
                              &ipv6_hdr->dst, byteorder_ntohs(ipv6_hdr->len));
            break;
        case GNRC_RPL_ICMPV6_CODE_DAO_ACK:
            DEBUG("RPL: DAO-ACK received\n");
            gnrc_rpl_recv_DAO_ACK((gnrc_rpl_dao_ack_t *)(icmpv6_hdr + 1), iface, &ipv6_hdr->src,
                                  &ipv6_hdr->dst, byteorder_ntohs(ipv6_hdr->len));
            break;
#ifdef MODULE_GNRC_RPL_P2P
        case GNRC_RPL_P2P_ICMPV6_CODE_DRO:
            DEBUG("RPL: P2P DRO received\n");
            gnrc_pktsnip_t *icmpv6_snip = gnrc_pktbuf_add(NULL, NULL, icmpv6->size,
                                                          GNRC_NETTYPE_ICMPV6);
            if (icmpv6_snip == NULL) {
                DEBUG("RPL-P2P: cannot copy ICMPv6 packet\n");
                break;
            }

            memcpy(icmpv6_snip->data, icmpv6->data, icmpv6->size);

            gnrc_rpl_p2p_recv_DRO(icmpv6_snip, &ipv6_hdr->src);
            break;
        case GNRC_RPL_P2P_ICMPV6_CODE_DRO_ACK:
            DEBUG("RPL: P2P DRO-ACK received\n");
            break;
#endif
        default:
            DEBUG("RPL: Unknown ICMPV6 code received\n");
            break;
    }

    gnrc_pktbuf_release(icmpv6);
}
Exemple #21
0
void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
              size_t frag_size, size_t offset)
{
    rbuf_t *entry;
    /* cppcheck-suppress variableScope
     * (reason: cppcheck is clearly wrong here) */
    unsigned int data_offset = 0;
    size_t original_size = frag_size;
    sixlowpan_frag_t *frag = pkt->data;
    rbuf_int_t *ptr;
    uint8_t *data = ((uint8_t *)pkt->data) + sizeof(sixlowpan_frag_t);

    _rbuf_gc();
    entry = _rbuf_get(gnrc_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len,
                      gnrc_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len,
                      byteorder_ntohs(frag->disp_size) & SIXLOWPAN_FRAG_SIZE_MASK,
                      byteorder_ntohs(frag->tag));

    if (entry == NULL) {
        DEBUG("6lo rbuf: reassembly buffer full.\n");
        return;
    }

    ptr = entry->ints;

    /* dispatches in the first fragment are ignored */
    if (offset == 0) {
        if (data[0] == SIXLOWPAN_UNCOMP) {
            data++;             /* skip 6LoWPAN dispatch */
            frag_size--;
        }
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC
        else if (sixlowpan_iphc_is(data)) {
            size_t iphc_len, nh_len = 0;
            iphc_len = gnrc_sixlowpan_iphc_decode(&entry->pkt, pkt, entry->pkt->size,
                                                  sizeof(sixlowpan_frag_t), &nh_len);
            if (iphc_len == 0) {
                DEBUG("6lo rfrag: could not decode IPHC dispatch\n");
                gnrc_pktbuf_release(entry->pkt);
                _rbuf_rem(entry);
                return;
            }
            data += iphc_len;       /* take remaining data as data */
            frag_size -= iphc_len;  /* and reduce frag size by IPHC dispatch length */
            /* but add IPv6 header + next header lengths */
            frag_size += sizeof(ipv6_hdr_t) + nh_len;
            /* start copying after IPv6 header and next headers */
            data_offset += sizeof(ipv6_hdr_t) + nh_len;
        }
#endif
    }
    else {
        data++; /* FRAGN header is one byte longer (offset) */
    }

    if ((offset + frag_size) > entry->pkt->size) {
        DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n");
        gnrc_pktbuf_release(entry->pkt);
        _rbuf_rem(entry);
        return;
    }

    /* If the fragment overlaps another fragment and differs in either the size
     * or the offset of the overlapped fragment, discards the datagram
     * https://tools.ietf.org/html/rfc4944#section-5.3 */
    while (ptr != NULL) {
        if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) {
            DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n");
            gnrc_pktbuf_release(entry->pkt);
            _rbuf_rem(entry);

            /* "A fresh reassembly may be commenced with the most recently
             * received link fragment"
             * https://tools.ietf.org/html/rfc4944#section-5.3 */
            rbuf_add(netif_hdr, pkt, original_size, offset);

            return;
        }

        ptr = ptr->next;
    }

    if (_rbuf_update_ints(entry, offset, frag_size)) {
        DEBUG("6lo rbuf: add fragment data\n");
        entry->cur_size += (uint16_t)frag_size;
        memcpy(((uint8_t *)entry->pkt->data) + offset + data_offset, data,
               frag_size - data_offset);
    }

    if (entry->cur_size == entry->pkt->size) {
        gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(entry->src, entry->src_len,
                                                     entry->dst, entry->dst_len);

        if (netif == NULL) {
            DEBUG("6lo rbuf: error allocating netif header\n");
            gnrc_pktbuf_release(entry->pkt);
            _rbuf_rem(entry);
            return;
        }

        /* copy the transmit information of the latest fragment into the newly
         * created header to have some link_layer information. The link_layer
         * info of the previous fragments is discarded.
         */
        gnrc_netif_hdr_t *new_netif_hdr = netif->data;
        new_netif_hdr->if_pid = netif_hdr->if_pid;
        new_netif_hdr->flags = netif_hdr->flags;
        new_netif_hdr->lqi = netif_hdr->lqi;
        new_netif_hdr->rssi = netif_hdr->rssi;
        LL_APPEND(entry->pkt, netif);

        if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL,
                                          entry->pkt)) {
            DEBUG("6lo rbuf: No receivers for this packet found\n");
            gnrc_pktbuf_release(entry->pkt);
        }

        _rbuf_rem(entry);
    }
}
Exemple #22
0
static gnrc_pktsnip_t *_recv(gnrc_netdev2_t *gnrc_netdev2)
{
    netdev2_t *dev = gnrc_netdev2->dev;
    int bytes_expected = dev->driver->recv(dev, NULL, 0);
    gnrc_pktsnip_t *pkt = NULL;

    if (bytes_expected) {
        pkt = gnrc_pktbuf_add(NULL, NULL,
                bytes_expected,
                GNRC_NETTYPE_UNDEF);

        if(!pkt) {
            DEBUG("_recv_ethernet_packet: cannot allocate pktsnip.\n");
            goto out;
        }

        int nread = dev->driver->recv(dev, pkt->data, bytes_expected);
        if(nread <= 0) {
            DEBUG("_recv_ethernet_packet: read error.\n");
            goto safe_out;
        }

        if (nread < bytes_expected) {
            /* we've got less then the expected packet size,
             * so free the unused space.*/

            DEBUG("_recv_ethernet_packet: reallocating.\n");
            gnrc_pktbuf_realloc_data(pkt, nread);
        }

        /* mark ethernet header */
        gnrc_pktsnip_t *eth_hdr = gnrc_pktbuf_mark(pkt, sizeof(ethernet_hdr_t), GNRC_NETTYPE_UNDEF);
        if (!eth_hdr) {
            DEBUG("gnrc_netdev2_eth: no space left in packet buffer\n");
            goto safe_out;
        }

        ethernet_hdr_t *hdr = (ethernet_hdr_t *)eth_hdr->data;

        /* set payload type from ethertype */
        pkt->type = gnrc_nettype_from_ethertype(byteorder_ntohs(hdr->type));

        /* create netif header */
        gnrc_pktsnip_t *netif_hdr;
        netif_hdr = gnrc_pktbuf_add(NULL, NULL,
                sizeof(gnrc_netif_hdr_t) + (2 * ETHERNET_ADDR_LEN),
                GNRC_NETTYPE_NETIF);

        if (netif_hdr == NULL) {
            DEBUG("gnrc_netdev2_eth: no space left in packet buffer\n");
            pkt = eth_hdr;
            goto safe_out;
        }

        gnrc_netif_hdr_init(netif_hdr->data, ETHERNET_ADDR_LEN, ETHERNET_ADDR_LEN);
        gnrc_netif_hdr_set_src_addr(netif_hdr->data, hdr->src, ETHERNET_ADDR_LEN);
        gnrc_netif_hdr_set_dst_addr(netif_hdr->data, hdr->dst, ETHERNET_ADDR_LEN);
        ((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = thread_getpid();

        DEBUG("gnrc_netdev2_eth: received packet from %02x:%02x:%02x:%02x:%02x:%02x "
                "of length %zu\n",
                hdr->src[0], hdr->src[1], hdr->src[2], hdr->src[3], hdr->src[4],
                hdr->src[5], nread);
#if defined(MODULE_OD) && ENABLE_DEBUG
        od_hex_dump(hdr, nread, OD_WIDTH_DEFAULT);
#endif

        gnrc_pktbuf_remove_snip(pkt, eth_hdr);
        LL_APPEND(pkt, netif_hdr);
    }

out:
    return pkt;

safe_out:
    gnrc_pktbuf_release(pkt);
    return NULL;
}
Exemple #23
0
bool _tftp_validate_ack(tftp_context_t *ctxt, uint8_t *buf)
{
    tftp_packet_data_t *pkt = (tftp_packet_data_t *) buf;

    return ctxt->block_nr == byteorder_ntohs(pkt->block_nr);
}
Exemple #24
0
void gnrc_rpl_p2p_recv_DRO(gnrc_pktsnip_t *pkt, ipv6_addr_t *src)
{
    gnrc_pktsnip_t *icmpv6_snip = gnrc_pktbuf_mark(pkt, sizeof(icmpv6_hdr_t), GNRC_NETTYPE_ICMPV6);
    gnrc_pktsnip_t *dro_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_dro_t),
                                                GNRC_NETTYPE_UNDEF);
    gnrc_pktsnip_t *rdo_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_opt_rdo_t),
                                                GNRC_NETTYPE_UNDEF);
    gnrc_pktsnip_t *addr_snip = pkt;
    gnrc_rpl_instance_t *inst;
    gnrc_rpl_dodag_t *dodag;
    gnrc_rpl_p2p_ext_t *p2p_ext;
    gnrc_rpl_p2p_dro_t *dro;
    gnrc_rpl_p2p_opt_rdo_t *rdo;
    uint8_t *addr_vec;
    uint16_t flags;
    size_t addr_len;

    if (!rdo_snip || !dro_snip) {
        DEBUG("RPL-P2P: Error - No DRO or RDO received\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    dro = dro_snip->data;

    if ((inst = gnrc_rpl_instance_get(dro->instance_id)) == NULL) {
        DEBUG("RPL-P2P: Error - Instance (%d) does not exist\n", dro->instance_id);
        return;
    }

    dodag = &inst->dodag;

    if ((p2p_ext = gnrc_rpl_p2p_ext_get(dodag)) == NULL) {
        DEBUG("RPL-P2P: Error - No P2P-RPL DODAG extension found\n");
        return;
    }

    if (p2p_ext->for_me) {
        DEBUG("RPL-P2P: Ignore DRO\n");
        return;
    }

    flags = byteorder_ntohs(dro->flags_rev);
    p2p_ext->stop = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_STOP)) >> GNRC_RPL_P2P_DRO_FLAGS_STOP;
    p2p_ext->dro_ack = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_ACK)) >> GNRC_RPL_P2P_DRO_FLAGS_ACK;
    p2p_ext->dro_seq = (flags & (0x3 << GNRC_RPL_P2P_DRO_FLAGS_SEQ)) >> GNRC_RPL_P2P_DRO_FLAGS_SEQ;

    addr_len = sizeof(ipv6_addr_t) - p2p_ext->compr;
    ipv6_addr_t addr = p2p_ext->dodag->dodag_id;
    ipv6_addr_t *me = NULL;
    addr_vec = addr_snip->data;

    rdo = rdo_snip->data;

    if (rdo->lmn > 0) {
        rdo->lmn--;
        memcpy(&addr.u8[p2p_ext->compr], &addr_vec[addr_len * rdo->lmn], addr_len);
    }

    if (gnrc_ipv6_netif_find_by_addr(&me, &addr) == dodag->iface) {
        gnrc_ipv6_nib_ft_add(&p2p_ext->target, IPV6_ADDR_BIT_LEN, src, dodag->iface,
                             p2p_ext->dodag->default_lifetime *
                             p2p_ext->dodag->lifetime_unit);

        if (p2p_ext->dodag->node_status != GNRC_RPL_ROOT_NODE) {
            if ((rdo_snip = gnrc_pktbuf_start_write(rdo_snip)) == NULL) {
                DEBUG("RPL-P2P: Error - Cannot allocate new RDO\n");
                return;
            }

            addr_snip->next = NULL;
            rdo_snip->next = addr_snip;
            dro_snip->next = rdo_snip;

            icmpv6_snip = gnrc_icmpv6_build(dro_snip, ICMPV6_RPL_CTRL, GNRC_RPL_P2P_ICMPV6_CODE_DRO,
                                            sizeof(icmpv6_hdr_t));
            if (icmpv6_snip == NULL) {
                DEBUG("RPL-P2P: cannot allocate ICMPv6 - no space left in packet buffer\n");
                gnrc_pktbuf_release(pkt);
                return;
            }

            gnrc_rpl_send(icmpv6_snip, p2p_ext->dodag->iface, NULL, NULL, &p2p_ext->dodag->dodag_id);
            return;
        }
    }

    gnrc_pktbuf_release(pkt);

    return;
}
Exemple #25
0
tftp_state _tftp_state_processes(tftp_context_t *ctxt, msg_t *m)
{
    gnrc_pktsnip_t *outbuf = gnrc_pktbuf_add(NULL, NULL, TFTP_DEFAULT_DATA_SIZE,
                                             GNRC_NETTYPE_UNDEF);

    /* check if this is an client start */
    if (!m) {
        DEBUG("tftp: starting transaction as client\n");
        return _tftp_send_start(ctxt, outbuf);
    }
    else if (m->type == TFTP_TIMEOUT_MSG) {
        DEBUG("tftp: timeout occured\n");
        if (++(ctxt->retries) > GNRC_TFTP_MAX_RETRIES) {
            /* transfer failed due to lost peer */
            DEBUG("tftp: peer lost\n");
            gnrc_pktbuf_release(outbuf);
            return TS_FAILED;
        }

        /* increase the timeout for congestion control */
        ctxt->block_timeout <<= 1;

        /* the send message timed out, re-sending */
        if (ctxt->dst_port == GNRC_TFTP_DEFAULT_DST_PORT) {
            DEBUG("tftp: sending timed out, re-sending\n");
            /* we are still negotiating resent, start */
            return _tftp_send_start(ctxt, outbuf);
        }
        else {
            DEBUG("tftp: last data or ack packet lost, resending\n");
            /* we are sending / receiving data */
            /* if we are reading resent the ACK, if writing the DATA */
            return _tftp_send_dack(ctxt, outbuf, (ctxt->op == TO_RRQ) ? TO_ACK : TO_DATA);
        }
    }
    else if (m->type != GNRC_NETAPI_MSG_TYPE_RCV) {
        DEBUG("tftp: unknown message\n");
        gnrc_pktbuf_release(outbuf);
        return TS_BUSY;
    }

    gnrc_pktsnip_t *pkt = m->content.ptr;

    gnrc_pktsnip_t *tmp;
    tmp = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_UDP);
    udp_hdr_t *udp = (udp_hdr_t *)tmp->data;

    tmp = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
    ipv6_hdr_t *ip = (ipv6_hdr_t *)tmp->data;
    uint8_t *data = (uint8_t *)pkt->data;

    xtimer_remove(&(ctxt->timer));

    switch (_tftp_parse_type(data)) {
        case TO_RRQ:
        case TO_WRQ: {
            if (byteorder_ntohs(udp->dst_port) != GNRC_TFTP_DEFAULT_DST_PORT) {
                /* not a valid start packet */
                DEBUG("tftp: incoming packet on port %d dropped\n", byteorder_ntohs(udp->dst_port));
                gnrc_pktbuf_release(outbuf);
                return TS_FAILED;
            }

            /* reinitialize the context with the current client */
            tftp_opcodes_t op = _tftp_parse_type(data);
            _tftp_init_ctxt(&(ip->src), NULL, op, TTM_ASCII, CT_SERVER,
                            ctxt->start_cb, ctxt->stop_cb, ctxt->data_cb,
                            ctxt->enable_options, ctxt);

            /* get the context of the client */
            ctxt->dst_port = byteorder_ntohs(udp->src_port);
            DEBUG("tftp: client's port is %" PRIu16 "\n", ctxt->dst_port);

            int offset = _tftp_decode_start(ctxt, data, outbuf);
            DEBUG("tftp: offset after decode start = %i\n", offset);
            if (offset < 0) {
                DEBUG("tftp: there is no data?\n");
                gnrc_pktbuf_release(outbuf);
                return TS_FAILED;
            }

            /* register a listener for the UDP port */
            gnrc_netreg_entry_init_pid(&(ctxt->entry), ctxt->src_port,
                                       sched_active_pid);
            gnrc_netreg_register(GNRC_NETTYPE_UDP, &(ctxt->entry));

            /* try to decode the options */
            tftp_state state;
            tftp_opcodes_t opcode;
            if (ctxt->enable_options &&
                _tftp_decode_options(ctxt, pkt, offset) > offset) {
                DEBUG("tftp: send option ACK\n");

                /* the client send the TFTP options */
                opcode = TO_OACK;
            }
            else {
                DEBUG("tftp: send normal ACK\n");

                /* the client didn't send options, use ACK and set defaults */
                _tftp_set_default_options(ctxt);

                /* send the first data block */
                if (ctxt->op == TO_RRQ) {
                    ++(ctxt->block_nr);
                    opcode = TO_DATA;
                }
                else {
                    opcode = TO_ACK;
                }
            }

            /* validate if the application accepts the action, mode, filename and transfer_size */
            tftp_action_t action = (ctxt->op == TO_RRQ) ? TFTP_READ : TFTP_WRITE;
            if (!ctxt->start_cb(action, ctxt->mode, ctxt->file_name, &(ctxt->transfer_size))) {
                _tftp_send_error(ctxt, outbuf, TE_ACCESS, "Blocked by user application");
                DEBUG("tftp: callback not able to handle mode\n");
                return TS_FAILED;
            }

            /* the client send the TFTP options */
            state = _tftp_send_dack(ctxt, outbuf, opcode);

            /* check if the client negotiation was successful */
            if (state != TS_BUSY) {
                DEBUG("tftp: not able to send ACK\n");
            }
            return state;
        } break;

        case TO_DATA: {
            /* try to process the data */
            int proc = _tftp_process_data(ctxt, pkt);
            if (proc < 0) {
                DEBUG("tftp: data not accepted\n");
                /* the data is not accepted return */
                gnrc_pktbuf_release(outbuf);
                return TS_BUSY;
            }

            /* check if this is the first block */
            if (!ctxt->block_nr
                && ctxt->dst_port == GNRC_TFTP_DEFAULT_DST_PORT
                && !ctxt->use_options) {
                /* no OACK received, restore default TFTP parameters */
                _tftp_set_default_options(ctxt);
                DEBUG("tftp: restore default TFTP parameters\n");

                /* switch the destination port to the src port of the server */
                ctxt->dst_port = byteorder_ntohs(udp->src_port);
            }

            /* wait for the next data block */
            DEBUG("tftp: wait for the next data block\n");
            ++(ctxt->block_nr);
            _tftp_send_dack(ctxt, outbuf, TO_ACK);

            /* check if the data transfer has finished */
            if (proc < ctxt->block_size) {
                DEBUG("tftp: transfer finished\n");

                if (ctxt->stop_cb) {
                    ctxt->stop_cb(TFTP_SUCCESS, NULL);
                }

                return TS_FINISHED;
            }

            return TS_BUSY;
        } break;

        case TO_ACK: {
            /* validate if this is the ACK we are waiting for */
            if (!_tftp_validate_ack(ctxt, data)) {
                /* invalid packet ACK, drop */
                gnrc_pktbuf_release(outbuf);
                return TS_BUSY;
            }

            /* check if the write action is finished */
            if (ctxt->write_finished) {
                gnrc_pktbuf_release(outbuf);

                if (ctxt->stop_cb) {
                    ctxt->stop_cb(TFTP_SUCCESS, NULL);
                }

                return TS_FINISHED;
            }

            /* check if this is the first ACK */
            if (!ctxt->block_nr && ctxt->dst_port != byteorder_ntohs(udp->src_port)) {
                /* no OACK received restore default TFTP parameters */
                _tftp_set_default_options(ctxt);

                /* switch the destination port to the src port of the server */
                ctxt->dst_port = byteorder_ntohs(udp->src_port);
            }

            /* send the next data block */
            ++(ctxt->block_nr);

            return _tftp_send_dack(ctxt, outbuf, TO_DATA);
        } break;

        case TO_ERROR: {
            tftp_err_codes_t err;
            const char *err_msg;

            /* decode the received error */
            _tftp_decode_error(data, &err, &err_msg);

            /* inform the user application about the error */
            if (ctxt->stop_cb) {
                ctxt->stop_cb(TFTP_PEER_ERROR, err_msg);
            }

            DEBUG("tftp: ERROR: %s\n", err_msg);
            gnrc_pktbuf_release(outbuf);
            return TS_FAILED;
        } break;

        case TO_OACK: {
            /* only allow one OACK to be received */
            if (ctxt->dst_port != byteorder_ntohs(udp->src_port)) {
                DEBUG("tftp: TO_OACK received\n");

                /* decode the options */
                _tftp_decode_options(ctxt, pkt, 0);

                /* take the new source port */
                ctxt->dst_port = byteorder_ntohs(udp->src_port);

                /* we must send block one to finish the negotiation in send mode */
                if (ctxt->op == TO_WRQ) {
                    ++(ctxt->block_nr);
                }
            }
            else {
                DEBUG("tftp: dropping double TO_OACK\n");
            }

            return _tftp_send_dack(ctxt, outbuf, (ctxt->op == TO_WRQ) ? TO_DATA : TO_ACK);
        } break;
    }

    gnrc_pktbuf_release(outbuf);
    return TS_FAILED;
}
Exemple #26
0
static void _receive(gnrc_pktsnip_t *pkt)
{
    kernel_pid_t iface = KERNEL_PID_UNDEF;
    gnrc_pktsnip_t *ipv6, *netif;
    ipv6_hdr_t *hdr;

    assert(pkt != NULL);

    LL_SEARCH_SCALAR(pkt, netif, type, GNRC_NETTYPE_NETIF);

    if (netif != NULL) {
        iface = ((gnrc_netif_hdr_t *)netif->data)->if_pid;
    }

    if ((pkt->next != NULL) && (pkt->next->type == GNRC_NETTYPE_IPV6) &&
        (pkt->next->size == sizeof(ipv6_hdr_t))) {
        /* IP header was already marked. Take it. */
        ipv6 = pkt->next;

        if (!ipv6_hdr_is(ipv6->data)) {
            DEBUG("ipv6: Received packet was not IPv6, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }
    else {
        if (!ipv6_hdr_is(pkt->data)) {
            DEBUG("ipv6: Received packet was not IPv6, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        /* seize ipv6 as a temporary variable */
        ipv6 = gnrc_pktbuf_start_write(pkt);

        if (ipv6 == NULL) {
            DEBUG("ipv6: unable to get write access to packet, drop it\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        pkt = ipv6;     /* reset pkt from temporary variable */

        ipv6 = gnrc_pktbuf_mark(pkt, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6);

        if (ipv6 == NULL) {
            DEBUG("ipv6: error marking IPv6 header, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }

    /* extract header */
    hdr = (ipv6_hdr_t *)ipv6->data;

    /* if available, remove any padding that was added by lower layers
     * to fulfill their minimum size requirements (e.g. ethernet) */
    if (byteorder_ntohs(hdr->len) < pkt->size) {
        gnrc_pktbuf_realloc_data(pkt, byteorder_ntohs(hdr->len));
    }

    DEBUG("ipv6: Received (src = %s, ",
          ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str)));
    DEBUG("dst = %s, next header = %" PRIu8 ", length = %" PRIu16 ")\n",
          ipv6_addr_to_str(addr_str, &(hdr->dst), sizeof(addr_str)),
          hdr->nh, byteorder_ntohs(hdr->len));

    if (_pkt_not_for_me(&iface, hdr)) { /* if packet is not for me */
        DEBUG("ipv6: packet destination not this host\n");

#ifdef MODULE_GNRC_IPV6_ROUTER    /* only routers redirect */
        /* redirect to next hop */
        DEBUG("ipv6: decrement hop limit to %" PRIu8 "\n", hdr->hl - 1);

        /* RFC 4291, section 2.5.6 states: "Routers must not forward any
         * packets with Link-Local source or destination addresses to other
         * links."
         */
        if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) {
            DEBUG("ipv6: do not forward packets with link-local source or"\
                  " destination address\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
        /* TODO: check if receiving interface is router */
        else if (--(hdr->hl) > 0) {  /* drop packets that *reach* Hop Limit 0 */
            gnrc_pktsnip_t *tmp = pkt;

            DEBUG("ipv6: forward packet to next hop\n");

            /* pkt might not be writable yet, if header was given above */
            pkt = gnrc_pktbuf_start_write(tmp);
            ipv6 = gnrc_pktbuf_start_write(ipv6);

            if ((ipv6 == NULL) || (pkt == NULL)) {
                DEBUG("ipv6: unable to get write access to packet: dropping it\n");
                gnrc_pktbuf_release(tmp);
                return;
            }

            gnrc_pktbuf_release(ipv6->next);    /* remove headers around IPV6 */
            ipv6->next = pkt;                   /* reorder for sending */
            pkt->next = NULL;
            _send(ipv6, false);
            return;
        }
        else {
            DEBUG("ipv6: hop limit reached 0: drop packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

#else  /* MODULE_GNRC_IPV6_ROUTER */
        DEBUG("ipv6: dropping packet\n");
        /* non rounting hosts just drop the packet */
        gnrc_pktbuf_release(pkt);
        return;
#endif /* MODULE_GNRC_IPV6_ROUTER */
    }

    /* IPv6 internal demuxing (ICMPv6, Extension headers etc.) */
    gnrc_ipv6_demux(iface, pkt, hdr->nh);
}
Exemple #27
0
void rpl_recv_DIO(void)
{
    ipv6_buf = get_rpl_ipv6_buf();

    rpl_dio_buf = get_rpl_dio_buf();
    DEBUGF("instance %04X ", rpl_dio_buf->rpl_instanceid);
    DEBUGF("rank %04X\n", byteorder_ntohs(rpl_dio_buf->rank));
    int len = DIO_BASE_LEN;

    rpl_instance_t *dio_inst = rpl_get_instance(rpl_dio_buf->rpl_instanceid);
    rpl_instance_t *my_inst = rpl_get_my_instance();

    if (dio_inst == NULL) {
        if (my_inst != NULL) {
            /* already part of a DODAG -> impossible to join other instance */
            DEBUGF("Not joining another DODAG!\n");
            return;
        }

        dio_inst = rpl_new_instance(rpl_dio_buf->rpl_instanceid);

        if (dio_inst == NULL) {
            DEBUGF("Failed to create a new RPL instance!\n");
            return;
        }
    }
    else if (my_inst == NULL) {
        DEBUGF("Not joined an instance yet\n");
    }
    else if (my_inst->id != dio_inst->id) {
        /* TODO: Add support support for several instances.  */

        /* At the moment, nodes can only join one instance, this is
        * the instance they join first.
        * Instances cannot be switched later on.  */

        DEBUGF("Ignoring instance - we are %d and got %d\n", my_inst->id, dio_inst->id);
        return;
    }

    rpl_dodag_t dio_dodag;
    memset(&dio_dodag, 0, sizeof(dio_dodag));

    memcpy(&dio_dodag.dodag_id, &rpl_dio_buf->dodagid, sizeof(dio_dodag.dodag_id));
    dio_dodag.dtsn = rpl_dio_buf->dtsn;
    dio_dodag.mop = ((rpl_dio_buf->g_mop_prf >> RPL_MOP_SHIFT) & RPL_SHIFTED_MOP_MASK);
    dio_dodag.grounded = rpl_dio_buf->g_mop_prf >> RPL_GROUNDED_SHIFT;
    dio_dodag.prf = (rpl_dio_buf->g_mop_prf & RPL_PRF_MASK);
    dio_dodag.version = rpl_dio_buf->version_number;
    dio_dodag.instance = dio_inst;

    uint8_t has_dodag_conf_opt = 0;

    /* Parse until all options are consumed.
     * ipv6_buf->length contains the packet length minus ipv6 and
     * icmpv6 header, so only ICMPV6_HDR_LEN remains to be
     * subtracted.  */
    while (len < (NTOHS(ipv6_buf->length) - ICMPV6_HDR_LEN)) {
        DEBUGF("parsing DIO options\n");
        rpl_opt_buf = get_rpl_opt_buf(len);

        switch (rpl_opt_buf->type) {

            case (RPL_OPT_PAD1): {
                len += 1;
                break;
            }

            case (RPL_OPT_PADN): {
                len += rpl_opt_buf->length;
                break;
            }

            case (RPL_OPT_DAG_METRIC_CONTAINER): {
                len += rpl_opt_buf->length;
                break;
            }

            case (RPL_OPT_ROUTE_INFO): {
                len += rpl_opt_buf->length;
                break;
            }

            case (RPL_OPT_DODAG_CONF): {
                has_dodag_conf_opt = 1;

                if (rpl_opt_buf->length != RPL_OPT_DODAG_CONF_LEN) {
                    DEBUGF("DODAG configuration is malformed.\n");
                    /* error malformed */
                    return;
                }

                rpl_opt_dodag_conf_buf = get_rpl_opt_dodag_conf_buf(len);
                dio_dodag.dio_interval_doubling = rpl_opt_dodag_conf_buf->DIOIntDoubl;
                dio_dodag.dio_min = rpl_opt_dodag_conf_buf->DIOIntMin;
                dio_dodag.dio_redundancy = rpl_opt_dodag_conf_buf->DIORedun;
                dio_dodag.maxrankincrease = byteorder_ntohs(rpl_opt_dodag_conf_buf->MaxRankIncrease);
                dio_dodag.minhoprankincrease = byteorder_ntohs(rpl_opt_dodag_conf_buf->MinHopRankIncrease);
                dio_dodag.default_lifetime = rpl_opt_dodag_conf_buf->default_lifetime;
                dio_dodag.lifetime_unit = byteorder_ntohs(rpl_opt_dodag_conf_buf->lifetime_unit);
                dio_dodag.of = (struct rpl_of_t *) rpl_get_of_for_ocp(byteorder_ntohs(rpl_opt_dodag_conf_buf->ocp));
                if (dio_dodag.of == NULL) {
                    DEBUGF("[Error] OCP from DIO is not supported! ocp: %x\n",
                    byteorder_ntohs(rpl_opt_dodag_conf_buf->ocp));
                    return;
                }

                len += RPL_OPT_DODAG_CONF_LEN_WITH_OPT_LEN;
                break;
            }

            case (RPL_OPT_PREFIX_INFO): {
                if (rpl_opt_buf->length != RPL_OPT_PREFIX_INFO_LEN) {
                    /* error malformed */
                    return;
                }

                rpl_opt_prefix_information_buf = get_rpl_opt_prefix_information_buf(len);

                /* autonomous address-configuration flag */
                if (rpl_opt_prefix_information_buf->flags & (1 << 6)) {
                    ipv6_addr_t tmp;
                    tmp = rpl_opt_prefix_information_buf->prefix;
                    if (!ipv6_addr_is_link_local(&tmp)) {
                        if (byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime)
                                <= byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime)) {
                            ipv6_addr_set_by_eui64(&tmp, rpl_if_id, &tmp);
                            ipv6_net_if_add_addr(rpl_if_id, &tmp,
                                    NDP_ADDR_STATE_PREFERRED,
                                    byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime),
                                    byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime),
                                    0);
                            dio_dodag.prefix = rpl_opt_prefix_information_buf->prefix;
                            dio_dodag.prefix_length = rpl_opt_prefix_information_buf->prefix_length;
                            dio_dodag.prefix_valid_lifetime =
                                byteorder_ntohl(rpl_opt_prefix_information_buf->valid_lifetime);
                            dio_dodag.prefix_preferred_lifetime =
                                byteorder_ntohl(rpl_opt_prefix_information_buf->preferred_lifetime);
                            dio_dodag.prefix_flags = rpl_opt_prefix_information_buf->flags;
                        }
                    }
                }

                len += RPL_OPT_PREFIX_INFO_LEN_WITH_OPT_LEN;
                break;
            }

            default:
                DEBUGF("[Error] Unsupported DIO option\n");
                return;
        }
    }

    /* handle packet content... */
    rpl_dodag_t *my_dodag = rpl_get_joined_dodag(dio_inst->id);

    if (my_dodag == NULL) {
        if (!has_dodag_conf_opt) {
            DEBUGF("send DIS\n");
            rpl_send_DIS(&ipv6_buf->srcaddr);
        }

        if (byteorder_ntohs(rpl_dio_buf->rank) < ROOT_RANK) {
            DEBUGF("DIO with Rank < ROOT_RANK\n");
        }

        if (dio_dodag.mop != RPL_DEFAULT_MOP) {
            DEBUGF("Required MOP not supported\n");
        }

        if (dio_dodag.of == NULL) {
            DEBUGF("Required objective function not supported\n");
        }

        if (byteorder_ntohs(rpl_dio_buf->rank) != INFINITE_RANK) {
            DEBUGF("Will join DODAG\n");
            rpl_join_dodag(&dio_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank));
        }
        else {
            DEBUGF("Cannot access DODAG because of DIO with infinite rank\n");
        }

        return;
    }

    if (rpl_equal_id(&my_dodag->dodag_id, &dio_dodag.dodag_id)) {
        /* "our" DODAG */
        if (RPL_COUNTER_GREATER_THAN(dio_dodag.version, my_dodag->version)) {
            if (my_dodag->my_rank == ROOT_RANK) {
                DEBUGF("[Warning] Inconsistent Dodag Version\n");
                my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version);
                trickle_reset_timer(&my_dodag->trickle);
            }
            else {
                DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n");
                my_dodag->version = dio_dodag.version;
                rpl_global_repair(my_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank));
            }

            return;
        }
        else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) {
            /* lower version number detected -> send more DIOs */
            trickle_reset_timer(&my_dodag->trickle);
            return;
        }
    }

    /* version matches, DODAG matches */
    if (byteorder_ntohs(rpl_dio_buf->rank) == INFINITE_RANK) {
        trickle_reset_timer(&my_dodag->trickle);
    }

    /* We are root, all done!*/
    if (my_dodag->my_rank == ROOT_RANK) {
        if (byteorder_ntohs(rpl_dio_buf->rank) != INFINITE_RANK) {
            trickle_increment_counter(&my_dodag->trickle);
        }

        return;
    }

    /*********************  Parent Handling *********************/

    rpl_parent_t *parent;
    parent = rpl_find_parent(my_dodag, &ipv6_buf->srcaddr);

    if (parent == NULL) {
        /* add new parent candidate */
        parent = rpl_new_parent(my_dodag, &ipv6_buf->srcaddr, byteorder_ntohs(rpl_dio_buf->rank));

        if (parent == NULL) {
            return;
        }
    }
    else {
        /* DIO OK */
        trickle_increment_counter(&my_dodag->trickle);
    }

    /* update parent rank */
    parent->rank = byteorder_ntohs(rpl_dio_buf->rank);
    rpl_parent_update(my_dodag, parent);

    if (my_dodag->my_preferred_parent == NULL) {
        DEBUGF("My dodag has no preferred_parent yet - seems to be odd since I have a parent...\n");
    }
    else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) &&
             (parent->dtsn != rpl_dio_buf->dtsn)) {
        rpl_delay_dao(my_dodag);
    }

    parent->dtsn = rpl_dio_buf->dtsn;

}
Exemple #28
0
static void _receive(ng_pktsnip_t *pkt)
{
    kernel_pid_t iface = KERNEL_PID_UNDEF;
    ng_pktsnip_t *ipv6, *netif;
    ng_ipv6_hdr_t *hdr;

    LL_SEARCH_SCALAR(pkt, netif, type, NG_NETTYPE_NETIF);

    if (netif != NULL) {
        iface = ((ng_netif_hdr_t *)netif->data)->if_pid;
    }

    if ((pkt->next != NULL) && (pkt->next->type == NG_NETTYPE_IPV6) &&
        (pkt->next->size == sizeof(ng_ipv6_hdr_t))) {
        /* IP header was already marked. Take it. */
        ipv6 = pkt->next;

        if (!ng_ipv6_hdr_is(ipv6->data)) {
            DEBUG("ipv6: Received packet was not IPv6, dropping packet\n");
            ng_pktbuf_release(pkt);
            return;
        }
    }
    else {
        if (!ng_ipv6_hdr_is(pkt->data)) {
            DEBUG("ipv6: Received packet was not IPv6, dropping packet\n");
            ng_pktbuf_release(pkt);
            return;
        }

        /* seize ipv6 as a temporary variable */
        ipv6 = ng_pktbuf_start_write(pkt);

        if (ipv6 == NULL) {
            DEBUG("ipv6: unable to get write access to packet, drop it\n");
            ng_pktbuf_release(pkt);
            return;
        }

        pkt = ipv6;     /* reset pkt from temporary variable */

        ipv6 = ng_pktbuf_add(pkt, pkt->data, sizeof(ng_ipv6_hdr_t),
                             NG_NETTYPE_IPV6);

        if (ipv6 == NULL) {
            DEBUG("ipv6: error marking IPv6 header, dropping packet\n");
            ng_pktbuf_release(pkt);
            return;
        }
    }

    /* extract header */
    hdr = (ng_ipv6_hdr_t *)ipv6->data;

    DEBUG("ipv6: Received (src = %s, ",
          ng_ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str)));
    DEBUG("dst = %s, next header = %" PRIu8 ", length = %" PRIu16 ")\n",
          ng_ipv6_addr_to_str(addr_str, &(hdr->dst), sizeof(addr_str)),
          hdr->nh, byteorder_ntohs(hdr->len));

    if (_pkt_not_for_me(&iface, hdr)) { /* if packet is not for me */
        DEBUG("ipv6: packet destination not this host\n");

#ifdef MODULE_NG_IPV6_ROUTER    /* only routers redirect */
        /* redirect to next hop */
        DEBUG("ipv6: decrement hop limit to %" PRIu8 "\n", hdr->hl - 1);

        /* TODO: check if receiving interface is router */
        if (--(hdr->hl) > 0) {  /* drop packets that *reach* Hop Limit 0 */
            ng_pktsnip_t *tmp = pkt;

            DEBUG("ipv6: forward packet to next hop\n");

            /* pkt might not be writable yet, if header was given above */
            pkt = ng_pktbuf_start_write(tmp);
            ipv6 = ng_pktbuf_start_write(ipv6);

            if ((ipv6 == NULL) || (pkt == NULL)) {
                DEBUG("ipv6: unable to get write access to packet: dropping it\n");
                ng_pktbuf_release(tmp);
                return;
            }

            ng_pktbuf_release(ipv6->next);  /* remove headers around IPV6 */
            ipv6->next = pkt;           /* reorder for sending */
            pkt->next = NULL;
            _send(ipv6, false);
        }
        else {
            DEBUG("ipv6: hop limit reached 0: drop packet\n");
            ng_pktbuf_release(pkt);
            return;
        }

#else  /* MODULE_NG_IPV6_ROUTER */
        DEBUG("ipv6: dropping packet\n");
        /* non rounting hosts just drop the packet */
        ng_pktbuf_release(pkt);
        return;
#endif /* MODULE_NG_IPV6_ROUTER */
    }

    /* IPv6 internal demuxing (ICMPv6, Extension headers etc.) */
    ng_ipv6_demux(iface, pkt, hdr->nh);
}
Exemple #29
0
void ng_icmpv6_echo_req_handle(kernel_pid_t iface, ng_ipv6_hdr_t *ipv6_hdr,
                               ng_icmpv6_echo_t *echo, uint16_t len)
{
    uint8_t *payload = ((uint8_t *)echo) + sizeof(ng_icmpv6_echo_t);
    ng_pktsnip_t *hdr, *pkt;
    ng_netreg_entry_t *sendto = NULL;

    if ((echo == NULL) || (len < sizeof(ng_icmpv6_echo_t))) {
        DEBUG("icmpv6_echo: echo was NULL or len (%" PRIu16
              ") was < sizeof(ng_icmpv6_echo_t)\n", len);
        return;
    }

    pkt = ng_icmpv6_echo_build(NG_ICMPV6_ECHO_REP, byteorder_ntohs(echo->id),
                               byteorder_ntohs(echo->seq), payload,
                               len - sizeof(ng_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 = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)&ipv6_hdr->src,
                                sizeof(ipv6_addr_t));
    }
    else {
        hdr = ng_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");
        ng_pktbuf_release(pkt);
        return;
    }

    pkt = hdr;
    hdr = ng_netif_hdr_build(NULL, 0, NULL, 0);

    ((ng_netif_hdr_t *)hdr->data)->if_pid = iface;

    LL_PREPEND(pkt, hdr);

    sendto = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL);

    if (sendto == NULL) {
        DEBUG("icmpv6_echo: no receivers for IPv6 packets\n");
        ng_pktbuf_release(pkt);
        return;
    }

    /* ICMPv6 is not interested anymore so `- 1` */
    ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL) - 1);

    while (sendto != NULL) {
        ng_netapi_send(sendto->pid, pkt);
        sendto = ng_netreg_getnext(sendto);
    }
}
Exemple #30
0
void recv(netdev2_t *dev)
{
    uint8_t src[IEEE802154_LONG_ADDRESS_LEN], dst[IEEE802154_LONG_ADDRESS_LEN];
    size_t mhr_len, data_len, src_len, dst_len;
    netdev2_ieee802154_rx_info_t rx_info;
    le_uint16_t src_pan, dst_pan;

    putchar('\n');
    data_len = dev->driver->recv(dev, buffer, sizeof(buffer), &rx_info);
    mhr_len = ieee802154_get_frame_hdr_len(buffer);
    if (mhr_len == 0) {
        puts("Unexpected MHR for incoming packet");
        return;
    }
    dst_len = ieee802154_get_dst(buffer, dst, &dst_pan);
    src_len = ieee802154_get_src(buffer, src, &src_pan);
    switch (buffer[0] & IEEE802154_FCF_TYPE_MASK) {
        case IEEE802154_FCF_TYPE_BEACON:
            puts("BEACON");
            break;
        case IEEE802154_FCF_TYPE_DATA:
            puts("DATA");
            break;
        case IEEE802154_FCF_TYPE_ACK:
            puts("ACK");
            break;
        case IEEE802154_FCF_TYPE_MACCMD:
            puts("MACCMD");
            break;
        default:
            puts("UNKNOWN");
            break;
    }
    printf("Dest. PAN: 0x%04x, Dest. addr.: ",
           byteorder_ntohs(byteorder_ltobs(dst_pan)));
    print_addr(dst, dst_len);
    printf("\nSrc. PAN: 0x%04x, Src. addr.: ",
           byteorder_ntohs(byteorder_ltobs(src_pan)));
    print_addr(src, src_len);
    printf("\nSecurity: ");
    if (buffer[0] & IEEE802154_FCF_SECURITY_EN) {
        printf("1, ");
    }
    else {
        printf("0, ");
    }
    printf("Frame pend.: ");
    if (buffer[0] & IEEE802154_FCF_FRAME_PEND) {
        printf("1, ");
    }
    else {
        printf("0, ");
    }
    printf("ACK req.: ");
    if (buffer[0] & IEEE802154_FCF_ACK_REQ) {
        printf("1, ");
    }
    else {
        printf("0, ");
    }
    printf("PAN comp.: ");
    if (buffer[0] & IEEE802154_FCF_PAN_COMP) {
        puts("1");
    }
    else {
        puts("0");
    }
    printf("Version: ");
    printf("%u, ", (unsigned)((buffer[1] & IEEE802154_FCF_VERS_MASK) >> 4));
    printf("Seq.: %u\n", (unsigned)ieee802154_get_seq(buffer));
    od_hex_dump(buffer + mhr_len, data_len - mhr_len, 0);
    printf("txt: ");
    for (int i = mhr_len; i < data_len; i++) {
        if ((buffer[i] > 0x1F) && (buffer[i] < 0x80)) {
            putchar((char)buffer[i]);
        }
        else {
            putchar('?');
        }
        if (((((i - mhr_len) + 1) % (MAX_LINE - sizeof("txt: "))) == 1) &&
            (i - mhr_len) != 0) {
            printf("\n     ");
        }
    }
    printf("\n");
    printf("RSSI: %u, LQI: %u\n\n", rx_info.rssi, rx_info.lqi);
}