1 /*
2  * Copyright (c) 2020 Siddharth Chandrasekaran <siddharth@embedjournal.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_DECLARE(osdp, CONFIG_OSDP_LOG_LEVEL);
9 
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include "osdp_common.h"
14 
15 #define CMD_POLL_DATA_LEN              0
16 #define CMD_LSTAT_DATA_LEN             0
17 #define CMD_ISTAT_DATA_LEN             0
18 #define CMD_OSTAT_DATA_LEN             0
19 #define CMD_RSTAT_DATA_LEN             0
20 #define CMD_ID_DATA_LEN                1
21 #define CMD_CAP_DATA_LEN               1
22 #define CMD_OUT_DATA_LEN               4
23 #define CMD_LED_DATA_LEN               14
24 #define CMD_BUZ_DATA_LEN               5
25 #define CMD_TEXT_DATA_LEN              6   /* variable length command */
26 #define CMD_COMSET_DATA_LEN            5
27 #define CMD_KEYSET_DATA_LEN            18
28 #define CMD_CHLNG_DATA_LEN             8
29 #define CMD_SCRYPT_DATA_LEN            16
30 
31 #define REPLY_ACK_LEN                  1
32 #define REPLY_PDID_LEN                 13
33 #define REPLY_PDCAP_LEN                1   /* variable length command */
34 #define REPLY_PDCAP_ENTITY_LEN         3
35 #define REPLY_LSTATR_LEN               3
36 #define REPLY_RSTATR_LEN               2
37 #define REPLY_COM_LEN                  6
38 #define REPLY_NAK_LEN                  2
39 #define REPLY_CCRYPT_LEN               33
40 #define REPLY_RMAC_I_LEN               17
41 #define REPLY_KEYPAD_LEN               2
42 #define REPLY_RAW_LEN                  4
43 #define REPLY_FMT_LEN                  3
44 
45 enum osdp_pd_error_e {
46 	OSDP_PD_ERR_NONE = 0,
47 	OSDP_PD_ERR_NO_DATA = -1,
48 	OSDP_PD_ERR_GENERIC = -2,
49 	OSDP_PD_ERR_REPLY = -3,
50 	OSDP_PD_ERR_IGNORE = -4,
51 };
52 
53 static struct osdp_pd_id osdp_pd_id = {
54 	.version = CONFIG_OSDP_PD_ID_VERSION,
55 	.model = CONFIG_OSDP_PD_ID_MODEL,
56 	.vendor_code = CONFIG_OSDP_PD_ID_VENDOR_CODE,
57 	.serial_number = CONFIG_OSDP_PD_ID_SERIAL_NUMBER,
58 	.firmware_version = CONFIG_OSDP_PD_ID_FIRMWARE_VERSION,
59 };
60 
61 static struct osdp_pd_cap osdp_pd_cap[] = {
62 	/* Driver Implicit capabilities */
63 	{
64 		OSDP_PD_CAP_CHECK_CHARACTER_SUPPORT,
65 		1, /* The PD supports the 16-bit CRC-16 mode */
66 		0, /* N/A */
67 	},
68 	{
69 		OSDP_PD_CAP_COMMUNICATION_SECURITY,
70 #ifdef CONFIG_OSDP_SC_ENABLED
71 		1, /* (Bit-0) AES128 support */
72 		1, /* (Bit-0) default AES128 key */
73 #else
74 		0, /* SC not supported */
75 		0, /* SC not supported */
76 #endif
77 	},
78 	/* Configured from Kconfig */
79 	{
80 		OSDP_PD_CAP_CONTACT_STATUS_MONITORING,
81 		CONFIG_OSDP_PD_CAP_CONTACT_STATUS_MONITORING_COMP_LEVEL,
82 		CONFIG_OSDP_PD_CAP_CONTACT_STATUS_MONITORING_NUM_ITEMS,
83 	},
84 	{
85 		OSDP_PD_CAP_OUTPUT_CONTROL,
86 		CONFIG_OSDP_PD_CAP_OUTPUT_CONTROL_COMP_LEVEL,
87 		CONFIG_OSDP_PD_CAP_OUTPUT_CONTROL_NUM_ITEMS,
88 	},
89 	{
90 		OSDP_PD_CAP_READER_LED_CONTROL,
91 		CONFIG_OSDP_PD_CAP_READER_LED_CONTROL_COMP_LEVEL,
92 		CONFIG_OSDP_PD_CAP_READER_LED_CONTROL_NUM_ITEMS,
93 	},
94 	{
95 		OSDP_PD_CAP_READER_AUDIBLE_OUTPUT,
96 		CONFIG_OSDP_PD_CAP_READER_AUDIBLE_OUTPUT_COMP_LEVEL,
97 		CONFIG_OSDP_PD_CAP_READER_AUDIBLE_OUTPUT_NUM_ITEMS,
98 	},
99 	{
100 		OSDP_PD_CAP_READER_TEXT_OUTPUT,
101 		CONFIG_OSDP_PD_CAP_READER_TEXT_OUTPUT_COMP_LEVEL,
102 		CONFIG_OSDP_PD_CAP_READER_TEXT_OUTPUT_NUM_ITEMS,
103 	},
104 	{
105 		OSDP_PD_CAP_CARD_DATA_FORMAT,
106 		CONFIG_OSDP_PD_CAP_CARD_DATA_FORMAT_COMP_LEVEL,
107 		0, /* N/A set to 0 */
108 	},
109 	{
110 		OSDP_PD_CAP_TIME_KEEPING,
111 		CONFIG_OSDP_PD_CAP_TIME_KEEPING_COMP_LEVEL,
112 		0, /* N/A set to 0 */
113 	},
114 	{ -1, 0, 0 } /* Sentinel */
115 };
116 
pd_event_alloc(struct osdp_pd * pd)117 static struct osdp_event *pd_event_alloc(struct osdp_pd *pd)
118 {
119 	struct osdp_event *event = NULL;
120 
121 	if (k_mem_slab_alloc(&pd->event.slab, (void **)&event, K_MSEC(100))) {
122 		LOG_ERR("Memory allocation time-out");
123 		return NULL;
124 	}
125 	return event;
126 }
127 
pd_event_free(struct osdp_pd * pd,struct osdp_event * event)128 static void pd_event_free(struct osdp_pd *pd, struct osdp_event *event)
129 {
130 	k_mem_slab_free(&pd->event.slab, (void *)event);
131 }
132 
pd_event_enqueue(struct osdp_pd * pd,struct osdp_event * event)133 static void pd_event_enqueue(struct osdp_pd *pd, struct osdp_event *event)
134 {
135 	sys_slist_append(&pd->event.queue, &event->node);
136 }
137 
pd_event_dequeue(struct osdp_pd * pd,struct osdp_event ** event)138 static int pd_event_dequeue(struct osdp_pd *pd, struct osdp_event **event)
139 {
140 	sys_snode_t *node;
141 
142 	node = sys_slist_peek_head(&pd->event.queue);
143 	if (node == NULL) {
144 		return -1;
145 	}
146 	sys_slist_remove(&pd->event.queue, NULL, node);
147 	*event = CONTAINER_OF(node, struct osdp_event, node);
148 	return 0;
149 }
150 
pd_translate_event(struct osdp_pd * pd,struct osdp_event * event)151 static int pd_translate_event(struct osdp_pd *pd, struct osdp_event *event)
152 {
153 	int reply_code = 0;
154 
155 	switch (event->type) {
156 	case OSDP_EVENT_CARDREAD:
157 		if (event->cardread.format == OSDP_CARD_FMT_RAW_UNSPECIFIED ||
158 		    event->cardread.format == OSDP_CARD_FMT_RAW_WIEGAND) {
159 			reply_code = REPLY_RAW;
160 		} else if (event->cardread.format == OSDP_CARD_FMT_ASCII) {
161 			reply_code = REPLY_FMT;
162 		} else {
163 			LOG_ERR("Event: cardread; Error: unknown format");
164 			break;
165 		}
166 		break;
167 	case OSDP_EVENT_KEYPRESS:
168 		reply_code = REPLY_KEYPPAD;
169 		break;
170 	default:
171 		LOG_ERR("Unknown event type %d", event->type);
172 		break;
173 	}
174 	if (reply_code == 0) {
175 		/* POLL command cannot fail even when there are errors here */
176 		return REPLY_ACK;
177 	}
178 	memcpy(pd->ephemeral_data, event, sizeof(struct osdp_event));
179 	return reply_code;
180 }
181 
do_command_callback(struct osdp_pd * pd,struct osdp_cmd * cmd)182 static bool do_command_callback(struct osdp_pd *pd, struct osdp_cmd *cmd)
183 {
184 	int ret;
185 
186 	ret = pd->command_callback(pd->command_callback_arg, cmd);
187 	if (ret != 0) {
188 		pd->reply_id = REPLY_NAK;
189 		pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD;
190 		return false;
191 	}
192 	return true;
193 }
194 
pd_cmd_cap_ok(struct osdp_pd * pd,struct osdp_cmd * cmd)195 static int pd_cmd_cap_ok(struct osdp_pd *pd, struct osdp_cmd *cmd)
196 {
197 	struct osdp_pd_cap *cap = NULL;
198 
199 	/* Validate the cmd_id against a PD capabilities where applicable */
200 	switch (pd->cmd_id) {
201 	case CMD_ISTAT:
202 		cap = &pd->cap[OSDP_PD_CAP_CONTACT_STATUS_MONITORING];
203 		if (cap->num_items == 0 || cap->compliance_level == 0) {
204 			break;
205 		}
206 		return 0; /* Remove this when REPLY_ISTATR is supported */
207 	case CMD_OSTAT:
208 		cap = &pd->cap[OSDP_PD_CAP_OUTPUT_CONTROL];
209 		if (cap->num_items == 0 || cap->compliance_level == 0) {
210 			break;
211 		}
212 		return 0; /* Remove this when REPLY_OSTATR is supported */
213 	case CMD_OUT:
214 		cap = &pd->cap[OSDP_PD_CAP_OUTPUT_CONTROL];
215 		if (!cmd || cap->compliance_level == 0 ||
216 		    cmd->output.output_no + 1 > cap->num_items) {
217 			break;
218 		}
219 		return 1;
220 	case CMD_LED:
221 		cap = &pd->cap[OSDP_PD_CAP_READER_LED_CONTROL];
222 		if (!cmd || cap->compliance_level == 0 ||
223 		    cmd->led.led_number + 1 > cap->num_items) {
224 			break;
225 		}
226 		return 1;
227 	case CMD_BUZ:
228 		cap = &pd->cap[OSDP_PD_CAP_READER_AUDIBLE_OUTPUT];
229 		if (cap->num_items == 0 || cap->compliance_level == 0) {
230 			break;
231 		}
232 		return 1;
233 	case CMD_TEXT:
234 		cap = &pd->cap[OSDP_PD_CAP_READER_TEXT_OUTPUT];
235 		if (cap->num_items == 0 || cap->compliance_level == 0) {
236 			break;
237 		}
238 		return 1;
239 	case CMD_CHLNG:
240 	case CMD_SCRYPT:
241 	case CMD_KEYSET:
242 		cap = &pd->cap[OSDP_PD_CAP_COMMUNICATION_SECURITY];
243 		if (cap->compliance_level == 0) {
244 			pd->reply_id = REPLY_NAK;
245 			pd->ephemeral_data[0] = OSDP_PD_NAK_SC_UNSUP;
246 			return 0;
247 		}
248 		return 1;
249 	}
250 
251 	pd->reply_id = REPLY_NAK;
252 	pd->ephemeral_data[0] = OSDP_PD_NAK_CMD_UNKNOWN;
253 	LOG_ERR("PD is not capable of handling CMD(%02x); "
254 		"Reply with NAK_CMD_UNKNOWN", pd->cmd_id);
255 	return 0;
256 }
257 
pd_decode_command(struct osdp_pd * pd,uint8_t * buf,int len)258 static int pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len)
259 {
260 	int ret = OSDP_PD_ERR_GENERIC;
261 	int pos = 0;
262 	struct osdp_cmd cmd;
263 	struct osdp_event *event;
264 
265 	pd->reply_id = 0;
266 	pd->cmd_id = cmd.id = buf[pos++];
267 	len--;
268 
269 	switch (pd->cmd_id) {
270 	case CMD_POLL:
271 		if (len != CMD_POLL_DATA_LEN) {
272 			break;
273 		}
274 		/* Check if we have external events in the queue */
275 		if (pd_event_dequeue(pd, &event) == 0) {
276 			ret = pd_translate_event(pd, event);
277 			pd->reply_id = ret;
278 			pd_event_free(pd, event);
279 		} else {
280 			pd->reply_id = REPLY_ACK;
281 		}
282 		ret = OSDP_PD_ERR_NONE;
283 		break;
284 	case CMD_LSTAT:
285 		if (len != CMD_LSTAT_DATA_LEN) {
286 			break;
287 		}
288 		pd->reply_id = REPLY_LSTATR;
289 		ret = OSDP_PD_ERR_NONE;
290 		break;
291 	case CMD_ISTAT:
292 		if (len != CMD_ISTAT_DATA_LEN) {
293 			break;
294 		}
295 		if (!pd_cmd_cap_ok(pd, NULL)) {
296 			ret = OSDP_PD_ERR_REPLY;
297 			break;
298 		}
299 		pd->reply_id = REPLY_ISTATR;
300 		ret = OSDP_PD_ERR_NONE;
301 		break;
302 	case CMD_OSTAT:
303 		if (len != CMD_OSTAT_DATA_LEN) {
304 			break;
305 		}
306 		if (!pd_cmd_cap_ok(pd, NULL)) {
307 			ret = OSDP_PD_ERR_REPLY;
308 			break;
309 		}
310 		pd->reply_id = REPLY_OSTATR;
311 		ret = OSDP_PD_ERR_NONE;
312 		break;
313 	case CMD_RSTAT:
314 		if (len != CMD_RSTAT_DATA_LEN) {
315 			break;
316 		}
317 		pd->reply_id = REPLY_RSTATR;
318 		ret = OSDP_PD_ERR_NONE;
319 		break;
320 	case CMD_ID:
321 		if (len != CMD_ID_DATA_LEN) {
322 			break;
323 		}
324 		pos++;		/* Skip reply type info. */
325 		pd->reply_id = REPLY_PDID;
326 		ret = OSDP_PD_ERR_NONE;
327 		break;
328 	case CMD_CAP:
329 		if (len != CMD_CAP_DATA_LEN) {
330 			break;
331 		}
332 		pos++;		/* Skip reply type info. */
333 		pd->reply_id = REPLY_PDCAP;
334 		ret = OSDP_PD_ERR_NONE;
335 		break;
336 	case CMD_OUT:
337 		if (len != CMD_OUT_DATA_LEN || !pd->command_callback) {
338 			break;
339 		}
340 		cmd.id = OSDP_CMD_OUTPUT;
341 		cmd.output.output_no = buf[pos++];
342 		cmd.output.control_code = buf[pos++];
343 		cmd.output.timer_count = buf[pos++];
344 		cmd.output.timer_count |= buf[pos++] << 8;
345 		ret = OSDP_PD_ERR_REPLY;
346 		if (!pd_cmd_cap_ok(pd, &cmd)) {
347 			break;
348 		}
349 		if (!do_command_callback(pd, &cmd)) {
350 			break;
351 		}
352 		pd->reply_id = REPLY_ACK;
353 		ret = OSDP_PD_ERR_NONE;
354 		break;
355 	case CMD_LED:
356 		if (len != CMD_LED_DATA_LEN || !pd->command_callback) {
357 			break;
358 		}
359 		cmd.id = OSDP_CMD_LED;
360 		cmd.led.reader = buf[pos++];
361 		cmd.led.led_number = buf[pos++];
362 
363 		cmd.led.temporary.control_code = buf[pos++];
364 		cmd.led.temporary.on_count = buf[pos++];
365 		cmd.led.temporary.off_count = buf[pos++];
366 		cmd.led.temporary.on_color = buf[pos++];
367 		cmd.led.temporary.off_color = buf[pos++];
368 		cmd.led.temporary.timer_count = buf[pos++];
369 		cmd.led.temporary.timer_count |= buf[pos++] << 8;
370 
371 		cmd.led.permanent.control_code = buf[pos++];
372 		cmd.led.permanent.on_count = buf[pos++];
373 		cmd.led.permanent.off_count = buf[pos++];
374 		cmd.led.permanent.on_color = buf[pos++];
375 		cmd.led.permanent.off_color = buf[pos++];
376 		ret = OSDP_PD_ERR_REPLY;
377 		if (!pd_cmd_cap_ok(pd, &cmd)) {
378 			break;
379 		}
380 		if (!do_command_callback(pd, &cmd)) {
381 			break;
382 		}
383 		pd->reply_id = REPLY_ACK;
384 		ret = OSDP_PD_ERR_NONE;
385 		break;
386 	case CMD_BUZ:
387 		if (len != CMD_BUZ_DATA_LEN || !pd->command_callback) {
388 			break;
389 		}
390 		cmd.id = OSDP_CMD_BUZZER;
391 		cmd.buzzer.reader = buf[pos++];
392 		cmd.buzzer.control_code = buf[pos++];
393 		cmd.buzzer.on_count = buf[pos++];
394 		cmd.buzzer.off_count = buf[pos++];
395 		cmd.buzzer.rep_count = buf[pos++];
396 		ret = OSDP_PD_ERR_REPLY;
397 		if (!pd_cmd_cap_ok(pd, &cmd)) {
398 			break;
399 		}
400 		if (!do_command_callback(pd, &cmd)) {
401 			break;
402 		}
403 		pd->reply_id = REPLY_ACK;
404 		ret = OSDP_PD_ERR_NONE;
405 		break;
406 	case CMD_TEXT:
407 		if (len < CMD_TEXT_DATA_LEN || !pd->command_callback) {
408 			break;
409 		}
410 		cmd.id = OSDP_CMD_TEXT;
411 		cmd.text.reader = buf[pos++];
412 		cmd.text.control_code = buf[pos++];
413 		cmd.text.temp_time = buf[pos++];
414 		cmd.text.offset_row = buf[pos++];
415 		cmd.text.offset_col = buf[pos++];
416 		cmd.text.length = buf[pos++];
417 		if (cmd.text.length > OSDP_CMD_TEXT_MAX_LEN ||
418 		    ((len - CMD_TEXT_DATA_LEN) < cmd.text.length) ||
419 		    cmd.text.length > OSDP_CMD_TEXT_MAX_LEN) {
420 			break;
421 		}
422 		memcpy(cmd.text.data, buf + pos, cmd.text.length);
423 		ret = OSDP_PD_ERR_REPLY;
424 		if (!pd_cmd_cap_ok(pd, &cmd)) {
425 			break;
426 		}
427 		if (!do_command_callback(pd, &cmd)) {
428 			break;
429 		}
430 		pd->reply_id = REPLY_ACK;
431 		ret = OSDP_PD_ERR_NONE;
432 		break;
433 	case CMD_COMSET:
434 		if (len != CMD_COMSET_DATA_LEN || !pd->command_callback) {
435 			break;
436 		}
437 		cmd.id = OSDP_CMD_COMSET;
438 		cmd.comset.address = buf[pos++];
439 		cmd.comset.baud_rate = buf[pos++];
440 		cmd.comset.baud_rate |= buf[pos++] << 8;
441 		cmd.comset.baud_rate |= buf[pos++] << 16;
442 		cmd.comset.baud_rate |= buf[pos++] << 24;
443 		if (cmd.comset.address >= 0x7F ||
444 		    (cmd.comset.baud_rate != 9600 &&
445 		     cmd.comset.baud_rate != 19200 &&
446 		     cmd.comset.baud_rate != 38400 &&
447 		     cmd.comset.baud_rate != 115200 &&
448 		     cmd.comset.baud_rate != 230400)) {
449 			LOG_ERR("COMSET Failed! command discarded");
450 			cmd.comset.address = pd->address;
451 			cmd.comset.baud_rate = pd->baud_rate;
452 			break;
453 		}
454 		if (!do_command_callback(pd, &cmd)) {
455 			ret = OSDP_PD_ERR_REPLY;
456 			break;
457 		}
458 		memcpy(pd->ephemeral_data, &cmd, sizeof(struct osdp_cmd));
459 		pd->reply_id = REPLY_COM;
460 		ret = OSDP_PD_ERR_NONE;
461 		break;
462 #ifdef CONFIG_OSDP_SC_ENABLED
463 	case CMD_KEYSET:
464 		if (len != CMD_KEYSET_DATA_LEN) {
465 			break;
466 		}
467 		/* only key_type == 1 (SCBK) and key_len == 16 is supported */
468 		if (buf[pos] != 1 || buf[pos + 1] != 16) {
469 			LOG_ERR("Keyset invalid len/type: %d/%d",
470 				buf[pos], buf[pos + 1]);
471 			break;
472 		}
473 		ret = OSDP_PD_ERR_REPLY;
474 		if (!pd_cmd_cap_ok(pd, NULL)) {
475 			break;
476 		}
477 		/**
478 		 * For CMD_KEYSET to be accepted, PD must be
479 		 * ONLINE and SC_ACTIVE.
480 		 */
481 		if (!sc_is_active(pd)) {
482 			pd->reply_id = REPLY_NAK;
483 			pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND;
484 			LOG_ERR("Keyset with SC inactive");
485 			break;
486 		}
487 		cmd.id = OSDP_CMD_KEYSET;
488 		cmd.keyset.type = buf[pos++];
489 		cmd.keyset.length = buf[pos++];
490 		memcpy(cmd.keyset.data, buf + pos, 16);
491 		if (!pd->command_callback) {
492 			LOG_ERR("Keyset without a command callback! The SC new "
493 				"SCBK will be lost when the PD reboots.");
494 		} else if (!do_command_callback(pd, &cmd)) {
495 			break;
496 		}
497 		memcpy(pd->sc.scbk, cmd.keyset.data, 16);
498 		CLEAR_FLAG(pd, PD_FLAG_SC_USE_SCBKD);
499 		CLEAR_FLAG(pd, PD_FLAG_INSTALL_MODE);
500 		sc_deactivate(pd);
501 		pd->reply_id = REPLY_ACK;
502 		ret = OSDP_PD_ERR_NONE;
503 		break;
504 	case CMD_CHLNG:
505 		if (len != CMD_CHLNG_DATA_LEN) {
506 			break;
507 		}
508 		ret = OSDP_PD_ERR_REPLY;
509 		if (!pd_cmd_cap_ok(pd, NULL)) {
510 			break;
511 		}
512 		sc_deactivate(pd);
513 		osdp_sc_setup(pd);
514 		memcpy(pd->sc.cp_random, buf + pos, 8);
515 		pd->reply_id = REPLY_CCRYPT;
516 		ret = OSDP_PD_ERR_NONE;
517 		break;
518 	case CMD_SCRYPT:
519 		if (len != CMD_SCRYPT_DATA_LEN) {
520 			break;
521 		}
522 		ret = OSDP_PD_ERR_REPLY;
523 		if (!pd_cmd_cap_ok(pd, NULL)) {
524 			break;
525 		}
526 		if (sc_is_active(pd)) {
527 			pd->reply_id = REPLY_NAK;
528 			pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND;
529 			LOG_ERR("Out of order CMD_SCRYPT; has CP gone rogue?");
530 			break;
531 		}
532 		memcpy(pd->sc.cp_cryptogram, buf + pos, CMD_SCRYPT_DATA_LEN);
533 		pd->reply_id = REPLY_RMAC_I;
534 		ret = OSDP_PD_ERR_NONE;
535 		break;
536 #endif /* CONFIG_OSDP_SC_ENABLED */
537 	default:
538 		LOG_ERR("Unknown CMD(%02x)", pd->cmd_id);
539 		pd->reply_id = REPLY_NAK;
540 		pd->ephemeral_data[0] = OSDP_PD_NAK_CMD_UNKNOWN;
541 		return OSDP_PD_ERR_REPLY;
542 	}
543 
544 	if (ret == OSDP_PD_ERR_GENERIC) {
545 		LOG_ERR("Failed to decode command: CMD(%02x) Len:%d ret:%d",
546 			pd->cmd_id, len, ret);
547 		pd->reply_id = REPLY_NAK;
548 		pd->ephemeral_data[0] = OSDP_PD_NAK_CMD_LEN;
549 		ret = OSDP_PD_ERR_REPLY;
550 	}
551 
552 	if (pd->cmd_id != CMD_POLL) {
553 		LOG_DBG("CMD: %02x REPLY: %02x", pd->cmd_id, pd->reply_id);
554 	}
555 
556 	return ret;
557 }
558 
check_buf_len(int need,int have)559 static inline bool check_buf_len(int need, int have)
560 {
561 	if (need > have) {
562 		LOG_ERR("OOM at build reply: need:%d have:%d", need, have);
563 		return false;
564 	}
565 	return true;
566 }
567 
568 /**
569  * Returns:
570  * +ve: length of command
571  * -ve: error
572  */
pd_build_reply(struct osdp_pd * pd,uint8_t * buf,int max_len)573 static int pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len)
574 {
575 	int ret = OSDP_PD_ERR_GENERIC;
576 	int i, len = 0;
577 	struct osdp_cmd *cmd;
578 	struct osdp_event *event;
579 	int data_off = osdp_phy_packet_get_data_offset(pd, buf);
580 #ifdef CONFIG_OSDP_SC_ENABLED
581 	uint8_t *smb = osdp_phy_packet_get_smb(pd, buf);
582 #endif
583 	buf += data_off;
584 	max_len -= data_off;
585 
586 	switch (pd->reply_id) {
587 	case REPLY_ACK:
588 		if (!check_buf_len(REPLY_ACK_LEN, max_len)) {
589 			return OSDP_PD_ERR_GENERIC;
590 		}
591 		buf[len++] = pd->reply_id;
592 		ret = OSDP_PD_ERR_NONE;
593 		break;
594 	case REPLY_PDID:
595 		if (!check_buf_len(REPLY_PDID_LEN, max_len)) {
596 			return OSDP_PD_ERR_GENERIC;
597 		}
598 		buf[len++] = pd->reply_id;
599 
600 		buf[len++] = BYTE_0(pd->id.vendor_code);
601 		buf[len++] = BYTE_1(pd->id.vendor_code);
602 		buf[len++] = BYTE_2(pd->id.vendor_code);
603 
604 		buf[len++] = pd->id.model;
605 		buf[len++] = pd->id.version;
606 
607 		buf[len++] = BYTE_0(pd->id.serial_number);
608 		buf[len++] = BYTE_1(pd->id.serial_number);
609 		buf[len++] = BYTE_2(pd->id.serial_number);
610 		buf[len++] = BYTE_3(pd->id.serial_number);
611 
612 		buf[len++] = BYTE_3(pd->id.firmware_version);
613 		buf[len++] = BYTE_2(pd->id.firmware_version);
614 		buf[len++] = BYTE_1(pd->id.firmware_version);
615 		ret = OSDP_PD_ERR_NONE;
616 		break;
617 	case REPLY_PDCAP:
618 		if (!check_buf_len(REPLY_PDCAP_LEN, max_len)) {
619 			return OSDP_PD_ERR_GENERIC;
620 		}
621 		buf[len++] = pd->reply_id;
622 		for (i = 1; i < OSDP_PD_CAP_SENTINEL; i++) {
623 			if (pd->cap[i].function_code != i) {
624 				continue;
625 			}
626 			if (max_len < REPLY_PDCAP_ENTITY_LEN) {
627 				LOG_ERR("Out of buffer space!");
628 				break;
629 			}
630 			buf[len++] = i;
631 			buf[len++] = pd->cap[i].compliance_level;
632 			buf[len++] = pd->cap[i].num_items;
633 			max_len -= REPLY_PDCAP_ENTITY_LEN;
634 		}
635 		ret = OSDP_PD_ERR_NONE;
636 		break;
637 	case REPLY_LSTATR:
638 		if (!check_buf_len(REPLY_LSTATR_LEN, max_len)) {
639 			return OSDP_PD_ERR_GENERIC;
640 		}
641 		buf[len++] = pd->reply_id;
642 		buf[len++] = ISSET_FLAG(pd, PD_FLAG_TAMPER);
643 		buf[len++] = ISSET_FLAG(pd, PD_FLAG_POWER);
644 		ret = OSDP_PD_ERR_NONE;
645 		break;
646 	case REPLY_RSTATR:
647 		if (!check_buf_len(REPLY_RSTATR_LEN, max_len)) {
648 			return OSDP_PD_ERR_GENERIC;
649 		}
650 		buf[len++] = pd->reply_id;
651 		buf[len++] = ISSET_FLAG(pd, PD_FLAG_R_TAMPER);
652 		ret = OSDP_PD_ERR_NONE;
653 		break;
654 	case REPLY_KEYPPAD:
655 		event = (struct osdp_event *)pd->ephemeral_data;
656 		if (!check_buf_len(REPLY_KEYPAD_LEN + event->keypress.length, max_len)) {
657 			return OSDP_PD_ERR_GENERIC;
658 		}
659 		buf[len++] = pd->reply_id;
660 		buf[len++] = (uint8_t)event->keypress.reader_no;
661 		buf[len++] = (uint8_t)event->keypress.length;
662 		memcpy(buf + len, event->keypress.data, event->keypress.length);
663 		len += event->keypress.length;
664 		ret = OSDP_PD_ERR_NONE;
665 		break;
666 	case REPLY_RAW: {
667 		int len_bytes;
668 
669 		event = (struct osdp_event *)pd->ephemeral_data;
670 		len_bytes = (event->cardread.length + 7) / 8;
671 		if (!check_buf_len(REPLY_RAW_LEN + len_bytes, max_len)) {
672 			return OSDP_PD_ERR_GENERIC;
673 		}
674 		buf[len++] = pd->reply_id;
675 		buf[len++] = (uint8_t)event->cardread.reader_no;
676 		buf[len++] = (uint8_t)event->cardread.format;
677 		buf[len++] = BYTE_0(event->cardread.length);
678 		buf[len++] = BYTE_1(event->cardread.length);
679 		memcpy(buf + len, event->cardread.data, len_bytes);
680 		len += len_bytes;
681 		ret = OSDP_PD_ERR_NONE;
682 		break;
683 	}
684 	case REPLY_FMT:
685 		event = (struct osdp_event *)pd->ephemeral_data;
686 		if (!check_buf_len(REPLY_FMT_LEN + event->cardread.length, max_len)) {
687 			return OSDP_PD_ERR_GENERIC;
688 		}
689 		buf[len++] = pd->reply_id;
690 		buf[len++] = (uint8_t)event->cardread.reader_no;
691 		buf[len++] = (uint8_t)event->cardread.direction;
692 		buf[len++] = (uint8_t)event->cardread.length;
693 		memcpy(buf + len, event->cardread.data, event->cardread.length);
694 		len += event->cardread.length;
695 		ret = OSDP_PD_ERR_NONE;
696 		break;
697 	case REPLY_COM:
698 		if (!check_buf_len(REPLY_COM_LEN, max_len)) {
699 			return OSDP_PD_ERR_GENERIC;
700 		}
701 		/**
702 		 * If COMSET succeeds, the PD must reply with the old params and
703 		 * then switch to the new params from then on. We have the
704 		 * new params in the commands struct that we just enqueued so
705 		 * we can peek at tail of command queue and set that to
706 		 * pd->addr/pd->baud_rate.
707 		 *
708 		 * TODO: Persist pd->address and pd->baud_rate via
709 		 * subsys/settings
710 		 */
711 		cmd = (struct osdp_cmd *)pd->ephemeral_data;
712 		buf[len++] = pd->reply_id;
713 		buf[len++] = cmd->comset.address;
714 		buf[len++] = BYTE_0(cmd->comset.baud_rate);
715 		buf[len++] = BYTE_1(cmd->comset.baud_rate);
716 		buf[len++] = BYTE_2(cmd->comset.baud_rate);
717 		buf[len++] = BYTE_3(cmd->comset.baud_rate);
718 
719 		pd->address = (int)cmd->comset.address;
720 		pd->baud_rate = (int)cmd->comset.baud_rate;
721 		LOG_INF("COMSET Succeeded! New PD-Addr: %d; Baud: %d",
722 			pd->address, pd->baud_rate);
723 		ret = OSDP_PD_ERR_NONE;
724 		break;
725 	case REPLY_NAK:
726 		if (!check_buf_len(REPLY_NAK_LEN, max_len)) {
727 			return OSDP_PD_ERR_GENERIC;
728 		}
729 		buf[len++] = pd->reply_id;
730 		buf[len++] = pd->ephemeral_data[0];
731 		ret = OSDP_PD_ERR_NONE;
732 		break;
733 #ifdef CONFIG_OSDP_SC_ENABLED
734 	case REPLY_CCRYPT:
735 		if (smb == NULL) {
736 			break;
737 		}
738 		if (!check_buf_len(REPLY_CCRYPT_LEN, max_len)) {
739 			return OSDP_PD_ERR_GENERIC;
740 		}
741 		osdp_fill_random(pd->sc.pd_random, 8);
742 		osdp_compute_session_keys(pd);
743 		osdp_compute_pd_cryptogram(pd);
744 		buf[len++] = pd->reply_id;
745 		memcpy(buf + len, pd->sc.pd_client_uid, 8);
746 		memcpy(buf + len + 8, pd->sc.pd_random, 8);
747 		memcpy(buf + len + 16, pd->sc.pd_cryptogram, 16);
748 		len += 32;
749 		smb[0] = 3;      /* length */
750 		smb[1] = SCS_12; /* type */
751 		smb[2] = ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD) ? 0 : 1;
752 		ret = OSDP_PD_ERR_NONE;
753 		break;
754 	case REPLY_RMAC_I:
755 		if (smb == NULL) {
756 			break;
757 		}
758 		if (!check_buf_len(REPLY_RMAC_I_LEN, max_len)) {
759 			return OSDP_PD_ERR_GENERIC;
760 		}
761 		osdp_compute_rmac_i(pd);
762 		buf[len++] = pd->reply_id;
763 		memcpy(buf + len, pd->sc.r_mac, 16);
764 		len += 16;
765 		smb[0] = 3;       /* length */
766 		smb[1] = SCS_14;  /* type */
767 		if (osdp_verify_cp_cryptogram(pd) == 0) {
768 			smb[2] = 1;  /* CP auth succeeded */
769 			sc_activate(pd);
770 			pd->sc_tstamp = osdp_millis_now();
771 			if (ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD)) {
772 				LOG_WRN("SC Active with SCBK-D");
773 			} else {
774 				LOG_INF("SC Active");
775 			}
776 		} else {
777 			smb[2] = 0;  /* CP auth failed */
778 			LOG_WRN("failed to verify CP_crypt");
779 		}
780 		ret = OSDP_PD_ERR_NONE;
781 		break;
782 #endif /* CONFIG_OSDP_SC_ENABLED */
783 	}
784 
785 #ifdef CONFIG_OSDP_SC_ENABLED
786 	if (smb && (smb[1] > SCS_14) && sc_is_active(pd)) {
787 		smb[0] = 2; /* length */
788 		smb[1] = (len > 1) ? SCS_18 : SCS_16;
789 	}
790 #endif /* CONFIG_OSDP_SC_ENABLED */
791 
792 	if (ret != 0) {
793 		/* catch all errors and report it as a RECORD error to CP */
794 		LOG_ERR("Failed to build REPLY(%02x); Sending NAK instead!",
795 			pd->reply_id);
796 		if (!check_buf_len(REPLY_NAK_LEN, max_len)) {
797 			return OSDP_PD_ERR_GENERIC;
798 		}
799 		buf[0] = REPLY_NAK;
800 		buf[1] = OSDP_PD_NAK_RECORD;
801 		len = 2;
802 	}
803 
804 	return len;
805 }
806 
pd_send_reply(struct osdp_pd * pd)807 static int pd_send_reply(struct osdp_pd *pd)
808 {
809 	int ret, len;
810 
811 	/* init packet buf with header */
812 	len = osdp_phy_packet_init(pd, pd->rx_buf, sizeof(pd->rx_buf));
813 	if (len < 0) {
814 		return OSDP_PD_ERR_GENERIC;
815 	}
816 
817 	/* fill reply data */
818 	ret = pd_build_reply(pd, pd->rx_buf, sizeof(pd->rx_buf));
819 	if (ret <= 0) {
820 		return OSDP_PD_ERR_GENERIC;
821 	}
822 	len += ret;
823 
824 	/* finalize packet */
825 	len = osdp_phy_packet_finalize(pd, pd->rx_buf, len, sizeof(pd->rx_buf));
826 	if (len < 0) {
827 		return OSDP_PD_ERR_GENERIC;
828 	}
829 
830 	/* flush rx to remove any invalid data. */
831 	if (pd->channel.flush) {
832 		pd->channel.flush(pd->channel.data);
833 	}
834 
835 	ret = pd->channel.send(pd->channel.data, pd->rx_buf, len);
836 	if (ret != len) {
837 		LOG_ERR("Channel send for %d bytes failed! ret: %d", len, ret);
838 		return OSDP_PD_ERR_GENERIC;
839 	}
840 
841 	if (IS_ENABLED(CONFIG_OSDP_PACKET_TRACE)) {
842 		if (pd->cmd_id != CMD_POLL) {
843 			osdp_dump("PD sent", pd->rx_buf, len);
844 		}
845 	}
846 
847 	return OSDP_PD_ERR_NONE;
848 }
849 
pd_decode_packet(struct osdp_pd * pd,int * one_pkt_len)850 static int pd_decode_packet(struct osdp_pd *pd, int *one_pkt_len)
851 {
852 	int err, len;
853 	uint8_t *buf;
854 
855 	err = osdp_phy_check_packet(pd, pd->rx_buf, pd->rx_buf_len, one_pkt_len);
856 
857 	/* Translate phy error codes to PD errors */
858 	switch (err) {
859 	case OSDP_ERR_PKT_NONE:
860 		break;
861 	case OSDP_ERR_PKT_NACK:
862 		return OSDP_PD_ERR_REPLY;
863 	case OSDP_ERR_PKT_WAIT:
864 		return OSDP_PD_ERR_NO_DATA;
865 	case OSDP_ERR_PKT_SKIP:
866 		return OSDP_PD_ERR_IGNORE;
867 	case OSDP_ERR_PKT_FMT:
868 		return OSDP_PD_ERR_GENERIC;
869 	default:
870 		return err; /* propagate other errors as-is */
871 	}
872 
873 	len = osdp_phy_decode_packet(pd, pd->rx_buf, *one_pkt_len, &buf);
874 	if (len <= 0) {
875 		if (len == OSDP_ERR_PKT_NACK) {
876 			return OSDP_PD_ERR_REPLY; /* Send a NAK */
877 		}
878 		return OSDP_PD_ERR_GENERIC; /* fatal errors */
879 	}
880 
881 	return pd_decode_command(pd, buf, len);
882 }
883 
pd_receive_and_process_command(struct osdp_pd * pd)884 static int pd_receive_and_process_command(struct osdp_pd *pd)
885 {
886 	uint8_t *buf;
887 	int len, err, remaining;
888 
889 	buf = pd->rx_buf + pd->rx_buf_len;
890 	remaining = sizeof(pd->rx_buf) - pd->rx_buf_len;
891 
892 	len = pd->channel.recv(pd->channel.data, buf, remaining);
893 	if (len <= 0) { /* No data received */
894 		return OSDP_PD_ERR_NO_DATA;
895 	}
896 
897 	/**
898 	 * We received some data on the bus; update pd->tstamp. A rouge CP can
899 	 * send one byte at a time to extend this command's window but that
900 	 * shouldn't cause any issues related to secure channel as it has it's
901 	 * own timestamp.
902 	 */
903 	pd->tstamp = osdp_millis_now();
904 	pd->rx_buf_len += len;
905 
906 	if (IS_ENABLED(CONFIG_OSDP_PACKET_TRACE)) {
907 		/**
908 		 * A crude way of identifying and not printing poll messages
909 		 * when CONFIG_OSDP_PACKET_TRACE is enabled. This is an early
910 		 * print to catch errors so keeping it simple.
911 		 */
912 		if (pd->rx_buf_len > 8 &&
913 		    pd->rx_buf[6] != CMD_POLL && pd->rx_buf[8] != CMD_POLL) {
914 			osdp_dump("PD received", pd->rx_buf, pd->rx_buf_len);
915 		}
916 	}
917 
918 	err = pd_decode_packet(pd, &len);
919 
920 	if (err == OSDP_PD_ERR_NO_DATA) {
921 		return err;
922 	}
923 
924 	/* We are done with the packet (error or not). Remove processed bytes */
925 	remaining = pd->rx_buf_len - len;
926 	if (remaining) {
927 		memmove(pd->rx_buf, pd->rx_buf + len, remaining);
928 	}
929 
930 	/**
931 	 * Store remaining length that needs to be processed.
932 	 * State machine will be updated accordingly.
933 	 */
934 	pd->rx_buf_len = remaining;
935 
936 	return err;
937 }
938 
pd_error_reset(struct osdp_pd * pd)939 static inline void pd_error_reset(struct osdp_pd *pd)
940 {
941 	sc_deactivate(pd);
942 	if (pd->channel.flush) {
943 		pd->channel.flush(pd->channel.data);
944 	}
945 	pd->rx_buf_len = 0;
946 }
947 
osdp_update(struct osdp * ctx)948 void osdp_update(struct osdp *ctx)
949 {
950 	int ret;
951 	struct osdp_pd *pd = osdp_to_pd(ctx, 0);
952 
953 #ifdef CONFIG_OSDP_SC_ENABLED
954 	/**
955 	 * If secure channel is established, we need to make sure that
956 	 * the session is valid before accepting a command.
957 	 */
958 	if (sc_is_active(pd) &&
959 	    osdp_millis_since(pd->sc_tstamp) > OSDP_PD_SC_TIMEOUT_MS) {
960 		LOG_INF("PD SC session timeout!");
961 		sc_deactivate(pd);
962 	}
963 #endif
964 
965 	ret = pd_receive_and_process_command(pd);
966 
967 	if (ret == OSDP_PD_ERR_IGNORE) {
968 		return;
969 	}
970 
971 	if (ret == OSDP_PD_ERR_NO_DATA) {
972 		if (pd->rx_buf_len == 0 ||
973 		    osdp_millis_since(pd->tstamp) < OSDP_RESP_TOUT_MS) {
974 			return;
975 		}
976 		LOG_DBG("rx_buf: %d", pd->rx_buf_len);
977 		osdp_dump("Buf", pd->rx_buf, pd->rx_buf_len);
978 	}
979 
980 	if (ret != OSDP_PD_ERR_NONE && ret != OSDP_PD_ERR_REPLY) {
981 		LOG_ERR("CMD receive error/timeout - err:%d", ret);
982 		pd_error_reset(pd);
983 		return;
984 	}
985 
986 #ifdef CONFIG_OSDP_SC_ENABLED
987 	if (ret == OSDP_PD_ERR_NONE && sc_is_active(pd)) {
988 		pd->sc_tstamp = osdp_millis_now();
989 	}
990 #endif
991 
992 	ret = pd_send_reply(pd);
993 	if (ret != OSDP_PD_ERR_NONE) {
994 		/**
995 		 * PD received and decoded a valid command from CP but failed to
996 		 * send the intended response?? This should not happen; but if
997 		 * it did, we cannot do anything about it, just complain about
998 		 * it and limp back home.
999 		 */
1000 		LOG_WRN("REPLY send failed! CP may be waiting..");
1001 		return;
1002 	}
1003 
1004 }
1005 
osdp_pd_set_attributes(struct osdp_pd * pd,struct osdp_pd_cap * cap,struct osdp_pd_id * id)1006 static void osdp_pd_set_attributes(struct osdp_pd *pd, struct osdp_pd_cap *cap,
1007 				   struct osdp_pd_id *id)
1008 {
1009 	int fc;
1010 
1011 	while (cap && ((fc = cap->function_code) > 0)) {
1012 		if (fc >= OSDP_PD_CAP_SENTINEL) {
1013 			break;
1014 		}
1015 		pd->cap[fc].function_code = cap->function_code;
1016 		pd->cap[fc].compliance_level = cap->compliance_level;
1017 		pd->cap[fc].num_items = cap->num_items;
1018 		cap++;
1019 	}
1020 	if (id != NULL) {
1021 		memcpy(&pd->id, id, sizeof(struct osdp_pd_id));
1022 	}
1023 }
1024 
osdp_setup(struct osdp * ctx,uint8_t * key)1025 int osdp_setup(struct osdp *ctx, uint8_t *key)
1026 {
1027 	ARG_UNUSED(key);
1028 	struct osdp_pd *pd;
1029 
1030 	if (NUM_PD(ctx) != 1) {
1031 		return -1;
1032 	}
1033 	pd = osdp_to_pd(ctx, 0);
1034 	osdp_pd_set_attributes(pd, osdp_pd_cap, &osdp_pd_id);
1035 	SET_FLAG(pd, PD_FLAG_PD_MODE);
1036 #ifdef CONFIG_OSDP_SC_ENABLED
1037 	if (key == NULL) {
1038 		LOG_WRN("SCBK not provided. PD is in INSTALL_MODE");
1039 		SET_FLAG(pd, PD_FLAG_INSTALL_MODE);
1040 	} else {
1041 		memcpy(pd->sc.scbk, key, 16);
1042 	}
1043 	SET_FLAG(pd, PD_FLAG_SC_CAPABLE);
1044 #endif
1045 	return 0;
1046 }
1047 
1048 /* --- Exported Methods --- */
1049 
osdp_pd_set_command_callback(pd_command_callback_t cb,void * arg)1050 void osdp_pd_set_command_callback(pd_command_callback_t cb, void *arg)
1051 {
1052 	struct osdp_pd *pd = osdp_to_pd(osdp_get_ctx(), 0);
1053 
1054 	pd->command_callback_arg = arg;
1055 	pd->command_callback = cb;
1056 }
1057 
osdp_pd_notify_event(const struct osdp_event * event)1058 int osdp_pd_notify_event(const struct osdp_event *event)
1059 {
1060 	struct osdp_event *ev;
1061 	struct osdp_pd *pd = osdp_to_pd(osdp_get_ctx(), 0);
1062 
1063 	ev = pd_event_alloc(pd);
1064 	if (ev == NULL) {
1065 		return -1;
1066 	}
1067 
1068 	memcpy(ev, event, sizeof(struct osdp_event));
1069 	pd_event_enqueue(pd, ev);
1070 	return 0;
1071 }
1072