aboutsummaryrefslogtreecommitdiff
path: root/helper/include/odp/helper/ip.h
blob: 91776fad61812698edb891234e5492bf2501e16b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/* Copyright (c) 2014, Linaro Limited
 * All rights reserved.
 *
 * SPDX-License-Identifier:     BSD-3-Clause
 */

/**
 * @file
 *
 * ODP IP header
 */

#ifndef ODPH_IP_H_
#define ODPH_IP_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <odp_api.h>
#include <odp/helper/chksum.h>

#include <string.h>

/** @addtogroup odph_header ODPH HEADER
 *  @{
 */

#define ODPH_IPV4             4  /**< IP version 4 */
#define ODPH_IPV4HDR_LEN     20  /**< Min length of IP header (no options) */
#define ODPH_IPV4HDR_IHL_MIN  5  /**< Minimum IHL value*/
#define ODPH_IPV4ADDR_LEN     4  /**< IPv4 address length in bytes */

/** The one byte IPv4 tos or IPv6 tc field is composed of the following two
 * subfields - a six bit Differentiated Service Code Point (DSCP) and a two
 * bit Explicit Congestion Notification (ECN) subfield.  The following
 * constants can be used to extract or modify these fields.  Despite the
 * name prefix being ODPH_IP_TOS_* these constants apply equally well for
 * the IPv6 Traffic Class (tc) field.
 */
#define ODPH_IP_TOS_MAX_DSCP   63    /**< 6-bit DSCP field has max value 63  */
#define ODPH_IP_TOS_DSCP_MASK  0xFC  /**< DSCP field is in bits <7:2>  */
#define ODPH_IP_TOS_DSCP_SHIFT 2     /**< DSCP field is shifted letf by 2  */
#define ODPH_IP_TOS_MAX_ECN    3     /**< 2-bit ECN field has max value 3  */
#define ODPH_IP_TOS_ECN_MASK   0x03  /**< ECN field is in bits <1:0>  */
#define ODPH_IP_TOS_ECN_SHIFT  0     /**< ECN field is not shifted.  */

/** The following constants give names to the four possible ECN values,
 * as described in RFC 3168.
 */
#define ODPH_IP_ECN_NOT_ECT  0  /**< 0 indicates not participating in ECN */
#define ODPH_IP_ECN_ECT1     1  /**< Indicates no congestion seen yet */
#define ODPH_IP_ECN_ECT0     2  /**< Indicates no congestion seen yet */
#define ODPH_IP_ECN_CE       3  /**< Used to signal Congestion Experienced */

/** @internal Returns IPv4 version */
#define ODPH_IPV4HDR_VER(ver_ihl) (((ver_ihl) & 0xf0) >> 4)

/** @internal Returns IPv4 header length */
#define ODPH_IPV4HDR_IHL(ver_ihl) ((ver_ihl) & 0x0f)

/** @internal Returns IPv4 DSCP */
#define ODPH_IPV4HDR_DSCP(tos) (((tos) & 0xfc) >> 2)

/** @internal Returns IPv4 Don't fragment */
#define ODPH_IPV4HDR_FLAGS_DONT_FRAG(frag_offset)  ((frag_offset) & 0x4000)

/** @internal Returns IPv4 more fragments */
#define ODPH_IPV4HDR_FLAGS_MORE_FRAGS(frag_offset)  ((frag_offset) & 0x2000)

/** @internal Returns IPv4 fragment offset */
#define ODPH_IPV4HDR_FRAG_OFFSET(frag_offset) ((frag_offset) & 0x1fff)

/** @internal Returns true if IPv4 packet is a fragment */
#define ODPH_IPV4HDR_IS_FRAGMENT(frag_offset) ((frag_offset) & 0x3fff)

/** IPv4 header */
typedef struct ODP_PACKED {
	uint8_t    ver_ihl;     /**< Version / Header length */
	uint8_t    tos;         /**< Type of service */
	odp_u16be_t tot_len;    /**< Total length */
	odp_u16be_t id;         /**< ID */
	odp_u16be_t frag_offset;/**< Fragmentation offset */
	uint8_t    ttl;         /**< Time to live */
	uint8_t    proto;       /**< Protocol */
	odp_u16sum_t chksum;    /**< Checksum */
	odp_u32be_t src_addr;   /**< Source address */
	odp_u32be_t dst_addr;   /**< Destination address */
} odph_ipv4hdr_t;

/** @internal Compile time assert */
ODP_STATIC_ASSERT(sizeof(odph_ipv4hdr_t) == ODPH_IPV4HDR_LEN,
		  "ODPH_IPV4HDR_T__SIZE_ERROR");

/**
 * Check if IPv4 checksum is valid
 *
 * @param pkt  ODP packet
 *
 * @return 1 if checksum is valid, otherwise 0
 */
static inline int odph_ipv4_csum_valid(odp_packet_t pkt)
{
	uint32_t offset;
	odp_u16be_t res = 0;
	uint16_t *w;
	int nleft = sizeof(odph_ipv4hdr_t);
	odph_ipv4hdr_t ip;
	odp_u16be_t chksum;

	offset = odp_packet_l3_offset(pkt);
	if (offset == ODP_PACKET_OFFSET_INVALID)
		return 0;

	odp_packet_copy_to_mem(pkt, offset, sizeof(odph_ipv4hdr_t), &ip);

	w = (uint16_t *)(void *)&ip;
	chksum = ip.chksum;
	ip.chksum = 0x0;

	res = odph_chksum(w, nleft);
	return (res == chksum) ? 1 : 0;
}

