These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / include / ipxe / pccrc.h
diff --git a/qemu/roms/ipxe/src/include/ipxe/pccrc.h b/qemu/roms/ipxe/src/include/ipxe/pccrc.h
new file mode 100644 (file)
index 0000000..7f09634
--- /dev/null
@@ -0,0 +1,447 @@
+#ifndef _IPXE_PCCRC_H
+#define _IPXE_PCCRC_H
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC]
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/crypto.h>
+
+/******************************************************************************
+ *
+ * Content Information versioning
+ *
+ ******************************************************************************
+ *
+ * Note that version 1 data structures are little-endian, but version
+ * 2 data structures are big-endian.
+ */
+
+/** Content Information version number */
+union peerdist_info_version {
+       /** Raw version number
+        *
+        * Always little-endian, regardless of whether the
+        * encompassing structure is version 1 (little-endian) or
+        * version 2 (big-endian).
+        */
+       uint16_t raw;
+       /** Major:minor version number */
+       struct {
+               /** Minor version number */
+               uint8_t minor;
+               /** Major version number */
+               uint8_t major;
+       } __attribute__ (( packed ));
+} __attribute__ (( packed ));
+
+/** Content Information version 1 */
+#define PEERDIST_INFO_V1 0x0100
+
+/** Content Information version 2 */
+#define PEERDIST_INFO_V2 0x0200
+
+/******************************************************************************
+ *
+ * Content Information version 1
+ *
+ ******************************************************************************
+ */
+
+/** Content Information version 1 data structure header
+ *
+ * All fields are little-endian.
+ */
+struct peerdist_info_v1 {
+       /** Version number */
+       union peerdist_info_version version;
+       /** Hash algorithm
+        *
+        * This is a @c PEERDIST_INFO_V1_HASH_XXX constant.
+        */
+       uint32_t hash;
+       /** Length to skip in first segment
+        *
+        * Length at the start of the first segment which is not
+        * included within the content range.
+        */
+       uint32_t first;
+       /** Length to read in last segment, or zero
+        *
+        * Length within the last segment which is included within the
+        * content range.  A zero value indicates that the whole of
+        * the last segment is included within the content range.
+        */
+       uint32_t last;
+       /** Number of segments within the content information */
+       uint32_t segments;
+       /* Followed by a variable-length array of segment descriptions
+        * and a list of variable-length block descriptions:
+        *
+        * peerdist_info_v1_segment_t(digestsize) segment[segments];
+        * peerdist_info_v1_block_t(digestsize, block0.blocks) block0;
+        * peerdist_info_v1_block_t(digestsize, block1.blocks) block1;
+        * ...
+        * peerdist_info_v1_block_t(digestsize, blockN.blocks) blockN;
+        */
+} __attribute__ (( packed ));
+
+/** SHA-256 hash algorithm */
+#define PEERDIST_INFO_V1_HASH_SHA256 0x0000800cUL
+
+/** SHA-384 hash algorithm */
+#define PEERDIST_INFO_V1_HASH_SHA384 0x0000800dUL
+
+/** SHA-512 hash algorithm */
+#define PEERDIST_INFO_V1_HASH_SHA512 0x0000800eUL
+
+/** Content Information version 1 segment description header
+ *
+ * All fields are little-endian.
+ */
+struct peerdist_info_v1_segment {
+       /** Offset of this segment within the content */
+       uint64_t offset;
+       /** Length of this segment
+        *
+        * Should always be 32MB, except for the last segment within
+        * the content.
+        */
+       uint32_t len;
+       /** Block size for this segment
+        *
+        * Should always be 64kB.  Note that the last block within the
+        * last segment may actually be less than 64kB.
+        */
+       uint32_t blksize;
+       /* Followed by two variable-length hashes:
+        *
+        * uint8_t hash[digestsize];
+        * uint8_t secret[digestsize];
+        *
+        * where digestsize is the digest size for the selected hash
+        * algorithm.
+        *
+        * Note that the hash is taken over (the hashes of all blocks
+        * within) the entire segment, even if the blocks do not
+        * intersect the content range (and so do not appear within
+        * the block list).  It therefore functions only as a segment
+        * identifier; it cannot be used to verify the content of the
+        * segment (since we may not download all blocks within the
+        * segment).
+        */
+} __attribute__ (( packed ));
+
+/** Content Information version 1 segment description
+ *
+ * @v digestsize       Digest size
+ */
+#define peerdist_info_v1_segment_t( digestsize )                       \
+       struct {                                                        \
+               struct peerdist_info_v1_segment segment;                \
+               uint8_t hash[digestsize];                               \
+               uint8_t secret[digestsize];                             \
+       } __attribute__ (( packed ))
+
+/** Content Information version 1 block description header
+ *
+ * All fields are little-endian.
+ */
+struct peerdist_info_v1_block {
+       /** Number of blocks within the block description
+        *
+        * This is the number of blocks within the segment which
+        * overlap the content range.  It may therefore be less than
+        * the number of blocks within the segment.
+        */
+       uint32_t blocks;
+       /* Followed by an array of variable-length hashes:
+        *
+        * uint8_t hash[blocks][digestsize];
+        *
+        * where digestsize is the digest size for the selected hash
+        * algorithm.
+        */
+ } __attribute__ (( packed ));
+
+/** Content Information version 1 block description
+ *
+ * @v digestsize       Digest size
+ * @v blocks           Number of blocks
+ */
+#define peerdist_info_v1_block_t( digestsize, blocks )                 \
+       struct {                                                        \
+               struct peerdist_info_v1_block block;                    \
+               uint8_t hash[blocks][digestsize];                       \
+       } __attribute__ (( packed ))
+
+/******************************************************************************
+ *
+ * Content Information version 2
+ *
+ ******************************************************************************
+ */
+
+/** Content Information version 2 data structure header
+ *
+ * All fields are big-endian.
+ */
+struct peerdist_info_v2 {
+       /** Version number */
+       union peerdist_info_version version;
+       /** Hash algorithm
+        *
+        * This is a @c PEERDIST_INFO_V2_HASH_XXX constant.
+        */
+       uint8_t hash;
+       /** Offset of the first segment within the content */
+       uint64_t offset;
+       /** Index of the first segment within the content */
+       uint64_t index;
+       /** Length to skip in first segment
+        *
+        * Length at the start of the first segment which is not
+        * included within the content range.
+        */
+       uint32_t first;
+       /** Length of content range, or zero
+        *
+        * Length of the content range.  A zero indicates that
+        * everything up to the end of the last segment is included in
+        * the content range.
+        */
+       uint64_t len;
+       /* Followed by a list of chunk descriptions */
+} __attribute__ (( packed ));
+
+/** SHA-512 hash algorithm with output truncated to first 256 bits */
+#define PEERDIST_INFO_V2_HASH_SHA512_TRUNC 0x04
+
+/** Content Information version 2 chunk description header
+ *
+ * All fields are big-endian.
+ */
+struct peerdist_info_v2_chunk {
+       /** Chunk type */
+       uint8_t type;
+       /** Chunk data length */
+       uint32_t len;
+       /* Followed by an array of segment descriptions:
+        *
+        * peerdist_info_v2_segment_t(digestsize) segment[segments]
+        *
+        * where digestsize is the digest size for the selected hash
+        * algorithm, and segments is equal to @c len divided by the
+        * size of each segment array entry.
+        */
+} __attribute__ (( packed ));
+
+/** Content Information version 2 chunk description
+ *
+ * @v digestsize       Digest size
+ */
+#define peerdist_info_v2_chunk_t( digestsize )                         \
+       struct {                                                        \
+               struct peerdist_info_v2_chunk chunk;                    \
+               peerdist_info_v2_segment_t ( digestsize ) segment[0];   \
+       } __attribute__ (( packed ))
+
+/** Chunk type */
+#define PEERDIST_INFO_V2_CHUNK_TYPE 0x00
+
+/** Content Information version 2 segment description header
+ *
+ * All fields are big-endian.
+ */
+struct peerdist_info_v2_segment {
+       /** Segment length */
+       uint32_t len;
+       /* Followed by two variable-length hashes:
+        *
+        * uint8_t hash[digestsize];
+        * uint8_t secret[digestsize];
+        *
+        * where digestsize is the digest size for the selected hash
+        * algorithm.
+        */
+} __attribute__ (( packed ));
+
+/** Content Information version 2 segment description
+ *
+ * @v digestsize       Digest size
+ */
+#define peerdist_info_v2_segment_t( digestsize )                       \
+       struct {                                                        \
+               struct peerdist_info_v2_segment segment;                \
+               uint8_t hash[digestsize];                               \
+               uint8_t secret[digestsize];                             \
+       } __attribute__ (( packed ))
+
+/******************************************************************************
+ *
+ * Content Information
+ *
+ ******************************************************************************
+ */
+
+/** Maximum digest size for any supported algorithm
+ *
+ * The largest digest size that we support is for SHA-512 at 64 bytes
+ */
+#define PEERDIST_DIGEST_MAX_SIZE 64
+
+/** Raw content information */
+struct peerdist_raw {
+       /** Data buffer */
+       userptr_t data;
+       /** Length of data buffer */
+       size_t len;
+};
+
+/** A content range */
+struct peerdist_range {
+       /** Start offset */
+       size_t start;
+       /** End offset */
+       size_t end;
+};
+
+/** Content information */
+struct peerdist_info {
+       /** Raw content information */
+       struct peerdist_raw raw;
+
+       /** Content information operations */
+       struct peerdist_info_operations *op;
+       /** Digest algorithm */
+       struct digest_algorithm *digest;
+       /** Digest size
+        *
+        * Note that this may be shorter than the digest size of the
+        * digest algorithm.  The truncation does not always take
+        * place as soon as a digest is calculated.  For example,
+        * version 2 content information uses SHA-512 with a truncated
+        * digest size of 32 (256 bits), but the segment identifier
+        * ("HoHoDk") is calculated by using HMAC with the full
+        * SHA-512 digest and then truncating the HMAC output, rather
+        * than by simply using HMAC with the truncated SHA-512
+        * digest.  This is, of course, totally undocumented.
+        */
+       size_t digestsize;
+       /** Content range */
+       struct peerdist_range range;
+       /** Trimmed content range */
+       struct peerdist_range trim;
+       /** Number of segments within the content information */
+       unsigned int segments;
+};
+
+/** A content information segment */
+struct peerdist_info_segment {
+       /** Content information */
+       const struct peerdist_info *info;
+       /** Segment index */
+       unsigned int index;
+
+       /** Content range
+        *
+        * Note that this range may exceed the overall content range.
+        */
+       struct peerdist_range range;
+       /** Number of blocks within this segment */
+       unsigned int blocks;
+       /** Block size */
+       size_t blksize;
+       /** Segment hash of data
+        *
+        * This is MS-PCCRC's "HoD".
+        */
+       uint8_t hash[PEERDIST_DIGEST_MAX_SIZE];
+       /** Segment secret
+        *
+        * This is MS-PCCRC's "Ke = Kp".
+        */
+       uint8_t secret[PEERDIST_DIGEST_MAX_SIZE];
+       /** Segment identifier
+        *
+        * This is MS-PCCRC's "HoHoDk".
+        */
+       uint8_t id[PEERDIST_DIGEST_MAX_SIZE];
+};
+
+/** Magic string constant used to calculate segment identifier
+ *
+ * Note that the MS-PCCRC specification states that this constant is
+ *
+ *   "the null-terminated ASCII string constant "MS_P2P_CACHING";
+ *    string literals are all ASCII strings with NULL terminators
+ *    unless otherwise noted."
+ *
+ * The specification lies.  This constant is a UTF-16LE string, not an
+ * ASCII string.  The terminating wNUL *is* included within the
+ * constant.
+ */
+#define PEERDIST_SEGMENT_ID_MAGIC L"MS_P2P_CACHING"
+
+/** A content information block */
+struct peerdist_info_block {
+       /** Content information segment */
+       const struct peerdist_info_segment *segment;
+       /** Block index */
+       unsigned int index;
+
+       /** Content range
+        *
+        * Note that this range may exceed the overall content range.
+        */
+       struct peerdist_range range;
+       /** Trimmed content range */
+       struct peerdist_range trim;
+       /** Block hash */
+       uint8_t hash[PEERDIST_DIGEST_MAX_SIZE];
+};
+
+/** Content information operations */
+struct peerdist_info_operations {
+       /**
+        * Populate content information
+        *
+        * @v info              Content information to fill in
+        * @ret rc              Return status code
+        */
+       int ( * info ) ( struct peerdist_info *info );
+       /**
+        * Populate content information segment
+        *
+        * @v segment           Content information segment to fill in
+        * @ret rc              Return status code
+        */
+       int ( * segment ) ( struct peerdist_info_segment *segment );
+       /**
+        * Populate content information block
+        *
+        * @v block             Content information block to fill in
+        * @ret rc              Return status code
+        */
+       int ( * block ) ( struct peerdist_info_block *block );
+};
+
+extern struct digest_algorithm sha512_trunc_algorithm;
+
+extern int peerdist_info ( userptr_t data, size_t len,
+                          struct peerdist_info *info );
+extern int peerdist_info_segment ( const struct peerdist_info *info,
+                                  struct peerdist_info_segment *segment,
+                                  unsigned int index );
+extern int peerdist_info_block ( const struct peerdist_info_segment *segment,
+                                struct peerdist_info_block *block,
+                                unsigned int index );
+
+#endif /* _IPXE_PCCRC_H */