/** @file @brief IPv4 related functions This is not to be included by the application. */ /* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #ifndef __IPV4_H #define __IPV4_H #include #include #include #include #include #define NET_IPV4_IHL_MASK 0x0F #define NET_IPV4_DSCP_MASK 0xFC #define NET_IPV4_DSCP_OFFSET 2 #define NET_IPV4_ECN_MASK 0x03 /* IPv4 Options */ #define NET_IPV4_OPTS_EO 0 /* End of Options */ #define NET_IPV4_OPTS_NOP 1 /* No operation */ #define NET_IPV4_OPTS_RR 7 /* Record Route */ #define NET_IPV4_OPTS_TS 68 /* Timestamp */ #define NET_IPV4_OPTS_RA 148 /* Router Alert */ /* IPv4 Options Timestamp flags */ #define NET_IPV4_TS_OPT_TS_ONLY 0 /* Timestamp only */ #define NET_IPV4_TS_OPT_TS_ADDR 1 /* Timestamp and address */ #define NET_IPV4_TS_OPT_TS_PRES 3 /* Timestamp prespecified hops*/ #define NET_IPV4_HDR_OPTNS_MAX_LEN 40 /* Fragment bits */ #define NET_IPV4_MF BIT(0) /* More fragments */ #define NET_IPV4_DF BIT(1) /* Do not fragment */ #define NET_IPV4_IGMP_QUERY 0x11 /* Membership query */ #define NET_IPV4_IGMP_REPORT_V1 0x12 /* v1 Membership report */ #define NET_IPV4_IGMP_REPORT_V2 0x16 /* v2 Membership report */ #define NET_IPV4_IGMP_LEAVE 0x17 /* v2 Leave group */ #define NET_IPV4_IGMP_REPORT_V3 0x22 /* v3 Membership report */ struct net_ipv4_igmp_v2_query { /* IGMP message type */ uint8_t type; /* Max response code */ uint8_t max_rsp; /* 16-bit ones' complement of the entire message */ uint16_t chksum; /* The multicast address being queried */ struct in_addr address; } __packed; struct net_ipv4_igmp_v2_report { /* IGMP message type */ uint8_t type; /* Max response code */ uint8_t max_rsp; /* 16-bit ones' complement of the entire message */ uint16_t chksum; /* The multicast address being queried */ struct in_addr address; } __packed; struct net_ipv4_igmp_v3_query { /* IGMP message type */ uint8_t type; /* Max response code */ uint8_t max_rsp; /* 16-bit ones' complement of the entire message */ uint16_t chksum; /* The multicast address being queried */ struct in_addr address; /* Reserved field, ignore */ uint8_t reserved: 4; /* Suppress Router-side Processing Flag */ uint8_t suppress: 1; /* Querier's Robustness Variable */ uint8_t qrv: 3; /* Querier's Query Interval Code */ uint8_t qqic; /* Number of Source Addresses */ uint16_t sources_len; } __packed; struct net_ipv4_igmp_v3_group_record { /* Record type */ uint8_t type; /* Aux Data Len */ uint8_t aux_len; /* Number of Source Addresses */ uint16_t sources_len; /* The multicast address to report to*/ struct in_addr address; } __packed; struct net_ipv4_igmp_v3_report { /* IGMP message type */ uint8_t type; /* Reserved field, ignore */ uint8_t reserved_1; /* 16-bit ones' complement of the entire message */ uint16_t chksum; /* Reserved field, ignore */ uint16_t reserved_2; /* Number of Group Records */ uint16_t groups_len; } __packed; /** * @brief Create IPv4 packet in provided net_pkt with option to set all the * caller settable values. * * @param pkt Network packet * @param src Source IPv4 address * @param dst Destination IPv4 address * @param tos Type of service * @param id Fragment id * @param flags Fragmentation flags * @param offset Fragment offset * * @return 0 on success, negative errno otherwise. */ #if defined(CONFIG_NET_NATIVE_IPV4) int 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); #else static inline int 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) { ARG_UNUSED(pkt); ARG_UNUSED(src); ARG_UNUSED(dst); ARG_UNUSED(tos); ARG_UNUSED(id); ARG_UNUSED(flags); ARG_UNUSED(offset); return -ENOTSUP; } #endif /** * @brief Create IPv4 packet in provided net_pkt. * * @param pkt Network packet * @param src Source IPv4 address * @param dst Destination IPv4 address * * @return 0 on success, negative errno otherwise. */ #if defined(CONFIG_NET_NATIVE_IPV4) int net_ipv4_create(struct net_pkt *pkt, const struct in_addr *src, const struct in_addr *dst); #else static inline int net_ipv4_create(struct net_pkt *pkt, const struct in_addr *src, const struct in_addr *dst) { ARG_UNUSED(pkt); ARG_UNUSED(src); ARG_UNUSED(dst); return -ENOTSUP; } #endif /** * @brief Finalize IPv4 packet. It should be called right before * sending the packet and after all the data has been added into * the packet. This function will set the length of the * packet and calculate the higher protocol checksum if needed. * * @param pkt Network packet * @param next_header_proto Protocol type of the next header after IPv4 header. * * @return 0 on success, negative errno otherwise. */ #if defined(CONFIG_NET_NATIVE_IPV4) int net_ipv4_finalize(struct net_pkt *pkt, uint8_t next_header_proto); #else static inline int net_ipv4_finalize(struct net_pkt *pkt, uint8_t next_header_proto) { ARG_UNUSED(pkt); ARG_UNUSED(next_header_proto); return -ENOTSUP; } #endif /** * @typedef net_ipv4_parse_hdr_options_cb_t * @brief IPv4 header options handle callback * * @details The callback is called when parser encounter * supported options. * * @param opt_type Option type * @param opt_data Option data * @param opt_len Option length * @param user_data Userdata given in net_ipv4_parse_hdr_options() * * @return 0 on success, negative otherwise. */ typedef int (*net_ipv4_parse_hdr_options_cb_t)(uint8_t opt_type, uint8_t *opt_data, uint8_t opt_len, void *user_data); /** * @brief Parse IPv4 header options. * Parse the IPv4 header options and call the callback with * options type, data and length along with user_data. * * @param pkt Network packet * @param cb callback to handle IPv4 header options * @param user_data User data * * @return 0 on success, negative otherwise. */ #if defined(CONFIG_NET_IPV4_HDR_OPTIONS) int net_ipv4_parse_hdr_options(struct net_pkt *pkt, net_ipv4_parse_hdr_options_cb_t cb, void *user_data); #else static inline int net_ipv4_parse_hdr_options(struct net_pkt *pkt, net_ipv4_parse_hdr_options_cb_t cb, void *user_data) { ARG_UNUSED(pkt); ARG_UNUSED(cb); ARG_UNUSED(user_data); return -ENOTSUP; } #endif /** * @brief Decode DSCP value from ToS field. * * @param tos ToS field value from the IPv4 header. * * @return Decoded DSCP value. */ static inline uint8_t net_ipv4_get_dscp(uint8_t tos) { return (tos & NET_IPV4_DSCP_MASK) >> NET_IPV4_DSCP_OFFSET; } /** * @brief Encode DSCP value into ToS field. * * @param tos A pointer to the ToS field. * @param dscp DSCP value to set. */ static inline void net_ipv4_set_dscp(uint8_t *tos, uint8_t dscp) { *tos &= ~NET_IPV4_DSCP_MASK; *tos |= (dscp << NET_IPV4_DSCP_OFFSET) & NET_IPV4_DSCP_MASK; } /** * @brief Convert DSCP value to priority. * * @param dscp DSCP value. */ static inline uint8_t net_ipv4_dscp_to_priority(uint8_t dscp) { return dscp >> 3; } /** * @brief Decode ECN value from ToS field. * * @param tos ToS field value from the IPv4 header. * * @return Decoded ECN value. */ static inline uint8_t net_ipv4_get_ecn(uint8_t tos) { return tos & NET_IPV4_ECN_MASK; } /** * @brief Encode ECN value into ToS field. * * @param tos A pointer to the ToS field. * @param ecn ECN value to set. */ static inline void net_ipv4_set_ecn(uint8_t *tos, uint8_t ecn) { *tos &= ~NET_IPV4_ECN_MASK; *tos |= ecn & NET_IPV4_ECN_MASK; } #if defined(CONFIG_NET_IPV4_FRAGMENT) /** Store pending IPv4 fragment information that is needed for reassembly. */ struct net_ipv4_reassembly { /** IPv4 source address of the fragment */ struct in_addr src; /** IPv4 destination address of the fragment */ struct in_addr dst; /** * Timeout for cancelling the reassembly. The timer is used * also to detect if this reassembly slot is used or not. */ struct k_work_delayable timer; /** Pointers to pending fragments */ struct net_pkt *pkt[CONFIG_NET_IPV4_FRAGMENT_MAX_PKT]; /** IPv4 fragment identification */ uint16_t id; uint8_t protocol; }; #else struct net_ipv4_reassembly; #endif /** * @typedef net_ipv4_frag_cb_t * @brief Callback used while iterating over pending IPv4 fragments. * * @param reass IPv4 fragment reassembly struct * @param user_data A valid pointer on some user data or NULL */ typedef void (*net_ipv4_frag_cb_t)(struct net_ipv4_reassembly *reass, void *user_data); /** * @brief Go through all the currently pending IPv4 fragments. * * @param cb Callback to call for each pending IPv4 fragment. * @param user_data User specified data or NULL. */ void net_ipv4_frag_foreach(net_ipv4_frag_cb_t cb, void *user_data); #if defined(CONFIG_NET_NATIVE_IPV4) /** * @brief Initialises IPv4 */ void net_ipv4_init(void); /** * @brief Handles IPv4 fragmented packets. * * @param pkt Network head packet. * @param hdr The IPv4 header of the current packet * * @return Return verdict about the packet. */ #if defined(CONFIG_NET_IPV4_FRAGMENT) enum net_verdict net_ipv4_handle_fragment_hdr(struct net_pkt *pkt, struct net_ipv4_hdr *hdr); #else static inline enum net_verdict net_ipv4_handle_fragment_hdr(struct net_pkt *pkt, struct net_ipv4_hdr *hdr) { ARG_UNUSED(pkt); ARG_UNUSED(hdr); return NET_DROP; } #endif /* CONFIG_NET_IPV4_FRAGMENT */ /** * @brief Prepare packet for sending, this will split up a packet that is too large to send into * multiple fragments so that it can be sent. * * @param pkt Network packet * * @return Return verdict about the packet. */ #if defined(CONFIG_NET_IPV4_FRAGMENT) enum net_verdict net_ipv4_prepare_for_send(struct net_pkt *pkt); #else static inline enum net_verdict net_ipv4_prepare_for_send(struct net_pkt *pkt) { return NET_OK; } #endif /* CONFIG_NET_IPV4_FRAGMENT */ /** * @brief Sets up fragment buffers for usage, should only be called by the SYS_INIT() handler in * net_core.c */ #if defined(CONFIG_NET_IPV4_FRAGMENT) void net_ipv4_setup_fragment_buffers(void); #else static inline void net_ipv4_setup_fragment_buffers(void) { } #endif /* CONFIG_NET_IPV4_FRAGMENT */ #else #define net_ipv4_init(...) #endif /* CONFIG_NET_NATIVE_IPV4 */ /** * @brief Starts address conflict detection for an IPv4 address. * * @param iface Network interface the address belongs to. * @param ifaddr IPv4 address to probe. * * @return 0 on success, negative otherwise. */ int net_ipv4_acd_start(struct net_if *iface, struct net_if_addr *ifaddr); /** * @brief Cancel address conflict detection for an IPv4 address. * * @param iface Network interface the address belongs to. * @param ifaddr IPv4 address to probe. */ void net_ipv4_acd_cancel(struct net_if *iface, struct net_if_addr *ifaddr); /** * @brief Notify no conflict was detected for an IPv4 address. * * @param iface Network interface the address belongs to. * @param ifaddr IPv4 address. */ void net_if_ipv4_acd_succeeded(struct net_if *iface, struct net_if_addr *ifaddr); /** * @brief Notify conflict for an IPv4 address. * * @param iface Network interface the address belongs to. * @param ifaddr IPv4 address. */ void net_if_ipv4_acd_failed(struct net_if *iface, struct net_if_addr *ifaddr); /** * @brief Initialize IPv4 address conflict detection module. */ void net_ipv4_acd_init(void); /** * @brief Process ARP packet in terms of conflict detection. * * @param iface Network interface the packet was received on. * @param pkt ARP packet to process. * * @return Return verdict about the packet. */ enum net_verdict net_ipv4_acd_input(struct net_if *iface, struct net_pkt *pkt); #endif /* __IPV4_H */