text: /*
   * Copyright (c) 2016-2018 Nordic Semiconductor ASA
   * Copyright (c) 2016 Vinayak Kariappa Chettimada
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  
  #include <zephyr/types.h>
  #include <stddef.h>
  #include <string.h>
  
  #include <soc.h>
  #include <device.h>
  #include <drivers/entropy.h>
  #include <drivers/clock_control.h>
  #include <bluetooth/hci.h>
  #include <bluetooth/hci_vs.h>
  #include <sys/util.h>
  #include <sys/byteorder.h>
  
  #include "ll.h"
  #include "ll_feat.h"
  #include "ll_settings.h"
  
  #if defined(CONFIG_SOC_COMPATIBLE_NRF)
  #include <drivers/clock_control/nrf_clock_control.h>
  #endif /* CONFIG_SOC_COMPATIBLE_NRF */
  
  #include "hal/cpu.h"
  #include "hal/ecb.h"
  #include "hal/ccm.h"
  #include "hal/radio.h"
  #include "hal/ticker.h"
  #include "hal/debug.h"
  
  #include "util/util.h"
  #include "util/mem.h"
  #include "util/memq.h"
  #include "util/mayfly.h"
  
  #include "ticker/ticker.h"
  
  #include "pdu.h"
  #include "lll.h"
  #include "ctrl.h"
  #include "ctrl_internal.h"
  
  #include "ll_filter.h"
  
  #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
  #define LOG_MODULE_NAME bt_ctlr_ctrl
  #include "common/log.h"
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  #define RADIO_RSSI_SAMPLE_COUNT	10
  #define RADIO_RSSI_THRESHOLD	4
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  #define SILENT_CONNECTION	0
  
  /* Macro to convert time in us to connection interval units */
  #define RADIO_CONN_EVENTS(x, y) ((u16_t)(((x) + (y) - 1) / (y)))
  
  /* Macro to return packet time */
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  #define RADIO_PKT_TIME(octets, phy) \
  	(((phy) & BIT(2)) ? \
  	 (80 + 256 + 16 + 24 + ((((2 + (octets) + 4) * 8) + 24 + 3) * 8)) : \
  	 (((octets) + 14) * 8 / BIT(((phy) & 0x03) >> 1)))
  #else /* !CONFIG_BT_CTLR_PHY_CODED */
  #define RADIO_PKT_TIME(octets, phy) \
  	(((octets) + 14) * 8 / BIT(((phy) & 0x03) >> 1))
  #endif /* !CONFIG_BT_CTLR_PHY_CODED */
  
  /* Inter Frame Space */
  #define RADIO_TIFS    150 /* BT Spec. defined */
  /* Inter Event Space */
  #define RADIO_TIES_US 625 /* Implementation defined */
  /* Range Delay
   * Refer to BT Spec v5.1 Vol.6, Part B, Section 4.2.3 Range Delay
   * "4 / 1000" is an approximation of the propagation time in us of the
   * signal to travel 1 meter.
   */
  #define RADIO_RANGE_DISTANCE 1000 /* meters */
  #define RADIO_RANGE_DELAY_US (2 * RADIO_RANGE_DISTANCE * 4 / 1000)
  
  /* Implementation defines */
  #define RADIO_TICKER_JITTER_US           16
  #define RADIO_TICKER_START_PART_US       300
  #define RADIO_TICKER_XTAL_OFFSET_US      1200
  #define RADIO_TICKER_PREEMPT_PART_US     0
  #define RADIO_TICKER_PREEMPT_PART_MIN_US 0
  #define RADIO_TICKER_PREEMPT_PART_MAX_US RADIO_TICKER_XTAL_OFFSET_US
  
  enum role {
  	ROLE_NONE,
  	ROLE_ADV,
  	ROLE_SCAN,
  	ROLE_SLAVE,
  	ROLE_MASTER,
  };
  
  enum state {
  	STATE_NONE,
  	STATE_RX,
  	STATE_TX,
  	STATE_CLOSE,
  	STATE_STOP,
  	STATE_ABORT,
  };
  
  struct advertiser {
  	struct shdr hdr;
  
  	u8_t chan_map_current:3;
  	u8_t rfu:3;
  #if defined(CONFIG_BT_PERIPHERAL)
  	u8_t is_hdcd:1;
  #endif /* CONFIG_BT_PERIPHERAL */
  	u8_t is_enabled:1;
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  	u8_t phy_p:3;
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  	u8_t chan_map:3;
  	u8_t filter_policy:2;
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	u8_t rl_idx;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	u8_t  retry:3;
  	u8_t  is_mesh:1;
  	u8_t  rfu1:4;
  
  	u8_t  scan_delay_ms;
  	u16_t scan_window_ms;
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  	struct radio_adv_data adv_data;
  	struct radio_adv_data scan_data;
  
  	struct connection *conn;
  
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  	s8_t tx_pwr_lvl;
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  };
  
  struct scanner {
  	struct shdr hdr;
  
  	u8_t  is_enabled:1;
  	u8_t  state:1;
  	u8_t  chan:2;
  	u8_t  rfu:4;
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  	u8_t  phy:3;
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  	u8_t  type:1;
  	u8_t  filter_policy:2;
  	u8_t  adv_addr_type:1;
  	u8_t  init_addr_type:1;
  
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	u8_t  rpa_gen:1;
  	/* initiator only */
  	u8_t rl_idx;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  	u8_t  init_addr[BDADDR_SIZE];
  	u8_t  adv_addr[BDADDR_SIZE];
  
  	u32_t ticks_window;
  
  	u16_t conn_interval;
  	u16_t conn_latency;
  	u16_t conn_timeout;
  	u32_t ticks_conn_slot;
  	struct connection *conn;
  
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  	s8_t tx_pwr_lvl;
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  
  	u32_t win_offset_us;
  };
  
  static struct {
  	struct device *hf_clock;
  	struct device *entropy;
  
  	u32_t ticks_anchor;
  	u32_t remainder_anchor;
  
  	u8_t  volatile ticker_id_prepare;
  	u8_t  volatile ticker_id_event;
  	u8_t  volatile ticker_id_stop;
  	u8_t  volatile ticker_id_upd;
  
  	enum  role volatile role;
  	enum  state state;
  
  	struct advertiser advertiser;
  	struct scanner scanner;
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	u32_t mesh_adv_end_us;
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  	void  *conn_pool;
  	void  *conn_free;
  	u8_t  connection_count;
  	struct connection *conn_curr;
  
  	u8_t  packet_counter;
  	u8_t  crc_expire;
  
  	u8_t  data_chan_map[5];
  	u8_t  data_chan_count;
  	u8_t  sca;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	/* DLE global settings */
  	u16_t default_tx_octets;
  	u16_t default_tx_time;
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	u16_t default_phy_tx;
  	u16_t default_phy_rx;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  	/** @todo below members to be made role specific and quota managed for
  	 * Rx-es.
  	 */
  	/* Advertiser, Scanner, and Connections Rx data pool */
  	void  *pkt_rx_data_pool;
  	void  *pkt_rx_data_free;
  	u16_t packet_data_octets_max;
  	u16_t packet_rx_data_pool_size;
  	u16_t packet_rx_data_size;
  	u8_t  packet_rx_data_count;
  	/* Free queue Rx data buffers */
  	struct radio_pdu_node_rx **packet_rx;
  	u8_t  packet_rx_count;
  	u8_t  volatile packet_rx_last;
  	u8_t  packet_rx_acquire;
  
  	/* Controller to Host event-cum-data queue */
  	void        *link_rx_pool;
  	void        *link_rx_free;
  	memq_link_t *link_rx_head;
  	memq_link_t *volatile link_rx_tail;
  	u8_t        link_rx_data_quota;
  
  	/* Connections common Tx ctrl and data pool */
  	void  *pkt_tx_ctrl_pool;
  	void  *pkt_tx_ctrl_free;
  	void  *pkt_tx_data_pool;
  	void  *pkt_tx_data_free;
  	u16_t packet_tx_data_size;
  
  	/* Host to Controller Tx, and Controller to Host Num complete queue */
  	struct pdu_data_q_tx *pkt_tx;
  	struct pdu_data_q_tx *pkt_release;
  	u8_t  packet_tx_count;
  	u8_t  volatile packet_tx_first;
  	u8_t  packet_tx_last;
  	u8_t  packet_release_first;
  	u8_t  volatile packet_release_last;
  
  	u16_t fc_handle[TRIPLE_BUFFER_SIZE];
  	u8_t  volatile fc_req;
  	u8_t  fc_ack;
  	u8_t  fc_ena;
  
  	u32_t ticks_active_to_start;
  
  	struct connection *conn_upd;
  } _radio;
  
  static void common_init(void);
  static void ticker_success_assert(u32_t status, void *params);
  static void ticker_update_adv_assert(u32_t status, void *params);
  #if defined(CONFIG_BT_CONN)
  #if defined(CONFIG_BT_PERIPHERAL)
  static void ticker_stop_adv_assert(u32_t status, void *params);
  #endif /* CONFIG_BT_PERIPHERAL */
  #if defined(CONFIG_BT_CENTRAL)
  static void ticker_stop_scan_assert(u32_t status, void *params);
  #endif /* CONFIG_BT_CENTRAL */
  static void ticker_update_conn_assert(u32_t status, void *params);
  static void ticker_stop_conn_assert(u32_t status, void *params);
  static void ticker_start_conn_assert(u32_t status, void *params);
  #endif /* CONFIG_BT_CONN */
  #if defined(CONFIG_BT_PERIPHERAL) || defined(CONFIG_BT_HCI_MESH_EXT)
  static void ticker_stop_adv_stop(u32_t status, void *params);
  #endif /* CONFIG_BT_PERIPHERAL || CONFIG_BT_HCI_MESH_EXT */
  static void event_inactive(u32_t ticks_at_expire, u32_t remainder,
  			   u16_t lazy, void *context);
  
  #if defined(RADIO_UNIT_TEST) && \
  	defined(CONFIG_BT_CTLR_CHAN_SEL_2)
  static void chan_sel_2_ut(void);
  #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */
  
  static void adv_setup(void);
  static void event_adv(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
  		      void *context);
  static void event_scan_prepare(u32_t ticks_at_expire, u32_t remainder,
  			      u16_t lazy, void *context);
  static void event_scan(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
  		       void *context);
  #if defined(CONFIG_BT_PERIPHERAL)
  static void event_slave_prepare(u32_t ticks_at_expire, u32_t remainder,
  				u16_t lazy, void *context);
  static void event_slave(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
  			void *context);
  #endif /* CONFIG_BT_PERIPHERAL */
  #if defined(CONFIG_BT_CENTRAL)
  static void event_master_prepare(u32_t ticks_at_expire, u32_t remainder,
  				 u16_t lazy, void *context);
  static void event_master(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
  			 void *context);
  #endif /* CONFIG_BT_CENTRAL */
  static void rx_packet_set(struct connection *conn,
  			  struct pdu_data *pdu_data_rx);
  static void packet_rx_allocate(u8_t max);
  static inline u8_t packet_rx_acquired_count_get(void);
  static inline struct radio_pdu_node_rx *packet_rx_reserve_get(u8_t count);
  static void packet_rx_callback(void);
  static inline struct radio_pdu_node_rx *packet_rx_enqueue_get(void);
  static inline void packet_rx_enqueue_commit(struct radio_pdu_node_rx *node_rx);
  static inline void packet_rx_enqueue_hold(struct radio_pdu_node_rx *node_rx);
  static inline void packet_rx_enqueue_forward(void);
  static void packet_rx_enqueue(void);
  static void packet_tx_enqueue(u8_t max);
  static void pdu_node_tx_release(u16_t handle,
  				struct radio_pdu_node_tx *node_tx);
  #if defined(CONFIG_BT_CONN)
  static void tx_packet_set(struct connection *conn,
  			  struct pdu_data *pdu_data_tx);
  static struct pdu_data *empty_tx_enqueue(struct connection *conn);
  static void prepare_pdu_data_tx(struct connection *conn,
  				struct pdu_data **pdu_data_tx);
  static void ctrl_tx_enqueue(struct connection *conn,
  			    struct radio_pdu_node_tx *node_tx);
  static void connection_release(struct connection *conn);
  static void terminate_ind_rx_enqueue(struct connection *conn, u8_t reason);
  static u8_t conn_update(struct connection *conn, struct pdu_data *pdu_data_rx);
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
      defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  static u32_t conn_update_req(struct connection *conn);
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED && CONFIG_BT_CTLR_SCHED_ADVANCED */
  
  static u8_t chan_map_update(struct connection *conn,
  			    struct pdu_data *pdu_data_rx);
  
  #if defined(CONFIG_BT_CTLR_PHY)
  static inline u8_t phy_upd_ind_recv(struct radio_pdu_node_rx *node_rx,
  				    u8_t *rx_enqueue);
  #endif /* CONFIG_BT_CTLR_PHY */
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  static void enc_req_reused_send(struct connection *conn,
  				struct radio_pdu_node_tx *node_tx);
  #if defined(CONFIG_BT_PERIPHERAL)
  static u8_t enc_rsp_send(struct connection *conn);
  #endif /* CONFIG_BT_PERIPHERAL */
  static u8_t start_enc_rsp_send(struct connection *conn,
  			       struct pdu_data *pdu_ctrl_tx);
  static u8_t pause_enc_rsp_send(struct connection *conn, u8_t req);
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  static u8_t unknown_rsp_send(struct connection *conn, u8_t type);
  static u8_t feature_rsp_send(struct connection *conn,
  			     struct pdu_data *pdu_data_rx);
  static u8_t version_ind_send(struct connection *conn,
  			     struct pdu_data *pdu_data_rx, u8_t *rx_enqueue);
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  static u8_t ping_resp_send(struct connection *conn);
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) || \
      defined(CONFIG_BT_CTLR_PHY)
  static u8_t reject_ext_ind_send(struct connection *conn, u8_t reject_opcode,
  				u8_t error_code);
  #endif
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  #if !defined(CONFIG_BT_CTLR_PHY)
  static void length_resp_send(struct connection *conn,
  			     struct radio_pdu_node_tx *node_tx,
  			     u16_t eff_rx_octets, u16_t eff_tx_octets);
  #else /* CONFIG_BT_CTLR_PHY */
  static void length_resp_send(struct connection *conn,
  			     struct radio_pdu_node_tx *node_tx,
  			     u16_t eff_rx_octets, u16_t eff_rx_time,
  			     u16_t eff_tx_octets, u16_t eff_tx_time);
  #endif /* CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  static u8_t phy_rsp_send(struct connection *conn, struct pdu_data *pdu_data_rx);
  #endif /* CONFIG_BT_CTLR_PHY */
  
  static void rx_fc_lock(u16_t handle);
  
  static u16_t const gc_lookup_ppm[] = { 500, 250, 150, 100, 75, 50, 30, 20 };
  #endif /* CONFIG_BT_CONN */
  
  static u8_t role_disable(u8_t ticker_id_primary, u8_t ticker_id_stop);
  
  /*****************************************************************************
   *RADIO
   ****************************************************************************/
  u32_t radio_init(void *hf_clock, u8_t sca, void *entropy,
  		 u8_t connection_count_max,
  		 u8_t rx_count_max, u8_t tx_count_max,
  		 u16_t packet_data_octets_max,
  		 u16_t packet_tx_data_size, u8_t *mem_radio,
  		 u16_t mem_size)
  {
  	u32_t retcode;
  	u8_t *mem_radio_end;
  
  	/* intialise hf_clock device to use in prepare */
  	_radio.hf_clock = hf_clock;
  
  	/* initialise SCA */
  	_radio.sca = sca;
  
  	/* intialise entropy device to use in ISRs */
  	_radio.entropy = entropy;
  
  	/* initialised radio mem end variable */
  	mem_radio_end = mem_radio + mem_size;
  
  	/* initialise connection context memory */
  	_radio.connection_count = connection_count_max;
  	_radio.conn_pool = mem_radio;
  	mem_radio += (sizeof(struct connection) * _radio.connection_count);
  
  	/* initialise rx and tx queue counts */
  
  	/* additional for pdu to NACK or receive empty PDU,
  	 * 1 scan resp and 1* ctrl event.
  	 */
  	rx_count_max += 3;
  	 /* additional pdu to send enc_req ctrl pdu */
  	tx_count_max += 1;
  	_radio.packet_rx_count = (rx_count_max + 1);
  	_radio.packet_tx_count = (tx_count_max + 1);
  	_radio.link_rx_data_quota = rx_count_max;
  
  	/* initialise rx queue memory */
  	_radio.packet_rx = (void *)mem_radio;
  	mem_radio +=
  		(sizeof(struct radio_pdu_node_rx *)*_radio.packet_rx_count);
  
  	/* initialise tx queue memory */
  	_radio.pkt_tx = (void *)mem_radio;
  	mem_radio += (sizeof(struct pdu_data_q_tx) * _radio.packet_tx_count);
  
  	/* initialise tx release queue memory */
  	_radio.pkt_release = (void *)mem_radio;
  	mem_radio += (sizeof(struct pdu_data_q_tx) * _radio.packet_tx_count);
  
  	/* initialise rx memory size and count */
  	_radio.packet_data_octets_max = packet_data_octets_max;
  	if ((PDU_AC_SIZE_MAX + PDU_AC_SIZE_EXTRA) <
  	    (offsetof(struct pdu_data, lldata) +
  			_radio.packet_data_octets_max)) {
  		_radio.packet_rx_data_pool_size =
  		    (MROUND(offsetof(struct radio_pdu_node_rx, pdu_data) +
  			    offsetof(struct pdu_data, lldata) +
  			    _radio.packet_data_octets_max) * rx_count_max);
  	} else {
  		_radio.packet_rx_data_pool_size =
  			(MROUND(offsetof(struct radio_pdu_node_rx, pdu_data) +
  			  (PDU_AC_SIZE_MAX + PDU_AC_SIZE_EXTRA)) * rx_count_max);
  	}
  	_radio.packet_rx_data_size = PACKET_RX_DATA_SIZE_MIN;
  	_radio.packet_rx_data_count = (_radio.packet_rx_data_pool_size /
  				       _radio.packet_rx_data_size);
  
  	/* initialise rx data pool memory */
  	_radio.pkt_rx_data_pool = mem_radio;
  	mem_radio += _radio.packet_rx_data_pool_size;
  
  	/* initialise rx link pool memory */
  	_radio.link_rx_pool = mem_radio;
  	mem_radio += (sizeof(memq_link_t) * (_radio.packet_rx_count +
  					     _radio.connection_count));
  
  	/* initialise tx ctrl pool memory */
  	_radio.pkt_tx_ctrl_pool = mem_radio;
  	mem_radio += PACKET_TX_CTRL_SIZE_MIN * PACKET_MEM_COUNT_TX_CTRL;
  
  	/* initialise tx data memory size and count */
  	_radio.packet_tx_data_size =
  		MROUND(offsetof(struct radio_pdu_node_tx, pdu_data) +
  		       offsetof(struct pdu_data, lldata) +
  		       packet_tx_data_size);
  
  	/* initialise tx data pool memory */
  	_radio.pkt_tx_data_pool = mem_radio;
  	mem_radio += (_radio.packet_tx_data_size * tx_count_max);
  
  	/* check for sufficient memory allocation for stack
  	 * configuration.
  	 */
  	retcode = (mem_radio - mem_radio_end);
  	if (retcode) {
  		return (retcode + mem_size);
  	}
  
  	/* enable connection handle based on-off flow control feature.
  	 * This is a simple flow control to rx data only on one selected
  	 * connection handle.
  	 * TODO: replace this feature with host-to-controller flowcontrol
  	 * implementation/design.
  	 */
  	_radio.fc_ena = 1U;
  
  	/* memory allocations */
  	common_init();
  
  #if defined(RADIO_UNIT_TEST) && defined(CONFIG_BT_CTLR_CHAN_SEL_2)
  	chan_sel_2_ut();
  #endif /* RADIO_UNIT_TEST && CONFIG_BT_CTLR_CHAN_SEL_2 */
  
  	radio_setup();
  
  	return retcode;
  }
  
  struct device *radio_hf_clock_get(void)
  {
  	return _radio.hf_clock;
  }
  
  void ll_reset(void)
  {
  	u16_t conn_handle;
  
  	/* disable advertiser events */
  	role_disable(RADIO_TICKER_ID_ADV, RADIO_TICKER_ID_ADV_STOP);
  
  	/* disable oberver events */
  	role_disable(RADIO_TICKER_ID_SCAN, RADIO_TICKER_ID_SCAN_STOP);
  
  	/* disable connection events */
  	for (conn_handle = 0U; conn_handle < _radio.connection_count;
  	     conn_handle++) {
  		role_disable(RADIO_TICKER_ID_FIRST_CONNECTION + conn_handle,
  			     TICKER_NULL);
  	}
  
  	/* reset controller context members */
  	_radio.advertiser.is_enabled = 0U;
  	_radio.advertiser.conn = NULL;
  	_radio.scanner.is_enabled = 0U;
  	_radio.scanner.conn = NULL;
  	_radio.packet_rx_data_size = PACKET_RX_DATA_SIZE_MIN;
  	_radio.packet_rx_data_count = (_radio.packet_rx_data_pool_size /
  				       _radio.packet_rx_data_size);
  	_radio.packet_rx_last = 0U;
  	_radio.packet_rx_acquire = 0U;
  	_radio.link_rx_data_quota = _radio.packet_rx_count - 1;
  	_radio.packet_tx_first = 0U;
  	_radio.packet_tx_last = 0U;
  	_radio.packet_release_first = 0U;
  	_radio.packet_release_last = 0U;
  
  	/* reset FC feature */
  	/* TODO: remove this feature related all code in the future */
  	_radio.fc_ack = _radio.fc_req;
  
  	/* reset whitelist and resolving list */
  	if (IS_ENABLED(CONFIG_BT_CTLR_FILTER)) {
  		ll_filter_reset(false);
  	}
  
  	/* memory allocations */
  	common_init();
  }
  
  static void common_init(void)
  {
  	memq_link_t *link;
  
  	/* initialise connection pool. */
  	if (_radio.connection_count) {
  		mem_init(_radio.conn_pool, CONNECTION_T_SIZE,
  			 _radio.connection_count,
  			 &_radio.conn_free);
  	} else {
  		_radio.conn_free = NULL;
  	}
  
  	/* initialise rx pool. */
  	mem_init(_radio.pkt_rx_data_pool,
  		 _radio.packet_rx_data_size,
  		 _radio.packet_rx_data_count,
  		 &_radio.pkt_rx_data_free);
  
  	/* initialise rx link pool. */
  	mem_init(_radio.link_rx_pool, (sizeof(memq_link_t)),
  		 (_radio.packet_rx_count + _radio.connection_count),
  		 &_radio.link_rx_free);
  
  	/* initialise ctrl tx pool. */
  	mem_init(_radio.pkt_tx_ctrl_pool, PACKET_TX_CTRL_SIZE_MIN,
  		 PACKET_MEM_COUNT_TX_CTRL, &_radio.pkt_tx_ctrl_free);
  
  	/* initialise data tx pool. */
  	mem_init(_radio.pkt_tx_data_pool, _radio.packet_tx_data_size,
  		 (_radio.packet_tx_count - 1), &_radio.pkt_tx_data_free);
  
  	/* initialise the event-cum-data memq */
  	link = mem_acquire(&_radio.link_rx_free);
  	LL_ASSERT(link);
  	memq_init(link, &_radio.link_rx_head, (void *)&_radio.link_rx_tail);
  
  	/* initialise advertiser channel map */
  	_radio.advertiser.chan_map = 0x07;
  
  	/* initialise connection channel map */
  	_radio.data_chan_map[0] = 0xFF;
  	_radio.data_chan_map[1] = 0xFF;
  	_radio.data_chan_map[2] = 0xFF;
  	_radio.data_chan_map[3] = 0xFF;
  	_radio.data_chan_map[4] = 0x1F;
  	_radio.data_chan_count = 37U;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	/* Initialize the DLE defaults */
  	_radio.default_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
  	_radio.default_tx_time = RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0);
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	/* Initialize the PHY defaults */
  	_radio.default_phy_tx = BIT(0);
  	_radio.default_phy_rx = BIT(0);
  
  #if defined(CONFIG_BT_CTLR_PHY_2M)
  	_radio.default_phy_tx |= BIT(1);
  	_radio.default_phy_rx |= BIT(1);
  #endif /* CONFIG_BT_CTLR_PHY_2M */
  
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  	_radio.default_phy_tx |= BIT(2);
  	_radio.default_phy_rx |= BIT(2);
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  #endif /* CONFIG_BT_CTLR_PHY */
  
  	/* allocate the rx queue */
  	packet_rx_allocate(0xFF);
  
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  	_radio.advertiser.tx_pwr_lvl = RADIO_TXP_DEFAULT;
  	_radio.scanner.tx_pwr_lvl = RADIO_TXP_DEFAULT;
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  }
  
  static inline u32_t addr_us_get(u8_t phy)
  {
  	switch (phy) {
  	default:
  	case BIT(0): /* 1Mbps */
  		return 40;
  	case BIT(1): /* 2Mbps */
  		return 24;
  	case BIT(2): /* Coded */
  		return 376;
  	}
  }
  
  #if defined(SILENT_CONNECTION)
  static inline u32_t empty_pkt_us_get(u8_t phy)
  {
  	switch (phy) {
  	default:
  	case BIT(0):
  		return 80;
  	case BIT(1):
  		return 44;
  	case BIT(2):
  		return 720;
  	}
  }
  #endif
  
  static inline void isr_radio_state_tx(void)
  {
  	u32_t hcto;
  
  	_radio.state = STATE_RX;
  
  	hcto = radio_tmr_tifs_base_get() + RADIO_TIFS + 4 +
  	       RADIO_RANGE_DELAY_US + 1; /* 1us, end jitter */
  
  	radio_tmr_tifs_set(RADIO_TIFS);
  
  #if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  	radio_gpio_lna_setup();
  #endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
  
  	switch (_radio.role) {
  	case ROLE_ADV:
  		radio_switch_complete_and_tx(0, 0, 0, 0);
  		radio_pkt_rx_set(radio_pkt_scratch_get());
  
  		/* assert if radio packet ptr is not set and radio started rx */
  		LL_ASSERT(!radio_is_ready());
  
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		if (ctrl_rl_enabled()) {
  			u8_t count, *irks = ctrl_irks_get(&count);
  
  			radio_ar_configure(count, irks);
  		}
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  		hcto += radio_rx_chain_delay_get(0, 0);
  		hcto += addr_us_get(0);
  		hcto -= radio_tx_chain_delay_get(0, 0);
  
  		radio_tmr_hcto_configure(hcto);
  
  		/* capture end of CONNECT_IND PDU, used for calculating first
  		 * slave event.
  		 */
  		radio_tmr_end_capture();
  
  #if defined(CONFIG_BT_CTLR_SCAN_REQ_RSSI) || defined(CONFIG_BT_CTLR_CONN_RSSI)
  		radio_rssi_measure();
  #endif /* CONFIG_BT_CTLR_SCAN_REQ_RSSI || CONFIG_BT_CTLR_CONN_RSSI */
  
  #if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  		radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
  					 RADIO_TIFS - 4 -
  					 radio_tx_chain_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
  		break;
  
  	case ROLE_SCAN:
  		radio_switch_complete_and_tx(0, 0, 0, 0);
  		radio_pkt_rx_set(_radio.packet_rx
  					[_radio.packet_rx_last]->pdu_data);
  
  		/* assert if radio packet ptr is not set and radio started rx */
  		LL_ASSERT(!radio_is_ready());
  
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		if (ctrl_rl_enabled()) {
  			u8_t count, *irks = ctrl_irks_get(&count);
  
  			radio_ar_configure(count, irks);
  		}
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  		hcto += radio_rx_chain_delay_get(0, 0);
  		hcto += addr_us_get(0);
  		hcto -= radio_tx_chain_delay_get(0, 0);
  
  		radio_tmr_hcto_configure(hcto);
  		radio_rssi_measure();
  
  #if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  		radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
  					 RADIO_TIFS - 4 -
  					 radio_tx_chain_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
  		break;
  
  	case ROLE_MASTER:
  	case ROLE_SLAVE:
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		radio_switch_complete_and_tx(_radio.conn_curr->phy_rx, 0,
  					     _radio.conn_curr->phy_tx,
  					     _radio.conn_curr->phy_flags);
  #else /* !CONFIG_BT_CTLR_PHY */
  		radio_switch_complete_and_tx(0, 0, 0, 0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  		rx_packet_set(_radio.conn_curr,	(void *)
  			_radio.packet_rx[_radio.packet_rx_last]->pdu_data);
  
  		/* assert if radio packet ptr is not set and radio started rx */
  		LL_ASSERT(!radio_is_ready());
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		hcto += radio_rx_chain_delay_get(_radio.conn_curr->phy_rx, 1);
  		hcto += addr_us_get(_radio.conn_curr->phy_rx);
  		hcto -= radio_tx_chain_delay_get(_radio.conn_curr->phy_tx,
  						 _radio.conn_curr->phy_flags);
  #else /* !CONFIG_BT_CTLR_PHY */
  		hcto += radio_rx_chain_delay_get(0, 0);
  		hcto += addr_us_get(0);
  		hcto -= radio_tx_chain_delay_get(0, 0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  		radio_tmr_hcto_configure(hcto);
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  		if ((_radio.role == ROLE_MASTER) &&
  		    (_radio.packet_counter == 0)) {
  			radio_rssi_measure();
  		}
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  #if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  #if defined(CONFIG_BT_CTLR_PHY)
  		radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
  					 RADIO_TIFS - 4 -
  					 radio_tx_chain_delay_get(
  						 _radio.conn_curr->phy_tx,
  						 _radio.conn_curr->phy_flags) -
  					 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #else /* !CONFIG_BT_CTLR_PHY */
  		radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
  					 RADIO_TIFS - 4 -
  					 radio_tx_chain_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #endif /* !CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR) || \
      defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  		radio_tmr_end_capture();
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  		/* Route the tx packet to respective connections */
  		/* TODO: use timebox for tx enqueue (instead of 1 packet
  		 * that is routed, which may not be for the current connection)
  		 * try to route as much tx packet in queue into corresponding
  		 * connection's tx list.
  		 */
  		packet_tx_enqueue(1);
  
  		break;
  
  	case ROLE_NONE:
  	default:
  		LL_ASSERT(0);
  		break;
  	}
  }
  
  #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
  static u32_t isr_rx_adv_sr_report(struct pdu_adv *pdu_adv_rx, u8_t rssi_ready)
  {
  	struct radio_pdu_node_rx *node_rx;
  	struct pdu_adv *pdu_adv;
  	u8_t pdu_len;
  
  	node_rx = packet_rx_reserve_get(3);
  	if (node_rx == 0) {
  		return 1;
  	}
  
  	/* Prepare the report (scan req) */
  	node_rx->hdr.handle = 0xffff;
  	node_rx->hdr.type = NODE_RX_TYPE_SCAN_REQ;
  
  	/* Make a copy of PDU into Rx node (as the received PDU is in the
  	 * scratch buffer), and save the RSSI value.
  	 */
  	pdu_adv = (void *)node_rx->pdu_data;
  	pdu_len = offsetof(struct pdu_adv, payload) + pdu_adv_rx->len;
  	memcpy(pdu_adv, pdu_adv_rx, pdu_len);
  	((u8_t *)pdu_adv)[pdu_len] =
  		(rssi_ready) ? (radio_rssi_get() & 0x7f) : 0x7f;
  
  	packet_rx_enqueue();
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */
  
  static inline bool isr_adv_sr_adva_check(struct pdu_adv *adv,
  					 struct pdu_adv *sr)
  {
  	return (adv->tx_addr == sr->rx_addr) &&
  		!memcmp(adv->adv_ind.addr, sr->scan_req.adv_addr, BDADDR_SIZE);
  }
  
  static inline bool isr_adv_sr_check(struct pdu_adv *adv, struct pdu_adv *sr,
  				    u8_t devmatch_ok, u8_t *rl_idx)
  {
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	return ((((_radio.advertiser.filter_policy & 0x01) == 0) &&
  		 ctrl_rl_addr_allowed(sr->tx_addr, sr->scan_req.scan_addr,
  				      rl_idx)) ||
  		(((_radio.advertiser.filter_policy & 0x01) != 0) &&
  		 (devmatch_ok || ctrl_irk_whitelisted(*rl_idx)))) &&
  		isr_adv_sr_adva_check(adv, sr);
  #else
  	return (((_radio.advertiser.filter_policy & 0x01) == 0) ||
  		(devmatch_ok)) &&
  		isr_adv_sr_adva_check(adv, sr);
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  }
  
  static inline bool isr_adv_ci_tgta_check(struct pdu_adv *adv, struct pdu_adv *ci,
  					 u8_t rl_idx)
  {
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	if (rl_idx != FILTER_IDX_NONE) {
  		return rl_idx == _radio.advertiser.rl_idx;
  	}
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  	return (adv->rx_addr == ci->tx_addr) &&
  	       !memcmp(adv->direct_ind.tgt_addr, ci->connect_ind.init_addr,
  		       BDADDR_SIZE);
  }
  
  static inline bool isr_adv_ci_adva_check(struct pdu_adv *adv,
  					 struct pdu_adv *ci)
  {
  	return (adv->tx_addr == ci->rx_addr) &&
  		(((adv->type == PDU_ADV_TYPE_DIRECT_IND) &&
  		 !memcmp(adv->direct_ind.adv_addr, ci->connect_ind.adv_addr,
  			 BDADDR_SIZE)) ||
  		 (!memcmp(adv->adv_ind.addr, ci->connect_ind.adv_addr,
  			  BDADDR_SIZE)));
  }
  
  static inline bool isr_adv_ci_check(struct pdu_adv *adv, struct pdu_adv *ci,
  				    u8_t devmatch_ok, u8_t *rl_idx)
  {
  	/* LL 4.3.2: filter policy shall be ignored for directed adv */
  	if (adv->type == PDU_ADV_TYPE_DIRECT_IND) {
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		return ctrl_rl_addr_allowed(ci->tx_addr,
  					    ci->connect_ind.init_addr,
  					    rl_idx) &&
  #else
  		return (1) &&
  #endif
  		       isr_adv_ci_adva_check(adv, ci) &&
  		       isr_adv_ci_tgta_check(adv, ci, *rl_idx);
  	}
  
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	return ((((_radio.advertiser.filter_policy & 0x02) == 0) &&
  		 ctrl_rl_addr_allowed(ci->tx_addr, ci->connect_ind.init_addr,
  				      rl_idx)) ||
  		(((_radio.advertiser.filter_policy & 0x02) != 0) &&
  		 (devmatch_ok || ctrl_irk_whitelisted(*rl_idx)))) &&
  	       isr_adv_ci_adva_check(adv, ci);
  #else
  	return (((_radio.advertiser.filter_policy & 0x02) == 0) ||
  		(devmatch_ok)) &&
  	       isr_adv_ci_adva_check(adv, ci);
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  }
  
  static inline u32_t isr_rx_adv(u8_t devmatch_ok, u8_t devmatch_id,
  			       u8_t irkmatch_ok, u8_t irkmatch_id,
  			       u8_t rssi_ready)
  {
  	struct pdu_adv *pdu_adv, *_pdu_adv;
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	/* An IRK match implies address resolution enabled */
  	u8_t rl_idx = irkmatch_ok ? ctrl_rl_irk_idx(irkmatch_id) :
  				    FILTER_IDX_NONE;
  #else
  	u8_t rl_idx = FILTER_IDX_NONE;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  	pdu_adv = (void *)radio_pkt_scratch_get();
  	_pdu_adv = (void *)&_radio.advertiser.adv_data.data
  					[_radio.advertiser.adv_data.first][0];
  
  	if ((pdu_adv->type == PDU_ADV_TYPE_SCAN_REQ) &&
  	    (pdu_adv->len == sizeof(struct pdu_adv_scan_req)) &&
  	    (_pdu_adv->type != PDU_ADV_TYPE_DIRECT_IND) &&
  	    isr_adv_sr_check(_pdu_adv, pdu_adv, devmatch_ok, &rl_idx)) {
  
  #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
  		if (!IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT) ||
  		    0 /* TODO: extended adv. scan req notification enabled */) {
  			u32_t err;
  
  			/* Generate the scan request event */
  			err = isr_rx_adv_sr_report(pdu_adv, rssi_ready);
  			if (err) {
  				/* Scan Response will not be transmitted */
  				return err;
  			}
  		}
  #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */
  
  		_radio.state = STATE_CLOSE;
  
  		radio_switch_complete_and_disable();
  
  		radio_pkt_tx_set(&_radio.advertiser.scan_data.data
  					[_radio.advertiser.scan_data.first][0]);
  
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  		radio_gpio_pa_setup();
  		radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
  					 RADIO_TIFS -
  					 radio_rx_chain_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #endif /* CONFIG_BT_CTLR_GPIO_PA_PIN */
  
  		/* assert if radio packet ptr is not set and radio started tx */
  		LL_ASSERT(!radio_is_ready());
  
  		return 0;
  #if defined(CONFIG_BT_PERIPHERAL)
  	} else if ((pdu_adv->type == PDU_ADV_TYPE_CONNECT_IND) &&
  		   (pdu_adv->len == sizeof(struct pdu_adv_connect_ind)) &&
  		   isr_adv_ci_check(_pdu_adv, pdu_adv, devmatch_ok, &rl_idx) &&
  		   ((_radio.fc_ena == 0) || (_radio.fc_req == _radio.fc_ack)) &&
  		   (_radio.advertiser.conn)) {
  		struct radio_le_conn_cmplt *radio_le_conn_cmplt;
  		struct radio_pdu_node_rx *node_rx;
  		struct connection *conn;
  		u32_t ticks_slot_offset;
  		u32_t conn_interval_us;
  		u32_t conn_offset_us;
  		u32_t rx_ready_delay;
  		u32_t ticker_status;
  
  		if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
  			node_rx = packet_rx_reserve_get(4);
  		} else {
  			node_rx = packet_rx_reserve_get(3);
  		}
  
  		if (!node_rx) {
  			return 1;
  		}
  
  		_radio.state = STATE_STOP;
  		radio_disable();
  
  		/* acquire the slave context from advertiser */
  		conn = _radio.advertiser.conn;
  		_radio.advertiser.conn = NULL;
  
  		/* Populate the slave context */
  		conn->handle = mem_index_get(conn, _radio.conn_pool,
  			CONNECTION_T_SIZE);
  		memcpy(&conn->crc_init[0],
  		       &pdu_adv->connect_ind.crc_init[0],
  		       3);
  		memcpy(&conn->access_addr[0],
  		       &pdu_adv->connect_ind.access_addr[0],
  		       4);
  		memcpy(&conn->data_chan_map[0],
  		       &pdu_adv->connect_ind.chan_map[0],
  		       sizeof(conn->data_chan_map));
  		conn->data_chan_count =
  			util_ones_count_get(&conn->data_chan_map[0],
  					    sizeof(conn->data_chan_map));
  		conn->data_chan_hop = pdu_adv->connect_ind.hop;
  		conn->conn_interval =
  			pdu_adv->connect_ind.interval;
  		conn_interval_us =
  			pdu_adv->connect_ind.interval * 1250;
  		conn->latency = pdu_adv->connect_ind.latency;
  		memcpy((void *)&conn->slave.force, &conn->access_addr[0],
  		       sizeof(conn->slave.force));
  		conn->supervision_reload =
  			RADIO_CONN_EVENTS((pdu_adv->connect_ind.timeout
  					   * 10 * 1000), conn_interval_us);
  		conn->procedure_reload = RADIO_CONN_EVENTS((40 * 1000 * 1000),
  							   conn_interval_us);
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  		/* APTO in no. of connection events */
  		conn->apto_reload = RADIO_CONN_EVENTS((30 * 1000 * 1000),
  						      conn_interval_us);
  		/* Dispatch LE Ping PDU 6 connection events (that peer would
  		 * listen to) before 30s timeout
  		 * TODO: "peer listens to" is greater than 30s due to latency
  		 */
  		conn->appto_reload = (conn->apto_reload > (conn->latency + 6)) ?
  				     (conn->apto_reload - (conn->latency + 6)) :
  				     conn->apto_reload;
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  		conn->rssi_latest = (rssi_ready) ? (radio_rssi_get() & 0x7f) :
  						   0x7f;
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  		/* Prepare the rx packet structure */
  		node_rx->hdr.handle = conn->handle;
  		node_rx->hdr.type = NODE_RX_TYPE_CONNECTION;
  
  		/* prepare connection complete structure */
  		radio_le_conn_cmplt = (void *)node_rx->pdu_data;
  		radio_le_conn_cmplt->status = 0x00;
  		radio_le_conn_cmplt->role = 0x01;
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		radio_le_conn_cmplt->own_addr_type = pdu_adv->rx_addr;
  		memcpy(&radio_le_conn_cmplt->own_addr[0],
  		       &pdu_adv->connect_ind.adv_addr[0], BDADDR_SIZE);
  		if (irkmatch_ok && rl_idx != FILTER_IDX_NONE) {
  			/* TODO: store rl_idx instead if safe */
  			/* Store identity address */
  			ll_rl_id_addr_get(rl_idx,
  					  &radio_le_conn_cmplt->peer_addr_type,
  					  &radio_le_conn_cmplt->peer_addr[0]);
  			/* Mark it as identity address from RPA (0x02, 0x03) */
  			radio_le_conn_cmplt->peer_addr_type += 2;
  
  			/* Store peer RPA */
  			memcpy(&radio_le_conn_cmplt->peer_rpa[0],
  			       &pdu_adv->connect_ind.init_addr[0],
  			       BDADDR_SIZE);
  		} else {
  			memset(&radio_le_conn_cmplt->peer_rpa[0], 0x0,
  			       BDADDR_SIZE);
  #else
  		if (1) {
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  			radio_le_conn_cmplt->peer_addr_type = pdu_adv->tx_addr;
  			memcpy(&radio_le_conn_cmplt->peer_addr[0],
  			       &pdu_adv->connect_ind.init_addr[0],
  			       BDADDR_SIZE);
  		}
  
  		radio_le_conn_cmplt->interval =
  			pdu_adv->connect_ind.interval;
  		radio_le_conn_cmplt->latency =
  			pdu_adv->connect_ind.latency;
  		radio_le_conn_cmplt->timeout =
  			pdu_adv->connect_ind.timeout;
  		radio_le_conn_cmplt->mca =
  			pdu_adv->connect_ind.sca;
  
  		/* enqueue connection complete structure into queue */
  		rx_fc_lock(conn->handle);
  		packet_rx_enqueue();
  
  		/* Use Channel Selection Algorithm #2 if peer too supports it */
  		if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
  			struct radio_le_chan_sel_algo *le_chan_sel_algo;
  
  			/* Generate LE Channel Selection Algorithm event */
  			node_rx = packet_rx_reserve_get(3);
  			LL_ASSERT(node_rx);
  
  			node_rx->hdr.handle = conn->handle;
  			node_rx->hdr.type = NODE_RX_TYPE_CHAN_SEL_ALGO;
  
  			le_chan_sel_algo = (void *)node_rx->pdu_data;
  
  			if (pdu_adv->chan_sel) {
  				u16_t aa_ls =
  					((u16_t)conn->access_addr[1] << 8) |
  					conn->access_addr[0];
  				u16_t aa_ms =
  					((u16_t)conn->access_addr[3] << 8) |
  					 conn->access_addr[2];
  
  				conn->data_chan_sel = 1;
  				conn->data_chan_id = aa_ms ^ aa_ls;
  
  				le_chan_sel_algo->chan_sel_algo = 0x01;
  			} else {
  				le_chan_sel_algo->chan_sel_algo = 0x00;
  			}
  
  			packet_rx_enqueue();
  		}
  
  		/* calculate the window widening */
  		conn->slave.sca = pdu_adv->connect_ind.sca;
  		conn->slave.window_widening_periodic_us =
  			(((gc_lookup_ppm[_radio.sca] +
  			   gc_lookup_ppm[conn->slave.sca]) *
  			  conn_interval_us) + (1000000 - 1)) / 1000000;
  		conn->slave.window_widening_max_us =
  			(conn_interval_us >> 1) - RADIO_TIFS;
  		conn->slave.window_size_event_us =
  			pdu_adv->connect_ind.win_size * 1250;
  		conn->slave.window_size_prepare_us = 0;
  
  		rx_ready_delay = radio_rx_ready_delay_get(0, 0);
  
  		/* calculate slave slot */
  		conn->hdr.ticks_slot =
  			HAL_TICKER_US_TO_TICKS(RADIO_TICKER_START_PART_US +
  					       rx_ready_delay + 328 +
  					       RADIO_TIFS + 328);
  		conn->hdr.ticks_active_to_start = _radio.ticks_active_to_start;
  		conn->hdr.ticks_xtal_to_start =
  			HAL_TICKER_US_TO_TICKS(RADIO_TICKER_XTAL_OFFSET_US);
  		conn->hdr.ticks_preempt_to_start =
  			HAL_TICKER_US_TO_TICKS(RADIO_TICKER_PREEMPT_PART_MIN_US);
  		ticks_slot_offset = MAX(conn->hdr.ticks_active_to_start,
  					conn->hdr.ticks_xtal_to_start);
  		conn_interval_us -=
  			conn->slave.window_widening_periodic_us;
  
  		conn_offset_us = radio_tmr_end_get();
  		conn_offset_us +=
  			((u64_t)pdu_adv->connect_ind.win_offset +
  			 1) * 1250;
  		conn_offset_us -= radio_tx_chain_delay_get(0, 0);
  		conn_offset_us -= rx_ready_delay;
  		conn_offset_us -= RADIO_TICKER_JITTER_US << 1;
  		conn_offset_us -= RADIO_TICKER_JITTER_US;
  
  #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		/* disable ticker job, in order to chain stop and start
  		 * to avoid RTC being stopped if no tickers active.
  		 */
  		u32_t mayfly_was_enabled =
  			mayfly_is_enabled(RADIO_TICKER_USER_ID_WORKER,
  					  RADIO_TICKER_USER_ID_JOB);
  		mayfly_enable(RADIO_TICKER_USER_ID_WORKER,
  			      RADIO_TICKER_USER_ID_JOB, 0);
  #endif
  
  		/* Stop Advertiser */
  		ticker_status = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  					    RADIO_TICKER_USER_ID_WORKER,
  					    RADIO_TICKER_ID_ADV,
  					    ticker_stop_adv_assert,
  					    (void *)__LINE__);
  		ticker_stop_adv_assert(ticker_status, (void *)__LINE__);
  
  		/* Stop Direct Adv Stopper */
  		if (_pdu_adv->type == PDU_ADV_TYPE_DIRECT_IND) {
  			/* Advertiser stop can expire while here in this ISR.
  			 * Deferred attempt to stop can fail as it would have
  			 * expired, hence ignore failure.
  			 */
  			ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  				    RADIO_TICKER_USER_ID_WORKER,
  				    RADIO_TICKER_ID_ADV_STOP, NULL, NULL);
  		}
  
  		/* Start Slave */
  		ticker_status = ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  		     RADIO_TICKER_USER_ID_WORKER,
  		     RADIO_TICKER_ID_FIRST_CONNECTION + conn->handle,
  		     (_radio.ticks_anchor - ticks_slot_offset),
  		     HAL_TICKER_US_TO_TICKS(conn_offset_us),
  		     HAL_TICKER_US_TO_TICKS(conn_interval_us),
  		     HAL_TICKER_REMAINDER(conn_interval_us), TICKER_NULL_LAZY,
  		     (ticks_slot_offset + conn->hdr.ticks_slot),
  		     event_slave_prepare, conn, ticker_success_assert,
  		     (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  
  #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		/* enable ticker job, if disabled in this function */
  		if (mayfly_was_enabled) {
  			mayfly_enable(RADIO_TICKER_USER_ID_WORKER,
  				      RADIO_TICKER_USER_ID_JOB, 1);
  		}
  #endif
  
  		return 0;
  #endif /* CONFIG_BT_PERIPHERAL */
  	}
  
  	return 1;
  }
  
  static u32_t isr_rx_scan_report(u8_t rssi_ready, u8_t rl_idx, bool dir_report)
  {
  	struct radio_pdu_node_rx *node_rx;
  	struct pdu_adv *pdu_adv_rx;
  	u8_t *extra;
  
  	node_rx = packet_rx_reserve_get(3);
  	if (node_rx == 0) {
  		return 1;
  	}
  
  	/* Prepare the report (adv or scan resp) */
  	node_rx->hdr.handle = 0xffff;
  	if (0) {
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	} else if (_radio.advertiser.is_enabled &&
  		   _radio.advertiser.is_mesh) {
  		node_rx->hdr.type = NODE_RX_TYPE_MESH_REPORT;
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  	} else if (_radio.scanner.phy) {
  		switch (_radio.scanner.phy) {
  		case BIT(0):
  			node_rx->hdr.type = NODE_RX_TYPE_EXT_1M_REPORT;
  			break;
  
  		case BIT(2):
  			node_rx->hdr.type = NODE_RX_TYPE_EXT_CODED_REPORT;
  			break;
  
  		default:
  			LL_ASSERT(0);
  			break;
  		}
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  	} else {
  #if defined(CONFIG_BT_OBSERVER)
  		node_rx->hdr.type = NODE_RX_TYPE_REPORT;
  #endif /* CONFIG_BT_OBSERVER */
  	}
  
  	pdu_adv_rx = (void *)node_rx->pdu_data;
  	extra = &((u8_t *)pdu_adv_rx)[offsetof(struct pdu_adv, payload) +
  				      pdu_adv_rx->len];
  	/* save the RSSI value */
  	*extra = (rssi_ready) ? (radio_rssi_get() & 0x7f) : 0x7f;
  	extra += PDU_AC_SIZE_RSSI;
  
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	/* save the resolving list index. */
  	*extra = rl_idx;
  	extra += PDU_AC_SIZE_PRIV;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
  	/* save the directed adv report flag */
  	*extra = dir_report ? 1 : 0;
  	extra += PDU_AC_SIZE_SCFP;
  #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	if (node_rx->hdr.type == NODE_RX_TYPE_MESH_REPORT) {
  		/* save the directed adv report flag */
  		*extra = _radio.scanner.chan - 1;
  		extra++;
  		sys_put_le32(_radio.ticks_anchor, extra);
  	}
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  	packet_rx_enqueue();
  
  	return 0;
  }
  
  static inline bool isr_rx_scan_check(u8_t irkmatch_ok, u8_t devmatch_ok,
  				     u8_t rl_idx)
  {
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	return (((_radio.scanner.filter_policy & 0x01) == 0) &&
  		 (!devmatch_ok || ctrl_rl_idx_allowed(irkmatch_ok, rl_idx))) ||
  		(((_radio.scanner.filter_policy & 0x01) != 0) &&
  		 (devmatch_ok || ctrl_irk_whitelisted(rl_idx)));
  #else
  	return ((_radio.scanner.filter_policy & 0x01) == 0) ||
  		devmatch_ok;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  }
  
  static inline bool isr_scan_rsp_adva_matches(struct pdu_adv *srsp)
  {
  	struct pdu_adv *sreq = (void *)radio_pkt_scratch_get();
  
  	return ((sreq->rx_addr == srsp->tx_addr) &&
  		(memcmp(&sreq->scan_req.adv_addr[0],
  			&srsp->scan_rsp.addr[0], BDADDR_SIZE) == 0));
  }
  
  static inline bool isr_scan_init_adva_check(struct pdu_adv *pdu,
  					    u8_t rl_idx)
  {
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	/* Only applies to initiator with no whitelist */
  	if (rl_idx != FILTER_IDX_NONE) {
  		return (rl_idx == _radio.scanner.rl_idx);
  	}
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  	return ((_radio.scanner.adv_addr_type == pdu->tx_addr) &&
  		(memcmp(&_radio.scanner.adv_addr[0],
  			&pdu->adv_ind.addr[0], BDADDR_SIZE) == 0));
  }
  
  static inline bool isr_scan_tgta_rpa_check(struct pdu_adv *pdu,
  					   bool *dir_report)
  {
  	if (((_radio.scanner.filter_policy & 0x02) != 0) &&
  	    (pdu->rx_addr != 0) &&
  	    ((pdu->direct_ind.tgt_addr[5] & 0xc0) == 0x40)) {
  
  		if (dir_report) {
  			*dir_report = true;
  		}
  
  		return true;
  	}
  
  	return false;
  }
  
  static inline bool isr_scan_tgta_check(bool init, struct pdu_adv *pdu,
  				       u8_t rl_idx, bool *dir_report)
  {
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	if (ctrl_rl_addr_resolve(pdu->rx_addr,
  				 pdu->direct_ind.tgt_addr, rl_idx)) {
  		return true;
  	} else if (init && _radio.scanner.rpa_gen && ctrl_lrpa_get(rl_idx)) {
  		/* Initiator generating RPAs, and could not resolve TargetA:
  		 * discard
  		 */
  		return false;
  	}
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  	return (((_radio.scanner.init_addr_type == pdu->rx_addr) &&
  		(memcmp(&_radio.scanner.init_addr[0],
  			&pdu->direct_ind.tgt_addr[0],
  			BDADDR_SIZE) == 0))) ||
  		  /* allow directed adv packets where TargetA address
  		   * is resolvable private address (scanner only)
  		   */
  	       isr_scan_tgta_rpa_check(pdu, dir_report);
  }
  
  static inline bool isr_scan_init_check(struct pdu_adv *pdu, u8_t rl_idx)
  {
  	return ((((_radio.scanner.filter_policy & 0x01) != 0) ||
  		isr_scan_init_adva_check(pdu, rl_idx)) &&
  		(((pdu->type == PDU_ADV_TYPE_ADV_IND) &&
  		  (pdu->len <= sizeof(struct pdu_adv_adv_ind))) ||
  		 ((pdu->type == PDU_ADV_TYPE_DIRECT_IND) &&
  		  (pdu->len == sizeof(struct pdu_adv_direct_ind)) &&
  		  (/* allow directed adv packets addressed to this device */
  		   isr_scan_tgta_check(true, pdu, rl_idx, NULL)))));
  }
  
  static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id,
  				u8_t irkmatch_ok, u8_t irkmatch_id, u8_t rl_idx,
  				u8_t rssi_ready)
  {
  	struct pdu_adv *pdu_adv_rx;
  	/* Directed Adverising Report */
  	bool dir_report = false;
  
  	pdu_adv_rx = (void *)_radio.packet_rx[_radio.packet_rx_last]->pdu_data;
  
  	if (0) {
  
  #if defined(CONFIG_BT_CENTRAL)
  	} else
  	/* Initiator */
  	if ((_radio.scanner.conn) && ((_radio.fc_ena == 0) ||
  				      (_radio.fc_req == _radio.fc_ack)) &&
  	    isr_scan_init_check(pdu_adv_rx, rl_idx) &&
  	    ((radio_tmr_end_get() + 502 + (RADIO_TICKER_JITTER_US << 1)) <
  	     (HAL_TICKER_TICKS_TO_US(_radio.scanner.hdr.ticks_slot) -
  	      RADIO_TICKER_START_PART_US))) {
  		struct radio_le_conn_cmplt *radio_le_conn_cmplt;
  		struct radio_pdu_node_rx *node_rx;
  		struct pdu_adv *pdu_adv_tx;
  		u8_t pdu_adv_rx_chan_sel;
  		struct connection *conn;
  		u32_t ticks_slot_offset;
  		u32_t conn_interval_us;
  		u32_t conn_offset_us;
  		u32_t ticker_status;
  		u32_t conn_space_us;
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		bt_addr_t *lrpa;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  		if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
  			node_rx = packet_rx_reserve_get(4);
  		} else {
  			node_rx = packet_rx_reserve_get(3);
  		}
  
  		if (node_rx == 0) {
  			return 1;
  		}
  
  		_radio.state = STATE_STOP;
  
  		/* acquire the master context from scanner */
  		conn = _radio.scanner.conn;
  		_radio.scanner.conn = NULL;
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  		conn->rssi_latest = (rssi_ready) ? (radio_rssi_get() & 0x7f) :
  						   0x7f;
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  		/* Tx the connect request packet */
  		pdu_adv_tx = (void *)radio_pkt_scratch_get();
  		pdu_adv_tx->type = PDU_ADV_TYPE_CONNECT_IND;
  
  		if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
  			pdu_adv_tx->chan_sel = 1;
  
  			/* backup, as Rx-ed buffer is used to enqueue
  			 * connection message.
  			 */
  			pdu_adv_rx_chan_sel = pdu_adv_rx->chan_sel;
  		} else {
  			pdu_adv_tx->chan_sel = 0;
  		}
  
  		pdu_adv_tx->rx_addr = pdu_adv_rx->tx_addr;
  		pdu_adv_tx->len = sizeof(struct pdu_adv_connect_ind);
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		lrpa = ctrl_lrpa_get(rl_idx);
  		if (_radio.scanner.rpa_gen && lrpa) {
  			pdu_adv_tx->tx_addr = 1;
  			memcpy(&pdu_adv_tx->connect_ind.init_addr[0],
  			       lrpa->val, BDADDR_SIZE);
  		} else {
  #else
  		if (1) {
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  			pdu_adv_tx->tx_addr = _radio.scanner.init_addr_type;
  			memcpy(&pdu_adv_tx->connect_ind.init_addr[0],
  			       &_radio.scanner.init_addr[0], BDADDR_SIZE);
  		}
  		memcpy(&pdu_adv_tx->connect_ind.adv_addr[0],
  			 &pdu_adv_rx->adv_ind.addr[0], BDADDR_SIZE);
  		memcpy(&pdu_adv_tx->connect_ind.
  		       access_addr[0], &conn->access_addr[0], 4);
  		memcpy(&pdu_adv_tx->connect_ind.crc_init[0],
  		       &conn->crc_init[0], 3);
  		pdu_adv_tx->connect_ind.win_size = 1;
  
  		conn_interval_us =
  			(u32_t)_radio.scanner.conn_interval * 1250;
  
  		conn_offset_us = radio_tmr_end_get() + 502 + 1250;
  
  		/* The ticker module generates the timeout callbacks with a
  		 * +/- half the 32KHz clock resolution. In order to achieve
  		 * a microsecond resolution, in the case of negative remainder,
  		 * the radio packet timer is started one 32KHz tick early,
  		 * hence subtract one tick unit from the measurement of the
  		 * packet end.
  		 */
  		if (!_radio.remainder_anchor ||
  		    (_radio.remainder_anchor & BIT(31))) {
  			conn_offset_us -= HAL_TICKER_TICKS_TO_US(1);
  		}
  
  		if (_radio.scanner.win_offset_us == 0) {
  			conn_space_us = conn_offset_us;
  			pdu_adv_tx->connect_ind.win_offset = 0;
  		} else {
  			conn_space_us = _radio.scanner.win_offset_us;
  			while ((conn_space_us & ((u32_t)1 << 31)) ||
  			       (conn_space_us < conn_offset_us)) {
  				conn_space_us += conn_interval_us;
  			}
  			pdu_adv_tx->connect_ind.win_offset =
  				(conn_space_us - conn_offset_us) / 1250;
  			pdu_adv_tx->connect_ind.win_size++;
  		}
  
  		conn_space_us -= radio_tx_ready_delay_get(0, 0);
  		conn_space_us -= radio_tx_chain_delay_get(0, 0);
  
  		/* Workaround: Due to the missing remainder param in
  		 * ticker_start function for first interval; add a
  		 * tick so as to use the ceiled value.
  		 */
  		conn_space_us += HAL_TICKER_TICKS_TO_US(1);
  
  		pdu_adv_tx->connect_ind.interval =
  			_radio.scanner.conn_interval;
  		pdu_adv_tx->connect_ind.latency =
  			_radio.scanner.conn_latency;
  		pdu_adv_tx->connect_ind.timeout =
  			_radio.scanner.conn_timeout;
  		memcpy(&pdu_adv_tx->connect_ind.chan_map[0],
  		       &conn->data_chan_map[0],
  		       sizeof(pdu_adv_tx->connect_ind.chan_map));
  		pdu_adv_tx->connect_ind.hop =
  			conn->data_chan_hop;
  		pdu_adv_tx->connect_ind.sca = _radio.sca;
  
  		radio_switch_complete_and_disable();
  
  		radio_pkt_tx_set(pdu_adv_tx);
  
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  		radio_gpio_pa_setup();
  		radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
  					 RADIO_TIFS -
  					 radio_rx_chain_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #endif /* CONFIG_BT_CTLR_GPIO_PA_PIN */
  
  		/* assert if radio packet ptr is not set and radio started tx */
  		LL_ASSERT(!radio_is_ready());
  
  		/* block CPU so that there is no CRC error on pdu tx,
  		 * this is only needed if we want the CPU to sleep.
  		 * while(!radio_has_disabled())
  		 * {cpu_sleep();}
  		 * radio_status_reset();
  		 */
  
  		/* Populate the master context */
  		conn->handle = mem_index_get(conn, _radio.conn_pool,
  					     CONNECTION_T_SIZE);
  
  		/* Prepare the rx packet structure */
  		node_rx->hdr.handle = conn->handle;
  		node_rx->hdr.type = NODE_RX_TYPE_CONNECTION;
  
  		/* prepare connection complete structure */
  		radio_le_conn_cmplt = (void *)node_rx->pdu_data;
  		radio_le_conn_cmplt->status = 0x00;
  		radio_le_conn_cmplt->role = 0x00;
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		radio_le_conn_cmplt->own_addr_type = pdu_adv_tx->tx_addr;
  		memcpy(&radio_le_conn_cmplt->own_addr[0],
  		       &pdu_adv_tx->connect_ind.init_addr[0],
  		       BDADDR_SIZE);
  
  		if (irkmatch_ok && rl_idx != FILTER_IDX_NONE) {
  			/* TODO: store rl_idx instead if safe */
  			/* Store identity address */
  			ll_rl_id_addr_get(rl_idx,
  					  &radio_le_conn_cmplt->peer_addr_type,
  					  &radio_le_conn_cmplt->peer_addr[0]);
  			/* Mark it as identity address from RPA (0x02, 0x03) */
  			radio_le_conn_cmplt->peer_addr_type += 2;
  
  			/* Store peer RPA */
  			memcpy(&radio_le_conn_cmplt->peer_rpa[0],
  			       &pdu_adv_tx->connect_ind.adv_addr[0],
  			       BDADDR_SIZE);
  		} else {
  			memset(&radio_le_conn_cmplt->peer_rpa[0], 0x0,
  			       BDADDR_SIZE);
  #else
  		if (1) {
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  			radio_le_conn_cmplt->peer_addr_type =
  				pdu_adv_tx->rx_addr;
  			memcpy(&radio_le_conn_cmplt->peer_addr[0],
  			       &pdu_adv_tx->connect_ind.adv_addr[0],
  			       BDADDR_SIZE);
  		}
  
  		radio_le_conn_cmplt->interval = _radio.scanner.conn_interval;
  		radio_le_conn_cmplt->latency = _radio.scanner.conn_latency;
  		radio_le_conn_cmplt->timeout = _radio.scanner.conn_timeout;
  		radio_le_conn_cmplt->mca =
  			pdu_adv_tx->connect_ind.sca;
  
  		/* enqueue connection complete structure into queue */
  		rx_fc_lock(conn->handle);
  		packet_rx_enqueue();
  
  		/* Use Channel Selection Algorithm #2 if peer too supports it */
  		if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
  			struct radio_le_chan_sel_algo *le_chan_sel_algo;
  
  			/* Generate LE Channel Selection Algorithm event */
  			node_rx = packet_rx_reserve_get(3);
  			LL_ASSERT(node_rx);
  
  			node_rx->hdr.handle = conn->handle;
  			node_rx->hdr.type = NODE_RX_TYPE_CHAN_SEL_ALGO;
  
  			le_chan_sel_algo = (void *)node_rx->pdu_data;
  
  			if (pdu_adv_rx_chan_sel) {
  				u16_t aa_ls =
  					((u16_t)conn->access_addr[1] << 8) |
  					conn->access_addr[0];
  				u16_t aa_ms =
  					((u16_t)conn->access_addr[3] << 8) |
  					 conn->access_addr[2];
  
  				conn->data_chan_sel = 1;
  				conn->data_chan_id = aa_ms ^ aa_ls;
  
  				le_chan_sel_algo->chan_sel_algo = 0x01;
  			} else {
  				le_chan_sel_algo->chan_sel_algo = 0x00;
  			}
  
  			packet_rx_enqueue();
  		}
  
  		/* Calculate master slot */
  		conn->hdr.ticks_active_to_start = _radio.ticks_active_to_start;
  		conn->hdr.ticks_xtal_to_start =	HAL_TICKER_US_TO_TICKS(
  			RADIO_TICKER_XTAL_OFFSET_US);
  		conn->hdr.ticks_preempt_to_start = HAL_TICKER_US_TO_TICKS(
  			RADIO_TICKER_PREEMPT_PART_MIN_US);
  		conn->hdr.ticks_slot = _radio.scanner.ticks_conn_slot;
  		ticks_slot_offset = MAX(conn->hdr.ticks_active_to_start,
  					conn->hdr.ticks_xtal_to_start);
  
  #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		/* disable ticker job, in order to chain stop and start
  		 * to avoid RTC being stopped if no tickers active.
  		 */
  		u32_t mayfly_was_enabled =
  			mayfly_is_enabled(RADIO_TICKER_USER_ID_WORKER,
  					  RADIO_TICKER_USER_ID_JOB);
  		mayfly_enable(RADIO_TICKER_USER_ID_WORKER,
  			      RADIO_TICKER_USER_ID_JOB, 0);
  #endif
  
  		/* Stop Scanner */
  		ticker_status = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  					    RADIO_TICKER_USER_ID_WORKER,
  					    RADIO_TICKER_ID_SCAN,
  					    ticker_stop_scan_assert,
  					    (void *)__LINE__);
  		ticker_stop_scan_assert(ticker_status, (void *)__LINE__);
  
  		/* Scanner stop can expire while here in this ISR.
  		 * Deferred attempt to stop can fail as it would have
  		 * expired, hence ignore failure.
  		 */
  		ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  			    RADIO_TICKER_USER_ID_WORKER,
  			    RADIO_TICKER_ID_SCAN_STOP, NULL, NULL);
  
  		/* Start master */
  		ticker_status =
  			ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				     RADIO_TICKER_USER_ID_WORKER,
  				     RADIO_TICKER_ID_FIRST_CONNECTION +
  				     conn->handle,
  				     (_radio.ticks_anchor - ticks_slot_offset),
  				     HAL_TICKER_US_TO_TICKS(conn_space_us),
  				     HAL_TICKER_US_TO_TICKS(conn_interval_us),
  				     HAL_TICKER_REMAINDER(conn_interval_us),
  				     TICKER_NULL_LAZY,
  				     (ticks_slot_offset + conn->hdr.ticks_slot),
  				     event_master_prepare, conn,
  				     ticker_success_assert, (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  
  #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		/* enable ticker job, if disabled in this function */
  		if (mayfly_was_enabled) {
  			mayfly_enable(RADIO_TICKER_USER_ID_WORKER,
  				      RADIO_TICKER_USER_ID_JOB, 1);
  		}
  #endif
  
  		return 0;
  #endif /* CONFIG_BT_CENTRAL */
  	}
  
  	/* Active scanner */
  	else if (((pdu_adv_rx->type == PDU_ADV_TYPE_ADV_IND) ||
  		  (pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_IND)) &&
  		 (pdu_adv_rx->len <= sizeof(struct pdu_adv_adv_ind)) &&
  		 (_radio.scanner.type != 0) &&
  		 (_radio.scanner.conn == 0)) {
  		struct pdu_adv *pdu_adv_tx;
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		bt_addr_t *lrpa;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  		u32_t err;
  
  		/* save the adv packet */
  		err = isr_rx_scan_report(rssi_ready,
  					 irkmatch_ok ? rl_idx :
  						       FILTER_IDX_NONE,
  					 false);
  		if (err) {
  			return err;
  		}
  
  		/* prepare the scan request packet */
  		pdu_adv_tx = (void *)radio_pkt_scratch_get();
  		pdu_adv_tx->type = PDU_ADV_TYPE_SCAN_REQ;
  		pdu_adv_tx->rx_addr = pdu_adv_rx->tx_addr;
  		pdu_adv_tx->len = sizeof(struct pdu_adv_scan_req);
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		lrpa = ctrl_lrpa_get(rl_idx);
  		if (_radio.scanner.rpa_gen && lrpa) {
  			pdu_adv_tx->tx_addr = 1;
  			memcpy(&pdu_adv_tx->scan_req.scan_addr[0],
  			       lrpa->val, BDADDR_SIZE);
  		} else {
  #else
  		if (1) {
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  			pdu_adv_tx->tx_addr = _radio.scanner.init_addr_type;
  			memcpy(&pdu_adv_tx->scan_req.scan_addr[0],
  			       &_radio.scanner.init_addr[0], BDADDR_SIZE);
  		}
  		memcpy(&pdu_adv_tx->scan_req.adv_addr[0],
  		       &pdu_adv_rx->adv_ind.addr[0], BDADDR_SIZE);
  
  		/* switch scanner state to active */
  		_radio.scanner.state = 1;
  		_radio.state = STATE_TX;
  
  		radio_tmr_tifs_set(RADIO_TIFS);
  		radio_switch_complete_and_rx(0);
  		radio_pkt_tx_set(pdu_adv_tx);
  
  		/* capture end of Tx-ed PDU, used to calculate HCTO. */
  		radio_tmr_end_capture();
  
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  		radio_gpio_pa_setup();
  		radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
  					 RADIO_TIFS -
  					 radio_rx_chain_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #endif /* CONFIG_BT_CTLR_GPIO_PA_PIN */
  
  		/* assert if radio packet ptr is not set and radio started tx */
  		LL_ASSERT(!radio_is_ready());
  
  		return 0;
  	}
  	/* Passive scanner or scan responses */
  	else if (((((pdu_adv_rx->type == PDU_ADV_TYPE_ADV_IND) ||
  		    (pdu_adv_rx->type == PDU_ADV_TYPE_NONCONN_IND) ||
  		    (pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_IND)) &&
  		   (pdu_adv_rx->len <= sizeof(struct pdu_adv_adv_ind))) ||
  		  ((pdu_adv_rx->type == PDU_ADV_TYPE_DIRECT_IND) &&
  		   (pdu_adv_rx->len == sizeof(struct pdu_adv_direct_ind)) &&
  		   (/* allow directed adv packets addressed to this device */
  		    isr_scan_tgta_check(false, pdu_adv_rx, rl_idx,
  					&dir_report))) ||
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  		  ((pdu_adv_rx->type == PDU_ADV_TYPE_EXT_IND) &&
  		   (_radio.scanner.phy)) ||
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  		  ((pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_RSP) &&
  		   (pdu_adv_rx->len <= sizeof(struct pdu_adv_scan_rsp)) &&
  		   (_radio.scanner.state != 0) &&
  		   isr_scan_rsp_adva_matches(pdu_adv_rx))) &&
  		 (pdu_adv_rx->len != 0) && (!_radio.scanner.conn)) {
  		u32_t err;
  
  		/* save the scan response packet */
  		err = isr_rx_scan_report(rssi_ready,
  					 irkmatch_ok ? rl_idx :
  						       FILTER_IDX_NONE,
  					 dir_report);
  		if (err) {
  			return err;
  		}
  	}
  	/* invalid PDU */
  	else {
  		/* ignore and close this rx/tx chain ( code below ) */
  		return 1;
  	}
  
  	return 1;
  }
  
  #if defined(CONFIG_BT_CONN)
  #if defined(CONFIG_BT_CTLR_PHY)
  static inline void isr_rx_conn_phy_tx_time_set(void)
  {
  	/* select the probable PHY with longest Tx time, which will be
  	 * restricted to fit current connEffectiveMaxTxTime.
  	 */
  	u8_t phy_tx_time[8] = {BIT(0), BIT(0), BIT(1), BIT(0),
  			       BIT(2), BIT(2), BIT(2), BIT(2)};
  	struct connection *conn = _radio.conn_curr;
  	u8_t phys = conn->llcp_phy.tx | conn->phy_tx;
  
  	conn->phy_tx_time = phy_tx_time[phys];
  }
  #endif /* CONFIG_BT_CTLR_PHY */
  
  #define ERR_TERMINATE 1
  #define ERR_TX_NACK 2
  
  static inline u32_t isr_rx_conn_pkt_ack(struct pdu_data *pdu_data_tx,
  				       struct radio_pdu_node_tx **node_tx)
  {
  	u32_t ret = 0U;
  
  	switch (pdu_data_tx->llctrl.opcode) {
  	case PDU_DATA_LLCTRL_TYPE_TERMINATE_IND:
  		_radio.state = STATE_CLOSE;
  		radio_disable();
  
  		/* assert if radio packet ptr is not set and radio started tx */
  		LL_ASSERT(!radio_is_ready());
  
  		terminate_ind_rx_enqueue(_radio.conn_curr,
  		     (pdu_data_tx->llctrl.terminate_ind.error_code ==
  		      BT_HCI_ERR_REMOTE_USER_TERM_CONN) ?
  		     BT_HCI_ERR_LOCALHOST_TERM_CONN :
  		     pdu_data_tx->llctrl.terminate_ind.error_code);
  
  		/* Ack received, hence terminate */
  		ret = ERR_TERMINATE;
  		break;
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  	case PDU_DATA_LLCTRL_TYPE_ENC_REQ:
  		/* things from master stored for session key calculation */
  		memcpy(&_radio.conn_curr->llcp.encryption.skd[0],
  		       &pdu_data_tx->llctrl.enc_req.skdm[0], 8);
  		memcpy(&_radio.conn_curr->ccm_rx.iv[0],
  		       &pdu_data_tx->llctrl.enc_req.ivm[0], 4);
  
  		/* pause data packet tx */
  		_radio.conn_curr->pause_tx = 1U;
  
  		/* Start Procedure Timeout (this will not replace terminate
  		 * procedure which always gets place before any packets
  		 * going out, hence safe by design).
  		 */
  		_radio.conn_curr->procedure_expire =
  			_radio.conn_curr->procedure_reload;
  
  		/* Reset enc req queued state */
  		_radio.conn_curr->llcp_enc.ack = _radio.conn_curr->llcp_enc.req;
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_ENC_RSP:
  		/* pause data packet tx */
  		_radio.conn_curr->pause_tx = 1U;
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_START_ENC_REQ:
  		/* Nothing to do.
  		 * Remember that we may have received encrypted START_ENC_RSP
  		 * alongwith this tx ack at this point in time.
  		 */
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ:
  		/* pause data packet tx */
  		_radio.conn_curr->pause_tx = 1U;
  
  		/* key refresh */
  		_radio.conn_curr->refresh = 1U;
  
  		/* Start Procedure Timeout (this will not replace terminate
  		 * procedure which always gets place before any packets
  		 * going out, hence safe by design).
  		 */
  		_radio.conn_curr->procedure_expire =
  			_radio.conn_curr->procedure_reload;
  
  		/* Reset enc req queued state */
  		_radio.conn_curr->llcp_enc.ack = _radio.conn_curr->llcp_enc.req;
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP:
  		if (_radio.role == ROLE_MASTER) {
  			/* reused tx-ed PDU and send enc req */
  			enc_req_reused_send(_radio.conn_curr, *node_tx);
  
  			/* dont release ctrl PDU memory */
  			*node_tx = NULL;
  		} else {
  			/* pause data packet tx */
  			_radio.conn_curr->pause_tx = 1U;
  		}
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND:
  		if (pdu_data_tx->llctrl.reject_ext_ind.reject_opcode !=
  		    PDU_DATA_LLCTRL_TYPE_ENC_REQ) {
  			break;
  		}
  		/* Pass through */
  
  	case PDU_DATA_LLCTRL_TYPE_REJECT_IND:
  		/* resume data packet rx and tx */
  		_radio.conn_curr->pause_rx = 0U;
  		_radio.conn_curr->pause_tx = 0U;
  
  		/* Procedure complete */
  		_radio.conn_curr->procedure_expire = 0U;
  		break;
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	case PDU_DATA_LLCTRL_TYPE_LENGTH_REQ:
  		/* wait for response */
  		_radio.conn_curr->llcp_length.state =
  			LLCP_LENGTH_STATE_RSP_WAIT;
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_LENGTH_RSP:
  		if (_radio.conn_curr->llcp_length.req !=
  		    _radio.conn_curr->llcp_length.ack) {
  			struct connection *conn = _radio.conn_curr;
  
  			switch (conn->llcp_length.state) {
  			case LLCP_LENGTH_STATE_RSP_ACK_WAIT:
  			case LLCP_LENGTH_STATE_RESIZE_RSP:
  			case LLCP_LENGTH_STATE_RESIZE_RSP_ACK_WAIT:
  				/* accept the effective tx */
  				conn->max_tx_octets =
  					conn->llcp_length.tx_octets;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  				/* accept the effective tx time */
  				conn->max_tx_time = conn->llcp_length.tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  				if (conn->llcp_length.state ==
  				    LLCP_LENGTH_STATE_RESIZE_RSP) {
  					conn->llcp_length.state =
  						LLCP_LENGTH_STATE_RESIZE;
  
  					break;
  				}
  
  				/* check cache */
  				if (!conn->llcp_length.cache.tx_octets) {
  					/* Procedure complete */
  					conn->llcp_length.ack =
  						conn->llcp_length.req;
  					conn->procedure_expire = 0U;
  
  					break;
  				}
  
  				/* Initiate cached procedure */
  				conn->llcp_length.tx_octets =
  					conn->llcp_length.cache.tx_octets;
  				conn->llcp_length.cache.tx_octets = 0;
  #if defined(CONFIG_BT_CTLR_PHY)
  				conn->llcp_length.tx_time =
  					conn->llcp_length.cache.tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  				conn->llcp_length.state = LLCP_LENGTH_STATE_REQ;
  
  				break;
  
  			default:
  				break;
  			}
  		}
  		break;
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	case PDU_DATA_LLCTRL_TYPE_PHY_REQ:
  		_radio.conn_curr->llcp_phy.state = LLCP_PHY_STATE_RSP_WAIT;
  		/* fall through */
  
  	case PDU_DATA_LLCTRL_TYPE_PHY_RSP:
  		if (_radio.role == ROLE_SLAVE) {
  			isr_rx_conn_phy_tx_time_set();
  		}
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND:
  		_radio.conn_curr->phy_tx_time =
  			_radio.conn_curr->llcp.phy_upd_ind.tx;
  		break;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  	default:
  		/* Do nothing for other ctrl packet ack */
  		break;
  	}
  
  	return ret;
  }
  
  static inline struct radio_pdu_node_tx *
  isr_rx_conn_pkt_release(struct radio_pdu_node_tx *node_tx)
  {
  	struct connection *conn = _radio.conn_curr;
  
  	conn->packet_tx_head_len = 0U;
  	conn->packet_tx_head_offset = 0U;
  
  	/* release */
  	if (conn->pkt_tx_head == conn->pkt_tx_ctrl) {
  		if (node_tx) {
  			conn->pkt_tx_head = conn->pkt_tx_head->next;
  			if (conn->pkt_tx_ctrl == conn->pkt_tx_ctrl_last) {
  				conn->pkt_tx_ctrl = NULL;
  				conn->pkt_tx_ctrl_last = NULL;
  			} else {
  				conn->pkt_tx_ctrl = conn->pkt_tx_head;
  			}
  
  			mem_release(node_tx, &_radio.pkt_tx_ctrl_free);
  		}
  	} else {
  		if (conn->pkt_tx_head == conn->pkt_tx_data) {
  			conn->pkt_tx_data = conn->pkt_tx_data->next;
  		}
  		conn->pkt_tx_head = conn->pkt_tx_head->next;
  
  		return node_tx;
  	}
  
  	return NULL;
  }
  
  static inline u32_t feat_get(u8_t *features)
  {
  	u32_t feat;
  
  	feat = ~LL_FEAT_BIT_MASK_VALID | features[0] |
  	       (features[1] << 8) | (features[2] << 16);
  	feat &= LL_FEAT_BIT_MASK;
  
  	return feat;
  }
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  static inline void
  isr_rx_conn_pkt_ctrl_rej_conn_upd(struct radio_pdu_node_rx *node_rx,
  				  u8_t *rx_enqueue)
  {
  	struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind;
  	struct radio_le_conn_update_cmplt *cp;
  	struct pdu_data *pdu_data_rx;
  	struct connection *conn;
  
  	pdu_data_rx = (void *)node_rx->pdu_data;
  	rej_ext_ind = (void *)&pdu_data_rx->llctrl.reject_ext_ind;
  	if (rej_ext_ind->reject_opcode != PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ) {
  		return;
  	}
  
  	conn = _radio.conn_curr;
  
  	/* Unsupported remote feature */
  	if (!conn->role && (rej_ext_ind->error_code ==
  			    BT_HCI_ERR_UNSUPP_REMOTE_FEATURE)) {
  		LL_ASSERT(conn->llcp_cu.req == conn->llcp_cu.ack);
  
  		conn->llcp_conn_param.state = LLCP_CPR_STATE_UPD;
  
  		conn->llcp_cu.win_size = 1U;
  		conn->llcp_cu.win_offset_us = 0U;
  		conn->llcp_cu.interval = conn->llcp_conn_param.interval_max;
  		conn->llcp_cu.latency = conn->llcp_conn_param.latency;
  		conn->llcp_cu.timeout = conn->llcp_conn_param.timeout;
  		conn->llcp_cu.state = LLCP_CUI_STATE_USE;
  		conn->llcp_cu.cmd = conn->llcp_conn_param.cmd;
  		conn->llcp_cu.ack--;
  
  		return;
  	}
  	/* FIXME: handle unsupported LL parameters error */
  	else if (rej_ext_ind->error_code != BT_HCI_ERR_LL_PROC_COLLISION) {
  		/* update to next ticks offset */
  		if (conn->role) {
  			conn->slave.ticks_to_offset =
  			    conn->llcp_conn_param.ticks_to_offset_next;
  		}
  	}
  
  	if (conn->llcp_conn_param.state == LLCP_CPR_STATE_RSP_WAIT) {
  		LL_ASSERT(_radio.conn_upd == conn);
  
  		/* reset mutex */
  		_radio.conn_upd = NULL;
  
  		/* Procedure complete */
  		conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
  
  		/* Stop procedure timeout */
  		conn->procedure_expire = 0U;
  	}
  
  	/* skip event generation if not cmd initiated */
  	if (!conn->llcp_conn_param.cmd) {
  		return;
  	}
  
  	/* generate conn update complete event with error code */
  	node_rx->hdr.type = NODE_RX_TYPE_CONN_UPDATE;
  
  	/* prepare connection update complete structure */
  	cp = (void *)pdu_data_rx;
  	cp->status = rej_ext_ind->error_code;
  	cp->interval = conn->conn_interval;
  	cp->latency = conn->latency;
  	cp->timeout = conn->supervision_reload *
  		      conn->conn_interval * 125 / 1000;
  
  	*rx_enqueue = 1U;
  }
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  static inline void
  isr_rx_conn_pkt_ctrl_rej_dle(struct radio_pdu_node_rx *node_rx,
  			     u8_t *rx_enqueue)
  {
  	struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind;
  	struct pdu_data *pdu_data_rx;
  
  	pdu_data_rx = (void *)node_rx->pdu_data;
  	rej_ext_ind = (void *)&pdu_data_rx->llctrl.reject_ext_ind;
  	if (rej_ext_ind->reject_opcode == PDU_DATA_LLCTRL_TYPE_LENGTH_REQ) {
  		struct connection *conn = _radio.conn_curr;
  		struct pdu_data_llctrl_length_req *lr;
  
  		/* Procedure complete */
  		conn->llcp_length.ack = conn->llcp_length.req;
  		conn->procedure_expire = 0U;
  
  		/* prepare length rsp structure */
  		pdu_data_rx->len = offsetof(struct pdu_data_llctrl,
  					    length_rsp) +
  				   sizeof(struct pdu_data_llctrl_length_rsp);
  		pdu_data_rx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP;
  
  		lr = (void *)&pdu_data_rx->llctrl.length_req;
  		lr->max_rx_octets = conn->max_rx_octets;
  		lr->max_tx_octets = conn->max_tx_octets;
  #if !defined(CONFIG_BT_CTLR_PHY)
  		lr->max_rx_time = RADIO_PKT_TIME(conn->max_rx_octets, 0);
  		lr->max_tx_time = RADIO_PKT_TIME(conn->max_tx_octets, 0);
  #else /* CONFIG_BT_CTLR_PHY */
  		lr->max_rx_time = conn->max_rx_time;
  		lr->max_tx_time = conn->max_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		/* enqueue a length rsp */
  		*rx_enqueue = 1U;
  	}
  }
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  static inline void
  isr_rx_conn_pkt_ctrl_rej_phy_upd(struct radio_pdu_node_rx *node_rx,
  				 u8_t *rx_enqueue)
  {
  	struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind;
  	struct pdu_data *pdu_data_rx;
  
  	pdu_data_rx = (void *)node_rx->pdu_data;
  	rej_ext_ind = (void *)&pdu_data_rx->llctrl.reject_ext_ind;
  	if (rej_ext_ind->reject_opcode == PDU_DATA_LLCTRL_TYPE_PHY_REQ) {
  		struct radio_le_phy_upd_cmplt *p;
  
  		/* Same Procedure or Different Procedure Collision */
  
  		/* If not same procedure, stop procedure timeout, else
  		 * continue timer until phy upd ind is received.
  		 */
  		if (rej_ext_ind->error_code != BT_HCI_ERR_LL_PROC_COLLISION) {
  			/* Procedure complete */
  			_radio.conn_curr->llcp_phy.ack =
  				_radio.conn_curr->llcp_phy.req;
  
  			/* Reset packet timing restrictions */
  			_radio.conn_curr->phy_tx_time =
  				_radio.conn_curr->phy_tx;
  
  			/* Stop procedure timeout */
  			_radio.conn_curr->procedure_expire = 0U;
  		}
  
  		/* skip event generation if not cmd initiated */
  		if (!_radio.conn_curr->llcp_phy.cmd) {
  			return;
  		}
  
  		/* generate phy update complete event with error code */
  		node_rx->hdr.type = NODE_RX_TYPE_PHY_UPDATE;
  
  		p = (void *)pdu_data_rx;
  		p->status = rej_ext_ind->error_code;
  		p->tx = _radio.conn_curr->phy_tx;
  		p->rx = _radio.conn_curr->phy_rx;
  
  		/* enqueue the phy update complete */
  		*rx_enqueue = 1U;
  	}
  }
  #endif /* CONFIG_BT_CTLR_PHY */
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  static inline void
  isr_rx_conn_pkt_ctrl_rej_enc(struct radio_pdu_node_rx *node_rx,
  			     u8_t *rx_enqueue)
  {
  	/* resume data packet rx and tx */
  	_radio.conn_curr->pause_rx = 0U;
  	_radio.conn_curr->pause_tx = 0U;
  
  	/* Procedure complete */
  	_radio.conn_curr->llcp_ack = _radio.conn_curr->llcp_req;
  	_radio.conn_curr->procedure_expire = 0U;
  
  	*rx_enqueue = 1U;
  }
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  static inline void
  isr_rx_conn_pkt_ctrl_rej(struct radio_pdu_node_rx *node_rx, u8_t *rx_enqueue)
  {
  	struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind;
  	struct pdu_data *pdu_rx;
  
  	pdu_rx = (void *)node_rx->pdu_data;
  	rej_ext_ind = (void *)&pdu_rx->llctrl.reject_ext_ind;
  
  	switch (rej_ext_ind->reject_opcode) {
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  	case PDU_DATA_LLCTRL_TYPE_ENC_REQ:
  		if (_radio.conn_curr->llcp_ack != _radio.conn_curr->llcp_req &&
  		    _radio.conn_curr->llcp_type == LLCP_ENCRYPTION) {
  			/* enqueue as if it were a reject ind */
  			pdu_rx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_REJECT_IND;
  			pdu_rx->llctrl.reject_ind.error_code =
  				rej_ext_ind->error_code;
  
  			isr_rx_conn_pkt_ctrl_rej_enc(node_rx, rx_enqueue);
  		}
  		break;
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	case PDU_DATA_LLCTRL_TYPE_PHY_REQ:
  		if (_radio.conn_curr->llcp_phy.ack !=
  		    _radio.conn_curr->llcp_phy.req) {
  			isr_rx_conn_pkt_ctrl_rej_phy_upd(node_rx, rx_enqueue);
  		}
  		break;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  	case PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ:
  		if (_radio.conn_curr->llcp_conn_param.ack !=
  		    _radio.conn_curr->llcp_conn_param.req) {
  			isr_rx_conn_pkt_ctrl_rej_conn_upd(node_rx, rx_enqueue);
  		}
  		break;
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	case PDU_DATA_LLCTRL_TYPE_LENGTH_REQ:
  		if (_radio.conn_curr->llcp_length.ack !=
  		    _radio.conn_curr->llcp_length.req) {
  			isr_rx_conn_pkt_ctrl_rej_dle(node_rx, rx_enqueue);
  		}
  		break;
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  	default:
  		/* Ignore */
  		break;
  	}
  }
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  static inline u8_t isr_rx_conn_pkt_ctrl_dle(struct pdu_data *pdu_data_rx,
  					    u8_t *rx_enqueue)
  {
  	struct radio_pdu_node_tx *node_tx = NULL;
  	u16_t eff_rx_octets;
  	u16_t eff_tx_octets;
  #if defined(CONFIG_BT_CTLR_PHY)
  	u16_t eff_rx_time;
  	u16_t eff_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  	u8_t nack = 0U;
  
  	/* Check for free ctrl tx PDU */
  	if (pdu_data_rx->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_LENGTH_REQ) {
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			return 1;
  		}
  	}
  
  	eff_rx_octets = _radio.conn_curr->max_rx_octets;
  	eff_tx_octets = _radio.conn_curr->max_tx_octets;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	eff_rx_time = _radio.conn_curr->max_rx_time;
  	eff_tx_time = _radio.conn_curr->max_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  	if (/* Local idle, and Peer request then complete the Peer procedure
  	     * with response.
  	     */
  	    ((_radio.conn_curr->llcp_length.req ==
  	      _radio.conn_curr->llcp_length.ack) &&
  	     (pdu_data_rx->llctrl.opcode ==
  	      PDU_DATA_LLCTRL_TYPE_LENGTH_REQ)) ||
  	    /* or Local has active... */
  	    ((_radio.conn_curr->llcp_length.req !=
  	      _radio.conn_curr->llcp_length.ack) &&
  	     /* with Local requested and Peer request then complete the
  	      * Peer procedure with response.
  	      */
  	     ((((_radio.conn_curr->llcp_length.state ==
  		 LLCP_LENGTH_STATE_REQ) ||
  		(_radio.conn_curr->llcp_length.state ==
  		 LLCP_LENGTH_STATE_REQ_ACK_WAIT)) &&
  	       (pdu_data_rx->llctrl.opcode ==
  		PDU_DATA_LLCTRL_TYPE_LENGTH_REQ)) ||
  	      /* with Local waiting for response, and Peer response then
  	       * complete the Local procedure or Peer request then complete the
  	       * Peer procedure with response.
  	       */
  	      ((_radio.conn_curr->llcp_length.state ==
  		LLCP_LENGTH_STATE_RSP_WAIT) &&
  	       ((pdu_data_rx->llctrl.opcode ==
  		 PDU_DATA_LLCTRL_TYPE_LENGTH_RSP) ||
  		(pdu_data_rx->llctrl.opcode ==
  		 PDU_DATA_LLCTRL_TYPE_LENGTH_REQ)))))) {
  		struct pdu_data_llctrl_length_req *lr;
  
  		lr = &pdu_data_rx->llctrl.length_req;
  
  		/* use the minimal of our default_tx_octets and
  		 * peer max_rx_octets
  		 */
  		if (lr->max_rx_octets >= PDU_DC_PAYLOAD_SIZE_MIN) {
  			eff_tx_octets = MIN(lr->max_rx_octets,
  					    _radio.conn_curr->default_tx_octets);
  		}
  
  		/* use the minimal of our max supported and
  		 * peer max_tx_octets
  		 */
  		if (lr->max_tx_octets >= PDU_DC_PAYLOAD_SIZE_MIN) {
  			eff_rx_octets = MIN(lr->max_tx_octets,
  					    LL_LENGTH_OCTETS_RX_MAX);
  		}
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		/* use the minimal of our default_tx_time and
  		 * peer max_rx_time
  		 */
  		if (lr->max_rx_time >=
  		    RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0)) {
  			eff_tx_time =
  				MIN(lr->max_rx_time,
  				    _radio.conn_curr->default_tx_time);
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  			eff_tx_time =
  				MAX(eff_tx_time,
  				    RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
  						   _radio.conn_curr->phy_tx));
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  		}
  
  		/* use the minimal of our max supported and
  		 * peer max_tx_time
  		 */
  		if (lr->max_tx_time >=
  		    RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0)) {
  			eff_rx_time =
  				MIN(lr->max_tx_time,
  				    RADIO_PKT_TIME(LL_LENGTH_OCTETS_RX_MAX,
  						   BIT(2)));
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  			eff_rx_time =
  				MAX(eff_rx_time,
  				    RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
  						   _radio.conn_curr->phy_rx));
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  		}
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		/* check if change in rx octets */
  		if (eff_rx_octets != _radio.conn_curr->max_rx_octets) {
  			u16_t free_count_rx;
  
  			free_count_rx = packet_rx_acquired_count_get() +
  				mem_free_count_get(_radio.pkt_rx_data_free);
  			LL_ASSERT(free_count_rx <= 0xFF);
  
  			if (_radio.packet_rx_data_count == free_count_rx) {
  				/* trigger or retain the ctrl procedure so as
  				 * to resize the rx buffers.
  				 */
  				_radio.conn_curr->llcp_length.rx_octets =
  					eff_rx_octets;
  				_radio.conn_curr->llcp_length.tx_octets =
  					eff_tx_octets;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  				_radio.conn_curr->llcp_length.rx_time =
  					eff_rx_time;
  				_radio.conn_curr->llcp_length.tx_time =
  					eff_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  				/* flag an event length update*/
  				_radio.conn_curr->evt_len_upd = 1U;
  				_radio.conn_curr->evt_len_adv = 1U;
  
  				/* Request Rx buffer resize */
  				_radio.conn_curr->llcp_length.ack =
  					(_radio.conn_curr->llcp_length.req - 1);
  
  				if (node_tx) {
  					_radio.conn_curr->llcp_length.state =
  						LLCP_LENGTH_STATE_RESIZE_RSP;
  				} else {
  					/* accept the effective tx */
  					_radio.conn_curr->max_tx_octets =
  						eff_tx_octets;
  #if defined(CONFIG_BT_CTLR_PHY)
  					/* accept the effective tx time */
  					_radio.conn_curr->max_tx_time =
  						eff_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  					_radio.conn_curr->llcp_length.state =
  						LLCP_LENGTH_STATE_RESIZE;
  				}
  
  				/* close the current connection event, so as
  				 * to perform rx octet change.
  				 */
  				_radio.state = STATE_CLOSE;
  			} else {
  				nack = 1U;
  			}
  		} else {
  			/* Procedure complete */
  			_radio.conn_curr->llcp_length.ack =
  				_radio.conn_curr->llcp_length.req;
  			_radio.conn_curr->procedure_expire = 0U;
  
  			/* No change in effective octets or time */
  			if (eff_tx_octets == _radio.conn_curr->max_tx_octets &&
  #if defined(CONFIG_BT_CTLR_PHY)
  			    eff_tx_time == _radio.conn_curr->max_tx_time &&
  			    eff_rx_time == _radio.conn_curr->max_rx_time &&
  #endif /* CONFIG_BT_CTLR_PHY */
  			    (1)) {
  				goto send_length_resp;
  			}
  
  #if defined(CONFIG_BT_CTLR_PHY)
  			/* accept the effective rx time */
  			_radio.conn_curr->max_rx_time = eff_rx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  			if (node_tx) {
  				/* trigger or retain the ctrl procedure so as
  				 * to resize the rx buffers.
  				 */
  				_radio.conn_curr->llcp_length.rx_octets =
  					eff_rx_octets;
  				_radio.conn_curr->llcp_length.tx_octets =
  					eff_tx_octets;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  				_radio.conn_curr->llcp_length.rx_time =
  					eff_rx_time;
  				_radio.conn_curr->llcp_length.tx_time =
  					eff_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  				/* Wait for rsp ack before tx change  */
  				_radio.conn_curr->llcp_length.ack =
  					(_radio.conn_curr->llcp_length.req - 1);
  				_radio.conn_curr->llcp_length.state =
  					LLCP_LENGTH_STATE_RSP_ACK_WAIT;
  			} else {
  				/* accept the effective tx */
  				_radio.conn_curr->max_tx_octets = eff_tx_octets;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  				/* accept the effective tx time */
  				_radio.conn_curr->max_tx_time = eff_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  			}
  
  			/* flag an event length update*/
  			_radio.conn_curr->evt_len_upd = 1U;
  			_radio.conn_curr->evt_len_adv = 0U;
  
  			/* prepare event params */
  			lr->max_rx_octets = eff_rx_octets;
  			lr->max_tx_octets = eff_tx_octets;
  
  #if !defined(CONFIG_BT_CTLR_PHY)
  			lr->max_rx_time = RADIO_PKT_TIME(eff_rx_octets, 0);
  			lr->max_tx_time = RADIO_PKT_TIME(eff_tx_octets, 0);
  #else /* CONFIG_BT_CTLR_PHY */
  			lr->max_rx_time = eff_rx_time;
  			lr->max_tx_time = eff_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  			/* Enqueue data length change event (with no change in
  			 * rx length happened), safe to enqueue rx.
  			 */
  			*rx_enqueue = 1U;
  		}
  	} else {
  		/* Drop response with no Local initiated request. */
  		LL_ASSERT(pdu_data_rx->llctrl.opcode ==
  			  PDU_DATA_LLCTRL_TYPE_LENGTH_RSP);
  	}
  
  send_length_resp:
  	if (node_tx) {
  		if (nack) {
  			mem_release(node_tx, &_radio.pkt_tx_ctrl_free);
  		} else {
  #if !defined(CONFIG_BT_CTLR_PHY)
  			length_resp_send(_radio.conn_curr, node_tx,
  					 eff_rx_octets, eff_tx_octets);
  #else /* CONFIG_BT_CTLR_PHY */
  			length_resp_send(_radio.conn_curr, node_tx,
  					 eff_rx_octets, eff_rx_time,
  					 eff_tx_octets, eff_tx_time);
  #endif /* CONFIG_BT_CTLR_PHY */
  		}
  	}
  
  	return nack;
  }
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  static inline bool pdu_len_cmp(u8_t opcode, u8_t len)
  {
  	const u8_t ctrl_len_lut[] = {
  		(offsetof(struct pdu_data_llctrl, conn_update_ind) +
  		 sizeof(struct pdu_data_llctrl_conn_update_ind)),
  		(offsetof(struct pdu_data_llctrl, chan_map_ind) +
  		 sizeof(struct pdu_data_llctrl_chan_map_ind)),
  		(offsetof(struct pdu_data_llctrl, terminate_ind) +
  		 sizeof(struct pdu_data_llctrl_terminate_ind)),
  		(offsetof(struct pdu_data_llctrl, enc_req) +
  		 sizeof(struct pdu_data_llctrl_enc_req)),
  		(offsetof(struct pdu_data_llctrl, enc_rsp) +
  		 sizeof(struct pdu_data_llctrl_enc_rsp)),
  		(offsetof(struct pdu_data_llctrl, start_enc_req) +
  		 sizeof(struct pdu_data_llctrl_start_enc_req)),
  		(offsetof(struct pdu_data_llctrl, start_enc_rsp) +
  		 sizeof(struct pdu_data_llctrl_start_enc_rsp)),
  		(offsetof(struct pdu_data_llctrl, unknown_rsp) +
  		 sizeof(struct pdu_data_llctrl_unknown_rsp)),
  		(offsetof(struct pdu_data_llctrl, feature_req) +
  		 sizeof(struct pdu_data_llctrl_feature_req)),
  		(offsetof(struct pdu_data_llctrl, feature_rsp) +
  		 sizeof(struct pdu_data_llctrl_feature_rsp)),
  		(offsetof(struct pdu_data_llctrl, pause_enc_req) +
  		 sizeof(struct pdu_data_llctrl_pause_enc_req)),
  		(offsetof(struct pdu_data_llctrl, pause_enc_rsp) +
  		 sizeof(struct pdu_data_llctrl_pause_enc_rsp)),
  		(offsetof(struct pdu_data_llctrl, version_ind) +
  		 sizeof(struct pdu_data_llctrl_version_ind)),
  		(offsetof(struct pdu_data_llctrl, reject_ind) +
  		 sizeof(struct pdu_data_llctrl_reject_ind)),
  		(offsetof(struct pdu_data_llctrl, slave_feature_req) +
  		 sizeof(struct pdu_data_llctrl_slave_feature_req)),
  		(offsetof(struct pdu_data_llctrl, conn_param_req) +
  		 sizeof(struct pdu_data_llctrl_conn_param_req)),
  		(offsetof(struct pdu_data_llctrl, conn_param_rsp) +
  		 sizeof(struct pdu_data_llctrl_conn_param_rsp)),
  		(offsetof(struct pdu_data_llctrl, reject_ext_ind) +
  		 sizeof(struct pdu_data_llctrl_reject_ext_ind)),
  		(offsetof(struct pdu_data_llctrl, ping_req) +
  		 sizeof(struct pdu_data_llctrl_ping_req)),
  		(offsetof(struct pdu_data_llctrl, ping_rsp) +
  		 sizeof(struct pdu_data_llctrl_ping_rsp)),
  		(offsetof(struct pdu_data_llctrl, length_req) +
  		 sizeof(struct pdu_data_llctrl_length_req)),
  		(offsetof(struct pdu_data_llctrl, length_rsp) +
  		 sizeof(struct pdu_data_llctrl_length_rsp)),
  		(offsetof(struct pdu_data_llctrl, phy_req) +
  		 sizeof(struct pdu_data_llctrl_phy_req)),
  		(offsetof(struct pdu_data_llctrl, phy_rsp) +
  		 sizeof(struct pdu_data_llctrl_phy_rsp)),
  		(offsetof(struct pdu_data_llctrl, phy_upd_ind) +
  		 sizeof(struct pdu_data_llctrl_phy_upd_ind)),
  		(offsetof(struct pdu_data_llctrl, min_used_chans_ind) +
  		 sizeof(struct pdu_data_llctrl_min_used_chans_ind)),
  	};
  
  	return ctrl_len_lut[opcode] == len;
  }
  
  static inline u8_t
  isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
  		     u8_t *rx_enqueue)
  {
  	u8_t nack = 0U;
  	struct pdu_data *pdu_data_rx;
  
  	pdu_data_rx = (void *)node_rx->pdu_data;
  
  	switch (pdu_data_rx->llctrl.opcode) {
  	case PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND:
  	{
  		u8_t err;
  
  		if (!_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		err = conn_update(_radio.conn_curr, pdu_data_rx);
  		if (err) {
  			_radio.conn_curr->llcp_terminate.reason_peer = err;
  		} else {
  			/* conn param req procedure, if any, is complete */
  			_radio.conn_curr->procedure_expire = 0U;
  		}
  	}
  	break;
  
  	case PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND:
  	{
  		u8_t err;
  
  		if (!_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		err = chan_map_update(_radio.conn_curr, pdu_data_rx);
  		if (err) {
  			_radio.conn_curr->llcp_terminate.reason_peer = err;
  		}
  	}
  	break;
  
  	case PDU_DATA_LLCTRL_TYPE_TERMINATE_IND:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_TERMINATE_IND,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		/* Ack and then terminate */
  		_radio.conn_curr->llcp_terminate.reason_peer =
  			pdu_data_rx->llctrl.terminate_ind.error_code;
  		break;
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  	case PDU_DATA_LLCTRL_TYPE_ENC_REQ:
  		if (!_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_ENC_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		/* NOTE: workaround to defer peer initiated encryption while
  		 *       local initiated procedure with instant is not complete.
  		 *       Peer master has sent CONN_UPDATE_IND in response to
  		 *	 CONN_PARAM_REQ, and also has initiated a Encryption
  		 *       Setup thereafter.
  		 */
  		if (_radio.conn_curr->llcp_req != _radio.conn_curr->llcp_ack) {
  			nack = 1U;
  			break;
  		}
  
  #if defined(CONFIG_BT_CTLR_FAST_ENC)
  		/* TODO: BT Spec. text: may finalize the sending of additional
  		 * data channel PDUs queued in the controller.
  		 */
  		nack = enc_rsp_send(_radio.conn_curr);
  		if (nack) {
  			break;
  		}
  
  		/* enqueue the enc req */
  		*rx_enqueue = 1U;
  
  		/* Start Enc Req to be scheduled by LL api */
  		_radio.conn_curr->llcp.encryption.state =
  			LLCP_ENC_STATE_LTK_WAIT;
  #else /* !CONFIG_BT_CTLR_FAST_ENC */
  		/* back up rand and ediv for deferred generation of Enc Req */
  		memcpy(&_radio.conn_curr->llcp_enc.rand[0],
  		       &pdu_data_rx->llctrl.enc_req.rand[0],
  		       sizeof(_radio.conn_curr->llcp_enc.rand));
  		_radio.conn_curr->llcp_enc.ediv[0] =
  			pdu_data_rx->llctrl.enc_req.ediv[0];
  		_radio.conn_curr->llcp_enc.ediv[1] =
  			pdu_data_rx->llctrl.enc_req.ediv[1];
  
  		/* Enc rsp to be scheduled in master prepare */
  		_radio.conn_curr->llcp.encryption.state = LLCP_ENC_STATE_INIT;
  #endif /* !CONFIG_BT_CTLR_FAST_ENC */
  
  		/* Enc Setup requested */
  		_radio.conn_curr->llcp_type = LLCP_ENCRYPTION;
  		_radio.conn_curr->llcp_ack--;
  
  		/* things from master stored for session key calculation */
  		memcpy(&_radio.conn_curr->llcp.encryption.skd[0],
  		       &pdu_data_rx->llctrl.enc_req.skdm[0], 8);
  		memcpy(&_radio.conn_curr->ccm_rx.iv[0],
  		       &pdu_data_rx->llctrl.enc_req.ivm[0], 4);
  
  		/* pause rx data packets */
  		_radio.conn_curr->pause_rx = 1U;
  
  		/* Start Procedure Timeout (TODO: this shall not replace
  		 * terminate procedure).
  		 */
  		_radio.conn_curr->procedure_expire =
  			_radio.conn_curr->procedure_reload;
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_ENC_RSP:
  		if (_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_ENC_RSP,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		/* things sent by slave stored for session key calculation */
  		memcpy(&_radio.conn_curr->llcp.encryption.skd[8],
  		       &pdu_data_rx->llctrl.enc_rsp.skds[0], 8);
  		memcpy(&_radio.conn_curr->ccm_rx.iv[4],
  		       &pdu_data_rx->llctrl.enc_rsp.ivs[0], 4);
  
  		/* pause rx data packets */
  		_radio.conn_curr->pause_rx = 1U;
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_START_ENC_REQ:
  		if (_radio.conn_curr->role ||
  		    (_radio.conn_curr->llcp_req ==
  		      _radio.conn_curr->llcp_ack) ||
  		    (_radio.conn_curr->llcp_type != LLCP_ENCRYPTION) ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_START_ENC_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		/* start enc rsp to be scheduled in master prepare */
  		_radio.conn_curr->llcp.encryption.state = LLCP_ENC_STATE_INPROG;
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_START_ENC_RSP:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_START_ENC_RSP,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		if (_radio.role == ROLE_SLAVE) {
  #if !defined(CONFIG_BT_CTLR_FAST_ENC)
  			if ((_radio.conn_curr->llcp_req !=
  			     _radio.conn_curr->llcp_ack) &&
  			    (_radio.conn_curr->llcp_type != LLCP_ENCRYPTION)) {
  				goto isr_rx_conn_unknown_rsp_send;
  			}
  
  			/* start enc rsp to be scheduled in slave  prepare */
  			_radio.conn_curr->llcp.encryption.state =
  				LLCP_ENC_STATE_INPROG;
  			_radio.conn_curr->llcp_type = LLCP_ENCRYPTION;
  			_radio.conn_curr->llcp_ack--;
  #else /* CONFIG_BT_CTLR_FAST_ENC */
  			nack = start_enc_rsp_send(_radio.conn_curr, NULL);
  			if (nack) {
  				break;
  			}
  
  			/* resume data packet rx and tx */
  			_radio.conn_curr->pause_rx = 0U;
  			_radio.conn_curr->pause_tx = 0U;
  #endif /* CONFIG_BT_CTLR_FAST_ENC */
  
  		} else {
  			/* resume data packet rx and tx */
  			_radio.conn_curr->pause_rx = 0U;
  			_radio.conn_curr->pause_tx = 0U;
  		}
  
  		/* enqueue the start enc resp (encryption change/refresh) */
  		if (_radio.conn_curr->refresh) {
  			_radio.conn_curr->refresh = 0U;
  
  			/* key refresh event */
  			node_rx->hdr.type = NODE_RX_TYPE_ENC_REFRESH;
  		}
  		*rx_enqueue = 1U;
  
  		/* Procedure complete */
  		_radio.conn_curr->procedure_expire = 0U;
  		break;
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  	case PDU_DATA_LLCTRL_TYPE_FEATURE_REQ:
  		if (!_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_FEATURE_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		nack = feature_rsp_send(_radio.conn_curr, pdu_data_rx);
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_SLAVE_FEATURE_REQ:
  		if (_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_SLAVE_FEATURE_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		nack = feature_rsp_send(_radio.conn_curr, pdu_data_rx);
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_FEATURE_RSP:
  	{
  		struct pdu_data_llctrl_feature_rsp *rsp;
  
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_FEATURE_RSP,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		rsp = &pdu_data_rx->llctrl.feature_rsp;
  
  		/* AND the feature set to get Feature USED */
  		_radio.conn_curr->llcp_feature.features &=
  			feat_get(&rsp->features[0]);
  
  		/* features exchanged */
  		_radio.conn_curr->common.fex_valid = 1U;
  
  		/* enqueue the feature resp */
  		*rx_enqueue = 1U;
  
  		/* Procedure complete */
  		_radio.conn_curr->llcp_feature.ack =
  			_radio.conn_curr->llcp_feature.req;
  		_radio.conn_curr->procedure_expire = 0U;
  	}
  	break;
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  	case PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ:
  		if (!_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		nack = pause_enc_rsp_send(_radio.conn_curr, 1);
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		nack = pause_enc_rsp_send(_radio.conn_curr, 0);
  		break;
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  	case PDU_DATA_LLCTRL_TYPE_VERSION_IND:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_VERSION_IND,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		nack = version_ind_send(_radio.conn_curr, pdu_data_rx,
  					rx_enqueue);
  		break;
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  	case PDU_DATA_LLCTRL_TYPE_REJECT_IND:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_REJECT_IND,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		isr_rx_conn_pkt_ctrl_rej_enc(node_rx, rx_enqueue);
  		break;
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  	case PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  
  		/* check CUI/CPR mutex for other connections having CPR in
  		 * progress.
  		 */
  		if (_radio.conn_upd && (_radio.conn_upd != _radio.conn_curr)) {
  			/* Unsupported LL Parameter Value */
  			nack = reject_ext_ind_send(_radio.conn_curr,
  					PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ,
  					BT_HCI_ERR_UNSUPP_LL_PARAM_VAL);
  			break;
  		}
  
  		if (!_radio.conn_curr->role) {
  			struct connection *conn = _radio.conn_curr;
  
  			if ((conn->llcp_conn_param.req !=
  					conn->llcp_conn_param.ack) &&
  			    ((conn->llcp_conn_param.state ==
  			      LLCP_CPR_STATE_REQ) ||
  			     (conn->llcp_conn_param.state ==
  			      LLCP_CPR_STATE_RSP_WAIT) ||
  			     (conn->llcp_conn_param.state ==
  			      LLCP_CPR_STATE_UPD))) {
  				/* Same procedure collision  */
  				nack = reject_ext_ind_send(_radio.conn_curr,
  					PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ,
  					BT_HCI_ERR_LL_PROC_COLLISION);
  #if defined(CONFIG_BT_CTLR_PHY)
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  			} else if (((conn->llcp_req != conn->llcp_ack) &&
  				    (conn->llcp_type != LLCP_ENCRYPTION)) ||
  				   (conn->llcp_phy.req != conn->llcp_phy.ack)) {
  #else /* !CONFIG_BT_CTLR_LE_ENC */
  			} else if ((conn->llcp_req != conn->llcp_ack) ||
  				   (conn->llcp_phy.req != conn->llcp_phy.ack)) {
  #endif /* !CONFIG_BT_CTLR_LE_ENC */
  #else /* !CONFIG_BT_CTLR_PHY */
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  			} else if ((conn->llcp_req != conn->llcp_ack) &&
  				   (conn->llcp_type != LLCP_ENCRYPTION)) {
  #else /* !CONFIG_BT_CTLR_LE_ENC */
  			} else if (conn->llcp_req != conn->llcp_ack) {
  #endif /* !CONFIG_BT_CTLR_LE_ENC */
  #endif /* !CONFIG_BT_CTLR_PHY */
  				/* Different procedure collision */
  				nack = reject_ext_ind_send(_radio.conn_curr,
  					PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ,
  					BT_HCI_ERR_DIFF_TRANS_COLLISION);
  			} else {
  				struct pdu_data_llctrl_conn_param_req *cpr = (void *)
  					&pdu_data_rx->llctrl.conn_param_req;
  
  				/* Invalid parameters */
  				if ((cpr->interval_min < 6) ||
  				    (cpr->interval_max > 3200) ||
  				    (cpr->interval_min > cpr->interval_max) ||
  				    (cpr->latency > 499) ||
  				    (cpr->timeout < 10) ||
  				    (cpr->timeout > 3200) ||
  				    ((cpr->timeout * 4) <=
  				     ((cpr->latency + 1) *
  				      cpr->interval_max)) ||
  				    (cpr->preferred_periodicity >
  				     cpr->interval_max)) {
  					nack = reject_ext_ind_send(conn,
  						PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ,
  						BT_HCI_ERR_INVALID_LL_PARAM);
  					break;
  				}
  
  				/* save parameters to be used to select offset
  				 */
  				conn->llcp_conn_param.interval_min =
  					cpr->interval_min;
  				conn->llcp_conn_param.interval_max =
  					cpr->interval_max;
  				conn->llcp_conn_param.latency =	cpr->latency;
  				conn->llcp_conn_param.timeout =	cpr->timeout;
  				conn->llcp_conn_param.preferred_periodicity =
  					cpr->preferred_periodicity;
  				conn->llcp_conn_param.reference_conn_event_count =
  					cpr->reference_conn_event_count;
  				conn->llcp_conn_param.offset0 =	cpr->offset0;
  				conn->llcp_conn_param.offset1 =	cpr->offset1;
  				conn->llcp_conn_param.offset2 =	cpr->offset2;
  				conn->llcp_conn_param.offset3 =	cpr->offset3;
  				conn->llcp_conn_param.offset4 =	cpr->offset4;
  				conn->llcp_conn_param.offset5 =	cpr->offset5;
  
  				/* enqueue the conn param req, if parameters
  				 * changed, else respond.
  				 */
  				if ((conn->llcp_conn_param.interval_max !=
  				     conn->conn_interval) ||
  				    (conn->llcp_conn_param.latency !=
  				     conn->latency) ||
  				    (RADIO_CONN_EVENTS(conn->llcp_conn_param.timeout *
  						       10000,
  						       conn->conn_interval *
  						       1250) !=
  				     conn->supervision_reload)) {
  					/* postpone CP request event if under
  					 * encryption setup
  					 */
  					if (conn->pause_tx) {
  						conn->llcp_conn_param.state =
  							LLCP_CPR_STATE_APP_REQ;
  					} else {
  						*rx_enqueue = 1U;
  
  						conn->llcp_conn_param.state =
  							LLCP_CPR_STATE_APP_WAIT;
  					}
  				} else {
  					conn->llcp_conn_param.status = 0U;
  					conn->llcp_conn_param.cmd = 0U;
  					conn->llcp_conn_param.state =
  						LLCP_CPR_STATE_RSP;
  				}
  
  				conn->llcp_conn_param.ack--;
  
  				/* set mutex */
  				if (_radio.conn_upd == 0) {
  					_radio.conn_upd = conn;
  				}
  			}
  		} else if ((_radio.conn_curr->llcp_conn_param.req ==
  			    _radio.conn_curr->llcp_conn_param.ack) ||
  			   (_radio.conn_curr->llcp_conn_param.state ==
  			    LLCP_CPR_STATE_REQ) ||
  			   (_radio.conn_curr->llcp_conn_param.state ==
  			    LLCP_CPR_STATE_RSP_WAIT)) {
  			struct connection *conn = _radio.conn_curr;
  			struct pdu_data_llctrl_conn_param_req *cpr = (void *)
  				&pdu_data_rx->llctrl.conn_param_req;
  
  			/* Invalid parameters */
  			if ((cpr->interval_min < 6) ||
  			    (cpr->interval_max > 3200) ||
  			    (cpr->interval_min > cpr->interval_max) ||
  			    (cpr->latency > 499) ||
  			    (cpr->timeout < 10) || (cpr->timeout > 3200) ||
  			    ((cpr->timeout * 4) <= ((cpr->latency + 1) *
  						    cpr->interval_max)) ||
  			    (cpr->preferred_periodicity > cpr->interval_max)) {
  				nack = reject_ext_ind_send(conn,
  					PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ,
  					BT_HCI_ERR_INVALID_LL_PARAM);
  				break;
  			}
  
  			/* resp to be generated by app, for now save
  			 * parameters
  			 */
  			conn->llcp_conn_param.interval_min = cpr->interval_min;
  			conn->llcp_conn_param.interval_max = cpr->interval_max;
  			conn->llcp_conn_param.latency =	cpr->latency;
  			conn->llcp_conn_param.timeout =	cpr->timeout;
  			conn->llcp_conn_param.preferred_periodicity =
  				cpr->preferred_periodicity;
  			conn->llcp_conn_param.reference_conn_event_count =
  				cpr->reference_conn_event_count;
  			conn->llcp_conn_param.offset0 =	cpr->offset0;
  			conn->llcp_conn_param.offset1 =	cpr->offset1;
  			conn->llcp_conn_param.offset2 =	cpr->offset2;
  			conn->llcp_conn_param.offset3 =	cpr->offset3;
  			conn->llcp_conn_param.offset4 =	cpr->offset4;
  			conn->llcp_conn_param.offset5 =	cpr->offset5;
  
  			/* enqueue the conn param req, if parameters changed,
  			 * else respond
  			 */
  			if ((conn->llcp_conn_param.interval_max !=
  			     conn->conn_interval) ||
  			    (conn->llcp_conn_param.latency != conn->latency) ||
  			    (RADIO_CONN_EVENTS(conn->llcp_conn_param.timeout *
  					       10000,
  					       conn->conn_interval *
  					       1250) !=
  			     conn->supervision_reload)) {
  				*rx_enqueue = 1U;
  
  				conn->llcp_conn_param.state =
  					LLCP_CPR_STATE_APP_WAIT;
  			} else {
  				conn->llcp_conn_param.status = 0U;
  				conn->llcp_conn_param.cmd = 0U;
  				conn->llcp_conn_param.state =
  					LLCP_CPR_STATE_RSP;
  			}
  
  			conn->llcp_conn_param.ack--;
  
  			/* set mutex */
  			if (_radio.conn_upd == 0) {
  				_radio.conn_upd = conn;
  			}
  		} else {
  			LL_ASSERT(0);
  		}
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP:
  		if (_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		if (!_radio.conn_curr->role &&
  		    (_radio.conn_curr->llcp_conn_param.req !=
  		     _radio.conn_curr->llcp_conn_param.ack) &&
  		    (_radio.conn_curr->llcp_conn_param.state ==
  		     LLCP_CPR_STATE_RSP_WAIT)) {
  			struct connection *conn = _radio.conn_curr;
  			struct pdu_data_llctrl_conn_param_req *cpr = (void *)
  				&pdu_data_rx->llctrl.conn_param_req;
  
  			/* Invalid parameters */
  			if ((cpr->interval_min < 6) ||
  			    (cpr->interval_max > 3200) ||
  			    (cpr->interval_min > cpr->interval_max) ||
  			    (cpr->latency > 499) ||
  			    (cpr->timeout < 10) || (cpr->timeout > 3200) ||
  			    ((cpr->timeout * 4) <= ((cpr->latency + 1) *
  						    cpr->interval_max)) ||
  			    (cpr->preferred_periodicity > cpr->interval_max)) {
  				nack = reject_ext_ind_send(conn,
  					PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP,
  					BT_HCI_ERR_INVALID_LL_PARAM);
  				break;
  			}
  
  			/* Stop procedure timeout */
  			_radio.conn_curr->procedure_expire = 0U;
  
  			/* save parameters to be used to select offset
  			 */
  			conn->llcp_conn_param.interval_min = cpr->interval_min;
  			conn->llcp_conn_param.interval_max = cpr->interval_max;
  			conn->llcp_conn_param.latency =	cpr->latency;
  			conn->llcp_conn_param.timeout =	cpr->timeout;
  			conn->llcp_conn_param.preferred_periodicity =
  				cpr->preferred_periodicity;
  			conn->llcp_conn_param.reference_conn_event_count =
  				cpr->reference_conn_event_count;
  			conn->llcp_conn_param.offset0 =	cpr->offset0;
  			conn->llcp_conn_param.offset1 =	cpr->offset1;
  			conn->llcp_conn_param.offset2 =	cpr->offset2;
  			conn->llcp_conn_param.offset3 =	cpr->offset3;
  			conn->llcp_conn_param.offset4 =	cpr->offset4;
  			conn->llcp_conn_param.offset5 =	cpr->offset5;
  
  			/* Perform connection update */
  			conn->llcp_conn_param.state = LLCP_CPR_STATE_RSP;
  		}
  		break;
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  	case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		isr_rx_conn_pkt_ctrl_rej(node_rx, rx_enqueue);
  		break;
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  	case PDU_DATA_LLCTRL_TYPE_PING_REQ:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_PING_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		nack = ping_resp_send(_radio.conn_curr);
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_PING_RSP:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_PING_RSP,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		/* Procedure complete */
  		_radio.conn_curr->procedure_expire = 0U;
  		break;
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  	case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		if (0) {
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  		} else if (_radio.conn_curr->llcp_conn_param.ack !=
  			   _radio.conn_curr->llcp_conn_param.req) {
  			struct connection *conn = _radio.conn_curr;
  			struct radio_le_conn_update_cmplt *cp;
  
  			/* Mark CPR as unsupported */
  			conn->llcp_conn_param.disabled = 1U;
  
  			/* TODO: check for unsupported remote feature reason */
  			if (!conn->role) {
  				LL_ASSERT(conn->llcp_cu.req ==
  					  conn->llcp_cu.ack);
  
  				conn->llcp_conn_param.state =
  					LLCP_CPR_STATE_UPD;
  
  				conn->llcp_cu.win_size = 1U;
  				conn->llcp_cu.win_offset_us = 0U;
  				conn->llcp_cu.interval =
  					conn->llcp_conn_param.interval_max;
  				conn->llcp_cu.latency =
  					conn->llcp_conn_param.latency;
  				conn->llcp_cu.timeout =
  					conn->llcp_conn_param.timeout;
  				conn->llcp_cu.state = LLCP_CUI_STATE_USE;
  				conn->llcp_cu.cmd = conn->llcp_conn_param.cmd;
  				conn->llcp_cu.ack--;
  
  				break;
  			}
  
  			LL_ASSERT(_radio.conn_upd == conn);
  
  			/* reset mutex */
  			_radio.conn_upd = NULL;
  
  			/* Procedure complete */
  			conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
  
  			/* skip event generation if not cmd initiated */
  			if (!conn->llcp_conn_param.cmd) {
  				break;
  			}
  
  			/* generate conn upd complete event with error code */
  			node_rx->hdr.type = NODE_RX_TYPE_CONN_UPDATE;
  
  			/* prepare connection update complete structure */
  			cp = (void *)node_rx->pdu_data;
  			cp->status = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
  			cp->interval = conn->conn_interval;
  			cp->latency = conn->latency;
  			cp->timeout = conn->supervision_reload *
  				      conn->conn_interval * 125 / 1000;
  
  			*rx_enqueue = 1U;
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		} else if (_radio.conn_curr->llcp_length.req !=
  			   _radio.conn_curr->llcp_length.ack) {
  			/* Procedure complete */
  			_radio.conn_curr->llcp_length.ack =
  				_radio.conn_curr->llcp_length.req;
  
  			/* propagate the data length procedure to
  			 * host
  			 */
  			*rx_enqueue = 1U;
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		} else if (_radio.conn_curr->llcp_phy.req !=
  			   _radio.conn_curr->llcp_phy.ack) {
  			struct radio_le_phy_upd_cmplt *p;
  
  			/* Procedure complete */
  			_radio.conn_curr->llcp_phy.ack =
  				_radio.conn_curr->llcp_phy.req;
  
  			/* Reset packet timing restrictions */
  			_radio.conn_curr->phy_tx_time =
  				_radio.conn_curr->phy_tx;
  
  			/* skip event generation is not cmd initiated */
  			if (_radio.conn_curr->llcp_phy.cmd) {
  				/* generate phy update complete event */
  				node_rx->hdr.type = NODE_RX_TYPE_PHY_UPDATE;
  
  				p = (void *)node_rx->pdu_data;
  				p->status = 0U;
  				p->tx = _radio.conn_curr->phy_tx;
  				p->rx = _radio.conn_curr->phy_rx;
  
  				/* enqueue the phy update complete */
  				*rx_enqueue = 1U;
  			}
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		} else {
  			struct pdu_data_llctrl *llctrl;
  
  			llctrl = (void *)&pdu_data_rx->llctrl;
  			switch (llctrl->unknown_rsp.type) {
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  			case PDU_DATA_LLCTRL_TYPE_PING_REQ:
  				/* unknown rsp to LE Ping Req completes the
  				 * procedure; nothing to do here.
  				 */
  				break;
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  			default:
  				/* enqueue the error and let HCI handle it */
  				*rx_enqueue = 1U;
  				break;
  			}
  		}
  
  		/* Procedure complete */
  		_radio.conn_curr->procedure_expire = 0U;
  		break;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	case PDU_DATA_LLCTRL_TYPE_LENGTH_RSP:
  	case PDU_DATA_LLCTRL_TYPE_LENGTH_REQ:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_LENGTH_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		nack = isr_rx_conn_pkt_ctrl_dle(pdu_data_rx, rx_enqueue);
  		break;
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	case PDU_DATA_LLCTRL_TYPE_PHY_REQ:
  		if (!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_PHY_REQ,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		if (_radio.role == ROLE_MASTER) {
  			if ((_radio.conn_curr->llcp_phy.ack !=
  			     _radio.conn_curr->llcp_phy.req) &&
  			    ((_radio.conn_curr->llcp_phy.state ==
  			      LLCP_PHY_STATE_ACK_WAIT) ||
  			     (_radio.conn_curr->llcp_phy.state ==
  			      LLCP_PHY_STATE_RSP_WAIT) ||
  			     (_radio.conn_curr->llcp_phy.state ==
  			      LLCP_PHY_STATE_UPD))) {
  				/* Same procedure collision  */
  				nack = reject_ext_ind_send(_radio.conn_curr,
  					PDU_DATA_LLCTRL_TYPE_PHY_REQ,
  					BT_HCI_ERR_LL_PROC_COLLISION);
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  			} else if (((_radio.conn_curr->llcp_req !=
  				     _radio.conn_curr->llcp_ack) &&
  				    (_radio.conn_curr->llcp_type !=
  				     LLCP_ENCRYPTION)) ||
  				   (_radio.conn_curr->llcp_conn_param.req !=
  				    _radio.conn_curr->llcp_conn_param.ack)) {
  #else /* !CONFIG_BT_CTLR_LE_ENC */
  			} else if ((_radio.conn_curr->llcp_req !=
  				     _radio.conn_curr->llcp_ack) ||
  				   (_radio.conn_curr->llcp_conn_param.req !=
  				    _radio.conn_curr->llcp_conn_param.ack)) {
  #endif /* !CONFIG_BT_CTLR_LE_ENC */
  #else /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  			} else if ((_radio.conn_curr->llcp_req !=
  				    _radio.conn_curr->llcp_ack) &&
  				   (_radio.conn_curr->llcp_type !=
  				    LLCP_ENCRYPTION)) {
  #else /* !CONFIG_BT_CTLR_LE_ENC */
  			} else if (_radio.conn_curr->llcp_req !=
  				    _radio.conn_curr->llcp_ack) {
  #endif /* !CONFIG_BT_CTLR_LE_ENC */
  #endif /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
  				/* Different procedure collision */
  				nack = reject_ext_ind_send(_radio.conn_curr,
  					PDU_DATA_LLCTRL_TYPE_PHY_REQ,
  					BT_HCI_ERR_DIFF_TRANS_COLLISION);
  			} else {
  				struct pdu_data_llctrl *c =
  					&pdu_data_rx->llctrl;
  				struct pdu_data_llctrl_phy_req *p =
  					&c->phy_req;
  
  				_radio.conn_curr->llcp_phy.state =
  					LLCP_PHY_STATE_UPD;
  
  				if (_radio.conn_curr->llcp_phy.ack ==
  				    _radio.conn_curr->llcp_phy.req) {
  					_radio.conn_curr->llcp_phy.ack--;
  
  					_radio.conn_curr->llcp_phy.cmd = 0U;
  
  					_radio.conn_curr->llcp_phy.tx =
  						_radio.conn_curr->phy_pref_tx;
  					_radio.conn_curr->llcp_phy.rx =
  						_radio.conn_curr->phy_pref_rx;
  				}
  
  				_radio.conn_curr->llcp_phy.tx &= p->rx_phys;
  				_radio.conn_curr->llcp_phy.rx &= p->tx_phys;
  
  				if (!_radio.conn_curr->llcp_phy.tx ||
  				    !_radio.conn_curr->llcp_phy.rx) {
  					_radio.conn_curr->llcp_phy.tx = 0;
  					_radio.conn_curr->llcp_phy.rx = 0;
  				}
  			}
  		} else {
  			nack = phy_rsp_send(_radio.conn_curr, pdu_data_rx);
  		}
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_PHY_RSP:
  		if (_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_PHY_RSP,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		if ((_radio.role == ROLE_MASTER) &&
  		    (_radio.conn_curr->llcp_phy.ack !=
  		     _radio.conn_curr->llcp_phy.req) &&
  		    (_radio.conn_curr->llcp_phy.state ==
  		     LLCP_PHY_STATE_RSP_WAIT)) {
  			struct pdu_data_llctrl_phy_rsp *p =
  				&pdu_data_rx->llctrl.phy_rsp;
  
  			_radio.conn_curr->llcp_phy.state = LLCP_PHY_STATE_UPD;
  
  			_radio.conn_curr->llcp_phy.tx &= p->rx_phys;
  			_radio.conn_curr->llcp_phy.rx &= p->tx_phys;
  
  			if (!_radio.conn_curr->llcp_phy.tx ||
  			    !_radio.conn_curr->llcp_phy.rx) {
  				_radio.conn_curr->llcp_phy.tx = 0;
  				_radio.conn_curr->llcp_phy.rx = 0;
  			}
  
  			/* Procedure timeout is stopped */
  			_radio.conn_curr->procedure_expire = 0U;
  		}
  		break;
  
  	case PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND:
  	{
  		u8_t err;
  
  		if (!_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		err = phy_upd_ind_recv(node_rx, rx_enqueue);
  		if (err) {
  			_radio.conn_curr->llcp_terminate.reason_peer = err;
  		}
  	}
  	break;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  #if defined(CONFIG_BT_CTLR_MIN_USED_CHAN)
  	case PDU_DATA_LLCTRL_TYPE_MIN_USED_CHAN_IND:
  		if (_radio.conn_curr->role ||
  		    !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_MIN_USED_CHAN_IND,
  				 pdu_data_rx->len)) {
  			goto isr_rx_conn_unknown_rsp_send;
  		}
  
  		if (!_radio.conn_curr->role) {
  			struct pdu_data_llctrl_min_used_chans_ind *p =
  				&pdu_data_rx->llctrl.min_used_chans_ind;
  			struct connection *conn = _radio.conn_curr;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  			if (!(p->phys & (conn->phy_tx | conn->phy_rx))) {
  #else /* !CONFIG_BT_CTLR_PHY */
  			if (!(p->phys & 0x01)) {
  #endif /* !CONFIG_BT_CTLR_PHY */
  				break;
  			}
  
  			if (conn->llcp_req != conn->llcp_ack) {
  				break;
  			}
  
  			memcpy(&conn->llcp.chan_map.chm[0],
  			       &_radio.data_chan_map[0],
  			       sizeof(conn->llcp.chan_map.chm));
  			/* conn->llcp.chan_map.instant     = 0; */
  			conn->llcp.chan_map.initiate = 1U;
  
  			conn->llcp_type = LLCP_CHAN_MAP;
  			conn->llcp_ack--;
  		}
  		break;
  #endif /* CONFIG_BT_CTLR_MIN_USED_CHAN */
  
  	default:
  isr_rx_conn_unknown_rsp_send:
  		nack = unknown_rsp_send(_radio.conn_curr,
  					pdu_data_rx->llctrl.opcode);
  		break;
  	}
  
  	return nack;
  }
  
  static inline bool isr_rx_conn_enc_unexpected(struct connection *conn,
  					      struct pdu_data *pdu_data)
  {
  	u8_t opcode = pdu_data->llctrl.opcode;
  
  	return (pdu_data->ll_id != PDU_DATA_LLID_CTRL) ||
  	       (!conn->role &&
  		((!conn->refresh &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_TERMINATE_IND) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_START_ENC_REQ) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_START_ENC_RSP) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_REJECT_IND) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND)) ||
  		 (conn->refresh &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_TERMINATE_IND) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_ENC_RSP) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_START_ENC_REQ) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_START_ENC_RSP) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_REJECT_IND) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND)))) ||
  	       (conn->role &&
  		((!conn->refresh &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_TERMINATE_IND) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_START_ENC_RSP) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_REJECT_IND) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND)) ||
  		 (conn->refresh &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_TERMINATE_IND) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_ENC_REQ) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_START_ENC_RSP) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_REJECT_IND) &&
  		  (opcode != PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND))));
  }
  
  static inline u32_t
  isr_rx_conn_pkt(struct radio_pdu_node_rx *node_rx,
  		struct radio_pdu_node_tx **tx_release, u8_t *rx_enqueue)
  {
  	struct pdu_data *pdu_data_rx;
  	struct pdu_data *pdu_data_tx;
  	u32_t ret = 0U;
  
  	/* Ack for transmitted data */
  	pdu_data_rx = (void *)node_rx->pdu_data;
  	if (pdu_data_rx->nesn != _radio.conn_curr->sn) {
  		struct radio_pdu_node_tx *node_tx;
  
  		/* Increment serial number */
  		_radio.conn_curr->sn++;
  
  		/* First ack (and redundantly any other ack) enable use of
  		 * slave latency.
  		 */
  		if (_radio.role == ROLE_SLAVE) {
  			_radio.conn_curr->slave.latency_enabled = 1U;
  		}
  
  		if (!_radio.conn_curr->empty) {
  			node_tx = _radio.conn_curr->pkt_tx_head;
  		} else {
  			_radio.conn_curr->empty = 0U;
  			node_tx = NULL;
  		}
  
  		if (node_tx) {
  			u8_t pdu_data_tx_len;
  
  			pdu_data_tx = (void *)(node_tx->pdu_data +
  				_radio.conn_curr->packet_tx_head_offset);
  
  			pdu_data_tx_len = pdu_data_tx->len;
  			if (pdu_data_tx_len != 0) {
  				/* if encrypted increment tx counter */
  				if (_radio.conn_curr->enc_tx) {
  					_radio.conn_curr->ccm_tx.counter++;
  				}
  
  				/* process ctrl packet on tx cmplt */
  				if (pdu_data_tx->ll_id == PDU_DATA_LLID_CTRL) {
  					ret = isr_rx_conn_pkt_ack(pdu_data_tx,
  								  &node_tx);
  				}
  			}
  
  			_radio.conn_curr->packet_tx_head_offset +=
  				pdu_data_tx_len;
  			if (_radio.conn_curr->packet_tx_head_offset ==
  			    _radio.conn_curr->packet_tx_head_len) {
  				*tx_release = isr_rx_conn_pkt_release(node_tx);
  			}
  		}
  #if defined(CONFIG_BT_CTLR_TX_RETRY_DISABLE)
  	} else if (_radio.packet_counter != 1) {
  		ret = ERR_TX_NACK;
  #endif /* CONFIG_BT_CTLR_TX_RETRY_DISABLE */
  	}
  
  	/* local initiated disconnect procedure completed */
  	if (ret == ERR_TERMINATE) {
  		connection_release(_radio.conn_curr);
  		_radio.conn_curr = NULL;
  
  		return ret;
  	}
  
  	/* process received data */
  	if ((pdu_data_rx->sn == _radio.conn_curr->nesn) &&
  	/* check so that we will NEVER use the rx buffer reserved for empty
  	 * packet and internal control enqueue
  	 */
  	    (packet_rx_reserve_get(3) != 0) &&
  	    ((_radio.fc_ena == 0) ||
  	     ((_radio.link_rx_head == _radio.link_rx_tail) &&
  	      (_radio.fc_req == _radio.fc_ack)) ||
  	     ((_radio.link_rx_head != _radio.link_rx_tail) &&
  	      (_radio.fc_req != _radio.fc_ack) &&
  		(((_radio.fc_req == 0) &&
  		  (_radio.fc_handle[TRIPLE_BUFFER_SIZE - 1] ==
  		   _radio.conn_curr->handle)) ||
  		 ((_radio.fc_req != 0) &&
  		  (_radio.fc_handle[_radio.fc_req - 1] ==
  		   _radio.conn_curr->handle)))))) {
  		u8_t ccm_rx_increment = 0U;
  		u8_t nack = 0U;
  
  		if (pdu_data_rx->len != 0) {
  			bool mic_failure = false;
  
  			/* If required, wait for CCM to finish
  			 */
  			if (_radio.conn_curr->enc_rx) {
  				u32_t done;
  
  				done = radio_ccm_is_done();
  				LL_ASSERT(done);
  
  				mic_failure = !radio_ccm_mic_is_valid();
  
  				if (mic_failure &&
  				    _radio.conn_curr->pause_rx &&
  				    (pdu_data_rx->ll_id ==
  				     PDU_DATA_LLID_CTRL)) {
  					/* Received an LL control packet in the
  					 * middle of the LL encryption procedure
  					 * with MIC failure.
  					 * This could be an unencrypted packet
  					 */
  					struct pdu_data *scratch_pkt =
  						radio_pkt_scratch_get();
  
  					if (pdu_len_cmp(
  					     scratch_pkt->llctrl.opcode,
  					     scratch_pkt->len)) {
  						memcpy(pdu_data_rx,
  						       scratch_pkt,
  						       scratch_pkt->len +
  						       offsetof(struct pdu_data,
  							llctrl));
  						mic_failure = false;
  					}
  				} else {
  					ccm_rx_increment = 1U;
  				}
  			}
  
  			/* MIC Failure Check or data rx during pause */
  			if (mic_failure ||
  			    (_radio.conn_curr->pause_rx &&
  			     isr_rx_conn_enc_unexpected(_radio.conn_curr,
  							pdu_data_rx))) {
  				_radio.state = STATE_CLOSE;
  				radio_disable();
  
  				/* assert if radio packet ptr is not set and
  				 * radio started tx */
  				LL_ASSERT(!radio_is_ready());
  
  				terminate_ind_rx_enqueue(_radio.conn_curr,
  					BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL);
  
  				connection_release(_radio.conn_curr);
  				_radio.conn_curr = NULL;
  
  				return 1; /* terminated */
  			}
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  			/* stop authenticated payload (pre) timeout */
  			_radio.conn_curr->appto_expire = 0U;
  			_radio.conn_curr->apto_expire = 0U;
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  			switch (pdu_data_rx->ll_id) {
  			case PDU_DATA_LLID_DATA_CONTINUE:
  			case PDU_DATA_LLID_DATA_START:
  				/* enqueue data packet */
  				*rx_enqueue = 1U;
  				break;
  
  			case PDU_DATA_LLID_CTRL:
  				nack = isr_rx_conn_pkt_ctrl(node_rx,
  							    rx_enqueue);
  				break;
  			case PDU_DATA_LLID_RESV:
  			default:
  				/* Invalid LL id, drop it. */
  				break;
  			}
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  		} else if ((_radio.conn_curr->enc_rx) ||
  			   (_radio.conn_curr->pause_rx)) {
  			struct connection *conn = _radio.conn_curr;
  			u16_t appto_reload_new;
  
  			/* check for change in apto */
  			appto_reload_new = (conn->apto_reload >
  					    (conn->latency + 6)) ?
  					   (conn->apto_reload -
  					    (conn->latency + 6)) :
  					   conn->apto_reload;
  			if (conn->appto_reload != appto_reload_new) {
  				conn->appto_reload = appto_reload_new;
  				conn->apto_expire = 0U;
  			}
  
  			/* start authenticated payload (pre) timeout */
  			if (conn->apto_expire == 0) {
  				conn->appto_expire = conn->appto_reload;
  				conn->apto_expire = conn->apto_reload;
  			}
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  		}
  
  		if (!nack) {
  			_radio.conn_curr->nesn++;
  
  			if (ccm_rx_increment) {
  				_radio.conn_curr->ccm_rx.counter++;
  			}
  		}
  	}
  
  	return ret;
  }
  
  static inline void isr_rx_conn(u8_t crc_ok, u8_t trx_done,
  			       u8_t rssi_ready)
  {
  	struct radio_pdu_node_rx *node_rx;
  	struct radio_pdu_node_tx *tx_release = NULL;
  	u8_t is_empty_pdu_tx_retry;
  	struct pdu_data *pdu_data_rx;
  	struct pdu_data *pdu_data_tx;
  	u8_t rx_enqueue = 0U;
  	u8_t crc_close = 0U;
  	u32_t rx_ret = 0U;
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR)
  	static u8_t s_lmin = (u8_t) -1;
  	static u8_t s_min = (u8_t) -1;
  	static u8_t s_lmax;
  	static u8_t s_lprv;
  	static u8_t s_max;
  	static u8_t s_prv;
  
  	u8_t latency, elapsed, prv;
  	u32_t radio_tmr_end = 0U;
  	u32_t sample;
  	u8_t chg = 0U;
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  	/* Increment packet counter for this connection event */
  	_radio.packet_counter++;
  
  	/* received data packet */
  	node_rx = _radio.packet_rx[_radio.packet_rx_last];
  	node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
  
  	if (crc_ok) {
  		rx_ret = isr_rx_conn_pkt(node_rx, &tx_release, &rx_enqueue);
  		if (rx_ret == ERR_TERMINATE) {
  			goto isr_rx_conn_exit;
  		}
  
  		/* Reset CRC expiry counter */
  		_radio.crc_expire = 0U;
  
  		/* Reset supervision counter */
  		_radio.conn_curr->supervision_expire = 0U;
  	} else {
  		/* Start CRC error countdown, if not already started */
  		if (_radio.crc_expire == 0) {
  			_radio.crc_expire = 2U;
  		}
  
  		/* Check crc error countdown expiry */
  		_radio.crc_expire--;
  		crc_close = (_radio.crc_expire == 0);
  
  		/* Start supervision timeout, if not started already */
  		if (!_radio.conn_curr->supervision_expire) {
  			_radio.conn_curr->supervision_expire =
  				_radio.conn_curr->supervision_reload;
  		}
  	}
  
  	/* prepare transmit packet */
  	is_empty_pdu_tx_retry = _radio.conn_curr->empty;
  	prepare_pdu_data_tx(_radio.conn_curr, &pdu_data_tx);
  
  	/* silent connection */
  	if (SILENT_CONNECTION) {
  		/* slave silent, enter/be in supervision timeout */
  		if (_radio.packet_counter == 0) {
  			_radio.packet_counter = 0xFF;
  		}
  
  		/* master silent, hence avoid slave drift compensation, and
  		 * close slave if no tx packets
  		 */
  		if (!trx_done) {
  			/* avoid slave drift compensation if first packet
  			 * missed
  			 */
  			if (_radio.packet_counter == 1) {
  				_radio.packet_counter = 0xFF;
  			}
  
  			/* no Rx-ed packet and none to Tx, close event */
  			if ((_radio.conn_curr->empty) &&
  			    (pdu_data_tx->md == 0)) {
  				_radio.state = STATE_CLOSE;
  				radio_disable();
  
  				goto isr_rx_conn_exit;
  			}
  		}
  	}
  
  	/* Decide on event continuation and hence Radio Shorts to use */
  	pdu_data_rx = (void *)node_rx->pdu_data;
  	_radio.state = ((_radio.state == STATE_CLOSE) || (crc_close) ||
  			((crc_ok) && (pdu_data_rx->md == 0) &&
  			 ((pdu_data_tx->len == 0) ||
  #if defined(CONFIG_BT_CTLR_TX_RETRY_DISABLE)
  			  (rx_ret == ERR_TX_NACK))) ||
  #else /* !CONFIG_BT_CTLR_TX_RETRY_DISABLE */
  			  (0))) ||
  #endif /* !CONFIG_BT_CTLR_TX_RETRY_DISABLE */
  			_radio.conn_curr->llcp_terminate.reason_peer) ?
  			STATE_CLOSE : STATE_TX;
  
  	if (_radio.state == STATE_CLOSE) {
  		/* Event close for master */
  		if ((_radio.role == ROLE_MASTER) ||
  #if defined(CONFIG_BT_CTLR_TX_RETRY_DISABLE)
  		    (rx_ret == ERR_TX_NACK)) {
  #else /* !CONFIG_BT_CTLR_TX_RETRY_DISABLE */
  		    (0)) {
  #endif /* !CONFIG_BT_CTLR_TX_RETRY_DISABLE */
  			_radio.conn_curr->empty = is_empty_pdu_tx_retry;
  
  			radio_disable();
  
  			goto isr_rx_conn_exit;
  		}
  		/* Event close for slave */
  		else {
  			radio_switch_complete_and_disable();
  		}
  	} else {	/* if (_radio.state == STATE_TX) */
  		radio_tmr_tifs_set(RADIO_TIFS);
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		radio_switch_complete_and_rx(_radio.conn_curr->phy_rx);
  #else /* !CONFIG_BT_CTLR_PHY */
  		radio_switch_complete_and_rx(0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  		/* capture end of Tx-ed PDU, used to calculate HCTO. */
  		radio_tmr_end_capture();
  	}
  
  	/* fill sn and nesn */
  	pdu_data_tx->sn = _radio.conn_curr->sn;
  	pdu_data_tx->nesn = _radio.conn_curr->nesn;
  
  	/* setup the radio tx packet buffer */
  	tx_packet_set(_radio.conn_curr, pdu_data_tx);
  
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR)
  	/* PA enable is overwriting packet end used in ISR profiling, hence
  	 * back it up for later use.
  	 */
  	radio_tmr_end = radio_tmr_end_get();
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  	radio_gpio_pa_setup();
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() + RADIO_TIFS -
  				 radio_rx_chain_delay_get(
  					 _radio.conn_curr->phy_rx, 1) -
  				 CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #else /* !CONFIG_BT_CTLR_PHY */
  	radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() + RADIO_TIFS -
  				 radio_rx_chain_delay_get(0, 0) -
  				 CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #endif /* !CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CTLR_GPIO_PA_PIN */
  
  	/* assert if radio packet ptr is not set and radio started tx */
  	LL_ASSERT(!radio_is_ready());
  
  isr_rx_conn_exit:
  
  	/* Save the AA captured for the first Rx in connection event */
  	if (!radio_tmr_aa_restore()) {
  		radio_tmr_aa_save(radio_tmr_aa_get());
  	}
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR)
  	/* get the ISR latency sample */
  	sample = radio_tmr_sample_get();
  
  	/* sample the packet timer again, use it to calculate ISR execution time
  	 * and use it in profiling event
  	 */
  	radio_tmr_sample();
  
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  	/* NOTE: Check for connection termination and skip accessing connection
  	 * context.
  	 */
  	if (!_radio.conn_curr) {
  		goto isr_rx_conn_terminate_exit;
  	}
  
  	/* release tx node and generate event for num complete */
  	if (tx_release) {
  		/* forward held rx nodes */
  		if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  			packet_rx_enqueue_forward();
  		}
  
  		pdu_node_tx_release(_radio.conn_curr->handle, tx_release);
  	}
  
  	/* enqueue any rx packet/event towards application */
  	if (rx_enqueue) {
  		/* set data flow control lock on currently rx-ed connection */
  		rx_fc_lock(_radio.conn_curr->handle);
  
  		/* set the connection handle and enqueue */
  		node_rx->hdr.handle = _radio.conn_curr->handle;
  		packet_rx_enqueue();
  	}
  
  	/* forward held rx nodes, if any, and no tx release or rx enqueued */
  	if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD) && !tx_release &&
  	    !rx_enqueue) {
  		packet_rx_enqueue_forward();
  
  		/* callback to trigger application action */
  		packet_rx_callback();
  	}
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  	/* Collect RSSI for connection */
  	if (rssi_ready) {
  		u8_t rssi = radio_rssi_get();
  
  		_radio.conn_curr->rssi_latest = rssi;
  
  		if (((_radio.conn_curr->rssi_reported - rssi) & 0xFF) >
  		    RADIO_RSSI_THRESHOLD) {
  			if (_radio.conn_curr->rssi_sample_count) {
  				_radio.conn_curr->rssi_sample_count--;
  			}
  		} else {
  			_radio.conn_curr->rssi_sample_count =
  				RADIO_RSSI_SAMPLE_COUNT;
  		}
  	}
  #else /* !CONFIG_BT_CTLR_CONN_RSSI */
  	ARG_UNUSED(rssi_ready);
  #endif /* !CONFIG_BT_CTLR_CONN_RSSI */
  
  isr_rx_conn_terminate_exit:
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR)
  	/* calculate the elapsed time in us since on-air radio packet end
  	 * to ISR entry
  	 */
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  	latency = sample - radio_tmr_end;
  #else /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
  	ARG_UNUSED(radio_tmr_end);
  
  	latency = sample - radio_tmr_end_get();
  #endif /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
  
  	/* check changes in min, avg and max of latency */
  	if (latency > s_lmax) {
  		s_lmax = latency;
  		chg = 1U;
  	}
  	if (latency < s_lmin) {
  		s_lmin = latency;
  		chg = 1U;
  	}
  
  	/* check for +/- 1us change */
  	prv = ((u16_t)s_lprv + latency) >> 1;
  	if (prv != s_lprv) {
  		s_lprv = latency;
  		chg = 1U;
  	}
  
  	/* calculate the elapsed time in us since ISR entry */
  	elapsed = radio_tmr_sample_get() - sample;
  
  	/* check changes in min, avg and max */
  	if (elapsed > s_max) {
  		s_max = elapsed;
  		chg = 1U;
  	}
  
  	if (elapsed < s_min) {
  		s_min = elapsed;
  		chg = 1U;
  	}
  
  	/* check for +/- 1us change */
  	prv = ((u16_t)s_prv + elapsed) >> 1;
  	if (prv != s_prv) {
  		s_prv = elapsed;
  		chg = 1U;
  	}
  
  	/* generate event if any change */
  	if (chg) {
  		/* NOTE: enqueue only if rx buffer available, else ignore */
  		node_rx = packet_rx_reserve_get(2);
  		if (node_rx) {
  			node_rx->hdr.handle = 0xFFFF;
  			node_rx->hdr.type = NODE_RX_TYPE_PROFILE;
  			pdu_data_rx = (void *)node_rx->pdu_data;
  			pdu_data_rx->profile.lcur = latency;
  			pdu_data_rx->profile.lmin = s_lmin;
  			pdu_data_rx->profile.lmax = s_lmax;
  			pdu_data_rx->profile.cur = elapsed;
  			pdu_data_rx->profile.min = s_min;
  			pdu_data_rx->profile.max = s_max;
  			packet_rx_enqueue();
  		}
  	}
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  	return;
  }
  #endif /* CONFIG_BT_CONN */
  
  static inline void isr_radio_state_rx(u8_t trx_done, u8_t crc_ok,
  				      u8_t devmatch_ok, u8_t devmatch_id,
  				      u8_t irkmatch_ok, u8_t irkmatch_id,
  				      u8_t rssi_ready)
  {
  	u32_t err;
  	u8_t  rl_idx;
  
  	if (!((trx_done) || ((SILENT_CONNECTION) &&
  			     (_radio.role == ROLE_SLAVE)))) {
  		_radio.state = STATE_CLOSE;
  		radio_disable();
  
  		return;
  	}
  
  	switch (_radio.role) {
  	case ROLE_ADV:
  		if (crc_ok) {
  			err = isr_rx_adv(devmatch_ok, devmatch_id, irkmatch_ok,
  					 irkmatch_id, rssi_ready);
  		} else {
  			err = 1U;
  		}
  		if (err) {
  			_radio.state = STATE_CLOSE;
  			radio_disable();
  		}
  		break;
  
  	case ROLE_SCAN:
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		rl_idx = devmatch_ok ?
  			 ctrl_rl_idx(!!(_radio.scanner.filter_policy & 0x01),
  					devmatch_id) :
  			 irkmatch_ok ? ctrl_rl_irk_idx(irkmatch_id) :
  				       FILTER_IDX_NONE;
  #else
  		rl_idx = FILTER_IDX_NONE;
  #endif
  		if (crc_ok &&
  		    isr_rx_scan_check(irkmatch_ok, devmatch_ok, rl_idx)) {
  			err = isr_rx_scan(devmatch_ok, devmatch_id, irkmatch_ok,
  					  irkmatch_id, rl_idx, rssi_ready);
  		} else {
  			err = 1U;
  		}
  		if (err) {
  			_radio.state = STATE_CLOSE;
  			radio_disable();
  			/* switch scanner state to idle */
  			_radio.scanner.state = 0U;
  		}
  		break;
  
  #if defined(CONFIG_BT_CONN)
  #if defined(CONFIG_BT_PERIPHERAL)
  	case ROLE_SLAVE:
  #endif /* CONFIG_BT_PERIPHERAL */
  #if defined(CONFIG_BT_CENTRAL)
  	case ROLE_MASTER:
  #endif /* CONFIG_BT_CENTRAL */
  		isr_rx_conn(crc_ok, trx_done, rssi_ready);
  		break;
  #endif /* CONFIG_BT_CONN */
  
  	case ROLE_NONE:
  	default:
  		LL_ASSERT(0);
  		break;
  	}
  }
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  static void mayfly_mesh_stop(void *param)
  {
  	struct radio_pdu_node_rx *node_rx;
  	u8_t *adv_slot;
  
  	/* Prepare the rx packet structure */
  	node_rx = packet_rx_reserve_get(1);
  	LL_ASSERT(node_rx);
  
  	/* Connection handle */
  	node_rx->hdr.handle = 0xffff;
  	node_rx->hdr.type = NODE_RX_TYPE_MESH_ADV_CPLT;
  
  	adv_slot = (u8_t *)node_rx->pdu_data;
  	*adv_slot = 0;
  
  	/* enqueue event into rx queue */
  	packet_rx_enqueue();
  }
  
  static void ticker_start_mesh_scan(u32_t status, void *params)
  {
  	ARG_UNUSED(params);
  
  	/* Failed to schedule mesh advertise scan window */
  	if (status && !_radio.advertiser.retry) {
  		static memq_link_t s_link;
  		static struct mayfly s_mfy_mesh_stop = {0, 0, &s_link, NULL,
  							mayfly_mesh_stop};
  		u32_t retval;
  
  		/* Generate an event in WORKER Prio */
  		retval = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
  					RADIO_TICKER_USER_ID_WORKER, 0,
  					&s_mfy_mesh_stop);
  		LL_ASSERT(!retval);
  	}
  }
  
  static inline u32_t isr_close_adv_mesh(void)
  {
  	u32_t ticks_slot_offset;
  	u32_t ticker_status;
  	u32_t ticks_anchor;
  	u32_t ret = 0;
  
  	if (!_radio.advertiser.retry) {
  		ticker_status =	ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  					    RADIO_TICKER_USER_ID_WORKER,
  					    RADIO_TICKER_ID_ADV,
  					    ticker_stop_adv_stop,
  					    (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  
  		ret = 1;
  	} else {
  		_radio.advertiser.retry--;
  	}
  
  	_radio.scanner.ticks_window =
  		HAL_TICKER_US_TO_TICKS(_radio.advertiser.scan_window_ms * 1000 +
  				       radio_tmr_end_get() -
  				       _radio.mesh_adv_end_us);
  
  	_radio.scanner.hdr.ticks_active_to_start =
  		_radio.ticks_active_to_start;
  	_radio.scanner.hdr.ticks_xtal_to_start =
  		HAL_TICKER_US_TO_TICKS(RADIO_TICKER_XTAL_OFFSET_US);
  	_radio.scanner.hdr.ticks_preempt_to_start =
  		HAL_TICKER_US_TO_TICKS(RADIO_TICKER_PREEMPT_PART_MIN_US);
  	_radio.scanner.hdr.ticks_slot =
  		_radio.scanner.ticks_window +
  		HAL_TICKER_US_TO_TICKS(RADIO_TICKER_START_PART_US);
  
  	ticks_slot_offset = (_radio.scanner.hdr.ticks_active_to_start <
  			     _radio.scanner.hdr.ticks_xtal_to_start) ?
  			    _radio.scanner.hdr.ticks_xtal_to_start :
  			    _radio.scanner.hdr.ticks_active_to_start;
  
  	/* FIXME: remainder compensation and chain delays */
  	ticks_anchor = _radio.ticks_anchor +
  		       HAL_TICKER_US_TO_TICKS(_radio.mesh_adv_end_us +
  					      _radio.advertiser.scan_delay_ms *
  					      1000 -
  					      RADIO_TICKER_XTAL_OFFSET_US);
  
  	ticker_status = ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				     RADIO_TICKER_USER_ID_WORKER,
  				     RADIO_TICKER_ID_SCAN,
  				     ticks_anchor, 0, 0, 0, TICKER_NULL_LAZY,
  				     (ticks_slot_offset +
  				      _radio.scanner.hdr.ticks_slot),
  				     event_scan_prepare, NULL,
  				     ticker_start_mesh_scan, NULL);
  	LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  		  (ticker_status == TICKER_STATUS_BUSY));
  
  	return ret;
  }
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  static inline u32_t isr_close_adv(void)
  {
  	u32_t dont_close = 0U;
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	if (_radio.advertiser.is_mesh &&
  	    _radio.state == STATE_CLOSE &&
  	    !_radio.mesh_adv_end_us) {
  		_radio.mesh_adv_end_us = radio_tmr_end_get();
  	}
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  	if ((_radio.state == STATE_CLOSE) &&
  	    (_radio.advertiser.chan_map_current != 0)) {
  		u32_t start_us;
  
  		dont_close = 1U;
  
  		adv_setup();
  
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  		start_us = radio_tmr_start_now(1);
  
  		radio_gpio_pa_setup();
  		radio_gpio_pa_lna_enable(start_us +
  					 radio_tx_ready_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #else /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
  		ARG_UNUSED(start_us);
  
  		radio_tx_enable();
  #endif /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
  
  		/* capture end of Tx-ed PDU, used to calculate HCTO. */
  		radio_tmr_end_capture();
  	} else {
  		radio_filter_disable();
  
  		if ((_radio.state == STATE_CLOSE) &&
  #if defined(CONFIG_BT_PERIPHERAL)
  		    (!_radio.advertiser.is_hdcd)) {
  #else /* !CONFIG_BT_PERIPHERAL */
  		    (1)) {
  #endif /* !CONFIG_BT_PERIPHERAL */
  			u32_t ticker_status;
  			u16_t random_delay;
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  			if (_radio.advertiser.is_mesh) {
  				u32_t err;
  
  				err = isr_close_adv_mesh();
  				if (err) {
  					return 0;
  				}
  			}
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  			entropy_get_entropy_isr(_radio.entropy,
  						(void *)&random_delay,
  						sizeof(random_delay), 0);
  			random_delay %= HAL_TICKER_US_TO_TICKS(10000);
  			random_delay += 1;
  
  			/* Call to ticker_update can fail under the race
  			 * condition where in the Adv role is being stopped but
  			 * at the same time it is preempted by Adv event that
  			 * gets into close state. Accept failure when Adv role
  			 * is being stopped.
  			 */
  			ticker_status =
  				ticker_update(RADIO_TICKER_INSTANCE_ID_RADIO,
  					RADIO_TICKER_USER_ID_WORKER,
  					RADIO_TICKER_ID_ADV, random_delay,
  					0, 0, 0, 0, 0, ticker_update_adv_assert,
  					(void *)__LINE__);
  			LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  				  (ticker_status == TICKER_STATUS_BUSY) ||
  				  (_radio.ticker_id_stop ==
  				   RADIO_TICKER_ID_ADV));
  		}
  
  #if defined(CONFIG_BT_CTLR_ADV_INDICATION)
  		if (1) {
  			struct radio_pdu_node_rx *node_rx;
  
  			node_rx = packet_rx_reserve_get(3);
  			if (node_rx) {
  				node_rx->hdr.type = NODE_RX_TYPE_ADV_INDICATION;
  				node_rx->hdr.handle = 0xFFFF;
  				/* TODO: add other info by defining a payload
  				 * structure.
  				 */
  
  				packet_rx_enqueue();
  			}
  		}
  #endif /* CONFIG_BT_CTLR_ADV_INDICATION */
  	}
  
  	return dont_close;
  }
  
  static inline u32_t isr_close_scan(void)
  {
  	u32_t dont_close = 0U;
  
  	if (_radio.state == STATE_CLOSE) {
  		u32_t start_us;
  
  		dont_close = 1U;
  
  		radio_tmr_tifs_set(RADIO_TIFS);
  		radio_switch_complete_and_tx(0, 0, 0, 0);
  		radio_pkt_rx_set(_radio.packet_rx
  					[_radio.packet_rx_last]->pdu_data);
  		radio_rssi_measure();
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		if (ctrl_rl_enabled()) {
  			u8_t count, *irks = ctrl_irks_get(&count);
  
  			radio_ar_configure(count, irks);
  		}
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  		_radio.state = STATE_RX;
  
  #if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  		start_us = radio_tmr_start_now(0);
  
  		radio_gpio_lna_setup();
  		radio_gpio_pa_lna_enable(start_us +
  					 radio_rx_ready_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #else /* !CONFIG_BT_CTLR_GPIO_LNA_PIN */
  		ARG_UNUSED(start_us);
  
  		radio_rx_enable();
  #endif /* !CONFIG_BT_CTLR_GPIO_LNA_PIN */
  
  		/* capture end of Rx-ed PDU, for initiator to calculate first
  		 * master event.
  		 */
  		radio_tmr_end_capture();
  	} else {
  		radio_filter_disable();
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  		if (_radio.advertiser.is_enabled &&
  		    _radio.advertiser.is_mesh &&
  		    !_radio.advertiser.retry) {
  			mayfly_mesh_stop(NULL);
  		}
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  		if (_radio.state == STATE_ABORT) {
  			/* Scanner stop can expire while here in this ISR.
  			 * Deferred attempt to stop can fail as it would have
  			 * expired, hence ignore failure.
  			 */
  			ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  				    RADIO_TICKER_USER_ID_WORKER,
  				    RADIO_TICKER_ID_SCAN_STOP, NULL, NULL);
  		}
  	}
  
  	return dont_close;
  }
  
  #if defined(CONFIG_BT_CONN)
  static inline void isr_close_conn(void)
  {
  	u32_t ticks_drift_minus;
  	u32_t ticks_drift_plus;
  	u32_t ticks_slot_minus;
  	u32_t ticks_slot_plus;
  	u16_t latency_event;
  	u16_t elapsed_event;
  	u8_t reason_peer;
  	u16_t lazy;
  	u8_t force;
  
  	/* Local initiated terminate happened */
  	if (_radio.conn_curr == 0) {
  		return;
  	}
  
  	/* Master transmitted ack for the received terminate ind or
  	 * Slave received terminate ind.
  	 */
  	reason_peer = _radio.conn_curr->llcp_terminate.reason_peer;
  	if (reason_peer && ((_radio.role == ROLE_SLAVE) ||
  			    _radio.conn_curr->master.terminate_ack)) {
  		terminate_ind_rx_enqueue(_radio.conn_curr, reason_peer);
  
  		connection_release(_radio.conn_curr);
  		_radio.conn_curr = NULL;
  
  		return;
  	}
  
  	latency_event = _radio.conn_curr->latency_event;
  	elapsed_event = latency_event + 1;
  	ticks_drift_minus = 0U;
  	ticks_drift_plus = 0U;
  	ticks_slot_minus = 0U;
  	ticks_slot_plus = 0U;
  
  	/* calculate drift if anchor point sync-ed */
  	if (_radio.packet_counter &&
  	    (!SILENT_CONNECTION || (_radio.packet_counter != 0xFF))) {
  		if (_radio.role == ROLE_SLAVE) {
  			u32_t start_to_address_expected_us;
  			u32_t start_to_address_actual_us;
  			u32_t window_widening_event_us;
  			u32_t preamble_to_addr_us;
  
  			/* calculate the drift in ticks */
  			start_to_address_actual_us = radio_tmr_aa_restore() -
  						     radio_tmr_ready_get();
  			window_widening_event_us =
  				_radio.conn_curr->slave.window_widening_event_us;
  #if defined(CONFIG_BT_CTLR_PHY)
  			preamble_to_addr_us =
  				addr_us_get(_radio.conn_curr->phy_rx);
  #else /* !CONFIG_BT_CTLR_PHY */
  			preamble_to_addr_us = addr_us_get(0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  			start_to_address_expected_us = RADIO_TICKER_JITTER_US +
  				(RADIO_TICKER_JITTER_US << 1) +
  				preamble_to_addr_us +
  				window_widening_event_us;
  			if (start_to_address_actual_us <=
  			    start_to_address_expected_us) {
  				ticks_drift_plus = HAL_TICKER_US_TO_TICKS(
  					window_widening_event_us);
  				ticks_drift_minus = HAL_TICKER_US_TO_TICKS(
  					(start_to_address_expected_us -
  					 start_to_address_actual_us));
  			} else {
  				ticks_drift_plus = HAL_TICKER_US_TO_TICKS(
  					start_to_address_actual_us);
  				ticks_drift_minus = HAL_TICKER_US_TO_TICKS(
  					RADIO_TICKER_JITTER_US +
  					(RADIO_TICKER_JITTER_US << 1) +
  					preamble_to_addr_us);
  			}
  
  			/* Reset window widening, as anchor point sync-ed */
  			_radio.conn_curr->slave.window_widening_event_us = 0U;
  			_radio.conn_curr->slave.window_size_event_us = 0U;
  
  			/* apply latency if no more data */
  			if (_radio.conn_curr->pkt_tx_head) {
  				struct pdu_data *pdu_data_tx;
  
  				pdu_data_tx = (void *)
  					_radio.conn_curr->pkt_tx_head->pdu_data;
  				if (pdu_data_tx->len ||
  				    _radio.conn_curr->packet_tx_head_offset) {
  					_radio.conn_curr->latency_event = 0U;
  				}
  			} else if (_radio.conn_curr->slave.latency_enabled) {
  				_radio.conn_curr->latency_event =
  					_radio.conn_curr->latency;
  			}
  		} else if (reason_peer) {
  			_radio.conn_curr->master.terminate_ack = 1U;
  		}
  
  		/* Reset connection failed to establish procedure */
  		_radio.conn_curr->connect_expire = 0U;
  	}
  
  	/* check connection failed to establish */
  	else if (_radio.conn_curr->connect_expire) {
  		if (_radio.conn_curr->connect_expire > elapsed_event) {
  			_radio.conn_curr->connect_expire -= elapsed_event;
  		} else {
  			terminate_ind_rx_enqueue(_radio.conn_curr,
  						 BT_HCI_ERR_CONN_FAIL_TO_ESTAB);
  
  			connection_release(_radio.conn_curr);
  			_radio.conn_curr = NULL;
  
  			return;
  		}
  	}
  
  	/* if anchor point not sync-ed, start supervision timeout, and break
  	 * latency if any.
  	 */
  	else {
  		/* Start supervision timeout, if not started already */
  		if (!_radio.conn_curr->supervision_expire) {
  			_radio.conn_curr->supervision_expire =
  				_radio.conn_curr->supervision_reload;
  		}
  	}
  
  	/* check supervision timeout */
  	force = 0U;
  	if (_radio.conn_curr->supervision_expire) {
  		if (_radio.conn_curr->supervision_expire > elapsed_event) {
  			_radio.conn_curr->supervision_expire -= elapsed_event;
  
  			/* break latency */
  			_radio.conn_curr->latency_event = 0U;
  
  			/* Force both master and slave when close to
  			 * supervision timeout.
  			 */
  			if (_radio.conn_curr->supervision_expire <= 6) {
  				force = 1U;
  			}
  			/* use randomness to force slave role when anchor
  			 * points are being missed.
  			 */
  			else if (_radio.role == ROLE_SLAVE) {
  				if (latency_event != 0) {
  					force = 1U;
  				} else {
  					force = _radio.conn_curr->slave.force & 0x01;
  
  					/* rotate force bits */
  					_radio.conn_curr->slave.force >>= 1;
  					if (force) {
  						_radio.conn_curr->slave.force |=
  							((u32_t)1 << 31);
  					}
  				}
  			}
  		} else {
  			terminate_ind_rx_enqueue(_radio.conn_curr,
  						 BT_HCI_ERR_CONN_TIMEOUT);
  
  			connection_release(_radio.conn_curr);
  			_radio.conn_curr = NULL;
  
  			return;
  		}
  	}
  
  	/* check procedure timeout */
  	if (_radio.conn_curr->procedure_expire != 0) {
  		if (_radio.conn_curr->procedure_expire > elapsed_event) {
  			_radio.conn_curr->procedure_expire -= elapsed_event;
  		} else {
  			terminate_ind_rx_enqueue(_radio.conn_curr,
  						 BT_HCI_ERR_LL_RESP_TIMEOUT);
  
  			connection_release(_radio.conn_curr);
  			_radio.conn_curr = NULL;
  
  			return;
  		}
  	}
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  	/* check apto */
  	if (_radio.conn_curr->apto_expire != 0) {
  		if (_radio.conn_curr->apto_expire > elapsed_event) {
  			_radio.conn_curr->apto_expire -= elapsed_event;
  		} else {
  			struct radio_pdu_node_rx *node_rx;
  
  			_radio.conn_curr->apto_expire = 0U;
  
  			/* Prepare the rx packet structure */
  			node_rx = packet_rx_reserve_get(2);
  			LL_ASSERT(node_rx);
  
  			node_rx->hdr.handle = _radio.conn_curr->handle;
  			node_rx->hdr.type = NODE_RX_TYPE_APTO;
  
  			/* enqueue apto event into rx queue */
  			packet_rx_enqueue();
  		}
  	}
  
  	/* check appto */
  	if (_radio.conn_curr->appto_expire != 0) {
  		if (_radio.conn_curr->appto_expire > elapsed_event) {
  			_radio.conn_curr->appto_expire -= elapsed_event;
  		} else {
  			_radio.conn_curr->appto_expire = 0U;
  
  			if ((_radio.conn_curr->procedure_expire == 0) &&
  			    (_radio.conn_curr->llcp_req ==
  			     _radio.conn_curr->llcp_ack)) {
  				_radio.conn_curr->llcp_type = LLCP_PING;
  				_radio.conn_curr->llcp_ack--;
  			}
  		}
  	}
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  	/* generate RSSI event */
  	if (_radio.conn_curr->rssi_sample_count == 0) {
  		struct radio_pdu_node_rx *node_rx;
  		struct pdu_data *pdu_data_rx;
  
  		node_rx = packet_rx_reserve_get(2);
  		if (node_rx) {
  			_radio.conn_curr->rssi_reported =
  				_radio.conn_curr->rssi_latest;
  			_radio.conn_curr->rssi_sample_count =
  				RADIO_RSSI_SAMPLE_COUNT;
  
  			/* Prepare the rx packet structure */
  			node_rx->hdr.handle = _radio.conn_curr->handle;
  			node_rx->hdr.type = NODE_RX_TYPE_RSSI;
  
  			/* prepare connection RSSI structure */
  			pdu_data_rx = (void *)node_rx->pdu_data;
  			pdu_data_rx->rssi = _radio.conn_curr->rssi_reported;
  
  			/* enqueue connection RSSI structure into queue */
  			packet_rx_enqueue();
  		}
  	}
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  	/* break latency based on ctrl procedure pending */
  	if ((_radio.conn_curr->llcp_ack != _radio.conn_curr->llcp_req) &&
  	    ((_radio.conn_curr->llcp_type == LLCP_CONN_UPD) ||
  	     (_radio.conn_curr->llcp_type == LLCP_CHAN_MAP))) {
  		_radio.conn_curr->latency_event = 0U;
  	}
  
  	/* check if latency needs update */
  	lazy = 0U;
  	if ((force) || (latency_event != _radio.conn_curr->latency_event)) {
  		lazy = _radio.conn_curr->latency_event + 1;
  	}
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH) || defined(CONFIG_BT_CTLR_PHY)
  	/* TODO: Design connection event length use. for only reserve for single
  	 *       trx.
  	 */
  	if (_radio.conn_curr->evt_len_upd) {
  		u32_t ready_delay, rx_time, tx_time, ticks_slot;
  		struct connection *conn = _radio.conn_curr;
  
  		/* Reset event length update flag */
  		conn->evt_len_upd = 0U;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		ready_delay = (conn->role) ?
  			      radio_rx_ready_delay_get(conn->phy_rx, 1) :
  			      radio_tx_ready_delay_get(conn->phy_tx,
  						       conn->phy_flags);
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		tx_time = conn->max_tx_time;
  		if (conn->evt_len_adv) {
  			rx_time = conn->llcp_length.rx_time;
  		} else {
  			rx_time = conn->max_rx_time;
  		}
  #else /* !CONFIG_BT_CTLR_DATA_LENGTH */
  		tx_time = MAX(RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0),
  			      RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
  					     conn->phy_tx));
  		rx_time = MAX(RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0),
  			      RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
  					     conn->phy_rx));
  #endif /* !CONFIG_BT_CTLR_DATA_LENGTH */
  #else /* !CONFIG_BT_CTLR_PHY */
  		ready_delay = (conn->role) ?
  			      radio_rx_ready_delay_get(0, 0) :
  			      radio_tx_ready_delay_get(0, 0);
  		tx_time = RADIO_PKT_TIME(conn->max_tx_octets, 0);
  		if (conn->evt_len_adv) {
  			rx_time = RADIO_PKT_TIME(conn->llcp_length.rx_octets,
  						 0);
  		} else {
  			rx_time = RADIO_PKT_TIME(conn->max_rx_octets, 0);
  		}
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  		ticks_slot = HAL_TICKER_US_TO_TICKS(RADIO_TICKER_START_PART_US +
  						    ready_delay + RADIO_TIFS +
  						    rx_time + tx_time + 4);
  
  		if (ticks_slot > conn->hdr.ticks_slot) {
  			ticks_slot_plus = ticks_slot - conn->hdr.ticks_slot;
  		} else {
  			ticks_slot_minus = conn->hdr.ticks_slot - ticks_slot;
  		}
  		conn->hdr.ticks_slot = ticks_slot;
  	}
  #endif
  
  	if ((ticks_drift_plus != 0) || (ticks_drift_minus != 0) ||
  	    (ticks_slot_plus != 0) || (ticks_slot_minus != 0) ||
  	    (lazy != 0) || (force != 0)) {
  		u32_t ticker_status;
  		u8_t ticker_id = RADIO_TICKER_ID_FIRST_CONNECTION +
  				    _radio.conn_curr->handle;
  
  		/* Call to ticker_update can fail under the race
  		 * condition where in the Slave role is being stopped but
  		 * at the same time it is preempted by Slave event that
  		 * gets into close state. Accept failure when Slave role
  		 * is being stopped.
  		 */
  		ticker_status =
  			ticker_update(RADIO_TICKER_INSTANCE_ID_RADIO,
  				      RADIO_TICKER_USER_ID_WORKER,
  				      ticker_id,
  				      ticks_drift_plus, ticks_drift_minus,
  				      ticks_slot_plus, ticks_slot_minus,
  				      lazy, force, ticker_update_conn_assert,
  				      (void *)(u32_t)ticker_id);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY) ||
  			  (_radio.ticker_id_stop == ticker_id));
  	}
  }
  #endif /* CONFIG_BT_CONN */
  
  static inline void isr_radio_state_close(void)
  {
  	u32_t dont_close = 0U;
  	int err;
  
  	switch (_radio.role) {
  	case ROLE_ADV:
  		dont_close = isr_close_adv();
  		break;
  
  	case ROLE_SCAN:
  		dont_close = isr_close_scan();
  		break;
  
  #if defined(CONFIG_BT_CONN)
  #if defined(CONFIG_BT_PERIPHERAL)
  	case ROLE_SLAVE:
  #endif /* CONFIG_BT_PERIPHERAL */
  #if defined(CONFIG_BT_CENTRAL)
  	case ROLE_MASTER:
  #endif /* CONFIG_BT_CENTRAL */
  		isr_close_conn();
  		break;
  #endif /* CONFIG_BT_CONN */
  
  	case ROLE_NONE:
  		/* If a role closes graceful while it is being stopped, then
  		 * Radio ISR will be triggered to process the stop state with
  		 * no active role at that instance in time.
  		 * Just reset the state to none. The role has gracefully closed
  		 * before this ISR run.
  		 * The above applies to aborting a role event too.
  		 */
  		LL_ASSERT((_radio.state == STATE_STOP) ||
  			  (_radio.state == STATE_ABORT));
  
  		_radio.state = STATE_NONE;
  
  		return;
  
  	default:
  		LL_ASSERT(0);
  		break;
  	}
  
  	if (dont_close) {
  		return;
  	}
  
  	_radio.role = ROLE_NONE;
  	_radio.state = STATE_NONE;
  	_radio.ticker_id_event = 0U;
  
  	radio_tmr_stop();
  
  	event_inactive(0, 0, 0, NULL);
  
  	err = clock_control_off(_radio.hf_clock, CLOCK_CONTROL_NRF_SUBSYS_HF);
  	if (!err) {
  		DEBUG_RADIO_XTAL(0);
  	}
  
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  	mayfly_enable(RADIO_TICKER_USER_ID_WORKER, RADIO_TICKER_USER_ID_JOB, 1);
  #endif
  
  	DEBUG_RADIO_CLOSE(0);
  }
  
  static void isr(void *param)
  {
  	u8_t trx_done;
  	u8_t crc_ok;
  	u8_t devmatch_ok;
  	u8_t devmatch_id;
  	u8_t irkmatch_ok;
  	u8_t irkmatch_id;
  	u8_t rssi_ready;
  
  	DEBUG_RADIO_ISR(1);
  
  	/* Read radio status and events */
  	trx_done = radio_is_done();
  	if (trx_done) {
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR)
  		/* sample the packet timer here, use it to calculate ISR latency
  		 * and generate the profiling event at the end of the ISR.
  		 */
  		radio_tmr_sample();
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  		crc_ok = radio_crc_is_valid();
  		devmatch_ok = radio_filter_has_match();
  		devmatch_id = radio_filter_match_get();
  		irkmatch_ok = radio_ar_has_match();
  		irkmatch_id = radio_ar_match_get();
  		rssi_ready = radio_rssi_is_ready();
  	} else {
  		crc_ok = devmatch_ok = irkmatch_ok = rssi_ready = 0U;
  		devmatch_id = irkmatch_id = 0xFF;
  	}
  
  	/* Clear radio status and events */
  	radio_status_reset();
  	radio_tmr_status_reset();
  	radio_filter_status_reset();
  	radio_ar_status_reset();
  	radio_rssi_status_reset();
  
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN) || \
      defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  	radio_gpio_pa_lna_disable();
  #endif /* CONFIG_BT_CTLR_GPIO_PA_PIN || CONFIG_BT_CTLR_GPIO_LNA_PIN */
  
  	switch (_radio.state) {
  	case STATE_TX:
  		isr_radio_state_tx();
  		break;
  
  	case STATE_RX:
  		isr_radio_state_rx(trx_done, crc_ok, devmatch_ok, devmatch_id,
  				   irkmatch_ok, irkmatch_id, rssi_ready);
  		break;
  
  	case STATE_ABORT:
  	case STATE_STOP:
  	case STATE_CLOSE:
  		isr_radio_state_close();
  		break;
  
  	case STATE_NONE:
  		/* Ignore Duplicate Radio Disabled IRQ due to forced stop
  		 * using Radio Disable task.
  		 */
  		break;
  
  	default:
  		LL_ASSERT(0);
  		break;
  	}
  
  	DEBUG_RADIO_ISR(0);
  }
  
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  static void ticker_job_disable(u32_t status, void *op_context)
  {
  	ARG_UNUSED(status);
  	ARG_UNUSED(op_context);
  
  	if (_radio.state != STATE_NONE) {
  		mayfly_enable(RADIO_TICKER_USER_ID_JOB,
  			      RADIO_TICKER_USER_ID_JOB, 0);
  	}
  }
  #endif
  
  static void ticker_if_done(u32_t status, void *ops_context)
  {
  	*((u32_t volatile *)ops_context) = status;
  }
  
  static void ticker_success_assert(u32_t status, void *params)
  {
  	ARG_UNUSED(params);
  
  	LL_ASSERT(status == TICKER_STATUS_SUCCESS);
  }
  
  static void ticker_update_adv_assert(u32_t status, void *params)
  {
  	ARG_UNUSED(params);
  
  	LL_ASSERT((status == TICKER_STATUS_SUCCESS) ||
  		  (_radio.ticker_id_stop == RADIO_TICKER_ID_ADV));
  }
  
  #if defined(CONFIG_BT_CONN)
  #if defined(CONFIG_BT_PERIPHERAL)
  static void ticker_stop_adv_assert(u32_t status, void *params)
  {
  	ARG_UNUSED(params);
  
  	if (status == TICKER_STATUS_FAILURE) {
  		if (_radio.ticker_id_stop == RADIO_TICKER_ID_ADV) {
  			/* ticker_stop failed due to race condition
  			 * while in role_disable. Let the role_disable
  			 * be made aware of, so it can return failure
  			 * (to stop Adv role as it is now transitioned
  			 * to Slave role).
  			 */
  			_radio.ticker_id_stop = 0U;
  		} else {
  			LL_ASSERT(0);
  		}
  	} else {
  		/* This assert shall not happen if advertiser role's slot
  		 * calculation is correct, and next event shall not
  		 * overlap/pre-empt the current advertise role event.
  		 */
  		LL_ASSERT(_radio.ticker_id_prepare != RADIO_TICKER_ID_ADV);
  	}
  }
  #endif /* CONFIG_BT_PERIPHERAL */
  
  #if defined(CONFIG_BT_CENTRAL)
  static void ticker_stop_scan_assert(u32_t status, void *params)
  {
  	ARG_UNUSED(params);
  
  	if (status == TICKER_STATUS_FAILURE) {
  		if (_radio.ticker_id_stop == RADIO_TICKER_ID_SCAN) {
  			/* ticker_stop failed due to race condition
  			 * while in role_disable. Let the role_disable
  			 * be made aware of, so it can return failure
  			 * (to stop Scan role as it is now transitioned
  			 * to Master role).
  			 */
  			_radio.ticker_id_stop = 0U;
  		} else {
  			LL_ASSERT(0);
  		}
  	} else {
  		/* This assert shall not happen if scanner role's slot
  		 * calculation is correct, and next event shall not
  		 * overlap/pre-empt the current scanner role event.
  		 */
  		LL_ASSERT(_radio.ticker_id_prepare != RADIO_TICKER_ID_SCAN);
  	}
  }
  #endif /* CONFIG_BT_CENTRAL */
  
  static void ticker_update_conn_assert(u32_t status, void *params)
  {
  	u8_t ticker_id = (u32_t)params & 0xFF;
  
  	LL_ASSERT((status == TICKER_STATUS_SUCCESS) ||
  		  (_radio.ticker_id_stop == ticker_id) ||
  		  (_radio.ticker_id_upd == ticker_id));
  }
  
  static void ticker_stop_conn_assert(u32_t status, void *params)
  {
  	LL_ASSERT(status == TICKER_STATUS_SUCCESS);
  
  	_radio.ticker_id_upd = (u8_t)((u32_t)params & 0xFF);
  }
  
  static void ticker_start_conn_assert(u32_t status, void *params)
  {
  	LL_ASSERT(status == TICKER_STATUS_SUCCESS);
  
  	_radio.ticker_id_upd = 0;
  }
  #endif /* CONFIG_BT_CONN */
  
  static void mayfly_radio_active(void *params)
  {
  	static u8_t s_active;
  
  	if ((u32_t)params) {
  		if (s_active++) {
  			return;
  		}
  
  		DEBUG_RADIO_ACTIVE(1);
  
  		radio_active_callback(1);
  	} else {
  		LL_ASSERT(s_active);
  
  		if (--s_active) {
  			return;
  		}
  
  		DEBUG_RADIO_ACTIVE(0);
  
  		radio_active_callback(0);
  	}
  }
  
  static void event_active(u32_t ticks_at_expire, u32_t remainder,
  			 u16_t lazy, void *context)
  {
  	static memq_link_t s_link;
  	static struct mayfly s_mfy_radio_active = {0, 0, &s_link, (void *)1,
  						   mayfly_radio_active};
  	u32_t retval;
  
  	ARG_UNUSED(ticks_at_expire);
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  	ARG_UNUSED(context);
  
  	retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
  				RADIO_TICKER_USER_ID_WORKER, 0,
  				&s_mfy_radio_active);
  	LL_ASSERT(!retval);
  }
  
  static void mayfly_radio_inactive(void *params)
  {
  	ARG_UNUSED(params);
  
  	mayfly_radio_active(0);
  
  	DEBUG_RADIO_CLOSE(0);
  }
  
  static void event_inactive(u32_t ticks_at_expire, u32_t remainder,
  			   u16_t lazy, void *context)
  {
  	static memq_link_t s_link;
  	static struct mayfly s_mfy_radio_inactive = {0, 0, &s_link, NULL,
  						     mayfly_radio_inactive};
  	u32_t retval;
  
  	ARG_UNUSED(ticks_at_expire);
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  	ARG_UNUSED(context);
  
  	retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
  				RADIO_TICKER_USER_ID_WORKER, 0,
  				&s_mfy_radio_inactive);
  	LL_ASSERT(!retval);
  }
  
  static void mayfly_xtal_start(void *params)
  {
  	int err;
  
  	ARG_UNUSED(params);
  
  	/* turn on 16MHz clock, non-blocking mode. */
  	err = clock_control_on(_radio.hf_clock, CLOCK_CONTROL_NRF_SUBSYS_HF);
  	LL_ASSERT(!err || (err == -EINPROGRESS));
  
  	DEBUG_RADIO_XTAL(1);
  }
  
  static void event_xtal(u32_t ticks_at_expire, u32_t remainder,
  		       u16_t lazy, void *context)
  {
  	static memq_link_t s_link;
  	static struct mayfly s_mfy_xtal_start = {0, 0, &s_link, NULL,
  						 mayfly_xtal_start};
  	u32_t retval;
  
  	ARG_UNUSED(ticks_at_expire);
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  	ARG_UNUSED(context);
  
  	retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
  				RADIO_TICKER_USER_ID_WORKER, 0,
  				&s_mfy_xtal_start);
  	LL_ASSERT(!retval);
  }
  
  static void mayfly_xtal_stop(void *params)
  {
  	int err;
  
  	ARG_UNUSED(params);
  
  	err = clock_control_off(_radio.hf_clock, CLOCK_CONTROL_NRF_SUBSYS_HF);
  	if (!err) {
  		DEBUG_RADIO_XTAL(0);
  	}
  
  	DEBUG_RADIO_CLOSE(0);
  }
  
  static void k32src_wait(void)
  {
  	static bool done;
  
  	if (done) {
  		return;
  	}
  	done = true;
  
  	struct device *clock = device_get_binding(
  		DT_INST_0_NORDIC_NRF_CLOCK_LABEL);
  
  	LL_ASSERT(clock);
  
  	while (clock_control_on(clock, CLOCK_CONTROL_NRF_SUBSYS_LF)) {
  		DEBUG_CPU_SLEEP(1);
  		cpu_sleep();
  		DEBUG_CPU_SLEEP(0);
  	}
  }
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  #define XON_BITMASK BIT(31) /* XTAL has been retained from previous prepare */
  
  static void mayfly_xtal_retain(u8_t caller_id, u8_t retain)
  {
  	static u8_t s_xtal_retained;
  
  	if (retain) {
  		if (!s_xtal_retained) {
  			static memq_link_t s_link;
  			static struct mayfly s_mfy_xtal_start = {0, 0, &s_link,
  				NULL, mayfly_xtal_start};
  			u32_t retval;
  
  			/* Only user id job will try to retain the XTAL. */
  			LL_ASSERT(caller_id == RADIO_TICKER_USER_ID_JOB);
  
  			s_xtal_retained = 1U;
  
  			retval = mayfly_enqueue(caller_id,
  						RADIO_TICKER_USER_ID_WORKER, 0,
  						&s_mfy_xtal_start);
  			LL_ASSERT(!retval);
  		}
  	} else {
  		if (s_xtal_retained) {
  			static memq_link_t s_link[2];
  			static struct mayfly s_mfy_xtal_stop[2] = {
  				{0, 0, &s_link[0], NULL, mayfly_xtal_stop},
  				{0, 0, &s_link[1], NULL, mayfly_xtal_stop}
  			};
  			struct mayfly *p_mfy_xtal_stop = NULL;
  			u32_t retval;
  
  			s_xtal_retained = 0U;
  
  			switch (caller_id) {
  			case RADIO_TICKER_USER_ID_WORKER:
  				p_mfy_xtal_stop = &s_mfy_xtal_stop[0];
  				break;
  
  			case RADIO_TICKER_USER_ID_JOB:
  				p_mfy_xtal_stop = &s_mfy_xtal_stop[1];
  				break;
  
  			default:
  				LL_ASSERT(0);
  				break;
  			}
  
  			retval = mayfly_enqueue(caller_id,
  						RADIO_TICKER_USER_ID_WORKER, 0,
  						p_mfy_xtal_stop);
  			LL_ASSERT(!retval);
  		}
  	}
  }
  
  static void prepare_reduced(u32_t status, void *op_context)
  {
  	/* It is acceptable that ticker_update will fail, if ticker is stopped;
  	 * for example, scan ticker is stopped on connection estblishment but
  	 * is also preempted.
  	 */
  	if (status == 0) {
  		struct shdr *hdr = (void *)op_context;
  
  		hdr->ticks_xtal_to_start |= XON_BITMASK;
  	}
  }
  
  static void prepare_normal(u32_t status, void *op_context)
  {
  	/* It is acceptable that ticker_update will fail, if ticker is stopped;
  	 * for example, scan ticker is stopped on connection estblishment but
  	 * is also preempted.
  	 */
  	if (status == 0) {
  		struct shdr *hdr = (void *)op_context;
  
  		hdr->ticks_xtal_to_start &= ~XON_BITMASK;
  	}
  }
  
  static void prepare_normal_set(struct shdr *hdr, u8_t ticker_user_id,
  			       u8_t ticker_id)
  {
  	if (hdr->ticks_xtal_to_start & XON_BITMASK) {
  		u32_t ticker_status;
  		u32_t ticks_prepare_to_start =
  			MAX(hdr->ticks_active_to_start,
  			    hdr->ticks_preempt_to_start);
  		u32_t ticks_drift_minus = (hdr->ticks_xtal_to_start &
  					   ~XON_BITMASK) -
  					  ticks_prepare_to_start;
  
  		ticker_status =
  			ticker_update(RADIO_TICKER_INSTANCE_ID_RADIO,
  				      ticker_user_id,
  				      ticker_id, 0, ticks_drift_minus,
  				      ticks_drift_minus, 0, 0, 0,
  				      prepare_normal, hdr);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	}
  }
  
  #if (RADIO_TICKER_PREEMPT_PART_US <= RADIO_TICKER_PREEMPT_PART_MIN_US)
  static u32_t preempt_calc(struct shdr *hdr, u8_t ticker_id,
  			  u32_t ticks_at_expire)
  {
  	u32_t diff =
  		ticker_ticks_diff_get(ticker_ticks_now_get(), ticks_at_expire);
  
  	diff += 3;
  	if (diff > HAL_TICKER_US_TO_TICKS(RADIO_TICKER_START_PART_US)) {
  		mayfly_xtal_retain(RADIO_TICKER_USER_ID_WORKER, 0);
  
  		prepare_normal_set(hdr, RADIO_TICKER_USER_ID_WORKER, ticker_id);
  
  		diff += hdr->ticks_preempt_to_start;
  		if (diff <
  		    HAL_TICKER_US_TO_TICKS(RADIO_TICKER_PREEMPT_PART_MAX_US)) {
  			hdr->ticks_preempt_to_start = diff;
  		}
  
  		return 1;
  	}
  
  	return 0;
  }
  #endif
  
  static inline struct shdr *hdr_conn_get(u8_t ticker_id,
  					struct connection **conn)
  {
  	if (ticker_id >= RADIO_TICKER_ID_FIRST_CONNECTION) {
  		*conn = mem_get(_radio.conn_pool, CONNECTION_T_SIZE,
  				(ticker_id -
  				 RADIO_TICKER_ID_FIRST_CONNECTION));
  		return &(*conn)->hdr;
  	} else if (ticker_id == RADIO_TICKER_ID_ADV) {
  		return &_radio.advertiser.hdr;
  	} else if (ticker_id == RADIO_TICKER_ID_SCAN) {
  		return &_radio.scanner.hdr;
  	}
  
  	return NULL;
  }
  
  /* This function decides to start (additional call) xtal ahead of next ticker,
   * if next ticker is close to current ticker expire.
   *
   * NOTE: This function also detects if two tickers of same interval are drifting
   * close and issues a conn param req or does a conn update.
   *
   * TODO: Detect drift for already overlapping tickers.
   */
  static void mayfly_xtal_stop_calc(void *params)
  {
  	u8_t ticker_id_curr = ((u32_t)params & 0xff);
  	u32_t volatile ret_cb = TICKER_STATUS_BUSY;
  	struct connection *conn_curr = NULL;
  	struct connection *conn_next = NULL;
  	u32_t ticks_prepare_to_start_next;
  	struct shdr *hdr_curr = NULL;
  	struct shdr *hdr_next = NULL;
  	u32_t ticks_to_expire;
  	u32_t ticks_slot_abs;
  	u32_t ticks_current;
  	u8_t ticker_id_next;
  	u32_t ret;
  
  
  	ticker_id_next = 0xff;
  	ticks_to_expire = 0U;
  	do {
  		ret = ticker_next_slot_get(RADIO_TICKER_INSTANCE_ID_RADIO,
  					   RADIO_TICKER_USER_ID_JOB,
  					   &ticker_id_next, &ticks_current,
  					   &ticks_to_expire, ticker_if_done,
  					   (void *)&ret_cb);
  
  		if (ret == TICKER_STATUS_BUSY) {
  			while (ret_cb == TICKER_STATUS_BUSY) {
  				ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO,
  						 RADIO_TICKER_USER_ID_JOB);
  			}
  		}
  
  		LL_ASSERT(ret_cb == TICKER_STATUS_SUCCESS);
  	} while (ticker_id_next != TICKER_NULL &&
  		 ticker_id_next >= (RADIO_TICKER_ID_FIRST_CONNECTION +
  				    _radio.connection_count));
  
  	if ((ticker_id_next == TICKER_NULL) ||
  	    (ticker_id_next < RADIO_TICKER_ID_ADV) ||
  	    (ticker_id_next >= (RADIO_TICKER_ID_FIRST_CONNECTION +
  				_radio.connection_count))) {
  		mayfly_xtal_retain(RADIO_TICKER_USER_ID_JOB, 0);
  
  		return;
  	}
  
  	/* Select the current role's scheduling header */
  	hdr_curr = hdr_conn_get(ticker_id_curr, &conn_curr);
  	LL_ASSERT(hdr_curr);
  
  	/* Compensate for current ticker in reduced prepare */
  	if (hdr_curr->ticks_xtal_to_start & XON_BITMASK) {
  		ticks_slot_abs = MAX(hdr_curr->ticks_active_to_start,
  				     hdr_curr->ticks_preempt_to_start);
  	} else {
  		ticks_slot_abs = MAX(hdr_curr->ticks_active_to_start,
  				     hdr_curr->ticks_xtal_to_start);
  	}
  	ticks_slot_abs += hdr_curr->ticks_slot;
  
  	/* Select the next role's scheduling header */
  	hdr_next = hdr_conn_get(ticker_id_next, &conn_next);
  	LL_ASSERT(hdr_next);
  
  	ticks_prepare_to_start_next =
  		MAX(hdr_next->ticks_active_to_start,
  		    hdr_next->ticks_preempt_to_start);
  
  	/* Compensate for next ticker in reduced prepare */
  	if (hdr_next->ticks_xtal_to_start & XON_BITMASK) {
  		u32_t ticks_reduced = (hdr_next->ticks_xtal_to_start &
  				       ~XON_BITMASK) -
  				      ticks_prepare_to_start_next;
  
  		if (ticks_to_expire > ticks_reduced) {
  			ticks_to_expire -= ticks_reduced;
  		} else {
  			ticks_to_expire = 0U;
  		}
  	}
  
  	/* If beyond the xtal threshold reset to normal the next prepare,
  	 * else retain xtal and reduce the next prepare.
  	 */
  	if (ticks_to_expire >
  	    (ticks_slot_abs +
  	     HAL_TICKER_US_TO_TICKS(CONFIG_BT_CTLR_XTAL_THRESHOLD))) {
  		mayfly_xtal_retain(RADIO_TICKER_USER_ID_JOB, 0);
  		prepare_normal_set(hdr_next, RADIO_TICKER_USER_ID_JOB,
  				   ticker_id_next);
  	} else {
  		mayfly_xtal_retain(RADIO_TICKER_USER_ID_JOB, 1);
  
  		/* Reduce the next prepare if not already and, active to start
  		 * and preempt to start both are less than xtal to start
  		 */
  		if (!(hdr_next->ticks_xtal_to_start & XON_BITMASK) &&
  		    (hdr_next->ticks_xtal_to_start >
  		     ticks_prepare_to_start_next)) {
  			u32_t ticks_drift_plus = hdr_next->ticks_xtal_to_start -
  						 ticks_prepare_to_start_next;
  			u32_t ticker_status;
  
  			ticker_status =
  				ticker_update(RADIO_TICKER_INSTANCE_ID_RADIO,
  					      RADIO_TICKER_USER_ID_JOB,
  					      ticker_id_next,
  					      ticks_drift_plus, 0,
  					      0, ticks_drift_plus,
  					      0, 0,
  					      prepare_reduced, hdr_next);
  			LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  				  (ticker_status == TICKER_STATUS_BUSY));
  		}
  
  #if defined(CONFIG_BT_CONN) && defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  		if (!conn_curr || !conn_next) {
  			return;
  		}
  
  		/* auto conn param req or conn update procedure to
  		 * avoid connection collisions due to drifting roles.
  		 */
  		if (conn_curr->conn_interval == conn_next->conn_interval) {
  			u32_t ticks_conn_interval = HAL_TICKER_US_TO_TICKS(
  				conn_curr->conn_interval * 1250);
  
  			/* remove laziness, if any, from
  			 * ticks_to_expire.
  			 */
  			while (ticks_to_expire > ticks_conn_interval) {
  				ticks_to_expire -= ticks_conn_interval;
  			}
  
  			/* if next ticker close to this ticker, send
  			 * conn param req.
  			 */
  			if (conn_curr->role && !conn_next->role &&
  			    (ticks_to_expire <
  			     (ticks_slot_abs +
  			      HAL_TICKER_US_TO_TICKS(RADIO_TIES_US)))) {
  				u32_t status;
  
  				status = conn_update_req(conn_curr);
  				if (status == 2) {
  					conn_update_req(conn_next);
  				}
  			} else if (!conn_curr->role && conn_next->role &&
  				   (ticks_to_expire <
  				    (ticks_slot_abs +
  				     HAL_TICKER_US_TO_TICKS(RADIO_TIES_US)))) {
  				u32_t status;
  
  				status = conn_update_req(conn_next);
  				if (status == 2) {
  					conn_update_req(conn_curr);
  				}
  			}
  		}
  #endif /* CONFIG_BT_CONN && CONFIG_BT_CTLR_SCHED_ADVANCED */
  	}
  }
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  static void sched_after_mstr_free_slot_get(u8_t user_id,
  					   u32_t ticks_slot_abs,
  					   u32_t *ticks_anchor,
  					   u32_t *us_offset)
  {
  	u32_t ticks_to_expire_prev;
  	u32_t ticks_slot_abs_prev;
  	u32_t ticks_to_expire;
  	u8_t ticker_id_prev;
  	u8_t ticker_id;
  
  	ticks_slot_abs += HAL_TICKER_US_TO_TICKS(RADIO_TICKER_JITTER_US << 3);
  
  	ticker_id = ticker_id_prev = 0xff;
  	ticks_to_expire = ticks_to_expire_prev = *us_offset = 0U;
  	ticks_slot_abs_prev = 0U;
  	while (1) {
  		u32_t volatile ret_cb = TICKER_STATUS_BUSY;
  		struct connection *conn;
  		u32_t ret;
  
  		ret = ticker_next_slot_get(RADIO_TICKER_INSTANCE_ID_RADIO,
  					   user_id, &ticker_id, ticks_anchor,
  					   &ticks_to_expire, ticker_if_done,
  					   (void *)&ret_cb);
  
  		if (ret == TICKER_STATUS_BUSY) {
  			while (ret_cb == TICKER_STATUS_BUSY) {
  				ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO,
  						 user_id);
  			}
  		}
  
  		LL_ASSERT(ret_cb == TICKER_STATUS_SUCCESS);
  
  		if (ticker_id == 0xff) {
  			break;
  		}
  
  		if (ticker_id < RADIO_TICKER_ID_FIRST_CONNECTION ||
  		    ticker_id >= (RADIO_TICKER_ID_FIRST_CONNECTION +
  				  _radio.connection_count)) {
  			continue;
  		}
  
  		conn = mem_get(_radio.conn_pool, CONNECTION_T_SIZE,
  			       (ticker_id - RADIO_TICKER_ID_FIRST_CONNECTION));
  		if (conn && !conn->role) {
  			u32_t ticks_to_expire_normal = ticks_to_expire;
  			u32_t ticks_slot_abs_curr;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  			if (conn->hdr.ticks_xtal_to_start & XON_BITMASK) {
  				u32_t ticks_prepare_to_start =
  					MAX(conn->hdr.ticks_active_to_start,
  					    conn->hdr.ticks_preempt_to_start);
  
  				ticks_slot_abs_curr =
  					conn->hdr.ticks_xtal_to_start &
  					~XON_BITMASK;
  				ticks_to_expire_normal -=
  					ticks_slot_abs_curr -
  					ticks_prepare_to_start;
  			} else
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  			{
  				u32_t ticks_prepare_to_start =
  					MAX(conn->hdr.ticks_active_to_start,
  					    conn->hdr.ticks_xtal_to_start);
  
  				ticks_slot_abs_curr = ticks_prepare_to_start;
  			}
  
  			ticks_slot_abs_curr +=
  				conn->hdr.ticks_slot +
  				HAL_TICKER_US_TO_TICKS(RADIO_TICKER_JITTER_US <<
  						       3);
  
  			if ((ticker_id_prev != 0xFF) &&
  			    (ticker_ticks_diff_get(ticks_to_expire_normal,
  						   ticks_to_expire_prev) >
  			     (ticks_slot_abs_prev + ticks_slot_abs))) {
  				break;
  			}
  
  			ticker_id_prev = ticker_id;
  			ticks_to_expire_prev = ticks_to_expire_normal;
  			ticks_slot_abs_prev = ticks_slot_abs_curr;
  		}
  	}
  
  	if (ticker_id_prev != 0xff) {
  		*us_offset = HAL_TICKER_TICKS_TO_US(ticks_to_expire_prev +
  						    ticks_slot_abs_prev) +
  						    (RADIO_TICKER_JITTER_US <<
  						     3);
  	}
  }
  
  static void sched_after_mstr_free_offset_get(u16_t conn_interval,
  					     u32_t ticks_slot,
  					     u32_t ticks_anchor,
  					     u32_t *win_offset_us)
  {
  	u32_t ticks_anchor_offset = ticks_anchor;
  
  	sched_after_mstr_free_slot_get(RADIO_TICKER_USER_ID_JOB,
  				       (HAL_TICKER_US_TO_TICKS(
  						RADIO_TICKER_XTAL_OFFSET_US) +
  					ticks_slot), &ticks_anchor_offset,
  				       win_offset_us);
  
  	if (!*win_offset_us) {
  		return;
  	}
  
  	LL_ASSERT(!((ticks_anchor_offset - ticks_anchor) &
  		    BIT(HAL_TICKER_CNTR_MSBIT)));
  
  	*win_offset_us += HAL_TICKER_TICKS_TO_US(
  		ticker_ticks_diff_get(ticks_anchor_offset,
  				      ticks_anchor));
  
  	if ((*win_offset_us & BIT(31)) == 0) {
  		u32_t conn_interval_us = conn_interval * 1250;
  
  		while (*win_offset_us > conn_interval_us) {
  			*win_offset_us -= conn_interval_us;
  		}
  	}
  }
  
  static void mayfly_sched_after_mstr_free_offset_get(void *params)
  {
  	sched_after_mstr_free_offset_get(_radio.scanner.conn_interval,
  					 _radio.scanner.ticks_conn_slot,
  					 (u32_t)params,
  					 &_radio.scanner.win_offset_us);
  }
  
  #if defined(CONFIG_BT_CONN)
  static void mayfly_sched_win_offset_use(void *params)
  {
  	struct connection *conn = params;
  	u16_t win_offset;
  
  	sched_after_mstr_free_offset_get(conn->conn_interval,
  				conn->hdr.ticks_slot,
  				conn->llcp.conn_upd.ticks_anchor,
  				&conn->llcp_cu.win_offset_us);
  
  	win_offset = conn->llcp_cu.win_offset_us / 1250;
  	memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset,
  	       sizeof(u16_t));
  }
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  static void sched_free_win_offset_calc(struct connection *conn_curr,
  				       u8_t is_select,
  				       u32_t *ticks_to_offset_next,
  				       u16_t conn_interval,
  				       u8_t *offset_max,
  				       u8_t *win_offset)
  {
  	u32_t ticks_prepare_reduced = 0U;
  	u32_t ticks_to_expire_prev;
  	u32_t ticks_slot_abs_prev;
  	u32_t ticks_anchor_prev;
  	u32_t ticks_to_expire;
  	u32_t ticks_slot_abs;
  	u8_t ticker_id_other;
  	u8_t ticker_id_prev;
  	u32_t ticks_anchor;
  	u8_t offset_index;
  	u16_t _win_offset;
  	u8_t ticker_id;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  	if (conn_curr->hdr.ticks_xtal_to_start & XON_BITMASK) {
  		u32_t ticks_prepare_to_start =
  			MAX(conn_curr->hdr.ticks_active_to_start,
  			    conn_curr->hdr.ticks_preempt_to_start);
  
  		ticks_slot_abs = conn_curr->hdr.ticks_xtal_to_start &
  				 ~XON_BITMASK;
  		ticks_prepare_reduced = ticks_slot_abs - ticks_prepare_to_start;
  	} else
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  	{
  		u32_t ticks_prepare_to_start =
  			MAX(conn_curr->hdr.ticks_active_to_start,
  			    conn_curr->hdr.ticks_xtal_to_start);
  
  		ticks_slot_abs = ticks_prepare_to_start;
  	}
  
  	ticks_slot_abs += conn_curr->hdr.ticks_slot +
  			  HAL_TICKER_US_TO_TICKS(RADIO_TIES_US + 1250);
  
  	ticker_id = ticker_id_prev = ticker_id_other = 0xFF;
  	ticks_to_expire = ticks_to_expire_prev = ticks_anchor =
  		ticks_anchor_prev = offset_index = _win_offset = 0U;
  	ticks_slot_abs_prev = 0U;
  	do {
  		u32_t volatile ret_cb = TICKER_STATUS_BUSY;
  		struct connection *conn;
  		u32_t ret;
  
  		ret = ticker_next_slot_get(RADIO_TICKER_INSTANCE_ID_RADIO,
  					   RADIO_TICKER_USER_ID_JOB,
  					   &ticker_id, &ticks_anchor,
  					   &ticks_to_expire, ticker_if_done,
  					   (void *)&ret_cb);
  
  		if (ret == TICKER_STATUS_BUSY) {
  			while (ret_cb == TICKER_STATUS_BUSY) {
  				ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO,
  						 RADIO_TICKER_USER_ID_JOB);
  			}
  		}
  
  		LL_ASSERT(ret_cb == TICKER_STATUS_SUCCESS);
  
  		if (ticker_id == 0xff) {
  			break;
  		}
  
  		/* ticks_anchor shall not change during this loop */
  		if ((ticker_id_prev != 0xff) &&
  		    (ticks_anchor != ticks_anchor_prev)) {
  			LL_ASSERT(0);
  		}
  
  		/* consider advertiser time as available. Any other time used by
  		 * tickers declared outside the controller is also available.
  		 */
  		if (ticker_id <= RADIO_TICKER_ID_ADV ||
  		    ticker_id >= (RADIO_TICKER_ID_FIRST_CONNECTION +
  				  _radio.connection_count)) {
  			continue;
  		}
  
  		if (ticker_id < RADIO_TICKER_ID_FIRST_CONNECTION) {
  			/* non conn role found which could have preempted a
  			 * conn role, hence do not consider this free space
  			 * and any further as free slot for offset,
  			 */
  			ticker_id_other = ticker_id;
  			continue;
  		}
  
  		/* TODO: handle scanner; for now we exit with as much we
  		 * where able to fill (offsets).
  		 */
  		if (ticker_id_other != 0xFF) {
  			break;
  		}
  
  		conn = mem_get(_radio.conn_pool, CONNECTION_T_SIZE,
  			       (ticker_id - RADIO_TICKER_ID_FIRST_CONNECTION));
  
  		if ((conn != conn_curr) && (is_select || !conn->role)) {
  			u32_t ticks_to_expire_normal =
  				ticks_to_expire + ticks_prepare_reduced;
  			u32_t ticks_slot_abs_curr;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  			if (conn->hdr.ticks_xtal_to_start & XON_BITMASK) {
  				u32_t ticks_prepare_to_start =
  					MAX(conn->hdr.ticks_active_to_start,
  					    conn->hdr.ticks_preempt_to_start);
  
  				ticks_slot_abs_curr =
  					conn->hdr.ticks_xtal_to_start &
  					~XON_BITMASK;
  				ticks_to_expire_normal -=
  					ticks_slot_abs_curr -
  					ticks_prepare_to_start;
  			} else
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  			{
  				u32_t ticks_prepare_to_start =
  					MAX(conn->hdr.ticks_active_to_start,
  					    conn->hdr.ticks_xtal_to_start);
  
  				ticks_slot_abs_curr = ticks_prepare_to_start;
  			}
  
  			ticks_slot_abs_curr +=
  				conn->hdr.ticks_slot +
  				HAL_TICKER_US_TO_TICKS(RADIO_TIES_US + 1250);
  
  			if (*ticks_to_offset_next < ticks_to_expire_normal) {
  				if (ticks_to_expire_prev < *ticks_to_offset_next) {
  					ticks_to_expire_prev =
  						*ticks_to_offset_next;
  				}
  
  				while ((offset_index < *offset_max) &&
  				       (ticker_ticks_diff_get(
  							ticks_to_expire_normal,
  							ticks_to_expire_prev) >=
  					(ticks_slot_abs_prev +
  					 ticks_slot_abs))) {
  					_win_offset = HAL_TICKER_TICKS_TO_US(
  						ticks_to_expire_prev +
  						ticks_slot_abs_prev) / 1250;
  					if (_win_offset >= conn_interval) {
  						ticks_to_expire_prev = 0U;
  
  						break;
  					}
  
  					memcpy(win_offset +
  					       (sizeof(u16_t) * offset_index),
  					       &_win_offset, sizeof(u16_t));
  					offset_index++;
  
  					ticks_to_expire_prev +=
  						HAL_TICKER_US_TO_TICKS(1250);
  				}
  
  				*ticks_to_offset_next = ticks_to_expire_prev;
  
  				if (_win_offset >= conn_interval) {
  					break;
  				}
  			}
  
  			ticks_anchor_prev = ticks_anchor;
  			ticker_id_prev = ticker_id;
  			ticks_to_expire_prev = ticks_to_expire_normal;
  			ticks_slot_abs_prev = ticks_slot_abs_curr;
  		}
  	} while (offset_index < *offset_max);
  
  	if (ticker_id == 0xFF) {
  		if (ticks_to_expire_prev < *ticks_to_offset_next) {
  			ticks_to_expire_prev = *ticks_to_offset_next;
  		}
  
  		while (offset_index < *offset_max) {
  			_win_offset = HAL_TICKER_TICKS_TO_US(
  					ticks_to_expire_prev +
  					ticks_slot_abs_prev) / 1250;
  			if (_win_offset >= conn_interval) {
  				ticks_to_expire_prev = 0U;
  
  				break;
  			}
  
  			memcpy(win_offset + (sizeof(u16_t) * offset_index),
  			       &_win_offset, sizeof(u16_t));
  			offset_index++;
  
  			ticks_to_expire_prev += HAL_TICKER_US_TO_TICKS(1250);
  		}
  
  		*ticks_to_offset_next = ticks_to_expire_prev;
  	}
  
  	*offset_max = offset_index;
  }
  
  static void mayfly_sched_free_win_offset_calc(void *params)
  {
  	struct connection *conn = params;
  	u32_t ticks_to_offset_default = 0U;
  	u32_t *ticks_to_offset_next;
  	u8_t offset_max = 6U;
  
  	ticks_to_offset_next = &ticks_to_offset_default;
  
  	if (conn->role) {
  		conn->llcp_conn_param.ticks_to_offset_next =
  			conn->slave.ticks_to_offset;
  
  		ticks_to_offset_next =
  			&conn->llcp_conn_param.ticks_to_offset_next;
  	}
  
  	sched_free_win_offset_calc(conn, 0, ticks_to_offset_next,
  				   conn->llcp_conn_param.interval_max,
  				   &offset_max,
  				   (u8_t *)conn->llcp_conn_param.pdu_win_offset0);
  }
  
  static void mayfly_sched_win_offset_select(void *params)
  {
  #define OFFSET_S_MAX 6
  #define OFFSET_M_MAX 6
  	struct connection *conn = params;
  	u16_t win_offset_m[OFFSET_M_MAX] = {0, };
  	u8_t offset_m_max = OFFSET_M_MAX;
  	u8_t offset_index_s = 0U;
  	u8_t has_offset_s = 0U;
  	u32_t ticks_to_offset;
  	u16_t win_offset_s;
  
  	ticks_to_offset = HAL_TICKER_US_TO_TICKS(conn->llcp_conn_param.offset0 *
  						 1250);
  
  	sched_free_win_offset_calc(conn, 1, &ticks_to_offset,
  				   conn->llcp_conn_param.interval_max,
  				   &offset_m_max, (u8_t *)&win_offset_m[0]);
  
  	while (offset_index_s < OFFSET_S_MAX) {
  		u8_t offset_index_m = 0U;
  
  		memcpy((u8_t *)&win_offset_s,
  		       ((u8_t *)&conn->llcp_conn_param.offset0 +
  			(sizeof(u16_t) * offset_index_s)), sizeof(u16_t));
  
  		while (offset_index_m < offset_m_max) {
  			if (win_offset_s != 0xffff) {
  				if (win_offset_s ==
  				    win_offset_m[offset_index_m]) {
  					break;
  				}
  
  				has_offset_s = 1U;
  			}
  
  			offset_index_m++;
  		}
  
  		if (offset_index_m < offset_m_max) {
  			break;
  		}
  
  		offset_index_s++;
  	}
  
  	if (offset_index_s < OFFSET_S_MAX) {
  		conn->llcp_cu.win_offset_us = win_offset_s * 1250;
  		memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset_s,
  		       sizeof(u16_t));
  	} else if (!has_offset_s) {
  		conn->llcp_cu.win_offset_us = win_offset_m[0] * 1250;
  		memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset_m[0],
  		       sizeof(u16_t));
  	} else {
  		struct pdu_data *pdu_ctrl_tx;
  
  		/* procedure request acked */
  		conn->llcp_ack = conn->llcp_req;
  
  		/* CPR request acked */
  		conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
  
  		/* reset mutex */
  		_radio.conn_upd = NULL;
  
  		/* send reject_ind_ext */
  		pdu_ctrl_tx = (void *)
  			((u8_t *)conn->llcp.conn_upd.pdu_win_offset -
  			 offsetof(struct pdu_data,
  				  llctrl.conn_update_ind.win_offset));
  		pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_tx->len =
  			offsetof(struct pdu_data_llctrl, reject_ext_ind) +
  			sizeof(struct pdu_data_llctrl_reject_ext_ind);
  		pdu_ctrl_tx->llctrl.opcode =
  			PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND;
  		pdu_ctrl_tx->llctrl.reject_ext_ind.reject_opcode =
  			PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
  		pdu_ctrl_tx->llctrl.reject_ext_ind.error_code =
  			BT_HCI_ERR_UNSUPP_LL_PARAM_VAL;
  	}
  }
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  #endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
  #endif /* CONFIG_BT_CONN */
  
  static void mayfly_radio_stop(void *params)
  {
  	enum state state = (enum state)((u32_t)params & 0xff);
  	u32_t radio_used;
  
  	LL_ASSERT((state == STATE_STOP) || (state == STATE_ABORT));
  
  	radio_used = ((_radio.state != STATE_NONE) &&
  		      (_radio.state != STATE_STOP) &&
  		      (_radio.state != STATE_ABORT));
  	if (radio_used || !radio_is_idle()) {
  		if (radio_used) {
  			_radio.state = state;
  		}
  
  		/** @todo try designing so as to not to abort tx packet */
  		radio_disable();
  	}
  }
  
  static void event_stop(u32_t ticks_at_expire, u32_t remainder,
  		       u16_t lazy, void *context)
  {
  	static memq_link_t s_link;
  	static struct mayfly s_mfy_radio_stop = {0, 0, &s_link, NULL,
  						 mayfly_radio_stop};
  	u32_t retval;
  
  	ARG_UNUSED(ticks_at_expire);
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  
  	/* Radio state requested (stop or abort) stored in context is supplied
  	 * in params.
  	 */
  	s_mfy_radio_stop.param = context;
  
  	/* Stop Radio Tx/Rx */
  	retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
  				RADIO_TICKER_USER_ID_WORKER, 0,
  				&s_mfy_radio_stop);
  	LL_ASSERT(!retval);
  }
  
  static void event_common_prepare(u32_t ticks_at_expire,
  				 u32_t remainder,
  				 u32_t *ticks_xtal_to_start,
  				 u32_t *ticks_active_to_start,
  				 u32_t ticks_preempt_to_start,
  				 u8_t ticker_id,
  				 ticker_timeout_func ticker_timeout_fp,
  				 void *context)
  {
  	u32_t ticker_status;
  	u32_t _ticks_xtal_to_start = *ticks_xtal_to_start;
  	u32_t _ticks_active_to_start = *ticks_active_to_start;
  	u32_t ticks_to_start;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  	/* in case this event is short prepare, xtal to start duration will be
  	 * active to start duration.
  	 */
  	if (_ticks_xtal_to_start & XON_BITMASK) {
  		_ticks_xtal_to_start = MAX(_ticks_active_to_start,
  					   ticks_preempt_to_start);
  	}
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  	/* decide whether its XTAL start or active event that is the current
  	 * execution context and accordingly setup the ticker for the other
  	 * event (XTAL or active event). These are oneshot ticker.
  	 */
  	if (_ticks_active_to_start < _ticks_xtal_to_start) {
  		u32_t ticks_to_active;
  
  		/* XTAL is before Active */
  		ticks_to_active = _ticks_xtal_to_start - _ticks_active_to_start;
  		ticks_to_start = _ticks_xtal_to_start;
  
  		ticker_status =
  			ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				     RADIO_TICKER_USER_ID_WORKER,
  				     RADIO_TICKER_ID_MARKER_0, ticks_at_expire,
  				     ticks_to_active, TICKER_NULL_PERIOD,
  				     TICKER_NULL_REMAINDER, TICKER_NULL_LAZY,
  				     TICKER_NULL_SLOT, event_active, NULL,
  				     ticker_success_assert, (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  
  		event_xtal(0, 0, 0, NULL);
  	} else if (_ticks_active_to_start > _ticks_xtal_to_start) {
  		u32_t ticks_to_xtal;
  
  		/* Active is before XTAL */
  		ticks_to_xtal = _ticks_active_to_start - _ticks_xtal_to_start;
  		ticks_to_start = _ticks_active_to_start;
  
  		event_active(0, 0, 0, NULL);
  
  		ticker_status =
  			ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				     RADIO_TICKER_USER_ID_WORKER,
  				     RADIO_TICKER_ID_MARKER_0, ticks_at_expire,
  				     ticks_to_xtal, TICKER_NULL_PERIOD,
  				     TICKER_NULL_REMAINDER, TICKER_NULL_LAZY,
  				     TICKER_NULL_SLOT, event_xtal, NULL,
  				     ticker_success_assert, (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	} else {
  		/* Active and XTAL are at the same time,
  		 * no ticker required to be setup.
  		 */
  		ticks_to_start = _ticks_xtal_to_start;
  
  		event_active(0, 0, 0, NULL);
  		event_xtal(0, 0, 0, NULL);
  	}
  
  	/* remember the remainder to be used in pkticker */
  	_radio.remainder_anchor = remainder;
  
  	/* setup the start ticker */
  	ticker_status =
  		ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  			     RADIO_TICKER_USER_ID_WORKER, RADIO_TICKER_ID_EVENT,
  			     ticks_at_expire, ticks_to_start,
  			     TICKER_NULL_PERIOD, TICKER_NULL_REMAINDER,
  			     TICKER_NULL_LAZY, TICKER_NULL_SLOT,
  			     ticker_timeout_fp, context, ticker_success_assert,
  			     (void *)__LINE__);
  	LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  		  (ticker_status == TICKER_STATUS_BUSY));
  
  #define RADIO_DEFERRED_PREEMPT 0
  #if RADIO_DEFERRED_PREEMPT
  	/* setup pre-empt ticker if any running state present */
  	if (_radio.state != STATE_NONE) {
  		ticker_status =
  			ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				     RADIO_TICKER_USER_ID_WORKER,
  				     RADIO_TICKER_ID_PRE_EMPT, ticks_at_expire,
  				     (ticks_to_start - conn->hdr.ticks_preempt_to_start),
  				     TICKER_NULL_PERIOD, TICKER_NULL_REMAINDER,
  				     TICKER_NULL_LAZY, TICKER_NULL_SLOT,
  				     event_stop, (void *)STATE_ABORT,
  				     ticker_success_assert, (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	}
  #else
  	event_stop(0, 0, 0, (void *)STATE_ABORT);
  #endif
  #undef RADIO_DEFERRED_PREEMPT
  
  	/** Handle change in _ticks_active_to_start */
  	if (_radio.ticks_active_to_start != _ticks_active_to_start) {
  		u32_t ticks_to_start_new;
  
  		*ticks_active_to_start = _radio.ticks_active_to_start;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  		if (*ticks_xtal_to_start & XON_BITMASK) {
  			*ticks_xtal_to_start &= ~XON_BITMASK;
  		}
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  		ticks_to_start_new = MAX(_radio.ticks_active_to_start,
  					 *ticks_xtal_to_start);
  
  		/* drift the primary as required due to active line change */
  		ticker_status =
  			ticker_update(RADIO_TICKER_INSTANCE_ID_RADIO,
  				      RADIO_TICKER_USER_ID_WORKER, ticker_id,
  				      ticks_to_start, ticks_to_start_new,
  				      ticks_to_start_new, ticks_to_start, 0, 0,
  				      ticker_success_assert, (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	}
  
  	/* route all packets queued for connections */
  	packet_tx_enqueue(0xFF);
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  	/* calc whether xtal needs to be retained after this event */
  	{
  		static memq_link_t s_link;
  		static struct mayfly s_mfy_xtal_stop_calc = {0, 0, &s_link, NULL,
  			mayfly_xtal_stop_calc};
  		u32_t retval;
  
  		s_mfy_xtal_stop_calc.param = (void *)(u32_t)ticker_id;
  
  		retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
  					RADIO_TICKER_USER_ID_JOB, 1,
  					&s_mfy_xtal_stop_calc);
  		LL_ASSERT(!retval);
  	}
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  }
  
  static void chan_set(u32_t chan)
  {
  	switch (chan) {
  	case 37:
  		radio_freq_chan_set(2);
  		break;
  
  	case 38:
  		radio_freq_chan_set(26);
  		break;
  
  	case 39:
  		radio_freq_chan_set(80);
  		break;
  
  	default:
  		if (chan < 11) {
  			radio_freq_chan_set(4 + (2 * chan));
  		} else if (chan < 40) {
  			radio_freq_chan_set(28 + (2 * (chan - 11)));
  		} else {
  			LL_ASSERT(0);
  		}
  		break;
  	}
  
  	radio_whiten_iv_set(chan);
  }
  
  #if defined(CONFIG_BT_CONN)
  static u8_t chan_sel_remap(u8_t *chan_map, u8_t chan_index)
  {
  	u8_t chan_next;
  	u8_t byte_count;
  
  	chan_next = 0U;
  	byte_count = 5U;
  	while (byte_count--) {
  		u8_t bite;
  		u8_t bit_count;
  
  		bite = *chan_map;
  		bit_count = 8U;
  		while (bit_count--) {
  			if (bite & 0x01) {
  				if (chan_index == 0) {
  					break;
  				}
  				chan_index--;
  			}
  			chan_next++;
  			bite >>= 1;
  		}
  
  		if (bit_count < 8) {
  			break;
  		}
  
  		chan_map++;
  	}
  
  	return chan_next;
  }
  
  static u8_t chan_sel_1(u8_t *chan_use, u8_t hop, u16_t latency, u8_t *chan_map,
  		       u8_t chan_count)
  {
  	u8_t chan_next;
  
  	chan_next = ((*chan_use) + (hop * (1 + latency))) % 37;
  	*chan_use = chan_next;
  
  	if ((chan_map[chan_next >> 3] & (1 << (chan_next % 8))) == 0) {
  		u8_t chan_index;
  
  		chan_index = chan_next % chan_count;
  		chan_next = chan_sel_remap(chan_map, chan_index);
  
  	} else {
  		/* channel can be used, return it */
  	}
  
  	return chan_next;
  }
  
  #if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
  static u8_t chan_rev_8(u8_t i)
  {
  	u8_t iterate;
  	u8_t o;
  
  	o = 0U;
  	for (iterate = 0U; iterate < 8; iterate++) {
  		o <<= 1;
  		o |= (i & 1);
  		i >>= 1;
  	}
  
  	return o;
  }
  
  static u16_t chan_perm(u16_t i)
  {
  	return (chan_rev_8((i >> 8) & 0xFF) << 8) | chan_rev_8(i & 0xFF);
  }
  
  static u16_t chan_mam(u16_t a, u16_t b)
  {
  	return ((u32_t)a * 17 + b) & 0xFFFF;
  }
  
  static u16_t chan_prn(u16_t counter, u16_t chan_id)
  {
  	u8_t iterate;
  	u16_t prn_e;
  
  	prn_e = counter ^ chan_id;
  
  	for (iterate = 0U; iterate < 3; iterate++) {
  		prn_e = chan_perm(prn_e);
  		prn_e = chan_mam(prn_e, chan_id);
  	}
  
  	prn_e ^= chan_id;
  
  	return prn_e;
  }
  
  static u8_t chan_sel_2(u16_t counter, u16_t chan_id, u8_t *chan_map,
  		       u8_t chan_count)
  {
  	u8_t chan_next;
  	u16_t prn_e;
  
  	prn_e = chan_prn(counter, chan_id);
  	chan_next = prn_e % 37;
  
  	if ((chan_map[chan_next >> 3] & (1 << (chan_next % 8))) == 0) {
  		u8_t chan_index;
  
  		chan_index = ((u32_t)chan_count * prn_e) >> 16;
  		chan_next = chan_sel_remap(chan_map, chan_index);
  
  	} else {
  		/* channel can be used, return it */
  	}
  
  	return chan_next;
  }
  
  #if defined(RADIO_UNIT_TEST)
  static void chan_sel_2_ut(void)
  {
  	u8_t chan_map_1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x1F};
  	u8_t chan_map_2[] = {0x00, 0x06, 0xE0, 0x00, 0x1E};
  	u8_t m;
  
  	m = chan_sel_2(1, 0x305F, chan_map_1, 37);
  	LL_ASSERT(m == 20);
  
  	m = chan_sel_2(2, 0x305F, chan_map_1, 37);
  	LL_ASSERT(m == 6);
  
  	m = chan_sel_2(3, 0x305F, chan_map_1, 37);
  	LL_ASSERT(m == 21);
  
  	m = chan_sel_2(6, 0x305F, chan_map_2, 9);
  	LL_ASSERT(m == 23);
  
  	m = chan_sel_2(7, 0x305F, chan_map_2, 9);
  	LL_ASSERT(m == 9);
  
  	m = chan_sel_2(8, 0x305F, chan_map_2, 9);
  	LL_ASSERT(m == 34);
  }
  #endif /* RADIO_UNIT_TEST */
  #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */
  
  /** @brief Prepare access address as per BT Spec.
   *
   * - It shall have no more than six consecutive zeros or ones.
   * - It shall not be the advertising channel packets' Access Address.
   * - It shall not be a sequence that differs from the advertising channel
   *   packets Access Address by only one bit.
   * - It shall not have all four octets equal.
   * - It shall have no more than 24 transitions.
   * - It shall have a minimum of two transitions in the most significant six
   *   bits.
   *
   * LE Coded PHY requirements:
   * - It shall have at least three ones in the least significant 8 bits.
   * - It shall have no more than eleven transitions in the least significant 16
   *   bits.
   */
  static u32_t access_addr_get(void)
  {
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  	u8_t transitions_lsb16;
  	u8_t ones_count_lsb8;
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  	u8_t consecutive_cnt;
  	u8_t consecutive_bit;
  	u32_t adv_aa_check;
  	u32_t access_addr;
  	u8_t transitions;
  	u8_t bit_idx;
  	u8_t retry;
  
  	retry = 3U;
  again:
  	LL_ASSERT(retry);
  	retry--;
  
  	util_rand(&access_addr, sizeof(u32_t));
  
  	bit_idx = 31U;
  	transitions = 0U;
  	consecutive_cnt = 1U;
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  	ones_count_lsb8 = 0U;
  	transitions_lsb16 = 0U;
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  	consecutive_bit = (access_addr >> bit_idx) & 0x01;
  	while (bit_idx--) {
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  		u8_t transitions_lsb16_prev = transitions_lsb16;
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  		u8_t consecutive_cnt_prev = consecutive_cnt;
  		u8_t transitions_prev = transitions;
  		u8_t bit;
  
  		bit = (access_addr >> bit_idx) & 0x01;
  		if (bit == consecutive_bit) {
  			consecutive_cnt++;
  		} else {
  			consecutive_cnt = 1U;
  			consecutive_bit = bit;
  			transitions++;
  
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  			if (bit_idx < 15) {
  				transitions_lsb16++;
  			}
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  		}
  
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  		if ((bit_idx < 8) && bit) {
  			ones_count_lsb8++;
  		}
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  
  		/* It shall have no more than six consecutive zeros or ones. */
  		/* It shall have a minimum of two transitions in the most
  		 * significant six bits.
  		 */
  		if ((consecutive_cnt > 6) ||
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  		    (!bit && (((bit_idx < 6) && (ones_count_lsb8 < 1)) ||
  			      ((bit_idx < 5) && (ones_count_lsb8 < 2)) ||
  			      ((bit_idx < 4) && (ones_count_lsb8 < 3)))) ||
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  		    ((consecutive_cnt < 6) &&
  		     (((bit_idx < 29) && (transitions < 1)) ||
  		      ((bit_idx < 28) && (transitions < 2))))) {
  			if (consecutive_bit) {
  				consecutive_bit = 0U;
  				access_addr &= ~BIT(bit_idx);
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  				if (bit_idx < 8) {
  					ones_count_lsb8--;
  				}
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  			} else {
  				consecutive_bit = 1U;
  				access_addr |= BIT(bit_idx);
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  				if (bit_idx < 8) {
  					ones_count_lsb8++;
  				}
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  			}
  
  			if (transitions != transitions_prev) {
  				consecutive_cnt = consecutive_cnt_prev;
  				transitions = transitions_prev;
  			} else {
  				consecutive_cnt = 1U;
  				transitions++;
  			}
  
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  			if (bit_idx < 15) {
  				if (transitions_lsb16 !=
  				    transitions_lsb16_prev) {
  					transitions_lsb16 =
  						transitions_lsb16_prev;
  				} else {
  					transitions_lsb16++;
  				}
  			}
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  		}
  
  		/* It shall have no more than 24 transitions
  		 * It shall have no more than eleven transitions in the least
  		 * significant 16 bits.
  		 */
  		if ((transitions > 24) ||
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  		    (transitions_lsb16 > 11) ||
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  		    0) {
  			if (consecutive_bit) {
  				access_addr &= ~(BIT(bit_idx + 1) - 1);
  			} else {
  				access_addr |= (BIT(bit_idx + 1) - 1);
  			}
  
  			break;
  		}
  	}
  
  	/* It shall not be the advertising channel packets Access Address.
  	 * It shall not be a sequence that differs from the advertising channel
  	 * packets Access Address by only one bit.
  	 */
  	adv_aa_check = access_addr ^ PDU_AC_ACCESS_ADDR;
  	if (util_ones_count_get((u8_t *)&adv_aa_check,
  				sizeof(adv_aa_check)) <= 1) {
  		goto again;
  	}
  
  	/* It shall not have all four octets equal. */
  	if (!((access_addr & 0xFFFF) ^ (access_addr >> 16)) &&
  	    !((access_addr & 0xFF) ^ (access_addr >> 24))) {
  		goto again;
  	}
  
  	return access_addr;
  }
  #endif /* CONFIG_BT_CONN */
  
  void radio_event_adv_prepare(u32_t ticks_at_expire, u32_t remainder,
  			     u16_t lazy, void *context)
  {
  	ARG_UNUSED(lazy);
  	ARG_UNUSED(context);
  
  	DEBUG_RADIO_PREPARE_A(1);
  
  	LL_ASSERT(!_radio.ticker_id_prepare);
  	_radio.ticker_id_prepare = RADIO_TICKER_ID_ADV;
  
  	event_common_prepare(ticks_at_expire, remainder,
  			     &_radio.advertiser.hdr.ticks_xtal_to_start,
  			     &_radio.advertiser.hdr.ticks_active_to_start,
  			     _radio.advertiser.hdr.ticks_preempt_to_start,
  			     RADIO_TICKER_ID_ADV, event_adv, NULL);
  
  	DEBUG_RADIO_PREPARE_A(0);
  }
  
  static void adv_setup(void)
  {
  	struct pdu_adv *pdu;
  	u8_t bitmap;
  	u8_t chan;
  	u8_t upd = 0U;
  
  	/* Use latest adv data PDU buffer */
  	if (_radio.advertiser.adv_data.first !=
  	    _radio.advertiser.adv_data.last) {
  		u8_t first;
  
  		first = _radio.advertiser.adv_data.first + 1;
  		if (first == DOUBLE_BUFFER_SIZE) {
  			first = 0U;
  		}
  		_radio.advertiser.adv_data.first = first;
  		upd = 1U;
  	}
  
  	/* Use latest scan data PDU buffer */
  	if (_radio.advertiser.scan_data.first != _radio.
  	    advertiser.scan_data.last) {
  		u8_t first;
  
  		first = _radio.advertiser.scan_data.first + 1;
  		if (first == DOUBLE_BUFFER_SIZE) {
  			first = 0U;
  		}
  		_radio.advertiser.scan_data.first = first;
  		upd = 1U;
  	}
  
  	pdu = (void *)_radio.advertiser.adv_data.data
  					[_radio.advertiser.adv_data.first];
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	if (upd) {
  		struct pdu_adv *scan_pdu = (void *)
  			_radio.advertiser.scan_data.data
  					[_radio.advertiser.scan_data.first];
  
  		/* Copy the address from the adv packet we will send into the
  		 * scan response.
  		 */
  		memcpy(&scan_pdu->scan_rsp.addr[0],
  		       &pdu->adv_ind.addr[0], BDADDR_SIZE);
  	}
  #else
  	ARG_UNUSED(upd);
  #endif /* !CONFIG_BT_CTLR_PRIVACY */
  
  	radio_pkt_tx_set(pdu);
  
  	if ((pdu->type != PDU_ADV_TYPE_NONCONN_IND) &&
  	    (!IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT) ||
  	     (pdu->type != PDU_ADV_TYPE_EXT_IND))) {
  		_radio.state = STATE_TX;
  		radio_tmr_tifs_set(RADIO_TIFS);
  		radio_switch_complete_and_rx(0);
  	} else {
  		_radio.state = STATE_CLOSE;
  		radio_switch_complete_and_disable();
  	}
  
  	bitmap = _radio.advertiser.chan_map_current;
  	chan = 0U;
  	while ((bitmap & 0x01) == 0) {
  		chan++;
  		bitmap >>= 1;
  	}
  	_radio.advertiser.chan_map_current &=
  		(_radio.advertiser.chan_map_current - 1);
  
  	chan_set(37 + chan);
  }
  
  static void event_adv(u32_t ticks_at_expire, u32_t remainder,
  		      u16_t lazy, void *context)
  {
  	u32_t remainder_us;
  	u32_t aa = PDU_AC_ACCESS_ADDR;
  
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  	ARG_UNUSED(context);
  
  	DEBUG_RADIO_START_A(1);
  
  	LL_ASSERT(_radio.role == ROLE_NONE);
  	LL_ASSERT(_radio.ticker_id_prepare == RADIO_TICKER_ID_ADV);
  
  	/** @todo check if XTAL is started,
  	 * options 1: abort Radio Start,
  	 * 2: wait for XTAL start.
  	 */
  
  	_radio.role = ROLE_ADV;
  	_radio.ticker_id_prepare = 0U;
  	_radio.ticker_id_event = RADIO_TICKER_ID_ADV;
  	_radio.ticks_anchor = ticks_at_expire;
  
  	radio_reset();
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  	radio_tx_power_set(_radio.advertiser.tx_pwr_lvl);
  #else
  	radio_tx_power_set(RADIO_TXP_DEFAULT);
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  	radio_isr_set(isr, NULL);
  
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  	/* TODO: if coded we use S8? */
  	radio_phy_set(_radio.advertiser.phy_p, 1);
  	radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX,
  			(_radio.advertiser.phy_p << 1));
  #else /* !CONFIG_BT_CTLR_ADV_EXT */
  	radio_phy_set(0, 0);
  	radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX, 0);
  #endif /* !CONFIG_BT_CTLR_ADV_EXT */
  
  	radio_aa_set((u8_t *)&aa);
  	radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
  			    0x555555);
  
  	_radio.advertiser.chan_map_current = _radio.advertiser.chan_map;
  	adv_setup();
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	_radio.mesh_adv_end_us = 0;
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  
  	/* Setup Radio Filter */
  	if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY) && ctrl_rl_enabled()) {
  		struct ll_filter *filter =
  			ctrl_filter_get(!!(_radio.advertiser.filter_policy));
  
  		radio_filter_configure(filter->enable_bitmask,
  				       filter->addr_type_bitmask,
  				       (u8_t *)filter->bdaddr);
  	} else if (IS_ENABLED(CONFIG_BT_CTLR_FILTER) &&
  		   _radio.advertiser.filter_policy) {
  
  		struct ll_filter *wl = ctrl_filter_get(true);
  
  		radio_filter_configure(wl->enable_bitmask,
  				       wl->addr_type_bitmask,
  				       (u8_t *)wl->bdaddr);
  	}
  
  	remainder_us = radio_tmr_start(1, ticks_at_expire +
  					  HAL_TICKER_US_TO_TICKS(
  						RADIO_TICKER_START_PART_US),
  				       _radio.remainder_anchor);
  
  	/* capture end of Tx-ed PDU, used to calculate HCTO. */
  	radio_tmr_end_capture();
  
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  	radio_gpio_pa_setup();
  	radio_gpio_pa_lna_enable(remainder_us +
  				 radio_tx_ready_delay_get(0, 0) -
  				 CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #else /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
  	ARG_UNUSED(remainder_us);
  #endif /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
  
  #if (defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
       (RADIO_TICKER_PREEMPT_PART_US <= RADIO_TICKER_PREEMPT_PART_MIN_US))
  	/* check if preempt to start has changed */
  	if (preempt_calc(&_radio.advertiser.hdr, RADIO_TICKER_ID_ADV,
  			 ticks_at_expire) != 0) {
  		_radio.state = STATE_STOP;
  		radio_disable();
  	} else
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  	/* Ticker Job Silence */
  	{
  		u32_t ticker_status;
  
  		ticker_status =
  		    ticker_job_idle_get(RADIO_TICKER_INSTANCE_ID_RADIO,
  					RADIO_TICKER_USER_ID_WORKER,
  					ticker_job_disable, NULL);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	}
  #endif
  
  	DEBUG_RADIO_START_A(0);
  }
  
  #if defined(CONFIG_BT_PERIPHERAL) || defined(CONFIG_BT_HCI_MESH_EXT)
  #if defined(CONFIG_BT_PERIPHERAL)
  static void mayfly_adv_stop(void *param)
  {
  	struct radio_le_conn_cmplt *radio_le_conn_cmplt;
  	struct radio_pdu_node_rx *node_rx;
  
  	/* Prepare the rx packet structure */
  	node_rx = packet_rx_reserve_get(1);
  	LL_ASSERT(node_rx);
  
  	/** Connection handle */
  	node_rx->hdr.handle = 0xffff;
  	node_rx->hdr.type = NODE_RX_TYPE_CONNECTION;
  
  	/* prepare connection complete structure */
  	radio_le_conn_cmplt = (void *)node_rx->pdu_data;
  	(void)memset(radio_le_conn_cmplt, 0x00,
  		     sizeof(struct radio_le_conn_cmplt));
  	radio_le_conn_cmplt->status = BT_HCI_ERR_ADV_TIMEOUT;
  
  	/* enqueue connection complete structure into queue */
  	packet_rx_enqueue();
  }
  #endif /* CONFIG_BT_PERIPHERAL */
  
  static inline void ticker_stop_adv_stop_active(void)
  {
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  	static memq_link_t link_calc;
  	static struct mayfly s_mfy_xtal_calc = {0, 0, &link_calc,
  						(void *)RADIO_TICKER_ID_ADV,
  						mayfly_xtal_stop_calc};
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  	static memq_link_t link_inact;
  	static struct mayfly s_mfy_radio_inactive = {0, 0, &link_inact, NULL,
  						     mayfly_radio_inactive};
  	u32_t volatile ret_cb_evt = TICKER_STATUS_BUSY;
  	u32_t ret;
  
  	/* Step 2: Is caller before Event? Stop Event */
  	ret = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  			  RADIO_TICKER_USER_ID_JOB, RADIO_TICKER_ID_EVENT,
  			  ticker_if_done, (void *)&ret_cb_evt);
  
  	if (ret == TICKER_STATUS_BUSY) {
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		mayfly_enable(RADIO_TICKER_USER_ID_JOB,
  			      RADIO_TICKER_USER_ID_JOB, 1);
  #endif
  
  		while (ret_cb_evt == TICKER_STATUS_BUSY) {
  			ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO,
  					 RADIO_TICKER_USER_ID_JOB);
  		}
  	}
  
  	if (ret_cb_evt == TICKER_STATUS_SUCCESS) {
  		static memq_link_t link_xtal;
  		static struct mayfly s_mfy_xtal_stop = {0, 0, &link_xtal, NULL,
  							mayfly_xtal_stop};
  		u32_t volatile ret_cb_m0 = TICKER_STATUS_BUSY;
  
  		/* Reset the stored ticker id in prepare phase. */
  		LL_ASSERT(_radio.ticker_id_prepare);
  		_radio.ticker_id_prepare = 0U;
  
  		/* Step 2.1: Is caller between Primary and Marker0?
  		 * Stop the Marker0 event
  		 */
  		ret = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  				  RADIO_TICKER_USER_ID_JOB,
  				  RADIO_TICKER_ID_MARKER_0,
  				  ticker_if_done, (void *)&ret_cb_m0);
  
  		if (ret == TICKER_STATUS_BUSY) {
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  			mayfly_enable(RADIO_TICKER_USER_ID_JOB,
  				      RADIO_TICKER_USER_ID_JOB, 1);
  #endif
  
  			while (ret_cb_m0 == TICKER_STATUS_BUSY) {
  				ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO,
  						 RADIO_TICKER_USER_ID_JOB);
  			}
  		}
  
  		if (ret_cb_m0 == TICKER_STATUS_SUCCESS) {
  			u32_t ticks_xtal_to_start =
  				_radio.advertiser.hdr.ticks_xtal_to_start;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  			/* If in reduced prepare, use the absolute value */
  			ticks_xtal_to_start &= ~XON_BITMASK;
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  			/* Step 2.1.1: Check and deassert Radio Active or XTAL
  			 * start
  			 */
  			if (_radio.advertiser.hdr.ticks_active_to_start >
  			    ticks_xtal_to_start) {
  				/* radio active asserted, handle deasserting
  				 * here
  				 */
  				ret = mayfly_enqueue(
  						RADIO_TICKER_USER_ID_JOB,
  						RADIO_TICKER_USER_ID_WORKER, 0,
  						&s_mfy_radio_inactive);
  				LL_ASSERT(!ret);
  			} else {
  				/* XTAL started, handle XTAL stop here */
  				ret = mayfly_enqueue(
  						RADIO_TICKER_USER_ID_JOB,
  						RADIO_TICKER_USER_ID_WORKER, 0,
  						&s_mfy_xtal_stop);
  				LL_ASSERT(!ret);
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  				/* calc whether xtal needs to be retained after
  				 * this event
  				 */
  				ret = mayfly_enqueue(
  						RADIO_TICKER_USER_ID_JOB,
  						RADIO_TICKER_USER_ID_JOB, 0,
  						&s_mfy_xtal_calc);
  				LL_ASSERT(!ret);
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  			}
  		} else if (ret_cb_m0 == TICKER_STATUS_FAILURE) {
  			/* Step 2.1.2: Deassert Radio Active and XTAL start */
  
  			/* radio active asserted, handle deasserting here */
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
  					     RADIO_TICKER_USER_ID_WORKER, 0,
  					     &s_mfy_radio_inactive);
  			LL_ASSERT(!ret);
  
  			/* XTAL started, handle XTAL stop here */
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
  					     RADIO_TICKER_USER_ID_WORKER, 0,
  					     &s_mfy_xtal_stop);
  			LL_ASSERT(!ret);
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  			/* calc whether xtal needs to be retained after this
  			 * event
  			 */
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
  					     RADIO_TICKER_USER_ID_JOB, 0,
  					     &s_mfy_xtal_calc);
  			LL_ASSERT(!ret);
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  		} else {
  			LL_ASSERT(0);
  		}
  	} else if (ret_cb_evt == TICKER_STATUS_FAILURE) {
  		/* Step 3: Caller inside Event, handle graceful stop of Event
  		 * (role dependent)
  		 */
  		if (_radio.role != ROLE_NONE) {
  			static memq_link_t link_radio;
  			static struct mayfly s_mfy_radio_stop = {
  				0, 0, &link_radio, NULL, mayfly_radio_stop};
  
  			/* Radio state STOP is supplied in params */
  			s_mfy_radio_stop.param = (void *)STATE_STOP;
  
  			/* Stop Radio Tx/Rx */
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
  						RADIO_TICKER_USER_ID_WORKER, 0,
  						&s_mfy_radio_stop);
  			LL_ASSERT(!ret);
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  			/* calc whether xtal needs to be retained after this
  			 * event
  			 */
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
  					     RADIO_TICKER_USER_ID_JOB, 0,
  					     &s_mfy_xtal_calc);
  			LL_ASSERT(!ret);
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  			/* NOTE: Cannot wait here for the event to finish
  			 * as we need to let radio ISR to execute if we are in
  			 * the same priority.
  			 */
  		}
  	} else {
  		LL_ASSERT(0);
  	}
  }
  
  static void ticker_stop_adv_stop(u32_t status, void *params)
  {
  #if defined(CONFIG_BT_PERIPHERAL)
  	static memq_link_t s_link;
  	static struct mayfly s_mfy_adv_stop = {0, 0, &s_link, NULL,
  					       mayfly_adv_stop};
  	u32_t retval;
  #endif /* CONFIG_BT_PERIPHERAL */
  
  	/* Ignore if being stopped from app/thread prio */
  	if (status != TICKER_STATUS_SUCCESS) {
  		LL_ASSERT(_radio.ticker_id_stop == RADIO_TICKER_ID_ADV);
  
  		return;
  	}
  
  	/* Handle adv stop inside a prepare and/or event */
  	if ((_radio.ticker_id_prepare == RADIO_TICKER_ID_ADV) ||
  	    (_radio.ticker_id_event == RADIO_TICKER_ID_ADV)) {
  		ticker_stop_adv_stop_active();
  	}
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	if (params) {
  		return;
  	}
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  #if defined(CONFIG_BT_PERIPHERAL)
  	/* Generate an event in WORKER Prio */
  	retval = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
  				RADIO_TICKER_USER_ID_WORKER, 0,
  				&s_mfy_adv_stop);
  	LL_ASSERT(!retval);
  #endif /* CONFIG_BT_PERIPHERAL */
  }
  
  void event_adv_stop(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
  		    void *context)
  {
  	u32_t ticker_status;
  
  	ARG_UNUSED(ticks_at_expire);
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  	ARG_UNUSED(context);
  
  	/* Abort an event, if any, to avoid Rx queue corruption used by Radio
  	 * ISR.
  	 */
  	event_stop(0, 0, 0, (void *)STATE_ABORT);
  
  	/* Stop Direct Adv */
  	ticker_status =
  	    ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  			RADIO_TICKER_USER_ID_WORKER, RADIO_TICKER_ID_ADV,
  			ticker_stop_adv_stop, NULL);
  	LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  		  (ticker_status == TICKER_STATUS_BUSY));
  }
  #endif /* CONFIG_BT_PERIPHERAL || CONFIG_BT_HCI_MESH_EXT */
  
  static void event_scan_prepare(u32_t ticks_at_expire, u32_t remainder,
  			      u16_t lazy, void *context)
  {
  	ARG_UNUSED(lazy);
  	ARG_UNUSED(context);
  
  	DEBUG_RADIO_PREPARE_O(1);
  
  	LL_ASSERT(!_radio.ticker_id_prepare);
  	_radio.ticker_id_prepare = RADIO_TICKER_ID_SCAN;
  
  	event_common_prepare(ticks_at_expire, remainder,
  			     &_radio.scanner.hdr.ticks_xtal_to_start,
  			     &_radio.scanner.hdr.ticks_active_to_start,
  			     _radio.scanner.hdr.ticks_preempt_to_start,
  			     RADIO_TICKER_ID_SCAN, event_scan, NULL);
  
  #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  	/* calc next group in us for the anchor where first connection event
  	 * to be placed
  	 */
  	if (_radio.scanner.conn) {
  		static memq_link_t s_link;
  		static struct mayfly s_mfy_sched_after_mstr_free_offset_get = {
  			0, 0, &s_link, NULL,
  			mayfly_sched_after_mstr_free_offset_get};
  		u32_t ticks_at_expire_normal = ticks_at_expire;
  		u32_t retval;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  		if (_radio.scanner.hdr.ticks_xtal_to_start & XON_BITMASK) {
  			u32_t ticks_prepare_to_start =
  				MAX(_radio.scanner.hdr.ticks_active_to_start,
  				    _radio.scanner.hdr.ticks_preempt_to_start);
  
  			ticks_at_expire_normal -=
  				(_radio.scanner.hdr.ticks_xtal_to_start &
  				 ~XON_BITMASK) - ticks_prepare_to_start;
  		}
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  		s_mfy_sched_after_mstr_free_offset_get.param =
  			(void *)ticks_at_expire_normal;
  
  		retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
  				RADIO_TICKER_USER_ID_JOB, 1,
  				&s_mfy_sched_after_mstr_free_offset_get);
  		LL_ASSERT(!retval);
  	}
  #endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
  
  	DEBUG_RADIO_PREPARE_O(0);
  }
  
  static void event_scan(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
  		      void *context)
  {
  	u32_t remainder_us;
  	u32_t ret;
  	u32_t aa = PDU_AC_ACCESS_ADDR;
  
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  	ARG_UNUSED(context);
  
  	DEBUG_RADIO_START_O(1);
  
  	LL_ASSERT(_radio.role == ROLE_NONE);
  	LL_ASSERT(_radio.ticker_id_prepare == RADIO_TICKER_ID_SCAN);
  
  	/** @todo check if XTAL is started, options 1: abort Radio Start,
  	 * 2: wait for XTAL start
  	 */
  	_radio.role = ROLE_SCAN;
  	_radio.state = STATE_RX;
  	_radio.ticker_id_prepare = 0U;
  	_radio.ticker_id_event = RADIO_TICKER_ID_SCAN;
  	_radio.ticks_anchor = ticks_at_expire;
  	_radio.scanner.state = 0U;
  
  	radio_reset();
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  	radio_tx_power_set(_radio.scanner.tx_pwr_lvl);
  #else
  	radio_tx_power_set(RADIO_TXP_DEFAULT);
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  	radio_isr_set(isr, NULL);
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  	/* if coded then use S8. */
  	radio_phy_set(_radio.scanner.phy, 1);
  	radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX,
  			(_radio.scanner.phy << 1));
  #else /* !CONFIG_BT_CTLR_ADV_EXT */
  	radio_phy_set(0, 0);
  	radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX, 0);
  #endif /* !CONFIG_BT_CTLR_ADV_EXT */
  
  	radio_aa_set((u8_t *)&aa);
  	radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
  			    0x555555);
  
  
  	chan_set(37 + _radio.scanner.chan++);
  	if (_radio.scanner.chan == 3) {
  		_radio.scanner.chan = 0U;
  	}
  
  	radio_tmr_tifs_set(RADIO_TIFS);
  	radio_switch_complete_and_tx(0, 0, 0, 0);
  	radio_pkt_rx_set(_radio.packet_rx[_radio.packet_rx_last]->pdu_data);
  	radio_rssi_measure();
  
  	/* Setup Radio Filter */
  	if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY) && ctrl_rl_enabled()) {
  		struct ll_filter *filter =
  			ctrl_filter_get(!!(_radio.scanner.filter_policy & 0x1));
  		u8_t count, *irks = ctrl_irks_get(&count);
  
  		radio_filter_configure(filter->enable_bitmask,
  				       filter->addr_type_bitmask,
  				       (u8_t *)filter->bdaddr);
  
  		radio_ar_configure(count, irks);
  	} else if (IS_ENABLED(CONFIG_BT_CTLR_FILTER) &&
  		   _radio.scanner.filter_policy) {
  		struct ll_filter *wl = ctrl_filter_get(true);
  
  		radio_filter_configure(wl->enable_bitmask,
  				       wl->addr_type_bitmask,
  				       (u8_t *)wl->bdaddr);
  	}
  
  	remainder_us = radio_tmr_start(0, ticks_at_expire +
  					  HAL_TICKER_US_TO_TICKS(
  						RADIO_TICKER_START_PART_US),
  				       _radio.remainder_anchor);
  
  	/* capture end of Rx-ed PDU, for initiator to calculate first
  	 * master event.
  	 */
  	radio_tmr_end_capture();
  
  #if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  	radio_gpio_lna_setup();
  	radio_gpio_pa_lna_enable(remainder_us +
  				 radio_rx_ready_delay_get(0, 0) -
  				 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #else /* !CONFIG_BT_CTLR_GPIO_LNA_PIN */
  	ARG_UNUSED(remainder_us);
  #endif /* !CONFIG_BT_CTLR_GPIO_LNA_PIN */
  
  #if (defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
       (RADIO_TICKER_PREEMPT_PART_US <= RADIO_TICKER_PREEMPT_PART_MIN_US))
  	/* check if preempt to start has changed */
  	if (preempt_calc(&_radio.scanner.hdr, RADIO_TICKER_ID_SCAN,
  			 ticks_at_expire) != 0) {
  		_radio.state = STATE_STOP;
  		radio_disable();
  	} else
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  	{
  		/* start window close timeout */
  		ret = ticker_start(
  				RADIO_TICKER_INSTANCE_ID_RADIO,
  				RADIO_TICKER_USER_ID_WORKER,
  				RADIO_TICKER_ID_SCAN_STOP, ticks_at_expire,
  				_radio.scanner.ticks_window +
  				HAL_TICKER_US_TO_TICKS(
  					RADIO_TICKER_START_PART_US),
  				TICKER_NULL_PERIOD, TICKER_NULL_REMAINDER,
  				TICKER_NULL_LAZY, TICKER_NULL_SLOT,
  				event_stop, (void *)STATE_STOP,
  				ticker_success_assert, (void *)__LINE__);
  
  		LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
  			  (ret == TICKER_STATUS_BUSY));
  
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		/* Ticker Job Silence */
  		ret = ticker_job_idle_get(RADIO_TICKER_INSTANCE_ID_RADIO,
  					  RADIO_TICKER_USER_ID_WORKER,
  					  ticker_job_disable, NULL);
  
  		LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
  			  (ret == TICKER_STATUS_BUSY));
  #endif
  	}
  
  	DEBUG_RADIO_START_O(0);
  }
  
  #if defined(CONFIG_BT_CONN)
  static inline void event_conn_upd_init(struct connection *conn,
  				       u16_t event_counter,
  				       u32_t ticks_at_expire,
  				       struct pdu_data *pdu_ctrl_tx,
  				       struct mayfly *mayfly_sched_offset,
  				       void (*fp_mayfly_select_or_use)(void *))
  {
  	/* move to in progress */
  	conn->llcp_cu.state = LLCP_CUI_STATE_INPROG;
  
  	/* set instant */
  	conn->llcp.conn_upd.instant =
  		event_counter + conn->latency + 6;
  
  	/* place the conn update req packet as next in tx queue */
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, conn_update_ind) +
  		sizeof(struct pdu_data_llctrl_conn_update_ind);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND;
  	pdu_ctrl_tx->llctrl.conn_update_ind.win_size = conn->llcp_cu.win_size;
  	pdu_ctrl_tx->llctrl.conn_update_ind.win_offset =
  		conn->llcp_cu.win_offset_us / 1250;
  	pdu_ctrl_tx->llctrl.conn_update_ind.interval = conn->llcp_cu.interval;
  	pdu_ctrl_tx->llctrl.conn_update_ind.latency = conn->llcp_cu.latency;
  	pdu_ctrl_tx->llctrl.conn_update_ind.timeout = conn->llcp_cu.timeout;
  	pdu_ctrl_tx->llctrl.conn_update_ind.instant =
  		conn->llcp.conn_upd.instant;
  
  #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  	{
  		u32_t retval;
  
  		/* calculate window offset that places the connection in the
  		 * next available slot after existing masters.
  		 */
  		conn->llcp.conn_upd.ticks_anchor = ticks_at_expire;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  		if (conn->hdr.ticks_xtal_to_start & XON_BITMASK) {
  			u32_t ticks_prepare_to_start =
  				MAX(conn->hdr.ticks_active_to_start,
  				    conn->hdr.ticks_preempt_to_start);
  
  			conn->llcp.conn_upd.ticks_anchor -=
  				(conn->hdr.ticks_xtal_to_start &
  				 ~XON_BITMASK) - ticks_prepare_to_start;
  		}
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  		conn->llcp.conn_upd.pdu_win_offset = (u16_t *)
  			&pdu_ctrl_tx->llctrl.conn_update_ind.win_offset;
  
  		mayfly_sched_offset->fp = fp_mayfly_select_or_use;
  		mayfly_sched_offset->param = (void *)conn;
  
  		retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
  					RADIO_TICKER_USER_ID_JOB, 1,
  					mayfly_sched_offset);
  		LL_ASSERT(!retval);
  	}
  #else /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
  	ARG_UNUSED(ticks_at_expire);
  	ARG_UNUSED(mayfly_sched_offset);
  	ARG_UNUSED(fp_mayfly_select_or_use);
  #endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
  }
  
  static inline u32_t event_conn_upd_prep(struct connection *conn,
  					u16_t event_counter,
  					u32_t ticks_at_expire)
  {
  	struct connection *conn_upd;
  	u16_t instant_latency;
  
  	conn_upd = _radio.conn_upd;
  
  	/* set mutex */
  	if (!conn_upd) {
  		_radio.conn_upd = conn;
  	}
  
  	instant_latency = (event_counter - conn->llcp.conn_upd.instant) &
  			  0xffff;
  	if (conn->llcp_cu.state != LLCP_CUI_STATE_INPROG) {
  #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  		static memq_link_t s_link;
  		static struct mayfly s_mfy_sched_offset = {0, 0,
  			&s_link, 0, 0 };
  		void (*fp_mayfly_select_or_use)(void *) = NULL;
  #endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
  		struct radio_pdu_node_tx *node_tx;
  		struct pdu_data *pdu_ctrl_tx;
  
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			return 1;
  		}
  
  		pdu_ctrl_tx = (void *)node_tx->pdu_data;
  
  #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  		switch (conn->llcp_cu.state) {
  		case LLCP_CUI_STATE_USE:
  			fp_mayfly_select_or_use = mayfly_sched_win_offset_use;
  			break;
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  		case LLCP_CUI_STATE_SELECT:
  			fp_mayfly_select_or_use =
  				mayfly_sched_win_offset_select;
  			break;
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  		default:
  			LL_ASSERT(0);
  			break;
  		}
  
  		event_conn_upd_init(conn, event_counter, ticks_at_expire,
  				    pdu_ctrl_tx, &s_mfy_sched_offset,
  				    fp_mayfly_select_or_use);
  #else /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
  		event_conn_upd_init(conn, event_counter, ticks_at_expire,
  				    pdu_ctrl_tx, NULL, NULL);
  #endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
  
  		ctrl_tx_enqueue(conn, node_tx);
  
  	} else if (instant_latency <= 0x7FFF) {
  		struct radio_le_conn_update_cmplt *radio_le_conn_update_cmplt;
  		struct radio_pdu_node_rx *node_rx;
  		u16_t conn_interval_old;
  		u16_t conn_interval_new;
  		u32_t ticks_slot_offset;
  		u32_t ticks_win_offset;
  		u32_t conn_interval_us;
  		u32_t ticker_status;
  		u32_t periodic_us;
  		u8_t ticker_id;
  		u16_t latency;
  
  		/* procedure request acked */
  		conn->llcp_cu.ack = conn->llcp_cu.req;
  		conn->llcp_ack = conn->llcp_req;
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  		if ((conn->llcp_conn_param.req != conn->llcp_conn_param.ack) &&
  		    (conn->llcp_conn_param.state == LLCP_CPR_STATE_UPD)) {
  			conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
  
  			/* Stop procedure timeout */
  			conn->procedure_expire = 0U;
  		}
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  		/* reset mutex */
  		if (_radio.conn_upd == conn) {
  			_radio.conn_upd = NULL;
  		}
  
  		/* Prepare the rx packet structure */
  		if ((conn->llcp_cu.interval != conn->conn_interval) ||
  		    (conn->llcp_cu.latency != conn->latency) ||
  		    (RADIO_CONN_EVENTS(conn->llcp_cu.timeout * 10000,
  				       conn->conn_interval * 1250) !=
  		     conn->supervision_reload)) {
  			node_rx = packet_rx_reserve_get(2);
  			LL_ASSERT(node_rx);
  
  			node_rx->hdr.handle = conn->handle;
  			node_rx->hdr.type = NODE_RX_TYPE_CONN_UPDATE;
  
  			/* prepare connection update complete structure */
  			radio_le_conn_update_cmplt = (void *) node_rx->pdu_data;
  			radio_le_conn_update_cmplt->status = 0x00;
  			radio_le_conn_update_cmplt->interval =
  				conn->llcp_cu.interval;
  			radio_le_conn_update_cmplt->latency =
  				conn->llcp_cu.latency;
  			radio_le_conn_update_cmplt->timeout =
  				conn->llcp_cu.timeout;
  
  			/* enqueue connection update complete structure
  			 * into queue.
  			 */
  			if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  				packet_rx_enqueue_get(); /* ignore return as its
  							  * same node_rx
  							  */
  				packet_rx_enqueue_hold(node_rx);
  			} else {
  				packet_rx_enqueue();
  			}
  		}
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  		/* restore to normal prepare */
  		if (conn->hdr.ticks_xtal_to_start & XON_BITMASK) {
  			u32_t ticks_prepare_to_start =
  				MAX(conn->hdr.ticks_active_to_start,
  				    conn->hdr.ticks_preempt_to_start);
  
  			conn->hdr.ticks_xtal_to_start &= ~XON_BITMASK;
  			ticks_at_expire -= (conn->hdr.ticks_xtal_to_start -
  					    ticks_prepare_to_start);
  		}
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  		/* compensate for instant_latency due to laziness */
  		conn_interval_old = instant_latency * conn->conn_interval;
  		latency = conn_interval_old / conn->llcp_cu.interval;
  		conn_interval_new = latency * conn->llcp_cu.interval;
  		if (conn_interval_new > conn_interval_old) {
  			ticks_at_expire += HAL_TICKER_US_TO_TICKS(
  				(conn_interval_new - conn_interval_old) * 1250);
  		} else {
  			ticks_at_expire -= HAL_TICKER_US_TO_TICKS(
  				(conn_interval_old - conn_interval_new) * 1250);
  		}
  		conn->latency_prepare -= (instant_latency - latency);
  
  		/* calculate the offset, window widening and interval */
  		ticks_slot_offset = MAX(conn->hdr.ticks_active_to_start,
  					conn->hdr.ticks_xtal_to_start);
  		conn_interval_us = conn->llcp_cu.interval * 1250;
  		periodic_us = conn_interval_us;
  		if (conn->role) {
  			conn->slave.window_widening_prepare_us -=
  				conn->slave.window_widening_periodic_us *
  				instant_latency;
  
  			conn->slave.window_widening_periodic_us =
  				(((gc_lookup_ppm[_radio.sca] +
  				   gc_lookup_ppm[conn->slave.sca]) *
  				  conn_interval_us) + (1000000 - 1)) / 1000000;
  			conn->slave.window_widening_max_us =
  				(conn_interval_us >> 1) - RADIO_TIFS;
  			conn->slave.window_size_prepare_us =
  				conn->llcp_cu.win_size * 1250;
  			conn->slave.ticks_to_offset = 0U;
  
  			conn->slave.window_widening_prepare_us +=
  				conn->slave.window_widening_periodic_us *
  				latency;
  			if (conn->slave.window_widening_prepare_us >
  			    conn->slave.window_widening_max_us) {
  				conn->slave.window_widening_prepare_us =
  					conn->slave.window_widening_max_us;
  			}
  
  			ticks_at_expire -= HAL_TICKER_US_TO_TICKS(
  				conn->slave.window_widening_periodic_us *
  				latency);
  			ticks_win_offset = HAL_TICKER_US_TO_TICKS(
  				(conn->llcp_cu.win_offset_us / 1250) * 1250);
  			periodic_us -= conn->slave.window_widening_periodic_us;
  		} else {
  			ticks_win_offset = HAL_TICKER_US_TO_TICKS(
  				conn->llcp_cu.win_offset_us);
  
  			/* Workaround: Due to the missing remainder param in
  			 * ticker_start function for first interval; add a
  			 * tick so as to use the ceiled value.
  			 */
  			ticks_win_offset += 1;
  		}
  		conn->conn_interval = conn->llcp_cu.interval;
  		conn->latency = conn->llcp_cu.latency;
  		conn->supervision_reload =
  			RADIO_CONN_EVENTS((conn->llcp_cu.timeout * 10 * 1000),
  					  conn_interval_us);
  		conn->procedure_reload =
  			RADIO_CONN_EVENTS((40 * 1000 * 1000), conn_interval_us);
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  		/* APTO in no. of connection events */
  		conn->apto_reload = RADIO_CONN_EVENTS((30 * 1000 * 1000),
  						      conn_interval_us);
  		/* Dispatch LE Ping PDU 6 connection events (that peer would
  		 * listen to) before 30s timeout
  		 * TODO: "peer listens to" is greater than 30s due to latency
  		 */
  		conn->appto_reload = (conn->apto_reload > (conn->latency + 6)) ?
  				     (conn->apto_reload - (conn->latency + 6)) :
  				     conn->apto_reload;
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  		if (conn->llcp_cu.cmd) {
  			conn->supervision_expire = 0U;
  		}
  
  #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		/* disable ticker job, in order to chain stop and start
  		 * to avoid RTC being stopped if no tickers active.
  		 */
  		u32_t mayfly_was_enabled =
  			mayfly_is_enabled(RADIO_TICKER_USER_ID_WORKER,
  					  RADIO_TICKER_USER_ID_JOB);
  		mayfly_enable(RADIO_TICKER_USER_ID_WORKER,
  			      RADIO_TICKER_USER_ID_JOB, 0);
  #endif
  
  		/* start slave/master with new timings */
  		ticker_id = RADIO_TICKER_ID_FIRST_CONNECTION + conn->handle;
  		ticker_status =
  			ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  				    RADIO_TICKER_USER_ID_WORKER, ticker_id,
  				    ticker_stop_conn_assert,
  				    (void *)(u32_t)ticker_id);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  		ticker_status =
  			ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				     RADIO_TICKER_USER_ID_WORKER, ticker_id,
  				     ticks_at_expire, ticks_win_offset,
  				     HAL_TICKER_US_TO_TICKS(periodic_us),
  				     HAL_TICKER_REMAINDER(periodic_us),
  				     TICKER_NULL_LAZY,
  				     (ticks_slot_offset + conn->hdr.ticks_slot),
  #if defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_CENTRAL)
  				     conn->role ?
  				     event_slave_prepare : event_master_prepare,
  #elif defined(CONFIG_BT_PERIPHERAL)
  				     event_slave_prepare,
  #else
  				     event_master_prepare,
  #endif
  				     conn, ticker_start_conn_assert,
  				     (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  
  #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		/* enable ticker job, if disabled in this function */
  		if (mayfly_was_enabled) {
  			mayfly_enable(RADIO_TICKER_USER_ID_WORKER,
  				      RADIO_TICKER_USER_ID_JOB, 1);
  		}
  #endif
  
  		return 0;
  	}
  
  	return 1;
  }
  
  static inline void event_ch_map_prep(struct connection *conn,
  				     u16_t event_counter)
  {
  	if (conn->llcp.chan_map.initiate) {
  		struct radio_pdu_node_tx *node_tx;
  
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (node_tx) {
  			struct pdu_data *pdu_ctrl_tx = (void *)
  						       node_tx->pdu_data;
  
  			/* reset initiate flag */
  			conn->llcp.chan_map.initiate = 0U;
  
  			/* set instant */
  			conn->llcp.chan_map.instant =
  				event_counter + conn->latency + 6;
  
  			/* place the channel map req packet as next in
  			 * tx queue
  			 */
  			pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  			pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl,
  						    chan_map_ind) +
  				sizeof(struct pdu_data_llctrl_chan_map_ind);
  			pdu_ctrl_tx->llctrl.opcode =
  				PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND;
  			memcpy(&pdu_ctrl_tx->llctrl.chan_map_ind.chm[0],
  			       &conn->llcp.chan_map.chm[0],
  			       sizeof(pdu_ctrl_tx->llctrl.chan_map_ind.chm));
  			pdu_ctrl_tx->llctrl.chan_map_ind.instant =
  				conn->llcp.chan_map.instant;
  
  			ctrl_tx_enqueue(conn, node_tx);
  		}
  	} else if (((event_counter - conn->llcp.chan_map.instant) & 0xFFFF)
  			    <= 0x7FFF) {
  		/* procedure request acked */
  		conn->llcp_ack = conn->llcp_req;
  
  		/* copy to active channel map */
  		memcpy(&conn->data_chan_map[0],
  		       &conn->llcp.chan_map.chm[0],
  		       sizeof(conn->data_chan_map));
  		conn->data_chan_count =
  			util_ones_count_get(&conn->data_chan_map[0],
  					    sizeof(conn->data_chan_map));
  		conn->chm_update = 1U;
  	}
  
  }
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  static inline void event_enc_reject_prep(struct connection *conn,
  					 struct pdu_data *pdu)
  {
  	pdu->ll_id = PDU_DATA_LLID_CTRL;
  
  	if (conn->common.fex_valid &&
  	    (conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_EXT_REJ_IND))) {
  		struct pdu_data_llctrl_reject_ext_ind *p;
  
  		pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND;
  
  		p = (void *)&pdu->llctrl.reject_ext_ind;
  		p->reject_opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ;
  		p->error_code = conn->llcp.encryption.error_code;
  
  		pdu->len = sizeof(struct pdu_data_llctrl_reject_ext_ind);
  	} else {
  		struct pdu_data_llctrl_reject_ind *p;
  
  		pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_REJECT_IND;
  
  		p = (void *)&pdu->llctrl.reject_ind;
  		p->error_code =	conn->llcp.encryption.error_code;
  
  		pdu->len = sizeof(struct pdu_data_llctrl_reject_ind);
  	}
  
  	pdu->len += offsetof(struct pdu_data_llctrl, reject_ind);
  
  	conn->llcp.encryption.error_code = 0U;
  }
  
  static inline void event_enc_prep(struct connection *conn)
  {
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	if (conn->llcp.encryption.state) {
  #if !defined(CONFIG_BT_CTLR_FAST_ENC) && defined(CONFIG_BT_PERIPHERAL)
  		if (conn->role &&
  		    (conn->llcp.encryption.state == LLCP_ENC_STATE_INIT)) {
  			struct radio_pdu_node_rx *node_rx;
  			struct pdu_data *pdu_ctrl_rx;
  			u8_t err;
  
  			/* TODO BT Spec. text: may finalize the sending
  			 * of additional data channel PDUs queued in the
  			 * controller.
  			 */
  			err = enc_rsp_send(conn);
  			if (err) {
  				return;
  			}
  
  			/* Prepare the rx packet structure */
  			node_rx = packet_rx_reserve_get(2);
  			LL_ASSERT(node_rx);
  
  			node_rx->hdr.handle = conn->handle;
  			node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
  
  			/* prepare enc req structure */
  			pdu_ctrl_rx = (void *)node_rx->pdu_data;
  			pdu_ctrl_rx->ll_id = PDU_DATA_LLID_CTRL;
  			pdu_ctrl_rx->len =
  				offsetof(struct pdu_data_llctrl, enc_req) +
  				sizeof(struct pdu_data_llctrl_enc_req);
  			pdu_ctrl_rx->llctrl.opcode =
  				PDU_DATA_LLCTRL_TYPE_ENC_REQ;
  			memcpy(&pdu_ctrl_rx->llctrl.enc_req.rand[0],
  			       &conn->llcp_enc.rand[0],
  			       sizeof(pdu_ctrl_rx->llctrl.enc_req.rand));
  			pdu_ctrl_rx->llctrl.enc_req.ediv[0] =
  				conn->llcp_enc.ediv[0];
  			pdu_ctrl_rx->llctrl.enc_req.ediv[1] =
  				conn->llcp_enc.ediv[1];
  
  			/* enqueue enc req structure into rx queue */
  			packet_rx_enqueue();
  
  			/* Wait for LTK reply */
  			conn->llcp.encryption.state = LLCP_ENC_STATE_LTK_WAIT;
  		}
  #endif /* !CONFIG_BT_CTLR_FAST_ENC && CONFIG_BT_PERIPHERAL */
  
  		return;
  	}
  
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return;
  	}
  
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  
  	/* master sends encrypted enc start rsp in control priority */
  	if (!conn->role) {
  		/* calc the Session Key */
  		ecb_encrypt(&conn->llcp_enc.ltk[0],
  			    &conn->llcp.encryption.skd[0],
  			    NULL, &conn->ccm_rx.key[0]);
  
  		/* copy the Session Key */
  		memcpy(&conn->ccm_tx.key[0], &conn->ccm_rx.key[0],
  		       sizeof(conn->ccm_tx.key));
  
  		/* copy the IV */
  		memcpy(&conn->ccm_tx.iv[0], &conn->ccm_rx.iv[0],
  		       sizeof(conn->ccm_tx.iv));
  
  		/* initialise counter */
  		conn->ccm_rx.counter = 0;
  		conn->ccm_tx.counter = 0;
  
  		/* set direction: slave to master = 0,
  		 * master to slave = 1
  		 */
  		conn->ccm_rx.direction = 0;
  		conn->ccm_tx.direction = 1;
  
  		/* enable receive encryption */
  		conn->enc_rx = 1;
  
  		/* send enc start resp */
  		start_enc_rsp_send(conn, pdu_ctrl_tx);
  	}
  
  	/* slave send reject ind or start enc req at control priority */
  
  #if defined(CONFIG_BT_CTLR_FAST_ENC)
  	else {
  #else /* !CONFIG_BT_CTLR_FAST_ENC */
  	else if (!conn->enc_rx) {
  #endif /* !CONFIG_BT_CTLR_FAST_ENC */
  
  		/* place the reject ind packet as next in tx queue */
  		if (conn->llcp.encryption.error_code) {
  			event_enc_reject_prep(conn, pdu_ctrl_tx);
  		}
  		/* place the start enc req packet as next in tx queue */
  		else {
  			/* calc the Session Key */
  			ecb_encrypt(&conn->llcp_enc.ltk[0],
  				    &conn->llcp.encryption.skd[0], NULL,
  				    &conn->ccm_rx.key[0]);
  
  			/* copy the Session Key */
  			memcpy(&conn->ccm_tx.key[0],
  			       &conn->ccm_rx.key[0],
  			       sizeof(conn->ccm_tx.key));
  
  			/* copy the IV */
  			memcpy(&conn->ccm_tx.iv[0], &conn->ccm_rx.iv[0],
  			       sizeof(conn->ccm_tx.iv));
  
  			/* initialise counter */
  			conn->ccm_rx.counter = 0;
  			conn->ccm_tx.counter = 0;
  
  			/* set direction: slave to master = 0,
  			 * master to slave = 1
  			 */
  			conn->ccm_rx.direction = 1;
  			conn->ccm_tx.direction = 0;
  
  			/* enable receive encryption (transmit turned
  			 * on when start enc resp from master is
  			 * received)
  			 */
  			conn->enc_rx = 1;
  
  			/* prepare the start enc req */
  			pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  			pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl,
  						    start_enc_req) +
  				sizeof(struct pdu_data_llctrl_start_enc_req);
  			pdu_ctrl_tx->llctrl.opcode =
  				PDU_DATA_LLCTRL_TYPE_START_ENC_REQ;
  		}
  
  #if !defined(CONFIG_BT_CTLR_FAST_ENC)
  	} else {
  		start_enc_rsp_send(conn, pdu_ctrl_tx);
  
  		/* resume data packet rx and tx */
  		conn->pause_rx = 0;
  		conn->pause_tx = 0;
  #endif /* !CONFIG_BT_CTLR_FAST_ENC */
  
  	}
  
  	ctrl_tx_enqueue(conn, node_tx);
  
  	/* procedure request acked */
  	conn->llcp_ack = conn->llcp_req;
  }
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  static inline void event_fex_prep(struct connection *conn)
  {
  	struct radio_pdu_node_tx *node_tx;
  
  	/* If waiting for response, do nothing */
  	if (!((conn->llcp_feature.ack - conn->llcp_feature.req) & 0x01)) {
  		return;
  	}
  
  	if (conn->common.fex_valid) {
  		struct radio_pdu_node_rx *node_rx;
  		struct pdu_data *pdu_ctrl_rx;
  
  		/* procedure request acked */
  		conn->llcp_feature.ack = conn->llcp_feature.req;
  
  		/* Prepare the rx packet structure */
  		node_rx = packet_rx_reserve_get(2);
  		LL_ASSERT(node_rx);
  
  		node_rx->hdr.handle = conn->handle;
  		node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
  
  		/* prepare feature rsp structure */
  		pdu_ctrl_rx = (void *)node_rx->pdu_data;
  		pdu_ctrl_rx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_rx->len = offsetof(struct pdu_data_llctrl,
  					    feature_rsp) +
  				   sizeof(struct pdu_data_llctrl_feature_rsp);
  		pdu_ctrl_rx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_FEATURE_RSP;
  		(void)memset(&pdu_ctrl_rx->llctrl.feature_rsp.features[0], 0x00,
  			     sizeof(pdu_ctrl_rx->llctrl.feature_rsp.features));
  		sys_put_le24(conn->llcp_feature.features,
  			     pdu_ctrl_rx->llctrl.feature_req.features);
  
  		/* enqueue feature rsp structure into rx queue */
  		packet_rx_enqueue();
  
  		return;
  	}
  
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (node_tx) {
  		struct pdu_data *pdu_ctrl_tx = (void *)node_tx->pdu_data;
  
  		/* procedure request acked, move to waiting state  */
  		conn->llcp_feature.ack--;
  
  		/* use initial feature bitmap */
  		conn->llcp_feature.features = LL_FEAT;
  
  		/* place the feature exchange req packet as next in tx queue */
  		pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_tx->len =
  			offsetof(struct pdu_data_llctrl, feature_req) +
  			sizeof(struct pdu_data_llctrl_feature_req);
  		pdu_ctrl_tx->llctrl.opcode =
  			!conn->role ?
  			PDU_DATA_LLCTRL_TYPE_FEATURE_REQ :
  			PDU_DATA_LLCTRL_TYPE_SLAVE_FEATURE_REQ;
  		(void)memset(&pdu_ctrl_tx->llctrl.feature_req.features[0],
  			     0x00,
  			     sizeof(pdu_ctrl_tx->llctrl.feature_req.features));
  		sys_put_le24(conn->llcp_feature.features,
  			     pdu_ctrl_tx->llctrl.feature_req.features);
  
  		ctrl_tx_enqueue(conn, node_tx);
  
  		/* Start Procedure Timeout (TODO: this shall not replace
  		 * terminate procedure)
  		 */
  		conn->procedure_expire = conn->procedure_reload;
  	}
  
  }
  
  static inline void event_vex_prep(struct connection *conn)
  {
  	/* If waiting for response, do nothing */
  	if (!((conn->llcp_version.ack - conn->llcp_version.req) & 0x01)) {
  		return;
  	}
  
  	if (conn->llcp_version.tx == 0) {
  		struct radio_pdu_node_tx *node_tx;
  
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (node_tx) {
  			struct pdu_data *pdu_ctrl_tx = (void *)
  						       node_tx->pdu_data;
  
  			/* procedure request acked, move to waiting state  */
  			conn->llcp_version.ack--;
  
  			/* set version ind tx-ed flag */
  			conn->llcp_version.tx = 1U;
  
  			/* place the version ind packet as next in tx queue */
  			pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  			pdu_ctrl_tx->len =
  				offsetof(struct pdu_data_llctrl, version_ind) +
  				sizeof(struct pdu_data_llctrl_version_ind);
  			pdu_ctrl_tx->llctrl.opcode =
  				PDU_DATA_LLCTRL_TYPE_VERSION_IND;
  			pdu_ctrl_tx->llctrl.version_ind.version_number =
  				LL_VERSION_NUMBER;
  			pdu_ctrl_tx->llctrl.version_ind.company_id =
  				ll_settings_company_id();
  			pdu_ctrl_tx->llctrl.version_ind.sub_version_number =
  				ll_settings_subversion_number();
  
  			ctrl_tx_enqueue(conn, node_tx);
  
  			/* Start Procedure Timeout (TODO: this shall not
  			 * replace terminate procedure)
  			 */
  			conn->procedure_expire = conn->procedure_reload;
  		}
  	} else if (conn->llcp_version.rx != 0) {
  		struct radio_pdu_node_rx *node_rx;
  		struct pdu_data *pdu_ctrl_rx;
  
  		/* procedure request acked */
  		conn->llcp_version.ack = conn->llcp_version.req;
  
  		/* Prepare the rx packet structure */
  		node_rx = packet_rx_reserve_get(2);
  		LL_ASSERT(node_rx);
  
  		node_rx->hdr.handle = conn->handle;
  		node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
  
  		/* prepare version ind structure */
  		pdu_ctrl_rx = (void *)node_rx->pdu_data;
  		pdu_ctrl_rx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_rx->len =
  			offsetof(struct pdu_data_llctrl, version_ind) +
  			sizeof(struct pdu_data_llctrl_version_ind);
  		pdu_ctrl_rx->llctrl.opcode =
  			PDU_DATA_LLCTRL_TYPE_VERSION_IND;
  		pdu_ctrl_rx->llctrl.version_ind.version_number =
  			conn->llcp_version.version_number;
  		pdu_ctrl_rx->llctrl.version_ind.company_id =
  			conn->llcp_version.company_id;
  		pdu_ctrl_rx->llctrl.version_ind.sub_version_number =
  			conn->llcp_version.sub_version_number;
  
  		/* enqueue version ind structure into rx queue */
  		packet_rx_enqueue();
  	} else {
  		/* tx-ed but no rx, and new request placed */
  		LL_ASSERT(0);
  	}
  
  }
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  static inline void event_conn_param_req(struct connection *conn,
  					u16_t event_counter,
  					u32_t ticks_at_expire)
  {
  	struct pdu_data_llctrl_conn_param_req *p;
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return;
  	}
  
  	/* move to wait for conn_update/rsp/rej */
  	conn->llcp_conn_param.state = LLCP_CPR_STATE_RSP_WAIT;
  
  	/* place the conn param req packet as next in tx queue */
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, conn_param_req) +
  		sizeof(struct pdu_data_llctrl_conn_param_req);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
  	p = (void *)&pdu_ctrl_tx->llctrl.conn_param_req;
  	p->interval_min = conn->llcp_conn_param.interval_min;
  	p->interval_max = conn->llcp_conn_param.interval_max;
  	p->latency = conn->llcp_conn_param.latency;
  	p->timeout = conn->llcp_conn_param.timeout;
  	p->preferred_periodicity = 0U;
  	p->reference_conn_event_count = event_counter;
  	p->offset0 = 0x0000;
  	p->offset1 = 0xffff;
  	p->offset2 = 0xffff;
  	p->offset3 = 0xffff;
  	p->offset4 = 0xffff;
  	p->offset5 = 0xffff;
  
  	ctrl_tx_enqueue(conn, node_tx);
  
  	/* set CUI/CPR mutex */
  	_radio.conn_upd = conn;
  
  	/* Start Procedure Timeout (TODO: this shall not replace
  	 * terminate procedure).
  	 */
  	conn->procedure_expire = conn->procedure_reload;
  
  #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  	{
  		static memq_link_t s_link;
  		static struct mayfly s_mfy_sched_offset = {0, 0, &s_link, NULL,
  			mayfly_sched_free_win_offset_calc};
  		u32_t retval;
  
  		conn->llcp_conn_param.ticks_ref = ticks_at_expire;
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  		if (conn->hdr.ticks_xtal_to_start & XON_BITMASK) {
  			u32_t ticks_prepare_to_start =
  				MAX(conn->hdr.ticks_active_to_start,
  				    conn->hdr.ticks_preempt_to_start);
  
  			conn->llcp_conn_param.ticks_ref -=
  				(conn->hdr.ticks_xtal_to_start &
  				 ~XON_BITMASK) - ticks_prepare_to_start;
  		}
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  		conn->llcp_conn_param.pdu_win_offset0 = (u16_t *)&p->offset0;
  
  		s_mfy_sched_offset.param = (void *)conn;
  
  		retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
  					RADIO_TICKER_USER_ID_JOB, 1,
  					&s_mfy_sched_offset);
  		LL_ASSERT(!retval);
  	}
  #else /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
  	ARG_UNUSED(ticks_at_expire);
  #endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */
  }
  
  static inline void event_conn_param_rsp(struct connection *conn)
  {
  	struct pdu_data_llctrl_conn_param_rsp *rsp;
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu;
  
  	/* handle rejects */
  	if (conn->llcp_conn_param.status) {
  		struct pdu_data_llctrl_reject_ext_ind *rej;
  
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			return;
  		}
  
  		/* master/slave response with reject ext ind */
  		pdu = (void *)node_tx->pdu_data;
  		pdu->ll_id = PDU_DATA_LLID_CTRL;
  		pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND;
  		pdu->len = offsetof(struct pdu_data_llctrl, reject_ext_ind) +
  			   sizeof(struct pdu_data_llctrl_reject_ext_ind);
  
  		rej = (void *)&pdu->llctrl.reject_ext_ind;
  		rej->reject_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
  		rej->error_code = conn->llcp_conn_param.status;
  
  		ctrl_tx_enqueue(conn, node_tx);
  
  		/* procedure request acked */
  		conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
  
  		/* reset mutex */
  		_radio.conn_upd = NULL;
  
  		return;
  	}
  
  	/* master respond with connection update */
  	if (!conn->role) {
  		if (conn->llcp_cu.req != conn->llcp_cu.ack) {
  			return;
  		}
  
  		/* Move to waiting for connection update completion */
  		conn->llcp_conn_param.state = LLCP_CPR_STATE_UPD;
  
  		/* Initiate connection update procedure */
  		conn->llcp_cu.win_size = 1U;
  		conn->llcp_cu.win_offset_us = 0U;
  		if (conn->llcp_conn_param.preferred_periodicity) {
  			conn->llcp_cu.interval =
  				((conn->llcp_conn_param.interval_min /
  				  conn->llcp_conn_param.preferred_periodicity) +
  				 1) *
  				conn->llcp_conn_param.preferred_periodicity;
  		} else {
  			conn->llcp_cu.interval =
  				conn->llcp_conn_param.interval_max;
  		}
  		conn->llcp_cu.latency = conn->llcp_conn_param.latency;
  		conn->llcp_cu.timeout = conn->llcp_conn_param.timeout;
  		conn->llcp_cu.state = LLCP_CUI_STATE_SELECT;
  		conn->llcp_cu.cmd = conn->llcp_conn_param.cmd;
  		conn->llcp_cu.ack--;
  
  		return;
  	}
  
  	/* slave response with connection parameter response */
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return;
  	}
  
  	/* place the conn param rsp packet as next in tx queue */
  	pdu = (void *)node_tx->pdu_data;
  	pdu->ll_id = PDU_DATA_LLID_CTRL;
  	pdu->len = offsetof(struct pdu_data_llctrl, conn_param_rsp) +
  		sizeof(struct pdu_data_llctrl_conn_param_rsp);
  	pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP;
  	rsp = (void *)&pdu->llctrl.conn_param_rsp;
  	rsp->interval_min = conn->llcp_conn_param.interval_min;
  	rsp->interval_max = conn->llcp_conn_param.interval_max;
  	rsp->latency = conn->llcp_conn_param.latency;
  	rsp->timeout = conn->llcp_conn_param.timeout;
  	rsp->preferred_periodicity =
  		conn->llcp_conn_param.preferred_periodicity;
  	rsp->reference_conn_event_count =
  		conn->llcp_conn_param.reference_conn_event_count;
  	rsp->offset0 = conn->llcp_conn_param.offset0;
  	rsp->offset1 = conn->llcp_conn_param.offset1;
  	rsp->offset2 = conn->llcp_conn_param.offset2;
  	rsp->offset3 = conn->llcp_conn_param.offset3;
  	rsp->offset4 = conn->llcp_conn_param.offset4;
  	rsp->offset5 = conn->llcp_conn_param.offset5;
  
  	ctrl_tx_enqueue(conn, node_tx);
  
  	/* procedure request acked */
  	conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
  
  	/* reset mutex */
  	_radio.conn_upd = NULL;
  }
  
  static inline void event_conn_param_app_req(struct connection *conn)
  {
  	struct pdu_data_llctrl_conn_param_req *p;
  	struct radio_pdu_node_rx *node_rx;
  	struct pdu_data *pdu;
  
  	/* defer until encryption setup is complete */
  	if (conn->pause_tx) {
  		return;
  	}
  
  	/* wait for free rx buffer */
  	node_rx = packet_rx_reserve_get(2);
  	if (!node_rx) {
  		return;
  	}
  
  	/* move to wait for conn_update/rsp/rej */
  	conn->llcp_conn_param.state = LLCP_CPR_STATE_APP_WAIT;
  
  	/* Emulate as Rx-ed CPR data channel PDU */
  	node_rx->hdr.handle = conn->handle;
  	node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
  
  	/* place the conn param req packet as next in rx queue */
  	pdu = (void *)node_rx->pdu_data;
  	pdu->ll_id = PDU_DATA_LLID_CTRL;
  	pdu->len = offsetof(struct pdu_data_llctrl, conn_param_req) +
  		sizeof(struct pdu_data_llctrl_conn_param_req);
  	pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
  	p = (void *) &pdu->llctrl.conn_param_req;
  	p->interval_min = conn->llcp_conn_param.interval_min;
  	p->interval_max = conn->llcp_conn_param.interval_max;
  	p->latency = conn->llcp_conn_param.latency;
  	p->timeout = conn->llcp_conn_param.timeout;
  
  	/* enqueue connection parameter request into rx queue */
  	packet_rx_enqueue();
  }
  
  static inline void event_conn_param_prep(struct connection *conn,
  					 u16_t event_counter,
  					 u32_t ticks_at_expire)
  {
  	struct connection *conn_upd;
  
  	conn_upd = _radio.conn_upd;
  	if (conn_upd && (conn_upd != conn)) {
  		return;
  	}
  
  	switch (conn->llcp_conn_param.state) {
  	case LLCP_CPR_STATE_REQ:
  		event_conn_param_req(conn, event_counter, ticks_at_expire);
  		break;
  
  	case LLCP_CPR_STATE_RSP:
  		event_conn_param_rsp(conn);
  		break;
  
  	case LLCP_CPR_STATE_APP_REQ:
  		event_conn_param_app_req(conn);
  		break;
  
  	case LLCP_CPR_STATE_APP_WAIT:
  	case LLCP_CPR_STATE_RSP_WAIT:
  	case LLCP_CPR_STATE_UPD:
  		/* Do nothing */
  		break;
  
  	default:
  		LL_ASSERT(0);
  		break;
  	}
  }
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  static inline void event_ping_prep(struct connection *conn)
  {
  	struct radio_pdu_node_tx *node_tx;
  
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (node_tx) {
  		struct pdu_data *pdu_ctrl_tx = (void *)node_tx->pdu_data;
  
  		/* procedure request acked */
  		conn->llcp_ack = conn->llcp_req;
  
  		/* place the ping req packet as next in tx queue */
  		pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, ping_req) +
  				   sizeof(struct pdu_data_llctrl_ping_req);
  		pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_PING_REQ;
  
  		ctrl_tx_enqueue(conn, node_tx);
  
  		/* Start Procedure Timeout (TODO: this shall not replace
  		 * terminate procedure)
  		 */
  		conn->procedure_expire = conn->procedure_reload;
  	}
  
  }
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  static inline int event_len_prep(struct connection *conn)
  {
  	switch (conn->llcp_length.state) {
  	case LLCP_LENGTH_STATE_REQ:
  	{
  		struct pdu_data_llctrl_length_req *lr;
  		struct radio_pdu_node_tx *node_tx;
  		struct pdu_data *pdu_ctrl_tx;
  		u16_t free_count_rx;
  
  		free_count_rx = packet_rx_acquired_count_get() +
  			mem_free_count_get(_radio.pkt_rx_data_free);
  		LL_ASSERT(free_count_rx <= 0xFF);
  
  		if (_radio.packet_rx_data_count != free_count_rx) {
  			return 0;
  		}
  
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			return 0;
  		}
  
  		/* wait for resp before completing the procedure */
  		conn->llcp_length.state = LLCP_LENGTH_STATE_REQ_ACK_WAIT;
  
  		/* set the default tx octets/time to requested value */
  		conn->default_tx_octets = conn->llcp_length.tx_octets;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		conn->default_tx_time = conn->llcp_length.tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		/* place the length req packet as next in tx queue */
  		pdu_ctrl_tx = (void *) node_tx->pdu_data;
  		pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_tx->len =
  			offsetof(struct pdu_data_llctrl, length_req) +
  			sizeof(struct pdu_data_llctrl_length_req);
  		pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_REQ;
  
  		lr = &pdu_ctrl_tx->llctrl.length_req;
  		lr->max_rx_octets = LL_LENGTH_OCTETS_RX_MAX;
  		lr->max_tx_octets = conn->default_tx_octets;
  
  		if (!conn->common.fex_valid ||
  #if defined(CONFIG_BT_CTLR_PHY)
  		     (
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  		      !(conn->llcp_feature.features &
  			BIT(BT_LE_FEAT_BIT_PHY_CODED)) &&
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  
  #if defined(CONFIG_BT_CTLR_PHY_2M)
  		      !(conn->llcp_feature.features &
  			BIT(BT_LE_FEAT_BIT_PHY_2M)) &&
  #endif /* CONFIG_BT_CTLR_PHY_2M */
  		      1)
  #else /* !CONFIG_BT_CTLR_PHY */
  		    0
  #endif /* !CONFIG_BT_CTLR_PHY */
  		   ) {
  			lr->max_rx_time =
  				RADIO_PKT_TIME(LL_LENGTH_OCTETS_RX_MAX, 0);
  #if defined(CONFIG_BT_CTLR_PHY)
  			lr->max_tx_time = conn->default_tx_time;
  #else /* !CONFIG_BT_CTLR_PHY */
  			lr->max_tx_time =
  				RADIO_PKT_TIME(conn->default_tx_octets, 0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  		} else if (conn->llcp_feature.features &
  			   BIT(BT_LE_FEAT_BIT_PHY_CODED)) {
  			lr->max_rx_time =
  				RADIO_PKT_TIME(LL_LENGTH_OCTETS_RX_MAX, BIT(2));
  			lr->max_tx_time = conn->default_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  
  #if defined(CONFIG_BT_CTLR_PHY_2M)
  		} else if (conn->llcp_feature.features &
  			   BIT(BT_LE_FEAT_BIT_PHY_2M)) {
  			lr->max_rx_time =
  				RADIO_PKT_TIME(LL_LENGTH_OCTETS_RX_MAX, BIT(1));
  			if (conn->default_tx_time > lr->max_rx_time) {
  				lr->max_tx_time = lr->max_rx_time;
  			} else {
  				lr->max_tx_time = conn->default_tx_time;
  			}
  #endif /* CONFIG_BT_CTLR_PHY_2M */
  #endif /* CONFIG_BT_CTLR_PHY */
  		}
  
  		ctrl_tx_enqueue(conn, node_tx);
  
  		/* Start Procedure Timeout (TODO: this shall not replace
  		 * terminate procedure).
  		 */
  		conn->procedure_expire = conn->procedure_reload;
  	}
  	break;
  
  	case LLCP_LENGTH_STATE_RESIZE:
  	case LLCP_LENGTH_STATE_RESIZE_RSP:
  	{
  		struct pdu_data_llctrl_length_rsp *lr;
  		struct radio_pdu_node_rx *node_rx;
  		struct pdu_data *pdu_ctrl_rx;
  		u16_t packet_rx_data_size;
  		u16_t free_count_conn;
  		u16_t free_count_rx;
  		u16_t tx_octets;
  
  		/* Ensure the rx pool is not in use.
  		 * This is important to be able to re-size the pool
  		 * ensuring there is no chance that an operation on
  		 * the pool is pre-empted causing memory corruption.
  		 */
  		free_count_rx = packet_rx_acquired_count_get() +
  			mem_free_count_get(_radio.pkt_rx_data_free);
  		LL_ASSERT(free_count_rx <= 0xFF);
  
  		if (_radio.packet_rx_data_count != free_count_rx) {
  			/* NOTE: Another role instance has obtained
  			 * memory from rx pool, skip this event and
  			 * check in the next event if resize can be
  			 * done.
  			 */
  			return -EAGAIN;
  		}
  
  		/* Use the new rx octets in the connection */
  		conn->max_rx_octets = conn->llcp_length.rx_octets;
  
  		/* backup tx_octets */
  		tx_octets = conn->llcp_length.tx_octets;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		/* Use the new rx time in the connection */
  		conn->max_rx_time = conn->llcp_length.rx_time;
  
  		/* backup tx time */
  		u16_t tx_time = conn->llcp_length.tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		/* Reset event length update advanced flag */
  		conn->evt_len_adv = 0U;
  
  		/* switch states, to wait for ack, to request cached values or
  		 * complete the procedure
  		 */
  		if (conn->llcp_length.state == LLCP_LENGTH_STATE_RESIZE) {
  			/* check cache */
  			if (!conn->llcp_length.cache.tx_octets) {
  				/* Procedure complete */
  				conn->llcp_length.ack = conn->llcp_length.req;
  				conn->procedure_expire = 0U;
  			} else {
  				/* Initiate cached procedure */
  				conn->llcp_length.tx_octets =
  					conn->llcp_length.cache.tx_octets;
  				conn->llcp_length.cache.tx_octets = 0;
  #if defined(CONFIG_BT_CTLR_PHY)
  				conn->llcp_length.tx_time =
  					conn->llcp_length.cache.tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  				conn->llcp_length.state = LLCP_LENGTH_STATE_REQ;
  			}
  		} else {
  			conn->llcp_length.state =
  				LLCP_LENGTH_STATE_RESIZE_RSP_ACK_WAIT;
  		}
  
  		/** TODO This design is exception as memory initialization
  		 * and allocation is done in radio context here, breaking the
  		 * rule that the rx buffers are allocated in application
  		 * context.
  		 * Design mem_* such that mem_init could interrupt mem_acquire,
  		 * when the pool is full?
  		 */
  		free_count_conn = mem_free_count_get(_radio.conn_free);
  		if (_radio.advertiser.conn) {
  			free_count_conn++;
  		}
  		if (_radio.scanner.conn) {
  			free_count_conn++;
  		}
  		packet_rx_data_size = MROUND(offsetof(struct radio_pdu_node_rx,
  						      pdu_data) +
  					     offsetof(struct pdu_data,
  						      lldata) +
  					     conn->max_rx_octets);
  		/* Resize to lower or higher size if this is the only active
  		 * connection, or resize to only higher sizes as there may be
  		 * other connections using the current size.
  		 */
  		if (((free_count_conn + 1) == _radio.connection_count) ||
  		    (packet_rx_data_size > _radio.packet_rx_data_size)) {
  			/* as rx mem is to be re-sized, release acquired
  			 * memq link.
  			 */
  			while (_radio.packet_rx_acquire !=
  				_radio.packet_rx_last) {
  				if (_radio.packet_rx_acquire == 0) {
  					_radio.packet_rx_acquire =
  						_radio.packet_rx_count - 1;
  				} else {
  					_radio.packet_rx_acquire -= 1;
  				}
  
  				node_rx = _radio.packet_rx[
  						_radio.packet_rx_acquire];
  				mem_release(node_rx->hdr.link,
  					&_radio.link_rx_free);
  
  				LL_ASSERT(_radio.link_rx_data_quota <
  					  (_radio.packet_rx_count - 1));
  				_radio.link_rx_data_quota++;
  
  				/* no need to release node_rx as we mem_init
  				 * later down in code.
  				 */
  			}
  
  			/* calculate the new rx node size and new count */
  			if (conn->max_rx_octets < (PDU_AC_SIZE_MAX +
  						   PDU_AC_SIZE_EXTRA)) {
  				_radio.packet_rx_data_size =
  				    MROUND(offsetof(struct radio_pdu_node_rx,
  						    pdu_data) +
  					   (PDU_AC_SIZE_MAX +
  					    PDU_AC_SIZE_EXTRA));
  			} else {
  				_radio.packet_rx_data_size =
  					packet_rx_data_size;
  			}
  			_radio.packet_rx_data_count =
  				_radio.packet_rx_data_pool_size /
  				_radio.packet_rx_data_size;
  			LL_ASSERT(_radio.packet_rx_data_count);
  
  			/* re-size (re-init) the free rx pool */
  			mem_init(_radio.pkt_rx_data_pool,
  				 _radio.packet_rx_data_size,
  				 _radio.packet_rx_data_count,
  				 &_radio.pkt_rx_data_free);
  
  			/* allocate the rx queue include one extra for
  			 * generating event in following lines.
  			 */
  			packet_rx_allocate(4);
  		}
  
  		/* Prepare the rx packet structure */
  		node_rx = packet_rx_reserve_get(2);
  		LL_ASSERT(node_rx);
  		node_rx->hdr.handle = conn->handle;
  		node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
  
  		/* prepare length rsp structure */
  		pdu_ctrl_rx = (void *) node_rx->pdu_data;
  		pdu_ctrl_rx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_rx->len =
  			offsetof(struct pdu_data_llctrl, length_rsp) +
  			sizeof(struct pdu_data_llctrl_length_rsp);
  		pdu_ctrl_rx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP;
  
  		lr = &pdu_ctrl_rx->llctrl.length_rsp;
  		lr->max_rx_octets = conn->max_rx_octets;
  		lr->max_tx_octets = tx_octets;
  #if !defined(CONFIG_BT_CTLR_PHY)
  		lr->max_rx_time = RADIO_PKT_TIME(conn->max_rx_octets, 0);
  		lr->max_tx_time = RADIO_PKT_TIME(tx_octets, 0);
  #else /* CONFIG_BT_CTLR_PHY */
  		lr->max_rx_time = conn->max_rx_time;
  		lr->max_tx_time = tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		/* enqueue version ind structure into rx queue */
  		packet_rx_enqueue();
  	}
  	break;
  
  	case LLCP_LENGTH_STATE_REQ_ACK_WAIT:
  	case LLCP_LENGTH_STATE_RSP_WAIT:
  	case LLCP_LENGTH_STATE_RSP_ACK_WAIT:
  	case LLCP_LENGTH_STATE_RESIZE_RSP_ACK_WAIT:
  		/* no nothing */
  		break;
  
  	default:
  		LL_ASSERT(0);
  		break;
  	}
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  static inline void event_phy_req_prep(struct connection *conn)
  {
  	switch (conn->llcp_phy.state) {
  	case LLCP_PHY_STATE_REQ:
  	{
  		struct pdu_data_llctrl_phy_req *pr;
  		struct radio_pdu_node_tx *node_tx;
  		struct pdu_data *pdu_ctrl_tx;
  
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			break;
  		}
  
  		conn->llcp_phy.state = LLCP_PHY_STATE_ACK_WAIT;
  
  		/* update preferred phy */
  		conn->phy_pref_tx = conn->llcp_phy.tx;
  		conn->phy_pref_rx = conn->llcp_phy.rx;
  		conn->phy_pref_flags = conn->llcp_phy.flags;
  
  		/* place the phy req packet as next in tx queue */
  		pdu_ctrl_tx = (void *) node_tx->pdu_data;
  		pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_tx->len =
  			offsetof(struct pdu_data_llctrl, phy_req) +
  			sizeof(struct pdu_data_llctrl_phy_req);
  		pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_PHY_REQ;
  
  		pr = &pdu_ctrl_tx->llctrl.phy_req;
  		pr->tx_phys = conn->llcp_phy.tx;
  		pr->rx_phys = conn->llcp_phy.rx;
  
  		ctrl_tx_enqueue(conn, node_tx);
  
  		/* Start Procedure Timeout (TODO: this shall not replace
  		 * terminate procedure).
  		 */
  		conn->procedure_expire = conn->procedure_reload;
  	}
  	break;
  
  	case LLCP_PHY_STATE_UPD:
  	{
  		/* Defer if another procedure in progress */
  		if (conn->llcp_ack != conn->llcp_req) {
  			return;
  		}
  
  		/* Procedure complete */
  		conn->llcp_phy.ack = conn->llcp_phy.req;
  
  		/* select only one tx phy, prefer 2M */
  		if (conn->llcp_phy.tx & BIT(1)) {
  			conn->llcp_phy.tx = BIT(1);
  		} else if (conn->llcp_phy.tx & BIT(0)) {
  			conn->llcp_phy.tx = BIT(0);
  		} else if (conn->llcp_phy.tx & BIT(2)) {
  			conn->llcp_phy.tx = BIT(2);
  		} else {
  			conn->llcp_phy.tx = 0U;
  		}
  
  		/* select only one rx phy, prefer 2M */
  		if (conn->llcp_phy.rx & BIT(1)) {
  			conn->llcp_phy.rx = BIT(1);
  		} else if (conn->llcp_phy.rx & BIT(0)) {
  			conn->llcp_phy.rx = BIT(0);
  		} else if (conn->llcp_phy.rx & BIT(2)) {
  			conn->llcp_phy.rx = BIT(2);
  		} else {
  			conn->llcp_phy.rx = 0U;
  		}
  
  		/* Initiate PHY Update Ind */
  		if (conn->llcp_phy.tx != conn->phy_tx) {
  			conn->llcp.phy_upd_ind.tx = conn->llcp_phy.tx;
  		} else {
  			conn->llcp.phy_upd_ind.tx = 0U;
  		}
  		if (conn->llcp_phy.rx != conn->phy_rx) {
  			conn->llcp.phy_upd_ind.rx = conn->llcp_phy.rx;
  		} else {
  			conn->llcp.phy_upd_ind.rx = 0U;
  		}
  		/* conn->llcp.phy_upd_ind.instant = 0; */
  		conn->llcp.phy_upd_ind.initiate = 1U;
  		conn->llcp.phy_upd_ind.cmd = conn->llcp_phy.cmd;
  
  		conn->llcp_type = LLCP_PHY_UPD;
  		conn->llcp_ack--;
  	}
  	break;
  
  	case LLCP_PHY_STATE_ACK_WAIT:
  	case LLCP_PHY_STATE_RSP_WAIT:
  		/* no nothing */
  		break;
  
  	default:
  		LL_ASSERT(0);
  		break;
  	}
  }
  
  static inline void event_phy_upd_ind_prep(struct connection *conn,
  					  u16_t event_counter)
  {
  	struct radio_le_phy_upd_cmplt *upd;
  
  	if (conn->llcp.phy_upd_ind.initiate) {
  		struct radio_pdu_node_tx *node_tx;
  
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (node_tx) {
  			struct pdu_data *pdu_ctrl_tx = (void *)
  						       node_tx->pdu_data;
  			struct pdu_data_llctrl_phy_upd_ind *ind;
  
  			/* reset initiate flag */
  			conn->llcp.phy_upd_ind.initiate = 0U;
  
  			/* Check if both tx and rx PHY unchanged */
  			if (!((conn->llcp.phy_upd_ind.tx |
  			       conn->llcp.phy_upd_ind.rx) & 0x07)) {
  				/* Procedure complete */
  				conn->llcp_ack = conn->llcp_req;
  
  				/* 0 instant */
  				conn->llcp.phy_upd_ind.instant = 0U;
  
  				/* generate phy update event */
  				if (conn->llcp.phy_upd_ind.cmd) {
  					struct radio_pdu_node_rx *node_rx;
  
  					node_rx = packet_rx_reserve_get(2);
  					LL_ASSERT(node_rx);
  
  					node_rx->hdr.handle = conn->handle;
  					node_rx->hdr.type =
  						NODE_RX_TYPE_PHY_UPDATE;
  
  					upd = (void *)&node_rx->pdu_data;
  					upd->status = 0U;
  					upd->tx = conn->phy_tx;
  					upd->rx = conn->phy_rx;
  
  					packet_rx_enqueue();
  				}
  			} else {
  				/* set instant */
  				conn->llcp.phy_upd_ind.instant = event_counter +
  								 conn->latency +
  								 6;
  			}
  
  			/* place the phy update ind packet as next in
  			 * tx queue
  			 */
  			pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  			pdu_ctrl_tx->len =
  				offsetof(struct pdu_data_llctrl, phy_upd_ind) +
  				sizeof(struct pdu_data_llctrl_phy_upd_ind);
  			pdu_ctrl_tx->llctrl.opcode =
  				PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND;
  			ind = &pdu_ctrl_tx->llctrl.phy_upd_ind;
  			ind->m_to_s_phy = conn->llcp.phy_upd_ind.tx;
  			ind->s_to_m_phy = conn->llcp.phy_upd_ind.rx;
  			ind->instant = conn->llcp.phy_upd_ind.instant;
  
  			ctrl_tx_enqueue(conn, node_tx);
  		}
  	} else if (((event_counter - conn->llcp.phy_upd_ind.instant) & 0xFFFF)
  			    <= 0x7FFF) {
  		struct radio_pdu_node_rx *node_rx;
  		u8_t old_tx, old_rx;
  
  		/* procedure request acked */
  		conn->llcp_ack = conn->llcp_req;
  
  		/* apply new phy */
  		old_tx = conn->phy_tx;
  		old_rx = conn->phy_rx;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		u16_t eff_tx_time = conn->max_tx_time;
  		u16_t eff_rx_time = conn->max_rx_time;
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  		if (conn->llcp.phy_upd_ind.tx) {
  			conn->phy_tx = conn->llcp.phy_upd_ind.tx;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  			u16_t tx_time = RADIO_PKT_TIME(conn->max_tx_octets,
  						       conn->phy_tx);
  			if (tx_time >=
  			    RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0)) {
  				eff_tx_time = MIN(tx_time,
  						  conn->default_tx_time);
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  				eff_tx_time = MAX(eff_tx_time,
  					RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
  						       conn->phy_tx));
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  			} else {
  				eff_tx_time =
  					RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
  						       0);
  			}
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  		}
  
  		if (conn->llcp.phy_upd_ind.rx) {
  			conn->phy_rx = conn->llcp.phy_upd_ind.rx;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  			u16_t rx_time = RADIO_PKT_TIME(conn->max_rx_octets,
  						       conn->phy_rx);
  			if (rx_time >=
  			    RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0)) {
  				eff_rx_time = MIN(rx_time,
  					RADIO_PKT_TIME(LL_LENGTH_OCTETS_RX_MAX,
  						       BIT(2)));
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  				eff_rx_time = MAX(eff_rx_time,
  					RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
  						       conn->phy_rx));
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  			} else {
  				eff_rx_time =
  					RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
  						       0);
  			}
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  		}
  		conn->phy_flags = conn->phy_pref_flags;
  
  		/* generate event if phy changed or initiated by cmd */
  		if (!conn->llcp.phy_upd_ind.cmd && (conn->phy_tx == old_tx) &&
  		    (conn->phy_rx == old_rx)) {
  			return;
  		}
  
  		/* Prepare the rx packet structure */
  		node_rx = packet_rx_reserve_get(2);
  		LL_ASSERT(node_rx);
  
  		node_rx->hdr.handle = conn->handle;
  		node_rx->hdr.type = NODE_RX_TYPE_PHY_UPDATE;
  
  		upd = (void *)&node_rx->pdu_data;
  		upd->status = 0U;
  		upd->tx = conn->phy_tx;
  		upd->rx = conn->phy_rx;
  
  		if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  			/* deferred enqueue phy update structure into rx queue
  			 */
  			packet_rx_enqueue_get(); /* ignore return as its same
  						  * node_rx
  						  */
  			packet_rx_enqueue_hold(node_rx);
  		} else {
  			packet_rx_enqueue();
  		}
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		/* Update max tx and/or max rx if changed */
  		if ((eff_tx_time <= conn->max_tx_time) &&
  		    (eff_rx_time <= conn->max_rx_time)) {
  			return;
  		}
  		conn->max_tx_time = eff_tx_time;
  		conn->max_rx_time = eff_rx_time;
  
  		/* Prepare the rx packet structure */
  		node_rx = packet_rx_reserve_get(2);
  		LL_ASSERT(node_rx);
  		node_rx->hdr.handle = conn->handle;
  		node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
  
  		/* prepare length rsp structure */
  		struct pdu_data *pdu_ctrl_rx = (void *)node_rx->pdu_data;
  
  		pdu_ctrl_rx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_rx->len =
  			offsetof(struct pdu_data_llctrl, length_rsp) +
  			sizeof(struct pdu_data_llctrl_length_rsp);
  		pdu_ctrl_rx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP;
  
  		struct pdu_data_llctrl_length_req *lr =
  			(void *)&pdu_ctrl_rx->llctrl.length_rsp;
  		lr->max_rx_octets = conn->max_rx_octets;
  		lr->max_tx_octets = conn->max_tx_octets;
  		lr->max_rx_time = conn->max_rx_time;
  		lr->max_tx_time = conn->max_tx_time;
  
  		if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  			/* deferred enqueue data length update structure into
  			 * rx queue
  			 */
  			packet_rx_enqueue_get(); /* ignore return as its same
  						  * node_rx
  						  */
  			packet_rx_enqueue_hold(node_rx);
  		} else {
  			packet_rx_enqueue();
  		}
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  		/* flag an event length update*/
  		conn->evt_len_upd = 1U;
  	}
  }
  #endif /* CONFIG_BT_CTLR_PHY */
  
  static void event_connection_prepare(u32_t ticks_at_expire,
  				     u32_t remainder, u16_t lazy,
  				     struct connection *conn)
  {
  	u16_t event_counter;
  
  	LL_ASSERT(!_radio.ticker_id_prepare);
  	_radio.ticker_id_prepare = RADIO_TICKER_ID_FIRST_CONNECTION +
  				   conn->handle;
  
  	/* Calc window widening */
  	if (conn->role) {
  		conn->slave.window_widening_prepare_us +=
  		    conn->slave.window_widening_periodic_us * (lazy + 1);
  		if (conn->slave.window_widening_prepare_us >
  		    conn->slave.window_widening_max_us) {
  			conn->slave.window_widening_prepare_us =
  				conn->slave.window_widening_max_us;
  		}
  	}
  
  	/* save the latency for use in event */
  	conn->latency_prepare += lazy;
  
  	/* calc current event counter value */
  	event_counter = conn->event_counter + conn->latency_prepare;
  
  	/* Check if no other procedure with instant is requested and not in
  	 * Encryption setup.
  	 */
  	if ((conn->llcp_ack == conn->llcp_req) && !conn->pause_rx) {
  		if (conn->llcp_cu.ack != conn->llcp_cu.req) {
  			/* Previous event will be stop in the switch clause
  			 * below.
  			 */
  			conn->llcp_type = LLCP_CONN_UPD;
  			conn->llcp_ack--;
  
  		} else if (conn->llcp_feature.ack != conn->llcp_feature.req) {
  			/* Stop previous event, to avoid Radio DMA corrupting
  			 * the rx queue.
  			 */
  			event_stop(0, 0, 0, (void *)STATE_ABORT);
  
  			event_fex_prep(conn);
  
  		} else if (conn->llcp_version.ack != conn->llcp_version.req) {
  			/* Stop previous event, to avoid Radio DMA corrupting
  			 * the rx queue.
  			 */
  			event_stop(0, 0, 0, (void *)STATE_ABORT);
  
  			event_vex_prep(conn);
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  		/* check if CPR procedure is requested */
  		} else if (conn->llcp_conn_param.ack !=
  			   conn->llcp_conn_param.req) {
  			/* Stop previous event, to avoid Radio DMA corrupting
  			 * the rx queue.
  			 */
  			event_stop(0, 0, 0, (void *)STATE_ABORT);
  
  			/* handle CPR state machine */
  			event_conn_param_prep(conn, event_counter,
  					      ticks_at_expire);
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		/* check if DLE procedure is requested */
  		} else if (conn->llcp_length.ack != conn->llcp_length.req) {
  			/* Stop previous event, to avoid Radio DMA corrupting
  			 * the rx queue
  			 */
  			event_stop(0, 0, 0, (void *)STATE_ABORT);
  
  			/* handle DLU state machine */
  			if (event_len_prep(conn)) {
  				/* NOTE: rx pool could not be resized, lets
  				 * skip this event and try in the next event.
  				 */
  				_radio.ticker_id_prepare = 0U;
  
  				goto event_connection_prepare_skip;
  			}
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		/* check if PHY Req procedure is requested */
  		} else if (conn->llcp_phy.ack != conn->llcp_phy.req) {
  			/* Stop previous event, to avoid Radio DMA corrupting
  			 * the rx queue.
  			 */
  			event_stop(0, 0, 0, (void *)STATE_ABORT);
  
  			/* handle PHY Upd state machine */
  			event_phy_req_prep(conn);
  #endif /* CONFIG_BT_CTLR_PHY */
  		}
  	}
  
  	/* Check if procedures with instant or encryption setup is requested or
  	 * active.
  	 */
  	if (conn->llcp_ack != conn->llcp_req) {
  		/* Stop previous event, to avoid Radio DMA corrupting the
  		 * rx queue
  		 */
  		event_stop(0, 0, 0, (void *)STATE_ABORT);
  
  		/* Process parallel procedures that are active */
  		if (0) {
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		/* Check if DLE in progress */
  		} else if (conn->llcp_length.ack != conn->llcp_length.req) {
  			if ((conn->llcp_length.state ==
  			     LLCP_LENGTH_STATE_RESIZE) ||
  			    (conn->llcp_length.state ==
  			     LLCP_LENGTH_STATE_RESIZE_RSP)) {
  				/* handle DLU state machine */
  				if (event_len_prep(conn)) {
  					/* NOTE: rx pool could not be resized,
  					 * lets skip this event and try in the
  					 * next event.
  					 */
  					_radio.ticker_id_prepare = 0U;
  
  					goto event_connection_prepare_skip;
  				}
  			}
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  		}
  
  		/* Process procedures with instants or encryption setup */
  		/* FIXME: Make LE Ping cacheable */
  		switch (conn->llcp_type) {
  		case LLCP_CONN_UPD:
  			if (!event_conn_upd_prep(conn, event_counter,
  						 ticks_at_expire)) {
  				/* Reset ticker_id_prepare as role is not
  				 * continued further due to conn update at
  				 * this event.
  				 */
  				_radio.ticker_id_prepare = 0U;
  				return;
  			}
  			break;
  		case LLCP_CHAN_MAP:
  			event_ch_map_prep(conn, event_counter);
  			break;
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  		case LLCP_ENCRYPTION:
  			event_enc_prep(conn);
  			break;
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  		case LLCP_PING:
  			event_ping_prep(conn);
  			break;
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		case LLCP_PHY_UPD:
  			event_phy_upd_ind_prep(conn, event_counter);
  			break;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		default:
  			LL_ASSERT(0);
  			break;
  		}
  	}
  
  	/* Terminate Procedure Request */
  	if (conn->llcp_terminate.ack != conn->llcp_terminate.req) {
  		struct radio_pdu_node_tx *node_tx;
  
  		/* Stop previous event, to avoid Radio DMA corrupting the rx
  		 * queue
  		 */
  		event_stop(0, 0, 0, (void *)STATE_ABORT);
  
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (node_tx) {
  			struct pdu_data *pdu_ctrl_tx = (void *)
  						       node_tx->pdu_data;
  
  			/* Terminate Procedure acked */
  			conn->llcp_terminate.ack = conn->llcp_terminate.req;
  
  			/* place the terminate ind packet in tx queue */
  			pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  			pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl,
  						    terminate_ind) +
  				sizeof(struct pdu_data_llctrl_terminate_ind);
  			pdu_ctrl_tx->llctrl.opcode =
  				PDU_DATA_LLCTRL_TYPE_TERMINATE_IND;
  			pdu_ctrl_tx->llctrl.terminate_ind.error_code =
  				conn->llcp_terminate.reason_own;
  
  			ctrl_tx_enqueue(conn, node_tx);
  
  			/* Terminate Procedure timeout is started, will
  			 * replace any other timeout running
  			 */
  			conn->procedure_expire = conn->supervision_reload;
  
  			/* NOTE: if supervision timeout equals connection
  			 * interval, dont timeout in current event.
  			 */
  			if (conn->procedure_expire <= 1) {
  				conn->procedure_expire++;
  			}
  		}
  	}
  
  	/* Setup XTAL startup and radio active events */
  	event_common_prepare(ticks_at_expire, remainder,
  			     &conn->hdr.ticks_xtal_to_start,
  			     &conn->hdr.ticks_active_to_start,
  			     conn->hdr.ticks_preempt_to_start,
  			     (RADIO_TICKER_ID_FIRST_CONNECTION + conn->handle),
  #if defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_CENTRAL)
  			     conn->role ? event_slave : event_master,
  #elif defined(CONFIG_BT_PERIPHERAL)
  			     event_slave,
  #else
  			     event_master,
  #endif
  			     conn);
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  event_connection_prepare_skip:
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  	/* store the next event counter value */
  	conn->event_counter = event_counter + 1;
  }
  
  static void connection_configure(struct connection *conn)
  {
  	radio_reset();
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  	radio_tx_power_set(conn->tx_pwr_lvl);
  #else
  	radio_tx_power_set(RADIO_TXP_DEFAULT);
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  	radio_isr_set(isr, NULL);
  	radio_aa_set(conn->access_addr);
  	radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
  			    (((u32_t)conn->crc_init[2] << 16) |
  			     ((u32_t)conn->crc_init[1] << 8) |
  			     ((u32_t)conn->crc_init[0])));
  }
  
  #if defined(CONFIG_BT_PERIPHERAL)
  static void event_slave_prepare(u32_t ticks_at_expire, u32_t remainder,
  				u16_t lazy, void *context)
  {
  	DEBUG_RADIO_PREPARE_S(1);
  
  	event_connection_prepare(ticks_at_expire, remainder, lazy, context);
  
  	DEBUG_RADIO_PREPARE_S(0);
  }
  
  static void event_slave(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
  			void *context)
  {
  	struct connection *conn = context;
  	u8_t data_chan_use = 0U;
  	u32_t remainder_us;
  	u32_t hcto;
  
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  
  	DEBUG_RADIO_START_S(1);
  
  	LL_ASSERT(_radio.role == ROLE_NONE);
  
  	LL_ASSERT(_radio.ticker_id_prepare ==
  		  (RADIO_TICKER_ID_FIRST_CONNECTION + conn->handle));
  
  	_radio.role = ROLE_SLAVE;
  	_radio.state = STATE_RX;
  	_radio.ticker_id_prepare = 0U;
  	_radio.ticker_id_event =
  		(RADIO_TICKER_ID_FIRST_CONNECTION + conn->handle);
  	_radio.ticks_anchor = ticks_at_expire;
  	_radio.packet_counter = 0U;
  	_radio.crc_expire = 0U;
  
  	_radio.conn_curr = conn;
  
  	conn->latency_event = conn->latency_prepare;
  	conn->latency_prepare = 0U;
  
  	connection_configure(conn);
  
  	radio_tmr_tifs_set(RADIO_TIFS);
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	radio_switch_complete_and_tx(conn->phy_rx, 0, conn->phy_tx,
  				     conn->phy_flags);
  #else /* !CONFIG_BT_CTLR_PHY */
  	radio_switch_complete_and_tx(0, 0, 0, 0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  	rx_packet_set(conn, (void *)
  		      _radio.packet_rx[_radio.packet_rx_last]->pdu_data);
  
  	/* Setup Radio Channel */
  	if (conn->data_chan_sel) {
  #if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
  		data_chan_use = chan_sel_2(conn->event_counter - 1,
  					   conn->data_chan_id,
  					   &conn->data_chan_map[0],
  					   conn->data_chan_count);
  #else /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
  		LL_ASSERT(0);
  #endif /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
  	} else {
  		data_chan_use = chan_sel_1(&conn->data_chan_use,
  					   conn->data_chan_hop,
  					   conn->latency_event,
  					   &conn->data_chan_map[0],
  					   conn->data_chan_count);
  	}
  	chan_set(data_chan_use);
  
  	/* current window widening */
  	conn->slave.window_widening_event_us +=
  		conn->slave.window_widening_prepare_us;
  	conn->slave.window_widening_prepare_us = 0U;
  	if (conn->slave.window_widening_event_us >
  	    conn->slave.window_widening_max_us) {
  		conn->slave.window_widening_event_us =
  			conn->slave.window_widening_max_us;
  	}
  
  	/* current window size */
  	conn->slave.window_size_event_us +=
  		conn->slave.window_size_prepare_us;
  	conn->slave.window_size_prepare_us = 0U;
  
  	remainder_us = radio_tmr_start(0, ticks_at_expire +
  					  HAL_TICKER_US_TO_TICKS(
  						RADIO_TICKER_START_PART_US),
  				       _radio.remainder_anchor);
  
  	radio_tmr_aa_capture();
  	radio_tmr_aa_save(0);
  
  	hcto = remainder_us + RADIO_TICKER_JITTER_US +
  	       (RADIO_TICKER_JITTER_US << 2) +
  	       (conn->slave.window_widening_event_us << 1) +
  	       conn->slave.window_size_event_us;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	hcto += radio_rx_ready_delay_get(conn->phy_rx, 1);
  	hcto += addr_us_get(conn->phy_rx);
  	hcto += radio_rx_chain_delay_get(conn->phy_rx, 1);
  #else /* !CONFIG_BT_CTLR_PHY */
  	hcto += radio_rx_ready_delay_get(0, 0);
  	hcto += addr_us_get(0);
  	hcto += radio_rx_chain_delay_get(0, 0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  	radio_tmr_hcto_configure(hcto);
  
  #if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  	radio_gpio_lna_setup();
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	radio_gpio_pa_lna_enable(remainder_us +
  				 radio_rx_ready_delay_get(conn->phy_rx, 1) -
  				 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #else /* !CONFIG_BT_CTLR_PHY */
  	radio_gpio_pa_lna_enable(remainder_us +
  				 radio_rx_ready_delay_get(0, 0) -
  				 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #endif /* !CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR) || \
      defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  	radio_tmr_end_capture();
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  	radio_rssi_measure();
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  #if (defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
       (RADIO_TICKER_PREEMPT_PART_US <= RADIO_TICKER_PREEMPT_PART_MIN_US))
  	/* check if preempt to start has changed */
  	if (preempt_calc(&conn->hdr, (RADIO_TICKER_ID_FIRST_CONNECTION +
  				      conn->handle), ticks_at_expire) != 0) {
  		_radio.state = STATE_STOP;
  		radio_disable();
  	} else
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  	/* Ticker Job Silence */
  	{
  		u32_t ticker_status;
  
  		ticker_status =
  			ticker_job_idle_get(RADIO_TICKER_INSTANCE_ID_RADIO,
  					    RADIO_TICKER_USER_ID_WORKER,
  					    ticker_job_disable, NULL);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	}
  #endif
  
  	/* Route the tx packet to respective connections */
  	packet_tx_enqueue(2);
  
  	DEBUG_RADIO_START_S(0);
  }
  #endif /* CONFIG_BT_PERIPHERAL */
  
  #if defined(CONFIG_BT_CENTRAL)
  static void event_master_prepare(u32_t ticks_at_expire, u32_t remainder,
  				 u16_t lazy, void *context)
  {
  	DEBUG_RADIO_PREPARE_M(1);
  
  	event_connection_prepare(ticks_at_expire, remainder, lazy, context);
  
  	DEBUG_RADIO_PREPARE_M(0);
  }
  
  static void event_master(u32_t ticks_at_expire, u32_t remainder, u16_t lazy,
  			 void *context)
  {
  	struct connection *conn = context;
  	struct pdu_data *pdu_data_tx;
  	u8_t data_chan_use = 0U;
  	u32_t remainder_us;
  
  	ARG_UNUSED(remainder);
  	ARG_UNUSED(lazy);
  
  	DEBUG_RADIO_START_M(1);
  
  	LL_ASSERT(_radio.role == ROLE_NONE);
  
  	LL_ASSERT(_radio.ticker_id_prepare ==
  		  (RADIO_TICKER_ID_FIRST_CONNECTION + conn->handle));
  
  	_radio.role = ROLE_MASTER;
  	_radio.state = STATE_TX;
  	_radio.ticker_id_prepare = 0U;
  	_radio.ticker_id_event =
  	    (RADIO_TICKER_ID_FIRST_CONNECTION + conn->handle);
  	_radio.ticks_anchor = ticks_at_expire;
  	_radio.packet_counter = 0U;
  	_radio.crc_expire = 0U;
  
  	_radio.conn_curr = conn;
  
  	conn->latency_event = conn->latency_prepare;
  	conn->latency_prepare = 0U;
  
  	/* Route the tx packet to respective connections */
  	packet_tx_enqueue(2);
  
  	/* prepare transmit packet */
  	prepare_pdu_data_tx(conn, &pdu_data_tx);
  
  	pdu_data_tx->sn = conn->sn;
  	pdu_data_tx->nesn = conn->nesn;
  
  	connection_configure(conn);
  
  	radio_tmr_tifs_set(RADIO_TIFS);
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	radio_switch_complete_and_rx(conn->phy_rx);
  #else /* !CONFIG_BT_CTLR_PHY */
  	radio_switch_complete_and_rx(0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  	tx_packet_set(conn, pdu_data_tx);
  
  	/* Setup Radio Channel */
  	if (conn->data_chan_sel) {
  #if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
  		data_chan_use = chan_sel_2(conn->event_counter - 1,
  					   conn->data_chan_id,
  					   &conn->data_chan_map[0],
  					   conn->data_chan_count);
  #else /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
  		LL_ASSERT(0);
  #endif /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
  	} else {
  		data_chan_use = chan_sel_1(&conn->data_chan_use,
  					   conn->data_chan_hop,
  					   conn->latency_event,
  					   &conn->data_chan_map[0],
  					   conn->data_chan_count);
  	}
  	chan_set(data_chan_use);
  
  	/* normal connection! */
  #if SILENT_CONNECTION
  	if (!conn->empty || pdu_data_tx->md ||
  	    (conn->supervision_expire && (conn->supervision_expire <= 6)) ||
  	    (conn->connect_expire && (conn->connect_expire <= 6))) {
  #endif
  		remainder_us = radio_tmr_start(1,
  					       ticks_at_expire +
  					       HAL_TICKER_US_TO_TICKS(
  						RADIO_TICKER_START_PART_US),
  					       _radio.remainder_anchor);
  
  		/* capture end of Tx-ed PDU, used to calculate HCTO. */
  		radio_tmr_end_capture();
  
  #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
  		radio_gpio_pa_setup();
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		radio_gpio_pa_lna_enable(remainder_us +
  			radio_tx_ready_delay_get(conn->phy_tx,
  						 conn->phy_flags) -
  			CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #else /* !CONFIG_BT_CTLR_PHY */
  		radio_gpio_pa_lna_enable(remainder_us +
  					 radio_tx_ready_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_PA_OFFSET);
  #endif /* !CONFIG_BT_CTLR_PHY */
  #else /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
  		ARG_UNUSED(remainder_us);
  #endif /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
  
  #if SILENT_CONNECTION
  	/* silent connection! */
  	} else {
  		u32_t remainder_us;
  		u32_t hcto;
  
  		/* start in RX state */
  		_radio.state = STATE_RX;
  		_radio.packet_counter = 0xFF;
  
  		radio_tmr_tifs_set(RADIO_TIFS);
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		radio_switch_complete_and_tx(conn->phy_rx, 0, conn->phy_tx,
  					     conn->phy_flags);
  #else /* !CONFIG_BT_CTLR_PHY */
  		radio_switch_complete_and_tx(0, 0, 0, 0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  		rx_packet_set(conn, (void *)
  			_radio.packet_rx[_radio.packet_rx_last]->pdu_data);
  
  		/* setup pkticker and hcto */
  		remainder_us = radio_tmr_start(0,
  					       ticks_at_expire +
  					       HAL_TICKER_US_TO_TICKS(
  						RADIO_TICKER_START_PART_US),
  					       _radio.remainder_anchor);
  
  		radio_tmr_aa_capture();
  		radio_tmr_aa_save(0);
  
  		hcto = remainder_us + RADIO_TIFS;
  #if defined(CONFIG_BT_CTLR_PHY)
  		hcto += radio_tx_ready_delay_get(conn->phy_tx, conn->phy_flags);
  		hcto += empty_pkt_us_get(conn->phy_rx);
  		hcto += addr_us_get(conn->phy_rx);
  #else /* !CONFIG_BT_CTLR_PHY */
  		hcto += radio_tx_ready_delay_get(0, 0);
  		hcto += empty_pkt_us_get(0);
  		hcto += addr_us_get(0);
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  		/* TODO: account for slave window widening */
  		hcto += 256;
  
  		radio_tmr_hcto_configure(hcto);
  
  #if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
  		radio_gpio_lna_setup();
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		radio_gpio_pa_lna_enable(remainder_us +
  			radio_rx_ready_delay_get(conn->phy_rx, 1) -
  			CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #else /* !CONFIG_BT_CTLR_PHY */
  		radio_gpio_pa_lna_enable(remainder_us +
  					 radio_rx_ready_delay_get(0, 0) -
  					 CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
  #endif /* !CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
  	}
  #endif
  
  #if (defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
       (RADIO_TICKER_PREEMPT_PART_US <= RADIO_TICKER_PREEMPT_PART_MIN_US))
  	/* check if preempt to start has changed */
  	if (0 !=
  	    preempt_calc(&conn->hdr, (RADIO_TICKER_ID_FIRST_CONNECTION +
  				      conn->handle), ticks_at_expire)) {
  		_radio.state = STATE_STOP;
  		radio_disable();
  	} else
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  	/* Ticker Job Silence */
  	{
  		u32_t ticker_status;
  
  		ticker_status =
  			ticker_job_idle_get(RADIO_TICKER_INSTANCE_ID_RADIO,
  					    RADIO_TICKER_USER_ID_WORKER,
  					    ticker_job_disable, NULL);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	}
  #endif
  
  	DEBUG_RADIO_START_M(0);
  }
  #endif /* CONFIG_BT_CENTRAL */
  #endif /* CONFIG_BT_CONN */
  
  static void rx_packet_set(struct connection *conn, struct pdu_data *pdu_data_rx)
  {
  	u16_t max_rx_octets;
  	u8_t phy;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	max_rx_octets = conn->max_rx_octets;
  #else /* !CONFIG_BT_CTLR_DATA_LENGTH */
  	max_rx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
  #endif /* !CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	phy = conn->phy_rx;
  #else /* !CONFIG_BT_CTLR_PHY */
  	phy = 0U;
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  	radio_phy_set(phy, 0);
  
  	if (conn->enc_rx) {
  		radio_pkt_configure(8, (max_rx_octets + 4), (phy << 1) | 0x01);
  
  		radio_pkt_rx_set(radio_ccm_rx_pkt_set(&conn->ccm_rx, phy,
  						      pdu_data_rx));
  	} else {
  		radio_pkt_configure(8, max_rx_octets, (phy << 1) | 0x01);
  
  		radio_pkt_rx_set(pdu_data_rx);
  	}
  }
  
  static void packet_rx_allocate(u8_t max)
  {
  	u8_t acquire;
  
  	if (max > _radio.link_rx_data_quota) {
  		max = _radio.link_rx_data_quota;
  	}
  
  	acquire = _radio.packet_rx_acquire + 1;
  	if (acquire == _radio.packet_rx_count) {
  		acquire = 0U;
  	}
  
  	while ((max--) && (acquire != _radio.packet_rx_last)) {
  		memq_link_t *link;
  		struct radio_pdu_node_rx *node_rx;
  
  		link = mem_acquire(&_radio.link_rx_free);
  		if (!link) {
  			break;
  		}
  
  		node_rx = mem_acquire(&_radio.pkt_rx_data_free);
  		if (!node_rx) {
  			mem_release(link, &_radio.link_rx_free);
  			break;
  		}
  
  		if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  			link->next = link->mem = NULL;
  		}
  
  		node_rx->hdr.link = link;
  
  		_radio.packet_rx[_radio.packet_rx_acquire] = node_rx;
  		_radio.packet_rx_acquire = acquire;
  
  		acquire = _radio.packet_rx_acquire + 1;
  		if (acquire == _radio.packet_rx_count) {
  			acquire = 0U;
  		}
  
  		_radio.link_rx_data_quota--;
  	}
  }
  
  static inline u8_t packet_rx_acquired_count_get(void)
  {
  	if (_radio.packet_rx_acquire >=
  	    _radio.packet_rx_last) {
  		return (_radio.packet_rx_acquire -
  			_radio.packet_rx_last);
  	} else {
  		return (_radio.packet_rx_count -
  			_radio.packet_rx_last +
  			_radio.packet_rx_acquire);
  	}
  }
  
  static inline struct radio_pdu_node_rx *packet_rx_reserve_get(u8_t count)
  {
  	if (count > packet_rx_acquired_count_get()) {
  		return 0;
  	}
  
  	return _radio.packet_rx[_radio.packet_rx_last];
  }
  
  static void packet_rx_callback(void)
  {
  	/* Inline call of callback. If JOB configured as lower priority then
  	 * callback will tailchain at end of every radio ISR. If JOB configured
  	 * as same then call inline so as to have callback for every radio ISR.
  	 */
  #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  	radio_event_callback();
  #else
  	static memq_link_t s_link;
  	static struct mayfly s_mfy_callback = {0, 0, &s_link, NULL,
  		(void *)radio_event_callback};
  
  	mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER, RADIO_TICKER_USER_ID_JOB, 1,
  		       &s_mfy_callback);
  #endif
  }
  
  static inline struct radio_pdu_node_rx *packet_rx_enqueue_get(void)
  {
  	struct radio_pdu_node_rx *node_rx;
  	u8_t last;
  
  	LL_ASSERT(_radio.packet_rx_last != _radio.packet_rx_acquire);
  
  	node_rx = _radio.packet_rx[_radio.packet_rx_last];
  
  	/* dequeue from acquired rx queue */
  	last = _radio.packet_rx_last + 1;
  	if (last == _radio.packet_rx_count) {
  		last = 0U;
  	}
  	_radio.packet_rx_last = last;
  
  	return node_rx;
  }
  
  static inline void packet_rx_enqueue_commit(struct radio_pdu_node_rx *node_rx)
  {
  	memq_link_t *link;
  
  	/* back up link stored in rx node */
  	link = node_rx->hdr.link;
  
  	/* serialize release queue with rx queue by storing reference to last
  	 * element in release queue
  	 */
  	node_rx->hdr.packet_release_last = _radio.packet_release_last;
  
  	/* Enqueue into event-cum-data queue */
  	link = memq_enqueue(link, node_rx, (void *)&_radio.link_rx_tail);
  	LL_ASSERT(link);
  }
  
  static inline void packet_rx_enqueue_hold(struct radio_pdu_node_rx *node_rx)
  {
  	struct radio_pdu_node_rx *next;
  	memq_link_t *link, *link_last;
  
  	LL_ASSERT(_radio.packet_rx_last != _radio.packet_rx_acquire);
  
  	/* fetch the next available free rx node */
  	next = _radio.packet_rx[_radio.packet_rx_last];
  
  	/* hold the rx node inside the link of the first free rx node */
  	link = next->hdr.link;
  	if (!link->next) {
  		link_last = (void *)node_rx->hdr.link;
  		if (!link_last->next) {
  			link->mem = (void *)node_rx;
  			link->next = (void *)node_rx;
  		} else {
  			struct radio_pdu_node_rx *last = (void *)link_last->mem;
  
  			link->mem = node_rx;
  			link->next = link_last->next;
  			link_last->next = NULL;
  
  			link_last = last->hdr.link;
  			link_last->next = (void *)node_rx;
  		}
  	} else {
  		struct radio_pdu_node_rx *last = (void *)link->mem;
  
  		link_last = (void *)last->hdr.link;
  		link_last->next = (void *)node_rx;
  		link_last = (void *)node_rx->hdr.link;
  		link->mem = link_last->mem;
  	}
  }
  
  static inline void packet_rx_enqueue_forward(void)
  {
  	struct radio_pdu_node_rx *next, *p;
  	memq_link_t *link;
  
  	/* fetch the next available free rx node */
  	next = _radio.packet_rx[_radio.packet_rx_last];
  
  	link = next->hdr.link;
  	p = (void *)link->next;
  	if (!p) {
  		return;
  	}
  
  	link->next = link->mem = NULL;
  
  	do {
  		struct radio_pdu_node_rx *node_rx = p;
  
  		link = p->hdr.link;
  		p = (void *)link->next;
  
  		packet_rx_enqueue_commit(node_rx);
  	} while (p);
  }
  
  static void packet_rx_enqueue(void)
  {
  	struct radio_pdu_node_rx *node_rx;
  
  	/* forward held rx nodes */
  	if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  		packet_rx_enqueue_forward();
  	}
  
  	/* Get the populated rx node from the free queue */
  	node_rx = packet_rx_enqueue_get();
  
  	/* Link the rx node with tx ack queue and enqueue towards host */
  	packet_rx_enqueue_commit(node_rx);
  
  	/* callback to trigger application action */
  	packet_rx_callback();
  }
  
  static void packet_tx_enqueue(u8_t max)
  {
  	while ((max--) && (_radio.packet_tx_first != _radio.packet_tx_last)) {
  		struct pdu_data_q_tx *pdu_data_q_tx;
  		struct radio_pdu_node_tx *node_tx_new;
  		struct connection *conn;
  		u8_t first;
  
  		pdu_data_q_tx = &_radio.pkt_tx[_radio.packet_tx_first];
  		node_tx_new = pdu_data_q_tx->node_tx;
  		node_tx_new->next = NULL;
  		conn = mem_get(_radio.conn_pool, CONNECTION_T_SIZE,
  				pdu_data_q_tx->handle);
  
  		if (conn->handle == pdu_data_q_tx->handle) {
  			if (IS_ENABLED(CONFIG_BT_CTLR_LLID_DATA_START_EMPTY)) {
  				struct pdu_data *p;
  
  				p = (void *)node_tx_new->pdu_data;
  				if ((p->ll_id == PDU_DATA_LLID_DATA_START) &&
  				    !p->len) {
  					conn->start_empty = 1U;
  					pdu_node_tx_release(conn->handle,
  							    node_tx_new);
  					goto packet_tx_enqueue_release;
  				} else if (p->len && conn->start_empty) {
  					conn->start_empty = 0U;
  					if (p->ll_id ==
  					    PDU_DATA_LLID_DATA_CONTINUE) {
  						p->ll_id =
  							PDU_DATA_LLID_DATA_START;
  					}
  				}
  			}
  
  			if (conn->pkt_tx_data == 0) {
  				conn->pkt_tx_data = node_tx_new;
  
  				if (conn->pkt_tx_head == 0) {
  					conn->pkt_tx_head = node_tx_new;
  					conn->pkt_tx_last = NULL;
  				}
  			}
  
  			if (conn->pkt_tx_last) {
  				conn->pkt_tx_last->next = node_tx_new;
  			}
  
  			conn->pkt_tx_last = node_tx_new;
  		} else {
  			struct pdu_data *pdu_data_tx;
  
  			pdu_data_tx = (void *)node_tx_new->pdu_data;
  
  			/* By setting it resv, when app gets num cmplt, no
  			 * num cmplt is counted, but the buffer is released
  			 */
  			pdu_data_tx->ll_id = PDU_DATA_LLID_RESV;
  
  			pdu_node_tx_release(pdu_data_q_tx->handle, node_tx_new);
  		}
  
  packet_tx_enqueue_release:
  		first = _radio.packet_tx_first + 1;
  		if (first == _radio.packet_tx_count) {
  			first = 0U;
  		}
  		_radio.packet_tx_first = first;
  	}
  }
  
  static void pdu_node_tx_release(u16_t handle,
  				struct radio_pdu_node_tx *node_tx)
  {
  	u8_t last;
  
  	last = _radio.packet_release_last + 1;
  	if (last == _radio.packet_tx_count) {
  		last = 0U;
  	}
  
  	LL_ASSERT(last != _radio.packet_release_first);
  
  	/* Enqueue app mem for release */
  	_radio.pkt_release[_radio.packet_release_last].handle = handle;
  	_radio.pkt_release[_radio.packet_release_last].node_tx = node_tx;
  	_radio.packet_release_last = last;
  
  	/* callback to trigger application action */
  	packet_rx_callback();
  }
  
  #if defined(CONFIG_BT_CONN)
  static void tx_packet_set(struct connection *conn, struct pdu_data *pdu_data_tx)
  {
  	u16_t max_tx_octets;
  	u8_t phy, flags;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	max_tx_octets = conn->max_tx_octets;
  #else /* !CONFIG_BT_CTLR_DATA_LENGTH */
  	max_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
  #endif /* !CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	phy = conn->phy_tx;
  	flags = conn->phy_flags;
  #else /* !CONFIG_BT_CTLR_PHY */
  	phy = 0U;
  	flags = 0U;
  #endif /* !CONFIG_BT_CTLR_PHY */
  
  	radio_phy_set(phy, flags);
  
  	if (conn->enc_tx) {
  		radio_pkt_configure(8, (max_tx_octets + 4), (phy << 1) | 0x01);
  
  		radio_pkt_tx_set(radio_ccm_tx_pkt_set(&conn->ccm_tx,
  						      pdu_data_tx));
  	} else {
  		radio_pkt_configure(8, max_tx_octets, (phy << 1) | 0x01);
  
  		radio_pkt_tx_set(pdu_data_tx);
  	}
  }
  
  static struct pdu_data *empty_tx_enqueue(struct connection *conn)
  {
  	struct pdu_data *pdu_data_tx;
  
  	conn->empty = 1U;
  
  	pdu_data_tx = (void *)radio_pkt_empty_get();
  	pdu_data_tx->ll_id = PDU_DATA_LLID_DATA_CONTINUE;
  	pdu_data_tx->len = 0U;
  	if (conn->pkt_tx_head) {
  		pdu_data_tx->md = 1U;
  	} else {
  		pdu_data_tx->md = 0U;
  	}
  
  	return pdu_data_tx;
  }
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  static bool is_enc_req_pause_tx(struct connection *conn)
  {
  	struct pdu_data *pdu_data_tx;
  
  	pdu_data_tx = (void *)conn->pkt_tx_head->pdu_data;
  	if ((pdu_data_tx->ll_id == PDU_DATA_LLID_CTRL) &&
  	    ((pdu_data_tx->llctrl.opcode ==
  	      PDU_DATA_LLCTRL_TYPE_ENC_REQ) ||
  	     (pdu_data_tx->llctrl.opcode ==
  	      PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ))) {
  		if (((conn->llcp_req != conn->llcp_ack) &&
  		     (conn->llcp_type != LLCP_ENCRYPTION)) ||
  		    ((conn->llcp_req == conn->llcp_ack) &&
  		     ((conn->llcp_feature.ack != conn->llcp_feature.req) ||
  		      (conn->llcp_version.ack != conn->llcp_version.req) ||
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  		      (conn->llcp_conn_param.ack !=
  		       conn->llcp_conn_param.req) ||
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		      (conn->llcp_length.ack != conn->llcp_length.req) ||
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  #if defined(CONFIG_BT_CTLR_PHY)
  		      (conn->llcp_phy.ack != conn->llcp_phy.req) ||
  #endif /* CONFIG_BT_CTLR_PHY */
  		      0))) {
  			struct radio_pdu_node_tx *node_tx;
  
  			/* if we have control packets enqueued after this PDU
  			 * bring it ahead, and move the enc_req to last of
  			 * ctrl queue.
  			 */
  			node_tx = conn->pkt_tx_head;
  			if ((node_tx->next != NULL) &&
  			    (node_tx->next == conn->pkt_tx_ctrl)) {
  				conn->pkt_tx_head = node_tx->next;
  				node_tx->next = conn->pkt_tx_ctrl_last->next;
  				conn->pkt_tx_ctrl_last->next = node_tx;
  				conn->pkt_tx_data = node_tx;
  				if (!conn->pkt_tx_last) {
  					conn->pkt_tx_last = node_tx;
  				}
  
  				/* Head now contains a control packet permitted
  				 * to be transmitted to peer.
  				 */
  				return false;
  			}
  
  			/* Head contains ENC_REQ packet deferred due to another
  			 * control procedure in progress.
  			 */
  			return true;
  		}
  
  		if (conn->llcp_req == conn->llcp_ack) {
  			conn->llcp.encryption.state = LLCP_ENC_STATE_INIT;
  
  			conn->llcp_type = LLCP_ENCRYPTION;
  			conn->llcp_ack--;
  		} else {
  			LL_ASSERT(conn->llcp_type == LLCP_ENCRYPTION);
  		}
  	}
  
  	/* Head contains a permitted data or control packet. */
  	return false;
  }
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  static void prepare_pdu_data_tx(struct connection *conn,
  				struct pdu_data **pdu_data_tx)
  {
  	struct pdu_data *_pdu_data_tx;
  	bool pause_tx = false;
  
  	if (/* empty packet */
  	    conn->empty ||
  	    /* no ctrl or data packet */
  	    !conn->pkt_tx_head ||
  	    /* data tx paused, only control packets allowed */
  	    ((
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  	      conn->pause_tx ||
  	      /* Encryption setup queued */
  	      (pause_tx = is_enc_req_pause_tx(conn)) ||
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  	      0) &&
  	    /* Encryption setup queued or data paused */
  	    (pause_tx || (conn->pkt_tx_head != conn->pkt_tx_ctrl)))) {
  			_pdu_data_tx = empty_tx_enqueue(conn);
  	} else {
  		u16_t max_tx_octets;
  
  		_pdu_data_tx = (void *)(conn->pkt_tx_head->pdu_data +
  					conn->packet_tx_head_offset);
  
  		if (!conn->packet_tx_head_len) {
  			conn->packet_tx_head_len = _pdu_data_tx->len;
  		}
  
  		if (conn->packet_tx_head_offset) {
  			_pdu_data_tx->ll_id = PDU_DATA_LLID_DATA_CONTINUE;
  		}
  
  		_pdu_data_tx->len = conn->packet_tx_head_len -
  				    conn->packet_tx_head_offset;
  		_pdu_data_tx->md = 0U;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  #if defined(CONFIG_BT_CTLR_PHY)
  		switch (conn->phy_tx_time) {
  		default:
  		case BIT(0):
  			/* 1M PHY, 1us = 1 bit, hence divide by 8.
  			 * Deduct 10 bytes for preamble (1), access address (4),
  			 * header (2), and CRC (3).
  			 */
  			max_tx_octets = (conn->max_tx_time >> 3) - 10;
  			break;
  
  		case BIT(1):
  			/* 2M PHY, 1us = 2 bits, hence divide by 4.
  			 * Deduct 11 bytes for preamble (2), access address (4),
  			 * header (2), and CRC (3).
  			 */
  			max_tx_octets = (conn->max_tx_time >> 2) - 11;
  			break;
  
  #if defined(CONFIG_BT_CTLR_PHY_CODED)
  		case BIT(2):
  			if (conn->phy_flags & 0x01) {
  				/* S8 Coded PHY, 8us = 1 bit, hence divide by
  				 * 64.
  				 * Subtract time for preamble (80), AA (256),
  				 * CI (16), TERM1 (24), CRC (192) and
  				 * TERM2 (24), total 592 us.
  				 * Subtract 2 bytes for header.
  				 */
  				max_tx_octets = ((conn->max_tx_time - 592) >>
  						 6) - 2;
  			} else {
  				/* S2 Coded PHY, 2us = 1 bit, hence divide by
  				 * 16.
  				 * Subtract time for preamble (80), AA (256),
  				 * CI (16), TERM1 (24), CRC (48) and
  				 * TERM2 (6), total 430 us.
  				 * Subtract 2 bytes for header.
  				 */
  				max_tx_octets = ((conn->max_tx_time - 430) >>
  						 4) - 2;
  			}
  			break;
  #endif /* CONFIG_BT_CTLR_PHY_CODED */
  		}
  
  		if (conn->enc_tx) {
  			/* deduct the MIC */
  			max_tx_octets -= 4;
  		}
  
  		if (max_tx_octets > conn->max_tx_octets) {
  			max_tx_octets = conn->max_tx_octets;
  		}
  #else /* !CONFIG_BT_CTLR_PHY */
  		max_tx_octets = conn->max_tx_octets;
  #endif /* !CONFIG_BT_CTLR_PHY */
  #else /* !CONFIG_BT_CTLR_DATA_LENGTH */
  		max_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
  #endif /* !CONFIG_BT_CTLR_DATA_LENGTH */
  
  		if (_pdu_data_tx->len > max_tx_octets) {
  			_pdu_data_tx->len = max_tx_octets;
  			_pdu_data_tx->md = 1U;
  		}
  
  		if (conn->pkt_tx_head->next) {
  			_pdu_data_tx->md = 1U;
  		}
  
  		if (!conn->pkt_tx_ctrl &&
  		    (conn->pkt_tx_head != conn->pkt_tx_data)) {
  			struct pdu_data *pdu_data_tx;
  
  			pdu_data_tx = (void *)conn->pkt_tx_head->pdu_data;
  			if ((pdu_data_tx->ll_id != PDU_DATA_LLID_CTRL) ||
  			    ((pdu_data_tx->llctrl.opcode !=
  			      PDU_DATA_LLCTRL_TYPE_ENC_REQ) &&
  			     (pdu_data_tx->llctrl.opcode !=
  			      PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ))) {
  				conn->pkt_tx_ctrl = conn->pkt_tx_ctrl_last =
  					conn->pkt_tx_head;
  			}
  		}
  	}
  
  	_pdu_data_tx->rfu = 0U;
  
  #if !defined(CONFIG_BT_CTLR_DATA_LENGTH_CLEAR)
  	_pdu_data_tx->resv = 0U;
  #endif /* !CONFIG_BT_CTLR_DATA_LENGTH_CLEAR */
  
  	*pdu_data_tx = _pdu_data_tx;
  }
  
  static void ctrl_tx_last_enqueue(struct connection *conn,
  				 struct radio_pdu_node_tx *node_tx)
  {
  	node_tx->next = conn->pkt_tx_ctrl_last->next;
  	conn->pkt_tx_ctrl_last->next = node_tx;
  	conn->pkt_tx_ctrl_last = node_tx;
  }
  
  static inline void ctrl_tx_pause_enqueue(struct connection *conn,
  					 struct radio_pdu_node_tx *node_tx,
  					 bool pause)
  {
  	/* check if a packet was tx-ed and not acked by peer */
  	if (
  	    /* An explicit empty PDU is not enqueued */
  	    !conn->empty &&
  	    /* and data/ctrl packet is in the head */
  	    conn->pkt_tx_head &&
  	    /* data PDU tx is not paused */
  	    !conn->pause_tx) {
  		/* data or ctrl may have been transmitted once, but not acked
  		 * by peer, hence place this new ctrl after head
  		 */
  
  		/* if data transmitted once, keep it at head of the tx list,
  		 * as we will insert a ctrl after it, hence advance the
  		 * data pointer
  		 */
  		if (conn->pkt_tx_head == conn->pkt_tx_data) {
  			conn->pkt_tx_data = conn->pkt_tx_data->next;
  		}
  
  		/* if no ctrl packet already queued, new ctrl added will be
  		 * the ctrl pointer and is inserted after head.
  		 */
  		if (!conn->pkt_tx_ctrl) {
  			node_tx->next = conn->pkt_tx_head->next;
  			conn->pkt_tx_head->next = node_tx;
  
  			/* If in Encryption Procedure, other control PDUs,
  			 * Feature Rsp and Version Ind, are placed before data
  			 * marker and after control last marker. Hence, if no
  			 * control marker i.e. this is the first control PDU and
  			 * to be paused, do not set the control marker. A valid
  			 * control PDU in Encryption Procedure that is not
  			 * implicitly paused, will set the control and control
  			 * last marker.
  			 */
  			if (!pause) {
  				conn->pkt_tx_ctrl = node_tx;
  				conn->pkt_tx_ctrl_last = node_tx;
  			}
  		} else {
  			/* ENC_REQ PDU is always allocated from data pool, hence
  			 * the head can not have the control marker, and pause
  			 * be true.
  			 */
  			LL_ASSERT(!pause);
  
  			ctrl_tx_last_enqueue(conn, node_tx);
  		}
  	} else {
  		/* No packet needing ACK. */
  
  		/* If first ctrl packet then add it as head else add it to the
  		 * tail of the ctrl packets.
  		 */
  		if (!conn->pkt_tx_ctrl) {
  			node_tx->next = conn->pkt_tx_head;
  			conn->pkt_tx_head = node_tx;
  			if (!pause) {
  				conn->pkt_tx_ctrl = node_tx;
  				conn->pkt_tx_ctrl_last = node_tx;
  			}
  		} else {
  			LL_ASSERT(!pause);
  
  			ctrl_tx_last_enqueue(conn, node_tx);
  		}
  	}
  
  	/* Update last pointer if ctrl added at end of tx list */
  	if (node_tx->next == 0) {
  		conn->pkt_tx_last = node_tx;
  	}
  }
  
  static void ctrl_tx_enqueue(struct connection *conn,
  			    struct radio_pdu_node_tx *node_tx)
  {
  	ctrl_tx_pause_enqueue(conn, node_tx, false);
  }
  
  static void ctrl_tx_sec_enqueue(struct connection *conn,
  				  struct radio_pdu_node_tx *node_tx)
  {
  	bool pause = false;
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  	if (conn->pause_tx) {
  		if (!conn->pkt_tx_ctrl) {
  			/* As data PDU tx is paused and no control PDU in queue,
  			 * its safe to add new control PDU at head.
  			 * Note, here the PDUs are stacked, not queued. Last In
  			 * First Out.
  			 */
  			node_tx->next = conn->pkt_tx_head;
  			conn->pkt_tx_head = node_tx;
  		} else {
  			/* As data PDU tx is paused and there are control PDUs
  			 * in the queue, add it after control PDUs last marker
  			 * and before the data start marker.
  			 * Note, here the PDUs are stacked, not queued. Last In
  			 * First Out.
  			 */
  			node_tx->next = conn->pkt_tx_ctrl_last->next;
  			conn->pkt_tx_ctrl_last->next = node_tx;
  		}
  
  		/* Update last pointer if ctrl added at end of tx list */
  		if (!node_tx->next) {
  			conn->pkt_tx_last = node_tx;
  		}
  	} else {
  		/* check if Encryption Request is at head, it may have been
  		 * transmitted and not ack-ed. Hence, enqueue this control PDU
  		 * after control last marker and before data marker.
  		 * This way it is paused until Encryption Setup completes.
  		 */
  		if (conn->pkt_tx_head) {
  			struct pdu_data *pdu_data_tx;
  
  			pdu_data_tx = (void *)conn->pkt_tx_head->pdu_data;
  			if ((conn->llcp_req != conn->llcp_ack) &&
  			    (conn->llcp_type == LLCP_ENCRYPTION) &&
  			    (pdu_data_tx->ll_id == PDU_DATA_LLID_CTRL) &&
  			    ((pdu_data_tx->llctrl.opcode ==
  			      PDU_DATA_LLCTRL_TYPE_ENC_REQ) ||
  			     (pdu_data_tx->llctrl.opcode ==
  			      PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ))) {
  				pause = true;
  			}
  		}
  
  #else /* !CONFIG_BT_CTLR_LE_ENC */
  	{
  #endif /* !CONFIG_BT_CTLR_LE_ENC */
  
  		ctrl_tx_pause_enqueue(conn, node_tx, pause);
  	}
  }
  
  static void connection_release(struct connection *conn)
  {
  	u32_t ticker_status;
  
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  	/* Enable Ticker Job, we are in a radio event which disabled it if
  	 * worker0 and job0 priority where same.
  	 */
  	mayfly_enable(RADIO_TICKER_USER_ID_WORKER, RADIO_TICKER_USER_ID_JOB, 1);
  #endif
  
  	/** @todo correctly stop tickers ensuring crystal and radio active are
  	 * placed in right states
  	 */
  
  	/* Stop Master/Slave role ticker */
  	ticker_status =
  		ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  			    RADIO_TICKER_USER_ID_WORKER,
  			    (RADIO_TICKER_ID_FIRST_CONNECTION + conn->handle),
  			    ticker_success_assert, (void *)__LINE__);
  	LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  		  (ticker_status == TICKER_STATUS_BUSY));
  
  	/* Stop Marker 0 and event single-shot tickers */
  	if ((_radio.state == STATE_ABORT) &&
  	    (_radio.ticker_id_prepare == (RADIO_TICKER_ID_FIRST_CONNECTION +
  					  conn->handle))) {
  		/* Reset the stored ticker id in prepare phase that
  		 * initiated the connection event abort (pre-emption).
  		 */
  		_radio.ticker_id_prepare = 0U;
  
  		ticker_status =
  			ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  				    RADIO_TICKER_USER_ID_WORKER,
  				    RADIO_TICKER_ID_MARKER_0,
  				    ticker_success_assert, (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  		ticker_status =
  		    ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  				RADIO_TICKER_USER_ID_WORKER,
  				RADIO_TICKER_ID_EVENT,
  				ticker_success_assert, (void *)__LINE__);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	}
  
  	/* flush and release, data packet before ctrl */
  	while ((conn->pkt_tx_head != conn->pkt_tx_ctrl) &&
  	       (conn->pkt_tx_head != conn->pkt_tx_data)) {
  		struct radio_pdu_node_tx *node_tx;
  		struct pdu_data *pdu_data_tx;
  
  		/* By setting it resv, when app gets num cmplt, no num cmplt
  		 * is counted, but the buffer is released
  		 */
  		node_tx = conn->pkt_tx_head;
  		pdu_data_tx = (void *)node_tx->pdu_data;
  		pdu_data_tx->ll_id = PDU_DATA_LLID_RESV;
  
  		conn->pkt_tx_head = conn->pkt_tx_head->next;
  
  		pdu_node_tx_release(conn->handle, node_tx);
  	}
  
  	/* flush and release, ctrl packet before data */
  	while ((conn->pkt_tx_head) &&
  	       (conn->pkt_tx_head != conn->pkt_tx_data)) {
  		void *release;
  
  		release = conn->pkt_tx_head;
  		conn->pkt_tx_head = conn->pkt_tx_head->next;
  		conn->pkt_tx_ctrl = conn->pkt_tx_head;
  
  		mem_release(release, &_radio.pkt_tx_ctrl_free);
  	}
  	conn->pkt_tx_ctrl = NULL;
  	conn->pkt_tx_ctrl_last = NULL;
  
  	/* flush and release, rest of data */
  	while (conn->pkt_tx_head) {
  		struct radio_pdu_node_tx *node_tx;
  		struct pdu_data *pdu_data_tx;
  
  		/* By setting it resv, when app gets num cmplt, no num cmplt
  		 * is counted, but the buffer is released
  		 */
  		node_tx = conn->pkt_tx_head;
  		pdu_data_tx = (void *)node_tx->pdu_data;
  		pdu_data_tx->ll_id = PDU_DATA_LLID_RESV;
  
  		conn->pkt_tx_head = conn->pkt_tx_head->next;
  		conn->pkt_tx_data = conn->pkt_tx_head;
  
  		pdu_node_tx_release(conn->handle, node_tx);
  	}
  
  	conn->handle = 0xffff;
  
  	/* reset mutex */
  	if (_radio.conn_upd == conn) {
  		_radio.conn_upd = NULL;
  	}
  }
  
  static void terminate_ind_rx_enqueue(struct connection *conn, u8_t reason)
  {
  	struct radio_pdu_node_rx *node_rx;
  
  	/* forward held rx nodes */
  	if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  		packet_rx_enqueue_forward();
  	}
  
  	/* Prepare the rx packet structure */
  	node_rx = (void *)&conn->llcp_terminate.radio_pdu_node_rx;
  	LL_ASSERT(node_rx->hdr.link);
  
  	node_rx->hdr.handle = conn->handle;
  	node_rx->hdr.type = NODE_RX_TYPE_TERMINATE;
  	*((u8_t *)node_rx->pdu_data) = reason;
  
  	/* Link the rx node with tx ack queue and enqueue towards host */
  	packet_rx_enqueue_commit(node_rx);
  
  	/* callback to trigger application action */
  	packet_rx_callback();
  }
  
  static u8_t conn_update(struct connection *conn, struct pdu_data *pdu_data_rx)
  {
  	if (((pdu_data_rx->llctrl.conn_update_ind.instant -
  	      conn->event_counter) & 0xFFFF) > 0x7FFF) {
  		return BT_HCI_ERR_INSTANT_PASSED;
  	}
  
  	/* different transaction collision */
  	if (conn->llcp_req != conn->llcp_ack) {
  		return BT_HCI_ERR_DIFF_TRANS_COLLISION;
  	}
  
  	/* set mutex, if only not already set. As a master the mutex shall
  	 * be set, but a slave we accept it as new 'set' of mutex.
  	 */
  	if (_radio.conn_upd == 0) {
  		LL_ASSERT(conn->role);
  
  		_radio.conn_upd = conn;
  	}
  
  	conn->llcp_cu.win_size = pdu_data_rx->llctrl.conn_update_ind.win_size;
  	conn->llcp_cu.win_offset_us =
  		pdu_data_rx->llctrl.conn_update_ind.win_offset * 1250;
  	conn->llcp_cu.interval = pdu_data_rx->llctrl.conn_update_ind.interval;
  	conn->llcp_cu.latency = pdu_data_rx->llctrl.conn_update_ind.latency;
  	conn->llcp_cu.timeout = pdu_data_rx->llctrl.conn_update_ind.timeout;
  	conn->llcp.conn_upd.instant =
  		pdu_data_rx->llctrl.conn_update_ind.instant;
  	conn->llcp_cu.state = LLCP_CUI_STATE_INPROG;
  	conn->llcp_cu.cmd = 1U;
  	conn->llcp_cu.ack--;
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  	if ((conn->llcp_conn_param.req != conn->llcp_conn_param.ack) &&
  	    (conn->llcp_conn_param.state == LLCP_CPR_STATE_RSP_WAIT)) {
  		conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
  	}
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  	return 0;
  }
  
  #if defined (CONFIG_BT_CTLR_XTAL_ADVANCED) && \
      defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  static u32_t conn_update_req(struct connection *conn)
  {
  	if (conn->llcp_cu.req != conn->llcp_cu.ack) {
  		return 1;
  	}
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  	if (conn->llcp_conn_param.req != conn->llcp_conn_param.ack) {
  		return 1;
  	}
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  	if (!conn->role) {
  		conn->llcp_cu.win_size = 1U;
  		conn->llcp_cu.win_offset_us = 0U;
  		conn->llcp_cu.interval = conn->conn_interval;
  		conn->llcp_cu.latency = conn->latency;
  		conn->llcp_cu.timeout = conn->conn_interval *
  					conn->supervision_reload * 125 / 1000;
  		conn->llcp_cu.state = LLCP_CUI_STATE_USE;
  		conn->llcp_cu.cmd = 0U;
  		conn->llcp_cu.ack--;
  
  		return 0;
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  	} else if (!conn->llcp_conn_param.disabled &&
  		   (!conn->common.fex_valid ||
  		    (conn->llcp_feature.features &
  		     BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ)))) {
  		/** Perform slave intiated conn param req */
  		conn->llcp_conn_param.status = 0U;
  		conn->llcp_conn_param.interval_min = conn->conn_interval;
  		conn->llcp_conn_param.interval_max = conn->conn_interval;
  		conn->llcp_conn_param.latency = conn->latency;
  		conn->llcp_conn_param.timeout = conn->conn_interval *
  						conn->supervision_reload *
  						125 / 1000;
  		conn->llcp_conn_param.state = LLCP_CPR_STATE_REQ;
  		conn->llcp_conn_param.cmd = 0U;
  		conn->llcp_conn_param.ack--;
  
  		return 0;
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  	}
  
  	return 2;
  }
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED && CONFIG_BT_CTLR_SCHED_ADVANCED */
  
  static u8_t chan_map_update(struct connection *conn,
  			    struct pdu_data *pdu_data_rx)
  {
  	if (((pdu_data_rx->llctrl.chan_map_ind.instant -
  	      conn->event_counter) & 0xffff) > 0x7fff) {
  		return BT_HCI_ERR_INSTANT_PASSED;
  	}
  
  	/* different transaction collision */
  	if (conn->llcp_req != conn->llcp_ack) {
  		return BT_HCI_ERR_DIFF_TRANS_COLLISION;
  	}
  
  
  	memcpy(&conn->llcp.chan_map.chm[0],
  	       &pdu_data_rx->llctrl.chan_map_ind.chm[0],
  	       sizeof(conn->llcp.chan_map.chm));
  	conn->llcp.chan_map.instant =
  		pdu_data_rx->llctrl.chan_map_ind.instant;
  	conn->llcp.chan_map.initiate = 0U;
  
  	conn->llcp_type = LLCP_CHAN_MAP;
  	conn->llcp_ack--;
  
  	return 0;
  }
  
  #if defined(CONFIG_BT_CTLR_PHY)
  static inline u8_t phy_upd_ind_recv(struct radio_pdu_node_rx *node_rx,
  				    u8_t *rx_enqueue)
  {
  	struct connection *conn = _radio.conn_curr;
  	struct pdu_data_llctrl_phy_upd_ind *ind;
  	struct pdu_data *pdu_data_rx;
  
  	pdu_data_rx = (void *)node_rx->pdu_data;
  	ind = &pdu_data_rx->llctrl.phy_upd_ind;
  
  	/* Both tx and rx PHY unchanged */
  	if (!((ind->m_to_s_phy | ind->s_to_m_phy) & 0x07)) {
  		struct radio_le_phy_upd_cmplt *upd;
  
  		/* Not in PHY Update Procedure or PDU in wrong state */
  		if ((conn->llcp_phy.ack == conn->llcp_phy.req) ||
  		    (conn->llcp_phy.state != LLCP_PHY_STATE_RSP_WAIT)) {
  			return 0;
  		}
  
  		/* Procedure complete */
  		conn->llcp_phy.ack = conn->llcp_phy.req;
  		conn->procedure_expire = 0U;
  
  		/* Reset packet timing restrictions */
  		conn->phy_tx_time = conn->phy_tx;
  
  		/* Ignore event generation if not local cmd initiated */
  		if (!conn->llcp_phy.cmd) {
  			return 0;
  		}
  
  		/* generate phy update complete event */
  		node_rx->hdr.type = NODE_RX_TYPE_PHY_UPDATE;
  
  		upd = (void *)pdu_data_rx;
  		upd->status = 0U;
  		upd->tx = conn->phy_tx;
  		upd->rx = conn->phy_rx;
  
  		/* enqueue the phy update complete */
  		*rx_enqueue = 1U;
  
  		return 0;
  	}
  
  	/* instant passed */
  	if (((ind->instant - conn->event_counter) & 0xffff) > 0x7fff) {
  		return BT_HCI_ERR_INSTANT_PASSED;
  	}
  
  	/* different transaction collision */
  	if (conn->llcp_req != conn->llcp_ack) {
  		return BT_HCI_ERR_DIFF_TRANS_COLLISION;
  	}
  
  	if ((conn->llcp_phy.ack != conn->llcp_phy.req) &&
  	    (conn->llcp_phy.state == LLCP_PHY_STATE_RSP_WAIT)) {
  		conn->llcp_phy.ack = conn->llcp_phy.req;
  		conn->llcp.phy_upd_ind.cmd = conn->llcp_phy.cmd;
  
  		/* Procedure complete, just wait for instant */
  		conn->procedure_expire = 0U;
  	}
  
  	conn->llcp.phy_upd_ind.tx = ind->s_to_m_phy;
  	conn->llcp.phy_upd_ind.rx = ind->m_to_s_phy;
  	conn->llcp.phy_upd_ind.instant = ind->instant;
  	conn->llcp.phy_upd_ind.initiate = 0U;
  
  	conn->llcp_type = LLCP_PHY_UPD;
  	conn->llcp_ack--;
  
  	if (conn->llcp.phy_upd_ind.tx) {
  		conn->phy_tx_time = conn->llcp.phy_upd_ind.tx;
  	}
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_PHY */
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  static void enc_req_reused_send(struct connection *conn,
  				struct radio_pdu_node_tx *node_tx)
  {
  	struct pdu_data *pdu_ctrl_tx;
  
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, enc_req) +
  			   sizeof(struct pdu_data_llctrl_enc_req);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ;
  	memcpy(&pdu_ctrl_tx->llctrl.enc_req.rand[0],
  	       &conn->llcp_enc.rand[0],
  	       sizeof(pdu_ctrl_tx->llctrl.enc_req.rand));
  	pdu_ctrl_tx->llctrl.enc_req.ediv[0] =
  		conn->llcp_enc.ediv[0];
  	pdu_ctrl_tx->llctrl.enc_req.ediv[1] =
  		conn->llcp_enc.ediv[1];
  
  	/*
  	 * Take advantage of the fact that ivm and skdm fields, which both have
  	 * to be filled with random data, are adjacent and use single call to
  	 * the entropy driver.
  	 */
  	BUILD_ASSERT(offsetof(__typeof(pdu_ctrl_tx->llctrl.enc_req), ivm) ==
  		     (offsetof(__typeof(pdu_ctrl_tx->llctrl.enc_req), skdm) +
  		     sizeof(pdu_ctrl_tx->llctrl.enc_req.skdm)));
  
  	/* NOTE: if not sufficient random numbers, ignore waiting */
  	entropy_get_entropy_isr(_radio.entropy,
  				pdu_ctrl_tx->llctrl.enc_req.skdm,
  				sizeof(pdu_ctrl_tx->llctrl.enc_req.skdm) +
  				sizeof(pdu_ctrl_tx->llctrl.enc_req.ivm), 0);
  }
  
  #if defined(CONFIG_BT_PERIPHERAL)
  static u8_t enc_rsp_send(struct connection *conn)
  {
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	/* acquire tx mem */
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return 1;
  	}
  
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, enc_rsp) +
  			   sizeof(struct pdu_data_llctrl_enc_rsp);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_ENC_RSP;
  
  	/*
  	 * Take advantage of the fact that ivs and skds fields, which both have
  	 * to be filled with random data, are adjacent and use single call to
  	 * the entropy driver.
  	 */
  	BUILD_ASSERT(offsetof(__typeof(pdu_ctrl_tx->llctrl.enc_rsp), ivs) ==
  		     (offsetof(__typeof(pdu_ctrl_tx->llctrl.enc_rsp), skds) +
  		     sizeof(pdu_ctrl_tx->llctrl.enc_rsp.skds)));
  
  	/* NOTE: if not sufficient random numbers, ignore waiting */
  	entropy_get_entropy_isr(_radio.entropy,
  				pdu_ctrl_tx->llctrl.enc_rsp.skds,
  				sizeof(pdu_ctrl_tx->llctrl.enc_rsp.skds) +
  				sizeof(pdu_ctrl_tx->llctrl.enc_rsp.ivs), 0);
  
  	/* things from slave stored for session key calculation */
  	memcpy(&conn->llcp.encryption.skd[8],
  	       &pdu_ctrl_tx->llctrl.enc_rsp.skds[0], 8);
  	memcpy(&conn->ccm_rx.iv[4],
  	       &pdu_ctrl_tx->llctrl.enc_rsp.ivs[0], 4);
  
  	ctrl_tx_enqueue(conn, node_tx);
  
  	return 0;
  }
  #endif /* CONFIG_BT_PERIPHERAL */
  
  static u8_t start_enc_rsp_send(struct connection *conn,
  			       struct pdu_data *pdu_ctrl_tx)
  {
  	struct radio_pdu_node_tx *node_tx = NULL;
  
  	if (!pdu_ctrl_tx) {
  		/* acquire tx mem */
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			return 1;
  		}
  
  		pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	}
  
  	/* enable transmit encryption */
  	conn->enc_tx = 1U;
  
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, enc_rsp);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_START_ENC_RSP;
  
  	if (node_tx) {
  		ctrl_tx_enqueue(conn, node_tx);
  	}
  
  	return 0;
  }
  
  static u8_t pause_enc_rsp_send(struct connection *conn, u8_t req)
  {
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	if (req) {
  		/* acquire tx mem */
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			return 1;
  		}
  
  		/* key refresh */
  		conn->refresh = 1U;
  	} else if (!conn->role) {
  		/* acquire tx mem */
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			return 1;
  		}
  
  		/* disable transmit encryption */
  		conn->enc_tx = 0U;
  	} else {
  		/* disable transmit encryption */
  		conn->enc_tx = 0U;
  
  		return 0;
  	}
  
  	/* pause data packet rx */
  	conn->pause_rx = 1U;
  
  	/* disable receive encryption */
  	conn->enc_rx = 0U;
  
  	/* Enqueue pause enc rsp */
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, enc_rsp);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP;
  
  	ctrl_tx_enqueue(conn, node_tx);
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  static u8_t unknown_rsp_send(struct connection *conn, u8_t type)
  {
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	/* acquire tx mem */
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return 1;
  	}
  
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, unknown_rsp) +
  			   sizeof(struct pdu_data_llctrl_unknown_rsp);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP;
  	pdu_ctrl_tx->llctrl.unknown_rsp.type = type;
  
  	ctrl_tx_enqueue(conn, node_tx);
  
  	return 0;
  }
  
  static u8_t feature_rsp_send(struct connection *conn,
  			     struct pdu_data *pdu_data_rx)
  {
  	struct pdu_data_llctrl_feature_req *req;
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	/* acquire tx mem */
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return 1;
  	}
  
  	/* AND the feature set to get Feature USED */
  	req = &pdu_data_rx->llctrl.feature_req;
  	conn->llcp_feature.features &= feat_get(&req->features[0]);
  
  	/* features exchanged */
  	conn->common.fex_valid = 1U;
  
  	/* Enqueue feature response */
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, feature_rsp) +
  		sizeof(struct pdu_data_llctrl_feature_rsp);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_FEATURE_RSP;
  	(void)memset(&pdu_ctrl_tx->llctrl.feature_rsp.features[0], 0x00,
  		     sizeof(pdu_ctrl_tx->llctrl.feature_rsp.features));
  	sys_put_le24(conn->llcp_feature.features,
  		     pdu_ctrl_tx->llctrl.feature_req.features);
  
  	ctrl_tx_sec_enqueue(conn, node_tx);
  
  	return 0;
  }
  
  static u8_t version_ind_send(struct connection *conn,
  			     struct pdu_data *pdu_data_rx, u8_t *rx_enqueue)
  {
  	struct pdu_data_llctrl_version_ind *v;
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	if (!conn->llcp_version.tx) {
  		/* acquire tx mem */
  		node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  		if (!node_tx) {
  			return 1;
  		}
  		conn->llcp_version.tx = 1U;
  
  		pdu_ctrl_tx = (void *)node_tx->pdu_data;
  		pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  		pdu_ctrl_tx->len =
  			offsetof(struct pdu_data_llctrl, version_ind) +
  			sizeof(struct pdu_data_llctrl_version_ind);
  		pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_VERSION_IND;
  		v = &pdu_ctrl_tx->llctrl.version_ind;
  		v->version_number = LL_VERSION_NUMBER;
  		v->company_id =	CONFIG_BT_CTLR_COMPANY_ID;
  		v->sub_version_number =	CONFIG_BT_CTLR_SUBVERSION_NUMBER;
  
  		ctrl_tx_sec_enqueue(conn, node_tx);
  
  		/* Apple work-around, add empty packet before version_ind */
  		empty_tx_enqueue(conn);
  
  	} else if (!conn->llcp_version.rx) {
  		LL_ASSERT(conn->llcp_version.ack != conn->llcp_version.req);
  
  		/* Procedure complete */
  		conn->llcp_version.ack = conn->llcp_version.req;
  		conn->procedure_expire = 0U;
  
  		/* enqueue the version ind */
  		*rx_enqueue = 1U;
  	} else {
  		/* Tx-ed and Rx-ed before, ignore this invalid Rx. */
  		return 0;
  	}
  
  	v = &pdu_data_rx->llctrl.version_ind;
  	conn->llcp_version.version_number = v->version_number;
  	conn->llcp_version.company_id = v->company_id;
  	conn->llcp_version.sub_version_number = v->sub_version_number;
  	conn->llcp_version.rx = 1U;
  
  	return 0;
  }
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  static u8_t ping_resp_send(struct connection *conn)
  {
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	/* acquire tx mem */
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return 1;
  	}
  
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, ping_rsp) +
  			   sizeof(struct pdu_data_llctrl_ping_rsp);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_PING_RSP;
  
  	ctrl_tx_sec_enqueue(conn, node_tx);
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) || defined(CONFIG_BT_CTLR_PHY)
  static u8_t reject_ext_ind_send(struct connection *conn,
  				u8_t reject_opcode, u8_t error_code)
  {
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  
  	/* acquire tx mem */
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return 1;
  	}
  
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, reject_ext_ind) +
  		sizeof(struct pdu_data_llctrl_reject_ext_ind);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND;
  	pdu_ctrl_tx->llctrl.reject_ext_ind.reject_opcode = reject_opcode;
  	pdu_ctrl_tx->llctrl.reject_ext_ind.error_code = error_code;
  
  	ctrl_tx_enqueue(conn, node_tx);
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ  || PHY */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  #if !defined(CONFIG_BT_CTLR_PHY)
  static void length_resp_send(struct connection *conn,
  			     struct radio_pdu_node_tx *node_tx,
  			     u16_t eff_rx_octets, u16_t eff_tx_octets)
  #else /* CONFIG_BT_CTLR_PHY */
  static void length_resp_send(struct connection *conn,
  			     struct radio_pdu_node_tx *node_tx,
  			     u16_t eff_rx_octets, u16_t eff_rx_time,
  			     u16_t eff_tx_octets, u16_t eff_tx_time)
  #endif /* CONFIG_BT_CTLR_PHY */
  {
  	struct pdu_data *pdu_ctrl_tx;
  
  	pdu_ctrl_tx = (void *) node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, length_rsp) +
  		sizeof(struct pdu_data_llctrl_length_rsp);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP;
  	pdu_ctrl_tx->llctrl.length_rsp.max_rx_octets = eff_rx_octets;
  	pdu_ctrl_tx->llctrl.length_rsp.max_tx_octets = eff_tx_octets;
  
  #if !defined(CONFIG_BT_CTLR_PHY)
  	pdu_ctrl_tx->llctrl.length_rsp.max_rx_time =
  		RADIO_PKT_TIME(eff_rx_octets, 0);
  	pdu_ctrl_tx->llctrl.length_rsp.max_tx_time =
  		RADIO_PKT_TIME(eff_tx_octets, 0);
  #else /* CONFIG_BT_CTLR_PHY */
  	pdu_ctrl_tx->llctrl.length_rsp.max_rx_time = eff_rx_time;
  	pdu_ctrl_tx->llctrl.length_rsp.max_tx_time = eff_tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  	ctrl_tx_sec_enqueue(conn, node_tx);
  }
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  static u8_t phy_rsp_send(struct connection *conn, struct pdu_data *pdu_data_rx)
  {
  	struct pdu_data_llctrl_phy_req *p;
  	struct radio_pdu_node_tx *node_tx;
  	struct pdu_data *pdu_ctrl_tx;
  	struct pdu_data_llctrl *c;
  
  	/* acquire tx mem */
  	node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free);
  	if (!node_tx) {
  		return 1;
  	}
  
  	/* Wait for peer master to complete the procedure */
  	conn->llcp_phy.state = LLCP_PHY_STATE_RSP_WAIT;
  	if (conn->llcp_phy.ack ==
  	    conn->llcp_phy.req) {
  		conn->llcp_phy.ack--;
  
  		conn->llcp_phy.cmd = 0U;
  
  		conn->llcp_phy.tx =
  			conn->phy_pref_tx;
  		conn->llcp_phy.rx =
  			conn->phy_pref_rx;
  
  		/* Start Procedure Timeout (TODO: this shall not
  		 * replace terminate procedure).
  		 */
  		conn->procedure_expire =
  			conn->procedure_reload;
  	}
  
  	c = &pdu_data_rx->llctrl;
  	p = &c->phy_req;
  
  	conn->llcp_phy.tx &= p->rx_phys;
  	conn->llcp_phy.rx &= p->tx_phys;
  
  	pdu_ctrl_tx = (void *)node_tx->pdu_data;
  	pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
  	pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, phy_rsp) +
  			   sizeof(struct pdu_data_llctrl_phy_rsp);
  	pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_PHY_RSP;
  	pdu_ctrl_tx->llctrl.phy_rsp.tx_phys = conn->phy_pref_tx;
  	pdu_ctrl_tx->llctrl.phy_rsp.rx_phys = conn->phy_pref_rx;
  
  	ctrl_tx_enqueue(conn, node_tx);
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CONN */
  
  void ll_radio_state_abort(void)
  {
  	event_stop(0, 0, 0, (void *)STATE_ABORT);
  }
  
  u32_t ll_radio_state_is_idle(void)
  {
  	return radio_is_idle();
  }
  
  void radio_ticks_active_to_start_set(u32_t ticks_active_to_start)
  {
  	_radio.ticks_active_to_start = ticks_active_to_start;
  }
  
  struct radio_adv_data *radio_adv_data_get(void)
  {
  	return &_radio.advertiser.adv_data;
  }
  
  struct radio_adv_data *radio_scan_data_get(void)
  {
  	return &_radio.advertiser.scan_data;
  }
  
  static struct connection *connection_get(u16_t handle)
  {
  	struct connection *conn;
  
  	if (handle < _radio.connection_count) {
  		conn = mem_get(_radio.conn_pool, CONNECTION_T_SIZE, handle);
  		if ((conn) && (conn->handle == handle)) {
  			return conn;
  		}
  	}
  
  	return 0;
  }
  
  static inline void role_active_disable(u8_t ticker_id_stop,
  				       u32_t ticks_xtal_to_start,
  				       u32_t ticks_active_to_start)
  {
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  	static memq_link_t link_calc;
  	static struct mayfly s_mfy_xtal_calc = {0, 0, &link_calc, NULL,
  						mayfly_xtal_stop_calc};
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  	static memq_link_t link_inact;
  	static struct mayfly s_mfy_radio_inactive = {0, 0, &link_inact, NULL,
  						     mayfly_radio_inactive};
  	u32_t volatile ret_cb_evt = TICKER_STATUS_BUSY;
  	u32_t ret;
  
  	/* Step 2: Is caller before Event? Stop Event */
  	ret = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  			  RADIO_TICKER_USER_ID_APP, RADIO_TICKER_ID_EVENT,
  			  ticker_if_done, (void *)&ret_cb_evt);
  
  	if (ret == TICKER_STATUS_BUSY) {
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		mayfly_enable(RADIO_TICKER_USER_ID_APP,
  			      RADIO_TICKER_USER_ID_JOB, 1);
  #endif
  
  		LL_ASSERT(ret_cb_evt != TICKER_STATUS_BUSY);
  	}
  
  	if (ret_cb_evt == TICKER_STATUS_SUCCESS) {
  		static memq_link_t link_xtal;
  		static struct mayfly s_mfy_xtal_stop = {0, 0, &link_xtal, NULL,
  							mayfly_xtal_stop};
  		u32_t volatile ret_cb_m0 = TICKER_STATUS_BUSY;
  
  		/* Reset the stored ticker id in prepare phase. */
  		LL_ASSERT(_radio.ticker_id_prepare);
  		_radio.ticker_id_prepare = 0U;
  
  		/* Step 2.1: Is caller between Primary and Marker0?
  		 * Stop the Marker0 event
  		 */
  		ret = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  				  RADIO_TICKER_USER_ID_APP,
  				  RADIO_TICKER_ID_MARKER_0,
  				  ticker_if_done, (void *)&ret_cb_m0);
  
  		if (ret == TICKER_STATUS_BUSY) {
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  			mayfly_enable(RADIO_TICKER_USER_ID_APP,
  				      RADIO_TICKER_USER_ID_JOB, 1);
  #endif
  
  			LL_ASSERT(ret_cb_m0 != TICKER_STATUS_BUSY);
  		}
  
  		if (ret_cb_m0 == TICKER_STATUS_SUCCESS) {
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  			/* If in reduced prepare, use the absolute value */
  			ticks_xtal_to_start &= ~XON_BITMASK;
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  			/* Step 2.1.1: Check and deassert Radio Active or XTAL
  			 * start
  			 */
  			if (ticks_active_to_start > ticks_xtal_to_start) {
  				/* radio active asserted, handle deasserting
  				 * here
  				 */
  				ret = mayfly_enqueue(
  						RADIO_TICKER_USER_ID_APP,
  						RADIO_TICKER_USER_ID_WORKER, 0,
  						&s_mfy_radio_inactive);
  				LL_ASSERT(!ret);
  			} else {
  				/* XTAL started, handle XTAL stop here */
  				ret = mayfly_enqueue(
  						RADIO_TICKER_USER_ID_APP,
  						RADIO_TICKER_USER_ID_WORKER, 0,
  						&s_mfy_xtal_stop);
  				LL_ASSERT(!ret);
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  				/* calc whether xtal needs to be retained after
  				 * this event
  				 */
  				s_mfy_xtal_calc.param =
  					(void *)(u32_t)_radio.ticker_id_stop;
  				ret = mayfly_enqueue(
  						RADIO_TICKER_USER_ID_APP,
  						RADIO_TICKER_USER_ID_JOB, 0,
  						&s_mfy_xtal_calc);
  				LL_ASSERT(!ret);
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  			}
  		} else if (ret_cb_m0 == TICKER_STATUS_FAILURE) {
  			/* Step 2.1.2: Deassert Radio Active and XTAL start */
  
  			/* radio active asserted, handle deasserting here */
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_APP,
  					     RADIO_TICKER_USER_ID_WORKER, 0,
  					     &s_mfy_radio_inactive);
  			LL_ASSERT(!ret);
  
  			/* XTAL started, handle XTAL stop here */
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_APP,
  					     RADIO_TICKER_USER_ID_WORKER, 0,
  					     &s_mfy_xtal_stop);
  			LL_ASSERT(!ret);
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  			/* calc whether xtal needs to be retained after this
  			 * event
  			 */
  			s_mfy_xtal_calc.param =
  				(void *)(u32_t)_radio.ticker_id_stop;
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_APP,
  					     RADIO_TICKER_USER_ID_JOB, 0,
  					     &s_mfy_xtal_calc);
  			LL_ASSERT(!ret);
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  		} else {
  			LL_ASSERT(0);
  		}
  	} else if (ret_cb_evt == TICKER_STATUS_FAILURE) {
  		/* Step 3: Caller inside Event, handle graceful stop of Event
  		 * (role dependent)
  		 */
  
  		/* Stop ticker "may" be in use for direct adv or scanner,
  		 * hence stop may fail if ticker not used.
  		 *
  		 * Connection instances do not use a stop ticker, hence do not
  		 * try to stop an invalid ticker id.
  		 */
  		if (ticker_id_stop != TICKER_NULL) {
  			u32_t volatile ret_cb_stop = TICKER_STATUS_BUSY;
  
  			ret = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  					  RADIO_TICKER_USER_ID_APP,
  					  ticker_id_stop, ticker_if_done,
  					  (void *)&ret_cb_stop);
  
  			if (ret == TICKER_STATUS_BUSY) {
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  				mayfly_enable(RADIO_TICKER_USER_ID_APP,
  					      RADIO_TICKER_USER_ID_JOB, 1);
  #endif
  
  				LL_ASSERT(ret_cb_stop != TICKER_STATUS_BUSY);
  			}
  
  			LL_ASSERT((ret_cb_stop == TICKER_STATUS_SUCCESS) ||
  				  (ret_cb_stop == TICKER_STATUS_FAILURE));
  		}
  
  		/* Force Radio ISR execution and wait for role to stop */
  		if (_radio.role != ROLE_NONE) {
  			static memq_link_t link_radio;
  			static struct mayfly s_mfy_radio_stop = {
  				0, 0, &link_radio, NULL, mayfly_radio_stop};
  
  			/* Radio state STOP is supplied in params */
  			s_mfy_radio_stop.param = (void *)STATE_STOP;
  
  			/* Stop Radio Tx/Rx */
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_APP,
  					     RADIO_TICKER_USER_ID_WORKER, 0,
  					     &s_mfy_radio_stop);
  			LL_ASSERT(!ret);
  
  #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
  			/* calc whether xtal needs to be retained after this
  			 * event
  			 */
  			s_mfy_xtal_calc.param =
  				(void *)(u32_t)_radio.ticker_id_stop;
  			ret = mayfly_enqueue(RADIO_TICKER_USER_ID_APP,
  					     RADIO_TICKER_USER_ID_JOB, 0,
  					     &s_mfy_xtal_calc);
  			LL_ASSERT(!ret);
  #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
  
  			/* wait for radio ISR to exit */
  			while (_radio.role != ROLE_NONE) {
  				cpu_sleep();
  			}
  		}
  	} else {
  		LL_ASSERT(0);
  	}
  }
  
  static u8_t role_disable(u8_t ticker_id_primary, u8_t ticker_id_stop)
  {
  	u32_t volatile ret_cb = TICKER_STATUS_BUSY;
  	u32_t ticks_active_to_start = 0U;
  	u32_t ticks_xtal_to_start = 0U;
  	u32_t ret;
  
  	/* Determine xtal, active and start ticks. Stop directed adv stop
  	 * ticker.
  	 */
  	switch (ticker_id_primary) {
  	case RADIO_TICKER_ID_ADV:
  		ticks_xtal_to_start =
  			_radio.advertiser.hdr.ticks_xtal_to_start;
  		ticks_active_to_start =
  			_radio.advertiser.hdr.ticks_active_to_start;
  
  		/* Stop ticker "may" be in use for direct adv,
  		 * hence stop may fail if ticker not used.
  		 */
  		ret = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  				  RADIO_TICKER_USER_ID_APP, ticker_id_stop,
  				  ticker_if_done, (void *)&ret_cb);
  		if (ret == TICKER_STATUS_BUSY) {
  			/* wait for ticker to be stopped */
  			while (ret_cb == TICKER_STATUS_BUSY) {
  				cpu_sleep();
  			}
  		}
  
  		LL_ASSERT((ret_cb == TICKER_STATUS_SUCCESS) ||
  			  (ret_cb == TICKER_STATUS_FAILURE));
  		break;
  
  	case RADIO_TICKER_ID_SCAN:
  		ticks_xtal_to_start =
  			_radio.scanner.hdr.ticks_xtal_to_start;
  		ticks_active_to_start =
  			_radio.scanner.hdr.ticks_active_to_start;
  		break;
  	default:
  		if (ticker_id_primary >= RADIO_TICKER_ID_FIRST_CONNECTION) {
  			struct connection *conn;
  			u16_t conn_handle;
  
  			conn_handle = ticker_id_primary -
  				      RADIO_TICKER_ID_FIRST_CONNECTION;
  			conn = connection_get(conn_handle);
  			if (!conn) {
  				return BT_HCI_ERR_UNKNOWN_CONN_ID;
  			}
  
  			ticks_xtal_to_start =
  				conn->hdr.ticks_xtal_to_start;
  			ticks_active_to_start =
  				conn->hdr.ticks_active_to_start;
  		} else {
  			LL_ASSERT(0);
  		}
  		break;
  	}
  
  	LL_ASSERT(!_radio.ticker_id_stop);
  	_radio.ticker_id_stop = ticker_id_primary;
  
  	/* Step 1: Is Primary started? Stop the Primary ticker */
  	ret_cb = TICKER_STATUS_BUSY;
  	ret = ticker_stop(RADIO_TICKER_INSTANCE_ID_RADIO,
  			  RADIO_TICKER_USER_ID_APP, ticker_id_primary,
  			  ticker_if_done, (void *)&ret_cb);
  
  	if (ret == TICKER_STATUS_BUSY) {
  #if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE) && \
  	(RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
  		/* if inside our event, enable Job. */
  		if (_radio.ticker_id_event == ticker_id_primary) {
  			mayfly_enable(RADIO_TICKER_USER_ID_APP,
  				      RADIO_TICKER_USER_ID_JOB, 1);
  		}
  #endif
  
  		/* wait for ticker to be stopped */
  		while (ret_cb == TICKER_STATUS_BUSY) {
  			cpu_sleep();
  		}
  	}
  
  	if (ret_cb != TICKER_STATUS_SUCCESS) {
  		goto role_disable_cleanup;
  	}
  
  	/* Inside our event, gracefully handle XTAL and Radio actives */
  	if ((_radio.ticker_id_prepare == ticker_id_primary)
  	    || (_radio.ticker_id_event == ticker_id_primary)) {
  
  		role_active_disable(ticker_id_stop,
  				    ticks_xtal_to_start, ticks_active_to_start);
  	}
  
  	if (!_radio.ticker_id_stop) {
  		ret_cb = TICKER_STATUS_FAILURE;
  	}
  
  role_disable_cleanup:
  	_radio.ticker_id_stop = 0U;
  
  	return ret_cb ? BT_HCI_ERR_CMD_DISALLOWED : 0;
  }
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  u32_t radio_adv_enable(u8_t phy_p, u16_t interval, u8_t chan_map,
  		       u8_t filter_policy, u8_t rl_idx,
  #else /* !CONFIG_BT_CTLR_ADV_EXT */
  u32_t radio_adv_enable(u16_t interval, u8_t chan_map, u8_t filter_policy,
  		       u8_t rl_idx,
  #endif /* !CONFIG_BT_CTLR_ADV_EXT */
  		       u8_t at_anchor, u32_t ticks_anchor, u8_t retry,
  		       u8_t scan_window, u8_t scan_delay)
  {
  #else /* !CONFIG_BT_HCI_MESH_EXT */
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  u32_t radio_adv_enable(u8_t phy_p, u16_t interval, u8_t chan_map,
  		       u8_t filter_policy, u8_t rl_idx)
  #else /* !CONFIG_BT_CTLR_ADV_EXT */
  u32_t radio_adv_enable(u16_t interval, u8_t chan_map, u8_t filter_policy,
  		       u8_t rl_idx)
  #endif /* !CONFIG_BT_CTLR_ADV_EXT */
  {
  	u32_t ticks_anchor;
  #endif /* !CONFIG_BT_HCI_MESH_EXT */
  	u32_t volatile ret_cb = TICKER_STATUS_BUSY;
  	u32_t ticks_slot_offset;
  	struct connection *conn;
  	struct pdu_adv *pdu_adv;
  	u32_t slot_us;
  	u8_t chan_cnt;
  	u32_t ret;
  
  	if (_radio.advertiser.is_enabled) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	if (scan_delay) {
  		if (_radio.scanner.is_enabled) {
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  
  		_radio.advertiser.is_mesh = 1;
  	}
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  	pdu_adv = (void *)&_radio.advertiser.adv_data.data
  					[_radio.advertiser.adv_data.last][0];
  	if ((pdu_adv->type == PDU_ADV_TYPE_ADV_IND) ||
  	    (pdu_adv->type == PDU_ADV_TYPE_DIRECT_IND)) {
  		memq_link_t *link;
  
  		if (_radio.advertiser.conn) {
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  
  		conn = mem_acquire(&_radio.conn_free);
  		if (!conn) {
  			return BT_HCI_ERR_CONN_LIMIT_EXCEEDED;
  		}
  
  		link = mem_acquire(&_radio.link_rx_free);
  		if (!link) {
  			mem_release(conn, &_radio.conn_free);
  			return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
  		}
  
  		conn->handle = 0xFFFF;
  		conn->llcp_feature.features = LL_FEAT;
  		conn->data_chan_sel = 0U;
  		conn->data_chan_use = 0U;
  		conn->event_counter = 0U;
  		conn->latency_prepare = 0U;
  		conn->latency_event = 0U;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		conn->default_tx_octets = _radio.default_tx_octets;
  		conn->max_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
  		conn->max_rx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		conn->default_tx_time = _radio.default_tx_time;
  		conn->max_tx_time =
  			RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0);
  		conn->max_rx_time =
  			RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0);
  #endif /* CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		conn->phy_pref_tx = _radio.default_phy_tx;
  		conn->phy_tx = BIT(0);
  		conn->phy_pref_flags = 0U;
  		conn->phy_flags = 0U;
  		conn->phy_tx_time = BIT(0);
  		conn->phy_pref_rx = _radio.default_phy_rx;
  		conn->phy_rx = BIT(0);
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		conn->role = 1U;
  		conn->connect_expire = 6U;
  		conn->common.fex_valid = 0U;
  		conn->slave.latency_enabled = 0U;
  		conn->slave.latency_cancel = 0U;
  		conn->slave.window_widening_prepare_us = 0U;
  		conn->slave.window_widening_event_us = 0U;
  		conn->slave.ticks_to_offset = 0U;
  		conn->supervision_expire = 0U;
  		conn->procedure_expire = 0U;
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  		conn->apto_expire = 0U;
  		conn->appto_expire = 0U;
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  		conn->llcp_req = 0U;
  		conn->llcp_ack = 0U;
  		conn->llcp_cu.req = 0U;
  		conn->llcp_cu.ack = 0U;
  		conn->llcp_feature.req = 0U;
  		conn->llcp_feature.ack = 0U;
  		conn->llcp_version.req = 0U;
  		conn->llcp_version.ack = 0U;
  		conn->llcp_version.tx = 0U;
  		conn->llcp_version.rx = 0U;
  		conn->llcp_terminate.req = 0U;
  		conn->llcp_terminate.ack = 0U;
  		conn->llcp_terminate.reason_peer = 0U;
  		conn->llcp_terminate.radio_pdu_node_rx.hdr.link = link;
  
  		if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  			link->next = link->mem = NULL;
  		}
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  		conn->llcp_enc.req = 0U;
  		conn->llcp_enc.ack = 0U;
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  		conn->llcp_conn_param.req = 0U;
  		conn->llcp_conn_param.ack = 0U;
  		conn->llcp_conn_param.disabled = 0U;
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  		conn->llcp_length.req = 0U;
  		conn->llcp_length.ack = 0U;
  		conn->llcp_length.cache.tx_octets = 0U;
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		conn->llcp_phy.req = 0U;
  		conn->llcp_phy.ack = 0U;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  		conn->sn = 0U;
  		conn->nesn = 0U;
  		conn->pause_rx = 0U;
  		conn->pause_tx = 0U;
  		conn->enc_rx = 0U;
  		conn->enc_tx = 0U;
  		conn->refresh = 0U;
  		conn->empty = 0U;
  		conn->pkt_tx_head = NULL;
  		conn->pkt_tx_ctrl = NULL;
  		conn->pkt_tx_ctrl_last = NULL;
  		conn->pkt_tx_data = NULL;
  		conn->pkt_tx_last = NULL;
  		conn->packet_tx_head_len = 0U;
  		conn->packet_tx_head_offset = 0U;
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  		conn->rssi_latest = 0x7F;
  		conn->rssi_reported = 0x7F;
  		conn->rssi_sample_count = 0U;
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  		conn->tx_pwr_lvl = RADIO_TXP_DEFAULT;
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  
  		/* wait for stable 32KHz clock */
  		k32src_wait();
  
  		_radio.advertiser.conn = conn;
  	} else {
  		conn = NULL;
  	}
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  	_radio.advertiser.phy_p = phy_p;
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  
  	_radio.advertiser.chan_map = chan_map;
  	_radio.advertiser.filter_policy = filter_policy;
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	_radio.advertiser.rl_idx = rl_idx;
  #else
  	ARG_UNUSED(rl_idx);
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  	_radio.advertiser.hdr.ticks_active_to_start =
  		_radio.ticks_active_to_start;
  	_radio.advertiser.hdr.ticks_xtal_to_start =
  		HAL_TICKER_US_TO_TICKS(RADIO_TICKER_XTAL_OFFSET_US);
  	_radio.advertiser.hdr.ticks_preempt_to_start =
  		HAL_TICKER_US_TO_TICKS(RADIO_TICKER_PREEMPT_PART_MIN_US);
  
  	chan_cnt = util_ones_count_get(&chan_map, sizeof(chan_map));
  
  	/* TODO: use adv data len in slot duration calculation, instead of
  	 * hardcoded max. numbers used below.
  	 */
  	if (pdu_adv->type == PDU_ADV_TYPE_DIRECT_IND) {
  		/* Max. chain is DIRECT_IND * channels + CONNECT_IND */
  		slot_us = ((RADIO_TICKER_START_PART_US + 176 + 152 + 40) *
  			   chan_cnt) - 40 + 352;
  	} else if (pdu_adv->type == PDU_ADV_TYPE_NONCONN_IND) {
  		slot_us = (RADIO_TICKER_START_PART_US + 376) * chan_cnt;
  	} else {
  		/* Max. chain is ADV/SCAN_IND + SCAN_REQ + SCAN_RESP */
  		slot_us = (RADIO_TICKER_START_PART_US + 376 + 152 + 176 +
  			   152 + 376) * chan_cnt;
  	}
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	if (_radio.advertiser.is_mesh) {
  		u16_t interval_min_us;
  
  		_radio.advertiser.retry = retry;
  		_radio.advertiser.scan_delay_ms = scan_delay;
  		_radio.advertiser.scan_window_ms = scan_window;
  
  		interval_min_us = slot_us + (scan_delay + scan_window) * 1000;
  		if ((interval * 625) < interval_min_us) {
  			interval = (interval_min_us + (625 - 1)) / 625;
  		}
  
  		/* passive scanning */
  		_radio.scanner.type = 0;
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  		/* TODO: Coded PHY support */
  		_radio.scanner.phy = 0;
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  		/* TODO: Privacy support */
  		_radio.scanner.rpa_gen = 0;
  		_radio.scanner.rl_idx = rl_idx;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  		_radio.scanner.filter_policy = filter_policy;
  	}
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  	_radio.advertiser.hdr.ticks_slot = HAL_TICKER_US_TO_TICKS(slot_us);
  
  	ticks_slot_offset =
  		MAX(_radio.advertiser.hdr.ticks_active_to_start,
  		    _radio.advertiser.hdr.ticks_xtal_to_start);
  
  #if !defined(CONFIG_BT_HCI_MESH_EXT)
  	ticks_anchor = ticker_ticks_now_get();
  #else /* CONFIG_BT_HCI_MESH_EXT */
  	if (!at_anchor) {
  		ticks_anchor = ticker_ticks_now_get();
  	}
  #endif /* !CONFIG_BT_HCI_MESH_EXT */
  
  #if defined(CONFIG_BT_PERIPHERAL)
  	/* High Duty Cycle Directed Advertising if interval is 0. */
  	_radio.advertiser.is_hdcd = !interval &&
  				    (pdu_adv->type == PDU_ADV_TYPE_DIRECT_IND);
  	if (_radio.advertiser.is_hdcd) {
  		ret = ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				   RADIO_TICKER_USER_ID_APP,
  				   RADIO_TICKER_ID_ADV, ticks_anchor, 0,
  				   (ticks_slot_offset +
  				    _radio.advertiser.hdr.ticks_slot),
  				   TICKER_NULL_REMAINDER, TICKER_NULL_LAZY,
  				   (ticks_slot_offset +
  				    _radio.advertiser.hdr.ticks_slot),
  				   radio_event_adv_prepare, NULL,
  				   ticker_if_done, (void *)&ret_cb);
  
  		if (ret == TICKER_STATUS_BUSY) {
  			while (ret_cb == TICKER_STATUS_BUSY) {
  				cpu_sleep();
  			}
  		}
  
  		if (ret_cb != TICKER_STATUS_SUCCESS) {
  			goto failure_cleanup;
  		}
  
  		ret_cb = TICKER_STATUS_BUSY;
  		ret =
  			ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				     RADIO_TICKER_USER_ID_APP,
  				     RADIO_TICKER_ID_ADV_STOP, ticks_anchor,
  				     HAL_TICKER_US_TO_TICKS(
  					(1280 * 1000) +
  					RADIO_TICKER_XTAL_OFFSET_US),
  				     TICKER_NULL_PERIOD, TICKER_NULL_REMAINDER,
  				     TICKER_NULL_LAZY, TICKER_NULL_SLOT,
  				     event_adv_stop, NULL, ticker_if_done,
  				     (void *)&ret_cb);
  	} else
  #endif /* CONFIG_BT_PERIPHERAL */
  	{
  		ret =
  			ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  				     RADIO_TICKER_USER_ID_APP,
  				     RADIO_TICKER_ID_ADV,
  				     ticks_anchor, 0,
  				     HAL_TICKER_US_TO_TICKS((u64_t)interval *
  							    625),
  				     TICKER_NULL_REMAINDER, TICKER_NULL_LAZY,
  				     (ticks_slot_offset +
  				      _radio.advertiser.hdr.ticks_slot),
  				     radio_event_adv_prepare, NULL,
  				     ticker_if_done, (void *)&ret_cb);
  	}
  
  	if (ret == TICKER_STATUS_BUSY) {
  		while (ret_cb == TICKER_STATUS_BUSY) {
  			cpu_sleep();
  		}
  	}
  
  	if (ret_cb == TICKER_STATUS_SUCCESS) {
  		_radio.advertiser.is_enabled = 1U;
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  		if (_radio.advertiser.is_mesh) {
  			_radio.scanner.is_enabled = 1;
  
  			ll_adv_scan_state_cb(BIT(0) | BIT(1));
  		}
  #else /* !CONFIG_BT_HCI_MESH_EXT */
  		if (!_radio.scanner.is_enabled) {
  			ll_adv_scan_state_cb(BIT(0));
  		}
  #endif /* !CONFIG_BT_HCI_MESH_EXT */
  
  		return 0;
  	}
  
  #if defined(CONFIG_BT_PERIPHERAL)
  failure_cleanup:
  
  	if (conn) {
  		mem_release(conn->llcp_terminate.radio_pdu_node_rx.hdr.link,
  			    &_radio.link_rx_free);
  		mem_release(conn, &_radio.conn_free);
  	}
  #endif /* CONFIG_BT_PERIPHERAL */
  
  	return BT_HCI_ERR_CMD_DISALLOWED;
  }
  
  u8_t radio_adv_disable(void)
  {
  	u8_t status;
  
  	status = role_disable(RADIO_TICKER_ID_ADV,
  			      RADIO_TICKER_ID_ADV_STOP);
  	if (!status) {
  		struct connection *conn;
  
  		_radio.advertiser.is_enabled = 0U;
  
  		if (!_radio.scanner.is_enabled) {
  			ll_adv_scan_state_cb(0);
  		}
  
  		conn = _radio.advertiser.conn;
  		if (conn) {
  			struct radio_pdu_node_rx_hdr *hdr;
  
  			_radio.advertiser.conn = NULL;
  
  			hdr = &conn->llcp_terminate.radio_pdu_node_rx.hdr;
  			mem_release(hdr->link, &_radio.link_rx_free);
  			mem_release(conn, &_radio.conn_free);
  		}
  	}
  
  	return status;
  }
  
  u32_t ll_adv_is_enabled(u16_t handle)
  {
  	return _radio.advertiser.is_enabled;
  }
  
  u32_t radio_adv_filter_pol_get(void)
  {
  	/* NOTE: filter_policy is only written in thread mode; if is_enabled is
  	 * unset by ISR, returning the stale filter_policy is acceptable because
  	 * the unset code path in ISR will generate a connection complete
  	 * event.
  	 */
  	if (_radio.advertiser.is_enabled) {
  		return _radio.advertiser.filter_policy;
  	}
  
  	return 0;
  }
  
  u32_t radio_scan_enable(u8_t type, u8_t init_addr_type, u8_t *init_addr,
  			u16_t interval, u16_t window, u8_t filter_policy,
  			u8_t rpa_gen, u8_t rl_idx)
  {
  	u32_t volatile ret_cb = TICKER_STATUS_BUSY;
  	u32_t ticks_slot_offset;
  	u32_t ticks_interval;
  	u32_t ticks_anchor;
  	u32_t us_offset;
  	u32_t ret;
  
  	if (_radio.scanner.is_enabled) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	_radio.scanner.type = type;
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  	_radio.scanner.phy = type >> 1;
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  
  #if defined(CONFIG_BT_CTLR_PRIVACY)
  	_radio.scanner.rpa_gen = rpa_gen;
  	_radio.scanner.rl_idx = rl_idx;
  #endif /* CONFIG_BT_CTLR_PRIVACY */
  
  	_radio.scanner.init_addr_type = init_addr_type;
  	memcpy(&_radio.scanner.init_addr[0], init_addr, BDADDR_SIZE);
  	_radio.scanner.ticks_window = HAL_TICKER_US_TO_TICKS((u64_t)window *
  							     625);
  	_radio.scanner.filter_policy = filter_policy;
  
  	_radio.scanner.hdr.ticks_active_to_start =
  		_radio.ticks_active_to_start;
  	_radio.scanner.hdr.ticks_xtal_to_start =
  		HAL_TICKER_US_TO_TICKS(RADIO_TICKER_XTAL_OFFSET_US);
  	_radio.scanner.hdr.ticks_preempt_to_start =
  		HAL_TICKER_US_TO_TICKS(RADIO_TICKER_PREEMPT_PART_MIN_US);
  	_radio.scanner.hdr.ticks_slot =
  		_radio.scanner.ticks_window +
  		HAL_TICKER_US_TO_TICKS(RADIO_TICKER_START_PART_US);
  
  	ticks_interval = HAL_TICKER_US_TO_TICKS((u64_t) interval * 625);
  	if (_radio.scanner.hdr.ticks_slot >
  	    (ticks_interval -
  	     HAL_TICKER_US_TO_TICKS(RADIO_TICKER_XTAL_OFFSET_US))) {
  		_radio.scanner.hdr.ticks_slot =
  			(ticks_interval -
  			 HAL_TICKER_US_TO_TICKS(RADIO_TICKER_XTAL_OFFSET_US));
  	}
  
  	ticks_slot_offset = MAX(_radio.scanner.hdr.ticks_active_to_start,
  				_radio.scanner.hdr.ticks_xtal_to_start);
  
  	ticks_anchor = ticker_ticks_now_get();
  
  	if ((_radio.scanner.conn) ||
  	    !IS_ENABLED(CONFIG_BT_CTLR_SCHED_ADVANCED)) {
  		us_offset = 0U;
  	}
  #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
  	else {
  		u32_t ticks_ref = 0U;
  
  		sched_after_mstr_free_slot_get(RADIO_TICKER_USER_ID_APP,
  					       (ticks_slot_offset +
  						_radio.scanner.hdr.ticks_slot),
  					       &ticks_ref, &us_offset);
  		/* Use the ticks_ref as scanner's anchor if a free time space
  		 * after any master role is available (indicated by a non-zero
  		 * us_offset value).
  		 */
  		if (us_offset) {
  			ticks_anchor = ticks_ref;
  		}
  	}
  #endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
  
  	ret = ticker_start(RADIO_TICKER_INSTANCE_ID_RADIO,
  			   RADIO_TICKER_USER_ID_APP, RADIO_TICKER_ID_SCAN,
  			   (ticks_anchor + HAL_TICKER_US_TO_TICKS(us_offset)),
  			   0, ticks_interval,
  			   HAL_TICKER_REMAINDER((u64_t) interval * 625),
  			   TICKER_NULL_LAZY,
  			   (ticks_slot_offset +
  			    _radio.scanner.hdr.ticks_slot),
  			   event_scan_prepare, NULL, ticker_if_done,
  			   (void *)&ret_cb);
  
  	if (ret == TICKER_STATUS_BUSY) {
  		while (ret_cb == TICKER_STATUS_BUSY) {
  			cpu_sleep();
  		}
  	}
  
  	if (ret_cb != TICKER_STATUS_SUCCESS) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	_radio.scanner.is_enabled = 1U;
  
  	if (!_radio.advertiser.is_enabled) {
  		ll_adv_scan_state_cb(BIT(1));
  	}
  
  	return 0;
  }
  
  u8_t radio_scan_disable(bool scanner)
  {
  	u8_t status;
  
  	if (scanner && _radio.scanner.conn) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	status = role_disable(RADIO_TICKER_ID_SCAN,
  			      RADIO_TICKER_ID_SCAN_STOP);
  	if (!status && !_radio.scanner.conn) {
  		_radio.scanner.is_enabled = 0U;
  
  		if (!_radio.advertiser.is_enabled) {
  			ll_adv_scan_state_cb(0);
  		}
  	}
  
  	return status;
  }
  
  u32_t ll_scan_is_enabled(u16_t handle)
  {
  	/* NOTE: BIT(0) - passive scanning enabled
  	 *       BIT(1) - active scanning enabled
  	 *       BIT(2) - initiator enabled
  	 */
  	return ((u32_t)_radio.scanner.is_enabled << _radio.scanner.type) |
  	       (_radio.scanner.conn ? BIT(2) : 0);
  }
  
  u32_t radio_scan_filter_pol_get(void)
  {
  	/* NOTE: filter_policy is only written in thread mode; if is_enabled is
  	 * unset by ISR, returning the stale filter_policy is acceptable because
  	 * the unset code path in ISR will generate a connection complete
  	 * event.
  	 */
  	if (_radio.scanner.is_enabled) {
  		return _radio.scanner.filter_policy;
  	}
  
  	return 0;
  }
  
  #if defined(CONFIG_BT_CONN)
  u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr, u16_t interval,
  			   u16_t latency, u16_t timeout)
  {
  	struct connection *conn;
  	u32_t conn_interval_us;
  	u32_t access_addr;
  	memq_link_t *link;
  
  	if (_radio.scanner.conn) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	link = mem_acquire(&_radio.link_rx_free);
  	if (!link) {
  		return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
  	}
  
  	conn = mem_acquire(&_radio.conn_free);
  	if (!conn) {
  		mem_release(link, &_radio.link_rx_free);
  		return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
  	}
  
  	_radio.scanner.adv_addr_type = adv_addr_type;
  	memcpy(&_radio.scanner.adv_addr[0], adv_addr, BDADDR_SIZE);
  	_radio.scanner.conn_interval = interval;
  	_radio.scanner.conn_latency = latency;
  	_radio.scanner.conn_timeout = timeout;
  	_radio.scanner.ticks_conn_slot = HAL_TICKER_US_TO_TICKS(
  		RADIO_TICKER_START_PART_US + radio_tx_ready_delay_get(0, 0) +
  		328 + RADIO_TIFS + 328);
  
  	conn->handle = 0xFFFF;
  	conn->llcp_feature.features = LL_FEAT;
  	access_addr = access_addr_get();
  	memcpy(&conn->access_addr[0], &access_addr, sizeof(conn->access_addr));
  	util_rand(&conn->crc_init[0], 3);
  	memcpy(&conn->data_chan_map[0], &_radio.data_chan_map[0],
  	       sizeof(conn->data_chan_map));
  	conn->data_chan_count = _radio.data_chan_count;
  	conn->data_chan_sel = 0U;
  	conn->data_chan_hop = 6U;
  	conn->data_chan_use = 0U;
  	conn->event_counter = 0U;
  	conn->conn_interval = _radio.scanner.conn_interval;
  	conn->latency_prepare = 0U;
  	conn->latency_event = 0U;
  	conn->latency = _radio.scanner.conn_latency;
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	conn->default_tx_octets = _radio.default_tx_octets;
  	conn->max_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
  	conn->max_rx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	conn->default_tx_time = _radio.default_tx_time;
  	conn->max_tx_time = RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0);
  	conn->max_rx_time = RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0);
  #endif /* CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	conn->phy_pref_tx = _radio.default_phy_tx;
  	conn->phy_tx = BIT(0);
  	conn->phy_pref_flags = 0U;
  	conn->phy_flags = 0U;
  	conn->phy_tx_time = BIT(0);
  	conn->phy_pref_rx = _radio.default_phy_rx;
  	conn->phy_rx = BIT(0);
  #endif /* CONFIG_BT_CTLR_PHY */
  
  	conn->role = 0U;
  	conn->connect_expire = 6U;
  	conn->common.fex_valid = 0U;
  	conn->master.terminate_ack = 0U;
  	conn_interval_us =
  		(u32_t)_radio.scanner.conn_interval * 1250;
  	conn->supervision_reload =
  		RADIO_CONN_EVENTS((_radio.scanner.conn_timeout * 10 * 1000),
  				  conn_interval_us);
  	conn->supervision_expire = 0U;
  	conn->procedure_reload =
  		RADIO_CONN_EVENTS((40 * 1000 * 1000), conn_interval_us);
  	conn->procedure_expire = 0U;
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  	/* APTO in no. of connection events */
  	conn->apto_reload = RADIO_CONN_EVENTS((30 * 1000 * 1000),
  					      conn_interval_us);
  	/* Dispatch LE Ping PDU 6 connection events (that peer would listen to)
  	 * before 30s timeout
  	 * TODO: "peer listens to" is greater than 30s due to latency
  	 */
  	conn->appto_reload = (conn->apto_reload > (conn->latency + 6)) ?
  			     (conn->apto_reload - (conn->latency + 6)) :
  			     conn->apto_reload;
  	conn->apto_expire = 0U;
  	conn->appto_expire = 0U;
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  	conn->llcp_req = 0U;
  	conn->llcp_ack = 0U;
  	conn->llcp_cu.req = 0U;
  	conn->llcp_cu.ack = 0U;
  	conn->llcp_feature.req = 0U;
  	conn->llcp_feature.ack = 0U;
  	conn->llcp_version.req = 0U;
  	conn->llcp_version.ack = 0U;
  	conn->llcp_version.tx = 0U;
  	conn->llcp_version.rx = 0U;
  	conn->llcp_terminate.req = 0U;
  	conn->llcp_terminate.ack = 0U;
  	conn->llcp_terminate.reason_peer = 0U;
  	conn->llcp_terminate.radio_pdu_node_rx.hdr.link = link;
  
  	if (IS_ENABLED(CONFIG_BT_CTLR_RX_ENQUEUE_HOLD)) {
  		link->next = link->mem = NULL;
  	}
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  	conn->llcp_enc.req = 0U;
  	conn->llcp_enc.ack = 0U;
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  	conn->llcp_conn_param.req = 0U;
  	conn->llcp_conn_param.ack = 0U;
  	conn->llcp_conn_param.disabled = 0U;
  #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  	conn->llcp_length.req = 0U;
  	conn->llcp_length.ack = 0U;
  	conn->llcp_length.cache.tx_octets = 0U;
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	conn->llcp_phy.req = 0U;
  	conn->llcp_phy.ack = 0U;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  	conn->sn = 0U;
  	conn->nesn = 0U;
  	conn->pause_rx = 0U;
  	conn->pause_tx = 0U;
  	conn->enc_rx = 0U;
  	conn->enc_tx = 0U;
  	conn->refresh = 0U;
  	conn->empty = 0U;
  	conn->pkt_tx_head = NULL;
  	conn->pkt_tx_ctrl = NULL;
  	conn->pkt_tx_ctrl_last = NULL;
  	conn->pkt_tx_data = NULL;
  	conn->pkt_tx_last = NULL;
  	conn->packet_tx_head_len = 0U;
  	conn->packet_tx_head_offset = 0U;
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  	conn->rssi_latest = 0x7F;
  	conn->rssi_reported = 0x7F;
  	conn->rssi_sample_count = 0U;
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  	conn->tx_pwr_lvl = RADIO_TXP_DEFAULT;
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  
  	/* wait for stable 32KHz clock */
  	k32src_wait();
  
  	_radio.scanner.conn = conn;
  
  	return 0;
  }
  
  u8_t ll_connect_disable(void **node_rx)
  {
  	u32_t status;
  
  	if (_radio.scanner.conn == 0) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	status = radio_scan_disable(false);
  	if (!status) {
  		struct connection *conn = _radio.scanner.conn;
  		struct radio_pdu_node_rx *rx;
  
  		rx = (void *)&conn->llcp_terminate.radio_pdu_node_rx;
  
  		/* free the memq link early, as caller could overwrite it */
  		mem_release(rx->hdr.link, &_radio.link_rx_free);
  
  		rx->hdr.type = NODE_RX_TYPE_CONNECTION;
  		rx->hdr.handle = 0xffff;
  		*((u8_t *)rx->pdu_data) = BT_HCI_ERR_UNKNOWN_CONN_ID;
  		*node_rx = rx;
  	}
  
  	return status;
  }
  
  u8_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status, u16_t interval_min,
  		    u16_t interval_max, u16_t latency, u16_t timeout)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	if (!cmd) {
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  		if (!conn->llcp_conn_param.disabled &&
  		    (!conn->common.fex_valid ||
  		     (conn->llcp_feature.features &
  		      BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ)))) {
  			cmd++;
  		} else if (conn->role) {
  			return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
  		}
  #else /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
  		if (conn->role) {
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  #endif /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
  	}
  
  	if (!cmd) {
  		if (conn->llcp_cu.req != conn->llcp_cu.ack) {
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  
  		conn->llcp_cu.win_size = 1U;
  		conn->llcp_cu.win_offset_us = 0U;
  		conn->llcp_cu.interval = interval_max;
  		conn->llcp_cu.latency = latency;
  		conn->llcp_cu.timeout = timeout;
  		conn->llcp_cu.state = LLCP_CUI_STATE_USE;
  		conn->llcp_cu.cmd = 1U;
  
  		conn->llcp_cu.req++;
  	} else {
  #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
  		cmd--;
  
  		if (cmd) {
  			if ((conn->llcp_conn_param.req ==
  			     conn->llcp_conn_param.ack) ||
  			    (conn->llcp_conn_param.state !=
  			     LLCP_CPR_STATE_APP_WAIT)) {
  				return BT_HCI_ERR_CMD_DISALLOWED;
  			}
  
  			conn->llcp_conn_param.status = status;
  			conn->llcp_conn_param.state = cmd;
  			conn->llcp_conn_param.cmd = 1U;
  		} else {
  			if (conn->llcp_conn_param.req !=
  			    conn->llcp_conn_param.ack) {
  				return BT_HCI_ERR_CMD_DISALLOWED;
  			}
  
  			conn->llcp_conn_param.status = 0U;
  			conn->llcp_conn_param.interval_min = interval_min;
  			conn->llcp_conn_param.interval_max = interval_max;
  			conn->llcp_conn_param.latency = latency;
  			conn->llcp_conn_param.timeout = timeout;
  			conn->llcp_conn_param.state = cmd;
  			conn->llcp_conn_param.cmd = 1U;
  			conn->llcp_conn_param.req++;
  		}
  
  #else /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
  		/* CPR feature not supported */
  		return BT_HCI_ERR_CMD_DISALLOWED;
  #endif /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
  	}
  
  	return 0;
  }
  
  u8_t ll_chm_update(u8_t *chm)
  {
  	u8_t instance;
  
  	memcpy(&_radio.data_chan_map[0], chm,
  	       sizeof(_radio.data_chan_map));
  	_radio.data_chan_count =
  		util_ones_count_get(&_radio.data_chan_map[0],
  				    sizeof(_radio.data_chan_map));
  
  	instance = _radio.connection_count;
  	while (instance--) {
  		struct connection *conn;
  
  		conn = connection_get(instance);
  		if (!conn || conn->role) {
  			continue;
  		}
  
  		if (conn->llcp_req != conn->llcp_ack) {
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  
  		memcpy(&conn->llcp.chan_map.chm[0], chm,
  		       sizeof(conn->llcp.chan_map.chm));
  		/* conn->llcp.chan_map.instant     = 0; */
  		conn->llcp.chan_map.initiate = 1U;
  
  		conn->llcp_type = LLCP_CHAN_MAP;
  		conn->llcp_req++;
  	}
  
  	return 0;
  }
  
  u8_t ll_chm_get(u16_t handle, u8_t *chm)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	/* Iterate until we are sure the ISR did not modify the value while
  	 * we were reading it from memory.
  	 */
  	do {
  		conn->chm_update = 0U;
  		memcpy(chm, conn->data_chan_map, sizeof(conn->data_chan_map));
  	} while (conn->chm_update);
  
  	return 0;
  }
  
  #if defined(CONFIG_BT_CTLR_LE_ENC)
  u8_t ll_enc_req_send(u16_t handle, u8_t *rand, u8_t *ediv, u8_t *ltk)
  {
  	struct connection *conn;
  	struct radio_pdu_node_tx *node_tx;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	if ((conn->llcp_enc.req != conn->llcp_enc.ack) ||
  	    ((conn->llcp_req != conn->llcp_ack) &&
  	     (conn->llcp_type == LLCP_ENCRYPTION))) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	node_tx = ll_tx_mem_acquire();
  	if (node_tx) {
  		struct pdu_data *pdu_data_tx;
  
  		pdu_data_tx = (void *)node_tx->pdu_data;
  
  		memcpy(&conn->llcp_enc.ltk[0], ltk, sizeof(conn->llcp_enc.ltk));
  
  		if (!conn->enc_rx && !conn->enc_tx) {
  			struct pdu_data_llctrl_enc_req *enc_req;
  
  			pdu_data_tx->ll_id = PDU_DATA_LLID_CTRL;
  			pdu_data_tx->len =
  				offsetof(struct pdu_data_llctrl, enc_rsp) +
  				sizeof(struct pdu_data_llctrl_enc_req);
  			pdu_data_tx->llctrl.opcode =
  				PDU_DATA_LLCTRL_TYPE_ENC_REQ;
  			enc_req = (void *)
  				&pdu_data_tx->llctrl.enc_req;
  			memcpy(enc_req->rand, rand, sizeof(enc_req->rand));
  			enc_req->ediv[0] = ediv[0];
  			enc_req->ediv[1] = ediv[1];
  			util_rand(enc_req->skdm, sizeof(enc_req->skdm));
  			util_rand(enc_req->ivm, sizeof(enc_req->ivm));
  		} else if (conn->enc_rx && conn->enc_tx) {
  			memcpy(&conn->llcp_enc.rand[0], rand,
  			       sizeof(conn->llcp_enc.rand));
  
  			conn->llcp_enc.ediv[0] = ediv[0];
  			conn->llcp_enc.ediv[1] = ediv[1];
  
  			pdu_data_tx->ll_id = PDU_DATA_LLID_CTRL;
  			pdu_data_tx->len = offsetof(struct pdu_data_llctrl,
  						    enc_req);
  			pdu_data_tx->llctrl.opcode =
  				PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ;
  		} else {
  			ll_tx_mem_release(node_tx);
  
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  
  		if (ll_tx_mem_enqueue(handle, node_tx)) {
  			ll_tx_mem_release(node_tx);
  
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  
  		conn->llcp_enc.req++;
  
  		return 0;
  	}
  
  	return BT_HCI_ERR_CMD_DISALLOWED;
  }
  
  u8_t ll_start_enc_req_send(u16_t handle, u8_t error_code,
  			    u8_t const *const ltk)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	if (error_code) {
  		if (conn->refresh == 0) {
  			if ((conn->llcp_req == conn->llcp_ack) ||
  			     (conn->llcp_type != LLCP_ENCRYPTION)) {
  				return BT_HCI_ERR_CMD_DISALLOWED;
  			}
  
  			conn->llcp.encryption.error_code = error_code;
  			conn->llcp.encryption.state = LLCP_ENC_STATE_INPROG;
  		} else {
  			if (conn->llcp_terminate.ack !=
  			    conn->llcp_terminate.req) {
  				return BT_HCI_ERR_CMD_DISALLOWED;
  			}
  
  			conn->llcp_terminate.reason_own = error_code;
  
  			conn->llcp_terminate.req++;
  		}
  	} else {
  		if ((conn->llcp_req == conn->llcp_ack) ||
  		     (conn->llcp_type != LLCP_ENCRYPTION)) {
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  
  		memcpy(&conn->llcp_enc.ltk[0], ltk,
  		       sizeof(conn->llcp_enc.ltk));
  
  		conn->llcp.encryption.error_code = 0U;
  		conn->llcp.encryption.state = LLCP_ENC_STATE_INPROG;
  	}
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_LE_ENC */
  
  u8_t ll_feature_req_send(u16_t handle)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	if (conn->llcp_feature.req != conn->llcp_feature.ack) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	conn->llcp_feature.req++;
  
  	return 0;
  }
  
  u8_t ll_version_ind_send(u16_t handle)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	if (conn->llcp_version.req != conn->llcp_version.ack) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	conn->llcp_version.req++;
  
  	return 0;
  }
  
  u8_t ll_terminate_ind_send(u16_t handle, u8_t reason)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	if (conn->llcp_terminate.ack != conn->llcp_terminate.req) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	conn->llcp_terminate.reason_own = reason;
  
  	conn->llcp_terminate.req++;
  
  	return 0;
  }
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  u8_t ll_rssi_get(u16_t handle, u8_t *rssi)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	*rssi = conn->rssi_latest;
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  u8_t ll_apto_get(u16_t handle, u16_t *apto)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	*apto = conn->apto_reload * conn->conn_interval * 125 / 1000;
  
  	return 0;
  }
  
  u8_t ll_apto_set(u16_t handle, u16_t apto)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	conn->apto_reload = RADIO_CONN_EVENTS(apto * 10 * 1000,
  					      conn->conn_interval * 1250);
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  #if defined(CONFIG_BT_CTLR_DATA_LENGTH)
  u32_t ll_length_req_send(u16_t handle, u16_t tx_octets, u16_t tx_time)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	if (conn->llcp_length.req != conn->llcp_length.ack) {
  		switch (conn->llcp_length.state) {
  		case LLCP_LENGTH_STATE_RSP_ACK_WAIT:
  		case LLCP_LENGTH_STATE_RESIZE_RSP:
  		case LLCP_LENGTH_STATE_RESIZE_RSP_ACK_WAIT:
  			/* cached until peer procedure completes */
  			if (!conn->llcp_length.cache.tx_octets) {
  				conn->llcp_length.cache.tx_octets = tx_octets;
  #if defined(CONFIG_BT_CTLR_PHY)
  				conn->llcp_length.cache.tx_time = tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  				return 0;
  			}
  			/* pass through */
  		default:
  			return BT_HCI_ERR_CMD_DISALLOWED;
  		}
  	}
  
  	/* TODO: parameter check tx_octets and tx_time */
  
  	conn->llcp_length.state = LLCP_LENGTH_STATE_REQ;
  	conn->llcp_length.tx_octets = tx_octets;
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	conn->llcp_length.tx_time = tx_time;
  #endif /* CONFIG_BT_CTLR_PHY */
  
  	conn->llcp_length.req++;
  
  	return 0;
  }
  
  void ll_length_default_get(u16_t *max_tx_octets, u16_t *max_tx_time)
  {
  	*max_tx_octets = _radio.default_tx_octets;
  	*max_tx_time = _radio.default_tx_time;
  }
  
  u32_t ll_length_default_set(u16_t max_tx_octets, u16_t max_tx_time)
  {
  	/* TODO: parameter check (for BT 5.0 compliance) */
  
  	_radio.default_tx_octets = max_tx_octets;
  	_radio.default_tx_time = max_tx_time;
  
  	return 0;
  }
  
  void ll_length_max_get(u16_t *max_tx_octets, u16_t *max_tx_time,
  		       u16_t *max_rx_octets, u16_t *max_rx_time)
  {
  	*max_tx_octets = LL_LENGTH_OCTETS_RX_MAX;
  	*max_tx_time = RADIO_PKT_TIME(LL_LENGTH_OCTETS_RX_MAX, BIT(2));
  	*max_rx_octets = LL_LENGTH_OCTETS_RX_MAX;
  	*max_rx_time = RADIO_PKT_TIME(LL_LENGTH_OCTETS_RX_MAX, BIT(2));
  }
  #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
  
  #if defined(CONFIG_BT_CTLR_PHY)
  u8_t ll_phy_get(u16_t handle, u8_t *tx, u8_t *rx)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	/* TODO: context safe read */
  	*tx = conn->phy_tx;
  	*rx = conn->phy_rx;
  
  	return 0;
  }
  
  u8_t ll_phy_default_set(u8_t tx, u8_t rx)
  {
  	/* TODO: validate against supported phy */
  
  	_radio.default_phy_tx = tx;
  	_radio.default_phy_rx = rx;
  
  	return 0;
  }
  
  u8_t ll_phy_req_send(u16_t handle, u8_t tx, u8_t flags, u8_t rx)
  {
  	struct connection *conn;
  
  	conn = connection_get(handle);
  	if (!conn) {
  		return BT_HCI_ERR_UNKNOWN_CONN_ID;
  	}
  
  	if (conn->llcp_phy.req != conn->llcp_phy.ack) {
  		return BT_HCI_ERR_CMD_DISALLOWED;
  	}
  
  	conn->llcp_phy.state = LLCP_PHY_STATE_REQ;
  	conn->llcp_phy.cmd = 1U;
  	conn->llcp_phy.tx = tx;
  	conn->llcp_phy.flags = flags;
  	conn->llcp_phy.rx = rx;
  	conn->llcp_phy.req++;
  
  	return 0;
  }
  #endif /* CONFIG_BT_CTLR_PHY */
  #endif /* CONFIG_BT_CONN */
  
  u8_t ll_tx_pwr_lvl_get(u8_t handle_type,
  		       u16_t handle, u8_t type, s8_t *tx_pwr_lvl)
  {
  	switch (handle_type) {
  #if defined(CONFIG_BT_BROADCASTER) &&\
  	defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  		case (BT_HCI_VS_LL_HANDLE_TYPE_ADV): {
  			/* Unique global advertiser as part of ctrl */
  			*tx_pwr_lvl = _radio.advertiser.tx_pwr_lvl;
  			break;
  		}
  #endif /* CONFIG_BT_BROADCASTER && CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  #if defined(CONFIG_BT_OBSERVER) &&\
  	defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  		case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): {
  			/* Unique global scanner as part of ctrl */
  			*tx_pwr_lvl = _radio.scanner.tx_pwr_lvl;
  			break;
  		}
  #endif /* CONFIG_BT_OBSERVER && CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  #if defined(CONFIG_BT_CONN)
  		case (BT_HCI_VS_LL_HANDLE_TYPE_CONN): {
  			struct connection *conn;
  
  			conn = connection_get(handle);
  			if (!conn) {
  				return BT_HCI_ERR_UNKNOWN_CONN_ID;
  			}
  			if (type) {
  				/* Level desired is maximum available */
  				*tx_pwr_lvl = radio_tx_power_max_get();
  			} else {
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  				/* Current level is requested */
  				*tx_pwr_lvl = conn->tx_pwr_lvl;
  #else
  				*tx_pwr_lvl = RADIO_TXP_DEFAULT;
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  			}
  			break;
  		}
  #endif /* CONFIG_BT_CONN */
  		default: {
  			return BT_HCI_ERR_UNKNOWN_CMD;
  		}
  	}
  
  	return BT_HCI_ERR_SUCCESS;
  }
  
  u8_t ll_tx_pwr_lvl_set(u8_t handle_type,
  		       u16_t handle, s8_t *tx_pwr_lvl)
  {
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  	if (*tx_pwr_lvl == BT_HCI_VS_LL_TX_POWER_LEVEL_NO_PREF) {
  		/* If no preference selected, then use default Tx power */
  		*tx_pwr_lvl = RADIO_TXP_DEFAULT;
  	}
  
  	/**
  	 * Check that desired Tx power matches the achievable transceiver
  	 * Tx power capabilities by flooring - if selected power matches than
  	 * is used, otherwise next smaller power available is used.
  	 */
  	*tx_pwr_lvl = lll_radio_tx_pwr_floor(*tx_pwr_lvl);
  #endif
  
  	switch (handle_type) {
  #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
  #if defined(CONFIG_BT_BROADCASTER)
  		case (BT_HCI_VS_LL_HANDLE_TYPE_ADV): {
  			/* Unique global advertiser as part of ctrl */
  			_radio.advertiser.tx_pwr_lvl = *tx_pwr_lvl;
  			break;
  		}
  #endif /* CONFIG_BT_BROADCASTER */
  #if defined(CONFIG_BT_OBSERVER)
  		case (BT_HCI_VS_LL_HANDLE_TYPE_SCAN): {
  			/* Unique global scanner as part of ctrl */
  			_radio.scanner.tx_pwr_lvl = *tx_pwr_lvl;
  			break;
  		}
  #endif /* CONFIG_BT_OBSERVER */
  #if defined(CONFIG_BT_CONN)
  		case (BT_HCI_VS_LL_HANDLE_TYPE_CONN): {
  			struct connection *conn;
  
  			conn = connection_get(handle);
  			if (!conn) {
  				return BT_HCI_ERR_UNKNOWN_CONN_ID;
  			}
  			conn->tx_pwr_lvl = *tx_pwr_lvl;
  			break;
  		}
  #endif /* CONFIG_BT_CONN */
  #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
  		default: {
  			return BT_HCI_ERR_UNKNOWN_CMD;
  		}
  	}
  
  	return BT_HCI_ERR_SUCCESS;
  }
  
  s8_t lll_radio_tx_pwr_min_get(void)
  {
  	return radio_tx_power_min_get();
  }
  
  s8_t lll_radio_tx_pwr_max_get(void)
  {
  	return radio_tx_power_max_get();
  }
  
  s8_t lll_radio_tx_pwr_floor(s8_t tx_pwr_lvl)
  {
  	return radio_tx_power_floor(tx_pwr_lvl);
  }
  
  static u8_t tx_cmplt_get(u16_t *handle, u8_t *first, u8_t last)
  {
  	u8_t _first;
  	u8_t cmplt;
  
  	_first = *first;
  	if (_first == last) {
  		return 0;
  	}
  
  	cmplt = 0U;
  	*handle = _radio.pkt_release[_first].handle;
  	do {
  		struct radio_pdu_node_tx *node_tx;
  		struct pdu_data *pdu_data_tx;
  
  		if (*handle != _radio.pkt_release[_first].handle) {
  			break;
  		}
  
  		node_tx = _radio.pkt_release[_first].node_tx;
  		/*@FIXME: assign before first 3 if conditions */
  		pdu_data_tx = (void *)node_tx->pdu_data;
  		if ((!node_tx) || (node_tx == (void *)1) ||
  		    ((((u32_t)node_tx & ~(0x00000003)) != 0) &&
  		     (pdu_data_tx) && (pdu_data_tx->len != 0) &&
  		     ((pdu_data_tx->ll_id == PDU_DATA_LLID_DATA_START) ||
  		      (pdu_data_tx->ll_id == PDU_DATA_LLID_DATA_CONTINUE)))) {
  
  			/* data packet, hence count num cmplt */
  			_radio.pkt_release[_first].node_tx = (void *)1;
  
  			cmplt++;
  		} else {
  			/* ctrl packet, hence not num cmplt */
  			_radio.pkt_release[_first].node_tx = (void *)2;
  		}
  
  		if (((u32_t)node_tx & ~(0x00000003)) != 0) {
  			mem_release(node_tx, &_radio.pkt_tx_data_free);
  		}
  
  		_first = _first + 1;
  		if (_first == _radio.packet_tx_count) {
  			_first = 0U;
  		}
  
  	} while (_first != last);
  
  	*first = _first;
  
  	return cmplt;
  }
  
  u8_t ll_rx_get(void **node_rx, u16_t *handle)
  {
  	u8_t cmplt;
  
  	cmplt = 0U;
  	if (_radio.link_rx_head != _radio.link_rx_tail) {
  		struct radio_pdu_node_rx *_node_rx;
  
  		_node_rx = _radio.link_rx_head->mem;
  
  		cmplt = tx_cmplt_get(handle, &_radio.packet_release_first,
  				     _node_rx->hdr.packet_release_last);
  		if (!cmplt) {
  			u8_t first, cmplt_prev, cmplt_curr;
  			u16_t h;
  
  			first = _radio.packet_release_first;
  			cmplt_curr = 0U;
  			do {
  				cmplt_prev = cmplt_curr;
  				cmplt_curr = tx_cmplt_get(&h, &first,
  						_radio.packet_release_last);
  			} while ((cmplt_prev != 0) ||
  				 (cmplt_prev != cmplt_curr));
  
  			*node_rx = _node_rx;
  		} else {
  			*node_rx = NULL;
  		}
  	} else {
  		cmplt = tx_cmplt_get(handle, &_radio.packet_release_first,
  				     _radio.packet_release_last);
  
  		*node_rx = NULL;
  	}
  
  	return cmplt;
  }
  
  void ll_rx_dequeue(void)
  {
  	struct radio_pdu_node_rx *node_rx = NULL;
  	memq_link_t *link;
  
  	link = memq_dequeue(_radio.link_rx_tail, &_radio.link_rx_head,
  			    (void **)&node_rx);
  	LL_ASSERT(link);
  
  	mem_release(link, &_radio.link_rx_free);
  
  	switch (node_rx->hdr.type) {
  	case NODE_RX_TYPE_DC_PDU:
  
  #if defined(CONFIG_BT_OBSERVER)
  	case NODE_RX_TYPE_REPORT:
  #endif /* CONFIG_BT_OBSERVER */
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  	case NODE_RX_TYPE_EXT_1M_REPORT:
  	case NODE_RX_TYPE_EXT_CODED_REPORT:
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  
  #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
  	case NODE_RX_TYPE_SCAN_REQ:
  #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */
  
  #if defined(CONFIG_BT_CONN)
  	case NODE_RX_TYPE_CONNECTION:
  	case NODE_RX_TYPE_CONN_UPDATE:
  	case NODE_RX_TYPE_ENC_REFRESH:
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  	case NODE_RX_TYPE_APTO:
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  	case NODE_RX_TYPE_CHAN_SEL_ALGO:
  
  #if defined(CONFIG_BT_CTLR_PHY)
  	case NODE_RX_TYPE_PHY_UPDATE:
  #endif /* CONFIG_BT_CTLR_PHY */
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  	case NODE_RX_TYPE_RSSI:
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  #endif /* CONFIG_BT_CONN */
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR)
  	case NODE_RX_TYPE_PROFILE:
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  #if defined(CONFIG_BT_CTLR_ADV_INDICATION)
  	case NODE_RX_TYPE_ADV_INDICATION:
  #endif /* CONFIG_BT_CTLR_ADV_INDICATION */
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	case NODE_RX_TYPE_MESH_ADV_CPLT:
  	case NODE_RX_TYPE_MESH_REPORT:
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  		/* release data link credit quota */
  		LL_ASSERT(_radio.link_rx_data_quota <
  			  (_radio.packet_rx_count - 1));
  
  		_radio.link_rx_data_quota++;
  		break;
  
  #if defined(CONFIG_BT_CONN)
  	case NODE_RX_TYPE_TERMINATE:
  		/* did not use data link quota */
  		break;
  #endif /* CONFIG_BT_CONN */
  
  	default:
  		LL_ASSERT(0);
  		break;
  	}
  
  	if (0) {
  #if defined(CONFIG_BT_CONN)
  	} else
  	if (node_rx->hdr.type == NODE_RX_TYPE_CONNECTION) {
  		struct radio_le_conn_cmplt *radio_le_conn_cmplt;
  		struct connection *conn = NULL;
  		u8_t bm;
  
  		radio_le_conn_cmplt = (void *)node_rx->pdu_data;
  		if ((radio_le_conn_cmplt->status == BT_HCI_ERR_ADV_TIMEOUT) ||
  		    radio_le_conn_cmplt->role) {
  			if (radio_le_conn_cmplt->status ==
  			    BT_HCI_ERR_ADV_TIMEOUT) {
  				conn = _radio.advertiser.conn;
  				_radio.advertiser.conn = NULL;
  			}
  
  			LL_ASSERT(_radio.advertiser.is_enabled);
  			_radio.advertiser.is_enabled = 0U;
  		} else {
  			LL_ASSERT(_radio.scanner.is_enabled);
  			_radio.scanner.is_enabled = 0U;
  		}
  
  		if (conn) {
  			struct radio_pdu_node_rx *node_rx = (void *)
  				&conn->llcp_terminate.radio_pdu_node_rx;
  
  			mem_release(node_rx->hdr.link,
  				    &_radio.link_rx_free);
  			mem_release(conn, &_radio.conn_free);
  		}
  
  		bm = ((u8_t)_radio.scanner.is_enabled << 1) |
  		     _radio.advertiser.is_enabled;
  
  		if (!bm) {
  			ll_adv_scan_state_cb(0);
  		}
  #endif /* CONFIG_BT_CONN */
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  	} else if (node_rx->hdr.type == NODE_RX_TYPE_MESH_ADV_CPLT) {
  		LL_ASSERT(_radio.advertiser.is_enabled);
  		_radio.advertiser.is_enabled = 0;
  
  		LL_ASSERT(_radio.scanner.is_enabled);
  		_radio.scanner.is_enabled = 0;
  
  		ll_adv_scan_state_cb(0);
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  	}
  
  }
  
  void ll_rx_mem_release(void **node_rx)
  {
  	struct radio_pdu_node_rx *_node_rx;
  
  	_node_rx = *node_rx;
  	while (_node_rx) {
  		struct radio_pdu_node_rx *_node_rx_free;
  
  		_node_rx_free = _node_rx;
  		_node_rx = _node_rx->hdr.next;
  
  		switch (_node_rx_free->hdr.type) {
  #if defined(CONFIG_BT_CONN)
  		case NODE_RX_TYPE_CONNECTION:
  			if (IS_ENABLED(CONFIG_BT_CENTRAL)) {
  				if (*((u8_t *)_node_rx_free->pdu_data) ==
  				    BT_HCI_ERR_UNKNOWN_CONN_ID) {
  					struct connection *conn;
  
  					conn = _radio.scanner.conn;
  					_radio.scanner.conn = NULL;
  
  					mem_release(conn, &_radio.conn_free);
  
  					_radio.scanner.is_enabled = 0U;
  
  					if (!_radio.advertiser.is_enabled) {
  						ll_adv_scan_state_cb(0);
  					}
  
  					break;
  				}
  			}
  			/* fall through */
  		case NODE_RX_TYPE_DC_PDU:
  #endif /* CONFIG_BT_CONN */
  
  #if defined(CONFIG_BT_OBSERVER)
  		case NODE_RX_TYPE_REPORT:
  #endif /* CONFIG_BT_OBSERVER */
  
  #if defined(CONFIG_BT_CTLR_ADV_EXT)
  		case NODE_RX_TYPE_EXT_1M_REPORT:
  		case NODE_RX_TYPE_EXT_CODED_REPORT:
  #endif /* CONFIG_BT_CTLR_ADV_EXT */
  
  #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
  		case NODE_RX_TYPE_SCAN_REQ:
  #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */
  
  #if defined(CONFIG_BT_CONN)
  		case NODE_RX_TYPE_CONN_UPDATE:
  		case NODE_RX_TYPE_ENC_REFRESH:
  
  #if defined(CONFIG_BT_CTLR_LE_PING)
  		case NODE_RX_TYPE_APTO:
  #endif /* CONFIG_BT_CTLR_LE_PING */
  
  		case NODE_RX_TYPE_CHAN_SEL_ALGO:
  
  #if defined(CONFIG_BT_CTLR_PHY)
  		case NODE_RX_TYPE_PHY_UPDATE:
  #endif /* CONFIG_BT_CTLR_PHY */
  
  #if defined(CONFIG_BT_CTLR_CONN_RSSI)
  		case NODE_RX_TYPE_RSSI:
  #endif /* CONFIG_BT_CTLR_CONN_RSSI */
  #endif /* CONFIG_BT_CONN */
  
  #if defined(CONFIG_BT_CTLR_PROFILE_ISR)
  		case NODE_RX_TYPE_PROFILE:
  #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
  
  #if defined(CONFIG_BT_CTLR_ADV_INDICATION)
  		case NODE_RX_TYPE_ADV_INDICATION:
  #endif /* CONFIG_BT_CTLR_ADV_INDICATION */
  
  #if defined(CONFIG_BT_HCI_MESH_EXT)
  		case NODE_RX_TYPE_MESH_ADV_CPLT:
  		case NODE_RX_TYPE_MESH_REPORT:
  #endif /* CONFIG_BT_HCI_MESH_EXT */
  
  		/* fall through */
  
  		/* Ensure that at least one 'case' statement is present for this
  		 * code block.
  		 */
  		case NODE_RX_TYPE_NONE:
  			LL_ASSERT(_node_rx_free->hdr.type != NODE_RX_TYPE_NONE);
  			mem_release(_node_rx_free,
  				    &_radio.pkt_rx_data_free);
  			break;
  
  #if defined(CONFIG_BT_CONN)
  		case NODE_RX_TYPE_TERMINATE:
  		{
  			struct connection *conn;
  
  			conn = mem_get(_radio.conn_pool, CONNECTION_T_SIZE,
  				       _node_rx_free->hdr.handle);
  
  			mem_release(conn, &_radio.conn_free);
  		}
  		break;
  #endif /* CONFIG_BT_CONN */
  
  		default:
  			LL_ASSERT(0);
  			break;
  		}
  	}
  
  	*node_rx = _node_rx;
  
  	packet_rx_allocate(0xff);
  }
  
  #if defined(CONFIG_BT_CONN)
  static void rx_fc_lock(u16_t handle)
  {
  	if (_radio.fc_req == _radio.fc_ack) {
  		u8_t req;
  
  		_radio.fc_handle[_radio.fc_req] = handle;
  		req = _radio.fc_req + 1;
  		if (req == TRIPLE_BUFFER_SIZE) {
  			req = 0U;
  		}
  		_radio.fc_req = req;
  	}
  }
  #endif /* CONFIG_BT_CONN */
  
  static u8_t do_radio_rx_fc_set(u16_t handle, u8_t req, u8_t ack)
  {
  	if (req == ack) {
  		if (_radio.link_rx_head == _radio.link_rx_tail) {
  			u8_t ack1 = ack;
  
  			if (ack1 == 0) {
  				ack1 = TRIPLE_BUFFER_SIZE;
  			}
  			_radio.fc_handle[--ack1] = handle;
  			_radio.fc_ack = ack1;
  
  			/* check if ISR updated FC by changing fc_req */
  			if (req != _radio.fc_req) {
  				_radio.fc_ack = ack;
  
  				return 1;
  			}
  		} else {
  			return 1;
  		}
  	} else if (((req == 0) &&
  		    (_radio.fc_handle[TRIPLE_BUFFER_SIZE - 1] != handle)) ||
  		   ((req != 0) && (_radio.fc_handle[req - 1] != handle))) {
  		return 1;
  	}
  
  	return 0;
  }
  
  u8_t radio_rx_fc_set(u16_t handle, u8_t fc)
  {
  	if (_radio.fc_ena) {
  		u8_t req = _radio.fc_req;
  		u8_t ack = _radio.fc_ack;
  
  		if (fc) {
  			if (handle != 0xffff) {
  				return do_radio_rx_fc_set(handle, req, ack);
  			}
  		} else if ((_radio.link_rx_head == _radio.link_rx_tail) &&
  			   (req != ack)
  		    ) {
  			_radio.fc_ack = req;
  
  			if ((_radio.link_rx_head != _radio.link_rx_tail) &&
  			    (req == _radio.fc_req)) {
  				_radio.fc_ack = ack;
  			}
  		}
  	}
  
  	return 0;
  }
  
  u8_t radio_rx_fc_get(u16_t *handle)
  {
  	u8_t req = _radio.fc_req;
  	u8_t ack = _radio.fc_ack;
  
  	if (req != ack) {
  		if (handle) {
  			*handle = _radio.fc_handle[ack];
  		}
  		return 1;
  	}
  
  	return 0;
  }
  
  void *ll_tx_mem_acquire(void)
  {
  	return mem_acquire(&_radio.pkt_tx_data_free);
  }
  
  void ll_tx_mem_release(void *node_tx)
  {
  	mem_release(node_tx, &_radio.pkt_tx_data_free);
  }
  
  static void ticker_op_latency_cancelled(u32_t ticker_status, void *params)
  {
  	struct connection *conn = params;
  
  	LL_ASSERT(ticker_status == TICKER_STATUS_SUCCESS);
  
  	conn->slave.latency_cancel = 0U;
  }
  
  int ll_tx_mem_enqueue(u16_t handle, void *node_tx)
  {
  	u8_t last;
  	struct connection *conn;
  	struct pdu_data *pdu_data;
  
  	last = _radio.packet_tx_last + 1;
  	if (last == _radio.packet_tx_count) {
  		last = 0U;
  	}
  
  	pdu_data = (void *)((struct radio_pdu_node_tx *)node_tx)->pdu_data;
  	conn = connection_get(handle);
  	if (!conn) {
  		return -EINVAL;
  	}
  
  	if (last == _radio.packet_tx_first) {
  		return -ENOBUFS;
  	}
  
  	LL_ASSERT(pdu_data->len <= (_radio.packet_tx_data_size -
  				    offsetof(struct radio_pdu_node_tx,
  					     pdu_data) -
  				    offsetof(struct pdu_data, lldata)));
  
  	_radio.pkt_tx[_radio.packet_tx_last].handle = handle;
  	_radio.pkt_tx[_radio.packet_tx_last].node_tx = node_tx;
  	_radio.packet_tx_last = last;
  
  	/* break slave latency */
  	if (conn->role && conn->latency_event && !conn->slave.latency_cancel) {
  		u32_t ticker_status;
  
  		conn->slave.latency_cancel = 1U;
  
  		ticker_status = ticker_update(RADIO_TICKER_INSTANCE_ID_RADIO,
  				 RADIO_TICKER_USER_ID_APP,
  				 RADIO_TICKER_ID_FIRST_CONNECTION +
  				 conn->handle, 0, 0, 0, 0, 1, 0,
  				 ticker_op_latency_cancelled,
  				 (void *)conn);
  		LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
  			  (ticker_status == TICKER_STATUS_BUSY));
  	}
  
  	return 0;
  }
  
  void __weak ll_adv_scan_state_cb(u8_t bm)
  {
  }
  