aboutsummaryrefslogtreecommitdiffstats
path: root/src/diag_log.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2016-12-24 01:21:03 +0100
committerHarald Welte <laforge@gnumonks.org>2016-12-24 01:21:03 +0100
commitfaea754d39248d76cdd1806414f8a8c171b2049b (patch)
tree23a9e0bdb2cad9152f5cada3bf765b775e8dd62c /src/diag_log.c
parent2c36375f5bbbaa1ccdb587f97ced6e4dd7562ec3 (diff)
re-structure the LOG dispatcher
we now have a nice structure for dispatching log messages to various handlers, each self-contained. As an added benefit, we remove the need to manually enable all the various log codes, as we simply auto-generate the default config from all the message types we support. Furthermore, we reduce computational complexity by avoiding linear iteration over the array of registered log handlers.
Diffstat (limited to 'src/diag_log.c')
-rw-r--r--src/diag_log.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/diag_log.c b/src/diag_log.c
new file mode 100644
index 0000000..1bb3a72
--- /dev/null
+++ b/src/diag_log.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <osmocom/core/msgb.h>
+
+#include "diag_log.h"
+#include "protocol.h"
+#include "diagcmd.h"
+
+/***********************************************************************
+ * LOG Configuration / Protocol
+ ***********************************************************************/
+
+enum log_config_op {
+ LOG_CONFIG_DISABLE_OP = 0,
+ LOG_CONFIG_RETRIEVE_ID_RANGES_OP = 1,
+ LOG_CONFIG_RETRIEVE_VALID_MASK_OP = 2,
+ LOG_CONFIG_SET_MASK_OP = 3,
+ LOG_CONFIG_GET_LOGMASK_OP = 4,
+};
+
+struct diag_log_config_req_hdr {
+ uint8_t msg_type;
+ uint8_t pad[3];
+ uint32_t operation;
+} __attribute((packed));
+
+struct diag_log_config_set_mask {
+ struct diag_log_config_req_hdr hdr;
+ uint32_t equip_id;
+ uint32_t last_item;
+ uint8_t data[0];
+} __attribute((packed));
+
+struct msgb *gen_log_config_set_mask(uint32_t equip_id, uint32_t last_item)
+{
+ struct msgb *msg = msgb_alloc(DIAG_MAX_REQ_SIZE, "Diag Tx");
+ struct diag_log_config_set_mask *dlcsm;
+
+ msg->l2h = msgb_put(msg, sizeof(*dlcsm));
+ dlcsm = (struct diag_log_config_set_mask *) msg->l2h;
+ dlcsm->hdr.msg_type = DIAG_LOG_CONFIG_F;
+ dlcsm->hdr.operation = LOG_CONFIG_SET_MASK_OP;
+ dlcsm->equip_id = equip_id;
+ dlcsm->last_item = last_item;
+ msg->l3h = msgb_put(msg, dlcsm->last_item/8);
+
+ return msg;
+}
+
+int log_config_set_mask_bit(struct msgb *msg, uint32_t bit_in)
+{
+ struct diag_log_config_set_mask *dlcsm;
+ dlcsm = (struct diag_log_config_set_mask *) msg->l2h;
+ uint8_t *mask = msg->l3h;
+ unsigned int byte = bit_in / 8;
+ unsigned int bit = bit_in % 8;
+
+ if (byte > dlcsm->last_item/8)
+ return -1;
+
+ mask[byte] |= (1 << bit);
+
+ return 0;
+}
+
+
+/***********************************************************************
+ * LOG Dispatch
+ ***********************************************************************/
+
+/* not particularly memory efficient, but welll, only 500kB on 64bit */
+static diag_log_handler *log_handlers[0xffff];
+
+/* called by individual modules to register their own decoders */
+void diag_log_reg_dispatch(const struct diag_log_dispatch_tbl *tbl, unsigned int size)
+{
+ unsigned int i;
+ for (i = 0; i < size; i++) {
+ printf("Registering dispatch for 0x%04x\n", tbl[i].code);
+ log_handlers[tbl[i].code] = tbl[i].handler;
+ }
+}
+
+void diag_log_enable_all_supported_family(struct diag_instance *di, uint8_t family)
+{
+ struct msgb *msg;
+ unsigned int i, size;
+ unsigned int family_base = (family & 0xf) << 12;
+ unsigned int max = 0;
+
+ for (i = family_base; i < family_base + 0x1000; i++) {
+ if (log_handlers[i]) {
+ if (max < i)
+ max = i;
+ }
+ }
+
+ if (!max)
+ return;
+
+ size = max - family_base;
+ printf("family %u: allocating log mask of size %u\n", family, size);
+ msg = gen_log_config_set_mask(family, size);
+ for (i = family_base; i < family_base + 0x1000; i++) {
+ if (log_handlers[i])
+ log_config_set_mask_bit(msg, i-family_base);
+ }
+
+ diag_transmit_msgb(di, msg);
+ diag_read(di);
+}
+
+void diag_log_enable_all_supported(struct diag_instance *di)
+{
+ unsigned int i;
+
+ for (i = 0; i < 0xF; i++) {
+ diag_log_enable_all_supported_family(di, i);
+ }
+}
+
+void diag_log_handle(struct diag_instance *di, struct msgb *msg)
+{
+ struct diag_log_hdr *dlh;
+ struct log_hdr *lh;
+
+ dlh = (struct diag_log_hdr *) msg->data;
+ /* FIXME: verify length */
+ msg->l3h = msgb_pull(msg, sizeof(*dlh));
+
+ lh = (struct log_hdr *) msg->l3h;
+ /* FIXME: verify length */
+ msgb_pull(msg, sizeof(*lh));
+
+ printf("LOG(0x%04x|%u|%u): ", lh->code,
+ diag_ts_to_epoch(lh->ts), diag_ts_to_fn(lh->ts));
+
+ if (log_handlers[lh->code])
+ log_handlers[lh->code](lh, msg);
+ else
+ printf("%s\n", osmo_hexdump(lh->data, lh->len));
+}