| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <atomic.h> |
| |
| #define BT_DBG_ENABLED IS_ENABLED(CONFIG_NBLE_DEBUG_RPC) |
| #include <bluetooth/log.h> |
| #include <bluetooth/gatt.h> |
| /* for bt_security_t */ |
| #include <bluetooth/conn.h> |
| |
| #ifdef CONFIG_PRINTK |
| #include <misc/printk.h> |
| #define PRINTK(...) printk(__VA_ARGS__) |
| #else |
| #define PRINTK(...) |
| #endif /* CONFIG_PRINTK */ |
| |
| #include "rpc.h" |
| #include "gap_internal.h" |
| #include "gatt_internal.h" |
| |
| #include "rpc_functions_to_quark.h" |
| |
| /* Build the list of prototypes and check that list are made only of matching |
| * signatures |
| */ |
| #define FN_SIG_NONE(__fn) void __fn(void); |
| LIST_FN_SIG_NONE |
| #undef FN_SIG_NONE |
| |
| #define FN_SIG_S(__fn, __s) void __fn(__s p_s); |
| LIST_FN_SIG_S |
| #undef FN_SIG_S |
| |
| #define FN_SIG_P(__fn, __type) void __fn(__type priv); |
| LIST_FN_SIG_P |
| #undef FN_SIG_P |
| |
| #define FN_SIG_S_B(__fn, __s, __type, __length) \ |
| void __fn(__s p_s, __type buf, __length length); |
| LIST_FN_SIG_S_B |
| #undef FN_SIG_S_B |
| |
| #define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, \ |
| __type3) \ |
| void __fn(__type1 p_buf1, __length1 length1, __type2 p_buf2, \ |
| __length2 length2, __type3 priv); |
| LIST_FN_SIG_B_B_P |
| #undef FN_SIG_B_B_P |
| |
| #define FN_SIG_S_P(__fn, __s, __type) void __fn(__s p_s, __type priv); |
| LIST_FN_SIG_S_P |
| #undef FN_SIG_S_P |
| |
| #define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \ |
| void __fn(__s p_s, __type buf, __length length, __type_ptr priv); |
| LIST_FN_SIG_S_B_P |
| #undef FN_SIG_S_B_P |
| |
| #define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, \ |
| __length2, __type_ptr) \ |
| void __fn(__s p_s, __type1 p_buf1, __length1 length1, \ |
| __type2 p_buf2, __length2 length2, __type_ptr priv); |
| LIST_FN_SIG_S_B_B_P |
| #undef FN_SIG_S_B_B_P |
| |
| /* 1 - define the size check arrays */ |
| #define FN_SIG_NONE(__fn) |
| |
| #define FN_SIG_S(__fn, __s) sizeof(*((__s)0)), |
| |
| #define FN_SIG_P(__fn, __type) |
| |
| #define FN_SIG_S_B(__fn, __s, __type, __length) sizeof(*((__s)0)), |
| |
| #define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, \ |
| __type3) sizeof(*((__s)0)), |
| |
| #define FN_SIG_S_P(__fn, __s, __type) sizeof(*((__s)0)), |
| |
| #define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \ |
| sizeof(*((__s)0)), |
| |
| #define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, \ |
| __length2, __type3) sizeof(*((__s)0)), |
| |
| static uint8_t m_size_s[] = { LIST_FN_SIG_S }; |
| static uint8_t m_size_s_b[] = { LIST_FN_SIG_S_B }; |
| static uint8_t m_size_s_p[] = { LIST_FN_SIG_S_P }; |
| static uint8_t m_size_s_b_p[] = { LIST_FN_SIG_S_B_P }; |
| static uint8_t m_size_s_b_b_p[] = { LIST_FN_SIG_S_B_B_P }; |
| |
| #undef FN_SIG_NONE |
| #undef FN_SIG_S |
| #undef FN_SIG_P |
| #undef FN_SIG_S_B |
| #undef FN_SIG_B_B_P |
| #undef FN_SIG_S_P |
| #undef FN_SIG_S_B_P |
| #undef FN_SIG_S_B_B_P |
| |
| /* 2- build the enumerations list */ |
| #define FN_SIG_NONE(__fn) fn_index_##__fn, |
| #define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) |
| #define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B(__fn, __s, __type, __length) FN_SIG_NONE(__fn) |
| #define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, \ |
| __type3) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \ |
| FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, \ |
| __length2, __type3) FN_SIG_NONE(__fn) |
| |
| /* Build the list of function indexes in the deserialization array */ |
| enum { LIST_FN_SIG_NONE fn_none_index_max }; |
| enum { LIST_FN_SIG_S fn_s_index_max }; |
| enum { LIST_FN_SIG_P fn_p_index_max }; |
| enum { LIST_FN_SIG_S_B fn_s_b_index_max }; |
| enum { LIST_FN_SIG_B_B_P fn_b_b_p_index_max }; |
| enum { LIST_FN_SIG_S_P fn_s_p_index_max }; |
| enum { LIST_FN_SIG_S_B_P fn_s_b_p_index_max }; |
| enum { LIST_FN_SIG_S_B_B_P fn_s_b_b_p_index_max }; |
| |
| #undef FN_SIG_NONE |
| #undef FN_SIG_S |
| #undef FN_SIG_P |
| #undef FN_SIG_S_B |
| #undef FN_SIG_B_B_P |
| #undef FN_SIG_S_P |
| #undef FN_SIG_S_B_P |
| #undef FN_SIG_S_B_B_P |
| |
| /* 3- build the array */ |
| #define FN_SIG_NONE(__fn) [fn_index_##__fn] = \ |
| (void *)__fn, |
| #define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) |
| #define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B(__fn, __s, __type, __length) \ |
| FN_SIG_NONE(__fn) |
| #define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, \ |
| __type3) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \ |
| FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, \ |
| __length2, __type3) FN_SIG_NONE(__fn) |
| |
| static void (*m_fct_none[])(void) = { LIST_FN_SIG_NONE }; |
| static void (*m_fct_s[])(void *structure) = { LIST_FN_SIG_S }; |
| static void (*m_fct_p[])(void *pointer) = { LIST_FN_SIG_P }; |
| static void (*m_fct_s_b[])(void *structure, void *buffer, |
| uint8_t length) = { LIST_FN_SIG_S_B }; |
| static void (*m_fct_b_b_p[])(void *buffer1, uint8_t length1, |
| void *buffer2, uint8_t length2, |
| void *pointer) = { LIST_FN_SIG_B_B_P }; |
| static void (*m_fct_s_p[])(void *structure, |
| void *pointer) = { LIST_FN_SIG_S_P }; |
| static void (*m_fct_s_b_p[])(void *structure, void *buffer, uint8_t length, |
| void *pointer) = { LIST_FN_SIG_S_B_P }; |
| static void (*m_fct_s_b_b_p[])(void *structure, void *buffer1, uint8_t length1, |
| void *buffer2, uint8_t length2, |
| void *pointer) = { LIST_FN_SIG_S_B_B_P }; |
| |
| /* Build debug table to help development with this "robust" macro stuff */ |
| |
| #if defined(CONFIG_NBLE_DEBUG_RPC) |
| |
| #undef FN_SIG_NONE |
| #undef FN_SIG_S |
| #undef FN_SIG_P |
| #undef FN_SIG_S_B |
| #undef FN_SIG_B_B_P |
| #undef FN_SIG_S_P |
| #undef FN_SIG_S_B_P |
| #undef FN_SIG_S_B_B_P |
| |
| #define FN_SIG_NONE(__fn) #__fn, |
| #define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) |
| #define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B(__fn, __s, __type, __length) \ |
| FN_SIG_NONE(__fn) |
| #define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, \ |
| __type3) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \ |
| FN_SIG_NONE(__fn) |
| #define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, \ |
| __length2, __type3) FN_SIG_NONE(__fn) |
| |
| static char *debug_func_none[] = { LIST_FN_SIG_NONE }; |
| static char *debug_func_s[] = { LIST_FN_SIG_S }; |
| static char *debug_func_p[] = { LIST_FN_SIG_P }; |
| static char *debug_func_s_b[] = { LIST_FN_SIG_S_B }; |
| static char *debug_func_b_b_p[] = { LIST_FN_SIG_B_B_P }; |
| static char *debug_func_s_p[] = { LIST_FN_SIG_S_P }; |
| static char *debug_func_s_b_p[] = { LIST_FN_SIG_S_B_P }; |
| static char *debug_func_s_b_b_p[] = { LIST_FN_SIG_S_B_B_P}; |
| |
| #define DBG_FUNC(name) BT_DBG("%s", name) |
| #else |
| #define DBG_FUNC(name) |
| #endif |
| |
| #undef FN_SIG_NONE |
| #undef FN_SIG_S |
| #undef FN_SIG_P |
| #undef FN_SIG_S_B |
| #undef FN_SIG_B_B_P |
| #undef FN_SIG_S_P |
| #undef FN_SIG_S_B_P |
| #undef FN_SIG_S_B_B_P |
| |
| #define DJB2_HASH(__h, __v) ((((__h) << 5) + (__h)) + (__v)) |
| |
| #define FN_SIG_NONE(__fn) \ |
| hash = DJB2_HASH(hash, 1); |
| |
| #define FN_SIG_S(__fn, __s) \ |
| do { \ |
| hash = DJB2_HASH(hash, 2); \ |
| hash = DJB2_HASH(hash, sizeof(*((__s)0))); \ |
| } while (0); |
| |
| #define FN_SIG_P(__fn, __type) \ |
| hash = DJB2_HASH(hash, 3); |
| |
| #define FN_SIG_S_B(__fn, __s, __type, __length) \ |
| do { \ |
| hash = DJB2_HASH(hash, 4); \ |
| hash = DJB2_HASH(hash, sizeof(*((__s)0))); \ |
| } while (0); |
| |
| #define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, \ |
| __type3) \ |
| do { \ |
| hash = DJB2_HASH(hash, 5); \ |
| hash = DJB2_HASH(hash, sizeof(*((__s)0))); \ |
| } while (0); |
| |
| #define FN_SIG_S_P(__fn, __s, __type) \ |
| do { \ |
| hash = DJB2_HASH(hash, 6); \ |
| hash = DJB2_HASH(hash, sizeof(*((__s)0))); \ |
| } while (0); |
| |
| #define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \ |
| do { \ |
| hash = DJB2_HASH(hash, 7); \ |
| hash = DJB2_HASH(hash, sizeof(*((__s)0))); \ |
| } while (0); |
| |
| #define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, \ |
| __length2, __type3) \ |
| do { \ |
| hash = DJB2_HASH(hash, 8); \ |
| hash = DJB2_HASH(hash, sizeof(*((__s)0))); \ |
| } while (0); |
| |
| uint32_t rpc_deserialize_hash(void) |
| { |
| uint32_t hash = 5381; |
| |
| LIST_FN_SIG_NONE; |
| LIST_FN_SIG_S; |
| LIST_FN_SIG_P; |
| LIST_FN_SIG_S_B; |
| LIST_FN_SIG_B_B_P; |
| LIST_FN_SIG_S_P; |
| LIST_FN_SIG_S_B_P; |
| LIST_FN_SIG_S_B_B_P; |
| |
| return hash; |
| } |
| |
| static void panic(int err) |
| { |
| PRINTK("panic: errcode %d", err); |
| |
| while (true) { |
| } |
| } |
| |
| static void deserialize_struct(struct net_buf *buf, const uint8_t **struct_ptr, |
| uint8_t *struct_length) |
| { |
| *struct_length = net_buf_pull_u8(buf); |
| *struct_ptr = buf->data; |
| net_buf_pull(buf, *struct_length); |
| } |
| |
| static void deserialize_buf(struct net_buf *buf, const uint8_t **buf_ptr, |
| uint16_t *buf_len) |
| { |
| uint8_t b; |
| |
| /* Get the current byte */ |
| b = net_buf_pull_u8(buf); |
| *buf_len = b & 0x7F; |
| if (b & 0x80) { |
| /* Get the current byte */ |
| b = net_buf_pull_u8(buf); |
| *buf_len += (uint16_t)b << 7; |
| } |
| |
| /* Return the values */ |
| *buf_ptr = buf->data; |
| |
| net_buf_pull(buf, *buf_len); |
| } |
| |
| static void deserialize_ptr(struct net_buf *buf, uintptr_t *priv) |
| { |
| memcpy(priv, buf->data, sizeof(*priv)); |
| net_buf_pull(buf, sizeof(*priv)); |
| } |
| |
| static void deserialize_none(uint8_t fn_index, struct net_buf *buf) |
| { |
| (void)buf; |
| |
| if (buf->len != 0) { |
| panic(-1); |
| } |
| |
| m_fct_none[fn_index](); |
| } |
| |
| static void deserialize_s(uint8_t fn_index, struct net_buf *buf) |
| { |
| const uint8_t *struct_ptr; |
| uint8_t struct_length; |
| |
| deserialize_struct(buf, &struct_ptr, &struct_length); |
| |
| if (struct_length != m_size_s[fn_index]) { |
| panic(-1); |
| } else { |
| /* Always align structures on word boundary */ |
| uintptr_t struct_data[(struct_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| |
| memcpy(struct_data, struct_ptr, struct_length); |
| |
| m_fct_s[fn_index](struct_data); |
| } |
| } |
| |
| static void deserialize_p(uint8_t fn_index, struct net_buf *buf) |
| { |
| uintptr_t priv; |
| |
| if (buf->len != sizeof(priv)) { |
| panic(-1); |
| } |
| |
| deserialize_ptr(buf, &priv); |
| |
| m_fct_p[fn_index]((void *)priv); |
| } |
| |
| static void deserialize_s_b(uint8_t fn_index, struct net_buf *buf) |
| { |
| const uint8_t *p_struct_data; |
| uint8_t struct_length; |
| const uint8_t *p_vbuf; |
| uint16_t vbuf_length; |
| |
| deserialize_struct(buf, &p_struct_data, &struct_length); |
| deserialize_buf(buf, &p_vbuf, &vbuf_length); |
| |
| if (struct_length != m_size_s_b[fn_index]) { |
| panic(-1); |
| } else { |
| /* Always align structures on word boundary */ |
| uintptr_t struct_data[(struct_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| uintptr_t vbuf[(vbuf_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| void *buf = NULL; |
| |
| memcpy(struct_data, p_struct_data, struct_length); |
| |
| if (vbuf_length) { |
| memcpy(vbuf, p_vbuf, vbuf_length); |
| buf = vbuf; |
| } |
| |
| m_fct_s_b[fn_index](struct_data, buf, vbuf_length); |
| } |
| } |
| |
| static void deserialize_b_b_p(uint8_t fn_index, struct net_buf *buf) |
| { |
| const uint8_t *p_vbuf1; |
| uint16_t vbuf1_length; |
| const uint8_t *p_vbuf2; |
| uint16_t vbuf2_length; |
| uintptr_t priv; |
| |
| deserialize_buf(buf, &p_vbuf1, &vbuf1_length); |
| deserialize_buf(buf, &p_vbuf2, &vbuf2_length); |
| deserialize_ptr(buf, &priv); |
| |
| { |
| /* Always align structures on word boundary */ |
| uintptr_t vbuf1[(vbuf1_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| uintptr_t vbuf2[(vbuf2_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| void *buf1 = NULL; |
| void *buf2 = NULL; |
| |
| if (vbuf1_length) { |
| memcpy(vbuf1, p_vbuf1, vbuf1_length); |
| buf1 = vbuf1; |
| } |
| |
| if (vbuf2_length) { |
| memcpy(vbuf2, p_vbuf2, vbuf2_length); |
| buf2 = vbuf2; |
| } |
| |
| m_fct_b_b_p[fn_index](buf1, vbuf1_length, buf2, vbuf2_length, |
| (void *)priv); |
| } |
| } |
| |
| static void deserialize_s_p(uint8_t fn_index, struct net_buf *buf) |
| { |
| const uint8_t *p_struct_data; |
| uint8_t struct_length; |
| uintptr_t priv; |
| |
| deserialize_struct(buf, &p_struct_data, &struct_length); |
| deserialize_ptr(buf, &priv); |
| |
| if (struct_length != m_size_s_p[fn_index]) { |
| panic(-1); |
| } else { |
| /* Always align structures on word boundary */ |
| uintptr_t struct_data[(struct_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| |
| memcpy(struct_data, p_struct_data, struct_length); |
| |
| m_fct_s_p[fn_index](struct_data, (void *)priv); |
| } |
| } |
| |
| static void deserialize_s_b_p(uint8_t fn_index, struct net_buf *buf) |
| { |
| const uint8_t *p_struct_data; |
| uint8_t struct_length; |
| const uint8_t *p_vbuf; |
| uint16_t vbuf_length; |
| uintptr_t priv; |
| |
| deserialize_struct(buf, &p_struct_data, &struct_length); |
| deserialize_buf(buf, &p_vbuf, &vbuf_length); |
| deserialize_ptr(buf, &priv); |
| |
| if (struct_length != m_size_s_b_p[fn_index]) { |
| panic(-1); |
| } else { |
| /* Always align structures on word boundary */ |
| uintptr_t struct_data[(struct_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| uintptr_t vbuf[(vbuf_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| void *buf = NULL; |
| |
| memcpy(struct_data, p_struct_data, struct_length); |
| |
| if (vbuf_length) { |
| memcpy(vbuf, p_vbuf, vbuf_length); |
| buf = vbuf; |
| } |
| |
| m_fct_s_b_p[fn_index](struct_data, buf, vbuf_length, |
| (void *)priv); |
| } |
| } |
| |
| static void deserialize_s_b_b_p(uint8_t fn_index, struct net_buf *buf) |
| { |
| const uint8_t *p_struct_data; |
| uint8_t struct_length; |
| const uint8_t *p_vbuf1; |
| uint16_t vbuf1_length; |
| const uint8_t *p_vbuf2; |
| uint16_t vbuf2_length; |
| uintptr_t priv; |
| |
| deserialize_struct(buf, &p_struct_data, &struct_length); |
| deserialize_buf(buf, &p_vbuf1, &vbuf1_length); |
| deserialize_buf(buf, &p_vbuf2, &vbuf2_length); |
| deserialize_ptr(buf, &priv); |
| |
| if (struct_length != m_size_s_b_b_p[fn_index]) { |
| panic(-1); |
| } else { |
| /* Always align structures on word boundary */ |
| uintptr_t struct_data[(struct_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| uintptr_t vbuf1[(vbuf1_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| uintptr_t vbuf2[(vbuf2_length + |
| (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; |
| void *buf1 = NULL; |
| void *buf2 = NULL; |
| |
| memcpy(struct_data, p_struct_data, struct_length); |
| |
| if (vbuf1_length) { |
| memcpy(vbuf1, p_vbuf1, vbuf1_length); |
| buf1 = vbuf1; |
| } |
| |
| if (vbuf2_length) { |
| memcpy(vbuf2, p_vbuf2, vbuf2_length); |
| buf2 = vbuf2; |
| } |
| |
| m_fct_s_b_b_p[fn_index](struct_data, buf1, vbuf1_length, buf2, |
| vbuf2_length, (void *)priv); |
| } |
| } |
| |
| static void deserialize_control(uint8_t fn_index, struct net_buf *buf) |
| { |
| const uint8_t *p_struct_data; |
| uint8_t struct_length; |
| struct { |
| uint32_t version; |
| uint32_t ser_hash; |
| uint32_t des_hash; |
| } struct_data; |
| |
| switch (fn_index) { |
| case 0: |
| deserialize_struct(buf, &p_struct_data, &struct_length); |
| |
| if (struct_length != sizeof(struct_data)) |
| panic(-1); |
| memcpy(&struct_data, p_struct_data, struct_length); |
| if (struct_data.ser_hash != rpc_deserialize_hash() || |
| struct_data.des_hash != rpc_serialize_hash()) { |
| rpc_init_cb(struct_data.version, false); |
| } else { |
| rpc_init_cb(struct_data.version, true); |
| } |
| break; |
| break; |
| panic(-1); |
| } |
| } |
| |
| void rpc_deserialize(struct net_buf *buf) |
| { |
| |
| uint8_t fn_index; |
| uint8_t sig_type; |
| |
| sig_type = buf->data[0]; |
| fn_index = buf->data[1]; |
| |
| net_buf_pull(buf, 2); |
| |
| switch (sig_type) { |
| case SIG_TYPE_NONE: |
| if (fn_index < ARRAY_SIZE(m_fct_none)) { |
| DBG_FUNC(debug_func_none[fn_index]); |
| deserialize_none(fn_index, buf); |
| } |
| break; |
| case SIG_TYPE_S: |
| if (fn_index < ARRAY_SIZE(m_fct_s)) { |
| DBG_FUNC(debug_func_s[fn_index]); |
| deserialize_s(fn_index, buf); |
| } |
| break; |
| case SIG_TYPE_P: |
| if (fn_index < ARRAY_SIZE(m_fct_p)) { |
| DBG_FUNC(debug_func_p[fn_index]); |
| deserialize_p(fn_index, buf); |
| } |
| break; |
| case SIG_TYPE_S_B: |
| if (fn_index < ARRAY_SIZE(m_fct_s_b)) { |
| DBG_FUNC(debug_func_s_b[fn_index]); |
| deserialize_s_b(fn_index, buf); |
| } |
| break; |
| case SIG_TYPE_B_B_P: |
| if (fn_index < ARRAY_SIZE(m_fct_b_b_p)) { |
| DBG_FUNC(debug_func_b_b_p[fn_index]); |
| deserialize_b_b_p(fn_index, buf); |
| } |
| break; |
| case SIG_TYPE_S_P: |
| if (fn_index < ARRAY_SIZE(m_fct_s_p)) { |
| DBG_FUNC(debug_func_s_p[fn_index]); |
| deserialize_s_p(fn_index, buf); |
| } |
| break; |
| case SIG_TYPE_S_B_P: |
| if (fn_index < ARRAY_SIZE(m_fct_s_b_p)) { |
| DBG_FUNC(debug_func_s_b_p[fn_index]); |
| deserialize_s_b_p(fn_index, buf); |
| } |
| break; |
| case SIG_TYPE_S_B_B_P: |
| if (fn_index < ARRAY_SIZE(m_fct_s_b_b_p)) { |
| DBG_FUNC(debug_func_s_b_b_p[fn_index]); |
| deserialize_s_b_b_p(fn_index, buf); |
| } |
| break; |
| case SIG_TYPE_CONTROL: |
| deserialize_control(fn_index, buf); |
| break; |
| default: |
| panic(-1); |
| break; |
| } |
| } |
| |
| __weak |
| void rpc_init_cb(uint32_t version, bool compatible) |
| { |
| } |