2 * Copyright © 2011 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 #define AO_CMAC_KEY_LEN AO_AES_LEN
21 #define AO_CMAC_MAX_LEN (128 - AO_CMAC_KEY_LEN)
23 static __xdata uint8_t ao_radio_cmac_mutex;
24 static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN];
25 static __pdata uint8_t ao_radio_cmac_len;
32 b = ao_cmd_hexchar(getchar());
34 ao_cmd_status = ao_cmd_lex_error;
50 round_len(uint8_t len)
54 /* Make sure we transfer at least one packet, and
55 * then make sure every packet is full. Note that
56 * there is no length encoded, and that the receiver
57 * must deal with any extra bytes in the packet
59 if (len < AO_CMAC_KEY_LEN)
60 len = AO_CMAC_KEY_LEN;
61 rem = len % AO_CMAC_KEY_LEN;
63 len += (AO_CMAC_KEY_LEN - rem);
68 * Sign and deliver the data sitting in the cmac buffer
71 radio_cmac_send(uint8_t len) __reentrant
76 /* Make sure the AES key is loaded */
83 ao_mutex_get(&ao_aes_mutex);
84 ao_aes_set_mode(ao_aes_mode_cbc_mac);
85 ao_aes_set_key(ao_config.aes_key);
87 for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
88 if (i + AO_CMAC_KEY_LEN < len)
89 ao_aes_run(&cmac_data[i], NULL);
91 ao_aes_run(&cmac_data[i], &cmac_data[len]);
93 ao_mutex_put(&ao_aes_mutex);
95 ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN);
99 * Receive and validate an incoming packet
103 radio_cmac_recv(uint8_t len, uint16_t timeout) __reentrant
107 len = round_len(len);
114 i = ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2);
118 return AO_RADIO_CMAC_TIMEOUT;
120 if (!(cmac_data[len + AO_CMAC_KEY_LEN +1] & PKT_APPEND_STATUS_1_CRC_OK))
121 return AO_RADIO_CMAC_CRC_ERROR;
125 /* Compute the packet signature
127 ao_mutex_get(&ao_aes_mutex);
128 ao_aes_set_mode(ao_aes_mode_cbc_mac);
129 ao_aes_set_key(ao_config.aes_key);
131 for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
132 if (i + AO_CMAC_KEY_LEN < len)
133 ao_aes_run(&cmac_data[i], NULL);
135 ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]);
137 ao_mutex_put(&ao_aes_mutex);
139 /* Check the packet signature against the signature provided
143 if (memcmp(&cmac_data[len],
144 &cmac_data[len + AO_CMAC_KEY_LEN + 2],
145 AO_CMAC_KEY_LEN) != 0) {
146 return AO_RADIO_CMAC_MAC_ERROR;
149 return AO_RADIO_CMAC_OK;
153 ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant
155 if (len > AO_CMAC_MAX_LEN)
156 return AO_RADIO_CMAC_LEN_ERROR;
157 ao_mutex_get(&ao_radio_cmac_mutex);
158 memcpy(cmac_data, packet, len);
159 radio_cmac_send(len);
160 ao_mutex_put(&ao_radio_cmac_mutex);
161 return AO_RADIO_CMAC_OK;
165 ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant
168 if (len > AO_CMAC_MAX_LEN)
169 return AO_RADIO_CMAC_LEN_ERROR;
170 ao_mutex_get(&ao_radio_cmac_mutex);
171 i = radio_cmac_recv(len, timeout);
172 if (i == AO_RADIO_CMAC_OK)
173 memcpy(packet, cmac_data, len);
174 ao_mutex_put(&ao_radio_cmac_mutex);
179 radio_cmac_send_cmd(void) __reentrant
185 if (ao_cmd_status != ao_cmd_success)
188 if (len > AO_CMAC_MAX_LEN) {
189 ao_cmd_status = ao_cmd_syntax_error;
193 ao_mutex_get(&ao_radio_cmac_mutex);
195 for (i = 0; i < len; i++) {
196 cmac_data[i] = getbyte();
197 if (ao_cmd_status != ao_cmd_success)
200 radio_cmac_send(len);
201 ao_mutex_put(&ao_radio_cmac_mutex);
205 radio_cmac_recv_cmd(void) __reentrant
211 if (ao_cmd_status != ao_cmd_success)
215 if (ao_cmd_status != ao_cmd_success)
217 timeout = AO_MS_TO_TICKS(ao_cmd_lex_i);
218 ao_mutex_get(&ao_radio_cmac_mutex);
219 i = radio_cmac_recv(len, timeout);
220 if (i == AO_RADIO_CMAC_OK) {
222 for (i = 0; i < len; i++)
223 printf("%02x", cmac_data[i]);
226 printf ("ERROR %d\n", i);
227 ao_mutex_put(&ao_radio_cmac_mutex);
231 launch_report_cmd(void) __reentrant
233 static __xdata struct ao_launch_command command;
234 static __xdata struct ao_launch_query query;
240 serial = ao_cmd_lex_i;
242 channel = ao_cmd_lex_i;
243 if (ao_cmd_status != ao_cmd_success)
246 for (i = 0; i < 10; i++) {
247 printf ("."); flush();
249 command.serial = serial;
250 command.cmd = AO_LAUNCH_QUERY;
251 command.channel = channel;
252 ao_radio_cmac_send(&command, sizeof (command));
253 switch (ao_radio_cmac_recv(&query, sizeof (query), AO_MS_TO_TICKS(500))) {
254 case AO_RADIO_CMAC_OK:
256 switch (query.arm_status) {
257 case ao_igniter_ready:
258 case ao_igniter_active:
260 switch (query.igniter_status) {
262 printf("unknown status\n");
264 case ao_igniter_ready:
265 printf("igniter good\n");
267 case ao_igniter_open:
268 printf("igniter bad\n");
272 printf("Disarmed\n");
279 printf ("Timeout\n");
282 static __code struct ao_cmds ao_radio_cmac_cmds[] = {
283 { radio_cmac_send_cmd, "s <length>\0Send AES-CMAC packet. Bytes to send follow on next line" },
284 { radio_cmac_recv_cmd, "S <length> <timeout>\0Receive AES-CMAC packet. Timeout in ms" },
285 { launch_report_cmd, "l <serial> <channel>\0Get remote launch status" },
290 ao_radio_cmac_init(void)
292 ao_cmd_register(&ao_radio_cmac_cmds[0]);