http://marcin-wiacek.fkn.pl/english/zips/mygnokii.tar.gz
[gnokii.git] / Docs / developers / other / sniffs / irda / tools / intercept / irda_intercept.c
diff --git a/Docs/developers/other/sniffs/irda/tools/intercept/irda_intercept.c b/Docs/developers/other/sniffs/irda/tools/intercept/irda_intercept.c
new file mode 100644 (file)
index 0000000..1381418
--- /dev/null
@@ -0,0 +1,613 @@
+/*********************************************************************
+ *
+ * Filename:      irda_intercept.c
+ * Version:
+ * Description:   intercept irda-traffic incl. negotation and write
+ *                output to a file
+ * Status:        Experimental.
+ * Author:        Thomas Schneider <nok-trace-men@dev-thomynet.de>
+ * Created at:    
+ * Modified at:   
+ * Modified by:   Thomas Schneider <nok-trace-men@dev-thomynet.de>
+ *
+ *     Copyright (c) 1999 Thomas Schneider, All Rights Reserved.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * IN NO EVENT SHALL THOMAS SCHNEIDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THOMAS SCHNEIDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
+ * DAMAGE.
+ *
+ * THOMAS SCHNEIDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER
+ * IS ON AN "AS IS" BASIS, AND THOMAS SCHNEIDER HAS NO OBLIGATION TO 
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 
+ * MODIFICATIONS.
+ *
+ *         This material is provided "AS-IS" and at no charge.
+ *
+ ********************************************************************/
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <glib.h>
+#include "../include/irda.h"
+#include "../include/irlap.h"
+#include "../fcs/fcs.h"
+
+#define INIT_BAUDRATE B9600
+
+#define _POSIX_SOURCE 1 /* POSIX compliant source */
+
+#define INITIAL_TIMEOUT 15
+#define DEFAULT_TIMEOUT  5
+
+#define OUTFILE_SUFFIX ".trc"
+#define DEFAULT_OUTFILE "out"OUTFILE_SUFFIX
+
+static int initfdflags = -1;        /* Initial file descriptor flags */
+static struct termios old_port_sets; /* old port-termios for restore  */
+
+int port_fd;
+
+NEGOTATION_PARAM negotation_param;
+CONNECTION connection;
+
+static speed_t speed_list[8] = { B2400, B9600, B19200, B38400,
+                            B57600, B115200, B576000, B1152000 };
+static const char *speed_name[] = { "2400", "9600", "19200", "38400",
+                               "57600", "115200", "576000", "1152000"};
+
+/*
+ * negotation
+ * ----------
+ * - in negotation set new device speed
+ */
+void negotation ( IRLAP_FRAME * irlap_frame )
+{
+   BYTE cmd          = irlap_frame -> a & 0x01;
+   speed_t new_speed = 0;
+   int i             = 0;
+   int m             = 0;
+   struct termios set;
+   BYTE tmp          = 0;
+
+   /* 
+    * snrm-frame
+    * ----------
+    * - 4 src
+    * - 4 dest
+    * - 1 new connection address
+    * - 1 pi
+    * - 1 pl
+    * - [pl] pv
+    * ua-frame
+    * --------
+    * - 4 src
+    * - 4 dest
+    * - 1 pi
+    * - 1 pl
+    * - [pl] pv
+    */
+
+   if ( cmd ) {
+     /*
+      * SNRM - CMD
+      * ----------
+      * - in IrLAP (V. 1.1) page 27
+      * - U32 : src-dev-adr
+      * - U32 : dest-dev-adr
+      * - U8  : connection address
+      * - start of neg. params
+      */
+     if ( irlap_frame -> info_length < ( IRLAP_NEG_SNRM_PARAM_OFF +3 ) ) {
+       printf ("\t==> IrLAP: in SNRM-CMD no Info! <==\n");
+     } else {
+       memcpy ( &connection.p_src_adr,
+               &(irlap_frame -> info[IRLAP_SNRM_SRC_ADR]),
+               sizeof(connection.p_src_adr));
+       memcpy ( &connection.s_src_adr,
+               &(irlap_frame -> info[IRLAP_SNRM_DEST_ADR]),
+               sizeof(connection.s_src_adr));
+       connection.conn_adr = irlap_frame -> info[IRLAP_SNRM_CONN_ADR];
+       if ( irlap_frame -> info[IRLAP_NEG_SNRM_PARAM_OFF] == 
+           IRLAP_NEG_BPS_PI ) {
+        /* really bps-parameter-identifier */
+        if ( irlap_frame -> info[IRLAP_NEG_SNRM_PARAM_OFF + 1] == 1 ) {
+          negotation_param.baud_rate_master = 
+            irlap_frame -> info [IRLAP_NEG_SNRM_PARAM_OFF + 2];
+          negotation_param.state = NEG_WAIT_FOR_UA;
+        } else {
+          printf ("\t==> IrLAP: SNRM-CMD: speed in 2 bytes! <==\n");
+          printf ("\t\t==> IrLAP: my max. speed is 115.2 kbps! <==\n");
+          negotation_param.baud_rate_master = 
+            irlap_frame -> info [IRLAP_NEG_SNRM_PARAM_OFF + 3];
+        } 
+       } else {
+        printf ("\t==> IrLAP: SNRM-CMD: "
+                "No baud rate dictate in 1. byte! <==\n");
+       }
+     }
+   } else {
+     /* UA -rsp */
+     negotation_param.baud_rate_client = irlap_frame -> info [10];
+     negotation_param.state = NEG_UA_OK;
+   
+     /* now compute the new speed */
+     tmp = 
+       negotation_param.baud_rate_master & negotation_param.baud_rate_client;
+     if ( tmp & 0x01 ) {
+       new_speed = speed_list[i];
+       m = 0;
+     }
+     for ( i=1; i < 7; i++) {
+       tmp = tmp >> 1;
+       if ( tmp & 0x01 ) {
+        new_speed = speed_list[i];
+        m = i;
+       }
+     }
+     if ( m > 5 ) {
+       /* not defined as B... on my system */
+       printf ("Sorry: Required speed (%s baud) not supported!\n",
+              speed_name[m]);
+     } else {
+       printf ("New speed is: %s\n", speed_name[m]);
+       /* now set the new speed */
+       tcgetattr (port_fd, &set);
+       cfsetospeed(&set, new_speed);
+       cfsetispeed(&set, new_speed);
+       tcsetattr(port_fd, TCSANOW, &set);
+       tcgetattr(port_fd, &set);
+       if ( (cfgetospeed(&set) != new_speed) ||
+           (cfgetispeed(&set) != new_speed) ) {
+        printf ("New speed is not set!\n");
+       }
+     }
+   }
+}
+
+/*
+ * decode_irlap_frame
+ * ------------------
+ * - decode the irlap-c-field
+ */
+void decode_irlap_frame ( IRLAP_FRAME * irlap_frame) 
+{
+  BYTE cmd = irlap_frame -> a & 0x01;
+  BYTE poll = irlap_frame -> c & (IRLAP_PF_BIT_MASK);
+  BYTE adr = (irlap_frame -> a) >> 1;
+  
+  switch ( irlap_frame -> c & IRLAP_C_MASK ) {
+  case IRLAP_U_FRAME:
+    printf ("U-Frame:\tAdr: %02X Nr: %02X ", adr,
+           (irlap_frame -> c & 0xE0) >> 5);
+    printf ("P/F: %X \t\t", poll >> 4);
+    switch (irlap_frame -> c & IRLAP_PF_BIT_CLR_MASK ) {
+    case IRLAP_SNRM_RNRM:
+      /* SNRM cmd/RNRM response */
+      if ( cmd ) {
+       printf ("SNRM cmd\n");
+       switch (connection.irlap_state) {
+       case IRLAP_DISC:
+         printf ("\t==> IrLAP in DISC but SNRM-CMD? <==\n");
+         break;
+       case IRLAP_NDM:
+         printf ("\t==> Start IrLAP - negotation <==\n");
+         negotation ( irlap_frame );
+         break;
+       case IRLAP_NRM:
+         printf ("\t==> IrLAP in NRM but SNRM-CMD? <==\n");
+         break;
+       default:
+         printf ("\t==> IrLAP in not defined state but SNRM-CMD? <==\n");
+       }
+      } else {
+       printf ("RNRM response\n"); 
+      }
+      break;
+    case IRLAP_DISC_RD:
+      /* DISC cmd/RD response */
+      if ( cmd ) {
+       printf ("DISC cmd\n"); 
+      } else {
+       printf ("RD response\n");
+      }
+      break;
+    case IRLAP_UI_UI:
+      /* UI cmd/UI response */
+      if ( cmd ) {
+       printf ("UI cmd\n");
+      } else {
+       printf ("UI response\n");
+      }
+      break;
+    case IRLAP_XID_CMD:
+      /* XID cmd */
+      printf ("XID cmd\n");
+      if ( connection.irlap_state == IRLAP_DISC ) {
+       connection.irlap_state = IRLAP_NDM;
+       printf ("\t==> Set IrLAP-state to:" 
+               "NDM (normal disconnected mode) <==\n");
+      }
+      break;
+    case IRLAP_TEST_TEST:
+      /* Test cmd/response */
+      if ( cmd ) {
+       printf ("TEST cmd\n");
+      } else {
+       printf ("TEST response\n");
+      }
+      break;
+    case IRLAP_UA_RSP:
+      /* UA response */
+      printf ("UA response\n");
+      switch (connection.irlap_state) {
+      case IRLAP_DISC:
+       printf ("\t==> IrLAP in DISC but UA-RESPONSE? <==\n");
+       break;
+      case IRLAP_NDM:
+       if ( negotation_param.state == NEG_WAIT_FOR_UA ) {
+         printf ("\t==> Continue IrLAP - negotation! <==\n");
+         negotation ( irlap_frame );
+       } else {
+         printf ("\t==> IrLAP in NDM but not wait for  negotation! <==\n");
+       }
+       break;
+      case IRLAP_NRM:
+       printf ("\t==> UA: IrLAP was/is in NRM ... <==\n");
+       break;
+      default:
+       printf ("\t==> IrLAP in not defined state but UA-RESPONSE? <==\n");
+      }
+      break;
+    case IRLAP_FRMR_RSP:
+      /* FRMR response */
+      printf ("FRMR response\n");
+      break;
+    case IRLAP_DM_RSP:
+      /* DM response */
+      printf ("DM response\n");
+      break;
+    case IRLAP_XID_RSP:
+      /* XID response */
+      printf ("XID response\n");
+      break;
+    default:
+      /* unknown cmd/response */
+      printf ("Unknown IrLAP-U-Frame\n");
+    } /* end of irlap-u-frames */
+    break;
+  case IRLAP_S_FRAME:
+    printf ("S-Frame:\tAdr: %02X Nr: %02X ", adr,
+           (irlap_frame -> c & 0xE0) >> 5);
+    printf ("P/F: %X \t\t", poll >> 4);
+    switch ( irlap_frame -> c & 
+            (IRLAP_PF_BIT_CLR_MASK & IRLAP_Nr_CLR_MASK) ) {
+    case IRLAP_RR:
+      /* RR command/response */
+      if ( cmd ) {
+       printf ("RR cmd\n");
+      } else {
+       printf ("RR response\n");
+      }
+      break;
+    case IRLAP_RNR:
+      /* RNR cmd/response */
+      printf ("RNR cmd/response\n");
+      break;
+    case IRLAP_REJ:
+      /* REJ cmd/response */
+      printf ("REJ cmd/response\n");
+      break;
+    case IRLAP_SREJ:
+      /* SREJ cmd/response */
+      printf ("SREJ cmd/response\n");
+      break;
+    default:
+      /* unknown cmd/response */
+      printf ("Unknown IrLAP-S-Frame\n");
+    } /* end of irlap-s-frames */
+    break;
+  default:
+    printf ("I-Frame:\tAdr: %02X Nr: %02X ", adr,
+           (irlap_frame -> c & 0xE0) >> 5);
+    printf ("\tP/F: %X\t", poll >> 4);
+    printf ("Ns: %02X \t", (irlap_frame -> c & 0x0E) >> 1);
+    printf ("Information\n");
+  }
+}
+
+/* unwrap_raw_frame
+ * ----------------
+ * - put raw-frame-datas in irlap-frame
+ */
+void unwrap_raw_frame ( RAW_FRAME * raw_frame ) 
+{
+  IRLAP_FRAME irlap_frame;
+  BYTE * info_ptr;
+  
+  bzero ( &irlap_frame, sizeof(irlap_frame) );
+
+  irlap_frame.a = raw_frame -> buf[IRLAP_A_OFF];
+  irlap_frame.c = raw_frame -> buf[IRLAP_C_OFF];
+  irlap_frame.fcs  = raw_frame -> buf [(raw_frame -> length) -2] << 8;
+  irlap_frame.fcs |= raw_frame -> buf [(raw_frame -> length) -1];
+  
+  irlap_frame.info_length = raw_frame -> length - 
+    IRLAP_A_LENGTH - IRLAP_C_LENGTH - IRLAP_FCS_LENGTH;
+
+  info_ptr = g_malloc ( irlap_frame.info_length * sizeof (BYTE) );
+  memcpy ( info_ptr, &(raw_frame -> buf[IRLAP_I_OFF]),
+          irlap_frame.info_length);
+  irlap_frame.info = info_ptr;
+  decode_irlap_frame ( &irlap_frame );
+  g_free(info_ptr);
+  
+  printf ("IrLAP: FCS: %04X \n\n", irlap_frame.fcs );
+
+}
+
+/*
+ * cleanup_termios
+ * ---------------
+ * - call on some signals from signalhandler
+ * - before end set the original setting
+ */
+void cleanup_termios ( int signal )
+{
+  tcsetattr(port_fd, TCSANOW, &old_port_sets);
+  exit (0);
+}
+
+/*
+ * init_port
+ * ---------
+ * - get original port-settings and store it
+ * - set new port-settings
+ */
+void init_port ( void ) 
+{
+  struct termios new_port_sets;
+  
+  /* get the original settings and store it for restore */
+  tcgetattr( port_fd, &old_port_sets);
+
+  /* init new settings */
+  bzero(&new_port_sets, sizeof(new_port_sets));
+  new_port_sets.c_cflag = INIT_BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
+  new_port_sets.c_iflag = IGNBRK | IGNPAR;
+  new_port_sets.c_oflag = 0;
+
+  /* set input mode (non-canonical, no echo,...) */
+  new_port_sets.c_lflag = 0;
+        
+  /* inter-character timer unused x0.1s */
+  new_port_sets.c_cc[VTIME]    = 0;
+  /* blocking read until 5 chars received */
+  new_port_sets.c_cc[VMIN]     = 1;
+
+  /* set the port now */
+  tcflush(port_fd, TCIFLUSH);
+  tcsetattr(port_fd, TCSANOW, &new_port_sets);
+}
+
+/*
+ * main
+ * ----
+ * - output-file and port open
+ * - get/set port settings
+ * - dataread-loop
+ */
+int main( int argc, char * argv[] )
+{
+  struct sigaction sact;                                /* signalhandle    */
+  GString *outfile_name = g_string_new(DEFAULT_OUTFILE); /* outfile name    */
+  FILE *outfile;                                        /* outfile FILE    */
+  fd_set ready;                                          /* for select      */
+  struct timeval timeout;                               /* select-timeout  */
+  int no_timeout        = 1;                            /* timeout reached */
+  int nr_read           = 0;                            /* byte readed     */
+  unsigned char in_buffer[255];                                 /* temp. buffer    */
+  RAW_FRAME raw_frame;                                  /* a raw frame     */
+  int is_inframe        = FALSE;                         /* loop in frame   */
+  int frame_complete    = FALSE;                         /* frame complete  */
+  int done              = 0;                            /* loop control    */
+  int i                 = 0;                            /* for-index       */
+  int nr_of_bytes       = 0;                            /* total bytes     */
+  int nr_of_frames      = 0;                            /* total frames    */
+  int irlap_bytes       = 0;                             /* w/o BOF etc.    */
+  BYTE must_escaped     = FALSE;                         /* after CE = 0x07 */
+  U16 fcsrx             = INIT_FCS;                      /* for fcs-comput. */
+  BYTE nr_esc           = 0;                            /* nr of CE's      */
+//CONNECT_STATISTIC statistic;                           /* statistic       */
+//OUTPUT_PARAMS output_params;                           /* output-control  */
+
+  /*
+   * Open the serial device
+   */
+  if ( (port_fd = open( MODEMDEVICE, O_NONBLOCK | O_RDWR)) < 0 ) {
+    printf ( "Failed to open %s!\n", MODEMDEVICE);
+    exit(1);
+  }
+
+  /*
+   * get/set device fd flags
+   */
+  if ( (initfdflags = fcntl( port_fd, F_GETFL)) == -1 ) {
+    printf ( "Couldn't get device fd flags for: %s!", MODEMDEVICE);
+    exit(1);
+  }
+  initfdflags &= ~O_NONBLOCK;
+  fcntl( port_fd, F_SETFL, initfdflags);
+
+  init_port();
+
+  /*
+   * set signal-handler
+   */
+  sact.sa_handler = cleanup_termios;
+  sigaction( SIGHUP,  &sact, NULL);
+  sigaction( SIGINT,  &sact, NULL);
+  sigaction( SIGPIPE, &sact, NULL);
+  sigaction( SIGTERM, &sact, NULL);
+  
+  /*
+   *  Set device for non-blocking reads.
+   */
+  if ( fcntl( port_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
+    printf ("Couldn't set device to non-blocking mode (%s)!\n", MODEMDEVICE);
+    exit(1);
+  }
+  
+  /*
+   * output-file-handling
+   */
+  if ( argc < 2 ) {
+    printf ("Use default OutPutFile: %s\n", outfile_name -> str);
+  } else {
+    g_string_assign(outfile_name, argv[1]);
+    g_string_append(outfile_name, OUTFILE_SUFFIX);
+    printf ("Use OutPutFile: %s\n", outfile_name -> str);
+  }
+  if ( (outfile = fopen( outfile_name -> str, "wb")) == NULL ) {
+    printf ("Failed to open OutPutFile: %s\n", outfile_name -> str);
+    exit (1);
+  }
+
+  /*
+   * initial timeout
+   * ---------------
+   * - wait 15 seconds
+   */
+  timeout.tv_sec  = INITIAL_TIMEOUT;
+  timeout.tv_usec =  0;
+  
+  /*
+   * init raw-frame, negotation-struct, connection
+   */
+  bzero(&raw_frame, sizeof(raw_frame));
+  bzero(&negotation_param, sizeof(negotation_param));
+  bzero(&connection, sizeof(connection));
+
+  /* hope we have no irda traffic in moment */
+  connection.irlap_state = IRLAP_DISC;
+  
+  /*
+   * now make the data-read-loop
+   */
+  do {
+    FD_ZERO(&ready);
+    FD_SET(port_fd, &ready);
+    no_timeout = select(port_fd + 1, &ready, NULL, NULL, &timeout);
+    if ( FD_ISSET(port_fd, &ready) ) {
+      /* data on port - returns after 16 chars have been input */
+      nr_read = read(port_fd, in_buffer, 16);
+      nr_of_bytes = nr_of_bytes + nr_read;
+      if ( nr_read >= 1 ) {
+       /* write all readed bytes to file */
+       fwrite( in_buffer, 1, nr_read, outfile);
+       /* process every single byte */
+       for (i=0; i < nr_read; i++) {
+         if (raw_frame.length < (4096-1) ) {
+           switch ( in_buffer[i] ) {
+           case IRLAP_XBOF:
+             if ( is_inframe ) {
+               /*
+                * no - its not a XBOF we are inside a frame 
+                * broadcast in xid for example
+                */
+               irlap_bytes++;
+               fcsrx = IR_FCS(fcsrx, in_buffer[i]);
+               is_inframe = TRUE;
+               raw_frame.buf[raw_frame.length] = in_buffer[i];
+             }
+             break;
+           case IRLAP_BOF:
+             is_inframe = TRUE;
+             break;
+           case IRLAP_EOF:
+             frame_complete = TRUE;
+             is_inframe = FALSE;
+             break;
+           case IRLAP_CE:
+             must_escaped = TRUE;
+             is_inframe = TRUE;
+             nr_esc++;
+             break;
+           default:
+             is_inframe = TRUE;
+             if ( must_escaped ) {
+               fcsrx = IR_FCS(fcsrx, (in_buffer[i] ^ IRLAP_ESC_MASK) );
+               raw_frame.buf[raw_frame.length] = 
+                 (in_buffer[i]^IRLAP_ESC_MASK);
+               must_escaped = FALSE;
+             } else {
+               fcsrx = IR_FCS(fcsrx, in_buffer[i]);
+               raw_frame.buf[raw_frame.length] = in_buffer[i];
+             }
+             irlap_bytes++;
+           }
+           raw_frame.length = irlap_bytes;
+           if ( frame_complete ) {
+             /* now raw-frame is complete */
+             if ( fcsrx != GOOD_FCS ) {
+               printf (" **** !!! FCS-ERROR !!! ****\n");
+             } else {
+               unwrap_raw_frame ( &raw_frame );
+             }
+             nr_of_frames++;
+             /* reset all to defaults     */
+             raw_frame.length   = 0;
+             raw_frame.a_offset = 0;
+             frame_complete     = FALSE;
+             fcsrx              = INIT_FCS;
+             nr_esc             = 0;
+             irlap_bytes        = 0;
+           }
+         }
+       }
+      } else {
+       printf ("No data to read - why?\n");
+       done = 1;
+      }
+    }
+    /*
+     * reset timeout - wait 5 seconds
+     */
+    timeout.tv_sec  = DEFAULT_TIMEOUT;
+    timeout.tv_usec = 0;
+    if ( ! no_timeout ) {
+      printf ("TimeOut!\nConnection summary:\n-------------------\n");
+      printf ("Total nr of received bytes : %i\n", nr_of_bytes);
+      printf ("Total nr of received frames: %i\n", nr_of_frames);
+      done = 1;
+    }
+  } while ( ! done );
+
+  g_string_free(outfile_name, TRUE);
+  fclose (outfile);
+  tcsetattr(port_fd, TCSANOW, &old_port_sets);
+  exit(0);
+}