net/netdev: Use upper half of netdev to simplify sim driver

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-03-13 16:54:42 +08:00 committed by Xiang Xiao
parent 72b77d36e2
commit f21742899f
3 changed files with 320 additions and 245 deletions

View File

@ -66,288 +66,150 @@
#include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/netdev_lowerhalf.h>
#include <nuttx/net/pkt.h>
#include "sim_internal.h"
#if CONFIG_IOB_BUFSIZE >= (MAX_NETDEV_PKTSIZE + \
CONFIG_NET_GUARDSIZE + CONFIG_NET_LL_GUARDSIZE)
# define SIM_NETDEV_IOB_OFFLOAD
#define SIM_NETDEV_BUFSIZE (MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE)
/* We don't know packet length before receiving, so we can only offload it
* when netpkt's buffer is long enough.
*/
#if NETPKT_BUFLEN >= SIM_NETDEV_BUFSIZE
# define SIM_NETDEV_RECV_OFFLOAD
#endif
/* Get index / buffer from dev pointer. */
#define DEVIDX(p) ((struct sim_netdev_s *)(p) - g_sim_dev)
#define DEVBUF(p) (((struct sim_netdev_s *)(p))->buf)
/****************************************************************************
* Private Types
****************************************************************************/
struct sim_netdev_s
{
struct netdev_lowerhalf_s dev;
uint8_t buf[SIM_NETDEV_BUFSIZE]; /* Used when packet buffer is fragmented */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void netdriver_txdone_interrupt(void *priv);
static int netdriver_send(struct netdev_lowerhalf_s *dev, netpkt_t *pkt);
static netpkt_t *netdriver_recv(struct netdev_lowerhalf_s *dev);
static int netdriver_ifup(struct netdev_lowerhalf_s *dev);
static int netdriver_ifdown(struct netdev_lowerhalf_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
/* Net driver worker */
static struct work_s g_avail_work[CONFIG_SIM_NETDEV_NUMBER];
static struct work_s g_recv_work[CONFIG_SIM_NETDEV_NUMBER];
/* Ethernet peripheral state */
static struct net_driver_s g_sim_dev[CONFIG_SIM_NETDEV_NUMBER];
static struct sim_netdev_s g_sim_dev[CONFIG_SIM_NETDEV_NUMBER];
static const struct netdev_ops_s g_ops =
{
netdriver_ifup, /* ifup */
netdriver_ifdown, /* ifdown */
netdriver_send, /* transmit */
netdriver_recv /* receive */
};
/****************************************************************************
* Private Functions
****************************************************************************/
static void netdriver_send(struct net_driver_s *dev)
static int netdriver_send(struct netdev_lowerhalf_s *dev, netpkt_t *pkt)
{
int devidx = (intptr_t)dev->d_private;
#ifdef SIM_NETDEV_IOB_OFFLOAD
uint8_t *buf = NETLLBUF;
#else
uint8_t *buf = dev->d_buf;
#endif
unsigned int len = netpkt_getdatalen(dev, pkt);
UNUSED(devidx);
#ifdef CONFIG_NET_PKT
/* When packet sockets are enabled, feed the tx frame into it */
pkt_input(dev);
#endif
sim_netdev_send(devidx, buf, dev->d_len);
}
static void netdriver_reply(struct net_driver_s *dev)
{
/* If the receiving resulted in data that should be sent out on
* the network, the field d_len is set to a value > 0.
*/
if (dev->d_len > 0)
if (netpkt_is_fragmented(pkt))
{
/* Send the packet */
NETDEV_TXPACKETS(dev);
netdriver_send(dev);
NETDEV_TXDONE(dev);
netpkt_copyout(dev, DEVBUF(dev), pkt, len, 0);
sim_netdev_send(DEVIDX(dev), DEVBUF(dev), len);
}
else
{
sim_netdev_send(DEVIDX(dev), netpkt_getdata(dev, pkt), len);
}
netpkt_free(dev, pkt, NETPKT_TX);
return OK;
}
static void netdriver_recv_work(void *arg)
static netpkt_t *netdriver_recv(struct netdev_lowerhalf_s *dev)
{
struct net_driver_s *dev = arg;
struct eth_hdr_s *eth;
int devidx = (intptr_t)dev->d_private;
netpkt_t *pkt = NULL;
unsigned int len;
UNUSED(devidx);
net_lock();
/* Retrieve all the queued RX frames from the network device
* to prevent RX data stream congestion.
*/
while (sim_netdev_avail(devidx))
if (sim_netdev_avail(DEVIDX(dev)))
{
#ifdef SIM_NETDEV_IOB_OFFLOAD
if (netdev_iob_prepare(dev, false, 0) != OK)
pkt = netpkt_alloc(dev, NETPKT_RX);
if (pkt == NULL)
{
netdriver_txdone_interrupt(dev);
break;
return NULL;
}
#endif
/* sim_netdev_read will return 0 on a timeout event and > 0
* on a data received event
*/
dev->d_len = sim_netdev_read(devidx,
(unsigned char *)dev->d_buf,
dev->d_pktsize);
if (dev->d_len > 0)
#ifdef SIM_NETDEV_RECV_OFFLOAD
len = sim_netdev_read(DEVIDX(dev), netpkt_getbase(pkt),
SIM_NETDEV_BUFSIZE);
#else
len = sim_netdev_read(DEVIDX(dev), DEVBUF(dev), SIM_NETDEV_BUFSIZE);
#endif
if (len == 0)
{
NETDEV_RXPACKETS(dev);
#ifdef SIM_NETDEV_IOB_OFFLOAD
iob_update_pktlen(dev->d_iob, dev->d_len - NET_LL_HDRLEN(dev));
#endif
/* Data received event. Check for valid Ethernet header with
* destination == our MAC address
*/
eth = (struct eth_hdr_s *)dev->d_buf;
if (dev->d_len > ETH_HDRLEN)
{
#ifdef CONFIG_NET_PKT
/* When packet sockets are enabled, feed the frame into
* the packet tap.
*/
pkt_input(dev);
#endif /* CONFIG_NET_PKT */
/* We only accept IP packets of the configured type
* and ARP packets
*/
#ifdef CONFIG_NET_IPv4
if (eth->type == HTONS(ETHTYPE_IP))
{
ninfo("IPv4 frame\n");
NETDEV_RXIPV4(dev);
/* Receive an IPv4 packet from the network device */
ipv4_input(dev);
/* Check for a reply to the IPv4 packet */
netdriver_reply(dev);
}
else
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
if (eth->type == HTONS(ETHTYPE_IP6))
{
ninfo("IPv6 frame\n");
NETDEV_RXIPV6(dev);
/* Give the IPv6 packet to the network layer */
ipv6_input(dev);
/* Check for a reply to the IPv6 packet */
netdriver_reply(dev);
}
else
#endif/* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_ARP
if (eth->type == HTONS(ETHTYPE_ARP))
{
ninfo("ARP frame\n");
NETDEV_RXARP(dev);
arp_input(dev);
/* If the above function invocation resulted in data that
* should be sent out on the network, the global variable
* d_len is set to a value > 0.
*/
if (dev->d_len > 0)
{
netdriver_send(dev);
}
}
else
#endif
{
NETDEV_RXDROPPED(dev);
nwarn("WARNING: Unsupported Ethernet type %u\n",
eth->type);
}
}
else
{
NETDEV_RXERRORS(dev);
}
netpkt_free(dev, pkt, NETPKT_RX);
return NULL;
}
#ifdef SIM_NETDEV_IOB_OFFLOAD
netdev_iob_release(dev);
#ifdef SIM_NETDEV_RECV_OFFLOAD
netpkt_reset_reserved(dev, pkt, 0); /* No overhead before data. */
netpkt_setdatalen(dev, pkt, len);
#else
netpkt_copyin(dev, pkt, DEVBUF(dev), len, 0);
#endif
}
net_unlock();
return pkt;
}
static int netdriver_txpoll(struct net_driver_s *dev)
static int netdriver_ifup(struct netdev_lowerhalf_s *dev)
{
/* Send the packet */
NETDEV_TXPACKETS(dev);
netdriver_send(dev);
NETDEV_TXDONE(dev);
/* If zero is returned, the polling will continue until all connections
* have been examined.
*/
return 0;
}
static int netdriver_ifup(struct net_driver_s *dev)
{
int devidx = (intptr_t)dev->d_private;
UNUSED(devidx);
#ifdef CONFIG_NET_IPv4
sim_netdev_ifup(devidx, &dev->d_ipaddr);
sim_netdev_ifup(DEVIDX(dev), &dev->netdev.d_ipaddr);
#else /* CONFIG_NET_IPv6 */
sim_netdev_ifup(devidx, &dev->d_ipv6addr);
sim_netdev_ifup(DEVIDX(dev), &dev->netdev.d_ipv6addr);
#endif /* CONFIG_NET_IPv4 */
netdev_carrier_on(dev);
netdev_lower_carrier_on(dev);
return OK;
}
static int netdriver_ifdown(struct net_driver_s *dev)
static int netdriver_ifdown(struct netdev_lowerhalf_s *dev)
{
int devidx = (intptr_t)dev->d_private;
UNUSED(devidx);
netdev_carrier_off(dev);
sim_netdev_ifdown(devidx);
return OK;
}
static void netdriver_txavail_work(void *arg)
{
struct net_driver_s *dev = arg;
net_lock();
if (IFF_IS_UP(dev->d_flags))
{
devif_poll(dev, netdriver_txpoll);
}
net_unlock();
}
static int netdriver_txavail(struct net_driver_s *dev)
{
int devidx = (intptr_t)dev->d_private;
if (work_available(&g_avail_work[devidx]))
{
work_queue(LPWORK, &g_avail_work[devidx], netdriver_txavail_work,
dev, 0);
}
netdev_lower_carrier_off(dev);
sim_netdev_ifdown(DEVIDX(dev));
return OK;
}
static void netdriver_txdone_interrupt(void *priv)
{
struct net_driver_s *dev = (struct net_driver_s *)priv;
int devidx = (intptr_t)dev->d_private;
if (work_available(&g_avail_work[devidx]))
{
work_queue(LPWORK, &g_avail_work[devidx], netdriver_txavail_work,
dev, 0);
}
struct netdev_lowerhalf_s *dev = (struct netdev_lowerhalf_s *)priv;
netdev_lower_txdone(dev);
}
static void netdriver_rxready_interrupt(void *priv)
{
struct net_driver_s *dev = (struct net_driver_s *)priv;
int devidx = (intptr_t)dev->d_private;
if (work_available(&g_recv_work[devidx]))
{
work_queue(LPWORK, &g_recv_work[devidx], netdriver_recv_work, dev, 0);
}
struct netdev_lowerhalf_s *dev = (struct netdev_lowerhalf_s *)priv;
netdev_lower_rxready(dev);
}
/****************************************************************************
@ -356,42 +218,30 @@ static void netdriver_rxready_interrupt(void *priv)
int sim_netdriver_init(void)
{
struct net_driver_s *dev;
struct netdev_lowerhalf_s *dev;
int devidx;
for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++)
{
dev = &g_sim_dev[devidx];
dev = &g_sim_dev[devidx].dev;
/* Internal initialization */
sim_netdev_init(devidx, dev,
netdriver_txdone_interrupt,
netdriver_rxready_interrupt);
netdriver_txdone_interrupt,
netdriver_rxready_interrupt);
/* Allocate packet buffer */
/* 1TX + 1RX is enough for sim. */
#ifndef SIM_NETDEV_IOB_OFFLOAD
dev->d_buf = kmm_malloc(dev->d_pktsize != 0 ?
dev->d_pktsize :
(MAX_NETDEV_PKTSIZE +
CONFIG_NET_GUARDSIZE));
if (dev->d_buf == NULL)
{
return -ENOMEM;
}
#endif
dev->d_ifup = netdriver_ifup;
dev->d_ifdown = netdriver_ifdown;
dev->d_txavail = netdriver_txavail;
dev->d_private = (void *)(intptr_t)devidx;
dev->quota[NETPKT_TX] = 1;
dev->quota[NETPKT_RX] = 1;
dev->ops = &g_ops;
/* Register the device with the OS so that socket IOCTLs can be
* performed
*/
netdev_register(dev, NET_LL_ETHERNET);
netdev_lower_register(dev, NET_LL_ETHERNET);
}
return OK;
@ -399,13 +249,13 @@ int sim_netdriver_init(void)
void sim_netdriver_setmacaddr(int devidx, unsigned char *macaddr)
{
memcpy(g_sim_dev[devidx].d_mac.ether.ether_addr_octet, macaddr,
memcpy(g_sim_dev[devidx].dev.netdev.d_mac.ether.ether_addr_octet, macaddr,
IFHWADDRLEN);
}
void sim_netdriver_setmtu(int devidx, int mtu)
{
g_sim_dev[devidx].d_pktsize = mtu + ETH_HDRLEN;
g_sim_dev[devidx].dev.netdev.d_pktsize = mtu + ETH_HDRLEN;
}
void sim_netdriver_loop(void)
@ -413,10 +263,9 @@ void sim_netdriver_loop(void)
int devidx;
for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++)
{
if (work_available(&g_recv_work[devidx]) && sim_netdev_avail(devidx))
if (sim_netdev_avail(devidx))
{
work_queue(LPWORK, &g_recv_work[devidx], netdriver_recv_work,
&g_sim_dev[devidx], 0);
netdev_lower_rxready(&g_sim_dev[devidx].dev);
}
}
}

