Call the dumper routine to finish write a file the "finish" routine.
[metze/wireshark/wip.git] / wiretap / eyesdn.c
1 /* eyesdn.c
2  *
3  * Wiretap Library
4  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22 #include "wtap-int.h"
23 #include "eyesdn.h"
24 #include "file_wrappers.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29
30 /* This module reads the output of the EyeSDN USB S0/E1 ISDN probes
31  * They store HDLC frames of D and B channels in a binary format
32  * The fileformat is
33  *
34  * 1-6 Byte: EyeSDN - Magic
35  * 7-n Byte: Frames
36  *
37  * Each Frame starts with the 0xff Flag byte
38  * - Bytes 0-2: timestamp (usec in network byte order)
39  * - Bytes 3-7: timestamp (40bits sec since 1970 in network byte order)
40  * - Byte 8: channel (0 for D channel, 1-30 for B1-B30)
41  * - Byte 9: Sender Bit 0(0 NT, 1 TE), Protocol in Bits 7:1, see enum
42  * - Byte 10-11: frame size in bytes
43  * - Byte 12-n: Frame Payload
44  *
45  * All multibyte values are represented in network byte order
46  * The frame is terminated with a flag character (0xff)
47  * bytes 0xff within a frame are escaped using the 0xfe escape character
48  * the byte following the escape character is decremented by two:
49  * so 0xfe 0xfd is actually a 0xff
50  * Characters that need to be escaped are 0xff and 0xfe
51  */
52
53
54 static gboolean esc_read(FILE_T fh, guint8 *buf, int len, int *err, gchar **err_info)
55 {
56         int i;
57         int value;
58
59         for(i=0; i<len; i++) {
60                 value=file_getc(fh);
61                 if(value==-1) {
62                         /* EOF or error */
63                         *err=file_error(fh, err_info);
64                         if(*err==0)
65                                 *err=WTAP_ERR_SHORT_READ;
66                         return FALSE;
67                 }
68                 if(value==0xff) {
69                         /* error !!, read into next frame */
70                         *err=WTAP_ERR_BAD_FILE;
71                         *err_info=g_strdup("eyesdn: No flag character seen in frame");
72                         return FALSE;
73                 }
74                 if(value==0xfe) {
75                         /* we need to escape */
76                         value=file_getc(fh);
77                         if(value==-1) {
78                                 /* EOF or error */
79                                 *err=file_error(fh, err_info);
80                                 if(*err==0)
81                                         *err=WTAP_ERR_SHORT_READ;
82                                 return FALSE;
83                         }
84                         value+=2;
85                 }
86                 buf[i]=value;
87         }
88
89         return TRUE;
90 }
91
92 /* Magic text to check for eyesdn-ness of file */
93 static const unsigned char eyesdn_hdr_magic[]  =
94 { 'E', 'y', 'e', 'S', 'D', 'N'};
95 #define EYESDN_HDR_MAGIC_SIZE  (sizeof(eyesdn_hdr_magic)  / sizeof(eyesdn_hdr_magic[0]))
96
97 /* Size of a record header */
98 #define EYESDN_HDR_LENGTH               12
99
100 /*
101  * XXX - is this the biggest packet we can get?
102  */
103 #define EYESDN_MAX_PACKET_LEN   16384
104
105 static gboolean eyesdn_read(wtap *wth, int *err, gchar **err_info,
106         gint64 *data_offset);
107 static gboolean eyesdn_seek_read(wtap *wth, gint64 seek_off,
108         struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
109 static int read_eyesdn_rec(FILE_T fh, struct wtap_pkthdr *phdr, Buffer* buf,
110         int *err, gchar **err_info);
111
112 /* Seeks to the beginning of the next packet, and returns the
113    byte offset.  Returns -1 on failure, and sets "*err" to the error
114    and "*err_info" to null or an additional error string. */
115 static gint64 eyesdn_seek_next_packet(wtap *wth, int *err, gchar **err_info)
116 {
117         int byte;
118         gint64 cur_off;
119
120         while ((byte = file_getc(wth->fh)) != EOF) {
121                 if (byte == 0xff) {
122                         cur_off = file_tell(wth->fh);
123                         if (cur_off == -1) {
124                                 /* Error. */
125                                 *err = file_error(wth->fh, err_info);
126                                 return -1;
127                         }
128                         return cur_off;
129                 }
130         }
131         /* EOF or error. */
132         *err = file_error(wth->fh, err_info);
133         return -1;
134 }
135
136 wtap_open_return_val eyesdn_open(wtap *wth, int *err, gchar **err_info)
137 {
138         char    magic[EYESDN_HDR_MAGIC_SIZE];
139
140         /* Look for eyesdn header */
141         if (!wtap_read_bytes(wth->fh, &magic, sizeof magic, err, err_info)) {
142                 if (*err != WTAP_ERR_SHORT_READ)
143                         return WTAP_OPEN_ERROR;
144                 return WTAP_OPEN_NOT_MINE;
145         }
146         if (memcmp(magic, eyesdn_hdr_magic, EYESDN_HDR_MAGIC_SIZE) != 0)
147                 return WTAP_OPEN_NOT_MINE;
148
149         wth->file_encap = WTAP_ENCAP_PER_PACKET;
150         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_EYESDN;
151         wth->snapshot_length = 0; /* not known */
152         wth->subtype_read = eyesdn_read;
153         wth->subtype_seek_read = eyesdn_seek_read;
154         wth->file_tsprec = WTAP_TSPREC_USEC;
155
156         return WTAP_OPEN_MINE;
157 }
158
159 /* Find the next packet and parse it; called from wtap_read(). */
160 static gboolean eyesdn_read(wtap *wth, int *err, gchar **err_info,
161     gint64 *data_offset)
162 {
163         gint64  offset;
164
165         /* Find the next record */
166         offset = eyesdn_seek_next_packet(wth, err, err_info);
167         if (offset < 1)
168                 return FALSE;
169         *data_offset = offset;
170
171         /* Parse the record */
172         return read_eyesdn_rec(wth->fh, &wth->phdr, wth->frame_buffer,
173             err, err_info);
174 }
175
176 /* Used to read packets in random-access fashion */
177 static gboolean
178 eyesdn_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
179         Buffer *buf, int *err, gchar **err_info)
180 {
181         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
182                 return FALSE;
183
184         return read_eyesdn_rec(wth->random_fh, phdr, buf, err, err_info);
185 }
186
187 /* Parses a record. */
188 static gboolean
189 read_eyesdn_rec(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf, int *err,
190     gchar **err_info)
191 {
192         union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
193         guint8          hdr[EYESDN_HDR_LENGTH];
194         time_t          secs;
195         int             usecs;
196         int             pkt_len;
197         guint8          channel, direction;
198         guint8          *pd;
199
200         /* Our file pointer should be at the summary information header
201          * for a packet. Read in that header and extract the useful
202          * information.
203          */
204         if (!esc_read(fh, hdr, EYESDN_HDR_LENGTH, err, err_info))
205                 return FALSE;
206
207         /* extract information from header */
208         usecs = pntoh24(&hdr[0]);
209 #ifdef TV64BITS
210         secs = hdr[3];
211 #else
212         secs = 0;
213 #endif
214         secs = (secs << 8) | hdr[4];
215         secs = (secs << 8) | hdr[5];
216         secs = (secs << 8) | hdr[6];
217         secs = (secs << 8) | hdr[7];
218
219         channel = hdr[8];
220         direction = hdr[9];
221         pkt_len = pntoh16(&hdr[10]);
222
223         switch(direction >> 1) {
224
225         default:
226         case EYESDN_ENCAP_ISDN: /* ISDN */
227                 pseudo_header->isdn.uton = direction & 1;
228                 pseudo_header->isdn.channel = channel;
229                 if(channel) { /* bearer channels */
230                         phdr->pkt_encap = WTAP_ENCAP_ISDN; /* recognises PPP */
231                         pseudo_header->isdn.uton=!pseudo_header->isdn.uton; /* bug */
232                 } else { /* D channel */
233                         phdr->pkt_encap = WTAP_ENCAP_ISDN;
234                 }
235                 break;
236
237         case EYESDN_ENCAP_MSG: /* Layer 1 message */
238                 phdr->pkt_encap = WTAP_ENCAP_LAYER1_EVENT;
239                 pseudo_header->l1event.uton = (direction & 1);
240                 break;
241
242         case EYESDN_ENCAP_LAPB: /* X.25 via LAPB */
243                 phdr->pkt_encap = WTAP_ENCAP_LAPB;
244                 pseudo_header->x25.flags = (direction & 1) ? 0 : 0x80;
245                 break;
246
247         case EYESDN_ENCAP_ATM: { /* ATM cells */
248 #define CELL_LEN 53
249                 unsigned char cell[CELL_LEN];
250                 gint64 cur_off;
251
252                 if(pkt_len != CELL_LEN) {
253                         *err = WTAP_ERR_BAD_FILE;
254                         *err_info = g_strdup_printf(
255                             "eyesdn: ATM cell has a length != 53 (%u)",
256                             pkt_len);
257                         return FALSE;
258                 }
259
260                 cur_off = file_tell(fh);
261                 if (!esc_read(fh, cell, CELL_LEN, err, err_info))
262                         return FALSE;
263                 if (file_seek(fh, cur_off, SEEK_SET, err) == -1)
264                         return FALSE;
265                 phdr->pkt_encap = WTAP_ENCAP_ATM_PDUS_UNTRUNCATED;
266                 pseudo_header->atm.flags=ATM_RAW_CELL;
267                 pseudo_header->atm.aal=AAL_UNKNOWN;
268                 pseudo_header->atm.type=TRAF_UMTS_FP;
269                 pseudo_header->atm.subtype=TRAF_ST_UNKNOWN;
270                 pseudo_header->atm.vpi=((cell[0]&0xf)<<4) + (cell[0]&0xf);
271                 pseudo_header->atm.vci=((cell[0]&0xf)<<4) + cell[0]; /* from cell */
272                 pseudo_header->atm.channel=direction & 1;
273                 }
274                 break;
275
276         case EYESDN_ENCAP_MTP2: /* SS7 frames */
277                 pseudo_header->mtp2.sent = direction & 1;
278                 pseudo_header->mtp2.annex_a_used = MTP2_ANNEX_A_USED_UNKNOWN;
279                 pseudo_header->mtp2.link_number = channel;
280                 phdr->pkt_encap = WTAP_ENCAP_MTP2_WITH_PHDR;
281                 break;
282
283         case EYESDN_ENCAP_DPNSS: /* DPNSS */
284                 pseudo_header->isdn.uton = direction & 1;
285                 pseudo_header->isdn.channel = channel;
286                 phdr->pkt_encap = WTAP_ENCAP_DPNSS;
287                 break;
288
289         case EYESDN_ENCAP_DASS2: /* DASS2 frames */
290                 pseudo_header->isdn.uton = direction & 1;
291                 pseudo_header->isdn.channel = channel;
292                 phdr->pkt_encap = WTAP_ENCAP_DPNSS;
293                 break;
294
295         case EYESDN_ENCAP_BACNET: /* BACNET async over HDLC frames */
296                 pseudo_header->isdn.uton = direction & 1;
297                 pseudo_header->isdn.channel = channel;
298                 phdr->pkt_encap = WTAP_ENCAP_BACNET_MS_TP_WITH_PHDR;
299                 break;
300
301         case EYESDN_ENCAP_V5_EF: /* V5EF */
302                 pseudo_header->isdn.uton = direction & 1;
303                 pseudo_header->isdn.channel = channel;
304                 phdr->pkt_encap = WTAP_ENCAP_V5_EF;
305                 break;
306         }
307
308         if(pkt_len > EYESDN_MAX_PACKET_LEN) {
309                 *err = WTAP_ERR_BAD_FILE;
310                 *err_info = g_strdup_printf("eyesdn: File has %u-byte packet, bigger than maximum of %u",
311                     pkt_len, EYESDN_MAX_PACKET_LEN);
312                 return FALSE;
313         }
314
315         phdr->rec_type = REC_TYPE_PACKET;
316         phdr->presence_flags = WTAP_HAS_TS;
317         phdr->ts.secs = secs;
318         phdr->ts.nsecs = usecs * 1000;
319         phdr->caplen = pkt_len;
320         phdr->len = pkt_len;
321
322         /* Make sure we have enough room for the packet */
323         ws_buffer_assure_space(buf, EYESDN_MAX_PACKET_LEN);
324
325         pd = ws_buffer_start_ptr(buf);
326         if (!esc_read(fh, pd, pkt_len, err, err_info))
327                 return FALSE;
328         return TRUE;
329 }
330
331
332 static gboolean
333 esc_write(wtap_dumper *wdh, const guint8 *buf, int len, int *err)
334 {
335         int i;
336         guint8 byte;
337         static const guint8 esc = 0xfe;
338
339         for(i=0; i<len; i++) {
340                 byte=buf[i];
341                 if(byte == 0xff || byte == 0xfe) {
342                         /*
343                          * Escape the frame delimiter and escape byte.
344                          */
345                         if (!wtap_dump_file_write(wdh, &esc, sizeof esc, err))
346                                 return FALSE;
347                         byte-=2;
348                 }
349                 if (!wtap_dump_file_write(wdh, &byte, sizeof byte, err))
350                         return FALSE;
351         }
352         return TRUE;
353 }
354
355 static gboolean eyesdn_dump(wtap_dumper *wdh,
356                             const struct wtap_pkthdr *phdr,
357                             const guint8 *pd, int *err, gchar **err_info);
358
359 gboolean eyesdn_dump_open(wtap_dumper *wdh, int *err)
360 {
361         wdh->subtype_write=eyesdn_dump;
362
363         if (!wtap_dump_file_write(wdh, eyesdn_hdr_magic,
364             EYESDN_HDR_MAGIC_SIZE, err))
365                 return FALSE;
366         wdh->bytes_dumped += EYESDN_HDR_MAGIC_SIZE;
367         *err=0;
368         return TRUE;
369 }
370
371 int eyesdn_dump_can_write_encap(int encap)
372 {
373         switch (encap) {
374         case WTAP_ENCAP_ISDN:
375         case WTAP_ENCAP_LAYER1_EVENT:
376         case WTAP_ENCAP_DPNSS:
377         case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
378         case WTAP_ENCAP_LAPB:
379         case WTAP_ENCAP_MTP2_WITH_PHDR:
380         case WTAP_ENCAP_BACNET_MS_TP_WITH_PHDR:
381         case WTAP_ENCAP_PER_PACKET:
382                 return 0;
383
384         default:
385                 return WTAP_ERR_UNWRITABLE_ENCAP;
386         }
387 }
388
389 /* Write a record for a packet to a dump file.
390  *    Returns TRUE on success, FALSE on failure. */
391 static gboolean eyesdn_dump(wtap_dumper *wdh,
392                             const struct wtap_pkthdr *phdr,
393                             const guint8 *pd, int *err, gchar **err_info _U_)
394 {
395         static const guint8 start_flag = 0xff;
396         const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
397         guint8 buf[EYESDN_HDR_LENGTH];
398         int usecs;
399         time_t secs;
400         int channel;
401         int origin;
402         int protocol;
403         int size;
404
405         /* We can only write packet records. */
406         if (phdr->rec_type != REC_TYPE_PACKET) {
407                 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
408                 return FALSE;
409         }
410
411         /* Don't write out anything bigger than we can read.
412          * (The length field in packet headers is 16 bits, which
413          * imposes a hard limit.) */
414         if (phdr->caplen > 65535) {
415                 *err = WTAP_ERR_PACKET_TOO_LARGE;
416                 return FALSE;
417         }
418
419         usecs=phdr->ts.nsecs/1000;
420         secs=phdr->ts.secs;
421         size=phdr->caplen;
422         origin = pseudo_header->isdn.uton;
423         channel = pseudo_header->isdn.channel;
424
425         switch(phdr->pkt_encap) {
426
427         case WTAP_ENCAP_ISDN:
428                 protocol=EYESDN_ENCAP_ISDN; /* set depending on decoder format and mode */
429                 break;
430
431         case WTAP_ENCAP_LAYER1_EVENT:
432                 protocol=EYESDN_ENCAP_MSG;
433                 break;
434
435         case WTAP_ENCAP_DPNSS:
436                 protocol=EYESDN_ENCAP_DPNSS;
437                 break;
438
439 #if 0
440         case WTAP_ENCAP_DASS2:
441                 protocol=EYESDN_ENCAP_DASS2;
442                 break;
443 #endif
444
445         case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
446                 protocol=EYESDN_ENCAP_ATM;
447                 channel=0x80;
448                 break;
449
450         case WTAP_ENCAP_LAPB:
451                 protocol=EYESDN_ENCAP_LAPB;
452                 break;
453
454         case WTAP_ENCAP_MTP2_WITH_PHDR:
455                 protocol=EYESDN_ENCAP_MTP2;
456                 break;
457
458         case WTAP_ENCAP_BACNET_MS_TP_WITH_PHDR:
459                 protocol=EYESDN_ENCAP_BACNET;
460                 break;
461
462         case WTAP_ENCAP_V5_EF:
463                 protocol=EYESDN_ENCAP_V5_EF;
464                 break;
465
466         default:
467                 *err=WTAP_ERR_UNWRITABLE_ENCAP;
468                 return FALSE;
469         }
470
471         phton24(&buf[0], usecs);
472
473         buf[3] = (guint8)0;
474         buf[4] = (guint8)(0xff & (secs >> 24));
475         buf[5] = (guint8)(0xff & (secs >> 16));
476         buf[6] = (guint8)(0xff & (secs >> 8));
477         buf[7] = (guint8)(0xff & (secs >> 0));
478
479         buf[8] = (guint8) channel;
480         buf[9] = (guint8) (origin?1:0) + (protocol << 1);
481         phtons(&buf[10], size);
482
483         /* start flag */
484         if (!wtap_dump_file_write(wdh, &start_flag, sizeof start_flag, err))
485                 return FALSE;
486         if (!esc_write(wdh, buf, 12, err))
487                 return FALSE;
488         if (!esc_write(wdh, pd, size, err))
489                 return FALSE;
490         return TRUE;
491 }
492
493 /*
494  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
495  *
496  * Local variables:
497  * c-basic-offset: 8
498  * tab-width: 8
499  * indent-tabs-mode: t
500  * End:
501  *
502  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
503  * :indentSize=8:tabSize=8:noTabs=false:
504  */