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.
29 #include "ascend-int.h"
30 #include "file_wrappers.h"
31 #include "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-grammar.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" },
81 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
83 static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
84 union wtap_pseudo_header *pseudo_head, guint8 *pd, int len,
85 int *err, gchar **err_info);
86 static void ascend_close(wtap *wth);
88 /* Seeks to the beginning of the next packet, and returns the
89 byte offset at which the header for that packet begins.
90 Returns -1 on failure. */
91 static gint64 ascend_seek(wtap *wth, int *err)
94 gint64 date_off = -1, cur_off, packet_off;
95 guint string_level[ASCEND_MAGIC_STRINGS];
96 guint string_i = 0, type = 0;
97 guint excessive_read_count = 262144;
99 memset(&string_level, 0, sizeof(string_level));
101 while (((byte = file_getc(wth->fh)) != EOF)) {
102 excessive_read_count--;
104 if (!excessive_read_count) {
108 for (string_i = 0; string_i < ASCEND_MAGIC_STRINGS; string_i++) {
109 const gchar *strptr = ascend_magic[string_i].strptr;
110 guint len = strlen(strptr);
112 if (byte == *(strptr + string_level[string_i])) {
113 string_level[string_i]++;
114 if (string_level[string_i] >= len) {
115 cur_off = file_tell(wth->fh);
118 *err = file_error(wth->fh);
122 /* Date: header is a special case. Remember the offset,
123 but keep looking for other headers. */
124 if (strcmp(strptr, ASCEND_DATE) == 0) {
125 date_off = cur_off - len;
127 if (date_off == -1) {
128 /* Back up over the header we just read; that's where a read
129 of this packet should start. */
130 packet_off = cur_off - len;
132 /* This packet has a date/time header; a read of it should
133 start at the beginning of *that* header. */
134 packet_off = date_off;
137 type = ascend_magic[string_i].type;
142 string_level[string_i] = 0;
147 if (byte != EOF || file_eof(wth->fh)) {
148 /* Either we didn't find the offset, or we got an EOF. */
151 /* We (presumably) got an error (there's no equivalent to "ferror()"
152 in zlib, alas, so we don't have a wrapper to check for an error). */
153 *err = file_error(wth->fh);
159 * Move to where the read for this packet should start, and return
162 if (file_seek(wth->fh, packet_off, SEEK_SET, err) == -1)
165 wth->pseudo_header.ascend.type = type;
170 int ascend_open(wtap *wth, int *err, gchar **err_info _U_)
174 guint8 buf[ASCEND_MAX_PKT_LEN];
175 ascend_pkthdr header;
176 gint64 dummy_seek_start;
178 /* We haven't yet allocated a data structure for our private stuff;
179 set the pointer to null, so that "ascend_seek()" knows not to
181 wth->capture.ascend = NULL;
183 offset = ascend_seek(wth, err);
191 /* Do a trial parse of the first packet just found to see if we might really have an Ascend file */
193 if (! parse_ascend(wth->fh, buf, &wth->pseudo_header.ascend, &header, &dummy_seek_start)) {
197 wth->data_offset = offset;
198 wth->file_type = WTAP_FILE_ASCEND;
200 switch(wth->pseudo_header.ascend.type) {
201 case ASCEND_PFX_ISDN_X:
202 case ASCEND_PFX_ISDN_R:
203 wth->file_encap = WTAP_ENCAP_ISDN;
206 case ASCEND_PFX_ETHER:
207 wth->file_encap = WTAP_ENCAP_ETHERNET;
211 wth->file_encap = WTAP_ENCAP_ASCEND;
214 wth->snapshot_length = ASCEND_MAX_PKT_LEN;
215 wth->subtype_read = ascend_read;
216 wth->subtype_seek_read = ascend_seek_read;
217 wth->subtype_close = ascend_close;
218 wth->capture.ascend = g_malloc(sizeof(ascend_t));
220 /* The first packet we want to read is the one that "ascend_seek()"
221 just found; start searching for it at the offset at which it
223 wth->capture.ascend->next_packet_seek_start = offset;
225 /* MAXen and Pipelines report the time since reboot. In order to keep
226 from reporting packet times near the epoch, we subtract the first
227 packet's timestamp from the capture file's ctime, which gives us an
228 offset that we can apply to each packet.
230 if (fstat(wth->fd, &statbuf) == -1) {
232 g_free(wth->capture.ascend);
235 wth->capture.ascend->inittime = statbuf.st_ctime;
236 wth->capture.ascend->adjusted = 0;
237 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
244 static void config_pseudo_header(union wtap_pseudo_header *pseudo_head)
246 switch(pseudo_head->ascend.type) {
247 case ASCEND_PFX_ISDN_X:
248 pseudo_head->isdn.uton = TRUE;
249 pseudo_head->isdn.channel = 0;
252 case ASCEND_PFX_ISDN_R:
253 pseudo_head->isdn.uton = FALSE;
254 pseudo_head->isdn.channel = 0;
257 case ASCEND_PFX_ETHER:
258 pseudo_head->eth.fcs_len = 0;
263 /* Read the next packet; called from wtap_read(). */
264 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
268 guint8 *buf = buffer_start_ptr(wth->frame_buffer);
269 ascend_pkthdr header;
271 /* parse_ascend() will advance the point at which to look for the next
272 packet's header, to just after the last packet's header (ie. at the
273 start of the last packet's data). We have to get past the last
274 packet's header because we might mistake part of it for a new header. */
275 if (file_seek(wth->fh, wth->capture.ascend->next_packet_seek_start,
276 SEEK_SET, err) == -1)
279 offset = ascend_seek(wth, err);
282 if (! parse_ascend(wth->fh, buf, &wth->pseudo_header.ascend, &header, &(wth->capture.ascend->next_packet_seek_start))) {
283 *err = WTAP_ERR_BAD_RECORD;
284 *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
288 buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
290 config_pseudo_header(&wth->pseudo_header);
292 if (! wth->capture.ascend->adjusted) {
293 wth->capture.ascend->adjusted = 1;
294 if (header.start_time != 0) {
296 * Capture file contained a date and time.
297 * We do this only if this is the very first packet we've seen -
298 * i.e., if "wth->capture.ascend->adjusted" is false - because
299 * if we get a date and time after the first packet, we can't
300 * go back and adjust the time stamps of the packets we've already
301 * processed, and basing the time stamps of this and following
302 * packets on the time stamp from the file text rather than the
303 * ctime of the capture file means times before this and after
304 * this can't be compared.
306 wth->capture.ascend->inittime = header.start_time;
308 if (wth->capture.ascend->inittime > header.secs)
309 wth->capture.ascend->inittime -= header.secs;
311 wth->phdr.ts.secs = header.secs + wth->capture.ascend->inittime;
312 wth->phdr.ts.nsecs = header.usecs * 1000;
313 wth->phdr.caplen = header.caplen;
314 wth->phdr.len = header.len;
315 wth->data_offset = offset;
317 *data_offset = offset;
321 static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
322 union wtap_pseudo_header *pseudo_head, guint8 *pd, int len,
323 int *err, gchar **err_info)
325 /* don't care for length. */
328 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
330 if (! parse_ascend(wth->random_fh, pd, &pseudo_head->ascend, NULL, &(wth->capture.ascend->next_packet_seek_start))) {
331 *err = WTAP_ERR_BAD_RECORD;
332 *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
336 config_pseudo_header(pseudo_head);
340 static void ascend_close(wtap *wth)
342 g_free(wth->capture.ascend);