decoder for RLC-EPDAN, MDSP-CMD, L2-STATE and L2-TRANSM-STATUS
diff --git a/src/diag_gsm.c b/src/diag_gsm.c
index b05f6ca..594150c 100644
--- a/src/diag_gsm.c
+++ b/src/diag_gsm.c
@@ -71,7 +71,61 @@
 	{ 0, NULL }
 };
 
+const struct value_string diag_gsm_l2_sapi0_st_vals[] = {
+	{ DIAG_SAPI0_ST_NULL,		"NULL" },
+	{ DIAG_SAPI0_ST_CON_PEND,	"CONN_PEND" },
+	{ DIAG_SAPI0_ST_IDLE,		"IDLE" },
+	{ DIAG_SAPI0_ST_EST_PEND,	"EST_PEND" },
+	{ DIAG_SAPI0_ST_REL_PEND,	"REL_PEND" },
+	{ DIAG_SAPI0_ST_LINK_EST,	"LINK_ESTABLISHED" },
+	{ DIAG_SAPI0_ST_TMR_RECOV,	"TIMER_RECOVERY" },
+	{ DIAG_SAPI0_ST_LINK_SUSP,	"LINK_SUSPENDED" },
+	{ DIAG_SAPI0_ST_UA_PEND,	"UA_PENDING" },
+	{ 0, NULL }
+};
 
+const struct value_string diag_gsm_l2_sapi3_st_vals[] = {
+	{ DIAG_SAPI3_ST_NULL,		"NULL" },
+	{ DIAG_SAPI3_ST_CON_PEND,	"CONN_PEND" },
+	{ DIAG_SAPI3_ST_IDLE,		"IDLE" },
+	{ DIAG_SAPI3_ST_EST_PEND,	"EST_PEND" },
+	{ DIAG_SAPI3_ST_REL_PEND,	"REL_PEND" },
+	{ DIAG_SAPI3_ST_LINK_EST,	"LINK_ESTABLISHED" },
+	{ DIAG_SAPI3_ST_TMR_RECOV,	"TIMER_RECOVERY" },
+	{ DIAG_SAPI3_ST_UA_PEND,	"UA_PENDING" },
+	{ 0, NULL }
+};
+
+const struct value_string diag_gsm_l2_event_vals[] = {
+	{ DIAG_L2_EV_NO_EVENT,		"NONE" },
+	{ DIAG_L2_EV_CONNECT_RECEIVED,	"CON-RX" },
+	{ DIAG_L2_EV_ESTABLISH_REQUEST,	"EST.req" },
+	{ DIAG_L2_EV_RELEASE_REQUEST,	"REL.req" },
+	{ DIAG_L2_EV_SUSPEND_REQUEST,	"SUSP.req" },
+	{ DIAG_L2_EV_RESUME_REQUEST,	"RESUME.req" },
+	{ DIAG_L2_EV_RECONNECT_REQUEST,	"RECONN.req" },
+	{ DIAG_L2_EV_DATA_REQUEST,	"DATA.req" },
+	{ DIAG_L2_EV_MDL_RELEASE_REQUEST, "MDL-REL.req" },
+	{ DIAG_L2_EV_UA_RECEIVED,	"UA-RX" },
+	{ DIAG_L2_EV_DM_RECEIVED,	"DM-RX" },
+	{ DIAG_L2_EV_DISC_RECEIVED,	"DISC-RX" },
+	{ DIAG_L2_EV_SABM_RECEIVED,	"SABM-RX" },
+	{ DIAG_L2_EV_I_RECEIVED,	"I-RX" },
+	{ DIAG_L2_EV_UI_RECEIVED,	"UI-RX" },
+	{ DIAG_L2_EV_RR_RECEIVED,	"RR-RX" },
+	{ DIAG_L2_EV_REJ_RECEIVED,	"REJ-RX" },
+	{ DIAG_L2_EV_T200_TIMEOUT,	"T200-EXP" },
+	{ DIAG_L2_EV_CONTENTION_FAILED,	"CONTENT-FAIL" },
+	{ DIAG_L2_EV_ABORT_ESTABLISHMENT, "ABORT-EST" },
+	{ DIAG_L2_EV_LINK_ESTABLISHED,	"LINK-ESTABLISHED" },
+	{ DIAG_L2_EV_RELEASE_CONFIRMED,	"REL.conf" },
+	{ DIAG_L2_EV_CLEAR_RECOVERY_CONDITION, "CLEAR-RECOV-COND" },
+	{ DIAG_L2_EV_OPTIONAL_SEND,	"OPT-SEND" },
+	{ DIAG_L2_EV_RESET_L2,		"RESET-L2" },
+	{ DIAG_L2_EV_UA_SENT,		"UA-SENT" },
+	{ DIAG_L2_EV_FORCED_SUSPEND_REQ,"FORCED-SUSP.req" },
+	{ 0, NULL }
+};
 
 /* GSM_GPRS_LOG_PACKET_REQ_F */
 struct diag_gsm_log_packet_req {
diff --git a/src/diag_log_gprs.c b/src/diag_log_gprs.c
index e7504d8..89e5e18 100644
--- a/src/diag_log_gprs.c
+++ b/src/diag_log_gprs.c
@@ -307,6 +307,29 @@
 		metr->msg_len, metr->usf);
 }
 
