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