/* * Copyright (c) 2016 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include /* for bt_security_t */ #include #include #ifdef CONFIG_PRINTK #include #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" #if !defined(CONFIG_NBLE_DEBUG_RPC) #undef BT_DBG #define BT_DBG(fmt, ...) #endif /* 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}; #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)) { BT_DBG("%s", debug_func_none[fn_index]); deserialize_none(fn_index, buf); } break; case SIG_TYPE_S: if (fn_index < ARRAY_SIZE(m_fct_s)) { BT_DBG("%s", debug_func_s[fn_index]); deserialize_s(fn_index, buf); } break; case SIG_TYPE_P: if (fn_index < ARRAY_SIZE(m_fct_p)) { BT_DBG("%s", 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)) { BT_DBG("%s", 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)) { BT_DBG("%s", 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)) { BT_DBG("%s", 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)) { BT_DBG("%s", 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)) { BT_DBG("%s", 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) { }