3 * File format support for Micropross mplog files
4 * Copyright (c) 2016 by Martin Kaiser <martin@kaiser.cx>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 The mplog file format logs the communication between a contactless
28 smartcard and a card reader. Such files contain information about the
29 physical layer as well as the bytes exchanged between devices.
30 Some commercial logging and testing tools by the French company Micropross
33 The information used for implementing this wiretap module were
34 obtained from reverse-engineering. There is no publicly available
35 documentation of the mplog file format.
37 Mplog files start with the string "MPCSII". This string is part of
38 the header which is in total 0x80 bytes long.
40 Following the header, the file is a sequence of 8 byte-blocks.
45 The timestamp is a counter in little-endian format. The counter is in
53 #include <file_wrappers.h>
58 #define TYPE_PCD_PICC_A 0x70
59 #define TYPE_PICC_PCD_A 0x71
60 #define TYPE_PCD_PICC_B 0x72
61 #define TYPE_PICC_PCD_B 0x73
62 #define TYPE_UNKNOWN 0xFF
64 #define KNOWN_TYPE(x) \
66 ((x) == TYPE_PCD_PICC_A) || \
67 ((x) == TYPE_PICC_PCD_A) || \
68 ((x) == TYPE_PCD_PICC_B) || \
69 ((x) == TYPE_PICC_PCD_B) \
72 #define MPLOG_BLOCK_SIZE 8
74 /* ISO14443 pseudo-header, see http://www.kaiser.cx/pcap-iso14443.html */
75 #define ISO14443_PSEUDO_HDR_VER 0
76 #define ISO14443_PSEUDO_HDR_LEN 4
77 /* the two transfer events are the types that include a trailing CRC
78 the CRC is always present in mplog files */
79 #define ISO14443_PSEUDO_HDR_PICC_TO_PCD 0xFF
80 #define ISO14443_PSEUDO_HDR_PCD_TO_PICC 0xFE
83 #define ISO14443_MAX_PKT_LEN 256
85 #define PKT_BUF_LEN (ISO14443_PSEUDO_HDR_LEN + ISO14443_MAX_PKT_LEN)
88 /* read the next packet, starting at the current position of fh
89 as we know very little about the file format, our approach is rather simple:
90 - we read block-by-block until a known block-type is found
91 - this block's type is the type of the next packet
92 - this block's timestamp will become the packet's timestamp
93 - the data byte will be our packet's first byte
94 - we carry on reading blocks and add the data bytes
95 of all blocks of "our" type
96 - if a different well-known block type is found, this is the end of
97 our packet, we go back one block so that this block can be picked
98 up as the start of the next packet
99 - if two blocks of our packet's block type are more than 200us apart,
100 we treat this as a packet boundary as described above
102 static gboolean mplog_read_packet(FILE_T fh, struct wtap_pkthdr *phdr,
103 Buffer *buf, int *err, gchar **err_info)
106 /* --- the last block of a known type --- */
107 guint64 last_ctr = 0;
108 /* --- the current block --- */
109 guint8 block[MPLOG_BLOCK_SIZE]; /* the entire block */
110 guint8 data, type; /* its data and block type bytes */
111 guint64 ctr; /* its timestamp counter */
112 /* --- the packet we're assembling --- */
114 guint8 pkt_type = TYPE_UNKNOWN;
115 /* the timestamp of the packet's first block,
116 this will become the packet's timestamp */
120 ws_buffer_assure_space(buf, PKT_BUF_LEN);
121 p = ws_buffer_start_ptr(buf);
124 /* leave space for the iso14443 pseudo header
125 we can't create it until we've seen the entire packet */
126 p += ISO14443_PSEUDO_HDR_LEN;
129 if (!wtap_read_bytes_or_eof(fh, block, sizeof(block), err, err_info))
133 ctr = pletoh48(&block[2]);
135 if (pkt_type == TYPE_UNKNOWN) {
136 if (KNOWN_TYPE(type)) {
142 if (type == pkt_type) {
144 /* if the distance to the last byte of the
145 same type is larger than 200us, this is very likely the
146 first byte of a new packet -> go back one block and exit
147 ctr and last_ctr are in units of 10ns
148 at 106kbit/s, it takes approx 75us to send one byte */
149 if (ctr - last_ctr > 200*100) {
150 file_seek(fh, -MPLOG_BLOCK_SIZE, SEEK_CUR, err);
159 else if (KNOWN_TYPE(type)) {
160 file_seek(fh, -MPLOG_BLOCK_SIZE, SEEK_CUR, err);
163 } while (pkt_bytes < ISO14443_MAX_PKT_LEN);
165 if (pkt_type == TYPE_UNKNOWN)
168 start_p[0] = ISO14443_PSEUDO_HDR_VER;
170 if (pkt_type==TYPE_PCD_PICC_A || pkt_type==TYPE_PCD_PICC_B)
171 start_p[1] = ISO14443_PSEUDO_HDR_PCD_TO_PICC;
173 start_p[1] = ISO14443_PSEUDO_HDR_PICC_TO_PCD;
175 start_p[2] = pkt_bytes >> 8;
176 start_p[3] = pkt_bytes & 0xFF;
178 phdr->rec_type = REC_TYPE_PACKET;
179 phdr->pkt_encap = WTAP_ENCAP_ISO14443;
180 phdr->presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN;
181 phdr->ts.secs = (time_t)((pkt_ctr*10)/(1000*1000*1000));
182 phdr->ts.nsecs = (int)((pkt_ctr*10)%(1000*1000*1000));
183 phdr->caplen = ISO14443_PSEUDO_HDR_LEN + pkt_bytes;
184 phdr->len = phdr->caplen;
191 mplog_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
193 *data_offset = file_tell(wth->fh);
195 return mplog_read_packet(
196 wth->fh, &wth->phdr, wth->frame_buffer, err, err_info);
201 mplog_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *pkthdr,
202 Buffer *buf, int *err, gchar **err_info)
204 if (-1 == file_seek(wth->random_fh, seek_off, SEEK_SET, err))
207 return mplog_read_packet(wth->random_fh, pkthdr, buf, err, err_info);
211 wtap_open_return_val mplog_open(wtap *wth, int *err, gchar **err_info _U_)
216 /* rewind the fh so we re-read from the beginning */
217 if (-1 == file_seek(wth->fh, 0, SEEK_SET, err))
218 return WTAP_OPEN_ERROR;
220 ok = wtap_read_bytes_or_eof(wth->fh, str, 6, err, err_info);
222 return WTAP_OPEN_NOT_MINE;
223 if (memcmp(str, "MPCSII", 6) != 0)
224 return WTAP_OPEN_NOT_MINE;
226 wth->file_encap = WTAP_ENCAP_ISO14443;
227 wth->snapshot_length = 0;
228 wth->file_tsprec = WTAP_TSPREC_NSEC;
232 wth->subtype_read = mplog_read;
233 wth->subtype_seek_read = mplog_seek_read;
234 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_MPLOG;
236 /* skip the file header */
237 if (-1 == file_seek(wth->fh, 0x80, SEEK_SET, err))
238 return WTAP_OPEN_ERROR;
241 return WTAP_OPEN_MINE;
246 * Editor modelines - http://www.wireshark.org/tools/modelines.html
251 * indent-tabs-mode: nil
254 * vi: set shiftwidth=4 tabstop=8 expandtab:
255 * :indentSize=4:tabSize=8:noTabs=true: