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 #ifdef __KERNEL__
36 # include <linux/types.h>
37 #else
38 # include <stdbool.h>
39 #endif
40 
41 
42 /** The selected IP header */
43 typedef enum
44 {
45  ROHC_IP_HDR_NONE = 0, /**< No IP header selected */
46  ROHC_IP_HDR_FIRST = 1, /**< The first IP header is selected */
47  ROHC_IP_HDR_SECOND = 2, /**< The second IP header is selected */
48  /* max 2 IP headers hanlded at the moment */
50 
51 
52 /// IP version
53 typedef enum
54 {
55  /// IP version 4
56  IPV4 = 4,
57  /// IP version 6
58  IPV6 = 6,
59  /// not IP
61  /// IP version 4 (malformed)
63  /// IP version 6 (malformed)
65 } ip_version;
66 
67 
68 /** A network header */
69 struct net_hdr
70 {
71  uint8_t proto; /**< The header protocol */
72  uint8_t *data; /**< The header data */
73  size_t len; /**< The header length (in bytes) */
74 };
75 
76 
77 /**
78  * @brief Defines an IP-agnostic packet that can handle
79  * an IPv4 or IPv6 packet
80  */
81 struct ip_packet
82 {
83  /// The version of the IP packet
85 
86  /// The IP header
87  union
88  {
89  /// The IPv4 header
90  struct ipv4_hdr v4;
91  /// The IPv6 header
92  struct ipv6_hdr v6;
93  } header;
94 
95  /// The whole IP data (header + payload) if not NULL
96  const uint8_t *data;
97 
98  /// The length (in bytes) of the whole IP data (header + payload)
99  size_t size;
100 
101  struct net_hdr nh; /**< The next header (extension headers included) */
102  struct net_hdr nl; /**< The next layer (extension headers excluded) */
103 };
104 
105 
106 /*
107  * Inline functions
108  */
109 
110 #ifndef __KERNEL__ /* already provided by Linux kernel */
111 
112 static inline uint16_t swab16(const uint16_t value)
113  __attribute__((warn_unused_result, const));
114 
115 /**
116  * @brief In-place change the byte order in a two-byte value.
117  *
118  * @param value The two-byte value to modify
119  * @return The same value with the byte order changed
120  */
121 static inline uint16_t swab16(const uint16_t value)
122 {
123  return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8);
124 }
125 
126 
127 #if defined(__i386__) || defined(__x86_64__)
128 
129 static inline uint16_t ip_fast_csum(const uint8_t *iph,
130  const size_t ihl)
131  __attribute__((nonnull(1), warn_unused_result, pure));
132 
133 /**
134  * @brief This is a version of ip_compute_csum() optimized for IP headers,
135  * which always checksum on 4 octet boundaries.
136  *
137  * @author Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
138  * Arnt Gulbrandsen.
139  *
140  * @param iph The IPv4 header
141  * @param ihl The length of the IPv4 header
142  * @return The IPv4 checksum
143  */
144 static inline uint16_t ip_fast_csum(const uint8_t *iph,
145  const size_t ihl)
146 {
147  uint32_t __ihl = ihl;
148  uint32_t sum;
149 
150  __asm__ __volatile__(
151  " \n\
152  movl (%1), %0 \n\
153  subl $4, %2 \n\
154  jbe 2f \n\
155  addl 4(%1), %0 \n\
156  adcl 8(%1), %0 \n\
157  adcl 12(%1), %0 \n\
158 1: adcl 16(%1), %0 \n\
159  lea 4(%1), %1 \n\
160  decl %2 \n\
161  jne 1b \n\
162  adcl $0, %0 \n\
163  movl %0, %2 \n\
164  shrl $16, %0 \n\
165  addw %w2, %w0 \n\
166  adcl $0, %0 \n\
167  notl %0 \n\
168 2: \n\
169  "
170  /* Since the input registers which are loaded with iph and ihl
171  are modified, we must also specify them as outputs, or gcc
172  will assume they contain their original values. */
173  : "=r" (sum), "=r" (iph), "=r" (__ihl)
174  : "1" (iph), "2" (__ihl)
175  : "memory");
176 
177  return (uint16_t) (sum & 0xffff);
178 }
179 
180 
181 #else
182 
183 static inline uint16_t from32to16(const uint32_t x)
184  __attribute__((warn_unused_result, const));
185 
186 static inline uint16_t from32to16(const uint32_t x)
187 {
188  uint32_t y;
189  /* add up 16-bit and 16-bit for 16+c bit */
190  y = (x & 0xffff) + (x >> 16);
191  /* add up carry.. */
192  y = (y & 0xffff) + (y >> 16);
193  return y;
194 }
195 
196 static inline uint16_t ip_fast_csum(const uint8_t *const iph,
197  const size_t ihl)
198  __attribute__((nonnull(1), warn_unused_result, pure));
199 
200 /**
201  * This is a version of ip_compute_csum() optimized for IP headers,
202  * which always checksum on 4 octet boundaries.
203  */
204 static inline uint16_t ip_fast_csum(const uint8_t *const iph,
205  const size_t ihl)
206 {
207  const uint8_t *buff = iph;
208  size_t len = ihl * 4;
209  bool odd;
210  size_t count;
211  uint32_t result = 0;
212 
213  if(len == 0)
214  {
215  goto out;
216  }
217  odd = 1 & (uintptr_t) buff;
218  if(odd)
219  {
220 #ifdef __LITTLE_ENDIAN
221  result = *buff;
222 #else
223  result += (*buff << 8);
224 #endif
225  len--;
226  buff++;
227  }
228  count = len >> 1; /* nr of 16-bit words.. */
229  if(count)
230  {
231  if(2 & (uintptr_t) buff)
232  {
233  result += *(uint16_t *) buff;
234  count--;
235  len -= 2;
236  buff += 2;
237  }
238  count >>= 1; /* nr of 32-bit words.. */
239  if(count)
240  {
241  uint32_t carry = 0;
242  do
243  {
244  uint32_t word = *(uint32_t *) buff;
245  count--;
246  buff += sizeof(uint32_t);
247  result += carry;
248  result += word;
249  carry = (word > result);
250  }
251  while(count);
252  result += carry;
253  result = (result & 0xffff) + (result >> 16);
254  }
255  if(len & 2)
256  {
257  result += *(uint16_t *) buff;
258  buff += 2;
259  }
260  }
261  if(len & 1)
262  {
263 #ifdef __LITTLE_ENDIAN
264  result += *buff;
265 #else
266  result += (*buff << 8);
267 #endif
268  }
269  result = from32to16(result);
270  if(odd)
271  {
272  result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
273  }
274 out:
275  return ~result;
276 }
277 
278 
279 #endif /* !__i386__ && !__x86_64__ */
280 
281 #else /* !__KERNEL__ */
282 # include <asm/checksum.h>
283 #endif /* __KERNEL__ */
284 
285 
286 /*
287  * Function prototypes.
288  */
289 
290 /* Generic functions */
291 
292 bool ip_create(struct ip_packet *const ip,
293  const uint8_t *const packet,
294  const size_t size)
295  __attribute__((warn_unused_result, nonnull(1, 2)));
296 bool ip_get_inner_packet(const struct ip_packet *const outer,
297  struct ip_packet *const inner)
298  __attribute__((warn_unused_result, nonnull(1, 2)));
299 
300 const uint8_t * ip_get_raw_data(const struct ip_packet *const ip)
301  __attribute__((warn_unused_result, nonnull(1), pure));
302 uint8_t * ip_get_next_header(const struct ip_packet *const ip,
303  uint8_t *const type)
304  __attribute__((warn_unused_result, nonnull(1, 2)));
305 uint8_t * ip_get_next_layer(const struct ip_packet *const ip)
306  __attribute__((warn_unused_result, nonnull(1)));
307 uint8_t * ip_get_next_ext_from_ip(const struct ip_packet *const ip,
308  uint8_t *const type)
309  __attribute__((warn_unused_result, nonnull(1, 2)));
310 uint8_t * ip_get_next_ext_from_ext(const uint8_t *const ext,
311  uint8_t *const type)
312  __attribute__((warn_unused_result, nonnull(1, 2)));
313 
314 unsigned int ip_get_totlen(const struct ip_packet *const ip)
315  __attribute__((warn_unused_result, nonnull(1), pure));
316 unsigned int ip_get_hdrlen(const struct ip_packet *const ip)
317  __attribute__((warn_unused_result, nonnull(1)));
318 
319 bool ip_is_fragment(const struct ip_packet *const ip)
320  __attribute__((warn_unused_result, nonnull(1), pure));
321 ip_version ip_get_version(const struct ip_packet *const ip)
322  __attribute__((warn_unused_result, nonnull(1), pure));
323 uint8_t ip_get_protocol(const struct ip_packet *const ip)
324  __attribute__((warn_unused_result, nonnull(1), pure));
325 unsigned int ip_get_tos(const struct ip_packet *const ip)
326  __attribute__((warn_unused_result, nonnull(1), pure));
327 unsigned int ip_get_ttl(const struct ip_packet *const ip)
328  __attribute__((warn_unused_result, nonnull(1), pure));
329 
330 void ip_set_version(struct ip_packet *const ip, const ip_version value)
331  __attribute__((nonnull(1)));
332 void ip_set_protocol(struct ip_packet *const ip, const uint8_t value)
333  __attribute__((nonnull(1)));
334 void ip_set_tos(struct ip_packet *const ip, const uint8_t value)
335  __attribute__((nonnull(1)));
336 void ip_set_ttl(struct ip_packet *const ip, const uint8_t value)
337  __attribute__((nonnull(1)));
338 void ip_set_saddr(struct ip_packet *const ip, const uint8_t *value)
339  __attribute__((nonnull(1, 2)));
340 void ip_set_daddr(struct ip_packet *const ip, const uint8_t *value)
341  __attribute__((nonnull(1, 2)));
342 
343 /* IPv4 specific functions */
344 
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 const struct ipv6_hdr * ipv6_get_header(const struct ip_packet *const ip)
366  __attribute__((warn_unused_result, nonnull(1), pure));
367 uint32_t ip_get_flow_label(const struct ip_packet *const ip)
368  __attribute__((warn_unused_result, nonnull(1), pure));
369 const struct ipv6_addr * ipv6_get_saddr(const struct ip_packet *const ip)
370  __attribute__((warn_unused_result, nonnull(1), pure));
371 const struct ipv6_addr * ipv6_get_daddr(const struct ip_packet *const ip)
372  __attribute__((warn_unused_result, nonnull(1), pure));
373 void ip_set_flow_label(struct ip_packet *const ip, const uint32_t value)
374  __attribute__((nonnull(1)));
375 unsigned short ip_get_extension_size(const uint8_t *const ext)
376  __attribute__((warn_unused_result, nonnull(1), pure));
377 unsigned short ip_get_total_extension_size(const struct ip_packet *const ip)
378  __attribute__((warn_unused_result, nonnull(1)));
379 
380 
381 #endif
382 
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:567
size_t size
The length (in bytes) of the whole IP data (header + payload)
Definition: ip.h:99
uint8_t * ip_get_next_layer(const struct ip_packet *const ip)
Get the next header (but skip IP extensions)
Definition: ip.c:258
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:787
struct ipv4_hdr v4
The IPv4 header.
Definition: ip.h:90
IP version 4 (malformed)
Definition: ip.h:62
not IP
Definition: ip.h:60
const struct ipv6_addr * ipv6_get_daddr(const struct ip_packet *const ip)
Get the destination address of an IPv6 packet.
Definition: ip.c:967
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:363
const uint8_t * data
The whole IP data (header + payload) if not NULL.
Definition: ip.h:96
static uint16_t swab16(const uint16_t value)
In-place change the byte order in a two-byte value.
Definition: ip.h:121
Definition: ip.h:46
ip_header_pos_t
Definition: ip.h:43
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:935
IP version 6.
Definition: ip.h:58
unsigned short ip_get_extension_size(const uint8_t *const ext)
Get the size of an IPv6 extension.
Definition: ip.c:346
uint8_t ip_get_protocol(const struct ip_packet *const ip)
Get the protocol transported by an IP packet.
Definition: ip.c:522
static uint16_t ip_fast_csum(const uint8_t *const iph, const size_t ihl)
Definition: ip.h:204
ip_version version
The version of the IP packet.
Definition: ip.h:84
The IPv6 header.
Definition: ipv6.h:88
bool 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:70
uint8_t proto
Definition: ip.h:71
uint32_t ip_get_flow_label(const struct ip_packet *const ip)
Get the flow label of an IPv6 packet.
Definition: ip.c:919
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:602
size_t len
Definition: ip.h:73
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:882
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:280
The IPv4 header.
const struct ipv6_hdr * ipv6_get_header(const struct ip_packet *const ip)
Get the IPv6 header.
Definition: ip.c:903
int ipv4_get_df(const struct ip_packet *const ip)
Get the Don't Fragment (DF) bit of an IPv4 packet.
Definition: ip.c:834
void ip_set_daddr(struct ip_packet *const ip, const uint8_t *value)
Set the Destination Address of an IP packet.
Definition: ip.c:719
void ipv4_set_df(struct ip_packet *const ip, const int value)
Set the Don't Fragment (DF) bit of an IPv4 packet.
Definition: ip.c:850
void ip_set_saddr(struct ip_packet *const ip, const uint8_t *value)
Set the Source Address of an IP packet.
Definition: ip.c:692
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:665
Definition: ip.h:47
const uint8_t * ip_get_raw_data(const struct ip_packet *const ip)
Get the IP raw data (header + payload)
Definition: ip.c:203
unsigned int ip_get_hdrlen(const struct ip_packet *const ip)
Get the length of an IP header.
Definition: ip.c:457
struct net_hdr nh
Definition: ip.h:101
const struct ipv4_hdr * ipv4_get_header(const struct ip_packet *const ip)
Get the IPv4 header.
Definition: ip.c:751
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:818
Definition: ip.h:69
const struct ipv6_addr * ipv6_get_saddr(const struct ip_packet *const ip)
Get the source address of an IPv6 packet.
Definition: ip.c:951
IP version 6 (malformed)
Definition: ip.h:64
bool 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:219
ip_version
IP version.
Definition: ip.h:53
Defines an IP-agnostic packet that can handle an IPv4 or IPv6 packet.
Definition: ip.h:81
IP version 4.
Definition: ip.h:56
uint8_t * ip_get_next_header(const struct ip_packet *const ip, uint8_t *const type)
Get the IP next header.
Definition: ip.c:237
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:630
bool ip_is_fragment(const struct ip_packet *const ip)
Whether the IP packet is an IP fragment or not.
Definition: ip.c:393
void ip_set_protocol(struct ip_packet *const ip, const uint8_t value)
Set the protocol transported by an IP packet.
Definition: ip.c:537
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:503
unsigned int ip_get_totlen(const struct ip_packet *const ip)
Get the total length of an IP packet.
Definition: ip.c:427
uint32_t ipv4_get_saddr(const struct ip_packet *const ip)
Get the source address of an IPv4 packet.
Definition: ip.c:866
uint8_t * data
Definition: ip.h:72
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:318
struct ipv6_hdr v6
The IPv6 header.
Definition: ip.h:92
static uint16_t from32to16(const uint32_t x)
Definition: ip.h:186
Definition: ip.h:45
uint16_t ipv4_get_id(const struct ip_packet *const ip)
Get the IP-ID of an IPv4 packet.
Definition: ip.c:770
struct net_hdr nl
Definition: ip.h:102
ip_version ip_get_version(const struct ip_packet *const ip)
Get the IP version of an IP packet.
Definition: ip.c:491