Added support for HPUX11 NETTL captures for the NS_LS_DRIVER type.
[obnox/wireshark/wip.git] / wiretap / nettl.c
1 /* nettl.c
2  *
3  * $Id: nettl.c,v 1.27 2002/05/17 09:53:20 sahlberg Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include "wtap-int.h"
31 #include "file_wrappers.h"
32 #include "buffer.h"
33 #include "nettl.h"
34
35 static u_char nettl_magic_hpux9[12] = {
36     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x00
37 };
38 static u_char nettl_magic_hpux10[12] = {
39     0x54, 0x52, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80
40 };
41
42 /* HP nettl record header for the SX25L2 subsystem - The FCS is not included in the file. */
43 struct nettlrec_sx25l2_hdr {
44     guint8      xxa[8];
45     guint8      from_dce;
46     guint8      xxb[55];
47     guint8      length[2];
48     guint8      length2[2];    /* don't know which one is captured length / real length */
49     guint8      xxc[4];
50     guint8      sec[4];
51     guint8      usec[4];
52     guint8      xxd[4];
53 };
54
55 /* HP nettl record header for the NS_LS_IP subsystem */
56 /* This also works for BASE100 and GSC100BT */
57 struct nettlrec_ns_ls_ip_hdr {
58     guint8      xxa[28];
59     guint8      length[4];
60     guint8      length2[4];    /* don't know which one is captured length / real length */
61     guint8      sec[4];
62     guint8      usec[4];
63     guint8      xxb[16];
64 };
65
66
67 /* header is followed by data and once again the total length (2 bytes) ! */
68
69
70 /* NL_LS_DRIVER :
71 The following shows what the header looks like for NS_LS_DRIVER
72 The capture was taken on HPUX11 and for a 100baseT interface.
73
74 000080 00 44 00 0b 00 00 00 02 00 00 00 00 20 00 00 00
75 000090 00 00 00 00 00 00 04 06 00 00 00 00 00 00 00 00
76 0000a0 00 00 00 74 00 00 00 74 3c e3 76 19 00 06 34 63
77 0000b0 ff ff ff ff 00 00 00 00 00 00 00 00 ff ff ff ff
78 0000c0 00 00 00 00 00 00 01 02 00 5c 00 5c ff ff ff ff
79 0000d0 3c e3 76 19 00 06 34 5a 00 0b 00 14 <here starts the MAC heder>
80
81 Each entry starts with 0x0044000b
82
83 The values 0x005c at position 0x0000c8 and 0x0000ca matches the number of bytes in
84 the packet up to the next entry, which starts with 0x00440b again. These probably
85 indicate the real and captured length of the packet (order unknown)
86
87 The values 0x00000074 at positions 0x0000a0 and 0x0000a4 seems to indicate
88 the same number as positions 0x0000c8 and 0x0000ca but added with 24.
89 Perhaps we have here two layers of headers.
90 The first layer is fixed and consists of all the bytes from 0x000084 up to and 
91 including 0x0000c3 which is a generic header for all packets captured from any
92 device. This header might be of fixed size 64 bytes and there might be something in
93 it which indicates the type of the next header which is link type specific.
94 Following this header there is another header for the 100baseT interface which
95 in this case is 24 bytes long spanning positions 0x0000c4 to 0x0000db.
96
97 When someone reports that the loading of the captures breaks, we can compare 
98 this header above with what he/she got to learn how to distinguish between different
99 types of link specific headers.
100
101
102 For now:
103 The first header seems to be
104         0-27    unknown
105         28-31   length1
106         32-35   length2
107         36-39   secs
108         40-43   100 x nsecs 
109         44-63   unknown
110
111 The header for 100baseT seems to be
112         0-3     unknown
113         4-5     length1   these are probably total/captured len. unknown which.
114         6-7     length2
115         8-11    unknown 
116         12-15   secs
117         16-19   100 x nsec
118         20-23   unknown
119 */
120 struct nettlrec_ns_ls_drv_hdr {
121     guint8      xxa[64];
122 };
123 struct nettlrec_ns_ls_drv_eth_hdr {
124     guint8      xxa[4];
125     guint8      length[2];
126     guint8      length2[2];
127     guint8      xxb[4];
128     guint8      sec[4];
129     guint8      cnsec[4];  /* unit of 100 nsec */
130     guint8      xxc[4];
131 };
132
133
134 static gboolean nettl_read(wtap *wth, int *err, long *data_offset);
135 static gboolean nettl_seek_read(wtap *wth, long seek_off,
136                 union wtap_pseudo_header *pseudo_header, u_char *pd,
137                 int length, int *err);
138 static int nettl_read_rec_header(wtap *wth, FILE_T fh,
139                 struct wtap_pkthdr *phdr, union wtap_pseudo_header *pseudo_header,
140                 int *err);
141 static gboolean nettl_read_rec_data(FILE_T fh, u_char *pd, int length,
142                 int *err);
143 static void nettl_close(wtap *wth);
144
145 int nettl_open(wtap *wth, int *err)
146 {
147     char magic[12], os_vers[2];
148     int bytes_read;
149
150     /* Read in the string that should be at the start of a HP file */
151     errno = WTAP_ERR_CANT_READ;
152     bytes_read = file_read(magic, 1, 12, wth->fh);
153     if (bytes_read != 12) {
154         *err = file_error(wth->fh);
155         if (*err != 0)
156             return -1;
157         return 0;
158     }
159
160     if (memcmp(magic, nettl_magic_hpux9, 12) &&
161         memcmp(magic, nettl_magic_hpux10, 12)) {
162         return 0;
163     }
164
165     if (file_seek(wth->fh, 0x63, SEEK_SET) == -1) {
166         *err = file_error(wth->fh);
167         return -1;
168     }
169     wth->data_offset = 0x63;
170     bytes_read = file_read(os_vers, 1, 2, wth->fh);
171     if (bytes_read != 2) {
172         *err = file_error(wth->fh);
173         if (*err != 0)
174             return -1;
175         return 0;
176     }
177
178     if (file_seek(wth->fh, 0x80, SEEK_SET) == -1) {
179         *err = file_error(wth->fh);
180         return -1;
181     }
182     wth->data_offset = 0x80;
183
184     /* This is an nettl file */
185     wth->file_type = WTAP_FILE_NETTL;
186     wth->capture.nettl = g_malloc(sizeof(nettl_t));
187     if (os_vers[0] == '1' && os_vers[1] == '1')
188         wth->capture.nettl->is_hpux_11 = TRUE;
189     else
190         wth->capture.nettl->is_hpux_11 = FALSE;
191     wth->subtype_read = nettl_read;
192     wth->subtype_seek_read = nettl_seek_read;
193     wth->subtype_close = nettl_close;
194     wth->snapshot_length = 0;   /* not available in header, only in frame */
195
196     return 1;
197 }
198
199 /* Read the next packet */
200 static gboolean nettl_read(wtap *wth, int *err, long *data_offset)
201 {
202     int ret;
203
204     /* Read record header. */
205     *data_offset = wth->data_offset;
206     ret = nettl_read_rec_header(wth, wth->fh, &wth->phdr, &wth->pseudo_header,
207         err);
208     if (ret <= 0) {
209         /* Read error or EOF */
210         return FALSE;
211     }
212     wth->data_offset += ret;
213
214     /*
215      * Read the packet data.
216      */
217     buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
218     if (!nettl_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
219                 wth->phdr.caplen, err))
220         return FALSE;   /* Read error */
221     wth->data_offset += wth->phdr.caplen;
222     return TRUE;
223 }
224
225 static gboolean
226 nettl_seek_read(wtap *wth, long seek_off,
227                 union wtap_pseudo_header *pseudo_header, u_char *pd,
228                 int length, int *err)
229 {
230     int ret;
231     struct wtap_pkthdr phdr;
232
233     if (file_seek(wth->random_fh, seek_off, SEEK_SET) == -1) {
234         *err = file_error(wth->random_fh);
235         return FALSE;
236     }
237
238     /* Read record header. */
239     ret = nettl_read_rec_header(wth, wth->random_fh, &phdr, pseudo_header,
240         err);
241     if (ret <= 0) {
242         /* Read error or EOF */
243         if (ret == 0) {
244             /* EOF means "short read" in random-access mode */
245             *err = WTAP_ERR_SHORT_READ;
246         }
247         return FALSE;
248     }
249
250     /*
251      * Read the packet data.
252      */
253     return nettl_read_rec_data(wth->random_fh, pd, length, err);
254 }
255
256 static int
257 nettl_read_rec_header(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
258                 union wtap_pseudo_header *pseudo_header, int *err)
259 {
260     int bytes_read;
261     struct nettlrec_sx25l2_hdr lapb_hdr;
262     struct nettlrec_ns_ls_ip_hdr ip_hdr;
263     struct nettlrec_ns_ls_drv_hdr drv_hdr;
264     struct nettlrec_ns_ls_drv_eth_hdr drv_eth_hdr;
265     guint16 length;
266     int offset = 0;
267     guint8 encap[4];
268     guint8 dummy[4];
269
270     errno = WTAP_ERR_CANT_READ;
271     bytes_read = file_read(encap, 1, 4, fh);
272     if (bytes_read != 4) {
273         *err = file_error(fh);
274         if (*err != 0)
275             return -1;
276         if (bytes_read != 0) {
277             *err = WTAP_ERR_SHORT_READ;
278             return -1;
279         }
280         return 0;
281     }
282     offset += 4;
283
284     switch (encap[3]) {
285         case NETTL_SUBSYS_BASE100 :
286         case NETTL_SUBSYS_GSC100BT :
287         case NETTL_SUBSYS_NS_LS_IP :
288             if (encap[3] == NETTL_SUBSYS_NS_LS_IP) {
289                 phdr->pkt_encap = WTAP_ENCAP_RAW_IP; 
290             } else {
291                 wth->file_encap = WTAP_ENCAP_ETHERNET;
292                 phdr->pkt_encap = WTAP_ENCAP_ETHERNET; 
293             }
294
295             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
296             if (bytes_read != sizeof ip_hdr) {
297                 *err = file_error(fh);
298                 if (*err != 0)
299                     return -1;
300                 if (bytes_read != 0) {
301                     *err = WTAP_ERR_SHORT_READ;
302                     return -1;
303                 }
304                 return 0;
305             }
306             offset += sizeof ip_hdr;
307
308             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
309              * HP-UX 9 and 10 */
310             if (wth->capture.nettl->is_hpux_11) {
311                 bytes_read = file_read(dummy, 1, 4, fh);
312                 if (bytes_read != 4) {
313                     *err = file_error(fh);
314                     if (*err != 0)
315                         return -1;
316                     if (bytes_read != 0) {
317                         *err = WTAP_ERR_SHORT_READ;
318                         return -1;
319                     }
320                     return 0;
321                 }
322                 offset += 4;
323             }
324
325             length = pntohl(&ip_hdr.length);
326             if (length <= 0) return 0;
327             phdr->len = length;
328             phdr->caplen = length;
329
330             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
331             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
332             break;
333         case NETTL_SUBSYS_NS_LS_DRIVER :
334             bytes_read = file_read(&drv_hdr, 1, sizeof drv_hdr, fh);
335             if (bytes_read != sizeof drv_hdr) {
336                 *err = file_error(fh);
337                 if (*err != 0)
338                     return -1;
339                 if (bytes_read != 0) {
340                     *err = WTAP_ERR_SHORT_READ;
341                     return -1;
342                 }
343                 return 0;
344             }
345             offset += sizeof drv_hdr;
346
347             /* XXX we dont know how to identify this as ehternet frames, so
348                we assumes everything is. We will crash and burn for anything else */
349             /* for encapsulated 100baseT we do this */
350             phdr->pkt_encap = WTAP_ENCAP_ETHERNET; 
351             bytes_read = file_read(&drv_eth_hdr, 1, sizeof drv_eth_hdr, fh);
352             if (bytes_read != sizeof drv_eth_hdr) {
353                 *err = file_error(fh);
354                 if (*err != 0)
355                     return -1;
356                 if (bytes_read != 0) {
357                     *err = WTAP_ERR_SHORT_READ;
358                     return -1;
359                 }
360                 return 0;
361             }
362             offset += sizeof drv_eth_hdr;
363
364             length = pntohl(&drv_eth_hdr.length);
365             if (length <= 0) return 0;
366             phdr->len = length;
367             phdr->caplen = length;
368
369             phdr->ts.tv_sec = pntohl(&drv_eth_hdr.sec);
370             phdr->ts.tv_usec = pntohl(&drv_eth_hdr.cnsec)/10;
371
372             break;
373         case NETTL_SUBSYS_SX25L2 :
374             phdr->pkt_encap = WTAP_ENCAP_LAPB;
375             bytes_read = file_read(&lapb_hdr, 1, sizeof lapb_hdr, fh);
376             if (bytes_read != sizeof lapb_hdr) {
377                 *err = file_error(fh);
378                 if (*err != 0)
379                     return -1;
380                 if (bytes_read != 0) {
381                     *err = WTAP_ERR_SHORT_READ;
382                     return -1;
383                 }
384                 return 0;
385             }
386             offset += sizeof lapb_hdr;
387
388             if (wth->capture.nettl->is_hpux_11) {
389                 bytes_read = file_read(dummy, 1, 4, fh);
390                 if (bytes_read != 4) {
391                     *err = file_error(fh);
392                     if (*err != 0)
393                         return -1;
394                     if (bytes_read != 0) {
395                         *err = WTAP_ERR_SHORT_READ;
396                         return -1;
397                     }
398                     return 0;
399                 }
400                 offset += 4;
401             }
402
403             length = pntohs(&lapb_hdr.length);
404             if (length <= 0) return 0;
405             phdr->len = length;
406             phdr->caplen = length;
407
408             phdr->ts.tv_sec = pntohl(&lapb_hdr.sec);
409             phdr->ts.tv_usec = pntohl(&lapb_hdr.usec);
410             pseudo_header->x25.flags =
411                 (lapb_hdr.from_dce & 0x20 ? FROM_DCE : 0x00);
412             break;
413         default:
414             g_message("nettl: network type %u unknown or unsupported",
415                     encap[3]);
416             *err = WTAP_ERR_UNSUPPORTED_ENCAP;
417             return -1;
418     }
419     return offset;
420 }
421
422 static gboolean
423 nettl_read_rec_data(FILE_T fh, u_char *pd, int length, int *err)
424 {
425     int bytes_read;
426
427     bytes_read = file_read(pd, 1, length, fh);
428
429     if (bytes_read != length) {
430         *err = file_error(fh);
431         if (*err == 0)
432             *err = WTAP_ERR_SHORT_READ;
433         return FALSE;
434     }
435     return TRUE;
436 }
437
438 static void nettl_close(wtap *wth)
439 {
440     g_free(wth->capture.nettl);
441 }