49 #define PEERBLK_DECRYPT_CHUNKSIZE 2048 68 #define PEERBLK_RAW_MAX 2 74 #define PEERBLK_RAW_OPEN_TIMEOUT ( 10 * TICKS_PER_SEC ) 80 #define PEERBLK_RAW_RX_TIMEOUT ( 15 * TICKS_PER_SEC ) 86 #define PEERBLK_RETRIEVAL_OPEN_TIMEOUT ( 3 * TICKS_PER_SEC ) 92 #define PEERBLK_RETRIEVAL_RX_TIMEOUT ( 5 * TICKS_PER_SEC ) 103 #define PEERBLK_MAX_ATTEMPT_CYCLES 4 107 { .
name =
"peerblk.download" };
111 { .
name =
"peerblk.attempt.success" };
115 { .
name =
"peerblk.attempt.failure" };
119 { .
name =
"peerblk.attempt.timeout" };
123 { .
name =
"peerblk.discovery.success" };
127 { .
name =
"peerblk.discovery.timeout" };
136 static inline __attribute__ (( always_inline ))
unsigned long 179 if ( peerblk->
queue )
251 size_t end = ( pos +
len );
264 if ( start < peerblk->
start ) {
268 if (
end > peerblk->
end ) {
274 memcpy ( &xfer_meta,
meta,
sizeof ( xfer_meta ) );
280 &xfer_meta ) ) != 0 ) {
281 DBGC ( peerblk,
"PEERBLK %p %d.%d could not deliver data: %s\n",
306 DBGC ( peerblk,
"PEERBLK %p %d.%d attempt failed: %s\n",
315 DBGC ( peerblk,
"PEERBLK %p %d.%d digest mismatch:\n",
362 DBGC2 ( peerblk,
"PEERBLK %p %d.%d attempting raw range request\n",
373 DBGC ( peerblk,
"PEERBLK %p %d.%d could not create range " 374 "request: %s\n", peerblk, peerblk->
segment,
405 size_t pos = peerblk->
pos;
430 if ( ( pos <
mid ) && ( ( pos +
len ) >=
mid ) &&
501 if ( (
rc =
queue->open ( peerblk ) ) != 0 ) {
584 char uri_string[ 7 +
strlen ( location ) +
588 snprintf ( uri_string,
sizeof ( uri_string ),
603 const char *location ) {
611 DBGC2 ( peerblk,
"PEERBLK %p %d.%d attempting retrieval from %s\n",
615 memset ( &req, 0,
sizeof ( req ) );
618 req.getblks.hdr.len =
htonl (
sizeof ( req ) );
622 req.ranges.ranges.count =
htonl ( 1 );
623 req.ranges.range[0].first =
htonl ( peerblk->
block );
624 req.ranges.range[0].count =
htonl ( 1 );
627 memset ( &content, 0,
sizeof ( content ) );
629 content.
len =
sizeof ( req );
643 NULL, &content ) ) != 0 ) {
644 DBGC ( peerblk,
"PEERBLK %p %d.%d could not create retrieval " 645 "request: %s\n", peerblk, peerblk->
segment,
719 if ( ( start < peerblk->
start ) && (
len > 0 ) ) {
729 DBGC ( peerblk,
"PEERBLK %p %d.%d could not buffer " 730 "data: %s\n", peerblk, peerblk->
segment,
737 if ( (
end > peerblk->
end ) && (
len > 0 ) ) {
745 cut = ( peerblk->
end - peerblk->
start );
750 DBGC ( peerblk,
"PEERBLK %p %d.%d could not buffer " 751 "data: %s\n", peerblk, peerblk->
segment,
769 if ( ( start < peerblk->
end ) && (
end >= peerblk->
end ) &&
799 if (
len <
sizeof ( *
msg ) ) {
800 DBGC ( peerblk,
"PEERBLK %p %d.%d message too short for header " 801 "(%zd bytes)\n", peerblk, peerblk->
segment,
808 DBGC ( peerblk,
"PEERBLK %p %d.%d unexpected message type " 816 switch (
msg->msg.algorithm ) {
821 keylen = ( 128 / 8 );
824 keylen = ( 192 / 8 );
827 keylen = ( 256 / 8 );
830 DBGC ( peerblk,
"PEERBLK %p %d.%d unrecognised algorithm " 835 DBGC2 ( peerblk,
"PEERBLK %p %d.%d using %s with %zd-bit key\n",
837 ( cipher ? cipher->
name :
"plaintext" ), ( 8 * keylen ) );
841 DBGC ( peerblk,
"PEERBLK %p %d.%d %zd-byte secret too short " 842 "for %zd-bit key\n", peerblk, peerblk->
segment,
862 DBGC ( peerblk,
"PEERBLK %p %d.%d could not set key: %s\n",
888 DBGC ( peerblk,
"PEERBLK %p %d.%d message too short for " 889 "zero-length data (%zd bytes)\n", peerblk,
896 DBGC ( peerblk,
"PEERBLK %p %d.%d incorrect digest size %d\n",
898 ntohl (
msg->msg.segment.segment.digestsize ) );
904 DBGC ( peerblk,
"PEERBLK %p %d.%d segment ID mismatch\n",
911 DBGC ( peerblk,
"PEERBLK %p %d.%d block ID mismatch (got %d)\n",
920 DBGC ( peerblk,
"PEERBLK %p %d.%d block not found\n",
927 DBGC ( peerblk,
"PEERBLK %p %d.%d underlength block (%zd " 959 + *buf_len - peerblk->
start );
983 size_t buf_len,
size_t *vrf_len ) {
991 DBGC ( peerblk,
"PEERBLK %p %d.%d message too short for " 992 "zero-length uselessness (%zd bytes)\n", peerblk,
1020 if (
len <
sizeof ( *
msg ) ) {
1021 DBGC ( peerblk,
"PEERBLK %p %d.%d message too short for " 1022 "initialisation vector (%zd bytes)\n", peerblk,
1029 DBGC ( peerblk,
"PEERBLK %p %d.%d incorrect IV size %d\n",
1031 ntohl (
msg->msg.iv.iv.blksize ) );
1057 for ( ;
len ; decrypt++,
data += frag_len,
len -= frag_len ) {
1060 frag_len = decrypt->
len;
1061 if ( frag_len >
len )
1068 data, frag_len ) ) != 0 )
1084 const void *
data,
size_t len ) {
1090 for ( ;
len ; decrypt++,
data += frag_len,
len -= frag_len ) {
1093 frag_len = decrypt->
len;
1094 if ( frag_len >
len )
1101 data, frag_len ) ) != 0 )
1105 decrypt->
offset += frag_len;
1106 decrypt->
len -= frag_len;
1132 DBGC ( peerblk,
"PEERBLK %p %d.%d has no underlying data " 1133 "transfer buffer\n", peerblk, peerblk->
segment,
1136 goto err_xfer_buffer;
1144 digest_len = cipher_len;
1153 goto err_alloc_data;
1158 DBGC ( peerblk,
"PEERBLK %p %d.%d could not read ciphertext: " 1172 DBGC ( peerblk,
"PEERBLK %p %d.%d could not write plaintext: " 1244 DBGC ( peerblk,
"PEERBLK %p %d.%d unaligned data length %zd\n",
1288 if ( ( peerblk->
peer ==
NULL ) && (
timer->timeout != 0 ) ) {
1291 DBGC ( peerblk,
"PEERBLK %p %d.%d discovery timed out after " 1292 "%ld ticks\n", peerblk, peerblk->
segment,
1297 if ( ( peerblk->
peer !=
NULL ) && (
timer->timeout != 0 ) ) {
1300 DBGC ( peerblk,
"PEERBLK %p %d.%d timed out after %ld ticks\n",
1459 peerblk->
digestctx = ( ( (
void * ) peerblk ) +
sizeof ( *peerblk ) );
1471 DBGC2 ( peerblk,
"PEERBLK %p %d.%d id %02x%02x%02x%02x%02x..." 1472 "%02x%02x%02x [%08zx,%08zx)", peerblk, peerblk->
segment,
1473 peerblk->
block, peerblk->
id[0], peerblk->
id[1], peerblk->
id[2],
1479 DBGC2 ( peerblk,
" covers [%08zx,%08zx)",
1482 DBGC2 ( peerblk,
"\n" );
1487 goto err_open_discovery;
static struct process_descriptor peerblk_queue_desc
PeerDist block download queue process descriptor.
#define iob_pull(iobuf, len)
struct list_head peers
List of discovered peers.
An object interface operation.
uint32_t start
Starting bus:dev.fn address.
size_t blocksize
Block size.
static struct uri * peerblk_retrieval_uri(const char *location)
Construct PeerDist retrieval protocol URI.
uint16_t segment
Code segment.
struct arbelprm_rc_send_wqe rc
pseudo_bit_t hash[0x00010]
static void digest_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
void intf_close(struct interface *intf, int rc)
Close an object interface.
void intf_restart(struct interface *intf, int rc)
Shut down and restart an object interface.
static int peerblk_parse_useless(struct peerdist_block *peerblk, size_t buf_len, size_t *vrf_len)
Parse retrieval protocol message useless details.
PeerDist discovery client operations.
#define TICKS_PER_SEC
Number of ticks per second.
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
struct list_head list
List of queued downloads.
A content information segment.
struct xfer_buffer buffer
Data buffer.
static void uri_put(struct uri *uri)
Decrement URI reference count.
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
#define PEERBLK_RAW_OPEN_TIMEOUT
PeerDist raw block download attempt initial progress timeout.
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Data after the trimmed content.
#define PEERBLK_MAX_ATTEMPT_CYCLES
PeerDist maximum number of full download attempt cycles.
static size_t peerblk_offset(struct peerdist_block *peerblk, size_t pos)
Calculate offset within overall download.
Peer Content Caching and Retrieval: Retrieval Protocol [MS-PCCRR].
static struct uri * uri_get(struct uri *uri)
Increment URI reference count.
static int peerblk_retrieval_rx(struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive PeerDist retrieval protocol data.
#define PEERBLK_RETRIEVAL_RX_TIMEOUT
PeerDist retrieval protocol block download attempt ongoing progress timeout.
HTTP request range descriptor.
#define XFER_FL_ABS_OFFSET
Offset is absolute.
#define ref_init(refcnt, free)
Initialise a reference counter.
size_t digest_remaining
Remaining digest length (excluding AES padding bytes)
struct golan_inbox_hdr hdr
Message header.
#define PEERDIST_MSG_BLK_TYPE
Retrieval protocol block fetch response type.
#define PEERBLK_RETRIEVAL_OPEN_TIMEOUT
PeerDist retrieval protocol block download attempt initial progress timeout.
#define PEERDIST_MAGIC_PATH
Magic retrieval URI path.
uint16_t mid
Middle 16 bits of address.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
static void digest_final(struct digest_algorithm *digest, void *ctx, void *out)
size_t start
Start offset.
#define list_for_each_entry_continue(pos, head, member)
Iterate over entries in a list, starting after current position.
struct interface retrieval
Retrieval protocol interface.
A PeerDist discovery segment.
void * digestctx
Digest context (statically allocated at instantiation time)
A PeerDist retrieval protocol decryption buffer descriptor.
size_t offset
Offset of first byte in trimmed range within overall download.
static void peerblk_step(struct peerdist_block_queue *queue)
PeerDist block download queue process.
int32_t before
Initial microcode version.
#define ENOENT
No such file or directory.
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
static void peerdisc_init(struct peerdisc_client *peerdisc, struct peerdisc_client_operations *op)
Initialise PeerDist discovery.
static int peerblk_deliver(struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta, size_t pos)
Deliver download attempt data block.
int xfer_check_order(struct xfer_metadata *meta, size_t *pos, size_t len)
Check that data is delivered strictly in order.
static void peerblk_decrypt(struct peerdist_block *peerblk)
Decrypt one chunk of PeerDist retrieval protocol data.
#define PROC_INIT(_process, _desc)
Initialise a static process.
uint32_t data_len
Microcode data size (or 0 to indicate 2000 bytes)
int peerblk_open(struct interface *xfer, struct uri *uri, struct peerdist_info_block *block)
Open PeerDist block download.
static struct process_descriptor peerblk_process_desc
PeerDist block download decryption process descriptor.
unsigned int cycles
Number of full attempt cycles completed.
static void profile_custom(struct profiler *profiler, unsigned long sample)
Record profiling sample in custom units.
#define PEERBLK_STALL_RATE
#define PROC_DESC_ONCE(object_type, process, _step)
Define a process descriptor for a process that runs only once.
struct peerdisc_client discovery
Discovery client.
#define offsetof(type, field)
Get offset of a field within a structure.
A data structure for storing profiling information.
void xferbuf_free(struct xfer_buffer *xferbuf)
Free data transfer buffer.
struct process process
Decryption process.
Uniform Resource Identifiers.
int xferbuf_write(struct xfer_buffer *xferbuf, size_t offset, const void *data, size_t len)
Write to data transfer buffer.
void process_del(struct process *process)
Remove process from process list.
struct process process
Download opening process.
static unsigned long peerblk_timestamp(void)
Get profiling timestamp.
struct cipher_algorithm * cipher
Cipher algorithm.
#define ENOTSUP
Operation not supported.
static void peerblk_reset(struct peerdist_block *peerblk, int rc)
Reset PeerDist block download attempt.
static void peerblk_dequeue(struct peerdist_block *peerblk)
Remove block from download queue.
size_t end
End of trimmed content (relative to incoming data stream)
Data before the trimmed content.
Data transfer interfaces.
struct digest_algorithm * digest
Digest algorithm.
void peerdisc_stat(struct interface *intf, struct peerdisc_peer *peer, struct list_head *peers)
Report peer discovery statistics.
Data within the trimmed content.
uint32_t start
Starting offset.
#define list_empty(list)
Test whether a list is empty.
#define list_first_entry(list, type, member)
Get the container of the first entry in a list.
A content information block.
struct uri * uri
Original URI.
int rc
Most recent attempt failure.
#define list_del(list)
Delete an entry from a list.
#define ENOMEM
Not enough space.
struct peerdist_range range
Content range of this block.
#define iob_disown(iobuf)
Disown an I/O buffer.
void(* discovered)(struct peerdisc_client *peerdisc)
New peers have been discovered.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static int peerblk_decrypt_write(struct peerdist_block *peerblk, const void *data, size_t len)
Write to decryption buffers and update offsets and lengths.
#define PEERBLK_ABORT_RATE
#define PEERBLK_DECRYPT_CHUNKSIZE
PeerDist decryption chunksize.
A PeerDist block download.
Hyper Text Transport Protocol.
#define PEERDIST_MSG_GETBLKS_TYPE
Retrieval protocol block fetch request type.
#define be32_to_cpu(value)
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define container_of(ptr, type, field)
Get containing structure.
#define PEERBLK_RAW_RX_TIMEOUT
PeerDist raw block download attempt ongoing progress timeout.
A PeerDist discovery client.
int peerdisc_open(struct peerdisc_client *peerdisc, const void *id, size_t len)
Open PeerDist discovery client.
struct peerdist_block_queue * queue
Block download queue.
#define __unused
Declare a variable or data structure as unused.
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Peer Content Caching and Retrieval (PeerDist) protocol block downloads.
static void peerblk_expired(struct retry_timer *timer, int over __unused)
Handle PeerDist retry timer expiry.
unsigned int segment
Segment index.
struct interface raw
Raw data interface.
static void xferbuf_malloc_init(struct xfer_buffer *xferbuf)
Initialise malloc()-based data transfer buffer.
size_t offset
Offset within data transfer buffer.
unsigned int block
Block index.
uint8_t id[PEERDIST_DIGEST_MAX_SIZE]
Segment identifier.
struct peerdisc_peer * peer
Current position in discovered peer list.
struct interface xfer
Data transfer interface.
uint8_t hash[PEERDIST_DIGEST_MAX_SIZE]
Block hash.
#define EPROTO
Protocol error.
static struct peerdist_block_queue peerblk_raw_queue
Raw block download queue.
HTTP request content descriptor.
static int peerblk_raw_open(struct peerdist_block *peerblk)
Open PeerDist raw block download attempt.
void process_add(struct process *process)
Add process to process list.
static __always_inline void struct pci_range * range
static void digest_init(struct digest_algorithm *digest, void *ctx)
static struct peerdisc_client_operations peerblk_discovery_operations
PeerDist block download discovery operations.
static struct interface_operation peerblk_retrieval_operations[]
PeerDist block download retrieval protocol interface operations.
An object interface descriptor.
#define iob_unput(iobuf, len)
struct http_method http_get
HTTP GET method.
#define PEERDIST_MSG_GETBLKS_VERSION
Retrieval protocol block fetch request version.
#define ERANGE
Result too large.
char * strerror(int errno)
Retrieve string representation of error number.
void * cipherctx
Cipher context (dynamically allocated as needed)
PeerDist block download queue.
static void(* free)(struct refcnt *refcnt))
struct xfer_buffer * xferbuf
Data transfer buffer.
void * zalloc(size_t size)
Allocate cleared memory.
static void peerblk_free(struct refcnt *refcnt)
Free PeerDist block download.
char location[0]
Peer location.
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
static void cipher_setiv(struct cipher_algorithm *cipher, void *ctx, const void *iv, size_t ivlen)
static void peerblk_enqueue(struct peerdist_block *peerblk, struct peerdist_block_queue *queue)
Add block to download queue.
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
size_t strlen(const char *src)
Get length of string.
struct xfer_buffer * xfer_buffer(struct interface *intf)
Get underlying data transfer buffer.
size_t digestsize
Digest size.
size_t start
Start of trimmed content (relative to incoming data stream)
static int peerblk_raw_rx(struct peerdist_block *peerblk, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive PeerDist raw data.
unsigned long started
Time at which block download was started.
static int peerblk_parse_header(struct peerdist_block *peerblk)
Parse retrieval protocol message header.
static void process_init_stopped(struct process *process, struct process_descriptor *desc, struct refcnt *refcnt)
Initialise process without adding to process list.
size_t ctxsize
Context size.
#define cipher_decrypt(cipher, ctx, src, dst, len)
struct list_head queued
List of queued block downloads.
static struct interface_descriptor peerblk_retrieval_desc
PeerDist block download retrieval protocol interface descriptor.
static int peerblk_decrypt_read(struct peerdist_block *peerblk, void *data, size_t len)
Read from decryption buffers.
void * malloc(size_t size)
Allocate memory.
struct peerdisc_segment * segment
Discovery segment.
int xferbuf_read(struct xfer_buffer *xferbuf, size_t offset, void *data, size_t len)
Read from data transfer buffer.
struct cipher_algorithm aes_cbc_algorithm
unsigned long attempted
Time at which most recent attempt was started.
const void * data
Content data (if any)
struct refcnt refcnt
Reference count.
#define PEERBLK_RAW_MAX
PeerDist maximum number of concurrent raw block downloads.
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
#define PEERBLK_ANNUL_RATE
struct retry_timer timer
Retry timer.
size_t len
Content length.
#define INIT_LIST_HEAD(list)
Initialise a list head.
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
static void peerblk_close(struct peerdist_block *peerblk, int rc)
Close PeerDist block download.
void stop_timer(struct retry_timer *timer)
Stop timer.
static struct interface_operation peerblk_raw_operations[]
PeerDist block download raw data interface operations.
static void peerblk_done(struct peerdist_block *peerblk, int rc)
Finish PeerDist block download attempt.
#define peerblk_msg_blk_t(digestsize, len, vrf_len, blksize)
Retrieval protocol block fetch response (including transport header)
size_t ctxsize
Context size.
uint8_t block[3][8]
DES-encrypted blocks.
size_t digestsize
Digest size.
static int peerblk_retrieval_open(struct peerdist_block *peerblk, const char *location)
Open PeerDist retrieval protocol block download attempt.
int http_open(struct interface *xfer, struct http_method *method, struct uri *uri, struct http_request_range *range, struct http_request_content *content)
Open HTTP transaction.
int32_t after
Final microcode version.
struct peerdist_block_decrypt decrypt[PEERBLK_NUM_BUFFERS]
Decryption data buffer descriptors.
void * data
Start of data.
#define PROC_DESC(object_type, process, _step)
Define a process descriptor.
#define EIO
Input/output error.
#define PEERBLK_CORRUPT_RATE
static int peerblk_parse_block(struct peerdist_block *peerblk, size_t *buf_len)
Parse retrieval protocol message segment and block details.
uint8_t secret[PEERDIST_DIGEST_MAX_SIZE]
Segment secret.
A message digest algorithm.
uint32_t end
Ending offset.
uint8_t data[48]
Additional event data.
struct peerdist_range trim
Trimmed range of this block.
static struct interface_descriptor peerblk_raw_desc
PeerDist block download raw data interface descriptor.
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
static struct profiler peerblk_download_profiler __profiler
PeerDist block download profiler.
A Uniform Resource Identifier.
uint32_t blksize
Cipher block size.
static struct interface_descriptor peerblk_xfer_desc
PeerDist block download data transfer interface descriptor.
static void peerblk_discovered(struct peerdisc_client *discovery)
Handle PeerDist peer discovery.
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
struct mschapv2_challenge peer
Peer challenge.
static struct interface_operation peerblk_xfer_operations[]
PeerDist block download data transfer interface operations.
typeof(acpi_finder=acpi_find)
ACPI table finder.
uint32_t digestsize
Digest size (i.e.
unsigned long currticks(void)
Get current system time in ticks.
struct list_head list
List of peers.
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
#define LIST_HEAD_INIT(list)
Initialise a static list head.
const char * name
Algorithm name.
#define peerdist_msg_getblks_t(digestsize, count, vrf_len)
Retrieval protocol block fetch request.
static int peerblk_parse_iv(struct peerdist_block *peerblk, size_t buf_len, size_t vrf_len)
Parse retrieval protocol message initialisation vector details.
size_t cipher_remaining
Remaining decryption length.
#define list_entry(list, type, member)
Get the container of a list entry.
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
static void peerblk_raw_close(struct peerdist_block *peerblk, int rc)
Close PeerDist raw block download attempt.
#define NULL
NULL pointer (VOID *)
#define ETIMEDOUT
Connection timed out.
static void peerblk_retrieval_close(struct peerdist_block *peerblk, int rc)
Close PeerDist retrieval protocol block download attempt.
struct http_method http_post
HTTP POST method.
unsigned long timeout
Timeout value (in ticks)
struct bofm_section_header done
size_t pos
Current position (relative to incoming data stream)
size_t len
Length to use from data transfer buffer.
static int cipher_setkey(struct cipher_algorithm *cipher, void *ctx, const void *key, size_t keylen)
#define ref_put(refcnt)
Drop reference to object.
struct uri * parse_uri(const char *uri_string)
Parse URI.
void * memset(void *dest, int character, size_t len) __nonnull
void peerdisc_close(struct peerdisc_client *peerdisc)
Close PeerDist discovery client.
unsigned int peerdisc_timeout_secs
Recommended discovery timeout (in seconds)
A PeerDist discovery peer.