nuttx/drivers/net/slip.c

1030 lines
28 KiB
C
Raw Normal View History

/****************************************************************************
* drivers/net/slip.c
*
* Copyright (C) 2011-2012, 2015-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Reference: RFC 1055
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/clock.h>
#include <nuttx/signal.h>
#include <nuttx/kthread.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/slip.h>
#if defined(CONFIG_NET) && defined(CONFIG_NET_SLIP)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* NOTE: Slip requires UART hardware handshake. If hardware handshake is
* not available with your UART, then you might try the 'slattach' option
* -L which enable "3-wire operation." That allows operation without the
* hardware handshake (but with the possibility of data overrun).
*/
/* Configuration ************************************************************/
#ifndef CONFIG_NET_SLIP_STACKSIZE
# define CONFIG_NET_SLIP_STACKSIZE 2048
#endif
#ifndef CONFIG_NET_SLIP_DEFPRIO
# define CONFIG_NET_SLIP_DEFPRIO 128
#endif
/* The Linux slip module hard-codes its MTU size to 296 (40 bytes for the
* IP+TPC headers plus 256 bytes of data). So you might as well set
This commit attempts remove some long standard confusion in naming and some actual problems that result from the naming confusion. The basic problem is the standard MTU does not include the size of the Ethernet header. For clarity, I changed the naming of most things called MTU to PKTSIZE. For example, CONFIG_NET_ETH_MTU is now CONFIG_NET_ETH_PKTSIZE. This makes the user interface a little hostile. People thing of an MTU of 1500 bytes, but the corresponding packet is really 1514 bytes (including the 14 byte Ethernet header). A more friendly solution would configure the MTU (as before), but then derive the packet buffer size by adding the MAC header length. Instead, we define the packet buffer size then derive the MTU. The MTU is not common currency in networking. On the wire, the only real issue is the MSS which is derived from MTU by subtracting the IP header and TCP header sizes (for the case of TCP). Now it is derived for the PKTSIZE by subtracting the IP header, the TCP header, and the MAC header sizes. So we should be all good and without the recurring 14 byte error in MTU's and MSS's. Squashed commit of the following: Trivial update to fix some spacing issues. net/: Rename several macros containing _MTU to _PKTSIZE. net/: Rename CONFIG_NET_SLIP_MTU to CONFIG_NET_SLIP_PKTSIZE and similarly for CONFIG_NET_TUN_MTU. These are not the MTU which does not include the size of the link layer header. These are the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename CONFIG_NET_6LOWPAN_MTU to CONFIG_NET_6LOWPAN_PKTSIZE and similarly for CONFIG_NET_TUN_MTU. These are not the MTU which does not include the size of the link layer header. These are the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename CONFIG_NET_ETH_MTU to CONFIG_NET_ETH_PKTSIZE. This is not the MTU which does not include the size of the link layer header. This is the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename the file d_mtu in the network driver structure to d_pktsize. That value saved there is not the MTU. The packetsize is the memory large enough to hold the maximum packet PLUS the size of the link layer header. The MTU does not include the link layer header.
2018-07-04 22:10:40 +02:00
* CONFIG_NET_SLIP_PKTSIZE to 296 as well.
*
* There may be an issue with this setting, however. I see that Linux uses
* a MTU of 296 and window of 256, but actually only sends 168 bytes of data:
* 40 + 128. I believe that is to allow for the 2x worst cast packet
* expansion. Ideally we would like to advertise the 256 MSS, but restrict
* transfers to 128 bytes (possibly by modifying the tcp_mss() macro).
*/
This commit attempts remove some long standard confusion in naming and some actual problems that result from the naming confusion. The basic problem is the standard MTU does not include the size of the Ethernet header. For clarity, I changed the naming of most things called MTU to PKTSIZE. For example, CONFIG_NET_ETH_MTU is now CONFIG_NET_ETH_PKTSIZE. This makes the user interface a little hostile. People thing of an MTU of 1500 bytes, but the corresponding packet is really 1514 bytes (including the 14 byte Ethernet header). A more friendly solution would configure the MTU (as before), but then derive the packet buffer size by adding the MAC header length. Instead, we define the packet buffer size then derive the MTU. The MTU is not common currency in networking. On the wire, the only real issue is the MSS which is derived from MTU by subtracting the IP header and TCP header sizes (for the case of TCP). Now it is derived for the PKTSIZE by subtracting the IP header, the TCP header, and the MAC header sizes. So we should be all good and without the recurring 14 byte error in MTU's and MSS's. Squashed commit of the following: Trivial update to fix some spacing issues. net/: Rename several macros containing _MTU to _PKTSIZE. net/: Rename CONFIG_NET_SLIP_MTU to CONFIG_NET_SLIP_PKTSIZE and similarly for CONFIG_NET_TUN_MTU. These are not the MTU which does not include the size of the link layer header. These are the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename CONFIG_NET_6LOWPAN_MTU to CONFIG_NET_6LOWPAN_PKTSIZE and similarly for CONFIG_NET_TUN_MTU. These are not the MTU which does not include the size of the link layer header. These are the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename CONFIG_NET_ETH_MTU to CONFIG_NET_ETH_PKTSIZE. This is not the MTU which does not include the size of the link layer header. This is the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename the file d_mtu in the network driver structure to d_pktsize. That value saved there is not the MTU. The packetsize is the memory large enough to hold the maximum packet PLUS the size of the link layer header. The MTU does not include the link layer header.
2018-07-04 22:10:40 +02:00
#if CONFIG_NET_SLIP_PKTSIZE < 296
# error "CONFIG_NET_SLIP_PKTSIZE >= 296 is required"
#endif
/* CONFIG_NET_SLIP_NINTERFACES determines the number of physical interfaces
* that will be supported.
*/
#ifndef CONFIG_NET_SLIP_NINTERFACES
# define CONFIG_NET_SLIP_NINTERFACES 1
#endif
/* SLIP special character codes *******************************************/
#define SLIP_END 0300 /* Indicates end of packet */
#define SLIP_ESC 0333 /* Indicates byte stuffing */
#define SLIP_ESC_END 0334 /* ESC ESC_END means SLIP_END data byte */
#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */
/* General driver definitions **********************************************/
/* TX poll delay = 1 second = 1000000 microseconds. */
#define SLIP_WDDELAY (1*1000000)
#define SLIP_POLLHSEC (1*2)
/****************************************************************************
* Private Types
****************************************************************************/
/* The slip_driver_s encapsulates all state information for a single hardware
* interface
*/
struct slip_driver_s
{
volatile bool bifup; /* true:ifup false:ifdown */
bool txnodelay; /* True: nxsig_usleep() not needed */
int16_t fd; /* TTY file descriptor */
uint16_t rxlen; /* The number of bytes in rxbuf */
pid_t rxpid; /* Receiver thread ID */
pid_t txpid; /* Transmitter thread ID */
sem_t waitsem; /* Mutually exclusive access to the network */
/* This holds the information visible to the NuttX network */
struct net_driver_s dev; /* Interface understood by the network */
This commit attempts remove some long standard confusion in naming and some actual problems that result from the naming confusion. The basic problem is the standard MTU does not include the size of the Ethernet header. For clarity, I changed the naming of most things called MTU to PKTSIZE. For example, CONFIG_NET_ETH_MTU is now CONFIG_NET_ETH_PKTSIZE. This makes the user interface a little hostile. People thing of an MTU of 1500 bytes, but the corresponding packet is really 1514 bytes (including the 14 byte Ethernet header). A more friendly solution would configure the MTU (as before), but then derive the packet buffer size by adding the MAC header length. Instead, we define the packet buffer size then derive the MTU. The MTU is not common currency in networking. On the wire, the only real issue is the MSS which is derived from MTU by subtracting the IP header and TCP header sizes (for the case of TCP). Now it is derived for the PKTSIZE by subtracting the IP header, the TCP header, and the MAC header sizes. So we should be all good and without the recurring 14 byte error in MTU's and MSS's. Squashed commit of the following: Trivial update to fix some spacing issues. net/: Rename several macros containing _MTU to _PKTSIZE. net/: Rename CONFIG_NET_SLIP_MTU to CONFIG_NET_SLIP_PKTSIZE and similarly for CONFIG_NET_TUN_MTU. These are not the MTU which does not include the size of the link layer header. These are the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename CONFIG_NET_6LOWPAN_MTU to CONFIG_NET_6LOWPAN_PKTSIZE and similarly for CONFIG_NET_TUN_MTU. These are not the MTU which does not include the size of the link layer header. These are the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename CONFIG_NET_ETH_MTU to CONFIG_NET_ETH_PKTSIZE. This is not the MTU which does not include the size of the link layer header. This is the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename the file d_mtu in the network driver structure to d_pktsize. That value saved there is not the MTU. The packetsize is the memory large enough to hold the maximum packet PLUS the size of the link layer header. The MTU does not include the link layer header.
2018-07-04 22:10:40 +02:00
uint8_t rxbuf[CONFIG_NET_SLIP_PKTSIZE + 2];
uint8_t txbuf[CONFIG_NET_SLIP_PKTSIZE + 2];
};
/****************************************************************************
* Private Data
****************************************************************************/
2015-10-04 23:04:00 +02:00
/* We really should get rid of CONFIG_NET_SLIP_NINTERFACES and, instead,
* kmm_malloc() new interface instances as needed.
*/
static struct slip_driver_s g_slip[CONFIG_NET_SLIP_NINTERFACES];
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void slip_semtake(FAR struct slip_driver_s *priv);
/* Common TX logic */
static void slip_write(FAR struct slip_driver_s *priv,
FAR const uint8_t *buffer, int len);
static void slip_putc(FAR struct slip_driver_s *priv, int ch);
static int slip_transmit(FAR struct slip_driver_s *priv);
static int slip_txpoll(FAR struct net_driver_s *dev);
static void slip_txtask(int argc, FAR char *argv[]);
/* Packet receiver task */
static int slip_getc(FAR struct slip_driver_s *priv);
static inline void slip_receive(FAR struct slip_driver_s *priv);
static int slip_rxtask(int argc, FAR char *argv[]);
/* NuttX callback functions */
static int slip_ifup(FAR struct net_driver_s *dev);
static int slip_ifdown(FAR struct net_driver_s *dev);
static int slip_txavail(FAR struct net_driver_s *dev);
#ifdef CONFIG_NET_MCASTGROUP
static int slip_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
static int slip_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: slip_semtake
****************************************************************************/
static void slip_semtake(FAR struct slip_driver_s *priv)
{
int ret;
do
{
/* Take the semaphore (perhaps waiting) */
ret = nxsem_wait(&priv->waitsem);
/* The only case that an error should occur here is if the wait was
* awakened by a signal.
*/
DEBUGASSERT(ret == OK || ret == -EINTR);
}
while (ret == -EINTR);
}
#define slip_semgive(p) nxsem_post(&(p)->waitsem);
/****************************************************************************
* Name: slip_write
*
* Description:
* Just an inline wrapper around fwrite with error checking.
*
* Input Parameters:
* priv - Reference to the driver state structure
* buffer - Buffer data to send
* len - Buffer length in bytes
*
****************************************************************************/
static inline void slip_write(FAR struct slip_driver_s *priv,
FAR const uint8_t *buffer, int len)
{
/* Handle the case where the write is awakened by a signal */
while (write(priv->fd, buffer, len) < 0)
{
DEBUGASSERT(errno == EINTR);
}
}
/****************************************************************************
* Name: slip_putc
*
* Description:
* Just an inline wrapper around putc with error checking.
*
* Input Parameters:
* priv - Reference to the driver state structure
* ch - The character to send
*
****************************************************************************/
static inline void slip_putc(FAR struct slip_driver_s *priv, int ch)
{
uint8_t buffer = (uint8_t)ch;
slip_write(priv, &buffer, 1);
}
/****************************************************************************
* Name: slip_transmit
*
* Description:
* Start hardware transmission. Called either from the txdone interrupt
* handling or from watchdog based polling.
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* OK on success; a negated errno on failure
*
****************************************************************************/
static int slip_transmit(FAR struct slip_driver_s *priv)
{
uint8_t *src;
uint8_t *start;
uint8_t esc;
int remaining;
int len;
/* Increment statistics */
ninfo("Sending packet size %d\n", priv->dev.d_len);
NETDEV_TXPACKETS(&priv->dev);
/* Send an initial END character to flush out any data that may have
* accumulated in the receiver due to line noise
*/
slip_putc(priv, SLIP_END);
/* For each byte in the packet, send the appropriate character sequence */
src = priv->dev.d_buf;
remaining = priv->dev.d_len;
start = src;
len = 0;
2014-04-13 22:32:20 +02:00
while (remaining-- > 0)
{
switch (*src)
{
/* If it's the same code as an END character, we send a special two
* character code so as not to make the receiver think we sent an
* END
*/
case SLIP_END:
esc = SLIP_ESC_END;
goto escape;
/* If it's the same code as an ESC character, we send a special two
* character code so as not to make the receiver think we sent an
* ESC
*/
case SLIP_ESC:
esc = SLIP_ESC_ESC;
escape:
{
/* Flush any unsent data */
if (len > 0)
{
slip_write(priv, start, len);
2014-07-22 14:55:42 +02:00
}
2014-07-22 14:55:42 +02:00
/* Reset */
2014-07-22 14:55:42 +02:00
start = src + 1;
len = 0;
/* Then send the escape sequence */
slip_putc(priv, SLIP_ESC);
slip_putc(priv, esc);
}
break;
/* otherwise, just bump up the count */
default:
len++;
break;
}
/* Point to the next character in the packet */
src++;
}
/* We have looked at every character in the packet. Now flush any unsent
* data
*/
if (len > 0)
{
slip_write(priv, start, len);
}
/* And send the END token */
slip_putc(priv, SLIP_END);
NETDEV_TXDONE(&priv->dev);
priv->txnodelay = true;
return OK;
}
/****************************************************************************
* Name: slip_txpoll
*
* Description:
* Check if the network has any outgoing packets ready to send. This is a
* callback from devif_poll(). devif_poll() may be called:
*
* 1. When the preceding TX packet send is complete, or
* 2. During normal periodic polling
*
* Input Parameters:
* dev - Reference to the NuttX driver state structure
*
* Returned Value:
* OK on success; a negated errno on failure
*
* Assumptions:
* The initiator of the poll holds the priv->waitsem;
*
****************************************************************************/
static int slip_txpoll(FAR struct net_driver_s *dev)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
/* If the polling resulted in data that should be sent out on the network,
* the field d_len is set to a value > 0.
*/
if (priv->dev.d_len > 0)
{
if (!devif_loopback(&priv->dev))
{
slip_transmit(priv);
}
}
/* If zero is returned, the polling will continue until all connections have
* been examined.
*/
return 0;
}
/****************************************************************************
* Name: slip_txtask
*
* Description:
* Polling and transmission is performed on tx thread.
*
* Input Parameters:
* arg - Reference to the NuttX driver state structure
*
* Returned Value:
* None
*
****************************************************************************/
static void slip_txtask(int argc, FAR char *argv[])
{
FAR struct slip_driver_s *priv;
unsigned int index = *(argv[1]) - '0';
clock_t start_ticks;
clock_t now_ticks;
unsigned int hsec;
nerr("index: %d\n", index);
DEBUGASSERT(index < CONFIG_NET_SLIP_NINTERFACES);
/* Get our private data structure instance and wake up the waiting
* initialization logic.
*/
priv = &g_slip[index];
slip_semgive(priv);
/* Loop forever */
start_ticks = clock_systimer();
for (; ; )
{
/* Wait for the timeout to expire (or until we are signaled by by */
slip_semtake(priv);
if (!priv->txnodelay)
{
slip_semgive(priv);
nxsig_usleep(SLIP_WDDELAY);
}
else
{
priv->txnodelay = false;
slip_semgive(priv);
}
/* Is the interface up? */
if (priv->bifup)
{
/* Get exclusive access to the network (if it it is already being used
* slip_rxtask, then we have to wait).
*/
slip_semtake(priv);
/* Poll the networking layer for new XMIT data. */
net_lock();
priv->dev.d_buf = priv->txbuf;
/* Has a half second elapsed since the last timer poll? */
now_ticks = clock_systimer();
hsec = (unsigned int)((now_ticks - start_ticks) / TICK_PER_HSEC);
if (hsec > 0)
{
/* Yes, perform the timer poll */
(void)devif_timer(&priv->dev, slip_txpoll);
start_ticks += hsec * TICK_PER_HSEC;
}
else
{
/* No, perform the normal TX poll */
(void)devif_poll(&priv->dev, slip_txpoll);
}
net_unlock();
slip_semgive(priv);
}
}
}
/****************************************************************************
* Name: slip_getc
*
* Description:
* Get one byte from the serial input.
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* The returned byte
*
****************************************************************************/
static inline int slip_getc(FAR struct slip_driver_s *priv)
{
uint8_t ch;
while (read(priv->fd, &ch, 1) < 0)
{
DEBUGASSERT(errno == EINTR);
}
return (int)ch;
}
/****************************************************************************
* Name: slip_receive
*
* Description:
* Read a packet from the serial input
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* None
*
****************************************************************************/
static inline void slip_receive(FAR struct slip_driver_s *priv)
{
uint8_t ch;
/* Copy the data data from the hardware to to the RX buffer until we
* put together a whole packet. Make sure not to copy them into the
* packet if we run out of room.
*/
ninfo("Receiving packet\n");
for (; ; )
{
/* Get the next character in the stream. */
ch = slip_getc(priv);
/* Handle bytestuffing if necessary */
2014-04-13 22:32:20 +02:00
switch (ch)
{
/* If it's an END character then we're done with the packet.
* (OR we are just starting a packet)
*/
case SLIP_END:
{
ninfo("END\n");
/* A minor optimization: if there is no data in the packet,
* ignore it. This is meant to avoid bothering IP with all the
* empty packets generated by the duplicate END characters which
* are in turn sent to try to detect line noise.
*/
if (priv->rxlen > 0)
{
ninfo("Received packet size %d\n", priv->rxlen);
return;
}
}
break;
/* if it's the same code as an ESC character, wait and get another
* character and then figure out what to store in the packet based
* on that.
*/
case SLIP_ESC:
{
ninfo("ESC\n");
ch = slip_getc(priv);
/* if "ch" is not one of these two, then we have a protocol
* violation. The best bet seems to be to leave the byte alone
* and just stuff it into the packet
*/
switch (ch)
{
case SLIP_ESC_END:
ninfo("ESC-END\n");
ch = SLIP_END;
break;
case SLIP_ESC_ESC:
ninfo("ESC-ESC\n");
ch = SLIP_ESC;
break;
default:
nerr("ERROR: Protocol violation: %02x\n", ch);
break;
}
/* Here we fall into the default handler and let it store the
* character for us
*/
}
default:
{
This commit attempts remove some long standard confusion in naming and some actual problems that result from the naming confusion. The basic problem is the standard MTU does not include the size of the Ethernet header. For clarity, I changed the naming of most things called MTU to PKTSIZE. For example, CONFIG_NET_ETH_MTU is now CONFIG_NET_ETH_PKTSIZE. This makes the user interface a little hostile. People thing of an MTU of 1500 bytes, but the corresponding packet is really 1514 bytes (including the 14 byte Ethernet header). A more friendly solution would configure the MTU (as before), but then derive the packet buffer size by adding the MAC header length. Instead, we define the packet buffer size then derive the MTU. The MTU is not common currency in networking. On the wire, the only real issue is the MSS which is derived from MTU by subtracting the IP header and TCP header sizes (for the case of TCP). Now it is derived for the PKTSIZE by subtracting the IP header, the TCP header, and the MAC header sizes. So we should be all good and without the recurring 14 byte error in MTU's and MSS's. Squashed commit of the following: Trivial update to fix some spacing issues. net/: Rename several macros containing _MTU to _PKTSIZE. net/: Rename CONFIG_NET_SLIP_MTU to CONFIG_NET_SLIP_PKTSIZE and similarly for CONFIG_NET_TUN_MTU. These are not the MTU which does not include the size of the link layer header. These are the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename CONFIG_NET_6LOWPAN_MTU to CONFIG_NET_6LOWPAN_PKTSIZE and similarly for CONFIG_NET_TUN_MTU. These are not the MTU which does not include the size of the link layer header. These are the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename CONFIG_NET_ETH_MTU to CONFIG_NET_ETH_PKTSIZE. This is not the MTU which does not include the size of the link layer header. This is the full size of the packet buffer memory (minus any GUARD bytes). net/: Rename the file d_mtu in the network driver structure to d_pktsize. That value saved there is not the MTU. The packetsize is the memory large enough to hold the maximum packet PLUS the size of the link layer header. The MTU does not include the link layer header.
2018-07-04 22:10:40 +02:00
if (priv->rxlen < CONFIG_NET_SLIP_PKTSIZE+2)
{
priv->rxbuf[priv->rxlen++] = ch;
}
}
break;
}
}
}
/****************************************************************************
* Name: slip_rxtask
*
* Description:
* Wait for incoming data.
*
* Input Parameters:
* argc
* argv
*
* Returned Value:
* (Does not return)
*
* Assumptions:
*
****************************************************************************/
static int slip_rxtask(int argc, FAR char *argv[])
{
FAR struct slip_driver_s *priv;
unsigned int index = *(argv[1]) - '0';
int ch;
nerr("index: %d\n", index);
DEBUGASSERT(index < CONFIG_NET_SLIP_NINTERFACES);
/* Get our private data structure instance and wake up the waiting
* initialization logic.
*/
priv = &g_slip[index];
slip_semgive(priv);
/* Loop forever */
for (; ; )
{
/* Wait for the next character to be available on the input stream. */
ninfo("Waiting...\n");
ch = slip_getc(priv);
/* Ignore any input that we receive before the interface is up. */
if (!priv->bifup)
{
continue;
}
/* We have something...
*
* END characters may appear at packet boundaries BEFORE as well as
* after the beginning of the packet. This is normal and expected.
*/
if (ch == SLIP_END)
{
priv->rxlen = 0;
}
/* Otherwise, we are in danger of being out-of-sync. Apparently the
* leading END character is optional. Let's try to continue.
*/
else
{
priv->rxbuf[0] = (uint8_t)ch;
priv->rxlen = 1;
}
/* Copy the data data from the hardware to priv->rxbuf until we put
* together a whole packet.
*/
slip_receive(priv);
NETDEV_RXPACKETS(&priv->dev);
/* All packets are assumed to be IP packets (we don't have a choice..
* there is no Ethernet header containing the EtherType). So pass the
* received packet on for IP processing -- but only if it is big
* enough to hold an IP header.
*/
if (priv->rxlen >= IPv4_HDRLEN)
{
NETDEV_RXIPV4(&priv->dev);
/* Handle the IP input. Get exclusive access to the network. */
slip_semtake(priv);
priv->dev.d_buf = priv->rxbuf;
priv->dev.d_len = priv->rxlen;
net_lock();
ipv4_input(&priv->dev);
/* If the above function invocation resulted in data that should
* be sent out on the network, the field d_len will set to a
* value > 0. NOTE that we are transmitting using the RX buffer!
*/
if (priv->dev.d_len > 0)
{
2014-04-13 22:32:20 +02:00
slip_transmit(priv);
(void)nxsig_kill(priv->txpid, SIGALRM);
}
net_unlock();
slip_semgive(priv);
}
else
{
NETDEV_RXERRORS(&priv->dev);
}
}
/* We won't get here */
return OK;
}
/****************************************************************************
* Name: slip_ifup
*
* Description:
* NuttX Callback: Bring up the Ethernet interface when an IP address is
2014-04-13 22:32:20 +02:00
* provided
*
* Input Parameters:
* dev - Reference to the NuttX driver state structure
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
static int slip_ifup(FAR struct net_driver_s *dev)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
nerr("Bringing up: %d.%d.%d.%d\n",
dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
(dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24);
/* Mark the interface up */
priv->bifup = true;
return OK;
}
/****************************************************************************
* Name: slip_ifdown
*
* Description:
* NuttX Callback: Stop the interface.
*
* Input Parameters:
* dev - Reference to the NuttX driver state structure
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
static int slip_ifdown(FAR struct net_driver_s *dev)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
/* Mark the device "down" */
priv->bifup = false;
return OK;
}
/****************************************************************************
* Name: slip_txavail
*
* Description:
2014-04-13 22:32:20 +02:00
* Driver callback invoked when new TX data is available. This is a
* stimulus perform an out-of-cycle poll and, thereby, reduce the TX
* latency.
*
* Input Parameters:
* dev - Reference to the NuttX driver state structure
*
* Returned Value:
* None
*
****************************************************************************/
static int slip_txavail(FAR struct net_driver_s *dev)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
/* Ignore the notification if the interface is not yet up */
if (priv->bifup)
{
/* Wake up the TX polling thread */
priv->txnodelay = true;
(void)nxsig_kill(priv->txpid, SIGALRM);
}
return OK;
}
/****************************************************************************
* Name: slip_addmac
*
* Description:
* NuttX Callback: Add the specified MAC address to the hardware multicast
* address filtering
*
* Input Parameters:
* dev - Reference to the NuttX driver state structure
2014-04-13 22:32:20 +02:00
* mac - The MAC address to be added
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
#ifdef CONFIG_NET_MCASTGROUP
static int slip_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
/* Add the MAC address to the hardware multicast routing table */
return OK;
}
#endif
/****************************************************************************
* Name: slip_rmmac
*
* Description:
* NuttX Callback: Remove the specified MAC address from the hardware multicast
* address filtering
*
* Input Parameters:
* dev - Reference to the NuttX driver state structure
2014-04-13 22:32:20 +02:00
* mac - The MAC address to be removed
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
#ifdef CONFIG_NET_MCASTGROUP
static int slip_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
{
FAR struct slip_driver_s *priv = (FAR struct slip_driver_s *)dev->d_private;
/* Add the MAC address to the hardware multicast routing table */
return OK;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: slip_initialize
*
* Description:
* Instantiate a SLIP network interface.
*
* Input Parameters:
* intf - In the case where there are multiple SLIP interfaces, this
* value identifies which is to be initialized. The number of
* possible SLIP interfaces is determined by
* devname - This is the path to the serial device that will support SLIP.
* For example, this might be "/dev/ttyS1"
*
* Returned Value:
* OK on success; Negated errno on failure.
*
* Assumptions:
*
****************************************************************************/
int slip_initialize(int intf, FAR const char *devname)
{
FAR struct slip_driver_s *priv;
char buffer[8];
FAR char *argv[2];
int ret;
/* Get the interface structure associated with this interface number. */
DEBUGASSERT(intf < CONFIG_NET_SLIP_NINTERFACES);
priv = &g_slip[intf];
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct slip_driver_s));
priv->dev.d_ifup = slip_ifup; /* I/F up (new IP address) callback */
priv->dev.d_ifdown = slip_ifdown; /* I/F down callback */
priv->dev.d_txavail = slip_txavail; /* New TX data callback */
#ifdef CONFIG_NET_MCASTGROUP
priv->dev.d_addmac = slip_addmac; /* Add multicast MAC address */
priv->dev.d_rmmac = slip_rmmac; /* Remove multicast MAC address */
#endif
priv->dev.d_private = priv; /* Used to recover private state from dev */
/* Open the device */
priv->fd = nx_open(devname, O_RDWR, 0666);
if (priv->fd < 0)
{
ret = priv->fd;
nerr("ERROR: Failed to open %s: %d\n", devname, ret);
return ret;
}
/* Initialize the wait semaphore */
nxsem_init(&priv->waitsem, 0, 0);
nxsem_setprotocol(&priv->waitsem, SEM_PRIO_NONE);
/* Put the interface in the down state. This usually amounts to resetting
* the device and/or calling slip_ifdown().
*/
slip_ifdown(&priv->dev);
/* Start the SLIP receiver kernel thread */
snprintf(buffer, 8, "%d", intf);
argv[0] = buffer;
argv[1] = NULL;
priv->rxpid = kthread_create("rxslip", CONFIG_NET_SLIP_DEFPRIO,
CONFIG_NET_SLIP_STACKSIZE, (main_t)slip_rxtask,
(FAR char * const *)argv);
if (priv->rxpid < 0)
{
nerr("ERROR: Failed to start receiver task\n");
return -errno;
}
/* Wait and make sure that the receive task is started. */
slip_semtake(priv);
/* Start the SLIP transmitter kernel thread */
priv->txpid = kthread_create("txslip", CONFIG_NET_SLIP_DEFPRIO,
CONFIG_NET_SLIP_STACKSIZE, (main_t)slip_txtask,
(FAR char * const *)argv);
if (priv->txpid < 0)
{
nerr("ERROR: Failed to start receiver task\n");
return -errno;
}
/* Wait and make sure that the transmit task is started. */
slip_semtake(priv);
/* Bump the semaphore count so that it can now be used as a mutex */
slip_semgive(priv);
/* Register the device with the OS so that socket IOCTLs can be performed */
(void)netdev_register(&priv->dev, NET_LL_SLIP);
/* When the RX and TX tasks were created, the TTY file descriptor was
* dup'ed for each task. This task no longer needs the file descriptor
* and we can safely close it.
*/
close(priv->fd);
return OK;
}
#endif /* CONFIG_NET && CONFIG_NET_SLIP */