Contiki 2.6

slip.c

00001 /* -*- C -*- */
00002 /*
00003  * Copyright (c) 2005, Swedish Institute of Computer Science
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the Institute nor the names of its contributors
00015  *    may be used to endorse or promote products derived from this software
00016  *    without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00022  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00023  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00024  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00025  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00026  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00027  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * This file is part of the Contiki operating system.
00031  *
00032  * @(#)$Id: slip.c,v 1.12 2010/12/23 22:38:47 dak664 Exp $
00033  */
00034 
00035 
00036 #include <stdio.h>
00037 #include <string.h>
00038 
00039 #include "contiki.h"
00040 
00041 #include "net/uip.h"
00042 #include "net/uip-fw.h"
00043 #define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
00044 
00045 #include "dev/slip.h"
00046 
00047 #define SLIP_END     0300
00048 #define SLIP_ESC     0333
00049 #define SLIP_ESC_END 0334
00050 #define SLIP_ESC_ESC 0335
00051 
00052 PROCESS(slip_process, "SLIP driver");
00053 
00054 uint8_t slip_active;
00055 
00056 #if 1
00057 #define SLIP_STATISTICS(statement)
00058 #else
00059 uint16_t slip_rubbish, slip_twopackets, slip_overflow, slip_ip_drop;
00060 #define SLIP_STATISTICS(statement) statement
00061 #endif
00062 
00063 /* Must be at least one byte larger than UIP_BUFSIZE! */
00064 #define RX_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN + 16)
00065 
00066 enum {
00067   STATE_TWOPACKETS = 0, /* We have 2 packets and drop incoming data. */
00068   STATE_OK = 1,
00069   STATE_ESC = 2,
00070   STATE_RUBBISH = 3,
00071 };
00072 
00073 /*
00074  * Variables begin and end manage the buffer space in a cyclic
00075  * fashion. The first used byte is at begin and end is one byte past
00076  * the last. I.e. [begin, end) is the actively used space.
00077  *
00078  * If begin != pkt_end we have a packet at [begin, pkt_end),
00079  * furthermore, if state == STATE_TWOPACKETS we have one more packet at
00080  * [pkt_end, end). If more bytes arrive in state STATE_TWOPACKETS
00081  * they are discarded.
00082  */
00083 
00084 static uint8_t state = STATE_TWOPACKETS;
00085 static uint16_t begin, end;
00086 static uint8_t rxbuf[RX_BUFSIZE];
00087 static uint16_t pkt_end;                /* SLIP_END tracker. */
00088 
00089 static void (* input_callback)(void) = NULL;
00090 /*---------------------------------------------------------------------------*/
00091 void
00092 slip_set_input_callback(void (*c)(void))
00093 {
00094   input_callback = c;
00095 }
00096 /*---------------------------------------------------------------------------*/
00097 /* slip_send: forward (IPv4) packets with {UIP_FW_NETIF(..., slip_send)}
00098  * was used in slip-bridge.c
00099  */
00100 //#if WITH_UIP
00101 uint8_t
00102 slip_send(void)
00103 {
00104   uint16_t i;
00105   uint8_t *ptr;
00106   uint8_t c;
00107 
00108   slip_arch_writeb(SLIP_END);
00109 
00110   ptr = &uip_buf[UIP_LLH_LEN];
00111   for(i = 0; i < uip_len; ++i) {
00112     if(i == UIP_TCPIP_HLEN) {
00113       ptr = (uint8_t *)uip_appdata;
00114     }
00115     c = *ptr++;
00116     if(c == SLIP_END) {
00117       slip_arch_writeb(SLIP_ESC);
00118       c = SLIP_ESC_END;
00119     } else if(c == SLIP_ESC) {
00120       slip_arch_writeb(SLIP_ESC);
00121       c = SLIP_ESC_ESC;
00122     }
00123     slip_arch_writeb(c);
00124   }
00125   slip_arch_writeb(SLIP_END);
00126 
00127   return UIP_FW_OK;
00128 }
00129 //#endif /* WITH_UIP */
00130 /*---------------------------------------------------------------------------*/
00131 uint8_t
00132 slip_write(const void *_ptr, int len)
00133 {
00134   const uint8_t *ptr = _ptr;
00135   uint16_t i;
00136   uint8_t c;
00137 
00138   slip_arch_writeb(SLIP_END);
00139 
00140   for(i = 0; i < len; ++i) {
00141     c = *ptr++;
00142     if(c == SLIP_END) {
00143       slip_arch_writeb(SLIP_ESC);
00144       c = SLIP_ESC_END;
00145     } else if(c == SLIP_ESC) {
00146       slip_arch_writeb(SLIP_ESC);
00147       c = SLIP_ESC_ESC;
00148     }
00149     slip_arch_writeb(c);
00150   }
00151   slip_arch_writeb(SLIP_END);
00152 
00153   return len;
00154 }
00155 /*---------------------------------------------------------------------------*/
00156 static void
00157 rxbuf_init(void)
00158 {
00159   begin = end = pkt_end = 0;
00160   state = STATE_OK;
00161 }
00162 /*---------------------------------------------------------------------------*/
00163 /* Upper half does the polling. */
00164 static uint16_t
00165 slip_poll_handler(uint8_t *outbuf, uint16_t blen)
00166 {
00167   /* This is a hack and won't work across buffer edge! */
00168   if(rxbuf[begin] == 'C') {
00169     int i;
00170     if(begin < end && (end - begin) >= 6
00171        && memcmp(&rxbuf[begin], "CLIENT", 6) == 0) {
00172       state = STATE_TWOPACKETS; /* Interrupts do nothing. */
00173       memset(&rxbuf[begin], 0x0, 6);
00174       
00175       rxbuf_init();
00176       
00177       for(i = 0; i < 13; i++) {
00178         slip_arch_writeb("CLIENTSERVER\300"[i]);
00179       }
00180       return 0;
00181     }
00182   }
00183 #ifdef SLIP_CONF_ANSWER_MAC_REQUEST
00184   else if(rxbuf[begin] == '?') { 
00185     /* Used by tapslip6 to request mac for auto configure */
00186     int i, j;
00187     char* hexchar = "0123456789abcdef";
00188     if(begin < end && (end - begin) >= 2
00189        && rxbuf[begin + 1] == 'M') {
00190       state = STATE_TWOPACKETS; /* Interrupts do nothing. */
00191       rxbuf[begin] = 0;
00192       rxbuf[begin + 1] = 0;
00193       
00194       rxbuf_init();
00195       
00196       rimeaddr_t addr = get_mac_addr();
00197       /* this is just a test so far... just to see if it works */
00198       slip_arch_writeb('!');
00199       slip_arch_writeb('M');
00200       for(j = 0; j < 8; j++) {
00201         slip_arch_writeb(hexchar[addr.u8[j] >> 4]);
00202         slip_arch_writeb(hexchar[addr.u8[j] & 15]);
00203       }
00204       slip_arch_writeb(SLIP_END);
00205       return 0;
00206     }
00207   }
00208 #endif /* SLIP_CONF_ANSWER_MAC_REQUEST */
00209 
00210   /*
00211    * Interrupt can not change begin but may change pkt_end.
00212    * If pkt_end != begin it will not change again.
00213    */
00214   if(begin != pkt_end) {
00215     uint16_t len;
00216 
00217     if(begin < pkt_end) {
00218       len = pkt_end - begin;
00219       if(len > blen) {
00220         len = 0;
00221       } else {
00222         memcpy(outbuf, &rxbuf[begin], len);
00223       }
00224     } else {
00225       len = (RX_BUFSIZE - begin) + (pkt_end - 0);
00226       if(len > blen) {
00227         len = 0;
00228       } else {
00229         unsigned i;
00230         for(i = begin; i < RX_BUFSIZE; i++) {
00231           *outbuf++ = rxbuf[i];
00232         }
00233         for(i = 0; i < pkt_end; i++) {
00234           *outbuf++ = rxbuf[i];
00235         }
00236       }
00237     }
00238 
00239     /* Remove data from buffer together with the copied packet. */
00240     begin = pkt_end;
00241     if(state == STATE_TWOPACKETS) {
00242       pkt_end = end;
00243       state = STATE_OK;         /* Assume no bytes where lost! */
00244       
00245       /* One more packet is buffered, need to be polled again! */
00246       process_poll(&slip_process);
00247     }
00248     return len;
00249   }
00250 
00251   return 0;
00252 }
00253 /*---------------------------------------------------------------------------*/
00254 PROCESS_THREAD(slip_process, ev, data)
00255 {
00256   PROCESS_BEGIN();
00257 
00258   rxbuf_init();
00259 
00260   while(1) {
00261     PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
00262     
00263     slip_active = 1;
00264 
00265     /* Move packet from rxbuf to buffer provided by uIP. */
00266     uip_len = slip_poll_handler(&uip_buf[UIP_LLH_LEN],
00267                                 UIP_BUFSIZE - UIP_LLH_LEN);
00268 #if !UIP_CONF_IPV6
00269     if(uip_len == 4 && strncmp((char*)&uip_buf[UIP_LLH_LEN], "?IPA", 4) == 0) {
00270       char buf[8];
00271       memcpy(&buf[0], "=IPA", 4);
00272       memcpy(&buf[4], &uip_hostaddr, 4);
00273       if(input_callback) {
00274         input_callback();
00275       }
00276       slip_write(buf, 8);
00277     } else if(uip_len > 0
00278        && uip_len == (((uint16_t)(BUF->len[0]) << 8) + BUF->len[1])
00279        && uip_ipchksum() == 0xffff) {
00280 #define IP_DF   0x40
00281       if(BUF->ipid[0] == 0 && BUF->ipid[1] == 0 && BUF->ipoffset[0] & IP_DF) {
00282         static uint16_t ip_id;
00283         uint16_t nid = ip_id++;
00284         BUF->ipid[0] = nid >> 8;
00285         BUF->ipid[1] = nid;
00286         nid = uip_htons(nid);
00287         nid = ~nid;             /* negate */
00288         BUF->ipchksum += nid;   /* add */
00289         if(BUF->ipchksum < nid) { /* 1-complement overflow? */
00290           BUF->ipchksum++;
00291         }
00292       }
00293 #ifdef SLIP_CONF_TCPIP_INPUT
00294       SLIP_CONF_TCPIP_INPUT();
00295 #else
00296       tcpip_input();
00297 #endif
00298     } else {
00299       uip_len = 0;
00300       SLIP_STATISTICS(slip_ip_drop++);
00301     }
00302 #else /* UIP_CONF_IPV6 */
00303     if(uip_len > 0) {
00304       if(input_callback) {
00305         input_callback();
00306       }
00307 #ifdef SLIP_CONF_TCPIP_INPUT
00308       SLIP_CONF_TCPIP_INPUT();
00309 #else
00310       tcpip_input();
00311 #endif
00312     }
00313 #endif /* UIP_CONF_IPV6 */
00314   }
00315 
00316   PROCESS_END();
00317 }
00318 /*---------------------------------------------------------------------------*/
00319 int
00320 slip_input_byte(unsigned char c)
00321 {
00322   switch(state) {
00323   case STATE_RUBBISH:
00324     if(c == SLIP_END) {
00325       state = STATE_OK;
00326     }
00327     return 0;
00328     
00329   case STATE_TWOPACKETS:       /* Two packets are already buffered! */
00330     return 0;
00331 
00332   case STATE_ESC:
00333     if(c == SLIP_ESC_END) {
00334       c = SLIP_END;
00335     } else if(c == SLIP_ESC_ESC) {
00336       c = SLIP_ESC;
00337     } else {
00338       state = STATE_RUBBISH;
00339       SLIP_STATISTICS(slip_rubbish++);
00340       end = pkt_end;            /* remove rubbish */
00341       return 0;
00342     }
00343     state = STATE_OK;
00344     break;
00345 
00346   case STATE_OK:
00347     if(c == SLIP_ESC) {
00348       state = STATE_ESC;
00349       return 0;
00350     } else if(c == SLIP_END) {
00351         /*
00352          * We have a new packet, possibly of zero length.
00353          *
00354          * There may already be one packet buffered.
00355          */
00356       if(end != pkt_end) {      /* Non zero length. */
00357         if(begin == pkt_end) {  /* None buffered. */
00358           pkt_end = end;
00359         } else {
00360           state = STATE_TWOPACKETS;
00361           SLIP_STATISTICS(slip_twopackets++);
00362         }
00363         process_poll(&slip_process);
00364         return 1;
00365       }
00366       return 0;
00367     }
00368     break;
00369   }
00370 
00371   /* add_char: */
00372   {
00373     unsigned next;
00374     next = end + 1;
00375     if(next == RX_BUFSIZE) {
00376       next = 0;
00377     }
00378     if(next == begin) {         /* rxbuf is full */
00379       state = STATE_RUBBISH;
00380       SLIP_STATISTICS(slip_overflow++);
00381       end = pkt_end;            /* remove rubbish */
00382       return 0;
00383     }
00384     rxbuf[end] = c;
00385     end = next;
00386   }
00387 
00388   /* There could be a separate poll routine for this. */
00389   if(c == 'T' && rxbuf[begin] == 'C') {
00390     process_poll(&slip_process);
00391     return 1;
00392   }
00393 
00394   return 0;
00395 }
00396 /*---------------------------------------------------------------------------*/