static void test_pktbuf_hold__pkt_external(void) { gnrc_pktsnip_t pkt = { NULL, TEST_STRING8, sizeof(TEST_STRING8), 1, GNRC_NETTYPE_TEST }; gnrc_pktbuf_hold(&pkt, 1); TEST_ASSERT(gnrc_pktbuf_is_empty()); }
static void test_pktbuf_hold__success2(void) { gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16), GNRC_NETTYPE_TEST); gnrc_pktbuf_hold(pkt, TEST_UINT8); TEST_ASSERT_EQUAL_INT(TEST_UINT8 + 1, pkt->users); }
void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint8_t nh) { int receiver_num; pkt->type = gnrc_nettype_from_protnum(nh); switch (nh) { #ifdef MODULE_GNRC_ICMPV6 case PROTNUM_ICMPV6: DEBUG("ipv6: handle ICMPv6 packet (nh = %" PRIu8 ")\n", nh); gnrc_icmpv6_demux(iface, pkt); break; #endif #ifdef MODULE_GNRC_IPV6_EXT case PROTNUM_IPV6_EXT_HOPOPT: case PROTNUM_IPV6_EXT_DST: case PROTNUM_IPV6_EXT_RH: case PROTNUM_IPV6_EXT_FRAG: case PROTNUM_IPV6_EXT_AH: case PROTNUM_IPV6_EXT_ESP: case PROTNUM_IPV6_EXT_MOB: DEBUG("ipv6: handle extension header (nh = %" PRIu8 ")\n", nh); if (!gnrc_ipv6_ext_demux(iface, pkt, nh)) { DEBUG("ipv6: unable to parse extension headers.\n"); gnrc_pktbuf_release(pkt); return; } #endif case PROTNUM_IPV6: DEBUG("ipv6: handle encapsulated IPv6 packet (nh = %" PRIu8 ")\n", nh); _decapsulate(pkt); break; default: (void)iface; break; } DEBUG("ipv6: forward nh = %" PRIu8 " to other threads\n", nh); receiver_num = gnrc_netreg_num(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL) + gnrc_netreg_num(GNRC_NETTYPE_IPV6, nh); if (receiver_num == 0) { DEBUG("ipv6: unable to forward packet as no one is interested in it\n"); gnrc_pktbuf_release(pkt); return; } gnrc_pktbuf_hold(pkt, receiver_num - 1); /* IPv6 is not interested anymore so `- 1` */ /* XXX can't use gnrc_netapi_dispatch_receive() twice here since a call to that function * implicitly hands all rights to the packet to one of the receiving threads. As a result, * the second call to gnrc_netapi_dispatch_receive() would be invalid */ _dispatch_rcv_pkt(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt); _dispatch_rcv_pkt(GNRC_NETTYPE_IPV6, nh, pkt); }
static void test_pktbuf_hold__success(void) { gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16), GNRC_NETTYPE_TEST); for (uint8_t i = 0; i < TEST_UINT8; i++) { uint8_t prev_users = pkt->users; gnrc_pktbuf_hold(pkt, 1); TEST_ASSERT_EQUAL_INT(prev_users + 1, pkt->users); } }
int gnrc_gomach_send_data(gnrc_netif_t *netif, netopt_enable_t csma_enable) { assert(netif != NULL); gnrc_pktsnip_t *pkt = netif->mac.tx.packet; assert(pkt != NULL); /* Insert GoMacH header above NETIF header. */ gnrc_gomach_frame_data_t *gomach_data_hdr_pointer; gnrc_pktsnip_t *gomach_snip = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_GOMACH); if (gomach_snip != NULL) { gomach_data_hdr_pointer = gomach_snip->data; } else { gomach_data_hdr_pointer = NULL; } if (gomach_data_hdr_pointer == NULL) { /* No GoMacH header yet, build one. */ gnrc_gomach_frame_data_t gomach_data_hdr; gomach_data_hdr.header.type = GNRC_GOMACH_FRAME_DATA; /* Set the queue-length indicator according to its current queue situation. */ gomach_data_hdr.queue_indicator = gnrc_priority_pktqueue_length(&netif->mac.tx.current_neighbor->queue); /* Save the payload pointer. */ gnrc_pktsnip_t *payload = netif->mac.tx.packet->next; pkt->next = gnrc_pktbuf_add(pkt->next, &gomach_data_hdr, sizeof(gomach_data_hdr), GNRC_NETTYPE_GOMACH); if (pkt->next == NULL) { LOG_ERROR("ERROR: [GOMACH]: pktbuf add failed in gnrc_gomach_send_data().\n"); /* Make append payload after netif header again. */ netif->mac.tx.packet->next = payload; return -ENOBUFS; } } else { /* GoMacH header exists, update the queue-indicator. */ gomach_data_hdr_pointer->queue_indicator = gnrc_priority_pktqueue_length(&netif->mac.tx.current_neighbor->queue); } gnrc_pktbuf_hold(netif->mac.tx.packet, 1); /* Send the data packet here. */ return gnrc_gomach_send(netif, netif->mac.tx.packet, csma_enable); }
/* internal functions */ static void _dispatch_next_header(gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, uint8_t nh, bool interested) { #ifdef MODULE_GNRC_IPV6_EXT const bool should_dispatch_current_type = ((current->type != GNRC_NETTYPE_IPV6_EXT) || (current->next->type == GNRC_NETTYPE_IPV6)); #else const bool should_dispatch_current_type = (current->next->type == GNRC_NETTYPE_IPV6); #endif DEBUG("ipv6: forward nh = %u to other threads\n", nh); /* dispatch IPv6 extension header only once */ if (should_dispatch_current_type) { bool should_release = (gnrc_netreg_num(GNRC_NETTYPE_IPV6, nh) == 0) && (!interested); if (!should_release) { gnrc_pktbuf_hold(pkt, 1); /* don't remove from packet buffer in * next dispatch */ } if (gnrc_netapi_dispatch_receive(current->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt) == 0) { gnrc_pktbuf_release(pkt); } if (should_release) { return; } } if (interested) { gnrc_pktbuf_hold(pkt, 1); /* don't remove from packet buffer in * next dispatch */ } if (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, nh, pkt) == 0) { gnrc_pktbuf_release(pkt); } }
static void test_pktbuf_start_write__pkt_users_2(void) { gnrc_pktsnip_t *pkt_copy, *pkt = gnrc_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16), GNRC_NETTYPE_TEST); gnrc_pktbuf_hold(pkt, 1); TEST_ASSERT_NOT_NULL((pkt_copy = gnrc_pktbuf_start_write(pkt))); TEST_ASSERT(pkt != pkt_copy); TEST_ASSERT(pkt->next == pkt_copy->next); TEST_ASSERT_EQUAL_STRING(pkt->data, pkt_copy->data); TEST_ASSERT_EQUAL_INT(pkt->size, pkt_copy->size); TEST_ASSERT_EQUAL_INT(pkt->type, pkt_copy->type); TEST_ASSERT_EQUAL_INT(pkt->users, pkt_copy->users); TEST_ASSERT_EQUAL_INT(1, pkt->users); gnrc_pktbuf_release(pkt_copy); gnrc_pktbuf_release(pkt); TEST_ASSERT(gnrc_pktbuf_is_empty()); }
static void test_pktbuf_reverse_snips__too_full(void) { gnrc_pktsnip_t *pkt, *pkt_next, *pkt_huge; const size_t pkt_huge_size = GNRC_PKTBUF_SIZE - (3 * 8) - (3 * sizeof(gnrc_pktsnip_t)) - 4; pkt_next = gnrc_pktbuf_add(NULL, TEST_STRING8, 8, GNRC_NETTYPE_TEST); TEST_ASSERT_NOT_NULL(pkt_next); /* hold to enforce duplication */ gnrc_pktbuf_hold(pkt_next, 1); pkt = gnrc_pktbuf_add(pkt_next, TEST_STRING8, 8, GNRC_NETTYPE_TEST); TEST_ASSERT_NOT_NULL(pkt); /* filling up rest of packet buffer */ pkt_huge = gnrc_pktbuf_add(NULL, NULL, pkt_huge_size, GNRC_NETTYPE_UNDEF); TEST_ASSERT_NOT_NULL(pkt_huge); TEST_ASSERT_NULL(gnrc_pktbuf_reverse_snips(pkt)); gnrc_pktbuf_release(pkt_huge); /* release because of hold above */ gnrc_pktbuf_release(pkt_next); TEST_ASSERT(gnrc_pktbuf_is_empty()); }
int gnrc_netapi_dispatch(gnrc_nettype_t type, uint32_t demux_ctx, uint16_t cmd, gnrc_pktsnip_t *pkt) { int numof = gnrc_netreg_num(type, demux_ctx); if (numof != 0) { gnrc_netreg_entry_t *sendto = gnrc_netreg_lookup(type, demux_ctx); gnrc_pktbuf_hold(pkt, numof - 1); while (sendto) { if (_snd_rcv(sendto->pid, cmd, pkt) < 1) { /* unable to dispatch packet */ gnrc_pktbuf_release(pkt); } sendto = gnrc_netreg_getnext(sendto); } } return numof; }
static void test_pktbuf_hold__pkt_null(void) { gnrc_pktbuf_hold(NULL, 1); TEST_ASSERT(gnrc_pktbuf_is_empty()); }
static void _send_multicast(kernel_pid_t iface, gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *ipv6, gnrc_pktsnip_t *payload, bool prep_hdr) { kernel_pid_t ifs[GNRC_NETIF_NUMOF]; size_t ifnum = 0; if (iface == KERNEL_PID_UNDEF) { /* get list of interfaces */ ifnum = gnrc_netif_get(ifs); /* throw away packet if no one is interested */ if (ifnum == 0) { DEBUG("ipv6: no interfaces registered, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } } #if GNRC_NETIF_NUMOF > 1 /* netif header not present: send over all interfaces */ if (iface == KERNEL_PID_UNDEF) { assert(pkt == ipv6); /* send packet to link layer */ gnrc_pktbuf_hold(pkt, ifnum - 1); for (size_t i = 0; i < ifnum; i++) { gnrc_pktsnip_t *netif; if (prep_hdr) { /* need to get second write access (duplication) to fill IPv6 * header interface-local */ gnrc_pktsnip_t *tmp = gnrc_pktbuf_start_write(pkt); gnrc_pktsnip_t *ptr = tmp->next; ipv6 = tmp; if (ipv6 == NULL) { DEBUG("ipv6: unable to get write access to IPv6 header, " "for interface %" PRIkernel_pid "\n", ifs[i]); gnrc_pktbuf_release(pkt); return; } /* multiple interfaces => possibly different source addresses * => different checksums => duplication of payload needed */ while (ptr != payload->next) { /* duplicate everything including payload */ tmp->next = gnrc_pktbuf_start_write(ptr); if (tmp->next == NULL) { DEBUG("ipv6: unable to get write access to payload, drop it\n"); gnrc_pktbuf_release(ipv6); return; } tmp = tmp->next; ptr = ptr->next; } if (_fill_ipv6_hdr(ifs[i], ipv6, tmp) < 0) { /* error on filling up header */ gnrc_pktbuf_release(ipv6); return; } } /* allocate interface header */ netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0); if (netif == NULL) { DEBUG("ipv6: error on interface header allocation, " "dropping packet\n"); gnrc_pktbuf_release(ipv6); return; } LL_PREPEND(ipv6, netif); _send_multicast_over_iface(ifs[i], ipv6); } } else { /* iface != KERNEL_PID_UNDEF implies that netif header is present */ assert(pkt != ipv6); if (prep_hdr) { if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) { /* error on filling up header */ gnrc_pktbuf_release(pkt); return; } } _send_multicast_over_iface(iface, pkt); } #else /* GNRC_NETIF_NUMOF */ (void)ifnum; /* not used in this build branch */ if (iface == KERNEL_PID_UNDEF) { gnrc_pktsnip_t *netif; iface = ifs[0]; /* allocate interface header */ netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0); if (netif == NULL) { DEBUG("ipv6: error on interface header allocation, " "dropping packet\n"); gnrc_pktbuf_release(pkt); return; } LL_PREPEND(pkt, netif); } if (prep_hdr) { if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) { /* error on filling up header */ gnrc_pktbuf_release(pkt); return; } } _send_multicast_over_iface(iface, pkt); #endif /* GNRC_NETIF_NUMOF */ }
static void _send_multicast(kernel_pid_t iface, gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *ipv6, gnrc_pktsnip_t *payload, bool prep_hdr) { gnrc_pktsnip_t *netif; kernel_pid_t ifs[GNRC_NETIF_NUMOF]; size_t ifnum = 0; if (iface == KERNEL_PID_UNDEF) { /* get list of interfaces */ ifnum = gnrc_netif_get(ifs); /* throw away packet if no one is interested */ if (ifnum == 0) { DEBUG("ipv6: no interfaces registered, dropping packet\n"); gnrc_pktbuf_release(pkt); return; } } #if GNRC_NETIF_NUMOF > 1 /* netif header not present: send over all interfaces */ if (iface == KERNEL_PID_UNDEF) { /* send packet to link layer */ gnrc_pktbuf_hold(pkt, ifnum - 1); for (size_t i = 0; i < ifnum; i++) { if (prep_hdr) { /* need to get second write access (duplication) to fill IPv6 * header interface-local */ ipv6 = gnrc_pktbuf_start_write(ipv6); if (ipv6 == NULL) { DEBUG("ipv6: unable to get write access to IPv6 header, " "for interface %" PRIkernel_pid "\n", ifs[i]); gnrc_pktbuf_release(pkt); return; } if (_fill_ipv6_hdr(ifs[i], ipv6, payload) < 0) { /* error on filling up header */ gnrc_pktbuf_release(pkt); return; } } /* allocate interface header */ netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0); if (netif == NULL) { DEBUG("ipv6: error on interface header allocation, " "dropping packet\n"); gnrc_pktbuf_release(pkt); return; } LL_PREPEND(pkt, netif); _send_multicast_over_iface(ifs[i], pkt, netif); } } else { /* iface != KERNEL_PID_UNDEF implies that netif header is present */ if (prep_hdr) { if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) { /* error on filling up header */ gnrc_pktbuf_release(pkt); return; } } netif = pkt; _send_multicast_over_iface(iface, pkt, netif); } #else /* GNRC_NETIF_NUMOF */ (void)ifnum; /* not used in this build branch */ if (iface == KERNEL_PID_UNDEF) { iface = ifs[0]; /* allocate interface header */ netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0); if (netif == NULL) { DEBUG("ipv6: error on interface header allocation, " "dropping packet\n"); gnrc_pktbuf_release(pkt); return; } LL_PREPEND(pkt, netif); } else { netif = pkt; } if (prep_hdr) { if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) { /* error on filling up header */ gnrc_pktbuf_release(pkt); return; } } _send_multicast_over_iface(iface, pkt, netif); #endif /* GNRC_NETIF_NUMOF */ }
/* * current pkt * | | * v v * IPv6 <- IPv6_EXT <- IPv6_EXT <- UNDEF */ void gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, uint8_t nh) { ipv6_ext_t *ext; while (true) { ext = (ipv6_ext_t *) current->data; switch (nh) { case PROTNUM_IPV6_EXT_RH: #ifdef MODULE_GNRC_RPL_SRH switch (_handle_rh(current, pkt)) { case GNRC_IPV6_EXT_OK: /* We are the final destination. So proceeds like normal packet. */ nh = ext->nh; DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh); if ((current = _mark_extension_header(current, &pkt)) == NULL) { return; } gnrc_ipv6_demux(iface, current, pkt, nh); /* demultiplex next header */ return; case GNRC_IPV6_EXT_ERROR: /* already released by _handle_rh, so no release here */ return; case GNRC_IPV6_EXT_FORWARDED: /* the packet is forwarded and released. finish processing */ return; } break; #endif case PROTNUM_IPV6_EXT_HOPOPT: case PROTNUM_IPV6_EXT_DST: case PROTNUM_IPV6_EXT_FRAG: case PROTNUM_IPV6_EXT_AH: case PROTNUM_IPV6_EXT_ESP: case PROTNUM_IPV6_EXT_MOB: /* TODO: add handling of types */ nh = ext->nh; DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh); if ((current = _mark_extension_header(current, &pkt)) == NULL) { return; } gnrc_pktbuf_hold(pkt, 1); /* don't release on next dispatch */ if (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, nh, pkt) == 0) { gnrc_pktbuf_release(pkt); } break; default: gnrc_ipv6_demux(iface, current, pkt, nh); /* demultiplex next header */ return; } } assert(false); /* never reaches here */ }
void gnrc_icmpv6_echo_req_handle(kernel_pid_t iface, ipv6_hdr_t *ipv6_hdr, icmpv6_echo_t *echo, uint16_t len) { uint8_t *payload = ((uint8_t *)echo) + sizeof(icmpv6_echo_t); gnrc_pktsnip_t *hdr, *pkt; gnrc_netreg_entry_t *sendto = NULL; if ((echo == NULL) || (len < sizeof(icmpv6_echo_t))) { DEBUG("icmpv6_echo: echo was NULL or len (%" PRIu16 ") was < sizeof(icmpv6_echo_t)\n", len); return; } pkt = gnrc_icmpv6_echo_build(ICMPV6_ECHO_REP, byteorder_ntohs(echo->id), byteorder_ntohs(echo->seq), payload, len - sizeof(icmpv6_echo_t)); if (pkt == NULL) { DEBUG("icmpv6_echo: no space left in packet buffer\n"); return; } if (ipv6_addr_is_multicast(&ipv6_hdr->dst)) { hdr = gnrc_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)&ipv6_hdr->src, sizeof(ipv6_addr_t)); } else { hdr = gnrc_ipv6_hdr_build(pkt, (uint8_t *)&ipv6_hdr->dst, sizeof(ipv6_addr_t), (uint8_t *)&ipv6_hdr->src, sizeof(ipv6_addr_t)); } if (hdr == NULL) { DEBUG("icmpv6_echo: no space left in packet buffer\n"); gnrc_pktbuf_release(pkt); return; } pkt = hdr; hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0); ((gnrc_netif_hdr_t *)hdr->data)->if_pid = iface; LL_PREPEND(pkt, hdr); sendto = gnrc_netreg_lookup(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL); if (sendto == NULL) { DEBUG("icmpv6_echo: no receivers for IPv6 packets\n"); gnrc_pktbuf_release(pkt); return; } /* ICMPv6 is not interested anymore so `- 1` */ gnrc_pktbuf_hold(pkt, gnrc_netreg_num(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { if (gnrc_netapi_send(sendto->pid, pkt) < 1) { DEBUG("icmpv6_echo: unable to send packet\n"); gnrc_pktbuf_release(pkt); } sendto = gnrc_netreg_getnext(sendto); } }
void gnrc_icmpv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt) { gnrc_pktsnip_t *icmpv6, *ipv6; icmpv6_hdr_t *hdr; gnrc_netreg_entry_t *sendto; LL_SEARCH_SCALAR(pkt, icmpv6, type, GNRC_NETTYPE_ICMPV6); assert(icmpv6 != NULL); /* there can be extension headers between IPv6 and ICMPv6 header so we have * to search it */ LL_SEARCH_SCALAR(icmpv6, ipv6, type, GNRC_NETTYPE_IPV6); assert(ipv6 != NULL); hdr = (icmpv6_hdr_t *)icmpv6->data; if (_calc_csum(icmpv6, ipv6, pkt)) { DEBUG("icmpv6: wrong checksum.\n"); /* don't release: IPv6 does this */ return; } switch (hdr->type) { /* TODO: handle ICMPv6 errors */ #ifdef MODULE_GNRC_ICMPV6_ECHO case ICMPV6_ECHO_REQ: DEBUG("icmpv6: handle echo request.\n"); gnrc_icmpv6_echo_req_handle(iface, (ipv6_hdr_t *)ipv6->data, (icmpv6_echo_t *)hdr, icmpv6->size); break; #endif case ICMPV6_RTR_SOL: DEBUG("icmpv6: router solicitation received\n"); /* TODO */ break; case ICMPV6_RTR_ADV: DEBUG("icmpv6: router advertisement received\n"); /* TODO */ break; case ICMPV6_NBR_SOL: DEBUG("icmpv6: neighbor solicitation received\n"); gnrc_ndp_nbr_sol_handle(iface, pkt, ipv6->data, (ndp_nbr_sol_t *)hdr, icmpv6->size); break; case ICMPV6_NBR_ADV: DEBUG("icmpv6: neighbor advertisement received\n"); gnrc_ndp_nbr_adv_handle(iface, pkt, ipv6->data, (ndp_nbr_adv_t *)hdr, icmpv6->size); break; case ICMPV6_REDIRECT: DEBUG("icmpv6: redirect message received\n"); /* TODO */ break; default: DEBUG("icmpv6: unknown type field %" PRIu8 "\n", hdr->type); break; } /* ICMPv6-all will be send in gnrc_ipv6.c so only dispatch of subtypes is * needed */ sendto = gnrc_netreg_lookup(GNRC_NETTYPE_ICMPV6, hdr->type); if (sendto == NULL) { DEBUG("icmpv6: no receivers for ICMPv6 type %" PRIu8 "\n", hdr->type); /* don't release: IPv6 does this */ return; } /* ICMPv6 is not interested anymore so `- 1` */ gnrc_pktbuf_hold(pkt, gnrc_netreg_num(GNRC_NETTYPE_ICMPV6, hdr->type)); while (sendto != NULL) { gnrc_netapi_receive(sendto->pid, pkt); sendto = gnrc_netreg_getnext(sendto); } }
static uint8_t _send_bcast(gnrc_netif_t *netif) { assert(netif != NULL); uint8_t tx_info = 0; gnrc_pktsnip_t *pkt = netif->mac.tx.packet; bool first = false; if (gnrc_lwmac_timeout_is_running(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END)) { if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END)) { gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST); gnrc_pktbuf_release(pkt); netif->mac.tx.packet = NULL; tx_info |= GNRC_LWMAC_TX_SUCCESS; return tx_info; } } else { LOG_INFO("[LWMAC-tx] Initialize broadcasting\n"); gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END, GNRC_LWMAC_BROADCAST_DURATION_US); gnrc_pktsnip_t *pkt_payload; /* Prepare packet with LWMAC header*/ gnrc_lwmac_frame_broadcast_t hdr; hdr.header.type = GNRC_LWMAC_FRAMETYPE_BROADCAST; hdr.seq_nr = netif->mac.tx.bcast_seqnr++; pkt_payload = pkt->next; pkt->next = gnrc_pktbuf_add(pkt->next, &hdr, sizeof(hdr), GNRC_NETTYPE_LWMAC); if (pkt->next == NULL) { LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type FRAMETYPE_BROADCAST\n"); netif->mac.tx.packet->next = pkt_payload; /* Drop the broadcast packet */ LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the broadcast packet\n"); gnrc_pktbuf_release(netif->mac.tx.packet); /* clear packet point to avoid TX retry */ netif->mac.tx.packet = NULL; tx_info |= GNRC_LWMAC_TX_FAIL; return tx_info; } /* No Auto-ACK for broadcast packets */ netopt_enable_t autoack = NETOPT_DISABLE; netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack, sizeof(autoack)); first = true; } if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST) || first) { /* if found ongoing transmission, quit this cycle for collision avoidance. * Broadcast packet will be re-queued and try to send in the next cycle. */ if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) { /* save pointer to netif header */ gnrc_pktsnip_t *netif_snip = pkt->next->next; /* remove LWMAC header */ pkt->next->next = NULL; gnrc_pktbuf_release(pkt->next); /* make append netif header after payload again */ pkt->next = netif_snip; if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) { gnrc_pktbuf_release(netif->mac.tx.packet); LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n"); } /* drop pointer so it wont be free'd */ netif->mac.tx.packet = NULL; tx_info |= GNRC_LWMAC_TX_FAIL; return tx_info; } /* Don't let the packet be released yet, we want to send it again */ gnrc_pktbuf_hold(pkt, 1); int res = _gnrc_lwmac_transmit(netif, pkt); if (res < 0) { LOG_ERROR("ERROR: [LWMAC-tx] Send broadcast pkt failed."); tx_info |= GNRC_LWMAC_TX_FAIL; return tx_info; } gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST, GNRC_LWMAC_TIME_BETWEEN_BROADCAST_US); LOG_INFO("[LWMAC-tx] Broadcast sent\n"); } return tx_info; }