6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include "ascendtext.h"
29 #include "ascend-int.h"
30 #include "file_wrappers.h"
31 #include <wsutil/file_util.h>
42 /* Last updated: Feb 03 2005: Josh Bailey (joshbailey@lucent.com).
44 This module reads the text hex dump output of various TAOS
45 (Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
47 * pridisplay traces primary rate ISDN
48 * ether-display traces Ethernet packets (dangerous! CPU intensive)
49 * wanopening, wandisplay, wannext, wandsess
50 traces PPP or other WAN connections
52 Please see ascend.y for examples.
54 Detailed documentation on TAOS products is at http://support.lucent.com.
56 Support for other commands will be added on an ongoing basis. */
58 typedef struct _ascend_magic_string {
61 } ascend_magic_string;
63 #define ASCEND_MAGIC_STRINGS 11
64 #define ASCEND_DATE "Date:"
66 /* these magic strings signify the headers of a supported debug commands */
67 static const ascend_magic_string ascend_magic[] = {
68 { ASCEND_PFX_ISDN_X, "PRI-XMIT-" },
69 { ASCEND_PFX_ISDN_R, "PRI-RCV-" },
70 { ASCEND_PFX_WDS_X, "XMIT-" },
71 { ASCEND_PFX_WDS_R, "RECV-" },
72 { ASCEND_PFX_WDS_X, "XMIT:" },
73 { ASCEND_PFX_WDS_R, "RECV:" },
74 { ASCEND_PFX_WDS_X, "PPP-OUT" },
75 { ASCEND_PFX_WDS_R, "PPP-IN" },
76 { ASCEND_PFX_WDD, ASCEND_DATE },
77 { ASCEND_PFX_WDD, "WD_DIALOUT_DISP:" },
78 { ASCEND_PFX_ETHER, "ETHER" },
84 gint64 next_packet_seek_start;
87 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
89 static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
90 union wtap_pseudo_header *pseudo_head, guint8 *pd, int len,
91 int *err, gchar **err_info);
93 /* Seeks to the beginning of the next packet, and returns the
94 byte offset at which the header for that packet begins.
95 Returns -1 on failure. */
96 static gint64 ascend_seek(wtap *wth, int *err, gchar **err_info)
99 gint64 date_off = -1, cur_off, packet_off;
100 size_t string_level[ASCEND_MAGIC_STRINGS];
101 guint string_i = 0, type = 0;
102 guint excessive_read_count = 262144;
104 memset(&string_level, 0, sizeof(string_level));
106 while (((byte = file_getc(wth->fh)) != EOF)) {
107 excessive_read_count--;
109 if (!excessive_read_count) {
114 for (string_i = 0; string_i < ASCEND_MAGIC_STRINGS; string_i++) {
115 const gchar *strptr = ascend_magic[string_i].strptr;
116 size_t len = strlen(strptr);
118 if (byte == *(strptr + string_level[string_i])) {
119 string_level[string_i]++;
120 if (string_level[string_i] >= len) {
121 cur_off = file_tell(wth->fh);
124 *err = file_error(wth->fh, err_info);
128 /* Date: header is a special case. Remember the offset,
129 but keep looking for other headers. */
130 if (strcmp(strptr, ASCEND_DATE) == 0) {
131 date_off = cur_off - len;
133 if (date_off == -1) {
134 /* Back up over the header we just read; that's where a read
135 of this packet should start. */
136 packet_off = cur_off - len;
138 /* This packet has a date/time header; a read of it should
139 start at the beginning of *that* header. */
140 packet_off = date_off;
143 type = ascend_magic[string_i].type;
148 string_level[string_i] = 0;
153 if (byte != EOF || file_eof(wth->fh)) {
154 /* Either we didn't find the offset, or we got an EOF. */
157 /* We (presumably) got an error (there's no equivalent to "ferror()"
158 in zlib, alas, so we don't have a wrapper to check for an error). */
159 *err = file_error(wth->fh, err_info);
165 * Move to where the read for this packet should start, and return
168 if (file_seek(wth->fh, packet_off, SEEK_SET, err) == -1)
171 wth->pseudo_header.ascend.type = type;
176 int ascend_open(wtap *wth, int *err, gchar **err_info)
180 guint8 buf[ASCEND_MAX_PKT_LEN];
181 ascend_pkthdr header;
182 gint64 dummy_seek_start;
185 /* We haven't yet allocated a data structure for our private stuff;
186 set the pointer to null, so that "ascend_seek()" knows not to
190 offset = ascend_seek(wth, err, err_info);
198 /* Do a trial parse of the first packet just found to see if we might really have an Ascend file */
200 if (parse_ascend(wth->fh, buf, &wth->pseudo_header.ascend, &header,
201 &dummy_seek_start) != PARSED_RECORD) {
205 wth->data_offset = offset;
206 wth->file_type = WTAP_FILE_ASCEND;
208 switch(wth->pseudo_header.ascend.type) {
209 case ASCEND_PFX_ISDN_X:
210 case ASCEND_PFX_ISDN_R:
211 wth->file_encap = WTAP_ENCAP_ISDN;
214 case ASCEND_PFX_ETHER:
215 wth->file_encap = WTAP_ENCAP_ETHERNET;
219 wth->file_encap = WTAP_ENCAP_ASCEND;
222 wth->snapshot_length = ASCEND_MAX_PKT_LEN;
223 wth->subtype_read = ascend_read;
224 wth->subtype_seek_read = ascend_seek_read;
225 ascend = (ascend_t *)g_malloc(sizeof(ascend_t));
226 wth->priv = (void *)ascend;
228 /* The first packet we want to read is the one that "ascend_seek()"
229 just found; start searching for it at the offset at which it
231 ascend->next_packet_seek_start = offset;
233 /* MAXen and Pipelines report the time since reboot. In order to keep
234 from reporting packet times near the epoch, we subtract the first
235 packet's timestamp from the capture file's ctime, which gives us an
236 offset that we can apply to each packet.
238 if (wtap_fstat(wth, &statbuf, err) == -1) {
242 ascend->inittime = statbuf.st_ctime;
243 ascend->adjusted = 0;
244 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
251 static void config_pseudo_header(union wtap_pseudo_header *pseudo_head)
253 switch(pseudo_head->ascend.type) {
254 case ASCEND_PFX_ISDN_X:
255 pseudo_head->isdn.uton = TRUE;
256 pseudo_head->isdn.channel = 0;
259 case ASCEND_PFX_ISDN_R:
260 pseudo_head->isdn.uton = FALSE;
261 pseudo_head->isdn.channel = 0;
264 case ASCEND_PFX_ETHER:
265 pseudo_head->eth.fcs_len = 0;
270 /* Read the next packet; called from wtap_read(). */
271 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
274 ascend_t *ascend = (ascend_t *)wth->priv;
276 guint8 *buf = buffer_start_ptr(wth->frame_buffer);
277 ascend_pkthdr header;
279 /* parse_ascend() will advance the point at which to look for the next
280 packet's header, to just after the last packet's header (ie. at the
281 start of the last packet's data). We have to get past the last
282 packet's header because we might mistake part of it for a new header. */
283 if (file_seek(wth->fh, ascend->next_packet_seek_start,
284 SEEK_SET, err) == -1)
287 offset = ascend_seek(wth, err, err_info);
290 if (parse_ascend(wth->fh, buf, &wth->pseudo_header.ascend, &header,
291 &(ascend->next_packet_seek_start)) != PARSED_RECORD) {
292 *err = WTAP_ERR_BAD_FILE;
293 *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
297 buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
299 config_pseudo_header(&wth->pseudo_header);
301 if (! ascend->adjusted) {
302 ascend->adjusted = 1;
303 if (header.start_time != 0) {
305 * Capture file contained a date and time.
306 * We do this only if this is the very first packet we've seen -
307 * i.e., if "ascend->adjusted" is false - because
308 * if we get a date and time after the first packet, we can't
309 * go back and adjust the time stamps of the packets we've already
310 * processed, and basing the time stamps of this and following
311 * packets on the time stamp from the file text rather than the
312 * ctime of the capture file means times before this and after
313 * this can't be compared.
315 ascend->inittime = header.start_time;
317 if (ascend->inittime > header.secs)
318 ascend->inittime -= header.secs;
320 wth->phdr.presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
321 wth->phdr.ts.secs = header.secs + ascend->inittime;
322 wth->phdr.ts.nsecs = header.usecs * 1000;
323 wth->phdr.caplen = header.caplen;
324 wth->phdr.len = header.len;
325 wth->data_offset = offset;
327 *data_offset = offset;
331 static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
332 union wtap_pseudo_header *pseudo_head, guint8 *pd, int len _U_,
333 int *err, gchar **err_info)
335 ascend_t *ascend = (ascend_t *)wth->priv;
337 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
339 if (parse_ascend(wth->random_fh, pd, &pseudo_head->ascend, NULL,
340 &(ascend->next_packet_seek_start)) != PARSED_RECORD) {
341 *err = WTAP_ERR_BAD_FILE;
342 *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
346 config_pseudo_header(pseudo_head);