libwmc: beginning of bits for WMC-based devices like UML290

This commit is contained in:
Dan Williams
2011-09-17 13:27:54 -05:00
parent 953701a6f8
commit 3dd4cdaf2b
16 changed files with 983 additions and 11 deletions
+2
View File
@@ -0,0 +1,2 @@
SUBDIRS=src tests
+28
View File
@@ -0,0 +1,28 @@
noinst_LTLIBRARIES = libwmc.la libwmc-test.la
libwmc_la_CPPFLAGS = \
$(MM_CFLAGS)
libwmc_la_SOURCES = \
utils.c \
utils.h
libwmc_la_LIBADD = \
$(MM_LIBS)
###########################################
# Test library without symbol versioning
###########################################
libwmc_test_la_CPPFLAGS = \
$(MM_CFLAGS)
libwmc_test_la_SOURCES = \
utils.c \
utils.h
libwmc_test_la_LIBADD = \
$(MM_LIBS)
+374
View File
@@ -0,0 +1,374 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <malloc.h>
#include <fcntl.h>
#include <string.h>
#include "utils.h"
/* QCDM protocol frames are pseudo Async HDLC frames which end with a 3-byte
* trailer. This trailer consists of the 16-bit CRC of the frame plus an ending
* "async control character" whose value is 0x7E. The frame *and* the CRC are
* escaped before adding the trailing control character so that the control
* character (0x7E) and the escape marker (0x7D) are never seen in the frame.
*/
/* Table of CRCs for each possible byte, with a generator polynomial of 0x8408 */
const guint16 crc_table[256] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
/* Calculate the CRC for a buffer using a seed of 0xffff */
guint16
crc16 (const char *buffer, gsize len, guint16 seed)
{
guint16 crc = seed ? seed : 0xFFFF;
while (len--)
crc = crc_table[(crc ^ *buffer++) & 0xff] ^ (crc >> 8);
return ~crc;
}
#define DIAG_ESC_CHAR 0x7D /* Escape sequence 1st character value */
#define DIAG_ESC_MASK 0x20 /* Escape sequence complement value */
/* Performs DM escaping on inbuf putting the result into outbuf, and returns
* the final length of the buffer.
*/
gsize
hdlc_escape (const char *inbuf,
gsize inbuf_len,
gboolean escape_all_ctrl,
char *outbuf,
gsize outbuf_len)
{
const char *src = inbuf;
char *dst = outbuf;
size_t i = inbuf_len;
g_return_val_if_fail (inbuf != NULL, 0);
g_return_val_if_fail (inbuf_len > 0, 0);
g_return_val_if_fail (outbuf != NULL, 0);
g_return_val_if_fail (outbuf_len > inbuf_len, 0);
/* Since escaping potentially doubles the # of bytes, short-circuit the
* length check if destination buffer is clearly large enough. Note the
*
*/
if (outbuf_len <= inbuf_len << 1) {
size_t outbuf_required = inbuf_len + 1; /* +1 for the trailing control char */
/* Each escaped character takes up two bytes in the output buffer */
while (i--) {
if ( *src == DIAG_CONTROL_CHAR
|| *src == DIAG_ESC_CHAR
|| (escape_all_ctrl && *src <= 0x20))
outbuf_required++;
src++;
}
if (outbuf_len < outbuf_required)
return 0;
}
/* Do the actual escaping. Replace both the control character and
* the escape character in the source buffer with the following sequence:
*
* <escape_char> <src_byte ^ escape_mask>
*/
src = inbuf;
i = inbuf_len;
while (i--) {
if ( *src == DIAG_CONTROL_CHAR
|| *src == DIAG_ESC_CHAR
|| (escape_all_ctrl && *src <= 0x20)) {
*dst++ = DIAG_ESC_CHAR;
*dst++ = *src ^ DIAG_ESC_MASK;
} else
*dst++ = *src;
src++;
}
return (dst - outbuf);
}
gsize
hdlc_unescape (const char *inbuf,
gsize inbuf_len,
char *outbuf,
gsize outbuf_len,
gboolean *escaping)
{
size_t i, outsize;
g_return_val_if_fail (inbuf_len > 0, 0);
g_return_val_if_fail (outbuf_len >= inbuf_len, 0);
g_return_val_if_fail (escaping != NULL, 0);
for (i = 0, outsize = 0; i < inbuf_len; i++) {
if (*escaping) {
outbuf[outsize++] = inbuf[i] ^ DIAG_ESC_MASK;
*escaping = FALSE;
} else if (inbuf[i] == DIAG_ESC_CHAR)
*escaping = TRUE;
else
outbuf[outsize++] = inbuf[i];
/* About to overrun output buffer size */
if (outsize >= outbuf_len)
return 0;
}
return outsize;
}
/**
* hdlc_encapsulate_buffer:
* @inbuf: data buffer to encapsulate
* @cmd_len: size of the data contained in @inbuf
* @inbuf_len: total size of @inbuf itself (not just the data)
* @crc_seed: if non-zero, CRC-16 seed to use; if 0, uses standard 0xFFFF
* @add_trailer: if %TRUE, adds trailing 0x7E
* @escape_all_ctrl: if %TRUE, escapes all control characters instead of only
* special HDLC escape characters 0x7D and 0x7E
* @outbuf: buffer in which to put the encapsulated data
* @outbuf_len: total size of @outbuf
*
* Escapes and CRCs given data using HDLC-style mechanisms, and optionally adds
* the trailing control character that denotes the end of the HDLC frame.
*
* Returns: size of the encapsulated data writted to @outbuf.
**/
gsize
hdlc_encapsulate_buffer (char *inbuf,
gsize cmd_len,
gsize inbuf_len,
guint16 crc_seed,
gboolean add_trailer,
gboolean escape_all_ctrl,
char *outbuf,
gsize outbuf_len)
{
guint16 crc;
gsize escaped_len;
g_return_val_if_fail (inbuf != NULL, 0);
g_return_val_if_fail (cmd_len >= 1, 0);
g_return_val_if_fail (inbuf_len >= cmd_len + 2, 0); /* space for CRC */
g_return_val_if_fail (outbuf != NULL, 0);
/* Add the CRC */
crc = crc16 (inbuf, cmd_len, crc_seed ? crc_seed : 0xFFFF);
inbuf[cmd_len++] = crc & 0xFF;
inbuf[cmd_len++] = (crc >> 8) & 0xFF;
escaped_len = hdlc_escape (inbuf, cmd_len, escape_all_ctrl, outbuf, outbuf_len);
g_return_val_if_fail (outbuf_len > escaped_len, 0);
if (add_trailer)
outbuf[escaped_len++] = DIAG_CONTROL_CHAR;
return escaped_len;
}
#define AT_WMC_PREFIX "AT*WMC="
/**
* uml290_wmc_encapsulate:
* @inbuf: data buffer to encapsulate
* @cmd_len: size of the data contained in @inbuf
* @inbuf_len: total size of @inbuf itself (not just the data)
* @outbuf: buffer in which to put the encapsulated data
* @outbuf_len: total size of @outbuf
*
* Escapes and CRCs given data using HDLC-style mechanisms with UML290 specific
* quirks.
*
* Returns: size of the encapsulated data writted to @outbuf.
*/
gsize
uml290_wmc_encapsulate (char *inbuf,
gsize cmd_len,
gsize inbuf_len,
char *outbuf,
gsize outbuf_len)
{
gsize encap_len;
gsize estimated_out_len;
g_return_val_if_fail (inbuf != NULL, 0);
g_return_val_if_fail (cmd_len >= 1, 0);
g_return_val_if_fail (inbuf_len >= cmd_len + 2, 0); /* space for CRC */
g_return_val_if_fail (outbuf != NULL, 0);
estimated_out_len = inbuf_len + strlen (AT_WMC_PREFIX);
estimated_out_len += 3; /* CRC + trailer */
estimated_out_len += cmd_len * 1.3; /* escaping */
g_return_val_if_fail (outbuf_len > estimated_out_len, 0);
memcpy (outbuf, AT_WMC_PREFIX, strlen (AT_WMC_PREFIX));
encap_len = hdlc_encapsulate_buffer (inbuf, cmd_len, inbuf_len, 0xAAFE,
FALSE, TRUE,
outbuf + strlen (AT_WMC_PREFIX),
outbuf_len);
if (encap_len > 0) {
encap_len += strlen (AT_WMC_PREFIX);
outbuf[encap_len++] = 0x0D; /* trailer */
}
return encap_len;
}
/**
* hdlc_decapsulate_buffer:
* @inbuf: buffer in which to look for an HDLC frame
* @inbuf_len: length of valid data in @inbuf
* @outbuf: buffer in which to put decapsulated data from the HDLC frame
* @outbuf_len: max size of @outbuf
* @out_decap_len: on success, size of the decapsulated data
* @out_used: on either success or failure, amount of data used; caller should
* discard this much data from @inbuf before the next call to this function
* @out_need_more: when TRUE, indicates that more data is required before
* a determination about a valid HDLC frame can be made; caller should add
* more data to @inbuf before calling this function again.
*
* Attempts to retrieve, unescape, and CRC-check an HDLC frame from the given
* buffer.
*
* Returns: FALSE on error (packet was invalid or malformed, or the CRC check
* failed, etc) and places number of bytes to discard from @inbuf in @out_used.
* When TRUE, either more data is required (in which case @out_need_more will
* be TRUE), or a data packet was successfully retrieved from @inbuf and the
* decapsulated packet of length @out_decap_len was placed into @outbuf. In
* all cases the caller should advance the buffer by the number of bytes
* returned in @out_used before calling this function again.
**/
gboolean
hdlc_decapsulate_buffer (const char *inbuf,
gsize inbuf_len,
char *outbuf,
gsize outbuf_len,
gsize *out_decap_len,
gsize *out_used,
gboolean *out_need_more)
{
gboolean escaping = FALSE;
gsize i, pkt_len = 0, unesc_len;
guint16 crc, pkt_crc;
g_return_val_if_fail (inbuf != NULL, FALSE);
g_return_val_if_fail (outbuf != NULL, FALSE);
g_return_val_if_fail (outbuf_len > 0, FALSE);
g_return_val_if_fail (out_decap_len != NULL, FALSE);
g_return_val_if_fail (out_used != NULL, FALSE);
g_return_val_if_fail (out_need_more != NULL, FALSE);
*out_decap_len = 0;
*out_used = 0;
*out_need_more = FALSE;
if (inbuf_len < 4) {
*out_need_more = TRUE;
return TRUE;
}
/* Find the async control character */
for (i = 0; i < inbuf_len; i++) {
if (inbuf[i] == DIAG_CONTROL_CHAR) {
/* If the control character shows up in a position before a valid
* QCDM packet length (4), the packet is malformed.
*/
if (i < 3) {
/* Tell the caller to advance the buffer past the control char */
*out_used = i + 1;
return FALSE;
}
pkt_len = i;
break;
}
}
/* No control char yet, need more data */
if (!pkt_len) {
*out_need_more = TRUE;
return TRUE;
}
/* Unescape first; note that pkt_len */
unesc_len = hdlc_unescape (inbuf, pkt_len, outbuf, outbuf_len, &escaping);
if (!unesc_len) {
/* Tell the caller to advance the buffer past the control char */
*out_used = pkt_len + 1;
return FALSE;
}
if (escaping) {
*out_need_more = TRUE;
return TRUE;
}
/* Check the CRC of the packet's data */
crc = crc16 (outbuf, unesc_len - 2, 0);
pkt_crc = outbuf[unesc_len - 2] & 0xFF;
pkt_crc |= (outbuf[unesc_len - 1] & 0xFF) << 8;
if (crc != pkt_crc) {
*out_used = pkt_len + 1; /* packet + CRC + 0x7E */
return FALSE;
}
*out_used = pkt_len + 1; /* packet + CRC + 0x7E */
*out_decap_len = unesc_len - 2; /* decap_len should not include the CRC */
return TRUE;
}
+64
View File
@@ -0,0 +1,64 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#ifndef UTILS_H
#define UTILS_H
#include <glib.h>
#define DIAG_CONTROL_CHAR 0x7E
#define DIAG_TRAILER_LEN 3
guint16 crc16 (const char *buffer, gsize len, guint16 seed);
gsize hdlc_escape (const char *inbuf,
gsize inbuf_len,
gboolean escape_all_ctrl,
char *outbuf,
gsize outbuf_len);
gsize hdlc_unescape (const char *inbuf,
gsize inbuf_len,
char *outbuf,
gsize outbuf_len,
gboolean *escaping);
gsize hdlc_encapsulate_buffer (char *inbuf,
gsize cmd_len,
gsize inbuf_len,
guint16 crc_seed,
gboolean add_trailer,
gboolean escape_all_ctrl,
char *outbuf,
gsize outbuf_len);
gsize uml290_wmc_encapsulate (char *inbuf,
gsize cmd_len,
gsize inbuf_len,
char *outbuf,
gsize outbuf_len);
gboolean hdlc_decapsulate_buffer (const char *inbuf,
gsize inbuf_len,
char *outbuf,
gsize outbuf_len,
gsize *out_decap_len,
gsize *out_used,
gboolean *out_need_more);
#endif /* UTILS_H */
+28
View File
@@ -0,0 +1,28 @@
INCLUDES = \
-I$(top_srcdir)/libwmc/src
noinst_PROGRAMS = test-wmc
test_wmc_SOURCES = \
test-wmc-crc.c \
test-wmc-crc.h \
test-wmc-escaping.c \
test-wmc-escaping.h \
test-wmc-utils.c \
test-wmc-utils.h \
test-wmc.c
test_wmc_CPPFLAGS = \
$(MM_CFLAGS)
test_wmc_LDADD = \
$(top_builddir)/libwmc/src/libwmc.la \
$(MM_LIBS)
if WITH_TESTS
check-local: test-wmc
$(abs_builddir)/test-wmc
endif
+65
View File
@@ -0,0 +1,65 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#include <glib.h>
#include <string.h>
#include "test-wmc-crc.h"
#include "utils.h"
void
test_crc16_2 (void *f, void *data)
{
static const char buf[] = {
0x26, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00
};
guint16 crc;
guint16 expected = 0x6D69;
/* CRC check */
crc = crc16 (buf, sizeof (buf), 0);
g_assert (crc == expected);
}
void
test_crc16_1 (void *f, void *data)
{
static const char buf[] = {
0x4b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x3f,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
};
guint16 crc;
guint16 expected = 0x097A;
/* CRC check */
crc = crc16 (buf, sizeof (buf), 0);
g_assert (crc == expected);
}
+25
View File
@@ -0,0 +1,25 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#ifndef TEST_WMC_CRC_H
#define TEST_WMC_CRC_H
void test_crc16_2 (void *f, void *data);
void test_crc16_1 (void *f, void *data);
#endif /* TEST_WMC_CRC_H */
+124
View File
@@ -0,0 +1,124 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#include <glib.h>
#include <string.h>
#include "test-wmc-escaping.h"
#include "utils.h"
static const char data1[] = {
0x70, 0x68, 0x6f, 0x6e, 0x65, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65,
0x0a, 0x6e, 0x6f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x74, 0x6f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x0a, 0x70, 0x68, 0x6f,
0x6e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7d, 0x7e, 0x7d, 0x7e, 0x6e,
0x6b, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x0a, 0x6f, 0x70,
0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x6c,
0x6c, 0x6f, 0x77, 0x65, 0x64, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x6e, 0x6f, 0x74, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72,
0x74, 0x65, 0x64, 0x0a, 0x70, 0x68, 0x73, 0x69, 0x6d, 0x70, 0x69, 0x6e,
0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x0a, 0x70, 0x68, 0x66,
0x73, 0x69, 0x6d, 0x70, 0x69, 0x6e, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
0x65, 0x64, 0x0a, 0x70, 0x68, 0x66, 0x73, 0x69, 0x6d, 0x70, 0x75, 0x6b,
0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x0a, 0x73, 0x69, 0x6d,
0x6e, 0x6f, 0x74, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x0a,
0x73, 0x69, 0x6d, 0x70, 0x69, 0x6e, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
0x65, 0x64, 0x0a, 0x73, 0x69, 0x6d, 0x70, 0x75, 0x6b, 0x72, 0x65, 0x71,
0x75, 0x69, 0x72, 0x65, 0x64, 0x0a, 0x73, 0x69, 0x6d, 0x66, 0x61, 0x69,
0x6c, 0x75, 0x72, 0x65, 0x0a, 0x73, 0x69, 0x6d, 0x62, 0x75, 0x73, 0x79,
0x0a, 0x73, 0x69, 0x6d, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0x0a, 0x69, 0x6e,
0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x70, 0x61, 0x73, 0x73, 0x77,
0x6f, 0x72, 0x64, 0x0a, 0x73, 0x69, 0x6d, 0x70, 0x69, 0x6e, 0x32, 0x72,
0x65, 0x71, 0x75, 0x69
};
static const char expected1[] = {
0x70, 0x68, 0x6f, 0x6e, 0x65, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65,
0x0a, 0x6e, 0x6f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x74, 0x6f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x0a, 0x70, 0x68, 0x6f,
0x6e, 0x7d, 0x5e, 0x7d, 0x5e, 0x7d, 0x5e, 0x7d, 0x5d, 0x7d, 0x5d, 0x7d,
0x5e, 0x7d, 0x5d, 0x7d, 0x5e, 0x7d, 0x5d, 0x7d, 0x5e, 0x6e, 0x6b, 0x72,
0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x0a, 0x6f, 0x70, 0x65, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x6c, 0x6c, 0x6f,
0x77, 0x65, 0x64, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x6e, 0x6f, 0x74, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65,
0x64, 0x0a, 0x70, 0x68, 0x73, 0x69, 0x6d, 0x70, 0x69, 0x6e, 0x72, 0x65,
0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x0a, 0x70, 0x68, 0x66, 0x73, 0x69,
0x6d, 0x70, 0x69, 0x6e, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
0x0a, 0x70, 0x68, 0x66, 0x73, 0x69, 0x6d, 0x70, 0x75, 0x6b, 0x72, 0x65,
0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x0a, 0x73, 0x69, 0x6d, 0x6e, 0x6f,
0x74, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x0a, 0x73, 0x69,
0x6d, 0x70, 0x69, 0x6e, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
0x0a, 0x73, 0x69, 0x6d, 0x70, 0x75, 0x6b, 0x72, 0x65, 0x71, 0x75, 0x69,
0x72, 0x65, 0x64, 0x0a, 0x73, 0x69, 0x6d, 0x66, 0x61, 0x69, 0x6c, 0x75,
0x72, 0x65, 0x0a, 0x73, 0x69, 0x6d, 0x62, 0x75, 0x73, 0x79, 0x0a, 0x73,
0x69, 0x6d, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0x0a, 0x69, 0x6e, 0x63, 0x6f,
0x72, 0x72, 0x65, 0x63, 0x74, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x0a, 0x73, 0x69, 0x6d, 0x70, 0x69, 0x6e, 0x32, 0x72, 0x65, 0x71,
0x75, 0x69
};
void
test_escape1 (void *f, void *data)
{
char escaped[1024];
gsize len;
/* Ensure that escaping in general works */
len = hdlc_escape (data1, sizeof (data1), FALSE, escaped, sizeof (escaped));
g_assert (len == 266);
g_assert (len == sizeof (expected1));
g_assert (memcmp (escaped, expected1, len) == 0);
}
static const char data2[] = {
0x4b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x3f,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
};
void
test_escape2 (void *f, void *data)
{
char escaped[1024];
gsize len;
/* Ensure that escaping data that doesn't need escaping works */
len = hdlc_escape (data2, sizeof (data2), FALSE, escaped, sizeof (escaped));
g_assert (len == sizeof (data2));
g_assert (memcmp (escaped, data2, len) == 0);
}
void
test_escape_unescape (void *f, void *data)
{
char escaped[512];
char unescaped[512];
gsize len, unlen;
gboolean escaping = FALSE;
/* Ensure that escaping data that needs escaping, and then unescaping it,
* produces the exact same data as was originally escaped.
*/
len = hdlc_escape (data1, sizeof (data1), FALSE, escaped, sizeof (escaped));
unlen = hdlc_unescape (escaped, len, unescaped, sizeof (unescaped), &escaping);
g_assert (unlen == sizeof (data1));
g_assert (memcmp (unescaped, data1, unlen) == 0);
}
+26
View File
@@ -0,0 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#ifndef TEST_WMC_ESCAPING_H
#define TEST_WMC_ESCAPING_H
void test_escape1 (void *f, void *data);
void test_escape2 (void *f, void *data);
void test_escape_unescape (void *f, void *data);
#endif /* TEST_WMC_ESCAPING_H */
+107
View File
@@ -0,0 +1,107 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#include <glib.h>
#include <string.h>
#include "test-wmc-utils.h"
#include "utils.h"
static const char decap_inbuf[] = {
0x40, 0x03, 0x00, 0x01, 0x00, 0x19, 0xf0, 0x00, 0x16, 0x00, 0x21, 0x00,
0x1c, 0x00, 0xd8, 0x00, 0x3f, 0x00, 0x56, 0x01, 0x3f, 0x00, 0x15, 0x00,
0x1a, 0x00, 0x11, 0x01, 0x3f, 0x00, 0x92, 0x01, 0x3f, 0x00, 0x39, 0x00,
0x3f, 0x00, 0x95, 0x01, 0x3f, 0x00, 0x12, 0x00, 0x3f, 0x00, 0x23, 0x01,
0x3f, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x0b, 0x01, 0x3f, 0x00, 0xae, 0x00,
0x3f, 0x00, 0x02, 0x01, 0x3f, 0x00, 0xa8, 0x00, 0x3f, 0x00, 0x50, 0x01,
0x3f, 0x00, 0xf8, 0x01, 0x3f, 0x00, 0x57, 0x00, 0x3f, 0x00, 0x7d, 0x5e,
0x00, 0x3f, 0x00, 0x93, 0x00, 0x3f, 0x00, 0xbd, 0x00, 0x3f, 0x00, 0x77,
0x01, 0x3f, 0x00, 0xb7, 0x00, 0x3f, 0x00, 0xab, 0x00, 0x3f, 0x00, 0x33,
0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
0x13, 0x50, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x00, 0xaa, 0x19, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xc4, 0x7d, 0x5e,
0x7d, 0x5e, 0x7d, 0x5d, 0x5d, 0x04, 0x58, 0x1b, 0x5b, 0x1b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x65, 0x69, 0x7e
};
void
test_utils_decapsulate_buffer (void *f, void *data)
{
gboolean success;
char outbuf[512];
gsize decap_len = 0;
gsize used = 0;
gboolean more = FALSE;
success = hdlc_decapsulate_buffer (decap_inbuf, sizeof (decap_inbuf),
outbuf, sizeof (outbuf),
&decap_len, &used, &more);
g_assert (success);
g_assert (decap_len == 214);
g_assert (used == 221);
g_assert (more == FALSE);
}
static const char encap_outbuf[] = {
0x4b, 0x05, 0x08, 0x00, 0x01, 0xdd, 0x7e
};
void
test_utils_encapsulate_buffer (void *f, void *data)
{
char cmdbuf[10];
char outbuf[512];
gsize encap_len = 0;
cmdbuf[0] = 0x4B; /* DIAG_CMD_SUBSYS */
cmdbuf[1] = 0x05; /* DIAG_SUBSYS_HDR */
cmdbuf[2] = 0x08; /* first byte of DIAG_SUBSYS_HDR_STATE_INFO in LE */
cmdbuf[3] = 0x00; /* second byte of DIAG_SUBSYS_HDR_STATE_INFO in LE */
encap_len = hdlc_encapsulate_buffer (cmdbuf, 4, sizeof (cmdbuf),
0, TRUE, FALSE,
&outbuf[0], sizeof (outbuf));
g_assert (encap_len == sizeof (encap_outbuf));
g_assert (memcmp (outbuf, encap_outbuf, encap_len) == 0);
}
static const char cns_inbuf[] = {
0x00, 0x0a, 0x6b, 0x74, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e
};
void
test_utils_decapsulate_sierra_cns (void *f, void *data)
{
gboolean success;
char outbuf[512];
gsize decap_len = 0;
gsize used = 0;
gboolean more = FALSE;
success = hdlc_decapsulate_buffer (cns_inbuf, sizeof (cns_inbuf),
outbuf, sizeof (outbuf),
&decap_len, &used, &more);
g_assert (success == FALSE);
}
+28
View File
@@ -0,0 +1,28 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#ifndef TEST_WMC_UTILS_H
#define TEST_WMC_UTILS_H
void test_utils_decapsulate_buffer (void *f, void *data);
void test_utils_encapsulate_buffer (void *f, void *data);
void test_utils_decapsulate_sierra_cns (void *f, void *data);
#endif /* TEST_WMC_UTILS_H */
+54
View File
@@ -0,0 +1,54 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation
*
* 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/>.
*/
#include <glib.h>
#include <string.h>
#include "test-wmc-crc.h"
#include "test-wmc-escaping.h"
#include "test-wmc-utils.h"
#if GLIB_CHECK_VERSION(2,25,12)
typedef GTestFixtureFunc TCFunc;
#else
typedef void (*TCFunc)(void);
#endif
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
int main (int argc, char **argv)
{
GTestSuite *suite;
gint result;
g_test_init (&argc, &argv, NULL);
suite = g_test_get_root ();
g_test_suite_add (suite, TESTCASE (test_crc16_1, NULL));
g_test_suite_add (suite, TESTCASE (test_crc16_2, NULL));
g_test_suite_add (suite, TESTCASE (test_escape1, NULL));
g_test_suite_add (suite, TESTCASE (test_escape2, NULL));
g_test_suite_add (suite, TESTCASE (test_escape_unescape, NULL));
g_test_suite_add (suite, TESTCASE (test_utils_decapsulate_buffer, NULL));
g_test_suite_add (suite, TESTCASE (test_utils_encapsulate_buffer, NULL));
g_test_suite_add (suite, TESTCASE (test_utils_decapsulate_sierra_cns, NULL));
result = g_test_run ();
return result;
}
+206
View File
@@ -0,0 +1,206 @@
This document describes information about the Pantech UML290 and the WMC
protocol observed through USB packet capture and other investigation.
Pantech UML290 Notes
--------------------------------------
This device exposes 4 USB interfaces. They are, in no particular order, a
CDC-ACM compatible AT command port, a QCDM/Diag port, an WMC port, and a
raw IP network port. The modem's native command interface is the WMC port
which the Windows driver uses for all normal communication.
CDC-ACM AT Port
----------------
The modem's +GCAP response reports:
+GCAP: +CIS707-A, CIS-856, CIS-856-A, +CGSM, +CLTE1
and with recent firmware updates (L0290VWB333F.230 [Mar 15 2011 15:03:20] or
later) the device does, in fact, appear to support common IS-707-A and ETSI
27.007 GSM and LTE AT commands. This interface does support PPP data but when
PPP is used the device does not support handoffs between LTE and EVDO.
To support seamless operation of devices between LTE and EVDO Verizon has
upgraded their network to support the eHRPD protocol. Older, non-LTE capable
devices usually do not include support for eHRPD and use the standard HRPD
protocols. LTE-capable devices support both eHRPD and standard HRPD, but at
least with the UML290, connections to the 3G EVDO network using direct PPP over
the AT modem port do not use eHRPD. Thus to successfully connect to the 3G
EVDO network, the modem must be switched into standard HRPD mode by changing
the value of the NV_HDRSCP_FORCE_AT_CONFIG_I NVRAM item using the the QCDM/Diag
port and the DIAG protocol. Use of HRPD only prevents connections to the LTE
network. It is possible that connections initiated using the WMC port and
utilizing the "raw IP" network interface do not have this problem.
QCDM/Diag Port
----------------
This port is a normal QCDM/Diag port and responds to DIAG commands.
Raw IP Network Port
-------------------
This USB interface is the normal network interface port the device uses in
Windows for network communication. It appears to operate in a "raw IP" mode
where raw IP packets are sent and received over USB with no additional framing
or encapsulation. The IPv4 and IPv6 addresses for the interface are determined
using WMC commands on the WMC port, not through the AT command port. The AT
command port only supports PPP-based communication. More information about the
"raw IP" mode may be available in the Qualcomm CodeAurora SMD/QMI drivers which
implement a "raw IP" network communication mode for various MSM7xxx chipsets
used in Android devices.
WMC Port
-----------
This port accepts and responds to WMC protocol requests. Instead of using plain
WMC however, requests are prefixed with the string "AT*WMC=" and terminated with
a newline (0x0D) character instead of the normal WMC frame termination
character (0x7E). The data in between is normal binary WMC data, except that
all bytes less than 0x20 are escaped using normal HDLC/PPP escaping while a
normal WMC request would only escape the special HDLC/PPP characters of 0x7E and
0x7D. Thus a UML290 request looks like this in hexadecimal:
41542a574d433dc87d2a87b80d
This "AT"-style framing has not been observed on other devices.
WMC Protocol Framing
--------------------
The protocol is a request/response style protocol though unsolicited responses
are sometimes sent from the modem to the host. There does not appear to be any
sequence numbering in either the request or response packets. WMC packets
always begin with the frame start marker (0xC8). The second byte is the command
number, followed by the frame's data. The frame ends with a three-byte trailer
including a CRC-16 and a frame termination marker which differs between devices.
Most older devices use the standard HDLC/PPP frame termination marker (0x7E),
while some others (UML290) use a different termination marker as described
below. Thus a normal WMC packet looks like this:
0xC8 <command number> <data> <CRC-16> 0x7E
The entire frame (exclusive of the termination marker) is escaped using standard
HDLC/PPP escaping mechanisms to ensure that the bytes 0x7E and 0x7D never appear
in the packet. Some devices (UML290) escape more than the standard HDLC escape
characters.
Frames can span multiple USB packets. This behavior has been observed with the
PC5740 in various responses, in which case the frame is simply split up between
USB packets. It has also been observed with some UML290 requests, where it
appears that in addition to splitting the frame, each segment after the first
is prefixed with 0x20.
For example, a split response from a PC5740:
* c8 06 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 00 00 00 00 ................
...
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
...
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
...
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
...
00 00 00 01 ....
and an split request from a UML290:
* c8 56 86 02 00 00 00 00 00 00 39 30 30 30 38 30 .V........900080
...
00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
* 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
...
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
* 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
...
00 00 00 00 00 00 00 00 00 00 5b 1c 0d ..........[..
Requests
---------------
Requests are usually short, often only 4 or 5 bytes long, including the frame
start marker (0xC8), the command number, the 16-bit CRC, and the frame termination
marker. Requests almost always receive a response from the modem containing the
same command number.
The UML290 uses different "AT"-style framing of requests, prefixing the
request with "AT*WMC=" and using a frame termination marker of 0x0D instead
of the standard 0x7E. The UML290 also uses a different CRC-16 initial seed of
0xAAFE instead of the standard 0xFFFF used on other devices and with HDLC
framing in general. For added lolz the UML290 HDLC-escapes all control
characters in the request in addition to the standard 0x7D and 0x7E characters
escaped in HDLC.
Thus a normal WMC request (from a PC5740) looks like this:
c8 0a 77 a4 7e
<frame start> <cmd no> <CRC-16> <terminator>
while the same request from the UML290 looks like this:
41542a574d433d c8 7d2a 87 b8 0d
<AT*WMC=> <frame start> <cmd no> <CRC-16> <terminator>
Thus after removing all framing and escaping, this WMC request is a single
byte (0x0A) which indicates the command number of the request.
WMC Responses and Unsolicited Messages
--------------------------------------
Responses begin with the WMC frame start marker (0xC8) and end with the standard
HDLC/PPP frame terminator (0x7E) in all observed cases, even on the UML290.
The data in between is HDLC/PPP escaped and there is a CRC-16 before the frame
terminator. Not all devices use the same CRC-16 calculation however; the
UML290 always uses a CRC-16 of 0x3030, while the PC5740 includes a valid CRC-16
using a standard polynomial of 0x8408 and an initial seed of 0xFFFF. Responses
may span multiple USB packets if they are large enough, but the frame terminator
provides a convenient mechanism for detecting when the frame is complete.
A standard WMC response (from a UML290) looks like this:
c80d0000000030307e
which translates to:
c8 0d 00 00 00 00
WMC Command Numbers
-------------------
These command numbers have been observed and minimally investigated:
0x06: request device information, including manufacturer, model, firmware
revision, hardware revision, MCC/MNC, serial number
0x0A: request IP configuration when connected (IPv4 and IPv6) on the UML290; may
include elapsed connected time or traffic byte counts too. Request has
been observed on the PC5740 but is significantly shorter.
0x0B: get status including operator name, RSSI dBm, and possibly registration
status
0x13: retrieve SMS messages
0x4D: appears to request EPS bearer configuration; response includes the APN