| /**************************************************************************** |
| * net/sixlowpan/sixlowpan_send.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * 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 <nuttx/config.h> |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <debug.h> |
| |
| #include <nuttx/semaphore.h> |
| #include <nuttx/net/net.h> |
| #include <nuttx/net/radiodev.h> |
| |
| #include "netdev/netdev.h" |
| #include "devif/devif.h" |
| |
| #include "sixlowpan/sixlowpan_internal.h" |
| |
| #ifdef CONFIG_NET_6LOWPAN |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /* These are temporary stubs. Something like this would be needed to |
| * monitor the health of a IPv6 neighbor. |
| */ |
| |
| #define neighbor_reachable(dev) |
| #define neighbor_notreachable(dev) |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| /* This is the state data provided to the send event handler. No actions |
| * can be taken until the until we receive the TX poll, then we can call |
| * sixlowpan_queue_frames() with this data strurcture. |
| */ |
| |
| struct sixlowpan_send_s |
| { |
| FAR struct devif_callback_s *s_cb; /* Reference to callback |
| * instance */ |
| sem_t s_waitsem; /* Supports waiting for |
| * driver events */ |
| int s_result; /* The result of the transfer */ |
| FAR const struct ipv6_hdr_s *s_ipv6hdr; /* IPv6 header, followed by |
| * UDP or ICMP header. */ |
| FAR const struct netdev_varaddr_s *s_destmac; /* Destination MAC address */ |
| FAR const void *s_buf; /* Data to send */ |
| size_t s_len; /* Length of data in buf */ |
| }; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: send_eventhandler |
| * |
| * Description: |
| * This function is called with the network locked to perform the actual |
| * send operation when polled by the lower, device interfacing layer. |
| * |
| * Input Parameters: |
| * dev - The structure of the network driver that generated the event. |
| * pvpriv - An instance of struct sixlowpan_send_s cast to void* |
| * flags - Set of events describing why the callback was invoked |
| * |
| * Returned Value: |
| * None |
| * |
| * Assumptions: |
| * The network is locked. |
| * |
| ****************************************************************************/ |
| |
| static uint16_t send_eventhandler(FAR struct net_driver_s *dev, |
| FAR void *pvpriv, uint16_t flags) |
| { |
| FAR struct sixlowpan_send_s *sinfo = pvpriv; |
| |
| ninfo("flags: %04x\n", flags); |
| |
| /* Verify that this is a compatible network driver. */ |
| |
| if (dev->d_lltype != NET_LL_IEEE802154 && |
| dev->d_lltype != NET_LL_PKTRADIO) |
| { |
| ninfo("Not a compatible network device\n"); |
| return flags; |
| } |
| |
| /* REVISIT: Verify that this is the correct IEEE802.15.4 network driver to |
| * route the outgoing frame(s). Chances are that there is only one |
| * IEEE802.15.4 network driver |
| */ |
| |
| /* Check if the IEEE802.15.4 network driver went down */ |
| |
| if ((flags & NETDEV_DOWN) != 0) |
| { |
| nwarn("WARNING: Device is down\n"); |
| sinfo->s_result = -ENOTCONN; |
| goto end_wait; |
| } |
| |
| /* Check for a poll for TX data. */ |
| |
| if ((flags & WPAN_NEWDATA) == 0) |
| { |
| DEBUGASSERT((flags & WPAN_POLL) != 0); |
| |
| /* Transfer the frame list to the IEEE802.15.4 MAC device */ |
| |
| sinfo->s_result = |
| sixlowpan_queue_frames((FAR struct radio_driver_s *)dev, |
| sinfo->s_ipv6hdr, sinfo->s_buf, sinfo->s_len, |
| sinfo->s_destmac); |
| |
| flags &= ~WPAN_POLL; |
| neighbor_reachable(dev); |
| goto end_wait; |
| } |
| |
| /* Continue waiting */ |
| |
| return flags; |
| |
| end_wait: |
| |
| /* Do not allow any further callbacks */ |
| |
| sinfo->s_cb->flags = 0; |
| sinfo->s_cb->priv = NULL; |
| sinfo->s_cb->event = NULL; |
| |
| /* Wake up the waiting thread */ |
| |
| nxsem_post(&sinfo->s_waitsem); |
| return flags; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: sixlowpan_send |
| * |
| * Description: |
| * Process an outgoing UDP or ICMPv6 packet. Takes an IP packet and |
| * formats it to be sent on an 802.15.4 network using 6lowpan. Called |
| * from common UDP/ICMPv6 send logic. |
| * |
| * The payload data is in the caller 'buf' and is of length 'buflen'. |
| * Compressed headers will be added and if necessary the packet is |
| * fragmented. The resulting packet/fragments are submitted to the MAC |
| * via the network driver r_req_data method. |
| * |
| * Input Parameters: |
| * dev - The IEEE802.15.4 MAC network driver interface. |
| * list - Head of callback list for send events |
| * ipv6hdr - IPv6 header followed by UDP or ICMPv6 header. |
| * buf - Data to send |
| * len - Length of data to send |
| * destmac - The IEEE802.15.4 MAC address of the destination |
| * timeout - Send timeout in milliseconds |
| * |
| * Returned Value: |
| * Ok is returned on success; Otherwise a negated errno value is returned. |
| * This function is expected to fail if the driver is not an IEEE802.15.4 |
| * MAC network driver. In that case, the logic will fall back to normal |
| * IPv4/IPv6 formatting. |
| * |
| * Assumptions: |
| * Called with the network locked. |
| * |
| ****************************************************************************/ |
| |
| int sixlowpan_send(FAR struct net_driver_s *dev, |
| FAR struct devif_callback_s **list, |
| FAR struct devif_callback_s **list_tail, |
| FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, |
| size_t len, FAR const struct netdev_varaddr_s *destmac, |
| unsigned int timeout) |
| { |
| struct sixlowpan_send_s sinfo; |
| |
| ninfo("len=%lu timeout=%u\n", (unsigned long)len, timeout); |
| |
| /* Initialize the send state structure */ |
| |
| nxsem_init(&sinfo.s_waitsem, 0, 0); |
| |
| sinfo.s_result = -EBUSY; |
| sinfo.s_ipv6hdr = ipv6hdr; |
| sinfo.s_destmac = destmac; |
| sinfo.s_buf = buf; |
| sinfo.s_len = len; |
| |
| net_lock(); |
| if (len > 0) |
| { |
| /* Allocate resources to receive a callback. |
| * |
| * The second parameter is NULL meaning that we can get only |
| * device related events, no connect-related events. |
| */ |
| |
| sinfo.s_cb = devif_callback_alloc(dev, list, list_tail); |
| if (sinfo.s_cb != NULL) |
| { |
| int ret; |
| |
| /* Set up the callback in the connection */ |
| |
| sinfo.s_cb->flags = (NETDEV_DOWN | WPAN_POLL); |
| sinfo.s_cb->priv = (FAR void *)&sinfo; |
| sinfo.s_cb->event = send_eventhandler; |
| |
| /* Notify the IEEE802.15.4 MAC that we have data to send. */ |
| |
| netdev_txnotify_dev(dev); |
| |
| /* Wait for the send to complete or an error to occur. |
| * net_sem_timedwait will also terminate if a signal is received. |
| */ |
| |
| ninfo("Wait for send complete\n"); |
| |
| ret = net_sem_timedwait(&sinfo.s_waitsem, timeout); |
| if (ret < 0) |
| { |
| if (ret == -ETIMEDOUT) |
| { |
| ret = -EAGAIN; |
| neighbor_notreachable(dev); |
| } |
| |
| sinfo.s_result = ret; |
| } |
| |
| /* Make sure that no further events are processed */ |
| |
| devif_conn_callback_free(dev, sinfo.s_cb, list, list_tail); |
| } |
| } |
| |
| nxsem_destroy(&sinfo.s_waitsem); |
| net_unlock(); |
| |
| return (sinfo.s_result < 0 ? sinfo.s_result : len); |
| } |
| |
| #endif /* CONFIG_NET_6LOWPAN */ |