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); }
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; }
/* 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); } }
int _tftp_init_ctxt(ipv6_addr_t *addr, const char *file_name, tftp_opcodes_t op, tftp_mode_t mode, tftp_context_type type, tftp_start_cb_t start, tftp_stop_cb_t stop, tftp_data_cb_t data, bool enable_options, tftp_context_t *ctxt) { if (!addr) { return TS_FAILED; } memset(ctxt, 0, sizeof(*ctxt)); /* set the default context parameters */ ctxt->op = op; ctxt->ct = type; ctxt->data_cb = data; ctxt->start_cb = start; ctxt->stop_cb = stop; memcpy(&(ctxt->peer), addr, sizeof(ctxt->peer)); ctxt->mode = mode; if (file_name) { strncpy(ctxt->file_name, file_name, GNRC_TFTP_MAX_FILENAME_LEN); } ctxt->file_name[GNRC_TFTP_MAX_FILENAME_LEN - 1] = 0; ctxt->dst_port = GNRC_TFTP_DEFAULT_DST_PORT; ctxt->enable_options = enable_options; /* transport layer parameters */ ctxt->block_size = GNRC_TFTP_MAX_TRANSFER_UNIT; ctxt->block_timeout = GNRC_TFTP_DEFAULT_TIMEOUT; ctxt->write_finished = false; /* generate a random source UDP source port */ do { ctxt->src_port = (random_uint32() & 0xff) + GNRC_TFTP_DEFAULT_SRC_PORT; } while (gnrc_netreg_num(GNRC_NETTYPE_UDP, ctxt->src_port)); return TS_FINISHED; }
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); } }