Skip to content

Commit 8476da9

Browse files
committed
net: icmp: Remove NET_ICMP_HDR() macro and direct access to net_buf
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 <[email protected]>
1 parent 7e259e7 commit 8476da9

File tree

13 files changed

+792
-249
lines changed

13 files changed

+792
-249
lines changed

include/net/net_pkt.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,12 +333,6 @@ static inline u8_t *net_pkt_tcp_data(struct net_pkt *pkt)
333333
net_pkt_ipv6_ext_len(pkt)];
334334
}
335335

336-
static inline u8_t *net_pkt_icmp_data(struct net_pkt *pkt)
337-
{
338-
return &pkt->frags->data[net_pkt_ip_hdr_len(pkt) +
339-
net_pkt_ipv6_ext_len(pkt)];
340-
}
341-
342336
static inline u8_t *net_pkt_appdata(struct net_pkt *pkt)
343337
{
344338
return pkt->appdata;
@@ -414,7 +408,6 @@ static inline void net_pkt_set_ieee802154_rssi(struct net_pkt *pkt,
414408

415409
#define NET_IPV6_HDR(pkt) ((struct net_ipv6_hdr *)net_pkt_ip_data(pkt))
416410
#define NET_IPV4_HDR(pkt) ((struct net_ipv4_hdr *)net_pkt_ip_data(pkt))
417-
#define NET_ICMP_HDR(pkt) ((struct net_icmp_hdr *)net_pkt_icmp_data(pkt))
418411
#define NET_UDP_HDR(pkt) ((struct net_udp_hdr *)(net_pkt_udp_data(pkt)))
419412
#define NET_TCP_HDR(pkt) ((struct net_tcp_hdr *)(net_pkt_tcp_data(pkt)))
420413

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

1306+
/**
1307+
* @brief Return the fragment and offset within it according to network
1308+
* packet offset.
1309+
*
1310+
* @details This is typically used to get the protocol header pointer when
1311+
* we know the offset. According to this information, the corresponding fragment
1312+
* and position within that fragment is returned.
1313+
*
1314+
* @param pkt Network packet
1315+
* @param offset Offset of desired location in network packet. For example, if
1316+
* we want to know where UDP header is located after the IPv6 header,
1317+
* the offset could have a value of sizeof(struct net_ipv6_hdr). Note that this
1318+
* is a simplified example that does not take into account the possible IPv6
1319+
* extension headers.
1320+
* @param pos Pointer to position within result fragment corresponding to
1321+
* offset param. For example, if the IPv6 header is split between two fragments,
1322+
* then if we want to know the start of UDP header, the returned pos variable
1323+
* would indicate how many bytes from second fragment the UDP header starts.
1324+
*
1325+
* @return Pointer to the fragment where the the offset is located or
1326+
* NULL if there is not enough bytes in the packet
1327+
*/
1328+
struct net_buf *net_frag_get_pos(struct net_pkt *pkt,
1329+
u16_t offset,
1330+
u16_t *pos);
1331+
13131332
/**
13141333
* @brief Get information about predefined RX, TX and DATA pools.
13151334
*

subsys/net/ip/icmpv4.c

Lines changed: 101 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,93 @@
2626

2727
static sys_slist_t handlers;
2828

29+
struct net_icmp_hdr *net_icmpv4_set_hdr(struct net_pkt *pkt,
30+
struct net_icmp_hdr *hdr)
31+
{
32+
struct net_icmp_hdr *icmp_hdr;
33+
struct net_buf *frag;
34+
u16_t pos;
35+
36+
icmp_hdr = net_pkt_icmp_data(pkt);
37+
if (net_icmp_header_fits(pkt, icmp_hdr)) {
38+
return icmp_hdr;
39+
}
40+
41+
frag = net_pkt_write_u8(pkt, pkt->frags,
42+
net_pkt_ip_hdr_len(pkt),
43+
&pos, hdr->type);
44+
frag = net_pkt_write_u8(pkt, frag, pos, &pos, hdr->code);
45+
frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->chksum),
46+
(u8_t *)&hdr->chksum, PKT_WAIT_TIME);
47+
if (!frag) {
48+
NET_ASSERT(frag);
49+
return NULL;
50+
}
51+
52+
return hdr;
53+
}
54+
55+
struct net_icmp_hdr *net_icmpv4_get_hdr(struct net_pkt *pkt,
56+
struct net_icmp_hdr *hdr)
57+
{
58+
struct net_icmp_hdr *icmp_hdr;
59+
struct net_buf *frag;
60+
u16_t pos;
61+
62+
icmp_hdr = net_pkt_icmp_data(pkt);
63+
if (net_icmp_header_fits(pkt, icmp_hdr)) {
64+
return icmp_hdr;
65+
}
66+
67+
frag = net_frag_read_u8(pkt->frags, net_pkt_ip_hdr_len(pkt), &pos,
68+
&hdr->type);
69+
frag = net_frag_read_u8(frag, pos, &pos, &hdr->code);
70+
frag = net_frag_read(frag, pos, &pos, sizeof(hdr->chksum),
71+
(u8_t *)&hdr->chksum);
72+
if (!frag) {
73+
NET_ASSERT(frag);
74+
return NULL;
75+
}
76+
77+
return hdr;
78+
}
79+
80+
struct net_buf *net_icmpv4_set_chksum(struct net_pkt *pkt,
81+
struct net_buf *frag)
82+
{
83+
struct net_icmp_hdr *icmp_hdr;
84+
u16_t chksum = 0;
85+
u16_t pos;
86+
87+
icmp_hdr = net_pkt_icmp_data(pkt);
88+
if (net_icmp_header_fits(pkt, icmp_hdr)) {
89+
icmp_hdr->chksum = 0;
90+
icmp_hdr->chksum = ~net_calc_chksum_icmpv4(pkt);
91+
92+
return frag;
93+
}
94+
95+
frag = net_pkt_write(pkt, frag,
96+
net_pkt_ip_hdr_len(pkt) +
97+
1 + 1 /* type + code */, &pos,
98+
sizeof(chksum), (u8_t *)&chksum, PKT_WAIT_TIME);
99+
100+
chksum = ~net_calc_chksum_icmpv4(pkt);
101+
102+
frag = net_pkt_write(pkt, frag, pos - 2, &pos, sizeof(chksum),
103+
(u8_t *)&chksum, PKT_WAIT_TIME);
104+
105+
NET_ASSERT(frag);
106+
107+
return frag;
108+
}
109+
29110
static inline enum net_verdict handle_echo_request(struct net_pkt *pkt)
30111
{
31112
/* Note that we send the same data packets back and just swap
32113
* the addresses etc.
33114
*/
115+
struct net_icmp_hdr hdr, *icmp_hdr;
34116
struct in_addr addr;
35117

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

50-
NET_ICMP_HDR(pkt)->type = NET_ICMPV4_ECHO_REPLY;
51-
NET_ICMP_HDR(pkt)->code = 0;
52-
NET_ICMP_HDR(pkt)->chksum = 0;
53-
NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt);
132+
icmp_hdr = net_icmpv4_get_hdr(pkt, &hdr);
133+
icmp_hdr->type = NET_ICMPV4_ECHO_REPLY;
134+
icmp_hdr->code = 0;
135+
icmp_hdr->chksum = 0;
136+
net_icmpv4_set_hdr(pkt, icmp_hdr);
137+
net_icmpv4_set_chksum(pkt, pkt->frags);
54138

