ROHC compression/decompression library
ip.h
Go to the documentation of this file.
1 /*
2  * Copyright 2012,2013,2014 Didier Barvaux
3  * Copyright 2007,2008 Thales Alenia Space
4  * Copyright 2007,2009,2010,2013,2014 Viveris Technologies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file common/ip.h
23  * @brief IP-agnostic packet
24  * @author Didier Barvaux <didier.barvaux@toulouse.viveris.com>
25  */
26 
27 #ifndef ROHC_COMMON_IP_H
28 #define ROHC_COMMON_IP_H
29 
30 #include "protocols/ipv4.h"
31 #include "protocols/ipv6.h"
32 
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <stdbool.h>
36 
37 
38 /** The selected IP header */
39 typedef enum
40 {
41  ROHC_IP_HDR_NONE = 0, /**< No IP header selected */
42  ROHC_IP_HDR_FIRST = 1, /**< The first IP header is selected */
43  ROHC_IP_HDR_SECOND = 2, /**< The second IP header is selected */
44  /* max 2 IP headers handled at the moment */
46 
47 
48 /// IP version
49 typedef enum
50 {
51  /// IP version 4
52  IPV4 = 4,
53  /// IP version 6
54  IPV6 = 6,
55  /// not IP
57  /// IP version 4 (malformed)
59  /// IP version 6 (malformed)
61 } ip_version;
62 
63 
64 /** A network header */
65 struct net_hdr
66 {
67  uint8_t proto; /**< The header protocol */
68  uint8_t *data; /**< The header data */
69  size_t len; /**< The header length (in bytes) */
70 };
71 
72 
73 /**
74  * @brief Defines an IP-agnostic packet that can handle
75  * an IPv4 or IPv6 packet
76  */
77 struct ip_packet
78 {
79  /// The version of the IP packet
81 
82  /// The IP header
83  union
84  {
85  /// The IPv4 header
86  struct ipv4_hdr v4;
87  /// The IPv6 header
88  struct ipv6_hdr v6;
89  } header;
90 
91  /// The whole IP data (header + payload) if not NULL
92  const uint8_t *data;
93 
94  /// The length (in bytes) of the whole IP data (header + payload)
95  size_t size;
96 
97  struct net_hdr nh; /**< The next header (extension headers included) */
98  struct net_hdr nl; /**< The next layer (extension headers excluded) */
99 };
100 
101 
102 /*
103  * Inline functions
104  */
105 
106 #ifndef __KERNEL__ /* already provided by Linux kernel */
107 
108 static inline uint16_t swab16(const uint16_t value)
109  __attribute__((warn_unused_result, const));
110 
111 /**
112  * @brief In-place change the byte order in a two-byte value.
113  *
114  * @param value The two-byte value to modify
115  * @return The same value with the byte order changed
116  */
117 static inline uint16_t swab16(const uint16_t value)
118 {
119  return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8);
120 }
121 
122 
123 #if defined(__i386__) || defined(__x86_64__)
124 
125 static inline uint16_t ip_fast_csum(const uint8_t *iph,
126  const size_t ihl)
127  __attribute__((nonnull(1), warn_unused_result, pure));
128 
129 /**
130  * @brief This is a version of ip_compute_csum() optimized for IP headers,
131  * which always checksum on 4 octet boundaries.
132  *
133  * @author Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
134  * Arnt Gulbrandsen.
135  *
136  * @param iph The IPv4 header
137  * @param ihl The length of the IPv4 header
138  * @return The IPv4 checksum
139  */
140 static inline uint16_t ip_fast_csum(const uint8_t *iph,
141  const size_t ihl)
142 {
143  uint32_t __ihl = ihl;
144  uint32_t sum;
145 
146  __asm__ __volatile__(
147  " \n\
148  movl (%1), %0 \n\
149  subl $4, %2 \n\
150  jbe 2f \n\
151  addl 4(%1), %0 \n\
152  adcl 8(%1), %0 \n\
153  adcl 12(%1), %0 \n\
154 1: adcl 16(%1), %0 \n\
155  lea 4(%1), %1 \n\
156  decl %2 \n\
157  jne 1b \n\
158  adcl $0, %0 \n\
159  movl %0, %2 \n\
160  shrl $16, %0 \n\
161  addw %w2, %w0 \n\
162  adcl $0, %0 \n\
163  notl %0 \n\
164 2: \n\
165  "
166  /* Since the input registers which are loaded with iph and ihl
167  are modified, we must also specify them as outputs, or gcc
168  will assume they contain their original values. */
169  : "=r" (sum), "=r" (iph), "=r" (__ihl)
170  : "1" (iph), "2" (__ihl)
171  : "memory");
172 
173  return (uint16_t) (sum & 0xffff);
174 }
175 
176 
177 #else
178 
179 static inline uint16_t from32to16(const uint32_t x)
180  __attribute__((warn_unused_result, const));
181 
182 static inline uint16_t from32to16(const uint32_t x)
183 {
184  uint32_t y;
185  /* add up 16-bit and 16-bit for 16+c bit */
186  y = (x & 0xffff) + (x >> 16);
187  /* add up carry.. */
188  y = (y & 0xffff) + (y >> 16);
189  return y;
190 }
191 
192 static inline uint16_t ip_fast_csum(const uint8_t *const iph,
193  const size_t ihl)
194  __attribute__((nonnull(1), warn_unused_result, pure));
195 
196 /**
197  * This is a version of ip_compute_csum() optimized for IP headers,
198  * which always checksum on 4 octet boundaries.
199  */
200 static inline uint16_t ip_fast_csum(const uint8_t *const iph,
201  const size_t ihl)
202 {
203  const uint8_t *buff = iph;
204  size_t len = ihl * 4;
205  bool odd;
206  size_t count;
207  uint32_t result = 0;
208 
209  if(len == 0)
210  {
211  goto out;
212  }
213  odd = 1 & (uintptr_t) buff;
214  if(odd)
215  {
216 #ifdef __LITTLE_ENDIAN
217  result = *buff;
218 #else
219  result += (*buff << 8);
220 #endif
221  len--;
222  buff++;
223  }
224  count = len >> 1; /* nr of 16-bit words.. */
225  if(count)
226  {
227  if(2 & (uintptr_t) buff)
228  {
229  result += *(uint16_t *) buff;
230  count--;
231  len -= 2;
232  buff += 2;
233  }
234  count >>= 1; /* nr of 32-bit words.. */
235  if(count)
236  {
237  uint32_t carry = 0;
238  do
239  {
240  uint32_t word = *(uint32_t *) buff;
241  count--;
242  buff += sizeof(uint32_t);
243  result += carry;
244  result += word;
245  carry = (word > result);
246  }
247  while(count);
248  result += carry;
249  result = (result & 0xffff) + (result >> 16);
250  }
251  if(len & 2)
252  {
253  result += *(uint16_t *) buff;
254  buff += 2;
255  }
256  }
257  if(len & 1)
258  {
259 #ifdef __LITTLE_ENDIAN
260  result += *buff;
261 #else
262  result += (*buff << 8);
263 #endif
264  }
265  result = from32to16(result);
266  if(odd)
267  {
268  result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
269  }
270 out:
271  return ~result;
272 }
273 
274 
275 #endif /* !__i386__ && !__x86_64__ */
276 
277 #else /* !__KERNEL__ */
278 # include <asm/checksum.h>
279 #endif /* __KERNEL__ */
280 
281 
282 /*
283  * Function prototypes.
284  */
285 
286 /* Generic functions */
287 
288 static inline
289 ip_version ip_get_version(const struct ip_packet *const ip)
290  __attribute__((warn_unused_result, nonnull(1), pure));
291 uint8_t ip_get_protocol(const struct ip_packet *const ip)
292  __attribute__((warn_unused_result, nonnull(1), pure));
293 unsigned int ip_get_tos(const struct ip_packet *const ip)
294  __attribute__((warn_unused_result, nonnull(1), pure));
295 unsigned int ip_get_ttl(const struct ip_packet *const ip)
296  __attribute__((warn_unused_result, nonnull(1), pure));
297 
298 void ip_set_version(struct ip_packet *const ip, const ip_version value)
299  __attribute__((nonnull(1)));
300 void ip_set_protocol(struct ip_packet *const ip, const uint8_t value)
301  __attribute__((nonnull(1)));
302 void ip_set_tos(struct ip_packet *const ip, const uint8_t value)
303  __attribute__((nonnull(1)));
304 void ip_set_ttl(struct ip_packet *const ip, const uint8_t value)
305  __attribute__((nonnull(1)));
306 void ip_set_saddr(struct ip_packet *const ip, const uint8_t *value)
307  __attribute__((nonnull(1, 2)));
308 void ip_set_daddr(struct ip_packet *const ip, const uint8_t *value)
309  __attribute__((nonnull(1, 2)));
310 
311 /**
312  * @brief Get the IP version of an IP packet
313  *
314  * The function handles \ref ip_packet whose \ref ip_packet::version is
315  * \ref IP_UNKNOWN.
316  *
317  * @param ip The IP packet to analyze
318  * @return The version of the IP packet
319  */
320 static inline
321 ip_version ip_get_version(const struct ip_packet *const ip)
322 {
323  return ip->version;
324 }
325 
326 #endif
327 
unsigned int ip_get_tos(const struct ip_packet *const ip)
Get the IPv4 Type Of Service (TOS) or IPv6 Traffic Class (TC) of an IP packet.
Definition: ip.c:114
size_t size
The length (in bytes) of the whole IP data (header + payload)
Definition: ip.h:95
struct ipv4_hdr v4
The IPv4 header.
Definition: ip.h:86
IP version 4 (malformed)
Definition: ip.h:58
not IP
Definition: ip.h:56
union ip_packet::@1 header
The IP header.
const uint8_t * data
The whole IP data (header + payload) if not NULL.
Definition: ip.h:92
static uint16_t swab16(const uint16_t value)
In-place change the byte order in a two-byte value.
Definition: ip.h:117
Definition: ip.h:42
ip_header_pos_t
Definition: ip.h:39
IP version 6.
Definition: ip.h:54
static ip_version ip_get_version(const struct ip_packet *const ip)
Get the IP version of an IP packet.
Definition: ip.h:321
uint8_t ip_get_protocol(const struct ip_packet *const ip)
Get the protocol transported by an IP packet.
Definition: ip.c:69
static uint16_t ip_fast_csum(const uint8_t *const iph, const size_t ihl)
Definition: ip.h:200
ip_version version
The version of the IP packet.
Definition: ip.h:80
The IPv6 header.
Definition: ipv6.h:82
uint8_t proto
Definition: ip.h:67
void ip_set_tos(struct ip_packet *const ip, const uint8_t value)
Set the IPv4 Type Of Service (TOS) or IPv6 Traffic Class (TC) of an IP packet.
Definition: ip.c:149
size_t len
Definition: ip.h:69
The IPv4 header.
Definition: ipv4.h:53
The IPv4 header.
bool nonnull(1)))
void ip_set_daddr(struct ip_packet *const ip, const uint8_t *value)
Set the Destination Address of an IP packet.
Definition: ip.c:266
void ip_set_saddr(struct ip_packet *const ip, const uint8_t *value)
Set the Source Address of an IP packet.
Definition: ip.c:239
void ip_set_ttl(struct ip_packet *const ip, const uint8_t value)
Set the IPv4 Time To Live (TTL) or IPv6 Hop Limit (HL) of an IP packet.
Definition: ip.c:212
Definition: ip.h:43
struct net_hdr nh
Definition: ip.h:97
The IPv6 header.
Definition: ip.h:65
IP version 6 (malformed)
Definition: ip.h:60
ip_version
IP version.
Definition: ip.h:49
Defines an IP-agnostic packet that can handle an IPv4 or IPv6 packet.
Definition: ip.h:77
IP version 4.
Definition: ip.h:52
unsigned int ip_get_ttl(const struct ip_packet *const ip)
Get the IPv4 Time To Live (TTL) or IPv6 Hop Limit (HL) of an IP packet.
Definition: ip.c:177
void ip_set_protocol(struct ip_packet *const ip, const uint8_t value)
Set the protocol transported by an IP packet.
Definition: ip.c:84
void ip_set_version(struct ip_packet *const ip, const ip_version value)
Set the IP version of an IP packet.
Definition: ip.c:50
uint8_t * data
Definition: ip.h:68
struct ipv6_hdr v6
The IPv6 header.
Definition: ip.h:88
static uint16_t from32to16(const uint32_t x)
Definition: ip.h:182
Definition: ip.h:41
struct net_hdr nl
Definition: ip.h:98