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