From Mark C. Brown:
[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     guint8 dummy[4];
168     int bytes_read;
169
170     /* Read in the string that should be at the start of a HP file */
171     errno = WTAP_ERR_CANT_READ;
172     bytes_read = file_read(magic, 1, 12, wth->fh);
173     if (bytes_read != 12) {
174         *err = file_error(wth->fh);
175         if (*err != 0)
176             return -1;
177         return 0;
178     }
179
180     if (memcmp(magic, nettl_magic_hpux9, 12) &&
181         memcmp(magic, nettl_magic_hpux10, 12)) {
182         return 0;
183     }
184
185     if (file_seek(wth->fh, 0x63, SEEK_SET, err) == -1)
186         return -1;
187     wth->data_offset = 0x63;
188     bytes_read = file_read(os_vers, 1, 2, wth->fh);
189     if (bytes_read != 2) {
190         *err = file_error(wth->fh);
191         if (*err != 0)
192             return -1;
193         return 0;
194     }
195
196     if (file_seek(wth->fh, 0x80, SEEK_SET, err) == -1)
197         return -1;
198     wth->data_offset = 0x80;
199
200     /* This is an nettl file */
201     wth->file_type = WTAP_FILE_NETTL;
202     wth->capture.nettl = g_malloc(sizeof(nettl_t));
203     if (os_vers[0] == '1' && os_vers[1] == '1')
204         wth->capture.nettl->is_hpux_11 = TRUE;
205     else
206         wth->capture.nettl->is_hpux_11 = FALSE;
207     wth->subtype_read = nettl_read;
208     wth->subtype_seek_read = nettl_seek_read;
209     wth->subtype_close = nettl_close;
210     wth->snapshot_length = 0;   /* not available in header, only in frame */
211
212     /* read the first header to take a guess at the file encap */
213     bytes_read = file_read(dummy, 1, 4, wth->fh);
214     if (bytes_read != 4) {
215         if (*err != 0)
216             return -1;
217         if (bytes_read != 0) {
218             *err = WTAP_ERR_SHORT_READ;
219             return -1;
220         }
221         return 0;
222     }
223
224     switch (dummy[3]) {
225         case NETTL_SUBSYS_HPPB_FDDI :
226         case NETTL_SUBSYS_EISA_FDDI :
227         case NETTL_SUBSYS_PCI_FDDI :
228         case NETTL_SUBSYS_HSC_FDDI :
229                 wth->file_encap = WTAP_ENCAP_FDDI_BITSWAPPED;
230                 break;
231         case NETTL_SUBSYS_TOKEN :
232         case NETTL_SUBSYS_PCI_TR :
233                 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
234                 break;
235         case NETTL_SUBSYS_NS_LS_IP :
236         case NETTL_SUBSYS_NS_LS_LOOPBACK :
237         case NETTL_SUBSYS_NS_LS_TCP :
238         case NETTL_SUBSYS_NS_LS_UDP :
239         case NETTL_SUBSYS_NS_LS_IPV6 :
240                 wth->file_encap = WTAP_ENCAP_RAW_IP;
241                 break;
242         default:
243                 /* if assumption is bad, the read will catch it */
244                 wth->file_encap = WTAP_ENCAP_ETHERNET;
245     }
246
247     if (file_seek(wth->fh, 0x80, SEEK_SET, err) == -1)
248         return -1;
249     wth->data_offset = 0x80;
250
251     return 1;
252 }
253
254 /* Read the next packet */
255 static gboolean nettl_read(wtap *wth, int *err, gchar **err_info,
256     long *data_offset)
257 {
258     int ret;
259     gboolean fddihack=FALSE;
260
261     /* Read record header. */
262     *data_offset = wth->data_offset;
263     ret = nettl_read_rec_header(wth, wth->fh, &wth->phdr, &wth->pseudo_header,
264         err, err_info, &fddihack);
265     if (ret <= 0) {
266         /* Read error or EOF */
267         return FALSE;
268     }
269     wth->data_offset += ret;
270
271     /*
272      * If the per-file encapsulation isn't known, set it to this
273      * packet's encapsulation.
274      *
275      * If it *is* known, and it isn't this packet's encapsulation,
276      * set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
277      * have a single encapsulation for all packets in the file.
278      */
279     if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
280         wth->file_encap = wth->phdr.pkt_encap;
281     else {
282         if (wth->file_encap != wth->phdr.pkt_encap)
283             wth->file_encap = WTAP_ENCAP_PER_PACKET;
284     }
285
286     /*
287      * Read the packet data.
288      */
289     buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
290     if (!nettl_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
291                 wth->phdr.caplen, err, fddihack))
292         return FALSE;   /* Read error */
293     wth->data_offset += wth->phdr.caplen;
294     return TRUE;
295 }
296
297 static gboolean
298 nettl_seek_read(wtap *wth, long seek_off,
299                 union wtap_pseudo_header *pseudo_header, guchar *pd,
300                 int length, int *err, gchar **err_info)
301 {
302     int ret;
303     struct wtap_pkthdr phdr;
304     gboolean fddihack=FALSE;
305
306     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
307         return FALSE;
308
309     /* Read record header. */
310     ret = nettl_read_rec_header(wth, wth->random_fh, &phdr, pseudo_header,
311         err, err_info, &fddihack);
312     if (ret <= 0) {
313         /* Read error or EOF */
314         if (ret == 0) {
315             /* EOF means "short read" in random-access mode */
316             *err = WTAP_ERR_SHORT_READ;
317         }
318         return FALSE;
319     }
320
321     /*
322      * Read the packet data.
323      */
324     return nettl_read_rec_data(wth->random_fh, pd, length, err, fddihack);
325 }
326
327 static int
328 nettl_read_rec_header(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
329                 union wtap_pseudo_header *pseudo_header, int *err,
330                 gchar **err_info, gboolean *fddihack)
331 {
332     int bytes_read;
333     struct nettlrec_sx25l2_hdr lapb_hdr;
334     struct nettlrec_ns_ls_ip_hdr ip_hdr;
335     struct nettlrec_ns_ls_drv_eth_hdr drv_eth_hdr;
336     guint16 length;
337     int offset = 0;
338     int encap;
339     int padlen;
340     guint8 dummy[4];
341     guchar dummyc[12];
342
343     errno = WTAP_ERR_CANT_READ;
344     bytes_read = file_read(dummy, 1, 4, fh);
345     if (bytes_read != 4) {
346         *err = file_error(fh);
347         if (*err != 0)
348             return -1;
349         if (bytes_read != 0) {
350             *err = WTAP_ERR_SHORT_READ;
351             return -1;
352         }
353         return 0;
354     }
355     offset += 4;
356     encap=dummy[3];
357
358     switch (encap) {
359         case NETTL_SUBSYS_LAN100 :
360         case NETTL_SUBSYS_EISA100BT :
361         case NETTL_SUBSYS_BASE100 :
362         case NETTL_SUBSYS_GSC100BT :
363         case NETTL_SUBSYS_PCI100BT :
364         case NETTL_SUBSYS_SPP100BT :
365         case NETTL_SUBSYS_100VG :
366         case NETTL_SUBSYS_GELAN :
367         case NETTL_SUBSYS_BTLAN :
368         case NETTL_SUBSYS_INTL100 :
369         case NETTL_SUBSYS_IGELAN :
370         case NETTL_SUBSYS_IETHER :
371         case NETTL_SUBSYS_HPPB_FDDI :
372         case NETTL_SUBSYS_EISA_FDDI :
373         case NETTL_SUBSYS_PCI_FDDI :
374         case NETTL_SUBSYS_HSC_FDDI :
375         case NETTL_SUBSYS_TOKEN :
376         case NETTL_SUBSYS_PCI_TR :
377         case NETTL_SUBSYS_NS_LS_IP :
378         case NETTL_SUBSYS_NS_LS_LOOPBACK :
379         case NETTL_SUBSYS_NS_LS_TCP :
380         case NETTL_SUBSYS_NS_LS_UDP :
381         case NETTL_SUBSYS_HP_APAPORT :
382         case NETTL_SUBSYS_HP_APALACP :
383         case NETTL_SUBSYS_NS_LS_IPV6 :
384         case NETTL_SUBSYS_NS_LS_ICMPV6 :
385         case NETTL_SUBSYS_NS_LS_ICMP :
386             if( (encap == NETTL_SUBSYS_NS_LS_IP)
387              || (encap == NETTL_SUBSYS_NS_LS_LOOPBACK)
388              || (encap == NETTL_SUBSYS_NS_LS_UDP)
389              || (encap == NETTL_SUBSYS_NS_LS_TCP)
390              || (encap == NETTL_SUBSYS_NS_LS_IPV6)) {
391                 phdr->pkt_encap = WTAP_ENCAP_RAW_IP;
392             } else if (encap == NETTL_SUBSYS_NS_LS_ICMP) {
393                 phdr->pkt_encap = WTAP_ENCAP_RAW_ICMP;
394             } else if (encap == NETTL_SUBSYS_NS_LS_ICMPV6) {
395                 phdr->pkt_encap = WTAP_ENCAP_RAW_ICMPV6;
396             } else if( (encap == NETTL_SUBSYS_HPPB_FDDI)
397                     || (encap == NETTL_SUBSYS_EISA_FDDI)
398                     || (encap == NETTL_SUBSYS_PCI_FDDI)
399                     || (encap == NETTL_SUBSYS_HSC_FDDI) ) {
400                 phdr->pkt_encap = WTAP_ENCAP_FDDI_BITSWAPPED;
401             } else if( (encap == NETTL_SUBSYS_PCI_TR)
402                     || (encap == NETTL_SUBSYS_TOKEN) ) {
403                 phdr->pkt_encap = WTAP_ENCAP_TOKEN_RING;
404             } else {
405                 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
406                 /* We assume there's no FCS in this frame. */
407                 pseudo_header->eth.fcs_len = 0;
408             }
409
410             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
411             if (bytes_read != sizeof ip_hdr) {
412                 *err = file_error(fh);
413                 if (*err != 0)
414                     return -1;
415                 if (bytes_read != 0) {
416                     *err = WTAP_ERR_SHORT_READ;
417                     return -1;
418                 }
419                 return 0;
420             }
421             offset += sizeof ip_hdr;
422
423             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
424              * HP-UX 9 and 10 */
425             if (wth->capture.nettl->is_hpux_11) {
426                 bytes_read = file_read(dummy, 1, 4, fh);
427                 if (bytes_read != 4) {
428                     *err = file_error(fh);
429                     if (*err != 0)
430                         return -1;
431                     if (bytes_read != 0) {
432                         *err = WTAP_ERR_SHORT_READ;
433                         return -1;
434                     }
435                     return 0;
436                 }
437                 offset += 4;
438             }
439
440             /* HPPB FDDI has different inbound vs outbound trace records */
441             if (encap == NETTL_SUBSYS_HPPB_FDDI) {
442                 if (ip_hdr.rectype == NETTL_HDR_PDUIN) {
443                    /* inbound is very strange...
444                       there are an extra 3 bytes after the DSAP and SSAP
445                       for SNAP frames ???
446                    */
447                    *fddihack=TRUE;
448                    length = pntohl(&ip_hdr.length);
449                    if (length <= 0)
450                        return 0;
451                    phdr->len = length;
452                    length = pntohl(&ip_hdr.caplen);
453                    phdr->caplen = length;
454                 } else {
455                    /* outbound appears to have variable padding */
456                    bytes_read = file_read(dummyc, 1, 9, fh);
457                    if (bytes_read != 9) {
458                        *err = file_error(fh);
459                        if (*err != 0)
460                            return -1;
461                        if (bytes_read != 0) {
462                            *err = WTAP_ERR_SHORT_READ;
463                            return -1;
464                        }
465                        return 0;
466                    }
467                    /* padding is usually either a total 11 or 16 bytes??? */
468                    padlen = (int)dummyc[8];
469                    bytes_read = file_read(dummy, 1, padlen, fh);
470                    if (bytes_read != padlen) {
471                        *err = file_error(fh);
472                        if (*err != 0)
473                            return -1;
474                        if (bytes_read != 0) {
475                            *err = WTAP_ERR_SHORT_READ;
476                            return -1;
477                        }
478                        return 0;
479                    }
480                    padlen += 9;
481                    offset += padlen;
482                    length = pntohl(&ip_hdr.length);
483                    if (length <= 0)
484                            return 0;
485                    phdr->len = length - padlen;
486                    length = pntohl(&ip_hdr.caplen);
487                    phdr->caplen = length - padlen;
488                }
489             } else if ( (encap == NETTL_SUBSYS_PCI_FDDI)
490                      || (encap == NETTL_SUBSYS_EISA_FDDI)
491                      || (encap == NETTL_SUBSYS_HSC_FDDI) ) {
492                 /* other flavor FDDI cards have an extra 3 bytes of padding */
493                 bytes_read = file_read(dummy, 1, 3, fh);
494                 if (bytes_read != 3) {
495                     *err = file_error(fh);
496                     if (*err != 0)
497                         return -1;
498                     if (bytes_read != 0) {
499                         *err = WTAP_ERR_SHORT_READ;
500                         return -1;
501                     }
502                     return 0;
503                 }
504                 offset += 3;
505                 length = pntohl(&ip_hdr.length);
506                 if (length <= 0)
507                         return 0;
508                 phdr->len = length - 3;
509                 length = pntohl(&ip_hdr.caplen);
510                 phdr->caplen = length - 3;
511             } else if (encap == NETTL_SUBSYS_NS_LS_LOOPBACK) {
512                 /* LOOPBACK has an extra 26 bytes of padding */
513                 bytes_read = file_read(dummy, 1, 26, fh);
514                 if (bytes_read != 26) {
515                     *err = file_error(fh);
516                     if (*err != 0)
517                         return -1;
518                     if (bytes_read != 0) {
519                         *err = WTAP_ERR_SHORT_READ;
520                         return -1;
521                     }
522                     return 0;
523                 }
524                 offset += 26;
525                 length = pntohl(&ip_hdr.length);
526                 if (length <= 0)
527                         return 0;
528                 phdr->len = length - 26;
529                 length = pntohl(&ip_hdr.caplen);
530                 phdr->caplen = length - 26;
531             } else {
532                 length = pntohl(&ip_hdr.length);
533                 if (length <= 0)
534                     return 0;
535                 phdr->len = length;
536                 length = pntohl(&ip_hdr.caplen);
537                 phdr->caplen = length;
538             }
539
540             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
541             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
542             break;
543         case NETTL_SUBSYS_NS_LS_DRIVER :
544             bytes_read = file_read(&ip_hdr, 1, sizeof ip_hdr, fh);
545             if (bytes_read != sizeof ip_hdr) {
546                 *err = file_error(fh);
547                 if (*err != 0)
548                     return -1;
549                 if (bytes_read != 0) {
550                     *err = WTAP_ERR_SHORT_READ;
551                     return -1;
552                 }
553                 return 0;
554             }
555             offset += sizeof ip_hdr;
556
557             /* The packet header in HP-UX 11 nettl traces is 4 octets longer than
558              * HP-UX 9 and 10 */
559             if (wth->capture.nettl->is_hpux_11) {
560                 bytes_read = file_read(dummy, 1, 4, fh);
561                 if (bytes_read != 4) {
562                     *err = file_error(fh);
563                     if (*err != 0)
564                         return -1;
565                     if (bytes_read != 0) {
566                         *err = WTAP_ERR_SHORT_READ;
567                         return -1;
568                     }
569                     return 0;
570                 }
571                 offset += 4;
572             }
573
574             /* XXX we dont know how to identify this as ethernet frames, so
575                we assumes everything is. We will crash and burn for anything else */
576             /* for encapsulated 100baseT we do this */
577             phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
578             /* We assume there's no FCS in this frame. */
579             pseudo_header->eth.fcs_len = 0;
580             bytes_read = file_read(&drv_eth_hdr, 1, sizeof drv_eth_hdr, fh);
581             if (bytes_read != sizeof drv_eth_hdr) {
582                 *err = file_error(fh);
583                 if (*err != 0)
584                     return -1;
585                 if (bytes_read != 0) {
586                     *err = WTAP_ERR_SHORT_READ;
587                     return -1;
588                 }
589                 return 0;
590             }
591             offset += sizeof drv_eth_hdr;
592
593             length = pntohs(&drv_eth_hdr.length); 
594             if (length <= 0) return 0;
595             phdr->len = length;
596             length = pntohs(&drv_eth_hdr.caplen);
597             phdr->caplen = length;
598
599             phdr->ts.tv_sec = pntohl(&ip_hdr.sec);
600             phdr->ts.tv_usec = pntohl(&ip_hdr.usec);
601             break;
602         case NETTL_SUBSYS_SX25L2 :
603             phdr->pkt_encap = WTAP_ENCAP_LAPB;
604             bytes_read = file_read(&lapb_hdr, 1, sizeof lapb_hdr, fh);
605             if (bytes_read != sizeof lapb_hdr) {
606                 *err = file_error(fh);
607                 if (*err != 0)
608                     return -1;
609                 if (bytes_read != 0) {
610                     *err = WTAP_ERR_SHORT_READ;
611                     return -1;
612                 }
613                 return 0;
614             }
615             offset += sizeof lapb_hdr;
616
617             if (wth->capture.nettl->is_hpux_11) {
618                 bytes_read = file_read(dummy, 1, 4, fh);
619                 if (bytes_read != 4) {
620                     *err = file_error(fh);
621                     if (*err != 0)
622                         return -1;
623                     if (bytes_read != 0) {
624                         *err = WTAP_ERR_SHORT_READ;
625                         return -1;
626                     }
627                     return 0;
628                 }
629                 offset += 4;
630             }
631
632             length = pntohs(&lapb_hdr.length);
633             if (length <= 0) return 0;
634             phdr->len = length;
635             phdr->caplen = length;
636
637             phdr->ts.tv_sec = pntohl(&lapb_hdr.sec);
638             phdr->ts.tv_usec = pntohl(&lapb_hdr.usec);
639             pseudo_header->x25.flags =
640                 (lapb_hdr.from_dce & 0x20 ? FROM_DCE : 0x00);
641             break;
642         default:
643             *err = WTAP_ERR_UNSUPPORTED_ENCAP;
644             *err_info = g_strdup_printf("nettl: subsystem %u unknown or unsupported",
645                     encap);
646             return -1;
647     }
648     return offset;
649 }
650
651 static gboolean
652 nettl_read_rec_data(FILE_T fh, guchar *pd, int length, int *err, gboolean fddihack)
653 {
654     int bytes_read;
655     guchar *p=NULL;
656     guint8 dummy[3];
657
658     if (fddihack == TRUE) {
659        /* read in FC, dest, src, DSAP and SSAP */
660        if (file_read(pd, 1, 15, fh) == 15) {
661           if (pd[13] == 0xAA) {
662              /* it's SNAP, have to eat 3 bytes??? */
663              if (file_read(dummy, 1, 3, fh) == 3) {
664                 p=pd+15;
665                 bytes_read = file_read(p, 1, length-18, fh);
666                 bytes_read += 18;
667              } else {
668                 bytes_read = -1;
669              }
670           } else {
671              /* not SNAP */
672              p=pd+15;
673              bytes_read = file_read(p, 1, length-15, fh);
674              bytes_read += 15;
675           }
676        } else
677           bytes_read = -1;
678     } else
679        bytes_read = file_read(pd, 1, length, fh);
680
681     if (bytes_read != length) {
682         *err = file_error(fh);
683         if (*err == 0)
684             *err = WTAP_ERR_SHORT_READ;
685         return FALSE;
686     }
687     return TRUE;
688 }
689
690 static void nettl_close(wtap *wth)
691 {
692     g_free(wth->capture.nettl);
693 }
694
695
696 /* Returns 0 if we could write the specified encapsulation type,
697    an error indication otherwise.  nettl files are WTAP_ENCAP_UNKNOWN
698    when they are first opened, so we allow that for tethereal read/write.
699  */
700
701 int nettl_dump_can_write_encap(int encap)
702 {
703
704         switch (encap) {
705                 case WTAP_ENCAP_ETHERNET:
706                 case WTAP_ENCAP_FDDI_BITSWAPPED:
707                 case WTAP_ENCAP_TOKEN_RING:
708                 case WTAP_ENCAP_RAW_IP:
709                 case WTAP_ENCAP_RAW_ICMP:
710                 case WTAP_ENCAP_RAW_ICMPV6:
711                 case WTAP_ENCAP_PER_PACKET:
712                 case WTAP_ENCAP_UNKNOWN:
713                         return 0;
714                 default:
715                         return WTAP_ERR_UNSUPPORTED_ENCAP;
716         }
717 }
718
719
720 /* Returns TRUE on success, FALSE on failure;
721    sets "*err" to an error code on failure */
722 gboolean nettl_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err)
723 {
724         struct nettl_file_hdr file_hdr;
725         size_t nwritten;
726
727         /* This is a nettl file */
728         wdh->subtype_write = nettl_dump;
729         wdh->subtype_close = NULL;
730
731         /* Write the file header. */
732         memset(&file_hdr,0,sizeof(file_hdr));
733         memcpy(file_hdr.magic,nettl_magic_hpux10,sizeof(file_hdr.magic));
734         strcpy(file_hdr.file_name,"/tmp/ethereal.TRC000");
735         strcpy(file_hdr.tz,"UTC");
736         strcpy(file_hdr.host_name,"ethereal");
737         strcpy(file_hdr.os_vers,"B.11.11");
738         file_hdr.os_v=0x55;
739         strcpy(file_hdr.model,"9000/800");
740         file_hdr.unknown=g_htons(0x406);
741         nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
742         if (nwritten != sizeof(file_hdr)) {
743                 if (nwritten == 0 && ferror(wdh->fh))
744                         *err = errno;
745                 else
746                         *err = WTAP_ERR_SHORT_WRITE;
747                 return FALSE;
748         }
749         wdh->bytes_dumped += sizeof(file_hdr);
750
751         return TRUE;
752 }
753
754 /* Write a record for a packet to a dump file.
755    Returns TRUE on success, FALSE on failure. */
756 static gboolean nettl_dump(wtap_dumper *wdh,
757         const struct wtap_pkthdr *phdr,
758         const union wtap_pseudo_header *pseudo_header _U_,
759         const guchar *pd, int *err)
760 {
761         struct nettlrec_dump_hdr rec_hdr;
762         guint32 dummy=0;
763         size_t nwritten;
764
765         memset(&rec_hdr,0,sizeof(rec_hdr));
766         rec_hdr.hdr_len = g_htons(sizeof(rec_hdr));
767         rec_hdr.hdr.rectype = NETTL_HDR_PDUIN;
768         rec_hdr.hdr.sec = g_htonl(phdr->ts.tv_sec);
769         rec_hdr.hdr.usec = g_htonl(phdr->ts.tv_usec);
770         rec_hdr.hdr.caplen = g_htonl(phdr->caplen);
771         rec_hdr.hdr.length = g_htonl(phdr->len);
772
773         switch (phdr->pkt_encap) {
774
775                 case WTAP_ENCAP_RAW_IP:
776                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_NS_LS_IP);
777                         break;
778
779                 case WTAP_ENCAP_ETHERNET:
780                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_BTLAN);
781                         break;
782
783                 case WTAP_ENCAP_FDDI_BITSWAPPED:
784                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_PCI_FDDI);
785                         /* account for pad bytes */
786                         rec_hdr.hdr.caplen = g_htonl(phdr->caplen + 3);
787                         rec_hdr.hdr.length = g_htonl(phdr->len + 3);
788                         break;
789
790                 case WTAP_ENCAP_TOKEN_RING:
791                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_PCI_TR);
792                         break;
793         
794                 case WTAP_ENCAP_RAW_ICMP:
795                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_NS_LS_ICMP);
796                         break;
797         
798                 case WTAP_ENCAP_RAW_ICMPV6:
799                         rec_hdr.subsys = g_htons(NETTL_SUBSYS_NS_LS_ICMPV6);
800                         break;
801         
802                 default:
803                         /* found one we don't support */
804                         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
805                         return FALSE;
806         }
807
808         nwritten = fwrite(&rec_hdr, 1, sizeof(rec_hdr), wdh->fh);
809         if (nwritten != sizeof(rec_hdr)) {
810                 if (nwritten == 0 && ferror(wdh->fh))
811                         *err = errno;
812                 else
813                         *err = WTAP_ERR_SHORT_WRITE;
814                 return FALSE;
815         }
816         wdh->bytes_dumped += sizeof(rec_hdr);
817
818         if (phdr->pkt_encap == WTAP_ENCAP_FDDI_BITSWAPPED) {
819                 /* add those weird 3 bytes of padding */
820                 nwritten = fwrite(&dummy, 1, 3, wdh->fh);
821                 if (nwritten != 3) {
822                         if (nwritten == 0 && ferror(wdh->fh))
823                                 *err = errno;
824                         else
825                                 *err = WTAP_ERR_SHORT_WRITE;
826                         return FALSE;
827                 }
828                 wdh->bytes_dumped += 3;
829         }
830
831         /* write actual PDU data */
832
833         nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
834         if (nwritten != phdr->caplen) {
835                 if (nwritten == 0 && ferror(wdh->fh))
836                         *err = errno;
837                 else
838                         *err = WTAP_ERR_SHORT_WRITE;
839                 return FALSE;
840         }
841         wdh->bytes_dumped += phdr->caplen;
842
843         return TRUE;
844 }