d35e44df29dd8dd0bdb9568a20c23bb4f0dfd06f
[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 <wsutil/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 <string.h>
36
37 /* Last updated: Feb 03 2005: Josh Bailey (joshbailey@lucent.com).
38
39    This module reads the text hex dump output of various TAOS
40    (Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
41
42    * pridisplay         traces primary rate ISDN
43    * ether-display      traces Ethernet packets (dangerous! CPU intensive)
44    * wanopening, wandisplay, wannext, wandsess
45                         traces PPP or other WAN connections
46
47    Please see ascend.y for examples.
48
49    Detailed documentation on TAOS products is at http://support.lucent.com.
50
51    Support for other commands will be added on an ongoing basis. */
52
53 typedef struct _ascend_magic_string {
54   guint        type;
55   const gchar   *strptr;
56 } ascend_magic_string;
57
58 #define ASCEND_MAGIC_STRINGS    11
59 #define ASCEND_DATE             "Date:"
60
61 /* these magic strings signify the headers of a supported debug commands */
62 static const ascend_magic_string ascend_magic[] = {
63   { ASCEND_PFX_ISDN_X,  "PRI-XMIT-" },
64   { ASCEND_PFX_ISDN_R,  "PRI-RCV-" },
65   { ASCEND_PFX_WDS_X,   "XMIT-" },
66   { ASCEND_PFX_WDS_R,   "RECV-" },
67   { ASCEND_PFX_WDS_X,   "XMIT:" },
68   { ASCEND_PFX_WDS_R,   "RECV:" },
69   { ASCEND_PFX_WDS_X,   "PPP-OUT" },
70   { ASCEND_PFX_WDS_R,   "PPP-IN" },
71   { ASCEND_PFX_WDD,     ASCEND_DATE },
72   { ASCEND_PFX_WDD,     "WD_DIALOUT_DISP:" },
73   { ASCEND_PFX_ETHER,   "ETHER" },
74 };
75
76 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
77         gint64 *data_offset);
78 static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
79         struct wtap_pkthdr *phdr, Buffer *buf,
80         int *err, gchar **err_info);
81
82 /* Seeks to the beginning of the next packet, and returns the
83    byte offset at which the header for that packet begins.
84    Returns -1 on failure. */
85 static gint64 ascend_seek(wtap *wth, int *err, gchar **err_info)
86 {
87   int byte;
88   gint64 date_off = -1, cur_off, packet_off;
89   size_t string_level[ASCEND_MAGIC_STRINGS];
90   guint string_i = 0, type = 0;
91   guint excessive_read_count = 262144;
92
93   memset(&string_level, 0, sizeof(string_level));
94
95   while (((byte = file_getc(wth->fh)) != EOF)) {
96     excessive_read_count--;
97
98     if (!excessive_read_count) {
99       *err = 0;
100       return -1;
101     }
102
103     for (string_i = 0; string_i < ASCEND_MAGIC_STRINGS; string_i++) {
104       const gchar *strptr = ascend_magic[string_i].strptr;
105       size_t len          = strlen(strptr);
106
107       if (byte == *(strptr + string_level[string_i])) {
108         string_level[string_i]++;
109         if (string_level[string_i] >= len) {
110           cur_off = file_tell(wth->fh);
111           if (cur_off == -1) {
112             /* Error. */
113             *err = file_error(wth->fh, err_info);
114             return -1;
115           }
116
117           /* Date: header is a special case. Remember the offset,
118              but keep looking for other headers. */
119           if (strcmp(strptr, ASCEND_DATE) == 0) {
120             date_off = cur_off - len;
121           } else {
122             if (date_off == -1) {
123               /* Back up over the header we just read; that's where a read
124                  of this packet should start. */
125               packet_off = cur_off - len;
126             } else {
127               /* This packet has a date/time header; a read of it should
128                  start at the beginning of *that* header. */
129               packet_off = date_off;
130             }
131
132             type = ascend_magic[string_i].type;
133             goto found;
134           }
135         }
136       } else {
137         string_level[string_i] = 0;
138       }
139     }
140   }
141
142   *err = file_error(wth->fh, err_info);
143   return -1;
144
145 found:
146   /*
147    * Move to where the read for this packet should start, and return
148    * that seek offset.
149    */
150   if (file_seek(wth->fh, packet_off, SEEK_SET, err) == -1)
151     return -1;
152
153   wth->phdr.pseudo_header.ascend.type = type;
154
155   return packet_off;
156 }
157
158 wtap_open_return_val ascend_open(wtap *wth, int *err, gchar **err_info)
159 {
160   gint64 offset;
161   ws_statb64 statbuf;
162   ascend_t *ascend;
163
164   /* We haven't yet allocated a data structure for our private stuff;
165      set the pointer to null, so that "ascend_seek()" knows not to
166      fill it in. */
167   wth->priv = NULL;
168
169   offset = ascend_seek(wth, err, err_info);
170   if (offset == -1) {
171     if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
172       return WTAP_OPEN_ERROR;
173     return WTAP_OPEN_NOT_MINE;
174   }
175
176   /* Do a trial parse of the first packet just found to see if we might really have an Ascend file */
177   init_parse_ascend();
178   if (!check_ascend(wth->fh, &wth->phdr)) {
179     return WTAP_OPEN_NOT_MINE;
180   }
181
182   wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ASCEND;
183
184   switch(wth->phdr.pseudo_header.ascend.type) {
185     case ASCEND_PFX_ISDN_X:
186     case ASCEND_PFX_ISDN_R:
187       wth->file_encap = WTAP_ENCAP_ISDN;
188       break;
189
190     case ASCEND_PFX_ETHER:
191       wth->file_encap = WTAP_ENCAP_ETHERNET;
192       break;
193
194     default:
195       wth->file_encap = WTAP_ENCAP_ASCEND;
196   }
197
198   wth->snapshot_length = ASCEND_MAX_PKT_LEN;
199   wth->subtype_read = ascend_read;
200   wth->subtype_seek_read = ascend_seek_read;
201   ascend = (ascend_t *)g_malloc(sizeof(ascend_t));
202   wth->priv = (void *)ascend;
203
204   /* The first packet we want to read is the one that "ascend_seek()"
205      just found; start searching for it at the offset at which it
206      found it. */
207   ascend->next_packet_seek_start = offset;
208
209   /* MAXen and Pipelines report the time since reboot.  In order to keep
210      from reporting packet times near the epoch, we subtract the first
211      packet's timestamp from the capture file's ctime, which gives us an
212      offset that we can apply to each packet.
213    */
214   if (wtap_fstat(wth, &statbuf, err) == -1) {
215     return WTAP_OPEN_ERROR;
216   }
217   ascend->inittime = statbuf.st_ctime;
218   ascend->adjusted = FALSE;
219   wth->file_tsprec = WTAP_TSPREC_USEC;
220
221   init_parse_ascend();
222
223   return WTAP_OPEN_MINE;
224 }
225
226 /* Read the next packet; called from wtap_read(). */
227 static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
228         gint64 *data_offset)
229 {
230   ascend_t *ascend = (ascend_t *)wth->priv;
231   gint64 offset;
232
233   /* parse_ascend() will advance the point at which to look for the next
234      packet's header, to just after the last packet's header (ie. at the
235      start of the last packet's data). We have to get past the last
236      packet's header because we might mistake part of it for a new header. */
237   if (file_seek(wth->fh, ascend->next_packet_seek_start,
238                 SEEK_SET, err) == -1)
239     return FALSE;
240
241   offset = ascend_seek(wth, err, err_info);
242   if (offset == -1)
243     return FALSE;
244   if (parse_ascend(ascend, wth->fh, &wth->phdr, wth->frame_buffer,
245                    wth->snapshot_length) != PARSED_RECORD) {
246     *err = WTAP_ERR_BAD_FILE;
247     *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
248     return FALSE;
249   }
250
251   *data_offset = offset;
252   return TRUE;
253 }
254
255 static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
256         struct wtap_pkthdr *phdr, Buffer *buf,
257         int *err, gchar **err_info)
258 {
259   ascend_t *ascend = (ascend_t *)wth->priv;
260
261   if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
262     return FALSE;
263   if (parse_ascend(ascend, wth->random_fh, phdr, buf,
264                    wth->snapshot_length) != PARSED_RECORD) {
265     *err = WTAP_ERR_BAD_FILE;
266     *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
267     return FALSE;
268   }
269
270   return TRUE;
271 }