View File

@ -633,6 +633,46 @@ int netdev_lower_unregister(FAR struct netdev_lowerhalf_s *dev)
return OK;
}
/****************************************************************************
* Name: netdev_lower_carrier_on
*
* Description:
* Notifies the networking layer about an available carrier.
* (e.g. a cable was plugged in)
*
* Input Parameters:
* dev - The lower half device driver structure
*
* Returned Value:
* 0:Success; negated errno on failure
*
****************************************************************************/
int netdev_lower_carrier_on(FAR struct netdev_lowerhalf_s *dev)
{
return netdev_carrier_on(&dev->netdev);
}
/****************************************************************************
* Name: netdev_lower_carrier_off
*
* Description:
* Notifies the networking layer about an disappeared carrier.
* (e.g. a cable was unplugged)
*
* Input Parameters:
* dev - The lower half device driver structure
*
* Returned Value:
* 0:Success; negated errno on failure
*
****************************************************************************/
int netdev_lower_carrier_off(FAR struct netdev_lowerhalf_s *dev)
{
return netdev_carrier_off(&dev->netdev);
}
/****************************************************************************
* Name: netdev_lower_rxready
*
@ -779,6 +819,54 @@ int netpkt_copyout(FAR struct netdev_lowerhalf_s *dev, FAR uint8_t *dest,
return iob_copyout(dest, pkt, len, offset - NET_LL_HDRLEN(&dev->netdev));
}
/****************************************************************************
* Name: netpkt_getdata/getbase
*
* Description:
* Get the pointer of data/base in a netpkt, used when NETPKT_BUFLEN is
* big enough to fit a full packet in.
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
*
* Returned Value:
* Pointer data/base, NULL on failure.
*
****************************************************************************/
FAR uint8_t *netpkt_getdata(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt)
{
return IOB_DATA(pkt) - NET_LL_HDRLEN(&dev->netdev);
}
FAR uint8_t *netpkt_getbase(FAR netpkt_t *pkt)
{
return pkt->io_data;
}
/****************************************************************************
* Name: netpkt_setdatalen
*
* Description:
* Set the length of data in netpkt, used when data is written into
* netpkt by data/base pointer, no need to set this length after
* copyin.
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
* len - The length of data in netpkt
*
****************************************************************************/
void netpkt_setdatalen(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt, unsigned int len)
{
iob_update_pktlen(pkt, len - NET_LL_HDRLEN(&dev->netdev));
}
/****************************************************************************
* Name: netpkt_getdatalen
*
@ -799,3 +887,39 @@ unsigned int netpkt_getdatalen(FAR struct netdev_lowerhalf_s *dev,
{
return pkt->io_pktlen + NET_LL_HDRLEN(&dev->netdev);
}
/****************************************************************************
* Name: netpkt_reset_reserved
*
* Description:
* Reset the reserved length (the starting point of data) of netpkt
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
* len - The reserved length
*
****************************************************************************/
void netpkt_reset_reserved(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt, unsigned int len)
{
iob_reserve(pkt, len + NET_LL_HDRLEN(&dev->netdev));
}
/****************************************************************************
* Name: netpkt_is_fragmented
*
* Description:
* Returns whether the netpkt is fragmented into different blocks.
* In other words, NETPKT_BUFLEN < reserved + total data
*
* Input Parameters:
* pkt - The net packet
*
****************************************************************************/
bool netpkt_is_fragmented(FAR netpkt_t *pkt)
{
return pkt->io_flink != NULL;
}

