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/sha256.h>
29 #include <ipxe/sha512.h>
30 #include <ipxe/hmac.h>
31 #include <ipxe/base16.h>
32 #include <ipxe/pccrc.h>
33 
34 /** @file
35  *
36  * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC]
37  *
38  */
39 
40 /******************************************************************************
41  *
42  * Utility functions
43  *
44  ******************************************************************************
45  */
46 
47 /**
48  * Transcribe hash value (for debugging)
49  *
50  * @v info Content information
51  * @v hash Hash value
52  * @ret string Hash value string
53  */
54 static inline const char *
55 peerdist_info_hash_ntoa ( const struct peerdist_info *info, const void *hash ) {
56  static char buf[ ( 2 * PEERDIST_DIGEST_MAX_SIZE ) + 1 /* NUL */ ];
57  size_t digestsize = info->digestsize;
58 
59  /* Sanity check */
60  assert ( info != NULL );
61  assert ( digestsize != 0 );
62  assert ( base16_encoded_len ( digestsize ) < sizeof ( buf ) );
63 
64  /* Transcribe hash value */
65  base16_encode ( hash, digestsize, buf, sizeof ( buf ) );
66  return buf;
67 }
68 
69 /**
70  * Get raw data
71  *
72  * @v info Content information
73  * @v data Data buffer
74  * @v offset Starting offset
75  * @v len Length
76  * @ret rc Return status code
77  */
78 static int peerdist_info_get ( const struct peerdist_info *info, void *data,
79  size_t offset, size_t len ) {
80 
81  /* Sanity check */
82  if ( ( offset > info->raw.len ) ||
83  ( len > ( info->raw.len - offset ) ) ) {
84  DBGC ( info, "PCCRC %p data underrun at [%zx,%zx) of %zx\n",
85  info, offset, ( offset + len ), info->raw.len );
86  return -ERANGE;
87  }
88 
89  /* Copy data */
90  memcpy ( data, ( info->raw.data + offset ), len );
91 
92  return 0;
93 }
94 
95 /**
96  * Populate segment hashes
97  *
98  * @v segment Content information segment to fill in
99  * @v hash Segment hash of data
100  * @v secret Segment secret
101  */
103  const void *hash, const void *secret ){
104  const struct peerdist_info *info = segment->info;
105  struct digest_algorithm *digest = info->digest;
106  uint8_t ctx[ hmac_ctxsize ( digest ) ];
107  size_t digestsize = info->digestsize;
108  static const uint16_t magic[] = PEERDIST_SEGMENT_ID_MAGIC;
109 
110  /* Sanity check */
111  assert ( digestsize <= sizeof ( segment->hash ) );
112  assert ( digestsize <= sizeof ( segment->secret ) );
113  assert ( digestsize <= sizeof ( segment->id ) );
114 
115  /* Get segment hash of data */
116  memcpy ( segment->hash, hash, digestsize );
117 
118  /* Get segment secret */
119  memcpy ( segment->secret, secret, digestsize );
120 
121  /* Calculate segment identifier */
122  hmac_init ( digest, ctx, segment->secret, digestsize );
123  hmac_update ( digest, ctx, segment->hash, digestsize );
124  hmac_update ( digest, ctx, magic, sizeof ( magic ) );
125  hmac_final ( digest, ctx, segment->id );
126 }
127 
128 /******************************************************************************
129  *
130  * Content Information version 1
131  *
132  ******************************************************************************
133  */
134 
135 /**
136  * Get number of blocks within a block description
137  *
138  * @v info Content information
139  * @v offset Block description offset
140  * @ret blocks Number of blocks, or negative error
141  */
142 static int peerdist_info_v1_blocks ( const struct peerdist_info *info,
143  size_t offset ) {
145  unsigned int blocks;
146  int rc;
147 
148  /* Get block description header */
149  if ( ( rc = peerdist_info_get ( info, &raw, offset,
150  sizeof ( raw ) ) ) != 0 )
151  return rc;
152 
153  /* Calculate number of blocks */
154  blocks = le32_to_cpu ( raw.blocks );
155 
156  return blocks;
157 }
158 
159 /**
160  * Locate block description
161  *
162  * @v info Content information
163  * @v index Segment index
164  * @ret offset Block description offset, or negative error
165  */
167  unsigned int index ) {
168  size_t digestsize = info->digestsize;
169  unsigned int i;
170  size_t offset;
171  int blocks;
172  int rc;
173 
174  /* Sanity check */
175  assert ( index < info->segments );
176 
177  /* Calculate offset of first block description */
178  offset = ( sizeof ( struct peerdist_info_v1 ) +
179  ( info->segments *
180  sizeof ( peerdist_info_v1_segment_t ( digestsize ) ) ) );
181 
182  /* Iterate over block descriptions until we find this segment */
183  for ( i = 0 ; i < index ; i++ ) {
184 
185  /* Get number of blocks */
186  blocks = peerdist_info_v1_blocks ( info, offset );
187  if ( blocks < 0 ) {
188  rc = blocks;
189  DBGC ( info, "PCCRC %p segment %d could not get number "
190  "of blocks: %s\n", info, i, strerror ( rc ) );
191  return rc;
192  }
193 
194  /* Move to next block description */
196  blocks ) );
197  }
198 
199  return offset;
200 }
201 
202 /**
203  * Populate content information
204  *
205  * @v info Content information to fill in
206  * @ret rc Return status code
207  */
208 static int peerdist_info_v1 ( struct peerdist_info *info ) {
209  struct peerdist_info_v1 raw;
211  struct peerdist_info_segment last;
212  size_t first_skip;
213  size_t last_skip;
214  size_t last_read;
215  int rc;
216 
217  /* Get raw header */
218  if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
219  DBGC ( info, "PCCRC %p could not get V1 content information: "
220  "%s\n", info, strerror ( rc ) );
221  return rc;
222  }
223  assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V1 ) );
224 
225  /* Determine hash algorithm */
226  switch ( raw.hash ) {
228  info->digest = &sha256_algorithm;
229  break;
231  info->digest = &sha384_algorithm;
232  break;
234  info->digest = &sha512_algorithm;
235  break;
236  default:
237  DBGC ( info, "PCCRC %p unsupported hash algorithm %#08x\n",
238  info, le32_to_cpu ( raw.hash ) );
239  return -ENOTSUP;
240  }
241  info->digestsize = info->digest->digestsize;
242  assert ( info->digest != NULL );
243  DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
244  info, info->digest->name, ( info->digestsize * 8 ) );
245 
246  /* Calculate number of segments */
247  info->segments = le32_to_cpu ( raw.segments );
248 
249  /* Get first segment */
250  if ( ( rc = peerdist_info_segment ( info, &first, 0 ) ) != 0 )
251  return rc;
252 
253  /* Calculate range start offset */
254  info->range.start = first.range.start;
255 
256  /* Calculate trimmed range start offset */
257  first_skip = le32_to_cpu ( raw.first );
258  info->trim.start = ( first.range.start + first_skip );
259 
260  /* Get last segment */
261  if ( ( rc = peerdist_info_segment ( info, &last,
262  ( info->segments - 1 ) ) ) != 0 )
263  return rc;
264 
265  /* Calculate range end offset */
266  info->range.end = last.range.end;
267 
268  /* Calculate trimmed range end offset */
269  if ( raw.last ) {
270  /* Explicit length to include from last segment is given */
271  last_read = le32_to_cpu ( raw.last );
272  last_skip = ( last.index ? 0 : first_skip );
273  info->trim.end = ( last.range.start + last_skip + last_read );
274  } else {
275  /* No explicit length given: range extends to end of segment */
276  info->trim.end = last.range.end;
277  }
278 
279  return 0;
280 }
281 
282 /**
283  * Populate content information segment
284  *
285  * @v segment Content information segment to fill in
286  * @ret rc Return status code
287  */
289  const struct peerdist_info *info = segment->info;
290  size_t digestsize = info->digestsize;
292  ssize_t raw_offset;
293  int blocks;
294  int rc;
295 
296  /* Sanity checks */
297  assert ( segment->index < info->segments );
298 
299  /* Get raw description */
300  raw_offset = ( sizeof ( struct peerdist_info_v1 ) +
301  ( segment->index * sizeof ( raw ) ) );
302  if ( ( rc = peerdist_info_get ( info, &raw, raw_offset,
303  sizeof ( raw ) ) ) != 0 ) {
304  DBGC ( info, "PCCRC %p segment %d could not get segment "
305  "description: %s\n", info, segment->index,
306  strerror ( rc ) );
307  return rc;
308  }
309 
310  /* Calculate start offset of this segment */
311  segment->range.start = le64_to_cpu ( raw.segment.offset );
312 
313  /* Calculate end offset of this segment */
314  segment->range.end = ( segment->range.start +
315  le32_to_cpu ( raw.segment.len ) );
316 
317  /* Calculate block size of this segment */
318  segment->blksize = le32_to_cpu ( raw.segment.blksize );
319 
320  /* Locate block description for this segment */
321  raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
322  if ( raw_offset < 0 ) {
323  rc = raw_offset;
324  return rc;
325  }
326 
327  /* Get number of blocks */
328  blocks = peerdist_info_v1_blocks ( info, raw_offset );
329  if ( blocks < 0 ) {
330  rc = blocks;
331  DBGC ( info, "PCCRC %p segment %d could not get number of "
332  "blocks: %s\n", info, segment->index, strerror ( rc ) );
333  return rc;
334  }
335  segment->blocks = blocks;
336 
337  /* Calculate segment hashes */
338  peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
339 
340  return 0;
341 }
342 
343 /**
344  * Populate content information block
345  *
346  * @v block Content information block to fill in
347  * @ret rc Return status code
348  */
350  const struct peerdist_info_segment *segment = block->segment;
351  const struct peerdist_info *info = segment->info;
352  size_t digestsize = info->digestsize;
354  ssize_t raw_offset;
355  int rc;
356 
357  /* Sanity checks */
358  assert ( block->index < segment->blocks );
359 
360  /* Calculate start offset of this block */
361  block->range.start = ( segment->range.start +
362  ( block->index * segment->blksize ) );
363 
364  /* Calculate end offset of this block */
365  block->range.end = ( block->range.start + segment->blksize );
366  if ( block->range.end > segment->range.end )
367  block->range.end = segment->range.end;
368 
369  /* Locate block description */
370  raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
371  if ( raw_offset < 0 ) {
372  rc = raw_offset;
373  return rc;
374  }
375 
376  /* Get block hash */
377  raw_offset += offsetof ( typeof ( raw ), hash[block->index] );
378  if ( ( rc = peerdist_info_get ( info, block->hash, raw_offset,
379  digestsize ) ) != 0 ) {
380  DBGC ( info, "PCCRC %p segment %d block %d could not get "
381  "hash: %s\n", info, segment->index, block->index,
382  strerror ( rc ) );
383  return rc;
384  }
385 
386  return 0;
387 }
388 
389 /** Content information version 1 operations */
392  .segment = peerdist_info_v1_segment,
393  .block = peerdist_info_v1_block,
394 };
395 
396 /******************************************************************************
397  *
398  * Content Information version 2
399  *
400  ******************************************************************************
401  */
402 
403 /** A segment cursor */
405  /** Raw data offset */
406  size_t offset;
407  /** Number of segments remaining within this chunk */
408  unsigned int remaining;
409  /** Accumulated segment length */
410  size_t len;
411 };
412 
413 /**
414  * Initialise segment cursor
415  *
416  * @v cursor Segment cursor
417  */
418 static inline void
420 
421  /* Initialise cursor */
422  cursor->offset = ( sizeof ( struct peerdist_info_v2 ) +
423  sizeof ( struct peerdist_info_v2_chunk ) );
424  cursor->remaining = 0;
425  cursor->len = 0;
426 }
427 
428 /**
429  * Update segment cursor to next segment description
430  *
431  * @v info Content information
432  * @v offset Current offset
433  * @v remaining Number of segments remaining within this chunk
434  * @ret rc Return status code
435  */
436 static int
438  struct peerdist_info_v2_cursor *cursor ) {
439  size_t digestsize = info->digestsize;
441  struct peerdist_info_v2_chunk chunk;
442  int rc;
443 
444  /* Get chunk description if applicable */
445  if ( ! cursor->remaining ) {
446 
447  /* Get chunk description */
448  if ( ( rc = peerdist_info_get ( info, &chunk,
449  ( cursor->offset -
450  sizeof ( chunk ) ),
451  sizeof ( chunk ) ) ) != 0 )
452  return rc;
453 
454  /* Update number of segments remaining */
455  cursor->remaining = ( be32_to_cpu ( chunk.len ) /
456  sizeof ( raw ) );
457  }
458 
459  /* Get segment description header */
460  if ( ( rc = peerdist_info_get ( info, &raw.segment, cursor->offset,
461  sizeof ( raw.segment ) ) ) != 0 )
462  return rc;
463 
464  /* Update cursor */
465  cursor->offset += sizeof ( raw );
466  cursor->remaining--;
467  if ( ! cursor->remaining )
468  cursor->offset += sizeof ( chunk );
469  cursor->len += be32_to_cpu ( raw.segment.len );
470 
471  return 0;
472 }
473 
474 /**
475  * Get number of segments and total length
476  *
477  * @v info Content information
478  * @v len Length to fill in
479  * @ret rc Number of segments, or negative error
480  */
481 static int peerdist_info_v2_segments ( const struct peerdist_info *info,
482  size_t *len ) {
483  struct peerdist_info_v2_cursor cursor;
484  unsigned int segments;
485  int rc;
486 
487  /* Iterate over all segments */
488  for ( peerdist_info_v2_cursor_init ( &cursor ), segments = 0 ;
489  cursor.offset < info->raw.len ; segments++ ) {
490 
491  /* Update segment cursor */
493  &cursor ) ) != 0 ) {
494  DBGC ( info, "PCCRC %p segment %d could not update "
495  "segment cursor: %s\n",
496  info, segments, strerror ( rc ) );
497  return rc;
498  }
499  }
500 
501  /* Record accumulated length */
502  *len = cursor.len;
503 
504  return segments;
505 }
506 
507 /**
508  * Populate content information
509  *
510  * @v info Content information to fill in
511  * @ret rc Return status code
512  */
513 static int peerdist_info_v2 ( struct peerdist_info *info ) {
514  struct peerdist_info_v2 raw;
515  size_t len = 0;
516  int segments;
517  int rc;
518 
519  /* Get raw header */
520  if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
521  DBGC ( info, "PCCRC %p could not get V2 content information: "
522  "%s\n", info, strerror ( rc ) );
523  return rc;
524  }
525  assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V2 ) );
526 
527  /* Determine hash algorithm */
528  switch ( raw.hash ) {
530  info->digest = &sha512_algorithm;
531  info->digestsize = ( 256 / 8 );
532  break;
533  default:
534  DBGC ( info, "PCCRC %p unsupported hash algorithm %#02x\n",
535  info, raw.hash );
536  return -ENOTSUP;
537  }
538  assert ( info->digest != NULL );
539  DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
540  info, info->digest->name, ( info->digestsize * 8 ) );
541 
542  /* Calculate number of segments and total length */
543  segments = peerdist_info_v2_segments ( info, &len );
544  if ( segments < 0 ) {
545  rc = segments;
546  DBGC ( info, "PCCRC %p could not get segment count and length: "
547  "%s\n", info, strerror ( rc ) );
548  return rc;
549  }
550  info->segments = segments;
551 
552  /* Calculate range start offset */
553  info->range.start = be64_to_cpu ( raw.offset );
554 
555  /* Calculate trimmed range start offset */
556  info->trim.start = ( info->range.start + be32_to_cpu ( raw.first ) );
557 
558  /* Calculate range end offset */
559  info->range.end = ( info->range.start + len );
560 
561  /* Calculate trimmed range end offset */
562  info->trim.end = ( raw.len ? be64_to_cpu ( raw.len ) :
563  info->range.end );
564 
565  return 0;
566 }
567 
568 /**
569  * Populate content information segment
570  *
571  * @v segment Content information segment to fill in
572  * @ret rc Return status code
573  */
575  const struct peerdist_info *info = segment->info;
576  size_t digestsize = info->digestsize;
578  struct peerdist_info_v2_cursor cursor;
579  unsigned int index;
580  size_t len;
581  int rc;
582 
583  /* Sanity checks */
584  assert ( segment->index < info->segments );
585 
586  /* Iterate over all segments before the target segment */
587  for ( peerdist_info_v2_cursor_init ( &cursor ), index = 0 ;
588  index < segment->index ; index++ ) {
589 
590  /* Update segment cursor */
592  &cursor ) ) != 0 ) {
593  DBGC ( info, "PCCRC %p segment %d could not update "
594  "segment cursor: %s\n",
595  info, index, strerror ( rc ) );
596  return rc;
597  }
598  }
599 
600  /* Get raw description */
601  if ( ( rc = peerdist_info_get ( info, &raw, cursor.offset,
602  sizeof ( raw ) ) ) != 0 ) {
603  DBGC ( info, "PCCRC %p segment %d could not get segment "
604  "description: %s\n",
605  info, segment->index, strerror ( rc ) );
606  return rc;
607  }
608 
609  /* Calculate start offset of this segment */
610  segment->range.start = ( info->range.start + cursor.len );
611 
612  /* Calculate end offset of this segment */
613  len = be32_to_cpu ( raw.segment.len );
614  segment->range.end = ( segment->range.start + len );
615 
616  /* Model as a segment containing a single block */
617  segment->blocks = 1;
618  segment->blksize = len;
619 
620  /* Calculate segment hashes */
621  peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
622 
623  return 0;
624 }
625 
626 /**
627  * Populate content information block
628  *
629  * @v block Content information block to fill in
630  * @ret rc Return status code
631  */
633  const struct peerdist_info_segment *segment = block->segment;
634  const struct peerdist_info *info = segment->info;
635  size_t digestsize = info->digestsize;
636 
637  /* Sanity checks */
638  assert ( block->index < segment->blocks );
639 
640  /* Model as a block covering the whole segment */
641  memcpy ( &block->range, &segment->range, sizeof ( block->range ) );
642  memcpy ( block->hash, segment->hash, digestsize );
643 
644  return 0;
645 }
646 
647 /** Content information version 2 operations */
650  .segment = peerdist_info_v2_segment,
651  .info = peerdist_info_v2,
652 };
653 
654 /******************************************************************************
655  *
656  * Content Information
657  *
658  ******************************************************************************
659  */
660 
661 /**
662  * Populate content information
663  *
664  * @v data Raw data
665  * @v len Length of raw data
666  * @v info Content information to fill in
667  * @ret rc Return status code
668  */
669 int peerdist_info ( const void *data, size_t len,
670  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:138
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
pseudo_bit_t hash[0x00010]
Definition: arbel.h:13
A segment cursor.
Definition: pccrc.c:404
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:55
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define PEERDIST_INFO_V1_HASH_SHA512
SHA-512 hash algorithm.
Definition: pccrc.h:102
u32 info
Definition: ar9003_mac.h:67
A content information segment.
Definition: pccrc.h:346
static void peerdist_info_v2_cursor_init(struct peerdist_info_v2_cursor *cursor)
Initialise segment cursor.
Definition: pccrc.c:419
#define le32_to_cpu(value)
Definition: byteswap.h:113
Content Information version 1 data structure header.
Definition: pccrc.h:61
uint32_t first
First block in range.
Definition: pccrr.h:14
Error codes.
uint16_t magic
Magic signature.
Definition: bzimage.h:6
struct digest_algorithm sha512_algorithm
SHA-512 algorithm.
Definition: sha512.c:284
size_t start
Start offset.
Definition: pccrc.h:310
#define DBGC(...)
Definition: compiler.h:505
long index
Definition: bigint.h:62
uint32_t segments
Number of segments within the content information.
Definition: pccrc.h:83
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
unsigned int index
Segment index.
Definition: pccrc.h:350
struct golan_eq_context ctx
Definition: CIB_PRM.h:28
#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:24
A content information block.
Definition: pccrc.h:393
Content Information version 1 block description header.
Definition: pccrc.h:156
static struct peerdist_info_operations peerdist_info_v1_operations
Content information version 1 operations.
Definition: pccrc.c:390
void * memcpy(void *dest, const void *src, size_t len) __nonnull
unsigned int remaining
Number of segments remaining within this chunk.
Definition: pccrc.c:408
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:390
struct peerdist_range range
Content range.
Definition: pccrc.h:356
static int peerdist_info_v1(struct peerdist_info *info)
Populate content information.
Definition: pccrc.c:208
Assertions.
#define PEERDIST_INFO_V2
Content Information version 2.
Definition: pccrc.h:48
#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:340
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
ring len
Length.
Definition: dwmac.h:231
uint32_t len
Chunk data length.
Definition: pccrc.h:234
static int peerdist_info_v2_segments(const struct peerdist_info *info, size_t *len)
Get number of segments and total length.
Definition: pccrc.c:481
static int peerdist_info_v2(struct peerdist_info *info)
Populate content information.
Definition: pccrc.c:513
static int peerdist_info_v1_segment(struct peerdist_info_segment *segment)
Populate content information segment.
Definition: pccrc.c:288
static ssize_t peerdist_info_v1_block_offset(const struct peerdist_info *info, unsigned int index)
Locate block description.
Definition: pccrc.c:166
Content information.
Definition: pccrc.h:316
#define cpu_to_le32(value)
Definition: byteswap.h:107
size_t offset
Raw data offset.
Definition: pccrc.c:406
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
#define ERANGE
Result too large.
Definition: errno.h:639
static size_t hmac_ctxsize(struct digest_algorithm *digest)
Calculate HMAC context size.
Definition: hmac.h:28
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:279
static void peerdist_info_segment_hash(struct peerdist_info_segment *segment, const void *hash, const void *secret)
Populate segment hashes.
Definition: pccrc.c:102
static int peerdist_info_get(const struct peerdist_info *info, void *data, size_t offset, size_t len)
Get raw data.
Definition: pccrc.c:78
#define PEERDIST_INFO_V1_HASH_SHA384
SHA-384 hash algorithm.
Definition: pccrc.h:99
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:349
#define PEERDIST_INFO_V1_HASH_SHA256
SHA-256 hash algorithm.
Definition: pccrc.h:96
static int peerdist_info_v2_block(struct peerdist_info_block *block)
Populate content information block.
Definition: pccrc.c:632
#define PEERDIST_DIGEST_MAX_SIZE
Maximum digest size for any supported algorithm.
Definition: pccrc.h:297
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:142
size_t len
Accumulated segment length.
Definition: pccrc.c:410
#define peerdist_info_v1_segment_t(digestsize)
Content Information version 1 segment description.
Definition: pccrc.h:145
struct digest_algorithm sha256_algorithm
SHA-256 algorithm.
Definition: sha256.c:264
uint32_t blocks
Number of blocks within the block description.
Definition: pccrc.h:163
#define DBGC2(...)
Definition: compiler.h:522
uint8_t block[3][8]
DES-encrypted blocks.
Definition: mschapv2.h:12
static struct peerdist_info_operations peerdist_info_v2_operations
Content information version 2 operations.
Definition: pccrc.c:648
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:437
#define PEERDIST_INFO_V2_HASH_SHA512_TRUNC
SHA-512 hash algorithm with output truncated to first 256 bits.
Definition: pccrc.h:224
SHA-512 algorithm.
#define cpu_to_le16(value)
Definition: byteswap.h:106
A message digest algorithm.
Definition: crypto.h:18
uint32_t end
Ending offset.
Definition: netvsc.h:18
uint8_t data[48]
Additional event data.
Definition: ena.h:22
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:574
int(* info)(struct peerdist_info *info)
Populate content information.
Definition: pccrc.h:418
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:47
signed long ssize_t
Definition: stdint.h:7
uint32_t digestsize
Digest size (i.e.
Definition: pccrr.h:14
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
int peerdist_info(const void *data, size_t len, struct peerdist_info *info)
Populate content information.
Definition: pccrc.c:669
Content Information version 2 data structure header.
Definition: pccrc.h:195
Content Information version 2 chunk description header.
Definition: pccrc.h:230
#define le64_to_cpu(value)
Definition: byteswap.h:114
int(* block)(struct peerdist_info_block *block)
Populate content information block.
Definition: pccrc.h:432
SHA-256 algorithm.
Content information operations.
Definition: pccrc.h:411
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
#define PEERDIST_INFO_V1
Content Information version 1.
Definition: pccrc.h:45
Content Information version number.
Definition: pccrc.h:27
#define peerdist_info_v1_block_t(digestsize, blocks)
Content Information version 1 block description.
Definition: pccrc.h:178
size_t end
End offset.
Definition: pccrc.h:312
void * memset(void *dest, int character, size_t len) __nonnull
Base16 encoding.