/src/wireshark/wiretap/cosine.c
Line | Count | Source (jump to first uncovered line) |
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-int.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(FILE_T fh, wtap_rec *rec, |
157 | | char *line, int *err, char **err_info); |
158 | | static int parse_single_hex_dump_line(char* rec, uint8_t *buf, |
159 | | unsigned byte_offset); |
160 | | |
161 | | static int cosine_file_type_subtype = -1; |
162 | | |
163 | | void register_cosine(void); |
164 | | |
165 | | /* Returns true if the line appears to be an empty line. Otherwise it |
166 | | returns false. */ |
167 | | static bool empty_line(const char *line) |
168 | 0 | { |
169 | 0 | while (*line) { |
170 | 0 | if (g_ascii_isspace(*line)) { |
171 | 0 | line++; |
172 | 0 | continue; |
173 | 0 | } else { |
174 | 0 | break; |
175 | 0 | } |
176 | 0 | } |
177 | 0 | if (*line == '\0') |
178 | 0 | return true; |
179 | 0 | else |
180 | 0 | return false; |
181 | 0 | } |
182 | | |
183 | | /* Seeks to the beginning of the next packet, and returns the |
184 | | byte offset. Copy the header line to hdr. Returns -1 on failure, |
185 | | and sets "*err" to the error and sets "*err_info" to null or an |
186 | | additional error string. */ |
187 | | static int64_t cosine_seek_next_packet(wtap *wth, int *err, char **err_info, |
188 | | char *hdr) |
189 | 0 | { |
190 | 0 | int64_t cur_off; |
191 | 0 | char buf[COSINE_LINE_LENGTH]; |
192 | |
|
193 | 0 | while (1) { |
194 | 0 | cur_off = file_tell(wth->fh); |
195 | 0 | if (cur_off == -1) { |
196 | | /* Error */ |
197 | 0 | *err = file_error(wth->fh, err_info); |
198 | 0 | return -1; |
199 | 0 | } |
200 | 0 | if (file_gets(buf, sizeof(buf), wth->fh) == NULL) { |
201 | 0 | *err = file_error(wth->fh, err_info); |
202 | 0 | return -1; |
203 | 0 | } |
204 | 0 | if (strstr(buf, COSINE_REC_MAGIC_STR1) || |
205 | 0 | strstr(buf, COSINE_REC_MAGIC_STR2)) { |
206 | 0 | (void) g_strlcpy(hdr, buf, COSINE_LINE_LENGTH); |
207 | 0 | return cur_off; |
208 | 0 | } |
209 | 0 | } |
210 | 0 | return -1; |
211 | 0 | } |
212 | | |
213 | | /* Look through the first part of a file to see if this is |
214 | | * a CoSine L2 debug output. |
215 | | * |
216 | | * Returns true if it is, false if it isn't or if we get an I/O error; |
217 | | * if we get an I/O error, "*err" will be set to a non-zero value and |
218 | | * "*err_info" will be set to null or an additional error string. |
219 | | */ |
220 | | static bool cosine_check_file_type(wtap *wth, int *err, char **err_info) |
221 | 0 | { |
222 | 0 | char buf[COSINE_LINE_LENGTH]; |
223 | 0 | size_t reclen; |
224 | 0 | unsigned line; |
225 | |
|
226 | 0 | buf[COSINE_LINE_LENGTH-1] = '\0'; |
227 | |
|
228 | 0 | for (line = 0; line < COSINE_HEADER_LINES_TO_CHECK; line++) { |
229 | 0 | if (file_gets(buf, COSINE_LINE_LENGTH, wth->fh) == NULL) { |
230 | | /* EOF or error. */ |
231 | 0 | *err = file_error(wth->fh, err_info); |
232 | 0 | return false; |
233 | 0 | } |
234 | | |
235 | 0 | reclen = strlen(buf); |
236 | 0 | if (reclen < MIN(strlen(COSINE_HDR_MAGIC_STR1), strlen(COSINE_HDR_MAGIC_STR2))) { |
237 | 0 | continue; |
238 | 0 | } |
239 | | |
240 | 0 | if (strstr(buf, COSINE_HDR_MAGIC_STR1) || |
241 | 0 | strstr(buf, COSINE_HDR_MAGIC_STR2)) { |
242 | 0 | return true; |
243 | 0 | } |
244 | 0 | } |
245 | 0 | *err = 0; |
246 | 0 | return false; |
247 | 0 | } |
248 | | |
249 | | |
250 | | wtap_open_return_val cosine_open(wtap *wth, int *err, char **err_info) |
251 | 0 | { |
252 | | /* Look for CoSine header */ |
253 | 0 | if (!cosine_check_file_type(wth, err, err_info)) { |
254 | 0 | if (*err != 0 && *err != WTAP_ERR_SHORT_READ) |
255 | 0 | return WTAP_OPEN_ERROR; |
256 | 0 | return WTAP_OPEN_NOT_MINE; |
257 | 0 | } |
258 | | |
259 | 0 | if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) /* rewind */ |
260 | 0 | return WTAP_OPEN_ERROR; |
261 | | |
262 | 0 | wth->file_encap = WTAP_ENCAP_COSINE; |
263 | 0 | wth->file_type_subtype = cosine_file_type_subtype; |
264 | 0 | wth->snapshot_length = 0; /* not known */ |
265 | 0 | wth->subtype_read = cosine_read; |
266 | 0 | wth->subtype_seek_read = cosine_seek_read; |
267 | 0 | wth->file_tsprec = WTAP_TSPREC_10_MSEC; |
268 | | |
269 | | /* |
270 | | * Add an IDB; we don't know how many interfaces were |
271 | | * involved, so we just say one interface, about which |
272 | | * we only know the link-layer type, snapshot length, |
273 | | * and time stamp resolution. |
274 | | */ |
275 | 0 | wtap_add_generated_idb(wth); |
276 | |
|
277 | 0 | return WTAP_OPEN_MINE; |
278 | 0 | } |
279 | | |
280 | | /* Find the next packet and parse it; called from wtap_read(). */ |
281 | | static bool cosine_read(wtap *wth, wtap_rec *rec, |
282 | | int *err, char **err_info, int64_t *data_offset) |
283 | 0 | { |
284 | 0 | int64_t offset; |
285 | 0 | char line[COSINE_LINE_LENGTH]; |
286 | | |
287 | | /* Find the next packet */ |
288 | 0 | offset = cosine_seek_next_packet(wth, err, err_info, line); |
289 | 0 | if (offset < 0) |
290 | 0 | return false; |
291 | 0 | *data_offset = offset; |
292 | | |
293 | | /* Parse the header and convert the ASCII hex dump to binary data */ |
294 | 0 | return parse_cosine_packet(wth->fh, rec, line, err, err_info); |
295 | 0 | } |
296 | | |
297 | | /* Used to read packets in random-access fashion */ |
298 | | static bool |
299 | | cosine_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, |
300 | | int *err, char **err_info) |
301 | 0 | { |
302 | 0 | char line[COSINE_LINE_LENGTH]; |
303 | |
|
304 | 0 | if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) |
305 | 0 | return false; |
306 | | |
307 | 0 | if (file_gets(line, COSINE_LINE_LENGTH, wth->random_fh) == NULL) { |
308 | 0 | *err = file_error(wth->random_fh, err_info); |
309 | 0 | if (*err == 0) { |
310 | 0 | *err = WTAP_ERR_SHORT_READ; |
311 | 0 | } |
312 | 0 | return false; |
313 | 0 | } |
314 | | |
315 | | /* Parse the header and convert the ASCII hex dump to binary data */ |
316 | 0 | return parse_cosine_packet(wth->random_fh, rec, line, err, err_info); |
317 | 0 | } |
318 | | |
319 | | /* Parses a packet record header. There are two possible formats: |
320 | | 1) output to a control blade with date and time |
321 | | 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] |
322 | | 2) output to PE without date and time |
323 | | l2-tx (FR:3/7/1:1), Length:18, Pro:0, Off:0, Pri:0, RM:0, Err:0 [0x4000, 0x0] */ |
324 | | static bool |
325 | | parse_cosine_packet(FILE_T fh, wtap_rec *rec, |
326 | | char *line, int *err, char **err_info) |
327 | 0 | { |
328 | 0 | union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header; |
329 | 0 | int num_items_scanned; |
330 | 0 | int yy, mm, dd, hr, min, sec, csec, pkt_len; |
331 | 0 | int pro, off, pri, rm, error; |
332 | 0 | unsigned code1, code2; |
333 | 0 | char if_name[COSINE_MAX_IF_NAME_LEN] = "", direction[6] = ""; |
334 | 0 | struct tm tm; |
335 | 0 | uint8_t *pd; |
336 | 0 | int i, hex_lines, n, caplen = 0; |
337 | |
|
338 | 0 | if (sscanf(line, "%4d-%2d-%2d,%2d:%2d:%2d.%9d:", |
339 | 0 | &yy, &mm, &dd, &hr, &min, &sec, &csec) == 7) { |
340 | | /* appears to be output to a control blade */ |
341 | 0 | num_items_scanned = sscanf(line, |
342 | 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]", |
343 | 0 | &yy, &mm, &dd, &hr, &min, &sec, &csec, |
344 | 0 | direction, if_name, &pkt_len, |
345 | 0 | &pro, &off, &pri, &rm, &error, |
346 | 0 | &code1, &code2); |
347 | |
|
348 | 0 | if (num_items_scanned != 17) { |
349 | 0 | *err = WTAP_ERR_BAD_FILE; |
350 | 0 | *err_info = g_strdup("cosine: purported control blade line doesn't have code values"); |
351 | 0 | return false; |
352 | 0 | } |
353 | 0 | } else { |
354 | | /* appears to be output to PE */ |
355 | 0 | num_items_scanned = sscanf(line, |
356 | 0 | "%5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]", |
357 | 0 | direction, if_name, &pkt_len, |
358 | 0 | &pro, &off, &pri, &rm, &error, |
359 | 0 | &code1, &code2); |
360 | |
|
361 | 0 | if (num_items_scanned != 10) { |
362 | 0 | *err = WTAP_ERR_BAD_FILE; |
363 | 0 | *err_info = g_strdup("cosine: header line is neither control blade nor PE output"); |
364 | 0 | return false; |
365 | 0 | } |
366 | 0 | yy = mm = dd = hr = min = sec = csec = 0; |
367 | 0 | } |
368 | 0 | if (pkt_len < 0) { |
369 | 0 | *err = WTAP_ERR_BAD_FILE; |
370 | 0 | *err_info = g_strdup("cosine: packet header has a negative packet length"); |
371 | 0 | return false; |
372 | 0 | } |
373 | 0 | if ((unsigned)pkt_len > WTAP_MAX_PACKET_SIZE_STANDARD) { |
374 | | /* |
375 | | * Probably a corrupt capture file; don't blow up trying |
376 | | * to allocate space for an immensely-large packet. |
377 | | */ |
378 | 0 | *err = WTAP_ERR_BAD_FILE; |
379 | 0 | *err_info = ws_strdup_printf("cosine: File has %u-byte packet, bigger than maximum of %u", |
380 | 0 | (unsigned)pkt_len, WTAP_MAX_PACKET_SIZE_STANDARD); |
381 | 0 | return false; |
382 | 0 | } |
383 | | |
384 | 0 | rec->rec_type = REC_TYPE_PACKET; |
385 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
386 | 0 | rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN; |
387 | 0 | tm.tm_year = yy - 1900; |
388 | 0 | tm.tm_mon = mm - 1; |
389 | 0 | tm.tm_mday = dd; |
390 | 0 | tm.tm_hour = hr; |
391 | 0 | tm.tm_min = min; |
392 | 0 | tm.tm_sec = sec; |
393 | 0 | tm.tm_isdst = -1; |
394 | 0 | rec->ts.secs = mktime(&tm); |
395 | 0 | rec->ts.nsecs = csec * 10000000; |
396 | 0 | rec->rec_header.packet_header.len = pkt_len; |
397 | | |
398 | | /* XXX need to handle other encapsulations like Cisco HDLC, |
399 | | Frame Relay and ATM */ |
400 | 0 | if (strncmp(if_name, "TEST:", 5) == 0) { |
401 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_TEST; |
402 | 0 | } else if (strncmp(if_name, "PPoATM:", 7) == 0) { |
403 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_PPoATM; |
404 | 0 | } else if (strncmp(if_name, "PPoFR:", 6) == 0) { |
405 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_PPoFR; |
406 | 0 | } else if (strncmp(if_name, "ATM:", 4) == 0) { |
407 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_ATM; |
408 | 0 | } else if (strncmp(if_name, "FR:", 3) == 0) { |
409 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_FR; |
410 | 0 | } else if (strncmp(if_name, "HDLC:", 5) == 0) { |
411 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_HDLC; |
412 | 0 | } else if (strncmp(if_name, "PPP:", 4) == 0) { |
413 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_PPP; |
414 | 0 | } else if (strncmp(if_name, "ETH:", 4) == 0) { |
415 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_ETH; |
416 | 0 | } else { |
417 | 0 | pseudo_header->cosine.encap = COSINE_ENCAP_UNKNOWN; |
418 | 0 | } |
419 | 0 | if (strncmp(direction, "l2-tx", 5) == 0) { |
420 | 0 | pseudo_header->cosine.direction = COSINE_DIR_TX; |
421 | 0 | } else if (strncmp(direction, "l2-rx", 5) == 0) { |
422 | 0 | pseudo_header->cosine.direction = COSINE_DIR_RX; |
423 | 0 | } |
424 | 0 | (void) g_strlcpy(pseudo_header->cosine.if_name, if_name, |
425 | 0 | COSINE_MAX_IF_NAME_LEN); |
426 | 0 | pseudo_header->cosine.pro = pro; |
427 | 0 | pseudo_header->cosine.off = off; |
428 | 0 | pseudo_header->cosine.pri = pri; |
429 | 0 | pseudo_header->cosine.rm = rm; |
430 | 0 | pseudo_header->cosine.err = error; |
431 | | |
432 | | /* Make sure we have enough room for the packet */ |
433 | 0 | ws_buffer_assure_space(&rec->data, pkt_len); |
434 | 0 | pd = ws_buffer_start_ptr(&rec->data); |
435 | | |
436 | | /* Calculate the number of hex dump lines, each |
437 | | * containing 16 bytes of data */ |
438 | 0 | hex_lines = pkt_len / 16 + ((pkt_len % 16) ? 1 : 0); |
439 | |
|
440 | 0 | for (i = 0; i < hex_lines; i++) { |
441 | 0 | if (file_gets(line, COSINE_LINE_LENGTH, fh) == NULL) { |
442 | 0 | *err = file_error(fh, err_info); |
443 | 0 | if (*err == 0) { |
444 | 0 | *err = WTAP_ERR_SHORT_READ; |
445 | 0 | } |
446 | 0 | return false; |
447 | 0 | } |
448 | 0 | if (empty_line(line)) { |
449 | 0 | break; |
450 | 0 | } |
451 | 0 | if ((n = parse_single_hex_dump_line(line, pd, i*16)) == -1) { |
452 | 0 | *err = WTAP_ERR_BAD_FILE; |
453 | 0 | *err_info = g_strdup("cosine: hex dump line doesn't have 16 numbers"); |
454 | 0 | return false; |
455 | 0 | } |
456 | 0 | caplen += n; |
457 | 0 | } |
458 | 0 | rec->rec_header.packet_header.caplen = caplen; |
459 | 0 | return true; |
460 | 0 | } |
461 | | |
462 | | /* Take a string representing one line from a hex dump and converts |
463 | | * the text to binary data. We place the bytes in the buffer at the |
464 | | * specified offset. |
465 | | * |
466 | | * Returns number of bytes successfully read, -1 if bad. */ |
467 | | static int |
468 | | parse_single_hex_dump_line(char* rec, uint8_t *buf, unsigned byte_offset) |
469 | 0 | { |
470 | 0 | int num_items_scanned, i; |
471 | 0 | unsigned int bytes[16]; |
472 | |
|
473 | 0 | num_items_scanned = sscanf(rec, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", |
474 | 0 | &bytes[0], &bytes[1], &bytes[2], &bytes[3], |
475 | 0 | &bytes[4], &bytes[5], &bytes[6], &bytes[7], |
476 | 0 | &bytes[8], &bytes[9], &bytes[10], &bytes[11], |
477 | 0 | &bytes[12], &bytes[13], &bytes[14], &bytes[15]); |
478 | 0 | if (num_items_scanned == 0) |
479 | 0 | return -1; |
480 | | |
481 | 0 | if (num_items_scanned > 16) |
482 | 0 | num_items_scanned = 16; |
483 | |
|
484 | 0 | for (i=0; i<num_items_scanned; i++) { |
485 | 0 | buf[byte_offset + i] = (uint8_t)bytes[i]; |
486 | 0 | } |
487 | |
|
488 | 0 | return num_items_scanned; |
489 | 0 | } |
490 | | |
491 | | static const struct supported_block_type cosine_blocks_supported[] = { |
492 | | /* |
493 | | * We support packet blocks, with no comments or other options. |
494 | | */ |
495 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
496 | | }; |
497 | | |
498 | | static const struct file_type_subtype_info cosine_info = { |
499 | | "CoSine IPSX L2 capture", "cosine", "txt", NULL, |
500 | | false, BLOCKS_SUPPORTED(cosine_blocks_supported), |
501 | | NULL, NULL, NULL |
502 | | }; |
503 | | |
504 | | void register_cosine(void) |
505 | 2 | { |
506 | 2 | cosine_file_type_subtype = wtap_register_file_type_subtype(&cosine_info); |
507 | | |
508 | | /* |
509 | | * Register name for backwards compatibility with the |
510 | | * wtap_filetypes table in Lua. |
511 | | */ |
512 | 2 | wtap_register_backwards_compatibility_lua_name("COSINE", |
513 | 2 | cosine_file_type_subtype); |
514 | 2 | } |
515 | | |
516 | | /* |
517 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
518 | | * |
519 | | * Local variables: |
520 | | * c-basic-offset: 8 |
521 | | * tab-width: 8 |
522 | | * indent-tabs-mode: t |
523 | | * End: |
524 | | * |
525 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
526 | | * :indentSize=8:tabSize=8:noTabs=false: |
527 | | */ |