ROHC compression/decompression library
ip.h
Go to the documentation of this file.
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