/src/wireshark/wiretap/iseries.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* iseries.c |
2 | | * |
3 | | * Wiretap Library |
4 | | * Copyright (c) 2011 by Martin Warnes <Martin_Warnes@uk.ibm.com> |
5 | | * |
6 | | * Based on toshiba.c and vms.c |
7 | | * |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | */ |
10 | | |
11 | | /* |
12 | | * This module will read the contents of the iSeries (OS/400) Communication trace |
13 | | * Both ASCII & Unicode (little-endian UCS-2) formatted traces are supported. |
14 | | * |
15 | | * iSeries Comms traces consist of a header page and a subsequent number of packet records |
16 | | * |
17 | | * The header page contains details on the options set during running of the trace, |
18 | | * currently the following options are a requirement for this module: |
19 | | * |
20 | | * 1. Object protocol = ETHERNET (Default) |
21 | | * 2. ASCII or Unicode file formats. |
22 | | * |
23 | | * The above can be achieved by passing option ASCII(*YES) with the trace command |
24 | | * |
25 | | */ |
26 | | |
27 | | /* iSeries header page |
28 | | |
29 | | COMMUNICATIONS TRACE Title: OS400 - OS400 trace 10/28/05 11:44:50 Page: 1 |
30 | | Trace Description . . . . . : OS400 - OS400 trace |
31 | | Configuration object . . . . : ETH0 |
32 | | Type . . . . . . . . . . . . : 1 1=Line, 2=Network Interface |
33 | | 3=Network server |
34 | | Object protocol . . . . . . : ETHERNET |
35 | | Start date/Time . . . . . . : 10/28/05 11:43:00.341 |
36 | | End date/Time . . . . . . . : 10/28/05 11:44:22.148 |
37 | | Bytes collected . . . . . . : 11999 |
38 | | Buffer size . . . . . . . . : 2048 kilobytes |
39 | | Data direction . . . . . . . : 3 1=Sent, 2=Received, 3=Both |
40 | | Stop on buffer full . . . . : Y Y=Yes, N=No |
41 | | Number of bytes to trace |
42 | | Beginning bytes . . . . . : *MAX Value, *CALC, *MAX |
43 | | Ending bytes . . . . . . : *CALC Value, *CALC |
44 | | Controller name . . . . . . : *ALL *ALL, name |
45 | | Data representation . . . . : 1 1=ASCII, 2=EBCDIC, 3=*CALC |
46 | | Format SNA data only . . . . : N Y=Yes, N=No |
47 | | Format RR, RNR commands . . : N Y=Yes, N=No |
48 | | Format TCP/IP data only . . : Y Y=Yes, N=No |
49 | | IP address . . . . . . . . : *ALL *ALL, address |
50 | | IP address . . . . . . . . : *ALL *ALL, address |
51 | | IP port . . . . . . . . . : *ALL *ALL, IP port |
52 | | Format UI data only . . . . : N Y=Yes, N=No |
53 | | Select Ethernet data . . . . : 3 1=802.3, 2=ETHV2, 3=Both |
54 | | Format Broadcast data . . . : Y Y=Yes, N=No |
55 | | */ |
56 | | |
57 | | /* iSeries IPv4 formatted packet records consist of a packet header line |
58 | | * identifying the packet number, direction, size, timestamp, |
59 | | * source/destination MAC addresses and packet type. |
60 | | * |
61 | | * Thereafter there will be a formatted display of the headers above |
62 | | * the link layer, such as ARP, IP, TCP, UDP, and ICMP (all but |
63 | | * ICMP have either been seen in captures or on pages such as the ones |
64 | | * at |
65 | | * |
66 | | * http://www-912.ibm.com/s_dir/SLKBase.nsf/1ac66549a21402188625680b0002037e/e05fb0515bc3449686256ce600512c37?OpenDocument |
67 | | * |
68 | | * and |
69 | | * |
70 | | * http://publib.boulder.ibm.com/infocenter/javasdk/v5r0/index.jsp?topic=%2Fcom.ibm.java.doc.diagnostics.50%2Fdiag%2Fproblem_determination%2Fi5os_perf_io_commstrace.html |
71 | | * |
72 | | * so we cannot assume that "IP Header" or "TCP Header" will appear). The |
73 | | * formatted display includes lines that show the contents of some of the |
74 | | * fields in the header, as well as hex strings dumps of the headers |
75 | | * themselves, with tags such as "IP Header :", "ARP Header :", |
76 | | * "TCP Header :", "UDP Header :", and (presumably) "ICMP Header:". |
77 | | * |
78 | | * If the packet contains data this is displayed as 4 groups of 16 hex digits |
79 | | * followed by an ASCII representation of the data line. |
80 | | * |
81 | | * Information from the packet header line, higher-level headers and, if |
82 | | * available, data lines are extracted by the module for displaying. |
83 | | * |
84 | | * |
85 | | Record Data Record Controller Destination Source Frame |
86 | | Number S/R Length Timer Name MAC Address MAC Address Format |
87 | | ------ --- ------ --------------- ---------- ------------ ------------ ------ |
88 | | 8 S 145 11:43:59.82956 0006299C14AE 0006299C14FE ETHV2 Type: 0800 |
89 | | Frame Type : IP DSCP: 0 ECN: 00-NECT Length: 145 Protocol: TCP Datagram ID: 388B |
90 | | Src Addr: 10.20.144.150 Dest Addr: 10.20.144.151 Fragment Flags: DON'T,LAST |
91 | | IP Header : 45000091388B40004006CC860A1490960A149097 |
92 | | IP Options : NONE |
93 | | TCP . . . : Src Port: 6006,Unassigned Dest Port: 35366,Unassigned |
94 | | SEQ Number: 2666470699 ('9EEF1D2B'X) ACK Number: 2142147535 ('7FAE93CF'X) |
95 | | Code Bits: ACK PSH Window: 32648 TCP Option: NO OP |
96 | | TCP Header : 17768A269EEF1D2B7FAE93CF80187F885B5600000101080A0517E0F805166DE0 |
97 | | Data . . . . . : 5443503200020010 0000004980000000 B800000080470103 01001E0000002000 *TCP2.......I*...*...*G........ .* |
98 | | 002F010080000004 0300800700C00600 4002008000000304 00800000060FB067 *./..*.....*..*..@..*.....*....*G* |
99 | | FC276228786B3EB0 EF34F5F1D27EF8DF 20926820E7B322AA 739F1FB20D **'B(XK>**4***.** *H **"*S*.*. * |
100 | | */ |
101 | | |
102 | | /* iSeries IPv6 formatted traces are similar to the IPv4 version above, |
103 | | * except that the higher-level headers have "IPv6 Header:" and |
104 | | * "ICMPv6 Hdr:", and data is no longer output in groups of 16 hex |
105 | | * digits. |
106 | | * |
107 | | |
108 | | Record Data Record Destination Source Frame |
109 | | Number S/R Length Timer MAC Address MAC Address Format |
110 | | ------ --- ------ ------------ ------------ ------------ ------ |
111 | | 218 S 1488 15:01:14.389 0011BC358680 00096B6BD918 ETHV2 Type: 86DD |
112 | | IPv6 Data: Ver: 06 Traffic Class: 00 Flow Label: 000000 |
113 | | Payload Length: 1448 Next Header: 06,TCP Hop Limit: 64 |
114 | | Src Addr: fd00:0:0:20f2::122 |
115 | | Dest Addr: fd00:0:0:20a0::155 |
116 | | IPv6 Header: 6000000005A80640FD000000000020F20000000000000122FD000000000020A0 |
117 | | 0000000000000155 |
118 | | TCP . . . : Src Port: 21246,Unassigned Dest Port: 13601,Unassigned |
119 | | SEQ Number: 2282300877 ('880925CD'X) ACK Number: 3259003715 ('C2407343'X) |
120 | | Code Bits: ACK Window: 65535 TCP Option: NO OP |
121 | | TCP Header : 52FE3521880925CDC24073438010FFFFCFBB00000101080A0E15127000237A08 |
122 | | Data . . . . . : 54435032000200140000061880000000ECBEB867F0000000004CE640E6C1D9D5 *TCP2........*...***g*....L*@***** |
123 | | C9D5C740E3C8C9E240C9E240E3C8C540E6C1D9D5C9D5C740C6C9C5D3C4404040 ****@****@**@***@*******@*****@@@* |
124 | | 4040404040404040404040404040404040404040404040404040404040404040 *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* |
125 | | */ |
126 | | |
127 | | /* iSeries unformatted packet record consist of the same header record as |
128 | | * the formatted trace but all other records are simply unformatted data |
129 | | * containing higher-level headers and packet data combined. |
130 | | * |
131 | | Record Data Record Controller Destination Source Frame Number Number Poll/ |
132 | | Number S/R Length Timer Name MAC Address MAC Address Format Command Sent Received Final DSAP SSAP |
133 | | ------ --- ------ --------------- ---------- ------------ ------------ ------ ------- ------ -------- ----- ---- ---- |
134 | | 1 R 64 12:19:29.97108 000629ECF48E 0006D78E23C2 ETHV2 Type: 0800 |
135 | | Data . . . . . : 4500003C27954000 3A06CE3D9797440F 0A5964EAC4F50554 58C9915500000000 *E..<'*@.:.*=**D..YD***.TX**U....* |
136 | | A00216D06A200000 020405B40402080A 1104B6C000000000 010303000B443BF1 **..*J .....*......**.........D;** |
137 | | */ |
138 | | |
139 | | #include "config.h" |
140 | | #include "iseries.h" |
141 | | #include "wtap-int.h" |
142 | | #include "file_wrappers.h" |
143 | | |
144 | | #include <stdlib.h> |
145 | | #include <string.h> |
146 | | |
147 | | #include <wsutil/str_util.h> |
148 | | #include <wsutil/strtoi.h> |
149 | | #include <wsutil/ws_assert.h> |
150 | | |
151 | 0 | #define ISERIES_LINE_LENGTH 270 |
152 | 0 | #define ISERIES_HDR_LINES_TO_CHECK 100 |
153 | 0 | #define ISERIES_PKT_LINES_TO_CHECK 4 |
154 | 0 | #define ISERIES_MAX_TRACE_LEN 99999999 |
155 | 0 | #define ISERIES_FORMAT_ASCII 1 |
156 | 0 | #define ISERIES_FORMAT_UNICODE 2 |
157 | | |
158 | | /* |
159 | | * Magic strings - "COMMUNICATIONS TRACE", in ASCII and little-endian UCS-2. |
160 | | */ |
161 | | static const char iseries_hdr_magic_ascii[] = { |
162 | | 'C', 'O', 'M', 'M', |
163 | | 'U', 'N', 'I', 'C', |
164 | | 'A', 'T', 'I', 'O', |
165 | | 'N', 'S', ' ', 'T', |
166 | | 'R', 'A', 'C', 'E' |
167 | | }; |
168 | | static const char iseries_hdr_magic_le_ucs_2[] = { |
169 | | 'C', 0x0, 'O', 0x0, 'M', 0x0, 'M', 0x0, |
170 | | 'U', 0x0, 'N', 0x0, 'I', 0x0, 'C', 0x0, |
171 | | 'A', 0x0, 'T', 0x0, 'I', 0x0, 'O', 0x0, |
172 | | 'N', 0x0, 'S', 0x0, ' ', 0x0, 'T', 0x0, |
173 | | 'R', 0x0, 'A', 0x0, 'C', 0x0, 'E', 0x0 |
174 | | }; |
175 | | |
176 | | typedef struct { |
177 | | bool have_date; /* true if we found a capture start date */ |
178 | | int year, month, day; /* The start date */ |
179 | | int format; /* Trace format type */ |
180 | | } iseries_t; |
181 | | |
182 | | static bool iseries_read (wtap * wth, wtap_rec *rec, |
183 | | int *err, char ** err_info, int64_t *data_offset); |
184 | | static bool iseries_seek_read (wtap * wth, int64_t seek_off, |
185 | | wtap_rec *rec, |
186 | | int *err, char ** err_info); |
187 | | static bool iseries_check_file_type (wtap * wth, int *err, char **err_info, |
188 | | int format); |
189 | | static int64_t iseries_seek_next_packet (wtap * wth, int *err, char **err_info); |
190 | | static bool iseries_parse_packet (wtap * wth, FILE_T fh, |
191 | | wtap_rec *rec, |
192 | | int *err, char ** err_info); |
193 | | static int iseries_UNICODE_to_ASCII (uint8_t * buf, unsigned bytes); |
194 | | static bool iseries_parse_hex_string (const char * ascii, uint8_t * buf, |
195 | | size_t len); |
196 | | |
197 | | static int iseries_file_type_subtype = -1; |
198 | | static int iseries_unicode_file_type_subtype = -1; |
199 | | |
200 | | void register_iseries(void); |
201 | | |
202 | | /* |
203 | | * XXX - it would probably be cleaner to use a UCS-2 flavor of file_gets(), |
204 | | * rather than file_gets(), if we're reading a UCS-2 file. |
205 | | */ |
206 | | wtap_open_return_val |
207 | | iseries_open (wtap * wth, int *err, char ** err_info) |
208 | 0 | { |
209 | 0 | int offset; |
210 | 0 | char magic[ISERIES_LINE_LENGTH]; |
211 | | |
212 | | /* |
213 | | * Check that file starts with a valid iSeries COMMS TRACE header |
214 | | * by scanning for it in the first line |
215 | | */ |
216 | 0 | if (!wtap_read_bytes (wth->fh, &magic, sizeof magic, err, err_info)) |
217 | 0 | { |
218 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
219 | 0 | return WTAP_OPEN_ERROR; |
220 | 0 | return WTAP_OPEN_NOT_MINE; |
221 | 0 | } |
222 | | |
223 | | /* |
224 | | * Check if this is a little-endian UCS-2 Unicode formatted file by scanning |
225 | | * for the magic string |
226 | | */ |
227 | 0 | offset=0; |
228 | 0 | while ((unsigned int)offset < (ISERIES_LINE_LENGTH - (sizeof iseries_hdr_magic_le_ucs_2))) |
229 | 0 | { |
230 | 0 | if (memcmp (magic + offset, iseries_hdr_magic_le_ucs_2, sizeof iseries_hdr_magic_le_ucs_2) == 0) { |
231 | 0 | if (file_seek (wth->fh, 0, SEEK_SET, err) == -1) |
232 | 0 | { |
233 | 0 | return WTAP_OPEN_ERROR; |
234 | 0 | } |
235 | | /* |
236 | | * Do some basic sanity checking to ensure we can handle the |
237 | | * contents of this trace |
238 | | */ |
239 | 0 | if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_UNICODE)) |
240 | 0 | { |
241 | 0 | if (*err == 0) |
242 | 0 | return WTAP_OPEN_NOT_MINE; |
243 | 0 | else |
244 | 0 | return WTAP_OPEN_ERROR; |
245 | 0 | } |
246 | | |
247 | 0 | wth->file_encap = WTAP_ENCAP_ETHERNET; |
248 | 0 | wth->file_type_subtype = iseries_unicode_file_type_subtype; |
249 | 0 | wth->snapshot_length = 0; |
250 | 0 | wth->subtype_read = iseries_read; |
251 | 0 | wth->subtype_seek_read = iseries_seek_read; |
252 | 0 | wth->file_tsprec = WTAP_TSPREC_USEC; |
253 | |
|
254 | 0 | if (file_seek (wth->fh, 0, SEEK_SET, err) == -1) |
255 | 0 | { |
256 | 0 | return WTAP_OPEN_ERROR; |
257 | 0 | } |
258 | | |
259 | | /* |
260 | | * Add an IDB; we don't know how many interfaces were |
261 | | * involved, so we just say one interface, about which |
262 | | * we only know the link-layer type, snapshot length, |
263 | | * and time stamp resolution. |
264 | | */ |
265 | 0 | wtap_add_generated_idb(wth); |
266 | |
|
267 | 0 | return WTAP_OPEN_MINE; |
268 | 0 | } |
269 | 0 | offset += 1; |
270 | 0 | } |
271 | | |
272 | | /* |
273 | | * Check if this is a ASCII formatted file by scanning for the magic string |
274 | | */ |
275 | 0 | offset=0; |
276 | 0 | while ((unsigned int)offset < (ISERIES_LINE_LENGTH - sizeof iseries_hdr_magic_ascii)) |
277 | 0 | { |
278 | 0 | if (memcmp (magic + offset, iseries_hdr_magic_ascii, sizeof iseries_hdr_magic_ascii) == 0) |
279 | 0 | { |
280 | 0 | if (file_seek (wth->fh, 0, SEEK_SET, err) == -1) |
281 | 0 | { |
282 | 0 | return WTAP_OPEN_ERROR; |
283 | 0 | } |
284 | | /* |
285 | | * Do some basic sanity checking to ensure we can handle the |
286 | | * contents of this trace |
287 | | */ |
288 | 0 | if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_ASCII)) |
289 | 0 | { |
290 | 0 | if (*err == 0) |
291 | 0 | return WTAP_OPEN_NOT_MINE; |
292 | 0 | else |
293 | 0 | return WTAP_OPEN_ERROR; |
294 | 0 | } |
295 | | |
296 | 0 | wth->file_encap = WTAP_ENCAP_ETHERNET; |
297 | 0 | wth->file_type_subtype = iseries_file_type_subtype; |
298 | 0 | wth->snapshot_length = 0; |
299 | 0 | wth->subtype_read = iseries_read; |
300 | 0 | wth->subtype_seek_read = iseries_seek_read; |
301 | 0 | wth->file_tsprec = WTAP_TSPREC_USEC; |
302 | |
|
303 | 0 | if (file_seek (wth->fh, 0, SEEK_SET, err) == -1) |
304 | 0 | { |
305 | 0 | return WTAP_OPEN_ERROR; |
306 | 0 | } |
307 | | |
308 | | /* |
309 | | * Add an IDB; we don't know how many interfaces were |
310 | | * involved, so we just say one interface, about which |
311 | | * we only know the link-layer type, snapshot length, |
312 | | * and time stamp resolution. |
313 | | */ |
314 | 0 | wtap_add_generated_idb(wth); |
315 | |
|
316 | 0 | return WTAP_OPEN_MINE; |
317 | 0 | } |
318 | 0 | offset += 1; |
319 | 0 | } |
320 | | |
321 | | /* Neither ASCII or UNICODE so not supported */ |
322 | 0 | return WTAP_OPEN_NOT_MINE; |
323 | 0 | } |
324 | | |
325 | | /* |
326 | | * Do some basic sanity checking to ensure we can handle the |
327 | | * contents of this trace by checking the header page for |
328 | | * requisite requirements and additional information. |
329 | | */ |
330 | | static bool |
331 | | iseries_check_file_type (wtap * wth, int *err, char **err_info, int format) |
332 | 0 | { |
333 | 0 | bool is_iseries = false; |
334 | 0 | unsigned line; |
335 | 0 | int num_items_scanned; |
336 | 0 | char buf[ISERIES_LINE_LENGTH], protocol[9]; |
337 | 0 | iseries_t *iseries; |
338 | | |
339 | | /* Save trace format for passing between packets */ |
340 | 0 | iseries = g_new(iseries_t, 1); |
341 | 0 | iseries->have_date = false; |
342 | 0 | iseries->format = format; |
343 | |
|
344 | 0 | for (line = 0; line < ISERIES_HDR_LINES_TO_CHECK; line++) |
345 | 0 | { |
346 | 0 | memset(buf, 0x0, sizeof(buf)); |
347 | 0 | if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL) |
348 | 0 | { |
349 | | /* EOF or error. */ |
350 | 0 | *err = file_error (wth->fh, err_info); |
351 | 0 | if (*err == WTAP_ERR_SHORT_READ) |
352 | 0 | *err = 0; |
353 | 0 | break; |
354 | 0 | } |
355 | | |
356 | | /* |
357 | | * Check that we are dealing with an ETHERNET trace |
358 | | */ |
359 | 0 | if (iseries->format == ISERIES_FORMAT_UNICODE) |
360 | 0 | { |
361 | 0 | iseries_UNICODE_to_ASCII ((uint8_t *)buf, ISERIES_LINE_LENGTH); |
362 | 0 | } |
363 | 0 | ascii_strup_inplace (buf); |
364 | 0 | num_items_scanned = sscanf (buf, |
365 | 0 | "%*[ \n\t]OBJECT PROTOCOL%*[ .:\n\t]%8s", |
366 | 0 | protocol); |
367 | 0 | if (num_items_scanned == 1) |
368 | 0 | { |
369 | 0 | if (memcmp (protocol, "ETHERNET", 8) == 0) |
370 | 0 | { |
371 | 0 | *err = 0; |
372 | 0 | is_iseries = true; |
373 | 0 | } |
374 | 0 | } |
375 | | |
376 | | /* |
377 | | * The header is the only place where the date part of the timestamp is held, so |
378 | | * extract it here and store for all packets to access |
379 | | */ |
380 | 0 | num_items_scanned = sscanf (buf, |
381 | 0 | "%*[ \n\t]START DATE/TIME%*[ .:\n\t]%2d/%2d/%2d", |
382 | 0 | &iseries->month, &iseries->day, |
383 | 0 | &iseries->year); |
384 | 0 | if (num_items_scanned == 3) |
385 | 0 | { |
386 | 0 | iseries->have_date = true; |
387 | 0 | } |
388 | 0 | } |
389 | |
|
390 | 0 | if (is_iseries) |
391 | 0 | wth->priv = (void *) iseries; |
392 | 0 | else |
393 | 0 | g_free(iseries); |
394 | |
|
395 | 0 | return is_iseries; |
396 | 0 | } |
397 | | |
398 | | /* |
399 | | * Find the next packet and parse it; called from wtap_read(). |
400 | | */ |
401 | | static bool |
402 | | iseries_read (wtap * wth, wtap_rec *rec, int *err, char ** err_info, |
403 | | int64_t *data_offset) |
404 | 0 | { |
405 | 0 | int64_t offset; |
406 | | |
407 | | /* |
408 | | * Locate the next packet |
409 | | */ |
410 | 0 | offset = iseries_seek_next_packet (wth, err, err_info); |
411 | 0 | if (offset < 0) |
412 | 0 | return false; |
413 | 0 | *data_offset = offset; |
414 | | |
415 | | /* |
416 | | * Parse the packet and extract the various fields |
417 | | */ |
418 | 0 | return iseries_parse_packet (wth, wth->fh, rec, err, err_info); |
419 | 0 | } |
420 | | |
421 | | /* |
422 | | * Seeks to the beginning of the next packet, and returns the |
423 | | * byte offset. Returns -1 on failure or EOF; on EOF, sets |
424 | | * *err to 0, and, on failure, sets *err to the error and *err_info |
425 | | * to null or an additional error string. |
426 | | */ |
427 | | static int64_t |
428 | | iseries_seek_next_packet (wtap * wth, int *err, char **err_info) |
429 | 0 | { |
430 | 0 | iseries_t *iseries = (iseries_t *)wth->priv; |
431 | 0 | char buf[ISERIES_LINE_LENGTH],type[5]; |
432 | 0 | int line, num_items_scanned; |
433 | 0 | int64_t cur_off; |
434 | 0 | long buflen; |
435 | |
|
436 | 0 | for (line = 0; line < ISERIES_MAX_TRACE_LEN; line++) |
437 | 0 | { |
438 | 0 | if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL) |
439 | 0 | { |
440 | | /* EOF or error. */ |
441 | 0 | *err = file_error (wth->fh, err_info); |
442 | 0 | return -1; |
443 | 0 | } |
444 | | /* Convert UNICODE to ASCII if required and determine */ |
445 | | /* the number of bytes to rewind to beginning of record. */ |
446 | 0 | if (iseries->format == ISERIES_FORMAT_UNICODE) |
447 | 0 | { |
448 | | /* buflen is #bytes to 1st 0x0A */ |
449 | 0 | buflen = iseries_UNICODE_to_ASCII ((uint8_t *) buf, ISERIES_LINE_LENGTH); |
450 | 0 | } |
451 | 0 | else |
452 | 0 | { |
453 | | /* Else buflen is just length of the ASCII string */ |
454 | 0 | buflen = (long) strlen (buf); |
455 | 0 | } |
456 | 0 | ascii_strup_inplace (buf); |
457 | | /* Check we have enough data in the line */ |
458 | 0 | if (buflen < 78) |
459 | 0 | { |
460 | 0 | continue; |
461 | 0 | } |
462 | | /* If packet header found return the offset */ |
463 | 0 | num_items_scanned = |
464 | 0 | sscanf (buf+78, |
465 | 0 | "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type); |
466 | 0 | if (num_items_scanned == 1) |
467 | 0 | { |
468 | | /* Rewind to beginning of line */ |
469 | 0 | cur_off = file_tell (wth->fh); |
470 | 0 | if (cur_off == -1) |
471 | 0 | { |
472 | 0 | *err = file_error (wth->fh, err_info); |
473 | 0 | return -1; |
474 | 0 | } |
475 | 0 | if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1) |
476 | 0 | { |
477 | 0 | return -1; |
478 | 0 | } |
479 | 0 | return cur_off - buflen; |
480 | 0 | } |
481 | 0 | } |
482 | | |
483 | 0 | *err = WTAP_ERR_BAD_FILE; |
484 | 0 | *err_info = |
485 | 0 | ws_strdup_printf ("iseries: next packet header not found within %d lines", |
486 | 0 | ISERIES_MAX_TRACE_LEN); |
487 | 0 | return -1; |
488 | 0 | } |
489 | | |
490 | | /* |
491 | | * Read packets in random-access fashion |
492 | | */ |
493 | | static bool |
494 | | iseries_seek_read (wtap * wth, int64_t seek_off, wtap_rec *rec, |
495 | | int *err, char ** err_info) |
496 | 0 | { |
497 | | |
498 | | /* seek to packet location */ |
499 | 0 | if (file_seek (wth->random_fh, seek_off - 1, SEEK_SET, err) == -1) |
500 | 0 | return false; |
501 | | |
502 | | /* |
503 | | * Parse the packet and extract the various fields |
504 | | */ |
505 | 0 | return iseries_parse_packet (wth, wth->random_fh, rec, err, err_info); |
506 | 0 | } |
507 | | |
508 | | static int |
509 | | append_hex_digits(char *ascii_buf, int ascii_offset, int max_offset, |
510 | | char *data, int *err, char **err_info) |
511 | 0 | { |
512 | 0 | int in_offset, out_offset; |
513 | 0 | int c; |
514 | 0 | unsigned int i; |
515 | 0 | bool overflow = false; |
516 | |
|
517 | 0 | in_offset = 0; |
518 | 0 | out_offset = ascii_offset; |
519 | 0 | for (;;) |
520 | 0 | { |
521 | | /* |
522 | | * Process a block of up to 16 hex digits. |
523 | | * The block is terminated early by an end-of-line indication (NUL, |
524 | | * CR, or LF), by a space (which terminates the last block of the |
525 | | * data we're processing), or by a "*", which introduces the ASCII representation |
526 | | * of the data. |
527 | | * All characters in the block must be upper-case hex digits; |
528 | | * there might or might not be a space *after* a block, but, if so, |
529 | | * that will be skipped over after the block is processed. |
530 | | */ |
531 | 0 | for (i = 0; i < 16; i++, in_offset++) |
532 | 0 | { |
533 | | /* |
534 | | * If we see an end-of-line indication, or an early-end-of-block |
535 | | * indication (space), we're done. (Only the last block ends |
536 | | * early.) |
537 | | */ |
538 | 0 | c = data[in_offset] & 0xFF; |
539 | 0 | if (c == '\0' || c == ' ' || c == '*' || c == '\r' || c == '\n') |
540 | 0 | { |
541 | 0 | goto done; |
542 | 0 | } |
543 | 0 | if (!g_ascii_isxdigit(c) || g_ascii_islower(c)) |
544 | 0 | { |
545 | | /* |
546 | | * Not a hex digit, or a lower-case hex digit. |
547 | | * Treat this as an indication that the line isn't a data |
548 | | * line, so we just ignore it. |
549 | | * |
550 | | * XXX - do so only for continuation lines; treat non-hex-digit |
551 | | * characters as errors for other lines? |
552 | | */ |
553 | 0 | return ascii_offset; /* pretend we appended nothing */ |
554 | 0 | } |
555 | 0 | if (out_offset >= max_offset) |
556 | 0 | overflow = true; |
557 | 0 | else |
558 | 0 | { |
559 | 0 | ascii_buf[out_offset] = c; |
560 | 0 | out_offset++; |
561 | 0 | } |
562 | 0 | } |
563 | | /* |
564 | | * Skip blanks, if any. |
565 | | */ |
566 | 0 | for (; (data[in_offset] & 0xFF) == ' '; in_offset++) |
567 | 0 | ; |
568 | 0 | } |
569 | 0 | done: |
570 | | /* |
571 | | * If we processed an *odd* number of hex digits, report an error. |
572 | | */ |
573 | 0 | if ((i % 2) != 0) |
574 | 0 | { |
575 | 0 | *err = WTAP_ERR_BAD_FILE; |
576 | 0 | *err_info = g_strdup("iseries: odd number of hex digits in a line"); |
577 | 0 | return -1; |
578 | 0 | } |
579 | 0 | if (overflow) |
580 | 0 | { |
581 | 0 | *err = WTAP_ERR_BAD_FILE; |
582 | 0 | *err_info = g_strdup("iseries: more packet data than the packet length indicated"); |
583 | 0 | return -1; |
584 | 0 | } |
585 | 0 | return out_offset; |
586 | 0 | } |
587 | | |
588 | | /* return the multiplier for nanoseconds */ |
589 | | static uint32_t |
590 | | csec_multiplier(uint32_t csec) |
591 | 0 | { |
592 | 0 | if (csec < 10) return 100000000; |
593 | 0 | if (csec < 100) return 10000000; |
594 | 0 | if (csec < 1000) return 1000000; |
595 | 0 | if (csec < 10000) return 100000; |
596 | 0 | if (csec < 100000) return 10000; |
597 | 0 | if (csec < 1000000) return 1000; |
598 | 0 | if (csec < 10000000) return 100; |
599 | 0 | if (csec < 100000000) return 10; |
600 | 0 | return 1; |
601 | 0 | } |
602 | | |
603 | | /* Parses a packet. */ |
604 | | static bool |
605 | | iseries_parse_packet (wtap * wth, FILE_T fh, wtap_rec *rec, |
606 | | int *err, char **err_info) |
607 | 0 | { |
608 | 0 | iseries_t *iseries = (iseries_t *)wth->priv; |
609 | 0 | int64_t cur_off; |
610 | 0 | bool isValid, isCurrentPacket; |
611 | 0 | int num_items_scanned, line, pktline, buflen; |
612 | 0 | int pkt_len, pktnum, hr, min, sec; |
613 | 0 | char direction[2], destmac[13], srcmac[13], type[5]; |
614 | 0 | uint32_t csec; |
615 | 0 | char data[ISERIES_LINE_LENGTH * 2]; |
616 | 0 | int offset; |
617 | 0 | char *ascii_buf; |
618 | 0 | int ascii_offset; |
619 | 0 | struct tm tm; |
620 | | |
621 | | /* |
622 | | * Check for packet headers in first 3 lines this should handle page breaks |
623 | | * situations and the header lines output at each page throw and ensure we |
624 | | * read both the captured and packet lengths. |
625 | | */ |
626 | 0 | isValid = false; |
627 | 0 | for (line = 1; line < ISERIES_PKT_LINES_TO_CHECK; line++) |
628 | 0 | { |
629 | 0 | if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL) |
630 | 0 | { |
631 | 0 | *err = file_error (fh, err_info); |
632 | 0 | return false; |
633 | 0 | } |
634 | | /* Convert UNICODE data to ASCII */ |
635 | 0 | if (iseries->format == ISERIES_FORMAT_UNICODE) |
636 | 0 | { |
637 | 0 | iseries_UNICODE_to_ASCII ((uint8_t *)data, ISERIES_LINE_LENGTH); |
638 | 0 | } |
639 | 0 | ascii_strup_inplace (data); |
640 | 0 | num_items_scanned = |
641 | 0 | sscanf (data, |
642 | 0 | "%*[ \n\t]%6d%*[ *\n\t]%1s%*[ \n\t]%6d%*[ \n\t]%2d:%2d:%2d.%9u%*[ \n\t]" |
643 | 0 | "%12s%*[ \n\t]%12s%*[ \n\t]ETHV2%*[ \n\t]TYPE:%*[ \n\t]%4s", |
644 | 0 | &pktnum, direction, &pkt_len, &hr, &min, &sec, &csec, destmac, |
645 | 0 | srcmac, type); |
646 | 0 | if (num_items_scanned == 10) |
647 | 0 | { |
648 | 0 | if (pktnum < 0) |
649 | 0 | { |
650 | 0 | *err = WTAP_ERR_BAD_FILE; |
651 | 0 | *err_info = g_strdup ("iseries: packet header has a negative packet number"); |
652 | 0 | return false; |
653 | 0 | } |
654 | | |
655 | 0 | if (pkt_len < 0) |
656 | 0 | { |
657 | 0 | *err = WTAP_ERR_BAD_FILE; |
658 | 0 | *err_info = g_strdup ("iseries: packet header has a negative packet length"); |
659 | 0 | return false; |
660 | 0 | } |
661 | | |
662 | 0 | if (hr < 0) |
663 | 0 | { |
664 | 0 | *err = WTAP_ERR_BAD_FILE; |
665 | 0 | *err_info = g_strdup ("iseries: packet header has a negative hour in the time stamp"); |
666 | 0 | return false; |
667 | 0 | } |
668 | | |
669 | 0 | if (hr > 23) |
670 | 0 | { |
671 | 0 | *err = WTAP_ERR_BAD_FILE; |
672 | 0 | *err_info = g_strdup ("iseries: packet header has a hour in the time stamp greater than 23"); |
673 | 0 | return false; |
674 | 0 | } |
675 | | |
676 | 0 | if (min < 0) |
677 | 0 | { |
678 | 0 | *err = WTAP_ERR_BAD_FILE; |
679 | 0 | *err_info = g_strdup ("iseries: packet header has a negative minute in the time stamp"); |
680 | 0 | return false; |
681 | 0 | } |
682 | | |
683 | 0 | if (min > 59) |
684 | 0 | { |
685 | 0 | *err = WTAP_ERR_BAD_FILE; |
686 | 0 | *err_info = g_strdup ("iseries: packet header has a minute in the time stamp greater than 59"); |
687 | 0 | return false; |
688 | 0 | } |
689 | | |
690 | 0 | if (sec < 0) |
691 | 0 | { |
692 | 0 | *err = WTAP_ERR_BAD_FILE; |
693 | 0 | *err_info = g_strdup ("iseries: packet header has a negative second in the time stamp"); |
694 | 0 | return false; |
695 | 0 | } |
696 | | |
697 | | /* |
698 | | * Yes, 60, even though the time-conversion routines on most OSes |
699 | | * might not handle leap seconds. |
700 | | */ |
701 | 0 | if (sec > 60) |
702 | 0 | { |
703 | 0 | *err = WTAP_ERR_BAD_FILE; |
704 | 0 | *err_info = g_strdup ("iseries: packet header has a second in the time stamp greater than 60"); |
705 | 0 | return false; |
706 | 0 | } |
707 | | |
708 | 0 | if (strlen(destmac) != 12) |
709 | 0 | { |
710 | 0 | *err = WTAP_ERR_BAD_FILE; |
711 | 0 | *err_info = g_strdup ("iseries: packet header has a destination MAC address shorter than 6 bytes"); |
712 | 0 | return false; |
713 | 0 | } |
714 | | |
715 | 0 | if (strlen(srcmac) != 12) |
716 | 0 | { |
717 | 0 | *err = WTAP_ERR_BAD_FILE; |
718 | 0 | *err_info = g_strdup ("iseries: packet header has a source MAC address shorter than 6 bytes"); |
719 | 0 | return false; |
720 | 0 | } |
721 | | |
722 | 0 | if (strlen(type) != 4) |
723 | 0 | { |
724 | 0 | *err = WTAP_ERR_BAD_FILE; |
725 | 0 | *err_info = g_strdup ("iseries: packet header has an Ethernet type/length field than 2 bytes"); |
726 | 0 | return false; |
727 | 0 | } |
728 | | |
729 | | /* OK! We found the packet header line */ |
730 | 0 | isValid = true; |
731 | | /* |
732 | | * XXX - The Capture length returned by the iSeries trace doesn't |
733 | | * seem to include the Ethernet header, so we add its length here. |
734 | | * |
735 | | * Check the length first, just in case it's *so* big that, after |
736 | | * adding the Ethernet header length, it overflows. |
737 | | */ |
738 | 0 | if ((unsigned)pkt_len > WTAP_MAX_PACKET_SIZE_STANDARD - 14) |
739 | 0 | { |
740 | | /* |
741 | | * Probably a corrupt capture file; don't blow up trying |
742 | | * to allocate space for an immensely-large packet, and |
743 | | * don't think it's a really *small* packet because it |
744 | | * overflowed. (Calculate the size as a 64-bit value in |
745 | | * the error message, to avoid an overflow.) |
746 | | */ |
747 | 0 | *err = WTAP_ERR_BAD_FILE; |
748 | 0 | *err_info = ws_strdup_printf("iseries: File has %" PRIu64 "-byte packet, bigger than maximum of %u", |
749 | 0 | (uint64_t)pkt_len + 14, |
750 | 0 | WTAP_MAX_PACKET_SIZE_STANDARD); |
751 | 0 | return false; |
752 | 0 | } |
753 | 0 | pkt_len += 14; |
754 | 0 | break; |
755 | 0 | } |
756 | 0 | } |
757 | | |
758 | | /* |
759 | | * If no packet header found we exit at this point and inform the user. |
760 | | */ |
761 | 0 | if (!isValid) |
762 | 0 | { |
763 | 0 | *err = WTAP_ERR_BAD_FILE; |
764 | 0 | *err_info = g_strdup ("iseries: packet header isn't valid"); |
765 | 0 | return false; |
766 | 0 | } |
767 | | |
768 | 0 | rec->rec_type = REC_TYPE_PACKET; |
769 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
770 | 0 | rec->presence_flags = WTAP_HAS_CAP_LEN; |
771 | | |
772 | | /* |
773 | | * If we have Wiretap Header then populate it here |
774 | | * |
775 | | * Timer resolution on the iSeries is hardware dependent. We determine |
776 | | * the resolution based on how many digits we see. |
777 | | */ |
778 | 0 | if (iseries->have_date) |
779 | 0 | { |
780 | 0 | rec->presence_flags |= WTAP_HAS_TS; |
781 | 0 | tm.tm_year = 100 + iseries->year; |
782 | 0 | tm.tm_mon = iseries->month - 1; |
783 | 0 | tm.tm_mday = iseries->day; |
784 | 0 | tm.tm_hour = hr; |
785 | 0 | tm.tm_min = min; |
786 | 0 | tm.tm_sec = sec; |
787 | 0 | tm.tm_isdst = -1; |
788 | 0 | rec->ts.secs = mktime (&tm); |
789 | 0 | rec->ts.nsecs = csec * csec_multiplier(csec); |
790 | 0 | } |
791 | |
|
792 | 0 | rec->rec_header.packet_header.len = pkt_len; |
793 | 0 | rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ETHERNET; |
794 | 0 | rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1; |
795 | | |
796 | | /* |
797 | | * Allocate a buffer big enough to hold the claimed packet length |
798 | | * worth of byte values; each byte will be two hex digits, so the |
799 | | * buffer's size should be twice the packet length. |
800 | | * |
801 | | * (There is no need to null-terminate the buffer.) |
802 | | */ |
803 | 0 | ascii_buf = (char *)g_malloc (pkt_len*2); |
804 | 0 | ascii_offset = 0; |
805 | | |
806 | | /* |
807 | | * Copy in the Ethernet header. |
808 | | * |
809 | | * The three fields have already been checked to have the right length |
810 | | * (6 bytes, hence 12 characters, of hex-dump destination and source |
811 | | * addresses, and 2 bytes, hence 4 characters, of hex-dump type/length). |
812 | | * |
813 | | * pkt_len is guaranteed to be >= 14, so 2*pkt_len is guaranteed to be |
814 | | * >= 28, so we don't need to do any bounds checking. |
815 | | */ |
816 | 0 | memcpy(&ascii_buf[0], destmac, 12); |
817 | 0 | ascii_offset += 12; |
818 | 0 | memcpy(&ascii_buf[12], srcmac, 12); |
819 | 0 | ascii_offset += 12; |
820 | 0 | memcpy(&ascii_buf[24], type, 4); |
821 | 0 | ascii_offset += 4; |
822 | | |
823 | | /* |
824 | | * Start reading packet contents |
825 | | */ |
826 | 0 | isCurrentPacket = true; |
827 | | |
828 | | /* loop through packet lines and breakout when the next packet header is read */ |
829 | 0 | pktline = 0; |
830 | 0 | while (isCurrentPacket) |
831 | 0 | { |
832 | 0 | pktline++; |
833 | | /* Read the next line */ |
834 | 0 | if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL) |
835 | 0 | { |
836 | 0 | *err = file_error (fh, err_info); |
837 | 0 | if (*err == 0) |
838 | 0 | { |
839 | | /* Hit the EOF without an error */ |
840 | 0 | break; |
841 | 0 | } |
842 | 0 | goto errxit; |
843 | 0 | } |
844 | | |
845 | | /* Convert UNICODE data to ASCII and determine line length */ |
846 | 0 | if (iseries->format == ISERIES_FORMAT_UNICODE) |
847 | 0 | { |
848 | 0 | buflen = iseries_UNICODE_to_ASCII ((uint8_t *)data, ISERIES_LINE_LENGTH); |
849 | 0 | } |
850 | 0 | else |
851 | 0 | { |
852 | | /* Else bytes to rewind is just length of ASCII string */ |
853 | 0 | buflen = (int) strlen (data); |
854 | 0 | } |
855 | | |
856 | | /* |
857 | | * Skip leading white space. |
858 | | */ |
859 | 0 | for (offset = 0; g_ascii_isspace(data[offset]); offset++) |
860 | 0 | ; |
861 | | |
862 | | /* |
863 | | * The higher-level header information starts at an offset of |
864 | | * 22 characters. The header tags are 14 characters long. |
865 | | * |
866 | | * XXX - for IPv6, if the next header isn't the last header, |
867 | | * the intermediate headers do *NOT* appear to be shown in |
868 | | * the dump file *at all*, so the packet *cannot* be |
869 | | * reconstructed! |
870 | | */ |
871 | 0 | if (offset == 22) |
872 | 0 | { |
873 | 0 | if (strncmp(data + 22, "IP Header : ", 14) == 0 || |
874 | 0 | strncmp(data + 22, "IPv6 Header: ", 14) == 0 || |
875 | 0 | strncmp(data + 22, "ARP Header : ", 14) == 0 || |
876 | 0 | strncmp(data + 22, "TCP Header : ", 14) == 0 || |
877 | 0 | strncmp(data + 22, "UDP Header : ", 14) == 0 || |
878 | 0 | strncmp(data + 22, "ICMP Header: ", 14) == 0 || |
879 | 0 | strncmp(data + 22, "ICMPv6 Hdr: ", 14) == 0 || |
880 | 0 | strncmp(data + 22, "Option Hdr: ", 14) == 0) |
881 | 0 | { |
882 | 0 | ascii_offset = append_hex_digits(ascii_buf, ascii_offset, |
883 | 0 | pkt_len*2, |
884 | 0 | data + 22 + 14, err, |
885 | 0 | err_info); |
886 | 0 | if (ascii_offset == -1) |
887 | 0 | { |
888 | | /* Bad line. */ |
889 | 0 | return false; |
890 | 0 | } |
891 | 0 | continue; |
892 | 0 | } |
893 | 0 | } |
894 | | |
895 | | /* |
896 | | * Is this a data line? |
897 | | * |
898 | | * The "Data" starts at an offset of 8. |
899 | | */ |
900 | 0 | if (offset == 9) |
901 | 0 | { |
902 | 0 | if (strncmp(data + 9, "Data . . . . . : ", 18) == 0) |
903 | 0 | { |
904 | 0 | ascii_offset = append_hex_digits(ascii_buf, ascii_offset, |
905 | 0 | pkt_len*2, |
906 | 0 | data + 9 + 18, err, |
907 | 0 | err_info); |
908 | 0 | if (ascii_offset == -1) |
909 | 0 | { |
910 | | /* Bad line. */ |
911 | 0 | return false; |
912 | 0 | } |
913 | 0 | continue; |
914 | 0 | } |
915 | 0 | } |
916 | | |
917 | | /* |
918 | | * Is this a continuation of a previous header or data line? |
919 | | * That's blanks followed by hex digits; first try the |
920 | | * "no column separators" form. |
921 | | * |
922 | | * Continuations of header lines begin at an offset of 36; |
923 | | * continuations of data lines begin at an offset of 27. |
924 | | */ |
925 | 0 | if (offset == 36 || offset == 27) |
926 | 0 | { |
927 | 0 | ascii_offset = append_hex_digits(ascii_buf, ascii_offset, |
928 | 0 | pkt_len*2, |
929 | 0 | data + offset, err, |
930 | 0 | err_info); |
931 | 0 | if (ascii_offset == -1) |
932 | 0 | { |
933 | | /* Bad line. */ |
934 | 0 | return false; |
935 | 0 | } |
936 | 0 | continue; |
937 | 0 | } |
938 | | |
939 | | /* |
940 | | * If we see the identifier for the next packet then rewind and set |
941 | | * isCurrentPacket false |
942 | | */ |
943 | 0 | ascii_strup_inplace (data); |
944 | | /* If packet header found return the offset */ |
945 | 0 | num_items_scanned = |
946 | 0 | sscanf (data+78, |
947 | 0 | "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type); |
948 | 0 | if ((num_items_scanned == 1) && pktline > 1) |
949 | 0 | { |
950 | 0 | isCurrentPacket = false; |
951 | 0 | cur_off = file_tell( fh); |
952 | 0 | if (cur_off == -1) |
953 | 0 | { |
954 | | /* Error. */ |
955 | 0 | *err = file_error (fh, err_info); |
956 | 0 | goto errxit; |
957 | 0 | } |
958 | 0 | if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1) |
959 | 0 | { |
960 | | /* XXX: need to set err_info ?? */ |
961 | 0 | goto errxit; |
962 | 0 | } |
963 | 0 | } |
964 | 0 | } |
965 | | |
966 | | /* |
967 | | * Make the captured length be the amount of bytes we've read (which |
968 | | * is half the number of characters of hex dump we have). |
969 | | * |
970 | | * XXX - this can happen for IPv6 packets if the next header isn't the |
971 | | * last header. |
972 | | */ |
973 | 0 | rec->rec_header.packet_header.caplen = ((uint32_t) ascii_offset)/2; |
974 | | |
975 | | /* Make sure we have enough room for the packet. */ |
976 | 0 | ws_buffer_assure_space (&rec->data, rec->rec_header.packet_header.caplen); |
977 | | /* Convert ascii data to binary and return in the frame buffer */ |
978 | 0 | iseries_parse_hex_string (ascii_buf, ws_buffer_start_ptr (&rec->data), ascii_offset); |
979 | | |
980 | | /* free buffer allocs and return */ |
981 | 0 | *err = 0; |
982 | 0 | g_free (ascii_buf); |
983 | 0 | return true; |
984 | | |
985 | 0 | errxit: |
986 | 0 | g_free (ascii_buf); |
987 | 0 | return false; |
988 | 0 | } |
989 | | |
990 | | /* |
991 | | * Simple routine to convert an UNICODE buffer to ASCII |
992 | | * |
993 | | * XXX - This may be possible with iconv or similar |
994 | | */ |
995 | | static int |
996 | | iseries_UNICODE_to_ASCII (uint8_t * buf, unsigned bytes) |
997 | 0 | { |
998 | 0 | unsigned i; |
999 | 0 | uint8_t *bufptr; |
1000 | |
|
1001 | 0 | bufptr = buf; |
1002 | |
|
1003 | 0 | for (i = 0; i < bytes; i++) |
1004 | 0 | { |
1005 | 0 | switch (buf[i]) |
1006 | 0 | { |
1007 | 0 | case 0xFE: |
1008 | 0 | case 0xFF: |
1009 | 0 | case 0x00: |
1010 | 0 | break; |
1011 | 0 | default: |
1012 | 0 | *bufptr = buf[i]; |
1013 | 0 | bufptr++; |
1014 | 0 | } |
1015 | 0 | if (buf[i] == 0x0A) |
1016 | 0 | break; |
1017 | 0 | } |
1018 | 0 | ws_assert(bufptr < buf + bytes); |
1019 | 0 | *bufptr = '\0'; |
1020 | 0 | return i; |
1021 | 0 | } |
1022 | | |
1023 | | /* |
1024 | | * Simple routine to convert an ASCII hex string to binary data |
1025 | | * Requires ASCII hex data and buffer to populate with binary data |
1026 | | */ |
1027 | | static bool |
1028 | | iseries_parse_hex_string (const char * ascii, uint8_t * buf, size_t len) |
1029 | 0 | { |
1030 | 0 | size_t i; |
1031 | 0 | int byte; |
1032 | 0 | int hexvalue; |
1033 | 0 | uint8_t bytevalue; |
1034 | |
|
1035 | 0 | byte = 0; |
1036 | 0 | for (i = 0; i < len; i++) |
1037 | 0 | { |
1038 | 0 | hexvalue = g_ascii_xdigit_value(ascii[i]); |
1039 | 0 | i++; |
1040 | 0 | if (hexvalue == -1) |
1041 | 0 | return false; /* not a valid hex digit */ |
1042 | 0 | bytevalue = (uint8_t)(hexvalue << 4); |
1043 | 0 | if (i >= len) |
1044 | 0 | return false; /* only one hex digit of the byte is present */ |
1045 | 0 | hexvalue = g_ascii_xdigit_value(ascii[i]); |
1046 | 0 | if (hexvalue == -1) |
1047 | 0 | return false; /* not a valid hex digit */ |
1048 | 0 | bytevalue |= (uint8_t) hexvalue; |
1049 | 0 | buf[byte] = bytevalue; |
1050 | 0 | byte++; |
1051 | 0 | } |
1052 | 0 | return true; |
1053 | 0 | } |
1054 | | |
1055 | | static const struct supported_block_type iseries_blocks_supported[] = { |
1056 | | /* |
1057 | | * We support packet blocks, with no comments or other options. |
1058 | | */ |
1059 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
1060 | | }; |
1061 | | |
1062 | | static const struct file_type_subtype_info iseries_info = { |
1063 | | "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "txt", NULL, |
1064 | | false, BLOCKS_SUPPORTED(iseries_blocks_supported), |
1065 | | NULL, NULL, NULL |
1066 | | }; |
1067 | | |
1068 | | static const struct supported_block_type iseries_unicode_blocks_supported[] = { |
1069 | | /* |
1070 | | * We support packet blocks, with no comments or other options. |
1071 | | */ |
1072 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
1073 | | }; |
1074 | | |
1075 | | static const struct file_type_subtype_info iseries_unicode_info = { |
1076 | | "IBM iSeries comm. trace (Unicode)", "iseries_unicode", "txt", NULL, |
1077 | | false, BLOCKS_SUPPORTED(iseries_unicode_blocks_supported), |
1078 | | NULL, NULL, NULL |
1079 | | }; |
1080 | | |
1081 | | void register_iseries(void) |
1082 | 2 | { |
1083 | 2 | iseries_file_type_subtype = wtap_register_file_type_subtype(&iseries_info); |
1084 | 2 | iseries_unicode_file_type_subtype = wtap_register_file_type_subtype(&iseries_unicode_info); |
1085 | | |
1086 | | /* |
1087 | | * Register names for backwards compatibility with the |
1088 | | * wtap_filetypes table in Lua. |
1089 | | */ |
1090 | 2 | wtap_register_backwards_compatibility_lua_name("ISERIES", |
1091 | 2 | iseries_file_type_subtype); |
1092 | 2 | wtap_register_backwards_compatibility_lua_name("ISERIES_UNICODE", |
1093 | 2 | iseries_unicode_file_type_subtype); |
1094 | 2 | } |
1095 | | |
1096 | | /* |
1097 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1098 | | * |
1099 | | * Local variables: |
1100 | | * c-basic-offset: 2 |
1101 | | * tab-width: 8 |
1102 | | * indent-tabs-mode: nil |
1103 | | * End: |
1104 | | * |
1105 | | * vi: set shiftwidth=2 tabstop=8 expandtab: |
1106 | | * :indentSize=2:tabSize=8:noTabs=true: |
1107 | | */ |