+ len = round_len(len);
+ /* Make sure the AES key is loaded */
+ ao_config_get();
+
+#if HAS_MONITOR
+ ao_monitor_set(0);
+#endif
+
+ ao_mutex_get(&ao_aes_mutex);
+ ao_aes_set_mode(ao_aes_mode_cbc_mac);
+ ao_aes_set_key(ao_config.aes_key);
+ ao_aes_zero_iv();
+ for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
+ if (i + AO_CMAC_KEY_LEN < len)
+ ao_aes_run(&cmac_data[i], NULL);
+ else
+ ao_aes_run(&cmac_data[i], &cmac_data[len]);
+ }
+ ao_mutex_put(&ao_aes_mutex);
+
+ ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN);
+}
+
+/*
+ * Receive and validate an incoming packet
+ */
+
+static int8_t
+radio_cmac_recv(uint8_t len, uint16_t timeout) __reentrant
+{
+ uint8_t i;
+
+ len = round_len(len);
+#if HAS_MONITOR
+ ao_monitor_set(0);
+#endif
+ if (timeout)
+ ao_alarm(timeout);
+
+ i = ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2);
+ ao_clear_alarm();
+
+ if (!i) {
+ ao_radio_cmac_rssi = 0;
+ return AO_RADIO_CMAC_TIMEOUT;
+ }
+
+ ao_radio_cmac_rssi = (int16_t) (((int8_t) cmac_data[len + AO_CMAC_KEY_LEN]) >> 1) - 74;
+ if (!(cmac_data[len + AO_CMAC_KEY_LEN +1] & PKT_APPEND_STATUS_1_CRC_OK))
+ return AO_RADIO_CMAC_CRC_ERROR;
+
+ ao_config_get();
+
+ /* Compute the packet signature
+ */
+ ao_mutex_get(&ao_aes_mutex);
+ ao_aes_set_mode(ao_aes_mode_cbc_mac);
+ ao_aes_set_key(ao_config.aes_key);
+ ao_aes_zero_iv();
+ for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
+ if (i + AO_CMAC_KEY_LEN < len)
+ ao_aes_run(&cmac_data[i], NULL);
+ else
+ ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]);
+ }
+ ao_mutex_put(&ao_aes_mutex);
+
+ /* Check the packet signature against the signature provided
+ * over the link
+ */
+
+ if (memcmp(&cmac_data[len],
+ &cmac_data[len + AO_CMAC_KEY_LEN + 2],
+ AO_CMAC_KEY_LEN) != 0) {
+ return AO_RADIO_CMAC_MAC_ERROR;