On 2015-05-22 14:44, alexandru.badici...@linaro.org wrote:
> From: Alexandru Badicioiu <alexandru.badici...@linaro.org>
> 
> v1 - added comment for tunnel DB entry use
> v2 - fixed tun pointer initialization, new checkpatch compliance

This should not be in the changelog.

Anders

> 
> Tunnel mode is enabled from the command line using -t argument with
> the following format: SrcIP:DstIP:TunnelSrcIP:TunnelDstIP.
> SrcIP - cleartext packet source IP
> DstIP - cleartext packet destination IP
> TunnelSrcIP - tunnel source IP
> TunnelDstIP - tunnel destination IP
> 
> The outbound packets matching SrcIP:DstIP will be encapsulated
> in a TunnelSrcIP:TunnelDstIP IPSec tunnel (AH/ESP/AH+ESP)
> if a matching outbound SA is determined (as for transport mode).
> For inbound packets each entry in the IPSec cache is matched
> for the cleartext addresses, as in the transport mode (SrcIP:DstIP)
> and then for the tunnel addresses (TunnelSrcIP:TunnelDstIP)
> in case cleartext addresses didn't match. After authentication and
> decryption tunneled packets are verified against the tunnel entry
> (packets came in from the expected tunnel).
> 
> Signed-off-by: Alexandru Badicioiu <alexandru.badici...@linaro.org>
> Reviewed-by: Steve Kordus <skor...@cisco.com>
> ---
>  example/ipsec/odp_ipsec.c        |  107 +++++++++++++++++++++++++++---
>  example/ipsec/odp_ipsec_cache.c  |   32 +++++++++-
>  example/ipsec/odp_ipsec_cache.h  |    6 ++
>  example/ipsec/odp_ipsec_sa_db.c  |  134 
> +++++++++++++++++++++++++++++++++++++-
>  example/ipsec/odp_ipsec_sa_db.h  |   55 ++++++++++++++++
>  example/ipsec/odp_ipsec_stream.c |  102 ++++++++++++++++++++++++----
>  6 files changed, 406 insertions(+), 30 deletions(-)
> 
> diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c
> index 99ccd6b..ed56e14 100644
> --- a/example/ipsec/odp_ipsec.c
> +++ b/example/ipsec/odp_ipsec.c
> @@ -135,13 +135,20 @@ typedef struct {
>       uint8_t  ip_ttl;         /**< Saved IP TTL value */
>       int      hdr_len;        /**< Length of IPsec headers */
>       int      trl_len;        /**< Length of IPsec trailers */
> +     uint16_t tun_hdr_offset; /**< Offset of tunnel header from
> +                                   buffer start */
>       uint16_t ah_offset;      /**< Offset of AH header from buffer start */
>       uint16_t esp_offset;     /**< Offset of ESP header from buffer start */
>  
> +     /* Input only */
> +     uint32_t src_ip;         /**< SA source IP address */
> +     uint32_t dst_ip;         /**< SA dest IP address */
> +
>       /* Output only */
>       odp_crypto_op_params_t params;  /**< Parameters for crypto call */
>       uint32_t *ah_seq;               /**< AH sequence number location */
>       uint32_t *esp_seq;              /**< ESP sequence number location */
> +     uint16_t *tun_hdr_id;           /**< Tunnel header ID > */
>  } ipsec_ctx_t;
>  
>  /**
> @@ -357,6 +364,7 @@ void ipsec_init_pre(void)
>       /* Initialize our data bases */
>       init_sp_db();
>       init_sa_db();
> +     init_tun_db();
>       init_ipsec_cache();
>  }
>  
> @@ -376,19 +384,27 @@ void ipsec_init_post(crypto_api_mode_e api_mode)
>       for (entry = sp_db->list; NULL != entry; entry = entry->next) {
>               sa_db_entry_t *cipher_sa = NULL;
>               sa_db_entry_t *auth_sa = NULL;
> +             tun_db_entry_t *tun = NULL;
>  
> -             if (entry->esp)
> +             if (entry->esp) {
>                       cipher_sa = find_sa_db_entry(&entry->src_subnet,
>                                                    &entry->dst_subnet,
>                                                    1);
> -             if (entry->ah)
> +                     tun = find_tun_db_entry(cipher_sa->src_ip,
> +                                             cipher_sa->dst_ip);
> +             }
> +             if (entry->ah) {
>                       auth_sa = find_sa_db_entry(&entry->src_subnet,
>                                                  &entry->dst_subnet,
>                                                  0);
> +                     tun = find_tun_db_entry(auth_sa->src_ip,
> +                                             auth_sa->dst_ip);
> +             }
>  
>               if (cipher_sa || auth_sa) {
>                       if (create_ipsec_cache_entry(cipher_sa,
>                                                    auth_sa,
> +                                                  tun,
>                                                    api_mode,
>                                                    entry->input,
>                                                    completionq,
> @@ -670,6 +686,8 @@ pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt,
>       ctx->ipsec.esp_offset = esp ? ((uint8_t *)esp) - buf : 0;
>       ctx->ipsec.hdr_len = hdr_len;
>       ctx->ipsec.trl_len = 0;
> +     ctx->ipsec.src_ip = entry->src_ip;
> +     ctx->ipsec.dst_ip = entry->dst_ip;
>  
>       /*If authenticating, zero the mutable fields build the request */
>       if (ah) {
> @@ -750,6 +768,24 @@ pkt_disposition_e do_ipsec_in_finish(odp_packet_t pkt,
>               trl_len += esp_t->pad_len + sizeof(*esp_t);
>       }
>  
> +     /* We have a tunneled IPv4 packet */
> +     if (ip->proto == ODPH_IPV4) {
> +             odp_packet_pull_head(pkt, sizeof(*ip) + hdr_len);
> +             odp_packet_pull_tail(pkt, trl_len);
> +             odph_ethhdr_t *eth;
> +
> +             eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL);
> +             eth->type = ODPH_ETHTYPE_IPV4;
> +             ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
> +
> +             /* Check inbound policy */
> +             if ((ip->src_addr != ctx->ipsec.src_ip ||
> +                  ip->dst_addr != ctx->ipsec.dst_ip))
> +                     return PKT_DROP;
> +
> +             return PKT_CONTINUE;
> +     }
> +
>       /* Finalize the IPv4 header */
>       ipv4_adjust_len(ip, -(hdr_len + trl_len));
>       ip->ttl = ctx->ipsec.ip_ttl;
> @@ -821,9 +857,13 @@ pkt_disposition_e do_ipsec_out_classify(odp_packet_t pkt,
>       params.pkt = pkt;
>       params.out_pkt = entry->in_place ? pkt : ODP_PACKET_INVALID;
>  
> +     if (entry->mode == IPSEC_SA_MODE_TUNNEL) {
> +             hdr_len += sizeof(odph_ipv4hdr_t);
> +             ip_data = (uint8_t *)ip;
> +     }
>       /* Compute ah and esp, determine length of headers, move the data */
>       if (entry->ah.alg) {
> -             ah = (odph_ahhdr_t *)(ip_data);
> +             ah = (odph_ahhdr_t *)(ip_data + hdr_len);
>               hdr_len += sizeof(odph_ahhdr_t);
>               hdr_len += entry->ah.icv_len;
>       }
> @@ -835,21 +875,39 @@ pkt_disposition_e do_ipsec_out_classify(odp_packet_t 
> pkt,
>       memmove(ip_data + hdr_len, ip_data, ip_data_len);
>       ip_data += hdr_len;
>  
> +     /* update outer header in tunnel mode */
> +     if (entry->mode == IPSEC_SA_MODE_TUNNEL) {
> +             /* tunnel addresses */
> +             ip->src_addr = odp_cpu_to_be_32(entry->tun_src_ip);
> +             ip->dst_addr = odp_cpu_to_be_32(entry->tun_dst_ip);
> +     }
> +
>       /* For cipher, compute encrypt length, build headers and request */
>       if (esp) {
>               uint32_t encrypt_len;
>               odph_esptrl_t *esp_t;
>  
> -             encrypt_len = ESP_ENCODE_LEN(ip_data_len + sizeof(*esp_t),
> -                                          entry->esp.block_len);
> -             trl_len = encrypt_len - ip_data_len;
> +             if (entry->mode == IPSEC_SA_MODE_TUNNEL) {
> +                     encrypt_len = ESP_ENCODE_LEN(ip->tot_len +
> +                                                  sizeof(*esp_t),
> +                                                  entry->esp.block_len);
> +                     trl_len = encrypt_len - ip->tot_len;
> +             } else {
> +                     encrypt_len = ESP_ENCODE_LEN(ip_data_len +
> +                                                  sizeof(*esp_t),
> +                                                  entry->esp.block_len);
> +                     trl_len = encrypt_len - ip_data_len;
> +             }
>  
>               esp->spi = odp_cpu_to_be_32(entry->esp.spi);
>               memcpy(esp + 1, entry->state.iv, entry->esp.iv_len);
>  
>               esp_t = (odph_esptrl_t *)(ip_data + encrypt_len) - 1;
>               esp_t->pad_len     = trl_len - sizeof(*esp_t);
> -             esp_t->next_header = ip->proto;
> +             if (entry->mode == IPSEC_SA_MODE_TUNNEL)
> +                     esp_t->next_header = ODPH_IPV4;
> +             else
> +                     esp_t->next_header = ip->proto;
>               ip->proto = ODPH_IPPROTO_ESP;
>  
>               params.cipher_range.offset = ip_data - buf;
> @@ -861,7 +919,10 @@ pkt_disposition_e do_ipsec_out_classify(odp_packet_t pkt,
>               memset(ah, 0, sizeof(*ah) + entry->ah.icv_len);
>               ah->spi = odp_cpu_to_be_32(entry->ah.spi);
>               ah->ah_len = 1 + (entry->ah.icv_len / 4);
> -             ah->next_header = ip->proto;
> +             if (entry->mode == IPSEC_SA_MODE_TUNNEL && !esp)
> +                     ah->next_header = ODPH_IPV4;
> +             else
> +                     ah->next_header = ip->proto;
>               ip->proto = ODPH_IPPROTO_AH;
>  
>               ip->chksum = 0;
> @@ -884,8 +945,11 @@ pkt_disposition_e do_ipsec_out_classify(odp_packet_t pkt,
>       ctx->ipsec.trl_len = trl_len;
>       ctx->ipsec.ah_offset = ah ? ((uint8_t *)ah) - buf : 0;
>       ctx->ipsec.esp_offset = esp ? ((uint8_t *)esp) - buf : 0;
> +     ctx->ipsec.tun_hdr_offset = (entry->mode == IPSEC_SA_MODE_TUNNEL) ?
> +                                    ((uint8_t *)ip - buf) : 0;
>       ctx->ipsec.ah_seq = &entry->state.ah_seq;
>       ctx->ipsec.esp_seq = &entry->state.esp_seq;
> +     ctx->ipsec.tun_hdr_id = &entry->state.tun_hdr_id;
>       memcpy(&ctx->ipsec.params, &params, sizeof(params));
>  
>       *skip = FALSE;
> @@ -924,6 +988,21 @@ pkt_disposition_e do_ipsec_out_seq(odp_packet_t pkt,
>               esp = (odph_esphdr_t *)(ctx->ipsec.esp_offset + buf);
>               esp->seq_no = odp_cpu_to_be_32((*ctx->ipsec.esp_seq)++);
>       }
> +     if (ctx->ipsec.tun_hdr_offset) {
> +             odph_ipv4hdr_t *ip;
> +             int ret;
> +
> +             ip = (odph_ipv4hdr_t *)(ctx->ipsec.tun_hdr_offset + buf);
> +             ip->id = odp_cpu_to_be_16((*ctx->ipsec.tun_hdr_id)++);
> +             if (!ip->id) {
> +                     /* re-init tunnel hdr id */
> +                     ret = odp_random_data((uint8_t *)ctx->ipsec.tun_hdr_id,
> +                                           sizeof(*ctx->ipsec.tun_hdr_id),
> +                                           1);
> +                     if (ret != sizeof(*ctx->ipsec.tun_hdr_id))
> +                             abort();
> +             }
> +     }
>  
>       /* Issue crypto request */
>       if (odp_crypto_operation(&ctx->ipsec.params,
> @@ -1315,8 +1394,9 @@ static void parse_args(int argc, char *argv[], 
> appl_args_t *appl_args)
>               {"mode", required_argument, NULL, 'm'},         /* return 'm' */
>               {"route", required_argument, NULL, 'r'},        /* return 'r' */
>               {"policy", required_argument, NULL, 'p'},       /* return 'p' */
> -             {"ah", required_argument, NULL, 'a'},           /* return 'a' */
> -             {"esp", required_argument, NULL, 'e'},          /* return 'e' */
> +             {"ah", required_argument, NULL, 'a'},           /* return 'a' */
> +             {"esp", required_argument, NULL, 'e'},          /* return 'e' */
> +             {"tunnel", required_argument, NULL, 't'},       /* return 't' */
>               {"stream", required_argument, NULL, 's'},       /* return 's' */
>               {"help", no_argument, NULL, 'h'},               /* return 'h' */
>               {NULL, 0, NULL, 0}
> @@ -1327,7 +1407,7 @@ static void parse_args(int argc, char *argv[], 
> appl_args_t *appl_args)
>       appl_args->mode = 0;  /* turn off async crypto API by default */
>  
>       while (!rc) {
> -             opt = getopt_long(argc, argv, "+c:i:m:h:r:p:a:e:s:",
> +             opt = getopt_long(argc, argv, "+c:i:m:h:r:p:a:e:t:s:",
>                                 longopts, &long_index);
>  
>               if (-1 == opt)
> @@ -1398,6 +1478,10 @@ static void parse_args(int argc, char *argv[], 
> appl_args_t *appl_args)
>                       rc = create_sa_db_entry(optarg, TRUE);
>                       break;
>  
> +             case 't':
> +                     rc = create_tun_db_entry(optarg);
> +                     break;
> +
>               case 's':
>                       rc = create_stream_db_entry(optarg);
>                       break;
> @@ -1458,6 +1542,7 @@ static void print_info(char *progname, appl_args_t 
> *appl_args)
>       dump_fwd_db();
>       dump_sp_db();
>       dump_sa_db();
> +     dump_tun_db();
>       printf("\n\n");
>       fflush(NULL);
>  }
> diff --git a/example/ipsec/odp_ipsec_cache.c b/example/ipsec/odp_ipsec_cache.c
> index 12b960d..6a8f3c9 100644
> --- a/example/ipsec/odp_ipsec_cache.c
> +++ b/example/ipsec/odp_ipsec_cache.c
> @@ -38,6 +38,7 @@ void init_ipsec_cache(void)
>  
>  int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
>                            sa_db_entry_t *auth_sa,
> +                          tun_db_entry_t *tun,
>                            crypto_api_mode_e api_mode,
>                            odp_bool_t in,
>                            odp_queue_t completionq,
> @@ -47,12 +48,18 @@ int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
>       ipsec_cache_entry_t *entry;
>       enum odp_crypto_ses_create_err ses_create_rc;
>       odp_crypto_session_t session;
> +     sa_mode_t mode = IPSEC_SA_MODE_TRANSPORT;
>  
>       /* Verify we have a good entry */
>       entry = &ipsec_cache->array[ipsec_cache->index];
>       if (MAX_DB <= ipsec_cache->index)
>               return -1;
>  
> +     /* Verify SA mode match in case of cipher&auth */
> +     if (cipher_sa && auth_sa &&
> +         (cipher_sa->mode != auth_sa->mode))
> +             return -1;
> +
>       /* Setup parameters and call crypto library to create session */
>       params.op = (in) ? ODP_CRYPTO_OP_DECODE : ODP_CRYPTO_OP_ENCODE;
>       params.auth_cipher_text = TRUE;
> @@ -79,6 +86,7 @@ int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
>               params.cipher_key.length  = cipher_sa->key.length;
>               params.iv.data = entry->state.iv;
>               params.iv.length = cipher_sa->iv_len;
> +             mode = cipher_sa->mode;
>       } else {
>               params.cipher_alg = ODP_CIPHER_ALG_NULL;
>               params.iv.data = NULL;
> @@ -90,6 +98,7 @@ int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
>               params.auth_alg = auth_sa->alg.u.auth;
>               params.auth_key.data = auth_sa->key.data;
>               params.auth_key.length = auth_sa->key.length;
> +             mode = auth_sa->mode;
>       } else {
>               params.auth_alg = ODP_AUTH_ALG_NULL;
>       }
> @@ -128,6 +137,25 @@ int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
>               memcpy(&entry->ah.key, &auth_sa->key, sizeof(ipsec_key_t));
>       }
>  
> +     if (tun) {
> +             entry->tun_src_ip = tun->tun_src_ip;
> +             entry->tun_dst_ip = tun->tun_dst_ip;
> +             mode = IPSEC_SA_MODE_TUNNEL;
> +
> +             int ret;
> +
> +             if (!in) {
> +                     /* init tun hdr id */
> +                     ret = odp_random_data((uint8_t *)
> +                                           &entry->state.tun_hdr_id,
> +                                           sizeof(entry->state.tun_hdr_id),
> +                                           1);
> +                     if (ret != sizeof(entry->state.tun_hdr_id))
> +                             return -1;
> +             }
> +     }
> +     entry->mode = mode;
> +
>       /* Initialize state */
>       entry->state.esp_seq = 0;
>       entry->state.ah_seq = 0;
> @@ -156,7 +184,9 @@ ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t 
> src_ip,
>       /* Look for a hit */
>       for (; NULL != entry; entry = entry->next) {
>               if ((entry->src_ip != src_ip) || (entry->dst_ip != dst_ip))
> -                     continue;
> +                     if ((entry->tun_src_ip != src_ip) ||
> +                         (entry->tun_dst_ip != dst_ip))
> +                             continue;
>               if (ah &&
>                   ((!entry->ah.alg) ||
>                    (entry->ah.spi != odp_be_to_cpu_32(ah->spi))))
> diff --git a/example/ipsec/odp_ipsec_cache.h b/example/ipsec/odp_ipsec_cache.h
> index 714cae8..5706007 100644
> --- a/example/ipsec/odp_ipsec_cache.h
> +++ b/example/ipsec/odp_ipsec_cache.h
> @@ -34,6 +34,9 @@ typedef struct ipsec_cache_entry_s {
>       odp_bool_t                   in_place;    /**< Crypto API mode */
>       uint32_t                     src_ip;      /**< Source v4 address */
>       uint32_t                     dst_ip;      /**< Destination v4 address */
> +     sa_mode_t                    mode;        /**< SA mode - transport/tun 
> */
> +     uint32_t                     tun_src_ip;  /**< Tunnel src IPv4 addr */
> +     uint32_t                     tun_dst_ip;  /**< Tunnel dst IPv4 addr */
>       struct {
>               enum  odp_cipher_alg alg;         /**< Cipher algorithm */
>               uint32_t             spi;         /**< Cipher SPI */
> @@ -54,6 +57,7 @@ typedef struct ipsec_cache_entry_s {
>               uint32_t      esp_seq;         /**< ESP TX sequence number */
>               uint32_t      ah_seq;          /**< AH TX sequence number */
>               uint8_t       iv[MAX_IV_LEN];  /**< ESP IV storage */
> +             uint16be_t    tun_hdr_id;      /**< Tunnel header IP ID */
>       } state;
>  } ipsec_cache_entry_t;
>  
> @@ -78,6 +82,7 @@ void init_ipsec_cache(void);
>   *
>   * @param cipher_sa   Cipher SA DB entry pointer
>   * @param auth_sa     Auth SA DB entry pointer
> + * @param tun         Tunnel DB entry pointer
>   * @param api_mode    Crypto API mode for testing
>   * @param in          Direction (input versus output)
>   * @param completionq Completion queue
> @@ -87,6 +92,7 @@ void init_ipsec_cache(void);
>   */
>  int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
>                            sa_db_entry_t *auth_sa,
> +                          tun_db_entry_t *tun,
>                            crypto_api_mode_e api_mode,
>                            odp_bool_t in,
>                            odp_queue_t completionq,
> diff --git a/example/ipsec/odp_ipsec_sa_db.c b/example/ipsec/odp_ipsec_sa_db.c
> index 5837cb6..7967614 100644
> --- a/example/ipsec/odp_ipsec_sa_db.c
> +++ b/example/ipsec/odp_ipsec_sa_db.c
> @@ -1,7 +1,7 @@
>  /* Copyright (c) 2014, Linaro Limited
>   * All rights reserved.
>   *
> - * SPDX-License-Identifier:     BSD-3-Clause
> + * SPDX-License-Identifier:  BSD-3-Clause
>   */
>  
>  /* enable strtok */
> @@ -19,6 +19,9 @@
>  /** Global pointer to sa db */
>  static sa_db_t *sa_db;
>  
> +/** Global pointer to tun db */
> +static tun_db_t *tun_db;
> +
>  void init_sa_db(void)
>  {
>       odp_shm_t shm;
> @@ -37,6 +40,23 @@ void init_sa_db(void)
>       memset(sa_db, 0, sizeof(*sa_db));
>  }
>  
> +void init_tun_db(void)
> +{
> +     odp_shm_t shm;
> +
> +     shm = odp_shm_reserve("shm_tun_db",
> +                           sizeof(tun_db_t),
> +                           ODP_CACHE_LINE_SIZE,
> +                           0);
> +     tun_db = odp_shm_addr(shm);
> +
> +     if (!tun_db) {
> +             EXAMPLE_ERR("Error: shared mem alloc failed.\n");
> +             exit(EXIT_FAILURE);
> +     }
> +     memset(tun_db, 0, sizeof(*tun_db));
> +}
> +
>  int create_sa_db_entry(char *input, odp_bool_t cipher)
>  {
>       int pos = 0;
> @@ -81,7 +101,7 @@ int create_sa_db_entry(char *input, odp_bool_t cipher)
>                                       entry->alg.u.cipher =
>                                               ODP_CIPHER_ALG_3DES_CBC;
>                                       entry->block_len  = 8;
> -                                     entry->iv_len     = 8;
> +                                     entry->iv_len     = 8;
>                               } else {
>                                       entry->alg.u.cipher =
>                                               ODP_CIPHER_ALG_NULL;
> @@ -90,7 +110,7 @@ int create_sa_db_entry(char *input, odp_bool_t cipher)
>                               if (0 == strcmp(token, "md5")) {
>                                       entry->alg.u.auth =
>                                               ODP_AUTH_ALG_MD5_96;
> -                                     entry->icv_len    = 12;
> +                                     entry->icv_len    = 12;
>                               } else {
>                                       entry->alg.u.auth = ODP_AUTH_ALG_NULL;
>                               }
> @@ -132,6 +152,89 @@ int create_sa_db_entry(char *input, odp_bool_t cipher)
>       return 0;
>  }
>  
> +int create_tun_db_entry(char *input)
> +{
> +     int pos = 0;
> +     char *local;
> +     char *str;
> +     char *save;
> +     char *token;
> +     tun_db_entry_t *entry = &tun_db->array[tun_db->index];
> +
> +     /* Verify we have a good entry */
> +     if (MAX_DB <= tun_db->index)
> +             return -1;
> +
> +     /* Make a local copy */
> +     local = malloc(strlen(input) + 1);
> +     if (NULL == local)
> +             return -1;
> +     strcpy(local, input);
> +
> +     /* Setup for using "strtok_r" to search input string */
> +     str = local;
> +     save = NULL;
> +
> +     /* Parse tokens separated by ':' */
> +     while (NULL != (token = strtok_r(str, ":", &save))) {
> +             str = NULL;  /* reset str for subsequent strtok_r calls */
> +
> +             /* Parse token based on its position */
> +             switch (pos) {
> +             case 0:
> +                     parse_ipv4_string(token, &entry->src_ip, NULL);
> +                     break;
> +             case 1:
> +                     parse_ipv4_string(token, &entry->dst_ip, NULL);
> +                     break;
> +             case 2:
> +                     parse_ipv4_string(token, &entry->tun_src_ip, NULL);
> +                     break;
> +             case 3:
> +                     parse_ipv4_string(token, &entry->tun_dst_ip, NULL);
> +                     break;
> +             default:
> +                     printf("ERROR: extra token \"%s\" at position %d\n",
> +                            token, pos);
> +                     break;
> +             }
> +             pos++;
> +     }
> +
> +     /* Verify we parsed exactly the number of tokens we expected */
> +     if (4 != pos) {
> +             printf("ERROR: \"%s\" contains %d tokens, expected 4\n",
> +                    input,
> +                    pos);
> +             free(local);
> +             return -1;
> +     }
> +
> +     /* Add route to the list */
> +     tun_db->index++;
> +     entry->next = tun_db->list;
> +     tun_db->list = entry;
> +
> +     free(local);
> +     return 0;
> +}
> +
> +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,
> +                               uint32_t ip_dst)
> +{
> +     tun_db_entry_t *entry = NULL;
> +
> +     /* Scan all entries and return first match */
> +     for (entry = tun_db->list; NULL != entry; entry = entry->next) {
> +             if (entry->src_ip != ip_src)
> +                     continue;
> +             if (entry->dst_ip != ip_dst)
> +                     continue;
> +             break;
> +     }
> +     return entry;
> +}
> +
>  void dump_sa_db(void)
>  {
>       sa_db_entry_t *entry;
> @@ -182,3 +285,28 @@ sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,
>       }
>       return entry;
>  }
> +
> +void dump_tun_db(void)
> +{
> +     tun_db_entry_t *entry;
> +
> +     printf("\n"
> +            "Tunnel table\n"
> +            "--------------------------\n");
> +
> +     for (entry = tun_db->list; NULL != entry; entry = entry->next) {
> +             char src_ip_str[MAX_STRING];
> +             char dst_ip_str[MAX_STRING];
> +             char tun_src_ip_str[MAX_STRING];
> +             char tun_dst_ip_str[MAX_STRING];
> +
> +             printf(" %s:%s %s:%s ",
> +                    ipv4_addr_str(src_ip_str, entry->src_ip),
> +                    ipv4_addr_str(dst_ip_str, entry->dst_ip),
> +                    ipv4_addr_str(tun_src_ip_str, entry->tun_src_ip),
> +                    ipv4_addr_str(tun_dst_ip_str, entry->tun_dst_ip)
> +                   );
> +
> +             printf("\n");
> +     }
> +}
> diff --git a/example/ipsec/odp_ipsec_sa_db.h b/example/ipsec/odp_ipsec_sa_db.h
> index c30cbdb..409e82f 100644
> --- a/example/ipsec/odp_ipsec_sa_db.h
> +++ b/example/ipsec/odp_ipsec_sa_db.h
> @@ -13,6 +13,10 @@ extern "C" {
>  
>  #include <odp_ipsec_misc.h>
>  
> +typedef enum sa_mode_s {
> +     IPSEC_SA_MODE_TRANSPORT,
> +     IPSEC_SA_MODE_TUNNEL
> +} sa_mode_t;
>  /**
>   * Security Assocation (SA) data base entry
>   */
> @@ -26,6 +30,7 @@ typedef struct sa_db_entry_s {
>       uint32_t              block_len; /**< Cipher block length */
>       uint32_t              iv_len;    /**< Initialization Vector length */
>       uint32_t              icv_len;   /**< Integrity Check Value length */
> +     sa_mode_t             mode;      /**< SA mode - transport/tun */
>  } sa_db_entry_t;
>  
>  /**
> @@ -69,6 +74,56 @@ sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,
>                               ip_addr_range_t *dst,
>                               odp_bool_t cipher);
>  
> +/**
> + * Tunnel entry
> + */
> +typedef struct tun_db_entry_s {
> +     struct tun_db_entry_s *next;
> +     uint32_t        src_ip;        /**< Inner Source IPv4 address */
> +     uint32_t        dst_ip;        /**< Inner Destination IPv4 address */
> +     uint32_t        tun_src_ip; /**< Tunnel Source IPv4 address */
> +     uint32_t        tun_dst_ip; /**< Tunnel Source IPv4 address */
> +} tun_db_entry_t;
> +
> +/**
> + * Tunnel database
> + */
> +typedef struct tun_db_s {
> +     uint32_t         index;          /**< Index of next available entry */
> +     tun_db_entry_t *list;    /**< List of active entries */
> +     tun_db_entry_t array[MAX_DB]; /**< Entry storage */
> +} tun_db_t;
> +
> +/** Initialize tun database global control structure */
> +void init_tun_db(void);
> +
> +/**
> + * Create an tunnel DB entry
> + *
> + * String is of the format "SrcIP:DstIP:TunSrcIp:TunDstIp"
> + *
> + * @param input  Pointer to string describing tun
> + *
> + * @return 0 if successful else -1
> + */
> +int create_tun_db_entry(char *input);
> +
> +/**
> + * Display the tun DB
> + */
> +void dump_tun_db(void);
> +
> +/**
> + * Find a matching tun DB entry
> + *
> + * @param ip_src    Inner source IP address
> + * @param ip_dst    Inner destination IP address
> + *
> + * @return pointer to tun DB entry else NULL
> + */
> +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,
> +                               uint32_t ip_dst);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/example/ipsec/odp_ipsec_stream.c 
> b/example/ipsec/odp_ipsec_stream.c
> index 35042f5..a140d36 100644
> --- a/example/ipsec/odp_ipsec_stream.c
> +++ b/example/ipsec/odp_ipsec_stream.c
> @@ -169,18 +169,24 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t 
> *stream,
>                               uint8_t *dmac,
>                               odp_pool_t pkt_pool)
>  {
> -     ipsec_cache_entry_t *entry = stream->input.entry;
> +     ipsec_cache_entry_t *entry = NULL;
>       odp_packet_t pkt;
>       uint8_t *base;
>       uint8_t *data;
>       odph_ethhdr_t *eth;
>       odph_ipv4hdr_t *ip;
> +     odph_ipv4hdr_t *inner_ip = NULL;
>       odph_ahhdr_t *ah = NULL;
>       odph_esphdr_t *esp = NULL;
>       odph_icmphdr_t *icmp;
>       stream_pkt_hdr_t *test;
>       unsigned i;
>  
> +     if (stream->input.entry)
> +             entry = stream->input.entry;
> +     else if (stream->output.entry)
> +             entry = stream->output.entry;
> +
>       /* Get packet */
>       pkt = odp_packet_alloc(pkt_pool, 0);
>       if (ODP_PACKET_INVALID == pkt)
> @@ -205,13 +211,22 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t 
> *stream,
>       /* Wait until almost finished to fill in mutable fields */
>       memset((char *)ip, 0, sizeof(*ip));
>       ip->ver_ihl = 0x45;
> -     ip->proto = ODPH_IPPROTO_ICMP;
>       ip->id = odp_cpu_to_be_16(stream->id);
> -     ip->src_addr = odp_cpu_to_be_32(stream->src_ip);
> -     ip->dst_addr = odp_cpu_to_be_32(stream->dst_ip);
> +     /* Outer IP header in tunnel mode */
> +     if (entry && entry->mode == IPSEC_SA_MODE_TUNNEL &&
> +         (entry == stream->input.entry)) {
> +             ip->proto = ODPH_IPV4;
> +             ip->src_addr = odp_cpu_to_be_32(entry->tun_src_ip);
> +             ip->dst_addr = odp_cpu_to_be_32(entry->tun_dst_ip);
> +     } else {
> +             ip->proto = ODPH_IPPROTO_ICMP;
> +             ip->src_addr = odp_cpu_to_be_32(stream->src_ip);
> +             ip->dst_addr = odp_cpu_to_be_32(stream->dst_ip);
> +     }
>  
>       /* AH (if specified) */
> -     if (entry && (ODP_AUTH_ALG_NULL != entry->ah.alg)) {
> +     if (entry && (entry == stream->input.entry) &&
> +         (ODP_AUTH_ALG_NULL != entry->ah.alg)) {
>               if (ODP_AUTH_ALG_MD5_96 != entry->ah.alg)
>                       abort();
>  
> @@ -226,7 +241,8 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t *stream,
>       }
>  
>       /* ESP (if specified) */
> -     if (entry && (ODP_CIPHER_ALG_NULL != entry->esp.alg)) {
> +     if (entry && (entry == stream->input.entry) &&
> +         (ODP_CIPHER_ALG_NULL != entry->esp.alg)) {
>               if (ODP_CIPHER_ALG_3DES_CBC != entry->esp.alg)
>                       abort();
>  
> @@ -239,6 +255,23 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t 
> *stream,
>               RAND_bytes(esp->iv, 8);
>       }
>  
> +     /* Inner IP header in tunnel mode */
> +     if (entry && (entry == stream->input.entry) &&
> +         (entry->mode == IPSEC_SA_MODE_TUNNEL)) {
> +             inner_ip = (odph_ipv4hdr_t *)data;
> +             memset((char *)inner_ip, 0, sizeof(*inner_ip));
> +             inner_ip->ver_ihl = 0x45;
> +             inner_ip->proto = ODPH_IPPROTO_ICMP;
> +             inner_ip->id = odp_cpu_to_be_16(stream->id);
> +             inner_ip->ttl = 64;
> +             inner_ip->tos = 0;
> +             inner_ip->frag_offset = 0;
> +             inner_ip->src_addr = odp_cpu_to_be_32(stream->src_ip);
> +             inner_ip->dst_addr = odp_cpu_to_be_32(stream->dst_ip);
> +             inner_ip->chksum = odp_chksum(inner_ip, sizeof(inner_ip));
> +             data += sizeof(*inner_ip);
> +     }
> +
>       /* ICMP header so we can see it on wireshark */
>       icmp = (odph_icmphdr_t *)data;
>       data += sizeof(*icmp);
> @@ -261,6 +294,13 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t 
> *stream,
>       /* Close ESP if specified */
>       if (esp) {
>               int payload_len = data - (uint8_t *)icmp;
> +             uint8_t *encrypt_start = (uint8_t *)icmp;
> +
> +             if (entry->mode == IPSEC_SA_MODE_TUNNEL) {
> +                     payload_len = data - (uint8_t *)inner_ip;
> +                     encrypt_start = (uint8_t *)inner_ip;
> +             }
> +
>               int encrypt_len;
>               odph_esptrl_t *esp_t;
>               DES_key_schedule ks1, ks2, ks3;
> @@ -282,8 +322,8 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t *stream,
>               DES_set_key((DES_cblock *)&entry->esp.key.data[8], &ks2);
>               DES_set_key((DES_cblock *)&entry->esp.key.data[16], &ks3);
>  
> -             DES_ede3_cbc_encrypt((uint8_t *)icmp,
> -                                  (uint8_t *)icmp,
> +             DES_ede3_cbc_encrypt(encrypt_start,
> +                                  encrypt_start,
>                                    encrypt_len,
>                                    &ks1,
>                                    &ks2,
> @@ -332,7 +372,7 @@ odp_packet_t create_ipv4_packet(stream_db_entry_t *stream,
>  odp_bool_t verify_ipv4_packet(stream_db_entry_t *stream,
>                             odp_packet_t pkt)
>  {
> -     ipsec_cache_entry_t *entry = stream->output.entry;
> +     ipsec_cache_entry_t *entry = NULL;
>       uint8_t *data;
>       odph_ipv4hdr_t *ip;
>       odph_ahhdr_t *ah = NULL;
> @@ -340,6 +380,12 @@ odp_bool_t verify_ipv4_packet(stream_db_entry_t *stream,
>       int hdr_len;
>       odph_icmphdr_t *icmp;
>       stream_pkt_hdr_t *test;
> +     uint32_t src_ip, dst_ip;
> +
> +     if (stream->input.entry)
> +             entry = stream->input.entry;
> +     else if (stream->output.entry)
> +             entry = stream->output.entry;
>  
>       /* Basic IPv4 verify (add checksum verification) */
>       data = odp_packet_l3_ptr(pkt, NULL);
> @@ -347,13 +393,29 @@ odp_bool_t verify_ipv4_packet(stream_db_entry_t *stream,
>       data += sizeof(*ip);
>       if (0x45 != ip->ver_ihl)
>               return FALSE;
> -     if (stream->src_ip != odp_be_to_cpu_32(ip->src_addr))
> +
> +     src_ip = odp_be_to_cpu_32(ip->src_addr);
> +     dst_ip = odp_be_to_cpu_32(ip->dst_addr);
> +     if ((stream->src_ip != src_ip) && stream->output.entry &&
> +         (stream->output.entry->tun_src_ip != src_ip))
>               return FALSE;
> -     if (stream->dst_ip != odp_be_to_cpu_32(ip->dst_addr))
> +     if ((stream->dst_ip != dst_ip) && stream->output.entry &&
> +         (stream->output.entry->tun_dst_ip != dst_ip))
> +             return FALSE;
> +
> +     if ((stream->src_ip != src_ip) && stream->input.entry &&
> +         (stream->input.entry->tun_src_ip != src_ip))
> +             return FALSE;
> +     if ((stream->dst_ip != dst_ip) && stream->input.entry &&
> +         (stream->input.entry->tun_dst_ip != dst_ip))
>               return FALSE;
>  
>       /* Find IPsec headers if any and compare against entry */
>       hdr_len = locate_ipsec_headers(ip, &ah, &esp);
> +
> +     /* Cleartext packet */
> +     if (!ah && !esp)
> +             goto clear_packet;
>       if (ah) {
>               if (!entry)
>                       return FALSE;
> @@ -446,12 +508,22 @@ odp_bool_t verify_ipv4_packet(stream_db_entry_t *stream,
>               ip->proto = esp_t->next_header;
>       }
>  
> -     /* Verify ICMP packet */
> -     if (ODPH_IPPROTO_ICMP != ip->proto)
> -             return FALSE;
> +clear_packet:
> +     /* Verify IP/ICMP packet */
> +     if (entry && (entry->mode == IPSEC_SA_MODE_TUNNEL) && (ah || esp)) {
> +             if (ODPH_IPV4 != ip->proto)
> +                     return FALSE;
> +             odph_ipv4hdr_t *inner_ip = (odph_ipv4hdr_t *)data;
> +
> +             icmp = (odph_icmphdr_t *)(inner_ip + 1);
> +             data = (uint8_t *)icmp;
> +     } else {
> +             if (ODPH_IPPROTO_ICMP != ip->proto)
> +                     return FALSE;
> +             icmp = (odph_icmphdr_t *)data;
> +     }
>  
>       /* Verify ICMP header */
> -     icmp = (odph_icmphdr_t *)data;
>       data += sizeof(*icmp);
>       if (ICMP_ECHO != icmp->type)
>               return FALSE;
> -- 
> 1.7.3.4
> 
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> https://lists.linaro.org/mailman/listinfo/lng-odp

-- 
Anders Roxell
anders.rox...@linaro.org
M: +46 709 71 42 85 | IRC: roxell
_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to