4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "ascendtext.h"
25 #include "ascend-int.h"
26 #include "file_wrappers.h"
27 #include <wsutil/file_util.h>
38 /* Last updated: Feb 03 2005: Josh Bailey (joshbailey@lucent.com).
40 This module reads the text hex dump output of various TAOS
41 (Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
43 * pridisplay traces primary rate ISDN
44 * ether-display traces Ethernet packets (dangerous! CPU intensive)
45 * wanopening, wandisplay, wannext, wandsess
46 traces PPP or other WAN connections
48 Please see ascend.y for examples.
50 Detailed documentation on TAOS products is at http://support.lucent.com.
52 Support for other commands will be added on an ongoing basis. */
54 typedef struct _ascend_magic_string {
57 } ascend_magic_string;
59 #define ASCEND_MAGIC_STRINGS 11
60 #define ASCEND_DATE "Date:"
62 /* these magic strings signify the headers of a supported debug commands */
63 static const ascend_magic_string ascend_magic[] = {
64 { ASCEND_PFX_ISDN_X, "PRI-XMIT-" },
65 { ASCEND_PFX_ISDN_R, "PRI-RCV-" },
66 { ASCEND_PFX_WDS_X, "XMIT-" },
67 { ASCEND_PFX_WDS_R, "RECV-" },
68 { ASCEND_PFX_WDS_X, "XMIT:" },
69 { ASCEND_PFX_WDS_R, "RECV:" },
70 { ASCEND_PFX_WDS_X, "PPP-OUT" },
71 { ASCEND_PFX_WDS_R, "PPP-IN" },
72 { ASCEND_PFX_WDD, ASCEND_DATE },
73 { ASCEND_PFX_WDD, "WD_DIALOUT_DISP:" },
74 { ASCEND_PFX_ETHER, "ETHER" },
77 static int ascend_read(wtap *wth, int *err, gchar **err_info,
79 static int ascend_seek_read(wtap *wth, gint64 seek_off,
80 struct wtap_pkthdr *phdr, Buffer *buf,
81 int *err, gchar **err_info);
83 /* Seeks to the beginning of the next packet, and returns the
84 byte offset at which the header for that packet begins.
85 Returns -1 on failure. */
86 static gint64 ascend_seek(wtap *wth, int *err, gchar **err_info)
89 gint64 date_off = -1, cur_off, packet_off;
90 size_t string_level[ASCEND_MAGIC_STRINGS];
91 guint string_i = 0, type = 0;
92 guint excessive_read_count = 262144;
94 memset(&string_level, 0, sizeof(string_level));
96 while (((byte = file_getc(wth->fh)) != EOF)) {
97 excessive_read_count--;
99 if (!excessive_read_count) {
104 for (string_i = 0; string_i < ASCEND_MAGIC_STRINGS; string_i++) {
105 const gchar *strptr = ascend_magic[string_i].strptr;
106 size_t len = strlen(strptr);
108 if (byte == *(strptr + string_level[string_i])) {
109 string_level[string_i]++;
110 if (string_level[string_i] >= len) {
111 cur_off = file_tell(wth->fh);
114 *err = file_error(wth->fh, err_info);
118 /* Date: header is a special case. Remember the offset,
119 but keep looking for other headers. */
120 if (strcmp(strptr, ASCEND_DATE) == 0) {
121 date_off = cur_off - len;
123 if (date_off == -1) {
124 /* Back up over the header we just read; that's where a read
125 of this packet should start. */
126 packet_off = cur_off - len;
128 /* This packet has a date/time header; a read of it should
129 start at the beginning of *that* header. */
130 packet_off = date_off;
133 type = ascend_magic[string_i].type;
138 string_level[string_i] = 0;
143 *err = file_error(wth->fh, err_info);
148 * Move to where the read for this packet should start, and return
151 if (file_seek(wth->fh, packet_off, SEEK_SET, err) == -1)
154 wth->phdr.pseudo_header.ascend.type = type;
159 int ascend_open(wtap *wth, int *err, gchar **err_info)
165 /* We haven't yet allocated a data structure for our private stuff;
166 set the pointer to null, so that "ascend_seek()" knows not to
170 offset = ascend_seek(wth, err, err_info);
172 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
177 /* Do a trial parse of the first packet just found to see if we might really have an Ascend file */
179 if (!check_ascend(wth->fh, &wth->phdr)) {
183 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ASCEND;
185 switch(wth->phdr.pseudo_header.ascend.type) {
186 case ASCEND_PFX_ISDN_X:
187 case ASCEND_PFX_ISDN_R:
188 wth->file_encap = WTAP_ENCAP_ISDN;
191 case ASCEND_PFX_ETHER:
192 wth->file_encap = WTAP_ENCAP_ETHERNET;
196 wth->file_encap = WTAP_ENCAP_ASCEND;
199 wth->snapshot_length = ASCEND_MAX_PKT_LEN;
200 wth->subtype_read = ascend_read;
201 wth->subtype_seek_read = ascend_seek_read;
202 ascend = (ascend_t *)g_malloc(sizeof(ascend_t));
203 wth->priv = (void *)ascend;
205 /* The first packet we want to read is the one that "ascend_seek()"
206 just found; start searching for it at the offset at which it
208 ascend->next_packet_seek_start = offset;
210 /* MAXen and Pipelines report the time since reboot. In order to keep
211 from reporting packet times near the epoch, we subtract the first
212 packet's timestamp from the capture file's ctime, which gives us an
213 offset that we can apply to each packet.
215 if (wtap_fstat(wth, &statbuf, err) == -1) {
218 ascend->inittime = statbuf.st_ctime;
219 ascend->adjusted = FALSE;
220 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
227 /* Read the next packet; called from wtap_read(). */
228 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
231 ascend_t *ascend = (ascend_t *)wth->priv;
234 /* parse_ascend() will advance the point at which to look for the next
235 packet's header, to just after the last packet's header (ie. at the
236 start of the last packet's data). We have to get past the last
237 packet's header because we might mistake part of it for a new header. */
238 if (file_seek(wth->fh, ascend->next_packet_seek_start,
239 SEEK_SET, err) == -1)
242 offset = ascend_seek(wth, err, err_info);
245 if (parse_ascend(ascend, wth->fh, &wth->phdr, wth->frame_buffer,
246 wth->snapshot_length) != PARSED_RECORD) {
247 *err = WTAP_ERR_BAD_FILE;
248 *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
252 *data_offset = offset;
253 return REC_TYPE_PACKET;
256 static int ascend_seek_read(wtap *wth, gint64 seek_off,
257 struct wtap_pkthdr *phdr, Buffer *buf,
258 int *err, gchar **err_info)
260 ascend_t *ascend = (ascend_t *)wth->priv;
262 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
264 if (parse_ascend(ascend, wth->random_fh, phdr, buf,
265 wth->snapshot_length) != PARSED_RECORD) {
266 *err = WTAP_ERR_BAD_FILE;
267 *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
271 return REC_TYPE_PACKET;