1 /*
2 ** Copyright (C) 2005-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 ** rwaugroutingio.c
11 **
12 **      routines to do io stuff with augrouting records.
13 */
14 
15 #include <silk/silk.h>
16 
17 RCSIDENT("$SiLK: rwaugroutingio.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
18 
19 /* #define RWPACK_BYTES_PACKETS          1 */
20 #define RWPACK_FLAGS_TIMES_VOLUMES    1
21 #define RWPACK_PROTO_FLAGS            1
22 /* #define RWPACK_SBB_PEF                1 */
23 #define RWPACK_TIME_BYTES_PKTS_FLAGS  1
24 #define RWPACK_TIMES_FLAGS_PROTO      1
25 #include "skstream_priv.h"
26 #include "rwpack.c"
27 
28 
29 /* Version to use when SK_RECORD_VERSION_ANY is specified */
30 #define DEFAULT_RECORD_VERSION 4
31 
32 
33 /* ********************************************************************* */
34 
35 /*
36 **  RWAUGROUTING VERSION 5
37 **
38 **  in the following: EXPANDED == ((tcp_state & SK_TCPSTATE_EXPANDED) ? 1 : 0)
39 **
40 **    uint32_t      rflag_stime;     //  0- 3
41 **    // uint32_t     rest_flags: 8; //        is_tcp==0: Empty; else
42 **                                   //          EXPANDED==0:Empty
43 **                                   //          EXPANDED==1:TCPflags/!1st pkt
44 **    // uint32_t     is_tcp    : 1; //        1 if FLOW is TCP; 0 otherwise
45 **    // uint32_t     unused    : 1; //        Reserved
46 **    // uint32_t     stime     :22; //        Start time:msec offset from hour
47 **
48 **    uint8_t       proto_iflags;    //  4     is_tcp==0: Protocol; else:
49 **                                   //          EXPANDED==0:TCPflags/ALL pkts
50 **                                   //          EXPANDED==1:TCPflags/1st pkt
51 **    uint8_t       tcp_state;       //  5     TCP state machine info
52 **    uint16_t      application;     //  6- 7  Indication of type of traffic
53 **
54 **    uint16_t      sPort;           //  8- 9  Source port
55 **    uint16_t      dPort;           // 10-11  Destination port
56 **
57 **    uint32_t      elapsed;         // 12-15  Duration of the flow
58 **
59 **    uint32_t      pkts;            // 16-19  Count of packets
60 **    uint32_t      bytes;           // 20-23  Count of bytes
61 **
62 **    uint32_t      sIP;             // 24-27  Source IP
63 **    uint32_t      dIP;             // 28-31  Destination IP
64 **
65 **    uint32_t      nhIP;            // 32-35  Router Next Hop IP
66 **
67 **    uint16_t      input;           // 36-37  Router incoming SNMP interface
68 **    uint16_t      output;          // 38-39  Router outgoing SNMP interface
69 **
70 **
71 **  40 bytes on disk.
72 */
73 
74 #define RECLEN_RWAUGROUTING_V5 40
75 
76 
77 /*
78  *    Byte swap the RWAUGROUTING v5 record 'ar' in place.
79  */
80 #define augroutingioRecordSwap_V5(ar)                           \
81     {                                                           \
82         SWAP_DATA32((ar) +  0);   /* rflag_stime */             \
83         /* two single bytes (4)proto_iflags, (5)tcp_state */    \
84         SWAP_DATA16((ar) +  6);   /* application */             \
85         SWAP_DATA16((ar) +  8);   /* sPort */                   \
86         SWAP_DATA16((ar) + 10);   /* dPort */                   \
87         SWAP_DATA32((ar) + 12);   /* elapsed */                 \
88         SWAP_DATA32((ar) + 16);   /* pkts */                    \
89         SWAP_DATA32((ar) + 20);   /* bytes */                   \
90         SWAP_DATA32((ar) + 24);   /* sIP */                     \
91         SWAP_DATA32((ar) + 28);   /* dIP */                     \
92         SWAP_DATA32((ar) + 32);   /* nhIP */                    \
93         SWAP_DATA16((ar) + 36);   /* input */                   \
94         SWAP_DATA16((ar) + 38);   /* output */                  \
95     }
96 
97 
98 /*
99  *  Unpack the array of bytes 'ar' into a record 'rwrec'
100  */
101 static int
augroutingioRecordUnpack_V5(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)102 augroutingioRecordUnpack_V5(
103     skstream_t         *stream,
104     rwGenericRec_V5    *rwrec,
105     uint8_t            *ar)
106 {
107     /* swap if required */
108     if (stream->swapFlag) {
109         augroutingioRecordSwap_V5(ar);
110     }
111 
112     /* Start time, TCP flags, Protocol, TCP State */
113     rwpackUnpackTimesFlagsProto(rwrec, ar, stream->hdr_starttime);
114 
115     /* application */
116     rwRecMemSetApplication(rwrec, &ar[ 6]);
117 
118     /* sPort, dPort */
119     rwRecMemSetSPort(rwrec, &ar[ 8]);
120     rwRecMemSetDPort(rwrec, &ar[10]);
121 
122     /* Elapsed */
123     rwRecMemSetElapsed(rwrec, &ar[12]);
124 
125     /* packets, bytes */
126     rwRecMemSetPkts(rwrec,  &ar[16]);
127     rwRecMemSetBytes(rwrec, &ar[20]);
128 
129     /* sIP, dIP */
130     rwRecMemSetSIPv4(rwrec, &ar[24]);
131     rwRecMemSetDIPv4(rwrec, &ar[28]);
132 
133     /* nhIP */
134     rwRecMemSetNhIPv4(rwrec, &ar[32]);
135 
136     /* input, output */
137     rwRecMemSetInput(rwrec,  &ar[36]);
138     rwRecMemSetOutput(rwrec, &ar[38]);
139 
140     /* sensor, flow_type from file name/header */
141     rwRecSetSensor(rwrec, stream->hdr_sensor);
142     rwRecSetFlowType(rwrec, stream->hdr_flowtype);
143 
144     return SKSTREAM_OK;
145 }
146 
147 
148 /*
149  *  Pack the record 'rwrec' into an array of bytes 'ar'
150  */
151 static int
augroutingioRecordPack_V5(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)152 augroutingioRecordPack_V5(
153     skstream_t             *stream,
154     const rwGenericRec_V5  *rwrec,
155     uint8_t                *ar)
156 {
157     int rv;
158 
159     /* Start time, TCP Flags, Protocol, TCP State */
160     rv = rwpackPackTimesFlagsProto(rwrec, ar, stream->hdr_starttime);
161     if (rv) {
162         return rv;
163     }
164 
165     /* application */
166     rwRecMemGetApplication(rwrec, &ar[6]);
167 
168     /* sPort, dPort */
169     rwRecMemGetSPort(rwrec, &ar[ 8]);
170     rwRecMemGetDPort(rwrec, &ar[10]);
171 
172     /* Elapsed */
173     rwRecMemGetElapsed(rwrec, &ar[12]);
174 
175     /* packets, bytes */
176     rwRecMemGetPkts(rwrec,  &ar[16]);
177     rwRecMemGetBytes(rwrec, &ar[20]);
178 
179     /* sIP, dIP */
180     rwRecMemGetSIPv4(rwrec, &ar[24]);
181     rwRecMemGetDIPv4(rwrec, &ar[28]);
182 
183     /* nhIP */
184     rwRecMemGetNhIPv4(rwrec, &ar[32]);
185 
186     /* input, output */
187     rwRecMemGetInput(rwrec,  &ar[36]);
188     rwRecMemGetOutput(rwrec, &ar[38]);
189 
190     /* swap if required */
191     if (stream->swapFlag) {
192         augroutingioRecordSwap_V5(ar);
193     }
194 
195     return SKSTREAM_OK;
196 }
197 
198 
199 /* ********************************************************************* */
200 
201 /*
202 **  RWAUGROUTING VERSION 4
203 **
204 **  in the following: EXPANDED == ((tcp_state & SK_TCPSTATE_EXPANDED) ? 1 : 0)
205 **
206 **    uint32_t      stime_bb1;       //  0- 3
207 **    // uint32_t     stime     :22  //        Start time:msec offset from hour
208 **    // uint32_t     bPPkt1    :10; //        Whole bytes-per-packet (hi 10)
209 **
210 **    uint32_t      bb2_elapsed;     //  4- 7
211 **    // uint32_t     bPPkt2    : 4; //        Whole bytes-per-packet (low 4)
212 **    // uint32_t     bPPFrac   : 6; //        Fractional bytes-per-packet
213 **    // uint32_t     elapsed   :22; //        Duration of flow in msec
214 **
215 **    uint32_t      pro_flg_pkts;    //  8-11
216 **    // uint32_t     prot_flags: 8; //        is_tcp==0: IP protocol
217 **                                   //        is_tcp==1 &&
218 **                                   //          EXPANDED==0:TCPflags/All pkts
219 **                                   //          EXPANDED==1:TCPflags/1st pkt
220 **    // uint32_t     pflag     : 1; //        'pkts' requires multiplier?
221 **    // uint32_t     is_tcp    : 1; //        1 if flow is TCP; 0 otherwise
222 **    // uint32_t     padding   : 2; //
223 **    // uint32_t     pkts      :20; //        Count of packets
224 **
225 **    uint8_t       tcp_state;       // 12     TCP state machine info
226 **    uint8_t       rest_flags;      // 13     is_tcp==0: Flow's reported flags
227 **                                   //        is_tcp==1 &&
228 **                                   //          EXPANDED==0:Empty
229 **                                   //          EXPANDED==1:TCPflags/!1st pkt
230 **    uint16_t      application;     // 14-15  Type of traffic
231 **
232 **    uint16_t      sPort;           // 16-17  Source port
233 **    uint16_t      dPort;           // 18-19  Destination port
234 **
235 **    uint16_t      input;           // 20-21  Router incoming SNMP interface
236 **    uint16_t      output;          // 22-23  Router outgoing SNMP interface
237 **
238 **    uint32_t      sIP;             // 24-27  Source IP
239 **    uint32_t      dIP;             // 28-31  Destination IP
240 **
241 **    uint32_t      nhIP;            // 32-35  Router Next Hop IP
242 **
243 **
244 **  36 bytes on disk.
245 */
246 
247 #define RECLEN_RWAUGROUTING_V4 36
248 
249 
250 /*
251  *    Byte swap the RWAUGROUTING v4 record 'ar' in place.
252  */
253 #define augroutingioRecordSwap_V4(ar)                           \
254     {                                                           \
255         SWAP_DATA32((ar) +  0);   /* stime_bb1 */               \
256         SWAP_DATA32((ar) +  4);   /* bb2_elapsed */             \
257         SWAP_DATA32((ar) +  8);   /* pro_flg_pkts */            \
258         /* two single bytes (12)tcp_state, (13)rest_flags */    \
259         SWAP_DATA16((ar) + 14);   /* application */             \
260         SWAP_DATA16((ar) + 16);   /* sPort */                   \
261         SWAP_DATA16((ar) + 18);   /* dPort */                   \
262         SWAP_DATA16((ar) + 20);   /* input */                   \
263         SWAP_DATA16((ar) + 22);   /* output */                  \
264         SWAP_DATA32((ar) + 24);   /* sIP */                     \
265         SWAP_DATA32((ar) + 28);   /* dIP */                     \
266         SWAP_DATA32((ar) + 32);   /* nhIP */                    \
267     }
268 
269 
270 /*
271  *  Unpack the array of bytes 'ar' into a record 'rwrec'
272  */
273 static int
augroutingioRecordUnpack_V4(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)274 augroutingioRecordUnpack_V4(
275     skstream_t         *stream,
276     rwGenericRec_V5    *rwrec,
277     uint8_t            *ar)
278 {
279     /* swap if required */
280     if (stream->swapFlag) {
281         augroutingioRecordSwap_V4(ar);
282     }
283 
284     /* sTime, elapsed, pkts, bytes, proto, tcp-flags, state, application */
285     rwpackUnpackFlagsTimesVolumes(rwrec, ar, stream->hdr_starttime, 16, 0);
286 
287     /* sPort, dPort */
288     rwRecMemSetSPort(rwrec, &ar[16]);
289     rwRecMemSetDPort(rwrec, &ar[18]);
290 
291     /* input, output */
292     rwRecMemSetInput(rwrec, &ar[20]);
293     rwRecMemSetOutput(rwrec, &ar[22]);
294 
295     /* sIP, dIP, nhIP */
296     rwRecMemSetSIPv4(rwrec, &ar[24]);
297     rwRecMemSetDIPv4(rwrec, &ar[28]);
298     rwRecMemSetNhIPv4(rwrec, &ar[32]);
299 
300     /* sensor, flow_type from file name/header */
301     rwRecSetSensor(rwrec, stream->hdr_sensor);
302     rwRecSetFlowType(rwrec, stream->hdr_flowtype);
303 
304     return SKSTREAM_OK;
305 }
306 
307 
308 /*
309  *  Pack the record 'rwrec' into an array of bytes 'ar'
310  */
311 static int
augroutingioRecordPack_V4(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)312 augroutingioRecordPack_V4(
313     skstream_t             *stream,
314     const rwGenericRec_V5  *rwrec,
315     uint8_t                *ar)
316 {
317     int rv = SKSTREAM_OK; /* return value */
318 
319     /* sTime, elapsed, pkts, bytes, proto, tcp-flags, state, application */
320     rv = rwpackPackFlagsTimesVolumes(ar, rwrec, stream->hdr_starttime, 16);
321     if (rv) {
322         return rv;
323     }
324 
325     /* sPort, dPort */
326     rwRecMemGetSPort(rwrec, &ar[16]);
327     rwRecMemGetDPort(rwrec, &ar[18]);
328 
329     /* input, output */
330     rwRecMemGetInput(rwrec, &ar[20]);
331     rwRecMemGetOutput(rwrec, &ar[22]);
332 
333     /* sIP, dIP, nhIP */
334     rwRecMemGetSIPv4(rwrec, &ar[24]);
335     rwRecMemGetDIPv4(rwrec, &ar[28]);
336     rwRecMemGetNhIPv4(rwrec, &ar[32]);
337 
338     /* swap if required */
339     if (stream->swapFlag) {
340         augroutingioRecordSwap_V4(ar);
341     }
342 
343     return SKSTREAM_OK;
344 }
345 
346 
347 /* ********************************************************************* */
348 
349 /*
350 **  RWAUGROUTING VERSION 1
351 **  RWAUGROUTING VERSION 2
352 **  RWAUGROUTING VERSION 3
353 **
354 **  in the following: EXPANDED == ((tcp_state & SK_TCPSTATE_EXPANDED) ? 1 : 0)
355 **
356 **    uint32_t      sIP;             //  0- 3  Source IP
357 **    uint32_t      dIP;             //  4- 7  Destination IP
358 **
359 **    uint16_t      sPort;           //  8- 9  Source port
360 **    uint16_t      dPort;           // 10-11  Destination port
361 **
362 **    uint32_t      pkts_stime;      // 12-15
363 **    // uint32_t     pkts      :20; //        Count of packets
364 **    // uint32_t     sTime     :12; //        Start time--offset from hour
365 **
366 **    uint32_t      bbe;             // 16-19
367 **    // uint32_t     bPPkt     :14; //        Whole bytes-per-packet
368 **    // uint32_t     bPPFrac   : 6; //        Fractional bytes-per-packet
369 **    // uint32_t     elapsed   :12; //        Duration of flow
370 **
371 **    uint32_t      msec_flags       // 20-23
372 **    // uint32_t     sTime_msec:10; //        Fractional sTime (millisec)
373 **    // uint32_t     elaps_msec:10; //        Fractional elapsed (millisec)
374 **    // uint32_t     pflag     : 1; //        'pkts' requires multiplier?
375 **    // uint32_t     is_tcp    : 1; //        1 if flow is TCP; 0 otherwise
376 **    // uint32_t     padding   : 2; //        padding/reserved
377 **    // uint32_t     prot_flags: 8; //        is_tcp==0: IP protocol
378 **                                   //        is_tcp==1 &&
379 **                                   //          EXPANDED==0:TCPflags/All pkts
380 **                                   //          EXPANDED==1:TCPflags/1st pkt
381 **
382 **    uint16_t      application;     // 24-25  Type of traffic
383 **
384 **    uint8_t       tcp_state;       // 26     TCP state machine info
385 **    uint8_t       rest_flags;      // 27     is_tcp==0: Flow's reported flags
386 **                                   //        is_tcp==1 &&
387 **                                   //          EXPANDED==0:Empty
388 **                                   //          EXPANDED==1:TCPflags/!1st pkt
389 **
390 **    uint32_t      nhIP;            // 28-31  Router Next Hop IP
391 **
392 **    uint16_t      input;           // 32-33  Router incoming SNMP interface
393 **    uint16_t      output;          // 34-35  Router outgoing SNMP interface
394 **
395 **
396 **  36 bytes on disk.
397 */
398 
399 #define RECLEN_RWAUGROUTING_V1 36
400 #define RECLEN_RWAUGROUTING_V2 36
401 #define RECLEN_RWAUGROUTING_V3 36
402 
403 
404 /*
405  *    Byte swap the RWAUGROUTING v1 record 'ar' in place.
406  */
407 #define augroutingioRecordSwap_V1(ar)                           \
408     {                                                           \
409         SWAP_DATA32((ar) +  0);   /* sIP */                     \
410         SWAP_DATA32((ar) +  4);   /* dIP */                     \
411         SWAP_DATA16((ar) +  8);   /* sPort */                   \
412         SWAP_DATA16((ar) + 10);   /* dPort */                   \
413         SWAP_DATA32((ar) + 12);   /* pkts_stime */              \
414         SWAP_DATA32((ar) + 16);   /* bbe */                     \
415         SWAP_DATA32((ar) + 20);   /* msec_flags */              \
416         SWAP_DATA16((ar) + 24);   /* application */             \
417         /* Two single bytes: (26)tcp_state, (27)rest_flags */   \
418         SWAP_DATA32((ar) + 28);   /* nhIP */                    \
419         SWAP_DATA16((ar) + 32);   /* input */                   \
420         SWAP_DATA16((ar) + 34);   /* output */                  \
421     }
422 
423 
424 /*
425  *  Unpack the array of bytes 'ar' into a record 'rwrec'
426  */
427 static int
augroutingioRecordUnpack_V1(skstream_t * stream,rwGenericRec_V5 * rwrec,uint8_t * ar)428 augroutingioRecordUnpack_V1(
429     skstream_t         *stream,
430     rwGenericRec_V5    *rwrec,
431     uint8_t            *ar)
432 {
433     uint32_t msec_flags;
434     uint8_t is_tcp, prot_flags;
435 
436     /* swap if required */
437     if (stream->swapFlag) {
438         augroutingioRecordSwap_V1(ar);
439     }
440 
441     /* sIP, dIP, sPort, dPort */
442     rwRecMemSetSIPv4(rwrec, &ar[0]);
443     rwRecMemSetDIPv4(rwrec, &ar[4]);
444     rwRecMemSetSPort(rwrec, &ar[8]);
445     rwRecMemSetDPort(rwrec, &ar[10]);
446 
447     /* msec times, proto or flags */
448     memcpy(&msec_flags, &ar[20],  4);
449 
450     /* application */
451     rwRecMemSetApplication(rwrec, &ar[24]);
452 
453     /* sTime, pkts, bytes, elapsed, proto, tcp-flags, bpp */
454     rwpackUnpackTimeBytesPktsFlags(rwrec, stream->hdr_starttime,
455                                    (uint32_t*)&ar[12], (uint32_t*)&ar[16],
456                                    &msec_flags);
457 
458     /* extra TCP information */
459     is_tcp = (uint8_t)GET_MASKED_BITS(msec_flags, 10, 1);
460     prot_flags = (uint8_t)GET_MASKED_BITS(msec_flags, 0, 8);
461     rwpackUnpackProtoFlags(rwrec, is_tcp, prot_flags, ar[26], ar[27]);
462 
463     /* next hop, input & output interfaces */
464     rwRecMemSetNhIPv4(rwrec, &ar[28]);
465     rwRecMemSetInput(rwrec, &ar[32]);
466     rwRecMemSetOutput(rwrec, &ar[34]);
467 
468     /* sensor, flow_type from file name/header */
469     rwRecSetSensor(rwrec, stream->hdr_sensor);
470     rwRecSetFlowType(rwrec, stream->hdr_flowtype);
471 
472     return SKSTREAM_OK;
473 }
474 
475 
476 /*
477  *  Pack the record 'rwrec' into an array of bytes 'ar'
478  */
479 static int
augroutingioRecordPack_V1(skstream_t * stream,const rwGenericRec_V5 * rwrec,uint8_t * ar)480 augroutingioRecordPack_V1(
481     skstream_t             *stream,
482     const rwGenericRec_V5  *rwrec,
483     uint8_t                *ar)
484 {
485     int rv = SKSTREAM_OK; /* return value */
486     uint32_t msec_flags;
487     uint8_t is_tcp, prot_flags;
488 
489     /* sTime, pkts, bytes, elapsed, proto, tcp-flags, bpp */
490     rv = rwpackPackTimeBytesPktsFlags((uint32_t*)&ar[12], (uint32_t*)&ar[16],
491                                       &msec_flags,
492                                       rwrec, stream->hdr_starttime);
493     if (rv) {
494         return rv;
495     }
496 
497     rwpackPackProtoFlags(&is_tcp, &prot_flags, &ar[26], &ar[27], rwrec);
498 
499     /* msec_flags: sTime_msec:10; elaps_msec:10; pflag:1;
500      *             is_tcp:1; pad:2; prot_flags:8; */
501     /* overwrite the least significant 11 bits */
502     msec_flags = ((msec_flags & (MASKARRAY_21 << 11))
503                   | (is_tcp ? (1 << 10) : 0)
504                   | prot_flags);
505 
506     /* sIP, dIP, sPort, dPort */
507     rwRecMemGetSIPv4(rwrec, &ar[0]);
508     rwRecMemGetDIPv4(rwrec, &ar[4]);
509     rwRecMemGetSPort(rwrec, &ar[8]);
510     rwRecMemGetDPort(rwrec, &ar[10]);
511 
512     /* msec_flags */
513     memcpy(&ar[20], &msec_flags, 4);
514 
515     /* application */
516     rwRecMemGetApplication(rwrec, &ar[24]);
517 
518     /* next hop, input & output interfaces */
519     rwRecMemGetNhIPv4(rwrec, &ar[28]);
520     rwRecMemGetInput(rwrec, &ar[32]);
521     rwRecMemGetOutput(rwrec, &ar[34]);
522 
523     /* swap if required */
524     if (stream->swapFlag) {
525         augroutingioRecordSwap_V1(ar);
526     }
527 
528     return SKSTREAM_OK;
529 }
530 
531 
532 /* ********************************************************************* */
533 
534 /*
535  *  Return length of record of specified version, or 0 if no such
536  *  version exists.  See skstream_priv.h for details.
537  */
538 uint16_t
augroutingioGetRecLen(sk_file_version_t vers)539 augroutingioGetRecLen(
540     sk_file_version_t   vers)
541 {
542     switch (vers) {
543       case 1:
544         return RECLEN_RWAUGROUTING_V1;
545       case 2:
546         return RECLEN_RWAUGROUTING_V2;
547       case 3:
548         return RECLEN_RWAUGROUTING_V3;
549       case 4:
550         return RECLEN_RWAUGROUTING_V4;
551       case 5:
552         return RECLEN_RWAUGROUTING_V5;
553       default:
554         return 0;
555     }
556 }
557 
558 
559 /*
560  *  status = augroutingioPrepare(&stream);
561  *
562  *    Sets the record version to the default if it is unspecified,
563  *    checks that the record format supports the requested record
564  *    version, sets the record length, and sets the pack and unpack
565  *    functions for this record format and version.
566  */
567 int
augroutingioPrepare(skstream_t * stream)568 augroutingioPrepare(
569     skstream_t         *stream)
570 {
571 #define FILE_FORMAT "FT_RWAUGROUTING"
572     sk_file_header_t *hdr = stream->silk_hdr;
573     int rv = SKSTREAM_OK; /* return value */
574 
575     assert(skHeaderGetFileFormat(hdr) == FT_RWAUGROUTING);
576 
577     /* Set version if none was selected by caller */
578     if ((stream->io_mode == SK_IO_WRITE)
579         && (skHeaderGetRecordVersion(hdr) == SK_RECORD_VERSION_ANY))
580     {
581         skHeaderSetRecordVersion(hdr, DEFAULT_RECORD_VERSION);
582     }
583 
584     /* version check; set values based on version */
585     switch (skHeaderGetRecordVersion(hdr)) {
586       case 5:
587         stream->rwUnpackFn = &augroutingioRecordUnpack_V5;
588         stream->rwPackFn   = &augroutingioRecordPack_V5;
589         break;
590       case 4:
591         stream->rwUnpackFn = &augroutingioRecordUnpack_V4;
592         stream->rwPackFn   = &augroutingioRecordPack_V4;
593         break;
594       case 3:
595       case 2:
596       case 1:
597         /* V1 and V2 differ only in the padding of the header */
598         /* V2 and V3 differ only in that V3 supports compression on
599          * read and write; V2 supports compression only on read */
600         stream->rwUnpackFn = &augroutingioRecordUnpack_V1;
601         stream->rwPackFn   = &augroutingioRecordPack_V1;
602         break;
603       case 0:
604       default:
605         rv = SKSTREAM_ERR_UNSUPPORT_VERSION;
606         goto END;
607     }
608 
609     stream->recLen = augroutingioGetRecLen(skHeaderGetRecordVersion(hdr));
610 
611     /* verify lengths */
612     if (stream->recLen == 0) {
613         skAppPrintErr("Record length not set for %s version %u",
614                       FILE_FORMAT, (unsigned)skHeaderGetRecordVersion(hdr));
615         skAbort();
616     }
617     if (stream->recLen != skHeaderGetRecordLength(hdr)) {
618         if (0 == skHeaderGetRecordLength(hdr)) {
619             skHeaderSetRecordLength(hdr, stream->recLen);
620         } else {
621             skAppPrintErr(("Record length mismatch for %s version %u\n"
622                            "\tcode = %" PRIu16 " bytes;  header = %lu bytes"),
623                           FILE_FORMAT, (unsigned)skHeaderGetRecordVersion(hdr),
624                           stream->recLen,
625                           (unsigned long)skHeaderGetRecordLength(hdr));
626             skAbort();
627         }
628     }
629 
630   END:
631     return rv;
632 }
633 
634 
635 /*
636 ** Local Variables:
637 ** mode:c
638 ** indent-tabs-mode:nil
639 ** c-basic-offset:4
640 ** End:
641 */
642