84fafc2f33adaead85db41bb9c22b15994a2c9bc
[obnox/wireshark/wip.git] / wiretap / ascend.c
1 /* ascend.c
2  *
3  * $Id: ascend.c,v 1.16 2000/05/19 23:06:47 gram Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@xiexie.org>
7  * 
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.
12  * 
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.
17  * 
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.
21  *
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "wtap-int.h"
27 #include "buffer.h"
28 #include "ascend.h"
29 #include "ascend-int.h"
30 #include "file_wrappers.h"
31
32 #include <sys/stat.h>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <ctype.h>
39 #include <string.h>
40
41 /* This module reads the output of the 'wandsession', 'wannext',
42    'wandisplay', and similar commands available on Lucent/Ascend access
43    equipment.  The output is text, with a header line followed by the
44    packet data.  Usage instructions for the commands can be found by
45    searching http://aos.ascend.com .  Ascend likes to move their pages
46    around quite a bit, otherwise I'd put a more specific URL here.
47
48    Example 'wandsess' output data:
49    
50 RECV-iguana:241:(task: B02614C0, time: 1975432.85) 49 octets @ 8003BD94
51   [0000]: FF 03 00 3D C0 06 CA 22 2F 45 00 00 28 6A 3B 40 
52   [0010]: 00 3F 03 D7 37 CE 41 62 12 CF 00 FB 08 20 27 00 
53   [0020]: 50 E4 08 DD D7 7C 4C 71 92 50 10 7D 78 67 C8 00 
54   [0030]: 00 
55 XMIT-iguana:241:(task: B04E12C0, time: 1975432.85) 53 octets @ 8009EB16
56   [0000]: FF 03 00 3D C0 09 1E 31 21 45 00 00 2C 2D BD 40 
57   [0010]: 00 7A 06 D8 B1 CF 00 FB 08 CE 41 62 12 00 50 20 
58   [0020]: 29 7C 4C 71 9C 9A 6A 93 A4 60 12 22 38 3F 10 00 
59   [0030]: 00 02 04 05 B4 
60
61     Example 'wdd' output data:
62
63 Date: 01/12/1990.  Time: 12:22:33
64 Cause an attempt to place call to 14082750382
65 WD_DIALOUT_DISP: chunk 2515EE type IP.
66 (task: 251790, time: 994953.28) 44 octets @ 2782B8
67   [0000]: 00 C0 7B 71 45 6C 00 60 08 16 AA 51 08 00 45 00
68   [0010]: 00 2C 66 1C 40 00 80 06 53 F6 AC 14 00 18 CC 47
69   [0020]: C8 45 0A 31 00 50 3B D9 5B 75 00 00
70
71     (note that the capture whence this came dates back to January
72     *1999*; I presume that either the person who sent it to me
73     hadn't bothered keeping its internal clock set, or that its
74     internal clock or the date it displays in those messages
75     is only loosely connected to reality)
76
77   Note that a maximum of eight rows will be displayed (for a maximum of
78   128 bytes), no matter what the octet count is.
79   
80   When reading a packet, the module prepends an ascend_pkt_hdr to the 
81   data.
82
83  */
84
85 /* How far into the file we should look for packet headers */
86 #define ASCEND_MAX_SEEK 100000
87
88 /* XXX  Should we replace this with a more generalized array? */
89 /* Magic numbers for Ascend wandsession/wanopening/ether-display data */
90 static const char ascend_xmagic[]  = { 'X', 'M', 'I', 'T', '-' };
91 static const char ascend_rmagic[]  = { 'R', 'E', 'C', 'V', '-' };
92 static const char ascend_w1magic[] = { 'D', 'a', 't', 'e', ':',  };
93 static const char ascend_w2magic[] = { 'W', 'D', '_', 'D', 'I', 'A', 'L', 'O', 'U', 'T', '_', 'D', 'I', 'S', 'P', ':' };
94
95 #define ASCEND_X_SIZE  (sizeof ascend_xmagic  / sizeof ascend_xmagic[0])
96 #define ASCEND_R_SIZE  (sizeof ascend_rmagic  / sizeof ascend_rmagic[0])
97 #define ASCEND_W1_SIZE (sizeof ascend_w1magic / sizeof ascend_w1magic[0])
98 #define ASCEND_W2_SIZE (sizeof ascend_w2magic / sizeof ascend_w2magic[0])
99
100 static int ascend_read(wtap *wth, int *err);
101 static int ascend_seek_read (wtap *wth, int seek_off,
102         union wtap_pseudo_header *pseudo_header, guint8 *pd, int len);
103 static void ascend_close(wtap *wth);
104
105 /* Seeks to the beginning of the next packet, and returns the
106    byte offset.  Returns -1 on failure.  A valid offset is 0; since
107    that causes problems with wtap_loop, offsets are incremented by one. */
108 /* XXX - Handle I/O errors. */
109 static int ascend_seek(wtap *wth, int max_seek)
110 {
111   int byte, bytes_read = 0, date_off = 0;
112   int x_level = 0, r_level = 0, w1_level = 0, w2_level = 0;
113
114   while (((byte = file_getc(wth->fh)) != EOF) && bytes_read < max_seek) {
115     if (byte == ascend_xmagic[x_level]) {
116       x_level++;
117       if (x_level >= ASCEND_X_SIZE) {
118         file_seek(wth->fh, -(ASCEND_X_SIZE), SEEK_CUR);
119         return file_tell(wth->fh) + 1;
120       }
121     } else {
122       x_level = 0;
123     }
124     if (byte == ascend_rmagic[r_level]) {
125       r_level++;
126       if (r_level >= ASCEND_R_SIZE) {
127         file_seek(wth->fh, -(ASCEND_R_SIZE), SEEK_CUR);
128         return file_tell(wth->fh) + 1;
129       }
130     } else {
131       r_level = 0;
132     }
133     if (byte == ascend_w1magic[w1_level]) {
134       w1_level++;
135       if (w1_level >= ASCEND_W1_SIZE) {
136         date_off = file_tell(wth->fh) - ASCEND_W1_SIZE + 1;
137       }
138     } else {
139       w1_level = 0;
140     }
141     if (byte == ascend_w2magic[w2_level]) {
142       w2_level++;
143       if (w2_level >= ASCEND_W2_SIZE && date_off) {
144         file_seek(wth->fh, date_off - 1, SEEK_SET);
145         return date_off;
146       }
147     } else {
148       w2_level = 0;
149     }
150     bytes_read++;
151   }
152   return -1;
153 }
154
155 /* XXX - return -1 on I/O error and actually do something with 'err'. */
156 int ascend_open(wtap *wth, int *err)
157 {
158   int offset;
159
160   file_seek(wth->fh, 0, SEEK_SET);
161   offset = ascend_seek(wth, ASCEND_MAX_SEEK);
162   if (offset < 1) {
163     return 0;
164   }
165
166   wth->data_offset = offset;
167   wth->file_encap = WTAP_ENCAP_ASCEND;
168   wth->file_type = WTAP_FILE_ASCEND;
169   wth->snapshot_length = ASCEND_MAX_PKT_LEN;
170   wth->subtype_read = ascend_read;
171   wth->subtype_seek_read = ascend_seek_read;
172   wth->subtype_close = ascend_close;
173   wth->capture.ascend = g_malloc(sizeof(ascend_t));
174
175   /* MAXen and Pipelines report the time since reboot.  In order to keep 
176      from reporting packet times near the epoch, we subtract the first
177      packet's timestamp from the capture file's ctime, which gives us an
178      offset that we can apply to each packet.
179
180      NOTE: Since we can't fstat a compressed file, assume that the first
181      packet time is 0 and other packets are relative to this.
182    */
183   wth->capture.ascend->inittime = 0;
184   wth->capture.ascend->adjusted = 0;
185   wth->capture.ascend->seek_add = -1;
186
187   init_parse_ascend();
188
189   return 1;
190 }
191
192 /* Read the next packet; called from wtap_loop(). */
193 static int ascend_read(wtap *wth, int *err)
194 {
195   int offset;
196   guint8 *buf = buffer_start_ptr(wth->frame_buffer);
197   ascend_pkthdr header;
198
199   /* (f)lex reads large chunks of the file into memory, so file_tell() doesn't
200      give us the correct location of the packet.  Instead, we seek to the 
201      location of the last packet and try to find the next packet.  In
202      addition, we fool around with the seek offset in case a valid packet
203      starts at the beginning of the file.  */  
204   file_seek(wth->fh, wth->data_offset + wth->capture.ascend->seek_add, SEEK_SET);
205   wth->capture.ascend->seek_add = 0;
206   offset = ascend_seek(wth, ASCEND_MAX_SEEK);
207   if (offset < 1) {
208     return 0;
209   }
210   if (! parse_ascend(wth->fh, buf, &wth->pseudo_header.ascend, &header, 0)) {
211     *err = WTAP_ERR_BAD_RECORD;
212     return -1;
213   }
214
215   buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
216
217   if (! wth->capture.ascend->adjusted) {
218     wth->capture.ascend->adjusted = 1;
219     wth->capture.ascend->inittime = -header.secs;
220   }
221   wth->phdr.ts.tv_sec = header.secs + wth->capture.ascend->inittime;
222   wth->phdr.ts.tv_usec = header.usecs;
223   wth->phdr.caplen = header.caplen;
224   wth->phdr.len = header.len;
225   wth->phdr.pkt_encap = wth->file_encap;
226   wth->data_offset = offset;
227
228   return offset;
229 }
230
231 static int ascend_seek_read (wtap *wth, int seek_off,
232         union wtap_pseudo_header *pseudo_header, guint8 *pd, int len)
233 {
234   file_seek(wth->random_fh, seek_off - 1, SEEK_SET);
235   return parse_ascend(wth->random_fh, pd, &pseudo_header->ascend, NULL, len);
236 }
237
238 static void ascend_close(wtap *wth)
239 {
240   g_free(wth->capture.ascend);
241 }