1 /** @file
2  @brief IPv4 related functions
3 
4  This is not to be included by the application.
5  */
6 
7 /*
8  * Copyright (c) 2016 Intel Corporation
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #ifndef __IPV4_H
14 #define __IPV4_H
15 
16 #include <zephyr/types.h>
17 
18 #include <zephyr/net/net_ip.h>
19 #include <zephyr/net/net_pkt.h>
20 #include <zephyr/net/net_if.h>
21 #include <zephyr/net/net_context.h>
22 
23 #define NET_IPV4_IHL_MASK 0x0F
24 #define NET_IPV4_DSCP_MASK 0xFC
25 #define NET_IPV4_DSCP_OFFSET 2
26 #define NET_IPV4_ECN_MASK 0x03
27 
28 /* IPv4 DiffServ code points (DSCP) for Assured Forwarding (AF) group.
29  * See https://tools.ietf.org/html/rfc2597
30  *     https://en.wikipedia.org/wiki/Differentiated_services
31  */
32 /* Drop probability low */
33 #define NET_IPV4_DSCP_AF11 10 /* 001010 */ /* Class 1 */
34 #define NET_IPV4_DSCP_AF21 18 /* 010010 */ /* Class 2 */
35 #define NET_IPV4_DSCP_AF31 26 /* 011010 */ /* Class 3 */
36 #define NET_IPV4_DSCP_AF41 34 /* 100010 */ /* Class 4 */
37 /* Drop probability medium */
38 #define NET_IPV4_DSCP_AF12 12 /* 001100 */ /* Class 1 */
39 #define NET_IPV4_DSCP_AF22 20 /* 010100 */ /* Class 2 */
40 #define NET_IPV4_DSCP_AF32 28 /* 011100 */ /* Class 3 */
41 #define NET_IPV4_DSCP_AF42 36 /* 100100 */ /* Class 4 */
42 /* Drop probability high */
43 #define NET_IPV4_DSCP_AF13 14 /* 001110 */ /* Class 1 */
44 #define NET_IPV4_DSCP_AF23 22 /* 010110 */ /* Class 2 */
45 #define NET_IPV4_DSCP_AF33 30 /* 011110 */ /* Class 3 */
46 #define NET_IPV4_DSCP_AF43 38 /* 100110 */ /* Class 4 */
47 
48 /* IPv4 Options */
49 #define NET_IPV4_OPTS_EO   0   /* End of Options */
50 #define NET_IPV4_OPTS_NOP  1   /* No operation */
51 #define NET_IPV4_OPTS_RR   7   /* Record Route */
52 #define NET_IPV4_OPTS_TS   68  /* Timestamp */
53 #define NET_IPV4_OPTS_RA   148 /* Router Alert */
54 
55 /* IPv4 Options Timestamp flags */
56 #define NET_IPV4_TS_OPT_TS_ONLY	0 /* Timestamp only */
57 #define NET_IPV4_TS_OPT_TS_ADDR	1 /* Timestamp and address */
58 #define NET_IPV4_TS_OPT_TS_PRES	3 /* Timestamp prespecified hops*/
59 
60 #define NET_IPV4_HDR_OPTNS_MAX_LEN 40
61 
62 /* Fragment bits */
63 #define NET_IPV4_MF BIT(0) /* More fragments  */
64 #define NET_IPV4_DF BIT(1) /* Do not fragment */
65 
66 #define NET_IPV4_IGMP_QUERY     0x11 /* Membership query     */
67 #define NET_IPV4_IGMP_REPORT_V1 0x12 /* v1 Membership report */
68 #define NET_IPV4_IGMP_REPORT_V2 0x16 /* v2 Membership report */
69 #define NET_IPV4_IGMP_LEAVE     0x17 /* v2 Leave group       */
70 #define NET_IPV4_IGMP_REPORT_V3 0x22 /* v3 Membership report */
71 
72 struct net_ipv4_igmp_v2_query {
73 	/* IGMP message type */
74 	uint8_t type;
75 	/* Max response code */
76 	uint8_t max_rsp;
77 	/* 16-bit ones' complement of the entire message */
78 	uint16_t chksum;
79 	/* The multicast address being queried */
80 	struct in_addr address;
81 } __packed;
82 
83 struct net_ipv4_igmp_v2_report {
84 	/* IGMP message type */
85 	uint8_t type;
86 	/* Max response code */
87 	uint8_t max_rsp;
88 	/* 16-bit ones' complement of the entire message */
89 	uint16_t chksum;
90 	/* The multicast address being queried */
91 	struct in_addr address;
92 } __packed;
93 
94 struct net_ipv4_igmp_v3_query {
95 	/* IGMP message type */
96 	uint8_t type;
97 	/* Max response code */
98 	uint8_t max_rsp;
99 	/* 16-bit ones' complement of the entire message */
100 	uint16_t chksum;
101 	/* The multicast address being queried */
102 	struct in_addr address;
103 	/* Reserved field, ignore */
104 	uint8_t reserved: 4;
105 	/* Suppress Router-side Processing Flag */
106 	uint8_t suppress: 1;
107 	/* Querier's Robustness Variable */
108 	uint8_t qrv: 3;
109 	/* Querier's Query Interval Code */
110 	uint8_t qqic;
111 	/* Number of Source Addresses */
112 	uint16_t sources_len;
113 } __packed;
114 
115 struct net_ipv4_igmp_v3_group_record {
116 	/* Record type */
117 	uint8_t type;
118 	/* Aux Data Len */
119 	uint8_t aux_len;
120 	/* Number of Source Addresses */
121 	uint16_t sources_len;
122 	/* The multicast address to report to*/
123 	struct in_addr address;
124 } __packed;
125 
126 struct net_ipv4_igmp_v3_report {
127 	/* IGMP message type */
128 	uint8_t type;
129 	/* Reserved field, ignore */
130 	uint8_t reserved_1;
131 	/* 16-bit ones' complement of the entire message */
132 	uint16_t chksum;
133 	/* Reserved field, ignore */
134 	uint16_t reserved_2;
135 	/* Number of Group Records */
136 	uint16_t groups_len;
137 } __packed;
138 
139 /**
140  * @brief Create IPv4 packet in provided net_pkt with option to set all the
141  *        caller settable values.
142  *
143  * @param pkt Network packet
144  * @param src Source IPv4 address
145  * @param dst Destination IPv4 address
146  * @param tos Type of service
147  * @param id Fragment id
148  * @param flags Fragmentation flags
149  * @param offset Fragment offset
150  *
151  * @return 0 on success, negative errno otherwise.
152  */
153 #if defined(CONFIG_NET_NATIVE_IPV4)
154 int net_ipv4_create_full(struct net_pkt *pkt,
155 			 const struct in_addr *src,
156 			 const struct in_addr *dst,
157 			 uint8_t tos,
158 			 uint16_t id,
159 			 uint8_t flags,
160 			 uint16_t offset);
161 #else
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)162 static inline int net_ipv4_create_full(struct net_pkt *pkt,
163 				       const struct in_addr *src,
164 				       const struct in_addr *dst,
165 				       uint8_t tos,
166 				       uint16_t id,
167 				       uint8_t flags,
168 				       uint16_t offset)
169 {
170 	ARG_UNUSED(pkt);
171 	ARG_UNUSED(src);
172 	ARG_UNUSED(dst);
173 	ARG_UNUSED(tos);
174 	ARG_UNUSED(id);
175 	ARG_UNUSED(flags);
176 	ARG_UNUSED(offset);
177 
178 	return -ENOTSUP;
179 }
180 #endif
181 
182 /**
183  * @brief Create IPv4 packet in provided net_pkt.
184  *
185  * @param pkt Network packet
186  * @param src Source IPv4 address
187  * @param dst Destination IPv4 address
188  *
189  * @return 0 on success, negative errno otherwise.
190  */
191 #if defined(CONFIG_NET_NATIVE_IPV4)
192 int net_ipv4_create(struct net_pkt *pkt,
193 		    const struct in_addr *src,
194 		    const struct in_addr *dst);
195 #else
net_ipv4_create(struct net_pkt * pkt,const struct in_addr * src,const struct in_addr * dst)196 static inline int net_ipv4_create(struct net_pkt *pkt,
197 				  const struct in_addr *src,
198 				  const struct in_addr *dst)
199 {
200 	ARG_UNUSED(pkt);
201 	ARG_UNUSED(src);
202 	ARG_UNUSED(dst);
203 
204 	return -ENOTSUP;
205 }
206 #endif
207 
208 /**
209  * @brief Finalize IPv4 packet. It should be called right before
210  * sending the packet and after all the data has been added into
211  * the packet. This function will set the length of the
212  * packet and calculate the higher protocol checksum if needed.
213  *
214  * @param pkt Network packet
215  * @param next_header_proto Protocol type of the next header after IPv4 header.
216  *
217  * @return 0 on success, negative errno otherwise.
218  */
219 #if defined(CONFIG_NET_NATIVE_IPV4)
220 int net_ipv4_finalize(struct net_pkt *pkt, uint8_t next_header_proto);
221 #else
net_ipv4_finalize(struct net_pkt * pkt,uint8_t next_header_proto)222 static inline int net_ipv4_finalize(struct net_pkt *pkt,
223 				    uint8_t next_header_proto)
224 {
225 	ARG_UNUSED(pkt);
226 	ARG_UNUSED(next_header_proto);
227 
228 	return -ENOTSUP;
229 }
230 #endif
231 
232 /**
233  * @typedef net_ipv4_parse_hdr_options_cb_t
234  * @brief IPv4 header options handle callback
235  *
236  * @details The callback is called when parser encounter
237  * supported options.
238  *
239  * @param opt_type Option type
240  * @param opt_data Option data
241  * @param opt_len Option length
242  * @param user_data Userdata given in net_ipv4_parse_hdr_options()
243  *
244  * @return 0 on success, negative otherwise.
245  */
246 typedef int (*net_ipv4_parse_hdr_options_cb_t)(uint8_t opt_type,
247 					       uint8_t *opt_data,
248 					       uint8_t opt_len,
249 					       void *user_data);
250 
251 /**
252  * @brief Parse IPv4 header options.
253  * Parse the IPv4 header options and call the callback with
254  * options type, data and length along with user_data.
255  *
256  * @param pkt Network packet
257  * @param cb callback to handle IPv4 header options
258  * @param user_data User data
259  *
260  * @return 0 on success, negative otherwise.
261  */
262 #if defined(CONFIG_NET_IPV4_HDR_OPTIONS)
263 int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
264 			       net_ipv4_parse_hdr_options_cb_t cb,
265 			       void *user_data);
266 #else
net_ipv4_parse_hdr_options(struct net_pkt * pkt,net_ipv4_parse_hdr_options_cb_t cb,void * user_data)267 static inline int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
268 					     net_ipv4_parse_hdr_options_cb_t cb,
269 					     void *user_data)
270 {
271 	ARG_UNUSED(pkt);
272 	ARG_UNUSED(cb);
273 	ARG_UNUSED(user_data);
274 
275 	return -ENOTSUP;
276 }
277 #endif
278 
279 /**
280  * @brief Decode DSCP value from ToS field.
281  *
282  * @param tos ToS field value from the IPv4 header.
283  *
284  * @return Decoded DSCP value.
285  */
net_ipv4_get_dscp(uint8_t tos)286 static inline uint8_t net_ipv4_get_dscp(uint8_t tos)
287 {
288 	return (tos & NET_IPV4_DSCP_MASK) >> NET_IPV4_DSCP_OFFSET;
289 }
290 
291 /**
292  * @brief Encode DSCP value into ToS field.
293  *
294  * @param tos A pointer to the ToS field.
295  * @param dscp DSCP value to set.
296  */
net_ipv4_set_dscp(uint8_t * tos,uint8_t dscp)297 static inline void net_ipv4_set_dscp(uint8_t *tos, uint8_t dscp)
298 {
299 	*tos &= ~NET_IPV4_DSCP_MASK;
300 	*tos |= (dscp << NET_IPV4_DSCP_OFFSET) & NET_IPV4_DSCP_MASK;
301 }
302 
303 /**
304  * @brief Convert DSCP value to priority.
305  *
306  * @param dscp DSCP value.
307  */
net_ipv4_dscp_to_priority(uint8_t dscp)308 static inline uint8_t net_ipv4_dscp_to_priority(uint8_t dscp)
309 {
310 	return dscp >> 3;
311 }
312 
313 /**
314  * @brief Decode ECN value from ToS field.
315  *
316  * @param tos ToS field value from the IPv4 header.
317  *
318  * @return Decoded ECN value.
319  */
net_ipv4_get_ecn(uint8_t tos)320 static inline uint8_t net_ipv4_get_ecn(uint8_t tos)
321 {
322 	return tos & NET_IPV4_ECN_MASK;
323 }
324 
325 /**
326  * @brief Encode ECN value into ToS field.
327  *
328  * @param tos A pointer to the ToS field.
329  * @param ecn ECN value to set.
330  */
net_ipv4_set_ecn(uint8_t * tos,uint8_t ecn)331 static inline void net_ipv4_set_ecn(uint8_t *tos, uint8_t ecn)
332 {
333 	*tos &= ~NET_IPV4_ECN_MASK;
334 	*tos |= ecn & NET_IPV4_ECN_MASK;
335 }
336 
337 #if defined(CONFIG_NET_IPV4_FRAGMENT)
338 /** Store pending IPv4 fragment information that is needed for reassembly. */
339 struct net_ipv4_reassembly {
340 	/** IPv4 source address of the fragment */
341 	struct in_addr src;
342 
343 	/** IPv4 destination address of the fragment */
344 	struct in_addr dst;
345 
346 	/**
347 	 * Timeout for cancelling the reassembly. The timer is used
348 	 * also to detect if this reassembly slot is used or not.
349 	 */
350 	struct k_work_delayable timer;
351 
352 	/** Pointers to pending fragments */
353 	struct net_pkt *pkt[CONFIG_NET_IPV4_FRAGMENT_MAX_PKT];
354 
355 	/** IPv4 fragment identification */
356 	uint16_t id;
357 	uint8_t protocol;
358 };
359 #else
360 struct net_ipv4_reassembly;
361 #endif
362 
363 /**
364  * @typedef net_ipv4_frag_cb_t
365  * @brief Callback used while iterating over pending IPv4 fragments.
366  *
367  * @param reass IPv4 fragment reassembly struct
368  * @param user_data A valid pointer on some user data or NULL
369  */
370 typedef void (*net_ipv4_frag_cb_t)(struct net_ipv4_reassembly *reass, void *user_data);
371 
372 /**
373  * @brief Go through all the currently pending IPv4 fragments.
374  *
375  * @param cb Callback to call for each pending IPv4 fragment.
376  * @param user_data User specified data or NULL.
377  */
378 void net_ipv4_frag_foreach(net_ipv4_frag_cb_t cb, void *user_data);
379 
380 /**
381  * @brief Prepare packet for sending, this will split up a packet that is too large to send into
382  * multiple fragments so that it can be sent. It will also update PMTU destination cache if it
383  * is enabled.
384  *
385  * @param pkt Network packet
386  *
387  * @return Return verdict about the packet.
388  */
389 enum net_verdict net_ipv4_prepare_for_send(struct net_pkt *pkt);
390 
391 #if defined(CONFIG_NET_NATIVE_IPV4)
392 /**
393  * @brief Initialises IPv4
394  */
395 void net_ipv4_init(void);
396 
397 /**
398  * @brief Handles IPv4 fragmented packets.
399  *
400  * @param pkt     Network head packet.
401  * @param hdr     The IPv4 header of the current packet
402  *
403  * @return Return verdict about the packet.
404  */
405 #if defined(CONFIG_NET_IPV4_FRAGMENT)
406 enum net_verdict net_ipv4_handle_fragment_hdr(struct net_pkt *pkt, struct net_ipv4_hdr *hdr);
407 #else
net_ipv4_handle_fragment_hdr(struct net_pkt * pkt,struct net_ipv4_hdr * hdr)408 static inline enum net_verdict net_ipv4_handle_fragment_hdr(struct net_pkt *pkt,
409 							    struct net_ipv4_hdr *hdr)
410 {
411 	ARG_UNUSED(pkt);
412 	ARG_UNUSED(hdr);
413 
414 	return NET_DROP;
415 }
416 #endif /* CONFIG_NET_IPV4_FRAGMENT */
417 
418 #if defined(CONFIG_NET_IPV4_FRAGMENT)
419 enum net_verdict net_ipv4_prepare_for_send_fragment(struct net_pkt *pkt);
420 #endif
421 
422 /**
423  * @brief Sets up fragment buffers for usage, should only be called by the SYS_INIT() handler in
424  * net_core.c
425  */
426 #if defined(CONFIG_NET_IPV4_FRAGMENT)
427 void net_ipv4_setup_fragment_buffers(void);
428 #else
net_ipv4_setup_fragment_buffers(void)429 static inline void net_ipv4_setup_fragment_buffers(void)
430 {
431 }
432 #endif /* CONFIG_NET_IPV4_FRAGMENT */
433 #else
434 #define net_ipv4_init(...)
435 #endif /* CONFIG_NET_NATIVE_IPV4 */
436 
437 /**
438  * @brief Starts address conflict detection for an IPv4 address.
439  *
440  * @param iface Network interface the address belongs to.
441  * @param ifaddr IPv4 address to probe.
442  *
443  * @return 0 on success, negative otherwise.
444  */
445 int net_ipv4_acd_start(struct net_if *iface, struct net_if_addr *ifaddr);
446 
447 /**
448  * @brief Cancel address conflict detection for an IPv4 address.
449  *
450  * @param iface Network interface the address belongs to.
451  * @param ifaddr IPv4 address to probe.
452  */
453 void net_ipv4_acd_cancel(struct net_if *iface, struct net_if_addr *ifaddr);
454 
455 /**
456  * @brief Notify no conflict was detected for an IPv4 address.
457  *
458  * @param iface Network interface the address belongs to.
459  * @param ifaddr IPv4 address.
460  */
461 void net_if_ipv4_acd_succeeded(struct net_if *iface, struct net_if_addr *ifaddr);
462 
463 /**
464  * @brief Notify conflict for an IPv4 address.
465  *
466  * @param iface Network interface the address belongs to.
467  * @param ifaddr IPv4 address.
468  */
469 void net_if_ipv4_acd_failed(struct net_if *iface, struct net_if_addr *ifaddr);
470 
471 /**
472  * @brief Initialize IPv4 address conflict detection module.
473  */
474 void net_ipv4_acd_init(void);
475 
476 /**
477  * @brief Process ARP packet in terms of conflict detection.
478  *
479  * @param iface Network interface the packet was received on.
480  * @param pkt ARP packet to process.
481  *
482  * @return Return verdict about the packet.
483  */
484 enum net_verdict net_ipv4_acd_input(struct net_if *iface, struct net_pkt *pkt);
485 
486 #endif /* __IPV4_H */
487