First commit
[hackover2013-badge-firmware.git] / tools / wsbridge / v0.50 / Linux / main.c
1 /*******************************************************************
2 Copyright (C) 2009 FreakLabs
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. Neither the name of the the copyright holder nor the names of its contributors
15 may be used to endorse or promote products derived from this software
16 without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 SUCH DAMAGE.
29
30 Originally written by Christopher Wang aka Akiba.
31 Please post support questions to the FreakLabs forum.
32
33 *******************************************************************/
34 /*!
35 FreakLabs Freakduino/Wireshark Bridge
36
37 This program allows data from the Freakduino to be piped into wireshark.
38 When the sniffer firmware is loaded into the Freakduino, then the Freakduino
39 will be in promiscuous mode and will just dump any frames it sees. This
40 program takes the frame dump and sends it into Wireshark for analysis. The
41 global header is already set up to inform wireshark that the link layer for
42 all frames will be in IEEE 802.15.4 format. After that, it is up to the user
43 to choose any higher layer protocols to decode above 802.15.4 via the
44 wireshark "enable protocols" menu.
45 */
46 /**************************************************************************/
47 #include <stddef.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <errno.h>
52 #include <time.h>
53 #include <stdint.h>
54 #include <signal.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <fcntl.h>
58 #include <termios.h>
59
60 #define PORTBUFSIZE 32
61 #define BUFSIZE 1024
62 #define PACKET_FCS 2
63 #define DEBUG 1
64 #define PIPENAME "/tmp/wireshark"
65 #define BAUDRATE B115200
66
67 enum FSM
68 {
69 START_CAPTURE,
70 PACKET_CAPTURE
71 };
72
73 static int FD_pipe = -1;
74 static int FD_com = -1;
75 static uint8_t port_buf[PORTBUFSIZE];
76 static uint8_t circ_buf[BUFSIZE];
77 static uint16_t rd_idx = 0;
78 static uint16_t wr_idx = 0;
79 static uint8_t len;
80 static uint8_t state = START_CAPTURE;
81 static uint8_t file_write = 0;
82
83 /**************************************************************************/
84 /*!
85 Open the serial port that we'll be communicating with the Freakduino (sniffer)
86 through.
87 */
88 /**************************************************************************/
89 static int serial_open(char *portname)
90 {
91 int FD_com; // file descriptor for the serial port
92 struct termios term;
93
94 FD_com = open(portname, O_RDONLY | O_NOCTTY | O_NDELAY);
95
96 if(FD_com == -1) // if open is unsucessful
97 {
98 printf("serial_open: Unable to open %s.\n", portname);
99 }
100 else
101 {
102 // set speed of port
103 cfsetspeed(&term, BAUDRATE);
104
105 // set to 8-bits, no parity, 1 stop bit
106 term.c_cflag &= ~PARENB;
107 term.c_cflag &= ~CSTOPB;
108 term.c_cflag &= ~CSIZE;
109 term.c_cflag |= CS8;
110
111 term.c_cflag |= (CLOCAL | CREAD);
112 tcsetattr(FD_com, TCSANOW, &term);
113 }
114 return(FD_com);
115 }
116
117 /**************************************************************************/
118 /*!
119 Create the named pipe that we will be communicating with wireshark through.
120 */
121 /**************************************************************************/
122 static void named_pipe_create(char *name)
123 {
124 int rv = 0;
125 rv = mkfifo(name, 0666);
126 if ((rv == -1) && (errno != EEXIST))
127 {
128 perror("Error creating named pipe");
129 exit(1);
130 }
131
132 FD_pipe = open(name, O_WRONLY);
133
134 if (FD_pipe == -1)
135 {
136 perror("Error connecting to named pipe");
137 exit(1);
138 }
139 }
140
141 /**************************************************************************/
142 /*!
143 Write data to the pipe
144 */
145 /**************************************************************************/
146 size_t data_write(const void *ptr, size_t size)
147 {
148 ssize_t bytes = 0;
149 if (FD_pipe != -1)
150 {
151 bytes = write(FD_pipe, ptr, size);
152 }
153 }
154
155 /**************************************************************************/
156 /*!
157 Write the global header to wireshark. This is only done once at the
158 beginning of the capture.
159 */
160 /**************************************************************************/
161 static void write_global_hdr()
162 {
163 uint32_t magic_number = 0xa1b2c3d4; /* magic number */
164 uint16_t version_major = 2; /* major version number */
165 uint16_t version_minor = 4; /* minor version number */
166 int32_t thiszone = 0; /* GMT to local correction */
167 uint32_t sigfigs = 0; /* accuracy of timestamps */
168 uint32_t snaplen = 65535; /* max length of captured packets, in octets */
169 uint32_t network = 195; /* data link type (DLT) - IEEE 802.15.4 */
170
171 data_write(&magic_number, sizeof(magic_number));
172 data_write(&version_major, sizeof(version_major));
173 data_write(&version_minor, sizeof(version_minor));
174 data_write(&thiszone, sizeof(thiszone));
175 data_write(&sigfigs, sizeof(sigfigs));
176 data_write(&snaplen, sizeof(snaplen));
177 data_write(&network, sizeof(network));
178 }
179
180 /**************************************************************************/
181 /*!
182 Write the frame header into wireshark. This is required for the libpcap
183 format and informs wireshark that a new frame is coming.
184 */
185 /**************************************************************************/
186 static void write_frame_hdr(uint8_t len)
187 {
188 uint32_t ts_sec; /* timestamp seconds */
189 uint32_t ts_usec; /* timestamp microseconds */
190 uint32_t incl_len; /* number of octets of packet saved in file */
191 uint32_t orig_len; /* actual length of packet */
192 struct timeval tv;
193
194 gettimeofday(&tv, NULL);
195 ts_sec = tv.tv_sec;
196 ts_usec = tv.tv_usec;
197 incl_len = len;
198 orig_len = len + PACKET_FCS;
199
200 data_write(&ts_sec, sizeof(ts_sec));
201 data_write(&ts_usec, sizeof(ts_usec));
202 data_write(&incl_len, sizeof(incl_len));
203 data_write(&orig_len, sizeof(orig_len));
204 }
205
206 /**************************************************************************/
207 /*!
208 Write one frame into wireshark (via the pipe).
209 */
210 /**************************************************************************/
211 static void write_frame(uint8_t frame_len)
212 {
213 uint8_t i;
214
215 // actual frame length for wireshark should not include FCS
216 frame_len -= PACKET_FCS;
217
218 // write header to inform WS that new frame has arrived
219 write_frame_hdr(frame_len);
220
221 // bump rd_idx. we don't want to write the length byte
222 rd_idx = (rd_idx + 1) % BUFSIZE;
223
224 // write frame into wireshark
225 for (i=0; i<frame_len; i++)
226 {
227 data_write(&circ_buf[rd_idx], 1);
228 rd_idx = (rd_idx + 1) % BUFSIZE;
229 }
230
231 // bump rd_idx. we're not using the trailing FCS value
232 rd_idx = (rd_idx + 1) % BUFSIZE;
233 }
234
235 /**************************************************************************/
236 /*!
237 Calculate total number of bytes in buffer.
238 */
239 /**************************************************************************/
240 static uint16_t calc_bytes_in_buf()
241 {
242 if (rd_idx > wr_idx)
243 {
244 // read index is greater than write. we must have wrapped around
245 return (BUFSIZE - (rd_idx - wr_idx));
246 }
247 else
248 {
249 return (wr_idx - rd_idx);
250 }
251 }
252
253 /**************************************************************************/
254 /*!
255 Deal with any received signals. This includes ctrl-C to stop the program.
256 */
257 /**************************************************************************/
258 static void sig_int(int signo)
259 {
260 (void) signo;
261 if (FD_pipe != -1)
262 {
263 printf("\nClosing pipe.\n");
264 close(FD_pipe);
265 }
266
267 if (FD_com != -1)
268 {
269 printf("\nClosing serial port.\n");
270 close(FD_com);
271 }
272
273 printf("\nSignal captured and devices shut down.\n");
274
275 exit(0);
276 }
277
278 /**************************************************************************/
279 /*!
280 Init the signals we'll be checking for.
281 */
282 /**************************************************************************/
283 static void signal_init(void)
284 {
285 signal(SIGINT, sig_int);
286 signal(SIGHUP, sig_int);
287 signal(SIGTERM, sig_int);
288 }
289
290 /**************************************************************************/
291 /*!
292 Here's the meat of the code.
293 */
294 /**************************************************************************/
295 int main(int argc, char *argv[])
296 {
297 int nbytes;
298 uint8_t i;
299
300 // capture any signals that will terminate program
301 signal_init();
302
303 // make sure the COM port is specified
304 if (argc == 2)
305 {
306 // open the COM port
307 if ((FD_com = serial_open(argv[1])) == -1)
308 {
309 printf("Serial port not opened.\n");
310 return 0;
311 }
312 else
313 {
314 printf("Serial port connected. Waiting for wireshark connection.\n");
315 printf("Open wireshark and connect to local interface: %s\n", PIPENAME);
316 }
317 }
318 else
319 {
320 printf("Usage: wsbridge <portname>.\n");
321 return 0;
322 }
323
324
325 // create and open pipe for wireshark
326 named_pipe_create(PIPENAME);
327
328 // wait for wireshark to connect to pipe. Once wireshark
329 // connects, then the global header will be written to it.
330 if (FD_pipe != -1)
331 {
332 write_global_hdr();
333 printf("Client connected to pipe.\n");
334 }
335
336 for (;;)
337 {
338 uint16_t bytes_in_buf;
339 uint8_t frame_len, byte_ctr;
340
341 // wait for data to come in on the serial port
342 if ((nbytes = read(FD_com, port_buf, PORTBUFSIZE)) > 0)
343 {
344 // write data to circular buffer. loop through all received bytes
345 for (i=0; i<nbytes; i++)
346 {
347 switch (state)
348 {
349 case START_CAPTURE:
350 // new frame starting
351 len = port_buf[i];
352 byte_ctr = 0;
353
354 printf("Len = %02X.\n", len);
355
356 circ_buf[wr_idx] = len;
357 wr_idx = (wr_idx + 1) % BUFSIZE;
358 state = PACKET_CAPTURE;
359 break;
360
361
362 case PACKET_CAPTURE:
363 // continue capturing bytes until end of frame
364
365 // write data to circular buffer and increment index
366 circ_buf[wr_idx] = port_buf[i];
367
368 printf("%02X ", circ_buf[wr_idx]);
369
370 wr_idx = (wr_idx + 1) % BUFSIZE;
371
372 // track number of received bytes. when received bytes
373 // equals frame length, then restart state machine and
374 // write bytes to wireshark
375 byte_ctr++;
376 if (byte_ctr == (len - 1))
377 {
378 state = START_CAPTURE;
379 file_write = 1;
380 printf("\n");
381 }
382 break;
383 }
384 fflush(stdout);
385 }
386
387 // at least one frame has been written. loop through circular buffer
388 // and write out all completed frames
389 while (file_write)
390 {
391 // capture frame length and check buffer to see if one or more frames
392 // are available.
393 frame_len = circ_buf[rd_idx];
394 bytes_in_buf = calc_bytes_in_buf();
395
396 if (bytes_in_buf > frame_len)
397 {
398 // if more than one frame is available, then write one frame to
399 // wireshark and then see if any more are available.
400 write_frame(frame_len);
401 }
402 else if (bytes_in_buf == frame_len)
403 {
404 // only one frame is available. write to wireshark and then quit
405 // the loop
406 write_frame(frame_len);
407 file_write = 0;
408 }
409 else
410 {
411 // less than one frame is available. quit the loop and collect more
412 // bytes. we normally should not get here.
413 file_write = 0;
414 }
415 }
416 }
417 }
418 }
419
This page took 0.076958 seconds and 5 git commands to generate.