View File

@ -174,6 +174,40 @@ int netdev_lower_register(FAR struct netdev_lowerhalf_s *dev,
int netdev_lower_unregister(FAR struct netdev_lowerhalf_s *dev);
/****************************************************************************
* Name: netdev_lower_carrier_on
*
* Description:
* Notifies the networking layer about an available carrier.
* (e.g. a cable was plugged in)
*
* Input Parameters:
* dev - The lower half device driver structure
*
* Returned Value:
* 0:Success; negated errno on failure
*
****************************************************************************/
int netdev_lower_carrier_on(FAR struct netdev_lowerhalf_s *dev);
/****************************************************************************
* Name: netdev_lower_carrier_off
*
* Description:
* Notifies the networking layer about an disappeared carrier.
* (e.g. a cable was unplugged)
*
* Input Parameters:
* dev - The lower half device driver structure
*
* Returned Value:
* 0:Success; negated errno on failure
*
****************************************************************************/
int netdev_lower_carrier_off(FAR struct netdev_lowerhalf_s *dev);
/****************************************************************************
* Name: netdev_lower_rxready
*
@ -278,6 +312,44 @@ int netpkt_copyin(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt,
int netpkt_copyout(FAR struct netdev_lowerhalf_s *dev, FAR uint8_t *dest,
FAR const netpkt_t *pkt, unsigned int len, int offset);
/****************************************************************************
* Name: netpkt_getdata/getbase
*
* Description:
* Get the pointer of data/base in a netpkt, used when NETPKT_BUFLEN is
* big enough to fit a full packet in.
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
*
* Returned Value:
* Pointer data/base, NULL on failure.
*
****************************************************************************/
FAR uint8_t *netpkt_getdata(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt);
FAR uint8_t *netpkt_getbase(FAR netpkt_t *pkt);
/****************************************************************************
* Name: netpkt_setdatalen
*
* Description:
* Set the length of data in netpkt, used when data is written into
* netpkt by data/base pointer, no need to set this length after
* copyin.
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
* len - The length of data in netpkt
*
****************************************************************************/
void netpkt_setdatalen(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt, unsigned int len);
/****************************************************************************
* Name: netpkt_getdatalen
*
@ -296,4 +368,34 @@ int netpkt_copyout(FAR struct netdev_lowerhalf_s *dev, FAR uint8_t *dest,
unsigned int netpkt_getdatalen(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt);
/****************************************************************************
* Name: netpkt_reset_reserved
*
* Description:
* Reset the reserved length (the starting point of data) of netpkt
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
* len - The reserved length
*
****************************************************************************/
void netpkt_reset_reserved(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt, unsigned int len);
/****************************************************************************
* Name: netpkt_is_fragmented
*
* Description:
* Returns whether the netpkt is fragmented into different blocks.
* In other words, NETPKT_BUFLEN < reserved + total data
*
* Input Parameters:
* pkt - The net packet
*
****************************************************************************/
bool netpkt_is_fragmented(FAR netpkt_t *pkt);
#endif /* __INCLUDE_NUTTX_NET_NETDEV_LOWERHALF_H */