/**************************************************************************** * 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 #include #include #include #include #include #include #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 */