/src/wireshark/wiretap/aethra.c
Line | Count | Source |
1 | | /* aethra.c |
2 | | * |
3 | | * Wiretap Library |
4 | | * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu> |
5 | | * |
6 | | * SPDX-License-Identifier: GPL-2.0-or-later |
7 | | */ |
8 | | |
9 | 0 | #define WS_LOG_DOMAIN "aethra" |
10 | | |
11 | | #include "config.h" |
12 | | #include "aethra.h" |
13 | | |
14 | | #include <string.h> |
15 | | |
16 | | #include <wsutil/pint.h> |
17 | | |
18 | | #include "wtap_module.h" |
19 | | #include "file_wrappers.h" |
20 | | |
21 | | /* Magic number in Aethra PC108 files. */ |
22 | | #define MAGIC_SIZE 5 |
23 | | |
24 | | static const unsigned char aethra_magic[MAGIC_SIZE] = { |
25 | | 'V', '0', '2', '0', '8' |
26 | | }; |
27 | | |
28 | | /* Aethra file header. */ |
29 | | struct aethra_hdr { |
30 | | unsigned char magic[MAGIC_SIZE]; |
31 | | uint8_t unknown1[39]; /* 5-43 */ |
32 | | unsigned char sw_vers[60]; /* 44-103 - software version string, not null-terminated */ |
33 | | uint8_t unknown2[118]; /* 104-221 */ |
34 | | uint8_t start_sec; /* 222 - seconds of capture start time */ |
35 | | uint8_t start_min; /* 223 - minutes of capture start time */ |
36 | | uint8_t start_hour; /* 224 - hour of capture start time */ |
37 | | uint8_t unknown3[462]; /* 225-686 */ |
38 | | unsigned char xxx_string[37]; /* 687-723 - null-terminated short comment string? */ |
39 | | uint8_t unknown3_5[4]; /* 724-727 */ |
40 | | unsigned char yyy_string[4504];/* 728-5231 - null-terminated long comment string? */ |
41 | | uint8_t start_year[2]; /* 5232-5233 - year of capture start date */ |
42 | | uint8_t start_month[2]; /* 5234-5235 - month of capture start date */ |
43 | | uint8_t unknown4[2]; /* 5236-5237 */ |
44 | | uint8_t start_day[2]; /* 5238-5239 - day of capture start date */ |
45 | | uint8_t unknown5[8]; /* 5240-5247 */ |
46 | | unsigned char com_info[16]; /* 5248-5263 - COM port and speed, null-padded(?) */ |
47 | | uint8_t unknown6[107]; /* 5264-5370 */ |
48 | | unsigned char xxx_vers[41]; /* 5371-5411 - unknown version string (longer, null-padded?) */ |
49 | | }; |
50 | | |
51 | | /* Aethra record header. Yes, the alignment is weird. |
52 | | All multi-byte fields are little-endian. */ |
53 | | struct aethrarec_hdr { |
54 | | uint8_t rec_size[2]; /* record length, not counting the length itself */ |
55 | | uint8_t rec_type; /* record type */ |
56 | | uint8_t timestamp[4]; /* milliseconds since start of capture */ |
57 | | uint8_t flags; /* low-order bit: 0 = N->U, 1 = U->N */ |
58 | | }; |
59 | | |
60 | | /* |
61 | | * Record types. |
62 | | * |
63 | | * As the indications from the device and signalling messages appear not |
64 | | * to have the 8th bit set, and at least some B-channel records do, we |
65 | | * assume, for now, that the 8th bit indicates bearer information. |
66 | | * |
67 | | * 0x9F is the record type seen for B31 channel records; that might be |
68 | | * 0x80|31, so, for now, we assume that if the 8th bit is set, the B |
69 | | * channel number is in the low 7 bits. |
70 | | */ |
71 | | #define AETHRA_BEARER 0x80 /* bearer information */ |
72 | | |
73 | | #define AETHRA_DEVICE 0x00 /* indication from the monitoring device */ |
74 | 0 | #define AETHRA_ISDN_LINK 0x01 /* information from the ISDN link */ |
75 | | |
76 | | /* |
77 | | * In AETHRA_DEVICE records, the flags field has what appears to |
78 | | * be a record subtype. |
79 | | */ |
80 | | #define AETHRA_DEVICE_STOP_MONITOR 0x00 /* Stop Monitor */ |
81 | | #define AETHRA_DEVICE_START_MONITOR 0x04 /* Start Monitor */ |
82 | | #define AETHRA_DEVICE_ACTIVATION 0x05 /* Activation */ |
83 | | #define AETHRA_DEVICE_START_CAPTURE 0x5F /* Start Capture */ |
84 | | |
85 | | /* |
86 | | * In AETHRA_ISDN_LINK and bearer channel records, the flags field has |
87 | | * a direction flag and possibly some other bits. |
88 | | * |
89 | | * In AETHRA_ISDN_LINK records, at least some of the other bits are |
90 | | * a subtype. |
91 | | * |
92 | | * In bearer channel records, there are records with data and |
93 | | * "Constant Value" records with a single byte. Data has a |
94 | | * flags value of 0x14 ORed with the direction flag, and Constant Value |
95 | | * records have a flags value of 0x16 ORed with the direction flag. |
96 | | * There are also records of an unknown type with 0x02, probably |
97 | | * ORed with the direction flag. |
98 | | */ |
99 | 0 | #define AETHRA_U_TO_N 0x01 /* set for TE->NT */ |
100 | | |
101 | 0 | #define AETHRA_ISDN_LINK_SUBTYPE 0xFE |
102 | 0 | #define AETHRA_ISDN_LINK_LAPD 0x00 /* LAPD frame */ |
103 | 0 | #define AETHRA_ISDN_LINK_SA_BITS 0x2E /* 2048K PRI Sa bits (G.704 section 2.3.2) */ |
104 | 0 | #define AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED 0x30 /* All Alarms Cleared */ |
105 | | |
106 | | typedef struct { |
107 | | time_t start; |
108 | | unsigned int packet_number; |
109 | | } aethra_t; |
110 | | |
111 | | static int aethra_file_type_subtype = -1; |
112 | | |
113 | | void register_aethra(void); |
114 | | |
115 | | static bool |
116 | | aethra_read_rec_header(wtap* wth, FILE_T fh, struct aethrarec_hdr* hdr, |
117 | | wtap_rec* rec, int* err, char** err_info) |
118 | 0 | { |
119 | 0 | aethra_t* aethra = (aethra_t*)wth->priv; |
120 | 0 | uint32_t rec_size; |
121 | 0 | uint32_t packet_size; |
122 | 0 | uint32_t msecs; |
123 | | |
124 | | /* Read record header. */ |
125 | 0 | if (!wtap_read_bytes_or_eof(fh, hdr, sizeof * hdr, err, err_info)) |
126 | 0 | return false; |
127 | | |
128 | 0 | rec_size = pletohu16(hdr->rec_size); |
129 | 0 | if (rec_size < (sizeof * hdr - sizeof hdr->rec_size)) { |
130 | | /* The record is shorter than a record header. */ |
131 | 0 | *err = WTAP_ERR_BAD_FILE; |
132 | 0 | *err_info = ws_strdup_printf("aethra: File has %u-byte record, less than minimum of %u", |
133 | 0 | rec_size, |
134 | 0 | (unsigned int)(sizeof * hdr - sizeof hdr->rec_size)); |
135 | 0 | return false; |
136 | 0 | } |
137 | 0 | if (rec_size > WTAP_MAX_PACKET_SIZE_STANDARD) { |
138 | | /* |
139 | | * Probably a corrupt capture file; return an error, |
140 | | * so that our caller doesn't blow up trying to allocate |
141 | | * space for an immensely-large packet. |
142 | | */ |
143 | 0 | *err = WTAP_ERR_BAD_FILE; |
144 | 0 | *err_info = ws_strdup_printf("aethra: File has %u-byte packet, bigger than maximum of %u", |
145 | 0 | rec_size, WTAP_MAX_PACKET_SIZE_STANDARD); |
146 | 0 | return false; |
147 | 0 | } |
148 | | |
149 | 0 | packet_size = rec_size - (uint32_t)(sizeof * hdr - sizeof hdr->rec_size); |
150 | |
|
151 | 0 | wtap_setup_packet_rec(rec, wth->file_encap); |
152 | 0 | rec->presence_flags = WTAP_HAS_TS; |
153 | 0 | msecs = pletohu32(hdr->timestamp); |
154 | 0 | rec->ts.secs = aethra->start + (msecs / 1000); |
155 | 0 | rec->ts.nsecs = (msecs % 1000) * 1000000; |
156 | 0 | rec->rec_header.packet_header.caplen = packet_size; |
157 | 0 | rec->rec_header.packet_header.len = packet_size; |
158 | 0 | rec->rec_header.packet_header.pseudo_header.isdn.uton = (hdr->flags & AETHRA_U_TO_N); |
159 | 0 | rec->rec_header.packet_header.pseudo_header.isdn.channel = 0; /* XXX - D channel */ |
160 | |
|
161 | 0 | return true; |
162 | 0 | } |
163 | | |
164 | | /* Read the next packet */ |
165 | | static bool aethra_read(wtap *wth, wtap_rec *rec, int *err, |
166 | | char **err_info, int64_t *data_offset) |
167 | 0 | { |
168 | 0 | aethra_t* aethra = (aethra_t*)wth->priv; |
169 | 0 | struct aethrarec_hdr hdr; |
170 | | |
171 | | /* |
172 | | * Keep reading until we see an AETHRA_ISDN_LINK with a subtype |
173 | | * of AETHRA_ISDN_LINK_LAPD record or get an end-of-file. |
174 | | */ |
175 | 0 | for (;;) { |
176 | 0 | *data_offset = file_tell(wth->fh); |
177 | | |
178 | | /* Read record header. */ |
179 | 0 | if (!aethra_read_rec_header(wth, wth->fh, &hdr, rec, err, err_info)) |
180 | 0 | return false; |
181 | | |
182 | | /* |
183 | | * XXX - if this is big, we might waste memory by |
184 | | * growing the buffer to handle it. |
185 | | */ |
186 | 0 | if (rec->rec_header.packet_header.caplen != 0) { |
187 | 0 | if (!wtap_read_bytes_buffer(wth->fh, &rec->data, |
188 | 0 | rec->rec_header.packet_header.caplen, err, err_info)) |
189 | 0 | return false; /* Read error */ |
190 | 0 | } |
191 | 0 | aethra->packet_number++; |
192 | |
|
193 | 0 | switch (hdr.rec_type) { |
194 | | |
195 | 0 | case AETHRA_ISDN_LINK: |
196 | 0 | ws_noisy("Packet %u: type 0x%02x (AETHRA_ISDN_LINK)\n", aethra->packet_number, hdr.rec_type); |
197 | 0 | switch (hdr.flags & AETHRA_ISDN_LINK_SUBTYPE) { |
198 | | |
199 | 0 | case AETHRA_ISDN_LINK_LAPD: |
200 | | /* |
201 | | * The data is a LAPD frame. |
202 | | */ |
203 | 0 | ws_noisy(" subtype 0x%02x (AETHRA_ISDN_LINK_LAPD)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE); |
204 | 0 | goto found; |
205 | | |
206 | 0 | case AETHRA_ISDN_LINK_SA_BITS: |
207 | | /* |
208 | | * These records have one data byte, which |
209 | | * has the Sa bits in the lower 5 bits. |
210 | | * |
211 | | * XXX - what about stuff other than 2048K |
212 | | * PRI lines? |
213 | | */ |
214 | 0 | ws_noisy(" subtype 0x%02x (AETHRA_ISDN_LINK_SA_BITS)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE); |
215 | 0 | break; |
216 | | |
217 | 0 | case AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED: |
218 | | /* |
219 | | * No data, just an "all alarms cleared" |
220 | | * indication. |
221 | | */ |
222 | 0 | ws_noisy(" subtype 0x%02x (AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE); |
223 | 0 | break; |
224 | | |
225 | 0 | default: |
226 | 0 | ws_noisy(" subtype 0x%02x, packet_size %u, direction 0x%02x\n", |
227 | 0 | hdr.flags & AETHRA_ISDN_LINK_SUBTYPE, rec->rec_header.packet_header.caplen, hdr.flags & AETHRA_U_TO_N); |
228 | 0 | break; |
229 | 0 | } |
230 | 0 | break; |
231 | | |
232 | 0 | default: |
233 | 0 | ws_debug("Packet %u: type 0x%02x, packet_size %u, flags 0x%02x\n", aethra->packet_number, hdr.rec_type, rec->rec_header.packet_header.caplen, hdr.flags); |
234 | 0 | break; |
235 | 0 | } |
236 | 0 | } |
237 | | |
238 | 0 | found: |
239 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
240 | 0 | return true; |
241 | 0 | } |
242 | | |
243 | | static bool |
244 | | aethra_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, |
245 | | int *err, char **err_info) |
246 | 0 | { |
247 | 0 | struct aethrarec_hdr hdr; |
248 | |
|
249 | 0 | if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) |
250 | 0 | return false; |
251 | | |
252 | 0 | if (!aethra_read_rec_header(wth, wth->random_fh, &hdr, rec, err, |
253 | 0 | err_info)) { |
254 | 0 | if (*err == 0) |
255 | 0 | *err = WTAP_ERR_SHORT_READ; |
256 | 0 | return false; |
257 | 0 | } |
258 | | |
259 | | /* |
260 | | * Read the packet data. |
261 | | */ |
262 | 0 | if (!wtap_read_bytes_buffer(wth->random_fh, &rec->data, |
263 | 0 | rec->rec_header.packet_header.caplen, err, err_info)) |
264 | 0 | return false; /* failed */ |
265 | | |
266 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
267 | 0 | return true; |
268 | 0 | } |
269 | | |
270 | | wtap_open_return_val aethra_open(wtap* wth, int* err, char** err_info) |
271 | 0 | { |
272 | 0 | struct aethra_hdr hdr; |
273 | 0 | struct tm tm; |
274 | 0 | aethra_t* aethra; |
275 | | |
276 | | /* Read in the string that should be at the start of a "aethra" file */ |
277 | 0 | if (!wtap_read_bytes(wth->fh, hdr.magic, sizeof hdr.magic, err, |
278 | 0 | err_info)) { |
279 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
280 | 0 | return WTAP_OPEN_ERROR; |
281 | 0 | return WTAP_OPEN_NOT_MINE; |
282 | 0 | } |
283 | | |
284 | 0 | if (memcmp(hdr.magic, aethra_magic, sizeof aethra_magic) != 0) |
285 | 0 | return WTAP_OPEN_NOT_MINE; |
286 | | |
287 | | /* Read the rest of the header. */ |
288 | 0 | if (!wtap_read_bytes(wth->fh, (char*)&hdr + sizeof hdr.magic, |
289 | 0 | sizeof hdr - sizeof hdr.magic, err, err_info)) |
290 | 0 | return WTAP_OPEN_ERROR; |
291 | 0 | wth->file_type_subtype = aethra_file_type_subtype; |
292 | 0 | aethra = g_new(aethra_t, 1); |
293 | 0 | wth->priv = (void*)aethra; |
294 | 0 | wth->subtype_read = aethra_read; |
295 | 0 | wth->subtype_seek_read = aethra_seek_read; |
296 | | |
297 | | /* |
298 | | * Convert the time stamp to a "time_t". |
299 | | */ |
300 | 0 | tm.tm_year = pletohu16(&hdr.start_year) - 1900; |
301 | 0 | tm.tm_mon = pletohu16(&hdr.start_month) - 1; |
302 | 0 | tm.tm_mday = pletohu16(&hdr.start_day); |
303 | 0 | tm.tm_hour = hdr.start_hour; |
304 | 0 | tm.tm_min = hdr.start_min; |
305 | 0 | tm.tm_sec = hdr.start_sec; |
306 | 0 | tm.tm_isdst = -1; |
307 | 0 | aethra->start = mktime(&tm); |
308 | 0 | aethra->packet_number = 0; |
309 | | |
310 | | /* |
311 | | * We've only seen ISDN files, so, for now, we treat all |
312 | | * files as ISDN. |
313 | | */ |
314 | 0 | wth->file_encap = WTAP_ENCAP_ISDN; |
315 | 0 | wth->snapshot_length = 0; /* not available in header */ |
316 | 0 | wth->file_tsprec = WTAP_TSPREC_MSEC; |
317 | | |
318 | | /* |
319 | | * Add an IDB; we don't know how many interfaces were |
320 | | * involved, so we just say one interface, about which |
321 | | * we only know the link-layer type, snapshot length, |
322 | | * and time stamp resolution. |
323 | | */ |
324 | 0 | wtap_add_generated_idb(wth); |
325 | |
|
326 | 0 | return WTAP_OPEN_MINE; |
327 | 0 | } |
328 | | |
329 | | static const struct supported_block_type aethra_blocks_supported[] = { |
330 | | /* |
331 | | * We support packet blocks, with no comments or other options. |
332 | | */ |
333 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
334 | | }; |
335 | | |
336 | | static const struct file_type_subtype_info aethra_info = { |
337 | | "Aethra .aps file", "aethra", "aps", NULL, |
338 | | false, BLOCKS_SUPPORTED(aethra_blocks_supported), |
339 | | NULL, NULL, NULL |
340 | | }; |
341 | | |
342 | | void register_aethra(void) |
343 | 14 | { |
344 | 14 | aethra_file_type_subtype = wtap_register_file_type_subtype(&aethra_info); |
345 | | |
346 | | /* |
347 | | * Register name for backwards compatibility with the |
348 | | * wtap_filetypes table in Lua. |
349 | | */ |
350 | 14 | wtap_register_backwards_compatibility_lua_name("AETHRA", |
351 | 14 | aethra_file_type_subtype); |
352 | 14 | } |
353 | | |
354 | | /* |
355 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
356 | | * |
357 | | * Local variables: |
358 | | * c-basic-offset: 8 |
359 | | * tab-width: 8 |
360 | | * indent-tabs-mode: t |
361 | | * End: |
362 | | * |
363 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
364 | | * :indentSize=8:tabSize=8:noTabs=false: |
365 | | */ |