55139
#if defined(CONFIG_NET_DEBUG_ICMPV4)
56140
snprintk(out, sizeof(out), "%s",
@@ -75,6 +159,9 @@ static inline void setup_ipv4_header(struct net_pkt *pkt, u8_t extra_len,
75159
u8_t ttl, u8_t icmp_type,
76160
u8_t icmp_code)
77161
{
162+
struct net_buf *frag = pkt->frags;
163+
u16_t pos;
164+
78165
NET_IPV4_HDR(pkt)->vhl = 0x45;
79166
NET_IPV4_HDR(pkt)->tos = 0x00;
80167
NET_IPV4_HDR(pkt)->len[0] = 0;
@@ -91,11 +178,10 @@ static inline void setup_ipv4_header(struct net_pkt *pkt, u8_t extra_len,
91178
NET_IPV4_HDR(pkt)->chksum = 0;
92179
NET_IPV4_HDR(pkt)->chksum = ~net_calc_chksum_ipv4(pkt);
93180

94-
NET_ICMP_HDR(pkt)->type = icmp_type;
95-
NET_ICMP_HDR(pkt)->code = icmp_code;
96-
97-
memset(net_pkt_icmp_data(pkt) + sizeof(struct net_icmp_hdr), 0,
98-
NET_ICMPV4_UNUSED_LEN);
181+
frag = net_pkt_write_u8(pkt, frag, net_pkt_ip_hdr_len(pkt), &pos,
182+
icmp_type);
183+
frag = net_pkt_write_u8(pkt, frag, pos, &pos, icmp_code);
184+
net_pkt_write_be32(pkt, frag, pos, &pos, 0);
99185
}
100186

101187
int net_icmpv4_send_echo_request(struct net_if *iface,
@@ -133,8 +219,7 @@ int net_icmpv4_send_echo_request(struct net_if *iface,
133219
NET_ICMPV4_ECHO_REQ(pkt)->identifier = htons(identifier);
134220
NET_ICMPV4_ECHO_REQ(pkt)->sequence = htons(sequence);
135221

136-
NET_ICMP_HDR(pkt)->chksum = 0;
137-
NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt);
222+
net_icmpv4_set_chksum(pkt, pkt->frags);
138223

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

176261
if (NET_IPV4_HDR(orig)->proto == IPPROTO_ICMP) {
177-
if (NET_ICMP_HDR(orig)->code < 8) {
262+
struct net_icmp_hdr icmp_hdr[1];
263+
264+
if (!net_icmpv4_get_hdr(orig, icmp_hdr) ||
265+
icmp_hdr->code < 8) {
178266
/* We must not send ICMP errors back */
179267
err = -EINVAL;
180268
goto drop_no_pkt;
@@ -241,8 +329,7 @@ int net_icmpv4_send_error(struct net_pkt *orig, u8_t type, u8_t code)
241329
net_pkt_ll_dst(pkt)->addr = net_pkt_ll_src(orig)->addr;
242330
net_pkt_ll_dst(pkt)->len = net_pkt_ll_src(orig)->len;
243331

244-
NET_ICMP_HDR(pkt)->chksum = 0;
245-
NET_ICMP_HDR(pkt)->chksum = ~net_calc_chksum_icmpv4(pkt);
332+
net_icmpv4_set_chksum(pkt, pkt->frags);
246333

247334
#if defined(CONFIG_NET_DEBUG_ICMPV4)
248335
do {

subsys/net/ip/icmpv4.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ void net_icmpv4_unregister_handler(struct net_icmpv4_handler *handler);
7676
enum net_verdict net_icmpv4_input(struct net_pkt *pkt,
7777
u8_t type, u8_t code);
7878

79+
struct net_icmp_hdr *net_icmpv4_get_hdr(struct net_pkt *pkt,
80+
struct net_icmp_hdr *hdr);
81+
struct net_icmp_hdr *net_icmpv4_set_hdr(struct net_pkt *pkt,
82+
struct net_icmp_hdr *hdr);
83+
struct net_buf *net_icmpv4_set_chksum(struct net_pkt *pkt,
84+
struct net_buf *frag);
85+
7986
#if defined(CONFIG_NET_IPV4)
8087
void net_icmpv4_init(void);
8188
#else

0 commit comments

Comments
 (0)