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