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