diff options
author | Dan Williams <dcbw@redhat.com> | 2012-05-16 12:13:48 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2012-05-16 12:13:48 -0500 |
commit | 9bee743a9d193373df82a93ef4fd159504d0763e (patch) | |
tree | dd7f509495961c3c0cc99b88a2a3fee68fde9c61 | |
parent | df1f21d17f6923145926fba5be38cff947254cae (diff) |
vl600: add some reverse engineering docs and an AT com utility
-rwxr-xr-x | vl600/atcom.py | 147 | ||||
-rw-r--r-- | vl600/vl600.txt | 38 |
2 files changed, 185 insertions, 0 deletions
diff --git a/vl600/atcom.py b/vl600/atcom.py new file mode 100755 index 00000000..5ca52b03 --- /dev/null +++ b/vl600/atcom.py @@ -0,0 +1,147 @@ +#! /bin/env python +# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# +# 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 2 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: +# +# Copyright (C) 2012 Red Hat, Inc. +# + +import os +import sys +import select +import struct +import string +from termios import * + +debug = False + +def lg_pack(data, seqno): + l = len(data) + + fmt = "<" + fmt += "I" # magic + fmt += "I" # sequence number + fmt += "I" # data length + fmt += "H" # MUX channel + fmt += "%ds" % l # AT data + + # Packets always padded to 4-byte boundaries + sz = struct.calcsize(fmt) + padding = 0 + if sz % 4 > 0: + padding = 4 - (sz % 4) + fmt += "%ds" % padding + + return struct.pack(fmt, 0xa512485a, seqno, l, 0xf011, data, "\0" * padding) + +def lg_unpack(data): + fmt = "<" + fmt += "I" # magic + fmt += "I" # sequence number + fmt += "I" # data length + fmt += "H" # MUX channel + fmt += "%ds" % (len(data) - 14) # AT data + + (magic, seq, l, chan, resp) = struct.unpack(fmt, data) + + if magic != 0xa512485a: + raise Exception("Bad magic: 0x%08x" % magic) + if chan != 0xf011: + print "Unhandled channel 0x%04x" % chan + + # It appears that we're supposed to ignore any data after \r\n, or if + # we don't get a \r\n we ignore all of it. The modem adds random + # data to the end of the response, for example: + # + # > 5a 48 12 a5 08 00 00 00 0a 00 00 00 11 f0 41 54 2b 43 45 52 45 47 3f 0a + # < 5a 48 12 a5 4e 00 00 00 15 00 00 00 11 f0 2b 43 45 52 45 47 3a 20 30 2c 31 0d 0a 00 00 4f 4b 0d 0a 00 47 74 + # + # where there's a trailing "00 47 74". The trailing bytes appear + # totally random in value and length. + + crlf = resp.rfind("\r\n") + if crlf == -1: + return "" + + return resp[:crlf + 2] + +def dump_raw(data, to_modem): + if debug: + line = "" + if to_modem: + line += "> " + else: + line += "< " + for c in data: + line += "%02x " % ord(c) + print line + +def make_printable(data): + p = "" + for c in data: + if c in string.printable and ord(c) >= 32 or c == '\n' or c == '\r': + p += c + else: + p += "<%2x>" % ord(c) + return p + + +######################################### + +if len(sys.argv) != 2 and len(sys.argv) != 3: + print "Usage: %s <port> [--debug]" % sys.argv[0] + sys.exit(1) + +if len(sys.argv) > 2 and sys.argv[2] == "--debug": + debug = True + +fd = os.open(sys.argv[1], os.O_RDWR) + +# read existing port attributes and mask the ones we don't want +attrs = tcgetattr(fd) +attrs[0] = attrs[0] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) # iflag +attrs[1] = attrs[1] & ~OPOST # oflag +attrs[2] = attrs[2] & ~(CSIZE | PARENB) # cflag +attrs[3] = attrs[3] & ~(ECHO | ICANON | IEXTEN | ISIG) # lflag + +# Set up the attributes we do want +attrs[2] = attrs[2] | CS8 # cflag +attrs[4] = B115200 # ispeed +attrs[5] = B115200 # ospeed +attrs[6][VMIN] = 1 # cc +attrs[6][VTIME] = 0 # cc +tcsetattr(fd, TCSAFLUSH, attrs) + +infd = sys.stdin.fileno() +seqno = 0 +while 1: + try: + rfd, wfd, xfd = select.select([ fd, infd ], [], []) + except KeyboardInterrupt: + print "" + break + + if fd in rfd: + data = os.read(fd, 4096) + dump_raw(data, False) + line = lg_unpack(data) + if line: + print make_printable(line) + + if infd in rfd: + line = os.read(infd, 512) + if line: + data = lg_pack(line, seqno) + seqno += 1 + dump_raw(data, True) + os.write(fd, data) + +os.close(fd) diff --git a/vl600/vl600.txt b/vl600/vl600.txt new file mode 100644 index 00000000..f7f6719e --- /dev/null +++ b/vl600/vl600.txt @@ -0,0 +1,38 @@ +Device uses an LG L2000 LTE chip and a Qualcomm MDM6800A for CDMA/EVDO. + +The firmware flasher tool speaks DIAG and includes a lot of LTE-related +NV items. + +Device has two USB interfaces: + +0 - Proprietary ethernet interface +1 - CDC-ACM serial port + +The ACM port speaks a proprietary protocol that MUX-es traffic from the +following virtual interfaces (according to Windows): + +0: LGE LTE DM Port +1: LGE USB Modem Port +2: LGE LTE RF Serial Port (com) +3: LGE CDMA USB Serial Port (com) +4: LGE CDMA USB GPS NMEA Port (com) +5: LGE CDMA LBS Serial Port (com) + +MUX Header Format +----------------- + +u32: magic, always [ 0x5a 0x48 0x12 0xa5 ] +u32: sequence number (unpaired; host and device use separate sequence numbers) +u32: length (not including this header, but including any padding) +u16: MUX channel (21 f0: CMD) (11 f0: AT) +<data> + + +Packets are 4-byte aligned with padding of zeros, and this padding is included +in the length given in the header. + +AT commands may have trailing junk bytes. It appears that interpreters should +simply ignore any data in AT packets after the last CRLF. + +CMD packets are terminated with a standard HDLC CRC-16 and 0x7E. + |