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"
34 #ifdef HAVE_SYS_STAT_H
45 /* Last updated: Feb 03 2005: Josh Bailey (joshbailey@lucent.com).
47 This module reads the text hex dump output of various TAOS
48 (Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
50 * pridisplay traces primary rate ISDN
51 * ether-display traces Ethernet packets (dangerous! CPU intensive)
52 * wanopening, wandisplay, wannext, wandsess
53 traces PPP or other WAN connections
55 Please see ascend-grammar.y for examples.
57 Detailed documentation on TAOS products is at http://support.lucent.com.
59 Support for other commands will be added on an ongoing basis. */
61 /* How far into the file we should look for packet headers */
62 #define ASCEND_MAX_SEEK 100000
64 typedef struct _ascend_magic_string {
67 } ascend_magic_string;
69 #define ASCEND_MAGIC_STRINGS 11
70 #define ASCEND_DATE "Date:"
72 /* these magic strings signify the headers of a supported debug commands */
73 static const ascend_magic_string ascend_magic[] = {
74 { ASCEND_PFX_ISDN_X, "PRI-XMIT-" },
75 { ASCEND_PFX_ISDN_R, "PRI-RCV-" },
76 { ASCEND_PFX_WDS_X, "XMIT-" },
77 { ASCEND_PFX_WDS_R, "RECV-" },
78 { ASCEND_PFX_WDS_X, "XMIT:" },
79 { ASCEND_PFX_WDS_R, "RECV:" },
80 { ASCEND_PFX_WDS_X, "PPP-OUT" },
81 { ASCEND_PFX_WDS_R, "PPP-IN" },
82 { ASCEND_PFX_WDD, ASCEND_DATE },
83 { ASCEND_PFX_WDD, "WD_DIALOUT_DISP:" },
84 { ASCEND_PFX_ETHER, "ETHER" },
87 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
89 static gboolean ascend_seek_read(wtap *wth, long seek_off,
90 union wtap_pseudo_header *pseudo_head, guint8 *pd, int len,
91 int *err, gchar **err_info);
92 static void ascend_close(wtap *wth);
94 /* Seeks to the beginning of the next packet, and returns the
95 byte offset at which the header for that packet begins.
96 Returns -1 on failure. */
97 static long ascend_seek(wtap *wth, int max_seek, int *err)
99 int byte, bytes_read = 0;
100 long date_off = -1, cur_off, packet_off;
101 guint string_level[ASCEND_MAGIC_STRINGS];
102 guint string_i = 0, type = 0;
104 memset(&string_level, 0, sizeof(string_level));
106 while (((byte = file_getc(wth->fh)) != EOF) && bytes_read < max_seek) {
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_)
175 /* We haven't yet allocated a data structure for our private stuff;
176 set the pointer to null, so that "ascend_seek()" knows not to
178 wth->capture.ascend = NULL;
180 offset = ascend_seek(wth, ASCEND_MAX_SEEK, err);
188 wth->data_offset = offset;
189 wth->file_type = WTAP_FILE_ASCEND;
191 switch(wth->pseudo_header.ascend.type) {
192 case ASCEND_PFX_ISDN_X:
193 case ASCEND_PFX_ISDN_R:
194 wth->file_encap = WTAP_ENCAP_ISDN;
197 case ASCEND_PFX_ETHER:
198 wth->file_encap = WTAP_ENCAP_ETHERNET;
202 wth->file_encap = WTAP_ENCAP_ASCEND;
205 wth->snapshot_length = ASCEND_MAX_PKT_LEN;
206 wth->subtype_read = ascend_read;
207 wth->subtype_seek_read = ascend_seek_read;
208 wth->subtype_close = ascend_close;
209 wth->capture.ascend = g_malloc(sizeof(ascend_t));
211 /* The first packet we want to read is the one that "ascend_seek()"
212 just found; start searching for it at the offset at which it
214 wth->capture.ascend->next_packet_seek_start = offset;
216 /* MAXen and Pipelines report the time since reboot. In order to keep
217 from reporting packet times near the epoch, we subtract the first
218 packet's timestamp from the capture file's ctime, which gives us an
219 offset that we can apply to each packet.
221 if (fstat(wtap_fd(wth), &statbuf) == -1) {
223 g_free(wth->capture.ascend);
226 wth->capture.ascend->inittime = statbuf.st_ctime;
227 wth->capture.ascend->adjusted = 0;
234 static void config_pseudo_header(union wtap_pseudo_header *pseudo_head)
236 switch(pseudo_head->ascend.type) {
237 case ASCEND_PFX_ISDN_X:
238 pseudo_head->isdn.uton = TRUE;
239 pseudo_head->isdn.channel = 0;
242 case ASCEND_PFX_ISDN_R:
243 pseudo_head->isdn.uton = FALSE;
244 pseudo_head->isdn.channel = 0;
247 case ASCEND_PFX_ETHER:
248 pseudo_head->eth.fcs_len = 0;
253 /* Read the next packet; called from wtap_read(). */
254 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
258 guint8 *buf = buffer_start_ptr(wth->frame_buffer);
259 ascend_pkthdr header;
261 /* parse_ascend() will advance the point at which to look for the next
262 packet's header, to just after the last packet's header (ie. at the
263 start of the last packet's data). We have to get past the last
264 packet's header because we might mistake part of it for a new header. */
265 if (file_seek(wth->fh, wth->capture.ascend->next_packet_seek_start,
266 SEEK_SET, err) == -1)
269 offset = ascend_seek(wth, ASCEND_MAX_SEEK, err);
272 if (! parse_ascend(wth->fh, buf, &wth->pseudo_header.ascend, &header, &(wth->capture.ascend->next_packet_seek_start))) {
273 *err = WTAP_ERR_BAD_RECORD;
274 *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
278 buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
280 config_pseudo_header(&wth->pseudo_header);
282 if (! wth->capture.ascend->adjusted) {
283 wth->capture.ascend->adjusted = 1;
284 if (header.start_time != 0) {
286 * Capture file contained a date and time.
287 * We do this only if this is the very first packet we've seen -
288 * i.e., if "wth->capture.ascend->adjusted" is false - because
289 * if we get a date and time after the first packet, we can't
290 * go back and adjust the time stamps of the packets we've already
291 * processed, and basing the time stamps of this and following
292 * packets on the time stamp from the file text rather than the
293 * ctime of the capture file means times before this and after
294 * this can't be compared.
296 wth->capture.ascend->inittime = header.start_time;
298 if (wth->capture.ascend->inittime > header.secs)
299 wth->capture.ascend->inittime -= header.secs;
301 wth->phdr.ts.tv_sec = header.secs + wth->capture.ascend->inittime;
302 wth->phdr.ts.tv_usec = header.usecs;
303 wth->phdr.caplen = header.caplen;
304 wth->phdr.len = header.len;
305 wth->data_offset = offset;
307 *data_offset = offset;
311 static gboolean ascend_seek_read(wtap *wth, long seek_off,
312 union wtap_pseudo_header *pseudo_head, guint8 *pd, int len,
313 int *err, gchar **err_info)
315 /* don't care for length. */
318 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
320 if (! parse_ascend(wth->random_fh, pd, &pseudo_head->ascend, NULL, &(wth->capture.ascend->next_packet_seek_start))) {
321 *err = WTAP_ERR_BAD_RECORD;
322 *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
326 config_pseudo_header(pseudo_head);
330 static void ascend_close(wtap *wth)
332 g_free(wth->capture.ascend);