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