This commit was manufactured by cvs2svn to create branch 'uc'.
[gnokii.git] / Docs / developers / other / sniffs / irda / tools / intercept / irda_intercept.c
1 /*********************************************************************
2  *
3  * Filename:      irda_intercept.c
4  * Version:
5  * Description:   intercept irda-traffic incl. negotation and write
6  *                output to a file
7  * Status:        Experimental.
8  * Author:        Thomas Schneider <nok-trace-men@dev-thomynet.de>
9  * Created at:    
10  * Modified at:   
11  * Modified by:   Thomas Schneider <nok-trace-men@dev-thomynet.de>
12  *
13  *     Copyright (c) 1999 Thomas Schneider, All Rights Reserved.
14  *
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.
19  *
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.
24  *
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.
28  *
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 
33  * DAMAGE.
34  *
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 
40  * MODIFICATIONS.
41  *
42  *         This material is provided "AS-IS" and at no charge.
43  *
44  ********************************************************************/
45 #include <sys/time.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <termios.h>
50 #include <stdio.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <signal.h>
54 #include <glib.h>
55 #include "../include/irda.h"
56 #include "../include/irlap.h"
57 #include "../fcs/fcs.h"
58
59 #define INIT_BAUDRATE B9600
60
61 #define _POSIX_SOURCE 1 /* POSIX compliant source */
62
63 #define INITIAL_TIMEOUT 15
64 #define DEFAULT_TIMEOUT  5
65
66 #define OUTFILE_SUFFIX ".trc"
67 #define DEFAULT_OUTFILE "out"OUTFILE_SUFFIX
68
69 static int initfdflags = -1;         /* Initial file descriptor flags */
70 static struct termios old_port_sets; /* old port-termios for restore  */
71
72 int port_fd;
73
74 NEGOTATION_PARAM negotation_param;
75 CONNECTION connection;
76
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"};
81
82 /*
83  * negotation
84  * ----------
85  * - in negotation set new device speed
86  */
87 void negotation ( IRLAP_FRAME * irlap_frame )
88 {
89    BYTE cmd          = irlap_frame -> a & 0x01;
90    speed_t new_speed = 0;
91    int i             = 0;
92    int m             = 0;
93    struct termios set;
94    BYTE tmp          = 0;
95
96    /* 
97     * snrm-frame
98     * ----------
99     * - 4 src
100     * - 4 dest
101     * - 1 new connection address
102     * - 1 pi
103     * - 1 pl
104     * - [pl] pv
105     * ua-frame
106     * --------
107     * - 4 src
108     * - 4 dest
109     * - 1 pi
110     * - 1 pl
111     * - [pl] pv
112     */
113
114    if ( cmd ) {
115      /*
116       * SNRM - CMD
117       * ----------
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
123       */
124      if ( irlap_frame -> info_length < ( IRLAP_NEG_SNRM_PARAM_OFF +3 ) ) {
125        printf ("\t==> IrLAP: in SNRM-CMD no Info! <==\n");
126      } else {
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] == 
135             IRLAP_NEG_BPS_PI ) {
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;
141          } else {
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];
146          } 
147        } else {
148          printf ("\t==> IrLAP: SNRM-CMD: "
149                  "No baud rate dictate in 1. byte! <==\n");
150        }
151      }
152    } else {
153      /* UA -rsp */
154      negotation_param.baud_rate_client = irlap_frame -> info [10];
155      negotation_param.state = NEG_UA_OK;
156    
157      /* now compute the new speed */
158      tmp = 
159        negotation_param.baud_rate_master & negotation_param.baud_rate_client;
160      if ( tmp & 0x01 ) {
161        new_speed = speed_list[i];
162        m = 0;
163      }
164      for ( i=1; i < 7; i++) {
165        tmp = tmp >> 1;
166        if ( tmp & 0x01 ) {
167          new_speed = speed_list[i];
168          m = i;
169        }
170      }
171      if ( m > 5 ) {
172        /* not defined as B... on my system */
173        printf ("Sorry: Required speed (%s baud) not supported!\n",
174                speed_name[m]);
175      } else {
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");
186        }
187      }
188    }
189 }
190
191 /*
192  * decode_irlap_frame
193  * ------------------
194  * - decode the irlap-c-field
195  */
196 void decode_irlap_frame ( IRLAP_FRAME * irlap_frame) 
197 {
198   BYTE cmd = irlap_frame -> a & 0x01;
199   BYTE poll = irlap_frame -> c & (IRLAP_PF_BIT_MASK);
200   BYTE adr = (irlap_frame -> a) >> 1;
201   
202   switch ( irlap_frame -> c & IRLAP_C_MASK ) {
203   case IRLAP_U_FRAME:
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 */
210       if ( cmd ) {
211         printf ("SNRM cmd\n");
212         switch (connection.irlap_state) {
213         case IRLAP_DISC:
214           printf ("\t==> IrLAP in DISC but SNRM-CMD? <==\n");
215           break;
216         case IRLAP_NDM:
217           printf ("\t==> Start IrLAP - negotation <==\n");
218           negotation ( irlap_frame );
219           break;
220         case IRLAP_NRM:
221           printf ("\t==> IrLAP in NRM but SNRM-CMD? <==\n");
222           break;
223         default:
224           printf ("\t==> IrLAP in not defined state but SNRM-CMD? <==\n");
225         }
226       } else {
227         printf ("RNRM response\n"); 
228       }
229       break;
230     case IRLAP_DISC_RD:
231       /* DISC cmd/RD response */
232       if ( cmd ) {
233         printf ("DISC cmd\n"); 
234       } else {
235         printf ("RD response\n");
236       }
237       break;
238     case IRLAP_UI_UI:
239       /* UI cmd/UI response */
240       if ( cmd ) {
241         printf ("UI cmd\n");
242       } else {
243         printf ("UI response\n");
244       }
245       break;
246     case IRLAP_XID_CMD:
247       /* XID cmd */
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");
253       }
254       break;
255     case IRLAP_TEST_TEST:
256       /* Test cmd/response */
257       if ( cmd ) {
258         printf ("TEST cmd\n");
259       } else {
260         printf ("TEST response\n");
261       }
262       break;
263     case IRLAP_UA_RSP:
264       /* UA response */
265       printf ("UA response\n");
266       switch (connection.irlap_state) {
267       case IRLAP_DISC:
268         printf ("\t==> IrLAP in DISC but UA-RESPONSE? <==\n");
269         break;
270       case IRLAP_NDM:
271         if ( negotation_param.state == NEG_WAIT_FOR_UA ) {
272           printf ("\t==> Continue IrLAP - negotation! <==\n");
273           negotation ( irlap_frame );
274         } else {
275           printf ("\t==> IrLAP in NDM but not wait for  negotation! <==\n");
276         }
277         break;
278       case IRLAP_NRM:
279         printf ("\t==> UA: IrLAP was/is in NRM ... <==\n");
280         break;
281       default:
282         printf ("\t==> IrLAP in not defined state but UA-RESPONSE? <==\n");
283       }
284       break;
285     case IRLAP_FRMR_RSP:
286       /* FRMR response */
287       printf ("FRMR response\n");
288       break;
289     case IRLAP_DM_RSP:
290       /* DM response */
291       printf ("DM response\n");
292       break;
293     case IRLAP_XID_RSP:
294       /* XID response */
295       printf ("XID response\n");
296       break;
297     default:
298       /* unknown cmd/response */
299       printf ("Unknown IrLAP-U-Frame\n");
300     } /* end of irlap-u-frames */
301     break;
302   case IRLAP_S_FRAME:
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) ) {
308     case IRLAP_RR:
309       /* RR command/response */
310       if ( cmd ) {
311         printf ("RR cmd\n");
312       } else {
313         printf ("RR response\n");
314       }
315       break;
316     case IRLAP_RNR:
317       /* RNR cmd/response */
318       printf ("RNR cmd/response\n");
319       break;
320     case IRLAP_REJ:
321       /* REJ cmd/response */
322       printf ("REJ cmd/response\n");
323       break;
324     case IRLAP_SREJ:
325       /* SREJ cmd/response */
326       printf ("SREJ cmd/response\n");
327       break;
328     default:
329       /* unknown cmd/response */
330       printf ("Unknown IrLAP-S-Frame\n");
331     } /* end of irlap-s-frames */
332     break;
333   default:
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");
339   }
340 }
341
342 /* unwrap_raw_frame
343  * ----------------
344  * - put raw-frame-datas in irlap-frame
345  */
346 void unwrap_raw_frame ( RAW_FRAME * raw_frame ) 
347 {
348   IRLAP_FRAME irlap_frame;
349   BYTE * info_ptr;
350   
351   bzero ( &irlap_frame, sizeof(irlap_frame) );
352
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];
357   
358   irlap_frame.info_length = raw_frame -> length - 
359     IRLAP_A_LENGTH - IRLAP_C_LENGTH - IRLAP_FCS_LENGTH;
360
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 );
366   g_free(info_ptr);
367   
368   printf ("IrLAP: FCS: %04X \n\n", irlap_frame.fcs );
369
370 }
371
372 /*
373  * cleanup_termios
374  * ---------------
375  * - call on some signals from signalhandler
376  * - before end set the original setting
377  */
378 void cleanup_termios ( int signal )
379 {
380   tcsetattr(port_fd, TCSANOW, &old_port_sets);
381   exit (0);
382 }
383
384 /*
385  * init_port
386  * ---------
387  * - get original port-settings and store it
388  * - set new port-settings
389  */
390 void init_port ( void ) 
391 {
392   struct termios new_port_sets;
393   
394   /* get the original settings and store it for restore */
395   tcgetattr( port_fd, &old_port_sets);
396
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;
402
403   /* set input mode (non-canonical, no echo,...) */
404   new_port_sets.c_lflag = 0;
405         
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;
410
411   /* set the port now */
412   tcflush(port_fd, TCIFLUSH);
413   tcsetattr(port_fd, TCSANOW, &new_port_sets);
414 }
415
416 /*
417  * main
418  * ----
419  * - output-file and port open
420  * - get/set port settings
421  * - dataread-loop
422  */
423 int main( int argc, char * argv[] )
424 {
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  */
446
447   /*
448    * Open the serial device
449    */
450   if ( (port_fd = open( MODEMDEVICE, O_NONBLOCK | O_RDWR)) < 0 ) {
451     printf ( "Failed to open %s!\n", MODEMDEVICE);
452     exit(1);
453   }
454
455   /*
456    * get/set device fd flags
457    */
458   if ( (initfdflags = fcntl( port_fd, F_GETFL)) == -1 ) {
459     printf ( "Couldn't get device fd flags for: %s!", MODEMDEVICE);
460     exit(1);
461   }
462   initfdflags &= ~O_NONBLOCK;
463   fcntl( port_fd, F_SETFL, initfdflags);
464
465   init_port();
466
467   /*
468    * set signal-handler
469    */
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);
475   
476   /*
477    *  Set device for non-blocking reads.
478    */
479   if ( fcntl( port_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
480     printf ("Couldn't set device to non-blocking mode (%s)!\n", MODEMDEVICE);
481     exit(1);
482   }
483   
484   /*
485    * output-file-handling
486    */
487   if ( argc < 2 ) {
488     printf ("Use default OutPutFile: %s\n", outfile_name -> str);
489   } else {
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);
493   }
494   if ( (outfile = fopen( outfile_name -> str, "wb")) == NULL ) {
495     printf ("Failed to open OutPutFile: %s\n", outfile_name -> str);
496     exit (1);
497   }
498
499   /*
500    * initial timeout
501    * ---------------
502    * - wait 15 seconds
503    */
504   timeout.tv_sec  = INITIAL_TIMEOUT;
505   timeout.tv_usec =  0;
506   
507   /*
508    * init raw-frame, negotation-struct, connection
509    */
510   bzero(&raw_frame, sizeof(raw_frame));
511   bzero(&negotation_param, sizeof(negotation_param));
512   bzero(&connection, sizeof(connection));
513
514   /* hope we have no irda traffic in moment */
515   connection.irlap_state = IRLAP_DISC;
516   
517   /*
518    * now make the data-read-loop
519    */
520   do {
521     FD_ZERO(&ready);
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] ) {
535             case IRLAP_XBOF:
536               if ( is_inframe ) {
537                 /*
538                  * no - its not a XBOF we are inside a frame 
539                  * broadcast in xid for example
540                  */
541                 irlap_bytes++;
542                 fcsrx = IR_FCS(fcsrx, in_buffer[i]);
543                 is_inframe = TRUE;
544                 raw_frame.buf[raw_frame.length] = in_buffer[i];
545               }
546               break;
547             case IRLAP_BOF:
548               is_inframe = TRUE;
549               break;
550             case IRLAP_EOF:
551               frame_complete = TRUE;
552               is_inframe = FALSE;
553               break;
554             case IRLAP_CE:
555               must_escaped = TRUE;
556               is_inframe = TRUE;
557               nr_esc++;
558               break;
559             default:
560               is_inframe = 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;
566               } else {
567                 fcsrx = IR_FCS(fcsrx, in_buffer[i]);
568                 raw_frame.buf[raw_frame.length] = in_buffer[i];
569               }
570               irlap_bytes++;
571             }
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");
577               } else {
578                 unwrap_raw_frame ( &raw_frame );
579               }
580               nr_of_frames++;
581               /* reset all to defaults     */
582               raw_frame.length   = 0;
583               raw_frame.a_offset = 0;
584               frame_complete     = FALSE;
585               fcsrx              = INIT_FCS;
586               nr_esc             = 0;
587               irlap_bytes        = 0;
588             }
589           }
590         }
591       } else {
592         printf ("No data to read - why?\n");
593         done = 1;
594       }
595     }
596     /*
597      * reset timeout - wait 5 seconds
598      */
599     timeout.tv_sec  = DEFAULT_TIMEOUT;
600     timeout.tv_usec = 0;
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);
605       done = 1;
606     }
607   } while ( ! done );
608
609   g_string_free(outfile_name, TRUE);
610   fclose (outfile);
611   tcsetattr(port_fd, TCSANOW, &old_port_sets);
612   exit(0);
613 }