aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmtp/layer3.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmtp/layer3.c')
-rw-r--r--src/libmtp/layer3.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/libmtp/layer3.c b/src/libmtp/layer3.c
new file mode 100644
index 0000000..7726bd5
--- /dev/null
+++ b/src/libmtp/layer3.c
@@ -0,0 +1,103 @@
+/* Jolly's implementation of MTP layer 3
+ *
+ * (C) 2020 by Andreas Eversberg <jolly@eversberg.eu>
+ * All Rights Reserved
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This is only a minimal implementation to make a C-Netz-BTS working.
+ */
+
+#define CHAN mtp->name
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "../libtimer/timer.h"
+#include "../libdebug/debug.h"
+#include "mtp.h"
+
+/* message from layer 4 */
+int mtp_send(mtp_t *mtp, enum mtp_prim prim, uint8_t slc, uint8_t *data, int len)
+{
+ uint8_t buffer[len + 4];
+
+ if (prim == MTP_PRIM_DATA) {
+ PDEBUG_CHAN(DMTP3, DEBUG_DEBUG, "Send frame to remote: SIO=0x%02x DPC=%d OPC=%d SLC=%d %s\n", mtp->sio, mtp->remote_pc, mtp->local_pc, slc, debug_hex(data, len));
+ /* add header */
+ buffer[0] = mtp->remote_pc;
+ buffer[1] = (mtp->remote_pc >> 8) & 0x3f;
+ buffer[1] |= (mtp->local_pc << 6) & 0xc0;
+ buffer[2] = mtp->local_pc >> 2;
+ buffer[3] = (mtp->local_pc >> 10) & 0x0f;
+ buffer[3] |= slc << 4;
+
+ /* add payload */
+ if (len)
+ memcpy(buffer + 4, data, len);
+ data = buffer;
+ len += 4;
+ }
+
+ /* transmit */
+ return mtp_l3l2(mtp, prim, mtp->sio, data, len);
+}
+
+/* message from layer 2 */
+void mtp_l2l3(mtp_t *mtp, enum mtp_prim prim, uint8_t sio, uint8_t *data, int len)
+{
+ uint16_t dpc, opc;
+ uint8_t slc = 0;
+
+ if (prim == MTP_PRIM_DATA) {
+ if (len < 4) {
+ PDEBUG_CHAN(DMTP3, DEBUG_NOTICE, "Short frame from layer 2 (len=%d)\n", len);
+ return;
+ }
+
+ /* parse header */
+ dpc = data[0];
+ dpc |= (data[1] << 8) & 0x3f00;
+ opc = data[1] >> 6;
+ opc |= data[2] << 2;
+ opc |= (data[3] << 10) & 0x3c00;
+ slc = data[3] >> 4;
+ data += 4;
+ len -= 4;
+
+ PDEBUG_CHAN(DMTP3, DEBUG_DEBUG, "Received frame from remote: SIO=0x%02x DPC=%d OPC=%d SLC=%d %s\n", sio, dpc, opc, slc, debug_hex(data, len));
+
+ if (dpc != mtp->local_pc || opc != mtp->remote_pc) {
+ PDEBUG_CHAN(DMTP3, DEBUG_NOTICE, "Received message with wrong point codes: %d->%d but expecting %d->%d\n", opc, dpc, mtp->remote_pc, mtp->local_pc);
+ return;
+ }
+ if ((sio & 0x0f) == 0x0 && len >= 1) {
+ PDEBUG_CHAN(DMTP3, DEBUG_NOTICE, "MGMT message received: SLC=%d H0=%d H1=%d %s\n", slc, data[0] & 0xf, data[0] >> 4, debug_hex(data + 1, len - 1));
+ return;
+ }
+ if (sio != mtp->sio) {
+ PDEBUG_CHAN(DMTP3, DEBUG_NOTICE, "Received message with wrong SIO: 0x%02x but expecting 0x%02x\n", sio, mtp->sio);
+ return;
+ }
+ }
+
+ /* receive */
+ mtp->mtp_receive(mtp->inst, prim, slc, data, len);
+}
+