File: pcaplite.cpp

package info (click to toggle)
savvycan 220-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 12,456 kB
  • sloc: cpp: 61,803; sh: 293; javascript: 91; python: 44; makefile: 8
file content (229 lines) | stat: -rw-r--r-- 7,062 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#include <math.h>
#include "pcaplite.h"

#define MAGIC_NG 0x0A0D0D0A
#define MACIG 0xA1B2C3D4  

#define MAX_CAN_PACKET_SIZE 256

// some pcap format constants
#define PCAP_FILE_HEADER_LENGTH 24
#define PCAP_FRAME_HEADER_LENGTH 16
#define PCAP_CAP_FRAME_LENGTH_OFFSET 8
#define PCAP_FRAME_LENGTH_OFFSET 12

// some pcapng format constants
#define INTERFACE_DESCRITION_BLOCK 0x01
#define ENCHANCED_PACKET_BLOCK 0x06

static unsigned char pcap_buffer[MAX_CAN_PACKET_SIZE];
static pcap_t p;

pcap *pcap_open_offline(const char *filename, char *error_text, int expected_link_type) {
	FILE *file;

    snprintf(error_text, PCAP_ERRBUF_SIZE, "OK");

    file = fopen(filename,"rb");

    if (NULL == file) {
        snprintf(error_text, PCAP_ERRBUF_SIZE,
               "Cannot open input file");
        return NULL;
    }

	unsigned int magic;
	size_t bytes_read;

	bytes_read = fread(&magic, 1, sizeof(magic), file);
	if (bytes_read != sizeof(magic)) {
		snprintf(error_text, PCAP_ERRBUF_SIZE, "Cannot read magic word");
        fclose(file);
		return (NULL);
	}

    if (magic != MACIG && magic != MAGIC_NG) {
        snprintf(error_text, PCAP_ERRBUF_SIZE, "Not a supported format %04x", magic);
        fclose(file);
		return (NULL);
    }

    unsigned int link_type;
    fseek(file, PCAP_FILE_HEADER_LENGTH - 4, SEEK_SET);
    bytes_read = fread(&link_type, 1, sizeof(link_type), file);
    if (bytes_read != sizeof(link_type)) {
        snprintf(error_text, PCAP_ERRBUF_SIZE, "Cannot read linktype word");
        fclose(file);
        return (NULL);
    }
    if (expected_link_type >= 0) {
        // Check the link type
        if ((int) link_type != expected_link_type) {
            snprintf(error_text, PCAP_ERRBUF_SIZE, "This link type is not supported by this decoder");
            fclose(file);
            return (NULL);
        }
    }

    // set the format
    // and seek past file header
    if (MAGIC_NG == magic) {
        p.is_ng = 1;
        fseek(file, sizeof(magic), SEEK_SET);
        unsigned int  section_length;
        bytes_read = fread(&section_length, 1, sizeof(section_length), file);
        if (bytes_read != sizeof(section_length)) {
		    snprintf(error_text, PCAP_ERRBUF_SIZE, "Cannot read section length");
            fclose(file);
		    return (NULL);
	    }
        fseek(file, section_length, SEEK_SET);
    } else {
        p.is_ng = 0;
        fseek(file, PCAP_FILE_HEADER_LENGTH, SEEK_SET);
    }

    p.file = file;
	return(&p);
}

