1 /*
2 ** Copyright (C) 2001-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  rwipv6routingio.c
11 **
12 **    Routines to pack/unpack FT_RWIPV6ROUTING records.
13 */
14 
15 #include <silk/silk.h>
16 
17 RCSIDENT("$SiLK: rwipv6routingio.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
18 
19 #include "skstream_priv.h"
20 
21 
22 /* Version to use when SK_RECORD_VERSION_ANY is specified */
23 #define DEFAULT_RECORD_VERSION 1
24 
25 
26 /* LOCAL FUNCTION PROTOTYPES */
27 
28 static int
29 ipv6routingioRecordUnpack_V1(
30     skstream_t         *stream,
31     rwGenericRec_V5    *rwrec,
32     uint8_t            *ar);
33 
34 
35 static const uint8_t IP4in6_prefix[12] =
36     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF};
37 
38 
39 /* ********************************************************************* */
40 
41 /*
42 **  RWIPV6ROUTING VERSION 3
43 **
44 **    int64_t       sTime;       //  0- 7  Flow start time as milliseconds
45 **                               //        since UNIX epoch
46 **
47 **    uint32_t      elapsed;     //  8-11  Duration of flow in milliseconds
48 **                               //        (Allows for a 49 day flow)
49 **
50 **    uint16_t      sPort;       // 12-13  Source port
51 **    uint16_t      dPort;       // 14-15  Destination port
52 **
53 **    uint8_t       proto;       // 16     IP protocol
54 **    uint8_t       flow_type;   // 17     Class & Type info
55 **    uint16_t      sID;         // 18-19  Sensor ID
56 **
57 **    uint8_t       flags;       // 20     OR of all flags (Netflow flags)
58 **    uint8_t       init_flags;  // 21     TCP flags in first packet
59 **                               //        or blank for "legacy" data
60 **    uint8_t       rest_flags;  // 22     TCP flags on non-initial packet
61 **                               //        or blank for "legacy" data
62 **    uint8_t       tcp_state;   // 23     TCP state machine info (below)
63 **
64 **    uint16_t      application; // 24-25  Indication of type of traffic
65 **    uint16_t      memo;        // 26-27  Application specific field
66 **
67 **    uint32_t      input;       // 28-31  Router incoming SNMP interface
68 **
69 **    uint64_t      pkts;        // 32-39  Count of packets
70 **
71 **    uint64_t      bytes;       // 40-47  Count of bytes
72 **
73 **    uint8_t[16]   sIP;         // 48-63  (IPv4 in 60-63) Source IP
74 **    uint8_t[16]   dIP;         // 64-79  (IPv4 in 76-79) Destination IP
75 **    uint8_t[16]   nhIP;        // 80-95  (IPv4 in 92-95) Router Next Hop IP
76 **
77 **    uint32_t      output;      // 96-99  Router outgoing SNMP interface
78 **
79 **
80 **  100 bytes on disk.
81 */
82 
83 #define RECLEN_RWIPV6ROUTING_V3 100
84 
85 
86 /*
87  *    Byte swap the RWIPV6ROUTING v1 record 'ar' in place.
88  */
89 #define ipv6routingioRecordSwap_V3(ar)                                  \
90     {                                                                   \
91         SWAP_DATA64((ar) +  0);   /* sTime */                           \
92         SWAP_DATA32((ar) +  8);   /* elapsed */                         \
93         SWAP_DATA16((ar) + 12);   /* sPort */                           \
94         SWAP_DATA16((ar) + 14);   /* dPort */                           \
95         /* Two single bytes: (16)proto, (17)flow_type */                \
96         SWAP_DATA16((ar) + 18);   /* sID */                             \
97         /* Four single bytes: (20)flags, (21)init_flags,                \
98          *                    (22)rest_flags, (23)tcp_state */          \
99         SWAP_DATA16((ar) + 24);   /* application */                     \
100         SWAP_DATA16((ar) + 26);   /* memo */                            \
101         SWAP_DATA32((ar) + 28);   /* input */                           \
102         SWAP_DATA64((ar) + 32);   /* pkts */                            \
103         SWAP_DATA64((ar) + 40);   /* bytes */                           \
104         /* 48 bytes of sIP, dIP, nhIP always in network byte order */   \
105         SWAP_DATA32((ar) + 96);   /* output */                          \
106     }
107 
108 
109 /*
110  *  Unpack the array of bytes 'ar' into a record 'rwrec'
111  */
112 static int
ipv6routingioRecordUnpack_V3(skstream_t * stream,rwRec * rwrec,uint8_t * ar)113 ipv6routingioRecordUnpack_V3(
114     skstream_t         *stream,
115     rwRec              *rwrec,
116     uint8_t            *ar)
117 {
118     uint32_t u32;
119     uint64_t u64;
120 
121 #if !SK_ENABLE_IPV6
122     if (ar[23] & 0x80) {
123         /* Record is IPv6 */
124         return SKSTREAM_ERR_UNSUPPORT_IPV6;
125     }
126 #endif
127 
128     /* swap if required */
129     if (stream->swapFlag) {
130         ipv6routingioRecordSwap_V3(ar);
131     }
132 
133     rwRecMemSetStartTime(rwrec, &ar[0]);
134     rwRecMemSetElapsed(rwrec, &ar[8]);
135     rwRecMemSetSPort(rwrec, &ar[12]);
136     rwRecMemSetDPort(rwrec, &ar[14]);
137     rwRecMemSetProto(rwrec, &ar[16]);
138     rwRecMemSetFlowType(rwrec, &ar[17]);
139     rwRecMemSetSensor(rwrec, &ar[18]);
140     rwRecMemSetFlags(rwrec, &ar[20]);
141     rwRecMemSetInitFlags(rwrec, &ar[21]);
142     rwRecMemSetRestFlags(rwrec, &ar[22]);
143     rwRecMemSetTcpState(rwrec, &ar[23]);
144     rwRecMemSetApplication(rwrec, &ar[24]);
145     rwRecMemSetMemo(rwrec, &ar[26]);
146 
147     /* Input; set to UINT16_MAX if too large */
148     memcpy(&u32, &ar[28], sizeof(u32));
149     if (u32 > UINT16_MAX) {
150         rwRecSetInput(rwrec, UINT16_MAX);
151     } else {
152         rwRecSetInput(rwrec, (uint16_t)u32);
153     }
154 
155     /* Packets; set to UINT32_MAX if too large */
156     memcpy(&u64, &ar[32], sizeof(u64));
157     if (u64 > UINT32_MAX) {
158         rwRecSetPkts(rwrec, UINT32_MAX);
159     } else {
160         rwRecSetPkts(rwrec, (uint32_t)u64);
161     }
162 
163     /* Bytes; set to UINT32_MAX if too large */
164     memcpy(&u64, &ar[40], sizeof(u64));
165     if (u64 > UINT32_MAX) {
166         rwRecSetBytes(rwrec, UINT32_MAX);
167     } else {
168         rwRecSetBytes(rwrec, (uint32_t)u64);
169     }
170 
171     /* Output; set to UINT16_MAX if too large */
172     memcpy(&u32, &ar[96], sizeof(u32));
173     if (u32 > UINT16_MAX) {
174         rwRecSetOutput(rwrec, UINT16_MAX);
175     } else {
176         rwRecSetOutput(rwrec, (uint16_t)u32);
177     }
178 
179 #if SK_ENABLE_IPV6
180     if (ar[23] & 0x80) {
181         /* Record is IPv6 */
182         rwRecSetIPv6(rwrec);
183         rwRecMemSetSIPv6(rwrec, &ar[48]);
184         rwRecMemSetDIPv6(rwrec, &ar[64]);
185         rwRecMemSetNhIPv6(rwrec, &ar[80]);
186     } else
187 #endif  /* SK_ENABLE_IPV6 */
188     {
189         /* Record is IPv4, but data encoded as IPv6 */
190         uint32_t ip;
191 
192         /* sIP */
193         memcpy(&ip, &ar[60], sizeof(ip));
194         rwRecSetSIPv4(rwrec, ntohl(ip));
195 
196         /* dIP */
197         memcpy(&ip, &ar[76], sizeof(ip));
198         rwRecSetDIPv4(rwrec, ntohl(ip));
199 
200         /* nhIP */
201         memcpy(&ip, &ar[92], sizeof(ip));
202         rwRecSetNhIPv4(rwrec, ntohl(ip));
203     }
204 
205     /*
206      * No need for this; file format is post SiLK-3.6.0
207      * RWREC_MAYBE_CLEAR_TCPSTATE_EXPANDED(rwrec);
208      */
209 
210     return SKSTREAM_OK;
211 }
212 
213 
214 /*
215  *  Pack the record 'rwrec' into an array of bytes 'ar'
216  */
217 static int
ipv6routingioRecordPack_V3(skstream_t * stream,const rwRec * rwrec,uint8_t * ar)218 ipv6routingioRecordPack_V3(
219     skstream_t         *stream,
220     const rwRec        *rwrec,
221     uint8_t            *ar)
222 {
223     uint32_t u32;
224     uint64_t u64;
225 
226     rwRecMemGetStartTime(rwrec, &ar[0]);
227     rwRecMemGetElapsed(rwrec, &ar[8]);
228     rwRecMemGetSPort(rwrec, &ar[12]);
229     rwRecMemGetDPort(rwrec, &ar[14]);
230     rwRecMemGetProto(rwrec, &ar[16]);
231     rwRecMemGetFlowType(rwrec, &ar[17]);
232     rwRecMemGetSensor(rwrec, &ar[18]);
233     rwRecMemGetFlags(rwrec, &ar[20]);
234     rwRecMemGetInitFlags(rwrec, &ar[21]);
235     rwRecMemGetRestFlags(rwrec, &ar[22]);
236     rwRecMemGetTcpState(rwrec, &ar[23]);
237     rwRecMemGetApplication(rwrec, &ar[24]);
238     rwRecMemGetMemo(rwrec, &ar[26]);
239 
240     u32 = rwRecGetInput(rwrec);
241     memcpy(&ar[28], &u32, sizeof(u32));
242 
243     u64 = rwRecGetPkts(rwrec);
244     memcpy(&ar[32], &u64, sizeof(u64));
245 
246     u64 = rwRecGetBytes(rwrec);
247     memcpy(&ar[40], &u64, sizeof(u64));
248 
249     u32 = rwRecGetOutput(rwrec);
250     memcpy(&ar[96], &u32, sizeof(u32));
251 
252     if (rwRecIsIPv6(rwrec)) {
253         /* Record is IPv6 */
254 #if !SK_ENABLE_IPV6
255         return SKSTREAM_ERR_UNSUPPORT_IPV6;
256 #else
257         ar[23] |= 0x80;
258         rwRecMemGetSIPv6(rwrec, &ar[48]);
259         rwRecMemGetDIPv6(rwrec, &ar[64]);
260         rwRecMemGetNhIPv6(rwrec, &ar[80]);
261 #endif  /* SK_ENABLE_IPV6 */
262     } else {
263         /* Record is IPv4, but encode as IPv6 */
264         uint32_t ip;
265 
266         /* sIP */
267         ip = htonl(rwRecGetSIPv4(rwrec));
268         memcpy(&ar[48], IP4in6_prefix, sizeof(IP4in6_prefix));
269         memcpy(&ar[60], &ip, sizeof(ip));
270 
271         /* dIP */
272         ip = htonl(rwRecGetDIPv4(rwrec));
273         memcpy(&ar[64], IP4in6_prefix, sizeof(IP4in6_prefix));
274         memcpy(&ar[76], &ip, sizeof(ip));
275 
276         /* nhIP */
277         ip = htonl(rwRecGetNhIPv4(rwrec));
278         memcpy(&ar[80], IP4in6_prefix, sizeof(IP4in6_prefix));
279         memcpy(&ar[92], &ip, sizeof(ip));
280     }
281 
282     /* swap if required */
283     if (stream->swapFlag) {
284         ipv6routingioRecordSwap_V3(ar);
285     }
286 
287     return SKSTREAM_OK;
288 }
289 
290 
291 /* ********************************************************************* */
292 
293 /*
294 **  RWIPV6ROUTING VERSION 2
295 **
296 **    FT_RWIPV6ROUTING version 2 is identical to V1, expect must clear
297 **    the application field when unpacking.  Packing functions for V1
298 **    and V2 are identical.
299 */
300 
301 static int
ipv6routingioRecordUnpack_V2(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)302 ipv6routingioRecordUnpack_V2(
303     skstream_t         *stream,
304     rwGenericRec_V5    *rwrec,
305     uint8_t            *ar)
306 {
307     int rv;
308 
309     rv = ipv6routingioRecordUnpack_V1(stream, rwrec, ar);
310     rwRecSetApplication(rwrec, 0);
311     return rv;
312 }
313 
314 
315 /* ********************************************************************* */
316 
317 /*
318 **  RWIPV6ROUTING VERSION 1
319 **
320 **    int64_t       sTime;       //  0- 7  Flow start time as milliseconds
321 **                               //        since UNIX epoch
322 **
323 **    uint32_t      elapsed;     //  8-11  Duration of flow in milliseconds
324 **                               //        (Allows for a 49 day flow)
325 **
326 **    uint16_t      sPort;       // 12-13  Source port
327 **    uint16_t      dPort;       // 14-15  Destination port
328 **
329 **    uint8_t       proto;       // 16     IP protocol
330 **    uint8_t       flow_type;   // 17     Class & Type info
331 **    uint16_t      sID;         // 18-19  Sensor ID
332 **
333 **    uint8_t       flags;       // 20     OR of all flags (Netflow flags)
334 **    uint8_t       init_flags;  // 21     TCP flags in first packet
335 **                               //        or blank for "legacy" data
336 **    uint8_t       rest_flags;  // 22     TCP flags on non-initial packet
337 **                               //        or blank for "legacy" data
338 **    uint8_t       tcp_state;   // 23     TCP state machine info (below)
339 **
340 **    uint16_t      application; // 24-25  Indication of type of traffic
341 **    uint16_t      memo;        // 26-27  Application specific field
342 **
343 **    uint16_t      input;       // 28-29  Router incoming SNMP interface
344 **    uint16_t      output;      // 30-31  Router outgoing SNMP interface
345 **
346 **    uint32_t      pkts;        // 32-35  Count of packets
347 **    uint32_t      bytes;       // 36-39  Count of bytes
348 **
349 **    uint8_t[16]   sIP;         // 40-55  Source IP
350 **    uint8_t[16]   dIP;         // 56-71  Destination IP
351 **    uint8_t[16]   nhIP;        // 72-87  Router Next Hop IP
352 **
353 **
354 **  88 bytes on disk.
355 */
356 
357 #define RECLEN_RWIPV6ROUTING_V1 88
358 
359 
360 /*
361  *    Byte swap the RWIPV6ROUTING v1 record 'ar' in place.
362  */
363 #define ipv6routingioRecordSwap_V1(ar)                                  \
364     {                                                                   \
365         SWAP_DATA64((ar) +  0);   /* sTime */                           \
366         SWAP_DATA32((ar) +  8);   /* elapsed */                         \
367         SWAP_DATA16((ar) + 12);   /* sPort */                           \
368         SWAP_DATA16((ar) + 14);   /* dPort */                           \
369         /* Two single bytes: (16)proto, (17)flow_type */                \
370         SWAP_DATA16((ar) + 18);   /* sID */                             \
371         /* Four single bytes: (20)flags, (21)init_flags,                \
372          *                    (22)rest_flags, (23)tcp_state */          \
373         SWAP_DATA16((ar) + 24);   /* application */                     \
374         SWAP_DATA16((ar) + 26);   /* memo */                            \
375         SWAP_DATA16((ar) + 28);   /* input */                           \
376         SWAP_DATA16((ar) + 30);   /* output */                          \
377         SWAP_DATA32((ar) + 32);   /* pkts */                            \
378         SWAP_DATA32((ar) + 36);   /* bytes */                           \
379         /* 48 bytes of sIP, dIP, nhIP always in network byte order */   \
380     }
381 
382 
383 /*
384  *  Unpack the array of bytes 'ar' into a record 'rwrec'
385  */
386 static int
ipv6routingioRecordUnpack_V1(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)387 ipv6routingioRecordUnpack_V1(
388     skstream_t         *stream,
389     rwGenericRec_V5    *rwrec,
390     uint8_t            *ar)
391 {
392     uint32_t ip;
393 
394     /* swap if required */
395     if (stream->swapFlag) {
396         ipv6routingioRecordSwap_V1(ar);
397     }
398 
399     rwRecMemSetStartTime(rwrec, &ar[0]);
400     rwRecMemSetElapsed(rwrec, &ar[8]);
401     rwRecMemSetSPort(rwrec, &ar[12]);
402     rwRecMemSetDPort(rwrec, &ar[14]);
403     rwRecMemSetProto(rwrec, &ar[16]);
404     rwRecMemSetFlowType(rwrec, &ar[17]);
405     rwRecMemSetSensor(rwrec, &ar[18]);
406     rwRecMemSetFlags(rwrec, &ar[20]);
407     rwRecMemSetInitFlags(rwrec, &ar[21]);
408     rwRecMemSetRestFlags(rwrec, &ar[22]);
409     rwRecMemSetTcpState(rwrec, &ar[23]);
410     rwRecMemSetApplication(rwrec, &ar[24]);
411     rwRecMemSetMemo(rwrec, &ar[26]);
412     rwRecMemSetInput(rwrec, &ar[28]);
413     rwRecMemSetOutput(rwrec, &ar[30]);
414     rwRecMemSetPkts(rwrec, &ar[32]);
415     rwRecMemSetBytes(rwrec, &ar[36]);
416 
417     if (ar[23] & 0x80) {
418         /* Record is IPv6 */
419 #if !SK_ENABLE_IPV6
420         return SKSTREAM_ERR_UNSUPPORT_IPV6;
421 #else
422         rwRecSetIPv6(rwrec);
423         rwRecMemSetSIPv6(rwrec, &ar[40]);
424         rwRecMemSetDIPv6(rwrec, &ar[56]);
425         rwRecMemSetNhIPv6(rwrec, &ar[72]);
426 #endif /* SK_ENABLE_IPV6 */
427     } else {
428         /* Record is IPv4 */
429 
430         /* sIP */
431         memcpy(&ip, &ar[52], sizeof(ip));
432         rwRecSetSIPv4(rwrec, ntohl(ip));
433 
434         /* dIP */
435         memcpy(&ip, &ar[68], sizeof(ip));
436         rwRecSetDIPv4(rwrec, ntohl(ip));
437 
438         /* nhIP */
439         memcpy(&ip, &ar[84], sizeof(ip));
440         rwRecSetNhIPv4(rwrec, ntohl(ip));
441     }
442 
443     RWREC_MAYBE_CLEAR_TCPSTATE_EXPANDED(rwrec);
444 
445     return SKSTREAM_OK;
446 }
447 
448 
449 /*
450  *  Pack the record 'rwrec' into an array of bytes 'ar'
451  */
452 static int
ipv6routingioRecordPack_V1(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)453 ipv6routingioRecordPack_V1(
454     skstream_t             *stream,
455     const rwGenericRec_V5  *rwrec,
456     uint8_t                *ar)
457 {
458     uint32_t ip;
459 
460     rwRecMemGetStartTime(rwrec, &ar[0]);
461     rwRecMemGetElapsed(rwrec, &ar[8]);
462     rwRecMemGetSPort(rwrec, &ar[12]);
463     rwRecMemGetDPort(rwrec, &ar[14]);
464     rwRecMemGetProto(rwrec, &ar[16]);
465     rwRecMemGetFlowType(rwrec, &ar[17]);
466     rwRecMemGetSensor(rwrec, &ar[18]);
467     rwRecMemGetFlags(rwrec, &ar[20]);
468     rwRecMemGetInitFlags(rwrec, &ar[21]);
469     rwRecMemGetRestFlags(rwrec, &ar[22]);
470     rwRecMemGetTcpState(rwrec, &ar[23]);
471     rwRecMemGetApplication(rwrec, &ar[24]);
472     rwRecMemGetMemo(rwrec, &ar[26]);
473     rwRecMemGetInput(rwrec, &ar[28]);
474     rwRecMemGetOutput(rwrec, &ar[30]);
475     rwRecMemGetPkts(rwrec, &ar[32]);
476     rwRecMemGetBytes(rwrec, &ar[36]);
477 
478     if (rwRecIsIPv6(rwrec)) {
479         /* Record is IPv6 */
480 #if !SK_ENABLE_IPV6
481         return SKSTREAM_ERR_UNSUPPORT_IPV6;
482 #else
483         ar[23] |= 0x80;
484         rwRecMemGetSIPv6(rwrec, &ar[40]);
485         rwRecMemGetDIPv6(rwrec, &ar[56]);
486         rwRecMemGetNhIPv6(rwrec, &ar[72]);
487 #endif /* SK_ENABLE_IPV6 */
488     } else {
489         /* Record is IPv4, but encode as IPv6 */
490 
491         /* sIP */
492         ip = htonl(rwRecGetSIPv4(rwrec));
493         memcpy(&ar[40], IP4in6_prefix, sizeof(IP4in6_prefix));
494         memcpy(&ar[52], &ip, sizeof(ip));
495 
496         /* dIP */
497         ip = htonl(rwRecGetDIPv4(rwrec));
498         memcpy(&ar[56], IP4in6_prefix, sizeof(IP4in6_prefix));
499         memcpy(&ar[68], &ip, sizeof(ip));
500 
501         /* nhIP */
502         ip = htonl(rwRecGetNhIPv4(rwrec));
503         memcpy(&ar[72], IP4in6_prefix, sizeof(IP4in6_prefix));
504         memcpy(&ar[84], &ip, sizeof(ip));
505     }
506 
507     /* swap if required */
508     if (stream->swapFlag) {
509         ipv6routingioRecordSwap_V1(ar);
510     }
511 
512     return SKSTREAM_OK;
513 }
514 
515 
516 /* ********************************************************************* */
517 
518 /*
519  *  Return length of record of specified version, or 0 if no such
520  *  version exists.  See skstream_priv.h for details.
521  */
522 uint16_t
ipv6routingioGetRecLen(sk_file_version_t vers)523 ipv6routingioGetRecLen(
524     sk_file_version_t   vers)
525 {
526     switch (vers) {
527       case 1:
528       case 2:
529         return RECLEN_RWIPV6ROUTING_V1;
530       case 3:
531         return RECLEN_RWIPV6ROUTING_V3;
532       default:
533         return 0;
534     }
535 }
536 
537 
538 /*
539  *  status = ipv6routingioPrepare(stream);
540  *
541  *    Sets the record version to the default if it is unspecified,
542  *    checks that the record format supports the requested record
543  *    version, sets the record length, and sets the pack and unpack
544  *    functions for this record format and version.
545  */
546 int
ipv6routingioPrepare(skstream_t * stream)547 ipv6routingioPrepare(
548     skstream_t         *stream)
549 {
550 #define FILE_FORMAT "FT_RWIPV6ROUTING"
551     sk_file_header_t *hdr = stream->silk_hdr;
552     int rv = SKSTREAM_OK; /* return value */
553 
554     /* Set version if none was selected by caller */
555     if ((stream->io_mode == SK_IO_WRITE)
556         && (skHeaderGetRecordVersion(hdr) == SK_RECORD_VERSION_ANY))
557     {
558         skHeaderSetRecordVersion(hdr, DEFAULT_RECORD_VERSION);
559     }
560 
561     /* version check; set values based on version */
562     switch (skHeaderGetRecordVersion(hdr)) {
563       case 3:
564         stream->rwUnpackFn = &ipv6routingioRecordUnpack_V3;
565         stream->rwPackFn   = &ipv6routingioRecordPack_V3;
566         break;
567       case 2:
568         stream->rwUnpackFn = &ipv6routingioRecordUnpack_V2;
569         stream->rwPackFn   = &ipv6routingioRecordPack_V1;
570         break;
571       case 1:
572         stream->rwUnpackFn = &ipv6routingioRecordUnpack_V1;
573         stream->rwPackFn   = &ipv6routingioRecordPack_V1;
574         break;
575       case 0:
576       default:
577         rv = SKSTREAM_ERR_UNSUPPORT_VERSION;
578         goto END;
579     }
580 
581     stream->recLen = ipv6routingioGetRecLen(skHeaderGetRecordVersion(hdr));
582 
583     /* verify lengths */
584     if (stream->recLen == 0) {
585         skAppPrintErr("Record length not set for %s version %u",
586                       FILE_FORMAT, (unsigned)skHeaderGetRecordVersion(hdr));
587         skAbort();
588     }
589     if (stream->recLen != skHeaderGetRecordLength(hdr)) {
590         if (0 == skHeaderGetRecordLength(hdr)) {
591             skHeaderSetRecordLength(hdr, stream->recLen);
592         } else {
593             skAppPrintErr(("Record length mismatch for %s version %u\n"
594                            "\tcode = %" PRIu16 " bytes;  header = %lu bytes"),
595                           FILE_FORMAT, (unsigned)skHeaderGetRecordVersion(hdr),
596                           stream->recLen,
597                           (unsigned long)skHeaderGetRecordLength(hdr));
598             skAbort();
599         }
600     }
601 
602   END:
603     return rv;
604 }
605 
606 
607 /*
608 ** Local Variables:
609 ** mode:c
610 ** indent-tabs-mode:nil
611 ** c-basic-offset:4
612 ** End:
613 */
614