Contiki 3.x
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  */
33 
34 
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include "contiki.h"
39 
40 #include "net/ip/uip.h"
41 #include "net/ipv4/uip-fw.h"
42 #define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
43 
44 #include "dev/slip.h"
45 
46 #define SLIP_END 0300
47 #define SLIP_ESC 0333
48 #define SLIP_ESC_END 0334
49 #define SLIP_ESC_ESC 0335
50 
51 PROCESS(slip_process, "SLIP driver");
52 
53 uint8_t slip_active;
54 
55 #if 1
56 #define SLIP_STATISTICS(statement)
57 #else
58 uint16_t slip_rubbish, slip_twopackets, slip_overflow, slip_ip_drop;
59 #define SLIP_STATISTICS(statement) statement
60 #endif
61 
62 /* Must be at least one byte larger than UIP_BUFSIZE! */
63 #define RX_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN + 16)
64 
65 enum {
66  STATE_TWOPACKETS = 0, /* We have 2 packets and drop incoming data. */
67  STATE_OK = 1,
68  STATE_ESC = 2,
69  STATE_RUBBISH = 3,
70 };
71 
72 /*
73  * Variables begin and end manage the buffer space in a cyclic
74  * fashion. The first used byte is at begin and end is one byte past
75  * the last. I.e. [begin, end) is the actively used space.
76  *
77  * If begin != pkt_end we have a packet at [begin, pkt_end),
78  * furthermore, if state == STATE_TWOPACKETS we have one more packet at
79  * [pkt_end, end). If more bytes arrive in state STATE_TWOPACKETS
80  * they are discarded.
81  */
82 
83 static uint8_t state = STATE_TWOPACKETS;
84 static uint16_t begin, end;
85 static uint8_t rxbuf[RX_BUFSIZE];
86 static uint16_t pkt_end; /* SLIP_END tracker. */
87 
88 static void (* input_callback)(void) = NULL;
89 /*---------------------------------------------------------------------------*/
90 void
91 slip_set_input_callback(void (*c)(void))
92 {
93  input_callback = c;
94 }
95 /*---------------------------------------------------------------------------*/
96 /* slip_send: forward (IPv4) packets with {UIP_FW_NETIF(..., slip_send)}
97  * was used in slip-bridge.c
98  */
99 //#if WITH_UIP
100 uint8_t
101 slip_send(void)
102 {
103  uint16_t i;
104  uint8_t *ptr;
105  uint8_t c;
106 
107  slip_arch_writeb(SLIP_END);
108 
109  ptr = &uip_buf[UIP_LLH_LEN];
110  for(i = 0; i < uip_len; ++i) {
111  if(i == UIP_TCPIP_HLEN) {
112  ptr = (uint8_t *)uip_appdata;
113  }
114  c = *ptr++;
115  if(c == SLIP_END) {
116  slip_arch_writeb(SLIP_ESC);
117  c = SLIP_ESC_END;
118  } else if(c == SLIP_ESC) {
119  slip_arch_writeb(SLIP_ESC);
120  c = SLIP_ESC_ESC;
121  }
122  slip_arch_writeb(c);
123  }
124  slip_arch_writeb(SLIP_END);
125 
126  return UIP_FW_OK;
127 }
128 //#endif /* WITH_UIP */
129 /*---------------------------------------------------------------------------*/
130 uint8_t
131 slip_write(const void *_ptr, int len)
132 {
133  const uint8_t *ptr = _ptr;
134  uint16_t i;
135  uint8_t c;
136 
137  slip_arch_writeb(SLIP_END);
138 
139  for(i = 0; i < len; ++i) {
140  c = *ptr++;
141  if(c == SLIP_END) {
142  slip_arch_writeb(SLIP_ESC);
143  c = SLIP_ESC_END;
144  } else if(c == SLIP_ESC) {
145  slip_arch_writeb(SLIP_ESC);
146  c = SLIP_ESC_ESC;
147  }
148  slip_arch_writeb(c);
149  }
150  slip_arch_writeb(SLIP_END);
151 
152  return len;
153 }
154 /*---------------------------------------------------------------------------*/
155 static void
156 rxbuf_init(void)
157 {
158  begin = end = pkt_end = 0;
159  state = STATE_OK;
160 }
161 /*---------------------------------------------------------------------------*/
162 /* Upper half does the polling. */
163 static uint16_t
164 slip_poll_handler(uint8_t *outbuf, uint16_t blen)
165 {
166  /* This is a hack and won't work across buffer edge! */
167  if(rxbuf[begin] == 'C') {
168  int i;
169  if(begin < end && (end - begin) >= 6
170  && memcmp(&rxbuf[begin], "CLIENT", 6) == 0) {
171  state = STATE_TWOPACKETS; /* Interrupts do nothing. */
172  memset(&rxbuf[begin], 0x0, 6);
173 
174  rxbuf_init();
175 
176  for(i = 0; i < 13; i++) {
177  slip_arch_writeb("CLIENTSERVER\300"[i]);
178  }
179  return 0;
180  }
181  }
182 #ifdef SLIP_CONF_ANSWER_MAC_REQUEST
183  else if(rxbuf[begin] == '?') {
184  /* Used by tapslip6 to request mac for auto configure */
185  int i, j;
186  char* hexchar = "0123456789abcdef";
187  if(begin < end && (end - begin) >= 2
188  && rxbuf[begin + 1] == 'M') {
189  state = STATE_TWOPACKETS; /* Interrupts do nothing. */
190  rxbuf[begin] = 0;
191  rxbuf[begin + 1] = 0;
192 
193  rxbuf_init();
194 
195  linkaddr_t addr = get_mac_addr();
196  /* this is just a test so far... just to see if it works */
197  slip_arch_writeb('!');
198  slip_arch_writeb('M');
199  for(j = 0; j < 8; j++) {
200  slip_arch_writeb(hexchar[addr.u8[j] >> 4]);
201  slip_arch_writeb(hexchar[addr.u8[j] & 15]);
202  }
203  slip_arch_writeb(SLIP_END);
204  return 0;
205  }
206  }
207 #endif /* SLIP_CONF_ANSWER_MAC_REQUEST */
208 
209  /*
210  * Interrupt can not change begin but may change pkt_end.
211  * If pkt_end != begin it will not change again.
212  */
213  if(begin != pkt_end) {
214  uint16_t len;
215 
216  if(begin < pkt_end) {
217  len = pkt_end - begin;
218  if(len > blen) {
219  len = 0;
220  } else {
221  memcpy(outbuf, &rxbuf[begin], len);
222  }
223  } else {
224  len = (RX_BUFSIZE - begin) + (pkt_end - 0);
225  if(len > blen) {
226  len = 0;
227  } else {
228  unsigned i;
229  for(i = begin; i < RX_BUFSIZE; i++) {
230  *outbuf++ = rxbuf[i];
231  }
232  for(i = 0; i < pkt_end; i++) {
233  *outbuf++ = rxbuf[i];
234  }
235  }
236  }
237 
238  /* Remove data from buffer together with the copied packet. */
239  begin = pkt_end;
240  if(state == STATE_TWOPACKETS) {
241  pkt_end = end;
242  state = STATE_OK; /* Assume no bytes where lost! */
243 
244  /* One more packet is buffered, need to be polled again! */
245  process_poll(&slip_process);
246  }
247  return len;
248  }
249 
250  return 0;
251 }
252 /*---------------------------------------------------------------------------*/
253 PROCESS_THREAD(slip_process, ev, data)
254 {
255  PROCESS_BEGIN();
256 
257  rxbuf_init();
258 
259  while(1) {
260  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
261 
262  slip_active = 1;
263 
264  /* Move packet from rxbuf to buffer provided by uIP. */
265  uip_len = slip_poll_handler(&uip_buf[UIP_LLH_LEN],
266  UIP_BUFSIZE - UIP_LLH_LEN);
267 #if !UIP_CONF_IPV6
268  if(uip_len == 4 && strncmp((char*)&uip_buf[UIP_LLH_LEN], "?IPA", 4) == 0) {
269  char buf[8];
270  memcpy(&buf[0], "=IPA", 4);
271  memcpy(&buf[4], &uip_hostaddr, 4);
272  if(input_callback) {
273  input_callback();
274  }
275  slip_write(buf, 8);
276  } else if(uip_len > 0
277  && uip_len == (((uint16_t)(BUF->len[0]) << 8) + BUF->len[1])
278  && uip_ipchksum() == 0xffff) {
279 #define IP_DF 0x40
280  if(BUF->ipid[0] == 0 && BUF->ipid[1] == 0 && BUF->ipoffset[0] & IP_DF) {
281  static uint16_t ip_id;
282  uint16_t nid = ip_id++;
283  BUF->ipid[0] = nid >> 8;
284  BUF->ipid[1] = nid;
285  nid = uip_htons(nid);
286  nid = ~nid; /* negate */
287  BUF->ipchksum += nid; /* add */
288  if(BUF->ipchksum < nid) { /* 1-complement overflow? */
289  BUF->ipchksum++;
290  }
291  }
292 #ifdef SLIP_CONF_TCPIP_INPUT
293  SLIP_CONF_TCPIP_INPUT();
294 #else
295  tcpip_input();
296 #endif
297  } else {
298  uip_len = 0;
299  SLIP_STATISTICS(slip_ip_drop++);
300  }
301 #else /* UIP_CONF_IPV6 */
302  if(uip_len > 0) {
303  if(input_callback) {
304  input_callback();
305  }
306 #ifdef SLIP_CONF_TCPIP_INPUT
307  SLIP_CONF_TCPIP_INPUT();
308 #else
309  tcpip_input();
310 #endif
311  }
312 #endif /* UIP_CONF_IPV6 */
313  }
314 
315  PROCESS_END();
316 }
317 /*---------------------------------------------------------------------------*/
318 int
319 slip_input_byte(unsigned char c)
320 {
321  switch(state) {
322  case STATE_RUBBISH:
323  if(c == SLIP_END) {
324  state = STATE_OK;
325  }
326  return 0;
327 
328  case STATE_TWOPACKETS: /* Two packets are already buffered! */
329  return 0;
330 
331  case STATE_ESC:
332  if(c == SLIP_ESC_END) {
333  c = SLIP_END;
334  } else if(c == SLIP_ESC_ESC) {
335  c = SLIP_ESC;
336  } else {
337  state = STATE_RUBBISH;
338  SLIP_STATISTICS(slip_rubbish++);
339  end = pkt_end; /* remove rubbish */
340  return 0;
341  }
342  state = STATE_OK;
343  break;
344 
345  case STATE_OK:
346  if(c == SLIP_ESC) {
347  state = STATE_ESC;
348  return 0;
349  } else if(c == SLIP_END) {
350  /*
351  * We have a new packet, possibly of zero length.
352  *
353  * There may already be one packet buffered.
354  */
355  if(end != pkt_end) { /* Non zero length. */
356  if(begin == pkt_end) { /* None buffered. */
357  pkt_end = end;
358  } else {
359  state = STATE_TWOPACKETS;
360  SLIP_STATISTICS(slip_twopackets++);
361  }
362  process_poll(&slip_process);
363  return 1;
364  }
365  return 0;
366  }
367  break;
368  }
369 
370  /* add_char: */
371  {
372  unsigned next;
373  next = end + 1;
374  if(next == RX_BUFSIZE) {
375  next = 0;
376  }
377  if(next == begin) { /* rxbuf is full */
378  state = STATE_RUBBISH;
379  SLIP_STATISTICS(slip_overflow++);
380  end = pkt_end; /* remove rubbish */
381  return 0;
382  }
383  rxbuf[end] = c;
384  end = next;
385  }
386 
387  /* There could be a separate poll routine for this. */
388  if(c == 'T' && rxbuf[begin] == 'C') {
389  process_poll(&slip_process);
390  return 1;
391  }
392 
393  return 0;
394 }
395 /*---------------------------------------------------------------------------*/
void slip_arch_writeb(unsigned char c)
Copyright (c) 2014, Analog Devices, Inc.
Definition: slip-arch.c:46
uint16_t uip_ipchksum(void)
Calculate the IP header checksum of the packet header in uip_buf.
Definition: uip6.c:343
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
uIP packet forwarding header file.
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
Definition: tcpip.c:529
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
Header file for the uIP TCP/IP stack.
#define NULL
The null pointer.
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:173
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define UIP_LLH_LEN
The link level header length.
Definition: uipopt.h:160
CCIF uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
Definition: uip6.c:2298
tcirc_buf rxbuf
The RX circular buffer, for storing characters from serial port.
Definition: uart.c:56
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define UIP_FW_OK
A non-error message that indicates that something went OK.
Definition: uip-fw.h:132
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
uip_appdata
Pointer to the application data in the packet buffer.
Definition: tcp_loader.c:74