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); } }
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); }
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); }
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); } }
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; }
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; }
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; }
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))); }
/* 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; }
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); }
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; }
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); } }
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); }
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); } }
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); }
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); }
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); }
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); } }
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; }
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); }
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; }
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; }
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); }
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; }
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); }
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); } }
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); }