coap_async_state_t * coap_find_async(coap_context_t *context, coap_tid_t id) { coap_async_state_t *tmp; LL_SEARCH_SCALAR(context->async_state, tmp, id, id); return tmp; }
static void _send(ng_pktsnip_t *pkt) { ng_udp_hdr_t *hdr; ng_pktsnip_t *udp_snip; ng_netreg_entry_t *sendto; /* get udp snip and hdr */ LL_SEARCH_SCALAR(pkt, udp_snip, type, NG_NETTYPE_UDP); udp_snip = ng_pktbuf_start_write(udp_snip); if (udp_snip == NULL) { DEBUG("udp: cannot send packet: unable to allocate packet\n"); ng_pktbuf_release(pkt); return; } hdr = (ng_udp_hdr_t *)udp_snip->data; /* fill in size field */ hdr->length = byteorder_htons(ng_pkt_len(udp_snip)); /* and forward packet to the network layer */ sendto = ng_netreg_lookup(pkt->type, NG_NETREG_DEMUX_CTX_ALL); /* throw away packet if no one is interested */ if (sendto == NULL) { DEBUG("udp: cannot send packet: network layer not found\n"); ng_pktbuf_release(pkt); return; } /* send packet to network layer */ ng_pktbuf_hold(pkt, ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { ng_netapi_send(sendto->pid, pkt); sendto = ng_netreg_getnext(sendto); } }
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; }
gnrc_netreg_entry_t *gnrc_netreg_lookup(gnrc_nettype_t type, uint32_t demux_ctx) { gnrc_netreg_entry_t *res; if (_INVALID_TYPE(type)) { return NULL; } LL_SEARCH_SCALAR(netreg[type], res, demux_ctx, demux_ctx); return res; }
int main() { int i; el els[10], *e, *tmp, *tmp2; for(i=0;i<10;i++) els[i].id='a'+i; /* test LL macros */ printf("LL macros\n"); LL_APPEND(head,&els[0]); LL_APPEND(head,&els[1]); LL_APPEND(head,&els[2]); LL_FOREACH(head,e) printf("%c ", e->id); printf("\n"); LL_SEARCH_SCALAR(head, e, id, 'b'); if (e) printf("search scalar found b\n"); LL_SEARCH(head, e, &els[0], eltcmp); if (e) printf("search found %c\n",e->id); LL_FOREACH_SAFE(head,e,tmp) LL_DELETE(head,e); printf("\n"); /* test DL macros */ printf("DL macros\n"); DL_APPEND(head,&els[0]); DL_APPEND(head,&els[1]); DL_APPEND(head,&els[2]); DL_FOREACH(head,e) printf("%c ", e->id); printf("\n"); DL_SEARCH_SCALAR(head, e, id, 'b'); if (e) printf("search scalar found b\n"); DL_SEARCH(head, e, &els[0], eltcmp); if (e) printf("search found %c\n",e->id); DL_FOREACH_SAFE(head,e,tmp) DL_DELETE(head,e); printf("\n"); /* test CDL macros */ printf("CDL macros\n"); CDL_PREPEND(head,&els[0]); CDL_PREPEND(head,&els[1]); CDL_PREPEND(head,&els[2]); CDL_FOREACH(head,e) printf("%c ", e->id); printf("\n"); CDL_SEARCH_SCALAR(head, e, id, 'b'); if (e) printf("search scalar found b\n"); CDL_SEARCH(head, e, &els[0], eltcmp); if (e) printf("search found %c\n",e->id); CDL_FOREACH_SAFE(head,e,tmp,tmp2) CDL_DELETE(head,e); return 0; }
coap_async_state_t * coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data) { coap_async_state_t *s; coap_tid_t id; coap_transaction_id(peer, request, &id); LL_SEARCH_SCALAR(context->async_state, s, id, id); if (s != NULL) { /* We must return NULL here as the caller must know that he is * responsible for releasing @p data. */ debug("asynchronous state for transaction %d already registered\n", id); return NULL; } /* store information for handling the asynchronous task */ s = (coap_async_state_t *) coap_malloc(sizeof(coap_async_state_t) + request->hdr->token_length); if (!s) { coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n"); return NULL; } memset(s, 0, sizeof(coap_async_state_t) + request->hdr->token_length); /* set COAP_ASYNC_CONFIRM according to request's type */ s->flags = flags & ~COAP_ASYNC_CONFIRM; if (request->hdr->type == COAP_MESSAGE_CON) s->flags |= COAP_ASYNC_CONFIRM; s->appdata = data; memcpy(&s->peer, peer, sizeof(coap_address_t)); if (request->hdr->token_length) { s->tokenlen = request->hdr->token_length; memcpy(s->token, request->hdr->token, request->hdr->token_length); } memcpy(&s->id, &id, sizeof(coap_tid_t)); coap_touch_async(s); LL_PREPEND(context->async_state, s); return s; }
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); } }
gnrc_netreg_entry_t *gnrc_netreg_getnext(gnrc_netreg_entry_t *entry) { uint32_t demux_ctx; if (entry == NULL) { return NULL; } demux_ctx = entry->demux_ctx; LL_SEARCH_SCALAR(entry->next, entry, demux_ctx, demux_ctx); return entry; }
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); }
gnrc_pktsnip_t *gnrc_ipv6_ext_build(gnrc_pktsnip_t *ipv6, gnrc_pktsnip_t *next, uint8_t nh, size_t size) { gnrc_pktsnip_t *prev = NULL, *snip; ipv6_ext_t *ext; if (size < IPV6_EXT_LEN_UNIT) { return NULL; } if (ipv6 != NULL) { LL_SEARCH_SCALAR(ipv6, prev, next, next); if (prev == NULL) { return NULL; } } snip = gnrc_pktbuf_add(next, NULL, size, GNRC_NETTYPE_IPV6); if (snip == NULL) { return NULL; } ext = snip->data; ext->nh = nh; if (size & 0x7) { /* not divisible by eight */ ext->len = (size / IPV6_EXT_LEN_UNIT); } else { ext->len = (size / IPV6_EXT_LEN_UNIT) - 1; } if (prev != NULL) { prev->next = snip; } return snip; }
coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data) { coap_async_state_t *s; coap_tid_t id; coap_transport_t transport = COAP_UDP; unsigned char *token; unsigned int token_len = 0; switch(context->protocol) { case COAP_PROTO_UDP: case COAP_PROTO_DTLS: transport = COAP_UDP; break; case COAP_PROTO_TCP: case COAP_PROTO_TLS: transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)request->transport_hdr)[0] >> 4); break; default: break; } coap_transaction_id2(peer, request, &id, context->protocol); LL_SEARCH_SCALAR(context->async_state, s, id, id); coap_get_token2(request->transport_hdr, transport, &token, &token_len); if (token_len > 8) { debug("coap_register_async : invalied length of token\n"); return NULL; } if (s != NULL) { /* We must return NULL here as the caller must know that he is * responsible for releasing @p data. */ debug("coap_register_async : asynchronous state for transaction %d already registered\n", id); return NULL; } /* store information for handling the asynchronous task */ s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + token_len); if (!s) { coap_log(LOG_CRIT, "coap_register_async : insufficient memory\n"); return NULL; } memset(s, 0, sizeof(coap_async_state_t) + token_len); /* set COAP_ASYNC_CONFIRM according to request's type */ s->flags = flags & ~COAP_ASYNC_CONFIRM; if (context->protocol == COAP_PROTO_UDP || context->protocol == COAP_PROTO_TCP) { if (request->transport_hdr->udp.type == COAP_MESSAGE_CON) { s->flags |= COAP_ASYNC_CONFIRM; } } s->appdata = data; memcpy(&s->peer, peer, sizeof(coap_address_t)); if (token_len) { s->tokenlen = token_len; memcpy(s->token, token, token_len); } memcpy(&s->id, &id, sizeof(coap_tid_t)); coap_touch_async(s); LL_PREPEND(context->async_state, s); return s; }
/** * @brief FSM handling function for processing of an incomming TCP packet. * * @param[in,out] tcb TCB holding the connection information. * @param[in] in_pkt Incomming packet. * * @returns Zero on success. * -ENOMEM if receive buffer could not be allocated. */ static int _fsm_rcvd_pkt(gnrc_tcp_tcb_t *tcb, gnrc_pktsnip_t *in_pkt) { gnrc_pktsnip_t *out_pkt = NULL; /* Outgoing packet */ uint16_t seq_con = 0; /* Sequence number consumption of outgoing packet */ gnrc_pktsnip_t *snp = NULL; /* Temporary packet snip */ gnrc_tcp_tcb_t *lst = NULL; /* Temporary pointer to TCB */ uint16_t ctl = 0; /* Control bits of the incomming packet */ uint32_t seg_seq = 0; /* Sequence number of the incomming packet*/ uint32_t seg_ack = 0; /* Acknowledgment number of the incomming packet */ uint32_t seg_wnd = 0; /* Receive window of the incomming packet */ uint32_t seg_len = 0; /* Segment length of the incomming packet */ uint32_t pay_len = 0; /* Payload length of the incomming packet */ DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt()\n"); /* Search for TCP header. */ LL_SEARCH_SCALAR(in_pkt, snp, type, GNRC_NETTYPE_TCP); tcp_hdr_t *tcp_hdr = (tcp_hdr_t *) snp->data; /* Parse packet options, return if they are malformed */ if (_option_parse(tcb, tcp_hdr) < 0) { return 0; } /* Extract header values */ ctl = byteorder_ntohs(tcp_hdr->off_ctl); seg_seq = byteorder_ntohl(tcp_hdr->seq_num); seg_ack = byteorder_ntohl(tcp_hdr->ack_num); seg_wnd = byteorder_ntohs(tcp_hdr->window); /* Extract network layer header */ #ifdef MODULE_GNRC_IPV6 LL_SEARCH_SCALAR(in_pkt, snp, type, GNRC_NETTYPE_IPV6); if (snp == NULL) { DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() : incomming packet had no IPv6 header\n"); return 0; } void *ip = snp->data; #endif /* Handle state LISTEN */ if (tcb->state == FSM_STATE_LISTEN) { /* 1) Check RST: if RST is set: return */ if (ctl & MSK_RST) { return 0; } /* 2) Check ACK: if ACK is set: send RST with seq_no = ack_no and return */ if (ctl & MSK_ACK) { _pkt_build_reset_from_pkt(&out_pkt, in_pkt); _pkt_send(tcb, out_pkt, 0, false); return 0; } /* 3) Check SYN: if SYN is set prepare for incomming connection */ if (ctl & MSK_SYN) { uint16_t src = byteorder_ntohs(tcp_hdr->src_port); uint16_t dst = byteorder_ntohs(tcp_hdr->dst_port); /* Check if SYN request is handled by another connection */ lst = _list_tcb_head; while (lst) { /* Compare port numbers and network layer adresses */ if (lst->local_port == dst && lst->peer_port == src) { #ifdef MODULE_GNRC_IPV6 if (snp->type == GNRC_NETTYPE_IPV6 && lst->address_family == AF_INET6) { ipv6_addr_t *dst_addr = &((ipv6_hdr_t *)ip)->dst; ipv6_addr_t *src_addr = &((ipv6_hdr_t *)ip)->src; if (ipv6_addr_equal((ipv6_addr_t *)lst->local_addr, dst_addr) && ipv6_addr_equal((ipv6_addr_t *)lst->peer_addr, src_addr)) { break; } } #endif } lst = lst->next; } /* Return if connection is already handled (port and addresses match) */ if (lst != NULL) { DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() : Connection already handled\n"); return 0; } /* SYN request is valid, fill TCB with connection information */ #ifdef MODULE_GNRC_IPV6 if (snp->type == GNRC_NETTYPE_IPV6 && tcb->address_family == AF_INET6) { memcpy(tcb->local_addr, &((ipv6_hdr_t *)ip)->dst, sizeof(ipv6_addr_t)); memcpy(tcb->peer_addr, &((ipv6_hdr_t *)ip)->src, sizeof(ipv6_addr_t)); /* In case peer_addr is link local: Store interface Id in tcb */ if (ipv6_addr_is_link_local((ipv6_addr_t *) tcb->peer_addr)) { gnrc_pktsnip_t *tmp = NULL; LL_SEARCH_SCALAR(in_pkt, tmp, type, GNRC_NETTYPE_NETIF); /* cppcheck-suppress knownConditionTrueFalse * (reason: tmp *can* be != NULL after LL_SEARCH_SCALAR) */ if (tmp == NULL) { DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() :\ incomming packet had no netif header\n"); return 0; } tcb->ll_iface = ((gnrc_netif_hdr_t *)tmp->data)->if_pid; }
void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt) { ng_pktsnip_t *icmpv6, *ipv6; ng_icmpv6_hdr_t *hdr; ng_netreg_entry_t *sendto; LL_SEARCH_SCALAR(pkt, icmpv6, type, NG_NETTYPE_ICMPV6); /* there can be extension headers between IPv6 and ICMPv6 header so we have * to search it */ LL_SEARCH_SCALAR(icmpv6, ipv6, type, NG_NETTYPE_IPV6); hdr = (ng_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_NG_ICMPV6_ECHO case NG_ICMPV6_ECHO_REQ: DEBUG("icmpv6: handle echo request.\n"); ng_icmpv6_echo_req_handle(iface, (ng_ipv6_hdr_t *)ipv6->data, (ng_icmpv6_echo_t *)hdr, icmpv6->size); break; #endif case NG_ICMPV6_RTR_SOL: DEBUG("icmpv6: router solicitation received\n"); /* TODO */ break; case NG_ICMPV6_RTR_ADV: DEBUG("icmpv6: router advertisement received\n"); /* TODO */ break; case NG_ICMPV6_NBR_SOL: DEBUG("icmpv6: neighbor solicitation received\n"); ng_ndp_nbr_sol_handle(iface, pkt, ipv6->data, (ng_ndp_nbr_sol_t *)hdr, icmpv6->size); break; case NG_ICMPV6_NBR_ADV: DEBUG("icmpv6: neighbor advertisement received\n"); ng_ndp_nbr_adv_handle(iface, pkt, ipv6->data, (ng_ndp_nbr_adv_t *)hdr, icmpv6->size); break; case NG_ICMPV6_REDIRECT: DEBUG("icmpv6: redirect message received\n"); /* TODO */ break; #ifdef MODULE_NG_RPL case NG_ICMPV6_RPL_CTRL: DEBUG("icmpv6: RPL control message received\n"); /* TODO */ break; #endif default: DEBUG("icmpv6: unknown type field %" PRIu8 "\n", hdr->type); break; } /* ICMPv6-all will be send in ng_ipv6.c so only dispatch of subtypes is * needed */ sendto = ng_netreg_lookup(NG_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` */ ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_ICMPV6, hdr->type)); while (sendto != NULL) { ng_netapi_receive(sendto->pid, pkt); sendto = ng_netreg_getnext(sendto); } }
void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_adv_t *nbr_adv, size_t icmpv6_size) { uint16_t opt_offset = 0; uint8_t *buf = ((uint8_t *)nbr_adv) + sizeof(ng_ndp_nbr_adv_t); int l2tgt_len = 0; uint8_t l2tgt[NG_IPV6_NC_L2_ADDR_MAX]; int sicmpv6_size = (int)icmpv6_size; ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, &nbr_adv->tgt); ng_pktsnip_t *netif; ng_netif_hdr_t *netif_hdr = NULL; DEBUG("ndp: received neighbor advertisement (src: %s, ", ng_ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str))); DEBUG("dst: %s, ", ng_ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str))); DEBUG("tgt: %s)\n", ng_ipv6_addr_to_str(addr_str, &nbr_adv->tgt, sizeof(addr_str))); /* check validity */ if ((ipv6->hl != 255) || (nbr_adv->code != 0) || (icmpv6_size < sizeof(ng_ndp_nbr_adv_t)) || ng_ipv6_addr_is_multicast(&nbr_adv->tgt)) { DEBUG("ndp: neighbor advertisement was invalid.\n"); /* ipv6 releases */ return; } if (nc_entry == NULL) { /* see https://tools.ietf.org/html/rfc4861#section-7.2.5 */ DEBUG("ndp: no neighbor cache entry found for advertisement's target\n"); /* ipv6 releases */ return; } sicmpv6_size -= sizeof(ng_ndp_nbr_adv_t); while (sicmpv6_size > 0) { ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NG_NDP_OPT_TL2A: if ((l2tgt_len = _handle_tl2a_opt(pkt, ipv6, nbr_adv->type, opt, l2tgt)) < 0) { /* invalid target link-layer address option */ return; } break; default: /* silently discard all other options */ break; } opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); } LL_SEARCH_SCALAR(pkt, netif, type, NG_NETTYPE_NETIF); if (netif != NULL) { netif_hdr = netif->data; } if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) { ng_pktqueue_t *queued_pkt; if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) { /* link-layer has addresses, but no TLLAO supplied: discard silently * (see https://tools.ietf.org/html/rfc4861#section-7.2.5) */ return; } nc_entry->iface = iface; nc_entry->l2_addr_len = l2tgt_len; memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len); if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) { _set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE); } else { _set_state(nc_entry, NG_IPV6_NC_STATE_STALE); } if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_R) { nc_entry->flags |= NG_IPV6_NC_IS_ROUTER; } else { nc_entry->flags &= ~NG_IPV6_NC_IS_ROUTER; /* TODO: update FIB */ } while ((queued_pkt = ng_pktqueue_remove_head(&nc_entry->pkts)) != NULL) { ng_netapi_send(ng_ipv6_pid, queued_pkt->pkt); queued_pkt->pkt = NULL; } } else { /* first or-term: no link-layer, but nc_entry has l2addr, * second or-term: different l2addr cached */ bool l2tgt_changed = false; if ((!_pkt_has_l2addr(netif_hdr)) && (l2tgt_len == 0)) { /* there was previously a L2 address registered */ l2tgt_changed = (nc_entry->l2_addr_len != 0); } /* link-layer has addresses and TLLAO with different address */ else if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len != 0)) { l2tgt_changed = (!(l2tgt_len == nc_entry->l2_addr_len)) && (memcmp(nc_entry->l2_addr, l2tgt, l2tgt_len) == 0); } if ((nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_O) || !l2tgt_changed || (l2tgt_len == 0)) { if (l2tgt_len != 0) { nc_entry->iface = iface; nc_entry->l2_addr_len = l2tgt_len; memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len); } if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) { _set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE); } else if (l2tgt_changed && (l2tgt_len != 0)) { _set_state(nc_entry, NG_IPV6_NC_STATE_STALE); } if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_R) { nc_entry->flags |= NG_IPV6_NC_IS_ROUTER; } else { nc_entry->flags &= ~NG_IPV6_NC_IS_ROUTER; /* TODO: update FIB */ } } else if (l2tgt_changed) { if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_REACHABLE) { _set_state(nc_entry, NG_IPV6_NC_STATE_STALE); } } } return; }
void gnrc_ndp_nbr_adv_handle(kernel_pid_t iface, gnrc_pktsnip_t *pkt, ipv6_hdr_t *ipv6, ndp_nbr_adv_t *nbr_adv, size_t icmpv6_size) { uint16_t opt_offset = 0; uint8_t *buf = ((uint8_t *)nbr_adv) + sizeof(ndp_nbr_adv_t); int l2tgt_len = 0; uint8_t l2tgt[GNRC_IPV6_NC_L2_ADDR_MAX]; int sicmpv6_size = (int)icmpv6_size; gnrc_ipv6_nc_t *nc_entry = gnrc_ipv6_nc_get(iface, &nbr_adv->tgt); gnrc_pktsnip_t *netif; gnrc_netif_hdr_t *netif_hdr = NULL; DEBUG("ndp: received neighbor advertisement (src: %s, ", ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str))); DEBUG("dst: %s, ", ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str))); DEBUG("tgt: %s)\n", ipv6_addr_to_str(addr_str, &nbr_adv->tgt, sizeof(addr_str))); /* check validity */ if ((ipv6->hl != 255) || (nbr_adv->code != 0) || (icmpv6_size < sizeof(ndp_nbr_adv_t)) || ipv6_addr_is_multicast(&nbr_adv->tgt)) { DEBUG("ndp: neighbor advertisement was invalid.\n"); /* ipv6 releases */ return; } if (nc_entry == NULL) { /* see https://tools.ietf.org/html/rfc4861#section-7.2.5 */ DEBUG("ndp: no neighbor cache entry found for advertisement's target\n"); /* ipv6 releases */ return; } sicmpv6_size -= sizeof(ndp_nbr_adv_t); while (sicmpv6_size > 0) { ndp_opt_t *opt = (ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NDP_OPT_TL2A: if ((l2tgt_len = gnrc_ndp_internal_tl2a_opt_handle(pkt, ipv6, nbr_adv->type, opt, l2tgt)) < 0) { /* invalid target link-layer address option */ return; } break; #ifdef MODULE_GNRC_SIXLOWPAN_ND case NDP_OPT_AR: /* address registration option is always ignored when invalid */ gnrc_sixlowpan_nd_opt_ar_handle(iface, ipv6, nbr_adv->type, &nbr_adv->tgt, (sixlowpan_nd_opt_ar_t *)opt, NULL, 0); break; #endif default: /* silently discard all other options */ break; } 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 } LL_SEARCH_SCALAR(pkt, netif, type, GNRC_NETTYPE_NETIF); if (netif != NULL) { netif_hdr = netif->data; } if (l2tgt_len != -ENOTSUP) { #ifdef MODULE_GNRC_SIXLOWPAN_ND /* check if entry wasn't removed by ARO, ideally there should not be any TL2A in here */ nc_entry = gnrc_ipv6_nc_get(iface, &nbr_adv->tgt); if (nc_entry == NULL) { return; } #endif if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_INCOMPLETE) { if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) { /* link-layer has addresses, but no TLLAO supplied: discard silently * (see https://tools.ietf.org/html/rfc4861#section-7.2.5) */ return; } nc_entry->iface = iface; nc_entry->l2_addr_len = l2tgt_len; memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len); if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE); } else { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE); } if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_R) { nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER; } else { nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER; /* TODO: update state of neighbor as router in FIB? */ } #ifdef MODULE_GNRC_NDP_NODE gnrc_pktqueue_t *queued_pkt; while ((queued_pkt = gnrc_pktqueue_remove_head(&nc_entry->pkts)) != NULL) { if (gnrc_netapi_send(gnrc_ipv6_pid, queued_pkt->pkt) < 1) { DEBUG("ndp: unable to send queued packet\n"); gnrc_pktbuf_release(queued_pkt->pkt); } queued_pkt->pkt = NULL; } #endif } else { /* first or-term: no link-layer, but nc_entry has l2addr, * second or-term: different l2addr cached */ bool l2tgt_changed = false; if ((!_pkt_has_l2addr(netif_hdr)) && (l2tgt_len == 0)) { /* there was previously a L2 address registered */ l2tgt_changed = (nc_entry->l2_addr_len != 0); } /* link-layer has addresses and TLLAO with different address */ else if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len != 0)) { l2tgt_changed = (!(l2tgt_len == nc_entry->l2_addr_len)) && (memcmp(nc_entry->l2_addr, l2tgt, l2tgt_len) == 0); } if ((nbr_adv->flags & NDP_NBR_ADV_FLAGS_O) || !l2tgt_changed || (l2tgt_len == 0)) { if (l2tgt_len != 0) { nc_entry->iface = iface; nc_entry->l2_addr_len = l2tgt_len; memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len); } if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_S) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_REACHABLE); } else if (l2tgt_changed) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE); } if (nbr_adv->flags & NDP_NBR_ADV_FLAGS_R) { nc_entry->flags |= GNRC_IPV6_NC_IS_ROUTER; } else { nc_entry->flags &= ~GNRC_IPV6_NC_IS_ROUTER; /* TODO: update state of neighbor as router in FIB? */ } } else if (l2tgt_changed && gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_REACHABLE) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_STALE); } } } return; }
kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, kernel_pid_t iface, ipv6_addr_t *dst) { ipv6_addr_t *next_hop = NULL; gnrc_ipv6_nc_t *nc_entry = NULL; #ifdef MODULE_GNRC_IPV6_EXT_RH ipv6_hdr_t *hdr; gnrc_pktsnip_t *ipv6; LL_SEARCH_SCALAR(pkt, ipv6, type, GNRC_NETTYPE_IPV6); assert(ipv6); hdr = ipv6->data; next_hop = ipv6_ext_rh_next_hop(hdr); #endif #ifdef MODULE_FIB ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */ /* don't look-up link local addresses in FIB */ if ((next_hop == NULL) && !ipv6_addr_is_link_local(dst)) { size_t next_hop_size = sizeof(ipv6_addr_t); uint32_t next_hop_flags = 0; if ((next_hop == NULL) && (fib_get_next_hop(&gnrc_ipv6_fib_table, &iface, next_hop_actual.u8, &next_hop_size, &next_hop_flags, (uint8_t *)dst, sizeof(ipv6_addr_t), 0) >= 0) && (next_hop_size == sizeof(ipv6_addr_t))) { next_hop = &next_hop_actual; } } #endif #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER /* next hop determination: https://tools.ietf.org/html/rfc6775#section-6.5.4 */ nc_entry = gnrc_ipv6_nc_get(iface, dst); /* if NCE found */ if (nc_entry != NULL) { gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(nc_entry->iface); /* and interface is not 6LoWPAN */ if (!(ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) || /* or entry is registered */ (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_REGISTERED)) { next_hop = dst; } } #endif /* next hop determination according to: https://tools.ietf.org/html/rfc6775#section-5.6 */ if ((next_hop == NULL) && ipv6_addr_is_link_local(dst)) { /* prefix is "on-link" */ /* multicast is not handled here anyway so we don't need to check that */ next_hop = dst; } else if (next_hop == NULL) { /* prefix is off-link */ next_hop = gnrc_ndp_internal_default_router(); } /* address resolution of next_hop: https://tools.ietf.org/html/rfc6775#section-5.7 */ if ((nc_entry == NULL) || (next_hop != dst)) { /* get if not gotten from previous check */ nc_entry = gnrc_ipv6_nc_get(iface, next_hop); } /* If a NCE for this destination exist, we can use even for link-local * addresses. This should be only the case for 6LBRs. */ if ((ipv6_addr_is_link_local(next_hop)) && (nc_entry == NULL)) { /* in case of a border router there is no sensible way for address resolution * if the interface is not given */ #ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER /* if no interface is specified it is impossible to resolve the * link-layer address for a link-local address on a 6LBR */ if (iface == KERNEL_PID_UNDEF) { return KERNEL_PID_UNDEF; } #endif kernel_pid_t ifs[GNRC_NETIF_NUMOF]; size_t ifnum = gnrc_netif_get(ifs); /* we don't need address resolution, the EUI-64 is in next_hop's IID */ *l2addr_len = sizeof(eui64_t); memcpy(l2addr, &next_hop->u8[8], sizeof(eui64_t)); _revert_iid(l2addr); if (iface == KERNEL_PID_UNDEF) { for (unsigned i = 0; i < ifnum; i++) { gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(ifs[i]); if ((ipv6_if != NULL) && (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { /* always take the first 6LoWPAN interface we can find */ return ifs[i]; } } } return iface; } if ((nc_entry == NULL) || (!gnrc_ipv6_nc_is_reachable(nc_entry)) || (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) { return KERNEL_PID_UNDEF; } else { if (nc_entry->l2_addr_len > 0) { memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len); } *l2addr_len = nc_entry->l2_addr_len; } return nc_entry->iface; }
/** * @brief Checks if a given port number is currently used by a TCB as local_port. * * @note Must be called from a context where the TCB list is locked. * * @param[in] port_number Port number that should be checked. * * @returns Zero if @p port_number is currently not used. * 1 if @p port_number is used by an active connection. */ static int _is_local_port_in_use(const uint16_t port_number) { gnrc_tcp_tcb_t *iter = NULL; LL_SEARCH_SCALAR(_list_tcb_head, iter, local_port, port_number); return (iter != NULL); }
void _receive(ng_pktsnip_t *pkt) { ng_pktsnip_t *payload; uint8_t *dispatch; ng_netreg_entry_t *entry; LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_SIXLOWPAN); if ((payload == NULL) || (payload->size < 1)) { DEBUG("6lo: Received packet has no 6LoWPAN payload\n"); ng_pktbuf_release(pkt); } dispatch = payload->data; if (dispatch[0] == NG_SIXLOWPAN_UNCOMPRESSED) { ng_pktsnip_t *sixlowpan; DEBUG("6lo: received uncompressed IPv6 packet\n"); payload = ng_pktbuf_start_write(payload); if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && defined(ENABLE_DEBUG) ng_pktbuf_stats(); #endif ng_pktbuf_release(pkt); return; } /* packet is uncompressed: just mark and remove the dispatch */ sixlowpan = ng_pktbuf_add(payload, payload->data, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN); LL_DELETE(pkt, sixlowpan); ng_pktbuf_release(sixlowpan); } #ifdef MODULE_NG_SIXLOWPAN_FRAG else if (ng_sixlowpan_frag_is((ng_sixlowpan_frag_t *)dispatch)) { DEBUG("6lo: received 6LoWPAN fragment\n"); ng_sixlowpan_frag_handle_pkt(pkt); } #endif else { DEBUG("6lo: dispatch %02x ... is not supported\n", dispatch[0]); ng_pktbuf_release(pkt); return; } payload->type = NG_NETTYPE_IPV6; entry = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL); if (entry == NULL) { DEBUG("ipv6: No receivers for this packet found\n"); ng_pktbuf_release(pkt); return; } ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL) - 1); while (entry) { DEBUG("6lo: Send receive command for %p to %" PRIu16 "\n", (void *)pkt, entry->pid); ng_netapi_receive(entry->pid, pkt); entry = ng_netreg_getnext(entry); } }
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); }
static void _receive(ng_pktsnip_t *pkt) { ng_pktsnip_t *payload; uint8_t *dispatch; /* seize payload as a temporary variable */ payload = ng_pktbuf_start_write(pkt); /* need to duplicate since pkt->next * might get replaced */ if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && defined(ENABLE_DEBUG) ng_pktbuf_stats(); #endif ng_pktbuf_release(pkt); return; } pkt = payload; /* reset pkt from temporary variable */ LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_SIXLOWPAN); if ((payload == NULL) || (payload->size < 1)) { DEBUG("6lo: Received packet has no 6LoWPAN payload\n"); ng_pktbuf_release(pkt); return; } dispatch = payload->data; if (dispatch[0] == NG_SIXLOWPAN_UNCOMPRESSED) { ng_pktsnip_t *sixlowpan; DEBUG("6lo: received uncompressed IPv6 packet\n"); payload = ng_pktbuf_start_write(payload); if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && defined(ENABLE_DEBUG) ng_pktbuf_stats(); #endif ng_pktbuf_release(pkt); return; } /* packet is uncompressed: just mark and remove the dispatch */ sixlowpan = ng_pktbuf_add(payload, payload->data, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN); if (sixlowpan == NULL) { DEBUG("6lo: can not mark 6LoWPAN dispatch\n"); ng_pktbuf_release(pkt); return; } pkt = ng_pktbuf_remove_snip(pkt, sixlowpan); } #ifdef MODULE_NG_SIXLOWPAN_FRAG else if (ng_sixlowpan_frag_is((ng_sixlowpan_frag_t *)dispatch)) { DEBUG("6lo: received 6LoWPAN fragment\n"); ng_sixlowpan_frag_handle_pkt(pkt); return; } #endif else { DEBUG("6lo: dispatch %02x ... is not supported\n", dispatch[0]); ng_pktbuf_release(pkt); return; } #ifdef MODULE_NG_SIXLOWPAN_IPHC if (ng_sixlowpan_iphc_is(payload->data)) { if (!ng_sixlowpan_iphc_decode(pkt)) { DEBUG("6lo: error on IPHC decoding\n"); ng_pktbuf_release(pkt); return; } LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_IPV6); } #endif payload->type = NG_NETTYPE_IPV6; if (!ng_netapi_dispatch_receive(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("ipv6: No receivers for this packet found\n"); ng_pktbuf_release(pkt); } }
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); }