mirror of https://github.com/F-Stack/f-stack.git
1641 lines
52 KiB
C
1641 lines
52 KiB
C
/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
|
|
*
|
|
* Copyright 2008-2016 Freescale Semiconductor Inc.
|
|
* Copyright 2016 NXP
|
|
*
|
|
*/
|
|
|
|
#ifndef __DESC_IPSEC_H__
|
|
#define __DESC_IPSEC_H__
|
|
|
|
#include "hw/rta.h"
|
|
#include "common.h"
|
|
|
|
/**
|
|
* DOC: IPsec Shared Descriptor Constructors
|
|
*
|
|
* Shared descriptors for IPsec protocol.
|
|
*/
|
|
|
|
/* General IPSec ESP encap / decap PDB options */
|
|
|
|
/**
|
|
* PDBOPTS_ESP_ESN - Extended sequence included
|
|
*/
|
|
#define PDBOPTS_ESP_ESN 0x10
|
|
|
|
/**
|
|
* PDBOPTS_ESP_IPVSN - Process IPv6 header
|
|
*
|
|
* Valid only for IPsec legacy mode.
|
|
*/
|
|
#define PDBOPTS_ESP_IPVSN 0x02
|
|
|
|
/**
|
|
* PDBOPTS_ESP_TUNNEL - Tunnel mode next-header byte
|
|
*
|
|
* Valid only for IPsec legacy mode.
|
|
*/
|
|
#define PDBOPTS_ESP_TUNNEL 0x01
|
|
|
|
/* IPSec ESP Encap PDB options */
|
|
|
|
/**
|
|
* PDBOPTS_ESP_UPDATE_CSUM - Update ip header checksum
|
|
*
|
|
* Valid only for IPsec legacy mode.
|
|
*/
|
|
#define PDBOPTS_ESP_UPDATE_CSUM 0x80
|
|
|
|
/**
|
|
* PDBOPTS_ESP_DIFFSERV - Copy TOS/TC from inner iphdr
|
|
*
|
|
* Valid only for IPsec legacy mode.
|
|
*/
|
|
#define PDBOPTS_ESP_DIFFSERV 0x40
|
|
|
|
/**
|
|
* PDBOPTS_ESP_IVSRC - IV comes from internal random gen
|
|
*/
|
|
#define PDBOPTS_ESP_IVSRC 0x20
|
|
|
|
/**
|
|
* PDBOPTS_ESP_IPHDRSRC - IP header comes from PDB
|
|
*
|
|
* Valid only for IPsec legacy mode.
|
|
*/
|
|
#define PDBOPTS_ESP_IPHDRSRC 0x08
|
|
|
|
/**
|
|
* PDBOPTS_ESP_INCIPHDR - Prepend IP header to output frame
|
|
*
|
|
* Valid only for IPsec legacy mode.
|
|
*/
|
|
#define PDBOPTS_ESP_INCIPHDR 0x04
|
|
|
|
/**
|
|
* PDBOPTS_ESP_OIHI_MASK - Mask for Outer IP Header Included
|
|
*
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_OIHI_MASK 0x0c
|
|
|
|
/**
|
|
* PDBOPTS_ESP_OIHI_PDB_INL - Prepend IP header to output frame from PDB (where
|
|
* it is inlined).
|
|
*
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_OIHI_PDB_INL 0x0c
|
|
|
|
/**
|
|
* PDBOPTS_ESP_OIHI_PDB_REF - Prepend IP header to output frame from PDB
|
|
* (referenced by pointer).
|
|
*
|
|
* Vlid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_OIHI_PDB_REF 0x08
|
|
|
|
/**
|
|
* PDBOPTS_ESP_OIHI_IF - Prepend IP header to output frame from input frame
|
|
*
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_OIHI_IF 0x04
|
|
|
|
/**
|
|
* PDBOPTS_ESP_NAT - Enable RFC 3948 UDP-encapsulated-ESP
|
|
*
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_NAT 0x02
|
|
|
|
/**
|
|
* PDBOPTS_ESP_NUC - Enable NAT UDP Checksum
|
|
*
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_NUC 0x01
|
|
|
|
/* IPSec ESP Decap PDB options */
|
|
|
|
/**
|
|
* PDBOPTS_ESP_ARS_MASK - antireplay window mask
|
|
*/
|
|
#define PDBOPTS_ESP_ARS_MASK 0xc0
|
|
|
|
/**
|
|
* PDBOPTS_ESP_ARSNONE - No antireplay window
|
|
*/
|
|
#define PDBOPTS_ESP_ARSNONE 0x00
|
|
|
|
/**
|
|
* PDBOPTS_ESP_ARS64 - 64-entry antireplay window
|
|
*/
|
|
#define PDBOPTS_ESP_ARS64 0xc0
|
|
|
|
/**
|
|
* PDBOPTS_ESP_ARS128 - 128-entry antireplay window
|
|
*
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_ARS128 0x80
|
|
|
|
/**
|
|
* PDBOPTS_ESP_ARS32 - 32-entry antireplay window
|
|
*/
|
|
#define PDBOPTS_ESP_ARS32 0x40
|
|
|
|
/**
|
|
* PDBOPTS_ESP_VERIFY_CSUM - Validate ip header checksum
|
|
*
|
|
* Valid only for IPsec legacy mode.
|
|
*/
|
|
#define PDBOPTS_ESP_VERIFY_CSUM 0x20
|
|
|
|
/**
|
|
* PDBOPTS_ESP_TECN - Implement RRFC6040 ECN tunneling from outer header to
|
|
* inner header.
|
|
*
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_TECN 0x20
|
|
|
|
/**
|
|
* PDBOPTS_ESP_OUTFMT - Output only decapsulation
|
|
*
|
|
* Valid only for IPsec legacy mode.
|
|
*/
|
|
#define PDBOPTS_ESP_OUTFMT 0x08
|
|
|
|
/**
|
|
* PDBOPTS_ESP_AOFL - Adjust out frame len
|
|
*
|
|
* Valid only for IPsec legacy mode and for SEC >= 5.3.
|
|
*/
|
|
#define PDBOPTS_ESP_AOFL 0x04
|
|
|
|
/**
|
|
* PDBOPTS_ESP_ETU - EtherType Update
|
|
*
|
|
* Add corresponding ethertype (0x0800 for IPv4, 0x86dd for IPv6) in the output
|
|
* frame.
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBOPTS_ESP_ETU 0x01
|
|
|
|
#define PDBHMO_ESP_DECAP_SHIFT 28
|
|
#define PDBHMO_ESP_ENCAP_SHIFT 28
|
|
#define PDBNH_ESP_ENCAP_SHIFT 16
|
|
#define PDBNH_ESP_ENCAP_MASK (0xff << PDBNH_ESP_ENCAP_SHIFT)
|
|
#define PDBHDRLEN_ESP_DECAP_SHIFT 16
|
|
#define PDBHDRLEN_MASK (0x0fff << PDBHDRLEN_ESP_DECAP_SHIFT)
|
|
#define PDB_NH_OFFSET_SHIFT 8
|
|
#define PDB_NH_OFFSET_MASK (0xff << PDB_NH_OFFSET_SHIFT)
|
|
|
|
/**
|
|
* PDBHMO_ESP_DECAP_DTTL - IPsec ESP decrement TTL (IPv4) / Hop limit (IPv6)
|
|
* HMO option.
|
|
*/
|
|
#define PDBHMO_ESP_DECAP_DTTL (0x02 << PDBHMO_ESP_DECAP_SHIFT)
|
|
|
|
/**
|
|
* PDBHMO_ESP_ENCAP_DTTL - IPsec ESP increment TTL (IPv4) / Hop limit (IPv6)
|
|
* HMO option.
|
|
*/
|
|
#define PDBHMO_ESP_ENCAP_DTTL (0x02 << PDBHMO_ESP_ENCAP_SHIFT)
|
|
|
|
/**
|
|
* PDBHMO_ESP_DIFFSERV - (Decap) DiffServ Copy - Copy the IPv4 TOS or IPv6
|
|
* Traffic Class byte from the outer IP header to the
|
|
* inner IP header.
|
|
*/
|
|
#define PDBHMO_ESP_DIFFSERV (0x01 << PDBHMO_ESP_DECAP_SHIFT)
|
|
|
|
/**
|
|
* PDBHMO_ESP_SNR - (Encap) - Sequence Number Rollover control
|
|
*
|
|
* Configures behaviour in case of SN / ESN rollover:
|
|
* error if SNR = 1, rollover allowed if SNR = 0.
|
|
* Valid only for IPsec new mode.
|
|
*/
|
|
#define PDBHMO_ESP_SNR (0x01 << PDBHMO_ESP_ENCAP_SHIFT)
|
|
|
|
/**
|
|
* PDBHMO_ESP_DFBIT - (Encap) Copy DF bit - if an IPv4 tunnel mode outer IP
|
|
* header is coming from the PDB, copy the DF bit from the
|
|
* inner IP header to the outer IP header.
|
|
*/
|
|
#define PDBHMO_ESP_DFBIT (0x04 << PDBHMO_ESP_ENCAP_SHIFT)
|
|
|
|
/**
|
|
* PDBHMO_ESP_DFV - (Decap) - DF bit value
|
|
*
|
|
* If ODF = 1, DF bit in output frame is replaced by DFV.
|
|
* Valid only from SEC Era 5 onwards.
|
|
*/
|
|
#define PDBHMO_ESP_DFV (0x04 << PDBHMO_ESP_DECAP_SHIFT)
|
|
|
|
/**
|
|
* PDBHMO_ESP_ODF - (Decap) Override DF bit in IPv4 header of decapsulated
|
|
* output frame.
|
|
*
|
|
* If ODF = 1, DF is replaced with the value of DFV bit.
|
|
* Valid only from SEC Era 5 onwards.
|
|
*/
|
|
#define PDBHMO_ESP_ODF (0x08 << PDBHMO_ESP_DECAP_SHIFT)
|
|
|
|
/**
|
|
* struct ipsec_encap_cbc - PDB part for IPsec CBC encapsulation
|
|
* @iv: 16-byte array initialization vector
|
|
*/
|
|
struct ipsec_encap_cbc {
|
|
uint8_t iv[16];
|
|
};
|
|
|
|
|
|
/**
|
|
* struct ipsec_encap_ctr - PDB part for IPsec CTR encapsulation
|
|
* @ctr_nonce: 4-byte array nonce
|
|
* @ctr_initial: initial count constant
|
|
* @iv: initialization vector
|
|
*/
|
|
struct ipsec_encap_ctr {
|
|
uint8_t ctr_nonce[4];
|
|
uint32_t ctr_initial;
|
|
uint64_t iv;
|
|
};
|
|
|
|
/**
|
|
* struct ipsec_encap_ccm - PDB part for IPsec CCM encapsulation
|
|
* @salt: 3-byte array salt (lower 24 bits)
|
|
* @ccm_opt: CCM algorithm options - MSB-LSB description:
|
|
* b0_flags (8b) - CCM B0; use 0x5B for 8-byte ICV, 0x6B for 12-byte ICV,
|
|
* 0x7B for 16-byte ICV (cf. RFC4309, RFC3610)
|
|
* ctr_flags (8b) - counter flags; constant equal to 0x3
|
|
* ctr_initial (16b) - initial count constant
|
|
* @iv: initialization vector
|
|
*/
|
|
struct ipsec_encap_ccm {
|
|
uint8_t salt[4];
|
|
uint32_t ccm_opt;
|
|
uint64_t iv;
|
|
};
|
|
|
|
/**
|
|
* struct ipsec_encap_gcm - PDB part for IPsec GCM encapsulation
|
|
* @salt: 3-byte array salt (lower 24 bits)
|
|
* @rsvd: reserved, do not use
|
|
* @iv: initialization vector
|
|
*/
|
|
struct ipsec_encap_gcm {
|
|
uint8_t salt[4];
|
|
uint32_t rsvd;
|
|
uint64_t iv;
|
|
};
|
|
|
|
/**
|
|
* struct ipsec_encap_pdb - PDB for IPsec encapsulation
|
|
* @options: MSB-LSB description (both for legacy and new modes)
|
|
* hmo (header manipulation options) - 4b
|
|
* reserved - 4b
|
|
* next header (legacy) / reserved (new) - 8b
|
|
* next header offset (legacy) / AOIPHO (actual outer IP header offset) - 8b
|
|
* option flags (depend on selected algorithm) - 8b
|
|
* @seq_num_ext_hi: (optional) IPsec Extended Sequence Number (ESN)
|
|
* @seq_num: IPsec sequence number
|
|
* @spi: IPsec SPI (Security Parameters Index)
|
|
* @ip_hdr_len: optional IP Header length (in bytes)
|
|
* reserved - 16b
|
|
* Opt. IP Hdr Len - 16b
|
|
* @ip_hdr: optional IP Header content (only for IPsec legacy mode)
|
|
*/
|
|
struct ipsec_encap_pdb {
|
|
uint32_t options;
|
|
uint32_t seq_num_ext_hi;
|
|
uint32_t seq_num;
|
|
union {
|
|
struct ipsec_encap_cbc cbc;
|
|
struct ipsec_encap_ctr ctr;
|
|
struct ipsec_encap_ccm ccm;
|
|
struct ipsec_encap_gcm gcm;
|
|
};
|
|
uint32_t spi;
|
|
uint32_t ip_hdr_len;
|
|
uint8_t ip_hdr[0];
|
|
};
|
|
|
|
static inline unsigned int
|
|
__rta_copy_ipsec_encap_pdb(struct program *program,
|
|
struct ipsec_encap_pdb *pdb,
|
|
uint32_t algtype)
|
|
{
|
|
unsigned int start_pc = program->current_pc;
|
|
|
|
__rta_out32(program, pdb->options);
|
|
__rta_out32(program, pdb->seq_num_ext_hi);
|
|
__rta_out32(program, pdb->seq_num);
|
|
|
|
switch (algtype & OP_PCL_IPSEC_CIPHER_MASK) {
|
|
case OP_PCL_IPSEC_DES_IV64:
|
|
case OP_PCL_IPSEC_DES:
|
|
case OP_PCL_IPSEC_3DES:
|
|
case OP_PCL_IPSEC_AES_CBC:
|
|
case OP_PCL_IPSEC_NULL:
|
|
rta_copy_data(program, pdb->cbc.iv, sizeof(pdb->cbc.iv));
|
|
break;
|
|
|
|
case OP_PCL_IPSEC_AES_CTR:
|
|
rta_copy_data(program, pdb->ctr.ctr_nonce,
|
|
sizeof(pdb->ctr.ctr_nonce));
|
|
__rta_out32(program, pdb->ctr.ctr_initial);
|
|
__rta_out64(program, true, pdb->ctr.iv);
|
|
break;
|
|
|
|
case OP_PCL_IPSEC_AES_CCM8:
|
|
case OP_PCL_IPSEC_AES_CCM12:
|
|
case OP_PCL_IPSEC_AES_CCM16:
|
|
rta_copy_data(program, pdb->ccm.salt, sizeof(pdb->ccm.salt));
|
|
__rta_out32(program, pdb->ccm.ccm_opt);
|
|
__rta_out64(program, true, pdb->ccm.iv);
|
|
break;
|
|
|
|
case OP_PCL_IPSEC_AES_GCM8:
|
|
case OP_PCL_IPSEC_AES_GCM12:
|
|
case OP_PCL_IPSEC_AES_GCM16:
|
|
case OP_PCL_IPSEC_AES_NULL_WITH_GMAC:
|
|
rta_copy_data(program, pdb->gcm.salt, sizeof(pdb->gcm.salt));
|
|
__rta_out32(program, pdb->gcm.rsvd);
|
|
__rta_out64(program, true, pdb->gcm.iv);
|
|
break;
|
|
}
|
|
|
|
__rta_out32(program, pdb->spi);
|
|
__rta_out32(program, pdb->ip_hdr_len);
|
|
|
|
return start_pc;
|
|
}
|
|
|
|
/**
|
|
* struct ipsec_decap_cbc - PDB part for IPsec CBC decapsulation
|
|
* @rsvd: reserved, do not use
|
|
*/
|
|
struct ipsec_decap_cbc {
|
|
uint32_t rsvd[2];
|
|
};
|
|
|
|
/**
|
|
* struct ipsec_decap_ctr - PDB part for IPsec CTR decapsulation
|
|
* @ctr_nonce: 4-byte array nonce
|
|
* @ctr_initial: initial count constant
|
|
*/
|
|
struct ipsec_decap_ctr {
|
|
uint8_t ctr_nonce[4];
|
|
uint32_t ctr_initial;
|
|
};
|
|
|
|
/**
|
|
* struct ipsec_decap_ccm - PDB part for IPsec CCM decapsulation
|
|
* @salt: 3-byte salt (lower 24 bits)
|
|
* @ccm_opt: CCM algorithm options - MSB-LSB description:
|
|
* b0_flags (8b) - CCM B0; use 0x5B for 8-byte ICV, 0x6B for 12-byte ICV,
|
|
* 0x7B for 16-byte ICV (cf. RFC4309, RFC3610)
|
|
* ctr_flags (8b) - counter flags; constant equal to 0x3
|
|
* ctr_initial (16b) - initial count constant
|
|
*/
|
|
struct ipsec_decap_ccm {
|
|
uint8_t salt[4];
|
|
uint32_t ccm_opt;
|
|
};
|
|
|
|
/**
|
|
* struct ipsec_decap_gcm - PDB part for IPsec GCN decapsulation
|
|
* @salt: 4-byte salt
|
|
* @rsvd: reserved, do not use
|
|
*/
|
|
struct ipsec_decap_gcm {
|
|
uint8_t salt[4];
|
|
uint32_t rsvd;
|
|
};
|
|
|
|
/**
|
|
* struct ipsec_decap_pdb - PDB for IPsec decapsulation
|
|
* @options: MSB-LSB description (both for legacy and new modes)
|
|
* hmo (header manipulation options) - 4b
|
|
* IP header length - 12b
|
|
* next header offset (legacy) / AOIPHO (actual outer IP header offset) - 8b
|
|
* option flags (depend on selected algorithm) - 8b
|
|
* @seq_num_ext_hi: (optional) IPsec Extended Sequence Number (ESN)
|
|
* @seq_num: IPsec sequence number
|
|
* @anti_replay: Anti-replay window; size depends on ARS (option flags);
|
|
* format must be Big Endian, irrespective of platform
|
|
*/
|
|
struct ipsec_decap_pdb {
|
|
uint32_t options;
|
|
union {
|
|
struct ipsec_decap_cbc cbc;
|
|
struct ipsec_decap_ctr ctr;
|
|
struct ipsec_decap_ccm ccm;
|
|
struct ipsec_decap_gcm gcm;
|
|
};
|
|
uint32_t seq_num_ext_hi;
|
|
uint32_t seq_num;
|
|
uint32_t anti_replay[4];
|
|
};
|
|
|
|
static inline unsigned int
|
|
__rta_copy_ipsec_decap_pdb(struct program *program,
|
|
struct ipsec_decap_pdb *pdb,
|
|
uint32_t algtype)
|
|
{
|
|
unsigned int start_pc = program->current_pc;
|
|
unsigned int i, ars;
|
|
|
|
__rta_out32(program, pdb->options);
|
|
|
|
switch (algtype & OP_PCL_IPSEC_CIPHER_MASK) {
|
|
case OP_PCL_IPSEC_DES_IV64:
|
|
case OP_PCL_IPSEC_DES:
|
|
case OP_PCL_IPSEC_3DES:
|
|
case OP_PCL_IPSEC_AES_CBC:
|
|
case OP_PCL_IPSEC_NULL:
|
|
__rta_out32(program, pdb->cbc.rsvd[0]);
|
|
__rta_out32(program, pdb->cbc.rsvd[1]);
|
|
break;
|
|
|
|
case OP_PCL_IPSEC_AES_CTR:
|
|
rta_copy_data(program, pdb->ctr.ctr_nonce,
|
|
sizeof(pdb->ctr.ctr_nonce));
|
|
__rta_out32(program, pdb->ctr.ctr_initial);
|
|
break;
|
|
|
|
case OP_PCL_IPSEC_AES_CCM8:
|
|
case OP_PCL_IPSEC_AES_CCM12:
|
|
case OP_PCL_IPSEC_AES_CCM16:
|
|
rta_copy_data(program, pdb->ccm.salt, sizeof(pdb->ccm.salt));
|
|
__rta_out32(program, pdb->ccm.ccm_opt);
|
|
break;
|
|
|
|
case OP_PCL_IPSEC_AES_GCM8:
|
|
case OP_PCL_IPSEC_AES_GCM12:
|
|
case OP_PCL_IPSEC_AES_GCM16:
|
|
case OP_PCL_IPSEC_AES_NULL_WITH_GMAC:
|
|
rta_copy_data(program, pdb->gcm.salt, sizeof(pdb->gcm.salt));
|
|
__rta_out32(program, pdb->gcm.rsvd);
|
|
break;
|
|
}
|
|
|
|
__rta_out32(program, pdb->seq_num_ext_hi);
|
|
__rta_out32(program, pdb->seq_num);
|
|
|
|
switch (pdb->options & PDBOPTS_ESP_ARS_MASK) {
|
|
case PDBOPTS_ESP_ARS128:
|
|
ars = 4;
|
|
break;
|
|
case PDBOPTS_ESP_ARS64:
|
|
ars = 2;
|
|
break;
|
|
case PDBOPTS_ESP_ARS32:
|
|
ars = 1;
|
|
break;
|
|
case PDBOPTS_ESP_ARSNONE:
|
|
default:
|
|
ars = 0;
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < ars; i++)
|
|
__rta_out_be32(program, pdb->anti_replay[i]);
|
|
|
|
return start_pc;
|
|
}
|
|
|
|
/**
|
|
* enum ipsec_icv_size - Type selectors for icv size in IPsec protocol
|
|
* @IPSEC_ICV_MD5_SIZE: full-length MD5 ICV
|
|
* @IPSEC_ICV_MD5_TRUNC_SIZE: truncated MD5 ICV
|
|
*/
|
|
enum ipsec_icv_size {
|
|
IPSEC_ICV_MD5_SIZE = 16,
|
|
IPSEC_ICV_MD5_TRUNC_SIZE = 12
|
|
};
|
|
|
|
/*
|
|
* IPSec ESP Datapath Protocol Override Register (DPOVRD)
|
|
* IPSEC_N_* defines are for IPsec new mode.
|
|
*/
|
|
|
|
/**
|
|
* IPSEC_DPOVRD_USE - DPOVRD will override values specified in the PDB
|
|
*/
|
|
#define IPSEC_DPOVRD_USE BIT(31)
|
|
|
|
/**
|
|
* IPSEC_DPOVRD_ECN_SHIFT - Explicit Congestion Notification
|
|
*
|
|
* If set, MSB of the 4 bits indicates that the 2 LSBs will replace the ECN bits
|
|
* in the IP header.
|
|
*/
|
|
#define IPSEC_DPOVRD_ECN_SHIFT 24
|
|
|
|
/**
|
|
* IPSEC_DPOVRD_ECN_MASK - See IPSEC_DPOVRD_ECN_SHIFT
|
|
*/
|
|
#define IPSEC_DPOVRD_ECN_MASK (0xf << IPSEC_ENCAP_DPOVRD_ECN_SHIFT)
|
|
|
|
/**
|
|
* IPSEC_DPOVRD_IP_HDR_LEN_SHIFT - The length (in bytes) of the portion of the
|
|
* IP header that is not encrypted
|
|
*/
|
|
#define IPSEC_DPOVRD_IP_HDR_LEN_SHIFT 16
|
|
|
|
/**
|
|
* IPSEC_DPOVRD_IP_HDR_LEN_MASK - See IPSEC_DPOVRD_IP_HDR_LEN_SHIFT
|
|
*/
|
|
#define IPSEC_DPOVRD_IP_HDR_LEN_MASK (0xff << IPSEC_DPOVRD_IP_HDR_LEN_SHIFT)
|
|
|
|
/**
|
|
* IPSEC_DPOVRD_NH_OFFSET_SHIFT - The location of the next header field within
|
|
* the IP header of the transport mode packet
|
|
*
|
|
* Encap:
|
|
* ESP_Trailer_NH <-- IP_Hdr[DPOVRD[NH_OFFSET]]
|
|
* IP_Hdr[DPOVRD[NH_OFFSET]] <-- DPOVRD[NH]
|
|
*Decap:
|
|
* IP_Hdr[DPOVRD[NH_OFFSET]] <-- ESP_Trailer_NH
|
|
*/
|
|
#define IPSEC_DPOVRD_NH_OFFSET_SHIFT 8
|
|
|
|
/**
|
|
* IPSEC_DPOVRD_NH_OFFSET_MASK - See IPSEC_DPOVRD_NH_OFFSET_SHIFT
|
|
*/
|
|
#define IPSEC_DPOVRD_NH_OFFSET_MASK (0xff << IPSEC_DPOVRD_NH_OFFSET_SHIFT)
|
|
|
|
/**
|
|
* IPSEC_DPOVRD_NH_MASK - See IPSEC_DPOVRD_NH_OFFSET_SHIFT
|
|
* Valid only for encapsulation.
|
|
*/
|
|
#define IPSEC_DPOVRD_NH_MASK 0xff
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_OIM_LEN_SHIFT - Outer IP header Material length (encap)
|
|
* Valid only if L2_COPY is not set.
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_OIM_LEN_SHIFT 16
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_OIM_LEN_MASK - See IPSEC_N_ENCAP_DPOVRD_OIM_LEN_SHIFT
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_OIM_LEN_MASK \
|
|
(0xfff << IPSEC_N_ENCAP_DPOVRD_OIM_LEN_SHIFT)
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_L2_LEN_SHIFT - L2 header length
|
|
* Valid only if L2_COPY is set.
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_L2_LEN_SHIFT 16
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_L2_LEN_MASK - See IPSEC_N_ENCAP_DPOVRD_L2_LEN_SHIFT
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_L2_LEN_MASK \
|
|
(0xff << IPSEC_N_ENCAP_DPOVRD_L2_LEN_SHIFT)
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_OIMIF - Outer IP header Material in Input Frame
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_OIMIF BIT(15)
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_L2_COPY - L2 header present in input frame
|
|
*
|
|
* Note: For Era <= 8, this bit is reserved (not used) by HW.
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_L2_COPY BIT(14)
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_AOIPHO_SHIFT - Actual Outer IP Header Offset (encap)
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_AOIPHO_SHIFT 8
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_AOIPHO_MASK - See IPSEC_N_ENCAP_DPOVRD_AOIPHO_SHIFT
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_AOIPHO_MASK \
|
|
(0x3c << IPSEC_N_ENCAP_DPOVRD_AOIPHO_SHIFT)
|
|
|
|
/**
|
|
* IPSEC_N_ENCAP_DPOVRD_NH_MASK - Next Header
|
|
*
|
|
* Used in the Next Header field of the encapsulated payload.
|
|
*/
|
|
#define IPSEC_N_ENCAP_DPOVRD_NH_MASK 0xff
|
|
|
|
/**
|
|
* IPSEC_N_DECAP_DPOVRD_AOIPHO_SHIFT - Actual Outer IP Header Offset (decap)
|
|
*/
|
|
#define IPSEC_N_DECAP_DPOVRD_AOIPHO_SHIFT 12
|
|
|
|
/**
|
|
* IPSEC_N_DECAP_DPOVRD_AOIPHO_MASK - See IPSEC_N_DECAP_DPOVRD_AOIPHO_SHIFT
|
|
*/
|
|
#define IPSEC_N_DECAP_DPOVRD_AOIPHO_MASK \
|
|
(0xff << IPSEC_N_DECAP_DPOVRD_AOIPHO_SHIFT)
|
|
|
|
/**
|
|
* IPSEC_N_DECAP_DPOVRD_OIM_LEN_MASK - Outer IP header Material length (decap)
|
|
*/
|
|
#define IPSEC_N_DECAP_DPOVRD_OIM_LEN_MASK 0xfff
|
|
|
|
static inline void __gen_auth_key(struct program *program,
|
|
struct alginfo *authdata)
|
|
{
|
|
uint32_t dkp_protid;
|
|
|
|
switch (authdata->algtype & OP_PCL_IPSEC_AUTH_MASK) {
|
|
case OP_PCL_IPSEC_HMAC_MD5_96:
|
|
case OP_PCL_IPSEC_HMAC_MD5_128:
|
|
dkp_protid = OP_PCLID_DKP_MD5;
|
|
break;
|
|
case OP_PCL_IPSEC_HMAC_SHA1_96:
|
|
case OP_PCL_IPSEC_HMAC_SHA1_160:
|
|
dkp_protid = OP_PCLID_DKP_SHA1;
|
|
break;
|
|
case OP_PCL_IPSEC_HMAC_SHA2_256_128:
|
|
dkp_protid = OP_PCLID_DKP_SHA256;
|
|
break;
|
|
case OP_PCL_IPSEC_HMAC_SHA2_384_192:
|
|
dkp_protid = OP_PCLID_DKP_SHA384;
|
|
break;
|
|
case OP_PCL_IPSEC_HMAC_SHA2_512_256:
|
|
dkp_protid = OP_PCLID_DKP_SHA512;
|
|
break;
|
|
default:
|
|
KEY(program, KEY2, authdata->key_enc_flags, authdata->key,
|
|
authdata->keylen, INLINE_KEY(authdata));
|
|
return;
|
|
}
|
|
|
|
if (authdata->key_type == RTA_DATA_PTR)
|
|
DKP_PROTOCOL(program, dkp_protid, OP_PCL_DKP_SRC_PTR,
|
|
OP_PCL_DKP_DST_PTR, (uint16_t)authdata->keylen,
|
|
authdata->key, authdata->key_type);
|
|
else
|
|
DKP_PROTOCOL(program, dkp_protid, OP_PCL_DKP_SRC_IMM,
|
|
OP_PCL_DKP_DST_IMM, (uint16_t)authdata->keylen,
|
|
authdata->key, authdata->key_type);
|
|
}
|
|
|
|
/**
|
|
* cnstr_shdsc_ipsec_encap - IPSec ESP encapsulation protocol-level shared
|
|
* descriptor.
|
|
* @descbuf: pointer to buffer used for descriptor construction
|
|
* @ps: if 36/40bit addressing is desired, this parameter must be true
|
|
* @swap: if true, perform descriptor byte swapping on a 4-byte boundary
|
|
* @share: sharing type of shared descriptor
|
|
* @pdb: pointer to the PDB to be used with this descriptor
|
|
* This structure will be copied inline to the descriptor under
|
|
* construction. No error checking will be made. Refer to the
|
|
* block guide for a details of the encapsulation PDB.
|
|
* @cipherdata: pointer to block cipher transform definitions
|
|
* Valid algorithm values - one of OP_PCL_IPSEC_*
|
|
* @authdata: pointer to authentication transform definitions
|
|
* If an authentication key is required by the protocol:
|
|
* -For SEC Eras 1-5, an MDHA split key must be provided;
|
|
* Note that the size of the split key itself must be specified.
|
|
* -For SEC Eras 6+, a "normal" key must be provided; DKP (Derived
|
|
* Key Protocol) will be used to compute MDHA on the fly in HW.
|
|
* Valid algorithm values - one of OP_PCL_IPSEC_*
|
|
*
|
|
* Return: size of descriptor written in words or negative number on error
|
|
*/
|
|
static inline int
|
|
cnstr_shdsc_ipsec_encap(uint32_t *descbuf, bool ps, bool swap,
|
|
enum rta_share_type share,
|
|
struct ipsec_encap_pdb *pdb,
|
|
struct alginfo *cipherdata,
|
|
struct alginfo *authdata)
|
|
{
|
|
struct program prg;
|
|
struct program *p = &prg;
|
|
|
|
LABEL(keyjmp);
|
|
REFERENCE(pkeyjmp);
|
|
LABEL(hdr);
|
|
REFERENCE(phdr);
|
|
|
|
PROGRAM_CNTXT_INIT(p, descbuf, 0);
|
|
if (swap)
|
|
PROGRAM_SET_BSWAP(p);
|
|
if (ps)
|
|
PROGRAM_SET_36BIT_ADDR(p);
|
|
phdr = SHR_HDR(p, share, hdr, 0);
|
|
__rta_copy_ipsec_encap_pdb(p, pdb, cipherdata->algtype);
|
|
COPY_DATA(p, pdb->ip_hdr, pdb->ip_hdr_len);
|
|
SET_LABEL(p, hdr);
|
|
pkeyjmp = JUMP(p, keyjmp, LOCAL_JUMP, ALL_TRUE, BOTH|SHRD);
|
|
if (authdata->keylen) {
|
|
if (rta_sec_era < RTA_SEC_ERA_6)
|
|
KEY(p, MDHA_SPLIT_KEY, authdata->key_enc_flags,
|
|
authdata->key, authdata->keylen,
|
|
INLINE_KEY(authdata));
|
|
else
|
|
__gen_auth_key(p, authdata);
|
|
}
|
|
if (cipherdata->keylen)
|
|
KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
|
|
cipherdata->keylen, INLINE_KEY(cipherdata));
|
|
SET_LABEL(p, keyjmp);
|
|
PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL,
|
|
OP_PCLID_IPSEC,
|
|
(uint16_t)(cipherdata->algtype | authdata->algtype));
|
|
PATCH_JUMP(p, pkeyjmp, keyjmp);
|
|
PATCH_HDR(p, phdr, hdr);
|
|
return PROGRAM_FINALIZE(p);
|
|
}
|
|
|
|
/**
|
|
* cnstr_shdsc_ipsec_decap - IPSec ESP decapsulation protocol-level shared
|
|
* descriptor.
|
|
* @descbuf: pointer to buffer used for descriptor construction
|
|
* @ps: if 36/40bit addressing is desired, this parameter must be true
|
|
* @swap: if true, perform descriptor byte swapping on a 4-byte boundary
|
|
* @share: sharing type of shared descriptor
|
|
* @pdb: pointer to the PDB to be used with this descriptor
|
|
* This structure will be copied inline to the descriptor under
|
|
* construction. No error checking will be made. Refer to the
|
|
* block guide for details about the decapsulation PDB.
|
|
* @cipherdata: pointer to block cipher transform definitions.
|
|
* Valid algorithm values - one of OP_PCL_IPSEC_*
|
|
* @authdata: pointer to authentication transform definitions
|
|
* If an authentication key is required by the protocol:
|
|
* -For SEC Eras 1-5, an MDHA split key must be provided;
|
|
* Note that the size of the split key itself must be specified.
|
|
* -For SEC Eras 6+, a "normal" key must be provided; DKP (Derived
|
|
* Key Protocol) will be used to compute MDHA on the fly in HW.
|
|
* Valid algorithm values - one of OP_PCL_IPSEC_*
|
|
*
|
|
* Return: size of descriptor written in words or negative number on error
|
|
*/
|
|
static inline int
|
|
cnstr_shdsc_ipsec_decap(uint32_t *descbuf, bool ps, bool swap,
|
|
enum rta_share_type share,
|
|
struct ipsec_decap_pdb *pdb,
|
|
struct alginfo *cipherdata,
|
|
struct alginfo *authdata)
|
|
{
|
|
struct program prg;
|
|
struct program *p = &prg;
|
|
|
|
LABEL(keyjmp);
|
|
REFERENCE(pkeyjmp);
|
|
LABEL(hdr);
|
|
REFERENCE(phdr);
|
|
|
|
PROGRAM_CNTXT_INIT(p, descbuf, 0);
|
|
if (swap)
|
|
PROGRAM_SET_BSWAP(p);
|
|
if (ps)
|
|
PROGRAM_SET_36BIT_ADDR(p);
|
|
phdr = SHR_HDR(p, share, hdr, 0);
|
|
__rta_copy_ipsec_decap_pdb(p, pdb, cipherdata->algtype);
|
|
SET_LABEL(p, hdr);
|
|
pkeyjmp = JUMP(p, keyjmp, LOCAL_JUMP, ALL_TRUE, BOTH|SHRD);
|
|
if (authdata->keylen) {
|
|
if (rta_sec_era < RTA_SEC_ERA_6)
|
|
KEY(p, MDHA_SPLIT_KEY, authdata->key_enc_flags,
|
|
authdata->key, authdata->keylen,
|
|
INLINE_KEY(authdata));
|
|
else
|
|
__gen_auth_key(p, authdata);
|
|
}
|
|
if (cipherdata->keylen)
|
|
KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
|
|
cipherdata->keylen, INLINE_KEY(cipherdata));
|
|
SET_LABEL(p, keyjmp);
|
|
PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL,
|
|
OP_PCLID_IPSEC,
|
|
(uint16_t)(cipherdata->algtype | authdata->algtype));
|
|
PATCH_JUMP(p, pkeyjmp, keyjmp);
|
|
PATCH_HDR(p, phdr, hdr);
|
|
return PROGRAM_FINALIZE(p);
|
|
}
|
|
|
|
/**
|
|
* cnstr_shdsc_ipsec_encap_des_aes_xcbc - IPSec DES-CBC/3DES-CBC and
|
|
* AES-XCBC-MAC-96 ESP encapsulation shared descriptor.
|
|
* @descbuf: pointer to buffer used for descriptor construction
|
|
* @pdb: pointer to the PDB to be used with this descriptor
|
|
* This structure will be copied inline to the descriptor under
|
|
* construction. No error checking will be made. Refer to the
|
|
* block guide for a details of the encapsulation PDB.
|
|
* @cipherdata: pointer to block cipher transform definitions
|
|
* Valid algorithm values - OP_PCL_IPSEC_DES, OP_PCL_IPSEC_3DES.
|
|
* @authdata: pointer to authentication transform definitions
|
|
* Valid algorithm value: OP_PCL_IPSEC_AES_XCBC_MAC_96.
|
|
*
|
|
* Supported only for platforms with 32-bit address pointers and SEC ERA 4 or
|
|
* higher. The tunnel/transport mode of the IPsec ESP is supported only if the
|
|
* Outer/Transport IP Header is present in the encapsulation output packet.
|
|
* The descriptor performs DES-CBC/3DES-CBC & HMAC-MD5-96 and then rereads
|
|
* the input packet to do the AES-XCBC-MAC-96 calculation and to overwrite
|
|
* the MD5 ICV.
|
|
* The descriptor uses all the benefits of the built-in protocol by computing
|
|
* the IPsec ESP with a hardware supported algorithms combination
|
|
* (DES-CBC/3DES-CBC & HMAC-MD5-96). The HMAC-MD5 authentication algorithm
|
|
* was chosen in order to speed up the computational time for this intermediate
|
|
* step.
|
|
* Warning: The user must allocate at least 32 bytes for the authentication key
|
|
* (in order to use it also with HMAC-MD5-96),even when using a shorter key
|
|
* for the AES-XCBC-MAC-96.
|
|
*
|
|
* Return: size of descriptor written in words or negative number on error
|
|
*/
|
|
static inline int
|
|
cnstr_shdsc_ipsec_encap_des_aes_xcbc(uint32_t *descbuf,
|
|
struct ipsec_encap_pdb *pdb,
|
|
struct alginfo *cipherdata,
|
|
struct alginfo *authdata)
|
|
{
|
|
struct program prg;
|
|
struct program *p = &prg;
|
|
|
|
LABEL(hdr);
|
|
LABEL(shd_ptr);
|
|
LABEL(keyjump);
|
|
LABEL(outptr);
|
|
LABEL(swapped_seqin_fields);
|
|
LABEL(swapped_seqin_ptr);
|
|
REFERENCE(phdr);
|
|
REFERENCE(pkeyjump);
|
|
REFERENCE(move_outlen);
|
|
REFERENCE(move_seqout_ptr);
|
|
REFERENCE(swapped_seqin_ptr_jump);
|
|
REFERENCE(write_swapped_seqin_ptr);
|
|
|
|
PROGRAM_CNTXT_INIT(p, descbuf, 0);
|
|
phdr = SHR_HDR(p, SHR_SERIAL, hdr, 0);
|
|
__rta_copy_ipsec_encap_pdb(p, pdb, cipherdata->algtype);
|
|
COPY_DATA(p, pdb->ip_hdr, pdb->ip_hdr_len);
|
|
SET_LABEL(p, hdr);
|
|
pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF);
|
|
/*
|
|
* Hard-coded KEY arguments. The descriptor uses all the benefits of
|
|
* the built-in protocol by computing the IPsec ESP with a hardware
|
|
* supported algorithms combination (DES-CBC/3DES-CBC & HMAC-MD5-96).
|
|
* The HMAC-MD5 authentication algorithm was chosen with
|
|
* the keys options from below in order to speed up the computational
|
|
* time for this intermediate step.
|
|
* Warning: The user must allocate at least 32 bytes for
|
|
* the authentication key (in order to use it also with HMAC-MD5-96),
|
|
* even when using a shorter key for the AES-XCBC-MAC-96.
|
|
*/
|
|
KEY(p, MDHA_SPLIT_KEY, 0, authdata->key, 32, INLINE_KEY(authdata));
|
|
SET_LABEL(p, keyjump);
|
|
LOAD(p, LDST_SRCDST_WORD_CLRW | CLRW_CLR_C1MODE | CLRW_CLR_C1DATAS |
|
|
CLRW_CLR_C1CTX | CLRW_CLR_C1KEY | CLRW_RESET_CLS1_CHA, CLRW, 0, 4,
|
|
IMMED);
|
|
KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
|
|
cipherdata->keylen, INLINE_KEY(cipherdata));
|
|
PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL, OP_PCLID_IPSEC,
|
|
(uint16_t)(cipherdata->algtype | OP_PCL_IPSEC_HMAC_MD5_96));
|
|
/* Swap SEQINPTR to SEQOUTPTR. */
|
|
move_seqout_ptr = MOVE(p, DESCBUF, 0, MATH1, 0, 16, WAITCOMP | IMMED);
|
|
MATHB(p, MATH1, AND, ~(CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR), MATH1,
|
|
8, IFB | IMMED2);
|
|
/*
|
|
* TODO: RTA currently doesn't support creating a LOAD command
|
|
* with another command as IMM.
|
|
* To be changed when proper support is added in RTA.
|
|
*/
|
|
LOAD(p, 0xa00000e5, MATH3, 4, 4, IMMED);
|
|
MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
|
|
write_swapped_seqin_ptr = MOVE(p, MATH1, 0, DESCBUF, 0, 20, WAITCOMP |
|
|
IMMED);
|
|
swapped_seqin_ptr_jump = JUMP(p, swapped_seqin_ptr, LOCAL_JUMP,
|
|
ALL_TRUE, 0);
|
|
LOAD(p, LDST_SRCDST_WORD_CLRW | CLRW_CLR_C1MODE | CLRW_CLR_C1DATAS |
|
|
CLRW_CLR_C1CTX | CLRW_CLR_C1KEY | CLRW_RESET_CLS1_CHA, CLRW, 0, 4,
|
|
0);
|
|
SEQOUTPTR(p, 0, 65535, RTO);
|
|
move_outlen = MOVE(p, DESCBUF, 0, MATH0, 4, 8, WAITCOMP | IMMED);
|
|
MATHB(p, MATH0, SUB,
|
|
(uint64_t)(pdb->ip_hdr_len + IPSEC_ICV_MD5_TRUNC_SIZE),
|
|
VSEQINSZ, 4, IMMED2);
|
|
MATHB(p, MATH0, SUB, IPSEC_ICV_MD5_TRUNC_SIZE, VSEQOUTSZ, 4, IMMED2);
|
|
KEY(p, KEY1, authdata->key_enc_flags, authdata->key, authdata->keylen,
|
|
0);
|
|
ALG_OPERATION(p, OP_ALG_ALGSEL_AES, OP_ALG_AAI_XCBC_MAC,
|
|
OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, DIR_ENC);
|
|
SEQFIFOLOAD(p, SKIP, pdb->ip_hdr_len, 0);
|
|
SEQFIFOLOAD(p, MSG1, 0, VLF | FLUSH1 | LAST1);
|
|
SEQFIFOSTORE(p, SKIP, 0, 0, VLF);
|
|
SEQSTORE(p, CONTEXT1, 0, IPSEC_ICV_MD5_TRUNC_SIZE, 0);
|
|
/*
|
|
* TODO: RTA currently doesn't support adding labels in or after Job Descriptor.
|
|
* To be changed when proper support is added in RTA.
|
|
*/
|
|
/* Label the Shared Descriptor Pointer */
|
|
SET_LABEL(p, shd_ptr);
|
|
shd_ptr += 1;
|
|
/* Label the Output Pointer */
|
|
SET_LABEL(p, outptr);
|
|
outptr += 3;
|
|
/* Label the first word after JD */
|
|
SET_LABEL(p, swapped_seqin_fields);
|
|
swapped_seqin_fields += 8;
|
|
/* Label the second word after JD */
|
|
SET_LABEL(p, swapped_seqin_ptr);
|
|
swapped_seqin_ptr += 9;
|
|
|
|
PATCH_HDR(p, phdr, hdr);
|
|
PATCH_JUMP(p, pkeyjump, keyjump);
|
|
PATCH_JUMP(p, swapped_seqin_ptr_jump, swapped_seqin_ptr);
|
|
PATCH_MOVE(p, move_outlen, outptr);
|
|
PATCH_MOVE(p, move_seqout_ptr, shd_ptr);
|
|
PATCH_MOVE(p, write_swapped_seqin_ptr, swapped_seqin_fields);
|
|
return PROGRAM_FINALIZE(p);
|
|
}
|
|
|
|
/**
|
|
* cnstr_shdsc_ipsec_decap_des_aes_xcbc - IPSec DES-CBC/3DES-CBC and
|
|
* AES-XCBC-MAC-96 ESP decapsulation shared descriptor.
|
|
* @descbuf: pointer to buffer used for descriptor construction
|
|
* @pdb: pointer to the PDB to be used with this descriptor
|
|
* This structure will be copied inline to the descriptor under
|
|
* construction. No error checking will be made. Refer to the
|
|
* block guide for a details of the encapsulation PDB.
|
|
* @cipherdata: pointer to block cipher transform definitions
|
|
* Valid algorithm values - OP_PCL_IPSEC_DES, OP_PCL_IPSEC_3DES.
|
|
* @authdata: pointer to authentication transform definitions
|
|
* Valid algorithm value: OP_PCL_IPSEC_AES_XCBC_MAC_96.
|
|
*
|
|
* Supported only for platforms with 32-bit address pointers and SEC ERA 4 or
|
|
* higher. The tunnel/transport mode of the IPsec ESP is supported only if the
|
|
* Outer/Transport IP Header is present in the decapsulation input packet.
|
|
* The descriptor computes the AES-XCBC-MAC-96 to check if the received ICV
|
|
* is correct, rereads the input packet to compute the MD5 ICV, overwrites
|
|
* the XCBC ICV, and then sends the modified input packet to the
|
|
* DES-CBC/3DES-CBC & HMAC-MD5-96 IPsec.
|
|
* The descriptor uses all the benefits of the built-in protocol by computing
|
|
* the IPsec ESP with a hardware supported algorithms combination
|
|
* (DES-CBC/3DES-CBC & HMAC-MD5-96). The HMAC-MD5 authentication algorithm
|
|
* was chosen in order to speed up the computational time for this intermediate
|
|
* step.
|
|
* Warning: The user must allocate at least 32 bytes for the authentication key
|
|
* (in order to use it also with HMAC-MD5-96),even when using a shorter key
|
|
* for the AES-XCBC-MAC-96.
|
|
*
|
|
* Return: size of descriptor written in words or negative number on error
|
|
*/
|
|
static inline int
|
|
cnstr_shdsc_ipsec_decap_des_aes_xcbc(uint32_t *descbuf,
|
|
struct ipsec_decap_pdb *pdb,
|
|
struct alginfo *cipherdata,
|
|
struct alginfo *authdata)
|
|
{
|
|
struct program prg;
|
|
struct program *p = &prg;
|
|
uint32_t ip_hdr_len = (pdb->options & PDBHDRLEN_MASK) >>
|
|
PDBHDRLEN_ESP_DECAP_SHIFT;
|
|
|
|
LABEL(hdr);
|
|
LABEL(jump_cmd);
|
|
LABEL(keyjump);
|
|
LABEL(outlen);
|
|
LABEL(seqin_ptr);
|
|
LABEL(seqout_ptr);
|
|
LABEL(swapped_seqout_fields);
|
|
LABEL(swapped_seqout_ptr);
|
|
REFERENCE(seqout_ptr_jump);
|
|
REFERENCE(phdr);
|
|
REFERENCE(pkeyjump);
|
|
REFERENCE(move_jump);
|
|
REFERENCE(move_jump_back);
|
|
REFERENCE(move_seqin_ptr);
|
|
REFERENCE(swapped_seqout_ptr_jump);
|
|
REFERENCE(write_swapped_seqout_ptr);
|
|
|
|
PROGRAM_CNTXT_INIT(p, descbuf, 0);
|
|
phdr = SHR_HDR(p, SHR_SERIAL, hdr, 0);
|
|
__rta_copy_ipsec_decap_pdb(p, pdb, cipherdata->algtype);
|
|
SET_LABEL(p, hdr);
|
|
pkeyjump = JUMP(p, keyjump, LOCAL_JUMP, ALL_TRUE, SHRD | SELF);
|
|
/*
|
|
* Hard-coded KEY arguments. The descriptor uses all the benefits of
|
|
* the built-in protocol by computing the IPsec ESP with a hardware
|
|
* supported algorithms combination (DES-CBC/3DES-CBC & HMAC-MD5-96).
|
|
* The HMAC-MD5 authentication algorithm was chosen with
|
|
* the keys options from bellow in order to speed up the computational
|
|
* time for this intermediate step.
|
|
* Warning: The user must allocate at least 32 bytes for
|
|
* the authentication key (in order to use it also with HMAC-MD5-96),
|
|
* even when using a shorter key for the AES-XCBC-MAC-96.
|
|
*/
|
|
KEY(p, MDHA_SPLIT_KEY, 0, authdata->key, 32, INLINE_KEY(authdata));
|
|
SET_LABEL(p, keyjump);
|
|
LOAD(p, LDST_SRCDST_WORD_CLRW | CLRW_CLR_C1MODE | CLRW_CLR_C1DATAS |
|
|
CLRW_CLR_C1CTX | CLRW_CLR_C1KEY | CLRW_RESET_CLS1_CHA, CLRW, 0, 4,
|
|
0);
|
|
KEY(p, KEY1, authdata->key_enc_flags, authdata->key, authdata->keylen,
|
|
INLINE_KEY(authdata));
|
|
MATHB(p, SEQINSZ, SUB,
|
|
(uint64_t)(ip_hdr_len + IPSEC_ICV_MD5_TRUNC_SIZE), MATH0, 4,
|
|
IMMED2);
|
|
MATHB(p, MATH0, SUB, ZERO, VSEQINSZ, 4, 0);
|
|
ALG_OPERATION(p, OP_ALG_ALGSEL_MD5, OP_ALG_AAI_HMAC_PRECOMP,
|
|
OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, DIR_ENC);
|
|
ALG_OPERATION(p, OP_ALG_ALGSEL_AES, OP_ALG_AAI_XCBC_MAC,
|
|
OP_ALG_AS_INITFINAL, ICV_CHECK_ENABLE, DIR_DEC);
|
|
SEQFIFOLOAD(p, SKIP, ip_hdr_len, 0);
|
|
SEQFIFOLOAD(p, MSG1, 0, VLF | FLUSH1);
|
|
SEQFIFOLOAD(p, ICV1, IPSEC_ICV_MD5_TRUNC_SIZE, FLUSH1 | LAST1);
|
|
/* Swap SEQOUTPTR to SEQINPTR. */
|
|
move_seqin_ptr = MOVE(p, DESCBUF, 0, MATH1, 0, 16, WAITCOMP | IMMED);
|
|
MATHB(p, MATH1, OR, CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR, MATH1, 8,
|
|
IFB | IMMED2);
|
|
/*
|
|
* TODO: RTA currently doesn't support creating a LOAD command
|
|
* with another command as IMM.
|
|
* To be changed when proper support is added in RTA.
|
|
*/
|
|
LOAD(p, 0xA00000e1, MATH3, 4, 4, IMMED);
|
|
MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
|
|
write_swapped_seqout_ptr = MOVE(p, MATH1, 0, DESCBUF, 0, 20, WAITCOMP |
|
|
IMMED);
|
|
swapped_seqout_ptr_jump = JUMP(p, swapped_seqout_ptr, LOCAL_JUMP,
|
|
ALL_TRUE, 0);
|
|
/*
|
|
* TODO: To be changed when proper support is added in RTA (can't load
|
|
* a command that is also written by RTA).
|
|
* Change when proper RTA support is added.
|
|
*/
|
|
SET_LABEL(p, jump_cmd);
|
|
WORD(p, 0xA00000f3);
|
|
SEQINPTR(p, 0, 65535, RTO);
|
|
MATHB(p, MATH0, SUB, ZERO, VSEQINSZ, 4, 0);
|
|
MATHB(p, MATH0, ADD, ip_hdr_len, VSEQOUTSZ, 4, IMMED2);
|
|
move_jump = MOVE(p, DESCBUF, 0, OFIFO, 0, 8, WAITCOMP | IMMED);
|
|
move_jump_back = MOVE(p, OFIFO, 0, DESCBUF, 0, 8, IMMED);
|
|
SEQFIFOLOAD(p, SKIP, ip_hdr_len, 0);
|
|
SEQFIFOLOAD(p, MSG2, 0, VLF | LAST2);
|
|
SEQFIFOSTORE(p, SKIP, 0, 0, VLF);
|
|
SEQSTORE(p, CONTEXT2, 0, IPSEC_ICV_MD5_TRUNC_SIZE, 0);
|
|
seqout_ptr_jump = JUMP(p, seqout_ptr, LOCAL_JUMP, ALL_TRUE, CALM);
|
|
|
|
LOAD(p, LDST_SRCDST_WORD_CLRW | CLRW_CLR_C1MODE | CLRW_CLR_C1DATAS |
|
|
CLRW_CLR_C1CTX | CLRW_CLR_C1KEY | CLRW_CLR_C2MODE |
|
|
CLRW_CLR_C2DATAS | CLRW_CLR_C2CTX | CLRW_RESET_CLS1_CHA, CLRW, 0,
|
|
4, 0);
|
|
SEQINPTR(p, 0, 65535, RTO);
|
|
MATHB(p, MATH0, ADD,
|
|
(uint64_t)(ip_hdr_len + IPSEC_ICV_MD5_TRUNC_SIZE), SEQINSZ, 4,
|
|
IMMED2);
|
|
KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
|
|
cipherdata->keylen, INLINE_KEY(cipherdata));
|
|
PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL, OP_PCLID_IPSEC,
|
|
(uint16_t)(cipherdata->algtype | OP_PCL_IPSEC_HMAC_MD5_96));
|
|
/*
|
|
* TODO: RTA currently doesn't support adding labels in or after Job Descriptor.
|
|
* To be changed when proper support is added in RTA.
|
|
*/
|
|
/* Label the SEQ OUT PTR */
|
|
SET_LABEL(p, seqout_ptr);
|
|
seqout_ptr += 2;
|
|
/* Label the Output Length */
|
|
SET_LABEL(p, outlen);
|
|
outlen += 4;
|
|
/* Label the SEQ IN PTR */
|
|
SET_LABEL(p, seqin_ptr);
|
|
seqin_ptr += 5;
|
|
/* Label the first word after JD */
|
|
SET_LABEL(p, swapped_seqout_fields);
|
|
swapped_seqout_fields += 8;
|
|
/* Label the second word after JD */
|
|
SET_LABEL(p, swapped_seqout_ptr);
|
|
swapped_seqout_ptr += 9;
|
|
|
|
PATCH_HDR(p, phdr, hdr);
|
|
PATCH_JUMP(p, pkeyjump, keyjump);
|
|
PATCH_JUMP(p, seqout_ptr_jump, seqout_ptr);
|
|
PATCH_JUMP(p, swapped_seqout_ptr_jump, swapped_seqout_ptr);
|
|
PATCH_MOVE(p, move_jump, jump_cmd);
|
|
PATCH_MOVE(p, move_jump_back, seqin_ptr);
|
|
PATCH_MOVE(p, move_seqin_ptr, outlen);
|
|
PATCH_MOVE(p, write_swapped_seqout_ptr, swapped_seqout_fields);
|
|
return PROGRAM_FINALIZE(p);
|
|
}
|
|
|
|
/**
|
|
* IPSEC_NEW_ENC_BASE_DESC_LEN - IPsec new mode encap shared descriptor length
|
|
*
|
|
* Accounts only for the "base" commands and is intended to be used by upper
|
|
* layers to determine whether Outer IP Header and/or keys can be inlined or
|
|
* not. To be used as first parameter of rta_inline_query().
|
|
*/
|
|
#define IPSEC_NEW_ENC_BASE_DESC_LEN (12 * CAAM_CMD_SZ + \
|
|
sizeof(struct ipsec_encap_pdb))
|
|
|
|
/**
|
|
* IPSEC_NEW_NULL_ENC_BASE_DESC_LEN - IPsec new mode encap shared descriptor
|
|
* length for the case of
|
|
* NULL encryption / authentication
|
|
*
|
|
* Accounts only for the "base" commands and is intended to be used by upper
|
|
* layers to determine whether Outer IP Header and/or key can be inlined or
|
|
* not. To be used as first parameter of rta_inline_query().
|
|
*/
|
|
#define IPSEC_NEW_NULL_ENC_BASE_DESC_LEN (11 * CAAM_CMD_SZ + \
|
|
sizeof(struct ipsec_encap_pdb))
|
|
|
|
/**
|
|
* cnstr_shdsc_ipsec_new_encap - IPSec new mode ESP encapsulation
|
|
* protocol-level shared descriptor.
|
|
* @descbuf: pointer to buffer used for descriptor construction
|
|
* @ps: if 36/40bit addressing is desired, this parameter must be true
|
|
* @swap: must be true when core endianness doesn't match SEC endianness
|
|
* @share: sharing type of shared descriptor
|
|
* @pdb: pointer to the PDB to be used with this descriptor
|
|
* This structure will be copied inline to the descriptor under
|
|
* construction. No error checking will be made. Refer to the
|
|
* block guide for details about the encapsulation PDB.
|
|
* @opt_ip_hdr: pointer to Optional IP Header
|
|
* -if OIHI = PDBOPTS_ESP_OIHI_PDB_INL, opt_ip_hdr points to the buffer to
|
|
* be inlined in the PDB. Number of bytes (buffer size) copied is provided
|
|
* in pdb->ip_hdr_len.
|
|
* -if OIHI = PDBOPTS_ESP_OIHI_PDB_REF, opt_ip_hdr points to the address of
|
|
* the Optional IP Header. The address will be inlined in the PDB verbatim.
|
|
* -for other values of OIHI options field, opt_ip_hdr is not used.
|
|
* @cipherdata: pointer to block cipher transform definitions
|
|
* Valid algorithm values - one of OP_PCL_IPSEC_*
|
|
* @authdata: pointer to authentication transform definitions.
|
|
* If an authentication key is required by the protocol, a "normal"
|
|
* key must be provided; DKP (Derived Key Protocol) will be used to
|
|
* compute MDHA on the fly in HW.
|
|
* Valid algorithm values - one of OP_PCL_IPSEC_*
|
|
*
|
|
* Note: L2 header copy functionality is implemented assuming that bits 14
|
|
* (currently reserved) and 16-23 (part of Outer IP Header Material Length)
|
|
* in DPOVRD register are not used (which is usually the case when L3 header
|
|
* is provided in PDB).
|
|
* When DPOVRD[14] is set, frame starts with an L2 header; in this case, the
|
|
* L2 header length is found at DPOVRD[23:16]. SEC uses this length to copy
|
|
* the header and then it deletes DPOVRD[23:16] (so there is no side effect
|
|
* when later running IPsec protocol).
|
|
*
|
|
* Return: size of descriptor written in words or negative number on error
|
|
*/
|
|
static inline int
|
|
cnstr_shdsc_ipsec_new_encap(uint32_t *descbuf, bool ps,
|
|
bool swap,
|
|
enum rta_share_type share,
|
|
struct ipsec_encap_pdb *pdb,
|
|
uint8_t *opt_ip_hdr,
|
|
struct alginfo *cipherdata,
|
|
struct alginfo *authdata)
|
|
{
|
|
struct program prg;
|
|
struct program *p = &prg;
|
|
|
|
LABEL(keyjmp);
|
|
REFERENCE(pkeyjmp);
|
|
LABEL(hdr);
|
|
REFERENCE(phdr);
|
|
LABEL(l2copy);
|
|
REFERENCE(pl2copy);
|
|
|
|
if (rta_sec_era < RTA_SEC_ERA_8) {
|
|
pr_err("IPsec new mode encap: available only for Era %d or above\n",
|
|
USER_SEC_ERA(RTA_SEC_ERA_8));
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
PROGRAM_CNTXT_INIT(p, descbuf, 0);
|
|
if (swap)
|
|
PROGRAM_SET_BSWAP(p);
|
|
if (ps)
|
|
PROGRAM_SET_36BIT_ADDR(p);
|
|
phdr = SHR_HDR(p, share, hdr, 0);
|
|
|
|
__rta_copy_ipsec_encap_pdb(p, pdb, cipherdata->algtype);
|
|
|
|
switch (pdb->options & PDBOPTS_ESP_OIHI_MASK) {
|
|
case PDBOPTS_ESP_OIHI_PDB_INL:
|
|
COPY_DATA(p, opt_ip_hdr, pdb->ip_hdr_len);
|
|
break;
|
|
case PDBOPTS_ESP_OIHI_PDB_REF:
|
|
if (ps)
|
|
COPY_DATA(p, opt_ip_hdr, 8);
|
|
else
|
|
COPY_DATA(p, opt_ip_hdr, 4);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
SET_LABEL(p, hdr);
|
|
|
|
MATHB(p, DPOVRD, AND, IPSEC_N_ENCAP_DPOVRD_L2_COPY, NONE, 4, IMMED2);
|
|
pl2copy = JUMP(p, l2copy, LOCAL_JUMP, ALL_TRUE, MATH_Z);
|
|
MATHI(p, DPOVRD, RSHIFT, IPSEC_N_ENCAP_DPOVRD_L2_LEN_SHIFT, VSEQOUTSZ,
|
|
1, 0);
|
|
MATHB(p, DPOVRD, AND, ~IPSEC_N_ENCAP_DPOVRD_L2_LEN_MASK, DPOVRD, 4,
|
|
IMMED2);
|
|
/* TODO: CLASS2 corresponds to AUX=2'b10; add more intuitive defines */
|
|
SEQFIFOSTORE(p, METADATA, 0, 0, CLASS2 | VLF);
|
|
SET_LABEL(p, l2copy);
|
|
|
|
pkeyjmp = JUMP(p, keyjmp, LOCAL_JUMP, ALL_TRUE, SHRD);
|
|
if (authdata->keylen)
|
|
__gen_auth_key(p, authdata);
|
|
if (cipherdata->keylen)
|
|
KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
|
|
cipherdata->keylen, INLINE_KEY(cipherdata));
|
|
SET_LABEL(p, keyjmp);
|
|
PROTOCOL(p, OP_TYPE_ENCAP_PROTOCOL,
|
|
OP_PCLID_IPSEC_NEW,
|
|
(uint16_t)(cipherdata->algtype | authdata->algtype));
|
|
PATCH_JUMP(p, pl2copy, l2copy);
|
|
PATCH_JUMP(p, pkeyjmp, keyjmp);
|
|
PATCH_HDR(p, phdr, hdr);
|
|
return PROGRAM_FINALIZE(p);
|
|
}
|
|
|
|
/**
|
|
* IPSEC_NEW_DEC_BASE_DESC_LEN - IPsec new mode decap shared descriptor length
|
|
*
|
|
* Accounts only for the "base" commands and is intended to be used by upper
|
|
* layers to determine whether keys can be inlined or not. To be used as first
|
|
* parameter of rta_inline_query().
|
|
*/
|
|
#define IPSEC_NEW_DEC_BASE_DESC_LEN (5 * CAAM_CMD_SZ + \
|
|
sizeof(struct ipsec_decap_pdb))
|
|
|
|
/**
|
|
* IPSEC_NEW_NULL_DEC_BASE_DESC_LEN - IPsec new mode decap shared descriptor
|
|
* length for the case of
|
|
* NULL decryption / authentication
|
|
*
|
|
* Accounts only for the "base" commands and is intended to be used by upper
|
|
* layers to determine whether key can be inlined or not. To be used as first
|
|
* parameter of rta_inline_query().
|
|
*/
|
|
#define IPSEC_NEW_NULL_DEC_BASE_DESC_LEN (4 * CAAM_CMD_SZ + \
|
|
sizeof(struct ipsec_decap_pdb))
|
|
|
|
/**
|
|
* cnstr_shdsc_ipsec_new_decap - IPSec new mode ESP decapsulation protocol-level
|
|
* shared descriptor.
|
|
* @descbuf: pointer to buffer used for descriptor construction
|
|
* @ps: if 36/40bit addressing is desired, this parameter must be true
|
|
* @swap: must be true when core endianness doesn't match SEC endianness
|
|
* @share: sharing type of shared descriptor
|
|
* @pdb: pointer to the PDB to be used with this descriptor
|
|
* This structure will be copied inline to the descriptor under
|
|
* construction. No error checking will be made. Refer to the
|
|
* block guide for details about the decapsulation PDB.
|
|
* @cipherdata: pointer to block cipher transform definitions
|
|
* Valid algorithm values 0 one of OP_PCL_IPSEC_*
|
|
* @authdata: pointer to authentication transform definitions.
|
|
* If an authentication key is required by the protocol, a "normal"
|
|
* key must be provided; DKP (Derived Key Protocol) will be used to
|
|
* compute MDHA on the fly in HW.
|
|
* Valid algorithm values - one of OP_PCL_IPSEC_*
|
|
*
|
|
* Return: size of descriptor written in words or negative number on error
|
|
*/
|
|
static inline int
|
|
cnstr_shdsc_ipsec_new_decap(uint32_t *descbuf, bool ps,
|
|
bool swap,
|
|
enum rta_share_type share,
|
|
struct ipsec_decap_pdb *pdb,
|
|
struct alginfo *cipherdata,
|
|
struct alginfo *authdata)
|
|
{
|
|
struct program prg;
|
|
struct program *p = &prg;
|
|
|
|
LABEL(keyjmp);
|
|
REFERENCE(pkeyjmp);
|
|
LABEL(hdr);
|
|
REFERENCE(phdr);
|
|
|
|
if (rta_sec_era < RTA_SEC_ERA_8) {
|
|
pr_err("IPsec new mode decap: available only for Era %d or above\n",
|
|
USER_SEC_ERA(RTA_SEC_ERA_8));
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
PROGRAM_CNTXT_INIT(p, descbuf, 0);
|
|
if (swap)
|
|
PROGRAM_SET_BSWAP(p);
|
|
if (ps)
|
|
PROGRAM_SET_36BIT_ADDR(p);
|
|
phdr = SHR_HDR(p, share, hdr, 0);
|
|
__rta_copy_ipsec_decap_pdb(p, pdb, cipherdata->algtype);
|
|
SET_LABEL(p, hdr);
|
|
pkeyjmp = JUMP(p, keyjmp, LOCAL_JUMP, ALL_TRUE, SHRD);
|
|
if (authdata->keylen)
|
|
__gen_auth_key(p, authdata);
|
|
if (cipherdata->keylen)
|
|
KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
|
|
cipherdata->keylen, INLINE_KEY(cipherdata));
|
|
SET_LABEL(p, keyjmp);
|
|
PROTOCOL(p, OP_TYPE_DECAP_PROTOCOL,
|
|
OP_PCLID_IPSEC_NEW,
|
|
(uint16_t)(cipherdata->algtype | authdata->algtype));
|
|
PATCH_JUMP(p, pkeyjmp, keyjmp);
|
|
PATCH_HDR(p, phdr, hdr);
|
|
return PROGRAM_FINALIZE(p);
|
|
}
|
|
|
|
/**
|
|
* IPSEC_AUTH_VAR_BASE_DESC_LEN - IPsec encap/decap shared descriptor length
|
|
* for the case of variable-length authentication
|
|
* only data.
|
|
* Note: Only for SoCs with SEC_ERA >= 3.
|
|
*
|
|
* Accounts only for the "base" commands and is intended to be used by upper
|
|
* layers to determine whether keys can be inlined or not. To be used as first
|
|
* parameter of rta_inline_query().
|
|
*/
|
|
#define IPSEC_AUTH_VAR_BASE_DESC_LEN (27 * CAAM_CMD_SZ)
|
|
|
|
/**
|
|
* IPSEC_AUTH_VAR_AES_DEC_BASE_DESC_LEN - IPsec AES decap shared descriptor
|
|
* length for variable-length authentication only
|
|
* data.
|
|
* Note: Only for SoCs with SEC_ERA >= 3.
|
|
*
|
|
* Accounts only for the "base" commands and is intended to be used by upper
|
|
* layers to determine whether key can be inlined or not. To be used as first
|
|
* parameter of rta_inline_query().
|
|
*/
|
|
#define IPSEC_AUTH_VAR_AES_DEC_BASE_DESC_LEN \
|
|
(IPSEC_AUTH_VAR_BASE_DESC_LEN + CAAM_CMD_SZ)
|
|
|
|
/**
|
|
* IPSEC_AUTH_BASE_DESC_LEN - IPsec encap/decap shared descriptor length
|
|
*
|
|
* Accounts only for the "base" commands and is intended to be used by upper
|
|
* layers to determine whether key can be inlined or not. To be used as first
|
|
* parameter of rta_inline_query().
|
|
*/
|
|
#define IPSEC_AUTH_BASE_DESC_LEN (19 * CAAM_CMD_SZ)
|
|
|
|
/**
|
|
* IPSEC_AUTH_AES_DEC_BASE_DESC_LEN - IPsec AES decap shared descriptor length
|
|
*
|
|
* Accounts only for the "base" commands and is intended to be used by upper
|
|
* layers to determine whether key can be inlined or not. To be used as first
|
|
* parameter of rta_inline_query().
|
|
*/
|
|
#define IPSEC_AUTH_AES_DEC_BASE_DESC_LEN (IPSEC_AUTH_BASE_DESC_LEN + \
|
|
CAAM_CMD_SZ)
|
|
|
|
/**
|
|
* cnstr_shdsc_authenc - authenc-like descriptor
|
|
* @descbuf: pointer to buffer used for descriptor construction
|
|
* @ps: if 36/40bit addressing is desired, this parameter must be true
|
|
* @swap: if true, perform descriptor byte swapping on a 4-byte boundary
|
|
* @cipherdata: pointer to block cipher transform definitions.
|
|
* Valid algorithm values one of OP_ALG_ALGSEL_* {DES, 3DES, AES}
|
|
* Valid modes for:
|
|
* AES: OP_ALG_AAI_* {CBC, CTR}
|
|
* DES, 3DES: OP_ALG_AAI_CBC
|
|
* @authdata: pointer to authentication transform definitions.
|
|
* Valid algorithm values - one of OP_ALG_ALGSEL_* {MD5, SHA1,
|
|
* SHA224, SHA256, SHA384, SHA512}
|
|
* Note: The key for authentication is supposed to be given as plain text.
|
|
* Note: There's no support for keys longer than the block size of the
|
|
* underlying hash function, according to the selected algorithm.
|
|
*
|
|
* @ivlen: length of the IV to be read from the input frame, before any data
|
|
* to be processed
|
|
* @auth_only_len: length of the data to be authenticated-only (commonly IP
|
|
* header, IV, Sequence number and SPI)
|
|
* Note: Extended Sequence Number processing is NOT supported
|
|
*
|
|
* @trunc_len: the length of the ICV to be written to the output frame. If 0,
|
|
* then the corresponding length of the digest, according to the
|
|
* selected algorithm shall be used.
|
|
* @dir: Protocol direction, encapsulation or decapsulation (DIR_ENC/DIR_DEC)
|
|
*
|
|
* Note: Here's how the input frame needs to be formatted so that the processing
|
|
* will be done correctly:
|
|
* For encapsulation:
|
|
* Input:
|
|
* +----+----------------+---------------------------------------------+
|
|
* | IV | Auth-only data | Padded data to be authenticated & Encrypted |
|
|
* +----+----------------+---------------------------------------------+
|
|
* Output:
|
|
* +--------------------------------------+
|
|
* | Authenticated & Encrypted data | ICV |
|
|
* +--------------------------------+-----+
|
|
|
|
* For decapsulation:
|
|
* Input:
|
|
* +----+----------------+--------------------------------+-----+
|
|
* | IV | Auth-only data | Authenticated & Encrypted data | ICV |
|
|
* +----+----------------+--------------------------------+-----+
|
|
* Output:
|
|
* +----+--------------------------+
|
|
* | Decrypted & authenticated data |
|
|
* +----+--------------------------+
|
|
*
|
|
* Note: This descriptor can use per-packet commands, encoded as below in the
|
|
* DPOVRD register:
|
|
* 32 24 16 0
|
|
* +------+---------------------+
|
|
* | 0x80 | 0x00| auth_only_len |
|
|
* +------+---------------------+
|
|
*
|
|
* This mechanism is available only for SoCs having SEC ERA >= 3. In other
|
|
* words, this will not work for P4080TO2
|
|
*
|
|
* Note: The descriptor does not add any kind of padding to the input data,
|
|
* so the upper layer needs to ensure that the data is padded properly,
|
|
* according to the selected cipher. Failure to do so will result in
|
|
* the descriptor failing with a data-size error.
|
|
*
|
|
* Return: size of descriptor written in words or negative number on error
|
|
*/
|
|
static inline int
|
|
cnstr_shdsc_authenc(uint32_t *descbuf, bool ps, bool swap,
|
|
struct alginfo *cipherdata,
|
|
struct alginfo *authdata,
|
|
uint16_t ivlen, uint16_t auth_only_len,
|
|
uint8_t trunc_len, uint8_t dir)
|
|
{
|
|
struct program prg;
|
|
struct program *p = &prg;
|
|
const bool need_dk = (dir == DIR_DEC) &&
|
|
(cipherdata->algtype == OP_ALG_ALGSEL_AES) &&
|
|
(cipherdata->algmode == OP_ALG_AAI_CBC);
|
|
|
|
LABEL(skip_patch_len);
|
|
LABEL(keyjmp);
|
|
LABEL(skipkeys);
|
|
LABEL(aonly_len_offset);
|
|
REFERENCE(pskip_patch_len);
|
|
REFERENCE(pkeyjmp);
|
|
REFERENCE(pskipkeys);
|
|
REFERENCE(read_len);
|
|
REFERENCE(write_len);
|
|
|
|
PROGRAM_CNTXT_INIT(p, descbuf, 0);
|
|
|
|
if (swap)
|
|
PROGRAM_SET_BSWAP(p);
|
|
if (ps)
|
|
PROGRAM_SET_36BIT_ADDR(p);
|
|
|
|
/*
|
|
* Since we currently assume that key length is equal to hash digest
|
|
* size, it's ok to truncate keylen value.
|
|
*/
|
|
trunc_len = trunc_len && (trunc_len < authdata->keylen) ?
|
|
trunc_len : (uint8_t)authdata->keylen;
|
|
|
|
SHR_HDR(p, SHR_SERIAL, 1, SC);
|
|
|
|
/*
|
|
* M0 will contain the value provided by the user when creating
|
|
* the shared descriptor. If the user provided an override in
|
|
* DPOVRD, then M0 will contain that value
|
|
*/
|
|
MATHB(p, MATH0, ADD, auth_only_len, MATH0, 4, IMMED2);
|
|
|
|
if (rta_sec_era >= RTA_SEC_ERA_3) {
|
|
/*
|
|
* Check if the user wants to override the auth-only len
|
|
*/
|
|
MATHB(p, DPOVRD, ADD, 0x80000000, MATH2, 4, IMMED2);
|
|
|
|
/*
|
|
* No need to patch the length of the auth-only data read if
|
|
* the user did not override it
|
|
*/
|
|
pskip_patch_len = JUMP(p, skip_patch_len, LOCAL_JUMP, ALL_TRUE,
|
|
MATH_N);
|
|
|
|
/* Get auth-only len in M0 */
|
|
MATHB(p, MATH2, AND, 0xFFFF, MATH0, 4, IMMED2);
|
|
|
|
/*
|
|
* Since M0 is used in calculations, don't mangle it, copy
|
|
* its content to M1 and use this for patching.
|
|
*/
|
|
MATHB(p, MATH0, ADD, MATH1, MATH1, 4, 0);
|
|
|
|
read_len = MOVE(p, DESCBUF, 0, MATH1, 0, 6, WAITCOMP | IMMED);
|
|
write_len = MOVE(p, MATH1, 0, DESCBUF, 0, 8, WAITCOMP | IMMED);
|
|
|
|
SET_LABEL(p, skip_patch_len);
|
|
}
|
|
/*
|
|
* MATH0 contains the value in DPOVRD w/o the MSB, or the initial
|
|
* value, as provided by the user at descriptor creation time
|
|
*/
|
|
if (dir == DIR_ENC)
|
|
MATHB(p, MATH0, ADD, ivlen, MATH0, 4, IMMED2);
|
|
else
|
|
MATHB(p, MATH0, ADD, ivlen + trunc_len, MATH0, 4, IMMED2);
|
|
|
|
pkeyjmp = JUMP(p, keyjmp, LOCAL_JUMP, ALL_TRUE, SHRD);
|
|
|
|
KEY(p, KEY2, authdata->key_enc_flags, authdata->key, authdata->keylen,
|
|
INLINE_KEY(authdata));
|
|
|
|
/* Insert Key */
|
|
KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
|
|
cipherdata->keylen, INLINE_KEY(cipherdata));
|
|
|
|
/* Do operation */
|
|
ALG_OPERATION(p, authdata->algtype, OP_ALG_AAI_HMAC,
|
|
OP_ALG_AS_INITFINAL,
|
|
dir == DIR_ENC ? ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
|
|
dir);
|
|
|
|
if (need_dk)
|
|
ALG_OPERATION(p, OP_ALG_ALGSEL_AES, cipherdata->algmode,
|
|
OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, dir);
|
|
pskipkeys = JUMP(p, skipkeys, LOCAL_JUMP, ALL_TRUE, 0);
|
|
|
|
SET_LABEL(p, keyjmp);
|
|
|
|
ALG_OPERATION(p, authdata->algtype, OP_ALG_AAI_HMAC_PRECOMP,
|
|
OP_ALG_AS_INITFINAL,
|
|
dir == DIR_ENC ? ICV_CHECK_DISABLE : ICV_CHECK_ENABLE,
|
|
dir);
|
|
|
|
if (need_dk) {
|
|
ALG_OPERATION(p, OP_ALG_ALGSEL_AES, cipherdata->algmode |
|
|
OP_ALG_AAI_DK, OP_ALG_AS_INITFINAL,
|
|
ICV_CHECK_DISABLE, dir);
|
|
SET_LABEL(p, skipkeys);
|
|
} else {
|
|
SET_LABEL(p, skipkeys);
|
|
ALG_OPERATION(p, cipherdata->algtype, cipherdata->algmode,
|
|
OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, dir);
|
|
}
|
|
|
|
/*
|
|
* Prepare the length of the data to be both encrypted/decrypted
|
|
* and authenticated/checked
|
|
*/
|
|
MATHB(p, SEQINSZ, SUB, MATH0, VSEQINSZ, 4, 0);
|
|
|
|
MATHB(p, VSEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0);
|
|
|
|
/* Prepare for writing the output frame */
|
|
SEQFIFOSTORE(p, MSG, 0, 0, VLF);
|
|
|
|
SET_LABEL(p, aonly_len_offset);
|
|
|
|
/* Read IV */
|
|
if (cipherdata->algmode == OP_ALG_AAI_CTR)
|
|
SEQLOAD(p, CONTEXT1, 16, ivlen, 0);
|
|
else
|
|
SEQLOAD(p, CONTEXT1, 0, ivlen, 0);
|
|
|
|
/*
|
|
* Read data needed only for authentication. This is overwritten above
|
|
* if the user requested it.
|
|
*/
|
|
SEQFIFOLOAD(p, MSG2, auth_only_len, 0);
|
|
|
|
if (dir == DIR_ENC) {
|
|
/*
|
|
* Read input plaintext, encrypt and authenticate & write to
|
|
* output
|
|
*/
|
|
SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
|
|
|
|
/* Finally, write the ICV */
|
|
SEQSTORE(p, CONTEXT2, 0, trunc_len, 0);
|
|
} else {
|
|
/*
|
|
* Read input ciphertext, decrypt and authenticate & write to
|
|
* output
|
|
*/
|
|
SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST1 | LAST2 | FLUSH1);
|
|
|
|
/* Read the ICV to check */
|
|
SEQFIFOLOAD(p, ICV2, trunc_len, LAST2);
|
|
}
|
|
|
|
PATCH_JUMP(p, pkeyjmp, keyjmp);
|
|
PATCH_JUMP(p, pskipkeys, skipkeys);
|
|
PATCH_JUMP(p, pskipkeys, skipkeys);
|
|
|
|
if (rta_sec_era >= RTA_SEC_ERA_3) {
|
|
PATCH_JUMP(p, pskip_patch_len, skip_patch_len);
|
|
PATCH_MOVE(p, read_len, aonly_len_offset);
|
|
PATCH_MOVE(p, write_len, aonly_len_offset);
|
|
}
|
|
|
|
return PROGRAM_FINALIZE(p);
|
|
}
|
|
|
|
#endif /* __DESC_IPSEC_H__ */
|