From 8e0bcaee5054cd386eed6215491fba5b83f4bb52 Mon Sep 17 00:00:00 2001 From: salvopitru Date: Mon, 17 Jan 2011 09:16:55 +0000 Subject: [PATCH] Added new options that make wpcapslip6 work also with the rpl-border-router. --- tools/stm32w/wpcapslip6/README.txt | 16 +- tools/stm32w/wpcapslip6/wpcapslip6.c | 504 ++++++++++++++++--------- tools/stm32w/wpcapslip6/wpcapslip6.exe | Bin 40356 -> 43214 bytes 3 files changed, 341 insertions(+), 179 deletions(-) diff --git a/tools/stm32w/wpcapslip6/README.txt b/tools/stm32w/wpcapslip6/README.txt index 4d9eec9c3..7dab62e80 100644 --- a/tools/stm32w/wpcapslip6/README.txt +++ b/tools/stm32w/wpcapslip6/README.txt @@ -1,7 +1,19 @@ This software needs a working network adapter. You can install a Microsoft Loopback adapter. -(Windows XP users: remeber to reboot after the installation procedure). +(remeber to reboot after the installation procedure). In order to install this kind of device in Windows 7, use devcon utility (you can download it from Microsoft website). -> devcon.exe install %windir%\inf\netloop.inf *msloop \ No newline at end of file +> devcon.exe install %windir%\inf\netloop.inf *msloop + + +This utility can be used in conjunction with the uip6-bridge or the rpl-border-router +(the latter on Windows Vista and later only). + + +An example of usage with the RPL border router: +wpcapslip6 -s COMXX -b aaaa:: -a aaaa:1::1/128 02-00-00-00-00-01 + +where 02-00-00-00-00-01 is the MAC address of the local network adapter. +-a aaaa:1::1/128 can be omitted if an IP address is already set +to the network adapter. diff --git a/tools/stm32w/wpcapslip6/wpcapslip6.c b/tools/stm32w/wpcapslip6/wpcapslip6.c index cf2da4717..3b10ac1bc 100644 --- a/tools/stm32w/wpcapslip6/wpcapslip6.c +++ b/tools/stm32w/wpcapslip6/wpcapslip6.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2001, Adam Dunkels. * Copyright (c) 2009, Joakim Eriksson, Niclas Finne. +* Copyright (c) 2011, STMicroelectronics. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +30,7 @@ * * This file is part of the uIP TCP/IP stack. * -* $Id: wpcapslip6.c,v 1.1 2010/10/25 10:42:41 salvopitru Exp $ +* $Id: wpcapslip6.c,v 1.2 2011/01/17 09:16:55 salvopitru Exp $ */ /** @@ -93,21 +94,6 @@ void write_to_serial(void *inbuf, int len); //#define PROGRESS(s) fprintf(stderr, s) #define PROGRESS(s) do { } while (0) -#define USAGE_STRING "usage: wcapslip6 -s siodev [-B baudrate] [-a ipaddress[/prefixlen]|-p 64bit-prefix] [-c channel] [-r] [-v] " -#define HELP_STRING "usage: wcapslip6 -s siodev [-B baudrate] [-a ipaddress[/prefixlen]|-p 64bit-prefix] [-c channel] [-r] [-v] \r\n\n\ -Options:\r\n\ --s siodev\tDevice that identifies the bridge.\r\n\ --B baudrate\tBaudrate of the serial port (default:115200).\r\n\ --a ipaddress/[prefixlen] The address to be assigned to the network\r\n\ -\t\tadapter.\r\n\ --p 64bit-prefix\tAutomatic assignment of the IPv6 address from the specified\r\n\ -\t\tsubnet prefix. It may be followed by the prefix length\r\n\ --c channel\t 802.15.4 radio channel.\r\n\ --r\t\t Set sniffer mode. \r\n\ --v\t\tVerbose. Print more infos.\r\n\ -\tMAC address of the local interface that will\r\n\ -\t\tbe used by wcapslip6.\r\n" - #define REQUEST_MAC_TIMEOUT 3 typedef enum { @@ -115,21 +101,35 @@ typedef enum { true = 1, } bool; -//char tundev[32] = { "tap0" }; -static const char *ipaddr = NULL; +const char *prog; +/* Local adapter IP address. */ +static const char *local_ipaddr = NULL; +/* Attached device's IP address. */ +static char rem_ipaddr[INET6_ADDRSTRLEN]; static char *ipprefix = NULL; -static char autoconf_addr[40] = {0}; +static char autoconf_addr[INET6_ADDRSTRLEN] = {0}; static bool autoconf = false; static bool verbose = false; -static bool tobecleaned = false; -static struct uip_eth_addr eth_addr; +static bool tun = false; +static bool clean_addr = false; +static bool clean_route = false; +static bool clean_neighb = false; +static struct uip_eth_addr adapter_eth_addr; static char * if_name; OSVERSIONINFO osVersionInfo; -static int request_mac = 1; -static int send_mac = 1; -static int set_sniffer_mode = 1; -static int set_channel = 1; +/* Fictitious Ethernet address of the attached device (used in tun mode). */ +#define DEV_MAC_ADDR "02-00-00-00-00-02" +static const struct uip_eth_addr dev_eth_addr = {{0x02,0x00,0x00,0x00,0x00,0x02}}; + + +static bool request_mac = true; +static bool send_mac = true; +static bool set_sniffer_mode = true; +static bool set_channel = true; +static bool send_prefix = false; +/* Network prefix for border router. */ +const char * br_prefix = NULL; static int sniffer_mode = 0; static int channel = 0; @@ -141,6 +141,37 @@ ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); void addAddress(const char * ifname, const char * ipaddr); void delAddress(const char * ifname, const char * ipaddr); +void addLoWPANRoute(const char * ifname, const char * net, const char * gw); +void delLoWPANRoute(const char * ifname, const char * net); +void addNeighbor(const char * ifname, const char * neighb, const char * neighb_mac); +void delNeighbor(const char * ifname, const char * neighb); +int IPAddrFromPrefix(char * ipaddr, const char * ipprefix, const char * mac); + +void print_help() +{ + fprintf(stderr, "usage: %s -s siodev [options] \r\n\n", prog); + fprintf(stderr, "Options:\r\n"); + fprintf(stderr, "-s siodev\tDevice that identifies the bridge or the boder router.\r\n"); + fprintf(stderr, "-B baudrate\tBaudrate of the serial port (default:115200).\r\n"); + fprintf(stderr, " One between:\n"); + fprintf(stderr, " -a ipaddress/[prefixlen] The address to be assigned to the local interface.\r\n"); + fprintf(stderr, "\t\tadapter.\r\n"); + fprintf(stderr, " -p 64bit-prefix Automatic assignment of the IPv6 address from the specified\r\n"); + fprintf(stderr, "\t\tsubnet prefix, based on bridge's MAC address. It may be\r\n"); + fprintf(stderr, "\t\tfollowed by the prefix length.\r\n"); + fprintf(stderr, "\t\tNot allowed in Border Router mode.\r\n"); + fprintf(stderr, "-c channel\t802.15.4 radio channel.\r\n"); + //fprintf(stderr, "-r\t\tSet sniffer mode. \r\n"); + fprintf(stderr, "-t\t\tUse tun interface, i.e., send bare IP packets to device.\r\n"); + fprintf(stderr, "-b 64bit-prefix\tAttached device is an RPL Border Router (-t option forced).\r\n"); + fprintf(stderr, "\t\t64bit-prefix is the prefix the border router has to announce.\r\n"); + fprintf(stderr, "-v\t\tVerbose. Print more info.\r\n"); + fprintf(stderr, "-h\t\tShow this help.\r\n"); + fprintf(stderr, "\r\n\tMAC address of the local interface that will\r\n"); + fprintf(stderr, "\t\tbe used by wcapslip6.\r\n"); + + exit(0); +} int ssystem(const char *fmt, ...) @@ -218,15 +249,16 @@ execProcess(LPDWORD exitCode,const char *fmt, ...) /*static void print_packet(u_int8_t *p, int len) { -int i; -for(i = 0; i < len; i++) { -printf("%02x", p[i]); -if ((i & 3) == 3) -printf(" "); -if ((i & 15) == 15) -printf("\n"); -} -printf("\n"); + int i; + printf("\n"); + for(i = 0; i < len; i++) { + printf("%02x", p[i]); + if ((i & 3) == 3) + printf(" "); + if ((i & 15) == 15) + printf("\n"); + } + printf("\n"); }*/ int @@ -248,31 +280,35 @@ is_sensible_string(const unsigned char *s, int len) * Read from serial, when we have a packet write it to tun. No output * buffering, input buffered by stdio. */ + +#define BUF_SIZE 2000 + void serial_to_wpcap(FILE *inslip) { - static union { - unsigned char inbuf[2000]; - } uip; - static int inbufptr = 0; + unsigned char buf[BUF_SIZE]; - int ret; + static int inbufptr = 0; + int ret; unsigned char c; -#ifdef linux - ret = fread(&c, 1, 1, inslip); - if(ret == -1 || ret == 0) err(1, "serial_to_tun: read"); - goto after_fread; -#endif + unsigned char * inpktbuf; + + if(tun){ + inpktbuf = buf + sizeof(struct uip_eth_hdr); + } + else { + inpktbuf = buf; + } + + read_more: - if(inbufptr >= sizeof(uip.inbuf)) { + if(inbufptr >= BUF_SIZE) { inbufptr = 0; } ret = fread(&c, 1, 1, inslip); -#ifdef linux -after_fread: -#endif + if(ret == -1) { err(1, "serial_to_tun: read"); } @@ -286,13 +322,13 @@ after_fread: switch(c) { case SLIP_END: if(inbufptr > 0) { - if(uip.inbuf[0] == '!') { - if (uip.inbuf[1] == 'M' && inbufptr == 18) { + if(inpktbuf[0] == '!') { + if (inpktbuf[1] == 'M' && inbufptr == 18) { /* Read gateway MAC address and autoconfigure tap0 interface */ char macs[24]; int i, pos; for(i = 0, pos = 0; i < 16; i++) { - macs[pos++] = uip.inbuf[2 + i]; + macs[pos++] = inpktbuf[2 + i]; if ((i & 1) == 1 && i < 14) { macs[pos++] = ':'; } @@ -304,89 +340,66 @@ after_fread: if(autoconf){ - struct in6_addr ipv6addr; - struct uip_802154_longaddr dev_addr; - //DWORD exitCode = -1; - - { - - int addr_bytes[8]; // sscanf requires int instead of 8-bit for hexadecimal variables. - - sscanf(macs, "%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X", - &addr_bytes[0], - &addr_bytes[1], - &addr_bytes[2], - &addr_bytes[3], - &addr_bytes[4], - &addr_bytes[5], - &addr_bytes[6], - &addr_bytes[7]); - - for(i=0;i<8;i++){ - dev_addr.addr[i] = addr_bytes[i]; - } - } - - /*int i; - PRINTF("MAC:\n"); - for(i=0; i< 8; i++) - PRINTF("%02X ",dev_addr.addr[i]); - PRINTF("\n");*/ - - dev_addr.addr[0] |= 0x02; - - strtok(ipprefix,"/"); - - if(inet_pton(AF_INET6, ipprefix, &ipv6addr)!=1){ - printf("Invalid IPv6 address.\n"); + if(IPAddrFromPrefix(autoconf_addr, ipprefix, macs)!=0){ + fprintf(stderr, "Invalid IPv6 address.\n"); exit(1); - } - - // Copy modified EUI-64 to the last 64 bits of IPv6 address. - memcpy(&ipv6addr.s6_addr[8],&dev_addr,8); - - inet_ntop(AF_INET6,&ipv6addr,autoconf_addr,INET6_ADDRSTRLEN); // To string format. - - char * substr = strtok(NULL,"/"); - if(substr!=NULL){ // Add the prefix length. - strcat(autoconf_addr,"/"); - strcat(autoconf_addr,substr); - } - ipaddr = autoconf_addr; - - addAddress(if_name,ipaddr); + } + local_ipaddr = autoconf_addr; + addAddress(if_name,local_ipaddr); - - } + } + if(br_prefix != NULL){ + /* RPL Border Router mode. Add route towards LoWPAN. */ + + if(IPAddrFromPrefix(rem_ipaddr, br_prefix, macs)!=0){ + fprintf(stderr, "Invalid IPv6 address.\n"); + exit(1); + } + + addLoWPANRoute(if_name, br_prefix, rem_ipaddr); + addNeighbor(if_name, rem_ipaddr, DEV_MAC_ADDR); + } } #define DEBUG_LINE_MARKER '\r' } - else if(uip.inbuf[0] == '?') { - if (uip.inbuf[1] == 'M') { + else if(inpktbuf[0] == '?') { + if (inpktbuf[1] == 'M') { /* Send our MAC address. */ - send_mac = 1; - set_sniffer_mode = 1; - set_channel = 1; + send_mac = true; + set_sniffer_mode = true; + set_channel = true; + } + else if (inpktbuf[1] == 'P') { + /* Send LoWPAN network prefix to the border router. */ + send_prefix = true; } } - else if(uip.inbuf[0] == DEBUG_LINE_MARKER) { - fwrite(uip.inbuf + 1, inbufptr - 1, 1, stderr); + else if(inpktbuf[0] == DEBUG_LINE_MARKER) { + fwrite(inpktbuf + 1, inbufptr - 1, 1, stderr); } - else if(is_sensible_string(uip.inbuf, inbufptr)) { - fwrite(uip.inbuf, inbufptr, 1, stderr); + else if(is_sensible_string(inpktbuf, inbufptr)) { + fwrite(inpktbuf, inbufptr, 1, stderr); } else { - //PRINTF("Writing to tun len: %d\n", inbufptr); - /* print_packet(uip.inbuf, inbufptr);*/ - /*if(write(outfd, uip.inbuf, inbufptr) != inbufptr) { - err(1, "serial_to_tun: write"); - }*/ - PRINTF("Sending to wpcap\n"); - /*print_packet(uip.inbuf, inbufptr);*/ - wpcap_send(uip.inbuf, inbufptr); + PRINTF("Sending to wpcap\n"); + + if(tun){ + + //Ethernet header to be inserted before IP packet + struct uip_eth_hdr * eth_hdr = (struct uip_eth_hdr *)buf; + + memcpy(ð_hdr->dest, &adapter_eth_addr, sizeof(struct uip_eth_addr)); + memcpy(ð_hdr->src, &dev_eth_addr, sizeof(struct uip_eth_addr)); + + eth_hdr->type = htons(UIP_ETHTYPE_IPV6); + inbufptr += sizeof(struct uip_eth_hdr); + } + //print_packet(inpktbuf, inbufptr); + + wpcap_send(buf, inbufptr); /* printf("After sending to wpcap\n");*/ } inbufptr = 0; @@ -411,7 +424,7 @@ after_fread: } /* FALLTHROUGH */ default: - uip.inbuf[inbufptr++] = c; + inpktbuf[inbufptr++] = c; break; } @@ -432,6 +445,24 @@ slip_send(unsigned char c) slip_end++; } /*---------------------------------------------------------------------------*/ +void +slip_send_char(unsigned char c) +{ + switch(c) { + case SLIP_END: + slip_send(SLIP_ESC); + slip_send(SLIP_ESC_END); + break; + case SLIP_ESC: + slip_send(SLIP_ESC); + slip_send(SLIP_ESC_ESC); + break; + default: + slip_send(c); + break; + } +} +/*---------------------------------------------------------------------------*/ int slip_empty() { @@ -494,27 +525,6 @@ write_to_serial(void *inbuf, int len) PROGRESS("t"); } /*---------------------------------------------------------------------------*/ - -/* -* Read from tun, write to slip. -*/ -#if 0 -void -tun_to_serial(int infd, int outfd) -{ - struct { - unsigned char inbuf[2000]; - } uip; - int size; - - if((size = read(infd, uip.inbuf, 2000)) == -1) { - err(1, "tun_to_serial: read"); - } - - write_to_serial(uip.inbuf, size); -} -#endif /* 0 */ -/*---------------------------------------------------------------------------*/ #ifndef BAUDRATE #define BAUDRATE B115200 #endif @@ -616,9 +626,15 @@ void cleanup(void) { wpcap_exit(); - if(tobecleaned){ - delAddress(if_name,ipaddr); + if(clean_addr){ + delAddress(if_name,local_ipaddr); } + if(clean_route){ + delLoWPANRoute(if_name,br_prefix); + } + if(clean_neighb){ + delNeighbor(if_name, rem_ipaddr); + } } void @@ -632,7 +648,7 @@ void sigalarm(int signo) { if(!mac_received){ - fprintf(stderr, "Bridge not found!\n"); + fprintf(stderr, "Bridge/Router not found!\n"); exit(2); } } @@ -662,13 +678,13 @@ void send_commands(void) slip_send('M'); for(i=0; i < 6; i++){ - sprintf(buf,"%02X",eth_addr.addr[i]); + sprintf(buf,"%02X",adapter_eth_addr.addr[i]); slip_send(buf[0]); slip_send(buf[1]); } slip_send(SLIP_END); - send_mac = 0; + send_mac = false; } else if(set_sniffer_mode && slip_empty()){ @@ -708,6 +724,30 @@ void send_commands(void) set_channel = 0; } + else if(send_prefix && br_prefix != NULL && slip_empty()){ + + struct in6_addr addr; + int i; + + inet_pton(AF_INET6, br_prefix, &addr); + + fprintf(stderr,"*** Address:%s => %02x%02x:%02x%02x:%02x%02x:%02x%02x\n", + br_prefix, + addr.s6_addr[0], addr.s6_addr[1], + addr.s6_addr[2], addr.s6_addr[3], + addr.s6_addr[4], addr.s6_addr[5], + addr.s6_addr[6], addr.s6_addr[7]); + slip_send('!'); + slip_send('P'); + for(i = 0; i < 8; i++) { + /* need to call the slip_send_char for stuffing */ + slip_send_char(addr.s6_addr[i]); + } + slip_send(SLIP_END); + + send_prefix = false; + + } } void addAddress(const char * ifname, const char * ipaddr) @@ -737,7 +777,7 @@ void addAddress(const char * ifname, const char * ipaddr) execProcess(&exitCode,"netsh interface ipv6 add address \"%s\" %s",if_name,ipaddr); } if(exitCode==0) - tobecleaned = true; + clean_addr = true; } void delAddress(const char * ifname, const char * ipaddr) @@ -769,6 +809,101 @@ void delAddress(const char * ifname, const char * ipaddr) } +void addLoWPANRoute(const char * ifname, const char * net, const char * gw) +{ + DWORD exitCode = -1; + + execProcess(&exitCode,"netsh interface ipv6 add route %s/64 \"%s\" %s", net, if_name, gw); + if(exitCode==0) + clean_route = true; +} + +void delLoWPANRoute(const char * ifname, const char * net) +{ + execProcess(NULL,"netsh interface ipv6 delete route %s/64 \"%s\"", net, if_name); +} + +void addNeighbor(const char * ifname, const char * neighb, const char * neighb_mac) +{ + DWORD exitCode = -1; + + if(osVersionInfo.dwMajorVersion < 6){ // < Windows Vista (i.e., Windows XP; check if this command is ok for Windows Server 2003 too). + + fprintf(stderr,"Bridge mode only supported on Windows Vista and later OSs.\r\n"); + exit(-1); + + } + else{ + execProcess(&exitCode,"netsh interface ipv6 add neighbor \"%s\" %s \"%s\"", if_name, neighb, neighb_mac); + if(exitCode==0) + clean_neighb = true; + } +} + +void delNeighbor(const char * ifname, const char * neighb) +{ + execProcess(NULL,"netsh interface ipv6 delete neighbor \"%s\" %s", if_name, neighb); +} + +int IPAddrFromPrefix(char * ipaddr, const char * ipprefix, const char * mac) +{ + struct in6_addr ipv6addr; + struct uip_802154_longaddr dev_addr; + char tmp_ipprefix[INET6_ADDRSTRLEN]; + char str_addr[INET6_ADDRSTRLEN] = {0}; + int addr_bytes[8]; + int i; + + strncpy(tmp_ipprefix, ipprefix, INET6_ADDRSTRLEN); + + // sscanf requires int instead of 8-bit for hexadecimal variables. + + sscanf(mac, "%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X", + &addr_bytes[0], + &addr_bytes[1], + &addr_bytes[2], + &addr_bytes[3], + &addr_bytes[4], + &addr_bytes[5], + &addr_bytes[6], + &addr_bytes[7]); + + for(i=0;i<8;i++){ + dev_addr.addr[i] = addr_bytes[i]; + } + + /*int i; + PRINTF("MAC:\n"); + for(i=0; i< 8; i++) + PRINTF("%02X ",dev_addr.addr[i]); + PRINTF("\n");*/ + + dev_addr.addr[0] |= 0x02; + + strtok(tmp_ipprefix,"/"); + + if(inet_pton(AF_INET6, tmp_ipprefix, &ipv6addr)!=1){ + return 1; + } + + // Copy modified EUI-64 to the last 64 bits of IPv6 address. + memcpy(&ipv6addr.s6_addr[8],&dev_addr,8); + + inet_ntop(AF_INET6,&ipv6addr,str_addr,INET6_ADDRSTRLEN); // To string format. + + char * substr = strtok(NULL,"/"); + if(substr!=NULL){ // Add the prefix length. + strcat(str_addr,"/"); + strcat(str_addr,substr); + } + strcpy(ipaddr, str_addr); + + return 0; + +} + + + int main(int argc, char **argv) { @@ -781,6 +916,8 @@ main(int argc, char **argv) int baudrate = -2; char buf[4000]; + + prog = argv[0]; setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */ @@ -788,7 +925,7 @@ main(int argc, char **argv) osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osVersionInfo); - while((c = getopt(argc, argv, "B:D:hs:c:ra:p:v")) != -1) { + while((c = getopt(argc, argv, "B:D:hs:c:ra:p:v:tb:")) != -1) { switch (c) { case 'B': baudrate = atoi(optarg); @@ -808,14 +945,6 @@ main(int argc, char **argv) err(1,"port number is invalid"); } sprintf(siodev,"ttyS%d",portnum-1); - - /*int i = 0; - - while(optarg[i] && i < sizeof(siodev) - 1){ - siodev[i] = tolower((int)optarg[i]); - i++; - } - siodev[i] = '\0';*/ } else { strncpy(siodev,optarg,sizeof(siodev)-1); @@ -832,14 +961,14 @@ main(int argc, char **argv) case 'a': if(autoconf == true){ - errx(1, USAGE_STRING); + print_help(); } - ipaddr = optarg; + local_ipaddr = optarg; break; case 'p': - if(ipaddr !=NULL){ - errx(1, USAGE_STRING); + if(local_ipaddr !=NULL){ + print_help(); } autoconf = true; ipprefix = optarg; @@ -849,10 +978,21 @@ main(int argc, char **argv) verbose = true; break; + case 't': + tun = true; + break; + + case 'b': + br_prefix = optarg; + send_prefix = true; + send_mac = false; + tun = true; + break; + case '?': case 'h': default: - errx(1,HELP_STRING); + print_help(); break; } } @@ -860,16 +1000,23 @@ main(int argc, char **argv) argv += (optind - 1); if(argc != 2 || *siodev == '\0') { - errx(1, USAGE_STRING); + print_help(); } + if(autoconf == true && br_prefix != NULL){ + fprintf(stderr, "-p and -b options cannot be used together.\r\n"); + print_help(); + } + sscanf(argv[1],"%2X-%2X-%2X-%2X-%2X-%2X", - (int *)ð_addr.addr[0],(int *)ð_addr.addr[1],(int *)ð_addr.addr[2],(int *)ð_addr.addr[3],(int *)ð_addr.addr[4],(int *)ð_addr.addr[5]); - if_name = wpcap_start(ð_addr, verbose); + (int *)&adapter_eth_addr.addr[0],(int *)&adapter_eth_addr.addr[1], + (int *)&adapter_eth_addr.addr[2],(int *)&adapter_eth_addr.addr[3], + (int *)&adapter_eth_addr.addr[4],(int *)&adapter_eth_addr.addr[5]); + if_name = wpcap_start(&adapter_eth_addr, verbose); - if(ipaddr!=NULL){ - addAddress(if_name, ipaddr); + if(local_ipaddr!=NULL){ + addAddress(if_name, local_ipaddr); } @@ -897,15 +1044,12 @@ main(int argc, char **argv) } - //if(siodev != NULL) { - slipfd = devopen(siodev, O_RDWR | O_NONBLOCK | O_NOCTTY | O_NDELAY | O_DIRECT | O_SYNC ); - if(slipfd == -1) { - err(1, "can't open siodev ``/dev/%s''", siodev); - } - /*} else { - - err(1, "can't open siodev"); - }*/ + + slipfd = devopen(siodev, O_RDWR | O_NONBLOCK | O_NOCTTY | O_NDELAY | O_DIRECT | O_SYNC ); + if(slipfd == -1) { + err(1, "can't open siodev ``/dev/%s''", siodev); + } + fprintf(stderr, "slip started on ``/dev/%s''\n", siodev); stty_telos(slipfd); slip_send(SLIP_END); @@ -950,6 +1094,13 @@ main(int argc, char **argv) if(eth_hdr->type == htons(UIP_ETHTYPE_IPV6)){ // We forward only IPv6 packet. + + if(tun){ + // Cut away ethernet header. + pbuf += sizeof(struct uip_eth_hdr); + ret -= sizeof(struct uip_eth_hdr); + } + write_to_serial(pbuf, ret); /*print_packet(pbuf, ret);*/ slip_flushbuf(slipfd); @@ -968,7 +1119,6 @@ main(int argc, char **argv) else if(ret > 0) { if(FD_ISSET(slipfd, &rset)) { /* printf("serial_to_wpcap\n"); */ - /*serial_to_tun(inslip, tunfd);*/ serial_to_wpcap(inslip); /* printf("End of serial_to_wpcap\n");*/ } diff --git a/tools/stm32w/wpcapslip6/wpcapslip6.exe b/tools/stm32w/wpcapslip6/wpcapslip6.exe index ddd618111cb916c3b0df047f108d156a5d395280..b14fd55821b304b281021a567d36df51767f3a94 100644 GIT binary patch literal 43214 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 literal 40356 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