6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "file_wrappers.h"
34 /* This module reads the output of the EyeSDN USB S0/E1 ISDN probes
35 * They store HDLC frames of D and B channels in a binary format
38 * 1-6 Byte: EyeSDN - Magic
41 * Each Frame starts with the 0xff Flag byte
42 * - Bytes 0-2: timestamp (usec in network byte order)
43 * - Bytes 3-7: timestamp (40bits sec since 1970 in network byte order)
44 * - Byte 8: channel (0 for D channel, 1-30 for B1-B30)
45 * - Byte 9: Sender Bit 0(0 NT, 1 TE), Protocol in Bits 7:1, see enum
46 * - Byte 10-11: frame size in bytes
47 * - Byte 12-n: Frame Payload
49 * All multibyte values are represented in network byte order
50 * The frame is terminated with a flag character (0xff)
51 * bytes 0xff within a frame are escaped using the 0xfe escape character
52 * the byte following the escape character is decremented by two:
53 * so 0xfe 0xfd is actually a 0xff
54 * Characters that need to be escaped are 0xff and 0xfe
58 static int esc_read(guint8
*buf
, int len
, FILE_T fh
)
63 for(i
=0; i
<len
; i
++) {
66 return -2; /* EOF or error */
68 return -1; /* error !!, read into next frame */
70 /* we need to escape */
82 /* Magic text to check for eyesdn-ness of file */
83 static const unsigned char eyesdn_hdr_magic
[] =
84 { 'E', 'y', 'e', 'S', 'D', 'N'};
85 #define EYESDN_HDR_MAGIC_SIZE (sizeof(eyesdn_hdr_magic) / sizeof(eyesdn_hdr_magic[0]))
87 /* Size of a record header */
88 #define EYESDN_HDR_LENGTH 12
91 * XXX - is this the biggest packet we can get?
93 #define EYESDN_MAX_PACKET_LEN 16384
95 static gboolean
eyesdn_read(wtap
*wth
, int *err
, gchar
**err_info
,
97 static gboolean
eyesdn_seek_read(wtap
*wth
, gint64 seek_off
,
98 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int len
,
99 int *err
, gchar
**err_info
);
100 static int read_eyesdn_rec(FILE_T fh
, struct wtap_pkthdr
*phdr
, Buffer
* buf
,
101 int *err
, gchar
**err_info
);
103 /* Seeks to the beginning of the next packet, and returns the
104 byte offset. Returns -1 on failure, and sets "*err" to the error
105 and "*err_info" to null or an additional error string. */
106 static gint64
eyesdn_seek_next_packet(wtap
*wth
, int *err
, gchar
**err_info
)
111 while ((byte
= file_getc(wth
->fh
)) != EOF
) {
113 cur_off
= file_tell(wth
->fh
);
116 *err
= file_error(wth
->fh
, err_info
);
123 *err
= file_error(wth
->fh
, err_info
);
127 int eyesdn_open(wtap
*wth
, int *err
, gchar
**err_info
)
130 char magic
[EYESDN_HDR_MAGIC_SIZE
];
132 /* Look for eyesdn header */
133 errno
= WTAP_ERR_CANT_READ
;
134 bytes_read
= file_read(&magic
, sizeof magic
, wth
->fh
);
135 if (bytes_read
!= sizeof magic
) {
136 *err
= file_error(wth
->fh
, err_info
);
137 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
141 if (memcmp(magic
, eyesdn_hdr_magic
, EYESDN_HDR_MAGIC_SIZE
) != 0)
144 wth
->file_encap
= WTAP_ENCAP_PER_PACKET
;
145 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_EYESDN
;
146 wth
->snapshot_length
= 0; /* not known */
147 wth
->subtype_read
= eyesdn_read
;
148 wth
->subtype_seek_read
= eyesdn_seek_read
;
149 wth
->tsprecision
= WTAP_FILE_TSPREC_USEC
;
154 /* Find the next packet and parse it; called from wtap_read(). */
155 static gboolean
eyesdn_read(wtap
*wth
, int *err
, gchar
**err_info
,
160 /* Find the next record */
161 offset
= eyesdn_seek_next_packet(wth
, err
, err_info
);
164 *data_offset
= offset
;
166 /* Parse the record */
167 return read_eyesdn_rec(wth
->fh
, &wth
->phdr
, wth
->frame_buffer
,
171 /* Used to read packets in random-access fashion */
173 eyesdn_seek_read(wtap
*wth
, gint64 seek_off
, struct wtap_pkthdr
*phdr
,
174 Buffer
*buf
, int len _U_
, int *err
, gchar
**err_info
)
176 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
179 return read_eyesdn_rec(wth
->random_fh
, phdr
, buf
, err
, err_info
);
182 /* Parses a record. */
184 read_eyesdn_rec(FILE_T fh
, struct wtap_pkthdr
*phdr
, Buffer
*buf
, int *err
,
187 union wtap_pseudo_header
*pseudo_header
= &phdr
->pseudo_header
;
188 guint8 hdr
[EYESDN_HDR_LENGTH
];
192 guint8 channel
, direction
;
196 /* Our file pointer should be at the summary information header
197 * for a packet. Read in that header and extract the useful
200 if (esc_read(hdr
, EYESDN_HDR_LENGTH
, fh
) != EYESDN_HDR_LENGTH
) {
201 *err
= file_error(fh
, err_info
);
203 *err
= WTAP_ERR_SHORT_READ
;
207 /* extract information from header */
208 usecs
= pntoh24(&hdr
[0]);
214 secs
= (secs
<< 8) | hdr
[4];
215 secs
= (secs
<< 8) | hdr
[5];
216 secs
= (secs
<< 8) | hdr
[6];
217 secs
= (secs
<< 8) | hdr
[7];
221 pkt_len
= pntohs(&hdr
[10]);
223 switch(direction
>> 1) {
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
;
237 case EYESDN_ENCAP_MSG
: /* Layer 1 message */
238 phdr
->pkt_encap
= WTAP_ENCAP_LAYER1_EVENT
;
239 pseudo_header
->l1event
.uton
= (direction
& 1);
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;
247 case EYESDN_ENCAP_ATM
: { /* ATM cells */
249 unsigned char cell
[CELL_LEN
];
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)",
260 cur_off
= file_tell(fh
);
261 if (esc_read(cell
, CELL_LEN
, fh
) != CELL_LEN
) {
262 *err
= file_error(fh
, err_info
);
264 *err
= WTAP_ERR_SHORT_READ
;
267 if (file_seek(fh
, cur_off
, SEEK_SET
, err
) == -1)
269 phdr
->pkt_encap
= WTAP_ENCAP_ATM_PDUS_UNTRUNCATED
;
270 pseudo_header
->atm
.flags
=ATM_RAW_CELL
;
271 pseudo_header
->atm
.aal
=AAL_UNKNOWN
;
272 pseudo_header
->atm
.type
=TRAF_UMTS_FP
;
273 pseudo_header
->atm
.subtype
=TRAF_ST_UNKNOWN
;
274 pseudo_header
->atm
.vpi
=((cell
[0]&0xf)<<4) + (cell
[0]&0xf);
275 pseudo_header
->atm
.vci
=((cell
[0]&0xf)<<4) + cell
[0]; /* from cell */
276 pseudo_header
->atm
.channel
=direction
& 1;
280 case EYESDN_ENCAP_MTP2
: /* SS7 frames */
281 pseudo_header
->mtp2
.sent
= direction
& 1;
282 pseudo_header
->mtp2
.annex_a_used
= MTP2_ANNEX_A_USED_UNKNOWN
;
283 pseudo_header
->mtp2
.link_number
= channel
;
284 phdr
->pkt_encap
= WTAP_ENCAP_MTP2_WITH_PHDR
;
287 case EYESDN_ENCAP_DPNSS
: /* DPNSS */
288 pseudo_header
->isdn
.uton
= direction
& 1;
289 pseudo_header
->isdn
.channel
= channel
;
290 phdr
->pkt_encap
= WTAP_ENCAP_DPNSS
;
293 case EYESDN_ENCAP_DASS2
: /* DASS2 frames */
294 pseudo_header
->isdn
.uton
= direction
& 1;
295 pseudo_header
->isdn
.channel
= channel
;
296 phdr
->pkt_encap
= WTAP_ENCAP_DPNSS
;
299 case EYESDN_ENCAP_BACNET
: /* BACNET async over HDLC frames */
300 pseudo_header
->isdn
.uton
= direction
& 1;
301 pseudo_header
->isdn
.channel
= channel
;
302 phdr
->pkt_encap
= WTAP_ENCAP_BACNET_MS_TP_WITH_PHDR
;
305 case EYESDN_ENCAP_V5_EF
: /* V5EF */
306 pseudo_header
->isdn
.uton
= direction
& 1;
307 pseudo_header
->isdn
.channel
= channel
;
308 phdr
->pkt_encap
= WTAP_ENCAP_V5_EF
;
312 if(pkt_len
> EYESDN_MAX_PACKET_LEN
) {
313 *err
= WTAP_ERR_BAD_FILE
;
314 *err_info
= g_strdup_printf("eyesdn: File has %u-byte packet, bigger than maximum of %u",
315 pkt_len
, EYESDN_MAX_PACKET_LEN
);
319 phdr
->presence_flags
= WTAP_HAS_TS
;
320 phdr
->ts
.secs
= secs
;
321 phdr
->ts
.nsecs
= usecs
* 1000;
322 phdr
->caplen
= pkt_len
;
325 /* Make sure we have enough room for the packet */
326 buffer_assure_space(buf
, EYESDN_MAX_PACKET_LEN
);
328 errno
= WTAP_ERR_CANT_READ
;
329 pd
= buffer_start_ptr(buf
);
330 bytes_read
= esc_read(pd
, pkt_len
, fh
);
331 if (bytes_read
!= pkt_len
) {
332 if (bytes_read
== -2) {
333 *err
= file_error(fh
, err_info
);
335 *err
= WTAP_ERR_SHORT_READ
;
336 } else if (bytes_read
== -1) {
337 *err
= WTAP_ERR_BAD_FILE
;
338 *err_info
= g_strdup("eyesdn: No flag character seen in frame");
340 *err
= WTAP_ERR_SHORT_READ
;
348 esc_write(wtap_dumper
*wdh
, const guint8
*buf
, int len
, int *err
)
352 static const guint8 esc
= 0xfe;
354 for(i
=0; i
<len
; i
++) {
356 if(byte
== 0xff || byte
== 0xfe) {
358 * Escape the frame delimiter and escape byte.
360 if (!wtap_dump_file_write(wdh
, &esc
, sizeof esc
, err
))
364 if (!wtap_dump_file_write(wdh
, &byte
, sizeof byte
, err
))
370 static gboolean
eyesdn_dump(wtap_dumper
*wdh
,
371 const struct wtap_pkthdr
*phdr
,
372 const guint8
*pd
, int *err
);
374 gboolean
eyesdn_dump_open(wtap_dumper
*wdh
, int *err
)
376 wdh
->subtype_write
=eyesdn_dump
;
377 wdh
->subtype_close
=NULL
;
379 if (!wtap_dump_file_write(wdh
, eyesdn_hdr_magic
,
380 EYESDN_HDR_MAGIC_SIZE
, err
))
382 wdh
->bytes_dumped
+= EYESDN_HDR_MAGIC_SIZE
;
387 int eyesdn_dump_can_write_encap(int encap
)
390 case WTAP_ENCAP_ISDN
:
391 case WTAP_ENCAP_LAYER1_EVENT
:
392 case WTAP_ENCAP_DPNSS
:
393 case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED
:
394 case WTAP_ENCAP_LAPB
:
395 case WTAP_ENCAP_MTP2_WITH_PHDR
:
396 case WTAP_ENCAP_BACNET_MS_TP_WITH_PHDR
:
397 case WTAP_ENCAP_PER_PACKET
:
401 return WTAP_ERR_UNSUPPORTED_ENCAP
;
405 /* Write a record for a packet to a dump file.
406 * Returns TRUE on success, FALSE on failure. */
407 static gboolean
eyesdn_dump(wtap_dumper
*wdh
,
408 const struct wtap_pkthdr
*phdr
,
409 const guint8
*pd
, int *err
)
411 static const guint8 start_flag
= 0xff;
412 const union wtap_pseudo_header
*pseudo_header
= &phdr
->pseudo_header
;
413 guint8 buf
[EYESDN_HDR_LENGTH
];
421 usecs
=phdr
->ts
.nsecs
/1000;
424 origin
= pseudo_header
->isdn
.uton
;
425 channel
= pseudo_header
->isdn
.channel
;
427 switch(phdr
->pkt_encap
) {
429 case WTAP_ENCAP_ISDN
:
430 protocol
=EYESDN_ENCAP_ISDN
; /* set depending on decoder format and mode */
433 case WTAP_ENCAP_LAYER1_EVENT
:
434 protocol
=EYESDN_ENCAP_MSG
;
437 case WTAP_ENCAP_DPNSS
:
438 protocol
=EYESDN_ENCAP_DPNSS
;
442 case WTAP_ENCAP_DASS2
:
443 protocol
=EYESDN_ENCAP_DASS2
;
447 case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED
:
448 protocol
=EYESDN_ENCAP_ATM
;
452 case WTAP_ENCAP_LAPB
:
453 protocol
=EYESDN_ENCAP_LAPB
;
456 case WTAP_ENCAP_MTP2_WITH_PHDR
:
457 protocol
=EYESDN_ENCAP_MTP2
;
460 case WTAP_ENCAP_BACNET_MS_TP_WITH_PHDR
:
461 protocol
=EYESDN_ENCAP_BACNET
;
464 case WTAP_ENCAP_V5_EF
:
465 protocol
=EYESDN_ENCAP_V5_EF
;
469 *err
=WTAP_ERR_UNSUPPORTED_ENCAP
;
473 phton24(&buf
[0], usecs
);
476 buf
[4] = (guint8
)(0xff & (secs
>> 24));
477 buf
[5] = (guint8
)(0xff & (secs
>> 16));
478 buf
[6] = (guint8
)(0xff & (secs
>> 8));
479 buf
[7] = (guint8
)(0xff & (secs
>> 0));
481 buf
[8] = (guint8
) channel
;
482 buf
[9] = (guint8
) (origin
?1:0) + (protocol
<< 1);
483 phtons(&buf
[10], size
);
486 if (!wtap_dump_file_write(wdh
, &start_flag
, sizeof start_flag
, err
))
488 if (!esc_write(wdh
, buf
, 12, err
))
490 if (!esc_write(wdh
, pd
, size
, err
))