1 /** @file
2 * @brief IPv4 related functions
3 */
4
5 /*
6 * Copyright (c) 2016 Intel Corporation
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(net_ipv4, CONFIG_NET_IPV4_LOG_LEVEL);
13
14 #include <errno.h>
15 #include <zephyr/net/net_core.h>
16 #include <zephyr/net/net_pkt.h>
17 #include <zephyr/net/net_stats.h>
18 #include <zephyr/net/net_context.h>
19 #include <zephyr/net/virtual.h>
20 #include "net_private.h"
21 #include "connection.h"
22 #include "net_stats.h"
23 #include "icmpv4.h"
24 #include "udp_internal.h"
25 #include "tcp_internal.h"
26 #include "dhcpv4/dhcpv4_internal.h"
27 #include "ipv4.h"
28 #include "pmtu.h"
29
30 BUILD_ASSERT(sizeof(struct in_addr) == NET_IPV4_ADDR_SIZE);
31
32 /* Timeout for various buffer allocations in this file. */
33 #define NET_BUF_TIMEOUT K_MSEC(50)
34
net_ipv4_create_full(struct net_pkt * pkt,const struct in_addr * src,const struct in_addr * dst,uint8_t tos,uint16_t id,uint8_t flags,uint16_t offset)35 int net_ipv4_create_full(struct net_pkt *pkt,
36 const struct in_addr *src,
37 const struct in_addr *dst,
38 uint8_t tos,
39 uint16_t id,
40 uint8_t flags,
41 uint16_t offset)
42 {
43 NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
44 struct net_ipv4_hdr *ipv4_hdr;
45
46 ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access);
47 if (!ipv4_hdr) {
48 return -ENOBUFS;
49 }
50
51 ipv4_hdr->vhl = 0x45;
52 ipv4_hdr->tos = tos;
53 ipv4_hdr->len = 0U;
54 ipv4_hdr->id[0] = id >> 8;
55 ipv4_hdr->id[1] = id;
56 ipv4_hdr->offset[0] = (offset >> 8) | (flags << 5);
57 ipv4_hdr->offset[1] = offset;
58
59 ipv4_hdr->ttl = net_pkt_ipv4_ttl(pkt);
60 if (ipv4_hdr->ttl == 0U) {
61 if (net_ipv4_is_addr_mcast(dst)) {
62 if (net_pkt_context(pkt) != NULL) {
63 ipv4_hdr->ttl =
64 net_context_get_ipv4_mcast_ttl(net_pkt_context(pkt));
65 } else {
66 ipv4_hdr->ttl = net_if_ipv4_get_mcast_ttl(net_pkt_iface(pkt));
67 }
68 } else {
69 if (net_pkt_context(pkt) != NULL) {
70 ipv4_hdr->ttl =
71 net_context_get_ipv4_ttl(net_pkt_context(pkt));
72 } else {
73 ipv4_hdr->ttl = net_if_ipv4_get_ttl(net_pkt_iface(pkt));
74 }
75 }
76 }
77
78 ipv4_hdr->proto = 0U;
79 ipv4_hdr->chksum = 0U;
80
81 net_ipv4_addr_copy_raw(ipv4_hdr->dst, (uint8_t *)dst);
82 net_ipv4_addr_copy_raw(ipv4_hdr->src, (uint8_t *)src);
83
84 net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
85
86 return net_pkt_set_data(pkt, &ipv4_access);
87 }
88
net_ipv4_create(struct net_pkt * pkt,const struct in_addr * src,const struct in_addr * dst)89 int net_ipv4_create(struct net_pkt *pkt,
90 const struct in_addr *src,
91 const struct in_addr *dst)
92 {
93 uint8_t tos = 0;
94 uint8_t flags = 0U;
95
96 if (IS_ENABLED(CONFIG_NET_IP_DSCP_ECN)) {
97 net_ipv4_set_dscp(&tos, net_pkt_ip_dscp(pkt));
98 net_ipv4_set_ecn(&tos, net_pkt_ip_ecn(pkt));
99 }
100
101 if (IS_ENABLED(CONFIG_NET_IPV4_PMTU) && net_pkt_ipv4_pmtu(pkt)) {
102 flags = NET_IPV4_DF;
103 }
104
105 return net_ipv4_create_full(pkt, src, dst, tos, 0U, flags, 0U);
106 }
107
net_ipv4_finalize(struct net_pkt * pkt,uint8_t next_header_proto)108 int net_ipv4_finalize(struct net_pkt *pkt, uint8_t next_header_proto)
109 {
110 NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
111 struct net_ipv4_hdr *ipv4_hdr;
112
113 net_pkt_set_overwrite(pkt, true);
114
115 ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access);
116 if (!ipv4_hdr) {
117 return -ENOBUFS;
118 }
119
120 if (IS_ENABLED(CONFIG_NET_IPV4_HDR_OPTIONS)) {
121 if (net_pkt_ipv4_opts_len(pkt)) {
122 ipv4_hdr->vhl = 0x40 | (0x0F &
123 ((net_pkt_ip_hdr_len(pkt) +
124 net_pkt_ipv4_opts_len(pkt)) / 4U));
125 }
126 }
127
128 ipv4_hdr->len = htons(net_pkt_get_len(pkt));
129 ipv4_hdr->proto = next_header_proto;
130
131 if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt), NET_IF_CHECKSUM_IPV4_HEADER)) {
132 ipv4_hdr->chksum = net_calc_chksum_ipv4(pkt);
133 }
134
135 net_pkt_set_data(pkt, &ipv4_access);
136
137 if (IS_ENABLED(CONFIG_NET_UDP) &&
138 next_header_proto == IPPROTO_UDP) {
139 return net_udp_finalize(pkt, false);
140 } else if (IS_ENABLED(CONFIG_NET_TCP) &&
141 next_header_proto == IPPROTO_TCP) {
142 return net_tcp_finalize(pkt, false);
143 } else if (next_header_proto == IPPROTO_ICMP) {
144 return net_icmpv4_finalize(pkt, false);
145 }
146
147 return 0;
148 }
149
150 #if defined(CONFIG_NET_IPV4_HDR_OPTIONS)
net_ipv4_parse_hdr_options(struct net_pkt * pkt,net_ipv4_parse_hdr_options_cb_t cb,void * user_data)151 int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
152 net_ipv4_parse_hdr_options_cb_t cb,
153 void *user_data)
154 {
155 struct net_pkt_cursor cur;
156 uint8_t opt_data[NET_IPV4_HDR_OPTNS_MAX_LEN];
157 uint8_t total_opts_len;
158
159 if (!cb) {
160 return -EINVAL;
161 }
162
163 net_pkt_cursor_backup(pkt, &cur);
164 net_pkt_cursor_init(pkt);
165
166 if (net_pkt_skip(pkt, sizeof(struct net_ipv4_hdr))) {
167 return -EINVAL;
168 }
169
170 total_opts_len = net_pkt_ipv4_opts_len(pkt);
171
172 while (total_opts_len) {
173 uint8_t opt_len = 0U;
174 uint8_t opt_type;
175
176 if (net_pkt_read_u8(pkt, &opt_type)) {
177 return -EINVAL;
178 }
179
180 total_opts_len--;
181
182 if (!(opt_type == NET_IPV4_OPTS_EO ||
183 opt_type == NET_IPV4_OPTS_NOP)) {
184 if (net_pkt_read_u8(pkt, &opt_len)) {
185 return -EINVAL;
186 }
187
188 if (opt_len < 2U || total_opts_len < 1U) {
189 return -EINVAL;
190 }
191
192 opt_len -= 2U;
193 total_opts_len--;
194 }
195
196 if (opt_len > total_opts_len) {
197 return -EINVAL;
198 }
199
200 switch (opt_type) {
201 case NET_IPV4_OPTS_NOP:
202 break;
203
204 case NET_IPV4_OPTS_EO:
205 /* Options length should be zero, when cursor reaches to
206 * End of options.
207 */
208 if (total_opts_len) {
209 return -EINVAL;
210 }
211
212 break;
213 case NET_IPV4_OPTS_RR:
214 case NET_IPV4_OPTS_TS:
215 if (net_pkt_read(pkt, opt_data, opt_len)) {
216 return -EINVAL;
217 }
218
219 if (cb(opt_type, opt_data, opt_len, user_data)) {
220 return -EINVAL;
221 }
222
223 break;
224 default:
225 if (net_pkt_skip(pkt, opt_len)) {
226 return -EINVAL;
227 }
228
229 break;
230 }
231
232 total_opts_len -= opt_len;
233 }
234
235 net_pkt_cursor_restore(pkt, &cur);
236
237 return 0;
238 }
239 #endif
240
net_ipv4_input(struct net_pkt * pkt,bool is_loopback)241 enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback)
242 {
243 NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
244 NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
245 NET_PKT_DATA_ACCESS_DEFINE(tcp_access, struct net_tcp_hdr);
246 int real_len = net_pkt_get_len(pkt);
247 enum net_verdict verdict = NET_DROP;
248 union net_proto_header proto_hdr;
249 struct net_ipv4_hdr *hdr;
250 union net_ip_header ip;
251 uint8_t hdr_len;
252 uint8_t opts_len;
253 int pkt_len;
254
255 #if defined(CONFIG_NET_L2_IPIP)
256 struct net_pkt_cursor hdr_start;
257
258 net_pkt_cursor_backup(pkt, &hdr_start);
259 #endif
260
261 net_stats_update_ipv4_recv(net_pkt_iface(pkt));
262
263 hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access);
264 if (!hdr) {
265 NET_DBG("DROP: no buffer");
266 goto drop;
267 }
268
269 hdr_len = (hdr->vhl & NET_IPV4_IHL_MASK) * 4U;
270 if (hdr_len < sizeof(struct net_ipv4_hdr)) {
271 NET_DBG("DROP: Invalid hdr length");
272 goto drop;
273 }
274
275 net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
276
277 if (IS_ENABLED(CONFIG_NET_IP_DSCP_ECN)) {
278 net_pkt_set_ip_dscp(pkt, net_ipv4_get_dscp(hdr->tos));
279 net_pkt_set_ip_ecn(pkt, net_ipv4_get_ecn(hdr->tos));
280 }
281
282 opts_len = hdr_len - sizeof(struct net_ipv4_hdr);
283 if (opts_len > NET_IPV4_HDR_OPTNS_MAX_LEN) {
284 return -EINVAL;
285 }
286
287 if (hdr->ttl == 0) {
288 goto drop;
289 }
290
291 net_pkt_set_ipv4_opts_len(pkt, opts_len);
292
293 pkt_len = ntohs(hdr->len);
294 if (real_len < pkt_len) {
295 NET_DBG("DROP: pkt len per hdr %d != pkt real len %d",
296 pkt_len, real_len);
297 goto drop;
298 } else if (real_len > pkt_len) {
299 net_pkt_update_length(pkt, pkt_len);
300 }
301
302 if (!is_loopback) {
303 if (net_ipv4_is_addr_loopback((struct in_addr *)hdr->dst) ||
304 net_ipv4_is_addr_loopback((struct in_addr *)hdr->src)) {
305 NET_DBG("DROP: localhost packet");
306 goto drop;
307 }
308
309 if (net_ipv4_is_my_addr((struct in_addr *)hdr->src)) {
310 NET_DBG("DROP: src addr is %s", "mine");
311 goto drop;
312 }
313 }
314
315 if (net_ipv4_is_addr_mcast((struct in_addr *)hdr->src)) {
316 NET_DBG("DROP: src addr is %s", "mcast");
317 goto drop;
318 }
319
320 if (net_ipv4_is_addr_bcast(net_pkt_iface(pkt), (struct in_addr *)hdr->src)) {
321 NET_DBG("DROP: src addr is %s", "bcast");
322 goto drop;
323 }
324
325 if (net_ipv4_is_addr_unspecified((struct in_addr *)hdr->src) &&
326 !net_ipv4_is_addr_bcast(net_pkt_iface(pkt), (struct in_addr *)hdr->dst) &&
327 (hdr->proto != IPPROTO_IGMP)) {
328 NET_DBG("DROP: src addr is %s", "unspecified");
329 goto drop;
330 }
331
332 if (net_if_need_calc_rx_checksum(net_pkt_iface(pkt), NET_IF_CHECKSUM_IPV4_HEADER) &&
333 net_calc_chksum_ipv4(pkt) != 0U) {
334 NET_DBG("DROP: invalid chksum");
335 goto drop;
336 }
337
338 net_pkt_set_ipv4_ttl(pkt, hdr->ttl);
339
340 net_pkt_set_family(pkt, PF_INET);
341
342 if (!net_pkt_filter_ip_recv_ok(pkt)) {
343 /* drop the packet */
344 return NET_DROP;
345 }
346
347 if ((!net_ipv4_is_my_addr((struct in_addr *)hdr->dst) &&
348 !net_ipv4_is_addr_mcast((struct in_addr *)hdr->dst) &&
349 !(hdr->proto == IPPROTO_UDP &&
350 (net_ipv4_addr_cmp((struct in_addr *)hdr->dst, net_ipv4_broadcast_address()) ||
351 /* RFC 1122 ch. 3.3.6 The 0.0.0.0 is non-standard bcast addr */
352 (IS_ENABLED(CONFIG_NET_IPV4_ACCEPT_ZERO_BROADCAST) &&
353 net_ipv4_addr_cmp((struct in_addr *)hdr->dst,
354 net_ipv4_unspecified_address())) ||
355 net_dhcpv4_accept_unicast(pkt)))) ||
356 (hdr->proto == IPPROTO_TCP &&
357 net_ipv4_is_addr_bcast(net_pkt_iface(pkt), (struct in_addr *)hdr->dst))) {
358 NET_DBG("DROP: not for me");
359 goto drop;
360 }
361
362 net_pkt_acknowledge_data(pkt, &ipv4_access);
363
364 if (opts_len) {
365 /* Only few options are handled in EchoRequest, rest skipped */
366 if (net_pkt_skip(pkt, opts_len)) {
367 NET_DBG("Header too big? %u", hdr_len);
368 goto drop;
369 }
370 }
371
372 if (IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT)) {
373 /* Check if this is a fragmented packet, and if so, handle reassembly */
374 if ((ntohs(*((uint16_t *)&hdr->offset[0])) &
375 (NET_IPV4_FRAGH_OFFSET_MASK | NET_IPV4_MORE_FRAG_MASK)) != 0) {
376 return net_ipv4_handle_fragment_hdr(pkt, hdr);
377 }
378 }
379
380 NET_DBG("IPv4 packet received from %s to %s",
381 net_sprint_ipv4_addr(&hdr->src),
382 net_sprint_ipv4_addr(&hdr->dst));
383
384 switch (hdr->proto) {
385 case IPPROTO_ICMP:
386 verdict = net_icmpv4_input(pkt, hdr);
387 if (verdict == NET_DROP) {
388 goto drop;
389 }
390 return verdict;
391 #if defined(CONFIG_NET_IPV4_IGMP)
392 case IPPROTO_IGMP:
393 verdict = net_ipv4_igmp_input(pkt, hdr);
394 if (verdict == NET_DROP) {
395 goto drop;
396 }
397 return verdict;
398 #endif
399 case IPPROTO_TCP:
400 proto_hdr.tcp = net_tcp_input(pkt, &tcp_access);
401 if (proto_hdr.tcp) {
402 verdict = NET_OK;
403 }
404 break;
405 case IPPROTO_UDP:
406 proto_hdr.udp = net_udp_input(pkt, &udp_access);
407 if (proto_hdr.udp) {
408 verdict = NET_OK;
409 }
410 break;
411
412 #if defined(CONFIG_NET_L2_IPIP)
413 case IPPROTO_IPV6:
414 case IPPROTO_IPIP: {
415 struct sockaddr_in remote_addr = { 0 };
416 struct net_if *tunnel_iface;
417
418 remote_addr.sin_family = AF_INET;
419 net_ipv4_addr_copy_raw((uint8_t *)&remote_addr.sin_addr, hdr->src);
420
421 net_pkt_set_remote_address(pkt, (struct sockaddr *)&remote_addr,
422 sizeof(struct sockaddr_in));
423
424 /* Get rid of the old IP header */
425 net_pkt_cursor_restore(pkt, &hdr_start);
426 net_pkt_pull(pkt, net_pkt_ip_hdr_len(pkt) +
427 net_pkt_ipv4_opts_len(pkt));
428
429 tunnel_iface = net_ipip_get_virtual_interface(net_pkt_iface(pkt));
430 if (tunnel_iface != NULL && net_if_l2(tunnel_iface)->recv != NULL) {
431 return net_if_l2(tunnel_iface)->recv(net_pkt_iface(pkt), pkt);
432 }
433 }
434 #endif
435 }
436
437 if (verdict == NET_DROP) {
438 goto drop;
439 }
440
441 ip.ipv4 = hdr;
442
443 verdict = net_conn_input(pkt, &ip, hdr->proto, &proto_hdr);
444 if (verdict != NET_DROP) {
445 return verdict;
446 }
447
448 drop:
449 net_stats_update_ipv4_drop(net_pkt_iface(pkt));
450 return NET_DROP;
451 }
452
net_ipv4_prepare_for_send(struct net_pkt * pkt)453 enum net_verdict net_ipv4_prepare_for_send(struct net_pkt *pkt)
454 {
455 if (IS_ENABLED(CONFIG_NET_IPV4_PMTU)) {
456 struct net_pmtu_entry *entry;
457 struct sockaddr_in dst = {
458 .sin_family = AF_INET,
459 };
460 int ret;
461
462 net_ipv4_addr_copy_raw((uint8_t *)&dst.sin_addr,
463 NET_IPV4_HDR(pkt)->dst);
464 entry = net_pmtu_get_entry((struct sockaddr *)&dst);
465 if (entry == NULL) {
466 ret = net_pmtu_update_mtu((struct sockaddr *)&dst,
467 net_if_get_mtu(net_pkt_iface(pkt)));
468 if (ret < 0) {
469 NET_DBG("Cannot update PMTU for %s (%d)",
470 net_sprint_ipv4_addr(&dst.sin_addr),
471 ret);
472 }
473 }
474 }
475
476 #if defined(CONFIG_NET_IPV4_FRAGMENT)
477 return net_ipv4_prepare_for_send_fragment(pkt);
478 #else
479 return NET_OK;
480 #endif
481 }
482
net_ipv4_init(void)483 void net_ipv4_init(void)
484 {
485 if (IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT)) {
486 net_ipv4_setup_fragment_buffers();
487 }
488
489 if (IS_ENABLED(CONFIG_NET_IPV4_ACD)) {
490 net_ipv4_acd_init();
491 }
492 }
493