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 #endif /* __IPV4_H */
420