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