58ea2fbea6321d7d2e2c77d4da71d30febb723ac
[metze/wireshark/wip.git] / wiretap / ascendtext.c
1 /* ascendtext.c
2  *
3  * Wiretap Library
4  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5  *
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.
10  *
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.
15  *
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.
19  */
20
21 #include "config.h"
22 #include "wtap-int.h"
23 #include "buffer.h"
24 #include "ascendtext.h"
25 #include "ascend-int.h"
26 #include "file_wrappers.h"
27 #include <wsutil/file_util.h>
28
29 #include <errno.h>
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include <ctype.h>
36 #include <string.h>
37
38 /* Last updated: Feb 03 2005: Josh Bailey (joshbailey@lucent.com).
39
40    This module reads the text hex dump output of various TAOS
41    (Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
42
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
47
48    Please see ascend.y for examples.
49
50    Detailed documentation on TAOS products is at http://support.lucent.com.
51
52    Support for other commands will be added on an ongoing basis. */
53
54 typedef struct _ascend_magic_string {
55   guint        type;
56   const gchar   *strptr;
57 } ascend_magic_string;
58
59 #define ASCEND_MAGIC_STRINGS    11
60 #define ASCEND_DATE             "Date:"
61
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" },
75 };
76
77 static int ascend_read(wtap *wth, int *err, gchar **err_info,
78         gint64 *data_offset);
79 static int ascend_seek_read(wtap *wth, gint64 seek_off,
80         struct wtap_pkthdr *phdr, Buffer *buf,
81         int *err, gchar **err_info);
82
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)
87 {
88   int byte;
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;
93
94   memset(&string_level, 0, sizeof(string_level));
95
96   while (((byte = file_getc(wth->fh)) != EOF)) {
97     excessive_read_count--;
98
99     if (!excessive_read_count) {
100       *err = 0;
101       return -1;
102     }
103
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);
107
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);
112           if (cur_off == -1) {
113             /* Error. */
114             *err = file_error(wth->fh, err_info);
115             return -1;
116           }
117
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;
122           } else {
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;
127             } else {
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;
131             }
132
133             type = ascend_magic[string_i].type;
134             goto found;
135           }
136         }
137       } else {
138         string_level[string_i] = 0;
139       }
140     }
141   }
142
143   *err = file_error(wth->fh, err_info);
144   return -1;
145
146 found:
147   /*
148    * Move to where the read for this packet should start, and return
149    * that seek offset.
150    */
151   if (file_seek(wth->fh, packet_off, SEEK_SET, err) == -1)
152     return -1;
153
154   wth->phdr.pseudo_header.ascend.type = type;
155
156   return packet_off;
157 }
158
159 int ascend_open(wtap *wth, int *err, gchar **err_info)
160 {
161   gint64 offset;
162   ws_statb64 statbuf;
163   ascend_t *ascend;
164
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
167      fill it in. */
168   wth->priv = NULL;
169
170   offset = ascend_seek(wth, err, err_info);
171   if (offset == -1) {
172     if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
173       return -1;
174     return 0;
175   }
176
177   /* Do a trial parse of the first packet just found to see if we might really have an Ascend file */
178   init_parse_ascend();
179   if (!check_ascend(wth->fh, &wth->phdr)) {
180     return 0;
181   }
182
183   wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ASCEND;
184
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;
189       break;
190
191     case ASCEND_PFX_ETHER:
192       wth->file_encap = WTAP_ENCAP_ETHERNET;
193       break;
194
195     default:
196       wth->file_encap = WTAP_ENCAP_ASCEND;
197   }
198
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;
204
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
207      found it. */
208   ascend->next_packet_seek_start = offset;
209
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.
214    */
215   if (wtap_fstat(wth, &statbuf, err) == -1) {
216     return -1;
217   }
218   ascend->inittime = statbuf.st_ctime;
219   ascend->adjusted = FALSE;
220   wth->tsprecision = WTAP_FILE_TSPREC_USEC;
221
222   init_parse_ascend();
223
224   return 1;
225 }
226
227 /* Read the next packet; called from wtap_read(). */
228 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
229         gint64 *data_offset)
230 {
231   ascend_t *ascend = (ascend_t *)wth->priv;
232   gint64 offset;
233
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)
240     return -1;
241
242   offset = ascend_seek(wth, err, err_info);
243   if (offset == -1)
244     return -1;
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");
249     return -1;
250   }
251
252   *data_offset = offset;
253   return REC_TYPE_PACKET;
254 }
255
256 static int ascend_seek_read(wtap *wth, gint64 seek_off,
257         struct wtap_pkthdr *phdr, Buffer *buf,
258         int *err, gchar **err_info)
259 {
260   ascend_t *ascend = (ascend_t *)wth->priv;
261
262   if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
263     return -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");
268     return -1;
269   }
270
271   return REC_TYPE_PACKET;
272 }