iPXE
pccrc.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <errno.h>
27 #include <assert.h>
28 #include <ipxe/uaccess.h>
29 #include <ipxe/sha256.h>
30 #include <ipxe/sha512.h>
31 #include <ipxe/hmac.h>
32 #include <ipxe/base16.h>
33 #include <ipxe/pccrc.h>
34 
35 /** @file
36  *
37  * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC]
38  *
39  */
40 
41 /******************************************************************************
42  *
43  * Utility functions
44  *
45  ******************************************************************************
46  */
47 
48 /**
49  * Transcribe hash value (for debugging)
50  *
51  * @v info Content information
52  * @v hash Hash value
53  * @ret string Hash value string
54  */
55 static inline const char *
56 peerdist_info_hash_ntoa ( const struct peerdist_info *info, const void *hash ) {
57  static char buf[ ( 2 * PEERDIST_DIGEST_MAX_SIZE ) + 1 /* NUL */ ];
58  size_t digestsize = info->digestsize;
59 
60  /* Sanity check */
61  assert ( info != NULL );
62  assert ( digestsize != 0 );
63  assert ( base16_encoded_len ( digestsize ) < sizeof ( buf ) );
64 
65  /* Transcribe hash value */
66  base16_encode ( hash, digestsize, buf, sizeof ( buf ) );
67  return buf;
68 }
69 
70 /**
71  * Get raw data
72  *
73  * @v info Content information
74  * @v data Data buffer
75  * @v offset Starting offset
76  * @v len Length
77  * @ret rc Return status code
78  */
79 static int peerdist_info_get ( const struct peerdist_info *info, void *data,
80  size_t offset, size_t len ) {
81 
82  /* Sanity check */
83  if ( ( offset > info->raw.len ) ||
84  ( len > ( info->raw.len - offset ) ) ) {
85  DBGC ( info, "PCCRC %p data underrun at [%zx,%zx) of %zx\n",
86  info, offset, ( offset + len ), info->raw.len );
87  return -ERANGE;
88  }
89 
90  /* Copy data */
91  copy_from_user ( data, info->raw.data, offset, len );
92 
93  return 0;
94 }
95 
96 /**
97  * Populate segment hashes
98  *
99  * @v segment Content information segment to fill in
100  * @v hash Segment hash of data
101  * @v secret Segment secret
102  */
104  const void *hash, const void *secret ){
105  const struct peerdist_info *info = segment->info;
106  struct digest_algorithm *digest = info->digest;
107  uint8_t ctx[ hmac_ctxsize ( digest ) ];
108  size_t digestsize = info->digestsize;
109  static const uint16_t magic[] = PEERDIST_SEGMENT_ID_MAGIC;
110 
111  /* Sanity check */
112  assert ( digestsize <= sizeof ( segment->hash ) );
113  assert ( digestsize <= sizeof ( segment->secret ) );
114  assert ( digestsize <= sizeof ( segment->id ) );
115 
116  /* Get segment hash of data */
117  memcpy ( segment->hash, hash, digestsize );
118 
119  /* Get segment secret */
120  memcpy ( segment->secret, secret, digestsize );
121 
122  /* Calculate segment identifier */
123  hmac_init ( digest, ctx, segment->secret, digestsize );
124  hmac_update ( digest, ctx, segment->hash, digestsize );
125  hmac_update ( digest, ctx, magic, sizeof ( magic ) );
126  hmac_final ( digest, ctx, segment->id );
127 }
128 
129 /******************************************************************************
130  *
131  * Content Information version 1
132  *
133  ******************************************************************************
134  */
135 
136 /**
137  * Get number of blocks within a block description
138  *
139  * @v info Content information
140  * @v offset Block description offset
141  * @ret blocks Number of blocks, or negative error
142  */
143 static int peerdist_info_v1_blocks ( const struct peerdist_info *info,
144  size_t offset ) {
146  unsigned int blocks;
147  int rc;
148 
149  /* Get block description header */
150  if ( ( rc = peerdist_info_get ( info, &raw, offset,
151  sizeof ( raw ) ) ) != 0 )
152  return rc;
153 
154  /* Calculate number of blocks */
155  blocks = le32_to_cpu ( raw.blocks );
156 
157  return blocks;
158 }
159 
160 /**
161  * Locate block description
162  *
163  * @v info Content information
164  * @v index Segment index
165  * @ret offset Block description offset, or negative error
166  */
168  unsigned int index ) {
169  size_t digestsize = info->digestsize;
170  unsigned int i;
171  size_t offset;
172  int blocks;
173  int rc;
174 
175  /* Sanity check */
176  assert ( index < info->segments );
177 
178  /* Calculate offset of first block description */
179  offset = ( sizeof ( struct peerdist_info_v1 ) +
180  ( info->segments *
181  sizeof ( peerdist_info_v1_segment_t ( digestsize ) ) ) );
182 
183  /* Iterate over block descriptions until we find this segment */
184  for ( i = 0 ; i < index ; i++ ) {
185 
186  /* Get number of blocks */
188  if ( blocks < 0 ) {
189  rc = blocks;
190  DBGC ( info, "PCCRC %p segment %d could not get number "
191  "of blocks: %s\n", info, i, strerror ( rc ) );
192  return rc;
193  }
194 
195  /* Move to next block description */
197  blocks ) );
198  }
199 
200  return offset;
201 }
202 
203 /**
204  * Populate content information
205  *
206  * @v info Content information to fill in
207  * @ret rc Return status code
208  */
209 static int peerdist_info_v1 ( struct peerdist_info *info ) {
210  struct peerdist_info_v1 raw;
213  size_t first_skip;
214  size_t last_skip;
215  size_t last_read;
216  int rc;
217 
218  /* Get raw header */
219  if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
220  DBGC ( info, "PCCRC %p could not get V1 content information: "
221  "%s\n", info, strerror ( rc ) );
222  return rc;
223  }
224  assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V1 ) );
225 
226  /* Determine hash algorithm */
227  switch ( raw.hash ) {
229  info->digest = &sha256_algorithm;
230  break;
232  info->digest = &sha384_algorithm;
233  break;
235  info->digest = &sha512_algorithm;
236  break;
237  default:
238  DBGC ( info, "PCCRC %p unsupported hash algorithm %#08x\n",
239  info, le32_to_cpu ( raw.hash ) );
240  return -ENOTSUP;
241  }
242  info->digestsize = info->digest->digestsize;
243  assert ( info->digest != NULL );
244  DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
245  info, info->digest->name, ( info->digestsize * 8 ) );
246 
247  /* Calculate number of segments */
248  info->segments = le32_to_cpu ( raw.segments );
249 
250  /* Get first segment */
251  if ( ( rc = peerdist_info_segment ( info, &first, 0 ) ) != 0 )
252  return rc;
253 
254  /* Calculate range start offset */
255  info->range.start = first.range.start;
256 
257  /* Calculate trimmed range start offset */
258  first_skip = le32_to_cpu ( raw.first );
259  info->trim.start = ( first.range.start + first_skip );
260 
261  /* Get last segment */
262  if ( ( rc = peerdist_info_segment ( info, &last,
263  ( info->segments - 1 ) ) ) != 0 )
264  return rc;
265 
266  /* Calculate range end offset */
267  info->range.end = last.range.end;
268 
269  /* Calculate trimmed range end offset */
270  if ( raw.last ) {
271  /* Explicit length to include from last segment is given */
272  last_read = le32_to_cpu ( raw.last );
273  last_skip = ( last.index ? 0 : first_skip );
274  info->trim.end = ( last.range.start + last_skip + last_read );
275  } else {
276  /* No explicit length given: range extends to end of segment */
277  info->trim.end = last.range.end;
278  }
279 
280  return 0;
281 }
282 
283 /**
284  * Populate content information segment
285  *
286  * @v segment Content information segment to fill in
287  * @ret rc Return status code
288  */
290  const struct peerdist_info *info = segment->info;
291  size_t digestsize = info->digestsize;
293  ssize_t raw_offset;
294  int blocks;
295  int rc;
296 
297  /* Sanity checks */
298  assert ( segment->index < info->segments );
299 
300  /* Get raw description */
301  raw_offset = ( sizeof ( struct peerdist_info_v1 ) +
302  ( segment->index * sizeof ( raw ) ) );
303  if ( ( rc = peerdist_info_get ( info, &raw, raw_offset,
304  sizeof ( raw ) ) ) != 0 ) {
305  DBGC ( info, "PCCRC %p segment %d could not get segment "
306  "description: %s\n", info, segment->index,
307  strerror ( rc ) );
308  return rc;
309  }
310 
311  /* Calculate start offset of this segment */
312  segment->range.start = le64_to_cpu ( raw.segment.offset );
313 
314  /* Calculate end offset of this segment */
315  segment->range.end = ( segment->range.start +
316  le32_to_cpu ( raw.segment.len ) );
317 
318  /* Calculate block size of this segment */
319  segment->blksize = le32_to_cpu ( raw.segment.blksize );
320 
321  /* Locate block description for this segment */
322  raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
323  if ( raw_offset < 0 ) {
324  rc = raw_offset;
325  return rc;
326  }
327 
328  /* Get number of blocks */
329  blocks = peerdist_info_v1_blocks ( info, raw_offset );
330  if ( blocks < 0 ) {
331  rc = blocks;
332  DBGC ( info, "PCCRC %p segment %d could not get number of "
333  "blocks: %s\n", info, segment->index, strerror ( rc ) );
334  return rc;
335  }
336  segment->blocks = blocks;
337 
338  /* Calculate segment hashes */
339  peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
340 
341  return 0;
342 }
343 
344 /**
345  * Populate content information block
346  *
347  * @v block Content information block to fill in
348  * @ret rc Return status code
349  */
351  const struct peerdist_info_segment *segment = block->segment;
352  const struct peerdist_info *info = segment->info;
353  size_t digestsize = info->digestsize;
355  ssize_t raw_offset;
356  int rc;
357 
358  /* Sanity checks */
359  assert ( block->index < segment->blocks );
360 
361  /* Calculate start offset of this block */
362  block->range.start = ( segment->range.start +
363  ( block->index * segment->blksize ) );
364 
365  /* Calculate end offset of this block */
366  block->range.end = ( block->range.start + segment->blksize );
367  if ( block->range.end > segment->range.end )
368  block->range.end = segment->range.end;
369 
370  /* Locate block description */
371  raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
372  if ( raw_offset < 0 ) {
373  rc = raw_offset;
374  return rc;
375  }
376 
377  /* Get block hash */
378  raw_offset += offsetof ( typeof ( raw ), hash[block->index] );
379  if ( ( rc = peerdist_info_get ( info, block->hash, raw_offset,
380  digestsize ) ) != 0 ) {
381  DBGC ( info, "PCCRC %p segment %d block %d could not get "
382  "hash: %s\n", info, segment->index, block->index,
383  strerror ( rc ) );
384  return rc;
385  }
386 
387  return 0;
388 }
389 
390 /** Content information version 1 operations */
393  .segment = peerdist_info_v1_segment,
394  .block = peerdist_info_v1_block,
395 };
396 
397 /******************************************************************************
398  *
399  * Content Information version 2
400  *
401  ******************************************************************************
402  */
403 
404 /** A segment cursor */
406  /** Raw data offset */
407  size_t offset;
408  /** Number of segments remaining within this chunk */
409  unsigned int remaining;
410  /** Accumulated segment length */
411  size_t len;
412 };
413 
414 /**
415  * Initialise segment cursor
416  *
417  * @v cursor Segment cursor
418  */
419 static inline void
421 
422  /* Initialise cursor */
423  cursor->offset = ( sizeof ( struct peerdist_info_v2 ) +
424  sizeof ( struct peerdist_info_v2_chunk ) );
425  cursor->remaining = 0;
426  cursor->len = 0;
427 }
428 
429 /**
430  * Update segment cursor to next segment description
431  *
432  * @v info Content information
433  * @v offset Current offset
434  * @v remaining Number of segments remaining within this chunk
435  * @ret rc Return status code
436  */
437 static int
439  struct peerdist_info_v2_cursor *cursor ) {
440  size_t digestsize = info->digestsize;
442  struct peerdist_info_v2_chunk chunk;
443  int rc;
444 
445  /* Get chunk description if applicable */
446  if ( ! cursor->remaining ) {
447 
448  /* Get chunk description */
449  if ( ( rc = peerdist_info_get ( info, &chunk,
450  ( cursor->offset -
451  sizeof ( chunk ) ),
452  sizeof ( chunk ) ) ) != 0 )
453  return rc;
454 
455  /* Update number of segments remaining */
456  cursor->remaining = ( be32_to_cpu ( chunk.len ) /
457  sizeof ( raw ) );
458  }
459 
460  /* Get segment description header */
461  if ( ( rc = peerdist_info_get ( info, &raw.segment, cursor->offset,
462  sizeof ( raw.segment ) ) ) != 0 )
463  return rc;
464 
465  /* Update cursor */
466  cursor->offset += sizeof ( raw );
467  cursor->remaining--;
468  if ( ! cursor->remaining )
469  cursor->offset += sizeof ( chunk );
470  cursor->len += be32_to_cpu ( raw.segment.len );
471 
472  return 0;
473 }
474 
475 /**
476  * Get number of segments and total length
477  *
478  * @v info Content information
479  * @v len Length to fill in
480  * @ret rc Number of segments, or negative error
481  */
482 static int peerdist_info_v2_segments ( const struct peerdist_info *info,
483  size_t *len ) {
484  struct peerdist_info_v2_cursor cursor;
485  unsigned int segments;
486  int rc;
487 
488  /* Iterate over all segments */
489  for ( peerdist_info_v2_cursor_init ( &cursor ), segments = 0 ;
490  cursor.offset < info->raw.len ; segments++ ) {
491 
492  /* Update segment cursor */
494  &cursor ) ) != 0 ) {
495  DBGC ( info, "PCCRC %p segment %d could not update "
496  "segment cursor: %s\n",
497  info, segments, strerror ( rc ) );
498  return rc;
499  }
500  }
501 
502  /* Record accumulated length */
503  *len = cursor.len;
504 
505  return segments;
506 }
507 
508 /**
509  * Populate content information
510  *
511  * @v info Content information to fill in
512  * @ret rc Return status code
513  */
514 static int peerdist_info_v2 ( struct peerdist_info *info ) {
515  struct peerdist_info_v2 raw;
516  size_t len = 0;
517  int segments;
518  int rc;
519 
520  /* Get raw header */
521  if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
522  DBGC ( info, "PCCRC %p could not get V2 content information: "
523  "%s\n", info, strerror ( rc ) );
524  return rc;
525  }
526  assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V2 ) );
527 
528  /* Determine hash algorithm */
529  switch ( raw.hash ) {
531  info->digest = &sha512_algorithm;
532  info->digestsize = ( 256 / 8 );
533  break;
534  default:
535  DBGC ( info, "PCCRC %p unsupported hash algorithm %#02x\n",
536  info, raw.hash );
537  return -ENOTSUP;
538  }
539  assert ( info->digest != NULL );
540  DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
541  info, info->digest->name, ( info->digestsize * 8 ) );
542 
543  /* Calculate number of segments and total length */
545  if ( segments < 0 ) {
546  rc = segments;
547  DBGC ( info, "PCCRC %p could not get segment count and length: "
548  "%s\n", info, strerror ( rc ) );
549  return rc;
550  }
551  info->segments = segments;
552 
553  /* Calculate range start offset */
554  info->range.start = be64_to_cpu ( raw.offset );
555 
556  /* Calculate trimmed range start offset */
557  info->trim.start = ( info->range.start + be32_to_cpu ( raw.first ) );
558 
559  /* Calculate range end offset */
560  info->range.end = ( info->range.start + len );
561 
562  /* Calculate trimmed range end offset */
563  info->trim.end = ( raw.len ? be64_to_cpu ( raw.len ) :
564  info->range.end );
565 
566  return 0;
567 }
568 
569 /**
570  * Populate content information segment
571  *
572  * @v segment Content information segment to fill in
573  * @ret rc Return status code
574  */
576  const struct peerdist_info *info = segment->info;
577  size_t digestsize = info->digestsize;
579  struct peerdist_info_v2_cursor cursor;
580  unsigned int index;
581  size_t len;
582  int rc;
583 
584  /* Sanity checks */
585  assert ( segment->index < info->segments );
586 
587  /* Iterate over all segments before the target segment */
588  for ( peerdist_info_v2_cursor_init ( &cursor ), index = 0 ;
589  index < segment->index ; index++ ) {
590 
591  /* Update segment cursor */
593  &cursor ) ) != 0 ) {
594  DBGC ( info, "PCCRC %p segment %d could not update "
595  "segment cursor: %s\n",
596  info, index, strerror ( rc ) );
597  return rc;
598  }
599  }
600 
601  /* Get raw description */
602  if ( ( rc = peerdist_info_get ( info, &raw, cursor.offset,
603  sizeof ( raw ) ) ) != 0 ) {
604  DBGC ( info, "PCCRC %p segment %d could not get segment "
605  "description: %s\n",
606  info, segment->index, strerror ( rc ) );
607  return rc;
608  }
609 
610  /* Calculate start offset of this segment */
611  segment->range.start = ( info->range.start + cursor.len );
612 
613  /* Calculate end offset of this segment */
614  len = be32_to_cpu ( raw.segment.len );
615  segment->range.end = ( segment->range.start + len );
616 
617  /* Model as a segment containing a single block */
618  segment->blocks = 1;
619  segment->blksize = len;
620 
621  /* Calculate segment hashes */
622  peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
623 
624  return 0;
625 }
626 
627 /**
628  * Populate content information block
629  *
630  * @v block Content information block to fill in
631  * @ret rc Return status code
632  */
634  const struct peerdist_info_segment *segment = block->segment;
635  const struct peerdist_info *info = segment->info;
636  size_t digestsize = info->digestsize;
637 
638  /* Sanity checks */
639  assert ( block->index < segment->blocks );
640 
641  /* Model as a block covering the whole segment */
642  memcpy ( &block->range, &segment->range, sizeof ( block->range ) );
643  memcpy ( block->hash, segment->hash, digestsize );
644 
645  return 0;
646 }
647 
648 /** Content information version 2 operations */
651  .segment = peerdist_info_v2_segment,
652  .info = peerdist_info_v2,
653 };
654 
655 /******************************************************************************
656  *
657  * Content Information
658  *
659  ******************************************************************************
660  */
661 
662 /**
663  * Populate content information
664  *
665  * @v data Raw data
666  * @v len Length of raw data
667  * @v info Content information to fill in
668  * @ret rc Return status code
669  */
670 int peerdist_info ( userptr_t data, size_t len, struct peerdist_info *info ) {
672  int rc;
673 
674  /* Initialise structure */
675  memset ( info, 0, sizeof ( *info ) );
676  info->raw.data = data;
677  info->raw.len = len;
678 
679  /* Get version */
680  if ( ( rc = peerdist_info_get ( info, &version, 0,
681  sizeof ( version ) ) ) != 0 ) {
682  DBGC ( info, "PCCRC %p could not get version: %s\n",
683  info, strerror ( rc ) );
684  return rc;
685  }
686  DBGC2 ( info, "PCCRC %p version %d.%d\n",
687  info, version.major, version.minor );
688 
689  /* Determine version */
690  switch ( version.raw ) {
691  case cpu_to_le16 ( PEERDIST_INFO_V1 ) :
693  break;
694  case cpu_to_le16 ( PEERDIST_INFO_V2 ) :
696  break;
697  default:
698  DBGC ( info, "PCCRC %p unsupported version %d.%d\n",
699  info, version.major, version.minor );
700  return -ENOTSUP;
701  }
702  assert ( info->op != NULL );
703  assert ( info->op->info != NULL );
704 
705  /* Populate content information */
706  if ( ( rc = info->op->info ( info ) ) != 0 )
707  return rc;
708 
709  DBGC2 ( info, "PCCRC %p range [%08zx,%08zx) covers [%08zx,%08zx) with "
710  "%d segments\n", info, info->range.start, info->range.end,
711  info->trim.start, info->trim.end, info->segments );
712  return 0;
713 }
714 
715 /**
716  * Populate content information segment
717  *
718  * @v info Content information
719  * @v segment Content information segment to fill in
720  * @v index Segment index
721  * @ret rc Return status code
722  */
725  unsigned int index ) {
726  int rc;
727 
728  /* Sanity checks */
729  assert ( info != NULL );
730  assert ( info->op != NULL );
731  assert ( info->op->segment != NULL );
732  if ( index >= info->segments ) {
733  DBGC ( info, "PCCRC %p segment %d of [0,%d) out of range\n",
734  info, index, info->segments );
735  return -ERANGE;
736  }
737 
738  /* Initialise structure */
739  memset ( segment, 0, sizeof ( *segment ) );
740  segment->info = info;
741  segment->index = index;
742 
743  /* Populate content information segment */
744  if ( ( rc = info->op->segment ( segment ) ) != 0 )
745  return rc;
746 
747  DBGC2 ( info, "PCCRC %p segment %d range [%08zx,%08zx) with %d "
748  "blocks\n", info, segment->index, segment->range.start,
749  segment->range.end, segment->blocks );
750  DBGC2 ( info, "PCCRC %p segment %d digest %s\n", info, segment->index,
751  peerdist_info_hash_ntoa ( info, segment->hash ) );
752  DBGC2 ( info, "PCCRC %p segment %d secret %s\n", info, segment->index,
753  peerdist_info_hash_ntoa ( info, segment->secret ) );
754  DBGC2 ( info, "PCCRC %p segment %d identf %s\n", info, segment->index,
756  return 0;
757 }
758 
759 /**
760  * Populate content information block
761  *
762  * @v segment Content information segment
763  * @v block Content information block to fill in
764  * @v index Block index
765  * @ret rc Return status code
766  */
768  struct peerdist_info_block *block,
769  unsigned int index ) {
770  const struct peerdist_info *info = segment->info;
771  size_t start;
772  size_t end;
773  int rc;
774 
775  /* Sanity checks */
776  assert ( segment != NULL );
777  assert ( info != NULL );
778  assert ( info->op != NULL );
779  assert ( info->op->block != NULL );
780  if ( index >= segment->blocks ) {
781  DBGC ( info, "PCCRC %p segment %d block %d of [0,%d) out of "
782  "range\n", info, segment->index, index, segment->blocks);
783  return -ERANGE;
784  }
785 
786  /* Initialise structure */
787  memset ( block, 0, sizeof ( *block ) );
788  block->segment = segment;
789  block->index = index;
790 
791  /* Populate content information block */
792  if ( ( rc = info->op->block ( block ) ) != 0 )
793  return rc;
794 
795  /* Calculate trimmed range */
796  start = block->range.start;
797  if ( start < info->trim.start )
798  start = info->trim.start;
799  end = block->range.end;
800  if ( end > info->trim.end )
801  end = info->trim.end;
802  if ( end < start )
803  end = start;
804  block->trim.start = start;
805  block->trim.end = end;
806 
807  DBGC2 ( info, "PCCRC %p segment %d block %d hash %s\n",
808  info, segment->index, block->index,
809  peerdist_info_hash_ntoa ( info, block->hash ) );
810  DBGC2 ( info, "PCCRC %p segment %d block %d range [%08zx,%08zx) covers "
811  "[%08zx,%08zx)\n", info, segment->index, block->index,
812  block->range.start, block->range.end, block->trim.start,
813  block->trim.end );
814  return 0;
815 }
void hmac_init(struct digest_algorithm *digest, void *ctx, const void *key, size_t key_len)
Initialise HMAC.
Definition: hmac.c:57
uint16_t segment
Code segment.
Definition: librm.h:252
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
A segment cursor.
Definition: pccrc.c:405
unsigned short uint16_t
Definition: stdint.h:11
static const char * peerdist_info_hash_ntoa(const struct peerdist_info *info, const void *hash)
Transcribe hash value (for debugging)
Definition: pccrc.c:56
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define PEERDIST_INFO_V1_HASH_SHA512
SHA-512 hash algorithm.
Definition: pccrc.h:103
u32 info
Definition: ar9003_mac.h:67
A content information segment.
Definition: pccrc.h:347
static void peerdist_info_v2_cursor_init(struct peerdist_info_v2_cursor *cursor)
Initialise segment cursor.
Definition: pccrc.c:420
#define le32_to_cpu(value)
Definition: byteswap.h:113
Content Information version 1 data structure header.
Definition: pccrc.h:62
uint32_t blocks
Number of blocks within the block description.
Definition: pccrc.h:17
Error codes.
struct digest_algorithm sha512_algorithm
SHA-512 algorithm.
Definition: sha512.c:284
size_t start
Start offset.
Definition: pccrc.h:311
uint16_t block
Definition: tftp.h:12
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
#define DBGC(...)
Definition: compiler.h:505
uint32_t magic
Magic signature.
Definition: fdt.h:12
struct digest_algorithm sha384_algorithm
SHA-384 algorithm.
Definition: sha384.c:63
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:24
struct golan_eq_context ctx
Definition: CIB_PRM.h:28
struct md4_digest digest
Digest of data already processed.
Definition: md4.h:12
Access to external ("user") memory.
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
uint32_t start
Starting offset.
Definition: netvsc.h:12
static size_t base16_encoded_len(size_t raw_len)
Calculate length of base16-encoded data.
Definition: base16.h:21
A content information block.
Definition: pccrc.h:394
Content Information version 1 block description header.
Definition: pccrc.h:157
static struct peerdist_info_operations peerdist_info_v1_operations
Content information version 1 operations.
Definition: pccrc.c:391
void * memcpy(void *dest, const void *src, size_t len) __nonnull
unsigned int remaining
Number of segments remaining within this chunk.
Definition: pccrc.c:409
u32 version
Driver version.
Definition: ath9k_hw.c:1983
#define PEERDIST_SEGMENT_ID_MAGIC
Magic string constant used to calculate segment identifier.
Definition: pccrc.h:391
static int peerdist_info_v1(struct peerdist_info *info)
Populate content information.
Definition: pccrc.c:209
Assertions.
#define PEERDIST_INFO_V2
Content Information version 2.
Definition: pccrc.h:49
#define be32_to_cpu(value)
Definition: byteswap.h:116
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Keyed-Hashing for Message Authentication.
struct peerdist_range trim
Trimmed content range.
Definition: pccrc.h:341
int peerdist_info_segment(const struct peerdist_info *info, struct peerdist_info_segment *segment, unsigned int index)
Populate content information segment.
Definition: pccrc.c:723
uint32_t len
Chunk data length.
Definition: pccrc.h:235
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
static int peerdist_info_v2_segments(const struct peerdist_info *info, size_t *len)
Get number of segments and total length.
Definition: pccrc.c:482
static int peerdist_info_v2(struct peerdist_info *info)
Populate content information.
Definition: pccrc.c:514
static int peerdist_info_v1_segment(struct peerdist_info_segment *segment)
Populate content information segment.
Definition: pccrc.c:289
static ssize_t peerdist_info_v1_block_offset(const struct peerdist_info *info, unsigned int index)
Locate block description.
Definition: pccrc.c:167
int peerdist_info(userptr_t data, size_t len, struct peerdist_info *info)
Populate content information.
Definition: pccrc.c:670
Content information.
Definition: pccrc.h:317
#define cpu_to_le32(value)
Definition: byteswap.h:107
size_t offset
Raw data offset.
Definition: pccrc.c:407
Peer Content Caching and Retrieval: Content Identification [MS-PCCRC].
static void hmac_update(struct digest_algorithm *digest, void *ctx, const void *data, size_t len)
Update HMAC.
Definition: hmac.h:42
pseudo_bit_t hash[0x00010]
Hash algorithm.
Definition: arbel.h:13
#define ERANGE
Result too large.
Definition: errno.h:639
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
#define be64_to_cpu(value)
Definition: byteswap.h:117
#define peerdist_info_v2_segment_t(digestsize)
Content Information version 2 segment description.
Definition: pccrc.h:280
static void peerdist_info_segment_hash(struct peerdist_info_segment *segment, const void *hash, const void *secret)
Populate segment hashes.
Definition: pccrc.c:103
static int peerdist_info_get(const struct peerdist_info *info, void *data, size_t offset, size_t len)
Get raw data.
Definition: pccrc.c:79
#define PEERDIST_INFO_V1_HASH_SHA384
SHA-384 hash algorithm.
Definition: pccrc.h:100
int peerdist_info_block(const struct peerdist_info_segment *segment, struct peerdist_info_block *block, unsigned int index)
Populate content information block.
Definition: pccrc.c:767
unsigned char uint8_t
Definition: stdint.h:10
static int peerdist_info_v1_block(struct peerdist_info_block *block)
Populate content information block.
Definition: pccrc.c:350
#define PEERDIST_INFO_V1_HASH_SHA256
SHA-256 hash algorithm.
Definition: pccrc.h:97
static int peerdist_info_v2_block(struct peerdist_info_block *block)
Populate content information block.
Definition: pccrc.c:633
uint32_t last
Length to read in last segment, or zero.
Definition: pccrc.h:30
#define PEERDIST_DIGEST_MAX_SIZE
Maximum digest size for any supported algorithm.
Definition: pccrc.h:298
static int peerdist_info_v1_blocks(const struct peerdist_info *info, size_t offset)
Get number of blocks within a block description.
Definition: pccrc.c:143
size_t len
Accumulated segment length.
Definition: pccrc.c:411
#define peerdist_info_v1_segment_t(digestsize)
Content Information version 1 segment description.
Definition: pccrc.h:146
struct digest_algorithm sha256_algorithm
SHA-256 algorithm.
Definition: sha256.c:264
uint32_t len
Length.
Definition: ena.h:14
#define DBGC2(...)
Definition: compiler.h:522
uint32_t segments
Number of segments within the content information.
Definition: pccrc.h:32
static struct peerdist_info_operations peerdist_info_v2_operations
Content information version 2 operations.
Definition: pccrc.c:649
static int peerdist_info_v2_cursor_next(const struct peerdist_info *info, struct peerdist_info_v2_cursor *cursor)
Update segment cursor to next segment description.
Definition: pccrc.c:438
#define PEERDIST_INFO_V2_HASH_SHA512_TRUNC
SHA-512 hash algorithm with output truncated to first 256 bits.
Definition: pccrc.h:225
SHA-512 algorithm.
#define cpu_to_le16(value)
Definition: byteswap.h:106
A message digest algorithm.
Definition: crypto.h:17
uint32_t end
Ending offset.
Definition: netvsc.h:18
void hmac_final(struct digest_algorithm *digest, void *ctx, void *hmac)
Finalise HMAC.
Definition: hmac.c:87
__be32 raw[7]
Definition: CIB_PRM.h:28
static int peerdist_info_v2_segment(struct peerdist_info_segment *segment)
Populate content information segment.
Definition: pccrc.c:575
int(* info)(struct peerdist_info *info)
Populate content information.
Definition: pccrc.h:419
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:45
signed long ssize_t
Definition: stdint.h:7
uint32_t digestsize
Digest size (i.e.
Definition: pccrr.h:14
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21
Content Information version 2 data structure header.
Definition: pccrc.h:196
Content Information version 2 chunk description header.
Definition: pccrc.h:231
#define le64_to_cpu(value)
Definition: byteswap.h:114
int(* block)(struct peerdist_info_block *block)
Populate content information block.
Definition: pccrc.h:433
SHA-256 algorithm.
Content information operations.
Definition: pccrc.h:412
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
uint32_t first
Length to skip in first segment.
Definition: pccrc.h:23
#define PEERDIST_INFO_V1
Content Information version 1.
Definition: pccrc.h:46
Content Information version number.
Definition: pccrc.h:28
#define peerdist_info_v1_block_t(digestsize, blocks)
Content Information version 1 block description.
Definition: pccrc.h:179
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33
void * memset(void *dest, int character, size_t len) __nonnull
Base16 encoding.