From fb64e64ae2062e348ad321ec0d686b09310ad09f Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Tue, 24 Mar 2015 14:44:44 +0100 Subject: [PATCH] Java code to let Cooja connect to a serial port --- tools/wpcapslip/Connect.java | 193 ++++++++++ tools/wpcapslip/ConnectSocket.java | 115 ++++++ tools/wpcapslip/Makefile | 13 +- tools/wpcapslip/net/tcpdump.h | 40 ++ tools/wpcapslip/tcpdump.c | 289 ++++++++++++++ tools/wpcapslip/wpcap.c | 91 +++-- tools/wpcapslip/wpcapslip.c | 19 +- tools/wpcapslip/wpcapstdio.c | 597 +++++++++++++++++++++++++++++ 8 files changed, 1309 insertions(+), 48 deletions(-) create mode 100644 tools/wpcapslip/Connect.java create mode 100644 tools/wpcapslip/ConnectSocket.java create mode 100644 tools/wpcapslip/net/tcpdump.h create mode 100644 tools/wpcapslip/tcpdump.c create mode 100644 tools/wpcapslip/wpcapstdio.c diff --git a/tools/wpcapslip/Connect.java b/tools/wpcapslip/Connect.java new file mode 100644 index 000000000..7ec6a0699 --- /dev/null +++ b/tools/wpcapslip/Connect.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; + +public class Connect { + private static Process cmd1Process; + private static Process cmd2Process; + private static BufferedOutputStream cmd1Out = null; + private static BufferedOutputStream cmd2Out = null; + + private static final int BUFSIZE = 512; + + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.err.println("Usage: " + Connect.class.getName() + " [cmd1] [cmd2]"); + System.exit(1); + } + + /* Command 1 */ + String cmd1 = args[0]; + System.out.println("> " + cmd1); + cmd1Process = Runtime.getRuntime().exec(cmd1, null, new File(".")); + final DataInputStream cmd1Input = new DataInputStream( + cmd1Process.getInputStream()); + final BufferedReader cmd1Err = new BufferedReader( + new InputStreamReader(cmd1Process.getErrorStream())); + cmd1Out = new BufferedOutputStream(cmd1Process.getOutputStream()); + Thread readInput = new Thread(new Runnable() { + + public void run() { + int numRead = 0; + byte[] buf = new byte[BUFSIZE]; + try { + while (true) { + numRead = cmd1Input.read(buf, 0, BUFSIZE); + if (numRead > 0 && cmd2Out != null) { + /* System.err.println("1>2 " + numRead); */ + cmd2Out.write(buf, 0, numRead); + cmd2Out.flush(); + } + Thread.sleep(1); + } + } catch (Exception e) { + e.printStackTrace(); + } + String exitVal = "?"; + try { + if (cmd1Process != null) { + exitVal = "" + cmd1Process.exitValue(); + } + } catch (IllegalStateException e) { + e.printStackTrace(); + exitVal = "!"; + } + System.out.println("cmd1 terminated: " + exitVal); + exit(); + } + }, "read stdout cmd1"); + Thread readError = new Thread(new Runnable() { + public void run() { + String line; + try { + while ((line = cmd1Err.readLine()) != null) { + System.err.println("cmd1 err: " + line); + } + cmd1Err.close(); + } catch (IOException e) { + } + System.err.println("cmd1 terminated."); + exit(); + } + }, "read error cmd1"); + readInput.start(); + readError.start(); + + /* Command 2 */ + String cmd2 = args[1]; + System.err.println("> " + cmd2); + cmd2Process = Runtime.getRuntime().exec(cmd2, null, new File(".")); + final DataInputStream cmd2Input = new DataInputStream( + cmd2Process.getInputStream()); + final BufferedReader cmd2Err = new BufferedReader( + new InputStreamReader(cmd2Process.getErrorStream())); + cmd2Out = new BufferedOutputStream(cmd2Process.getOutputStream()); + readInput = new Thread(new Runnable() { + public void run() { + int numRead = 0; + byte[] buf = new byte[BUFSIZE]; + try { + while (true) { + numRead = cmd2Input.read(buf, 0, BUFSIZE); + if (numRead > 0 && cmd1Out != null) { + /* System.err.println("2>1 " + numRead); */ + cmd1Out.write(buf, 0, numRead); + cmd1Out.flush(); + } + Thread.sleep(1); + } + } catch (Exception e) { + e.printStackTrace(); + } + String exitVal = "?"; + try { + if (cmd2Process != null) { + exitVal = "" + cmd2Process.exitValue(); + } + } catch (IllegalStateException e) { + e.printStackTrace(); + exitVal = "!"; + } + System.out.println("cmd2 terminated: " + exitVal); + exit(); + } + }, "read stdout cmd2"); + readError = new Thread(new Runnable() { + public void run() { + String line; + try { + while ((line = cmd2Err.readLine()) != null) { + System.err.println("cmd2 err: " + line); + } + cmd2Err.close(); + } catch (IOException e) { + } + System.err.println("cmd2 terminated."); + exit(); + } + }, "read error cmd2"); + readInput.start(); + readError.start(); + + while (true) { + Thread.sleep(100); + } + } + + private static void exit() { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + try { + if (cmd1Process != null) { + cmd1Process.destroy(); + } + } catch (Exception e) { + } + try { + if (cmd2Process != null) { + cmd2Process.destroy(); + } + } catch (Exception e) { + } + System.err.flush(); + System.exit(1); + } + +} diff --git a/tools/wpcapslip/ConnectSocket.java b/tools/wpcapslip/ConnectSocket.java new file mode 100644 index 000000000..417ebac1d --- /dev/null +++ b/tools/wpcapslip/ConnectSocket.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2013, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.net.Socket; + +public class ConnectSocket { + private static BufferedOutputStream stdoutOutput = null; + private static BufferedOutputStream networkServerOutput = null; + + private static final int BUFSIZE = 512; + + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.err.println("Usage: " + ConnectSocket.class.getName() + " [server ip] [server port]"); + System.exit(1); + } + + /* Stdin */ + final BufferedInputStream stdinInput = new BufferedInputStream(new DataInputStream(System.in)); + stdoutOutput = new BufferedOutputStream(System.out); + Thread readInput = new Thread(new Runnable() { + public void run() { + int numRead = 0; + byte[] buf = new byte[BUFSIZE]; + try { + while (true) { + numRead = stdinInput.read(buf, 0, BUFSIZE); + if (numRead > 0 && networkServerOutput != null) { + /* System.err.println("1>2 " + numRead); */ + + networkServerOutput.write(buf, 0, numRead); + networkServerOutput.flush(); + } + Thread.sleep(1); + } + } catch (Exception e) { + e.printStackTrace(); + } + exit(); + } + }, "read stdin"); + readInput.start(); + + /* Network server */ + Socket networkServer = new Socket(args[0], Integer.parseInt(args[1])); + final BufferedInputStream networkServerInput = new BufferedInputStream(new DataInputStream(networkServer.getInputStream())); + networkServerOutput = new BufferedOutputStream(networkServer.getOutputStream()); + readInput = new Thread(new Runnable() { + public void run() { + int numRead = 0; + byte[] buf = new byte[BUFSIZE]; + try { + while (true) { + numRead = networkServerInput.read(buf, 0, BUFSIZE); + if (numRead > 0 && stdoutOutput != null) { + /* System.err.println("2>1 " + numRead); */ + stdoutOutput.write(buf, 0, numRead); + stdoutOutput.flush(); + } + Thread.sleep(1); + } + } catch (Exception e) { + e.printStackTrace(); + } + exit(); + } + }, "read network server"); + readInput.start(); + + while (true) { + Thread.sleep(100); + } + } + + private static void exit() { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + System.err.flush(); + System.exit(1); + } +} diff --git a/tools/wpcapslip/Makefile b/tools/wpcapslip/Makefile index 1ab2caff2..fb11826eb 100644 --- a/tools/wpcapslip/Makefile +++ b/tools/wpcapslip/Makefile @@ -1,12 +1,21 @@ CONTIKI=../.. -CFLAGS=-Wall -Werror -I$(CONTIKI)/core -I. +CC=gcc +CFLAGS=-Wall -I$(CONTIKI)/core -I. -all: wpcapslip +all: wpcapslip wpcapstdio Connect.class ConnectSocket.class +%.class: %.java + javac $*.java + vpath %.c $(CONTIKI)/core/net wpcapslip: wpcapslip.o wpcap.o tcpdump.o +wpcapstdio: wpcapstdio.o wpcap.o tcpdump.o + %: %.o $(CC) $(LDFLAGS) $^ /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a -o $@ + +clean: + rm -f *.class *.exe *.o \ No newline at end of file diff --git a/tools/wpcapslip/net/tcpdump.h b/tools/wpcapslip/net/tcpdump.h new file mode 100644 index 000000000..bfa9fdd3e --- /dev/null +++ b/tools/wpcapslip/net/tcpdump.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ +#ifndef __TCPDUMP_H__ +#define __TCPDUMP_H__ + +#include "net/ip/uip.h" + +int tcpdump_format(uint8_t *packet, uint16_t packetlen, + char *printbuf, uint16_t printbuflen); + +#endif /* __TCPDUMP_H__ */ diff --git a/tools/wpcapslip/tcpdump.c b/tools/wpcapslip/tcpdump.c new file mode 100644 index 000000000..6883cfec3 --- /dev/null +++ b/tools/wpcapslip/tcpdump.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include "contiki-net.h" + +#include +#include + + struct ip_hdr { + /* IP header. */ + uint8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16_t ipchksum; + uint8_t srcipaddr[4], + destipaddr[4]; + }; + +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_PSH 0x08 +#define TCP_ACK 0x10 +#define TCP_URG 0x20 +#define TCP_CTL 0x3f + +struct tcpip_hdr { + /* IP header. */ + uint8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16_t ipchksum; + uint8_t srcipaddr[4], + destipaddr[4]; + /* TCP header. */ + uint16_t srcport, + destport; + uint8_t seqno[4], + ackno[4], + tcpoffset, + flags, + wnd[2]; + uint16_t tcpchksum; + uint8_t urgp[2]; + uint8_t optdata[4]; +}; + +#define ICMP_ECHO_REPLY 0 +#define ICMP_ECHO 8 + +struct icmpip_hdr { + /* IP header. */ + uint8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16_t ipchksum; + uint8_t srcipaddr[4], + destipaddr[4]; + /* The ICMP and IP headers. */ + /* ICMP (echo) header. */ + uint8_t type, icode; + uint16_t icmpchksum; + uint16_t id, seqno; +}; + + +/* The UDP and IP headers. */ +struct udpip_hdr { + /* IP header. */ + uint8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16_t ipchksum; + uint8_t srcipaddr[4], + destipaddr[4]; + + /* UDP header. */ + uint16_t srcport, + destport; + uint16_t udplen; + uint16_t udpchksum; +}; + +#define ETHBUF ((struct eth_hdr *)&packet[0]) +#define IPBUF ((struct ip_hdr *)&packet[0]) +#define UDPBUF ((struct udpip_hdr *)&packet[0]) +#define ICMPBUF ((struct icmpip_hdr *)&packet[0]) +#define TCPBUF ((struct tcpip_hdr *)&packet[0]) + + +/*---------------------------------------------------------------------------*/ +static void +tcpflags(unsigned char flags, char *flagsstr) +{ + if(flags & TCP_FIN) { + *flagsstr++ = 'F'; + } + if(flags & TCP_SYN) { + *flagsstr++ = 'S'; + } + if(flags & TCP_RST) { + *flagsstr++ = 'R'; + } + if(flags & TCP_ACK) { + *flagsstr++ = 'A'; + } + if(flags & TCP_URG) { + *flagsstr++ = 'U'; + } + + *flagsstr = 0; +} +/*---------------------------------------------------------------------------*/ +static char * CC_FASTCALL +n(uint16_t num, char *ptr) +{ + uint16_t d; + uint8_t a, f; + + if(num == 0) { + *ptr = '0'; + return ptr + 1; + } else { + f = 0; + for(d = 10000; d >= 1; d /= 10) { + a = (num / d) % 10; + if(f == 1 || a > 0) { + *ptr = a + '0'; + ++ptr; + f = 1; + } + } + } + return ptr; +} +/*---------------------------------------------------------------------------*/ +static char * CC_FASTCALL +d(char *ptr) +{ + *ptr = '.'; + return ptr + 1; +} +/*---------------------------------------------------------------------------*/ +static char * CC_FASTCALL +s(char *str, char *ptr) +{ + strcpy(ptr, str); + return ptr + strlen(str); +} +/*---------------------------------------------------------------------------*/ +int +tcpdump_format(uint8_t *packet, uint16_t packetlen, + char *buf, uint16_t buflen) +{ + char flags[8]; + if(IPBUF->proto == UIP_PROTO_ICMP) { + if(ICMPBUF->type == ICMP_ECHO) { + return s(" ping", + n(IPBUF->destipaddr[3], d( + n(IPBUF->destipaddr[2], d( + n(IPBUF->destipaddr[1], d( + n(IPBUF->destipaddr[0], + s(" ", + n(IPBUF->srcipaddr[3], d( + n(IPBUF->srcipaddr[2], d( + n(IPBUF->srcipaddr[1], d( + n(IPBUF->srcipaddr[0], + buf)))))))))))))))) - buf; + + /* return sprintf(buf, "%d.%d.%d.%d %d.%d.%d.%d ping", + IPBUF->srcipaddr[0], IPBUF->srcipaddr[1], + IPBUF->srcipaddr[2], IPBUF->srcipaddr[3], + IPBUF->destipaddr[0], IPBUF->destipaddr[1], + IPBUF->destipaddr[2], IPBUF->destipaddr[3]);*/ + } else if(ICMPBUF->type == ICMP_ECHO_REPLY) { + return s(" pong", + n(IPBUF->destipaddr[3], d( + n(IPBUF->destipaddr[2], d( + n(IPBUF->destipaddr[1], d( + n(IPBUF->destipaddr[0], + s(" ", + n(IPBUF->srcipaddr[3], d( + n(IPBUF->srcipaddr[2], d( + n(IPBUF->srcipaddr[1], d( + n(IPBUF->srcipaddr[0], + buf)))))))))))))))) - buf; + /* return sprintf(buf, "%d.%d.%d.%d %d.%d.%d.%d pong", + IPBUF->srcipaddr[0], IPBUF->srcipaddr[1], + IPBUF->srcipaddr[2], IPBUF->srcipaddr[3], + IPBUF->destipaddr[0], IPBUF->destipaddr[1], + IPBUF->destipaddr[2], IPBUF->destipaddr[3]);*/ + } + } else if(IPBUF->proto == UIP_PROTO_UDP) { + return s(" UDP", + n(uip_htons(UDPBUF->destport), d( + n(IPBUF->destipaddr[3], d( + n(IPBUF->destipaddr[2], d( + n(IPBUF->destipaddr[1], d( + n(IPBUF->destipaddr[0], + s(" ", + n(uip_htons(UDPBUF->srcport), d( + n(IPBUF->srcipaddr[3], d( + n(IPBUF->srcipaddr[2], d( + n(IPBUF->srcipaddr[1], d( + n(IPBUF->srcipaddr[0], + buf)))))))))))))))))))) - buf; + /* return sprintf(buf, "%d.%d.%d.%d.%d %d.%d.%d.%d.%d UDP", + IPBUF->srcipaddr[0], IPBUF->srcipaddr[1], + IPBUF->srcipaddr[2], IPBUF->srcipaddr[3], + uip_htons(UDPBUF->srcport), + IPBUF->destipaddr[0], IPBUF->destipaddr[1], + IPBUF->destipaddr[2], IPBUF->destipaddr[3], + uip_htons(UDPBUF->destport));*/ + } else if(IPBUF->proto == UIP_PROTO_TCP) { + tcpflags(TCPBUF->flags, flags); + return s(flags, + s(" ", + n(uip_htons(TCPBUF->destport), d( + n(IPBUF->destipaddr[3], d( + n(IPBUF->destipaddr[2], d( + n(IPBUF->destipaddr[1], d( + n(IPBUF->destipaddr[0], + s(" ", + n(uip_htons(TCPBUF->srcport), d( + n(IPBUF->srcipaddr[3], d( + n(IPBUF->srcipaddr[2], d( + n(IPBUF->srcipaddr[1], d( + n(IPBUF->srcipaddr[0], + buf))))))))))))))))))))) - buf; + /* return sprintf(buf, "%d.%d.%d.%d.%d %d.%d.%d.%d.%d %s", + IPBUF->srcipaddr[0], IPBUF->srcipaddr[1], + IPBUF->srcipaddr[2], IPBUF->srcipaddr[3], + uip_htons(TCPBUF->srcport), + IPBUF->destipaddr[0], IPBUF->destipaddr[1], + IPBUF->destipaddr[2], IPBUF->destipaddr[3], + uip_htons(TCPBUF->destport), + flags); */ + } else { + strcpy(buf, "Unrecognized protocol"); + } + + return 0; +} +/*---------------------------------------------------------------------------*/ diff --git a/tools/wpcapslip/wpcap.c b/tools/wpcapslip/wpcap.c index 5584557a9..b8127d47c 100644 --- a/tools/wpcapslip/wpcap.c +++ b/tools/wpcapslip/wpcap.c @@ -58,7 +58,6 @@ #include #include -#include #include #include #include @@ -69,7 +68,7 @@ #define PROGRESS(x) -static void raw_send(void *buf, int len); +void raw_send(void *buf, int len); struct pcap; @@ -150,7 +149,7 @@ struct arp_entry { struct uip_eth_addr ethaddr; uint8_t time; }; -static struct uip_eth_addr uip_lladdr = {{0,0,0,0,0,0}}; +struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}}; static const uip_ipaddr_t all_zeroes_addr = { { 0x0, /* rest is 0 */ } }; static const struct uip_eth_addr broadcast_ethaddr = {{0xff,0xff,0xff,0xff,0xff,0xff}}; @@ -164,18 +163,20 @@ static int arptime; static int logging; +uip_lladdr_t uip_lladdr; + static void log_message(char *msg1, char *msg2) { if(logging) { - printf("Log: %s %s\n", msg1, msg2); + fprintf(stderr, "Log: %s %s\n", msg1, msg2); } } /*---------------------------------------------------------------------------*/ static void error_exit(char *msg1) { - printf("error_exit: %s", msg1); + fprintf(stderr, "error_exit: %s", msg1); exit(EXIT_FAILURE); } /*---------------------------------------------------------------------------*/ @@ -198,11 +199,11 @@ init_pcap(struct in_addr addr) paddr != NULL; paddr = paddr->next) { if(paddr->addr != NULL && paddr->addr->sa_family == AF_INET) { - + struct in_addr interface_addr; interface_addr = ((struct sockaddr_in *)paddr->addr)->sin_addr; log_message("init_pcap: with address: ", inet_ntoa(interface_addr)); - + if(interface_addr.s_addr == addr.s_addr) { pcap = pcap_open_live(interfaces->name, BUFSIZE, 0, -1, error); if(pcap == NULL) { @@ -263,7 +264,7 @@ set_ethaddr(struct in_addr addr) log_message("set_ethaddr: with address: ", inet_ntoa(adapter_addr)); if(adapter_addr.s_addr == addr.s_addr) { - printf("Using local network interface with address %s\n", + fprintf(stderr, "Using local network interface with address %s\n", inet_ntoa(adapter_addr)); if(adapters->PhysicalAddressLength != 6) { error_exit("ip addr specified on cmdline does not belong to an ethernet card\n"); @@ -292,12 +293,12 @@ print_packet(unsigned char *buf, int len) int i; for(i = 0; i < len; ++i) { - printf("0x%02x, ", buf[i]); + fprintf(stderr, "0x%02x, ", buf[i]); if(i % 8 == 7) { - printf("\n"); + fprintf(stderr, "\n"); } } - printf("\n\n"); + fprintf(stderr, "\n\n"); } /*---------------------------------------------------------------------------*/ static void @@ -305,7 +306,7 @@ uip_arp_update(uip_ipaddr_t *ipaddr, struct uip_eth_addr *ethaddr) { struct arp_entry *tabptr; int i, tmpage, c; - + /* Walk through the ARP mapping table and try to find an entry to update. If none is found, the IP -> MAC address mapping is inserted in the ARP table. */ @@ -318,7 +319,7 @@ uip_arp_update(uip_ipaddr_t *ipaddr, struct uip_eth_addr *ethaddr) /* Check if the source IP address of the incoming packet matches the IP address in this ARP table entry. */ if(uip_ipaddr_cmp(ipaddr, &tabptr->ipaddr)) { - + /* An old entry found, update this and return. */ memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); tabptr->time = arptime; @@ -399,7 +400,7 @@ arp_out(struct ethip_hdr *iphdr, int len) int i; #endif -#if 1 +#if 0 /* Find the destination IP address in the ARP table and construct the Ethernet header. If the destination IP addres isn't on the local network, we use the default router's IP address instead. @@ -425,7 +426,7 @@ arp_out(struct ethip_hdr *iphdr, int len) /* Else, we use the destination IP address. */ uip_ipaddr_copy(&ipaddr, &iphdr->destipaddr); } - + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { tabptr = &arp_table[i]; if(uip_ipaddr_cmp(&ipaddr, &tabptr->ipaddr)) { @@ -439,9 +440,9 @@ arp_out(struct ethip_hdr *iphdr, int len) memset(arphdr->ethhdr.dest.addr, 0xff, 6); memset(arphdr->dhwaddr.addr, 0x00, 6); - memcpy(arphdr->ethhdr.src.addr, uip_lladdr.addr, 6); - memcpy(arphdr->shwaddr.addr, uip_lladdr.addr, 6); - + memcpy(arphdr->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(arphdr->shwaddr.addr, uip_ethaddr.addr, 6); + uip_ipaddr_copy(&arphdr->dipaddr, &ipaddr); uip_ipaddr_copy(&arphdr->sipaddr, &netaddr); arphdr->opcode = UIP_HTONS(ARP_REQUEST); /* ARP request. */ @@ -476,27 +477,27 @@ do_arp(void *buf, int len) if(hdr->ethhdr.type == UIP_HTONS(UIP_ETHTYPE_ARP)) { if(hdr->opcode == UIP_HTONS(ARP_REQUEST)) { /* Check if the ARP is for our network */ - /* printf("ARP for %d.%d.%d.%d we are %d.%d.%d.%d/%d.%d.%d.%d\n", + /* fprintf(stderr, "ARP for %d.%d.%d.%d we are %d.%d.%d.%d/%d.%d.%d.%d\n", uip_ipaddr_to_quad(&hdr->dipaddr), uip_ipaddr_to_quad(&netaddr), uip_ipaddr_to_quad(&netmask));*/ if(uip_ipaddr_maskcmp(&hdr->dipaddr, &netaddr, &netmask)) { uip_ipaddr_t tmpaddr; - - /* printf("ARP for us.\n");*/ + + /* fprintf(stderr, "ARP for us.\n");*/ uip_arp_update(&hdr->sipaddr, &hdr->shwaddr); - + hdr->opcode = UIP_HTONS(ARP_REPLY); - + memcpy(&hdr->dhwaddr.addr, &hdr->shwaddr.addr, 6); memcpy(&hdr->shwaddr.addr, &uip_lladdr.addr, 6); memcpy(&hdr->ethhdr.src.addr, &uip_lladdr.addr, 6); memcpy(&hdr->ethhdr.dest.addr, &hdr->dhwaddr.addr, 6); - + uip_ipaddr_copy(&tmpaddr, &hdr->dipaddr); uip_ipaddr_copy(&hdr->dipaddr, &hdr->sipaddr); uip_ipaddr_copy(&hdr->sipaddr, &tmpaddr); - + hdr->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_ARP); raw_send(hdr, sizeof(struct arp_hdr)); return NULL; @@ -521,8 +522,8 @@ cleanup(void) char buf[1024]; snprintf(buf, sizeof(buf), "route delete %d.%d.%d.%d", - uip_ipaddr_to_quad(&ifaddr)); - printf("%s\n", buf); + uip_ipaddr_to_quad(&netaddr)); + fprintf(stderr, "%s\n", buf); system(buf); } @@ -540,9 +541,9 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log) struct in_addr addr; char buf[4000]; uint32_t tmpaddr; - + logging = log; - + addr.s_addr = inet_addr(ethcardaddr); tmpaddr = inet_addr(ethcardaddr); memcpy(&ifaddr.u16[0], &tmpaddr, sizeof(tmpaddr)); @@ -551,21 +552,21 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log) tmpaddr = inet_addr(slipnetmask); memcpy(&netmask.u16[0], &tmpaddr, sizeof(tmpaddr)); - printf("Network address %d.%d.%d.%d/%d.%d.%d.%d\n", + fprintf(stderr, "Network address %d.%d.%d.%d/%d.%d.%d.%d\n", uip_ipaddr_to_quad(&netaddr), uip_ipaddr_to_quad(&netmask)); - + snprintf(buf, sizeof(buf), "route add %d.%d.%d.%d mask %d.%d.%d.%d %d.%d.%d.%d", uip_ipaddr_to_quad(&netaddr), uip_ipaddr_to_quad(&netmask), uip_ipaddr_to_quad(&ifaddr)); - printf("%s\n", buf); + fprintf(stderr, "%s\n", buf); system(buf); signal(SIGTERM, remove_route); log_message("wpcap_init: cmdline address: ", inet_ntoa(addr)); - + wpcap = LoadLibrary("wpcap.dll"); pcap_findalldevs = (int (*)(struct pcap_if **, char *)) GetProcAddress(wpcap, "pcap_findalldevs"); @@ -588,12 +589,12 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log) #if 0 while(1) { int ret; - + ret = wpcap_poll(buf); if(ret > 0) { /* print_packet(buf, ret);*/ if(do_arp(buf, ret)) { - printf("IP packet\n"); + fprintf(stderr, "IP packet\n"); } } sleep(1); @@ -602,17 +603,16 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log) } /*---------------------------------------------------------------------------*/ uint16_t -wpcap_poll(char **buf) +wpcap_poll(char **buf, int eth) { struct pcap_pkthdr *packet_header; unsigned char *packet; int len; + int ret; char *buf2; - switch(pcap_next_ex(pcap, &packet_header, &packet)) { - case -1: - error_exit("error on poll\n"); - case 0: + ret = pcap_next_ex(pcap, &packet_header, &packet); + if (ret != 1) { return 0; } @@ -622,13 +622,20 @@ wpcap_poll(char **buf) CopyMemory(*buf, packet, packet_header->caplen); len = packet_header->caplen; - /* printf("len %d\n", len);*/ + + if(eth) { + /* poll requested us to return the raw ethernet packet */ + return len; + } + + buf2 = do_arp(*buf, len); if(buf2 == NULL) { return 0; } else { len = len - (buf2 - *buf); *buf = buf2; + /*fprintf(stderr, "wpcap_poll() %d\n", len);*/ return len; } } @@ -644,7 +651,7 @@ wpcap_send(void *buf, int len) raw_send(buf2, len); } /*---------------------------------------------------------------------------*/ -static void +void raw_send(void *buf, int len) { /* printf("sending len %d\n", len);*/ diff --git a/tools/wpcapslip/wpcapslip.c b/tools/wpcapslip/wpcapslip.c index e6e193f90..b60af7f6a 100644 --- a/tools/wpcapslip/wpcapslip.c +++ b/tools/wpcapslip/wpcapslip.c @@ -47,8 +47,6 @@ #include #include #include -#include -#include #include #include @@ -75,6 +73,18 @@ static int should_print = 0; #define IP_HLEN 20 +/*---------------------------------------------------------------------------*/ +uint16_t +uip_htons(uint16_t val) +{ + return UIP_HTONS(val); +} +/*---------------------------------------------------------------------------*/ +uint32_t +uip_htonl(uint32_t val) +{ + return UIP_HTONL(val); +} /*---------------------------------------------------------------------------*/ static void print_packet(uint8_t *packet, int len) @@ -289,8 +299,9 @@ serial_to_wpcap(FILE *inslip) */ #define DEBUG_LINE_MARKER '\r' int ecode; + ecode = check_ip(&uip.iphdr, inbufptr); - if(ecode < 0 && inbufptr == 8 && strncmp(uip.inbuf, "=IPA", 4) == 0) { + if(ecode < 0 && inbufptr == 8 && strncmp((const char*)uip.inbuf, "=IPA", 4) == 0) { static struct in_addr ipa; inbufptr = 0; @@ -902,7 +913,7 @@ main(int argc, char **argv) if(iphdr->ip_id != last_id) { last_id = iphdr->ip_id; /* printf("------ wpcap_poll ret %d\n", ret);*/ - print_packet(pbuf, ret); + print_packet((uint8_t*)pbuf, ret); write_to_serial(slipfd, pbuf, ret); slip_flushbuf(slipfd); sigalarm_reset(); diff --git a/tools/wpcapslip/wpcapstdio.c b/tools/wpcapslip/wpcapstdio.c new file mode 100644 index 000000000..88f1eace4 --- /dev/null +++ b/tools/wpcapslip/wpcapstdio.c @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2012, Thingsquare, www.thingsquare.com. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * Author: Fredrik Osterlind + * Based on wpcapslip.c by : Oliver Schmidt + */ + +/* This is a stripped-down version of wpcapslip: Instead of reading from and writing + * to a serial port, this program just reads and writes to stdin/stdout. To + * achieve the same functionality as wpcapslip, this program can hence be connected + * to serialdump. But, in contrast to wpcapslip, this program can easily be connected + * to networked or simulated serial ports. -- Fredrik, 2012 */ + +#include +#include +#include +#ifdef __CYGWIN__ +#include +#else /* __CYGWIN__ */ +#include +#endif /* __CYGWIN__ */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define PROGRESS(x) + +void wpcap_start(char *ethifaddr, char *netaddr, char *netmask, int logging); + +void wpcap_send(void *buf, int len); +void raw_send(void *buf, int len); + +uint16_t wpcap_poll(char **buf, int eth); + +#include "net/tcpdump.h" +static int should_print = 0; + +static int send_eth = 0; /* Sends ethernet frames or IP packets */ + +#define IP_HLEN 20 + +/*---------------------------------------------------------------------------*/ +uint16_t +uip_htons(uint16_t val) +{ + return UIP_HTONS(val); +} +/*---------------------------------------------------------------------------*/ +uint32_t +uip_htonl(uint32_t val) +{ + return UIP_HTONL(val); +} +/*---------------------------------------------------------------------------*/ +static void +print_packet(char* prefix, uint8_t *packet, int len) +{ + char buf[2000]; + if(should_print) { + tcpdump_format(packet, len, buf, sizeof(buf)); + fprintf(stderr, "%s: %s\n", prefix, buf); + } +} +/*---------------------------------------------------------------------------*/ +void cleanup(void); +/*---------------------------------------------------------------------------*/ +void +sigcleanup(int signo) +{ + fprintf(stderr, "signal %d\n", signo); + exit(0); /* exit(0) will call cleanup() */ +} +/*---------------------------------------------------------------------------*/ +#define SLIP_END 0300 +#define SLIP_ESC 0333 +#define SLIP_ESC_END 0334 +#define SLIP_ESC_ESC 0335 + +struct ip { + u_int8_t ip_vhl; /* version and header length */ +#define IP_V4 0x40 +#define IP_V 0xf0 +#define IP_HL 0x0f + u_int8_t ip_tos; /* type of service */ + u_int16_t ip_len; /* total length */ + u_int16_t ip_id; /* identification */ + u_int16_t ip_off; /* fragment offset field */ +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_int8_t ip_ttl; /* time to live */ + u_int8_t ip_p; /* protocol */ + u_int16_t ip_sum; /* checksum */ + u_int32_t ip_src, ip_dst; /* source and dest address */ + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + u_int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ +}; + +static int ip_id, last_id; + +int +ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); + +int +ssystem(const char *fmt, ...) +{ + char cmd[128]; + va_list ap; + va_start(ap, fmt); + vsnprintf(cmd, sizeof(cmd), fmt, ap); + va_end(ap); + fprintf(stderr, "%s\n", cmd); + fflush(stderr); + return system(cmd); +} +/*---------------------------------------------------------------------------*/ +int +is_sensible_string(const unsigned char *s, int len) +{ + int i; + for(i = 1; i < len; i++) { + if(s[i] == 0 || s[i] == '\r' || s[i] == '\n' || s[i] == '\t') { + continue; + } else if(s[i] < ' ' || '~' < s[i]) { + return 0; + } + } + return 1; +} +/*---------------------------------------------------------------------------*/ +u_int16_t +ip4sum(u_int16_t sum, const void *_p, u_int16_t len) +{ + u_int16_t t; + const u_int8_t *p = _p; + const u_int8_t *end = p + len; + + while(p < (end - 1)) { + t = (p[0] << 8) + p[1]; + sum += t; + if(sum < t) + sum++; + p += 2; + } + if(p < end) { + t = (p[0] << 8) + 0; + sum += t; + if(sum < t) + sum++; + } + return sum; +} +/*---------------------------------------------------------------------------*/ +static uint16_t +chksum(const void *p, uint16_t len) +{ + uint16_t sum = ip4sum(0, p, len); + return (sum == 0) ? 0xffff : uip_htons(sum); +} +/*---------------------------------------------------------------------------*/ +int +check_ip(const struct ip *ip, unsigned ip_len) +{ + u_int16_t sum, ip_hl; + + if(send_eth) { + return 0; + } + + /* Check IP version and length. */ + if((ip->ip_vhl & IP_V) != IP_V4) { + return -1; + } + + if(uip_ntohs(ip->ip_len) > ip_len) { + return -2; + } + + if(uip_ntohs(ip->ip_len) < ip_len) { + return -3; + } + + /* Check IP header. */ + ip_hl = 4 * (ip->ip_vhl & IP_HL); + sum = ip4sum(0, ip, ip_hl); + if(sum != 0xffff && sum != 0x0) { + return -4; + } + + if(ip->ip_p == 6 || ip->ip_p == 17) { /* Check TCP or UDP header. */ + u_int16_t tcp_len = ip_len - ip_hl; + + /* Sum pseudoheader. */ + sum = ip->ip_p + tcp_len; /* proto and len, no carry */ + sum = ip4sum(sum, &ip->ip_src, 8); /* src and dst */ + + /* Sum TCP/UDP header and data. */ + sum = ip4sum(sum, (u_int8_t*)ip + ip_hl, tcp_len); + + /* Failed checksum test? */ + if(sum != 0xffff && sum != 0x0) { + if(ip->ip_p == 6) { /* TCP == 6 */ + return -5; + } else { /* UDP */ + /* Deal with disabled UDP checksums. */ + if(ip->uh_sum != 0) { + return -6; + } + } + } + } else if(ip->ip_p == 1) { /* ICMP */ + u_int16_t icmp_len = ip_len - ip_hl; + + sum = ip4sum(0, (u_int8_t*)ip + ip_hl, icmp_len); + if(sum != 0xffff && sum != 0x0) { + return -7; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/* + * Read a single character from stdin. When we have a full packet, write it to + * the network interface. + */ +void +serial_to_wpcap(void) +{ + static union { + unsigned char inbuf[2000]; + struct ip iphdr; + } uip; + static int inbufptr = 0; + + int ret; + unsigned char c; + + if(inbufptr >= sizeof(uip.inbuf)) { + inbufptr = 0; + return; + } + ret = read(STDIN_FILENO, &c, 1); + + if(ret <= 0) { + err(1, "serial_to_wpcap: read"); + inbufptr = 0; + return; + } + + switch (c) { + case SLIP_END: + if(inbufptr > 0) { + /* + * Sanity checks. + */ +#define DEBUG_LINE_MARKER '\r' + int ecode; + + ecode = check_ip(&uip.iphdr, inbufptr); + if(ecode < 0 && inbufptr == 8 + && strncmp((const char*)uip.inbuf, "=IPA", 4) == 0) { + static struct in_addr ipa; + + inbufptr = 0; + if(memcmp(&ipa, &uip.inbuf[4], sizeof(ipa)) == 0) { + break; + } + + memcpy(&ipa, &uip.inbuf[4], sizeof(ipa)); + break; + } else if(ecode < 0) { + /* + * If sensible ASCII string, print it as debug info! + */ + /* printf("----------------------------------\n");*/ + if(uip.inbuf[0] == DEBUG_LINE_MARKER) { + fwrite(uip.inbuf + 1, inbufptr - 1, 1, stderr); + } else if(is_sensible_string(uip.inbuf, inbufptr)) { + fwrite(uip.inbuf, inbufptr, 1, stderr); + } else { + fprintf(stderr, "serial_to_wpcap: drop packet len=%d ecode=%d\n", + inbufptr, ecode); + } + inbufptr = 0; + break; + } + PROGRESS("s"); + + if(send_eth) { + raw_send(uip.inbuf, inbufptr); + } else { + /* printf("Sending to wpcap\n");*/ + if(uip.iphdr.ip_id != last_id) { + last_id = uip.iphdr.ip_id; + print_packet("to wpcap: ", uip.inbuf, inbufptr); + wpcap_send(uip.inbuf, inbufptr); + } else { + /*print_packet("IGNORED to wpcap: ", uip.inbuf, inbufptr);*/ + } + } + /* printf("After sending to wpcap\n");*/ + inbufptr = 0; + } + break; + + case SLIP_ESC: + /* TODO We do not actually check that we have another byte incoming, so + * we may block here */ + read(STDIN_FILENO, &c, 1); + + switch (c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; + break; + } + + /* FALLTHROUGH */ + default: + uip.inbuf[inbufptr++] = c; + break; + } +} +/*---------------------------------------------------------------------------*/ +unsigned char stdout_buf[2000]; +int stdout_buf_cnt; +/*---------------------------------------------------------------------------*/ +void +stdout_write(unsigned char c) +{ + if(stdout_buf_cnt >= sizeof(stdout_buf)) { + err(1, "stdout_write overflow"); + } + stdout_buf[stdout_buf_cnt] = c; + stdout_buf_cnt++; +} +/*---------------------------------------------------------------------------*/ +int +stdout_buf_empty(void) +{ + return stdout_buf_cnt == 0; +} +/*---------------------------------------------------------------------------*/ +void +stdout_flushbuf(void) +{ + if(stdout_buf_empty()) { + return; + } + + fwrite(stdout_buf, stdout_buf_cnt, 1, stdout); + stdout_buf_cnt = 0; + fflush(stdout); +} +/*---------------------------------------------------------------------------*/ +void +write_slip_stdout(void *inbuf, int len) +{ + u_int8_t *p = inbuf; + int i, ecode; + struct ip *iphdr = inbuf; + + if(!send_eth) { + /* + * Sanity checks. + */ + /*fprintf(stderr, "write_slip_stdout: %d\n", len);*/ + ecode = check_ip(inbuf, len); + if(ecode < 0) { + fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode); + return; + } + + if(iphdr->ip_id == 0 && iphdr->ip_off & IP_DF) { + uint16_t nid = uip_htons(ip_id++); + iphdr->ip_id = nid; + nid = ~nid; /* negate */ + iphdr->ip_sum += nid; /* add */ + if(iphdr->ip_sum < nid) { /* 1-complement overflow? */ + iphdr->ip_sum++; + } + ecode = check_ip(inbuf, len); + if(ecode < 0) { + fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode); + return; + } + } + + iphdr->ip_ttl = uip_htons(uip_htons(iphdr->ip_ttl) + 1); + if(iphdr->ip_ttl == 0) { + fprintf(stderr, "Packet with ttl %d dropped\n", iphdr->ip_ttl); + return; + } + iphdr->ip_sum = 0; + iphdr->ip_sum = ~chksum(iphdr, 4 * (iphdr->ip_vhl & IP_HL)); + ecode = check_ip(inbuf, len); + if(ecode < 0) { + fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode); + return; + } + } + + for(i = 0; i < len; i++) { + switch (p[i]) { + case SLIP_END: + stdout_write(SLIP_ESC); + stdout_write(SLIP_ESC_END); + break; + case SLIP_ESC: + stdout_write(SLIP_ESC); + stdout_write(SLIP_ESC_ESC); + break; + default: + stdout_write(p[i]); + break; + } + } + stdout_write(SLIP_END); + /* printf("slip end\n");*/ + PROGRESS("t"); +} +/*---------------------------------------------------------------------------*/ +/*const char *ipaddr;*/ +/*const char *netmask;*/ +static int got_sigalarm; +void +sigalarm(int signo) +{ + got_sigalarm = 1; + return; +} +/*---------------------------------------------------------------------------*/ +void +sigalarm_reset(void) +{ +#ifdef linux +#define TIMEOUT (997*1000) +#else +#define TIMEOUT (2451*1000) +#endif + ualarm(TIMEOUT, TIMEOUT); + got_sigalarm = 0; +} +/*---------------------------------------------------------------------------*/ +int +main(int argc, char **argv) +{ + int c; + int ret; + char buf[4000]; + int logging = 0; + + ip_id = getpid() * time(NULL); + + while((c = getopt(argc, argv, "E:D:hl:t:T")) != -1) { + switch (c) { + case 'E': + send_eth = 1; + break; + + case 'T': + should_print = 1; + break; + + case 'l': + logging = 1; + break; + + case '?': + case 'h': + default: + err(1, + "usage: wpcapstdio [-E] [-l] [-T] "); + break; + } + } + argc -= (optind - 1); + argv += (optind - 1); + + if(argc != 4) { + err(1, "usage: wpcapstdio [-E] [-T] "); + } + + wpcap_start(argv[1], argv[2], argv[3], logging); + stdout_write(SLIP_END); + + atexit(cleanup); + signal(SIGHUP, sigcleanup); + signal(SIGTERM, sigcleanup); + signal(SIGINT, sigcleanup); + signal(SIGALRM, sigalarm); + + while(1) { + if(got_sigalarm) { + /* Send "?IPA". */ + stdout_write('?'); + stdout_write('I'); + stdout_write('P'); + stdout_write('A'); + stdout_write(SLIP_END); + got_sigalarm = 0; + } + + if(stdout_buf_empty()) { + char *pbuf = buf; + + ret = wpcap_poll(&pbuf, send_eth); + if(ret > 0) { + if(send_eth) { + write_slip_stdout(pbuf, ret); + stdout_flushbuf(); + } else { + struct ip *iphdr = (struct ip *)pbuf; + if(iphdr->ip_id != last_id) { + /*last_id = iphdr->ip_id;*/ + print_packet("to stdout: ", (uint8_t*)pbuf, ret); + write_slip_stdout(pbuf, ret); + stdout_flushbuf(); + } else { + /*print_packet("IGNORED to stdout: ", (uint8_t*)pbuf, ret);*/ + } + } + } + } + + if(!stdout_buf_empty()) { + stdout_flushbuf(); + } + + { + fd_set s_rd; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 100; + + do { + FD_ZERO(&s_rd); + FD_SET(fileno(stdin), &s_rd); + select(fileno(stdin) + 1, &s_rd, NULL, NULL, &tv); + if(FD_ISSET(fileno(stdin), &s_rd)) { + serial_to_wpcap(); + } + } while(FD_ISSET(fileno(stdin), &s_rd)); + } + } +} +/*---------------------------------------------------------------------------*/