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