Home | History | Annotate | Download | only in netif
      1 /**
      2  * @file
      3  * SLIP Interface
      4  *
      5  */
      6 
      7 /*
      8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  *
     35  * This file is built upon the file: src/arch/rtxc/netif/sioslip.c
     36  *
     37  * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>
     38  */
     39 
     40 /*
     41  * This is an arch independent SLIP netif. The specific serial hooks must be
     42  * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send
     43  */
     44 
     45 #include "netif/slipif.h"
     46 #include "lwip/opt.h"
     47 
     48 #if LWIP_HAVE_SLIPIF
     49 
     50 #include "lwip/def.h"
     51 #include "lwip/pbuf.h"
     52 #include "lwip/sys.h"
     53 #include "lwip/stats.h"
     54 #include "lwip/snmp.h"
     55 #include "lwip/sio.h"
     56 
     57 #define SLIP_BLOCK     1
     58 #define SLIP_DONTBLOCK 0
     59 
     60 #define SLIP_END     0300 /* 0xC0 */
     61 #define SLIP_ESC     0333 /* 0xDB */
     62 #define SLIP_ESC_END 0334 /* 0xDC */
     63 #define SLIP_ESC_ESC 0335 /* 0xDD */
     64 
     65 #define SLIP_MAX_SIZE 1500
     66 
     67 enum slipif_recv_state {
     68     SLIP_RECV_NORMAL,
     69     SLIP_RECV_ESCAPE,
     70 };
     71 
     72 struct slipif_priv {
     73   sio_fd_t sd;
     74   /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
     75   struct pbuf *p, *q;
     76   enum slipif_recv_state state;
     77   u16_t i, recved;
     78 };
     79 
     80 /**
     81  * Send a pbuf doing the necessary SLIP encapsulation
     82  *
     83  * Uses the serial layer's sio_send()
     84  *
     85  * @param netif the lwip network interface structure for this slipif
     86  * @param p the pbuf chaing packet to send
     87  * @param ipaddr the ip address to send the packet to (not used for slipif)
     88  * @return always returns ERR_OK since the serial layer does not provide return values
     89  */
     90 err_t
     91 slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr)
     92 {
     93   struct slipif_priv *priv;
     94   struct pbuf *q;
     95   u16_t i;
     96   u8_t c;
     97 
     98   LWIP_ASSERT("netif != NULL", (netif != NULL));
     99   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
    100   LWIP_ASSERT("p != NULL", (p != NULL));
    101 
    102   LWIP_UNUSED_ARG(ipaddr);
    103 
    104   priv = netif->state;
    105 
    106   /* Send pbuf out on the serial I/O device. */
    107   sio_send(SLIP_END, priv->sd);
    108 
    109   for (q = p; q != NULL; q = q->next) {
    110     for (i = 0; i < q->len; i++) {
    111       c = ((u8_t *)q->payload)[i];
    112       switch (c) {
    113       case SLIP_END:
    114         sio_send(SLIP_ESC, priv->sd);
    115         sio_send(SLIP_ESC_END, priv->sd);
    116         break;
    117       case SLIP_ESC:
    118         sio_send(SLIP_ESC, priv->sd);
    119         sio_send(SLIP_ESC_ESC, priv->sd);
    120         break;
    121       default:
    122         sio_send(c, priv->sd);
    123         break;
    124       }
    125     }
    126   }
    127   sio_send(SLIP_END, priv->sd);
    128   return ERR_OK;
    129 }
    130 
    131 /**
    132  * Static function for easy use of blockig or non-blocking
    133  * sio_read
    134  *
    135  * @param fd serial device handle
    136  * @param data pointer to data buffer for receiving
    137  * @param len maximum length (in bytes) of data to receive
    138  * @param block if 1, call sio_read; if 0, call sio_tryread
    139  * @return return value of sio_read of sio_tryread
    140  */
    141 static u32_t
    142 slip_sio_read(sio_fd_t fd, u8_t* data, u32_t len, u8_t block)
    143 {
    144   if (block) {
    145     return sio_read(fd, data, len);
    146   } else {
    147     return sio_tryread(fd, data, len);
    148   }
    149 }
    150 
    151 /**
    152  * Handle the incoming SLIP stream character by character
    153  *
    154  * Poll the serial layer by calling sio_read() or sio_tryread().
    155  *
    156  * @param netif the lwip network interface structure for this slipif
    157  * @param block if 1, block until data is received; if 0, return when all data
    158  *        from the buffer is received (multiple calls to this function will
    159  *        return a complete packet, NULL is returned before - used for polling)
    160  * @return The IP packet when SLIP_END is received
    161  */
    162 static struct pbuf *
    163 slipif_input(struct netif *netif, u8_t block)
    164 {
    165   struct slipif_priv *priv;
    166   u8_t c;
    167   struct pbuf *t;
    168 
    169   LWIP_ASSERT("netif != NULL", (netif != NULL));
    170   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
    171 
    172   priv = netif->state;
    173 
    174   while (slip_sio_read(priv->sd, &c, 1, block) > 0) {
    175     switch (priv->state) {
    176     case SLIP_RECV_NORMAL:
    177       switch (c) {
    178       case SLIP_END:
    179         if (priv->recved > 0) {
    180           /* Received whole packet. */
    181           /* Trim the pbuf to the size of the received packet. */
    182           pbuf_realloc(priv->q, priv->recved);
    183 
    184           LINK_STATS_INC(link.recv);
    185 
    186           LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
    187           t = priv->q;
    188           priv->p = priv->q = NULL;
    189           priv->i = priv->recved = 0;
    190           return t;
    191         }
    192         continue;
    193       case SLIP_ESC:
    194         priv->state = SLIP_RECV_ESCAPE;
    195         continue;
    196       }
    197       break;
    198     case SLIP_RECV_ESCAPE:
    199       switch (c) {
    200       case SLIP_ESC_END:
    201         c = SLIP_END;
    202         break;
    203       case SLIP_ESC_ESC:
    204         c = SLIP_ESC;
    205         break;
    206       }
    207       priv->state = SLIP_RECV_NORMAL;
    208       /* FALLTHROUGH */
    209     }
    210 
    211     /* byte received, packet not yet completely received */
    212     if (priv->p == NULL) {
    213       /* allocate a new pbuf */
    214       LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
    215       priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL);
    216 
    217       if (priv->p == NULL) {
    218         LINK_STATS_INC(link.drop);
    219         LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
    220         /* don't process any further since we got no pbuf to receive to */
    221         break;
    222       }
    223 
    224       if (priv->q != NULL) {
    225         /* 'chain' the pbuf to the existing chain */
    226         pbuf_cat(priv->q, priv->p);
    227       } else {
    228         /* p is the first pbuf in the chain */
    229         priv->q = priv->p;
    230       }
    231     }
    232 
    233     /* this automatically drops bytes if > SLIP_MAX_SIZE */
    234     if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
    235       ((u8_t *)priv->p->payload)[priv->i] = c;
    236       priv->recved++;
    237       priv->i++;
    238       if (priv->i >= priv->p->len) {
    239         /* on to the next pbuf */
    240         priv->i = 0;
    241         if (priv->p->next != NULL && priv->p->next->len > 0) {
    242           /* p is a chain, on to the next in the chain */
    243             priv->p = priv->p->next;
    244         } else {
    245           /* p is a single pbuf, set it to NULL so next time a new
    246            * pbuf is allocated */
    247             priv->p = NULL;
    248         }
    249       }
    250     }
    251   }
    252 
    253   return NULL;
    254 }
    255 
    256 #if !NO_SYS
    257 /**
    258  * The SLIP input thread.
    259  *
    260  * Feed the IP layer with incoming packets
    261  *
    262  * @param nf the lwip network interface structure for this slipif
    263  */
    264 static void
    265 slipif_loop_thread(void *nf)
    266 {
    267   struct pbuf *p;
    268   struct netif *netif = (struct netif *)nf;
    269 
    270   while (1) {
    271     p = slipif_input(netif, SLIP_BLOCK);
    272     if (p != NULL) {
    273       if (netif->input(p, netif) != ERR_OK) {
    274         pbuf_free(p);
    275         p = NULL;
    276       }
    277     }
    278   }
    279 }
    280 #endif /* !NO_SYS */
    281 
    282 /**
    283  * SLIP netif initialization
    284  *
    285  * Call the arch specific sio_open and remember
    286  * the opened device in the state field of the netif.
    287  *
    288  * @param netif the lwip network interface structure for this slipif
    289  * @return ERR_OK if serial line could be opened,
    290  *         ERR_MEM if no memory could be allocated,
    291  *         ERR_IF is serial line couldn't be opened
    292  *
    293  * @note netif->num must contain the number of the serial port to open
    294  *       (0 by default)
    295  */
    296 err_t
    297 slipif_init(struct netif *netif)
    298 {
    299   struct slipif_priv *priv;
    300 
    301   LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));
    302 
    303   /* Allocate private data */
    304   priv = mem_malloc(sizeof(struct slipif_priv));
    305   if (!priv) {
    306     return ERR_MEM;
    307   }
    308 
    309   netif->name[0] = 's';
    310   netif->name[1] = 'l';
    311   netif->output = slipif_output;
    312   netif->mtu = SLIP_MAX_SIZE;
    313   netif->flags |= NETIF_FLAG_POINTTOPOINT;
    314 
    315   /* Try to open the serial port (netif->num contains the port number). */
    316   priv->sd = sio_open(netif->num);
    317   if (!priv->sd) {
    318     /* Opening the serial port failed. */
    319     mem_free(priv);
    320     return ERR_IF;
    321   }
    322 
    323   /* Initialize private data */
    324   priv->p = NULL;
    325   priv->q = NULL;
    326   priv->state = SLIP_RECV_NORMAL;
    327   priv->i = 0;
    328   priv->recved = 0;
    329 
    330   netif->state = priv;
    331 
    332   /* initialize the snmp variables and counters inside the struct netif
    333    * ifSpeed: no assumption can be made without knowing more about the
    334    * serial line!
    335    */
    336   NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0);
    337 
    338   /* Create a thread to poll the serial line. */
    339   sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
    340     SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
    341   return ERR_OK;
    342 }
    343 
    344 /**
    345  * Polls the serial device and feeds the IP layer with incoming packets.
    346  *
    347  * @param netif The lwip network interface structure for this slipif
    348  */
    349 void
    350 slipif_poll(struct netif *netif)
    351 {
    352   struct pbuf *p;
    353   struct slipif_priv *priv;
    354 
    355   LWIP_ASSERT("netif != NULL", (netif != NULL));
    356   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
    357 
    358   priv = netif->state;
    359 
    360   while ((p = slipif_input(netif, SLIP_DONTBLOCK)) != NULL) {
    361     if (netif->input(p, netif) != ERR_OK) {
    362       pbuf_free(p);
    363     }
    364   }
    365 }
    366 
    367 #endif /* LWIP_HAVE_SLIPIF */
    368