Contiki 2.5
slip.c
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2005, Swedish Institute of Computer Science
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the Institute nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * This file is part of the Contiki operating system.
31  *
32  * @(#)$Id: slip.c,v 1.12 2010/12/23 22:38:47 dak664 Exp $
33  */
34 
35 
36 #include <stdio.h>
37 #include <string.h>
38 
39 #include "contiki.h"
40 
41 #include "net/uip.h"
42 #include "net/uip-fw.h"
43 #define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
44 
45 #include "dev/slip.h"
46 
47 #define SLIP_END 0300
48 #define SLIP_ESC 0333
49 #define SLIP_ESC_END 0334
50 #define SLIP_ESC_ESC 0335
51 
52 PROCESS(slip_process, "SLIP driver");
53 
54 u8_t slip_active;
55 
56 #if 1
57 #define SLIP_STATISTICS(statement)
58 #else
59 u16_t slip_rubbish, slip_twopackets, slip_overflow, slip_ip_drop;
60 #define SLIP_STATISTICS(statement) statement
61 #endif
62 
63 /* Must be at least one byte larger than UIP_BUFSIZE! */
64 #define RX_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN + 16)
65 
66 enum {
67  STATE_TWOPACKETS = 0, /* We have 2 packets and drop incoming data. */
68  STATE_OK = 1,
69  STATE_ESC = 2,
70  STATE_RUBBISH = 3,
71 };
72 
73 /*
74  * Variables begin and end manage the buffer space in a cyclic
75  * fashion. The first used byte is at begin and end is one byte past
76  * the last. I.e. [begin, end) is the actively used space.
77  *
78  * If begin != pkt_end we have a packet at [begin, pkt_end),
79  * furthermore, if state == STATE_TWOPACKETS we have one more packet at
80  * [pkt_end, end). If more bytes arrive in state STATE_TWOPACKETS
81  * they are discarded.
82  */
83 
84 static u8_t state = STATE_TWOPACKETS;
85 static u16_t begin, end;
86 static u8_t rxbuf[RX_BUFSIZE];
87 static u16_t pkt_end; /* SLIP_END tracker. */
88 
89 static void (* input_callback)(void) = NULL;
90 /*---------------------------------------------------------------------------*/
91 void
92 slip_set_input_callback(void (*c)(void))
93 {
94  input_callback = c;
95 }
96 /*---------------------------------------------------------------------------*/
97 /* slip_send: forward (IPv4) packets with {UIP_FW_NETIF(..., slip_send)}
98  * was used in slip-bridge.c
99  */
100 //#if WITH_UIP
101 u8_t
102 slip_send(void)
103 {
104  u16_t i;
105  u8_t *ptr;
106  u8_t c;
107 
108  slip_arch_writeb(SLIP_END);
109 
110  ptr = &uip_buf[UIP_LLH_LEN];
111  for(i = 0; i < uip_len; ++i) {
112  if(i == UIP_TCPIP_HLEN) {
113  ptr = (u8_t *)uip_appdata;
114  }
115  c = *ptr++;
116  if(c == SLIP_END) {
117  slip_arch_writeb(SLIP_ESC);
118  c = SLIP_ESC_END;
119  } else if(c == SLIP_ESC) {
120  slip_arch_writeb(SLIP_ESC);
121  c = SLIP_ESC_ESC;
122  }
123  slip_arch_writeb(c);
124  }
125  slip_arch_writeb(SLIP_END);
126 
127  return UIP_FW_OK;
128 }
129 //#endif /* WITH_UIP */
130 /*---------------------------------------------------------------------------*/
131 u8_t
132 slip_write(const void *_ptr, int len)
133 {
134  const u8_t *ptr = _ptr;
135  u16_t i;
136  u8_t c;
137 
138  slip_arch_writeb(SLIP_END);
139 
140  for(i = 0; i < len; ++i) {
141  c = *ptr++;
142  if(c == SLIP_END) {
143  slip_arch_writeb(SLIP_ESC);
144  c = SLIP_ESC_END;
145  } else if(c == SLIP_ESC) {
146  slip_arch_writeb(SLIP_ESC);
147  c = SLIP_ESC_ESC;
148  }
149  slip_arch_writeb(c);
150  }
151  slip_arch_writeb(SLIP_END);
152 
153  return len;
154 }
155 /*---------------------------------------------------------------------------*/
156 static void
157 rxbuf_init(void)
158 {
159  begin = end = pkt_end = 0;
160  state = STATE_OK;
161 }
162 /*---------------------------------------------------------------------------*/
163 /* Upper half does the polling. */
164 static u16_t
165 slip_poll_handler(u8_t *outbuf, u16_t blen)
166 {
167  /* This is a hack and won't work across buffer edge! */
168  if(rxbuf[begin] == 'C') {
169  int i;
170  if(begin < end && (end - begin) >= 6
171  && memcmp(&rxbuf[begin], "CLIENT", 6) == 0) {
172  state = STATE_TWOPACKETS; /* Interrupts do nothing. */
173  memset(&rxbuf[begin], 0x0, 6);
174 
175  rxbuf_init();
176 
177  for(i = 0; i < 13; i++) {
178  slip_arch_writeb("CLIENTSERVER\300"[i]);
179  }
180  return 0;
181  }
182  }
183 #ifdef SLIP_CONF_ANSWER_MAC_REQUEST
184  else if(rxbuf[begin] == '?') {
185  /* Used by tapslip6 to request mac for auto configure */
186  int i, j;
187  char* hexchar = "0123456789abcdef";
188  if(begin < end && (end - begin) >= 2
189  && rxbuf[begin + 1] == 'M') {
190  state = STATE_TWOPACKETS; /* Interrupts do nothing. */
191  rxbuf[begin] = 0;
192  rxbuf[begin + 1] = 0;
193 
194  rxbuf_init();
195 
196  rimeaddr_t addr = get_mac_addr();
197  /* this is just a test so far... just to see if it works */
198  slip_arch_writeb('!');
199  slip_arch_writeb('M');
200  for(j = 0; j < 8; j++) {
201  slip_arch_writeb(hexchar[addr.u8[j] >> 4]);
202  slip_arch_writeb(hexchar[addr.u8[j] & 15]);
203  }
204  slip_arch_writeb(SLIP_END);
205  return 0;
206  }
207  }
208 #endif /* SLIP_CONF_ANSWER_MAC_REQUEST */
209 
210  /*
211  * Interrupt can not change begin but may change pkt_end.
212  * If pkt_end != begin it will not change again.
213  */
214  if(begin != pkt_end) {
215  u16_t len;
216 
217  if(begin < pkt_end) {
218  len = pkt_end - begin;
219  if(len > blen) {
220  len = 0;
221  } else {
222  memcpy(outbuf, &rxbuf[begin], len);
223  }
224  } else {
225  len = (RX_BUFSIZE - begin) + (pkt_end - 0);
226  if(len > blen) {
227  len = 0;
228  } else {
229  unsigned i;
230  for(i = begin; i < RX_BUFSIZE; i++) {
231  *outbuf++ = rxbuf[i];
232  }
233  for(i = 0; i < pkt_end; i++) {
234  *outbuf++ = rxbuf[i];
235  }
236  }
237  }
238 
239  /* Remove data from buffer together with the copied packet. */
240  begin = pkt_end;
241  if(state == STATE_TWOPACKETS) {
242  pkt_end = end;
243  state = STATE_OK; /* Assume no bytes where lost! */
244 
245  /* One more packet is buffered, need to be polled again! */
246  process_poll(&slip_process);
247  }
248  return len;
249  }
250 
251  return 0;
252 }
253 /*---------------------------------------------------------------------------*/
254 PROCESS_THREAD(slip_process, ev, data)
255 {
256  PROCESS_BEGIN();
257 
258  rxbuf_init();
259 
260  while(1) {
261  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
262 
263  slip_active = 1;
264 
265  /* Move packet from rxbuf to buffer provided by uIP. */
266  uip_len = slip_poll_handler(&uip_buf[UIP_LLH_LEN],
267  UIP_BUFSIZE - UIP_LLH_LEN);
268 #if !UIP_CONF_IPV6
269  if(uip_len == 4 && strncmp((char*)&uip_buf[UIP_LLH_LEN], "?IPA", 4) == 0) {
270  char buf[8];
271  memcpy(&buf[0], "=IPA", 4);
272  memcpy(&buf[4], &uip_hostaddr, 4);
273  if(input_callback) {
274  input_callback();
275  }
276  slip_write(buf, 8);
277  } else if(uip_len > 0
278  && uip_len == (((u16_t)(BUF->len[0]) << 8) + BUF->len[1])
279  && uip_ipchksum() == 0xffff) {
280 #define IP_DF 0x40
281  if(BUF->ipid[0] == 0 && BUF->ipid[1] == 0 && BUF->ipoffset[0] & IP_DF) {
282  static u16_t ip_id;
283  u16_t nid = ip_id++;
284  BUF->ipid[0] = nid >> 8;
285  BUF->ipid[1] = nid;
286  nid = uip_htons(nid);
287  nid = ~nid; /* negate */
288  BUF->ipchksum += nid; /* add */
289  if(BUF->ipchksum < nid) { /* 1-complement overflow? */
290  BUF->ipchksum++;
291  }
292  }
293 #ifdef SLIP_CONF_TCPIP_INPUT
294  SLIP_CONF_TCPIP_INPUT();
295 #else
296  tcpip_input();
297 #endif
298  } else {
299  uip_len = 0;
300  SLIP_STATISTICS(slip_ip_drop++);
301  }
302 #else /* UIP_CONF_IPV6 */
303  if(uip_len > 0) {
304  if(input_callback) {
305  input_callback();
306  }
307 #ifdef SLIP_CONF_TCPIP_INPUT
308  SLIP_CONF_TCPIP_INPUT();
309 #else
310  tcpip_input();
311 #endif
312  }
313 #endif /* UIP_CONF_IPV6 */
314  }
315 
316  PROCESS_END();
317 }
318 /*---------------------------------------------------------------------------*/
319 int
320 slip_input_byte(unsigned char c)
321 {
322  switch(state) {
323  case STATE_RUBBISH:
324  if(c == SLIP_END) {
325  state = STATE_OK;
326  }
327  return 0;
328 
329  case STATE_TWOPACKETS: /* Two packets are already buffered! */
330  return 0;
331 
332  case STATE_ESC:
333  if(c == SLIP_ESC_END) {
334  c = SLIP_END;
335  } else if(c == SLIP_ESC_ESC) {
336  c = SLIP_ESC;
337  } else {
338  state = STATE_RUBBISH;
339  SLIP_STATISTICS(slip_rubbish++);
340  end = pkt_end; /* remove rubbish */
341  return 0;
342  }
343  state = STATE_OK;
344  break;
345 
346  case STATE_OK:
347  if(c == SLIP_ESC) {
348  state = STATE_ESC;
349  return 0;
350  } else if(c == SLIP_END) {
351  /*
352  * We have a new packet, possibly of zero length.
353  *
354  * There may already be one packet buffered.
355  */
356  if(end != pkt_end) { /* Non zero length. */
357  if(begin == pkt_end) { /* None buffered. */
358  pkt_end = end;
359  } else {
360  state = STATE_TWOPACKETS;
361  SLIP_STATISTICS(slip_twopackets++);
362  }
363  process_poll(&slip_process);
364  return 1;
365  }
366  return 0;
367  }
368  break;
369  }
370 
371  /* add_char: */
372  {
373  unsigned next;
374  next = end + 1;
375  if(next == RX_BUFSIZE) {
376  next = 0;
377  }
378  if(next == begin) { /* rxbuf is full */
379  state = STATE_RUBBISH;
380  SLIP_STATISTICS(slip_overflow++);
381  end = pkt_end; /* remove rubbish */
382  return 0;
383  }
384  rxbuf[end] = c;
385  end = next;
386  }
387 
388  /* There could be a separate poll routine for this. */
389  if(c == 'T' && rxbuf[begin] == 'C') {
390  process_poll(&slip_process);
391  return 1;
392  }
393 
394  return 0;
395 }
396 /*---------------------------------------------------------------------------*/