/**
 * Calculate and fill in IPv4 checksum
 *
 * @note when using this api to populate data destined for the wire
 * odp_cpu_to_be_16() can be used to remove sparse warnings
 *
 * @param pkt  ODP packet
 *
 * @return IPv4 checksum in host cpu order, or 0 on failure
 */
static inline odp_u16sum_t odph_ipv4_csum_update(odp_packet_t pkt)
{
	uint16_t *w;
	odph_ipv4hdr_t *ip;
	int nleft = sizeof(odph_ipv4hdr_t);

	ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
	if (ip == NULL)
		return 0;

	w = (uint16_t *)(void *)ip;
	ip->chksum = odph_chksum(w, nleft);
	return ip->chksum;
}

/** IPv6 version */
#define ODPH_IPV6 6

/** IPv6 header length */
#define ODPH_IPV6HDR_LEN 40

/** IPv6 address length in bytes */
#define ODPH_IPV6ADDR_LEN 16

/** The following constants can be used to access the three subfields
 * of the 4 byte ver_tc_flow field - namely the four bit Version subfield,
 * the eight bit Traffic Class subfield (TC) and the twenty bit Flow Label
 * subfield.  Note that the IPv6 TC field is analogous to the IPv4 TOS
 * field and is composed of the DSCP and ECN subfields.  Use the ODPH_IP_TOS_*
 * constants above to access these subfields.
 */
#define ODPH_IPV6HDR_VERSION_MASK     0xF0000000 /**< Version field bit mask */
#define ODPH_IPV6HDR_VERSION_SHIFT    28         /**< Version field shift */
#define ODPH_IPV6HDR_TC_MASK          0x0FF00000 /**< TC field bit mask */
#define ODPH_IPV6HDR_TC_SHIFT         20         /**< TC field shift */
#define ODPH_IPV6HDR_FLOW_LABEL_MASK  0x000FFFFF /**< Flow Label bit mask */
#define ODPH_IPV6HDR_FLOW_LABEL_SHIFT 0          /**< Flow Label shift */

/** @internal Returns IPv6 DSCP */
#define ODPH_IPV6HDR_DSCP(ver_tc_flow) \
	(uint8_t)((((ver_tc_flow) & 0x0fc00000) >> 22) & 0xff)

/**
 * IPv6 header
 */
typedef struct ODP_PACKED {
	odp_u32be_t ver_tc_flow; /**< Version / Traffic class / Flow label */
	odp_u16be_t payload_len; /**< Payload length */
	uint8_t    next_hdr;     /**< Next header */
	uint8_t    hop_limit;    /**< Hop limit */
	uint8_t    src_addr[16]; /**< Source address */
	uint8_t    dst_addr[16]; /**< Destination address */
} odph_ipv6hdr_t;

/** @internal Compile time assert */
ODP_STATIC_ASSERT(sizeof(odph_ipv6hdr_t) == ODPH_IPV6HDR_LEN,
		  "ODPH_IPV6HDR_T__SIZE_ERROR");

/**
 * IPv6 Header extensions
 */
typedef struct ODP_PACKED {
	uint8_t    next_hdr;     /**< Protocol of next header */
	uint8_t    ext_len;      /**< Length of this extension in 8 byte units,
				    not counting first 8 bytes, so 0 = 8 bytes
				    1 = 16 bytes, etc. */
	uint8_t    filler[6];    /**< Fill out first 8 byte segment */
} odph_ipv6hdr_ext_t;

/** @name
 * IP protocol values (IPv4:'proto' or IPv6:'next_hdr')
 * @{*/
#define ODPH_IPPROTO_HOPOPTS 0x00 /**< IPv6 hop-by-hop options */
#define ODPH_IPPROTO_ICMPv4  0x01 /**< Internet Control Message Protocol (1) */
#define ODPH_IPPROTO_TCP     0x06 /**< Transmission Control Protocol (6) */
#define ODPH_IPPROTO_UDP     0x11 /**< User Datagram Protocol (17) */
#define ODPH_IPPROTO_ROUTE   0x2B /**< IPv6 Routing header (43) */
#define ODPH_IPPROTO_FRAG    0x2C /**< IPv6 Fragment (44) */
#define ODPH_IPPROTO_AH      0x33 /**< Authentication Header (51) */
#define ODPH_IPPROTO_ESP     0x32 /**< Encapsulating Security Payload (50) */
#define ODPH_IPPROTO_ICMPv6  0x3A /**< Internet Control Message Protocol (58) */
#define ODPH_IPPROTO_INVALID 0xFF /**< Reserved invalid by IANA */

/**@}*/

/**
 * Parse IPv4 address from a string
 *
 * Parses IPv4 address from the string which must be passed in the format of
 * four decimal digits delimited by dots (xxx.xxx.xxx.xxx). All four digits
 * have to be present and may have leading zeros. String does not have to be
 * NULL terminated. The address is written only when successful. The address
 * byte order is CPU native.
 *
 * @param[out] ip_addr    Pointer to IPv4 address for output (in native endian)
 * @param      str        IPv4 address string to be parsed
 *
 * @retval 0  on success
 * @retval <0 on failure
 */
int odph_ipv4_addr_parse(uint32_t *ip_addr, const char *str);

/**
 * @}
 */
#ifdef __cplusplus
}
#endif

#endif