1 /*********************************************************************
3 * Filename: irda_intercept.c
5 * Description: intercept irda-traffic incl. negotation and write
7 * Status: Experimental.
8 * Author: Thomas Schneider <nok-trace-men@dev-thomynet.de>
11 * Modified by: Thomas Schneider <nok-trace-men@dev-thomynet.de>
13 * Copyright (c) 1999 Thomas Schneider, All Rights Reserved.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 * IN NO EVENT SHALL THOMAS SCHNEIDER BE LIABLE TO ANY PARTY FOR
30 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
31 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
32 * IF THOMAS SCHNEIDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
35 * THOMAS SCHNEIDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
36 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
37 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER
38 * IS ON AN "AS IS" BASIS, AND THOMAS SCHNEIDER HAS NO OBLIGATION TO
39 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
42 * This material is provided "AS-IS" and at no charge.
44 ********************************************************************/
46 #include <sys/types.h>
55 #include "../include/irda.h"
56 #include "../include/irlap.h"
57 #include "../fcs/fcs.h"
59 #define INIT_BAUDRATE B9600
61 #define _POSIX_SOURCE 1 /* POSIX compliant source */
63 #define INITIAL_TIMEOUT 15
64 #define DEFAULT_TIMEOUT 5
66 #define OUTFILE_SUFFIX ".trc"
67 #define DEFAULT_OUTFILE "out"OUTFILE_SUFFIX
69 static int initfdflags = -1; /* Initial file descriptor flags */
70 static struct termios old_port_sets; /* old port-termios for restore */
74 NEGOTATION_PARAM negotation_param;
75 CONNECTION connection;
77 static speed_t speed_list[8] = { B2400, B9600, B19200, B38400,
78 B57600, B115200, B576000, B1152000 };
79 static const char *speed_name[] = { "2400", "9600", "19200", "38400",
80 "57600", "115200", "576000", "1152000"};
85 * - in negotation set new device speed
87 void negotation ( IRLAP_FRAME * irlap_frame )
89 BYTE cmd = irlap_frame -> a & 0x01;
90 speed_t new_speed = 0;
101 * - 1 new connection address
118 * - in IrLAP (V. 1.1) page 27
119 * - U32 : src-dev-adr
120 * - U32 : dest-dev-adr
121 * - U8 : connection address
122 * - start of neg. params
124 if ( irlap_frame -> info_length < ( IRLAP_NEG_SNRM_PARAM_OFF +3 ) ) {
125 printf ("\t==> IrLAP: in SNRM-CMD no Info! <==\n");
127 memcpy ( &connection.p_src_adr,
128 &(irlap_frame -> info[IRLAP_SNRM_SRC_ADR]),
129 sizeof(connection.p_src_adr));
130 memcpy ( &connection.s_src_adr,
131 &(irlap_frame -> info[IRLAP_SNRM_DEST_ADR]),
132 sizeof(connection.s_src_adr));
133 connection.conn_adr = irlap_frame -> info[IRLAP_SNRM_CONN_ADR];
134 if ( irlap_frame -> info[IRLAP_NEG_SNRM_PARAM_OFF] ==
136 /* really bps-parameter-identifier */
137 if ( irlap_frame -> info[IRLAP_NEG_SNRM_PARAM_OFF + 1] == 1 ) {
138 negotation_param.baud_rate_master =
139 irlap_frame -> info [IRLAP_NEG_SNRM_PARAM_OFF + 2];
140 negotation_param.state = NEG_WAIT_FOR_UA;
142 printf ("\t==> IrLAP: SNRM-CMD: speed in 2 bytes! <==\n");
143 printf ("\t\t==> IrLAP: my max. speed is 115.2 kbps! <==\n");
144 negotation_param.baud_rate_master =
145 irlap_frame -> info [IRLAP_NEG_SNRM_PARAM_OFF + 3];
148 printf ("\t==> IrLAP: SNRM-CMD: "
149 "No baud rate dictate in 1. byte! <==\n");
154 negotation_param.baud_rate_client = irlap_frame -> info [10];
155 negotation_param.state = NEG_UA_OK;
157 /* now compute the new speed */
159 negotation_param.baud_rate_master & negotation_param.baud_rate_client;
161 new_speed = speed_list[i];
164 for ( i=1; i < 7; i++) {
167 new_speed = speed_list[i];
172 /* not defined as B... on my system */
173 printf ("Sorry: Required speed (%s baud) not supported!\n",
176 printf ("New speed is: %s\n", speed_name[m]);
177 /* now set the new speed */
178 tcgetattr (port_fd, &set);
179 cfsetospeed(&set, new_speed);
180 cfsetispeed(&set, new_speed);
181 tcsetattr(port_fd, TCSANOW, &set);
182 tcgetattr(port_fd, &set);
183 if ( (cfgetospeed(&set) != new_speed) ||
184 (cfgetispeed(&set) != new_speed) ) {
185 printf ("New speed is not set!\n");
194 * - decode the irlap-c-field
196 void decode_irlap_frame ( IRLAP_FRAME * irlap_frame)
198 BYTE cmd = irlap_frame -> a & 0x01;
199 BYTE poll = irlap_frame -> c & (IRLAP_PF_BIT_MASK);
200 BYTE adr = (irlap_frame -> a) >> 1;
202 switch ( irlap_frame -> c & IRLAP_C_MASK ) {
204 printf ("U-Frame:\tAdr: %02X Nr: %02X ", adr,
205 (irlap_frame -> c & 0xE0) >> 5);
206 printf ("P/F: %X \t\t", poll >> 4);
207 switch (irlap_frame -> c & IRLAP_PF_BIT_CLR_MASK ) {
208 case IRLAP_SNRM_RNRM:
209 /* SNRM cmd/RNRM response */
211 printf ("SNRM cmd\n");
212 switch (connection.irlap_state) {
214 printf ("\t==> IrLAP in DISC but SNRM-CMD? <==\n");
217 printf ("\t==> Start IrLAP - negotation <==\n");
218 negotation ( irlap_frame );
221 printf ("\t==> IrLAP in NRM but SNRM-CMD? <==\n");
224 printf ("\t==> IrLAP in not defined state but SNRM-CMD? <==\n");
227 printf ("RNRM response\n");
231 /* DISC cmd/RD response */
233 printf ("DISC cmd\n");
235 printf ("RD response\n");
239 /* UI cmd/UI response */
243 printf ("UI response\n");
248 printf ("XID cmd\n");
249 if ( connection.irlap_state == IRLAP_DISC ) {
250 connection.irlap_state = IRLAP_NDM;
251 printf ("\t==> Set IrLAP-state to:"
252 "NDM (normal disconnected mode) <==\n");
255 case IRLAP_TEST_TEST:
256 /* Test cmd/response */
258 printf ("TEST cmd\n");
260 printf ("TEST response\n");
265 printf ("UA response\n");
266 switch (connection.irlap_state) {
268 printf ("\t==> IrLAP in DISC but UA-RESPONSE? <==\n");
271 if ( negotation_param.state == NEG_WAIT_FOR_UA ) {
272 printf ("\t==> Continue IrLAP - negotation! <==\n");
273 negotation ( irlap_frame );
275 printf ("\t==> IrLAP in NDM but not wait for negotation! <==\n");
279 printf ("\t==> UA: IrLAP was/is in NRM ... <==\n");
282 printf ("\t==> IrLAP in not defined state but UA-RESPONSE? <==\n");
287 printf ("FRMR response\n");
291 printf ("DM response\n");
295 printf ("XID response\n");
298 /* unknown cmd/response */
299 printf ("Unknown IrLAP-U-Frame\n");
300 } /* end of irlap-u-frames */
303 printf ("S-Frame:\tAdr: %02X Nr: %02X ", adr,
304 (irlap_frame -> c & 0xE0) >> 5);
305 printf ("P/F: %X \t\t", poll >> 4);
306 switch ( irlap_frame -> c &
307 (IRLAP_PF_BIT_CLR_MASK & IRLAP_Nr_CLR_MASK) ) {
309 /* RR command/response */
313 printf ("RR response\n");
317 /* RNR cmd/response */
318 printf ("RNR cmd/response\n");
321 /* REJ cmd/response */
322 printf ("REJ cmd/response\n");
325 /* SREJ cmd/response */
326 printf ("SREJ cmd/response\n");
329 /* unknown cmd/response */
330 printf ("Unknown IrLAP-S-Frame\n");
331 } /* end of irlap-s-frames */
334 printf ("I-Frame:\tAdr: %02X Nr: %02X ", adr,
335 (irlap_frame -> c & 0xE0) >> 5);
336 printf ("\tP/F: %X\t", poll >> 4);
337 printf ("Ns: %02X \t", (irlap_frame -> c & 0x0E) >> 1);
338 printf ("Information\n");
344 * - put raw-frame-datas in irlap-frame
346 void unwrap_raw_frame ( RAW_FRAME * raw_frame )
348 IRLAP_FRAME irlap_frame;
351 bzero ( &irlap_frame, sizeof(irlap_frame) );
353 irlap_frame.a = raw_frame -> buf[IRLAP_A_OFF];
354 irlap_frame.c = raw_frame -> buf[IRLAP_C_OFF];
355 irlap_frame.fcs = raw_frame -> buf [(raw_frame -> length) -2] << 8;
356 irlap_frame.fcs |= raw_frame -> buf [(raw_frame -> length) -1];
358 irlap_frame.info_length = raw_frame -> length -
359 IRLAP_A_LENGTH - IRLAP_C_LENGTH - IRLAP_FCS_LENGTH;
361 info_ptr = g_malloc ( irlap_frame.info_length * sizeof (BYTE) );
362 memcpy ( info_ptr, &(raw_frame -> buf[IRLAP_I_OFF]),
363 irlap_frame.info_length);
364 irlap_frame.info = info_ptr;
365 decode_irlap_frame ( &irlap_frame );
368 printf ("IrLAP: FCS: %04X \n\n", irlap_frame.fcs );
375 * - call on some signals from signalhandler
376 * - before end set the original setting
378 void cleanup_termios ( int signal )
380 tcsetattr(port_fd, TCSANOW, &old_port_sets);
387 * - get original port-settings and store it
388 * - set new port-settings
390 void init_port ( void )
392 struct termios new_port_sets;
394 /* get the original settings and store it for restore */
395 tcgetattr( port_fd, &old_port_sets);
397 /* init new settings */
398 bzero(&new_port_sets, sizeof(new_port_sets));
399 new_port_sets.c_cflag = INIT_BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
400 new_port_sets.c_iflag = IGNBRK | IGNPAR;
401 new_port_sets.c_oflag = 0;
403 /* set input mode (non-canonical, no echo,...) */
404 new_port_sets.c_lflag = 0;
406 /* inter-character timer unused x0.1s */
407 new_port_sets.c_cc[VTIME] = 0;
408 /* blocking read until 5 chars received */
409 new_port_sets.c_cc[VMIN] = 1;
411 /* set the port now */
412 tcflush(port_fd, TCIFLUSH);
413 tcsetattr(port_fd, TCSANOW, &new_port_sets);
419 * - output-file and port open
420 * - get/set port settings
423 int main( int argc, char * argv[] )
425 struct sigaction sact; /* signalhandle */
426 GString *outfile_name = g_string_new(DEFAULT_OUTFILE); /* outfile name */
427 FILE *outfile; /* outfile FILE */
428 fd_set ready; /* for select */
429 struct timeval timeout; /* select-timeout */
430 int no_timeout = 1; /* timeout reached */
431 int nr_read = 0; /* byte readed */
432 unsigned char in_buffer[255]; /* temp. buffer */
433 RAW_FRAME raw_frame; /* a raw frame */
434 int is_inframe = FALSE; /* loop in frame */
435 int frame_complete = FALSE; /* frame complete */
436 int done = 0; /* loop control */
437 int i = 0; /* for-index */
438 int nr_of_bytes = 0; /* total bytes */
439 int nr_of_frames = 0; /* total frames */
440 int irlap_bytes = 0; /* w/o BOF etc. */
441 BYTE must_escaped = FALSE; /* after CE = 0x07 */
442 U16 fcsrx = INIT_FCS; /* for fcs-comput. */
443 BYTE nr_esc = 0; /* nr of CE's */
444 //CONNECT_STATISTIC statistic; /* statistic */
445 //OUTPUT_PARAMS output_params; /* output-control */
448 * Open the serial device
450 if ( (port_fd = open( MODEMDEVICE, O_NONBLOCK | O_RDWR)) < 0 ) {
451 printf ( "Failed to open %s!\n", MODEMDEVICE);
456 * get/set device fd flags
458 if ( (initfdflags = fcntl( port_fd, F_GETFL)) == -1 ) {
459 printf ( "Couldn't get device fd flags for: %s!", MODEMDEVICE);
462 initfdflags &= ~O_NONBLOCK;
463 fcntl( port_fd, F_SETFL, initfdflags);
470 sact.sa_handler = cleanup_termios;
471 sigaction( SIGHUP, &sact, NULL);
472 sigaction( SIGINT, &sact, NULL);
473 sigaction( SIGPIPE, &sact, NULL);
474 sigaction( SIGTERM, &sact, NULL);
477 * Set device for non-blocking reads.
479 if ( fcntl( port_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
480 printf ("Couldn't set device to non-blocking mode (%s)!\n", MODEMDEVICE);
485 * output-file-handling
488 printf ("Use default OutPutFile: %s\n", outfile_name -> str);
490 g_string_assign(outfile_name, argv[1]);
491 g_string_append(outfile_name, OUTFILE_SUFFIX);
492 printf ("Use OutPutFile: %s\n", outfile_name -> str);
494 if ( (outfile = fopen( outfile_name -> str, "wb")) == NULL ) {
495 printf ("Failed to open OutPutFile: %s\n", outfile_name -> str);
504 timeout.tv_sec = INITIAL_TIMEOUT;
508 * init raw-frame, negotation-struct, connection
510 bzero(&raw_frame, sizeof(raw_frame));
511 bzero(&negotation_param, sizeof(negotation_param));
512 bzero(&connection, sizeof(connection));
514 /* hope we have no irda traffic in moment */
515 connection.irlap_state = IRLAP_DISC;
518 * now make the data-read-loop
522 FD_SET(port_fd, &ready);
523 no_timeout = select(port_fd + 1, &ready, NULL, NULL, &timeout);
524 if ( FD_ISSET(port_fd, &ready) ) {
525 /* data on port - returns after 16 chars have been input */
526 nr_read = read(port_fd, in_buffer, 16);
527 nr_of_bytes = nr_of_bytes + nr_read;
528 if ( nr_read >= 1 ) {
529 /* write all readed bytes to file */
530 fwrite( in_buffer, 1, nr_read, outfile);
531 /* process every single byte */
532 for (i=0; i < nr_read; i++) {
533 if (raw_frame.length < (4096-1) ) {
534 switch ( in_buffer[i] ) {
538 * no - its not a XBOF we are inside a frame
539 * broadcast in xid for example
542 fcsrx = IR_FCS(fcsrx, in_buffer[i]);
544 raw_frame.buf[raw_frame.length] = in_buffer[i];
551 frame_complete = TRUE;
561 if ( must_escaped ) {
562 fcsrx = IR_FCS(fcsrx, (in_buffer[i] ^ IRLAP_ESC_MASK) );
563 raw_frame.buf[raw_frame.length] =
564 (in_buffer[i]^IRLAP_ESC_MASK);
565 must_escaped = FALSE;
567 fcsrx = IR_FCS(fcsrx, in_buffer[i]);
568 raw_frame.buf[raw_frame.length] = in_buffer[i];
572 raw_frame.length = irlap_bytes;
573 if ( frame_complete ) {
574 /* now raw-frame is complete */
575 if ( fcsrx != GOOD_FCS ) {
576 printf (" **** !!! FCS-ERROR !!! ****\n");
578 unwrap_raw_frame ( &raw_frame );
581 /* reset all to defaults */
582 raw_frame.length = 0;
583 raw_frame.a_offset = 0;
584 frame_complete = FALSE;
592 printf ("No data to read - why?\n");
597 * reset timeout - wait 5 seconds
599 timeout.tv_sec = DEFAULT_TIMEOUT;
601 if ( ! no_timeout ) {
602 printf ("TimeOut!\nConnection summary:\n-------------------\n");
603 printf ("Total nr of received bytes : %i\n", nr_of_bytes);
604 printf ("Total nr of received frames: %i\n", nr_of_frames);
609 g_string_free(outfile_name, TRUE);
611 tcsetattr(port_fd, TCSANOW, &old_port_sets);