Commit 02c55311 authored by Milan Platisa's avatar Milan Platisa

#232 Fragmented echo reply: needed for v6LC.4.1.3: Non-zero ICMPv6 Code

parent a56b7104
......@@ -69,33 +69,117 @@ static int pico_icmp6_send_echoreply(struct pico_frame *echo)
struct pico_icmp6_hdr *ehdr = NULL, *rhdr = NULL;
struct pico_ip6 src;
struct pico_ip6 dst;
static uint32_t frag_id = 0;
reply = pico_proto_ipv6.alloc(&pico_proto_ipv6, echo->dev, (uint16_t)(echo->transport_len));
if (!reply) {
pico_err = PICO_ERR_ENOMEM;
return -1;
{
uint32_t mtu = echo->dev->mtu;
const struct pico_ipv6_path_id path_id = {((struct pico_ipv6_hdr *)echo->net_hdr)->src};
const uint16_t header_overhead = (uint16_t) (echo->net_len + (echo->net_hdr - echo->buffer));
#ifdef PICO_SUPPORT_IPV6PMTU
mtu = pico_ipv6_pmtu_get(&path_id);
if (mtu == 0) {
mtu = echo->dev->mtu;
pico_ipv6_path_add(&path_id, mtu);
}
#endif
if (echo->transport_len < mtu - header_overhead) {
reply = pico_proto_ipv6.alloc(&pico_proto_ipv6, echo->dev, (uint16_t)(echo->transport_len));
if (!reply) {
pico_err = PICO_ERR_ENOMEM;
return -1;
}
echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
reply->payload = reply->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
reply->payload_len = echo->transport_len;
ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr;
rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr;
rhdr->type = PICO_ICMP6_ECHO_REPLY;
rhdr->code = 0;
rhdr->msg.info.echo_reply.id = ehdr->msg.info.echo_reply.id;
rhdr->msg.info.echo_reply.seq = ehdr->msg.info.echo_request.seq;
memcpy(reply->payload, echo->payload, (uint32_t)(echo->transport_len - PICO_ICMP6HDR_ECHO_REQUEST_SIZE));
rhdr->crc = 0;
rhdr->crc = short_be(pico_icmp6_checksum(reply));
/* Get destination and source swapped */
memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6);
memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6);
pico_ipv6_frame_push(reply, &src, &dst, PICO_PROTO_ICMP6, 0);
} else {
uint16_t offset = 0;
const uint16_t frag_payload = (uint16_t) (echo->transport_len);
echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr;
/* Get destination and source swapped */
memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6);
memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6);
while (offset < frag_payload) {
uint16_t size = (uint16_t) (frag_payload - offset);
const uint16_t icmp_mss = (uint16_t) (mtu - PICO_IPV6_EXTHDR_FRAG_SIZE - header_overhead);
if (size > icmp_mss) {
size = (uint16_t) (icmp_mss - (icmp_mss % 8));
}
/* Allocate ipv6 with fragmentation header */
reply = pico_proto_ipv6.alloc(&pico_proto_ipv6, echo->dev, (uint16_t) (size + PICO_IPV6_EXTHDR_FRAG_SIZE));
if (!reply) {
pico_err = PICO_ERR_ENOMEM;
return -1;
}
reply->net_len = (uint16_t) (reply->net_len + PICO_IPV6_EXTHDR_FRAG_SIZE);
reply->transport_hdr += PICO_IPV6_EXTHDR_FRAG_SIZE;
reply->transport_len = (uint16_t) (reply->transport_len - PICO_IPV6_EXTHDR_FRAG_SIZE);
/* Populate fragmentation header */
{
struct pico_ipv6_exthdr * frag_header = (struct pico_ipv6_exthdr *) (reply->transport_hdr-PICO_IPV6_EXTHDR_FRAG_SIZE);
uint16_t octet_offset = short_be((uint16_t)(offset));
if (offset + size < frag_payload) {
octet_offset = octet_offset | short_be(1);
}
frag_header->nxthdr = PICO_PROTO_ICMP6;
memcpy(frag_header->ext.frag.id, (uint8_t *)(&frag_id), 4);
memcpy(frag_header->ext.frag.om, (uint8_t *)(&octet_offset), 2);
}
/* Prepare for sending */
memcpy(reply->transport_hdr, echo->transport_hdr + offset, size);
if (offset == 0){
rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr;
rhdr->type = PICO_ICMP6_ECHO_REPLY;
rhdr->code = 0;
rhdr->msg.info.echo_reply.id = ehdr->msg.info.echo_reply.id;
rhdr->msg.info.echo_reply.seq = ehdr->msg.info.echo_request.seq;
/* Received echo packet used for checksum calculation */
memcpy(((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, src.addr, PICO_SIZE_IP6);
memcpy(((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, dst.addr, PICO_SIZE_IP6);
ehdr->type = PICO_ICMP6_ECHO_REPLY;
ehdr->code = 0;
ehdr->crc = 0;
rhdr->crc = short_be(pico_icmp6_checksum(echo));
}
pico_ipv6_frame_push(reply, &src, &dst, PICO_IPV6_EXTHDR_FRAG, 0);
offset = (uint16_t)(offset + size);
}
}
}
echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
reply->payload = reply->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
reply->payload_len = echo->transport_len;
ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr;
rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr;
rhdr->type = PICO_ICMP6_ECHO_REPLY;
rhdr->code = 0;
rhdr->msg.info.echo_reply.id = ehdr->msg.info.echo_reply.id;
rhdr->msg.info.echo_reply.seq = ehdr->msg.info.echo_request.seq;
memcpy(reply->payload, echo->payload, (uint32_t)(echo->transport_len - PICO_ICMP6HDR_ECHO_REQUEST_SIZE));
rhdr->crc = 0;
rhdr->crc = short_be(pico_icmp6_checksum(reply));
/* Get destination and source swapped */
memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6);
memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6);
pico_ipv6_frame_push(reply, &src, &dst, PICO_PROTO_ICMP6, 0);
return 0;
}
static void pico_icmp6_ping_echo_recv_request(struct pico_frame *f)
{
icmp6_dbg("ICMP6: Received ECHO REQ\n");
f->transport_len = (uint16_t)(f->len - f->net_len - (uint16_t)(f->net_hdr - f->buffer));
pico_icmp6_send_echoreply(f);
pico_frame_discard(f);
}
static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame *f)
{
struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
......@@ -111,10 +195,7 @@ static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame *
break;
case PICO_ICMP6_ECHO_REQUEST:
icmp6_dbg("ICMP6: Received ECHO REQ\n");
f->transport_len = (uint16_t)(f->len - f->net_len - (uint16_t)(f->net_hdr - f->buffer));
pico_icmp6_send_echoreply(f);
pico_frame_discard(f);
pico_icmp6_ping_echo_recv_request(f);
break;
case PICO_ICMP6_ECHO_REPLY:
......@@ -912,23 +993,23 @@ int pico_icmp6_ping_abort(int id)
#ifdef PICO_SUPPORT_IPV6PMTU
static void pico_icmp6_update_pmtu(struct pico_frame *f)
{
const struct pico_icmp6_hdr *icmp_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
const struct pico_ipv6_hdr *icmp_payload = NULL;
struct pico_ipv6_path_id path_id;
const struct pico_icmp6_hdr *icmp_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
const struct pico_ipv6_hdr *icmp_payload = NULL;
struct pico_ipv6_path_id path_id;
f->net_hdr = f->transport_hdr + PICO_ICMP6HDR_PKT_TOO_BIG_SIZE;
icmp_payload = (struct pico_ipv6_hdr *)f->net_hdr;
path_id.dst = icmp_payload->dst;
f->net_hdr = f->transport_hdr + PICO_ICMP6HDR_PKT_TOO_BIG_SIZE;
icmp_payload = (struct pico_ipv6_hdr *)f->net_hdr;
path_id.dst = icmp_payload->dst;
if (pico_ipv6_path_update(&path_id, be_to_host_long(icmp_hdr->msg.err.pkt_too_big.mtu)) == PICO_PMTU_OK){
#if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP
f->transport_hdr = f->net_hdr + PICO_SIZE_IP6HDR;
f->transport_len = (uint16_t) (f->transport_len - ((uint16_t)PICO_SIZE_IP6HDR + PICO_ICMP6HDR_PKT_TOO_BIG_SIZE));
pico_transport_error(f, icmp_payload->nxthdr, PICO_ICMP6_ERR_PKT_TOO_BIG);
f->transport_hdr = f->net_hdr + PICO_SIZE_IP6HDR;
f->transport_len = (uint16_t) (f->transport_len - ((uint16_t)PICO_SIZE_IP6HDR + PICO_ICMP6HDR_PKT_TOO_BIG_SIZE));
pico_transport_error(f, icmp_payload->nxthdr, PICO_ICMP6_ERR_PKT_TOO_BIG);
#endif
} else {
pico_frame_discard(f);
}
} else {
pico_frame_discard(f);
}
}
#endif
......@@ -1326,6 +1326,10 @@ static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_l
#else
IGNORE_PARAMETER(hbh);
#endif
case PICO_IPV6_EXTHDR_FRAG:
{
break;
}
case PICO_PROTO_ICMP6:
{
icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
......
......@@ -24,6 +24,8 @@
#define PICO_IPV6_EXTHDR_NONE 59
#define PICO_IPV6_EXTHDR_DESTOPT 60
#define PICO_IPV6_EXTHDR_FRAG_SIZE 8
#define PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT 5
#define PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT_DATALEN 2
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment