LCOV - code coverage report
Current view: top level - util/net - fd_pcapng_iter.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 191 337 56.7 %
Date: 2026-01-19 05:27:37 Functions: 9 11 81.8 %

          Line data    Source code
       1             : #include "fd_pcapng_private.h"
       2             : #include "../fd_util.h"
       3             : #include <errno.h>
       4             : #include <stdio.h>
       5             : 
       6             : FD_FN_CONST ulong
       7           6 : fd_pcapng_iter_align( void ) {
       8           6 :   return alignof(fd_pcapng_iter_t);
       9           6 : }
      10             : 
      11             : FD_FN_CONST ulong
      12           6 : fd_pcapng_iter_footprint( void ) {
      13           6 :   return sizeof(fd_pcapng_iter_t);
      14           6 : }
      15             : 
      16             : static char const *
      17             : fd_pcapng_iter_strerror( int    error,
      18           0 :                          FILE * file ) {
      19           0 :   static FD_TL char err_cstr_buf[ 1024UL ];
      20           0 :   char * err_cstr = fd_cstr_init( err_cstr_buf );
      21           0 :   if( error==EPROTO ) {
      22           0 :     return fd_cstr_printf( err_cstr, sizeof(err_cstr_buf), NULL, "parse error at %#lx", (ulong)ftell(file) );
      23           0 :   } else if( error==-1 && !feof( file ) ) {
      24           0 :     return "end of section";
      25           0 :   } else {
      26           0 :     return fd_cstr_printf( err_cstr, sizeof(err_cstr_buf), NULL, "%i-%s", error, fd_io_strerror( error ) );
      27           0 :   }
      28           0 : }
      29             : 
      30             : static int
      31             : fd_pcapng_read_block( FILE *                  stream,
      32             :                       fd_pcapng_iter_t *      iter,
      33          33 :                       fd_pcapng_block_hdr_t * _hdr ) {
      34             : 
      35             :   /* Remember offset of block */
      36          33 :   long pos = ftell( stream );
      37          33 :   if( FD_UNLIKELY( pos<0L ) )
      38           0 :     return ferror( stream );
      39          33 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)pos, 4U ) ) ) {
      40           0 :     FD_LOG_DEBUG(( "pcapng: misaligned stream at %#lx", (ulong)pos ));
      41           0 :     return EPROTO;
      42           0 :   }
      43             : 
      44             :   /* Read header */
      45          33 :   fd_pcapng_block_hdr_t hdr;
      46          33 :   if( FD_UNLIKELY( 1UL!=fread( &hdr, sizeof(fd_pcapng_block_hdr_t), 1, stream ) ) ) {
      47           6 :     if( FD_LIKELY( feof( stream ) ) ) return -1; /* eof */
      48           0 :     else                              return ferror( stream );
      49           6 :   }
      50             : 
      51             :   /* Coherence check length field */
      52          27 :   if( FD_UNLIKELY( (hdr.block_sz <   12U) /* header and footer are mandatory */
      53          27 :                  | (hdr.block_sz >32768U) /* way too large */
      54          27 :                  | (!fd_ulong_is_aligned( hdr.block_sz, 4U )) ) ) {
      55           0 :     FD_LOG_DEBUG(( "pcapng: block with invalid size %#x at %#lx", hdr.block_sz, (ulong)pos ));
      56           0 :     return EPROTO;
      57           0 :   }
      58             : 
      59          27 :   if( FD_UNLIKELY( hdr.block_sz>FD_PCAPNG_BLOCK_SZ ) ) {
      60           0 :     FD_LOG_DEBUG(( "pcapng: block too large for buffer (%#x)", hdr.block_sz ));
      61           0 :     return EPROTO;
      62           0 :   }
      63             : 
      64          27 :   memcpy( iter->block_buf, &hdr, sizeof(fd_pcapng_block_hdr_t) );
      65          27 :   ulong remaining = hdr.block_sz - sizeof(fd_pcapng_block_hdr_t);
      66             : 
      67             :   /* Read rest of block */
      68          27 :   if( FD_UNLIKELY( 1UL!=fread( iter->block_buf + sizeof(fd_pcapng_block_hdr_t), remaining, 1, stream ) ) )
      69           0 :     return ferror( stream );
      70             : 
      71          27 :   iter->block_buf_sz  = hdr.block_sz;
      72          27 :   iter->block_buf_pos = sizeof(fd_pcapng_block_hdr_t);
      73             : 
      74             :   /* Verify footer */
      75          27 :   uint * footer = (uint *)( iter->block_buf + hdr.block_sz - sizeof(uint) );
      76          27 :   uint block_sz = *footer;
      77             : 
      78             :   /* Check that header and footer match */
      79          27 :   if( FD_UNLIKELY( hdr.block_sz != block_sz ) ) {
      80           0 :     FD_LOG_DEBUG(( "pcapng: block size in header and footer don't match at %#lx", (ulong)pos ));
      81           0 :     return EPROTO;
      82           0 :   }
      83             : 
      84          27 :   *_hdr = hdr;
      85             : 
      86          27 :   return 0; /* success */
      87          27 : }
      88             : 
      89             : static int
      90             : fd_pcapng_read_option( fd_pcapng_iter_t *   iter,
      91          45 :                        fd_pcapng_option_t * opt ) {
      92             : 
      93          45 :   if( FD_UNLIKELY( iter->block_buf_pos + 4UL > iter->block_buf_sz ) ) {
      94           3 :     opt->type  = 0;
      95           3 :     opt->sz    = 0;
      96           3 :     opt->value = NULL;
      97           3 :     return 0;
      98           3 :   }
      99             : 
     100          42 :   struct __attribute__((packed)) {
     101          42 :     ushort type;
     102          42 :     ushort sz;
     103          42 :   } opt_hdr;
     104          42 :   memcpy( &opt_hdr, iter->block_buf + iter->block_buf_pos, 4UL );
     105          42 :   iter->block_buf_pos += 4UL;
     106          42 :   if( FD_UNLIKELY( opt_hdr.sz > (iter->block_buf_sz - iter->block_buf_pos) ) ) {
     107           0 :     iter->error = EPROTO;
     108           0 :     FD_LOG_WARNING(( "option size out of bounds" ));
     109           0 :     return EPROTO;
     110           0 :   }
     111             : 
     112          42 :   uint read_sz = fd_uint_min( opt_hdr.sz, opt->sz );
     113          42 :   opt->type = opt_hdr.type;
     114          42 :   opt->sz   = (ushort)read_sz;
     115             : 
     116          42 :   if( read_sz ) {
     117          21 :     if( FD_UNLIKELY( iter->block_buf_pos + read_sz > iter->block_buf_sz ) ) {
     118           0 :     iter->error = EPROTO;
     119           0 :       FD_LOG_WARNING(( "out of bounds option" ));
     120           0 :       return EPROTO;
     121           0 :     }
     122          21 :     memcpy( opt->value, iter->block_buf + iter->block_buf_pos, read_sz );
     123          21 :   }
     124             : 
     125          42 :   iter->block_buf_pos += fd_uint_align_up( opt_hdr.sz, 4U );
     126          42 :   if( FD_UNLIKELY( iter->block_buf_pos > iter->block_buf_sz ) )
     127           0 :     return EPROTO;
     128             : 
     129          42 :   return 0; /* success */
     130          42 : }
     131             : 
     132             : fd_pcapng_iter_t *
     133             : fd_pcapng_iter_new( void * mem,
     134           6 :                     void * _file ) {
     135             : 
     136           6 :   if( FD_UNLIKELY( !mem ) ) {
     137           0 :     FD_LOG_WARNING(( "NULL mem" ));
     138           0 :     return NULL;
     139           0 :   }
     140           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_pcapng_iter_t) ) ) ) {
     141           0 :     FD_LOG_WARNING(( "unaligned mem" ));
     142           0 :     return NULL;
     143           0 :   }
     144           6 :   if( FD_UNLIKELY( !_file ) ) {
     145           0 :     FD_LOG_WARNING(( "NULL file" ));
     146           0 :     return NULL;
     147           0 :   }
     148             : 
     149           6 :   FILE * file = (FILE *)_file;
     150             : 
     151           6 :   memset( mem, 0, sizeof(fd_pcapng_iter_t) );
     152           6 :   fd_pcapng_iter_t * iter = (fd_pcapng_iter_t *)mem;
     153           6 :   iter->stream = (FILE *)file;
     154           6 :   iter->empty  = 1;
     155             : 
     156             :   /* File starts with a Section Header Block */
     157             : 
     158           6 :   fd_pcapng_block_hdr_t shb_hdr;
     159           6 :   int err = fd_pcapng_read_block( file, iter, &shb_hdr );
     160           6 :   if( FD_UNLIKELY( err ) ) {
     161           0 :     FD_LOG_WARNING(( "pcapng: SHB read failed (%s)", fd_pcapng_iter_strerror( err, file ) ));
     162           0 :     return NULL;
     163           0 :   }
     164           6 :   if( FD_UNLIKELY( shb_hdr.block_type!=FD_PCAPNG_BLOCK_TYPE_SHB
     165           6 :                 || shb_hdr.block_sz  < sizeof(fd_pcapng_shb_t)  ) ) {
     166           0 :     FD_LOG_WARNING(( "pcapng: not a valid Section Header Block" ));
     167           0 :     return NULL;
     168           0 :   }
     169             : 
     170             : 
     171           6 :   fd_pcapng_shb_t shb = FD_LOAD( fd_pcapng_shb_t, iter->block_buf );
     172           6 :   if( FD_UNLIKELY( (shb.version_major!=1) | (shb.version_minor!=0) ) ) {
     173           0 :     FD_LOG_WARNING(( "pcapng: unsupported file format version %u.%u",
     174           0 :                      shb.version_major, shb.version_minor ));
     175           0 :     return NULL;
     176           0 :   }
     177             : 
     178           6 :   return iter;
     179           6 : }
     180             : 
     181             : void *
     182           3 : fd_pcapng_iter_delete( fd_pcapng_iter_t * iter ) {
     183           3 :   void * mem = (void *)iter;
     184           3 :   memset( mem, 0, sizeof(fd_pcapng_iter_t) );
     185           3 :   return mem;
     186           3 : }
     187             : 
     188             : static fd_pcapng_frame_t *
     189          21 : fd_pcapng_iter_next1( fd_pcapng_iter_t * iter ) {
     190          21 :   fd_pcapng_frame_t * pkt = &iter->pkt;
     191             : 
     192             :   /* Clear fields */
     193          21 :   pkt->ts      = 0L;
     194          21 :   pkt->type    = 0U;
     195          21 :   pkt->data_sz = 0U;
     196          21 :   pkt->orig_sz = 0U;
     197          21 :   pkt->if_idx  = 0U;
     198          21 :   pkt->idb     = NULL;
     199             : 
     200          21 :   FILE * stream = iter->stream;
     201             : 
     202             :   /* Attempt a number of times to find a frame of known type.
     203             :      Abort if there are too many unknown frames. */
     204          27 :   for( uint attempt=0U; attempt<256U; attempt++ ) {
     205             : 
     206          27 :     fd_pcapng_block_hdr_t hdr;
     207          27 :     if( FD_UNLIKELY( 0!=(iter->error = fd_pcapng_read_block( stream, iter, &hdr )) ) ) {
     208           6 :       if( FD_UNLIKELY( iter->error != -1 ) )
     209           0 :         FD_LOG_WARNING(( "pcapng: read failed (%s)", fd_pcapng_iter_strerror( iter->error, stream ) ));
     210           6 :       return NULL;
     211           6 :     }
     212             : 
     213          21 :     switch( hdr.block_type ) {
     214           0 :     case FD_PCAPNG_BLOCK_TYPE_SHB: {
     215           0 :       iter->error = -1; /* eof */
     216             :       /* FIXME CONSIDER SILENTLY CONTINUING? */
     217           0 :       return NULL;
     218           0 :     }
     219           6 :     case FD_PCAPNG_BLOCK_TYPE_IDB: {
     220             :       /* Read IDB */
     221           6 :       if( FD_UNLIKELY( hdr.block_sz<sizeof(fd_pcapng_idb_t) ) ) {
     222           0 :         iter->error = EPROTO;
     223           0 :         FD_LOG_WARNING(( "pcapng: invalid IDB block size (%#x)", hdr.block_sz ));
     224           0 :         return NULL;
     225           0 :       }
     226           6 :       fd_pcapng_idb_t idb = FD_LOAD( fd_pcapng_idb_t, iter->block_buf );
     227           6 :       iter->block_buf_pos = sizeof(fd_pcapng_idb_t);
     228             : 
     229             :       /* Add interface to list */
     230           6 :       if( FD_UNLIKELY( iter->iface_cnt>=FD_PCAPNG_IFACE_CNT ) ) {
     231           0 :         iter->error = EPROTO;
     232           0 :         FD_LOG_WARNING(( "pcapng: too many interfaces (max %d)", FD_PCAPNG_IFACE_CNT ));
     233           0 :         return NULL;
     234           0 :       }
     235             : 
     236           6 :       fd_pcapng_idb_desc_t * iface = &iter->iface[ iter->iface_cnt++ ];
     237           6 :       memset( iface, 0, sizeof(fd_pcapng_idb_desc_t) );
     238           6 :       iface->link_type = idb.link_type;
     239             : 
     240             :       /* Read options */
     241          27 :       for( uint j=0; j<FD_PCAPNG_MAX_OPT_CNT; j++ ) {
     242          27 :         uchar opt_buf[ 128UL ] __attribute__((aligned(32UL)));
     243          27 :         fd_pcapng_option_t opt = { .sz=sizeof(opt_buf), .value=&opt_buf };
     244          27 :         if( FD_UNLIKELY( 0!=(iter->error = fd_pcapng_read_option( iter, &opt )) ) ) {
     245           0 :           FD_LOG_WARNING(( "pcapng: read failed (%s)", fd_pcapng_iter_strerror( iter->error, stream ) ));
     246           0 :           return NULL;
     247           0 :         }
     248          27 :         if( !opt.type ) break;
     249          21 :         switch( opt.type ) {
     250           0 :         case FD_PCAPNG_OPT_COMMENT:
     251           0 :           FD_LOG_HEXDUMP_DEBUG(( "IDB comment", opt_buf, opt.sz ));
     252           0 :           break;
     253           6 :         case FD_PCAPNG_IDB_OPT_NAME:
     254           6 :           fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( iface->opts.name ), (char const *)opt_buf, fd_ulong_min( sizeof(iface->opts.name)-1, opt.sz ) ) );
     255           6 :           iface->opts.name[ sizeof(iface->opts.name)-1 ] = '\0';
     256           6 :           break;
     257           3 :         case FD_PCAPNG_IDB_OPT_HARDWARE:
     258           3 :           fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( iface->opts.hardware ), (char const *)opt_buf, fd_ulong_min( sizeof(iface->opts.hardware)-1, opt.sz ) ) );
     259           3 :           iface->opts.hardware[ sizeof(iface->opts.hardware)-1 ] = '\0';
     260           3 :           break;
     261           3 :         case FD_PCAPNG_IDB_OPT_IPV4_ADDR:
     262           3 :           if( FD_UNLIKELY( opt.sz!=4U ) )
     263           0 :             continue;
     264           3 :           memcpy( iface->opts.ip4_addr, opt_buf, 4UL );
     265           3 :           break;
     266           3 :         case FD_PCAPNG_IDB_OPT_MAC_ADDR:
     267           3 :           if( FD_UNLIKELY( opt.sz!=6U ) )
     268           0 :             continue;
     269           3 :           memcpy( iface->opts.mac_addr, opt_buf, 6UL );
     270           3 :           break;
     271           6 :         case FD_PCAPNG_IDB_OPT_TSRESOL:
     272           6 :           if( FD_UNLIKELY( opt.sz!=1U ) )
     273           0 :             continue;
     274           6 :           iface->opts.tsresol = opt_buf[ 0 ];
     275           6 :           break;
     276           0 :         default:
     277           0 :           FD_LOG_DEBUG(( "Ignoring unknown IDB option type %#x", opt.type ));
     278           0 :           break;
     279          21 :         }
     280          21 :       }
     281             : 
     282           6 :       break;
     283           6 :     }
     284           6 :     case FD_PCAPNG_BLOCK_TYPE_SPB: {
     285             :       /* Read SPB */
     286           0 :       if( FD_UNLIKELY( hdr.block_sz<sizeof(fd_pcapng_spb_t) ) ) {
     287           0 :         iter->error = EPROTO;
     288           0 :         FD_LOG_WARNING(( "pcapng: invalid SPB block size (%#x)", hdr.block_sz ));
     289           0 :         return NULL;
     290           0 :       }
     291             : 
     292           0 :       uint hdr_sz  = sizeof(fd_pcapng_spb_t);
     293           0 :       uint data_sz = hdr.block_sz - hdr_sz;
     294             : 
     295           0 :       fd_pcapng_spb_t spb = FD_LOAD( fd_pcapng_spb_t, iter->block_buf );
     296           0 :       iter->block_buf_pos = hdr_sz;
     297             : 
     298           0 :       if( FD_UNLIKELY( spb.orig_len > (iter->block_buf_sz - iter->block_buf_pos) ) ) {
     299           0 :         iter->error = EPROTO;
     300           0 :         FD_LOG_WARNING(( "pcapng: invalid SPB block size (%#x)", hdr.block_sz ));
     301           0 :         return NULL;
     302           0 :       }
     303           0 :       pkt->data = iter->block_buf + iter->block_buf_pos;
     304             : 
     305           0 :       pkt->type    = FD_PCAPNG_FRAME_SIMPLE;
     306           0 :       pkt->data_sz = (ushort)data_sz;
     307           0 :       pkt->orig_sz = (ushort)spb.orig_len;
     308           0 :       return pkt;
     309           0 :     }
     310          12 :     case FD_PCAPNG_BLOCK_TYPE_EPB: {
     311             :       /* Read EPB */
     312          12 :       if( FD_UNLIKELY( hdr.block_sz<sizeof(fd_pcapng_epb_t) ) ) {
     313           0 :         iter->error = EPROTO;
     314           0 :         FD_LOG_WARNING(( "pcapng: invalid EPB block size (%#x)", hdr.block_sz ));
     315           0 :         return NULL;
     316           0 :       }
     317             : 
     318          12 :       fd_pcapng_epb_t epb = FD_LOAD( fd_pcapng_epb_t, iter->block_buf );
     319          12 :       iter->block_buf_pos = sizeof(fd_pcapng_epb_t);
     320             : 
     321          12 :       if( FD_UNLIKELY( epb.cap_len > (iter->block_buf_sz - iter->block_buf_pos) ) ) {
     322           0 :         iter->error = EPROTO;
     323           0 :         FD_LOG_WARNING(( "pcapng: invalid EPB block size (%#x)", hdr.block_sz ));
     324           0 :         return NULL;
     325           0 :       }
     326          12 :       pkt->data = iter->block_buf + iter->block_buf_pos;
     327          12 :       iter->block_buf_pos += fd_uint_align_up( epb.cap_len, 4U );
     328             : 
     329             :       /* Read options */
     330          15 :       for( uint j=0; j<FD_PCAPNG_MAX_OPT_CNT; j++ ) {
     331          15 :         uchar opt_buf[ 128UL ] __attribute__((aligned(32UL)));
     332          15 :         fd_pcapng_option_t opt = { .sz=sizeof(opt_buf), .value=&opt_buf };
     333          15 :         if( FD_UNLIKELY( 0!=(iter->error = fd_pcapng_read_option( iter, &opt )) ) ) {
     334           0 :           FD_LOG_WARNING(( "pcapng: read failed (%s)", fd_pcapng_iter_strerror( iter->error, stream ) ));
     335           0 :           return NULL;
     336           0 :         }
     337          15 :         if( !opt.type ) break;
     338           3 :         switch( opt.type ) {
     339           0 :         case FD_PCAPNG_OPT_COMMENT:
     340           0 :           FD_LOG_HEXDUMP_DEBUG(( "Packet comment", opt_buf, opt.sz ));
     341           0 :           break;
     342           3 :         default:
     343           3 :           FD_LOG_DEBUG(( "Ignoring unknown EPB option type %#x", opt.type ));
     344           3 :           break;
     345           3 :         }
     346           3 :       }
     347             : 
     348          12 :       if( FD_LIKELY( epb.if_idx < iter->iface_cnt ) ) {
     349          12 :         ulong raw = ( ((ulong)epb.ts_hi << 32UL) | (ulong)epb.ts_lo );
     350             :         /* FIXME support more timestamp resolutions */
     351          12 :         if( iter->iface[ epb.if_idx ].opts.tsresol == FD_PCAPNG_TSRESOL_NS ) {
     352          12 :           pkt->ts = (long)raw;
     353          12 :         }
     354          12 :       }
     355             : 
     356          12 :       pkt->type    = FD_PCAPNG_FRAME_ENHANCED;
     357          12 :       pkt->data_sz = (ushort)epb.cap_len;
     358          12 :       pkt->orig_sz = (ushort)epb.orig_len;
     359          12 :       pkt->if_idx  = epb.if_idx;
     360          12 :       pkt->idb     = (epb.if_idx<iter->iface_cnt) ? &iter->iface[ epb.if_idx ] : NULL;
     361          12 :       return pkt;
     362          12 :     }
     363           3 :     case FD_PCAPNG_BLOCK_TYPE_DSB: {
     364             :       /* Read DSB */
     365           3 :       if( FD_UNLIKELY( hdr.block_sz<sizeof(fd_pcapng_dsb_t) ) ) {
     366           0 :         iter->error = EPROTO;
     367           0 :         FD_LOG_WARNING(( "pcapng: invalid DSB block size (%#x)", hdr.block_sz ));
     368           0 :         return NULL;
     369           0 :       }
     370             : 
     371           3 :       fd_pcapng_dsb_t dsb = FD_LOAD( fd_pcapng_dsb_t, iter->block_buf );
     372           3 :       iter->block_buf_pos = sizeof(fd_pcapng_dsb_t);
     373             : 
     374           3 :       if( FD_UNLIKELY( dsb.secret_sz > (iter->block_buf_sz - iter->block_buf_pos) ) ) {
     375           0 :         iter->error = EPROTO;
     376           0 :         FD_LOG_WARNING(( "pcapng: invalid DSB block size (%#x)", hdr.block_sz ));
     377           0 :         return NULL;
     378           0 :       }
     379           3 :       pkt->data = iter->block_buf + sizeof(fd_pcapng_dsb_t);
     380           3 :       iter->block_buf_pos += fd_uint_align_up( dsb.secret_sz, 4U );
     381             : 
     382             :       /* Read options */
     383           3 :       for( uint j=0; j<FD_PCAPNG_MAX_OPT_CNT; j++ ) {
     384           3 :         uchar opt_buf[ 128UL ] __attribute__((aligned(32UL)));
     385           3 :         fd_pcapng_option_t opt = { .sz=sizeof(opt_buf), .value=&opt_buf };
     386           3 :         if( FD_UNLIKELY( 0!=(iter->error = fd_pcapng_read_option( iter, &opt )) ) ) {
     387           0 :           FD_LOG_WARNING(( "pcapng: read failed (%s)", fd_pcapng_iter_strerror( iter->error, stream ) ));
     388           0 :           return NULL;
     389           0 :         }
     390           3 :         if( !opt.type ) break;
     391           0 :         switch( opt.type ) {
     392           0 :         case FD_PCAPNG_OPT_COMMENT:
     393           0 :           FD_LOG_HEXDUMP_DEBUG(( "Decryption secrets comment", opt_buf, opt.sz ));
     394           0 :           break;
     395           0 :         default:
     396           0 :           FD_LOG_DEBUG(( "Ignoring unknown DSB option type %#x", opt.type ));
     397           0 :           break;
     398           0 :         }
     399           0 :       }
     400             : 
     401           3 :       if( dsb.secret_type!=FD_PCAPNG_SECRET_TYPE_TLS ) {
     402           0 :         FD_LOG_DEBUG(( "Ignoring secret (type %#x)", dsb.secret_type ));
     403           0 :         break;
     404           0 :       }
     405             : 
     406           3 :       pkt->type    = FD_PCAPNG_FRAME_TLSKEYS;
     407           3 :       pkt->data_sz = dsb.secret_sz;
     408           3 :       return pkt;
     409           3 :     }
     410           0 :     default:
     411           0 :       FD_LOG_DEBUG(( "pcapng: skipping unknown block (type=%#x)", hdr.block_type ));
     412           0 :       break;
     413          21 :     }
     414          21 :   }
     415             : 
     416             :   /* Found no blocks that are interesting to user */
     417           0 :   iter->error = EPROTO;
     418           0 :   FD_LOG_WARNING(( "pcapng: aborting, too many non-packet frames" ));
     419           0 :   return NULL;
     420          21 : }
     421             : 
     422             : fd_pcapng_frame_t *
     423          21 : fd_pcapng_iter_next( fd_pcapng_iter_t * iter ) {
     424          21 :   fd_pcapng_frame_t * frame = fd_pcapng_iter_next1( iter );
     425          21 :   iter->empty = !frame;
     426          21 :   return frame;
     427          21 : }
     428             : 
     429             : fd_pcapng_frame_t *
     430           0 : fd_pcapng_iter_ele( fd_pcapng_iter_t * iter ) {
     431           0 :   if( FD_UNLIKELY( iter->empty ) ) return NULL;
     432           0 :   return &iter->pkt;
     433           0 : }
     434             : 
     435             : FD_FN_PURE int
     436           9 : fd_pcapng_iter_err( fd_pcapng_iter_t const * iter ) {
     437           9 :   return iter->error;
     438           9 : }

Generated by: LCOV version 1.14