Skip to content

Commit

Permalink
net: icmp: Remove NET_ICMP_HDR() macro and direct access to net_buf
Browse files Browse the repository at this point in the history
Remove NET_ICMP_HDR() macro as we cannot safely access ICMP header
via it if the network packet header spans over multiple net_buf
fragments.

Jira: ZEP-2306

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
  • Loading branch information
jukkar committed Jul 7, 2017
1 parent 7e259e7 commit 8476da9
Show file tree
Hide file tree
Showing 13 changed files with 792 additions and 249 deletions.
33 changes: 26 additions & 7 deletions include/net/net_pkt.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,6 @@ static inline u8_t *net_pkt_tcp_data(struct net_pkt *pkt)
net_pkt_ipv6_ext_len(pkt)];
}

static inline u8_t *net_pkt_icmp_data(struct net_pkt *pkt)
{
return &pkt->frags->data[net_pkt_ip_hdr_len(pkt) +
net_pkt_ipv6_ext_len(pkt)];
}

static inline u8_t *net_pkt_appdata(struct net_pkt *pkt)
{
return pkt->appdata;
Expand Down Expand Up @@ -414,7 +408,6 @@ static inline void net_pkt_set_ieee802154_rssi(struct net_pkt *pkt,

#define NET_IPV6_HDR(pkt) ((struct net_ipv6_hdr *)net_pkt_ip_data(pkt))
#define NET_IPV4_HDR(pkt) ((struct net_ipv4_hdr *)net_pkt_ip_data(pkt))
#define NET_ICMP_HDR(pkt) ((struct net_icmp_hdr *)net_pkt_icmp_data(pkt))
#define NET_UDP_HDR(pkt) ((struct net_udp_hdr *)(net_pkt_udp_data(pkt)))
#define NET_TCP_HDR(pkt) ((struct net_tcp_hdr *)(net_pkt_tcp_data(pkt)))

Expand Down Expand Up @@ -1310,6 +1303,32 @@ int net_pkt_split(struct net_pkt *pkt, struct net_buf *orig_frag,
u16_t len, struct net_buf **fragA,
struct net_buf **fragB, s32_t timeout);

/**
* @brief Return the fragment and offset within it according to network
* packet offset.
*
* @details This is typically used to get the protocol header pointer when
* we know the offset. According to this information, the corresponding fragment
* and position within that fragment is returned.
*
* @param pkt Network packet
* @param offset Offset of desired location in network packet. For example, if
* we want to know where UDP header is located after the IPv6 header,
* the offset could have a value of sizeof(struct net_ipv6_hdr). Note that this
* is a simplified example that does not take into account the possible IPv6
* extension headers.
* @param pos Pointer to position within result fragment corresponding to
* offset param. For example, if the IPv6 header is split between two fragments,
* then if we want to know the start of UDP header, the returned pos variable
* would indicate how many bytes from second fragment the UDP header starts.
*
* @return Pointer to the fragment where the the offset is located or
* NULL if there is not enough bytes in the packet
*/
struct net_buf *net_frag_get_pos(struct net_pkt *pkt,
u16_t offset,
u16_t *pos);

/**
* @brief Get information about predefined RX, TX and DATA pools.
*
Expand Down
115 changes: 101 additions & 14 deletions subsys/net/ip/icmpv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,93 @@

static sys_slist_t handlers;

struct net_icmp_hdr *net_icmpv4_set_hdr(struct net_pkt *pkt,
struct net_icmp_hdr *hdr)
{
struct net_icmp_hdr *icmp_hdr;
struct net_buf *frag;
u16_t pos;

icmp_hdr = net_pkt_icmp_data(pkt);
if (net_icmp_header_fits(pkt, icmp_hdr)) {
return icmp_hdr;
}

frag = net_pkt_write_u8(pkt, pkt->frags,
net_pkt_ip_hdr_len(pkt),
&pos, hdr->type);
frag = net_pkt_write_u8(pkt, frag, pos, &pos, hdr->code);
frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->chksum),
(u8_t *)&hdr->chksum, PKT_WAIT_TIME);
if (!frag) {
NET_ASSERT(frag);
return NULL;
}

return hdr;
}

struct net_icmp_hdr *net_icmpv4_get_hdr(struct net_pkt *pkt,
struct net_icmp_hdr *hdr)
{
struct net_icmp_hdr *icmp_hdr;
struct net_buf *frag;
u16_t pos;

icmp_hdr = net_pkt_icmp_data(pkt);
if (net_icmp_header_fits(pkt, icmp_hdr)) {
return icmp_hdr;
}

frag = net_frag_read_u8(pkt->frags, net_pkt_ip_hdr_len(pkt), &pos,
&hdr->type);
frag = net_frag_read_u8(frag, pos, &pos, &hdr->code);
frag = net_frag_read(frag, pos, &pos, sizeof(hdr->chksum),
(u8_t *)&hdr->chksum);
if (!frag) {
NET_ASSERT(frag);
return NULL;
}

return hdr;
}

struct net_buf *net_icmpv4_set_chksum(struct net_pkt *pkt,
struct net_buf *frag)
{
struct net_icmp_hdr *icmp_hdr;
u16_t chksum = 0;
u16_t pos;

icmp_hdr = net_pkt_icmp_data(pkt);
if (net_icmp_header_fits(pkt, icmp_hdr)) {
icmp_hdr->chksum = 0;
icmp_hdr->chksum = ~net_calc_chksum_icmpv4(pkt);

return frag;
}

frag = net_pkt_write(pkt, frag,
net_pkt_ip_hdr_len(pkt) +
1 + 1 /* type + code */, &pos,
sizeof(chksum), (u8_t *)&chksum, PKT_WAIT_TIME);

chksum = ~net_calc_chksum_icmpv4(pkt);

frag = net_pkt_write(pkt, frag, pos - 2, &pos, sizeof(chksum),
(u8_t *)&chksum, PKT_WAIT_TIME);

NET_ASSERT(frag);

return frag;
}

