/* -*- C -*- */ /* * 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 #include #include "contiki.h" #include "net/linkaddr.h" #include "sys/ctimer.h" #include "net/ip/uip.h" #include "net/ipv4/uip-fw.h" #define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) #include "dev/slip.h" #include "../sicslow_ethernet.h" #include #include "dev/stm32w-radio.h" #define SLIP_END 0300 #define SLIP_ESC 0333 #define SLIP_ESC_END 0334 #define SLIP_ESC_ESC 0335 PROCESS(slip_process, "SLIP driver"); uint8_t slip_active; #if 1 #define SLIP_STATISTICS(statement) #else uint16_t slip_rubbish, slip_twopackets, slip_overflow, slip_ip_drop; #define SLIP_STATISTICS(statement) statement #endif /* Must be at least one byte larger than UIP_BUFSIZE! */ #define RX_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN + 16) enum { STATE_TWOPACKETS = 0, /* We have 2 packets and drop incoming data. */ STATE_OK = 1, STATE_ESC = 2, STATE_RUBBISH = 3, }; /* * Variables begin and end manage the buffer space in a cyclic * fashion. The first used byte is at begin and end is one byte past * the last. I.e. [begin, end) is the actively used space. * * If begin != pkt_end we have a packet at [begin, pkt_end), * furthermore, if state == STATE_TWOPACKETS we have one more packet at * [pkt_end, end). If more bytes arrive in state STATE_TWOPACKETS * they are discarded. */ static uint8_t state = STATE_TWOPACKETS; static uint16_t begin, end; static uint8_t rxbuf[RX_BUFSIZE]; static uint16_t pkt_end; /* SLIP_END tracker. */ struct uip_eth_addr slip_eth_addr = {{0}}; const struct uip_eth_addr eth_addr_null = {{0}}; static struct ctimer t; static void request_mac(void *); uint8_t mac_hextoi(struct uip_eth_addr *a, const char * mac); //static void (* input_callback)(void) = NULL; static void (* tcpip_input_callback)(void) = NULL; /*---------------------------------------------------------------------------*/ //void //slip_set_input_callback(void (*c)(void)) //{ // input_callback = c; //} /*---------------------------------------------------------------------------*/ void slip_set_tcpip_input_callback(void (*c)(void)) { tcpip_input_callback = c; } /*---------------------------------------------------------------------------*/ #if NETSTACK_CONF_WITH_IPV4 uint8_t slip_send(void) { uint16_t i; uint8_t *ptr; uint8_t c; slip_arch_writeb(SLIP_END); ptr = &uip_buf[UIP_LLH_LEN]; for(i = 0; i < uip_len; ++i) { if(i == UIP_TCPIP_HLEN) { ptr = (uint8_t *)uip_appdata; } c = *ptr++; if(c == SLIP_END) { slip_arch_writeb(SLIP_ESC); c = SLIP_ESC_END; } else if(c == SLIP_ESC) { slip_arch_writeb(SLIP_ESC); c = SLIP_ESC_ESC; } slip_arch_writeb(c); } slip_arch_writeb(SLIP_END); return UIP_FW_OK; } #endif /* NETSTACK_CONF_WITH_IPV4 */ /*---------------------------------------------------------------------------*/ uint8_t slip_write(const void *_ptr, int len) { const uint8_t *ptr = _ptr; uint16_t i; uint8_t c; slip_arch_writeb(SLIP_END); for(i = 0; i < len; ++i) { c = *ptr++; if(c == SLIP_END) { slip_arch_writeb(SLIP_ESC); c = SLIP_ESC_END; } else if(c == SLIP_ESC) { slip_arch_writeb(SLIP_ESC); c = SLIP_ESC_ESC; } slip_arch_writeb(c); } slip_arch_writeb(SLIP_END); return len; } /*---------------------------------------------------------------------------*/ static void rxbuf_init(void) { begin = end = pkt_end = 0; state = STATE_OK; } /*---------------------------------------------------------------------------*/ int from_slipbuffer(uint8_t *outbuf, uint16_t blen) { /* * Interrupt can not change begin but may change pkt_end. * If pkt_end != begin it will not change again. */ if(begin != pkt_end) { uint16_t len; if(begin < pkt_end) { len = pkt_end - begin; if(len > blen) { len = 0; } else { memcpy(outbuf, &rxbuf[begin], len); } } else { len = (RX_BUFSIZE - begin) + (pkt_end - 0); if(len > blen) { len = 0; } else { unsigned i; for(i = begin; i < RX_BUFSIZE; i++) { *outbuf++ = rxbuf[i]; } for(i = 0; i < pkt_end; i++) { *outbuf++ = rxbuf[i]; } } } /* Remove data from buffer together with the copied packet. */ begin = pkt_end; if(state == STATE_TWOPACKETS) { pkt_end = end; state = STATE_OK; /* Assume no bytes where lost! */ /* One more packet is buffered, need to be polled again! */ process_poll(&slip_process); } return len; } return 0; } /* Upper half does the polling. */ static uint16_t slip_poll_handler(uint8_t *outbuf, uint16_t blen) { /* This is a hack and won't work across buffer edge! */ #if 0 if(rxbuf[begin] == 'C') { int i; if(begin < end && (end - begin) >= 6 && memcmp(&rxbuf[begin], "CLIENT", 6) == 0) { state = STATE_TWOPACKETS; /* Interrupts do nothing. */ memset(&rxbuf[begin], 0x0, 6); rxbuf_init(); for(i = 0; i < 13; i++) { slip_arch_writeb("CLIENTSERVER\300"[i]); } return 0; } } #endif if(rxbuf[begin] == '?' || rxbuf[begin] == '!') { // Should this characters be escaped? uint8_t tmpbuf[14]; from_slipbuffer(tmpbuf, 14); if(tmpbuf[0] == '?') { int j; char* hexchar = "0123456789abcdef"; if(tmpbuf[1] == 'M') { /* this is just a test so far... just to see if it works */ slip_arch_writeb('!'); slip_arch_writeb('M'); for(j = 0; j < LINKADDR_SIZE; j++) { slip_arch_writeb(hexchar[linkaddr_node_addr.u8[j] >> 4]); slip_arch_writeb(hexchar[linkaddr_node_addr.u8[j] & 15]); } slip_arch_writeb(SLIP_END); return 0; } } #if 1 else if(tmpbuf[0] == '!') { if(tmpbuf[1] == 'M') { char * mac = (char *)tmpbuf + 2; if(mac_hextoi(&slip_eth_addr,mac)!=0){ /* Error! */ /*rxbuf_init(); slip_arch_writeb('!'); slip_arch_writeb('E'); slip_arch_writeb(SLIP_END);*/ printf("Error! Incorrect MAC format.\n"); } /*for(int i=0;i<6;i++) printf("%02X ",slip_eth_addr.addr[i]); printf("\n"); */ return 0; } else if(memcmp(&tmpbuf[1], "OS1", 3) == 0) { enable_sniffer_mode(1); return 0; } else if(memcmp(&tmpbuf[1], "OS0",3) == 0) { enable_sniffer_mode(0); return 0; } else if(memcmp(&tmpbuf[1], "OC", 2) == 0) { short ch_num; tmpbuf[5]='\0'; if(ch_num = atoi((char *)tmpbuf+3)){ ST_RadioSetChannel(ch_num); } return 0; } } } #endif return from_slipbuffer(outbuf, blen); } /*---------------------------------------------------------------------------*/ PROCESS_THREAD(slip_process, ev, data) { PROCESS_BEGIN(); rxbuf_init(); ctimer_set(&t, 2*CLOCK_SECOND, request_mac, NULL); while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); slip_active = 1; /* Move packet from rxbuf to buffer provided by uIP. */ uip_len = slip_poll_handler(&uip_buf[UIP_LLH_LEN], UIP_BUFSIZE - UIP_LLH_LEN); #if !NETSTACK_CONF_WITH_IPV6 if(uip_len == 4 && strncmp((char*)&uip_buf[UIP_LLH_LEN], "?IPA", 4) == 0) { char buf[8]; memcpy(&buf[0], "=IPA", 4); memcpy(&buf[4], &uip_hostaddr, 4); if(input_callback) { input_callback(); } slip_write(buf, 8); } else if(uip_len > 0 && uip_len == (((uint16_t)(BUF->len[0]) << 8) + BUF->len[1]) && uip_ipchksum() == 0xffff) { #define IP_DF 0x40 if(BUF->ipid[0] == 0 && BUF->ipid[1] == 0 && BUF->ipoffset[0] & IP_DF) { static uint16_t ip_id; uint16_t nid = ip_id++; BUF->ipid[0] = nid >> 8; BUF->ipid[1] = nid; nid = htons(nid); nid = ~nid; /* negate */ BUF->ipchksum += nid; /* add */ if(BUF->ipchksum < nid) { /* 1-complement overflow? */ BUF->ipchksum++; } } if(tcpip_input_callback) { tcpip_input_callback(); } else { tcpip_input(); } } else { uip_clear_buf(); SLIP_STATISTICS(slip_ip_drop++); } #else /* NETSTACK_CONF_WITH_IPV6 */ if(uip_len > 0) { if(tcpip_input_callback) { tcpip_input_callback(); } else { tcpip_input(); } } #endif /* NETSTACK_CONF_WITH_IPV6 */ } PROCESS_END(); } /*---------------------------------------------------------------------------*/ int slip_input_byte(unsigned char c) { switch(state) { case STATE_RUBBISH: if(c == SLIP_END) { state = STATE_OK; } return 0; case STATE_TWOPACKETS: /* Two packets are already buffered! */ return 0; case STATE_ESC: if(c == SLIP_ESC_END) { c = SLIP_END; } else if(c == SLIP_ESC_ESC) { c = SLIP_ESC; } else { state = STATE_RUBBISH; SLIP_STATISTICS(slip_rubbish++); end = pkt_end; /* remove rubbish */ return 0; } state = STATE_OK; break; case STATE_OK: if(c == SLIP_ESC) { state = STATE_ESC; return 0; } else if(c == SLIP_END) { /* * We have a new packet, possibly of zero length. * * There may already be one packet buffered. */ if(end != pkt_end) { /* Non zero length. */ if(begin == pkt_end) { /* None buffered. */ pkt_end = end; } else { state = STATE_TWOPACKETS; SLIP_STATISTICS(slip_twopackets++); } process_poll(&slip_process); return 1; } return 0; } break; } /* add_char: */ { unsigned next; next = end + 1; if(next == RX_BUFSIZE) { next = 0; } if(next == begin) { /* rxbuf is full */ state = STATE_RUBBISH; SLIP_STATISTICS(slip_overflow++); end = pkt_end; /* remove rubbish */ return 0; } rxbuf[end] = c; end = next; } /* There could be a separate poll routine for this. */ if(c == 'T' && rxbuf[begin] == 'C') { process_poll(&slip_process); return 1; } return 0; } /*---------------------------------------------------------------------------*/ uint8_t mac_hextoi(struct uip_eth_addr *a, const char * mac) { int i,j; memset(a,0,sizeof(struct uip_eth_addr)); for(i = 0, j = 0; j < 12; j++){ if((mac[j] >= '0' && mac[j] <= '9')){ a->addr[i] += (mac[j] - '0') * ((j & 1) ? 1 : 16); } else if(mac[j] >= 'A' && mac[j] <= 'F'){ a->addr[i] += (mac[j] - 'A' + 10) * ((j & 1) ? 1 : 16); } else { return 1; } if(j&1){ i++; } } return 0; } /*---------------------------------------------------------------------------*/ static void request_mac(void * ptr) { if(memcmp(&slip_eth_addr,ð_addr_null,6)==0){ slip_write("?M", 2); ctimer_set(&t, 6*CLOCK_SECOND, request_mac, NULL); } } /*---------------------------------------------------------------------------*/