+static inline uint32_t round_next_octet(uint32_t num_bits)
+{
+	uint32_t num_bytes = num_bits / 8;
+	if (num_bits % 8)
+		num_bytes++;
+	return num_bytes;
+}
+
+static void handle_egprs_rlc_epdan(struct log_hdr *lh, struct msgb *msg)
+{
+	struct diag_egprs_rlc_epdan *epd = (struct diag_egprs_rlc_epdan *) msgb_data(msg);
+
+	printf("EGPRS-RLC-EPDAN { tfi=%u, final_ack=%u, begin_of_win=%u, end_of_win=%u, esp=%u, starting_color_code=%u, gmsk=%u, psk=%u, ssn=%u, crrb_num_bits=%u, crrb=%s, ",
+		epd->tfi, epd->final_ack_ind, epd->begin_of_window, epd->end_of_window,
+		epd->esp, epd->starting_color_code, epd->gmsk_valid, epd->psk_valid,
+		epd->ssn, epd->crrb_num_bits,
+		osmo_hexdump_nospc(epd->crrb, round_next_octet(epd->crrb_num_bits)));
+	printf("urrb_num_bits=%u, urrb=%s, gmsk_bep=%u, psk_bep=%u, c_value=%u }\n",
+		epd->urrb_num_bits,
+		osmo_hexdump_nospc(epd->urrb, round_next_octet(epd->urrb_num_bits)),
+		epd->gmsk_bep, epd->psk_bep, epd->c_value);
+}
+
 static const struct diag_log_dispatch_tbl log_tbl[] = {
 	/* LLC */
 	{ GSM(LOG_GPRS_LLC_ME_INFO_C), handle_llc_me_info },		/* requested? */
@@ -324,6 +347,7 @@
 	{ GSM(LOG_GPRS_RLC_UL_ACKNACK_PARAMS_VER2_C), handle_ul_acknack_v2 },
 	{ GSM(LOG_GPRS_RLC_DL_ACKNACK_PARAMS_VER2_C), handle_dl_acknack_v2 },
 	{ GSM(LOG_EGPRS_RLC_UL_HEADER_C), handle_rlc_ul_header },
+	{ GSM(LOG_EGPRS_RLC_EPDAN_C), handle_egprs_rlc_epdan },
 	{ 0x5206, diag_log_hdl_default },
 	/* MAC */
 	{ GSM(LOG_GPRS_MAC_STATE_C), handle_mac_state },
@@ -355,15 +379,10 @@
 	{ 0x51f6, diag_log_hdl_default },
 	{ 0x51f7, diag_log_hdl_default },
 
-	{ 0x50c8, diag_log_hdl_default },
-	{ 0x50c9, diag_log_hdl_default },
-
-	{ 0x508c, diag_log_hdl_default },
 	//{ 0x508d, diag_log_hdl_default }, hardware cmd
 	{ 0x508f, diag_log_hdl_default },
 
 	{ 0x5209, diag_log_hdl_default },
-	{ 0x5211, diag_log_hdl_default },
 };
 
 static __attribute__((constructor)) void on_dso_load_gprs(void)
diff --git a/src/diag_log_gsm.c b/src/diag_log_gsm.c
index 8f44169..40290b6 100644
--- a/src/diag_log_gsm.c
+++ b/src/diag_log_gsm.c
@@ -39,9 +39,62 @@
 
 }
 
