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[digest->ctxsize];
108  size_t digestsize = info->digestsize;
109  size_t secretsize = digestsize;
110  static const uint16_t magic[] = PEERDIST_SEGMENT_ID_MAGIC;
111 
112  /* Sanity check */
113  assert ( digestsize <= sizeof ( segment->hash ) );
114  assert ( digestsize <= sizeof ( segment->secret ) );
115  assert ( digestsize <= sizeof ( segment->id ) );
116 
117  /* Get segment hash of data */
118  memcpy ( segment->hash, hash, digestsize );
119 
120  /* Get segment secret */
121  memcpy ( segment->secret, secret, digestsize );
122 
123  /* Calculate segment identifier */
124  hmac_init ( digest, ctx, segment->secret, &secretsize );
125  assert ( secretsize == digestsize );
126  hmac_update ( digest, ctx, segment->hash, digestsize );
127  hmac_update ( digest, ctx, magic, sizeof ( magic ) );
128  hmac_final ( digest, ctx, segment->secret, &secretsize, segment->id );
129  assert ( secretsize == digestsize );
130 }
131 
132 /******************************************************************************
133  *
134  * Content Information version 1
135  *
136  ******************************************************************************
137  */
138 
139 /**
140  * Get number of blocks within a block description
141  *
142  * @v info Content information
143  * @v offset Block description offset
144  * @ret blocks Number of blocks, or negative error
145  */
146 static int peerdist_info_v1_blocks ( const struct peerdist_info *info,
147  size_t offset ) {
149  unsigned int blocks;
150  int rc;
151 
152  /* Get block description header */
153  if ( ( rc = peerdist_info_get ( info, &raw, offset,
154  sizeof ( raw ) ) ) != 0 )
155  return rc;
156 
157  /* Calculate number of blocks */
158  blocks = le32_to_cpu ( raw.blocks );
159 
160  return blocks;
161 }
162 
163 /**
164  * Locate block description
165  *
166  * @v info Content information
167  * @v index Segment index
168  * @ret offset Block description offset, or negative error
169  */
171  unsigned int index ) {
172  size_t digestsize = info->digestsize;
173  unsigned int i;
174  size_t offset;
175  int blocks;
176  int rc;
177 
178  /* Sanity check */
179  assert ( index < info->segments );
180 
181  /* Calculate offset of first block description */
182  offset = ( sizeof ( struct peerdist_info_v1 ) +
183  ( info->segments *
184  sizeof ( peerdist_info_v1_segment_t ( digestsize ) ) ) );
185 
186  /* Iterate over block descriptions until we find this segment */
187  for ( i = 0 ; i < index ; i++ ) {
188 
189  /* Get number of blocks */
191  if ( blocks < 0 ) {
192  rc = blocks;
193  DBGC ( info, "PCCRC %p segment %d could not get number "
194  "of blocks: %s\n", info, i, strerror ( rc ) );
195  return rc;
196  }
197 
198  /* Move to next block description */
200  blocks ) );
201  }
202 
203  return offset;
204 }
205 
206 /**
207  * Populate content information
208  *
209  * @v info Content information to fill in
210  * @ret rc Return status code
211  */
212 static int peerdist_info_v1 ( struct peerdist_info *info ) {
213  struct peerdist_info_v1 raw;
216  size_t first_skip;
217  size_t last_skip;
218  size_t last_read;
219  int rc;
220 
221  /* Get raw header */
222  if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
223  DBGC ( info, "PCCRC %p could not get V1 content information: "
224  "%s\n", info, strerror ( rc ) );
225  return rc;
226  }
227  assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V1 ) );
228 
229  /* Determine hash algorithm */
230  switch ( raw.hash ) {
232  info->digest = &sha256_algorithm;
233  break;
235  info->digest = &sha384_algorithm;
236  break;
238  info->digest = &sha512_algorithm;
239  break;
240  default:
241  DBGC ( info, "PCCRC %p unsupported hash algorithm %#08x\n",
242  info, le32_to_cpu ( raw.hash ) );
243  return -ENOTSUP;
244  }
245  info->digestsize = info->digest->digestsize;
246  assert ( info->digest != NULL );
247  DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
248  info, info->digest->name, ( info->digestsize * 8 ) );
249 
250  /* Calculate number of segments */
251  info->segments = le32_to_cpu ( raw.segments );
252 
253  /* Get first segment */
254  if ( ( rc = peerdist_info_segment ( info, &first, 0 ) ) != 0 )
255  return rc;
256 
257  /* Calculate range start offset */
258  info->range.start = first.range.start;
259 
260  /* Calculate trimmed range start offset */
261  first_skip = le32_to_cpu ( raw.first );
262  info->trim.start = ( first.range.start + first_skip );
263 
264  /* Get last segment */
265  if ( ( rc = peerdist_info_segment ( info, &last,
266  ( info->segments - 1 ) ) ) != 0 )
267  return rc;
268 
269  /* Calculate range end offset */
270  info->range.end = last.range.end;
271 
272  /* Calculate trimmed range end offset */
273  if ( raw.last ) {
274  /* Explicit length to include from last segment is given */
275  last_read = le32_to_cpu ( raw.last );
276  last_skip = ( last.index ? 0 : first_skip );
277  info->trim.end = ( last.range.start + last_skip + last_read );
278  } else {
279  /* No explicit length given: range extends to end of segment */
280  info->trim.end = last.range.end;
281  }
282 
283  return 0;
284 }
285 
286 /**
287  * Populate content information segment
288  *
289  * @v segment Content information segment to fill in
290  * @ret rc Return status code
291  */
293  const struct peerdist_info *info = segment->info;
294  size_t digestsize = info->digestsize;
296  ssize_t raw_offset;
297  int blocks;
298  int rc;
299 
300  /* Sanity checks */
301  assert ( segment->index < info->segments );
302 
303  /* Get raw description */
304  raw_offset = ( sizeof ( struct peerdist_info_v1 ) +
305  ( segment->index * sizeof ( raw ) ) );
306  if ( ( rc = peerdist_info_get ( info, &raw, raw_offset,
307  sizeof ( raw ) ) ) != 0 ) {
308  DBGC ( info, "PCCRC %p segment %d could not get segment "
309  "description: %s\n", info, segment->index,
310  strerror ( rc ) );
311  return rc;
312  }
313 
314  /* Calculate start offset of this segment */
315  segment->range.start = le64_to_cpu ( raw.segment.offset );
316 
317  /* Calculate end offset of this segment */
318  segment->range.end = ( segment->range.start +
319  le32_to_cpu ( raw.segment.len ) );
320 
321  /* Calculate block size of this segment */
322  segment->blksize = le32_to_cpu ( raw.segment.blksize );
323 
324  /* Locate block description for this segment */
325  raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
326  if ( raw_offset < 0 ) {
327  rc = raw_offset;
328  return rc;
329  }
330 
331  /* Get number of blocks */
332  blocks = peerdist_info_v1_blocks ( info, raw_offset );
333  if ( blocks < 0 ) {
334  rc = blocks;
335  DBGC ( info, "PCCRC %p segment %d could not get number of "
336  "blocks: %s\n", info, segment->index, strerror ( rc ) );
337  return rc;
338  }
339  segment->blocks = blocks;
340 
341  /* Calculate segment hashes */
342  peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
343 
344  return 0;
345 }
346 
347 /**
348  * Populate content information block
349  *
350  * @v block Content information block to fill in
351  * @ret rc Return status code
352  */
354  const struct peerdist_info_segment *segment = block->segment;
355  const struct peerdist_info *info = segment->info;
356  size_t digestsize = info->digestsize;
358  ssize_t raw_offset;
359  int rc;
360 
361  /* Sanity checks */
362  assert ( block->index < segment->blocks );
363 
364  /* Calculate start offset of this block */
365  block->range.start = ( segment->range.start +
366  ( block->index * segment->blksize ) );
367 
368  /* Calculate end offset of this block */
369  block->range.end = ( block->range.start + segment->blksize );
370  if ( block->range.end > segment->range.end )
371  block->range.end = segment->range.end;
372 
373  /* Locate block description */
374  raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
375  if ( raw_offset < 0 ) {
376  rc = raw_offset;
377  return rc;
378  }
379 
380  /* Get block hash */
381  raw_offset += offsetof ( typeof ( raw ), hash[block->index] );
382  if ( ( rc = peerdist_info_get ( info, block->hash, raw_offset,
383  digestsize ) ) != 0 ) {
384  DBGC ( info, "PCCRC %p segment %d block %d could not get "
385  "hash: %s\n", info, segment->index, block->index,
386  strerror ( rc ) );
387  return rc;
388  }
389 
390  return 0;
391 }
392 
393 /** Content information version 1 operations */
396  .segment = peerdist_info_v1_segment,
397  .block = peerdist_info_v1_block,
398 };
399 
400 /******************************************************************************
401  *
402  * Content Information version 2
403  *
404  ******************************************************************************
405  */
406 
407 /** A segment cursor */
409  /** Raw data offset */
410  size_t offset;
411  /** Number of segments remaining within this chunk */
412  unsigned int remaining;
413  /** Accumulated segment length */
414  size_t len;
415 };
416 
417 /**
418  * Initialise segment cursor
419  *
420  * @v cursor Segment cursor
421  */
422 static inline void
424 
425  /* Initialise cursor */
426  cursor->offset = ( sizeof ( struct peerdist_info_v2 ) +
427  sizeof ( struct peerdist_info_v2_chunk ) );
428  cursor->remaining = 0;
429  cursor->len = 0;
430 }
431 
432 /**
433  * Update segment cursor to next segment description
434  *
435  * @v info Content information
436  * @v offset Current offset
437  * @v remaining Number of segments remaining within this chunk
438  * @ret rc Return status code
439  */
440 static int
442  struct peerdist_info_v2_cursor *cursor ) {
443  size_t digestsize = info->digestsize;
445  struct peerdist_info_v2_chunk chunk;
446  int rc;
447 
448  /* Get chunk description if applicable */
449  if ( ! cursor->remaining ) {
450 
451  /* Get chunk description */
452  if ( ( rc = peerdist_info_get ( info, &chunk,
453  ( cursor->offset -
454  sizeof ( chunk ) ),
455  sizeof ( chunk ) ) ) != 0 )
456  return rc;
457 
458  /* Update number of segments remaining */
459  cursor->remaining = ( be32_to_cpu ( chunk.len ) /
460  sizeof ( raw ) );
461  }
462 
463  /* Get segment description header */
464  if ( ( rc = peerdist_info_get ( info, &raw.segment, cursor->offset,
465  sizeof ( raw.segment ) ) ) != 0 )
466  return rc;
467 
468  /* Update cursor */
469  cursor->offset += sizeof ( raw );
470  cursor->remaining--;
471  if ( ! cursor->remaining )
472  cursor->offset += sizeof ( chunk );
473  cursor->len += be32_to_cpu ( raw.segment.len );
474 
475  return 0;
476 }
477 
478 /**
479  * Get number of segments and total length
480  *
481  * @v info Content information
482  * @v len Length to fill in
483  * @ret rc Number of segments, or negative error
484  */
485 static int peerdist_info_v2_segments ( const struct peerdist_info *info,
486  size_t *len ) {
487  struct peerdist_info_v2_cursor cursor;
488  unsigned int segments;
489  int rc;
490 
491  /* Iterate over all segments */
492  for ( peerdist_info_v2_cursor_init ( &cursor ), segments = 0 ;
493  cursor.offset < info->raw.len ; segments++ ) {
494 
495  /* Update segment cursor */
497  &cursor ) ) != 0 ) {
498  DBGC ( info, "PCCRC %p segment %d could not update "
499  "segment cursor: %s\n",
500  info, segments, strerror ( rc ) );
501  return rc;
502  }
503  }
504 
505  /* Record accumulated length */
506  *len = cursor.len;
507 
508  return segments;
509 }
510 
511 /**
512  * Populate content information
513  *
514  * @v info Content information to fill in
515  * @ret rc Return status code
516  */
517 static int peerdist_info_v2 ( struct peerdist_info *info ) {
518  struct peerdist_info_v2 raw;
519  size_t len = 0;
520  int segments;
521  int rc;
522 
523  /* Get raw header */
524  if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
525  DBGC ( info, "PCCRC %p could not get V2 content information: "
526  "%s\n", info, strerror ( rc ) );
527  return rc;
528  }
529  assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V2 ) );
530 
531  /* Determine hash algorithm */
532  switch ( raw.hash ) {
534  info->digest = &sha512_algorithm;
535  info->digestsize = ( 256 / 8 );
536  break;
537  default:
538  DBGC ( info, "PCCRC %p unsupported hash algorithm %#02x\n",
539  info, raw.hash );
540  return -ENOTSUP;
541  }
542  assert ( info->digest != NULL );
543  DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
544  info, info->digest->name, ( info->digestsize * 8 ) );
545 
546  /* Calculate number of segments and total length */
548  if ( segments < 0 ) {
549  rc = segments;
550  DBGC ( info, "PCCRC %p could not get segment count and length: "
551  "%s\n", info, strerror ( rc ) );
552  return rc;
553  }
554  info->segments = segments;
555 
556  /* Calculate range start offset */
557  info->range.start = be64_to_cpu ( raw.offset );
558 
559  /* Calculate trimmed range start offset */
560  info->trim.start = ( info->range.start + be32_to_cpu ( raw.first ) );
561 
562  /* Calculate range end offset */
563  info->range.end = ( info->range.start + len );
564 
565  /* Calculate trimmed range end offset */
566  info->trim.end = ( raw.len ? be64_to_cpu ( raw.len ) :
567  info->range.end );
568 
569  return 0;
570 }
571 
572 /**
573  * Populate content information segment
574  *
575  * @v segment Content information segment to fill in
576  * @ret rc Return status code
577  */
579  const struct peerdist_info *info = segment->info;
580  size_t digestsize = info->digestsize;
582  struct peerdist_info_v2_cursor cursor;
583  unsigned int index;
584  size_t len;
585  int rc;
586 
587  /* Sanity checks */
588  assert ( segment->index < info->segments );
589 
590  /* Iterate over all segments before the target segment */
591  for ( peerdist_info_v2_cursor_init ( &cursor ), index = 0 ;
592  index < segment->index ; index++ ) {
593 
594  /* Update segment cursor */
596  &cursor ) ) != 0 ) {
597  DBGC ( info, "PCCRC %p segment %d could not update "
598  "segment cursor: %s\n",
599  info, index, strerror ( rc ) );
600  return rc;
601  }
602  }
603 
604  /* Get raw description */
605  if ( ( rc = peerdist_info_get ( info, &raw, cursor.offset,
606  sizeof ( raw ) ) ) != 0 ) {
607  DBGC ( info, "PCCRC %p segment %d could not get segment "
608  "description: %s\n",
609  info, segment->index, strerror ( rc ) );
610  return rc;
611  }
612 
613  /* Calculate start offset of this segment */
614  segment->range.start = ( info->range.start + cursor.len );
615 
616  /* Calculate end offset of this segment */
617  len = be32_to_cpu ( raw.segment.len );
618  segment->range.end = ( segment->range.start + len );
619 
620  /* Model as a segment containing a single block */
621  segment->blocks = 1;
622  segment->blksize = len;
623 
624  /* Calculate segment hashes */
625  peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
626 
627  return 0;
628 }
629 
630 /**
631  * Populate content information block
632  *
633  * @v block Content information block to fill in
634  * @ret rc Return status code
635  */
637  const struct peerdist_info_segment *segment = block->segment;
638  const struct peerdist_info *info = segment->info;
639  size_t digestsize = info->digestsize;
640 
641  /* Sanity checks */
642  assert ( block->index < segment->blocks );
643 
644  /* Model as a block covering the whole segment */
645  memcpy ( &block->range, &segment->range, sizeof ( block->range ) );
646  memcpy ( block->hash, segment->hash, digestsize );
647 
648  return 0;
649 }
650 
651 /** Content information version 2 operations */
654  .segment = peerdist_info_v2_segment,
655  .info = peerdist_info_v2,
656 };
657 
658 /******************************************************************************
659  *
660  * Content Information
661  *
662  ******************************************************************************
663  */
664 
665 /**
666  * Populate content information
667  *
668  * @v data Raw data
669  * @v len Length of raw data
670  * @v info Content information to fill in
671  * @ret rc Return status code
672  */
673 int peerdist_info ( userptr_t data, size_t len, struct peerdist_info *info ) {
675  int rc;
676 
677  /* Initialise structure */
678  memset ( info, 0, sizeof ( *info ) );
679  info->raw.data = data;
680  info->raw.len = len;
681 
682  /* Get version */
683  if ( ( rc = peerdist_info_get ( info, &version, 0,
684  sizeof ( version ) ) ) != 0 ) {
685  DBGC ( info, "PCCRC %p could not get version: %s\n",
686  info, strerror ( rc ) );
687  return rc;
688  }
689  DBGC2 ( info, "PCCRC %p version %d.%d\n",
690  info, version.major, version.minor );
691 
692  /* Determine version */
693  switch ( version.raw ) {
694  case cpu_to_le16 ( PEERDIST_INFO_V1 ) :
696  break;
697  case cpu_to_le16 ( PEERDIST_INFO_V2 ) :
699  break;
700  default:
701  DBGC ( info, "PCCRC %p unsupported version %d.%d\n",
702  info, version.major, version.minor );
703  return -ENOTSUP;
704  }
705  assert ( info->op != NULL );
706  assert ( info->op->info != NULL );
707 
708  /* Populate content information */
709  if ( ( rc = info->op->info ( info ) ) != 0 )
710  return rc;
711 
712  DBGC2 ( info, "PCCRC %p range [%08zx,%08zx) covers [%08zx,%08zx) with "
713  "%d segments\n", info, info->range.start, info->range.end,
714  info->trim.start, info->trim.end, info->segments );
715  return 0;
716 }
717 
718 /**
719  * Populate content information segment
720  *
721  * @v info Content information
722  * @v segment Content information segment to fill in
723  * @v index Segment index
724  * @ret rc Return status code
725  */
728  unsigned int index ) {
729  int rc;
730 
731  /* Sanity checks */
732  assert ( info != NULL );
733  assert ( info->op != NULL );
734  assert ( info->op->segment != NULL );
735  if ( index >= info->segments ) {
736  DBGC ( info, "PCCRC %p segment %d of [0,%d) out of range\n",
737  info, index, info->segments );
738  return -ERANGE;
739  }
740 
741  /* Initialise structure */
742  memset ( segment, 0, sizeof ( *segment ) );
743  segment->info = info;
744  segment->index = index;
745 
746  /* Populate content information segment */
747  if ( ( rc = info->op->segment ( segment ) ) != 0 )
748  return rc;
749 
750  DBGC2 ( info, "PCCRC %p segment %d range [%08zx,%08zx) with %d "
751  "blocks\n", info, segment->index, segment->range.start,
752  segment->range.end, segment->blocks );
753  DBGC2 ( info, "PCCRC %p segment %d digest %s\n", info, segment->index,
754  peerdist_info_hash_ntoa ( info, segment->hash ) );
755  DBGC2 ( info, "PCCRC %p segment %d secret %s\n", info, segment->index,
756  peerdist_info_hash_ntoa ( info, segment->secret ) );
757  DBGC2 ( info, "PCCRC %p segment %d identf %s\n", info, segment->index,
759  return 0;
760 }
761 
762 /**
763  * Populate content information block
764  *
765  * @v segment Content information segment
766  * @v block Content information block to fill in
767  * @v index Block index
768  * @ret rc Return status code
769  */
771  struct peerdist_info_block *block,
772  unsigned int index ) {
773  const struct peerdist_info *info = segment->info;
774  size_t start;
775  size_t end;
776  int rc;
777 
778  /* Sanity checks */
779  assert ( segment != NULL );
780  assert ( info != NULL );
781  assert ( info->op != NULL );
782  assert ( info->op->block != NULL );
783  if ( index >= segment->blocks ) {
784  DBGC ( info, "PCCRC %p segment %d block %d of [0,%d) out of "
785  "range\n", info, segment->index, index, segment->blocks);
786  return -ERANGE;
787  }
788 
789  /* Initialise structure */
790  memset ( block, 0, sizeof ( *block ) );
791  block->segment = segment;
792  block->index = index;
793 
794  /* Populate content information block */
795  if ( ( rc = info->op->block ( block ) ) != 0 )
796  return rc;
797 
798  /* Calculate trimmed range */
799  start = block->range.start;
800  if ( start < info->trim.start )
801  start = info->trim.start;
802  end = block->range.end;
803  if ( end > info->trim.end )
804  end = info->trim.end;
805  if ( end < start )
806  end = start;
807  block->trim.start = start;
808  block->trim.end = end;
809 
810  DBGC2 ( info, "PCCRC %p segment %d block %d hash %s\n",
811  info, segment->index, block->index,
812  peerdist_info_hash_ntoa ( info, block->hash ) );
813  DBGC2 ( info, "PCCRC %p segment %d block %d range [%08zx,%08zx) covers "
814  "[%08zx,%08zx)\n", info, segment->index, block->index,
815  block->range.start, block->range.end, block->trim.start,
816  block->trim.end );
817  return 0;
818 }
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:408
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:423
#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:285
void hmac_final(struct digest_algorithm *digest, void *digest_ctx, void *key, size_t *key_len, void *hmac)
Finalise HMAC.
Definition: hmac.c:115
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:64
#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:394
void * memcpy(void *dest, const void *src, size_t len) __nonnull
unsigned int remaining
Number of segments remaining within this chunk.
Definition: pccrc.c:412
u32 version
Version number.
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:212
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:726
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:485
static int peerdist_info_v2(struct peerdist_info *info)
Populate content information.
Definition: pccrc.c:517
static int peerdist_info_v1_segment(struct peerdist_info_segment *segment)
Populate content information segment.
Definition: pccrc.c:292
static ssize_t peerdist_info_v1_block_offset(const struct peerdist_info *info, unsigned int index)
Locate block description.
Definition: pccrc.c:170
int peerdist_info(userptr_t data, size_t len, struct peerdist_info *info)
Populate content information.
Definition: pccrc.c:673
Content information.
Definition: pccrc.h:317
#define cpu_to_le32(value)
Definition: byteswap.h:107
size_t offset
Raw data offset.
Definition: pccrc.c:410
Peer Content Caching and Retrieval: Content Identification [MS-PCCRC].
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:770
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:353
#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:636
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:146
size_t len
Accumulated segment length.
Definition: pccrc.c:414
#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:265
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
void hmac_init(struct digest_algorithm *digest, void *digest_ctx, void *key, size_t *key_len)
Initialise HMAC.
Definition: hmac.c:80
static struct peerdist_info_operations peerdist_info_v2_operations
Content information version 2 operations.
Definition: pccrc.c:652
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:441
#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:16
uint32_t end
Ending offset.
Definition: netvsc.h:18
__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:578
int(* info)(struct peerdist_info *info)
Populate content information.
Definition: pccrc.h:419
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
static void hmac_update(struct digest_algorithm *digest, void *digest_ctx, const void *data, size_t len)
Update HMAC.
Definition: hmac.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
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21
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.