const unsigned char *pcap_next_ng(pcap_t *p, struct pcap_pkthdr *h) {
    // this is for ENCHANCED_PACKET_BLOCK
    struct block_header { 
        unsigned int block_type;
        unsigned int block_size;
        unsigned int interface_id;
        unsigned int timestamp_hi;
        unsigned int timestamp_lo;
        unsigned int cap_len;
        unsigned int len;
    } bh;

    struct option_header {
        unsigned short option_type;
        unsigned short option_length;
    } oh;

    size_t bytes_read;

    static double timestamp_multiplier = 0.000001; //microseconds resolution

    long fpos = ftell(p->file);
    
    do {
        bytes_read = fread(&bh, 1, sizeof(bh), p->file);
        if (bytes_read != sizeof(bh)) {
            //probably EOF
            return (NULL);
        }

        if (bh.block_type != ENCHANCED_PACKET_BLOCK) {
            if (INTERFACE_DESCRITION_BLOCK == bh.block_type) {
                // Seek to start of options part in the header
                fseek(p->file, fpos + 16, SEEK_SET);
                do {
                    bytes_read = fread(&oh, 1, sizeof(oh), p->file);
                    if (bytes_read != sizeof(oh)) {
                        //probably EOF
                        return (NULL);
                    }
                    
                    // calculate option length aligned on 4 byte boundary
                    unsigned int option_file_length = 4*(oh.option_length/4) + ((oh.option_length%4) ? 4:0);

                    
                    // read in the buffer if it's large enough or skip
                    if (option_file_length <= sizeof(pcap_buffer)) {
                        bytes_read = fread(pcap_buffer, 1, option_file_length, p->file);
                        if (bytes_read != option_file_length) {
                            //probably EOF
		                    return (NULL);
	                    }
                        //check if time resolution option
                        if (0x09 == oh.option_type) {
                            unsigned int res = *(unsigned int*)pcap_buffer;
                            if ((0x80000000 & res) == 0) {
                                timestamp_multiplier = 1/pow(10, res); 
                            } else {
                               timestamp_multiplier = 1/pow(2, (res & 0x7fffffff));  
                            }
                        }
                    } else if (fseek(p->file, option_file_length, SEEK_CUR)) {
                        //probably EOF
		                return (NULL);
                    }

                } while(ftell(p->file) < fpos + bh.block_size - sizeof(bh.block_size));

                if (fseek(p->file, sizeof(bh.block_size), SEEK_CUR)) {
                        //probably EOF
		                return (NULL);
                }
            }

            // skip to the next block
            if (fseek(p->file, fpos + bh.block_size, SEEK_SET)) {
                //probably EOF
		        return (NULL);
            }
            fpos = ftell(p->file);
        }
    } while (bh.block_type != ENCHANCED_PACKET_BLOCK);

    h->caplen = bh.cap_len;
    
    double timestamp = ((unsigned long long)bh.timestamp_hi << 32 | bh.timestamp_lo) * timestamp_multiplier;
    double fractional, integer;

    fractional = modf(timestamp, &integer);
    h->ts.tv_sec = (long)integer;
    h->ts.tv_usec = (long)(fractional * 1000000);
    
    bytes_read = fread(pcap_buffer, 1, h->caplen, p->file);
    if (bytes_read != h->caplen) {
        //probably EOF
		return (NULL);
	}
   
    //seek to the next block (go back with bytes read of the block and seek fwd with the block size)
    if (fseek(p->file, fpos + bh.block_size, SEEK_SET)) {
        //probably EOF
		return (NULL);
    }

    return pcap_buffer;
}


const unsigned char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
{
    if (p->is_ng) {
        return pcap_next_ng(p, h);
    }

	size_t bytes_read;

	bytes_read = fread(pcap_buffer, 1, PCAP_FRAME_HEADER_LENGTH, p->file);
    if (bytes_read != PCAP_FRAME_HEADER_LENGTH) {
        //probably EOF
		return (NULL);
	}

    h->ts.tv_sec = *(unsigned int*)(pcap_buffer);
    h->ts.tv_usec = *(unsigned int*)(pcap_buffer + 4);

    h->caplen = *(unsigned int*)(pcap_buffer + PCAP_CAP_FRAME_LENGTH_OFFSET);
    h->len = *(unsigned int*)(pcap_buffer + PCAP_FRAME_LENGTH_OFFSET);

    bytes_read = fread(pcap_buffer, 1, h->caplen, p->file);
    if (bytes_read != h->caplen) {
        //probably EOF
		return (NULL);
	}

    return pcap_buffer;
}

void pcap_close(pcap_t *p) {
    fclose(p->file);
}