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