int ipv6_send_packet(ipv6_hdr_t *packet) { uint16_t length = IPV6_HDR_LEN + NTOHS(packet->length); ndp_neighbor_cache_t *nce; ipv6_net_if_get_best_src_addr(&packet->srcaddr, &packet->destaddr); if (!ipv6_addr_is_multicast(&packet->destaddr) && ndp_addr_is_on_link(&packet->destaddr)) { nce = ndp_get_ll_address(&packet->destaddr); if (nce == NULL || sixlowpan_lowpan_sendto(nce->if_id, &nce->lladdr, nce->lladdr_len, (uint8_t *)packet, length) < 0) { /* XXX: this is wrong, but until ND does not work correctly, * this is the only way (aka the old way)*/ uint16_t raddr = NTOHS(packet->destaddr.uint16[7]); sixlowpan_lowpan_sendto(0, &raddr, 2, (uint8_t *)packet, length); /* return -1; */ } return length; } else { /* see if dest should be routed to a different next hop */ if (ipv6_addr_is_multicast(&packet->destaddr)) { /* if_id will be ignored */ uint16_t addr = 0xffff; return sixlowpan_lowpan_sendto(0, &addr, 2, (uint8_t *)packet, length); } if (ip_get_next_hop == NULL) { return -1; } ipv6_addr_t *dest = ip_get_next_hop(&packet->destaddr); if (dest == NULL) { return -1; } nce = ndp_get_ll_address(&packet->destaddr); if (nce == NULL || sixlowpan_lowpan_sendto(nce->if_id, &nce->lladdr, nce->lladdr_len, (uint8_t *)packet, length) < 0) { /* XXX: this is wrong, but until ND does not work correctly, * this is the only way (aka the old way)*/ uint16_t raddr = NTOHS(packet->destaddr.uint16[7]); sixlowpan_lowpan_sendto(0, &raddr, 2, (uint8_t *)packet, length); /* return -1; */ } return length; } }
void *ipv6_process(void *arg) { (void) arg; msg_t m_recv_lowpan, m_send_lowpan; msg_t m_recv, m_send; uint8_t i; uint16_t packet_length; msg_init_queue(ip_msg_queue, IP_PKT_RECV_BUF_SIZE); while (1) { msg_receive(&m_recv_lowpan); ipv6_buf = (ipv6_hdr_t *)m_recv_lowpan.content.ptr; /* identifiy packet */ nextheader = &ipv6_buf->nextheader; for (i = 0; i < SIXLOWIP_MAX_REGISTERED; i++) { if (sixlowip_reg[i]) { msg_t m_send; m_send.type = IPV6_PACKET_RECEIVED; m_send.content.ptr = (char *) ipv6_buf; msg_send(&m_send, sixlowip_reg[i], 1); } } /* destination is our address */ if (is_our_address(&ipv6_buf->destaddr)) { switch (*nextheader) { case (IPV6_PROTO_NUM_ICMPV6): { icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len); /* checksum test*/ if (ipv6_csum(ipv6_buf, (uint8_t *) icmp_buf, NTOHS(ipv6_buf->length), IPV6_PROTO_NUM_ICMPV6) != 0xffff) { DEBUG("ERROR: wrong checksum\n"); } icmpv6_demultiplex(icmp_buf); break; } case (IPV6_PROTO_NUM_TCP): { if (tcp_packet_handler_pid != KERNEL_PID_UNDEF) { m_send.content.ptr = (char *) ipv6_buf; msg_send_receive(&m_send, &m_recv, tcp_packet_handler_pid); } else { DEBUG("INFO: No TCP handler registered.\n"); } break; } case (IPV6_PROTO_NUM_UDP): { if (udp_packet_handler_pid != KERNEL_PID_UNDEF) { m_send.content.ptr = (char *) ipv6_buf; msg_send_receive(&m_send, &m_recv, udp_packet_handler_pid); } else { DEBUG("INFO: No UDP handler registered.\n"); } break; } case (IPV6_PROTO_NUM_NONE): { DEBUG("INFO: Packet with no Header following the IPv6 Header received.\n"); break; } default: DEBUG("INFO: Unknown next header\n"); break; } } /* destination is foreign address */ else { DEBUG("That's not for me, destination is %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_buf->destaddr)); packet_length = IPV6_HDR_LEN + NTOHS(ipv6_buf->length); ndp_neighbor_cache_t *nce; ipv6_addr_t *dest; if (ip_get_next_hop == NULL) { dest = &ipv6_buf->destaddr; } else { dest = ip_get_next_hop(&ipv6_buf->destaddr); } if ((dest == NULL) || ((--ipv6_buf->hoplimit) == 0)) { DEBUG("!!! Packet not for me, routing handler is set, but I "\ " have no idea where to send or the hop limit is exceeded.\n"); msg_reply(&m_recv_lowpan, &m_send_lowpan); continue; } nce = ndp_get_ll_address(dest); /* copy received packet to send buffer */ memcpy(ipv6_get_buf_send(), ipv6_get_buf(), packet_length); /* send packet to node ID derived from dest IP */ if (nce != NULL) { sixlowpan_lowpan_sendto(nce->if_id, &nce->lladdr, nce->lladdr_len, (uint8_t *)ipv6_get_buf_send(), packet_length); } else { /* XXX: this is wrong, but until ND does work correctly, * this is the only way (aka the old way)*/ uint16_t raddr = dest->uint16[7]; sixlowpan_lowpan_sendto(0, &raddr, 2, (uint8_t *)ipv6_get_buf_send(), packet_length); } } msg_reply(&m_recv_lowpan, &m_send_lowpan); } }