Give it an RCS ID.
[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 file header */
43 struct nettl_file_hdr {
44     guchar      magic[12];
45     guchar      file_name[56];
46     guchar      tz[20];
47     guchar      host_name[9];
48     guchar      os_vers[9];
49     guchar      os_v;
50     guint8      xxa[8];
51     guchar      model[11];
52     guint16     unknown;
53 };
54
55 /* HP nettl record header for the SX25L2 subsystem - The FCS is not included in the file. */
56 struct nettlrec_sx25l2_hdr {
57     guint8      xxa[8];
58     guint8      from_dce;
59     guint8      xxb[55];
60     guint8      caplen[2];
61     guint8      length[2];
62     guint8      xxc[4];
63     guint8      sec[4];
64     guint8      usec[4];
65     guint8      xxd[4];
66 };
67
68 /* HP nettl record header for the NS_LS_IP subsystem */
69 /* This also works for BASE100 and GSC100BT */
70 /* see /usr/include/sys/netdiag1.h for hints */
71 struct nettlrec_ns_ls_ip_hdr {
72     guint32     kind;
73     guint8      xxa[4];
74     guint8      rectype;
75     guint8      xxb[19];
76     guint32     caplen;
77     guint32     length;
78     guint32     sec;
79     guint32     usec;
80     guint8      xxc[16];
81 };
82
83 /* Full record header for writing out a nettl file */
84 struct nettlrec_dump_hdr {
85     guint16     hdr_len;
86     guint16     subsys;
87     struct      nettlrec_ns_ls_ip_hdr hdr;
88     guint8      xxd[4];
89 };
90
91 /* header is followed by data and once again the total length (2 bytes) ! */
92
93
94 /* NL_LS_DRIVER :
95 The following shows what the header looks like for NS_LS_DRIVER
96 The capture was taken on HPUX11 and for a 100baseT interface.
97
98 000080 00 44 00 0b 00 00 00 02 00 00 00 00 20 00 00 00
99 000090 00 00 00 00 00 00 04 06 00 00 00 00 00 00 00 00
100 0000a0 00 00 00 74 00 00 00 74 3c e3 76 19 00 06 34 63
101 0000b0 ff ff ff ff 00 00 00 00 00 00 00 00 ff ff ff ff
102 0000c0 00 00 00 00 00 00 01 02 00 5c 00 5c ff ff ff ff
103 0000d0 3c e3 76 19 00 06 34 5a 00 0b 00 14 <here starts the MAC heder>
104
105 Each entry starts with 0x0044000b
106
107 The values 0x005c at position 0x0000c8 and 0x0000ca matches the number of bytes in
108 the packet up to the next entry, which starts with 0x00440b again. These probably
109 indicate the real and captured length of the packet (order unknown)
110
111 The values 0x00000074 at positions 0x0000a0 and 0x0000a4 seems to indicate
112 the same number as positions 0x0000c8 and 0x0000ca but added with 24.
113 Perhaps we have here two layers of headers.
114 The first layer is fixed and consists of all the bytes from 0x000084 up to and
115 including 0x0000c3 which is a generic header for all packets captured from any
116 device. This header might be of fixed size 64 bytes and there might be something in
117 it which indicates the type of the next header which is link type specific.
118 Following this header there is another header for the 100baseT interface which
119 in this case is 24 bytes long spanning positions 0x0000c4 to 0x0000db.
120
121 When someone reports that the loading of the captures breaks, we can compare
122 this header above with what he/she got to learn how to distinguish between different
123 types of link specific headers.
124
125
126 For now:
127 The first header seems to be
128         a normal nettlrec_ns_ls_ip_hdr
129
130 The header for 100baseT seems to be
131         0-3     unknown
132         4-5     captured length
133         6-7     actual length
134         8-11    unknown
135         12-15   secs
136         16-19   usecs
137         20-23   unknown
138 */
139 struct nettlrec_ns_ls_drv_eth_hdr {
140     guint8      xxa[4];
141     guint8      caplen[2];
142     guint8      length[2];
143     guint8      xxb[4];
144     guint8      sec[4];
145     guint8      usec[4];
146     guint8      xxc[4];
147 };
148
149
150 static gboolean nettl_read(wtap *wth, int *err, gchar **err_info,
151                 long *data_offset);
152 static gboolean nettl_seek_read(wtap *wth, long seek_off,
153                 union wtap_pseudo_header *pseudo_header, guchar *pd,
154                 int length, int *err, gchar **err_info);
155 static int nettl_read_rec_header(wtap *wth, FILE_T fh,
156                 struct wtap_pkthdr *phdr, union wtap_pseudo_header *pseudo_header,
157                 int *err, gchar **err_info, gboolean *fddihack);
158 static gboolean nettl_read_rec_data(FILE_T fh, guchar *pd, int length,
159                 int *err, gboolean fddihack);
160 static void nettl_close(wtap *wth);
161 static gboolean nettl_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
162     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
163
164 int nettl_open(wtap *wth, int *err, gchar **err_info _U_)
165 {
166     char magic[12], os_vers[2];
167     guint16 dummy[2];
168     int subsys;
169     int bytes_read;
170
171     /* Read in the string that should be at the start of a HP file */
172     errno = WTAP_ERR_CANT_READ;
173     bytes_read = file_read(magic, 1, 12, wth->fh);
174     if (bytes_read != 12) {
175         *err = file_error(wth->fh);
176         if (*err != 0)
177             return -1;
178         return 0;
179     }
180
181     if (memcmp(magic, nettl_magic_hpux9, 12) &&
182         memcmp(magic, nettl_magic_hpux10, 12)) {
183         return 0;
184     }
185
186     if (file_seek(wth->fh, 0x63, SEEK_SET, err) == -1)
187         return -1;
188     wth->data_offset = 0x63;
189     bytes_read = file_read(os_vers, 1, 2, wth->fh);
190     if (bytes_read != 2) {
191         *err = file_error(wth->fh);
192         if (*err != 0)
193             return -1;
194         return 0;
195     }
196
197     if (file_seek(wth->fh, 0x80, SEEK_SET, err) == -1)
198         return -1;
199     wth->data_offset = 0x80;
200
201     /* This is an nettl file */
202     wth->file_type = WTAP_FILE_NETTL;
203     wth->capture.nettl = g_malloc(sizeof(nettl_t));
204     if (os_vers[0] == '1' && os_vers[1] == '1')
205         wth->capture.nettl->is_hpux_11 = TRUE;
206     else
207         wth->capture.nettl->is_hpux_11 = FALSE;
208     wth->subtype_read = nettl_read;
209     wth->subtype_seek_read = nettl_seek_read;
210     wth->subtype_close = nettl_close;
211     wth->snapshot_length = 0;   /* not available in header, only in frame */
212
213     /* read the first header to take a guess at the file encap */
214     bytes_read = file_read(dummy, 1, 4, wth->fh);
215     if (bytes_read != 4) {
216         if (*err != 0)
217             return -1;
218         if (bytes_read != 0) {
219             *err = WTAP_ERR_SHORT_READ;
220             return -1;
221         }
222         return 0;
223     }
224
225     subsys = g_ntohs(dummy[1]);
226     switch (subsys) {
227         case NETTL_SUBSYS_HPPB_FDDI :
228         case NETTL_SUBSYS_EISA_FDDI :
229         case NETTL_SUBSYS_PCI_FDDI :
230         case NETTL_SUBSYS_HSC_FDDI :
231                 wth->file_encap = WTAP_ENCAP_FDDI_BITSWAPPED;
232                 break;
233         case NETTL_SUBSYS_TOKEN :
234         case NETTL_SUBSYS_PCI_TR :
235                 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
236                 break;
237         case NETTL_SUBSYS_NS_LS_IP :
238         case NETTL_SUBSYS_NS_LS_LOOPBACK :
239         case NETTL_SUBSYS_NS_LS_TCP :
240         case NETTL_SUBSYS_NS_LS_UDP :
241         case NETTL_SUBSYS_NS_LS_IPV6 :
242                 wth->file_encap = WTAP_ENCAP_RAW_IP;
243                 break;
244         default:
245                 /* if assumption is bad, the read will catch it */
246                 wth->file_encap = WTAP_ENCAP_ETHERNET;
247     }
248
249     if (file_seek(wth->fh, 0x80, SEEK_SET, err) == -1)
250         return -1;
251     wth->data_offset = 0x80;
252
253     return 1;
254 }
255
256 /* Read the next packet */
257 static gboolean nettl_read(wtap *wth, int *err, gchar **err_info,
258     long *data_offset)
259 {
260     int ret;
261     gboolean fddihack=FALSE;
262
263     /* Read record header. */
264     *data_offset = wth->data_offset;
265     ret = nettl_read_rec_header(wth, wth->fh, &wth->phdr, &wth->pseudo_header,
266         err, err_info, &fddihack);
267     if (ret <= 0) {
268         /* Read error or EOF */
269         return FALSE;
270     }
271     wth->data_offset += ret;
272
273     /*
274      * If the per-file encapsulation isn't known, set it to this
275      * packet's encapsulation.
276      *
277      * If it *is* known, and it isn't this packet's encapsulation,
278      * set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
279      * have a single encapsulation for all packets in the file.
280      */
281     if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
282         wth->file_encap = wth->phdr.pkt_encap;
283     else {
284         if (wth->file_encap != wth->phdr.pkt_encap)
285             wth->file_encap = WTAP_ENCAP_PER_PACKET;
286     }
287
288     /*
289      * Read the packet data.
290      */
291     buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
292     if (!nettl_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
293                 wth->phdr.caplen, err, fddihack))
294         return FALSE;   /* Read error */
295     wth->data_offset += wth->phdr.caplen;
296     return TRUE;
297 }
298
299 static gboolean
300 nettl_seek_read(wtap *wth, long seek_off,
301                 union wtap_pseudo_header *pseudo_header, guchar *pd,
302                 int length, int *err, gchar **err_info)
303 {
304     int ret;
305     struct wtap_pkthdr phdr;
306     gboolean fddihack=FALSE;
307
308     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
309         return FALSE;
310
311     /* Read record header. */
312     ret = nettl_read_rec_header(wth, wth->random_fh, &phdr, pseudo_header,
313         err, err_info, &fddihack);
314     if (ret <= 0) {
315         /* Read error or EOF */
316         if (ret == 0) {
317             /* EOF means "short read" in random-access mode */
318             *err = WTAP_ERR_SHORT_READ;
319         }
320         return FALSE;
321     }
322
323     /*
324      * Read the packet data.
325      */
326     return nettl_read_rec_data(wth->random_fh, pd, length, err, fddihack);
327 }
328
329 static int
330 nettl_read_rec_header(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
331                 union wtap_pseudo_header *pseudo_header, int *err,
332                 gchar **err_info, gboolean *fddihack)
333 {
334     int bytes_read;
335     struct nettlrec_sx25l2_hdr lapb_hdr;
336     struct nettlrec_ns_ls_ip_hdr ip_hdr;
337     struct nettlrec_ns_ls_drv_eth_hdr drv_eth_hdr;
338     guint16 length;
339     int offset = 0;
340     int subsys;
341     int padlen;
342     guint16 dummy[2];
343     guchar dummyc[12];
344
345     errno = WTAP_ERR_CANT_READ;
346     bytes_read = file_read(dummy, 1, 4, fh);
347     if (bytes_read != 4) {
348         *err = file_error(fh);
349         if (*err != 0)
350             return -1;
351         if (bytes_read != 0) {
352             *err = WTAP_ERR_SHORT_READ;
353             return -1;
354         }
355         return 0;
356     }
357     offset += 4;
358
359     subsys = g_ntohs(dummy[1]);
360     switch (subsys) {
361         case NETTL_SUBSYS_LAN100 :
362         case NETTL_SUBSYS_EISA100BT :
363         case NETTL_SUBSYS_BASE100 :
364         case NETTL_SUBSYS_GSC100BT :
365         case NETTL_SUBSYS_PCI100BT :
366         case NETTL_SUBSYS_SPP100BT :
367         case NETTL_SUBSYS_100VG :
368         case NETTL_SUBSYS_GELAN :
369         case NETTL_SUBSYS_BTLAN :
370         case NETTL_SUBSYS_INTL100 :
371         case NETTL_SUBSYS_IGELAN :
372         case NETTL_SUBSYS_IETHER :
373         case NETTL_SUBSYS_IXGBE :
374         case NETTL_SUBSYS_HPPB_FDDI :
375         case NETTL_SUBSYS_EISA_FDDI :
376         case NETTL_SUBSYS_PCI_FDDI :
377         case NETTL_SUBSYS_HSC_FDDI :
378         case NETTL_SUBSYS_TOKEN :
379         case NETTL_SUBSYS_PCI_TR :
380         case NETTL_SUBSYS_NS_LS_IP :
381         case NETTL_SUBSYS_NS_LS_LOOPBACK :
382         case NETTL_SUBSYS_NS_LS_TCP :
383         case NETTL_SUBSYS_NS_LS_UDP :
384         case NETTL_SUBSYS_HP_APAPORT :
385         case NETTL_SUBSYS_HP_APALACP :
386         case NETTL_SUBSYS_NS_LS_IPV6 :
387         case NETTL_SUBSYS_NS_LS_ICMPV6 :
388         case NETTL_SUBSYS_NS_LS_ICMP :
389             if( (subsys == NETTL_SUBSYS_NS_LS_IP)
390              || (subsys == NETTL_SUBSYS_NS_LS_LOOPBACK)
391              || (subsys == NETTL_SUBSYS_NS_LS_UDP)
392              || (subsys == NETTL_SUBSYS_NS_LS_TCP)
393              || (subsys == NETTL_SUBSYS_NS_LS_IPV6)) {
394                 phdr->pkt_encap = WTAP_ENCAP_RAW_IP;
395             } else if (subsys == NETTL_SUBSYS_NS_LS_ICMP) {
396                 phdr->pkt_encap = WTAP_ENCAP_RAW_ICMP;
397             } else if (subsys == NETTL_SUBSYS_NS_LS_ICMPV6) {
398                 phdr->pkt_encap = WTAP_ENCAP_RAW_ICMPV6;
399             } else if( (subsys == NETTL_SUBSYS_HPPB_FDDI)
400                     || (subsys == NETTL_SUBSYS_EISA_FDDI)
401                     || (subsys == NETTL_SUBSYS_PCI_FDDI)
402                     || (subsys == NETTL_SUBSYS_HSC_FDDI) ) {
403                 phdr->pkt_encap = WTAP_ENCAP_FDDI_BITSWAPPED;
404             } else if( (subsys == NETTL_SUBSYS_PCI_TR)
405                     || (subsys == NETTL_SUBSYS_TOKEN) ) {
406                 phdr->pkt_encap = WTAP_ENCAP_TOKEN_RING;
407             } else {
408                 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
409                 /* We assume there's no FCS in this frame. */
410                 pseudo_header->eth.fcs_len = 0;
411             }
412
413             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
414             if (bytes_read != sizeof ip_hdr) {
415                 *err = file_error(fh);
416                 if (*err != 0)
417                     return -1;
418                 if (bytes_read != 0) {
419                     *err = WTAP_ERR_SHORT_READ;
420                     return -1;
421                 }
422                 return 0;
423             }
424             offset += sizeof ip_hdr;
425
426             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
427              * HP-UX 9 and 10 */
428             if (wth->capture.nettl->is_hpux_11) {
429                 bytes_read = file_read(dummy, 1, 4, fh);
430                 if (bytes_read != 4) {
431                     *err = file_error(fh);
432                     if (*err != 0)
433                         return -1;
434                     if (bytes_read != 0) {
435                         *err = WTAP_ERR_SHORT_READ;
436                         return -1;
437                     }
438                     return 0;
439                 }
440                 offset += 4;
441             }
442
443             /* HPPB FDDI has different inbound vs outbound trace records */
444             if (subsys == NETTL_SUBSYS_HPPB_FDDI) {
445                 if (ip_hdr.rectype == NETTL_HDR_PDUIN) {
446                    /* inbound is very strange...
447                       there are an extra 3 bytes after the DSAP and SSAP
448                       for SNAP frames ???
449                    */
450                    *fddihack=TRUE;
451                    length = pntohl(&ip_hdr.length);
452                    if (length <= 0)
453                        return 0;
454                    phdr->len = length;
455                    length = pntohl(&ip_hdr.caplen);
456                    phdr->caplen = length;
457                 } else {
458                    /* outbound appears to have variable padding */
459                    bytes_read = file_read(dummyc, 1, 9, fh);
460                    if (bytes_read != 9) {
461                        *err = file_error(fh);
462                        if (*err != 0)
463                            return -1;
464                        if (bytes_read != 0) {
465                            *err = WTAP_ERR_SHORT_READ;
466                            return -1;
467                        }
468                        return 0;
469                    }
470                    /* padding is usually either a total 11 or 16 bytes??? */
471                    padlen = (int)dummyc[8];
472                    bytes_read = file_read(dummy, 1, padlen, fh);
473                    if (bytes_read != padlen) {
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                    padlen += 9;
484                    offset += padlen;
485                    length = pntohl(&ip_hdr.length);
486                    if (length <= 0)
487                            return 0;
488                    phdr->len = length - padlen;
489                    length = pntohl(&ip_hdr.caplen);
490                    phdr->caplen = length - padlen;
491                }
492             } else if ( (subsys == NETTL_SUBSYS_PCI_FDDI)
493                      || (subsys == NETTL_SUBSYS_EISA_FDDI)
494                      || (subsys == NETTL_SUBSYS_HSC_FDDI) ) {
495                 /* other flavor FDDI cards have an extra 3 bytes of padding */
496                 bytes_read = file_read(dummy, 1, 3, fh);
497                 if (bytes_read != 3) {
498                     *err = file_error(fh);
499                     if (*err != 0)
500                         return -1;
501                     if (bytes_read != 0) {
502                         *err = WTAP_ERR_SHORT_READ;
503                         return -1;
504                     }
505                     return 0;
506                 }
507                 offset += 3;
508                 length = pntohl(&ip_hdr.length);
509                 if (length <= 0)
510                         return 0;
511                 phdr->len = length - 3;
512                 length = pntohl(&ip_hdr.caplen);
513                 phdr->caplen = length - 3;
514             } else if (subsys == NETTL_SUBSYS_NS_LS_LOOPBACK) {
515                 /* LOOPBACK has an extra 26 bytes of padding */
516                 bytes_read = file_read(dummy, 1, 26, fh);
517                 if (bytes_read != 26) {
518                     *err = file_error(fh);
519                     if (*err != 0)
520                         return -1;
521                     if (bytes_read != 0) {
522                         *err = WTAP_ERR_SHORT_READ;
523                         return -1;
524                     }
525                     return 0;
526                 }
527                 offset += 26;
528                 length = pntohl(&ip_hdr.length);
529                 if (length <= 0)
530                         return 0;
531                 phdr->len = length - 26;
532                 length = pntohl(&ip_hdr.caplen);
533                 phdr->caplen = length - 26;
534             } else {
535                 length = pntohl(&ip_hdr.length);
536                 if (length <= 0)
537                     return 0;
538                 phdr->len = length;
539                 length = pntohl(&ip_hdr.caplen);
540                 phdr->caplen = length;
541             }
542
543             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
544             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
545             break;
546         case NETTL_SUBSYS_NS_LS_DRIVER :
547             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
548             if (bytes_read != sizeof ip_hdr) {
549                 *err = file_error(fh);
550                 if (*err != 0)
551                     return -1;
552                 if (bytes_read != 0) {
553                     *err = WTAP_ERR_SHORT_READ;
554                     return -1;
555                 }
556                 return 0;
557             }
558             offset += sizeof ip_hdr;
559
560             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
561              * HP-UX 9 and 10 */
562             if (wth->capture.nettl->is_hpux_11) {
563                 bytes_read = file_read(dummy, 1, 4, fh);
564                 if (bytes_read != 4) {
565                     *err = file_error(fh);
566                     if (*err != 0)
567                         return -1;
568                     if (bytes_read != 0) {
569                         *err = WTAP_ERR_SHORT_READ;
570                         return -1;
571                     }
572                     return 0;
573                 }
574                 offset += 4;
575             }
576
577             /* XXX we dont know how to identify this as ethernet frames, so
578                we assumes everything is. We will crash and burn for anything else */
579             /* for encapsulated 100baseT we do this */
580             phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
581             /* We assume there's no FCS in this frame. */
582             pseudo_header->eth.fcs_len = 0;
583             bytes_read = file_read(&drv_eth_hdr, 1, sizeof drv_eth_hdr, fh);
584             if (bytes_read != sizeof drv_eth_hdr) {
585                 *err = file_error(fh);
586                 if (*err != 0)
587                     return -1;
588                 if (bytes_read != 0) {
589                     *err = WTAP_ERR_SHORT_READ;
590                     return -1;
591                 }
592                 return 0;
593             }
594             offset += sizeof drv_eth_hdr;
595
596             length = pntohs(&drv_eth_hdr.length); 
597             if (length <= 0) return 0;
598             phdr->len = length;
599             length = pntohs(&drv_eth_hdr.caplen);
600             phdr->caplen = length;
601
602             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
603             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
604             break;
605         case NETTL_SUBSYS_SX25L2 :
606             phdr->pkt_encap = WTAP_ENCAP_LAPB;
607             bytes_read = file_read(&lapb_hdr, 1, sizeof lapb_hdr, fh);
608             if (bytes_read != sizeof lapb_hdr) {
609                 *err = file_error(fh);
610                 if (*err != 0)
611                     return -1;
612                 if (bytes_read != 0) {
613                     *err = WTAP_ERR_SHORT_READ;
614                     return -1;
615                 }
616                 return 0;
617             }
618             offset += sizeof lapb_hdr;
619
620             if (wth->capture.nettl->is_hpux_11) {
621                 bytes_read = file_read(dummy, 1, 4, fh);
622                 if (bytes_read != 4) {
623                     *err = file_error(fh);
624                     if (*err != 0)
625                         return -1;
626                     if (bytes_read != 0) {
627                         *err = WTAP_ERR_SHORT_READ;
628                         return -1;
629                     }
630                     return 0;
631                 }
632                 offset += 4;
633             }
634
635             length = pntohs(&lapb_hdr.length);
636             if (length <= 0) return 0;
637             phdr->len = length;
638             phdr->caplen = length;
639
640             phdr->ts.tv_sec = pntohl(&lapb_hdr.sec);
641             phdr->ts.tv_usec = pntohl(&lapb_hdr.usec);
642             pseudo_header->x25.flags =
643                 (lapb_hdr.from_dce & 0x20 ? FROM_DCE : 0x00);
644             break;
645         default:
646             *err = WTAP_ERR_UNSUPPORTED_ENCAP;
647             *err_info = g_strdup_printf("nettl: subsystem %u unknown or unsupported",
648                     subsys);
649             return -1;
650     }
651     return offset;
652 }
653
654 static gboolean
655 nettl_read_rec_data(FILE_T fh, guchar *pd, int length, int *err, gboolean fddihack)
656 {
657     int bytes_read;
658     guchar *p=NULL;
659     guint8 dummy[3];
660
661     if (fddihack == TRUE) {
662        /* read in FC, dest, src, DSAP and SSAP */
663        if (file_read(pd, 1, 15, fh) == 15) {
664           if (pd[13] == 0xAA) {
665              /* it's SNAP, have to eat 3 bytes??? */
666              if (file_read(dummy, 1, 3, fh) == 3) {
667                 p=pd+15;
668                 bytes_read = file_read(p, 1, length-18, fh);
669                 bytes_read += 18;
670              } else {
671                 bytes_read = -1;
672              }
673           } else {
674              /* not SNAP */
675              p=pd+15;
676              bytes_read = file_read(p, 1, length-15, fh);
677              bytes_read += 15;
678           }
679        } else
680           bytes_read = -1;
681     } else
682        bytes_read = file_read(pd, 1, length, fh);
683
684     if (bytes_read != length) {
685         *err = file_error(fh);
686         if (*err == 0)
687             *err = WTAP_ERR_SHORT_READ;
688         return FALSE;
689     }
690     return TRUE;
691 }
692
693 static void nettl_close(wtap *wth)
694 {
695     g_free(wth->capture.nettl);
696 }
697
698
699 /* Returns 0 if we could write the specified encapsulation type,
700    an error indication otherwise.  nettl files are WTAP_ENCAP_UNKNOWN
701    when they are first opened, so we allow that for tethereal read/write.
702  */
703
704 int nettl_dump_can_write_encap(int encap)
705 {
706
707         switch (encap) {
708                 case WTAP_ENCAP_ETHERNET:
709                 case WTAP_ENCAP_FDDI_BITSWAPPED:
710                 case WTAP_ENCAP_TOKEN_RING:
711                 case WTAP_ENCAP_RAW_IP:
712                 case WTAP_ENCAP_RAW_ICMP:
713                 case WTAP_ENCAP_RAW_ICMPV6:
714                 case WTAP_ENCAP_PER_PACKET:
715                 case WTAP_ENCAP_UNKNOWN:
716                         return 0;
717                 default:
718                         return WTAP_ERR_UNSUPPORTED_ENCAP;
719         }
720 }
721
722
723 /* Returns TRUE on success, FALSE on failure;
724    sets "*err" to an error code on failure */
725 gboolean nettl_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err)
726 {
727         struct nettl_file_hdr file_hdr;
728         size_t nwritten;
729
730         /* This is a nettl file */
731         wdh->subtype_write = nettl_dump;
732         wdh->subtype_close = NULL;
733
734         /* Write the file header. */
735         memset(&file_hdr,0,sizeof(file_hdr));
736         memcpy(file_hdr.magic,nettl_magic_hpux10,sizeof(file_hdr.magic));
737         strcpy(file_hdr.file_name,"/tmp/ethereal.TRC000");
738         strcpy(file_hdr.tz,"UTC");
739         strcpy(file_hdr.host_name,"ethereal");
740         strcpy(file_hdr.os_vers,"B.11.11");
741         file_hdr.os_v=0x55;
742         strcpy(file_hdr.model,"9000/800");
743         file_hdr.unknown=g_htons(0x406);
744         nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
745         if (nwritten != sizeof(file_hdr)) {
746                 if (nwritten == 0 && ferror(wdh->fh))
747                         *err = errno;
748                 else
749                         *err = WTAP_ERR_SHORT_WRITE;
750                 return FALSE;
751         }
752         wdh->bytes_dumped += sizeof(file_hdr);
753
754         return TRUE;
755 }
756
757 /* Write a record for a packet to a dump file.
758    Returns TRUE on success, FALSE on failure. */
759 static gboolean nettl_dump(wtap_dumper *wdh,
760         const struct wtap_pkthdr *phdr,
761         const union wtap_pseudo_header *pseudo_header _U_,
762         const guchar *pd, int *err)
763 {
764         struct nettlrec_dump_hdr rec_hdr;
765         guint32 dummy=0;
766         size_t nwritten;
767
768         memset(&rec_hdr,0,sizeof(rec_hdr));
769         rec_hdr.hdr_len = g_htons(sizeof(rec_hdr));
770         rec_hdr.hdr.rectype = NETTL_HDR_PDUIN;
771         rec_hdr.hdr.sec = g_htonl(phdr->ts.tv_sec);
772         rec_hdr.hdr.usec = g_htonl(phdr->ts.tv_usec);
773         rec_hdr.hdr.caplen = g_htonl(phdr->caplen);
774         rec_hdr.hdr.length = g_htonl(phdr->len);
775
776         switch (phdr->pkt_encap) {
777
778                 case WTAP_ENCAP_RAW_IP:
779                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_NS_LS_IP);
780                         break;
781
782                 case WTAP_ENCAP_ETHERNET:
783                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_BTLAN);
784                         break;
785
786                 case WTAP_ENCAP_FDDI_BITSWAPPED:
787                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_PCI_FDDI);
788                         /* account for pad bytes */
789                         rec_hdr.hdr.caplen = g_htonl(phdr->caplen + 3);
790                         rec_hdr.hdr.length = g_htonl(phdr->len + 3);
791                         break;
792
793                 case WTAP_ENCAP_TOKEN_RING:
794                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_PCI_TR);
795                         break;
796         
797                 case WTAP_ENCAP_RAW_ICMP:
798                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_NS_LS_ICMP);
799                         break;
800         
801                 case WTAP_ENCAP_RAW_ICMPV6:
802                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_NS_LS_ICMPV6);
803                         break;
804         
805                 default:
806                         /* found one we don't support */
807                         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
808                         return FALSE;
809         }
810
811         nwritten = fwrite(&rec_hdr, 1, sizeof(rec_hdr), wdh->fh);
812         if (nwritten != sizeof(rec_hdr)) {
813                 if (nwritten == 0 && ferror(wdh->fh))
814                         *err = errno;
815                 else
816                         *err = WTAP_ERR_SHORT_WRITE;
817                 return FALSE;
818         }
819         wdh->bytes_dumped += sizeof(rec_hdr);
820
821         if (phdr->pkt_encap == WTAP_ENCAP_FDDI_BITSWAPPED) {
822                 /* add those weird 3 bytes of padding */
823                 nwritten = fwrite(&dummy, 1, 3, wdh->fh);
824                 if (nwritten != 3) {
825                         if (nwritten == 0 && ferror(wdh->fh))
826                                 *err = errno;
827                         else
828                                 *err = WTAP_ERR_SHORT_WRITE;
829                         return FALSE;
830                 }
831                 wdh->bytes_dumped += 3;
832         }
833
834         /* write actual PDU data */
835
836         nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
837         if (nwritten != phdr->caplen) {
838                 if (nwritten == 0 && ferror(wdh->fh))
839                         *err = errno;
840                 else
841                         *err = WTAP_ERR_SHORT_WRITE;
842                 return FALSE;
843         }
844         wdh->bytes_dumped += phdr->caplen;
845
846         return TRUE;
847 }