ROHC compression/decompression library
|
00001 /* 00002 * Copyright 2012,2013,2014 Didier Barvaux 00003 * Copyright 2007,2008 Thales Alenia Space 00004 * Copyright 2007,2009,2010,2013,2014 Viveris Technologies 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 /** 00022 * @file common/ip.h 00023 * @brief IP-agnostic packet 00024 * @author Didier Barvaux <didier.barvaux@toulouse.viveris.com> 00025 */ 00026 00027 #ifndef ROHC_COMMON_IP_H 00028 #define ROHC_COMMON_IP_H 00029 00030 #include "dllexport.h" 00031 #include "protocols/ipv4.h" 00032 #include "protocols/ipv6.h" 00033 00034 #include <stdlib.h> 00035 #include <stdint.h> 00036 #ifdef __KERNEL__ 00037 # include <linux/types.h> 00038 #else 00039 # include <stdbool.h> 00040 #endif 00041 00042 00043 /** The selected IP header */ 00044 typedef enum 00045 { 00046 ROHC_IP_HDR_NONE = 0, /**< No IP header selected */ 00047 ROHC_IP_HDR_FIRST = 1, /**< The first IP header is selected */ 00048 ROHC_IP_HDR_SECOND = 2, /**< The second IP header is selected */ 00049 /* max 2 IP headers hanlded at the moment */ 00050 } ip_header_pos_t; 00051 00052 00053 /// IP version 00054 typedef enum 00055 { 00056 /// IP version 4 00057 IPV4 = 4, 00058 /// IP version 6 00059 IPV6 = 6, 00060 /// not IP 00061 IP_UNKNOWN = 0, 00062 /// IP version 4 (malformed) 00063 IPV4_MALFORMED = 1, 00064 /// IP version 6 (malformed) 00065 IPV6_MALFORMED = 2, 00066 } ip_version; 00067 00068 00069 /** A network header */ 00070 struct net_hdr 00071 { 00072 uint8_t proto; /**< The header protocol */ 00073 uint8_t *data; /**< The header data */ 00074 size_t len; /**< The header length (in bytes) */ 00075 }; 00076 00077 00078 /** 00079 * @brief Defines an IP-agnostic packet that can handle 00080 * an IPv4 or IPv6 packet 00081 */ 00082 struct ip_packet 00083 { 00084 /// The version of the IP packet 00085 ip_version version; 00086 00087 /// The IP header 00088 union 00089 { 00090 /// The IPv4 header 00091 struct ipv4_hdr v4; 00092 /// The IPv6 header 00093 struct ipv6_hdr v6; 00094 } header; 00095 00096 /// The whole IP data (header + payload) if not NULL 00097 const uint8_t *data; 00098 00099 /// The length (in bytes) of the whole IP data (header + payload) 00100 size_t size; 00101 00102 struct net_hdr nh; /**< The next header (extension headers included) */ 00103 struct net_hdr nl; /**< The next layer (extension headers excluded) */ 00104 }; 00105 00106 00107 /* 00108 * Generic IP macros: 00109 */ 00110 00111 /// Get a subpart of a 16-bit IP field 00112 #define IP_GET_16_SUBFIELD(field, bitmask, offset) \ 00113 ((rohc_ntoh16(field) & (bitmask)) >> (offset)) 00114 00115 /// Get a subpart of a 32-bit IP field 00116 #define IP_GET_32_SUBFIELD(field, bitmask, offset) \ 00117 ((rohc_ntoh32(field) & (bitmask)) >> (offset)) 00118 00119 /// Set a subpart of a 16-bit IP field 00120 #define IP_SET_16_SUBFIELD(field, bitmask, offset, value) \ 00121 (field) = (((field) & rohc_hton16(~(bitmask))) | \ 00122 rohc_hton16(((value) << (offset)) & (bitmask))) 00123 00124 /// Set a subpart of a 32-bit IP field 00125 #define IP_SET_32_SUBFIELD(field, bitmask, offset, value) \ 00126 (field) = (((field) & rohc_hton32(~(bitmask))) | \ 00127 rohc_hton32(((value) << (offset)) & (bitmask))) 00128 00129 00130 /* 00131 * IPv4 definitions & macros: 00132 */ 00133 00134 /// The offset for the DF flag in an ipv4_hdr->frag_off variable 00135 #define IPV4_DF_OFFSET 14 00136 00137 /// Get the IPv4 Don't Fragment (DF) bit from an ipv4_hdr object 00138 #define IPV4_GET_DF(ip4) \ 00139 IP_GET_16_SUBFIELD((ip4).frag_off, IP_DF, IPV4_DF_OFFSET) 00140 00141 /// Set the IPv4 Don't Fragment (DF) bit in an ipv4_hdr object 00142 #define IPV4_SET_DF(ip4, value) \ 00143 IP_SET_16_SUBFIELD((ip4)->frag_off, IP_DF, IPV4_DF_OFFSET, (value)) 00144 00145 /// The format to print an IPv4 address 00146 #define IPV4_ADDR_FORMAT \ 00147 "%02x%02x%02x%02x (%u.%u.%u.%u)" 00148 00149 /// The data to print an IPv4 address in raw format 00150 #define IPV4_ADDR_RAW(x) \ 00151 (x)[0], (x)[1], (x)[2], (x)[3], \ 00152 (x)[0], (x)[1], (x)[2], (x)[3] 00153 00154 00155 /* 00156 * IPv6 definitions & macros: 00157 */ 00158 00159 /// The bitmask for the Version field in an ipv6_hdr->ip6_flow variable 00160 #define IPV6_VERSION_MASK 0xf0000000 00161 /// The offset for the Version field in an ipv6_hdr->ip6_flow variable 00162 #define IPV6_VERSION_OFFSET 28 00163 00164 /// The bitmask for the Traffic Class (TC) field in an ipv6_hdr->ip6_flow variable 00165 #define IPV6_TC_MASK 0x0ff00000 00166 /// The offset for the Traffic Class (TC) field in an ipv6_hdr->ip6_flow variable 00167 #define IPV6_TC_OFFSET 20 00168 00169 /// The bitmask for the FLow Label field in an ipv6_hdr->ip6_flow variable 00170 #define IPV6_FLOW_LABEL_MASK 0x000fffff 00171 00172 /// Get the IPv6 Version 4-bit field from ipv6_hdr object 00173 #define IPV6_GET_VERSION(ip6) \ 00174 IP_GET_32_SUBFIELD((ip6).ip6_flow, IPV6_VERSION_MASK, IPV6_VERSION_OFFSET) 00175 00176 /// Set the IPv6 Version 4-bit field in an ipv6_hdr object 00177 #define IPV6_SET_VERSION(ip6, value) \ 00178 IP_SET_32_SUBFIELD((ip6)->ip6_flow, IPV6_VERSION_MASK, IPV6_VERSION_OFFSET, (value)) 00179 00180 /// Get the IPv6 Traffic Class (TC) byte from an ipv6_hdr object 00181 #define IPV6_GET_TC(ip6) \ 00182 IP_GET_32_SUBFIELD((ip6).ip6_flow, IPV6_TC_MASK, IPV6_TC_OFFSET) 00183 00184 /// Set the IPv6 Traffic Class (TC) byte in an ipv6_hdr object 00185 #define IPV6_SET_TC(ip6, value) \ 00186 IP_SET_32_SUBFIELD((ip6)->ip6_flow, IPV6_TC_MASK, IPV6_TC_OFFSET, (value)) 00187 00188 /// Get the IPv6 Flow Label 20-bit field from an ipv6_hdr object 00189 #define IPV6_GET_FLOW_LABEL(ip6) \ 00190 IP_GET_32_SUBFIELD((ip6).ip6_flow, IPV6_FLOW_LABEL_MASK, 0) 00191 00192 /// Set the IPv6 Flow Label 20-bit field in an ipv6_hdr variable 00193 #define IPV6_SET_FLOW_LABEL(ip6, value) \ 00194 IP_SET_32_SUBFIELD((ip6)->ip6_flow, IPV6_FLOW_LABEL_MASK, 0, (value)) 00195 00196 /// The format to print an IPv6 address 00197 #define IPV6_ADDR_FORMAT \ 00198 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x" 00199 00200 /// The data to print an IPv6 address in (struct ipv6_addr *) format 00201 #define IPV6_ADDR_IN6(x) \ 00202 IPV6_ADDR_RAW((x)->addr.u8) 00203 00204 /// The data to print an IPv6 address in raw format 00205 #define IPV6_ADDR_RAW(x) \ 00206 (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5], (x)[6], (x)[7], \ 00207 (x)[8], (x)[9], (x)[10], (x)[11], (x)[12], (x)[13], (x)[14], (x)[15] 00208 00209 /// Compare two IPv6 addresses in (struct ipv6_addr *) format 00210 #define IPV6_ADDR_CMP(x, y) \ 00211 ((x)->addr.u32[0] == (y)->addr.u32[0] && \ 00212 (x)->addr.u32[1] == (y)->addr.u32[1] && \ 00213 (x)->addr.u32[2] == (y)->addr.u32[2] && \ 00214 (x)->addr.u32[3] == (y)->addr.u32[3]) 00215 00216 00217 /* 00218 * Inline functions 00219 */ 00220 00221 #ifndef __KERNEL__ /* already provided by Linux kernel */ 00222 00223 static inline uint16_t swab16(const uint16_t value) 00224 __attribute__((warn_unused_result, const)); 00225 00226 /** 00227 * @brief In-place change the byte order in a two-byte value. 00228 * 00229 * @param value The two-byte value to modify 00230 * @return The same value with the byte order changed 00231 */ 00232 static inline uint16_t swab16(const uint16_t value) 00233 { 00234 return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8); 00235 } 00236 00237 00238 #ifdef __i386__ 00239 00240 static inline uint16_t ip_fast_csum(const uint8_t *iph, 00241 size_t ihl) 00242 __attribute__((nonnull(1), warn_unused_result, pure)); 00243 00244 /** 00245 * @brief This is a version of ip_compute_csum() optimized for IP headers, 00246 * which always checksum on 4 octet boundaries. 00247 * 00248 * @author Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by 00249 * Arnt Gulbrandsen. 00250 * 00251 * @param iph The IPv4 header 00252 * @param ihl The length of the IPv4 header 00253 * @return The IPv4 checksum 00254 */ 00255 static inline uint16_t ip_fast_csum(const uint8_t *iph, 00256 size_t ihl) 00257 { 00258 uint32_t sum; 00259 00260 __asm__ __volatile__( 00261 " \n\ 00262 movl (%1), %0 \n\ 00263 subl $4, %2 \n\ 00264 jbe 2f \n\ 00265 addl 4(%1), %0 \n\ 00266 adcl 8(%1), %0 \n\ 00267 adcl 12(%1), %0 \n\ 00268 1: adcl 16(%1), %0 \n\ 00269 lea 4(%1), %1 \n\ 00270 decl %2 \n\ 00271 jne 1b \n\ 00272 adcl $0, %0 \n\ 00273 movl %0, %2 \n\ 00274 shrl $16, %0 \n\ 00275 addw %w2, %w0 \n\ 00276 adcl $0, %0 \n\ 00277 notl %0 \n\ 00278 2: \n\ 00279 " 00280 /* Since the input registers which are loaded with iph and ihl 00281 are modified, we must also specify them as outputs, or gcc 00282 will assume they contain their original values. */ 00283 : "=r" (sum), "=r" (iph), "=r" (ihl) 00284 : "1" (iph), "2" (ihl) 00285 : "memory"); 00286 00287 return (uint16_t) (sum & 0xffff); 00288 } 00289 00290 00291 #else 00292 00293 static inline uint16_t from32to16(const uint32_t x) 00294 __attribute__((warn_unused_result, const)); 00295 00296 static inline uint16_t from32to16(const uint32_t x) 00297 { 00298 uint32_t y; 00299 /* add up 16-bit and 16-bit for 16+c bit */ 00300 y = (x & 0xffff) + (x >> 16); 00301 /* add up carry.. */ 00302 y = (y & 0xffff) + (y >> 16); 00303 return y; 00304 } 00305 00306 static inline uint16_t ip_fast_csum(const uint8_t *const iph, 00307 const size_t ihl) 00308 __attribute__((nonnull(1), warn_unused_result, pure)); 00309 00310 /** 00311 * This is a version of ip_compute_csum() optimized for IP headers, 00312 * which always checksum on 4 octet boundaries. 00313 */ 00314 static inline uint16_t ip_fast_csum(const uint8_t *const iph, 00315 const size_t ihl) 00316 { 00317 const uint8_t *buff = iph; 00318 size_t len = ihl * 4; 00319 bool odd; 00320 size_t count; 00321 uint32_t result = 0; 00322 00323 if(len <= 0) 00324 { 00325 goto out; 00326 } 00327 odd = 1 & (uintptr_t) buff; 00328 if(odd) 00329 { 00330 #ifdef __LITTLE_ENDIAN 00331 result = *buff; 00332 #else 00333 result += (*buff << 8); 00334 #endif 00335 len--; 00336 buff++; 00337 } 00338 count = len >> 1; /* nr of 16-bit words.. */ 00339 if(count) 00340 { 00341 if(2 & (uintptr_t) buff) 00342 { 00343 result += *(uint16_t *) buff; 00344 count--; 00345 len -= 2; 00346 buff += 2; 00347 } 00348 count >>= 1; /* nr of 32-bit words.. */ 00349 if(count) 00350 { 00351 uint32_t carry = 0; 00352 do 00353 { 00354 uint32_t word = *(uint32_t *) buff; 00355 count--; 00356 buff += sizeof(uint32_t); 00357 result += carry; 00358 result += word; 00359 carry = (word > result); 00360 } 00361 while(count); 00362 result += carry; 00363 result = (result & 0xffff) + (result >> 16); 00364 } 00365 if(len & 2) 00366 { 00367 result += *(uint16_t *) buff; 00368 buff += 2; 00369 } 00370 } 00371 if(len & 1) 00372 { 00373 #ifdef __LITTLE_ENDIAN 00374 result += *buff; 00375 #else 00376 result += (*buff << 8); 00377 #endif 00378 } 00379 result = from32to16(result); 00380 if(odd) 00381 { 00382 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); 00383 } 00384 out: 00385 return ~result; 00386 } 00387 00388 00389 #endif /* !__i386__ */ 00390 00391 #else /* !__KERNEL__ */ 00392 # include <asm/checksum.h> 00393 #endif /* __KERNEL__ */ 00394 00395 00396 /* 00397 * Function prototypes. 00398 */ 00399 00400 /* Generic functions */ 00401 00402 bool ROHC_EXPORT ip_create(struct ip_packet *const ip, 00403 const uint8_t *const packet, 00404 const size_t size) 00405 __attribute__((warn_unused_result, nonnull(1, 2))); 00406 bool ROHC_EXPORT ip_get_inner_packet(const struct ip_packet *const outer, 00407 struct ip_packet *const inner) 00408 __attribute__((warn_unused_result, nonnull(1, 2))); 00409 00410 const uint8_t * ROHC_EXPORT ip_get_raw_data(const struct ip_packet *const ip) 00411 __attribute__((warn_unused_result, nonnull(1))); 00412 uint8_t * ROHC_EXPORT ip_get_next_header(const struct ip_packet *const ip, 00413 uint8_t *const type) 00414 __attribute__((warn_unused_result, nonnull(1, 2))); 00415 uint8_t * ROHC_EXPORT ip_get_next_layer(const struct ip_packet *const ip) 00416 __attribute__((warn_unused_result, nonnull(1))); 00417 uint8_t * ROHC_EXPORT ip_get_next_ext_from_ip(const struct ip_packet *const ip, 00418 uint8_t *const type) 00419 __attribute__((warn_unused_result, nonnull(1, 2))); 00420 uint8_t * ROHC_EXPORT ip_get_next_ext_from_ext(const uint8_t *const ext, 00421 uint8_t *const type) 00422 __attribute__((warn_unused_result, nonnull(1, 2))); 00423 00424 unsigned int ROHC_EXPORT ip_get_totlen(const struct ip_packet *const ip) 00425 __attribute__((warn_unused_result, nonnull(1))); 00426 unsigned int ROHC_EXPORT ip_get_hdrlen(const struct ip_packet *const ip) 00427 __attribute__((warn_unused_result, nonnull(1))); 00428 unsigned int ROHC_EXPORT ip_get_plen(const struct ip_packet *const ip) 00429 __attribute__((warn_unused_result, nonnull(1))); 00430 00431 bool ROHC_EXPORT ip_is_fragment(const struct ip_packet *const ip) 00432 __attribute__((warn_unused_result, nonnull(1), pure)); 00433 ip_version ROHC_EXPORT ip_get_version(const struct ip_packet *const ip) 00434 __attribute__((warn_unused_result, nonnull(1), pure)); 00435 uint8_t ROHC_EXPORT ip_get_protocol(const struct ip_packet *const ip) 00436 __attribute__((warn_unused_result, nonnull(1), pure)); 00437 unsigned int ROHC_EXPORT ip_get_tos(const struct ip_packet *const ip) 00438 __attribute__((warn_unused_result, nonnull(1), pure)); 00439 unsigned int ROHC_EXPORT ip_get_ttl(const struct ip_packet *const ip) 00440 __attribute__((warn_unused_result, nonnull(1), pure)); 00441 00442 void ROHC_EXPORT ip_set_version(struct ip_packet *const ip, 00443 const ip_version value) 00444 __attribute__((nonnull(1))); 00445 void ROHC_EXPORT ip_set_protocol(struct ip_packet *const ip, 00446 const uint8_t value) 00447 __attribute__((nonnull(1))); 00448 void ROHC_EXPORT ip_set_tos(struct ip_packet *const ip, 00449 const uint8_t value) 00450 __attribute__((nonnull(1))); 00451 void ROHC_EXPORT ip_set_ttl(struct ip_packet *const ip, 00452 const uint8_t value) 00453 __attribute__((nonnull(1))); 00454 void ROHC_EXPORT ip_set_saddr(struct ip_packet *const ip, 00455 const uint8_t *value) 00456 __attribute__((nonnull(1, 2))); 00457 void ROHC_EXPORT ip_set_daddr(struct ip_packet *const ip, 00458 const uint8_t *value) 00459 __attribute__((nonnull(1, 2))); 00460 00461 /* IPv4 specific functions */ 00462 00463 const struct ipv4_hdr * ROHC_EXPORT ipv4_get_header(const struct ip_packet *const ip) 00464 __attribute__((warn_unused_result, nonnull(1), pure)); 00465 uint16_t ROHC_EXPORT ipv4_get_id(const struct ip_packet *const ip) 00466 __attribute__((warn_unused_result, nonnull(1), pure)); 00467 uint16_t ROHC_EXPORT ipv4_get_id_nbo(const struct ip_packet *const ip, 00468 const unsigned int nbo) 00469 __attribute__((warn_unused_result, nonnull(1), pure)); 00470 int ROHC_EXPORT ipv4_get_df(const struct ip_packet *const ip) 00471 __attribute__((warn_unused_result, nonnull(1), pure)); 00472 uint32_t ROHC_EXPORT ipv4_get_saddr(const struct ip_packet *const ip) 00473 __attribute__((warn_unused_result, nonnull(1), pure)); 00474 uint32_t ROHC_EXPORT ipv4_get_daddr(const struct ip_packet *const ip) 00475 __attribute__((warn_unused_result, nonnull(1), pure)); 00476 00477 void ROHC_EXPORT ipv4_set_id(struct ip_packet *const ip, const int value) 00478 __attribute__((nonnull(1))); 00479 void ROHC_EXPORT ipv4_set_df(struct ip_packet *const ip, const int value) 00480 __attribute__((nonnull(1))); 00481 00482 /* IPv6 specific functions */ 00483 00484 const struct ipv6_hdr * ROHC_EXPORT ipv6_get_header(const struct ip_packet *const ip) 00485 __attribute__((warn_unused_result, nonnull(1), pure)); 00486 uint32_t ROHC_EXPORT ipv6_get_flow_label(const struct ip_packet *const ip) 00487 __attribute__((warn_unused_result, nonnull(1), pure)); 00488 const struct ipv6_addr * ROHC_EXPORT ipv6_get_saddr(const struct ip_packet *const ip) 00489 __attribute__((warn_unused_result, nonnull(1), pure)); 00490 const struct ipv6_addr * ROHC_EXPORT ipv6_get_daddr(const struct ip_packet *const ip) 00491 __attribute__((warn_unused_result, nonnull(1), pure)); 00492 void ROHC_EXPORT ipv6_set_flow_label(struct ip_packet *const ip, 00493 const uint32_t value) 00494 __attribute__((nonnull(1))); 00495 unsigned short ROHC_EXPORT ip_get_extension_size(const uint8_t *const ext) 00496 __attribute__((warn_unused_result, nonnull(1))); 00497 unsigned short ROHC_EXPORT ip_get_total_extension_size(const struct ip_packet *const ip) 00498 __attribute__((warn_unused_result, nonnull(1))); 00499 00500 /* Private functions (do not use directly) */ 00501 bool get_ip_version(const uint8_t *const packet, 00502 const size_t size, 00503 ip_version *const version) 00504 __attribute__((warn_unused_result, nonnull(1, 3))); 00505 00506 00507 #endif 00508