ip-over-ib description entry was missing
[metze/wireshark/wip.git] / wiretap / packetlogger.c
1 /* packetlogger.c
2  * Routines for opening Apple's (Bluetooth) PacketLogger file format captures
3  * Copyright 2008-2009, Stephen Fisher (see AUTHORS file)
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Based on commview.c, Linux's BlueZ-Gnome Analyzer program and hexdumps of
10  * the output files from Apple's PacketLogger tool.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
25  * USA.
26  */
27
28 #include "config.h"
29
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <string.h>
33
34 #include "wtap-int.h"
35 #include "file_wrappers.h"
36 #include "packetlogger.h"
37
38 typedef struct {
39         gboolean little_endian;
40 } packetlogger_t;
41
42 typedef struct packetlogger_header {
43         guint32 len;
44         guint32 ts_secs;
45         guint32 ts_usecs;
46 } packetlogger_header_t;
47
48 static gboolean packetlogger_read(wtap *wth, int *err, gchar **err_info,
49                                   gint64 *data_offset);
50 static gboolean packetlogger_seek_read(wtap *wth, gint64 seek_off,
51                                        struct wtap_pkthdr *phdr,
52                                        Buffer *buf, int *err, gchar **err_info);
53 static gboolean packetlogger_read_header(packetlogger_header_t *pl_hdr,
54                                          FILE_T fh, gboolean little_endian,
55                                          int *err, gchar **err_info);
56 static gboolean packetlogger_read_packet(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
57                                          Buffer *buf, int *err,
58                                          gchar **err_info);
59
60 wtap_open_return_val packetlogger_open(wtap *wth, int *err, gchar **err_info)
61 {
62         gboolean little_endian = FALSE;
63         packetlogger_header_t pl_hdr;
64         guint8 type;
65         packetlogger_t *packetlogger;
66
67         if(!packetlogger_read_header(&pl_hdr, wth->fh, little_endian,
68             err, err_info)) {
69                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
70                         return WTAP_OPEN_ERROR;
71                 return WTAP_OPEN_NOT_MINE;
72         }
73
74         if (!wtap_read_bytes(wth->fh, &type, 1, err, err_info)) {
75                 if (*err != WTAP_ERR_SHORT_READ)
76                         return WTAP_OPEN_ERROR;
77                 return WTAP_OPEN_NOT_MINE;
78         }
79
80         /*
81          * If the upper 16 bits of the length are non-zero and the lower
82          * 16 bits are zero, assume the file is little-endian.
83          */
84         if ((pl_hdr.len & 0x0000FFFF) == 0 &&
85             (pl_hdr.len & 0xFFFF0000) != 0) {
86                 /*
87                  * Byte-swap the upper 16 bits (the lower 16 bits are
88                  * zero, so we don't have to look at them).
89                  */
90                 pl_hdr.len = ((pl_hdr.len >> 24) & 0xFF) |
91                              (((pl_hdr.len >> 16) & 0xFF) << 8);
92                 little_endian = TRUE;
93         }
94
95         /* Verify this file belongs to us */
96         if (!((8 <= pl_hdr.len) && (pl_hdr.len < 65536) &&
97               (type < 0x04 || type == 0xFB || type == 0xFC || type == 0xFE || type == 0xFF)))
98                 return WTAP_OPEN_NOT_MINE;
99
100         /* No file header. Reset the fh to 0 so we can read the first packet */
101         if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
102                 return WTAP_OPEN_ERROR;
103
104         /* This is a PacketLogger file */
105         packetlogger = (packetlogger_t *)g_malloc(sizeof(packetlogger_t));
106         packetlogger->little_endian = little_endian;
107         wth->priv = (void *)packetlogger;
108
109         /* Set up the pointers to the handlers for this file type */
110         wth->subtype_read = packetlogger_read;
111         wth->subtype_seek_read = packetlogger_seek_read;
112
113         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PACKETLOGGER;
114         wth->file_encap = WTAP_ENCAP_PACKETLOGGER;
115         wth->file_tsprec = WTAP_TSPREC_USEC;
116
117         return WTAP_OPEN_MINE; /* Our kind of file */
118 }
119
120 static gboolean
121 packetlogger_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
122 {
123         *data_offset = file_tell(wth->fh);
124
125         return packetlogger_read_packet(wth, wth->fh, &wth->phdr,
126             wth->frame_buffer, err, err_info);
127 }
128
129 static gboolean
130 packetlogger_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
131                        Buffer *buf, int *err, gchar **err_info)
132 {
133         if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
134                 return FALSE;
135
136         if(!packetlogger_read_packet(wth, wth->random_fh, phdr, buf, err, err_info)) {
137                 if(*err == 0)
138                         *err = WTAP_ERR_SHORT_READ;
139
140                 return FALSE;
141         }
142         return TRUE;
143 }
144
145 static gboolean
146 packetlogger_read_header(packetlogger_header_t *pl_hdr, FILE_T fh,
147                          gboolean little_endian, int *err, gchar **err_info)
148 {
149         if (!wtap_read_bytes_or_eof(fh, &pl_hdr->len, 4, err, err_info))
150                 return FALSE;
151         if (!wtap_read_bytes(fh, &pl_hdr->ts_secs, 4, err, err_info))
152                 return FALSE;
153         if (!wtap_read_bytes(fh, &pl_hdr->ts_usecs, 4, err, err_info))
154                 return FALSE;
155
156         /* Convert multi-byte values to host endian */
157         if (little_endian) {
158                 pl_hdr->len = GUINT32_FROM_LE(pl_hdr->len);
159                 pl_hdr->ts_secs = GUINT32_FROM_LE(pl_hdr->ts_secs);
160                 pl_hdr->ts_usecs = GUINT32_FROM_LE(pl_hdr->ts_usecs);
161         } else {
162                 pl_hdr->len = GUINT32_FROM_BE(pl_hdr->len);
163                 pl_hdr->ts_secs = GUINT32_FROM_BE(pl_hdr->ts_secs);
164                 pl_hdr->ts_usecs = GUINT32_FROM_BE(pl_hdr->ts_usecs);
165         }
166
167         return TRUE;
168 }
169
170 static gboolean
171 packetlogger_read_packet(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
172                          int *err, gchar **err_info)
173 {
174         packetlogger_t *packetlogger = (packetlogger_t *)wth->priv;
175         packetlogger_header_t pl_hdr;
176
177         if(!packetlogger_read_header(&pl_hdr, fh, packetlogger->little_endian,
178             err, err_info))
179                 return FALSE;
180
181         if (pl_hdr.len < 8) {
182                 *err = WTAP_ERR_BAD_FILE;
183                 *err_info = g_strdup_printf("packetlogger: record length %u is too small", pl_hdr.len);
184                 return FALSE;
185         }
186         if (pl_hdr.len - 8 > WTAP_MAX_PACKET_SIZE) {
187                 /*
188                  * Probably a corrupt capture file; don't blow up trying
189                  * to allocate space for an immensely-large packet.
190                  */
191                 *err = WTAP_ERR_BAD_FILE;
192                 *err_info = g_strdup_printf("packetlogger: File has %u-byte packet, bigger than maximum of %u",
193                     pl_hdr.len - 8, WTAP_MAX_PACKET_SIZE);
194                 return FALSE;
195         }
196
197         phdr->rec_type = REC_TYPE_PACKET;
198         phdr->presence_flags = WTAP_HAS_TS;
199
200         phdr->len = pl_hdr.len - 8;
201         phdr->caplen = pl_hdr.len - 8;
202
203         phdr->ts.secs = (time_t)pl_hdr.ts_secs;
204         phdr->ts.nsecs = (int)(pl_hdr.ts_usecs * 1000);
205
206         return wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info);
207 }
208
209 /*
210  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
211  *
212  * Local variables:
213  * c-basic-offset: 8
214  * tab-width: 8
215  * indent-tabs-mode: t
216  * End:
217  *
218  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
219  * :indentSize=8:tabSize=8:noTabs=false:
220  */