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