mac802154.c 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185
  1. /****************************************************************************
  2. * wireless/ieee802154/mac802154.c
  3. *
  4. * Copyright (C) 2016 Sebastien Lorquet. All rights reserved.
  5. * Copyright (C) 2017 Gregory Nutt. All rights reserved.
  6. * Copyright (C) 2017 Verge Inc. All rights reserved.
  7. *
  8. * Author: Sebastien Lorquet <sebastien@lorquet.fr>
  9. * Author: Gregory Nutt <gnutt@nuttx.org>
  10. * Author: Anthony Merlino <anthony@vergeaero.com>
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. *
  16. * 1. Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. * 2. Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in
  20. * the documentation and/or other materials provided with the
  21. * distribution.
  22. * 3. Neither the name NuttX nor the names of its contributors may be
  23. * used to endorse or promote products derived from this software
  24. * without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  27. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  28. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  29. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  30. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  31. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  32. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  33. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  34. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  36. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. ****************************************************************************/
  40. /****************************************************************************
  41. * Included Files
  42. ****************************************************************************/
  43. #include <nuttx/config.h>
  44. #include <stdlib.h>
  45. #include <assert.h>
  46. #include <errno.h>
  47. #include <debug.h>
  48. #include <string.h>
  49. #include <nuttx/kmalloc.h>
  50. #include <nuttx/wqueue.h>
  51. #include <nuttx/semaphore.h>
  52. #include <nuttx/mm/iob.h>
  53. #include "mac802154.h"
  54. #include "mac802154_internal.h"
  55. #include "mac802154_assoc.h"
  56. #include "mac802154_scan.h"
  57. #include "mac802154_data.h"
  58. #include "mac802154_poll.h"
  59. #include <nuttx/wireless/ieee802154/ieee802154_mac.h>
  60. #include <nuttx/wireless/ieee802154/ieee802154_radio.h>
  61. /****************************************************************************
  62. * Private Function Prototypes
  63. ****************************************************************************/
  64. /* Data structure pools and allocation helpers */
  65. static void mac802154_resetqueues(FAR struct ieee802154_privmac_s *priv);
  66. /* IEEE 802.15.4 PHY Interface OPs */
  67. static int mac802154_radiopoll(FAR const struct ieee802154_radiocb_s *radiocb,
  68. bool gts,
  69. FAR struct ieee802154_txdesc_s **tx_desc);
  70. static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb,
  71. FAR struct ieee802154_txdesc_s *tx_desc);
  72. static void mac802154_txdone_worker(FAR void *arg);
  73. static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb,
  74. FAR struct ieee802154_data_ind_s *ind);
  75. static void mac802154_rxframe_worker(FAR void *arg);
  76. static void mac802154_edresult(FAR const struct ieee802154_radiocb_s *radiocb,
  77. uint8_t edval);
  78. static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb,
  79. enum ieee802154_sfevent_e sfevent);
  80. static void mac802154_purge_worker(FAR void *arg);
  81. static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv,
  82. FAR struct ieee802154_data_ind_s *ind);
  83. static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv,
  84. FAR struct ieee802154_data_ind_s *ind);
  85. static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv,
  86. FAR struct ieee802154_data_ind_s *ind);
  87. static void mac802154_notify_worker(FAR void *arg);
  88. /****************************************************************************
  89. * Private Functions
  90. ****************************************************************************/
  91. /****************************************************************************
  92. * Name: mac802154_resetqueues
  93. *
  94. * Description:
  95. * Initializes the various queues used in the MAC layer. Called on creation
  96. * of MAC.
  97. *
  98. ****************************************************************************/
  99. static void mac802154_resetqueues(FAR struct ieee802154_privmac_s *priv)
  100. {
  101. int i;
  102. sq_init(&priv->txdone_queue);
  103. sq_init(&priv->csma_queue);
  104. sq_init(&priv->gts_queue);
  105. sq_init(&priv->indirect_queue);
  106. sq_init(&priv->dataind_queue);
  107. sq_init(&priv->primitive_queue);
  108. /* Initialize the tx descriptor allocation pool */
  109. sq_init(&priv->txdesc_queue);
  110. for (i = 0; i < CONFIG_MAC802154_NTXDESC; i++)
  111. {
  112. sq_addlast((FAR sq_entry_t *)&priv->txdesc_pool[i],
  113. &priv->txdesc_queue);
  114. }
  115. nxsem_init(&priv->txdesc_sem, 0, CONFIG_MAC802154_NTXDESC);
  116. }
  117. /****************************************************************************
  118. * Name: mac802154_txdesc_pool
  119. *
  120. * Description:
  121. * This function allocates a tx descriptor and the dependent primitive (data
  122. * confirmation) from the free list. The primitive and tx descriptor must be
  123. * freed seperately.
  124. *
  125. * Assumptions:
  126. * priv MAC struct is locked when calling.
  127. *
  128. * Notes:
  129. * If any of the semaphore waits inside this function get interrupted, the
  130. * function will release the MAC layer. If this function returns -EINTR,
  131. * the calling code should NOT release the MAC semaphore.
  132. *
  133. ****************************************************************************/
  134. int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv,
  135. FAR struct ieee802154_txdesc_s **txdesc,
  136. bool allow_interrupt)
  137. {
  138. int ret;
  139. FAR struct ieee802154_primitive_s *primitive;
  140. /* Try and take a count from the semaphore. If this succeeds, we have
  141. * "reserved" the structure, but still need to unlink it from the free list.
  142. * The MAC is already locked, so there shouldn't be any other conflicting
  143. * calls.
  144. */
  145. ret = nxsem_trywait(&priv->txdesc_sem);
  146. if (ret == OK)
  147. {
  148. *txdesc =
  149. (FAR struct ieee802154_txdesc_s *)sq_remfirst(&priv->txdesc_queue);
  150. }
  151. else
  152. {
  153. /* Unlock MAC so that other work can be done to free a notification */
  154. mac802154_unlock(priv)
  155. /* Take a count from the tx desc semaphore, waiting if necessary. We
  156. * only return from here with an error if we are allowing interruptions
  157. * and we received a signal.
  158. */
  159. ret = mac802154_takesem(&priv->txdesc_sem, allow_interrupt);
  160. if (ret < 0)
  161. {
  162. /* MAC is already released */
  163. wlwarn("WARNING: mac802154_takesem failed: %d\n", ret);
  164. return -EINTR;
  165. }
  166. /* If we've taken a count from the semaphore, we have "reserved" the
  167. * struct but now we need to pop it off of the free list. We need to
  168. * re-lock the MAC in order to ensure this happens correctly.
  169. */
  170. ret = mac802154_lock(priv, allow_interrupt);
  171. if (ret < 0)
  172. {
  173. wlwarn("WARNING: mac802154_lock failed: %d\n", ret);
  174. mac802154_givesem(&priv->txdesc_sem);
  175. return -EINTR;
  176. }
  177. /* We can now safely unlink the next free structure from the free list */
  178. *txdesc =
  179. (FAR struct ieee802154_txdesc_s *)sq_remfirst(&priv->txdesc_queue);
  180. }
  181. /* We have now successfully allocated the tx descriptor. Now we need to
  182. * allocate the primitive for the data confirmation that gets passed along
  183. * with the tx descriptor. These are allocated together, but not freed
  184. * together.
  185. */
  186. primitive = ieee802154_primitive_allocate();
  187. (*txdesc)->purgetime = 0;
  188. (*txdesc)->retrycount = priv->maxretries;
  189. (*txdesc)->conf = &primitive->u.dataconf;
  190. return OK;
  191. }
  192. /****************************************************************************
  193. * Name: mac802154_createdatareq
  194. *
  195. * Description:
  196. * Internal function used by various parts of the MAC layer. This function
  197. * allocates an IOB, populates the frame according to input args, and links
  198. * the IOB into the provided tx descriptor.
  199. *
  200. * Assumptions:
  201. * Called with the MAC locked
  202. *
  203. ****************************************************************************/
  204. void mac802154_createdatareq(FAR struct ieee802154_privmac_s *priv,
  205. FAR struct ieee802154_addr_s *coordaddr,
  206. enum ieee802154_addrmode_e srcmode,
  207. FAR struct ieee802154_txdesc_s *txdesc)
  208. {
  209. FAR struct iob_s *iob;
  210. /* The only node allowed to use a source address of none is the PAN
  211. * Coordinator. PAN coordinators should not be sending data request
  212. * commands.
  213. */
  214. DEBUGASSERT(srcmode != IEEE802154_ADDRMODE_NONE);
  215. /* Allocate an IOB to put the frame in */
  216. iob = iob_alloc(false, IOBUSER_WIRELESS_MAC802154);
  217. DEBUGASSERT(iob != NULL);
  218. iob->io_flink = NULL;
  219. iob->io_len = 0;
  220. iob->io_offset = 0;
  221. iob->io_pktlen = 0;
  222. /* Set the frame control fields */
  223. iob->io_data[0] = 0;
  224. iob->io_data[1] = 0;
  225. IEEE802154_SETACKREQ(iob->io_data, 0);
  226. IEEE802154_SETFTYPE(iob->io_data, 0, IEEE802154_FRAME_COMMAND);
  227. IEEE802154_SETDADDRMODE(iob->io_data, 0, coordaddr->mode);
  228. IEEE802154_SETSADDRMODE(iob->io_data, 0, srcmode);
  229. iob->io_len = 2;
  230. /* Each time a data or a MAC command frame is generated, the MAC sublayer
  231. * shall copy the value of macDSN into the Sequence Number field of the
  232. * MHR of the outgoing frame and then increment it by one. [1] pg. 40.
  233. */
  234. iob->io_data[iob->io_len++] = priv->dsn++;
  235. /* If the destination address is present, copy the PAN ID and one of the
  236. * addresses, depending on mode, into the MHR.
  237. */
  238. if (coordaddr->mode != IEEE802154_ADDRMODE_NONE)
  239. {
  240. mac802154_putpanid(iob, coordaddr->panid);
  241. if (coordaddr->mode == IEEE802154_ADDRMODE_SHORT)
  242. {
  243. mac802154_putsaddr(iob, coordaddr->saddr);
  244. }
  245. else if (coordaddr->mode == IEEE802154_ADDRMODE_EXTENDED)
  246. {
  247. mac802154_puteaddr(iob, coordaddr->eaddr);
  248. }
  249. }
  250. /* If the Destination Addressing Mode field is set to indicate that
  251. * destination addressing information is not present, the PAN ID
  252. * Compression field shall be set to zero and the source PAN identifier
  253. * shall contain the value of macPANId. Otherwise, the PAN ID Compression
  254. * field shall be set to one. In this case and in accordance with the PAN
  255. * ID Compression field, the Destination PAN Identifier field shall
  256. * contain the value of macPANId, while the Source PAN Identifier field
  257. * shall be omitted. [1] pg. 72
  258. */
  259. if (coordaddr->mode != IEEE802154_ADDRMODE_NONE &&
  260. IEEE802154_PANIDCMP(coordaddr->panid, priv->addr.panid))
  261. {
  262. IEEE802154_SETPANIDCOMP(iob->io_data, 0);
  263. }
  264. else
  265. {
  266. mac802154_putpanid(iob, priv->addr.panid);
  267. }
  268. if (srcmode == IEEE802154_ADDRMODE_SHORT)
  269. {
  270. mac802154_putsaddr(iob, priv->addr.saddr);
  271. }
  272. else if (srcmode == IEEE802154_ADDRMODE_EXTENDED)
  273. {
  274. mac802154_puteaddr(iob, priv->addr.eaddr);
  275. }
  276. /* Copy in the Command Frame Identifier */
  277. iob->io_data[iob->io_len++] = IEEE802154_CMD_DATA_REQ;
  278. /* Copy the IOB reference to the descriptor */
  279. txdesc->frame = iob;
  280. txdesc->frametype = IEEE802154_FRAME_COMMAND;
  281. txdesc->ackreq = true;
  282. /* Save a copy of the destination addressing information into the tx
  283. * descriptor. We only do this for commands to help with handling their
  284. * progession.
  285. */
  286. memcpy(&txdesc->destaddr, &coordaddr, sizeof(struct ieee802154_addr_s));
  287. /* Save a reference of the tx descriptor */
  288. priv->cmd_desc = txdesc;
  289. }
  290. /****************************************************************************
  291. * Name: mac802154_notify
  292. *
  293. * Description:
  294. * Queue the primitive in the queue and queue work on the LPWORK
  295. * queue if is not already scheduled.
  296. *
  297. * Assumptions:
  298. * Called with the MAC locked
  299. *
  300. ****************************************************************************/
  301. void mac802154_notify(FAR struct ieee802154_privmac_s *priv,
  302. FAR struct ieee802154_primitive_s *primitive)
  303. {
  304. sq_addlast((FAR sq_entry_t *)primitive, &priv->primitive_queue);
  305. if (work_available(&priv->notifwork))
  306. {
  307. work_queue(LPWORK, &priv->notifwork, mac802154_notify_worker,
  308. (FAR void *)priv, 0);
  309. }
  310. }
  311. /****************************************************************************
  312. * Name: mac802154_notify_worker
  313. *
  314. * Description:
  315. * Pop each primitive off the queue and call the registered
  316. * callbacks. There is special logic for handling ieee802154_data_ind_s.
  317. *
  318. ****************************************************************************/
  319. static void mac802154_notify_worker(FAR void *arg)
  320. {
  321. FAR struct ieee802154_privmac_s *priv =
  322. (FAR struct ieee802154_privmac_s *)arg;
  323. FAR struct mac802154_maccb_s *cb;
  324. FAR struct ieee802154_primitive_s *primitive;
  325. int ret;
  326. mac802154_lock(priv, false);
  327. primitive =
  328. (FAR struct ieee802154_primitive_s *)sq_remfirst(&priv->primitive_queue);
  329. mac802154_unlock(priv);
  330. while (primitive != NULL)
  331. {
  332. /* Data indications are a special case since the frame can only be
  333. * passed to one place. The return value of the notify call is used to
  334. * accept or reject the primitive. In the case of the data indication,
  335. * there can only be one accept. Callbacks are stored in order of
  336. * there receiver priority ordered when the callbacks are bound in
  337. * mac802154_bind().
  338. */
  339. if (primitive->type == IEEE802154_PRIMITIVE_IND_DATA)
  340. {
  341. bool dispose = true;
  342. primitive->nclients = 1;
  343. for (cb = priv->cb; cb != NULL; cb = cb->flink)
  344. {
  345. if (cb->notify != NULL)
  346. {
  347. ret = cb->notify(cb, primitive);
  348. if (ret >= 0)
  349. {
  350. /* The receiver accepted and disposed of the frame and
  351. * it's meta-data. We are done.
  352. */
  353. dispose = false;
  354. break;
  355. }
  356. }
  357. }
  358. if (dispose)
  359. {
  360. iob_free(primitive->u.dataind.frame,
  361. IOBUSER_WIRELESS_MAC802154);
  362. ieee802154_primitive_free(primitive);
  363. }
  364. }
  365. else
  366. {
  367. /* Set the number of clients count so that the primitive resources
  368. * will be preserved until all clients are finished with it.
  369. */
  370. primitive->nclients = priv->nclients;
  371. /* Try to notify every registered MAC client */
  372. for (cb = priv->cb; cb != NULL; cb = cb->flink)
  373. {
  374. if (cb->notify != NULL)
  375. {
  376. ret = cb->notify(cb, primitive);
  377. if (ret < 0)
  378. {
  379. ieee802154_primitive_free(primitive);
  380. }
  381. }
  382. else
  383. {
  384. ieee802154_primitive_free(primitive);
  385. }
  386. }
  387. }
  388. /* Get the next primitive then loop */
  389. mac802154_lock(priv, false);
  390. primitive = (FAR struct ieee802154_primitive_s *)
  391. sq_remfirst(&priv->primitive_queue);
  392. mac802154_unlock(priv);
  393. }
  394. }
  395. /****************************************************************************
  396. * Name: mac802154_updatebeacon
  397. *
  398. * Description:
  399. * This function is called in the following scenarios:
  400. * - The MAC receives a START.request primitive
  401. * - Upon receiving the IEEE802154_SFEVENT_ENDOFACTIVE event from the
  402. * this radio layer, the MAC checks the bf_update flag and if set
  403. * calls function. The bf_update flag is set when various attributes
  404. * that effect the beacon are updated.
  405. *
  406. * Internal function used by various parts of the MAC layer. This function
  407. * uses the various MAC attributes to update the beacon frame. It loads the
  408. * inactive beacon frame structure and then notifies the radio layer of the
  409. * new frame. the provided tx descriptor in the indirect list and manages
  410. * the scheduling for purging the transaction if it does not get extracted
  411. * in time.
  412. *
  413. * Assumptions:
  414. * Called with the MAC locked
  415. *
  416. ****************************************************************************/
  417. void mac802154_updatebeacon(FAR struct ieee802154_privmac_s *priv)
  418. {
  419. FAR struct ieee802154_txdesc_s *txdesc;
  420. FAR struct ieee802154_beaconframe_s *beacon;
  421. uint8_t pendaddrspec_ind;
  422. uint8_t pendeaddr = 0;
  423. uint8_t pendsaddr = 0;
  424. /* Switch the buffer */
  425. priv->bf_ind = !priv->bf_ind;
  426. /* Get a local reference to the beacon frame */
  427. beacon = &priv->beaconframe[priv->bf_ind];
  428. /* Clear the frame control fields */
  429. beacon->bf_data[0] = 0;
  430. beacon->bf_data[1] = 0;
  431. beacon->bf_len = 2;
  432. IEEE802154_SETFTYPE(beacon->bf_data, 0, IEEE802154_FRAME_BEACON);
  433. /* Check if there is a broadcast message pending, if there is, we must set
  434. * the frame pending bit to 1.
  435. */
  436. /* TODO: handle broadcast frame */
  437. DEBUGASSERT(priv->addr.mode != IEEE802154_ADDRMODE_NONE);
  438. IEEE802154_SETDADDRMODE(beacon->bf_data, 0, IEEE802154_ADDRMODE_NONE);
  439. IEEE802154_SETSADDRMODE(beacon->bf_data, 0, priv->addr.mode);
  440. IEEE802154_SETVERSION(beacon->bf_data, 0, 1);
  441. /* The beacon sequence number has to be taken care of by the radio layer,
  442. * since we only want to update the whole frame when more changes than
  443. * just the bsn.
  444. */
  445. beacon->bf_len++;
  446. IEEE802154_PANIDCOPY(&beacon->bf_data[beacon->bf_len], priv->addr.panid);
  447. beacon->bf_len += IEEE802154_PANIDSIZE;
  448. if (priv->addr.mode == IEEE802154_ADDRMODE_SHORT)
  449. {
  450. IEEE802154_SADDRCOPY(&beacon->bf_data[beacon->bf_len],
  451. priv->addr.saddr);
  452. beacon->bf_len += IEEE802154_SADDRSIZE;
  453. }
  454. else
  455. {
  456. IEEE802154_EADDRCOPY(&beacon->bf_data[beacon->bf_len],
  457. priv->addr.eaddr);
  458. beacon->bf_len += IEEE802154_EADDRSIZE;
  459. }
  460. /* Clear the superframe specification, then set the appropriate bits */
  461. beacon->bf_data[beacon->bf_len] = 0;
  462. beacon->bf_data[beacon->bf_len + 1] = 0;
  463. IEEE802154_SETBEACONORDER(beacon->bf_data, beacon->bf_len,
  464. priv->sfspec.beaconorder);
  465. IEEE802154_SETSFORDER(beacon->bf_data, beacon->bf_len,
  466. priv->sfspec.sforder);
  467. IEEE802154_SETFINCAPSLOT(beacon->bf_data, beacon->bf_len,
  468. priv->sfspec.final_capslot);
  469. if (priv->sfspec.ble)
  470. {
  471. IEEE802154_SETBLE(beacon->bf_data, beacon->bf_len);
  472. }
  473. if (priv->sfspec.pancoord)
  474. {
  475. IEEE802154_SETPANCOORD(beacon->bf_data, beacon->bf_len);
  476. }
  477. if (priv->sfspec.assocpermit)
  478. {
  479. IEEE802154_SETASSOCPERMIT(beacon->bf_data, beacon->bf_len);
  480. }
  481. beacon->bf_len += 2;
  482. /* TODO: Handle GTS properly, for now, we just set the descriptor count to
  483. * zero and specify that we do not permit GTS requests.
  484. */
  485. beacon->bf_data[beacon->bf_len++] = 0;
  486. /* TODO: Add GTS List here */
  487. /* Skip the pending address specification field for now */
  488. pendaddrspec_ind = beacon->bf_len++;
  489. txdesc = (FAR struct ieee802154_txdesc_s *)
  490. sq_peek(&priv->indirect_queue);
  491. while (txdesc != NULL)
  492. {
  493. if (txdesc->destaddr.mode == IEEE802154_ADDRMODE_SHORT)
  494. {
  495. pendsaddr++;
  496. IEEE802154_SADDRCOPY(&beacon->bf_data[beacon->bf_len],
  497. txdesc->destaddr.saddr);
  498. beacon->bf_len += IEEE802154_SADDRSIZE;
  499. }
  500. else if (txdesc->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED)
  501. {
  502. pendeaddr++;
  503. IEEE802154_EADDRCOPY(&beacon->bf_data[beacon->bf_len],
  504. txdesc->destaddr.eaddr);
  505. beacon->bf_len += IEEE802154_EADDRSIZE;
  506. }
  507. /* Check if we are up to 7 addresses yet */
  508. if ((pendsaddr + pendeaddr) == 7)
  509. {
  510. break;
  511. }
  512. /* Get the next pending indirect transation */
  513. txdesc = (FAR struct ieee802154_txdesc_s *)
  514. sq_next((FAR sq_entry_t *)txdesc);
  515. }
  516. /* At this point, we know how many of each transaction we have, we can setup
  517. * the Pending Address Specification field
  518. */
  519. beacon->bf_data[pendaddrspec_ind] =
  520. (pendsaddr & 0x07) | ((pendeaddr << 4) & 0x70);
  521. /* Copy in the beacon payload */
  522. memcpy(&beacon->bf_data[beacon->bf_len], priv->beaconpayload,
  523. priv->beaconpayloadlength);
  524. beacon->bf_len += priv->beaconpayloadlength;
  525. priv->beaconupdate = false;
  526. }
  527. /****************************************************************************
  528. * Name: mac802154_setupindirect
  529. *
  530. * Description:
  531. * Internal function used by various parts of the MAC layer. This function
  532. * places the provided tx descriptor in the indirect list and manages the
  533. * scheduling for purging the transaction if it does not get extracted in
  534. * time.
  535. *
  536. * Assumptions:
  537. * Called with the MAC locked
  538. *
  539. ****************************************************************************/
  540. void mac802154_setupindirect(FAR struct ieee802154_privmac_s *priv,
  541. FAR struct ieee802154_txdesc_s *txdesc)
  542. {
  543. uint32_t ticks;
  544. uint32_t symbols;
  545. /* Link the tx descriptor into the list */
  546. sq_addlast((FAR sq_entry_t *)txdesc, &priv->indirect_queue);
  547. /* Update the timestamp for purging the transaction */
  548. /* The maximum time (in unit periods) that a transaction is stored by a
  549. * coordinator and indicated in its beacon. The unit period is governed by
  550. * macBeaconOrder, BO, as follows: For 0 ≤ BO ≤ 14, the unit period will
  551. * be aBaseSuperframeDuration × 2 BO . For BO = 15, the unit period will
  552. * be aBaseSuperframeDuration. [1] pg. 129
  553. */
  554. if (priv->sfspec.beaconorder < 15)
  555. {
  556. symbols = priv->trans_persisttime *
  557. (IEEE802154_BASE_SUPERFRAME_DURATION *
  558. (1 << priv->sfspec.beaconorder));
  559. }
  560. else
  561. {
  562. symbols = priv->trans_persisttime * IEEE802154_BASE_SUPERFRAME_DURATION;
  563. }
  564. ticks = mac802154_symtoticks(priv, symbols);
  565. txdesc->purgetime = clock_systimer() + ticks;
  566. /* Make sure the beacon gets updated */
  567. if (priv->sfspec.beaconorder < 15)
  568. {
  569. priv->beaconupdate = true;
  570. }
  571. /* Check to see if the purge indirect timer is scheduled. If it is, when the
  572. * timer fires, it will schedule the next purge timer event. Inherently, the
  573. * queue will be in order of which transaction needs to be purged next.
  574. *
  575. * If the purge indirect timer has not been scheduled, schedule it for when
  576. * this transaction should expire.
  577. */
  578. if (work_available(&priv->purge_work))
  579. {
  580. work_queue(HPWORK, &priv->purge_work, mac802154_purge_worker,
  581. (FAR void *)priv, ticks);
  582. }
  583. }
  584. /****************************************************************************
  585. * Name: mac802154_purge_worker
  586. *
  587. * Description:
  588. * Worker function scheduled in order to purge expired indirect
  589. * transactions. The first element in the list should always be removed.
  590. * The list is searched and transactions are removed until a transaction
  591. * has not yet expired. Then if there are any remaining transactions, the
  592. * work function is rescheduled for the next expiring transaction.
  593. *
  594. ****************************************************************************/
  595. static void mac802154_purge_worker(FAR void *arg)
  596. {
  597. FAR struct ieee802154_privmac_s *priv =
  598. (FAR struct ieee802154_privmac_s *)arg;
  599. FAR struct ieee802154_txdesc_s *txdesc;
  600. /* Get exclusive access to the driver structure. We don't care about any
  601. * signals so don't allow interruptions
  602. */
  603. mac802154_lock(priv, false);
  604. while (1)
  605. {
  606. /* Pop transactions off indirect queue until the transaction timeout
  607. * has not passed.
  608. */
  609. txdesc = (FAR struct ieee802154_txdesc_s *)
  610. sq_peek(&priv->indirect_queue);
  611. if (txdesc == NULL)
  612. {
  613. break;
  614. }
  615. /* Should probably check a little ahead and remove the transaction if
  616. * it is within a certain number of clock ticks away. There is no
  617. * since in scheduling the timer to expire in only a few ticks.
  618. */
  619. if (clock_systimer() >= txdesc->purgetime)
  620. {
  621. /* Unlink the transaction */
  622. sq_remfirst(&priv->indirect_queue);
  623. /* Free the IOB, the notification, and the tx descriptor */
  624. iob_free(txdesc->frame, IOBUSER_WIRELESS_MAC802154);
  625. ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)
  626. txdesc->conf);
  627. mac802154_txdesc_free(priv, txdesc);
  628. priv->beaconupdate = true;
  629. wlinfo("Indirect TX purged");
  630. }
  631. else
  632. {
  633. /* Reschedule the transaction for the next timeout */
  634. work_queue(HPWORK, &priv->purge_work, mac802154_purge_worker,
  635. (FAR void *)priv, txdesc->purgetime - clock_systimer());
  636. break;
  637. }
  638. }
  639. mac802154_unlock(priv);
  640. }
  641. /****************************************************************************
  642. * Name: mac802154_radiopoll
  643. *
  644. * Description:
  645. * Called from the radio driver through the callback struct. This
  646. * function is called when the radio has room for another transaction. If
  647. * the MAC layer has a transaction, it copies it into the supplied buffer
  648. * and returns the length. A descriptor is also populated with the
  649. * transaction.
  650. *
  651. ****************************************************************************/
  652. static int
  653. mac802154_radiopoll(FAR const struct ieee802154_radiocb_s *radiocb,
  654. bool gts, FAR struct ieee802154_txdesc_s **txdesc)
  655. {
  656. FAR struct mac802154_radiocb_s *cb =
  657. (FAR struct mac802154_radiocb_s *)radiocb;
  658. FAR struct ieee802154_privmac_s *priv;
  659. DEBUGASSERT(cb != NULL && cb->priv != NULL);
  660. priv = cb->priv;
  661. /* Get exclusive access to the driver structure. Ignore any EINTR signals */
  662. mac802154_lock(priv, false);
  663. if (gts)
  664. {
  665. /* Check to see if there are any GTS transactions waiting */
  666. *txdesc = (FAR struct ieee802154_txdesc_s *)
  667. sq_remfirst(&priv->gts_queue);
  668. }
  669. else
  670. {
  671. /* Check to see if there are any CSMA transactions waiting */
  672. *txdesc = (FAR struct ieee802154_txdesc_s *)
  673. sq_remfirst(&priv->csma_queue);
  674. }
  675. mac802154_unlock(priv)
  676. if (*txdesc != NULL)
  677. {
  678. return (*txdesc)->frame->io_len;
  679. }
  680. return 0;
  681. }
  682. /****************************************************************************
  683. * Name: mac802154_txdone
  684. *
  685. * Description:
  686. * Called from the radio driver through the callback struct. This
  687. * function is called when the radio has completed a transaction. The
  688. * txdesc passed gives provides information about the completed
  689. * transaction including the original handle provided when the transaction
  690. * was created and the status of the transaction. This function copies
  691. * the descriptor and schedules work to handle the transaction without
  692. * blocking the radio.
  693. *
  694. ****************************************************************************/
  695. static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb,
  696. FAR struct ieee802154_txdesc_s *txdesc)
  697. {
  698. FAR struct mac802154_radiocb_s *cb =
  699. (FAR struct mac802154_radiocb_s *)radiocb;
  700. FAR struct ieee802154_privmac_s *priv;
  701. DEBUGASSERT(cb != NULL && cb->priv != NULL);
  702. priv = cb->priv;
  703. /* Get exclusive access to the driver structure. We don't care about any
  704. * signals so don't allow interruptions
  705. */
  706. mac802154_lock(priv, false);
  707. sq_addlast((FAR sq_entry_t *)txdesc, &priv->txdone_queue);
  708. mac802154_unlock(priv)
  709. /* Schedule work with the work queue to process the completion further */
  710. if (work_available(&priv->txdone_work))
  711. {
  712. work_queue(HPWORK, &priv->txdone_work, mac802154_txdone_worker,
  713. (FAR void *)priv, 0);
  714. }
  715. }
  716. /****************************************************************************
  717. * Name: mac802154_txdone_worker
  718. *
  719. * Description:
  720. * Worker function scheduled from mac802154_txdone. This function pops any
  721. * TX descriptors off of the list and calls the next highest layers callback
  722. * to inform the layer of the completed transaction and the status of it.
  723. *
  724. ****************************************************************************/
  725. static void mac802154_txdone_worker(FAR void *arg)
  726. {
  727. FAR struct ieee802154_privmac_s *priv =
  728. (FAR struct ieee802154_privmac_s *)arg;
  729. FAR struct ieee802154_txdesc_s *txdesc;
  730. FAR struct ieee802154_primitive_s *primitive;
  731. /* Get exclusive access to the driver structure. We don't care about any
  732. * signals so don't allow interruptions
  733. */
  734. mac802154_lock(priv, false);
  735. while (1)
  736. {
  737. txdesc = (FAR struct ieee802154_txdesc_s *)
  738. sq_remfirst(&priv->txdone_queue);
  739. if (txdesc == NULL)
  740. {
  741. break;
  742. }
  743. /* Cast the data_conf to a notification. We get both the private and
  744. * public notification structure to make it easier to use.
  745. */
  746. primitive = (FAR struct ieee802154_primitive_s *)txdesc->conf;
  747. wlinfo("Tx status: %s\n",
  748. IEEE802154_STATUS_STRING[txdesc->conf->status]);
  749. switch (txdesc->frametype)
  750. {
  751. case IEEE802154_FRAME_DATA:
  752. {
  753. primitive->type = IEEE802154_PRIMITIVE_CONF_DATA;
  754. mac802154_notify(priv, primitive);
  755. }
  756. break;
  757. case IEEE802154_FRAME_COMMAND:
  758. {
  759. switch (priv->curr_cmd)
  760. {
  761. case IEEE802154_CMD_ASSOC_REQ:
  762. mac802154_txdone_assocreq(priv, txdesc);
  763. break;
  764. case IEEE802154_CMD_ASSOC_RESP:
  765. break;
  766. case IEEE802154_CMD_DISASSOC_NOT:
  767. break;
  768. case IEEE802154_CMD_DATA_REQ:
  769. /* Data requests can be sent for 3 different reasons.
  770. *
  771. * 1. On a beacon-enabled PAN, this command shall be sent
  772. * by a device when macAutoRequest is equal to TRUE and
  773. * a beacon frame indicating that data are pending for
  774. * that device is received from its coordinator.
  775. * 2. when instructed to do so by the next higher layer on
  776. * reception of the MLME-POLL.request primitive.
  777. * 3. a device may send this command to the coordinator
  778. * macResponseWaitTime after the acknowledgment to an
  779. * association request command.
  780. */
  781. switch (priv->curr_op)
  782. {
  783. case MAC802154_OP_ASSOC:
  784. mac802154_txdone_datareq_assoc(priv, txdesc);
  785. break;
  786. case MAC802154_OP_POLL:
  787. mac802154_txdone_datareq_poll(priv, txdesc);
  788. break;
  789. default:
  790. break;
  791. }
  792. break;
  793. case IEEE802154_CMD_PANID_CONF_NOT:
  794. break;
  795. case IEEE802154_CMD_ORPHAN_NOT:
  796. break;
  797. case IEEE802154_CMD_BEACON_REQ:
  798. break;
  799. case IEEE802154_CMD_COORD_REALIGN:
  800. break;
  801. case IEEE802154_CMD_GTS_REQ:
  802. break;
  803. default:
  804. ieee802154_primitive_free(primitive);
  805. break;
  806. }
  807. }
  808. break;
  809. default:
  810. {
  811. ieee802154_primitive_free(primitive);
  812. }
  813. break;
  814. }
  815. /* Free the IOB and the tx descriptor */
  816. iob_free(txdesc->frame, IOBUSER_WIRELESS_MAC802154);
  817. mac802154_txdesc_free(priv, txdesc);
  818. }
  819. mac802154_unlock(priv)
  820. }
  821. /****************************************************************************
  822. * Name: mac802154_rxframe
  823. *
  824. * Description:
  825. * Called from the radio driver through the callback struct. This
  826. * function is called when the radio has received a frame. The frame is
  827. * passed in an iob, so that we can free it when we are done processing.
  828. * A pointer to the RX descriptor is passed along with the iob, but it
  829. * must be copied here as it is allocated directly on the caller's stack.
  830. * We simply link the frame, copy the RX descriptor, and schedule a worker
  831. * to process the frame later so that we do not hold up the radio.
  832. *
  833. ****************************************************************************/
  834. static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb,
  835. FAR struct ieee802154_data_ind_s *ind)
  836. {
  837. FAR struct mac802154_radiocb_s *cb =
  838. (FAR struct mac802154_radiocb_s *)radiocb;
  839. FAR struct ieee802154_privmac_s *priv;
  840. DEBUGASSERT(cb != NULL && cb->priv != NULL);
  841. priv = cb->priv;
  842. /* Get exclusive access to the driver structure. We don't care about any
  843. * signals so if we see one, just go back to trying to get access again.
  844. */
  845. mac802154_lock(priv, false);
  846. /* Push the iob onto the tail of the frame list for processing */
  847. sq_addlast((FAR sq_entry_t *)ind, &priv->dataind_queue);
  848. wlinfo("Frame received\n");
  849. mac802154_unlock(priv)
  850. /* Schedule work with the work queue to process the completion further */
  851. if (work_available(&priv->rx_work))
  852. {
  853. work_queue(HPWORK, &priv->rx_work, mac802154_rxframe_worker,
  854. (FAR void *)priv, 0);
  855. }
  856. }
  857. /****************************************************************************
  858. * Name: mac802154_rxframe_worker
  859. *
  860. * Description:
  861. * Worker function scheduled from mac802154_rxframe. This function
  862. * processes any frames in the list. Frames intended to be consumed by
  863. * the MAC layer will not produce any callbacks to the next highest layer.
  864. * Frames intended for the application layer will be forwarded to them.
  865. *
  866. ****************************************************************************/
  867. static void mac802154_rxframe_worker(FAR void *arg)
  868. {
  869. FAR struct ieee802154_privmac_s *priv =
  870. (FAR struct ieee802154_privmac_s *)arg;
  871. FAR struct ieee802154_data_ind_s *ind;
  872. FAR struct iob_s *iob;
  873. uint16_t *frame_ctrl;
  874. bool panid_comp;
  875. uint8_t ftype;
  876. while (1)
  877. {
  878. /* Get exclusive access to the driver structure. We don't care about
  879. * any signals so if we see one, just go back to trying to get access
  880. * again.
  881. */
  882. mac802154_lock(priv, false);
  883. /* Pop the data indication from the head of the frame list for
  884. * processing. Note: dataind_queue contains ieee802154_primitive_s
  885. * which is safe to cast directly to a data indication.
  886. */
  887. ind = (FAR struct ieee802154_data_ind_s *)
  888. sq_remfirst(&priv->dataind_queue);
  889. /* Once we pop off the indication, we don't need to keep the mac locked */
  890. mac802154_unlock(priv)
  891. if (ind == NULL)
  892. {
  893. return;
  894. }
  895. /* Get a local copy of the frame to make it easier to access */
  896. iob = ind->frame;
  897. /* Set a local pointer to the frame control then move the offset past
  898. * the frame control field
  899. */
  900. frame_ctrl = (uint16_t *)&iob->io_data[iob->io_offset];
  901. iob->io_offset += 2;
  902. /* We use the data_ind_s as a container for the frame information even
  903. * if this isn't a data frame
  904. */
  905. ind->src.mode = (*frame_ctrl & IEEE802154_FRAMECTRL_SADDR) >>
  906. IEEE802154_FRAMECTRL_SHIFT_SADDR;
  907. ind->dest.mode = (*frame_ctrl & IEEE802154_FRAMECTRL_DADDR) >>
  908. IEEE802154_FRAMECTRL_SHIFT_DADDR;
  909. panid_comp = (*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP) >>
  910. IEEE802154_FRAMECTRL_SHIFT_PANIDCOMP;
  911. ind->dsn = iob->io_data[iob->io_offset++];
  912. /* If the destination address is included */
  913. if (ind->dest.mode != IEEE802154_ADDRMODE_NONE)
  914. {
  915. /* Get the destination PAN ID */
  916. mac802154_takepanid(iob, ind->dest.panid);
  917. if (ind->dest.mode == IEEE802154_ADDRMODE_SHORT)
  918. {
  919. mac802154_takesaddr(iob, ind->dest.saddr);
  920. }
  921. else if (ind->dest.mode == IEEE802154_ADDRMODE_EXTENDED)
  922. {
  923. mac802154_takeeaddr(iob, ind->dest.eaddr);
  924. }
  925. }
  926. if (ind->src.mode != IEEE802154_ADDRMODE_NONE)
  927. {
  928. /* If the source address is included, and the PAN ID compression
  929. * field is set, get the PAN ID from the header.
  930. */
  931. if (panid_comp)
  932. {
  933. /* The source PAN ID is equal to the destination PAN ID */
  934. IEEE802154_PANIDCOPY(ind->src.panid, ind->dest.panid);
  935. }
  936. else
  937. {
  938. mac802154_takepanid(iob, ind->src.panid);
  939. }
  940. if (ind->src.mode == IEEE802154_ADDRMODE_SHORT)
  941. {
  942. mac802154_takesaddr(iob, ind->src.saddr);
  943. }
  944. else if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED)
  945. {
  946. mac802154_takeeaddr(iob, ind->src.eaddr);
  947. }
  948. }
  949. /* If the MAC is in promiscuous mode, just pass everything to the next
  950. * layer assuming it is data
  951. */
  952. if (priv->promisc)
  953. {
  954. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)ind);
  955. continue;
  956. }
  957. ftype = (*frame_ctrl & IEEE802154_FRAMECTRL_FTYPE) >>
  958. IEEE802154_FRAMECTRL_SHIFT_FTYPE;
  959. switch (ftype)
  960. {
  961. case IEEE802154_FRAME_DATA:
  962. {
  963. mac802154_rxdataframe(priv, ind);
  964. }
  965. break;
  966. case IEEE802154_FRAME_COMMAND:
  967. {
  968. /* Get the command type. The command type is always the first
  969. * field after the MHR. Consu;me the byte by increasing offset
  970. * so that subsequent functions can start from the byte after
  971. * the command ID.
  972. */
  973. uint8_t cmdtype = iob->io_data[iob->io_offset++];
  974. switch (cmdtype)
  975. {
  976. case IEEE802154_CMD_ASSOC_REQ:
  977. wlinfo("Assoc request received\n");
  978. mac802154_rx_assocreq(priv, ind);
  979. break;
  980. case IEEE802154_CMD_ASSOC_RESP:
  981. wlinfo("Assoc response received\n");
  982. mac802154_rx_assocresp(priv, ind);
  983. break;
  984. case IEEE802154_CMD_DISASSOC_NOT:
  985. wlinfo("Disassoc primitive received\n");
  986. break;
  987. case IEEE802154_CMD_DATA_REQ:
  988. wlinfo("Data request received\n");
  989. mac802154_rxdatareq(priv, ind);
  990. break;
  991. case IEEE802154_CMD_PANID_CONF_NOT:
  992. wlinfo("PAN ID Conflict primitive received\n");
  993. break;
  994. case IEEE802154_CMD_ORPHAN_NOT:
  995. wlinfo("Orphan primitive received\n");
  996. break;
  997. case IEEE802154_CMD_BEACON_REQ:
  998. wlinfo("Beacon request received\n");
  999. break;
  1000. case IEEE802154_CMD_COORD_REALIGN:
  1001. wlinfo("Coord realign received\n");
  1002. break;
  1003. case IEEE802154_CMD_GTS_REQ:
  1004. wlinfo("GTS request received\n");
  1005. break;
  1006. }
  1007. /* Free the data indication struct from the pool */
  1008. ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)
  1009. ind);
  1010. }
  1011. break;
  1012. case IEEE802154_FRAME_BEACON:
  1013. {
  1014. wlinfo("Beacon frame received. BSN: 0x%02X\n", ind->dsn);
  1015. mac802154_rxbeaconframe(priv, ind);
  1016. ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)
  1017. ind);
  1018. }
  1019. break;
  1020. case IEEE802154_FRAME_ACK:
  1021. {
  1022. /* The radio layer is responsible for handling all ACKs and
  1023. * retries. If for some reason an ACK gets here, just throw
  1024. * it out.
  1025. */
  1026. wlinfo("ACK received\n");
  1027. ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)
  1028. ind);
  1029. }
  1030. break;
  1031. }
  1032. }
  1033. }
  1034. /****************************************************************************
  1035. * Name: mac802154_rxdataframe
  1036. *
  1037. * Description:
  1038. * Function called from the generic RX Frame worker to parse and handle the
  1039. * reception of a data frame.
  1040. *
  1041. ****************************************************************************/
  1042. static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv,
  1043. FAR struct ieee802154_data_ind_s *ind)
  1044. {
  1045. FAR struct ieee802154_primitive_s *primitive;
  1046. /* Get exclusive access to the MAC */
  1047. mac802154_lock(priv, false);
  1048. /* If we are currently performing a POLL operation and we've
  1049. * received a data response, use the addressing information
  1050. * to determine if it is extracted data. If the addressing info
  1051. * matches, notify the next highest layer using POLL.confirm
  1052. * primitive. If the addressing information does not match,
  1053. * handle the transaction like any other data transaction.
  1054. *
  1055. * Note: We can't receive frames without addressing information
  1056. * unless we are the PAN coordinator. And in that situation, we
  1057. * wouldn't be performing a POLL operation. Meaning:
  1058. *
  1059. * If the current operation is POLL, we aren't the PAN coordinator
  1060. * so the incoming frame CAN'T
  1061. *
  1062. * FIXME: Fix documentation
  1063. */
  1064. if (priv->curr_op == MAC802154_OP_POLL ||
  1065. priv->curr_op == MAC802154_OP_ASSOC ||
  1066. priv->curr_op == MAC802154_OP_AUTOEXTRACT)
  1067. {
  1068. /* If we are in promiscuous mode, we need to check if the
  1069. * frame is even for us first. If the address is not ours,
  1070. * then handle the frame like a normal transaction.
  1071. */
  1072. if (priv->promisc)
  1073. {
  1074. if (!IEEE802154_PANIDCMP(ind->dest.panid, priv->addr.panid))
  1075. {
  1076. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
  1077. ind);
  1078. }
  1079. if (ind->dest.mode == IEEE802154_ADDRMODE_SHORT &&
  1080. !IEEE802154_SADDRCMP(ind->dest.saddr, priv->addr.saddr))
  1081. {
  1082. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
  1083. ind);
  1084. }
  1085. else if (ind->dest.mode == IEEE802154_ADDRMODE_EXTENDED &&
  1086. !IEEE802154_EADDRCMP(ind->dest.eaddr, priv->addr.eaddr))
  1087. {
  1088. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
  1089. ind);
  1090. }
  1091. else
  1092. {
  1093. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
  1094. ind);
  1095. }
  1096. }
  1097. /* If this was our extracted data, the source addressing field can only
  1098. * be NONE if we are trying to extract data from the PAN coordinator.
  1099. * A PAN coordinator shouldn't be sending us a frame if it wasn't
  1100. * our extracted data. Therefore just assume if the address mode is set
  1101. * to NONE, we process it as our extracted frame
  1102. */
  1103. if (ind->src.mode != priv->cmd_desc->destaddr.mode)
  1104. {
  1105. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
  1106. ind);
  1107. }
  1108. if (ind->src.mode == IEEE802154_ADDRMODE_SHORT &&
  1109. !IEEE802154_SADDRCMP(ind->src.saddr,
  1110. priv->cmd_desc->destaddr.saddr))
  1111. {
  1112. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
  1113. ind);
  1114. }
  1115. else if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED &&
  1116. !IEEE802154_EADDRCMP(ind->src.eaddr,
  1117. priv->cmd_desc->destaddr.eaddr))
  1118. {
  1119. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
  1120. ind);
  1121. }
  1122. /* If we've gotten this far, the frame is our extracted data. Cancel
  1123. * the timeout
  1124. */
  1125. mac802154_timercancel(priv);
  1126. /* If a frame is received from the coordinator with a zero length
  1127. * payload or if the frame is a MAC command frame, the MLME will issue
  1128. * the MLME-POLL.confirm primitive with a status of NO_DATA. [1] pg.
  1129. * 111
  1130. */
  1131. primitive = ieee802154_primitive_allocate();
  1132. if (priv->curr_op == MAC802154_OP_POLL)
  1133. {
  1134. primitive->type = IEEE802154_PRIMITIVE_CONF_POLL;
  1135. if (ind->frame->io_offset == ind->frame->io_len)
  1136. {
  1137. primitive->u.pollconf.status = IEEE802154_STATUS_NO_DATA;
  1138. }
  1139. else
  1140. {
  1141. primitive->u.pollconf.status = IEEE802154_STATUS_SUCCESS;
  1142. }
  1143. }
  1144. else if (priv->curr_op == MAC802154_OP_ASSOC)
  1145. {
  1146. /* If we ever receive a data frame back as a response to the
  1147. * association request, we assume it means there wasn't any data.
  1148. */
  1149. primitive->type = IEEE802154_PRIMITIVE_CONF_ASSOC;
  1150. primitive->u.assocconf.status = IEEE802154_STATUS_NO_DATA;
  1151. }
  1152. /* We are no longer performing the association operation */
  1153. priv->curr_op = MAC802154_OP_NONE;
  1154. priv->cmd_desc = NULL;
  1155. mac802154_givesem(&priv->opsem);
  1156. /* Release the MAC and notify the next highest layer */
  1157. mac802154_notify(priv, primitive);
  1158. /* If there was data, pass it along */
  1159. if (ind->frame->io_len > ind->frame->io_offset)
  1160. {
  1161. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)ind);
  1162. }
  1163. else
  1164. {
  1165. ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)ind);
  1166. }
  1167. }
  1168. else
  1169. {
  1170. mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)ind);
  1171. }
  1172. mac802154_unlock(priv)
  1173. }
  1174. /****************************************************************************
  1175. * Name: mac802154_rxdatareq
  1176. *
  1177. * Description:
  1178. * Function called from the generic RX Frame worker to parse and handle the
  1179. * reception of an Data Request MAC command frame.
  1180. *
  1181. ****************************************************************************/
  1182. static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv,
  1183. FAR struct ieee802154_data_ind_s *ind)
  1184. {
  1185. FAR struct ieee802154_txdesc_s *txdesc;
  1186. FAR struct iob_s *iob;
  1187. uint16_t *frame_ctrl;
  1188. /* Get exclusive access to the MAC */
  1189. mac802154_lock(priv, false);
  1190. /* Search the list of indirect transactions to see if there are any waiting
  1191. * for the requesting device.
  1192. */
  1193. /* TODO: I believe there is an issue here. If there is for some reason a
  1194. * outgoing data frame to a device who is currently requesting association,
  1195. * we will send the data frame as a response to an association request. We
  1196. * need to check for this condition.
  1197. */
  1198. txdesc = (FAR struct ieee802154_txdesc_s *)sq_peek(&priv->indirect_queue);
  1199. while (txdesc != NULL)
  1200. {
  1201. if (txdesc->destaddr.mode == ind->src.mode)
  1202. {
  1203. if (txdesc->destaddr.mode == IEEE802154_ADDRMODE_SHORT)
  1204. {
  1205. if (IEEE802154_SADDRCMP(txdesc->destaddr.saddr, ind->src.saddr))
  1206. {
  1207. /* Remove the transaction from the queue */
  1208. sq_rem((FAR sq_entry_t *)txdesc, &priv->indirect_queue);
  1209. /* NOTE: We don't do anything with the purge timeout,
  1210. * because we really don't need to. As of now, I see no
  1211. * disadvantage to just letting the timeout expire, which
  1212. * won't purge the transaction since it is no longer on
  1213. * the list, and then it will reschedule the next timeout
  1214. * appropriately. The logic otherwise may get complicated
  1215. * even though it may save a few clock cycles.
  1216. */
  1217. /* The addresses match, send the transaction immediately */
  1218. priv->radio->txdelayed(priv->radio, txdesc, 0);
  1219. priv->beaconupdate = true;
  1220. mac802154_unlock(priv)
  1221. return;
  1222. }
  1223. }
  1224. else if (txdesc->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED)
  1225. {
  1226. if (IEEE802154_EADDRCMP(txdesc->destaddr.eaddr, ind->src.eaddr))
  1227. {
  1228. /* Remove the transaction from the queue */
  1229. sq_rem((FAR sq_entry_t *)txdesc, &priv->indirect_queue);
  1230. /* The addresses match, send the transaction immediately */
  1231. priv->radio->txdelayed(priv->radio, txdesc, 0);
  1232. priv->beaconupdate = true;
  1233. mac802154_unlock(priv)
  1234. return;
  1235. }
  1236. }
  1237. else
  1238. {
  1239. DEBUGASSERT(false);
  1240. }
  1241. }
  1242. txdesc = (FAR struct ieee802154_txdesc_s *)
  1243. sq_next((FAR sq_entry_t *)txdesc);
  1244. }
  1245. /* If there is no data frame pending for the requesting device, the
  1246. * coordinator shall send a data frame without requesting acknowledgment
  1247. * to the device containing a zero length payload, indicating that no data
  1248. * are present, using one of the mechanisms described in this subclause.
  1249. * [1] pg. 43
  1250. */
  1251. /* Allocate an IOB to put the frame in */
  1252. iob = iob_alloc(false, IOBUSER_WIRELESS_MAC802154);
  1253. DEBUGASSERT(iob != NULL);
  1254. iob->io_flink = NULL;
  1255. iob->io_len = 0;
  1256. iob->io_offset = 0;
  1257. iob->io_pktlen = 0;
  1258. iob->io_len += 2;
  1259. /* Cast the first two bytes of the IOB to a uint16_t frame control field */
  1260. frame_ctrl = (FAR uint16_t *)&iob->io_data[0];
  1261. /* Ensure we start with a clear frame control field */
  1262. *frame_ctrl = 0;
  1263. /* Set the frame type to Data */
  1264. *frame_ctrl |= IEEE802154_FRAME_DATA << IEEE802154_FRAMECTRL_SHIFT_FTYPE;
  1265. /* Each time a data or a MAC command frame is generated, the MAC sublayer
  1266. * shall copy the value of macDSN into the Sequence Number field of the MHR
  1267. * of the outgoing frame and then increment it by one. [1] pg. 40.
  1268. */
  1269. iob->io_data[iob->io_len++] = priv->dsn++;
  1270. /* Use the source address information from the received data request to
  1271. * respond.
  1272. */
  1273. mac802154_putpanid(iob, ind->src.panid);
  1274. if (ind->src.mode == IEEE802154_ADDRMODE_SHORT)
  1275. {
  1276. mac802154_putsaddr(iob, ind->src.saddr);
  1277. }
  1278. else if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED)
  1279. {
  1280. mac802154_puteaddr(iob, ind->src.eaddr);
  1281. }
  1282. else
  1283. {
  1284. DEBUGASSERT(false);
  1285. }
  1286. /* Set the destination addr mode inside the frame control field */
  1287. *frame_ctrl |= (ind->src.mode << IEEE802154_FRAMECTRL_SHIFT_DADDR);
  1288. /* Check if the source PAN ID of the incoming request is the same as ours. */
  1289. if (IEEE802154_PANIDCMP(ind->src.panid, priv->addr.panid))
  1290. {
  1291. *frame_ctrl |= IEEE802154_FRAMECTRL_PANIDCOMP;
  1292. }
  1293. else
  1294. {
  1295. /* Copy in our PAN ID */
  1296. mac802154_putpanid(iob, priv->addr.panid);
  1297. }
  1298. /* Copy in our address using the mode that the device used to address us */
  1299. if (ind->dest.mode == IEEE802154_ADDRMODE_SHORT)
  1300. {
  1301. mac802154_putsaddr(iob, priv->addr.saddr);
  1302. *frame_ctrl |= (IEEE802154_ADDRMODE_SHORT <<
  1303. IEEE802154_FRAMECTRL_SHIFT_SADDR);
  1304. }
  1305. else
  1306. {
  1307. mac802154_puteaddr(iob, priv->addr.eaddr);
  1308. *frame_ctrl |= (IEEE802154_ADDRMODE_EXTENDED <<
  1309. IEEE802154_FRAMECTRL_SHIFT_SADDR);
  1310. }
  1311. /* Allocate the txdesc, waiting if necessary, allow interruptions */
  1312. mac802154_txdesc_alloc(priv, &txdesc, false);
  1313. txdesc->frame = iob;
  1314. txdesc->frametype = IEEE802154_FRAME_DATA;
  1315. txdesc->ackreq = false;
  1316. mac802154_unlock(priv)
  1317. priv->radio->txdelayed(priv->radio, txdesc, 0);
  1318. }
  1319. /****************************************************************************
  1320. * Name: mac802154_edresult
  1321. *
  1322. * Description:
  1323. * Called from the radio driver through the callback struct. This
  1324. * function is called when the radio has finished an energy detect operation.
  1325. * This is triggered by a SCAN.request primitive with ScanType set to Energy
  1326. * Detect (ED)
  1327. *
  1328. ****************************************************************************/
  1329. static void mac802154_edresult(FAR const struct ieee802154_radiocb_s *radiocb,
  1330. uint8_t edval)
  1331. {
  1332. FAR struct mac802154_radiocb_s *cb =
  1333. (FAR struct mac802154_radiocb_s *)radiocb;
  1334. FAR struct ieee802154_privmac_s *priv;
  1335. DEBUGASSERT(cb != NULL && cb->priv != NULL);
  1336. priv = cb->priv;
  1337. /* Get exclusive access to the driver structure. We don't care about any
  1338. * signals so if we see one, just go back to trying to get access again.
  1339. */
  1340. mac802154_lock(priv, false);
  1341. /* If we are actively performing a scan operation, notify the scan handler */
  1342. if (priv->curr_op == MAC802154_OP_SCAN)
  1343. {
  1344. mac802154_edscan_onresult(priv, edval);
  1345. }
  1346. /* Relinquish control of the private structure */
  1347. mac802154_unlock(priv);
  1348. }
  1349. static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb,
  1350. enum ieee802154_sfevent_e sfevent)
  1351. {
  1352. FAR struct mac802154_radiocb_s *cb =
  1353. (FAR struct mac802154_radiocb_s *)radiocb;
  1354. FAR struct ieee802154_privmac_s *priv;
  1355. DEBUGASSERT(cb != NULL && cb->priv != NULL);
  1356. priv = cb->priv;
  1357. /* Get exclusive access to the driver structure. We don't care about any
  1358. * signals so if we see one, just go back to trying to get access again.
  1359. */
  1360. mac802154_lock(priv, false);
  1361. switch (sfevent)
  1362. {
  1363. case IEEE802154_SFEVENT_ENDOFACTIVE:
  1364. {
  1365. #ifdef CONFIG_MAC802154_SFEVENT_VERBOSE
  1366. wlinfo("End of superframe\n");
  1367. #endif
  1368. /* Check if there is any reason to update the beacon */
  1369. if (priv->beaconupdate)
  1370. {
  1371. mac802154_updatebeacon(priv);
  1372. priv->radio->beaconupdate(priv->radio,
  1373. &priv->beaconframe[priv->bf_ind]);
  1374. }
  1375. }
  1376. break;
  1377. default:
  1378. break;
  1379. }
  1380. mac802154_unlock(priv)
  1381. }
  1382. /****************************************************************************
  1383. * Name: mac802154_rxbeaconframe
  1384. *
  1385. * Description:
  1386. * Function called from the generic RX Frame worker to parse and handle the
  1387. * reception of a beacon frame.
  1388. *
  1389. * Assumptions: MAC is unlocked
  1390. *
  1391. ****************************************************************************/
  1392. static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv,
  1393. FAR struct ieee802154_data_ind_s *ind)
  1394. {
  1395. FAR struct ieee802154_txdesc_s *respdesc;
  1396. FAR struct ieee802154_primitive_s *primitive;
  1397. FAR struct ieee802154_beacon_ind_s *beacon;
  1398. FAR struct iob_s *iob = ind->frame;
  1399. uint8_t ngtsdesc;
  1400. uint8_t gtsdirmask;
  1401. bool pending_saddr = false;
  1402. bool pending_eaddr = false;
  1403. int i;
  1404. /* Even though we may not use the primitive, we allocate one to hold all the
  1405. * parsed beacon information. Freeing the primitive is quick, so it's worth
  1406. * worth saving a copy (If you were to parse all the info in locally, you
  1407. * would have to copy the data over in the case that you actually need to
  1408. * notify the next highest layer)
  1409. */
  1410. primitive = ieee802154_primitive_allocate();
  1411. beacon = &primitive->u.beaconind;
  1412. /* Make sure there is another 2 bytes to process */
  1413. if (iob->io_len < iob->io_offset + 2)
  1414. {
  1415. goto errout;
  1416. }
  1417. /* Copy the coordinator address and channel info into the pan descriptor */
  1418. memcpy(&beacon->pandesc.coordaddr, &ind->src,
  1419. sizeof(struct ieee802154_addr_s));
  1420. beacon->pandesc.chan = priv->currscan.channels[priv->scanindex];
  1421. beacon->pandesc.chpage = priv->currscan.chpage;
  1422. beacon->pandesc.lqi = ind->lqi;
  1423. beacon->pandesc.timestamp = ind->timestamp;
  1424. /* Parse the superframe specification field */
  1425. beacon->pandesc.sfspec.beaconorder =
  1426. IEEE802154_GETBEACONORDER(iob->io_data, iob->io_offset);
  1427. beacon->pandesc.sfspec.sforder =
  1428. IEEE802154_GETSFORDER(iob->io_data, iob->io_offset);
  1429. beacon->pandesc.sfspec.final_capslot =
  1430. IEEE802154_GETFINCAPSLOT(iob->io_data, iob->io_offset);
  1431. beacon->pandesc.sfspec.ble =
  1432. IEEE802154_GETBLE(iob->io_data, iob->io_offset);
  1433. beacon->pandesc.sfspec.pancoord =
  1434. IEEE802154_GETPANCOORD(iob->io_data, iob->io_offset);
  1435. beacon->pandesc.sfspec.assocpermit =
  1436. IEEE802154_GETASSOCPERMIT(iob->io_data, iob->io_offset);
  1437. iob->io_offset += 2;
  1438. /* Make sure there is another byte to process (GTS Spec) */
  1439. if (iob->io_len < iob->io_offset + 1)
  1440. {
  1441. goto errout;
  1442. }
  1443. /* Parse the GTS Specification field */
  1444. ngtsdesc =
  1445. IEEE802154_GETGTSDESCCOUNT(iob->io_data, iob->io_offset);
  1446. beacon->pandesc.gtspermit =
  1447. IEEE802154_GETGTSPERMIT(iob->io_data, iob->io_offset);
  1448. iob->io_offset++;
  1449. /* If there are any GTS descriptors, handle the GTS Dir and GTS List fields */
  1450. if (ngtsdesc > 0)
  1451. {
  1452. /* Make sure there is another bytes to process (GTS Direction) */
  1453. if (iob->io_len < iob->io_offset + 1)
  1454. {
  1455. goto errout;
  1456. }
  1457. gtsdirmask = IEEE802154_GETGTSDIRMASK(iob->io_data, iob->io_offset);
  1458. UNUSED(gtsdirmask);
  1459. iob->io_offset++;
  1460. /* Make sure there are enough bytes left to represent the GTS List */
  1461. if (iob->io_len < iob->io_offset + (3 * ngtsdesc))
  1462. {
  1463. goto errout;
  1464. }
  1465. for (i = 0; i < ngtsdesc; i++)
  1466. {
  1467. /* For now we just discard the data by skipping over it */
  1468. iob->io_offset += 3;
  1469. }
  1470. }
  1471. /* Pending address fields. Min 1 byte, the Pending Address Specification */
  1472. if (iob->io_len < iob->io_offset + 1)
  1473. {
  1474. goto errout;
  1475. }
  1476. beacon->pendaddr.nsaddr =
  1477. IEEE802154_GETNPENDSADDR(iob->io_data, iob->io_offset);
  1478. beacon->pendaddr.neaddr =
  1479. IEEE802154_GETNPENDEADDR(iob->io_data, iob->io_offset);
  1480. iob->io_offset++;
  1481. /* Make sure there are enough bytes left to represent the address list */
  1482. if (iob->io_len < (iob->io_offset +
  1483. (IEEE802154_SADDRSIZE * beacon->pendaddr.nsaddr) +
  1484. (IEEE802154_EADDRSIZE * beacon->pendaddr.neaddr)))
  1485. {
  1486. goto errout;
  1487. }
  1488. /* Copy in the pending addresses */
  1489. for (i = 0; i < beacon->pendaddr.nsaddr; i++)
  1490. {
  1491. beacon->pendaddr.addr[i].mode = IEEE802154_ADDRMODE_SHORT;
  1492. mac802154_takesaddr(iob, beacon->pendaddr.addr[i].saddr);
  1493. /* Check if the short address matches our short address */
  1494. if (IEEE802154_SADDRCMP(beacon->pendaddr.addr[i].saddr,
  1495. priv->addr.saddr))
  1496. {
  1497. /* Wait to actually decide how to handle this until we parse
  1498. * the rest of the frame
  1499. */
  1500. wlinfo("Data pending for us in coord\n");
  1501. pending_saddr = true;
  1502. }
  1503. }
  1504. for (i = beacon->pendaddr.nsaddr;
  1505. i < (beacon->pendaddr.nsaddr + beacon->pendaddr.neaddr);
  1506. i++)
  1507. {
  1508. beacon->pendaddr.addr[i].mode = IEEE802154_ADDRMODE_EXTENDED;
  1509. mac802154_takeeaddr(iob, beacon->pendaddr.addr[i].eaddr);
  1510. /* If the extended address matches our extended address */
  1511. if (IEEE802154_EADDRCMP(beacon->pendaddr.addr[i].eaddr,
  1512. priv->addr.eaddr))
  1513. {
  1514. /* Wait to actually decide how to handle this until we parse
  1515. * the rest of the frame
  1516. */
  1517. wlinfo("Data pending for us in coord\n");
  1518. pending_eaddr = true;
  1519. }
  1520. }
  1521. /* If there is anything left in the frame, process it as the beacon payload */
  1522. beacon->payloadlength = iob->io_len - iob->io_offset;
  1523. if (beacon->payloadlength > 0)
  1524. {
  1525. memcpy(beacon->payload, &iob->io_data[iob->io_offset],
  1526. beacon->payloadlength);
  1527. }
  1528. /* At this point, we have extracted all relevant info from the incoming frame */
  1529. mac802154_lock(priv, false);
  1530. if (priv->curr_op == MAC802154_OP_SCAN)
  1531. {
  1532. /* Check to see if we already have a frame from this coordinator */
  1533. for (i = 0; i < priv->npandesc; i++)
  1534. {
  1535. if (priv->currscan.channels[priv->scanindex] !=
  1536. priv->pandescs[i].chan)
  1537. {
  1538. continue;
  1539. }
  1540. if (memcmp(&ind->src, &priv->pandescs[i].coordaddr,
  1541. sizeof(struct ieee802154_addr_s)) != 0)
  1542. {
  1543. continue;
  1544. }
  1545. /* The beacon is the same as another, so discard it */
  1546. ieee802154_primitive_free(primitive);
  1547. mac802154_unlock(priv);
  1548. return;
  1549. }
  1550. /* TODO: There is supposed to be different logic for the scanning
  1551. * procedure based on the macAutoRequest attribute. Currently, we
  1552. * perform scan operations as if macAutoRequest is set to TRUE,
  1553. * without actually checking the value. Basically, if macAutoRequest
  1554. * is TRUE, we are supposed to round up all of the pandesc results and
  1555. * pass them all up via the SCAN.confirm primitive. If macAutoRequest
  1556. * is FALSE, we are supposed to notify the next highest layer each
  1557. * time a unique beacon is received via the BEACON.notify primitive,
  1558. * and pass a NULLed out list of pandesc when SCAN.confirm is sent.
  1559. */
  1560. /* Copy the pan desc to the list of pan desc */
  1561. memcpy(&priv->pandescs[priv->npandesc], &beacon->pandesc,
  1562. sizeof(struct ieee802154_pandesc_s));
  1563. priv->npandesc++;
  1564. if (priv->npandesc == MAC802154_NPANDESC)
  1565. {
  1566. mac802154_scanfinish(priv, IEEE802154_STATUS_LIMITREACHED);
  1567. }
  1568. }
  1569. /* If we are not performing a SCAN operation */
  1570. else
  1571. {
  1572. /* Check the superframe structure and update the appropriate attributes. */
  1573. if (memcmp(&priv->sfspec, &beacon->pandesc.sfspec,
  1574. sizeof(struct ieee802154_superframespec_s)) != 0)
  1575. {
  1576. /* Copy in the new superframe spec */
  1577. memcpy(&priv->sfspec, &beacon->pandesc.sfspec,
  1578. sizeof(struct ieee802154_superframespec_s));
  1579. /* Tell the radio layer about the superframe spec update */
  1580. priv->radio->sfupdate(priv->radio, &priv->sfspec);
  1581. }
  1582. /* If we are performing an association and there is data pending for us
  1583. * we ignore the autoRequest logic and just extract it. We also don't
  1584. * send a BEACON-NOTFIY.indication in this case, not sure if that
  1585. * is the right thing to do, can't find anything definitive in standard.
  1586. */
  1587. if (priv->curr_op == MAC802154_OP_ASSOC && pending_eaddr)
  1588. {
  1589. priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
  1590. mac802154_txdesc_alloc(priv, &respdesc, false);
  1591. mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
  1592. IEEE802154_ADDRMODE_EXTENDED, respdesc);
  1593. /* Link the transaction into the CSMA transaction list */
  1594. sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue);
  1595. /* Notify the radio driver that there is data available */
  1596. priv->radio->txnotify(priv->radio, false);
  1597. }
  1598. else
  1599. {
  1600. if (priv->autoreq || priv->curr_op == MAC802154_OP_POLL)
  1601. {
  1602. /* If a beacon frame is received and macAutoRequest is set to
  1603. * TRUE, the MLME shall first issue the MLME-
  1604. * BEACON-NOTIFY.indication primitive if the beacon contains any
  1605. * payload.
  1606. */
  1607. if (beacon->payloadlength > 0)
  1608. {
  1609. mac802154_notify(priv, primitive);
  1610. }
  1611. /* If we have data pending for us, attempt to extract it. If
  1612. * for some reason we have data pending under our short
  1613. * address and our extended address, let the short address
  1614. * arbitrarily take precedence
  1615. */
  1616. if (pending_saddr | pending_eaddr)
  1617. {
  1618. mac802154_txdesc_alloc(priv, &respdesc, false);
  1619. if (priv->curr_op == MAC802154_OP_POLL)
  1620. {
  1621. priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
  1622. }
  1623. else if (priv->curr_op == MAC802154_OP_ASSOC)
  1624. {
  1625. priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
  1626. }
  1627. else if (priv->curr_op == MAC802154_OP_NONE)
  1628. {
  1629. DEBUGASSERT(priv->opsem.semcount == 1);
  1630. mac802154_takesem(&priv->opsem, false);
  1631. priv->curr_op = MAC802154_OP_AUTOEXTRACT;
  1632. priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
  1633. }
  1634. if (pending_saddr)
  1635. {
  1636. mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
  1637. IEEE802154_ADDRMODE_SHORT,
  1638. respdesc);
  1639. }
  1640. else
  1641. {
  1642. mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
  1643. IEEE802154_ADDRMODE_EXTENDED,
  1644. respdesc);
  1645. }
  1646. /* Link the transaction into the CSMA transaction list */
  1647. sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue);
  1648. /* Notify the radio driver that there is data available */
  1649. priv->radio->txnotify(priv->radio, false);
  1650. }
  1651. /* If there was a beacon payload, we used the primitive, so
  1652. * return here to make sure we don't free the primitive.
  1653. */
  1654. if (beacon->payloadlength > 0)
  1655. {
  1656. mac802154_unlock(priv);
  1657. return;
  1658. }
  1659. }
  1660. else
  1661. {
  1662. /* If a valid beacon frame is received and macAutoRequest is
  1663. * set to FALSE, the MLME shall indicate the beacon parameters
  1664. * to the next higher layer by issuing the
  1665. * MLME-BEACON-NOTIFY.indication primitive. [1] pg. 38
  1666. */
  1667. mac802154_notify(priv, primitive);
  1668. mac802154_unlock(priv);
  1669. return; /* Return so that we don't free the primitive */
  1670. }
  1671. }
  1672. }
  1673. mac802154_unlock(priv);
  1674. ieee802154_primitive_free(primitive);
  1675. return;
  1676. errout:
  1677. wlwarn("Received beacon with bad format\n");
  1678. ieee802154_primitive_free(primitive);
  1679. }
  1680. /****************************************************************************
  1681. * Public Functions
  1682. ****************************************************************************/
  1683. /****************************************************************************
  1684. * Name: mac802154_create
  1685. *
  1686. * Description:
  1687. * Create a 802.15.4 MAC device from a 802.15.4 compatible radio device.
  1688. *
  1689. * The returned MAC structure should be passed to either the next highest
  1690. * layer in the network stack, or registered with a mac802154dev character
  1691. * or network drivers. In any of these scenarios, the next highest layer
  1692. * should register a set of callbacks with the MAC layer by setting the
  1693. * mac->cbs member.
  1694. *
  1695. * NOTE: This API does not create any device accessible to userspace. If
  1696. * you want to call these APIs from userspace, you have to wrap your mac
  1697. * in a character device via mac802154_device.c.
  1698. *
  1699. * Input Parameters:
  1700. * radiodev - an instance of an IEEE 802.15.4 radio
  1701. *
  1702. * Returned Value:
  1703. * An opaque reference to the MAC state data.
  1704. *
  1705. ****************************************************************************/
  1706. MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev)
  1707. {
  1708. FAR struct ieee802154_privmac_s *mac;
  1709. FAR struct ieee802154_radiocb_s *radiocb;
  1710. /* Allocate object */
  1711. mac = (FAR struct ieee802154_privmac_s *)
  1712. kmm_zalloc(sizeof(struct ieee802154_privmac_s));
  1713. if (mac == NULL)
  1714. {
  1715. wlinfo("Failed allocation privmac structure\n");
  1716. return NULL;
  1717. }
  1718. /* Allow exclusive access to the privmac struct */
  1719. nxsem_init(&mac->exclsem, 0, 1);
  1720. /* Allow exclusive access to the dedicated command transaction */
  1721. nxsem_init(&mac->opsem, 0, 1);
  1722. /* Initialize fields */
  1723. mac->radio = radiodev;
  1724. /* Initialize the Radio callbacks */
  1725. mac->radiocb.priv = mac;
  1726. radiocb = &mac->radiocb.cb;
  1727. radiocb->poll = mac802154_radiopoll;
  1728. radiocb->txdone = mac802154_txdone;
  1729. radiocb->rxframe = mac802154_rxframe;
  1730. radiocb->sfevent = mac802154_sfevent;
  1731. radiocb->edresult = mac802154_edresult;
  1732. /* Bind our callback structure */
  1733. radiodev->bind(radiodev, &mac->radiocb.cb);
  1734. /* Initialize our various data pools */
  1735. ieee802154_primitivepool_initialize();
  1736. mac802154_resetqueues(mac);
  1737. mac802154_req_reset((MACHANDLE)mac, true);
  1738. return (MACHANDLE)mac;
  1739. }