mac802154_assoc.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. /****************************************************************************
  2. * wireless/ieee802154/mac802154_assoc.c
  3. *
  4. * Copyright (C) 2017 Verge Inc. All rights reserved.
  5. * Author: Anthony Merlino <anthony@vergeaero.com>
  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 <stdlib.h>
  40. #include <assert.h>
  41. #include <errno.h>
  42. #include <debug.h>
  43. #include <string.h>
  44. #include <nuttx/wqueue.h>
  45. #include <nuttx/mm/iob.h>
  46. #include "mac802154.h"
  47. #include "mac802154_internal.h"
  48. #include "mac802154_assoc.h"
  49. #include <nuttx/wireless/ieee802154/ieee802154_mac.h>
  50. /****************************************************************************
  51. * Private Function Prototypes
  52. ****************************************************************************/
  53. static void mac802154_assoctimeout(FAR void *arg);
  54. static void mac802154_extract_assocresp(FAR void *arg);
  55. /****************************************************************************
  56. * Public MAC Functions
  57. ****************************************************************************/
  58. /****************************************************************************
  59. * Name: mac802154_req_associate
  60. *
  61. * Description:
  62. * The MLME-ASSOCIATE.request primitive allows a device to request an
  63. * association with a coordinator. Confirmation is returned via the
  64. * struct mac802154_maccb_s->conf_associate callback.
  65. *
  66. * On receipt of the MLME-ASSOCIATE.request primitive, the MLME of an
  67. * unassociated device first updates the appropriate PHY and MAC PIB
  68. * attributes, as described in 5.1.3.1, and then generates an association
  69. * request command, as defined in 5.3.1 [1] pg.80
  70. *
  71. ****************************************************************************/
  72. int mac802154_req_associate(MACHANDLE mac,
  73. FAR struct ieee802154_assoc_req_s *req)
  74. {
  75. FAR struct ieee802154_privmac_s *priv =
  76. (FAR struct ieee802154_privmac_s *)mac;
  77. FAR struct ieee802154_txdesc_s *txdesc;
  78. FAR struct iob_s *iob;
  79. int ret;
  80. int i;
  81. if (req->coordaddr.mode == IEEE802154_ADDRMODE_NONE)
  82. {
  83. return -EINVAL;
  84. }
  85. /* Get exclusive access to the operation semaphore. This must happen before
  86. * getting exclusive access to the MAC struct or else there could be a
  87. * lockup condition. This would occur if another thread is using the
  88. * cmdtrans but needs access to the MAC in order to unlock it.
  89. */
  90. ret = mac802154_takesem(&priv->opsem, true);
  91. if (ret < 0)
  92. {
  93. return ret;
  94. }
  95. priv->curr_op = MAC802154_OP_ASSOC;
  96. priv->curr_cmd = IEEE802154_CMD_ASSOC_REQ;
  97. /* Get exclusive access to the MAC */
  98. ret = mac802154_lock(priv, true);
  99. if (ret < 0)
  100. {
  101. mac802154_givesem(&priv->opsem);
  102. return ret;
  103. }
  104. /* Set the channel and channel page of the PHY layer */
  105. mac802154_setchannel(priv, req->chan);
  106. mac802154_setchpage(priv, req->chpage);
  107. /* Set the coordinator address attributes */
  108. mac802154_setcoordaddr(priv, &req->coordaddr);
  109. /* Copy the coordinator PAN ID to our PAN ID */
  110. mac802154_setpanid(priv, req->coordaddr.panid);
  111. /* Copy in the capabilities information bitfield */
  112. if (req->capabilities.devtype)
  113. {
  114. mac802154_setdevmode(priv, IEEE802154_DEVMODE_COORD);
  115. }
  116. else
  117. {
  118. mac802154_setdevmode(priv, IEEE802154_DEVMODE_ENDPOINT);
  119. }
  120. mac802154_setrxonidle(priv, req->capabilities.rxonidle);
  121. /* Allocate an IOB to put the frame in */
  122. iob = iob_alloc(false, IOBUSER_WIRELESS_MAC802154);
  123. DEBUGASSERT(iob != NULL);
  124. iob->io_flink = NULL;
  125. iob->io_len = 0;
  126. iob->io_offset = 0;
  127. iob->io_pktlen = 0;
  128. /* Allocate the txdesc, waiting if necessary */
  129. ret = mac802154_txdesc_alloc(priv, &txdesc, true);
  130. if (ret < 0)
  131. {
  132. iob_free(iob, IOBUSER_WIRELESS_MAC802154);
  133. mac802154_unlock(priv)
  134. mac802154_givesem(&priv->opsem);
  135. return ret;
  136. }
  137. /* Get a uin16_t reference to the first two bytes. ie frame control field */
  138. iob->io_data[0] = 0;
  139. iob->io_data[1] = 0;
  140. IEEE802154_SETACKREQ(iob->io_data, 0);
  141. IEEE802154_SETFTYPE(iob->io_data, 0, IEEE802154_FRAME_COMMAND);
  142. IEEE802154_SETDADDRMODE(iob->io_data, 0, priv->pandesc.coordaddr.mode);
  143. IEEE802154_SETSADDRMODE(iob->io_data, 0, IEEE802154_ADDRMODE_EXTENDED);
  144. iob->io_len = 2;
  145. /* Each time a data or a MAC command frame is generated, the MAC sublayer
  146. * shall copy the value of macDSN into the Sequence Number field of the MHR
  147. * of the outgoing frame and then increment it by one. [1] pg. 40.
  148. */
  149. iob->io_data[iob->io_len++] = priv->dsn++;
  150. /* The Destination PAN Identifier field shall contain the identifier of the
  151. * PAN to which to associate. [1] pg. 68
  152. */
  153. mac802154_putpanid(iob, priv->pandesc.coordaddr.panid);
  154. /* The Destination Address field shall contain the address from the beacon
  155. * frame that was transmitted by the coordinator to which the association
  156. * request command is being sent. [1] pg. 68
  157. */
  158. if (priv->pandesc.coordaddr.mode == IEEE802154_ADDRMODE_SHORT)
  159. {
  160. mac802154_putsaddr(iob, priv->pandesc.coordaddr.saddr);
  161. }
  162. else if (priv->pandesc.coordaddr.mode == IEEE802154_ADDRMODE_EXTENDED)
  163. {
  164. mac802154_puteaddr(iob, priv->pandesc.coordaddr.eaddr);
  165. }
  166. /* The Source PAN Identifier field shall contain the broadcast PAN identifier. */
  167. mac802154_putsaddr(iob, &IEEE802154_SADDR_BCAST);
  168. /* The Source Address field shall contain the value of macExtendedAddress. */
  169. mac802154_puteaddr(iob, priv->addr.eaddr);
  170. /* Copy in the Command Frame Identifier */
  171. iob->io_data[iob->io_len++] = IEEE802154_CMD_ASSOC_REQ;
  172. /* Copy in the capability information bits */
  173. iob->io_data[iob->io_len] = 0;
  174. iob->io_data[iob->io_len] |= (req->capabilities.devtype <<
  175. IEEE802154_CAPABILITY_SHIFT_DEVTYPE);
  176. iob->io_data[iob->io_len] |= (req->capabilities.powersource <<
  177. IEEE802154_CAPABILITY_SHIFT_PWRSRC);
  178. iob->io_data[iob->io_len] |= (req->capabilities.rxonidle <<
  179. IEEE802154_CAPABILITY_SHIFT_RXONIDLE);
  180. iob->io_data[iob->io_len] |= (req->capabilities.security <<
  181. IEEE802154_CAPABILITY_SHIFT_SECURITY);
  182. iob->io_data[iob->io_len] |= (req->capabilities.allocaddr <<
  183. IEEE802154_CAPABILITY_SHIFT_ALLOCADDR);
  184. iob->io_len++;
  185. txdesc->frame = iob;
  186. txdesc->frametype = IEEE802154_FRAME_COMMAND;
  187. txdesc->ackreq = true;
  188. /* Save a copy of the destination addressing infromation into the tx
  189. * descriptor. We only do this for commands to help with handling their
  190. * progession.
  191. */
  192. memcpy(&txdesc->destaddr, &req->coordaddr,
  193. sizeof(struct ieee802154_addr_s));
  194. /* Save a reference of the tx descriptor */
  195. priv->cmd_desc = txdesc;
  196. /* Search the list of PAN descriptors, that would have been populated by
  197. * the latest scan procedure. If we have seen a beacon from the
  198. * coordinator that we are about to associate with, we can check the
  199. * beacon order to determine whether we can send the command during the
  200. * CAP. If we haven't received a beacon frame from the desired
  201. * coordinator address, we have to just send the frame out immediately.
  202. */
  203. for (i = 0; i < priv->npandesc; i++)
  204. {
  205. /* Check to make sure the beacon is from the same channel as the request */
  206. if (req->chan != priv->pandescs[i].chan)
  207. {
  208. continue;
  209. }
  210. if (memcmp(&req->coordaddr, &priv->pandescs[i].coordaddr,
  211. sizeof(struct ieee802154_addr_s)) == 0)
  212. {
  213. wlinfo("Found matching beacon to use for settings\n");
  214. /* We have a beacon frame from this coordinator, we can set the
  215. * sfspec and send accordingly.
  216. */
  217. /* Copy in the new superframe spec */
  218. memcpy(&priv->sfspec, &priv->pandescs[i].sfspec,
  219. sizeof(struct ieee802154_superframespec_s));
  220. /* Tell the radio layer about the superframe spec update */
  221. priv->radio->sfupdate(priv->radio, &priv->pandescs[i].sfspec);
  222. }
  223. }
  224. if (priv->sfspec.beaconorder == 15)
  225. {
  226. wlinfo("Transmitting assoc request\n");
  227. /* Association Request command gets sent out immediately */
  228. priv->radio->txdelayed(priv->radio, txdesc, 0);
  229. }
  230. else
  231. {
  232. wlinfo("Queuing assoc request for CAP\n");
  233. /* Link the transaction into the CSMA transaction list */
  234. sq_addlast((FAR sq_entry_t *)txdesc, &priv->csma_queue);
  235. /* Notify the radio driver that there is data available */
  236. priv->radio->txnotify(priv->radio, false);
  237. }
  238. /* We no longer need to have the MAC layer locked. */
  239. mac802154_unlock(priv)
  240. return OK;
  241. }
  242. /****************************************************************************
  243. * Name: mac802154_resp_associate
  244. *
  245. * Description:
  246. * The MLME-ASSOCIATE.response primitive is used to initiate a response to
  247. * an MLME-ASSOCIATE.indication primitive.
  248. *
  249. ****************************************************************************/
  250. int mac802154_resp_associate(MACHANDLE mac,
  251. FAR struct ieee802154_assoc_resp_s *resp)
  252. {
  253. FAR struct ieee802154_privmac_s *priv =
  254. (FAR struct ieee802154_privmac_s *)mac;
  255. FAR struct ieee802154_txdesc_s *txdesc;
  256. FAR struct iob_s *iob;
  257. int ret;
  258. /* Allocate an IOB to put the frame in */
  259. iob = iob_alloc(false, IOBUSER_WIRELESS_MAC802154);
  260. DEBUGASSERT(iob != NULL);
  261. iob->io_flink = NULL;
  262. iob->io_len = 0;
  263. iob->io_offset = 0;
  264. iob->io_pktlen = 0;
  265. /* The Destination Addressing Mode and Source Addressing Mode fields shall
  266. * each be set to indicate extended addressing.
  267. *
  268. * The Frame Pending field shall be set to zero and ignored upon reception,
  269. * and the AR field shall be set to one.
  270. *
  271. * The PAN ID Compression field shall be set to one. [1] pg. 69
  272. */
  273. iob->io_data[0] = 0;
  274. iob->io_data[1] = 0;
  275. IEEE802154_SETACKREQ(iob->io_data, 0);
  276. IEEE802154_SETPANIDCOMP(iob->io_data, 0);
  277. IEEE802154_SETFTYPE(iob->io_data, 0, IEEE802154_FRAME_COMMAND);
  278. IEEE802154_SETDADDRMODE(iob->io_data, 0, IEEE802154_ADDRMODE_EXTENDED);
  279. IEEE802154_SETSADDRMODE(iob->io_data, 0, IEEE802154_ADDRMODE_EXTENDED);
  280. iob->io_len = 2;
  281. /* Each time a data or a MAC command frame is generated, the MAC sublayer
  282. * shall copy the value of macDSN into the Sequence Number field of the MHR
  283. * of the outgoing frame and then increment it by one. [1] pg. 40.
  284. */
  285. iob->io_data[iob->io_len++] = priv->dsn++;
  286. /* In accordance with this value of the PAN ID Compression field, the
  287. * Destination PAN Identifier field shall contain the value of macPANId,
  288. * while the Source PAN Identifier field shall be omitted. [1] pg. 69
  289. */
  290. mac802154_putpanid(iob, priv->addr.panid);
  291. /* The Destination Address field shall contain the extended address of the
  292. * device requesting association. [1] pg. 69
  293. */
  294. mac802154_puteaddr(iob, resp->devaddr);
  295. /* The Source Address field shall contain the value of macExtendedAddress. */
  296. mac802154_puteaddr(iob, priv->addr.eaddr);
  297. /* Copy in the Command Frame Identifier */
  298. iob->io_data[iob->io_len++] = IEEE802154_CMD_ASSOC_RESP;
  299. /* Copy in the assigned short address */
  300. if (resp->status == IEEE802154_STATUS_SUCCESS)
  301. {
  302. mac802154_putsaddr(iob, resp->assocsaddr);
  303. }
  304. else
  305. {
  306. mac802154_putsaddr(iob, &IEEE802154_SADDR_UNSPEC);
  307. }
  308. /* Copy in the association status */
  309. iob->io_data[iob->io_len++] = resp->status;
  310. /* Get exclusive access to the MAC */
  311. ret = mac802154_lock(priv, true);
  312. if (ret < 0)
  313. {
  314. iob_free(iob, IOBUSER_WIRELESS_MAC802154);
  315. return ret;
  316. }
  317. /* Allocate the txdesc, waiting if necessary */
  318. ret = mac802154_txdesc_alloc(priv, &txdesc, true);
  319. if (ret < 0)
  320. {
  321. iob_free(iob, IOBUSER_WIRELESS_MAC802154);
  322. mac802154_unlock(priv)
  323. return ret;
  324. }
  325. txdesc->frame = iob;
  326. txdesc->frametype = IEEE802154_FRAME_COMMAND;
  327. txdesc->ackreq = true;
  328. txdesc->destaddr.mode = IEEE802154_ADDRMODE_EXTENDED;
  329. IEEE802154_PANIDCOPY(txdesc->destaddr.panid, priv->addr.panid);
  330. IEEE802154_EADDRCOPY(txdesc->destaddr.eaddr, resp->devaddr);
  331. mac802154_setupindirect(priv, txdesc);
  332. mac802154_unlock(priv)
  333. return OK;
  334. }
  335. /****************************************************************************
  336. * Internal MAC Functions
  337. ****************************************************************************/
  338. /****************************************************************************
  339. * Name: mac802154_txdone_assocreq
  340. *
  341. * Description:
  342. * Handle the completion (success/failure) of transmitting an association
  343. * request command.
  344. *
  345. * Assumptions:
  346. * Called with the MAC locked.
  347. *
  348. ****************************************************************************/
  349. void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv,
  350. FAR struct ieee802154_txdesc_s *txdesc)
  351. {
  352. enum ieee802154_status_e status;
  353. FAR struct ieee802154_primitive_s *primitive =
  354. (FAR struct ieee802154_primitive_s *)txdesc->conf;
  355. if (txdesc->conf->status != IEEE802154_STATUS_SUCCESS)
  356. {
  357. /* if the association request command cannot be sent due to a
  358. * channel access failure, the MAC sublayer shall notify the next
  359. * higher layer. [1] pg. 33
  360. */
  361. /* We can actually high-jack the data conf notification since it
  362. * is allocated as an ieee80215_primitive_s anyway. Before we overwrite
  363. * any data though, we need to get the status from the data
  364. * confirmation as that is the method we use to get the reason
  365. * why the tx failed from the radio layer.
  366. */
  367. status = txdesc->conf->status;
  368. primitive->type = IEEE802154_PRIMITIVE_CONF_ASSOC;
  369. primitive->u.assocconf.status = status;
  370. /* The short device address allocated by the coordinator on
  371. * successful association. This parameter will be equal to 0xffff
  372. * if the association attempt was unsuccessful. [1] pg. 81
  373. */
  374. IEEE802154_SADDRCOPY(primitive->u.assocconf.saddr,
  375. &IEEE802154_SADDR_UNSPEC);
  376. /* We are now done the operation, unlock the semaphore */
  377. priv->curr_op = MAC802154_OP_NONE;
  378. priv->cmd_desc = NULL;
  379. mac802154_givesem(&priv->opsem);
  380. /* Release the MAC, call the callback, get exclusive access again */
  381. mac802154_notify(priv, primitive);
  382. }
  383. else
  384. {
  385. /* On receipt of the acknowledgment to the association request
  386. * command, the device shall wait for at most macResponseWaitTime
  387. * for the coordinator to make its association decision; the PIB
  388. * attribute macResponseWaitTime is a network-topology-dependent
  389. * parameter and may be set to match the specific requirements of
  390. * the network that a device is trying to join. If the device is
  391. * tracking the beacon, it shall attempt to extract the association
  392. * response command from the coordinator whenever it is indicated in
  393. * the beacon frame. If the device is not tracking the beacon, it
  394. * shall attempt to extract the association response command from
  395. * the coordinator after macResponseWaitTime. [1] pg. 34
  396. */
  397. if (priv->sfspec.beaconorder < 15)
  398. {
  399. /* We are tracking the beacon, so we should see our address in the
  400. * beacon frame within macResponseWaitTime if the coordinator is
  401. * going to respond. Setup a timeout for macResponseWaitTime so
  402. * that we can inform the next highest layer if the association
  403. * attempt fails due to NO_DATA.
  404. *
  405. * TODO: The standard defines macResponseWaitTime as:
  406. * The maximum time, in multiples of aBaseSuperframeDuration, a
  407. * device shall wait for a response command frame to be available
  408. * following a request command frame.
  409. *
  410. * However, on beacon-enabled networks, it seems the maximum value
  411. * isn't really that large of a value, AKA: assoc always fails
  412. * from timeout even though everything is working as expected.
  413. * The definition does say after we've sent a data request, which
  414. * we, haven't sent yet, but we do need a timeout for association
  415. * in general. Not sure what the correct answer is. For now, I am
  416. * going to change the way macResponseWaitTime is used with beacon-
  417. * enabled networks and make the timeout (BI * macResponseWaitTime)
  418. * where BI is Beacon Interval = aBaseSuperframeDuration *
  419. * 2^macBeaconOrder
  420. */
  421. wlinfo("Starting timeout timer\n");
  422. mac802154_timerstart(priv, (priv->resp_waittime *
  423. (IEEE802154_BASE_SUPERFRAME_DURATION *
  424. (1 << priv->sfspec.beaconorder))),
  425. mac802154_assoctimeout);
  426. }
  427. else
  428. {
  429. /* Make sure the coordinator address mode is not set to none. This
  430. * shouldn't happen since the association request should have set
  431. * the mode to short or extended
  432. */
  433. DEBUGASSERT(priv->pandesc.coordaddr.mode !=
  434. IEEE802154_ADDRMODE_NONE);
  435. /* Off-load extracting the Association Response to the work queue to
  436. * avoid locking up the calling thread.
  437. */
  438. DEBUGASSERT(work_available(&priv->macop_work));
  439. work_queue(LPWORK, &priv->macop_work, mac802154_extract_assocresp,
  440. priv, 0);
  441. }
  442. /* Deallocate the data conf notification as it is no longer needed. */
  443. ieee802154_primitive_free(primitive);
  444. }
  445. }
  446. /****************************************************************************
  447. * Name: mac802154_txdone_datareq_assoc
  448. *
  449. * Description:
  450. * Handle the completion (success/failure) of transmitting a data request
  451. * command in an effort to extract the association response from the
  452. * coordinator.
  453. *
  454. * Assumptions:
  455. * Called with the MAC locked.
  456. *
  457. ****************************************************************************/
  458. void mac802154_txdone_datareq_assoc(FAR struct ieee802154_privmac_s *priv,
  459. FAR struct ieee802154_txdesc_s *txdesc)
  460. {
  461. enum ieee802154_status_e status;
  462. FAR struct ieee802154_primitive_s *primitive =
  463. (FAR struct ieee802154_primitive_s *)txdesc->conf;
  464. /* If the data request failed to be sent, notify the next layer
  465. * that the association has failed.
  466. * OR
  467. * On receipt of the Ack frame with the Frame Pending field set
  468. * to zero, the device shall conclude that there are no data
  469. * pending at the coordinator. [1] pg. 43
  470. */
  471. if (primitive->u.dataconf.status != IEEE802154_STATUS_SUCCESS ||
  472. txdesc->framepending == 0)
  473. {
  474. if (primitive->u.dataconf.status != IEEE802154_STATUS_SUCCESS)
  475. {
  476. status = primitive->u.dataconf.status;
  477. }
  478. else
  479. {
  480. /* If the device does not extract an association response
  481. * command frame from the coordinator within macResponseWaitTime,
  482. * the MLME shall issue the MLME-ASSOCIATE.confirm primitive,
  483. * as described in 6.2.2.4, with a status of NO_DATA, and the
  484. * association attempt shall be deemed a failure. [1] pg. 34
  485. */
  486. status = IEEE802154_STATUS_NO_DATA;
  487. }
  488. primitive->type = IEEE802154_PRIMITIVE_CONF_ASSOC;
  489. primitive->u.assocconf.status = status;
  490. /* The short device address allocated by the coordinator on
  491. * successful association. This parameter will be equal to 0xffff
  492. * if the association attempt was unsuccessful. [1] pg. 81
  493. */
  494. IEEE802154_SADDRCOPY(primitive->u.assocconf.saddr,
  495. &IEEE802154_SADDR_UNSPEC);
  496. /* We are now done the operation, and can release the command */
  497. priv->curr_op = MAC802154_OP_NONE;
  498. priv->cmd_desc = NULL;
  499. mac802154_givesem(&priv->opsem);
  500. mac802154_notify(priv, primitive);
  501. }
  502. else
  503. {
  504. /* On receipt of the acknowledgment frame with the Frame
  505. * Pending field set to one, a device shall enable its
  506. * receiver for at most macMaxFrameTotalWaitTime to receive
  507. * the corresponding data frame from the coordinator. [1] pg.43
  508. */
  509. mac802154_rxenable(priv);
  510. /* If we are on a beacon-enabled network, we already have the
  511. * association timeout timer scheduled. So we only need to start the
  512. * timeout timer if we are operating on a non-beacon enabled network.
  513. *
  514. * NOTE: This may create a bad side-effect where the receiver is on
  515. * for longer than it needs to be during association. Revisit if power
  516. * is ever an issue.
  517. */
  518. if (priv->sfspec.beaconorder == 15)
  519. {
  520. /* Start a timer, if we receive the data frame, we will cancel
  521. * the timer, otherwise it will expire and we will notify the
  522. * next highest layer of the failure.
  523. */
  524. wlinfo("Starting timeout timer\n");
  525. mac802154_timerstart(priv, priv->max_frame_waittime,
  526. mac802154_assoctimeout);
  527. }
  528. /* Deallocate the data conf notification as it is no longer needed. */
  529. ieee802154_primitive_free(primitive);
  530. }
  531. }
  532. /****************************************************************************
  533. * Name: mac802154_rx_assocreq
  534. *
  535. * Description:
  536. * Function called from the generic RX Frame worker to parse and handle the
  537. * reception of an Association Request MAC command frame.
  538. *
  539. ****************************************************************************/
  540. void mac802154_rx_assocreq(FAR struct ieee802154_privmac_s *priv,
  541. FAR struct ieee802154_data_ind_s *ind)
  542. {
  543. FAR struct iob_s *frame = ind->frame;
  544. FAR struct ieee802154_primitive_s *primitive;
  545. uint8_t cap;
  546. /* Allocate a notification to pass to the next highest layer */
  547. primitive = ieee802154_primitive_allocate();
  548. primitive->type = IEEE802154_PRIMITIVE_IND_ASSOC;
  549. /* Association Requests should always be sent from a device with source
  550. * addressing mode set to extended mode. Throw out any request received
  551. * without addressing set to extended
  552. */
  553. if (ind->src.mode != IEEE802154_ADDRMODE_EXTENDED)
  554. {
  555. return;
  556. }
  557. /* Copy the extended address of the requesting device */
  558. IEEE802154_EADDRCOPY(primitive->u.assocind.devaddr, ind->src.eaddr);
  559. /* Copy in the capability information from the frame to the notification */
  560. cap = frame->io_data[frame->io_offset++];
  561. primitive->u.assocind.capabilities.devtype =
  562. (cap >> IEEE802154_CAPABILITY_SHIFT_DEVTYPE) & 0x01;
  563. primitive->u.assocind.capabilities.powersource =
  564. (cap >> IEEE802154_CAPABILITY_SHIFT_PWRSRC) & 0x01;
  565. primitive->u.assocind.capabilities.rxonidle =
  566. (cap >> IEEE802154_CAPABILITY_SHIFT_RXONIDLE) & 0x01;
  567. primitive->u.assocind.capabilities.security =
  568. (cap >> IEEE802154_CAPABILITY_SHIFT_SECURITY) & 0x01;
  569. primitive->u.assocind.capabilities.allocaddr =
  570. (cap >> IEEE802154_CAPABILITY_SHIFT_ALLOCADDR) & 0x01;
  571. #ifdef CONFIG_IEEE802154_SECURITY
  572. # error Missing security logic
  573. #endif
  574. /* Get exclusive access to the MAC */
  575. mac802154_lock(priv, false);
  576. /* Notify the next highest layer of the association status */
  577. mac802154_notify(priv, primitive);
  578. mac802154_unlock(priv)
  579. }
  580. /****************************************************************************
  581. * Name: mac802154_rx_assocresp
  582. *
  583. * Description:
  584. * Function called from the generic RX Frame worker to parse and handle the
  585. * reception of an Association Response MAC command frame.
  586. *
  587. ****************************************************************************/
  588. void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv,
  589. FAR struct ieee802154_data_ind_s *ind)
  590. {
  591. FAR struct iob_s *iob = ind->frame;
  592. FAR struct ieee802154_primitive_s *primitive;
  593. /* Check if we are performing an Association operation, if not, we will
  594. * just ignore the frame.
  595. */
  596. if (priv->curr_op != MAC802154_OP_ASSOC)
  597. {
  598. /* This situation can occur in a beacon-enabled network if the
  599. * association request has timed out, but the Coordinator has already
  600. * queued the response. Which means the beacon would contain our
  601. * address, causing us to extract the response.
  602. *
  603. * TODO: What is supposed to happen in this situation. Are we supposed
  604. * to accept the request? Are we supposed to Disassociate with the
  605. * network as a convienience to the PAN Coordinator. So that it does
  606. * not need to waste space holding our information?
  607. */
  608. wlinfo("Ignoring association response frame\n");
  609. return;
  610. }
  611. /* Cancel the timeout used if we didn't get a response */
  612. mac802154_timercancel(priv);
  613. /* Allocate a notification to pass to the next highest layer */
  614. primitive = ieee802154_primitive_allocate();
  615. primitive->type = IEEE802154_PRIMITIVE_CONF_ASSOC;
  616. /* Get exclusive access to the MAC */
  617. mac802154_lock(priv, false);
  618. /* Parse the short address from the response */
  619. mac802154_takesaddr(iob, priv->addr.saddr);
  620. /* Inform the radio of the address change */
  621. priv->radio->setattr(priv->radio, IEEE802154_ATTR_MAC_SADDR,
  622. (FAR union ieee802154_attr_u *)priv->addr.saddr);
  623. /* A Short Address field value equal to 0xfffe shall indicate that the
  624. * device has been successfully associated with a PAN but has not been
  625. * allocated a short address. In this case, the device shall communicate
  626. * on the PAN using only its extended address. [1] pg. 70
  627. */
  628. if (IEEE802154_SADDRCMP(priv->addr.saddr, &IEEE802154_SADDR_BCAST))
  629. {
  630. /* TODO: Figure out if this is sufficient */
  631. priv->addr.mode = IEEE802154_ADDRMODE_SHORT;
  632. }
  633. /* Parse the status from the response */
  634. primitive->u.assocconf.status = iob->io_data[iob->io_offset++];
  635. if (primitive->u.assocconf.status == IEEE802154_STATUS_SUCCESS)
  636. {
  637. priv->isassoc = true;
  638. }
  639. else
  640. {
  641. priv->isassoc = false;
  642. }
  643. IEEE802154_SADDRCOPY(primitive->u.assocconf.saddr, priv->addr.saddr);
  644. /* We are no longer performing the association operation */
  645. priv->curr_op = MAC802154_OP_NONE;
  646. priv->cmd_desc = NULL;
  647. mac802154_givesem(&priv->opsem);
  648. mac802154_rxdisable(priv);
  649. /* Notify the next highest layer of the association status */
  650. mac802154_notify(priv, primitive);
  651. mac802154_unlock(priv)
  652. }
  653. /****************************************************************************
  654. * Private Function
  655. ****************************************************************************/
  656. /****************************************************************************
  657. * Name: mac802154_assoctimeout
  658. *
  659. * Description:
  660. * Function registered with MAC timer that gets called via the work queue
  661. * to handle a timeout for extracting the Association Response from the
  662. * Coordinator.
  663. *
  664. ****************************************************************************/
  665. static void mac802154_assoctimeout(FAR void *arg)
  666. {
  667. FAR struct ieee802154_privmac_s *priv =
  668. (FAR struct ieee802154_privmac_s *)arg;
  669. FAR struct ieee802154_primitive_s *primitive;
  670. /* If there is work scheduled for the rxframe_worker, we want to reschedule
  671. * this work, so that we make sure if the frame we were waiting for was just
  672. * received, we don't timeout
  673. */
  674. if (!work_available(&priv->rx_work))
  675. {
  676. work_queue(HPWORK, &priv->timer_work, mac802154_assoctimeout, priv, 0);
  677. return;
  678. }
  679. DEBUGASSERT(priv->curr_op == MAC802154_OP_ASSOC);
  680. /* If the device does not extract an association response command
  681. * frame from the coordinator within macResponseWaitTime, the MLME
  682. * shall issue the MLME-ASSOCIATE.confirm primitive, as described
  683. * in 6.2.2.4, with a status of NO_DATA, and the association attempt
  684. * shall be deemed a failure. [1] pg. 33
  685. */
  686. /* Allocate a notification struct to pass to the next highest layer.
  687. * Don't allow EINTR to interrupt.
  688. */
  689. primitive = ieee802154_primitive_allocate();
  690. primitive->type = IEEE802154_PRIMITIVE_CONF_ASSOC;
  691. primitive->u.assocconf.status = IEEE802154_STATUS_NO_DATA;
  692. IEEE802154_SADDRCOPY(primitive->u.assocconf.saddr,
  693. &IEEE802154_SADDR_UNSPEC);
  694. /* We are no longer performing the association operation */
  695. priv->curr_op = MAC802154_OP_NONE;
  696. priv->cmd_desc = NULL;
  697. mac802154_givesem(&priv->opsem);
  698. mac802154_rxdisable(priv);
  699. mac802154_lock(priv, false);
  700. mac802154_notify(priv, primitive);
  701. mac802154_unlock(priv)
  702. }
  703. /****************************************************************************
  704. * Name: mac802154_extract_assocrespj
  705. *
  706. * Description:
  707. * Create and send a Data request command to extract the Association response
  708. * from the Coordinator.
  709. *
  710. * Assumptions:
  711. * Called with the MAC unlocked.
  712. *
  713. ****************************************************************************/
  714. static void mac802154_extract_assocresp(FAR void *arg)
  715. {
  716. FAR struct ieee802154_privmac_s *priv =
  717. (FAR struct ieee802154_privmac_s *)arg;
  718. FAR struct ieee802154_txdesc_s *respdesc;
  719. mac802154_lock(priv, false);
  720. mac802154_txdesc_alloc(priv, &respdesc, false);
  721. mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
  722. IEEE802154_ADDRMODE_EXTENDED, respdesc);
  723. mac802154_unlock(priv)
  724. priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
  725. priv->radio->txdelayed(priv->radio, respdesc,
  726. (priv->resp_waittime*IEEE802154_BASE_SUPERFRAME_DURATION));
  727. }