From Mark C. Brown: support for the NETTL_SUBSYS_HPPB_FDDI records.
[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_BASE100 :
297         case NETTL_SUBSYS_GSC100BT :
298         case NETTL_SUBSYS_PCI100BT :
299         case NETTL_SUBSYS_SPP100BT :
300         case NETTL_SUBSYS_GELAN :
301         case NETTL_SUBSYS_BTLAN :
302         case NETTL_SUBSYS_INTL100 :
303         case NETTL_SUBSYS_IGELAN :
304         case NETTL_SUBSYS_IETHER :
305         case NETTL_SUBSYS_HPPB_FDDI :
306         case NETTL_SUBSYS_PCI_FDDI :
307         case NETTL_SUBSYS_TOKEN :
308         case NETTL_SUBSYS_PCI_TR :
309         case NETTL_SUBSYS_NS_LS_IP :
310         case NETTL_SUBSYS_NS_LS_LOOPBACK :
311         case NETTL_SUBSYS_NS_LS_TCP :
312         case NETTL_SUBSYS_NS_LS_UDP :
313         case NETTL_SUBSYS_HP_APAPORT :
314         case NETTL_SUBSYS_HP_APALACP :
315         case NETTL_SUBSYS_NS_LS_IPV6 :
316         case NETTL_SUBSYS_NS_LS_ICMPV6 :
317         case NETTL_SUBSYS_NS_LS_ICMP :
318             if( (encap == NETTL_SUBSYS_NS_LS_IP)
319              || (encap == NETTL_SUBSYS_NS_LS_LOOPBACK)
320              || (encap == NETTL_SUBSYS_NS_LS_UDP)
321              || (encap == NETTL_SUBSYS_NS_LS_TCP)
322              || (encap == NETTL_SUBSYS_NS_LS_IPV6)) {
323                 phdr->pkt_encap = WTAP_ENCAP_RAW_IP;
324             } else if (encap == NETTL_SUBSYS_NS_LS_ICMP) {
325                 phdr->pkt_encap = WTAP_ENCAP_RAW_ICMP;
326             } else if (encap == NETTL_SUBSYS_NS_LS_ICMPV6) {
327                 phdr->pkt_encap = WTAP_ENCAP_RAW_ICMPV6;
328             } else if( (encap == NETTL_SUBSYS_HPPB_FDDI)
329                     || (encap == NETTL_SUBSYS_PCI_FDDI) ) {
330                 phdr->pkt_encap = WTAP_ENCAP_FDDI;
331             } else if( (encap == NETTL_SUBSYS_PCI_TR)
332                     || (encap == NETTL_SUBSYS_TOKEN) ) {
333                 phdr->pkt_encap = WTAP_ENCAP_TOKEN_RING;
334             } else {
335                 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
336                 /* We assume there's no FCS in this frame. */
337                 pseudo_header->eth.fcs_len = 0;
338             }
339
340             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
341             if (bytes_read != sizeof ip_hdr) {
342                 *err = file_error(fh);
343                 if (*err != 0)
344                     return -1;
345                 if (bytes_read != 0) {
346                     *err = WTAP_ERR_SHORT_READ;
347                     return -1;
348                 }
349                 return 0;
350             }
351             offset += sizeof ip_hdr;
352
353             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
354              * HP-UX 9 and 10 */
355             if (wth->capture.nettl->is_hpux_11) {
356                 bytes_read = file_read(dummy, 1, 4, fh);
357                 if (bytes_read != 4) {
358                     *err = file_error(fh);
359                     if (*err != 0)
360                         return -1;
361                     if (bytes_read != 0) {
362                         *err = WTAP_ERR_SHORT_READ;
363                         return -1;
364                     }
365                     return 0;
366                 }
367                 offset += 4;
368             }
369
370             /* HPPB FDDI has different inbound vs outbound trace records */
371             if (encap == NETTL_SUBSYS_HPPB_FDDI) {
372                 if (ip_hdr.rectype == NETTL_HDR_PDUIN) {
373                    /* inbound is very strange...
374                       there are an extra 3 bytes after the DSAP and SSAP
375                       for SNAP frames ???
376                    */
377                    *fddihack=TRUE;
378                    length = pntohl(&ip_hdr.length);
379                    if (length <= 0)
380                        return 0;
381                    phdr->len = length;
382                    length = pntohl(&ip_hdr.caplen);
383                    phdr->caplen = length;
384                 } else {
385                    /* outbound has an extra padding */
386                    bytes_read = file_read(dummyc, 1, 9, fh);
387                    if (bytes_read != 9) {
388                        *err = file_error(fh);
389                        if (*err != 0)
390                            return -1;
391                        if (bytes_read != 0) {
392                            *err = WTAP_ERR_SHORT_READ;
393                            return -1;
394                        }
395                        return 0;
396                    }
397                    /* padding is usually either a total 11 or 16 bytes??? */
398                    padlen = (int)dummyc[8];
399                    bytes_read = file_read(dummy, 1, padlen, fh);
400                    if (bytes_read != padlen) {
401                        *err = file_error(fh);
402                        if (*err != 0)
403                            return -1;
404                        if (bytes_read != 0) {
405                            *err = WTAP_ERR_SHORT_READ;
406                            return -1;
407                        }
408                        return 0;
409                    }
410                    padlen += 9;
411                    offset += padlen;
412                    length = pntohl(&ip_hdr.length);
413                    if (length <= 0)
414                            return 0;
415                    phdr->len = length - padlen;
416                    length = pntohl(&ip_hdr.caplen);
417                    phdr->caplen = length - padlen;
418                }
419             } else if (encap == NETTL_SUBSYS_PCI_FDDI) {
420                 /* PCI FDDI has an extra 3 bytes of padding */
421                 bytes_read = file_read(dummy, 1, 3, fh);
422                 if (bytes_read != 3) {
423                     *err = file_error(fh);
424                     if (*err != 0)
425                         return -1;
426                     if (bytes_read != 0) {
427                         *err = WTAP_ERR_SHORT_READ;
428                         return -1;
429                     }
430                     return 0;
431                 }
432                 offset += 3;
433                 length = pntohl(&ip_hdr.length);
434                 if (length <= 0)
435                         return 0;
436                 phdr->len = length - 3;
437                 length = pntohl(&ip_hdr.caplen);
438                 phdr->caplen = length - 3;
439             } else if (encap == NETTL_SUBSYS_NS_LS_LOOPBACK) {
440                 /* LOOPBACK has an extra 26 bytes of padding */
441                 bytes_read = file_read(dummy, 1, 26, fh);
442                 if (bytes_read != 26) {
443                     *err = file_error(fh);
444                     if (*err != 0)
445                         return -1;
446                     if (bytes_read != 0) {
447                         *err = WTAP_ERR_SHORT_READ;
448                         return -1;
449                     }
450                     return 0;
451                 }
452                 offset += 26;
453                 length = pntohl(&ip_hdr.length);
454                 if (length <= 0)
455                         return 0;
456                 phdr->len = length - 26;
457                 length = pntohl(&ip_hdr.caplen);
458                 phdr->caplen = length - 26;
459             } else {
460                 length = pntohl(&ip_hdr.length);
461                 if (length <= 0)
462                     return 0;
463                 phdr->len = length;
464                 length = pntohl(&ip_hdr.caplen);
465                 phdr->caplen = length;
466             }
467
468             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
469             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
470             break;
471         case NETTL_SUBSYS_NS_LS_DRIVER :
472             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
473             if (bytes_read != sizeof ip_hdr) {
474                 *err = file_error(fh);
475                 if (*err != 0)
476                     return -1;
477                 if (bytes_read != 0) {
478                     *err = WTAP_ERR_SHORT_READ;
479                     return -1;
480                 }
481                 return 0;
482             }
483             offset += sizeof ip_hdr;
484
485             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
486              * HP-UX 9 and 10 */
487             if (wth->capture.nettl->is_hpux_11) {
488                 bytes_read = file_read(dummy, 1, 4, fh);
489                 if (bytes_read != 4) {
490                     *err = file_error(fh);
491                     if (*err != 0)
492                         return -1;
493                     if (bytes_read != 0) {
494                         *err = WTAP_ERR_SHORT_READ;
495                         return -1;
496                     }
497                     return 0;
498                 }
499                 offset += 4;
500             }
501
502             /* XXX we dont know how to identify this as ethernet frames, so
503                we assumes everything is. We will crash and burn for anything else */
504             /* for encapsulated 100baseT we do this */
505             phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
506             /* We assume there's no FCS in this frame. */
507             pseudo_header->eth.fcs_len = 0;
508             bytes_read = file_read(&drv_eth_hdr, 1, sizeof drv_eth_hdr, fh);
509             if (bytes_read != sizeof drv_eth_hdr) {
510                 *err = file_error(fh);
511                 if (*err != 0)
512                     return -1;
513                 if (bytes_read != 0) {
514                     *err = WTAP_ERR_SHORT_READ;
515                     return -1;
516                 }
517                 return 0;
518             }
519             offset += sizeof drv_eth_hdr;
520
521             length = pntohs(&drv_eth_hdr.length); 
522             if (length <= 0) return 0;
523             phdr->len = length;
524             length = pntohs(&drv_eth_hdr.caplen);
525             phdr->caplen = length;
526
527             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
528             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
529             break;
530         case NETTL_SUBSYS_SX25L2 :
531             phdr->pkt_encap = WTAP_ENCAP_LAPB;
532             bytes_read = file_read(&lapb_hdr, 1, sizeof lapb_hdr, fh);
533             if (bytes_read != sizeof lapb_hdr) {
534                 *err = file_error(fh);
535                 if (*err != 0)
536                     return -1;
537                 if (bytes_read != 0) {
538                     *err = WTAP_ERR_SHORT_READ;
539                     return -1;
540                 }
541                 return 0;
542             }
543             offset += sizeof lapb_hdr;
544
545             if (wth->capture.nettl->is_hpux_11) {
546                 bytes_read = file_read(dummy, 1, 4, fh);
547                 if (bytes_read != 4) {
548                     *err = file_error(fh);
549                     if (*err != 0)
550                         return -1;
551                     if (bytes_read != 0) {
552                         *err = WTAP_ERR_SHORT_READ;
553                         return -1;
554                     }
555                     return 0;
556                 }
557                 offset += 4;
558             }
559
560             length = pntohs(&lapb_hdr.length);
561             if (length <= 0) return 0;
562             phdr->len = length;
563             phdr->caplen = length;
564
565             phdr->ts.tv_sec = pntohl(&lapb_hdr.sec);
566             phdr->ts.tv_usec = pntohl(&lapb_hdr.usec);
567             pseudo_header->x25.flags =
568                 (lapb_hdr.from_dce & 0x20 ? FROM_DCE : 0x00);
569             break;
570         default:
571             *err = WTAP_ERR_UNSUPPORTED_ENCAP;
572             *err_info = g_strdup_printf("nettl: subsystem %u unknown or unsupported",
573                     encap);
574             return -1;
575     }
576     return offset;
577 }
578
579 static gboolean
580 nettl_read_rec_data(FILE_T fh, guchar *pd, int length, int *err, gboolean fddihack)
581 {
582     int bytes_read;
583     guchar *p=NULL;
584     guint8 dummy[3];
585
586     if (fddihack == TRUE) {
587        /* read in FC, dest, src and DSAP */
588        if (file_read(pd, 1, 14, fh) == 14) {
589           if (pd[13] == 0xAA) {
590              /* it's SNAP, have to eat 3 bytes??? */
591              if (file_read(dummy, 1, 3, fh) == 3) {
592                 p=pd+14;
593                 bytes_read = file_read(p, 1, length-17, fh);
594                 bytes_read += 17;
595              } else {
596                 bytes_read = -1;
597              }
598           } else {
599              /* not SNAP */
600              p=pd+14;
601              bytes_read = file_read(p, 1, length-14, fh);
602              bytes_read += 14;
603           }
604        } else
605           bytes_read = -1;
606     } else
607        bytes_read = file_read(pd, 1, length, fh);
608
609     if (bytes_read != length) {
610         *err = file_error(fh);
611         if (*err == 0)
612             *err = WTAP_ERR_SHORT_READ;
613         return FALSE;
614     }
615     return TRUE;
616 }
617
618 static void nettl_close(wtap *wth)
619 {
620     g_free(wth->capture.nettl);
621 }