1 /*
2  * Copyright (c) 2025 Linumiz GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "ocpp_i.h"
8 #include "ocpp_j.h"
9 #include <zephyr/data/json.h>
10 #include <zephyr/random/random.h>
11 
extract_string_field(char * out_buf,int outlen,char * token)12 static int extract_string_field(char *out_buf, int outlen, char *token)
13 {
14 	char *end;
15 
16 	if (out_buf == NULL || token == NULL) {
17 		return -EINVAL;
18 	}
19 
20 	strncpy(out_buf, token + 1, outlen - 1);
21 	end = strchr(out_buf, '"');
22 	if (end != NULL) {
23 		*end = '\0';
24 	}
25 
26 	return 0;
27 }
28 
extract_payload(char * msg,int msglen)29 static int extract_payload(char *msg, int msglen)
30 {
31 	size_t len;
32 	char *start = strchr(msg, '{');
33 	char *end = strrchr(msg, '}');
34 
35 	if (start == NULL || end == NULL || end < start) {
36 		return -EINVAL;
37 	}
38 
39 	len = end - start + 1;
40 	if (len >= msglen) {
41 		return -ENOMEM;
42 	}
43 
44 	memmove(msg, start, len);
45 	msg[len] = '\0';
46 
47 	return 0;
48 }
49 
frame_rpc_call_req(char * rpcbuf,int len,int pdu,uint32_t ses,char * pdumsg)50 static int frame_rpc_call_req(char *rpcbuf, int len, int pdu,
51 			      uint32_t ses, char *pdumsg)
52 {
53 	int ret;
54 	char uid[JSON_MSG_BUF_128];
55 	const char *action;
56 	uint32_t rnd = sys_rand32_get();
57 
58 	snprintk(uid, sizeof(uid), "%u-%d-%u", ses, pdu, rnd);
59 
60 	action = ocpp_get_pdu_literal(pdu);
61 	if (action == NULL) {
62 		return -EINVAL;
63 	}
64 
65 	/* Encode OCPP Call Request msg: [2,"<UID>","<Action>",<Payload>] */
66 	ret = snprintk(rpcbuf, len,
67 		       "[2,\"%s\",\"%s\",%s]",
68 		       uid, action, pdumsg);
69 
70 	if (ret < 0 || ret >= len) {
71 		return -ENOMEM;
72 	}
73 
74 	return 0;
75 }
76 
frame_rpc_call_res(char * rpcbuf,int len,char * uid,char * pdumsg)77 static int frame_rpc_call_res(char *rpcbuf, int len,
78 			      char *uid, char *pdumsg)
79 {
80 	int ret;
81 
82 	/* Encode OCPP Call Result msg: [3,"<UID>",<Payload>] */
83 	ret = snprintk(rpcbuf, len, "[3,\"%s\",%s]", uid, pdumsg);
84 
85 	if (ret < 0 || ret >= len) {
86 		return -ENOMEM;
87 	}
88 
89 	return 0;
90 }
91 
frame_authorize_msg(char * buf,int len,struct ocpp_session * ses)92 static int frame_authorize_msg(char *buf, int len,
93 			       struct ocpp_session *ses)
94 {
95 	int ret;
96 	char auth_obj[JSON_MSG_BUF_128];
97 
98 	struct json_obj_descr authorize_descr[] = {
99 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "idTag",
100 					  val1, JSON_TOK_STRING),
101 	};
102 
103 	struct json_common_payload_field_str payload = {
104 		.val1 = ses->idtag,
105 	};
106 
107 	ret = json_obj_encode_buf(authorize_descr,
108 				  ARRAY_SIZE(authorize_descr),
109 				  &payload,
110 				  auth_obj,
111 				  sizeof(auth_obj));
112 	if (ret < 0) {
113 		return ret;
114 	}
115 
116 	ret = frame_rpc_call_req(buf, len, PDU_AUTHORIZE,
117 				 (uintptr_t)ses, auth_obj);
118 	if (ret < 0) {
119 		return ret;
120 	}
121 
122 	return 0;
123 }
124 
frame_heartbeat_msg(char * buf,int len,struct ocpp_session * ses)125 static int frame_heartbeat_msg(char *buf, int len, struct ocpp_session *ses)
126 {
127 	int ret;
128 	char tmp_buf[8] = "{}";
129 
130 	ret = frame_rpc_call_req(buf, len, PDU_HEARTBEAT,
131 				 (uintptr_t)ses, tmp_buf);
132 	if (ret < 0) {
133 		return ret;
134 	}
135 
136 	return 0;
137 }
138 
frame_bootnotif_msg(char * buf,int len,struct ocpp_session * ses,struct ocpp_cp_info * cpi)139 static int frame_bootnotif_msg(char *buf, int len,
140 			       struct ocpp_session *ses,
141 			       struct ocpp_cp_info *cpi)
142 {
143 	int ret;
144 	uint8_t descr_count = BOOTNOTIF_MIN_FIELDS;
145 	char tmp_buf[JSON_MSG_BUF_512];
146 
147 	struct json_ocpp_bootnotif_msg msg = {
148 		.charge_point_model = cpi->model,
149 		.charge_point_vendor = cpi->vendor,
150 		.charge_box_serial_number = cpi->box_sl_no ? cpi->box_sl_no : NULL,
151 		.charge_point_serial_number = cpi->sl_no ? cpi->sl_no : NULL,
152 		.firmware_version = cpi->fw_ver ? cpi->fw_ver : NULL,
153 		.iccid = cpi->iccid ? cpi->iccid : NULL,
154 		.imsi = cpi->imsi ? cpi->imsi : NULL,
155 		.meter_serial_number = cpi->meter_sl_no ? cpi->meter_sl_no : NULL,
156 		.meter_type = cpi->meter_type ? cpi->meter_type : NULL,
157 	};
158 
159 	struct json_obj_descr bootnotif_descr[BOOTNOTIF_MAX_FIELDS] = {
160 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointModel",
161 					  charge_point_model, JSON_TOK_STRING),
162 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointVendor",
163 					  charge_point_vendor, JSON_TOK_STRING),
164 		};
165 
166 	if (msg.charge_box_serial_number != NULL) {
167 		bootnotif_descr[descr_count++] = (struct json_obj_descr)
168 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargeBoxSerialNumber",
169 					  charge_box_serial_number, JSON_TOK_STRING);
170 	}
171 
172 	if (msg.charge_point_serial_number != NULL) {
173 		bootnotif_descr[descr_count++] = (struct json_obj_descr)
174 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "chargePointSerialNumber",
175 					  charge_point_serial_number, JSON_TOK_STRING);
176 	}
177 
178 	if (msg.firmware_version != NULL) {
179 		bootnotif_descr[descr_count++] = (struct json_obj_descr)
180 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "firmwareVersion",
181 					  firmware_version, JSON_TOK_STRING);
182 	}
183 
184 	if (msg.iccid != NULL) {
185 		bootnotif_descr[descr_count++] = (struct json_obj_descr)
186 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "iccid",
187 					  iccid, JSON_TOK_STRING);
188 	}
189 
190 	if (msg.imsi != NULL) {
191 		bootnotif_descr[descr_count++] = (struct json_obj_descr)
192 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "imsi",
193 					  imsi, JSON_TOK_STRING);
194 	}
195 
196 	if (msg.meter_serial_number != NULL) {
197 		bootnotif_descr[descr_count++] = (struct json_obj_descr)
198 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "meterSerialNumber",
199 					  meter_serial_number, JSON_TOK_STRING);
200 	}
201 
202 	if (msg.meter_type != NULL) {
203 		bootnotif_descr[descr_count++] = (struct json_obj_descr)
204 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_bootnotif_msg, "meterType",
205 					  meter_type, JSON_TOK_STRING);
206 	}
207 
208 	ret = json_obj_encode_buf(bootnotif_descr, descr_count,
209 				  &msg, tmp_buf, sizeof(tmp_buf));
210 	if (ret < 0) {
211 		return ret;
212 	}
213 
214 	ret = frame_rpc_call_req(buf, len, PDU_BOOTNOTIFICATION,
215 				 (uintptr_t)ses, tmp_buf);
216 	if (ret < 0) {
217 		return ret;
218 	}
219 
220 	return 0;
221 }
222 
frame_meter_val_msg(char * buf,int len,struct ocpp_session * ses,char * timestamp,char * val,char * measurand,char * unit)223 static int frame_meter_val_msg(char *buf, int len, struct ocpp_session *ses, char *timestamp,
224 			       char *val, char *measurand, char *unit)
225 {
226 	int ret;
227 	char tmp_buf[JSON_MSG_BUF_512];
228 	uint8_t descr_count = SAMPLED_VALUE_MIN_FIELDS;
229 
230 	struct json_ocpp_meter_val_msg msg = {
231 		.connector_id = ses ? ses->idcon : 0,
232 		.transaction_id = ses ? ses->idtxn : 0,
233 		.meter_value = {{
234 			.timestamp = timestamp,
235 			.sampled_value = {{
236 				.measurand = measurand,
237 				.value = val,
238 				.unit = unit ? unit : NULL,
239 			}},
240 			.sampled_value_len = 1,
241 		}},
242 		.meter_value_len = 1,
243 	};
244 
245 	struct json_obj_descr sampled_value_descr[SAMPLED_VALUE_MAX_FIELDS] = {
246 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "measurand",
247 					  measurand, JSON_TOK_STRING),
248 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "value",
249 					  value, JSON_TOK_STRING),
250 	};
251 
252 	if (msg.meter_value[0].sampled_value[0].unit != NULL) {
253 		sampled_value_descr[descr_count++] = (struct json_obj_descr)
254 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_sample_val, "unit",
255 					  unit, JSON_TOK_STRING);
256 	}
257 
258 	struct json_obj_descr meter_value_descr[] = {
259 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val, "timestamp",
260 					  timestamp, JSON_TOK_STRING),
261 		JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_meter_val, "sampledValue",
262 					       sampled_value, 1, sampled_value_len,
263 					       sampled_value_descr,
264 					       descr_count),
265 	};
266 
267 	struct json_obj_descr meter_val_msg_descr[] = {
268 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val_msg, "connectorId",
269 					  connector_id, JSON_TOK_NUMBER),
270 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_meter_val_msg, "transactionId",
271 					  transaction_id, JSON_TOK_NUMBER),
272 		JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_meter_val_msg, "meterValue",
273 					       meter_value, 1, meter_value_len,
274 					       meter_value_descr,
275 					       ARRAY_SIZE(meter_value_descr)),
276 	};
277 
278 	ret = json_obj_encode_buf(meter_val_msg_descr,
279 				  ARRAY_SIZE(meter_val_msg_descr),
280 				  &msg, tmp_buf, sizeof(tmp_buf));
281 	if (ret < 0) {
282 		return ret;
283 	}
284 
285 	ret = frame_rpc_call_req(buf, len, PDU_METER_VALUES,
286 				 (uintptr_t)ses, tmp_buf);
287 	if (ret < 0) {
288 		return ret;
289 	}
290 
291 	return 0;
292 }
293 
frame_stop_txn_msg(char * buf,int len,struct ocpp_session * ses,int Wh,char * reason,char * timestamp)294 static int frame_stop_txn_msg(char *buf, int len, struct ocpp_session *ses,
295 			      int Wh, char *reason, char *timestamp)
296 {
297 	int ret;
298 	char tmp_buf[JSON_MSG_BUF_256];
299 	uint8_t descr_count = STOP_TXN_MIN_FIELDS;
300 
301 	struct json_ocpp_stop_txn_msg msg = {
302 		.transaction_id = ses->idtxn,
303 		.meter_stop = Wh,
304 		.timestamp = timestamp,
305 		.reason = reason ? reason : NULL,
306 		.id_tag = ses->idtag[0] ? ses->idtag : NULL,
307 	};
308 
309 	struct json_obj_descr descr[STOP_TXN_MAX_FIELDS] = {
310 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "transactionId",
311 					  transaction_id, JSON_TOK_NUMBER),
312 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "meterStop",
313 					  meter_stop, JSON_TOK_NUMBER),
314 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "timestamp",
315 					  timestamp, JSON_TOK_STRING),
316 	};
317 
318 	if (msg.reason != NULL) {
319 		descr[descr_count++] = (struct json_obj_descr)
320 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "reason",
321 					  reason, JSON_TOK_STRING);
322 	}
323 
324 	if (msg.id_tag != NULL) {
325 		descr[descr_count++] = (struct json_obj_descr)
326 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_stop_txn_msg, "idTag",
327 					  id_tag, JSON_TOK_STRING);
328 	}
329 
330 	ret = json_obj_encode_buf(descr, descr_count, &msg,
331 				  tmp_buf, sizeof(tmp_buf));
332 	if (ret < 0) {
333 		return ret;
334 	}
335 
336 	ret = frame_rpc_call_req(buf, len, PDU_STOP_TRANSACTION,
337 				 (uintptr_t)ses, tmp_buf);
338 	if (ret < 0) {
339 		return ret;
340 	}
341 
342 	return 0;
343 }
344 
frame_start_txn_msg(char * buf,int len,struct ocpp_session * ses,int Wh,int reserv_id,char * timestamp)345 static int frame_start_txn_msg(char *buf, int len, struct ocpp_session *ses,
346 			       int Wh, int reserv_id, char *timestamp)
347 {
348 	int ret;
349 	char tmp_buf[JSON_MSG_BUF_256];
350 	uint8_t descr_count = START_TXN_MIN_FIELDS;
351 
352 	struct json_ocpp_start_txn_msg msg = {
353 		.connector_id = ses->idcon,
354 		.id_tag = ses->idtag,
355 		.meter_start = Wh,
356 		.timestamp = timestamp,
357 		.reservation_id = (reserv_id >= 0) ? reserv_id : -1,
358 	};
359 
360 	struct json_obj_descr descr[START_TXN_MAX_FIELDS] = {
361 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "connectorId",
362 					  connector_id, JSON_TOK_NUMBER),
363 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "idTag",
364 					  id_tag, JSON_TOK_STRING),
365 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "meterStart",
366 					  meter_start, JSON_TOK_NUMBER),
367 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "timestamp",
368 					  timestamp, JSON_TOK_STRING),
369 	};
370 
371 	if (msg.reservation_id != -1) {
372 		descr[descr_count++] = (struct json_obj_descr)
373 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_start_txn_msg, "reservationId",
374 					  reservation_id, JSON_TOK_NUMBER);
375 	}
376 
377 	ret = json_obj_encode_buf(descr, descr_count, &msg,
378 				  tmp_buf, sizeof(tmp_buf));
379 	if (ret < 0) {
380 		return ret;
381 	}
382 
383 	ret = frame_rpc_call_req(buf, len, PDU_START_TRANSACTION,
384 				 (uintptr_t)ses, tmp_buf);
385 	if (ret < 0) {
386 		return ret;
387 	}
388 
389 	return 0;
390 }
391 
frame_getconfig_msg(char * buf,int len,char * key,char * val,bool is_rw,char * uid)392 static int frame_getconfig_msg(char *buf, int len, char *key, char *val,
393 			       bool is_rw, char *uid)
394 {
395 	int ret;
396 	char tmp_buf[JSON_MSG_BUF_128];
397 
398 	struct json_ocpp_getconfig_msg msg = { 0 };
399 
400 	if (val != NULL) {
401 		msg.configuration_key[0].key = key;
402 		msg.configuration_key[0].readonly = !is_rw;
403 		msg.configuration_key[0].value = val;
404 		msg.configuration_key_len = 1;
405 	} else {
406 		msg.unknown_key = key;
407 	}
408 
409 	struct json_obj_descr keyval_descr[] = {
410 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "key",
411 					  key, JSON_TOK_STRING),
412 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "readonly",
413 					  readonly, JSON_TOK_NUMBER),
414 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_key_val, "value",
415 					  value, JSON_TOK_STRING),
416 	};
417 
418 	struct json_obj_descr config_descr[GET_CFG_MAX_FIELDS] = {
419 		JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct json_ocpp_getconfig_msg, "configurationKey",
420 					       configuration_key, 1, configuration_key_len,
421 					       keyval_descr, ARRAY_SIZE(keyval_descr))
422 	};
423 
424 	if (val == NULL) {
425 		config_descr[0] = (struct json_obj_descr)
426 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_ocpp_getconfig_msg, "unknownKey",
427 					  unknown_key, JSON_TOK_STRING);
428 	}
429 
430 	ret = json_obj_encode_buf(config_descr, GET_CFG_MAX_FIELDS, &msg,
431 				  tmp_buf, sizeof(tmp_buf));
432 	if (ret < 0) {
433 		return ret;
434 	}
435 
436 	ret = frame_rpc_call_res(buf, len, uid, tmp_buf);
437 	if (ret < 0) {
438 		return ret;
439 	}
440 
441 	return 0;
442 }
443 
frame_status_resp_msg(char * buf,int len,char * res,char * uid)444 static int frame_status_resp_msg(char *buf, int len, char *res, char *uid)
445 {
446 	int ret;
447 	char tmp_buf[JSON_MSG_BUF_128];
448 
449 	struct json_obj_descr descr[] = {
450 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "status",
451 					  val1, JSON_TOK_STRING),
452 	};
453 
454 	struct json_common_payload_field_str msg = {
455 		.val1 = res,
456 	};
457 
458 	ret = json_obj_encode_buf(descr, ARRAY_SIZE(descr), &msg,
459 				  tmp_buf, sizeof(tmp_buf));
460 	if (ret < 0) {
461 		return ret;
462 	}
463 
464 	ret = frame_rpc_call_res(buf, len, uid, tmp_buf);
465 	if (ret < 0) {
466 		return ret;
467 	}
468 
469 	return 0;
470 }
471 
472 /* parse msg from server */
parse_rpc_msg(char * msg,int msglen,char * uid,int uidlen,int * pdu,bool * is_rsp)473 int parse_rpc_msg(char *msg, int msglen, char *uid, int uidlen,
474 		  int *pdu, bool *is_rsp)
475 {
476 	int ret;
477 	char local_buf[JSON_MSG_BUF_512];
478 	char action[JSON_MSG_BUF_128];
479 	char *token;
480 	char *saveptr = NULL;
481 	int rpc_id = -1;
482 
483 	if (msg == NULL || uid == NULL || pdu == NULL || is_rsp == NULL) {
484 		return -EINVAL;
485 	}
486 
487 	memcpy(local_buf, msg + 1, sizeof(local_buf) - 1);
488 	local_buf[sizeof(local_buf) - 1] = '\0';
489 
490 	token = strtok_r(local_buf, ",", &saveptr);
491 	if (token == NULL) {
492 		return -EINVAL;
493 	}
494 
495 	rpc_id = *token - '0';
496 
497 	token = strtok_r(NULL, ",", &saveptr);
498 	if (token == NULL) {
499 		return -EINVAL;
500 	}
501 
502 	ret = extract_string_field(uid, uidlen, token);
503 	if (ret < 0) {
504 		return ret;
505 	}
506 
507 	switch (rpc_id + '0') {
508 	case OCPP_WAMP_RPC_REQ:
509 		token = strtok_r(NULL, ",", &saveptr);
510 		if (token == NULL) {
511 			return -EINVAL;
512 		}
513 
514 		ret = extract_string_field(action, sizeof(action), token);
515 		if (ret < 0) {
516 			return ret;
517 		}
518 		*pdu = ocpp_find_pdu_from_literal(action);
519 		__fallthrough;
520 
521 	case OCPP_WAMP_RPC_RESP:
522 		*is_rsp = rpc_id - 2;
523 		ret = extract_payload(msg, msglen);
524 		if (ret < 0) {
525 			return ret;
526 		}
527 		break;
528 
529 	case OCPP_WAMP_RPC_ERR:
530 		__fallthrough;
531 
532 	default:
533 		return -EINVAL;
534 	}
535 
536 	return 0;
537 }
538 
parse_idtag_info(char * json,struct ocpp_idtag_info * idtag_info)539 static int parse_idtag_info(char *json, struct ocpp_idtag_info *idtag_info)
540 {
541 	int ret;
542 	char *status;
543 
544 	struct json_obj_descr inner_descr[] = {
545 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "status",
546 					  json_id_tag_info.status, JSON_TOK_STRING),
547 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "parentIdTag",
548 					  json_id_tag_info.parent_id_tag, JSON_TOK_STRING),
549 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_idtag_info_root, "expiryDate",
550 					  json_id_tag_info.expiry_date, JSON_TOK_STRING),
551 	};
552 
553 	struct json_obj_descr root_descr[] = {
554 		JSON_OBJ_DESCR_OBJECT_NAMED(struct json_idtag_info_root, "idTagInfo",
555 					    json_id_tag_info, inner_descr),
556 	};
557 
558 	struct json_idtag_info_root parsed = { 0 };
559 
560 	ret = json_obj_parse(json, strlen(json), root_descr,
561 			     ARRAY_SIZE(root_descr), &parsed);
562 	if (ret < 0) {
563 		return ret;
564 	}
565 
566 	status = parsed.json_id_tag_info.status;
567 	if (status == 0) {
568 		return -EINVAL;
569 	}
570 
571 	switch (*status) {
572 	case 'A':
573 		idtag_info->auth_status = OCPP_AUTH_ACCEPTED;
574 		break;
575 	case 'B':
576 		idtag_info->auth_status = OCPP_AUTH_BLOCKED;
577 		break;
578 	case 'E':
579 		idtag_info->auth_status = OCPP_AUTH_EXPIRED;
580 		break;
581 	case 'I':
582 		idtag_info->auth_status = OCPP_AUTH_INVALID;
583 		break;
584 	case 'C':
585 		idtag_info->auth_status = OCPP_AUTH_CONCURRENT_TX;
586 		break;
587 	default:
588 		return -EINVAL;
589 	}
590 
591 	if (parsed.json_id_tag_info.parent_id_tag != NULL) {
592 		strncpy(idtag_info->p_idtag, parsed.json_id_tag_info.parent_id_tag,
593 			sizeof(idtag_info->p_idtag));
594 	}
595 
596 	if (parsed.json_id_tag_info.expiry_date != NULL) {
597 		strncpy(idtag_info->exptime, parsed.json_id_tag_info.expiry_date,
598 			sizeof(idtag_info->exptime));
599 	}
600 
601 	return 0;
602 }
603 
parse_heartbeat_msg(char * json,struct timeval * date)604 static int parse_heartbeat_msg(char *json, struct timeval *date)
605 {
606 	int ret;
607 
608 	struct json_obj_descr descr[] = {
609 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "currentTime",
610 					  val1, JSON_TOK_STRING),
611 	};
612 
613 	struct json_common_payload_field_str heartbeat = {0};
614 
615 	ret = json_obj_parse(json, strlen(json), descr,
616 			     ARRAY_SIZE(descr), &heartbeat);
617 
618 	/* todo: convert civil time to epoch and update local time */
619 
620 	if (ret < 0) {
621 		return ret;
622 	}
623 
624 	return 0;
625 }
626 
parse_authorize_msg(char * json,struct ocpp_idtag_info * idtag_info)627 static int parse_authorize_msg(char *json, struct ocpp_idtag_info *idtag_info)
628 {
629 	int ret;
630 
631 	ret = parse_idtag_info(json, idtag_info);
632 	if (ret < 0) {
633 		return ret;
634 	}
635 
636 	return 0;
637 }
638 
parse_bootnotification_msg(char * json,struct boot_notif * binfo)639 static int parse_bootnotification_msg(char *json, struct boot_notif *binfo)
640 {
641 	int ret;
642 
643 	struct json_obj_descr descr[] = {
644 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "status",
645 					  status, JSON_TOK_STRING),
646 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "interval",
647 					  interval, JSON_TOK_NUMBER),
648 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_bootnotif_payload, "currentTime",
649 					  current_time, JSON_TOK_STRING),
650 	};
651 
652 	struct json_bootnotif_payload msg = { 0 };
653 
654 	ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &msg);
655 	if (ret < 0) {
656 		return ret;
657 	}
658 
659 	if (msg.status == NULL) {
660 		return -EINVAL;
661 	}
662 
663 	switch (*msg.status) {
664 	case 'A':	/* accepted */
665 		binfo->status = BOOT_ACCEPTED;
666 		break;
667 	case 'P':	/* pending */
668 		binfo->status = BOOT_PENDING;
669 		break;
670 	case 'R':	/* rejected */
671 		binfo->status = BOOT_REJECTED;
672 		break;
673 	default:
674 		return -EINVAL;
675 	}
676 
677 	if (msg.interval == 0) {
678 		return -EINVAL;
679 	}
680 
681 	binfo->interval = msg.interval;
682 
683 	if (msg.current_time == NULL) {
684 		return -EINVAL;
685 	}
686 
687 	/* todo: convert civil time to epoch and update local time */
688 	(void)binfo->date;
689 
690 	return 0;
691 }
692 
parse_start_txn_msg(char * json,int * idtxn,struct ocpp_idtag_info * idtag_info)693 static int parse_start_txn_msg(char *json,
694 			       int *idtxn,
695 			       struct ocpp_idtag_info *idtag_info)
696 {
697 	int ret;
698 
699 	struct json_obj_descr descr[] = {
700 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "transactionId",
701 					  val1, JSON_TOK_NUMBER),
702 	};
703 
704 	struct json_common_payload_field payload = { 0 };
705 
706 	ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
707 	if (ret < 0) {
708 		return ret;
709 	}
710 
711 	*idtxn = payload.val1;
712 
713 	ret = parse_idtag_info(json, idtag_info);
714 	if (ret < 0) {
715 		return ret;
716 	}
717 
718 	return 0;
719 }
720 
parse_getconfig_msg(char * json,char * key)721 static int parse_getconfig_msg(char *json, char *key)
722 {
723 	int ret;
724 
725 	struct json_obj_descr descr[] = {
726 		JSON_OBJ_DESCR_ARRAY_NAMED(struct json_getconfig_payload, "key",
727 					   key, 1, key_len, JSON_TOK_STRING),
728 	};
729 
730 	struct json_getconfig_payload payload = { 0 };
731 
732 	ret = json_obj_parse(json, strlen(json), descr,
733 			     ARRAY_SIZE(descr), &payload);
734 	if (ret < 0) {
735 		return ret;
736 	}
737 
738 	/* key is optional so return success*/
739 	if (payload.key[0] != NULL) {
740 		strcpy(key, payload.key[0]);
741 	}
742 
743 	return 0;
744 }
745 
parse_changeconfig_msg(char * json,char * key,char * val)746 static int parse_changeconfig_msg(char *json, char *key, char *val)
747 {
748 	int ret;
749 
750 	struct json_obj_descr descr[] = {
751 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "key",
752 					  val1, JSON_TOK_STRING),
753 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field_str, "value",
754 					  val2, JSON_TOK_STRING),
755 	};
756 
757 	struct json_common_payload_field_str payload = { 0 };
758 
759 	ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
760 	if (ret < 0) {
761 		return ret;
762 	}
763 
764 	if (payload.val1 == NULL || payload.val2 == NULL) {
765 		return -EINVAL;
766 	}
767 
768 	strncpy(key, payload.val1, CISTR50);
769 	strncpy(val, payload.val2, CISTR500);
770 
771 	return 0;
772 }
773 
parse_remote_start_txn_msg(char * json,int * idcon,char * idtag)774 static int parse_remote_start_txn_msg(char *json,
775 				      int *idcon,
776 				      char *idtag)
777 {
778 	int ret;
779 
780 	struct json_obj_descr descr[] = {
781 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "connectorId",
782 					  val1, JSON_TOK_NUMBER),
783 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "idTag",
784 					  val2, JSON_TOK_STRING),
785 	};
786 
787 	struct json_common_payload_field payload = { 0 };
788 
789 	ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
790 	if (ret < 0) {
791 		return ret;
792 	}
793 
794 	if (payload.val2 == NULL) {
795 		return -EINVAL;
796 	}
797 
798 	strncpy(idtag, payload.val2, CISTR50);
799 	*idcon = payload.val1;
800 
801 	return 0;
802 }
803 
parse_remote_stop_txn_msg(char * json,int * idtxn)804 static int parse_remote_stop_txn_msg(char *json, int *idtxn)
805 {
806 	int ret;
807 
808 	struct json_obj_descr descr[] = {
809 		JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "transactionId",
810 					  val1, JSON_TOK_NUMBER),
811 	};
812 
813 	struct json_common_payload_field payload = { 0 };
814 
815 	ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
816 	if (ret < 0) {
817 		return ret;
818 	}
819 
820 	*idtxn = payload.val1;
821 
822 	return 0;
823 }
824 
parse_unlock_connectormsg(char * json,int * idcon)825 static int parse_unlock_connectormsg(char *json, int *idcon)
826 {
827 	int ret;
828 
829 	struct json_obj_descr descr[] = {
830 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_common_payload_field, "connectorId",
831 				  val1, JSON_TOK_NUMBER),
832 	};
833 
834 	struct json_common_payload_field payload = { 0 };
835 
836 	ret = json_obj_parse(json, strlen(json), descr, ARRAY_SIZE(descr), &payload);
837 	if (ret < 0) {
838 		return ret;
839 	}
840 
841 	if (payload.val1 == 0) {
842 		return -EINVAL;
843 	}
844 
845 	*idcon = payload.val1;
846 
847 	return 0;
848 }
849 
850 static ocpp_msg_fp_t ocpp_json_parser[PDU_MSG_END] = {
851 	[PDU_BOOTNOTIFICATION]	= (ocpp_msg_fp_t)parse_bootnotification_msg,
852 	[PDU_AUTHORIZE]		= (ocpp_msg_fp_t)parse_authorize_msg,
853 	[PDU_START_TRANSACTION]	= (ocpp_msg_fp_t)parse_start_txn_msg,
854 	[PDU_STOP_TRANSACTION]	= (ocpp_msg_fp_t)parse_authorize_msg,
855 	[PDU_METER_VALUES]	= NULL,
856 	[PDU_HEARTBEAT]		= (ocpp_msg_fp_t)parse_heartbeat_msg,
857 	[PDU_GET_CONFIGURATION]	= (ocpp_msg_fp_t)parse_getconfig_msg,
858 	[PDU_CHANGE_CONFIGURATION]	= (ocpp_msg_fp_t)parse_changeconfig_msg,
859 	[PDU_REMOTE_START_TRANSACTION]	= (ocpp_msg_fp_t)parse_remote_start_txn_msg,
860 	[PDU_REMOTE_STOP_TRANSACTION]	= (ocpp_msg_fp_t)parse_remote_stop_txn_msg,
861 	[PDU_UNLOCK_CONNECTOR]	= (ocpp_msg_fp_t)parse_unlock_connectormsg,
862 };
863 
864 static ocpp_msg_fp_t ocpp_json_frame[PDU_MSG_END] = {
865 	[PDU_BOOTNOTIFICATION]	=  (ocpp_msg_fp_t)frame_bootnotif_msg,
866 	[PDU_AUTHORIZE]		=  (ocpp_msg_fp_t)frame_authorize_msg,
867 	[PDU_START_TRANSACTION]	=  (ocpp_msg_fp_t)frame_start_txn_msg,
868 	[PDU_STOP_TRANSACTION]	=  (ocpp_msg_fp_t)frame_stop_txn_msg,
869 	[PDU_METER_VALUES]	=  (ocpp_msg_fp_t)frame_meter_val_msg,
870 	[PDU_HEARTBEAT]		=  (ocpp_msg_fp_t)frame_heartbeat_msg,
871 	[PDU_GET_CONFIGURATION]	=  (ocpp_msg_fp_t)frame_getconfig_msg,
872 	[PDU_CHANGE_CONFIGURATION] (ocpp_msg_fp_t)frame_status_resp_msg,
873 	[PDU_REMOTE_START_TRANSACTION]	= (ocpp_msg_fp_t)frame_status_resp_msg,
874 	[PDU_REMOTE_STOP_TRANSACTION]	= (ocpp_msg_fp_t)frame_status_resp_msg,
875 	[PDU_UNLOCK_CONNECTOR]	= (ocpp_msg_fp_t)frame_status_resp_msg,
876 };
877 
ocpp_parser_init(ocpp_msg_fp_t ** cfn,ocpp_msg_fp_t ** pfn)878 void ocpp_parser_init(ocpp_msg_fp_t **cfn, ocpp_msg_fp_t **pfn)
879 {
880 	*pfn = ocpp_json_parser;
881 	*cfn = ocpp_json_frame;
882 }
883