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 uint8_t
100 slip_send(void)
101 {
102  uint16_t i;
103  uint8_t *ptr;
104  uint8_t c;
105 
106  slip_arch_writeb(SLIP_END);
107 
108  ptr = &uip_buf[UIP_LLH_LEN];
109  for(i = 0; i < uip_len; ++i) {
110  if(i == UIP_TCPIP_HLEN) {
111  ptr = (uint8_t *)uip_appdata;
112  }
113  c = *ptr++;
114  if(c == SLIP_END) {
115  slip_arch_writeb(SLIP_ESC);
116  c = SLIP_ESC_END;
117  } else if(c == SLIP_ESC) {
118  slip_arch_writeb(SLIP_ESC);
119  c = SLIP_ESC_ESC;
120  }
121  slip_arch_writeb(c);
122  }
123  slip_arch_writeb(SLIP_END);
124 
125  return UIP_FW_OK;
126 }
127 /*---------------------------------------------------------------------------*/
128 uint8_t
129 slip_write(const void *_ptr, int len)
130 {
131  const uint8_t *ptr = _ptr;
132  uint16_t i;
133  uint8_t c;
134 
135  slip_arch_writeb(SLIP_END);
136 
137  for(i = 0; i < len; ++i) {
138  c = *ptr++;
139  if(c == SLIP_END) {
140  slip_arch_writeb(SLIP_ESC);
141  c = SLIP_ESC_END;
142  } else if(c == SLIP_ESC) {
143  slip_arch_writeb(SLIP_ESC);
144  c = SLIP_ESC_ESC;
145  }
146  slip_arch_writeb(c);
147  }
148  slip_arch_writeb(SLIP_END);
149 
150  return len;
151 }
152 /*---------------------------------------------------------------------------*/
153 static void
154 rxbuf_init(void)
155 {
156  begin = end = pkt_end = 0;
157  state = STATE_OK;
158 }
159 /*---------------------------------------------------------------------------*/
160 /* Upper half does the polling. */
161 static uint16_t
162 slip_poll_handler(uint8_t *outbuf, uint16_t blen)
163 {
164  /* This is a hack and won't work across buffer edge! */
165  if(rxbuf[begin] == 'C') {
166  int i;
167  if(begin < end && (end - begin) >= 6
168  && memcmp(&rxbuf[begin], "CLIENT", 6) == 0) {
169  state = STATE_TWOPACKETS; /* Interrupts do nothing. */
170  memset(&rxbuf[begin], 0x0, 6);
171 
172  rxbuf_init();
173 
174  for(i = 0; i < 13; i++) {
175  slip_arch_writeb("CLIENTSERVER\300"[i]);
176  }
177  return 0;
178  }
179  }
180 #ifdef SLIP_CONF_ANSWER_MAC_REQUEST
181  else if(rxbuf[begin] == '?') {
182  /* Used by tapslip6 to request mac for auto configure */
183  int i, j;
184  char* hexchar = "0123456789abcdef";
185  if(begin < end && (end - begin) >= 2
186  && rxbuf[begin + 1] == 'M') {
187  state = STATE_TWOPACKETS; /* Interrupts do nothing. */
188  rxbuf[begin] = 0;
189  rxbuf[begin + 1] = 0;
190 
191  rxbuf_init();
192 
193  linkaddr_t addr = get_mac_addr();
194  /* this is just a test so far... just to see if it works */
195  slip_arch_writeb('!');
196  slip_arch_writeb('M');
197  for(j = 0; j < 8; j++) {
198  slip_arch_writeb(hexchar[addr.u8[j] >> 4]);
199  slip_arch_writeb(hexchar[addr.u8[j] & 15]);
200  }
201  slip_arch_writeb(SLIP_END);
202  return 0;
203  }
204  }
205 #endif /* SLIP_CONF_ANSWER_MAC_REQUEST */
206 
207  /*
208  * Interrupt can not change begin but may change pkt_end.
209  * If pkt_end != begin it will not change again.
210  */
211  if(begin != pkt_end) {
212  uint16_t len;
213 
214  if(begin < pkt_end) {
215  len = pkt_end - begin;
216  if(len > blen) {
217  len = 0;
218  } else {
219  memcpy(outbuf, &rxbuf[begin], len);
220  }
221  } else {
222  len = (RX_BUFSIZE - begin) + (pkt_end - 0);
223  if(len > blen) {
224  len = 0;
225  } else {
226  unsigned i;
227  for(i = begin; i < RX_BUFSIZE; i++) {
228  *outbuf++ = rxbuf[i];
229  }
230  for(i = 0; i < pkt_end; i++) {
231  *outbuf++ = rxbuf[i];
232  }
233  }
234  }
235 
236  /* Remove data from buffer together with the copied packet. */
237  begin = pkt_end;
238  if(state == STATE_TWOPACKETS) {
239  pkt_end = end;
240  state = STATE_OK; /* Assume no bytes where lost! */
241 
242  /* One more packet is buffered, need to be polled again! */
243  process_poll(&slip_process);
244  }
245  return len;
246  }
247 
248  return 0;
249 }
250 /*---------------------------------------------------------------------------*/
251 PROCESS_THREAD(slip_process, ev, data)
252 {
253  PROCESS_BEGIN();
254 
255  rxbuf_init();
256 
257  while(1) {
258  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
259 
260  slip_active = 1;
261 
262  /* Move packet from rxbuf to buffer provided by uIP. */
263  uip_len = slip_poll_handler(&uip_buf[UIP_LLH_LEN],
264  UIP_BUFSIZE - UIP_LLH_LEN);
265 #if !NETSTACK_CONF_WITH_IPV6
266  if(uip_len == 4 && strncmp((char*)&uip_buf[UIP_LLH_LEN], "?IPA", 4) == 0) {
267  char buf[8];
268  memcpy(&buf[0], "=IPA", 4);
269  memcpy(&buf[4], &uip_hostaddr, 4);
270  if(input_callback) {
271  input_callback();
272  }
273  slip_write(buf, 8);
274  } else if(uip_len > 0
275  && uip_len == (((uint16_t)(BUF->len[0]) << 8) + BUF->len[1])
276  && uip_ipchksum() == 0xffff) {
277 #define IP_DF 0x40
278  if(BUF->ipid[0] == 0 && BUF->ipid[1] == 0 && BUF->ipoffset[0] & IP_DF) {
279  static uint16_t ip_id;
280  uint16_t nid = ip_id++;
281  BUF->ipid[0] = nid >> 8;
282  BUF->ipid[1] = nid;
283  nid = uip_htons(nid);
284  nid = ~nid; /* negate */
285  BUF->ipchksum += nid; /* add */
286  if(BUF->ipchksum < nid) { /* 1-complement overflow? */
287  BUF->ipchksum++;
288  }
289  }
290 #ifdef SLIP_CONF_TCPIP_INPUT
291  SLIP_CONF_TCPIP_INPUT();
292 #else
293  tcpip_input();
294 #endif
295  } else {
296  uip_clear_buf();
297  SLIP_STATISTICS(slip_ip_drop++);
298  }
299 #else /* NETSTACK_CONF_WITH_IPV6 */
300  if(uip_len > 0) {
301  if(input_callback) {
302  input_callback();
303  }
304 #ifdef SLIP_CONF_TCPIP_INPUT
305  SLIP_CONF_TCPIP_INPUT();
306 #else
307  tcpip_input();
308 #endif
309  }
310 #endif /* NETSTACK_CONF_WITH_IPV6 */
311  }
312 
313  PROCESS_END();
314 }
315 /*---------------------------------------------------------------------------*/
316 int
317 slip_input_byte(unsigned char c)
318 {
319  switch(state) {
320  case STATE_RUBBISH:
321  if(c == SLIP_END) {
322  state = STATE_OK;
323  }
324  return 0;
325 
326  case STATE_TWOPACKETS: /* Two packets are already buffered! */
327  return 0;
328 
329  case STATE_ESC:
330  if(c == SLIP_ESC_END) {
331  c = SLIP_END;
332  } else if(c == SLIP_ESC_ESC) {
333  c = SLIP_ESC;
334  } else {
335  state = STATE_RUBBISH;
336  SLIP_STATISTICS(slip_rubbish++);
337  end = pkt_end; /* remove rubbish */
338  return 0;
339  }
340  state = STATE_OK;
341  break;
342 
343  case STATE_OK:
344  if(c == SLIP_ESC) {
345  state = STATE_ESC;
346  return 0;
347  } else if(c == SLIP_END) {
348  /*
349  * We have a new packet, possibly of zero length.
350  *
351  * There may already be one packet buffered.
352  */
353  if(end != pkt_end) { /* Non zero length. */
354  if(begin == pkt_end) { /* None buffered. */
355  pkt_end = end;
356  } else {
357  state = STATE_TWOPACKETS;
358  SLIP_STATISTICS(slip_twopackets++);
359  }
360  process_poll(&slip_process);
361  return 1;
362  }
363  return 0;
364  }
365  break;
366  }
367 
368  /* add_char: */
369  {
370  unsigned next;
371  next = end + 1;
372  if(next == RX_BUFSIZE) {
373  next = 0;
374  }
375  if(next == begin) { /* rxbuf is full */
376  state = STATE_RUBBISH;
377  SLIP_STATISTICS(slip_overflow++);
378  end = pkt_end; /* remove rubbish */
379  return 0;
380  }
381  rxbuf[end] = c;
382  end = next;
383  }
384 
385  /* There could be a separate poll routine for this. */
386  if(c == 'T' && rxbuf[begin] == 'C') {
387  process_poll(&slip_process);
388  return 1;
389  }
390 
391  return 0;
392 }
393 /*---------------------------------------------------------------------------*/
uint16_t uip_ipchksum(void)
Calculate the IP header checksum of the packet header in uip_buf.
Definition: uip.c:302
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
uint8_t slip_send(void)
Send an IP packet from the uIP buffer with SLIP.
Definition: slip.c:193
#define UIP_FW_OK
A non-error message that indicates that something went OK.
Definition: uip-fw.h:132
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
void slip_arch_writeb(unsigned char c)
Copyright (c) 2014, Analog Devices, Inc.
Definition: slip-arch.c:46
#define UIP_LLH_LEN
The link level header length.
Definition: uipopt.h:160
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
uip_appdata
Pointer to the application data in the packet buffer.
Definition: tcp_loader.c:74
int slip_input_byte(unsigned char c)
Input a SLIP byte.
Definition: slip.c:361
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:523
void slip_set_input_callback(void(*c)(void))
Set a function to be called when there is activity on the SLIP interface; used for detecting if a nod...
Definition: slip.c:143
#define NULL
The null pointer.
uIP packet forwarding header file.
Header file for the uIP TCP/IP stack.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
Definition: tcpip.c:522
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:173
CCIF uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
Definition: uip.c:1948
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120