From Mark C. Brown: add EISA 100BaseTX, EISA FDDI, and HSC FDDI support,
[obnox/wireshark/wip.git] / wiretap / nettl.c
1 /* nettl.c
2  *
3  * $Id$
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 guchar nettl_magic_hpux9[12] = {
36     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x00
37 };
38 static guchar 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      caplen[2];
48     guint8      length[2];
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[8];
59     guint8      rectype;
60     guint8      xxb[19];
61     guint8      caplen[4];
62     guint8      length[4];
63     guint8      sec[4];
64     guint8      usec[4];
65     guint8      xxc[16];
66 };
67
68
69 /* header is followed by data and once again the total length (2 bytes) ! */
70
71
72 /* NL_LS_DRIVER :
73 The following shows what the header looks like for NS_LS_DRIVER
74 The capture was taken on HPUX11 and for a 100baseT interface.
75
76 000080 00 44 00 0b 00 00 00 02 00 00 00 00 20 00 00 00
77 000090 00 00 00 00 00 00 04 06 00 00 00 00 00 00 00 00
78 0000a0 00 00 00 74 00 00 00 74 3c e3 76 19 00 06 34 63
79 0000b0 ff ff ff ff 00 00 00 00 00 00 00 00 ff ff ff ff
80 0000c0 00 00 00 00 00 00 01 02 00 5c 00 5c ff ff ff ff
81 0000d0 3c e3 76 19 00 06 34 5a 00 0b 00 14 <here starts the MAC heder>
82
83 Each entry starts with 0x0044000b
84
85 The values 0x005c at position 0x0000c8 and 0x0000ca matches the number of bytes in
86 the packet up to the next entry, which starts with 0x00440b again. These probably
87 indicate the real and captured length of the packet (order unknown)
88
89 The values 0x00000074 at positions 0x0000a0 and 0x0000a4 seems to indicate
90 the same number as positions 0x0000c8 and 0x0000ca but added with 24.
91 Perhaps we have here two layers of headers.
92 The first layer is fixed and consists of all the bytes from 0x000084 up to and
93 including 0x0000c3 which is a generic header for all packets captured from any
94 device. This header might be of fixed size 64 bytes and there might be something in
95 it which indicates the type of the next header which is link type specific.
96 Following this header there is another header for the 100baseT interface which
97 in this case is 24 bytes long spanning positions 0x0000c4 to 0x0000db.
98
99 When someone reports that the loading of the captures breaks, we can compare
100 this header above with what he/she got to learn how to distinguish between different
101 types of link specific headers.
102
103
104 For now:
105 The first header seems to be
106         a normal nettlrec_ns_ls_ip_hdr
107
108 The header for 100baseT seems to be
109         0-3     unknown
110         4-5     captured length
111         6-7     actual length
112         8-11    unknown
113         12-15   secs
114         16-19   usecs
115         20-23   unknown
116 */
117 struct nettlrec_ns_ls_drv_eth_hdr {
118     guint8      xxa[4];
119     guint8      caplen[2];
120     guint8      length[2];
121     guint8      xxb[4];
122     guint8      sec[4];
123     guint8      usec[4];
124     guint8      xxc[4];
125 };
126
127
128 static gboolean nettl_read(wtap *wth, int *err, gchar **err_info,
129                 long *data_offset);
130 static gboolean nettl_seek_read(wtap *wth, long seek_off,
131                 union wtap_pseudo_header *pseudo_header, guchar *pd,
132                 int length, int *err, gchar **err_info);
133 static int nettl_read_rec_header(wtap *wth, FILE_T fh,
134                 struct wtap_pkthdr *phdr, union wtap_pseudo_header *pseudo_header,
135                 int *err, gchar **err_info, gboolean *fddihack);
136 static gboolean nettl_read_rec_data(FILE_T fh, guchar *pd, int length,
137                 int *err, gboolean fddihack);
138 static void nettl_close(wtap *wth);
139
140 int nettl_open(wtap *wth, int *err, gchar **err_info _U_)
141 {
142     char magic[12], os_vers[2];
143     int bytes_read;
144
145     /* Read in the string that should be at the start of a HP file */
146     errno = WTAP_ERR_CANT_READ;
147     bytes_read = file_read(magic, 1, 12, wth->fh);
148     if (bytes_read != 12) {
149         *err = file_error(wth->fh);
150         if (*err != 0)
151             return -1;
152         return 0;
153     }
154
155     if (memcmp(magic, nettl_magic_hpux9, 12) &&
156         memcmp(magic, nettl_magic_hpux10, 12)) {
157         return 0;
158     }
159
160     if (file_seek(wth->fh, 0x63, SEEK_SET, err) == -1)
161         return -1;
162     wth->data_offset = 0x63;
163     bytes_read = file_read(os_vers, 1, 2, wth->fh);
164     if (bytes_read != 2) {
165         *err = file_error(wth->fh);
166         if (*err != 0)
167             return -1;
168         return 0;
169     }
170
171     if (file_seek(wth->fh, 0x80, SEEK_SET, err) == -1)
172         return -1;
173     wth->data_offset = 0x80;
174
175     /* This is an nettl file */
176     wth->file_type = WTAP_FILE_NETTL;
177     wth->capture.nettl = g_malloc(sizeof(nettl_t));
178     if (os_vers[0] == '1' && os_vers[1] == '1')
179         wth->capture.nettl->is_hpux_11 = TRUE;
180     else
181         wth->capture.nettl->is_hpux_11 = FALSE;
182     wth->subtype_read = nettl_read;
183     wth->subtype_seek_read = nettl_seek_read;
184     wth->subtype_close = nettl_close;
185     wth->snapshot_length = 0;   /* not available in header, only in frame */
186
187     return 1;
188 }
189
190 /* Read the next packet */
191 static gboolean nettl_read(wtap *wth, int *err, gchar **err_info,
192     long *data_offset)
193 {
194     int ret;
195     gboolean fddihack=FALSE;
196
197     /* Read record header. */
198     *data_offset = wth->data_offset;
199     ret = nettl_read_rec_header(wth, wth->fh, &wth->phdr, &wth->pseudo_header,
200         err, err_info, &fddihack);
201     if (ret <= 0) {
202         /* Read error or EOF */
203         return FALSE;
204     }
205     wth->data_offset += ret;
206
207     /*
208      * If the per-file encapsulation isn't known, set it to this
209      * packet's encapsulation.
210      *
211      * If it *is* known, and it isn't this packet's encapsulation,
212      * set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
213      * have a single encapsulation for all packets in the file.
214      */
215     if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
216         wth->file_encap = wth->phdr.pkt_encap;
217     else {
218         if (wth->file_encap != wth->phdr.pkt_encap)
219             wth->file_encap = WTAP_ENCAP_PER_PACKET;
220     }
221
222     /*
223      * Read the packet data.
224      */
225     buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
226     if (!nettl_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
227                 wth->phdr.caplen, err, fddihack))
228         return FALSE;   /* Read error */
229     wth->data_offset += wth->phdr.caplen;
230     return TRUE;
231 }
232
233 static gboolean
234 nettl_seek_read(wtap *wth, long seek_off,
235                 union wtap_pseudo_header *pseudo_header, guchar *pd,
236                 int length, int *err, gchar **err_info)
237 {
238     int ret;
239     struct wtap_pkthdr phdr;
240     gboolean fddihack=FALSE;
241
242     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
243         return FALSE;
244
245     /* Read record header. */
246     ret = nettl_read_rec_header(wth, wth->random_fh, &phdr, pseudo_header,
247         err, err_info, &fddihack);
248     if (ret <= 0) {
249         /* Read error or EOF */
250         if (ret == 0) {
251             /* EOF means "short read" in random-access mode */
252             *err = WTAP_ERR_SHORT_READ;
253         }
254         return FALSE;
255     }
256
257     /*
258      * Read the packet data.
259      */
260     return nettl_read_rec_data(wth->random_fh, pd, length, err, fddihack);
261 }
262
263 static int
264 nettl_read_rec_header(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
265                 union wtap_pseudo_header *pseudo_header, int *err,
266                 gchar **err_info, gboolean *fddihack)
267 {
268     int bytes_read;
269     struct nettlrec_sx25l2_hdr lapb_hdr;
270     struct nettlrec_ns_ls_ip_hdr ip_hdr;
271     struct nettlrec_ns_ls_drv_eth_hdr drv_eth_hdr;
272     guint16 length;
273     int offset = 0;
274     int encap;
275     int padlen;
276     guint8 dummy[4];
277     guchar dummyc[12];
278
279     errno = WTAP_ERR_CANT_READ;
280     bytes_read = file_read(dummy, 1, 4, fh);
281     if (bytes_read != 4) {
282         *err = file_error(fh);
283         if (*err != 0)
284             return -1;
285         if (bytes_read != 0) {
286             *err = WTAP_ERR_SHORT_READ;
287             return -1;
288         }
289         return 0;
290     }
291     offset += 4;
292     encap=dummy[3];
293
294     switch (encap) {
295         case NETTL_SUBSYS_LAN100 :
296         case NETTL_SUBSYS_EISA100BT :
297         case NETTL_SUBSYS_BASE100 :
298         case NETTL_SUBSYS_GSC100BT :
299         case NETTL_SUBSYS_PCI100BT :
300         case NETTL_SUBSYS_SPP100BT :
301         case NETTL_SUBSYS_GELAN :
302         case NETTL_SUBSYS_BTLAN :
303         case NETTL_SUBSYS_INTL100 :
304         case NETTL_SUBSYS_IGELAN :
305         case NETTL_SUBSYS_IETHER :
306         case NETTL_SUBSYS_HPPB_FDDI :
307         case NETTL_SUBSYS_EISA_FDDI :
308         case NETTL_SUBSYS_PCI_FDDI :
309         case NETTL_SUBSYS_HSC_FDDI :
310         case NETTL_SUBSYS_TOKEN :
311         case NETTL_SUBSYS_PCI_TR :
312         case NETTL_SUBSYS_NS_LS_IP :
313         case NETTL_SUBSYS_NS_LS_LOOPBACK :
314         case NETTL_SUBSYS_NS_LS_TCP :
315         case NETTL_SUBSYS_NS_LS_UDP :
316         case NETTL_SUBSYS_HP_APAPORT :
317         case NETTL_SUBSYS_HP_APALACP :
318         case NETTL_SUBSYS_NS_LS_IPV6 :
319         case NETTL_SUBSYS_NS_LS_ICMPV6 :
320         case NETTL_SUBSYS_NS_LS_ICMP :
321             if( (encap == NETTL_SUBSYS_NS_LS_IP)
322              || (encap == NETTL_SUBSYS_NS_LS_LOOPBACK)
323              || (encap == NETTL_SUBSYS_NS_LS_UDP)
324              || (encap == NETTL_SUBSYS_NS_LS_TCP)
325              || (encap == NETTL_SUBSYS_NS_LS_IPV6)) {
326                 phdr->pkt_encap = WTAP_ENCAP_RAW_IP;
327             } else if (encap == NETTL_SUBSYS_NS_LS_ICMP) {
328                 phdr->pkt_encap = WTAP_ENCAP_RAW_ICMP;
329             } else if (encap == NETTL_SUBSYS_NS_LS_ICMPV6) {
330                 phdr->pkt_encap = WTAP_ENCAP_RAW_ICMPV6;
331             } else if( (encap == NETTL_SUBSYS_HPPB_FDDI)
332                     || (encap == NETTL_SUBSYS_EISA_FDDI)
333                     || (encap == NETTL_SUBSYS_PCI_FDDI)
334                     || (encap == NETTL_SUBSYS_HSC_FDDI) ) {
335                 phdr->pkt_encap = WTAP_ENCAP_FDDI;
336             } else if( (encap == NETTL_SUBSYS_PCI_TR)
337                     || (encap == NETTL_SUBSYS_TOKEN) ) {
338                 phdr->pkt_encap = WTAP_ENCAP_TOKEN_RING;
339             } else {
340                 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
341                 /* We assume there's no FCS in this frame. */
342                 pseudo_header->eth.fcs_len = 0;
343             }
344
345             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
346             if (bytes_read != sizeof ip_hdr) {
347                 *err = file_error(fh);
348                 if (*err != 0)
349                     return -1;
350                 if (bytes_read != 0) {
351                     *err = WTAP_ERR_SHORT_READ;
352                     return -1;
353                 }
354                 return 0;
355             }
356             offset += sizeof ip_hdr;
357
358             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
359              * HP-UX 9 and 10 */
360             if (wth->capture.nettl->is_hpux_11) {
361                 bytes_read = file_read(dummy, 1, 4, fh);
362                 if (bytes_read != 4) {
363                     *err = file_error(fh);
364                     if (*err != 0)
365                         return -1;
366                     if (bytes_read != 0) {
367                         *err = WTAP_ERR_SHORT_READ;
368                         return -1;
369                     }
370                     return 0;
371                 }
372                 offset += 4;
373             }
374
375             /* HPPB FDDI has different inbound vs outbound trace records */
376             if (encap == NETTL_SUBSYS_HPPB_FDDI) {
377                 if (ip_hdr.rectype == NETTL_HDR_PDUIN) {
378                    /* inbound is very strange...
379                       there are an extra 3 bytes after the DSAP and SSAP
380                       for SNAP frames ???
381                    */
382                    *fddihack=TRUE;
383                    length = pntohl(&ip_hdr.length);
384                    if (length <= 0)
385                        return 0;
386                    phdr->len = length;
387                    length = pntohl(&ip_hdr.caplen);
388                    phdr->caplen = length;
389                 } else {
390                    /* outbound appears to have variable padding */
391                    bytes_read = file_read(dummyc, 1, 9, fh);
392                    if (bytes_read != 9) {
393                        *err = file_error(fh);
394                        if (*err != 0)
395                            return -1;
396                        if (bytes_read != 0) {
397                            *err = WTAP_ERR_SHORT_READ;
398                            return -1;
399                        }
400                        return 0;
401                    }
402                    /* padding is usually either a total 11 or 16 bytes??? */
403                    padlen = (int)dummyc[8];
404                    bytes_read = file_read(dummy, 1, padlen, fh);
405                    if (bytes_read != padlen) {
406                        *err = file_error(fh);
407                        if (*err != 0)
408                            return -1;
409                        if (bytes_read != 0) {
410                            *err = WTAP_ERR_SHORT_READ;
411                            return -1;
412                        }
413                        return 0;
414                    }
415                    padlen += 9;
416                    offset += padlen;
417                    length = pntohl(&ip_hdr.length);
418                    if (length <= 0)
419                            return 0;
420                    phdr->len = length - padlen;
421                    length = pntohl(&ip_hdr.caplen);
422                    phdr->caplen = length - padlen;
423                }
424             } else if ( (encap == NETTL_SUBSYS_PCI_FDDI)
425                      || (encap == NETTL_SUBSYS_EISA_FDDI)
426                      || (encap == NETTL_SUBSYS_HSC_FDDI) ) {
427                 /* other flavor FDDI cards have an extra 3 bytes of padding */
428                 bytes_read = file_read(dummy, 1, 3, fh);
429                 if (bytes_read != 3) {
430                     *err = file_error(fh);
431                     if (*err != 0)
432                         return -1;
433                     if (bytes_read != 0) {
434                         *err = WTAP_ERR_SHORT_READ;
435                         return -1;
436                     }
437                     return 0;
438                 }
439                 offset += 3;
440                 length = pntohl(&ip_hdr.length);
441                 if (length <= 0)
442                         return 0;
443                 phdr->len = length - 3;
444                 length = pntohl(&ip_hdr.caplen);
445                 phdr->caplen = length - 3;
446             } else if (encap == NETTL_SUBSYS_NS_LS_LOOPBACK) {
447                 /* LOOPBACK has an extra 26 bytes of padding */
448                 bytes_read = file_read(dummy, 1, 26, fh);
449                 if (bytes_read != 26) {
450                     *err = file_error(fh);
451                     if (*err != 0)
452                         return -1;
453                     if (bytes_read != 0) {
454                         *err = WTAP_ERR_SHORT_READ;
455                         return -1;
456                     }
457                     return 0;
458                 }
459                 offset += 26;
460                 length = pntohl(&ip_hdr.length);
461                 if (length <= 0)
462                         return 0;
463                 phdr->len = length - 26;
464                 length = pntohl(&ip_hdr.caplen);
465                 phdr->caplen = length - 26;
466             } else {
467                 length = pntohl(&ip_hdr.length);
468                 if (length <= 0)
469                     return 0;
470                 phdr->len = length;
471                 length = pntohl(&ip_hdr.caplen);
472                 phdr->caplen = length;
473             }
474
475             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
476             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
477             break;
478         case NETTL_SUBSYS_NS_LS_DRIVER :
479             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
480             if (bytes_read != sizeof ip_hdr) {
481                 *err = file_error(fh);
482                 if (*err != 0)
483                     return -1;
484                 if (bytes_read != 0) {
485                     *err = WTAP_ERR_SHORT_READ;
486                     return -1;
487                 }
488                 return 0;
489             }
490             offset += sizeof ip_hdr;
491
492             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
493              * HP-UX 9 and 10 */
494             if (wth->capture.nettl->is_hpux_11) {
495                 bytes_read = file_read(dummy, 1, 4, fh);
496                 if (bytes_read != 4) {
497                     *err = file_error(fh);
498                     if (*err != 0)
499                         return -1;
500                     if (bytes_read != 0) {
501                         *err = WTAP_ERR_SHORT_READ;
502                         return -1;
503                     }
504                     return 0;
505                 }
506                 offset += 4;
507             }
508
509             /* XXX we dont know how to identify this as ethernet frames, so
510                we assumes everything is. We will crash and burn for anything else */
511             /* for encapsulated 100baseT we do this */
512             phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
513             /* We assume there's no FCS in this frame. */
514             pseudo_header->eth.fcs_len = 0;
515             bytes_read = file_read(&drv_eth_hdr, 1, sizeof drv_eth_hdr, fh);
516             if (bytes_read != sizeof drv_eth_hdr) {
517                 *err = file_error(fh);
518                 if (*err != 0)
519                     return -1;
520                 if (bytes_read != 0) {
521                     *err = WTAP_ERR_SHORT_READ;
522                     return -1;
523                 }
524                 return 0;
525             }
526             offset += sizeof drv_eth_hdr;
527
528             length = pntohs(&drv_eth_hdr.length); 
529             if (length <= 0) return 0;
530             phdr->len = length;
531             length = pntohs(&drv_eth_hdr.caplen);
532             phdr->caplen = length;
533
534             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
535             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
536             break;
537         case NETTL_SUBSYS_SX25L2 :
538             phdr->pkt_encap = WTAP_ENCAP_LAPB;
539             bytes_read = file_read(&lapb_hdr, 1, sizeof lapb_hdr, fh);
540             if (bytes_read != sizeof lapb_hdr) {
541                 *err = file_error(fh);
542                 if (*err != 0)
543                     return -1;
544                 if (bytes_read != 0) {
545                     *err = WTAP_ERR_SHORT_READ;
546                     return -1;
547                 }
548                 return 0;
549             }
550             offset += sizeof lapb_hdr;
551
552             if (wth->capture.nettl->is_hpux_11) {
553                 bytes_read = file_read(dummy, 1, 4, fh);
554                 if (bytes_read != 4) {
555                     *err = file_error(fh);
556                     if (*err != 0)
557                         return -1;
558                     if (bytes_read != 0) {
559                         *err = WTAP_ERR_SHORT_READ;
560                         return -1;
561                     }
562                     return 0;
563                 }
564                 offset += 4;
565             }
566
567             length = pntohs(&lapb_hdr.length);
568             if (length <= 0) return 0;
569             phdr->len = length;
570             phdr->caplen = length;
571
572             phdr->ts.tv_sec = pntohl(&lapb_hdr.sec);
573             phdr->ts.tv_usec = pntohl(&lapb_hdr.usec);
574             pseudo_header->x25.flags =
575                 (lapb_hdr.from_dce & 0x20 ? FROM_DCE : 0x00);
576             break;
577         default:
578             *err = WTAP_ERR_UNSUPPORTED_ENCAP;
579             *err_info = g_strdup_printf("nettl: subsystem %u unknown or unsupported",
580                     encap);
581             return -1;
582     }
583     return offset;
584 }
585
586 static gboolean
587 nettl_read_rec_data(FILE_T fh, guchar *pd, int length, int *err, gboolean fddihack)
588 {
589     int bytes_read;
590     guchar *p=NULL;
591     guint8 dummy[3];
592
593     if (fddihack == TRUE) {
594        /* read in FC, dest, src, DSAP and SSAP */
595        if (file_read(pd, 1, 15, fh) == 15) {
596           if (pd[13] == 0xAA) {
597              /* it's SNAP, have to eat 3 bytes??? */
598              if (file_read(dummy, 1, 3, fh) == 3) {
599                 p=pd+15;
600                 bytes_read = file_read(p, 1, length-18, fh);
601                 bytes_read += 18;
602              } else {
603                 bytes_read = -1;
604              }
605           } else {
606              /* not SNAP */
607              p=pd+15;
608              bytes_read = file_read(p, 1, length-15, fh);
609              bytes_read += 15;
610           }
611        } else
612           bytes_read = -1;
613     } else
614        bytes_read = file_read(pd, 1, length, fh);
615
616     if (bytes_read != length) {
617         *err = file_error(fh);
618         if (*err == 0)
619             *err = WTAP_ERR_SHORT_READ;
620         return FALSE;
621     }
622     return TRUE;
623 }
624
625 static void nettl_close(wtap *wth)
626 {
627     g_free(wth->capture.nettl);
628 }