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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "ascendtext.h"
27 #include "ascend-int.h"
28 #include "file_wrappers.h"
29 #include <wsutil/file_util.h>
40 /* Last updated: Feb 03 2005: Josh Bailey (joshbailey@lucent.com).
42 This module reads the text hex dump output of various TAOS
43 (Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
45 * pridisplay traces primary rate ISDN
46 * ether-display traces Ethernet packets (dangerous! CPU intensive)
47 * wanopening, wandisplay, wannext, wandsess
48 traces PPP or other WAN connections
50 Please see ascend.y for examples.
52 Detailed documentation on TAOS products is at http://support.lucent.com.
54 Support for other commands will be added on an ongoing basis. */
56 typedef struct _ascend_magic_string
{
59 } ascend_magic_string
;
61 #define ASCEND_MAGIC_STRINGS 11
62 #define ASCEND_DATE "Date:"
64 /* these magic strings signify the headers of a supported debug commands */
65 static const ascend_magic_string ascend_magic
[] = {
66 { ASCEND_PFX_ISDN_X
, "PRI-XMIT-" },
67 { ASCEND_PFX_ISDN_R
, "PRI-RCV-" },
68 { ASCEND_PFX_WDS_X
, "XMIT-" },
69 { ASCEND_PFX_WDS_R
, "RECV-" },
70 { ASCEND_PFX_WDS_X
, "XMIT:" },
71 { ASCEND_PFX_WDS_R
, "RECV:" },
72 { ASCEND_PFX_WDS_X
, "PPP-OUT" },
73 { ASCEND_PFX_WDS_R
, "PPP-IN" },
74 { ASCEND_PFX_WDD
, ASCEND_DATE
},
75 { ASCEND_PFX_WDD
, "WD_DIALOUT_DISP:" },
76 { ASCEND_PFX_ETHER
, "ETHER" },
79 static gboolean
ascend_read(wtap
*wth
, int *err
, gchar
**err_info
,
81 static gboolean
ascend_seek_read(wtap
*wth
, gint64 seek_off
,
82 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int len
,
83 int *err
, gchar
**err_info
);
85 /* Seeks to the beginning of the next packet, and returns the
86 byte offset at which the header for that packet begins.
87 Returns -1 on failure. */
88 static gint64
ascend_seek(wtap
*wth
, int *err
, gchar
**err_info
)
91 gint64 date_off
= -1, cur_off
, packet_off
;
92 size_t string_level
[ASCEND_MAGIC_STRINGS
];
93 guint string_i
= 0, type
= 0;
94 guint excessive_read_count
= 262144;
96 memset(&string_level
, 0, sizeof(string_level
));
98 while (((byte
= file_getc(wth
->fh
)) != EOF
)) {
99 excessive_read_count
--;
101 if (!excessive_read_count
) {
106 for (string_i
= 0; string_i
< ASCEND_MAGIC_STRINGS
; string_i
++) {
107 const gchar
*strptr
= ascend_magic
[string_i
].strptr
;
108 size_t len
= strlen(strptr
);
110 if (byte
== *(strptr
+ string_level
[string_i
])) {
111 string_level
[string_i
]++;
112 if (string_level
[string_i
] >= len
) {
113 cur_off
= file_tell(wth
->fh
);
116 *err
= file_error(wth
->fh
, err_info
);
120 /* Date: header is a special case. Remember the offset,
121 but keep looking for other headers. */
122 if (strcmp(strptr
, ASCEND_DATE
) == 0) {
123 date_off
= cur_off
- len
;
125 if (date_off
== -1) {
126 /* Back up over the header we just read; that's where a read
127 of this packet should start. */
128 packet_off
= cur_off
- len
;
130 /* This packet has a date/time header; a read of it should
131 start at the beginning of *that* header. */
132 packet_off
= date_off
;
135 type
= ascend_magic
[string_i
].type
;
140 string_level
[string_i
] = 0;
145 *err
= file_error(wth
->fh
, err_info
);
150 * Move to where the read for this packet should start, and return
153 if (file_seek(wth
->fh
, packet_off
, SEEK_SET
, err
) == -1)
156 wth
->phdr
.pseudo_header
.ascend
.type
= type
;
161 int ascend_open(wtap
*wth
, int *err
, gchar
**err_info
)
167 /* We haven't yet allocated a data structure for our private stuff;
168 set the pointer to null, so that "ascend_seek()" knows not to
172 offset
= ascend_seek(wth
, err
, err_info
);
174 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
179 /* Do a trial parse of the first packet just found to see if we might really have an Ascend file */
181 if (!check_ascend(wth
->fh
, &wth
->phdr
)) {
185 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_ASCEND
;
187 switch(wth
->phdr
.pseudo_header
.ascend
.type
) {
188 case ASCEND_PFX_ISDN_X
:
189 case ASCEND_PFX_ISDN_R
:
190 wth
->file_encap
= WTAP_ENCAP_ISDN
;
193 case ASCEND_PFX_ETHER
:
194 wth
->file_encap
= WTAP_ENCAP_ETHERNET
;
198 wth
->file_encap
= WTAP_ENCAP_ASCEND
;
201 wth
->snapshot_length
= ASCEND_MAX_PKT_LEN
;
202 wth
->subtype_read
= ascend_read
;
203 wth
->subtype_seek_read
= ascend_seek_read
;
204 ascend
= (ascend_t
*)g_malloc(sizeof(ascend_t
));
205 wth
->priv
= (void *)ascend
;
207 /* The first packet we want to read is the one that "ascend_seek()"
208 just found; start searching for it at the offset at which it
210 ascend
->next_packet_seek_start
= offset
;
212 /* MAXen and Pipelines report the time since reboot. In order to keep
213 from reporting packet times near the epoch, we subtract the first
214 packet's timestamp from the capture file's ctime, which gives us an
215 offset that we can apply to each packet.
217 if (wtap_fstat(wth
, &statbuf
, err
) == -1) {
220 ascend
->inittime
= statbuf
.st_ctime
;
221 ascend
->adjusted
= FALSE
;
222 wth
->tsprecision
= WTAP_FILE_TSPREC_USEC
;
229 /* Read the next packet; called from wtap_read(). */
230 static gboolean
ascend_read(wtap
*wth
, int *err
, gchar
**err_info
,
233 ascend_t
*ascend
= (ascend_t
*)wth
->priv
;
236 /* parse_ascend() will advance the point at which to look for the next
237 packet's header, to just after the last packet's header (ie. at the
238 start of the last packet's data). We have to get past the last
239 packet's header because we might mistake part of it for a new header. */
240 if (file_seek(wth
->fh
, ascend
->next_packet_seek_start
,
241 SEEK_SET
, err
) == -1)
244 offset
= ascend_seek(wth
, err
, err_info
);
247 if (parse_ascend(ascend
, wth
->fh
, &wth
->phdr
, wth
->frame_buffer
,
248 wth
->snapshot_length
) != PARSED_RECORD
) {
249 *err
= WTAP_ERR_BAD_FILE
;
250 *err_info
= g_strdup((ascend_parse_error
!= NULL
) ? ascend_parse_error
: "parse error");
254 *data_offset
= offset
;
258 static gboolean
ascend_seek_read(wtap
*wth
, gint64 seek_off
,
259 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int len _U_
,
260 int *err
, gchar
**err_info
)
262 ascend_t
*ascend
= (ascend_t
*)wth
->priv
;
264 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
266 if (parse_ascend(ascend
, wth
->random_fh
, phdr
, buf
,
267 wth
->snapshot_length
) != PARSED_RECORD
) {
268 *err
= WTAP_ERR_BAD_FILE
;
269 *err_info
= g_strdup((ascend_parse_error
!= NULL
) ? ascend_parse_error
: "parse error");