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 hanlded 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 void ip_create(struct ip_packet *const ip,
289  const uint8_t *const packet,
290  const size_t size)
291  __attribute__((nonnull(1, 2)));
292 void ip_get_inner_packet(const struct ip_packet *const outer,
293  struct ip_packet *const inner)
294  __attribute__((nonnull(1, 2)));
295 
296 const uint8_t * ip_get_raw_data(const struct ip_packet *const ip)
297  __attribute__((warn_unused_result, nonnull(1), pure));
298 uint8_t * ip_get_next_header(const struct ip_packet *const ip,
299  uint8_t *const type)
300  __attribute__((warn_unused_result, nonnull(1, 2)));
301 uint8_t * ip_get_next_layer(const struct ip_packet *const ip)
302  __attribute__((warn_unused_result, nonnull(1)));
303 uint8_t * ip_get_next_ext_from_ip(const struct ip_packet *const ip,
304  uint8_t *const type)
305  __attribute__((warn_unused_result, nonnull(1, 2)));
306 uint8_t * ip_get_next_ext_from_ext(const uint8_t *const ext,
307  uint8_t *const type)
308  __attribute__((warn_unused_result, nonnull(1, 2)));
309 
310 unsigned int ip_get_totlen(const struct ip_packet *const ip)
311  __attribute__((warn_unused_result, nonnull(1), pure));
312 unsigned int ip_get_hdrlen(const struct ip_packet *const ip)
313  __attribute__((warn_unused_result, nonnull(1)));
314 
315 bool ip_is_fragment(const struct ip_packet *const ip)
316  __attribute__((warn_unused_result, nonnull(1), pure));
317 static inline
318 ip_version ip_get_version(const struct ip_packet *const ip)
319  __attribute__((warn_unused_result, nonnull(1), pure));
320 uint8_t ip_get_protocol(const struct ip_packet *const ip)
321  __attribute__((warn_unused_result, nonnull(1), pure));
322 unsigned int ip_get_tos(const struct ip_packet *const ip)
323  __attribute__((warn_unused_result, nonnull(1), pure));
324 unsigned int ip_get_ttl(const struct ip_packet *const ip)
325  __attribute__((warn_unused_result, nonnull(1), pure));
326 
327 void ip_set_version(struct ip_packet *const ip, const ip_version value)
328  __attribute__((nonnull(1)));
329 void ip_set_protocol(struct ip_packet *const ip, const uint8_t value)
330  __attribute__((nonnull(1)));
331 void ip_set_tos(struct ip_packet *const ip, const uint8_t value)
332  __attribute__((nonnull(1)));
333 void ip_set_ttl(struct ip_packet *const ip, const uint8_t value)
334  __attribute__((nonnull(1)));
335 void ip_set_saddr(struct ip_packet *const ip, const uint8_t *value)
336  __attribute__((nonnull(1, 2)));
337 void ip_set_daddr(struct ip_packet *const ip, const uint8_t *value)
338  __attribute__((nonnull(1, 2)));
339 
340 /* IPv4 specific functions */
341 
342 static inline
343 size_t ipv4_get_hdrlen(const struct ip_packet *const ip)
344  __attribute__((warn_unused_result, nonnull(1), pure));
345 const struct ipv4_hdr * ipv4_get_header(const struct ip_packet *const ip)
346  __attribute__((warn_unused_result, nonnull(1), pure));
347 uint16_t ipv4_get_id(const struct ip_packet *const ip)
348  __attribute__((warn_unused_result, nonnull(1), pure));
349 uint16_t ipv4_get_id_nbo(const struct ip_packet *const ip, const unsigned int nbo)
350  __attribute__((warn_unused_result, nonnull(1), pure));
351 int ipv4_get_df(const struct ip_packet *const ip)
352  __attribute__((warn_unused_result, nonnull(1), pure));
353 uint32_t ipv4_get_saddr(const struct ip_packet *const ip)
354  __attribute__((warn_unused_result, nonnull(1), pure));
355 uint32_t ipv4_get_daddr(const struct ip_packet *const ip)
356  __attribute__((warn_unused_result, nonnull(1), pure));
357 
358 void ipv4_set_id(struct ip_packet *const ip, const int value)
359  __attribute__((nonnull(1)));
360 void ipv4_set_df(struct ip_packet *const ip, const int value)
361  __attribute__((nonnull(1)));
362 
363 /* IPv6 specific functions */
364 
365 static inline
366 size_t ipv6_get_hdrlen(const struct ip_packet *const ip)
367  __attribute__((warn_unused_result, nonnull(1), const));
368 const struct ipv6_hdr * ipv6_get_header(const struct ip_packet *const ip)
369  __attribute__((warn_unused_result, nonnull(1), pure));
370 uint32_t ip_get_flow_label(const struct ip_packet *const ip)
371  __attribute__((warn_unused_result, nonnull(1), pure));
372 const struct ipv6_addr * ipv6_get_saddr(const struct ip_packet *const ip)
373  __attribute__((warn_unused_result, nonnull(1), pure));
374 const struct ipv6_addr * ipv6_get_daddr(const struct ip_packet *const ip)
375  __attribute__((warn_unused_result, nonnull(1), pure));
376 void ip_set_flow_label(struct ip_packet *const ip, const uint32_t value)
377  __attribute__((nonnull(1)));
378 unsigned short ip_get_extension_size(const uint8_t *const ext)
379  __attribute__((warn_unused_result, nonnull(1), pure));
380 unsigned short ip_get_total_extension_size(const struct ip_packet *const ip)
381  __attribute__((warn_unused_result, nonnull(1)));
382 
383 
384 /**
385  * @brief Get the IP version of an IP packet
386  *
387  * The function handles \ref ip_packet whose \ref ip_packet::version is
388  * \ref IP_UNKNOWN.
389  *
390  * @param ip The IP packet to analyze
391  * @return The version of the IP packet
392  */
393 static inline
394 ip_version ip_get_version(const struct ip_packet *const ip)
395 {
396  return ip->version;
397 }
398 
399 
400 static inline
401 size_t ipv4_get_hdrlen(const struct ip_packet *const ip)
402 {
403  return (ip->header.v4.ihl * 4);
404 }
405 
406 
407 static inline
408 size_t ipv6_get_hdrlen(const struct ip_packet *const ip __attribute__((unused)))
409 {
410  return sizeof(struct ipv6_hdr);
411 }
412 
413 
414 #endif
415 
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:542
size_t size
The length (in bytes) of the whole IP data (header + payload)
Definition: ip.h:95
uint8_t * ip_get_next_layer(const struct ip_packet *const ip)
Get the next header (but skip IP extensions)
Definition: ip.c:248
uint16_t ipv4_get_id_nbo(const struct ip_packet *const ip, const unsigned int nbo)
Get the IP-ID of an IPv4 packet in Network Byte Order.
Definition: ip.c:762
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
const struct ipv6_addr * ipv6_get_daddr(const struct ip_packet *const ip)
Get the destination address of an IPv6 packet.
Definition: ip.c:942
union ip_packet::@1 header
The IP header.
unsigned short ip_get_total_extension_size(const struct ip_packet *const ip)
Get the size of the extension list.
Definition: ip.c:353
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
void ip_create(struct ip_packet *const ip, const uint8_t *const packet, const size_t size)
Create an IP packet from raw data.
Definition: ip.c:67
Definition: ip.h:42
ip_header_pos_t
Definition: ip.h:39
uint8_t ihl
Definition: ipv4.h:59
void ip_get_inner_packet(const struct ip_packet *const outer, struct ip_packet *const inner)
Get the inner IP packet (IP in IP)
Definition: ip.c:209
void ip_set_flow_label(struct ip_packet *const ip, const uint32_t value)
Set the flow label of an IPv6 packet.
Definition: ip.c:910
IP version 6.
Definition: ip.h:54
unsigned short ip_get_extension_size(const uint8_t *const ext)
Get the size of an IPv6 extension.
Definition: ip.c:336
static ip_version ip_get_version(const struct ip_packet *const ip)
Get the IP version of an IP packet.
Definition: ip.h:394
uint8_t ip_get_protocol(const struct ip_packet *const ip)
Get the protocol transported by an IP packet.
Definition: ip.c:497
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:88
uint8_t proto
Definition: ip.h:67
uint32_t ip_get_flow_label(const struct ip_packet *const ip)
Get the flow label of an IPv6 packet.
Definition: ip.c:894
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:577
size_t len
Definition: ip.h:69
The IPv4 header.
Definition: ipv4.h:53
uint32_t ipv4_get_daddr(const struct ip_packet *const ip)
Get the destination address of an IPv4 packet.
Definition: ip.c:857
uint8_t * ip_get_next_ext_from_ip(const struct ip_packet *const ip, uint8_t *const type)
Get the next extension header of IPv6 packets from an IPv6 header.
Definition: ip.c:270
The IPv4 header.
const struct ipv6_hdr * ipv6_get_header(const struct ip_packet *const ip)
Get the IPv6 header.
Definition: ip.c:878
int ipv4_get_df(const struct ip_packet *const ip)
Get the Don&#39;t Fragment (DF) bit of an IPv4 packet.
Definition: ip.c:809
void ip_set_daddr(struct ip_packet *const ip, const uint8_t *value)
Set the Destination Address of an IP packet.
Definition: ip.c:694
static size_t ipv6_get_hdrlen(const struct ip_packet *const ip)
Definition: ip.h:408
void ipv4_set_df(struct ip_packet *const ip, const int value)
Set the Don&#39;t Fragment (DF) bit of an IPv4 packet.
Definition: ip.c:825
void ip_set_saddr(struct ip_packet *const ip, const uint8_t *value)
Set the Source Address of an IP packet.
Definition: ip.c:667
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:640
Definition: ip.h:43
const uint8_t * ip_get_raw_data(const struct ip_packet *const ip)
Get the IP raw data (header + payload)
Definition: ip.c:194
unsigned int ip_get_hdrlen(const struct ip_packet *const ip)
Get the length of an IP header.
Definition: ip.c:447
const struct ipv4_hdr * ipv4_get_header(const struct ip_packet *const ip)
Get the IPv4 header.
Definition: ip.c:726
The IPv6 header.
void ipv4_set_id(struct ip_packet *const ip, const int value)
Set the IP-ID of an IPv4 packet.
Definition: ip.c:793
Definition: ip.h:65
const struct ipv6_addr * ipv6_get_saddr(const struct ip_packet *const ip)
Get the source address of an IPv6 packet.
Definition: ip.c:926
IP version 6 (malformed)
Definition: ip.h:60
ip_version
IP version.
Definition: ip.h:49
static size_t ipv4_get_hdrlen(const struct ip_packet *const ip)
Definition: ip.h:401
Defines an IP-agnostic packet that can handle an IPv4 or IPv6 packet.
Definition: ip.h:77
IP version 4.
Definition: ip.h:52
uint8_t * ip_get_next_header(const struct ip_packet *const ip, uint8_t *const type)
Get the IP next header.
Definition: ip.c:227
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:605
bool ip_is_fragment(const struct ip_packet *const ip)
Whether the IP packet is an IP fragment or not.
Definition: ip.c:383
void ip_set_protocol(struct ip_packet *const ip, const uint8_t value)
Set the protocol transported by an IP packet.
Definition: ip.c:512
The IPv6 address.
Definition: ipv6.h:65
void ip_set_version(struct ip_packet *const ip, const ip_version value)
Set the IP version of an IP packet.
Definition: ip.c:478
unsigned int ip_get_totlen(const struct ip_packet *const ip)
Get the total length of an IP packet.
Definition: ip.c:417
uint32_t ipv4_get_saddr(const struct ip_packet *const ip)
Get the source address of an IPv4 packet.
Definition: ip.c:841
uint8_t * data
Definition: ip.h:68
uint8_t * ip_get_next_ext_from_ext(const uint8_t *const ext, uint8_t *const type)
Get the next extension header of IPv6 packets from another extension.
Definition: ip.c:308
static uint16_t from32to16(const uint32_t x)
Definition: ip.h:182
Definition: ip.h:41
uint16_t ipv4_get_id(const struct ip_packet *const ip)
Get the IP-ID of an IPv4 packet.
Definition: ip.c:745