+static void handle_mdsp_cmd(struct log_hdr *lh, struct msgb *msg)
+{
+	struct diag_mdsp_log_cmds *dmlcs = (struct diag_mdsp_log_cmds *) msgb_data(msg);
+	int i;
+
+	printf("MDSP-COMMANDS { num_cmds=%u, cmds=[ ", dmlcs->num_cmds);
+
+	for (i = 0; i < dmlcs->num_cmds; i++) {
+		struct diag_mdsp_log_cmd *cmd = &dmlcs->cmds[i];
+		printf("{ fn=%u, cnt=%u, seq=%u, cmd=%u, params=[ %u, %u, %u, %u, %u ] }",
+			cmd->fn, cmd->cnt, cmd->seq, cmd->cmd,
+			cmd->params[0], cmd->params[1], cmd->params[2], cmd->params[3],
+			cmd->params[4]);
+		if (i+1 != dmlcs->num_cmds)
+			printf(", ");
+
+	}
+	printf(" ] }\n");
+}
+
+static void handle_l2_state(struct log_hdr *lh, struct msgb *msg)
+{
+	struct diag_gsm_l2_state *l2s = (struct diag_gsm_l2_state *) msgb_data(msg);
+
+	printf("L2-STATE { sapi=%u, ", l2s->sapi);
+	switch (l2s->sapi) {
+	case 0:
+		printf("l2_state=%s, ",
+			get_value_string(diag_gsm_l2_sapi0_st_vals, l2s->l2_state));
+		break;
+	case 3:
+		printf("l2_state=%s, ",
+			get_value_string(diag_gsm_l2_sapi3_st_vals, l2s->l2_state));
+		break;
+	default:
+		break;
+	}
+	printf("l2_event=%s }\n",
+		get_value_string(diag_gsm_l2_event_vals, l2s->l2_event));
+}
+
+static void handle_l2_transm_status(struct log_hdr *lh, struct msgb *msg)
+{
+	struct diag_gsm_l2_transm_status *lts = (struct diag_gsm_l2_transm_status *) msgb_data(msg);
+
+	printf("L2-TRANSM-STATUS { sapi=%u, chan_type=%u, vs=%u, va=%u, vr=%u, retrans_ctr=%u, seq_err=%u, frame_type=%u, msg_entries=%u, seg_entries=%u }\n",
+		lts->sapi, lts->channel_type, lts->vs, lts->va, lts->vr, lts->retrans_ctr,
+		lts->seq_err, lts->frame_type, lts->msg_entries, lts->seg_entries);
+}
+
 static const struct diag_log_dispatch_tbl log_tbl[] = {
 	{ GSM(LOG_GSM_RR_SIGNALING_MESSAGE_C), handle_rr_sig_msg },
 	{ GSM(LOG_GSM_RR_STATE_C), handle_rr_state_msg },
+	{ GSM(LOG_GSM_MDSP_CMD_C), handle_mdsp_cmd },
+	{ GSM(LOG_GSM_L2_STATE_C), handle_l2_state },
+	{ GSM(LOG_GSM_L2_TRANSMISSION_STATUS_C), handle_l2_transm_status},
 };
 
 static __attribute__((constructor)) void on_dso_load_gsm(void)
diff --git a/src/protocol/diag_log_gsm.h b/src/protocol/diag_log_gsm.h
index 946a213..a648014 100644
--- a/src/protocol/diag_log_gsm.h
+++ b/src/protocol/diag_log_gsm.h
@@ -11,11 +11,17 @@
 	LOG_GSM_AFC_ADJUST_C				= 0x7c,
 	LOG_GSM_MON_BURST_C				= 0x82,
 	LOG_GSM_BCCH_BURST_METRICS_C			= 0x85,
+	LOG_GSM_MDSP_CMD_C				= 0x8c,
 	LOG_GSM_GL1_HW_CMD_C				= 0x8d,
-	LOG_GSM_RR_STATE_C				= 0x12c,
 	LOG_GSM_RR_SIGNALING_MESSAGE_C			= 0x12f,
 
+	/* Layer2 (LAPDm) */
+	LOG_GSM_L2_STATE_C				= 200,
+	LOG_GSM_L2_TRANSMISSION_STATUS_C		= 201,
+	LOG_GSM_L2_OUTSTANDING_FRAME_C			= 202,
 
+
+	LOG_GSM_RR_STATE_C				= 300,
 	//= 303,
 	LOG_GSM_RR_CONTROL_CHANNEL_PARAMS_C		= 306,
 
