3 * Copyright 2014, Michal Labedzki for Tieto Corporation
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "file_wrappers.h"
29 /* Returns '?' for invalid priorities */
30 static gchar get_priority(const guint8 priority) {
31 static gchar priorities[] = "??VDIWEFS";
33 if (priority >= (guint8) sizeof(priorities))
36 return priorities[priority];
42 * -2 if we get an EOF at the beginning;
44 * 0 if the record doesn't appear to be valid;
45 * 1-{max gint} as a version number if we got a valid record.
47 static gint detect_version(FILE_T fh, int *err, gchar **err_info)
49 guint16 payload_length;
54 struct logger_entry *log_entry;
55 struct logger_entry_v2 *log_entry_v2;
63 /* 16-bit payload length */
64 if (!wtap_read_bytes_or_eof(fh, &tmp, 2, err, err_info)) {
67 * Got an EOF at the beginning.
71 if (*err != WTAP_ERR_SHORT_READ)
75 payload_length = pletoh16(&tmp);
77 /* must contain at least priority and two nulls as separator */
78 if (payload_length < 3)
80 /* payload length may not exceed the maximum payload size */
81 if (payload_length > LOGGER_ENTRY_MAX_PAYLOAD)
84 /* 16-bit header length (or padding, equal to 0x0000) */
85 if (!wtap_read_bytes(fh, &tmp, 2, err, err_info)) {
86 if (*err != WTAP_ERR_SHORT_READ)
90 hdr_size = pletoh16(&tmp);
93 /* ensure buffer is large enough for all versions */
94 buffer = (guint8 *) g_malloc(sizeof(*log_entry_v2) + payload_length);
95 log_entry_v2 = (struct logger_entry_v2 *)(void *) buffer;
96 log_entry = (struct logger_entry *)(void *) buffer;
98 /* cannot rely on __pad being 0 for v1, use heuristics to find out what
99 * version is in use. First assume the smallest msg. */
100 for (version = 1; version <= 2; ++version) {
102 msg_payload = (guint8 *) (log_entry + 1);
103 entry_len = sizeof(*log_entry) + payload_length;
104 } else if (version == 2) {
105 /* v2 is 4 bytes longer */
106 msg_payload = (guint8 *) (log_entry_v2 + 1);
107 entry_len = sizeof(*log_entry_v2) + payload_length;
108 if (hdr_size != sizeof(*log_entry_v2))
114 if (!wtap_read_bytes(fh, buffer + read_sofar, entry_len - read_sofar, err, err_info)) {
116 if (*err != WTAP_ERR_SHORT_READ)
120 read_sofar += entry_len - read_sofar;
122 /* A v2 msg has a 32-bit userid instead of v1 priority */
123 if (get_priority(msg_payload[0]) == '?')
126 /* Is there a terminating '\0' for the tag? */
127 msg_part = (guint8 *) memchr(msg_payload, '\0', payload_length - 1);
128 if (msg_part == NULL)
131 /* if msg is '\0'-terminated, is it equal to the payload len? */
133 msg_len = (guint16)(payload_length - (msg_part - msg_payload));
134 msg_end = (guint8 *) memchr(msg_part, '\0', msg_len);
135 /* is the end of the buffer (-1) equal to the end of msg? */
136 if (msg_end && (msg_payload + payload_length - 1 != msg_end))
143 /* No version number is valid */
148 gint logcat_exported_pdu_length(const guint8 *pd) {
150 const guint16 *tag_length;
153 tag = (const guint16 *)(const void *) pd;
155 while(GINT16_FROM_BE(*tag)) {
156 tag_length = (const guint16 *)(const void *) (pd + 2);
157 length += 2 + 2 + GINT16_FROM_BE(*tag_length);
159 pd += 2 + 2 + GINT16_FROM_BE(*tag_length);
160 tag = (const guint16 *)(const void *) pd;
168 static gboolean logcat_read_packet(struct logcat_phdr *logcat, FILE_T fh,
169 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
172 guint16 payload_length;
175 struct logger_entry *log_entry;
177 if (!wtap_read_bytes_or_eof(fh, &tmp, 2, err, err_info)) {
180 payload_length = pletoh16(tmp);
182 if (logcat->version == 1) {
183 packet_size = (gint)sizeof(struct logger_entry) + payload_length;
184 } else if (logcat->version == 2) {
185 packet_size = (gint)sizeof(struct logger_entry_v2) + payload_length;
190 * The maximum value of payload_length is 65535, which, even after
191 * the size of the logger entry structure is added to it, is less
192 * than WTAP_MAX_PACKET_SIZE will ever be, so we don't need to check
196 ws_buffer_assure_space(buf, packet_size);
197 pd = ws_buffer_start_ptr(buf);
198 log_entry = (struct logger_entry *)(void *) pd;
200 /* Copy the first two bytes of the packet. */
203 /* Read the rest of the packet. */
204 if (!wtap_read_bytes(fh, pd + 2, packet_size - 2, err, err_info)) {
208 phdr->rec_type = REC_TYPE_PACKET;
209 phdr->presence_flags = WTAP_HAS_TS;
210 phdr->ts.secs = (time_t) GINT32_FROM_LE(log_entry->sec);
211 phdr->ts.nsecs = GINT32_FROM_LE(log_entry->nsec);
212 phdr->caplen = packet_size;
213 phdr->len = packet_size;
215 phdr->pseudo_header.logcat.version = logcat->version;
220 static gboolean logcat_read(wtap *wth, int *err, gchar **err_info,
223 *data_offset = file_tell(wth->fh);
225 return logcat_read_packet((struct logcat_phdr *) wth->priv, wth->fh,
226 &wth->phdr, wth->frame_buffer, err, err_info);
229 static gboolean logcat_seek_read(wtap *wth, gint64 seek_off,
230 struct wtap_pkthdr *phdr, Buffer *buf,
231 int *err, gchar **err_info)
233 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
236 if (!logcat_read_packet((struct logcat_phdr *) wth->priv, wth->random_fh,
237 phdr, buf, err, err_info)) {
239 *err = WTAP_ERR_SHORT_READ;
245 wtap_open_return_val logcat_open(wtap *wth, int *err, gchar **err_info)
249 struct logcat_phdr *logcat;
251 /* check first 3 packets (or 2 or 1 if EOF) versions to check file format is correct */
252 version = detect_version(wth->fh, err, err_info); /* first packet */
254 return WTAP_OPEN_ERROR; /* I/O error */
256 return WTAP_OPEN_NOT_MINE; /* not a logcat file */
258 return WTAP_OPEN_NOT_MINE; /* empty file, so not any type of file */
260 tmp_version = detect_version(wth->fh, err, err_info); /* second packet */
261 if (tmp_version == -1)
262 return WTAP_OPEN_ERROR; /* I/O error */
263 if (tmp_version == 0)
264 return WTAP_OPEN_NOT_MINE; /* not a logcat file */
265 if (tmp_version != -2) {
266 /* we've read two packets; do they have the same version? */
267 if (tmp_version != version) {
268 /* no, so this is presumably not a logcat file */
269 return WTAP_OPEN_NOT_MINE;
272 tmp_version = detect_version(wth->fh, err, err_info); /* third packet */
274 return WTAP_OPEN_ERROR; /* I/O error */
275 if (tmp_version == 0)
276 return WTAP_OPEN_NOT_MINE; /* not a logcat file */
277 if (tmp_version != -2) {
279 * we've read three packets and the first two have the same
280 * version; does the third have the same version?
282 if (tmp_version != version) {
283 /* no, so this is presumably not a logcat file */
284 return WTAP_OPEN_NOT_MINE;
289 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
290 return WTAP_OPEN_ERROR;
292 logcat = (struct logcat_phdr *) g_malloc(sizeof(struct logcat_phdr));
293 logcat->version = version;
297 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LOGCAT;
298 wth->file_encap = WTAP_ENCAP_LOGCAT;
299 wth->snapshot_length = 0;
301 wth->subtype_read = logcat_read;
302 wth->subtype_seek_read = logcat_seek_read;
303 wth->file_tsprec = WTAP_TSPREC_USEC;
305 return WTAP_OPEN_MINE;
308 int logcat_dump_can_write_encap(int encap)
310 if (encap == WTAP_ENCAP_PER_PACKET)
311 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
313 if (encap != WTAP_ENCAP_LOGCAT && encap != WTAP_ENCAP_WIRESHARK_UPPER_PDU)
314 return WTAP_ERR_UNWRITABLE_ENCAP;
319 static gboolean logcat_binary_dump(wtap_dumper *wdh,
320 const struct wtap_pkthdr *phdr,
321 const guint8 *pd, int *err, gchar **err_info _U_)
325 /* We can only write packet records. */
326 if (phdr->rec_type != REC_TYPE_PACKET) {
327 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
331 caplen = phdr->caplen;
333 /* Skip EXPORTED_PDU*/
334 if (wdh->encap == WTAP_ENCAP_WIRESHARK_UPPER_PDU) {
337 skipped_length = logcat_exported_pdu_length(pd);
338 pd += skipped_length;
339 caplen -= skipped_length;
342 if (!wtap_dump_file_write(wdh, pd, caplen, err))
345 wdh->bytes_dumped += caplen;
350 gboolean logcat_binary_dump_open(wtap_dumper *wdh, int *err)
352 wdh->subtype_write = logcat_binary_dump;
354 switch (wdh->encap) {
355 case WTAP_ENCAP_LOGCAT:
356 case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
357 wdh->tsprecision = WTAP_TSPREC_USEC;
361 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
369 * Editor modelines - http://www.wireshark.org/tools/modelines.html
374 * indent-tabs-mode: nil
377 * vi: set shiftwidth=4 tabstop=8 expandtab:
378 * :indentSize=4:tabSize=8:noTabs=true: