ROHC compression/decompression library
ip.h
Go to the documentation of this file.
00001 /*
00002  * Copyright 2012,2013,2014 Didier Barvaux
00003  * Copyright 2007,2008 Thales Alenia Space
00004  * Copyright 2007,2009,2010,2013,2014 Viveris Technologies
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /**
00022  * @file   common/ip.h
00023  * @brief  IP-agnostic packet
00024  * @author Didier Barvaux <didier.barvaux@toulouse.viveris.com>
00025  */
00026 
00027 #ifndef ROHC_COMMON_IP_H
00028 #define ROHC_COMMON_IP_H
00029 
00030 #include "dllexport.h"
00031 #include "protocols/ipv4.h"
00032 #include "protocols/ipv6.h"
00033 
00034 #include <stdlib.h>
00035 #include <stdint.h>
00036 #ifdef __KERNEL__
00037 #       include <linux/types.h>
00038 #else
00039 #       include <stdbool.h>
00040 #endif
00041 
00042 
00043 /** The selected IP header */
00044 typedef enum
00045 {
00046         ROHC_IP_HDR_NONE   = 0,  /**< No IP header selected */
00047         ROHC_IP_HDR_FIRST  = 1,  /**< The first IP header is selected */
00048         ROHC_IP_HDR_SECOND = 2,  /**< The second IP header is selected */
00049         /* max 2 IP headers hanlded at the moment */
00050 } ip_header_pos_t;
00051 
00052 
00053 /// IP version
00054 typedef enum
00055 {
00056         /// IP version 4
00057         IPV4 = 4,
00058         /// IP version 6
00059         IPV6 = 6,
00060         /// not IP
00061         IP_UNKNOWN = 0,
00062         /// IP version 4 (malformed)
00063         IPV4_MALFORMED = 1,
00064         /// IP version 6 (malformed)
00065         IPV6_MALFORMED = 2,
00066 } ip_version;
00067 
00068 
00069 /** A network header */
00070 struct net_hdr
00071 {
00072         uint8_t proto;  /**< The header protocol */
00073         uint8_t *data;  /**< The header data */
00074         size_t len;     /**< The header length (in bytes) */
00075 };
00076 
00077 
00078 /**
00079  * @brief Defines an IP-agnostic packet that can handle
00080  *        an IPv4 or IPv6 packet
00081  */
00082 struct ip_packet
00083 {
00084         /// The version of the IP packet
00085         ip_version version;
00086 
00087         /// The IP header
00088         union
00089         {
00090                 /// The IPv4 header
00091                 struct ipv4_hdr v4;
00092                 /// The IPv6 header
00093                 struct ipv6_hdr v6;
00094         } header;
00095 
00096         /// The whole IP data (header + payload) if not NULL
00097         const uint8_t *data;
00098 
00099         /// The length (in bytes) of the whole IP data (header + payload)
00100         size_t size;
00101 
00102         struct net_hdr nh;  /**< The next header (extension headers included) */
00103         struct net_hdr nl;  /**< The next layer (extension headers excluded) */
00104 };
00105 
00106 
00107 /*
00108  * Generic IP macros:
00109  */
00110 
00111 /// Get a subpart of a 16-bit IP field
00112 #define IP_GET_16_SUBFIELD(field, bitmask, offset) \
00113         ((rohc_ntoh16(field) & (bitmask)) >> (offset))
00114 
00115 /// Get a subpart of a 32-bit IP field
00116 #define IP_GET_32_SUBFIELD(field, bitmask, offset) \
00117         ((rohc_ntoh32(field) & (bitmask)) >> (offset))
00118 
00119 /// Set a subpart of a 16-bit IP field
00120 #define IP_SET_16_SUBFIELD(field, bitmask, offset, value) \
00121         (field) = (((field) & rohc_hton16(~(bitmask))) | \
00122                    rohc_hton16(((value) << (offset)) & (bitmask)))
00123 
00124 /// Set a subpart of a 32-bit IP field
00125 #define IP_SET_32_SUBFIELD(field, bitmask, offset, value) \
00126         (field) = (((field) & rohc_hton32(~(bitmask))) | \
00127                    rohc_hton32(((value) << (offset)) & (bitmask)))
00128 
00129 
00130 /*
00131  * IPv4 definitions & macros:
00132  */
00133 
00134 /// The offset for the DF flag in an ipv4_hdr->frag_off variable
00135 #define IPV4_DF_OFFSET  14
00136 
00137 /// Get the IPv4 Don't Fragment (DF) bit from an ipv4_hdr object
00138 #define IPV4_GET_DF(ip4) \
00139         IP_GET_16_SUBFIELD((ip4).frag_off, IP_DF, IPV4_DF_OFFSET)
00140 
00141 /// Set the IPv4 Don't Fragment (DF) bit in an ipv4_hdr object
00142 #define IPV4_SET_DF(ip4, value) \
00143         IP_SET_16_SUBFIELD((ip4)->frag_off, IP_DF, IPV4_DF_OFFSET, (value))
00144 
00145 /// The format to print an IPv4 address
00146 #define IPV4_ADDR_FORMAT \
00147         "%02x%02x%02x%02x (%u.%u.%u.%u)"
00148 
00149 /// The data to print an IPv4 address in raw format
00150 #define IPV4_ADDR_RAW(x) \
00151         (x)[0], (x)[1], (x)[2], (x)[3], \
00152         (x)[0], (x)[1], (x)[2], (x)[3]
00153 
00154 
00155 /*
00156  * IPv6 definitions & macros:
00157  */
00158 
00159 /// The bitmask for the Version field in an ipv6_hdr->ip6_flow variable
00160 #define IPV6_VERSION_MASK  0xf0000000
00161 /// The offset for the Version field in an ipv6_hdr->ip6_flow variable
00162 #define IPV6_VERSION_OFFSET  28
00163 
00164 /// The bitmask for the Traffic Class (TC) field in an ipv6_hdr->ip6_flow variable
00165 #define IPV6_TC_MASK  0x0ff00000
00166 /// The offset for the Traffic Class (TC) field in an ipv6_hdr->ip6_flow variable
00167 #define IPV6_TC_OFFSET  20
00168 
00169 /// The bitmask for the FLow Label field in an ipv6_hdr->ip6_flow variable
00170 #define IPV6_FLOW_LABEL_MASK  0x000fffff
00171 
00172 /// Get the IPv6 Version 4-bit field from ipv6_hdr object
00173 #define IPV6_GET_VERSION(ip6) \
00174         IP_GET_32_SUBFIELD((ip6).ip6_flow, IPV6_VERSION_MASK, IPV6_VERSION_OFFSET)
00175 
00176 /// Set the IPv6 Version 4-bit field in an ipv6_hdr object
00177 #define IPV6_SET_VERSION(ip6, value) \
00178         IP_SET_32_SUBFIELD((ip6)->ip6_flow, IPV6_VERSION_MASK, IPV6_VERSION_OFFSET, (value))
00179 
00180 /// Get the IPv6 Traffic Class (TC) byte from an ipv6_hdr object
00181 #define IPV6_GET_TC(ip6) \
00182         IP_GET_32_SUBFIELD((ip6).ip6_flow, IPV6_TC_MASK, IPV6_TC_OFFSET)
00183 
00184 /// Set the IPv6 Traffic Class (TC) byte in an ipv6_hdr object
00185 #define IPV6_SET_TC(ip6, value) \
00186         IP_SET_32_SUBFIELD((ip6)->ip6_flow, IPV6_TC_MASK, IPV6_TC_OFFSET, (value))
00187 
00188 /// Get the IPv6 Flow Label 20-bit field from an ipv6_hdr object
00189 #define IPV6_GET_FLOW_LABEL(ip6) \
00190         IP_GET_32_SUBFIELD((ip6).ip6_flow, IPV6_FLOW_LABEL_MASK, 0)
00191 
00192 /// Set the IPv6 Flow Label 20-bit field in an ipv6_hdr variable
00193 #define IPV6_SET_FLOW_LABEL(ip6, value) \
00194         IP_SET_32_SUBFIELD((ip6)->ip6_flow, IPV6_FLOW_LABEL_MASK, 0, (value))
00195 
00196 /// The format to print an IPv6 address
00197 #define IPV6_ADDR_FORMAT \
00198         "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
00199 
00200 /// The data to print an IPv6 address in (struct ipv6_addr *) format
00201 #define IPV6_ADDR_IN6(x) \
00202         IPV6_ADDR_RAW((x)->addr.u8)
00203 
00204 /// The data to print an IPv6 address in raw format
00205 #define IPV6_ADDR_RAW(x) \
00206         (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5], (x)[6], (x)[7], \
00207         (x)[8], (x)[9], (x)[10], (x)[11], (x)[12], (x)[13], (x)[14], (x)[15]
00208 
00209 /// Compare two IPv6 addresses in (struct ipv6_addr *) format
00210 #define IPV6_ADDR_CMP(x, y) \
00211         ((x)->addr.u32[0] == (y)->addr.u32[0] && \
00212          (x)->addr.u32[1] == (y)->addr.u32[1] && \
00213          (x)->addr.u32[2] == (y)->addr.u32[2] && \
00214          (x)->addr.u32[3] == (y)->addr.u32[3])
00215 
00216 
00217 /*
00218  * Inline functions
00219  */
00220 
00221 #ifndef __KERNEL__ /* already provided by Linux kernel */
00222 
00223 static inline uint16_t swab16(const uint16_t value)
00224         __attribute__((warn_unused_result, const));
00225 
00226 /**
00227  * @brief In-place change the byte order in a two-byte value.
00228  *
00229  * @param value The two-byte value to modify
00230  * @return      The same value with the byte order changed
00231  */
00232 static inline uint16_t swab16(const uint16_t value)
00233 {
00234         return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8);
00235 }
00236 
00237 
00238 #ifdef __i386__
00239 
00240 static inline uint16_t ip_fast_csum(const uint8_t *iph,
00241                                     size_t ihl)
00242         __attribute__((nonnull(1), warn_unused_result, pure));
00243 
00244 /**
00245  * @brief This is a version of ip_compute_csum() optimized for IP headers,
00246  *        which always checksum on 4 octet boundaries.
00247  *
00248  * @author Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
00249  *         Arnt Gulbrandsen.
00250  *
00251  * @param iph The IPv4 header
00252  * @param ihl The length of the IPv4 header
00253  * @return    The IPv4 checksum
00254  */
00255 static inline uint16_t ip_fast_csum(const uint8_t *iph,
00256                                     size_t ihl)
00257 {
00258         uint32_t sum;
00259 
00260         __asm__ __volatile__(
00261            " \n\
00262        movl (%1), %0      \n\
00263        subl $4, %2              \n\
00264        jbe 2f           \n\
00265        addl 4(%1), %0   \n\
00266        adcl 8(%1), %0   \n\
00267        adcl 12(%1), %0  \n\
00268 1:     adcl 16(%1), %0  \n\
00269        lea 4(%1), %1    \n\
00270        decl %2          \n\
00271        jne 1b           \n\
00272        adcl $0, %0              \n\
00273        movl %0, %2              \n\
00274        shrl $16, %0     \n\
00275        addw %w2, %w0    \n\
00276        adcl $0, %0              \n\
00277        notl %0          \n\
00278 2:     \n\
00279        "
00280            /* Since the input registers which are loaded with iph and ihl
00281               are modified, we must also specify them as outputs, or gcc
00282               will assume they contain their original values. */
00283                 : "=r" (sum), "=r" (iph), "=r" (ihl)
00284                 : "1" (iph), "2" (ihl)
00285                 : "memory");
00286 
00287         return (uint16_t) (sum & 0xffff);
00288 }
00289 
00290 
00291 #else
00292 
00293 static inline uint16_t from32to16(const uint32_t x)
00294         __attribute__((warn_unused_result, const));
00295 
00296 static inline uint16_t from32to16(const uint32_t x)
00297 {
00298         uint32_t y;
00299         /* add up 16-bit and 16-bit for 16+c bit */
00300         y = (x & 0xffff) + (x >> 16);
00301         /* add up carry.. */
00302         y = (y & 0xffff) + (y >> 16);
00303         return y;
00304 }
00305 
00306 static inline uint16_t ip_fast_csum(const uint8_t *const iph,
00307                                     const size_t ihl)
00308         __attribute__((nonnull(1), warn_unused_result, pure));
00309 
00310 /**
00311  *  This is a version of ip_compute_csum() optimized for IP headers,
00312  *  which always checksum on 4 octet boundaries.
00313  */
00314 static inline uint16_t ip_fast_csum(const uint8_t *const iph,
00315                                     const size_t ihl)
00316 {
00317         const uint8_t *buff = iph;
00318         size_t len = ihl * 4;
00319         bool odd;
00320         size_t count;
00321         uint32_t result = 0;
00322 
00323         if(len <= 0)
00324         {
00325                 goto out;
00326         }
00327         odd = 1 & (uintptr_t) buff;
00328         if(odd)
00329         {
00330 #ifdef __LITTLE_ENDIAN
00331                 result = *buff;
00332 #else
00333                 result += (*buff << 8);
00334 #endif
00335                 len--;
00336                 buff++;
00337         }
00338         count = len >> 1; /* nr of 16-bit words.. */
00339         if(count)
00340         {
00341                 if(2 & (uintptr_t) buff)
00342                 {
00343                         result += *(uint16_t *) buff;
00344                         count--;
00345                         len -= 2;
00346                         buff += 2;
00347                 }
00348                 count >>= 1; /* nr of 32-bit words.. */
00349                 if(count)
00350                 {
00351                         uint32_t carry = 0;
00352                         do
00353                         {
00354                                 uint32_t word = *(uint32_t *) buff;
00355                                 count--;
00356                                 buff += sizeof(uint32_t);
00357                                 result += carry;
00358                                 result += word;
00359                                 carry = (word > result);
00360                         }
00361                         while(count);
00362                         result += carry;
00363                         result = (result & 0xffff) + (result >> 16);
00364                 }
00365                 if(len & 2)
00366                 {
00367                         result += *(uint16_t *) buff;
00368                         buff += 2;
00369                 }
00370         }
00371         if(len & 1)
00372         {
00373 #ifdef __LITTLE_ENDIAN
00374                 result += *buff;
00375 #else
00376                 result += (*buff << 8);
00377 #endif
00378         }
00379         result = from32to16(result);
00380         if(odd)
00381         {
00382                 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
00383         }
00384 out:
00385         return ~result;
00386 }
00387 
00388 
00389 #endif /* !__i386__ */
00390 
00391 #else /* !__KERNEL__ */
00392 #       include <asm/checksum.h>
00393 #endif /* __KERNEL__ */
00394 
00395 
00396 /*
00397  * Function prototypes.
00398  */
00399 
00400 /* Generic functions */
00401 
00402 bool ROHC_EXPORT ip_create(struct ip_packet *const ip,
00403                            const uint8_t *const packet,
00404                            const size_t size)
00405         __attribute__((warn_unused_result, nonnull(1, 2)));
00406 bool ROHC_EXPORT ip_get_inner_packet(const struct ip_packet *const outer,
00407                                      struct ip_packet *const inner)
00408         __attribute__((warn_unused_result, nonnull(1, 2)));
00409 
00410 const uint8_t * ROHC_EXPORT ip_get_raw_data(const struct ip_packet *const ip)
00411         __attribute__((warn_unused_result, nonnull(1)));
00412 uint8_t * ROHC_EXPORT ip_get_next_header(const struct ip_packet *const ip,
00413                                                uint8_t *const type)
00414         __attribute__((warn_unused_result, nonnull(1, 2)));
00415 uint8_t * ROHC_EXPORT ip_get_next_layer(const struct ip_packet *const ip)
00416         __attribute__((warn_unused_result, nonnull(1)));
00417 uint8_t * ROHC_EXPORT ip_get_next_ext_from_ip(const struct ip_packet *const ip,
00418                                                     uint8_t *const type)
00419         __attribute__((warn_unused_result, nonnull(1, 2)));
00420 uint8_t * ROHC_EXPORT ip_get_next_ext_from_ext(const uint8_t *const ext,
00421                                                      uint8_t *const type)
00422         __attribute__((warn_unused_result, nonnull(1, 2)));
00423 
00424 unsigned int ROHC_EXPORT ip_get_totlen(const struct ip_packet *const ip)
00425         __attribute__((warn_unused_result, nonnull(1)));
00426 unsigned int ROHC_EXPORT ip_get_hdrlen(const struct ip_packet *const ip)
00427         __attribute__((warn_unused_result, nonnull(1)));
00428 unsigned int ROHC_EXPORT ip_get_plen(const struct ip_packet *const ip)
00429         __attribute__((warn_unused_result, nonnull(1)));
00430 
00431 bool ROHC_EXPORT ip_is_fragment(const struct ip_packet *const ip)
00432         __attribute__((warn_unused_result, nonnull(1), pure));
00433 ip_version ROHC_EXPORT ip_get_version(const struct ip_packet *const ip)
00434         __attribute__((warn_unused_result, nonnull(1), pure));
00435 uint8_t ROHC_EXPORT ip_get_protocol(const struct ip_packet *const ip)
00436         __attribute__((warn_unused_result, nonnull(1), pure));
00437 unsigned int ROHC_EXPORT ip_get_tos(const struct ip_packet *const ip)
00438         __attribute__((warn_unused_result, nonnull(1), pure));
00439 unsigned int ROHC_EXPORT ip_get_ttl(const struct ip_packet *const ip)
00440         __attribute__((warn_unused_result, nonnull(1), pure));
00441 
00442 void ROHC_EXPORT ip_set_version(struct ip_packet *const ip,
00443                                 const ip_version value)
00444         __attribute__((nonnull(1)));
00445 void ROHC_EXPORT ip_set_protocol(struct ip_packet *const ip,
00446                                  const uint8_t value)
00447         __attribute__((nonnull(1)));
00448 void ROHC_EXPORT ip_set_tos(struct ip_packet *const ip,
00449                             const uint8_t value)
00450         __attribute__((nonnull(1)));
00451 void ROHC_EXPORT ip_set_ttl(struct ip_packet *const ip,
00452                             const uint8_t value)
00453         __attribute__((nonnull(1)));
00454 void ROHC_EXPORT ip_set_saddr(struct ip_packet *const ip,
00455                               const uint8_t *value)
00456         __attribute__((nonnull(1, 2)));
00457 void ROHC_EXPORT ip_set_daddr(struct ip_packet *const ip,
00458                               const uint8_t *value)
00459         __attribute__((nonnull(1, 2)));
00460 
00461 /* IPv4 specific functions */
00462 
00463 const struct ipv4_hdr * ROHC_EXPORT ipv4_get_header(const struct ip_packet *const ip)
00464         __attribute__((warn_unused_result, nonnull(1), pure));
00465 uint16_t ROHC_EXPORT ipv4_get_id(const struct ip_packet *const ip)
00466         __attribute__((warn_unused_result, nonnull(1), pure));
00467 uint16_t ROHC_EXPORT ipv4_get_id_nbo(const struct ip_packet *const ip,
00468                                      const unsigned int nbo)
00469         __attribute__((warn_unused_result, nonnull(1), pure));
00470 int ROHC_EXPORT ipv4_get_df(const struct ip_packet *const ip)
00471         __attribute__((warn_unused_result, nonnull(1), pure));
00472 uint32_t ROHC_EXPORT ipv4_get_saddr(const struct ip_packet *const ip)
00473         __attribute__((warn_unused_result, nonnull(1), pure));
00474 uint32_t ROHC_EXPORT ipv4_get_daddr(const struct ip_packet *const ip)
00475         __attribute__((warn_unused_result, nonnull(1), pure));
00476 
00477 void ROHC_EXPORT ipv4_set_id(struct ip_packet *const ip, const int value)
00478         __attribute__((nonnull(1)));
00479 void ROHC_EXPORT ipv4_set_df(struct ip_packet *const ip, const int value)
00480         __attribute__((nonnull(1)));
00481 
00482 /* IPv6 specific functions */
00483 
00484 const struct ipv6_hdr * ROHC_EXPORT ipv6_get_header(const struct ip_packet *const ip)
00485         __attribute__((warn_unused_result, nonnull(1), pure));
00486 uint32_t ROHC_EXPORT ipv6_get_flow_label(const struct ip_packet *const ip)
00487         __attribute__((warn_unused_result, nonnull(1), pure));
00488 const struct ipv6_addr * ROHC_EXPORT ipv6_get_saddr(const struct ip_packet *const ip)
00489         __attribute__((warn_unused_result, nonnull(1), pure));
00490 const struct ipv6_addr * ROHC_EXPORT ipv6_get_daddr(const struct ip_packet *const ip)
00491         __attribute__((warn_unused_result, nonnull(1), pure));
00492 void ROHC_EXPORT ipv6_set_flow_label(struct ip_packet *const ip,
00493                                      const uint32_t value)
00494         __attribute__((nonnull(1)));
00495 unsigned short ROHC_EXPORT ip_get_extension_size(const uint8_t *const ext)
00496         __attribute__((warn_unused_result, nonnull(1)));
00497 unsigned short ROHC_EXPORT ip_get_total_extension_size(const struct ip_packet *const ip)
00498         __attribute__((warn_unused_result, nonnull(1)));
00499 
00500 /* Private functions (do not use directly) */
00501 bool get_ip_version(const uint8_t *const packet,
00502                     const size_t size,
00503                     ip_version *const version)
00504         __attribute__((warn_unused_result, nonnull(1, 3)));
00505 
00506 
00507 #endif
00508