diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs index 6bd982fda2..76aa70e6b7 100644 --- a/drivers/net/Make.defs +++ b/drivers/net/Make.defs @@ -24,6 +24,10 @@ ifeq ($(CONFIG_NET),y) # Include network interface drivers +ifeq ($(CONFIG_MM_IOB),y) + CSRCS += netdev_upperhalf.c +endif + ifeq ($(CONFIG_NET_LOOPBACK),y) CSRCS += loopback.c endif diff --git a/drivers/net/netdev_upperhalf.c b/drivers/net/netdev_upperhalf.c new file mode 100644 index 0000000000..45325196e4 --- /dev/null +++ b/drivers/net/netdev_upperhalf.c @@ -0,0 +1,801 @@ +/**************************************************************************** + * drivers/net/netdev_upperhalf.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NETDEV_TX_CONTINUE 1 /* Return value for devif_poll */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the state of the upper half driver */ + +struct netdev_upperhalf_s +{ + FAR struct netdev_lowerhalf_s *lower; + + struct work_s work; /* Deferring poll work to the work queue */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netpkt_get + * + * Description: + * Wraps the d_iob of dev to a netpkt. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +static FAR netpkt_t *netpkt_get(FAR struct net_driver_s *dev, + enum netpkt_type_e type) +{ + FAR struct netdev_upperhalf_s *upper; + FAR netpkt_t *pkt; + + DEBUGASSERT(dev && dev->d_iob); + + upper = (FAR struct netdev_upperhalf_s *)dev->d_private; + pkt = dev->d_iob; + + netdev_iob_clear(dev); + + /* Do not limit quota here (simply relay iob instead of dropping), most + * cases will be limited by netdev_upper_can_tx and seldom reaches here. + */ + + if (upper->lower->quota[type]-- <= 0) + { + nwarn("WARNING: Allowing temperarily exceeding quota of %s.\n", + dev->d_ifname); + } + + return pkt; +} + +/**************************************************************************** + * Name: netpkt_put + * + * Description: + * Relay IOB to dev. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +static void netpkt_put(FAR struct net_driver_s *dev, FAR netpkt_t *pkt, + enum netpkt_type_e type) +{ + FAR struct netdev_upperhalf_s *upper = dev->d_private; + + DEBUGASSERT(dev && pkt); + + /* TODO: Using netdev_iob_release instead of netdev_iob_replace now, + * because netdev_iob_replace sets d_len = L3_LEN and d_buf, + * but we don't want these changes. + */ + + upper->lower->quota[type]++; + netdev_iob_release(dev); + dev->d_iob = pkt; + dev->d_len = netpkt_getdatalen(upper->lower, pkt); +} + +/**************************************************************************** + * Name: netdev_upper_alloc + * + * Description: + * Get the upper half of lower half structure, create one if not present. + * + ****************************************************************************/ + +static FAR struct netdev_upperhalf_s * +netdev_upper_alloc(FAR struct netdev_lowerhalf_s *dev) +{ + /* Allocate the upper-half data structure */ + + FAR struct netdev_upperhalf_s *upper; + + DEBUGASSERT(dev != NULL && dev->netdev.d_private == NULL); + + upper = kmm_zalloc(sizeof(struct netdev_upperhalf_s)); + if (upper == NULL) + { + nerr("ERROR: Allocation failed\n"); + return NULL; + } + + upper->lower = dev; + dev->netdev.d_private = upper; + + return upper; +} + +/**************************************************************************** + * Name: netdev_upper_can_tx + * + * Description: + * Check if we allow tx on this device. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +static inline bool netdev_upper_can_tx(FAR struct netdev_upperhalf_s *upper) +{ + return upper->lower->quota[NETPKT_TX] > 0; +} + +/**************************************************************************** + * Name: netdev_upper_txpoll + * + * Description: + * The transmitter is available, 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 + * 2. When the preceding TX packet send times out and the interface is + * reset + * 3. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Negated errno value - Error number that occurs. + * OK - Driver can send more, continue the poll. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +static int netdev_upper_txpoll(FAR struct net_driver_s *dev) +{ + FAR struct netdev_upperhalf_s *upper = dev->d_private; + FAR struct netdev_lowerhalf_s *lower = upper->lower; + FAR netpkt_t *pkt; + int ret; + + DEBUGASSERT(dev->d_len > 0); + + NETDEV_TXPACKETS(dev); + +#ifdef CONFIG_NET_PKT + /* When packet sockets are enabled, feed the tx frame into it */ + + pkt_input(dev); +#endif + + pkt = netpkt_get(dev, NETPKT_TX); + ret = lower->ops->transmit(lower, pkt); + + if (ret != OK) + { + /* Stop polling on any error + * REVISIT: maybe store the pkt in upper half and retry later? + */ + + NETDEV_TXERRORS(dev); + netpkt_put(dev, pkt, NETPKT_TX); + return ret; + } + + return NETDEV_TX_CONTINUE; +} + +/**************************************************************************** + * Name: netdev_upper_txavail_work + * + * Description: + * Perform an out-of-cycle tx poll on the worker thread. + * + * Input Parameters: + * upper - Reference to the upper half driver structure + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +static void netdev_upper_txavail_work(FAR struct netdev_upperhalf_s *upper) +{ + FAR struct net_driver_s *dev = &upper->lower->netdev; + + /* Ignore the notification if the interface is not yet up */ + + if (IFF_IS_UP(dev->d_flags)) + { + DEBUGASSERT(dev->d_buf == NULL); /* Make sure: IOB only. */ + while (netdev_upper_can_tx(upper) && + devif_poll(dev, netdev_upper_txpoll) == NETDEV_TX_CONTINUE); + } +} + +/**************************************************************************** + * Function: netdev_upper_rxpoll_work + * + * Description: + * Try to receive packets from device and pass packets into IP + * stack and send packets which is from IP stack if necessary. + * + * Input Parameters: + * upper - Reference to the upper half driver structure + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +static void netdev_upper_rxpoll_work(FAR struct netdev_upperhalf_s *upper) +{ + FAR struct netdev_lowerhalf_s *lower = upper->lower; + FAR struct net_driver_s *dev = &lower->netdev; + FAR struct eth_hdr_s *eth_hdr; + FAR netpkt_t *pkt; + + /* Loop while receive() successfully retrieves valid Ethernet frames. */ + + while ((pkt = lower->ops->receive(lower)) != NULL) + { + NETDEV_RXPACKETS(dev); + + if (!IFF_IS_UP(dev->d_flags)) + { + /* Interface down, drop frame */ + + NETDEV_RXDROPPED(dev); + netpkt_free(lower, pkt, NETPKT_RX); + continue; + } + + netpkt_put(dev, pkt, NETPKT_RX); + +#ifdef CONFIG_NET_PKT + /* When packet sockets are enabled, feed the frame into the tap */ + + pkt_input(dev); +#endif + + /* TODO: Support other ll types. */ + + DEBUGASSERT(dev->d_lltype == NET_LL_ETHERNET || + dev->d_lltype == NET_LL_IEEE80211); + + eth_hdr = (FAR struct eth_hdr_s *)NETLLBUF; + + /* Check if this is an 802.1Q VLAN tagged packet */ + + if (eth_hdr->type == HTONS(TPID_8021QVLAN)) + { + /* Need to remove the 4 octet VLAN Tag, by moving src and dest + * addresses 4 octets to the right, and then read the actual + * ethertype. The VLAN ID and priority fields are currently + * ignored. + */ + + memmove((FAR uint8_t *)eth_hdr + 4, eth_hdr, + offsetof(struct eth_hdr_s, type)); + dev->d_iob = iob_trimhead(dev->d_iob, 4); + dev->d_len -= 4; + + eth_hdr = (FAR struct eth_hdr_s *)NETLLBUF; + } + + /* We only accept IP packets of the configured type and ARP packets */ + +#ifdef CONFIG_NET_IPv4 + if (eth_hdr->type == HTONS(ETHTYPE_IP)) + { + ninfo("IPv4 frame\n"); + NETDEV_RXIPV4(dev); + + /* Receive an IPv4 packet from the network device */ + + ipv4_input(dev); + } + else +#endif +#ifdef CONFIG_NET_IPv6 + if (eth_hdr->type == HTONS(ETHTYPE_IP6)) + { + ninfo("IPv6 frame\n"); + NETDEV_RXIPV6(dev); + + /* Give the IPv6 packet to the network layer */ + + ipv6_input(dev); + } + else +#endif +#ifdef CONFIG_NET_ARP + if (eth_hdr->type == HTONS(ETHTYPE_ARP)) + { + ninfo("ARP frame\n"); + NETDEV_RXARP(dev); + + /* Handle ARP packet */ + + arp_input(dev); + } + else +#endif + { + ninfo("INFO: Dropped, Unknown type: %04x\n", eth_hdr->type); + NETDEV_RXDROPPED(dev); + dev->d_len = 0; + } + + /* 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. + */ + + if (dev->d_len > 0) + { + /* And send the packet */ + + netdev_upper_txpoll(dev); + } + } +} + +/**************************************************************************** + * Name: netdev_upper_txavail_work + * + * Description: + * Perform an out-of-cycle poll on a dedicated thread or the worker thread. + * + * Input Parameters: + * arg - Reference to the upper half driver structure (cast to void *) + * + * TODO: + * Support working in a dedicated thread. + * + ****************************************************************************/ + +static void netdev_upper_work(FAR void *arg) +{ + FAR struct netdev_upperhalf_s *upper = arg; + + /* RX may release quota and driver buffer, so do RX first. */ + + net_lock(); + netdev_upper_rxpoll_work(upper); + netdev_upper_txavail_work(upper); + net_unlock(); +} + +/**************************************************************************** + * Name: netdev_upper_queue_work + * + * Description: + * Called when there is any work to do. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + ****************************************************************************/ + +static inline void netdev_upper_queue_work(FAR struct net_driver_s *dev) +{ + FAR struct netdev_upperhalf_s *upper = dev->d_private; + + /* TODO: support trigger thread. */ + + if (work_available(&upper->work)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(LPWORK, &upper->work, netdev_upper_work, upper, 0); + } +} + +/**************************************************************************** + * Name: netdev_upper_txavail + * + * Description: + * Called when new TX data is available. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + ****************************************************************************/ + +static int netdev_upper_txavail(FAR struct net_driver_s *dev) +{ + netdev_upper_queue_work(dev); + return OK; +} + +/**************************************************************************** + * Name: netdev_upper_ifup/ifdown/addmac/rmmac/ioctl + * + * Description: + * Called by net stack and relayed to lower half driver. + * + ****************************************************************************/ + +static int netdev_upper_ifup(FAR struct net_driver_s *dev) +{ + FAR struct netdev_upperhalf_s *upper = dev->d_private; + + /* TODO: bring up a dedicated thread for work? */ + + if (upper->lower->ops->ifup) + { + return upper->lower->ops->ifup(upper->lower); + } + + return -ENOSYS; +} + +static int netdev_upper_ifdown(FAR struct net_driver_s *dev) +{ + FAR struct netdev_upperhalf_s *upper = dev->d_private; + + /* TODO: Support dedicated thread? */ + + work_cancel(LPWORK, &upper->work); + + if (upper->lower->ops->ifdown) + { + return upper->lower->ops->ifdown(upper->lower); + } + + return -ENOSYS; +} + +#ifdef CONFIG_NET_MCASTGROUP +static int netdev_upper_addmac(FAR struct net_driver_s *dev, + FAR const uint8_t *mac) +{ + FAR struct netdev_upperhalf_s *upper = dev->d_private; + + if (upper->lower->ops->addmac) + { + return upper->lower->ops->addmac(upper->lower, mac); + } + + return -ENOSYS; +} +#endif + +#ifdef CONFIG_NET_MCASTGROUP +static int netdev_upper_rmmac(FAR struct net_driver_s *dev, + FAR const uint8_t *mac) +{ + FAR struct netdev_upperhalf_s *upper = dev->d_private; + + if (upper->lower->ops->rmmac) + { + return upper->lower->ops->rmmac(upper->lower, mac); + } + + return -ENOSYS; +} +#endif + +#ifdef CONFIG_NETDEV_IOCTL +static int netdev_upper_ioctl(FAR struct net_driver_s *dev, int cmd, + unsigned long arg) +{ + FAR struct netdev_upperhalf_s *upper = dev->d_private; + + if (upper->lower->ops->ioctl) + { + return upper->lower->ops->ioctl(upper->lower, cmd, arg); + } + + return -ENOTTY; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netdev_lower_register + * + * Description: + * Register a network device driver and assign a name to it so that it can + * be found in subsequent network ioctl operations on the device. + * + * Input Parameters: + * dev - The lower half device driver structure to be registered. + * lltype - Link level protocol used by the driver (Ethernet, SLIP, TUN, + * ... + * + * Returned Value: + * 0:Success; negated errno on failure. + * + ****************************************************************************/ + +int netdev_lower_register(FAR struct netdev_lowerhalf_s *dev, + enum net_lltype_e lltype) +{ + FAR struct netdev_upperhalf_s *upper; + int ret; + + if (dev == NULL || dev->ops == NULL || + dev->ops->transmit == NULL || dev->ops->receive == NULL) + { + return -EINVAL; + } + + if ((upper = netdev_upper_alloc(dev)) == NULL) + { + return -ENOMEM; + } + + dev->netdev.d_ifup = netdev_upper_ifup; + dev->netdev.d_ifdown = netdev_upper_ifdown; + dev->netdev.d_txavail = netdev_upper_txavail; +#ifdef CONFIG_NET_MCASTGROUP + dev->netdev.d_addmac = netdev_upper_addmac; + dev->netdev.d_rmmac = netdev_upper_rmmac; +#endif +#ifdef CONFIG_NETDEV_IOCTL + dev->netdev.d_ioctl = netdev_upper_ioctl; +#endif + dev->netdev.d_private = upper; + + ret = netdev_register(&dev->netdev, lltype); + if (ret < 0) + { + kmm_free(upper); + dev->netdev.d_private = NULL; + } + + return ret; +} + +/**************************************************************************** + * Name: netdev_lower_unregister + * + * Description: + * Unregister a network device driver. + * + * Input Parameters: + * dev - The lower half device driver structure to un-register + * + * Returned Value: + * 0:Success; negated errno on failure + * + ****************************************************************************/ + +int netdev_lower_unregister(FAR struct netdev_lowerhalf_s *dev) +{ + FAR struct netdev_upperhalf_s *upper; + int ret; + + if (dev == NULL || dev->netdev.d_private == NULL) + { + return -EINVAL; + } + + upper = (FAR struct netdev_upperhalf_s *)dev->netdev.d_private; + ret = netdev_unregister(&dev->netdev); + if (ret < 0) + { + return ret; + } + + kmm_free(upper); + dev->netdev.d_private = NULL; + + return OK; +} + +/**************************************************************************** + * Name: netdev_lower_rxready + * + * Description: + * Notifies the networking layer about an RX packet is ready to read. + * + * Input Parameters: + * dev - The lower half device driver structure + * + ****************************************************************************/ + +void netdev_lower_rxready(FAR struct netdev_lowerhalf_s *dev) +{ + netdev_upper_queue_work(&dev->netdev); +} + +/**************************************************************************** + * Name: netdev_lower_txdone + * + * Description: + * Notifies the networking layer about a TX packet is sent. + * + * Input Parameters: + * dev - The lower half device driver structure + * + ****************************************************************************/ + +void netdev_lower_txdone(FAR struct netdev_lowerhalf_s *dev) +{ + NETDEV_TXDONE(&dev->netdev); + netdev_upper_queue_work(&dev->netdev); +} + +/**************************************************************************** + * Name: netpkt_alloc + * + * Description: + * Allocate a netpkt structure. + * + * Input Parameters: + * dev - The lower half device driver structure + * type - Whether used for TX or RX + * + * Returned Value: + * Pointer to the packet, NULL on failure + * + ****************************************************************************/ + +FAR netpkt_t *netpkt_alloc(FAR struct netdev_lowerhalf_s *dev, + enum netpkt_type_e type) +{ + FAR netpkt_t *pkt; + + if (dev->quota[type] <= 0) + { + return NULL; + } + + pkt = iob_tryalloc(false); + if (pkt == NULL) + { + return NULL; + } + + net_lock(); /* REVISIT: Do we have better solution? */ + dev->quota[type]--; + net_unlock(); + + iob_reserve(pkt, CONFIG_NET_LL_GUARDSIZE); + return pkt; +} + +/**************************************************************************** + * Name: netpkt_free + * + * Description: + * Release a netpkt structure. + * + * Input Parameters: + * dev - The lower half device driver structure + * pkt - The packet to release + * type - Whether used for TX or RX + * + ****************************************************************************/ + +void netpkt_free(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt, + enum netpkt_type_e type) +{ + net_lock(); /* REVISIT: Do we have better solution? */ + dev->quota[type]++; + net_unlock(); + + iob_free_chain(pkt); +} + +/**************************************************************************** + * Name: netpkt_copyin + * + * Description: + * Copy 'len' bytes of data from a buffer into the netpkt, starting at + * 'offset' of netpkt. + * + * Input Parameters: + * dev - The lower half device driver structure + * pkt - The net packet + * src - The source buffer + * len - How many bytes to copy + * offset - The offset of netpkt to put the data + * + * Returned Value: + * 0:Success; negated errno on failure + * + ****************************************************************************/ + +int netpkt_copyin(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt, + FAR const uint8_t *src, unsigned int len, int offset) +{ + return iob_trycopyin(pkt, src, len, + offset - NET_LL_HDRLEN(&dev->netdev), false); +} + +/**************************************************************************** + * Name: netpkt_copyout + * + * Description: + * Copy 'len' bytes of data from netpkt into a buffer, starting at + * 'offset' of netpkt. + * + * Input Parameters: + * dev - The lower half device driver structure + * dest - The destination buffer + * pkt - The net packet + * len - How many bytes to copy + * offset - The offset of netpkt to get the data + * + * Returned Value: + * 0:Success; negated errno on failure + * + ****************************************************************************/ + +int netpkt_copyout(FAR struct netdev_lowerhalf_s *dev, FAR uint8_t *dest, + FAR const netpkt_t *pkt, unsigned int len, int offset) +{ + return iob_copyout(dest, pkt, len, offset - NET_LL_HDRLEN(&dev->netdev)); +} + +/**************************************************************************** + * Name: netpkt_getdatalen + * + * Description: + * Get the length of data in netpkt. + * + * Input Parameters: + * dev - The lower half device driver structure + * pkt - The net packet + * + * Returned Value: + * The length of data in netpkt. + * + ****************************************************************************/ + +unsigned int netpkt_getdatalen(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt) +{ + return pkt->io_pktlen + NET_LL_HDRLEN(&dev->netdev); +} diff --git a/include/nuttx/net/netdev_lowerhalf.h b/include/nuttx/net/netdev_lowerhalf.h new file mode 100644 index 0000000000..3ce76e4c6b --- /dev/null +++ b/include/nuttx/net/netdev_lowerhalf.h @@ -0,0 +1,299 @@ +/**************************************************************************** + * include/nuttx/net/netdev_lowerhalf.h + * Defines architecture-specific device driver interfaces to the NuttX + * network. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_NET_NETDEV_LOWERHALF_H +#define __INCLUDE_NUTTX_NET_NETDEV_LOWERHALF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* | <-------------- NETPKT_BUFLEN ---------------> | + * +---------------------+-------------------+------+ +-------------+ + * | reserved for driver | data | free | ---> | next netpkt | + * +---------------------+-------------------+------+ +-------------+ + * | | <--- datalen ---> | + * ^base ^data + */ + +#define NETPKT_BUFLEN CONFIG_IOB_BUFSIZE + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* We use IOB as our buffer now, we may change to some other structure when + * needed, so define a type netpkt_t for lower half. + * TODO: Provide interface of its queue, maybe a simple wrapper of iob_queue. + */ + +typedef struct iob_s netpkt_t; + +enum netpkt_type_e +{ + NETPKT_TX, + NETPKT_RX, + NETPKT_TYPENUM +}; + +/* This structure is the generic form of state structure used by lower half + * netdev driver. This state structure is passed to the netdev driver when + * the driver is initialized. Then, on subsequent callbacks into the lower + * half netdev logic, this structure is provided so that the netdev logic can + * maintain state information. + * + * Normally that netdev logic will have its own, custom state structure + * that is simply cast to struct netdev_lowerhalf_s. In order to perform such + * casts, the initial fields of the custom state structure match the initial + * fields of the following generic netdev state structure. + */ + +struct netdev_ops_s; +struct netdev_lowerhalf_s +{ + FAR const struct netdev_ops_s *ops; + int quota[NETPKT_TYPENUM]; /* Max # of buffer held by driver */ + + /* The structure used by net stack. + * Note: Do not change its fields unless you know what you are doing. + * + * Fields that lowerhalf should never touch (used by upper half): + * d_ifup, d_ifdown, d_txavail, d_addmac, d_rmmac, d_ioctl, d_private + */ + + struct net_driver_s netdev; +}; + +/* This structure is a set a callback functions used to call from the upper- + * half, generic netdev driver into lower-half, platform-specific logic that + * supports the low-level functionality. + */ + +struct netdev_ops_s +{ + int (*ifup)(FAR struct netdev_lowerhalf_s *dev); + int (*ifdown)(FAR struct netdev_lowerhalf_s *dev); + + /* transmit - Try to send a packet, non-blocking, own the netpkt and + * need to call netpkt_free to free it sometime later. + * Returned Value: + * OK for successfully sent the packet, driver can take pkt to its + * own queue and return OK (remember to free it later). + * Negated errno value for failure, will stop current sending, the pkt + * will be recycled by upper half. + */ + + int (*transmit)(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt); + + /* receive - Try to receive a packet, non-blocking + * Returned Value: + * A netpkt contains the packet, or NULL if no more packets. + */ + + FAR netpkt_t *(*receive)(FAR struct netdev_lowerhalf_s *dev); + +#ifdef CONFIG_NET_MCASTGROUP + int (*addmac)(FAR struct netdev_lowerhalf_s *dev, FAR const uint8_t *mac); + int (*rmmac)(FAR struct netdev_lowerhalf_s *dev, FAR const uint8_t *mac); +#endif +#ifdef CONFIG_NETDEV_IOCTL + int (*ioctl)(FAR struct netdev_lowerhalf_s *dev, int cmd, + unsigned long arg); +#endif +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: netdev_lower_register + * + * Description: + * Register a network device driver and assign a name to it so that it can + * be found in subsequent network ioctl operations on the device. + * + * Input Parameters: + * dev - The lower half device driver structure to be registered. + * lltype - Link level protocol used by the driver (Ethernet, SLIP, TUN, + * ... + * + * Returned Value: + * 0:Success; negated errno on failure. + * + ****************************************************************************/ + +int netdev_lower_register(FAR struct netdev_lowerhalf_s *dev, + enum net_lltype_e lltype); + +/**************************************************************************** + * Name: netdev_lower_unregister + * + * Description: + * Unregister a network device driver. + * + * Input Parameters: + * dev - The lower half device driver structure to un-register + * + * Returned Value: + * 0:Success; negated errno on failure + * + ****************************************************************************/ + +int netdev_lower_unregister(FAR struct netdev_lowerhalf_s *dev); + +/**************************************************************************** + * Name: netdev_lower_rxready + * + * Description: + * Notifies the networking layer about an RX packet is ready to read. + * + * Input Parameters: + * dev - The lower half device driver structure + * + ****************************************************************************/ + +void netdev_lower_rxready(FAR struct netdev_lowerhalf_s *dev); + +/**************************************************************************** + * Name: netdev_lower_txdone + * + * Description: + * Notifies the networking layer about a TX packet is sent. + * + * Input Parameters: + * dev - The lower half device driver structure + * + ****************************************************************************/ + +void netdev_lower_txdone(FAR struct netdev_lowerhalf_s *dev); + +/**************************************************************************** + * Name: netpkt_alloc + * + * Description: + * Allocate a netpkt structure. + * + * Input Parameters: + * dev - The lower half device driver structure + * type - Whether used for TX or RX + * + * Returned Value: + * Pointer to the packet, NULL on failure + * + ****************************************************************************/ + +FAR netpkt_t *netpkt_alloc(FAR struct netdev_lowerhalf_s *dev, + enum netpkt_type_e type); + +/**************************************************************************** + * Name: netpkt_free + * + * Description: + * Release a netpkt structure. + * + * Input Parameters: + * dev - The lower half device driver structure + * pkt - The packet to release + * type - Whether used for TX or RX + * + ****************************************************************************/ + +void netpkt_free(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt, + enum netpkt_type_e type); + +/**************************************************************************** + * Name: netpkt_copyin + * + * Description: + * Copy 'len' bytes of data from a buffer into the netpkt, starting at + * 'offset' of netpkt. + * + * Input Parameters: + * dev - The lower half device driver structure + * pkt - The net packet + * src - The source buffer + * len - How many bytes to copy + * offset - The offset of netpkt to put the data + * + * Returned Value: + * 0:Success; negated errno on failure + * + ****************************************************************************/ + +int netpkt_copyin(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt, + FAR const uint8_t *src, unsigned int len, int offset); + +/**************************************************************************** + * Name: netpkt_copyout + * + * Description: + * Copy 'len' bytes of data from netpkt into a buffer, starting at + * 'offset' of netpkt. + * + * Input Parameters: + * dev - The lower half device driver structure + * dest - The destination buffer + * pkt - The net packet + * len - How many bytes to copy + * offset - The offset of netpkt to get the data + * + * Returned Value: + * 0:Success; negated errno on failure + * + ****************************************************************************/ + +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_getdatalen + * + * Description: + * Get the length of data in netpkt. + * + * Input Parameters: + * dev - The lower half device driver structure + * pkt - The net packet + * + * Returned Value: + * The length of data in netpkt. + * + ****************************************************************************/ + +unsigned int netpkt_getdatalen(FAR struct netdev_lowerhalf_s *dev, + FAR netpkt_t *pkt); + +#endif /* __INCLUDE_NUTTX_NET_NETDEV_LOWERHALF_H */