/src/wireshark/wiretap/cosine.c
Line | Count | Source |
1 | | /* cosine.c |
2 | | * |
3 | | * CoSine IPNOS L2 debug output parsing |
4 | | * Copyright (c) 2002 by Motonori Shindo <motonori@shin.do> |
5 | | * |
6 | | * Wiretap Library |
7 | | * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu> |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | #include "cosine.h" |
14 | | #include "wtap_module.h" |
15 | | #include "file_wrappers.h" |
16 | | |
17 | | #include <stdlib.h> |
18 | | #include <string.h> |
19 | | |
20 | | /* |
21 | | |
22 | | IPNOS: CONFIG VPN(100) VR(1.1.1.1)# diags |
23 | | ipnos diags: Control (1/0) :: layer-2 ? |
24 | | Registered commands for area "layer-2" |
25 | | apply-pkt-log-profile Configure packet logging on an interface |
26 | | create-pkt-log-profile Set packet-log-profile to be used for packet logging (see layer-2 pkt-log) |
27 | | detail Get Layer 2 low-level details |
28 | | |
29 | | ipnos diags: Control (1/0) :: layer-2 create ? |
30 | | create-pkt-log-profile <pkt-log-profile-id ctl-tx-trace-length ctl-rx-trace-length data-tx-trace-length data-rx-trace-length pe-logging-or-control-blade> |
31 | | |
32 | | ipnos diags: Control (1/0) :: layer-2 create 1 32 32 0 0 0 |
33 | | ipnos diags: Control (1/0) :: layer-2 create 2 32 32 100 100 0 |
34 | | ipnos diags: Control (1/0) :: layer-2 apply ? |
35 | | apply-pkt-log-profile <slot port channel subif pkt-log-profile-id> |
36 | | |
37 | | ipnos diags: Control (1/0) :: layer-2 apply 3 0x0701 100 0 1 |
38 | | Successfully applied packet-log-profile on LI |
39 | | |
40 | | -- Note that only the control packets are logged because the data packet size parameters are 0 in profile 1 |
41 | | IPNOS: CONFIG VPN(200) VR(3.3.3.3)# ping 20.20.20.43 |
42 | | vpn 200 : [max tries 4, timeout 5 seconds, data length 64 bytes, ttl 255] |
43 | | ping #1 ok, RTT 0.000 seconds |
44 | | ping #2 ok, RTT 0.000 seconds |
45 | | ping #3 ok, RTT 0.000 seconds |
46 | | ping #4 ok, RTT 0.000 seconds |
47 | | [finished] |
48 | | |
49 | | IPNOS: CONFIG VPN(200) VR(3.3.3.3)# 2000-2-1,18:19:46.8: l2-tx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] |
50 | | |
51 | | |
52 | | 2000-2-1,18:19:46.8: l2-rx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4001, 0x30000] |
53 | | |
54 | | 2000-2-1,18:19:46.8: l2-tx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] |
55 | | |
56 | | 2000-2-1,18:19:46.8: l2-rx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4001, 0x8030000] |
57 | | |
58 | | ipnos diags: Control (1/0) :: layer-2 apply 3 0x0701 100 0 0 |
59 | | Successfully applied packet-log-profile on LI |
60 | | ipnos diags: Control (1/0) :: layer-2 apply 3 0x0701 100 0 2 |
61 | | Successfully applied packet-log-profile on LI |
62 | | |
63 | | -- Note that both control and data packets are logged because the data packet size parameter is 100 in profile 2 |
64 | | Please ignore the event-log messages getting mixed up with the ping command |
65 | | ping 20.20.20.43 cou2000-2-1,18:20:17.0: l2-tx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] |
66 | | |
67 | | 00 D0 D8 D2 FF 03 C0 21 09 29 00 08 6B 60 84 AA |
68 | | |
69 | | 2000-2-1,18:20:17.0: l2-rx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4001, 0x30000] |
70 | | 00 D0 D8 D2 FF 03 C0 21 09 29 00 08 6D FE FA AA |
71 | | |
72 | | 2000-2-1,18:20:17.0: l2-tx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] |
73 | | 00 D0 D8 D2 FF 03 C0 21 0A 29 00 08 6B 60 84 AA |
74 | | |
75 | | 2000-2-1,18:20:17.0: l2-rx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4001, 0x8030000] |
76 | | 00 D0 D8 D2 FF 03 C0 21 0A 29 00 08 6D FE FA AA |
77 | | |
78 | | nt 1 length 500 |
79 | | vpn 200 : [max tries 1, timeout 5 seconds, data length 500 bytes, ttl 255] |
80 | | 2000-2-1,18:20:24.1: l2-tx (PPP:3/7/1:100), Length:536, Pro:1, Off:8, Pri:7, RM:0, Err:0 [0x4070, 0x801] |
81 | | 00 D0 D8 D2 FF 03 00 21 45 00 02 10 00 27 00 00 |
82 | | FF 01 69 51 14 14 14 22 14 14 14 2B 08 00 AD B8 |
83 | | 00 03 00 01 10 11 12 13 14 15 16 17 18 19 1A 1B |
84 | | 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B |
85 | | 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B |
86 | | 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B |
87 | | 4C 4D 4E 4F |
88 | | |
89 | | ping #1 ok, RTT 0.010 seconds |
90 | | 2000-2-1,18:20:24.1: l2-rx (PPP:3/7/1:100), Length:536, Pro:1, Off:8, Pri:7, RM:0, Err:0 [0x4071, 0x30801] |
91 | | 00 D0 D8 D2 FF 03 00 21 45 00 02 10 00 23 00 00 |
92 | | FF 01 69 55 14 14 14 2B 14 14 14 22 00 00 B5 B8 |
93 | | 00 03 00 01 10 11 12 13 14 15 16 17 18 19 1A 1B |
94 | | 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B |
95 | | 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B |
96 | | 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B |
97 | | 4C 4D 4E 4F |
98 | | |
99 | | [finished] |
100 | | |
101 | | IPNOS: CONFIG VPN(200) VR(3.3.3.3)# 2000-2-1,18:20:27.0: l2-tx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] |
102 | | |
103 | | 00 D0 D8 D2 FF 03 C0 21 09 2A 00 08 6B 60 84 AA |
104 | | |
105 | | 2000-2-1,18:20:27.0: l2-rx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4001, 0x30000] |
106 | | 00 D0 D8 D2 FF 03 C0 21 09 2A 00 08 6D FE FA AA |
107 | | |
108 | | 2000-2-1,18:20:27.0: l2-tx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] |
109 | | 00 D0 D8 D2 FF 03 C0 21 0A 2A 00 08 6B 60 84 AA |
110 | | |
111 | | 2000-2-1,18:20:27.0: l2-rx (PPP:3/7/1:100), Length:16, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4001, 0x30000] |
112 | | 00 D0 D8 D2 FF 03 C0 21 0A 2A 00 08 6D FE FA AA |
113 | | |
114 | | |
115 | | ipnos diags: Control (1/0) :: layer-2 apply 3 0x0701 100 0 0 |
116 | | Successfully applied packet-log-profile on LI |
117 | | ipnos diags: Control (1/0) :: |
118 | | |
119 | | */ |
120 | | |
121 | | /* XXX TODO: |
122 | | |
123 | | o Handle a case where an empty line doesn't exists as a delimiter of |
124 | | each packet. If the output is sent to a control blade and |
125 | | displayed as an event log, there's always an empty line between |
126 | | each packet output, but it may not be true when it is an PE |
127 | | output. |
128 | | |
129 | | o Some telnet client on Windows may put in a line break at 80 |
130 | | columns when it save the session to a text file ("CRT" is such an |
131 | | example). I don't think it's a good idea for the telnet client to |
132 | | do so, but CRT is widely used in Windows community, I should |
133 | | take care of that in the future. |
134 | | |
135 | | */ |
136 | | |
137 | | /* Magic text to check for CoSine L2 debug output */ |
138 | 0 | #define COSINE_HDR_MAGIC_STR1 "l2-tx" |
139 | 0 | #define COSINE_HDR_MAGIC_STR2 "l2-rx" |
140 | | |
141 | | /* Magic text for start of packet */ |
142 | 0 | #define COSINE_REC_MAGIC_STR1 COSINE_HDR_MAGIC_STR1 |
143 | 0 | #define COSINE_REC_MAGIC_STR2 COSINE_HDR_MAGIC_STR2 |
144 | | |
145 | 0 | #define COSINE_HEADER_LINES_TO_CHECK 200 |
146 | 0 | #define COSINE_LINE_LENGTH 240 |
147 | | |
148 | | static bool empty_line(const char *line); |
149 | | static int64_t cosine_seek_next_packet(wtap *wth, int *err, char **err_info, |
150 | | char *hdr); |
151 | | static bool cosine_check_file_type(wtap *wth, int *err, char **err_info); |
152 | | static bool cosine_read(wtap *wth, wtap_rec *rec, |
153 | | int *err, char **err_info, int64_t *data_offset); |
154 | | static bool cosine_seek_read(wtap *wth, int64_t seek_off, |
155 | | wtap_rec *rec, int *err, char **err_info); |
156 | | static bool parse_cosine_packet(wtap *wth, FILE_T fh, wtap_rec *rec, |
157 | | char *line, int *err, char **err_info); |
158 | | static int parse_single_hex_dump_line(char* rec, Buffer *buf); |
159 | | |
160 | | static int cosine_file_type_subtype = -1; |
161 | | |
162 | | void register_cosine(void); |
163 | | |
164 | | /* Returns true if the line appears to be an empty line. Otherwise it |
165 | | returns false. */ |
166 | | static bool empty_line(const char *line) |
167 | 0 | { |
168 | 0 | while (*line) { |
169 | 0 | if (g_ascii_isspace(*line)) { |
170 | 0 | line++; |
171 | 0 | continue; |
172 | 0 | } else { |
173 | 0 | break; |
174 | 0 | } |
175 | 0 | } |
176 | 0 | if (*line == '\0') |
177 | 0 | return true; |
178 | 0 | else |
179 | 0 | return false; |
180 | 0 | } |
181 | | |
182 | | /* Seeks to the beginning of the next packet, and returns the |
183 | | byte offset. Copy the header line to hdr. Returns -1 on failure, |
184 | | and sets "*err" to the error and sets "*err_info" to null or an |
185 | | additional error string. */ |
186 | | static int64_t cosine_seek_next_packet(wtap *wth, int *err, char **err_info, |
187 | | char *hdr) |
188 | 0 | { |
189 | 0 | int64_t cur_off; |
190 | 0 | char buf[COSINE_LINE_LENGTH]; |
191 | |
|
192 | 0 | while (1) { |
193 | 0 | cur_off = file_tell(wth->fh); |
194 | 0 | if (cur_off == -1) { |
195 | | /* Error */ |
196 | 0 | *err = file_error(wth->fh, err_info); |
197 | 0 | return -1; |
198 | 0 | } |
199 | 0 | if (file_gets(buf, sizeof(buf), wth->fh) == NULL) { |
200 | 0 | *err = file_error(wth->fh, err_info); |
201 | 0 | return -1; |
202 | 0 | } |
203 | 0 | if (strstr(buf, COSINE_REC_MAGIC_STR1) || |
204 | 0 | strstr(buf, COSINE_REC_MAGIC_STR2)) { |
205 | 0 | (void) g_strlcpy(hdr, buf, COSINE_LINE_LENGTH); |
206 | 0 | return cur_off; |
207 | 0 | } |
208 | 0 | } |
209 | 0 | return -1; |
210 | 0 | } |
211 | | |
212 | | /* Look through the first part of a file to see if this is |
213 | | * a CoSine L2 debug output. |
214 | | * |
215 | | * Returns true if it is, false if it isn't or if we get an I/O error; |
216 | | * if we get an I/O error, "*err" will be set to a non-zero value and |
217 | | * "*err_info" will be set to null or an additional error string. |
218 | | */ |
219 | | static bool cosine_check_file_type(wtap *wth, int *err, char **err_info) |
220 | 0 | { |
221 | 0 | char buf[COSINE_LINE_LENGTH]; |
222 | 0 | size_t reclen; |
223 | 0 | unsigned line; |
224 | |
|
225 | 0 | buf[COSINE_LINE_LENGTH-1] = '\0'; |
226 | |
|
227 | 0 | for (line = 0; line < COSINE_HEADER_LINES_TO_CHECK; line++) { |
228 | 0 | if (file_gets(buf, COSINE_LINE_LENGTH, wth->fh) == NULL) { |
229 | | /* EOF or error. */ |
230 | 0 | *err = file_error(wth->fh, err_info); |
231 | 0 | return false; |
232 | 0 | } |
233 | | |
234 | 0 | reclen = strlen(buf); |
235 | 0 | if (reclen < MIN(strlen(COSINE_HDR_MAGIC_STR1), strlen(COSINE_HDR_MAGIC_STR2))) { |
236 | 0 | continue; |
237 | 0 | } |
238 | | |
239 | 0 | if (strstr(buf, COSINE_HDR_MAGIC_STR1) || |
240 | 0 | strstr(buf, COSINE_HDR_MAGIC_STR2)) { |
241 | 0 | return true; |
242 | 0 | } |
243 | 0 | } |
244 | 0 | *err = 0; |
245 | 0 | return false; |
246 | 0 | } |
247 | | |
248 | | |
249 | | wtap_open_return_val cosine_open(wtap *wth, int *err, char **err_info) |
250 | 0 | { |
251 | | /* Look for CoSine header */ |
252 | 0 | if (!cosine_check_file_type(wth, err, err_info)) { |
253 | 0 | if (*err != 0 && *err != WTAP_ERR_SHORT_READ) |
254 | 0 | return WTAP_OPEN_ERROR; |
255 | 0 | return WTAP_OPEN_NOT_MINE; |
256 | 0 | } |
257 | | |
258 | 0 | if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) /* rewind */ |
259 | 0 | return WTAP_OPEN_ERROR; |
260 | | |
261 | 0 | wth->file_encap = WTAP_ENCAP_COSINE; |
262 | 0 | wth->file_type_subtype = cosine_file_type_subtype; |
263 | 0 | wth->snapshot_length = 0; /* not known */ |
264 | 0 | wth->subtype_read = cosine_read; |
265 | 0 | wth->subtype_seek_read = cosine_seek_read; |
266 | 0 | wth->file_tsprec = WTAP_TSPREC_10_MSEC; |
267 | | |
268 | | /* |
269 | | * Add an IDB; we don't know how many interfaces were |
270 | | * involved, so we just say one interface, about which |
271 | | * we only know the link-layer type, snapshot length, |
272 | | * and time stamp resolution. |
273 | | */ |
274 | 0 | wtap_add_generated_idb(wth); |
275 | |
|
276 | 0 | return WTAP_OPEN_MINE; |
277 | 0 | } |
278 | | |
279 | | /* Find the next packet and parse it; called from wtap_read(). */ |
280 | | static bool cosine_read(wtap *wth, wtap_rec *rec, |
281 | | int *err, char **err_info, int64_t *data_offset) |
282 | 0 | { |
283 | 0 | int64_t offset; |
284 | 0 | char line[COSINE_LINE_LENGTH]; |
285 | | |
286 | | /* Find the next packet */ |
287 | 0 | offset = cosine_seek_next_packet(wth, err, err_info, line); |
288 | 0 | if (offset < 0) |
289 | 0 | return false; |
290 | 0 | *data_offset = offset; |
291 | | |
292 | | /* Parse the header and convert the ASCII hex dump to binary data */ |
293 | 0 | return parse_cosine_packet(wth, wth->fh, rec, line, err, err_info); |
294 | 0 | } |
295 | | |
296 | | /* Used to read packets in random-access fashion */ |
297 | | static bool |
298 | | cosine_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, |
299 | | int *err, char **err_info) |
300 | 0 | { |
301 | 0 | char line[COSINE_LINE_LENGTH]; |
302 | |
|
303 | 0 | if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) |
304 | 0 | return false; |
305 | | |
306 | 0 | if (file_gets(line, COSINE_LINE_LENGTH, wth->random_fh) == NULL) { |
307 | 0 | *err = file_error(wth->random_fh, err_info); |
308 | 0 | if (*err == 0) { |
309 | 0 | *err = WTAP_ERR_SHORT_READ; |
310 | 0 | } |
311 | 0 | return false; |
312 | 0 | } |
313 | | |
314 | | /* Parse the header and convert the ASCII hex dump to binary data */ |
315 | 0 | return parse_cosine_packet(wth, wth->random_fh, rec, line, err, err_info); |
316 | 0 | } |
317 | | |
318 | | /* Parses a packet record header. There are two possible formats: |
319 | | 1) output to a control blade with date and time |
320 | | 2002-5-10,20:1:31.4: l2-tx (FR:3/7/1:1), Length:18, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] |
321 | | 2) output to PE without date and time |
322 | | l2-tx (FR:3/7/1:1), Length:18, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] */ |
323 | | static bool |
324 | | parse_cosine_packet(wtap *wth, FILE_T fh, wtap_rec *rec, |
325 | | char *line, int *err, char **err_info) |
326 | 0 | { |
327 | 0 | union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header; |
328 | 0 | int num_items_scanned; |
329 | 0 | int yy, mm, dd, hr, min, sec, csec, pkt_len; |
330 | 0 | int pro, off, pri, rm, error; |
331 | 0 | unsigned code1, code2; |
332 | 0 | char if_name[COSINE_MAX_IF_NAME_LEN] = "", direction[6] = ""; |
333 | 0 | struct tm tm; |
334 | 0 | int i, hex_lines, n, caplen = 0; |
335 | |
|
336 | 0 | if (sscanf(line, "%4d-%2d-%2d,%2d:%2d:%2d.%9d:", |
337 | 0 | &yy, &mm, &dd, &hr, &min, &sec, &csec) == 7) { |
338 | | /* appears to be output to a control blade */ |
339 | 0 | num_items_scanned = sscanf(line, |
340 | 0 | "%4d-%2d-%2d,%2d:%2d:%2d.%9d: %5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]", |
341 | 0 | &yy, &mm, &dd, &hr, &min, &sec, &csec, |
342 | 0 | direction, if_name, &pkt_len, |
343 | 0 | &pro, &off, &pri, &rm, &error, |
344 | 0 | &code1, &code2); |
345 | |
|
346 | 0 | if (num_items_scanned != 17) { |
347 | 0 | *err = WTAP_ERR_BAD_FILE; |
348 | 0 | *err_info = g_strdup("cosine: purported control blade line doesn't have code values"); |
349 | 0 | return false; |
350 | 0 | } |
351 | 0 | } else { |
352 | | /* appears to be output to PE */ |
353 | 0 | num_items_scanned = sscanf(line, |
354 | 0 | "%5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]", |
355 | 0 | direction, if_name, &pkt_len, |
356 | 0 | &pro, &off, &pri, &rm, &error, |
357 | 0 | &code1, &code2); |
358 | |
|
359 | 0 | if (num_items_scanned != 10) { |
360 | 0 | *err = WTAP_ERR_BAD_FILE; |
361 | 0 | *err_info = g_strdup("cosine: header line is neither control blade nor PE output"); |
362 | 0 | return false; |
363 | 0 | } |
364 | 0 | yy = mm = dd = hr = min = sec = csec = 0; |
365 | 0 | } |
366 | 0 | if (pkt_len < 0) { |
367 | 0 | *err = WTAP_ERR_BAD_FILE; |
368 | 0 | *err_info = g_strdup("cosine: packet header has a negative packet length"); |
369 | 0 | return false; |
370 | 0 | } |
371 | 0 | if ((unsigned)pkt_len > WTAP_MAX_PACKET_SIZE_STANDARD) { |
372 | | /* |
373 | | * Probably a corrupt capture file; don't blow up trying |
374 | | * to allocate space for an immensely-large packet. |
375 | | */ |
376 | 0 | *err = WTAP_ERR_BAD_FILE; |
377 | 0 | *err_info = ws_strdup_printf("cosine: File has %u-byte packet, bigger than maximum of %u", |
378 | 0 | (unsigned)pkt_len, WTAP_MAX_PACKET_SIZE_STANDARD); |
379 | 0 | return false; |
380 | 0 | } |
381 | | |
382 | 0 | wtap_setup_packet_rec(rec, wth->file_encap); |
383 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
384 | 0 | rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN; |
385 | 0 | tm.tm_year = yy - 1900; |
386 | 0 | tm.tm_mon = mm - 1; |
387 | 0 | tm.tm_mday = dd; |
388 | 0 | tm.tm_hour = hr; |
389 | 0 | tm.tm_min = min; |
390 | 0 | tm.tm_sec = sec; |
391 | 0 | tm.tm_isdst = -1; |
392 | 0 | rec->ts.secs = mktime(&tm); |
393 | 0 | rec->ts.nsecs = csec * 10000000; |
394 | 0 | rec->rec_header.packet_header.len = pkt_len; |
395 | | |
396 | | /* XXX need to handle other encapsulations like Cisco HDLC, |
397 | | Frame Relay and ATM */ |
398 | 0 | if (strncmp(if_name, "TEST:", 5) == 0) { |
399 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_TEST; |
400 | 0 | } else if (strncmp(if_name, "PPoATM:", 7) == 0) { |
401 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_PPoATM; |
402 | 0 | } else if (strncmp(if_name, "PPoFR:", 6) == 0) { |
403 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_PPoFR; |
404 | 0 | } else if (strncmp(if_name, "ATM:", 4) == 0) { |
405 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_ATM; |
406 | 0 | } else if (strncmp(if_name, "FR:", 3) == 0) { |
407 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_FR; |
408 | 0 | } else if (strncmp(if_name, "HDLC:", 5) == 0) { |
409 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_HDLC; |
410 | 0 | } else if (strncmp(if_name, "PPP:", 4) == 0) { |
411 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_PPP; |
412 | 0 | } else if (strncmp(if_name, "ETH:", 4) == 0) { |
413 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_ETH; |
414 | 0 | } else { |
415 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_UNKNOWN; |
416 | 0 | } |
417 | 0 | if (strncmp(direction, "l2-tx", 5) == 0) { |
418 | 0 | pseudo_header->cosine.direction = COSINE_DIR_TX; |
419 | 0 | } else if (strncmp(direction, "l2-rx", 5) == 0) { |
420 | 0 | pseudo_header->cosine.direction = COSINE_DIR_RX; |
421 | 0 | } |
422 | 0 | (void) g_strlcpy(pseudo_header->cosine.if_name, if_name, |
423 | 0 | COSINE_MAX_IF_NAME_LEN); |
424 | 0 | pseudo_header->cosine.pro = pro; |
425 | 0 | pseudo_header->cosine.off = off; |
426 | 0 | pseudo_header->cosine.pri = pri; |
427 | 0 | pseudo_header->cosine.rm = rm; |
428 | 0 | pseudo_header->cosine.err = error; |
429 | | |
430 | | /* Make sure we have enough room for the packet */ |
431 | 0 | ws_buffer_assure_space(&rec->data, pkt_len); |
432 | | |
433 | | /* Calculate the number of hex dump lines, each |
434 | | * containing 16 bytes of data */ |
435 | 0 | hex_lines = pkt_len / 16 + ((pkt_len % 16) ? 1 : 0); |
436 | |
|
437 | 0 | for (i = 0; i < hex_lines; i++) { |
438 | 0 | if (file_gets(line, COSINE_LINE_LENGTH, fh) == NULL) { |
439 | 0 | *err = file_error(fh, err_info); |
440 | 0 | if (*err == 0) { |
441 | 0 | *err = WTAP_ERR_SHORT_READ; |
442 | 0 | } |
443 | 0 | return false; |
444 | 0 | } |
445 | 0 | if (empty_line(line)) { |
446 | 0 | break; |
447 | 0 | } |
448 | 0 | if ((n = parse_single_hex_dump_line(line, &rec->data)) == -1) { |
449 | 0 | *err = WTAP_ERR_BAD_FILE; |
450 | 0 | *err_info = g_strdup("cosine: hex dump line doesn't have 16 numbers"); |
451 | 0 | return false; |
452 | 0 | } |
453 | 0 | caplen += n; |
454 | 0 | } |
455 | 0 | rec->rec_header.packet_header.caplen = caplen; |
456 | 0 | return true; |
457 | 0 | } |
458 | | |
459 | | /* Take a string representing one line from a hex dump and converts |
460 | | * the text to binary data. We place the bytes in the buffer at the |
461 | | * specified offset. |
462 | | * |
463 | | * Returns number of bytes successfully read, -1 if bad. */ |
464 | | static int |
465 | | parse_single_hex_dump_line(char* rec, Buffer *buf) |
466 | 0 | { |
467 | 0 | int num_items_scanned; |
468 | 0 | unsigned char bytes[16]; |
469 | |
|
470 | 0 | num_items_scanned = sscanf(rec, "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx", |
471 | 0 | &bytes[0], &bytes[1], &bytes[2], &bytes[3], |
472 | 0 | &bytes[4], &bytes[5], &bytes[6], &bytes[7], |
473 | 0 | &bytes[8], &bytes[9], &bytes[10], &bytes[11], |
474 | 0 | &bytes[12], &bytes[13], &bytes[14], &bytes[15]); |
475 | 0 | if (num_items_scanned <= 0) |
476 | 0 | return -1; |
477 | | |
478 | 0 | if (num_items_scanned > 16) |
479 | 0 | num_items_scanned = 16; |
480 | |
|
481 | 0 | ws_buffer_append(buf, bytes, num_items_scanned); |
482 | |
|
483 | 0 | return num_items_scanned; |
484 | 0 | } |
485 | | |
486 | | static const struct supported_block_type cosine_blocks_supported[] = { |
487 | | /* |
488 | | * We support packet blocks, with no comments or other options. |
489 | | */ |
490 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
491 | | }; |
492 | | |
493 | | static const struct file_type_subtype_info cosine_info = { |
494 | | "CoSine IPSX L2 capture", "cosine", "txt", NULL, |
495 | | false, BLOCKS_SUPPORTED(cosine_blocks_supported), |
496 | | NULL, NULL, NULL |
497 | | }; |
498 | | |
499 | | void register_cosine(void) |
500 | 16 | { |
501 | 16 | cosine_file_type_subtype = wtap_register_file_type_subtype(&cosine_info); |
502 | | |
503 | | /* |
504 | | * Register name for backwards compatibility with the |
505 | | * wtap_filetypes table in Lua. |
506 | | */ |
507 | 16 | wtap_register_backwards_compatibility_lua_name("COSINE", |
508 | 16 | cosine_file_type_subtype); |
509 | 16 | } |
510 | | |
511 | | /* |
512 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
513 | | * |
514 | | * Local variables: |
515 | | * c-basic-offset: 8 |
516 | | * tab-width: 8 |
517 | | * indent-tabs-mode: t |
518 | | * End: |
519 | | * |
520 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
521 | | * :indentSize=8:tabSize=8:noTabs=false: |
522 | | */ |