ieee802154_sendto.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /****************************************************************************
  2. * net/ieee802154/ieee802154_sendto.c
  3. *
  4. * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/types.h>
  40. #include <sys/socket.h>
  41. #include <stdint.h>
  42. #include <stdbool.h>
  43. #include <string.h>
  44. #include <errno.h>
  45. #include <assert.h>
  46. #include <debug.h>
  47. #include <arch/irq.h>
  48. #include <nuttx/clock.h>
  49. #include <nuttx/semaphore.h>
  50. #include <nuttx/mm/iob.h>
  51. #include <nuttx/net/radiodev.h>
  52. #include <nuttx/net/net.h>
  53. #include "utils/utils.h"
  54. #include "netdev/netdev.h"
  55. #include "devif/devif.h"
  56. #include "socket/socket.h"
  57. #include "ieee802154/ieee802154.h"
  58. #ifdef CONFIG_NET_IEEE802154
  59. /****************************************************************************
  60. * Private Types
  61. ****************************************************************************/
  62. /* This structure holds the state of the send operation until it can be
  63. * operated upon by the event handler.
  64. */
  65. struct ieee802154_sendto_s
  66. {
  67. FAR struct socket *is_sock; /* Points to the parent socket structure */
  68. FAR struct devif_callback_s *is_cb; /* Reference to callback instance */
  69. struct ieee802154_saddr_s is_destaddr; /* Frame destination address */
  70. sem_t is_sem; /* Used to wake up the waiting thread */
  71. FAR const uint8_t *is_buffer; /* User buffer of data to send */
  72. size_t is_buflen; /* Number of bytes in the is_buffer */
  73. ssize_t is_sent; /* The number of bytes sent (or error) */
  74. };
  75. /****************************************************************************
  76. * Private Functions
  77. ****************************************************************************/
  78. /****************************************************************************
  79. * Name: ieee802154_anyaddrnull
  80. *
  81. * Description:
  82. * If the destination address is all zero in the MAC header buf, then it is
  83. * broadcast on the 802.15.4 network.
  84. *
  85. * Input Parameters:
  86. * addr - The address to check
  87. * addrlen - The length of the address in bytes
  88. *
  89. * Returned Value:
  90. * True if the address is all zero.
  91. *
  92. ****************************************************************************/
  93. static bool ieee802154_anyaddrnull(FAR const uint8_t *addr, uint8_t addrlen)
  94. {
  95. while (addrlen-- > 0)
  96. {
  97. if (addr[addrlen] != 0x00)
  98. {
  99. return false;
  100. }
  101. }
  102. return true;
  103. }
  104. /****************************************************************************
  105. * Name: ieee802154_saddrnull
  106. *
  107. * Description:
  108. * If the destination address is all zero in the MAC header buf, then it is
  109. * broadcast on the 802.15.4 network.
  110. *
  111. * Input Parameters:
  112. * eaddr - The short address to check
  113. *
  114. * Returned Value:
  115. * The address length associated with the address mode.
  116. *
  117. ****************************************************************************/
  118. static inline bool ieee802154_saddrnull(FAR const uint8_t *saddr)
  119. {
  120. return ieee802154_anyaddrnull(saddr, IEEE802154_SADDRSIZE);
  121. }
  122. /****************************************************************************
  123. * Name: ieee802154_eaddrnull
  124. *
  125. * Description:
  126. * If the destination address is all zero in the MAC header buf, then it is
  127. * broadcast on the 802.15.4 network.
  128. *
  129. * Input Parameters:
  130. * eaddr - The extended address to check
  131. *
  132. * Returned Value:
  133. * The address length associated with the address mode.
  134. *
  135. ****************************************************************************/
  136. static inline bool ieee802154_eaddrnull(FAR const uint8_t *eaddr)
  137. {
  138. return ieee802154_anyaddrnull(eaddr, IEEE802154_EADDRSIZE);
  139. }
  140. /****************************************************************************
  141. * Name: ieee802154_meta_data
  142. *
  143. * Description:
  144. * Based on the collected attributes and addresses, construct the MAC meta
  145. * data structure that we need to interface with the IEEE 802.15.4 MAC.
  146. *
  147. * Input Parameters:
  148. * radio - Radio network driver state instance.
  149. * pstate - Send state structure instance
  150. * meta - Location to return the corresponding meta data.
  151. * paylen - The size of the data payload to be sent.
  152. *
  153. * Returned Value:
  154. * Ok is returned on success; Othewise a negated errno value is returned.
  155. *
  156. * Assumptions:
  157. * Called with the network locked.
  158. *
  159. ****************************************************************************/
  160. static void ieee802154_meta_data(FAR struct radio_driver_s *radio,
  161. FAR struct ieee802154_sendto_s *pstate,
  162. FAR struct ieee802154_frame_meta_s *meta)
  163. {
  164. FAR struct ieee802154_saddr_s *destaddr;
  165. FAR struct ieee802154_saddr_s *srcaddr;
  166. FAR struct ieee802154_conn_s *conn;
  167. FAR struct socket *psock;
  168. bool rcvrnull;
  169. DEBUGASSERT(radio != NULL && pstate != NULL && pstate->is_sock != NULL &&
  170. meta != NULL);
  171. psock = pstate->is_sock;
  172. DEBUGASSERT(psock->s_conn != NULL);
  173. conn = (FAR struct ieee802154_conn_s *)psock->s_conn;
  174. srcaddr = &conn->laddr;
  175. destaddr = &pstate->is_destaddr;
  176. DEBUGASSERT(srcaddr->s_mode != IEEE802154_ADDRMODE_NONE &&
  177. destaddr->s_mode != IEEE802154_ADDRMODE_NONE);
  178. /* Initialize all settings to all zero */
  179. memset(meta, 0, sizeof(struct ieee802154_frame_meta_s));
  180. /* Source address mode */
  181. meta->srcmode = srcaddr->s_mode;
  182. /* Check for a broadcast destination address (all zero) */
  183. if (destaddr->s_mode == IEEE802154_ADDRMODE_EXTENDED)
  184. {
  185. /* Extended destination address mode */
  186. rcvrnull = ieee802154_eaddrnull(destaddr->s_eaddr);
  187. }
  188. else
  189. {
  190. /* Short destination address mode */
  191. rcvrnull = ieee802154_saddrnull(destaddr->s_saddr);
  192. }
  193. if (rcvrnull)
  194. {
  195. meta->flags.ackreq = TRUE;
  196. }
  197. /* Destination address.
  198. *
  199. * If the output address is NULL, then it is broadcast on the 802.15.4
  200. * network.
  201. */
  202. if (rcvrnull)
  203. {
  204. /* Broadcast requires short address mode. */
  205. meta->destaddr.mode = IEEE802154_ADDRMODE_SHORT;
  206. IEEE802154_PANIDCOPY(meta->destaddr.panid, destaddr->s_panid);
  207. meta->destaddr.saddr[0] = 0xff;
  208. meta->destaddr.saddr[1] = 0xff;
  209. memset(meta->destaddr.eaddr, 0, IEEE802154_EADDRSIZE);
  210. }
  211. else
  212. {
  213. /* Destination address. */
  214. meta->destaddr.mode = destaddr->s_mode;
  215. IEEE802154_PANIDCOPY(meta->destaddr.panid, destaddr->s_panid);
  216. if (destaddr->s_mode == IEEE802154_ADDRMODE_SHORT)
  217. {
  218. IEEE802154_SADDRCOPY(meta->destaddr.saddr, destaddr->s_eaddr);
  219. memset(meta->destaddr.eaddr, 0, IEEE802154_EADDRSIZE);
  220. }
  221. else
  222. {
  223. IEEE802154_EADDRCOPY(meta->destaddr.eaddr, destaddr->s_eaddr);
  224. memset(meta->destaddr.saddr, 0, IEEE802154_SADDRSIZE);
  225. }
  226. }
  227. /* Handle associated with MSDU. Will increment once per packet, not
  228. * necesarily per frame: The same MSDU handle will be used for each
  229. * fragment of a disassembled packet.
  230. */
  231. meta->handle = radio->r_msdu_handle++;
  232. #ifdef CONFIG_IEEE802154_SECURITY
  233. # warning CONFIG_IEEE802154_SECURITY not yet supported
  234. #endif
  235. #ifdef CONFIG_IEEE802154_UWB
  236. # warning CONFIG_IEEE802154_UWB not yet supported
  237. #endif
  238. /* Ranging left zero */
  239. }
  240. /****************************************************************************
  241. * Name: ieee802154_sendto_eventhandler
  242. ****************************************************************************/
  243. static uint16_t ieee802154_sendto_eventhandler(FAR struct net_driver_s *dev,
  244. FAR void *pvconn,
  245. FAR void *pvpriv,
  246. uint16_t flags)
  247. {
  248. FAR struct radio_driver_s *radio;
  249. FAR struct ieee802154_sendto_s *pstate;
  250. struct ieee802154_frame_meta_s meta;
  251. FAR struct iob_s *iob;
  252. int hdrlen;
  253. int ret;
  254. DEBUGASSERT(pvpriv != NULL && dev != NULL && pvconn != NULL);
  255. /* Ignore polls from non IEEE 802.15.4 network drivers */
  256. if (dev->d_lltype != NET_LL_IEEE802154)
  257. {
  258. return flags;
  259. }
  260. /* Make sure that this is the driver to which the socket is connected. */
  261. #warning Missing logic
  262. pstate = (FAR struct ieee802154_sendto_s *)pvpriv;
  263. radio = (FAR struct radio_driver_s *)dev;
  264. ninfo("flags: %04x sent: %d\n", flags, pstate->is_sent);
  265. if (pstate != NULL && (flags & IEEE802154_POLL) != 0)
  266. {
  267. /* Initialize the meta data */
  268. ieee802154_meta_data(radio, pstate, &meta);
  269. /* Get the IEEE 802.15.4 MAC header length */
  270. hdrlen = radio->r_get_mhrlen(radio, &meta);
  271. if (hdrlen < 0)
  272. {
  273. nerr("ERROR: Failed to get header length: %d\n", hdrlen);
  274. ret = hdrlen;
  275. goto errout;
  276. }
  277. /* Verify that the user buffer can fit within the frame with this
  278. * MAC header.
  279. */
  280. DEBUGASSERT(CONFIG_NET_IEEE802154_FRAMELEN <= CONFIG_IOB_BUFSIZE);
  281. if (pstate->is_buflen + hdrlen > IEEE802154_FRAMELEN)
  282. {
  283. nerr("ERROR: User buffer will not fit into the frame: %u > %u\n",
  284. (unsigned int)(pstate->is_buflen + hdrlen),
  285. (unsigned int)CONFIG_IOB_BUFSIZE);
  286. ret = -E2BIG;
  287. goto errout;
  288. }
  289. /* Allocate an IOB to hold the frame data */
  290. iob = net_ioballoc(false);
  291. if (iob == NULL)
  292. {
  293. nwarn("WARNING: Failed to allocate IOB\n");
  294. return flags;
  295. }
  296. /* Initialize the IOB */
  297. iob->io_offset = hdrlen;
  298. iob->io_len = pstate->is_buflen + hdrlen;
  299. iob->io_pktlen = pstate->is_buflen + hdrlen;
  300. /* Copy the user data into the IOB */
  301. memcpy(&iob->io_data[hdrlen], pstate->is_buffer, pstate->is_buflen);
  302. /* And submit the IOB to the network driver */
  303. ret = radio->r_req_data(radio, &meta, iob);
  304. if (ret < 0)
  305. {
  306. nerr("ERROR: r_req_data() failed: %d\n", ret);
  307. goto errout;
  308. }
  309. /* Save the successful result */
  310. pstate->is_sent = pstate->is_buflen;
  311. /* Don't allow any further call backs. */
  312. pstate->is_cb->flags = 0;
  313. pstate->is_cb->priv = NULL;
  314. pstate->is_cb->event = NULL;
  315. /* Wake up the waiting thread */
  316. nxsem_post(&pstate->is_sem);
  317. }
  318. return flags;
  319. errout:
  320. /* Don't allow any further call backs. */
  321. pstate->is_cb->flags = 0;
  322. pstate->is_cb->priv = NULL;
  323. pstate->is_cb->event = NULL;
  324. pstate->is_sent = ret;
  325. /* Wake up the waiting thread */
  326. nxsem_post(&pstate->is_sem);
  327. return flags;
  328. }
  329. /****************************************************************************
  330. * Public Functions
  331. ****************************************************************************/
  332. /****************************************************************************
  333. * Name: psock_ieee802154_sendto
  334. *
  335. * Description:
  336. * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET)
  337. * socket, the parameters to and 'tolen' are ignored (and the error EISCONN
  338. * may be returned when they are not NULL and 0), and the error ENOTCONN is
  339. * returned when the socket was not actually connected.
  340. *
  341. * Input Parameters:
  342. * psock A pointer to a NuttX-specific, internal socket structure
  343. * buf Data to send
  344. * len Length of data to send
  345. * flags Send flags
  346. * to Address of recipient
  347. * tolen The length of the address structure
  348. *
  349. * Returned Value:
  350. * On success, returns the number of characters sent. On error,
  351. * a negated errno value is retruend. See sendto() for the complete list
  352. * of return values.
  353. *
  354. ****************************************************************************/
  355. ssize_t psock_ieee802154_sendto(FAR struct socket *psock, FAR const void *buf,
  356. size_t len, int flags,
  357. FAR const struct sockaddr *to, socklen_t tolen)
  358. {
  359. FAR struct sockaddr_ieee802154_s *destaddr;
  360. FAR struct radio_driver_s *radio;
  361. FAR struct ieee802154_conn_s *conn;
  362. struct ieee802154_sendto_s state;
  363. int ret = OK;
  364. /* Verify that the sockfd corresponds to valid, allocated socket */
  365. if (psock == NULL || psock->s_crefs <= 0)
  366. {
  367. return -EBADF;
  368. }
  369. conn = (FAR struct ieee802154_conn_s *)psock->s_conn;
  370. DEBUGASSERT(conn != NULL);
  371. /* Verify that the address is large enough to be a valid PF_IEEE802154
  372. * address.
  373. */
  374. if (tolen < sizeof(struct ieee802154_saddr_s))
  375. {
  376. return -EDESTADDRREQ;
  377. }
  378. /* Get the device driver that will service this transfer */
  379. radio = ieee802154_find_device(conn, &conn->laddr);
  380. if (radio == NULL)
  381. {
  382. return -ENODEV;
  383. }
  384. /* Set the socket state to sending */
  385. psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
  386. /* Perform the send operation */
  387. /* Initialize the state structure. This is done with the network
  388. * locked because we don't want anything to happen until we are
  389. * ready.
  390. */
  391. net_lock();
  392. memset(&state, 0, sizeof(struct ieee802154_sendto_s));
  393. /* This semaphore is used for signaling and, hence, should not have
  394. * priority inheritance enabled.
  395. */
  396. (void)nxsem_init(&state.is_sem, 0, 0); /* Doesn't really fail */
  397. (void)nxsem_setprotocol(&state.is_sem, SEM_PRIO_NONE);
  398. state.is_sock = psock; /* Socket descriptor to use */
  399. state.is_buflen = len; /* Number of bytes to send */
  400. state.is_buffer = buf; /* Buffer to send from */
  401. /* Copy the destination address */
  402. destaddr = (FAR struct sockaddr_ieee802154_s *)to;
  403. memcpy(&state.is_destaddr, &destaddr->sa_addr,
  404. sizeof(struct ieee802154_saddr_s));
  405. if (len > 0)
  406. {
  407. /* Allocate resource to receive a callback */
  408. state.is_cb = ieee802154_callback_alloc(&radio->r_dev, conn);
  409. if (state.is_cb)
  410. {
  411. /* Set up the callback in the connection */
  412. state.is_cb->flags = PKT_POLL;
  413. state.is_cb->priv = (FAR void *)&state;
  414. state.is_cb->event = ieee802154_sendto_eventhandler;
  415. /* Notify the device driver that new TX data is available. */
  416. netdev_txnotify_dev(&radio->r_dev);
  417. /* Wait for the send to complete or an error to occur.
  418. * net_lockedwait will also terminate if a signal is received.
  419. */
  420. ret = net_lockedwait(&state.is_sem);
  421. /* Make sure that no further events are processed */
  422. ieee802154_callback_free(&radio->r_dev, conn, state.is_cb);
  423. }
  424. }
  425. nxsem_destroy(&state.is_sem);
  426. net_unlock();
  427. /* Set the socket state to idle */
  428. psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
  429. /* Check for a errors, Errors are signaled by negative errno values
  430. * for the send length
  431. */
  432. if (state.is_sent < 0)
  433. {
  434. return state.is_sent;
  435. }
  436. /* If net_lockedwait failed, then we were probably reawakened by a signal. In
  437. * this case, net_lockedwait will have returned negated errno appropriately.
  438. */
  439. if (ret < 0)
  440. {
  441. return ret;
  442. }
  443. /* Return the number of bytes actually sent */
  444. return state.is_sent;
  445. }
  446. #endif /* CONFIG_NET_IEEE802154 */