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   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