Contiki 2.6
|
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 /*---------------------------------------------------------------------------*/