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