static inline enum net_verdict handle_echo_request(struct net_pkt *pkt)
{
/* Note that we send the same data packets back and just swap
* the addresses etc.
*/
struct net_icmp_hdr hdr, *icmp_hdr;
struct in_addr addr;

#if defined(CONFIG_NET_DEBUG_ICMPV4)
Expand All @@ -47,10 +129,12 @@ static inline enum net_verdict handle_echo_request(struct net_pkt *pkt)
&NET_IPV4_HDR(pkt)->dst);
net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr);

NET_ICMP_HDR(pkt)->type = NET_ICMPV4_ECHO_REPLY;
NET_ICMP_HDR(pkt)->code = 0;
NET_ICMP_HDR(pkt)->chksum = 0;
NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt);
icmp_hdr = net_icmpv4_get_hdr(pkt, &hdr);
icmp_hdr->type = NET_ICMPV4_ECHO_REPLY;
icmp_hdr->code = 0;
icmp_hdr->chksum = 0;
net_icmpv4_set_hdr(pkt, icmp_hdr);
net_icmpv4_set_chksum(pkt, pkt->frags);

#if defined(CONFIG_NET_DEBUG_ICMPV4)
snprintk(out, sizeof(out), "%s",
Expand All @@ -75,6 +159,9 @@ static inline void setup_ipv4_header(struct net_pkt *pkt, u8_t extra_len,
u8_t ttl, u8_t icmp_type,
u8_t icmp_code)
{
struct net_buf *frag = pkt->frags;
u16_t pos;

NET_IPV4_HDR(pkt)->vhl = 0x45;
NET_IPV4_HDR(pkt)->tos = 0x00;
NET_IPV4_HDR(pkt)->len[0] = 0;
Expand All @@ -91,11 +178,10 @@ static inline void setup_ipv4_header(struct net_pkt *pkt, u8_t extra_len,
NET_IPV4_HDR(pkt)->chksum = 0;
NET_IPV4_HDR(pkt)->chksum = ~net_calc_chksum_ipv4(pkt);

NET_ICMP_HDR(pkt)->type = icmp_type;
NET_ICMP_HDR(pkt)->code = icmp_code;

memset(net_pkt_icmp_data(pkt) + sizeof(struct net_icmp_hdr), 0,
NET_ICMPV4_UNUSED_LEN);
frag = net_pkt_write_u8(pkt, frag, net_pkt_ip_hdr_len(pkt), &pos,
icmp_type);
frag = net_pkt_write_u8(pkt, frag, pos, &pos, icmp_code);
net_pkt_write_be32(pkt, frag, pos, &pos, 0);
}

int net_icmpv4_send_echo_request(struct net_if *iface,
Expand Down Expand Up @@ -133,8 +219,7 @@ int net_icmpv4_send_echo_request(struct net_if *iface,
NET_ICMPV4_ECHO_REQ(pkt)->identifier = htons(identifier);
NET_ICMPV4_ECHO_REQ(pkt)->sequence = htons(sequence);

NET_ICMP_HDR(pkt)->chksum = 0;
NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt);
net_icmpv4_set_chksum(pkt, pkt->frags);

#if defined(CONFIG_NET_DEBUG_ICMPV4)
do {
Expand Down Expand Up @@ -174,7 +259,10 @@ int net_icmpv4_send_error(struct net_pkt *orig, u8_t type, u8_t code)
int err = -EIO;

if (NET_IPV4_HDR(orig)->proto == IPPROTO_ICMP) {
if (NET_ICMP_HDR(orig)->code < 8) {
struct net_icmp_hdr icmp_hdr[1];

if (!net_icmpv4_get_hdr(orig, icmp_hdr) ||
icmp_hdr->code < 8) {
/* We must not send ICMP errors back */
err = -EINVAL;
goto drop_no_pkt;
Expand Down Expand Up @@ -241,8 +329,7 @@ int net_icmpv4_send_error(struct net_pkt *orig, u8_t type, u8_t code)
net_pkt_ll_dst(pkt)->addr = net_pkt_ll_src(orig)->addr;
net_pkt_ll_dst(pkt)->len = net_pkt_ll_src(orig)->len;

NET_ICMP_HDR(pkt)->chksum = 0;
NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt);
net_icmpv4_set_chksum(pkt, pkt->frags);

#if defined(CONFIG_NET_DEBUG_ICMPV4)
do {
Expand Down
7 changes: 7 additions & 0 deletions subsys/net/ip/icmpv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler);
enum net_verdict net_icmpv4_input(struct net_pkt *pkt,
u8_t type, u8_t code);

struct net_icmp_hdr *net_icmpv4_get_hdr(struct net_pkt *pkt,
struct net_icmp_hdr *hdr);
struct net_icmp_hdr *net_icmpv4_set_hdr(struct net_pkt *pkt,
struct net_icmp_hdr *hdr);
struct net_buf *net_icmpv4_set_chksum(struct net_pkt *pkt,
struct net_buf *frag);

#if defined(CONFIG_NET_IPV4)
void net_icmpv4_init(void);
#else
Expand Down
Loading

0 comments on commit 8476da9

Please sign in to comment.