diff options
Diffstat (limited to 'src/vnet/ip/ip6_to_ip4.h')
-rw-r--r-- | src/vnet/ip/ip6_to_ip4.h | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/vnet/ip/ip6_to_ip4.h b/src/vnet/ip/ip6_to_ip4.h index 17a11e6df0a..6a533e3b54e 100644 --- a/src/vnet/ip/ip6_to_ip4.h +++ b/src/vnet/ip/ip6_to_ip4.h @@ -170,6 +170,57 @@ ip6_get_port (vlib_main_t * vm, vlib_buffer_t * b, ip6_header_t * ip6, if (dst_port) *dst_port = ((u16 *) (icmp))[2]; } + else if (clib_net_to_host_u16 (ip6->payload_length) >= 64) + { + u16 ip6_pay_len; + ip6_header_t *inner_ip6; + u8 inner_l4_protocol; + u16 inner_l4_offset; + u16 inner_frag_offset; + u8 *inner_l4; + + ip6_pay_len = clib_net_to_host_u16 (ip6->payload_length); + inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8); + + if (ip6_parse (vm, b, inner_ip6, ip6_pay_len - 8, + &inner_l4_protocol, &inner_l4_offset, + &inner_frag_offset)) + return 0; + + if (inner_frag_offset && + ip6_frag_hdr_offset (((ip6_frag_hdr_t *) + u8_ptr_add (inner_ip6, + inner_frag_offset)))) + return 0; + + inner_l4 = u8_ptr_add (inner_ip6, inner_l4_offset); + if (inner_l4_protocol == IP_PROTOCOL_TCP || + inner_l4_protocol == IP_PROTOCOL_UDP) + { + if (src_port) + *src_port = ((udp_header_t *) (inner_l4))->dst_port; + if (dst_port) + *dst_port = ((udp_header_t *) (inner_l4))->src_port; + } + else if (inner_l4_protocol == IP_PROTOCOL_ICMP6) + { + icmp46_header_t *inner_icmp = (icmp46_header_t *) (inner_l4); + if (inner_icmp->type == ICMP6_echo_request) + { + if (src_port) + *src_port = ((u16 *) (inner_icmp))[2]; + if (dst_port) + *dst_port = ((u16 *) (inner_icmp))[2]; + } + else if (inner_icmp->type == ICMP6_echo_reply) + { + if (src_port) + *src_port = ((u16 *) (inner_icmp))[2]; + if (dst_port) + *dst_port = ((u16 *) (inner_icmp))[2]; + } + } + } } return 1; } |