@@ -251,4 +257,93 @@
 	struct diag_xid_tuple8 ku;
 } __attribute__ ((packed));
 
+struct diag_mdsp_log_cmd {
+	uint32_t fn;
+	uint16_t cnt;
+	uint16_t seq;
+	uint16_t cmd;
+	uint16_t params[5];
+} __attribute__ ((packed));
+
+struct diag_mdsp_log_cmds {
+	uint32_t num_cmds;
+	struct diag_mdsp_log_cmd cmds[16];
+} __attribute__ ((packed));
+
+
+enum diag_gsm_sapi0_state {
+	DIAG_SAPI0_ST_NULL,
+	DIAG_SAPI0_ST_CON_PEND,
+	DIAG_SAPI0_ST_IDLE,
+	DIAG_SAPI0_ST_EST_PEND,
+	DIAG_SAPI0_ST_REL_PEND,
+	DIAG_SAPI0_ST_LINK_EST,
+	DIAG_SAPI0_ST_TMR_RECOV,
+	DIAG_SAPI0_ST_LINK_SUSP,
+	DIAG_SAPI0_ST_UA_PEND,
+};
+const struct value_string diag_gsm_l2_sapi0_st_vals[10];
+
+enum diag_gsm_sapi3_state {
+	DIAG_SAPI3_ST_NULL,
+	DIAG_SAPI3_ST_CON_PEND,
+	DIAG_SAPI3_ST_IDLE,
+	DIAG_SAPI3_ST_EST_PEND,
+	DIAG_SAPI3_ST_REL_PEND,
+	DIAG_SAPI3_ST_LINK_EST,
+	DIAG_SAPI3_ST_TMR_RECOV,
+	DIAG_SAPI3_ST_UA_PEND,
+};
+const struct value_string diag_gsm_l2_sapi3_st_vals[9];
+
+enum diag_gsm_l2_event {
+	DIAG_L2_EV_NO_EVENT,
+	DIAG_L2_EV_CONNECT_RECEIVED,
+	DIAG_L2_EV_ESTABLISH_REQUEST,
+	DIAG_L2_EV_RELEASE_REQUEST,
+	DIAG_L2_EV_SUSPEND_REQUEST,
+	DIAG_L2_EV_RESUME_REQUEST,
+	DIAG_L2_EV_RECONNECT_REQUEST,
+	DIAG_L2_EV_DATA_REQUEST,
+	DIAG_L2_EV_MDL_RELEASE_REQUEST,
+	DIAG_L2_EV_UA_RECEIVED,
+	DIAG_L2_EV_DM_RECEIVED,
+	DIAG_L2_EV_DISC_RECEIVED,
+	DIAG_L2_EV_SABM_RECEIVED,
+	DIAG_L2_EV_I_RECEIVED,
+	DIAG_L2_EV_UI_RECEIVED,
+	DIAG_L2_EV_RR_RECEIVED,
+	DIAG_L2_EV_REJ_RECEIVED,
+	DIAG_L2_EV_T200_TIMEOUT,
+	DIAG_L2_EV_CONTENTION_FAILED,
+	DIAG_L2_EV_ABORT_ESTABLISHMENT,
+	DIAG_L2_EV_LINK_ESTABLISHED,
+	DIAG_L2_EV_RELEASE_CONFIRMED,
+	DIAG_L2_EV_CLEAR_RECOVERY_CONDITION,
+	DIAG_L2_EV_OPTIONAL_SEND,
+	DIAG_L2_EV_RESET_L2,
+	DIAG_L2_EV_UA_SENT,
+	DIAG_L2_EV_FORCED_SUSPEND_REQ,
+};
+const struct value_string diag_gsm_l2_event_vals[27];
+
+struct diag_gsm_l2_state {
+	uint8_t sapi;
+	uint8_t l2_state;
+	uint8_t l2_event;
+} __attribute__ ((packed));
+
+struct diag_gsm_l2_transm_status {
+	uint8_t sapi;
+	uint8_t channel_type;
+	uint8_t vs;
+	uint8_t va;
+	uint8_t vr;
+	uint8_t retrans_ctr;
+	uint8_t seq_err;
+	uint8_t frame_type;
+	uint8_t msg_entries;
+	uint8_t seg_entries;
+} __attribute__ ((packed));
+
 struct msgb *diag_gsm_make_log_pack_req(uint16_t log_code, uint8_t zero_stats, uint8_t addl_info);