-
Notifications
You must be signed in to change notification settings - Fork 104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Empty USSD answer #116
Comments
I bisected this problem because occasionally I use USSD to load prepaid cards, the problem appears for me in commit 868bbd4 by @magcks Can you verify? This commit should not have happened imho in this form, much too large and complex for a single commit. Always split up such changes in multiple steps to make it easier to bisect and diagnose problems. |
The trouble could be that the module sends this
while the old module sent this
Both signifying *101# as a simple USSD code. Try this patch which forces UCS-2 for USSD: diff --git a/at_command.c b/at_command.c
index 4882d82..408691e 100644
--- a/at_command.c
+++ b/at_command.c
@@ -335,36 +335,26 @@ EXPORT_DEF int at_enqueue_ussd(struct cpvt *cpvt, const char *code)
static const char cmd_end[] = "\",15\r";
at_queue_cmd_t at_cmd = ATQ_CMD_DECLARE_DYN(CMD_AT_CUSD);
ssize_t res;
- int length;
- char buf[4096];
+ char buf[160*4+sizeof(cmd)+sizeof(cmd_end)+1];
+
+ int length = STRLEN(cmd);
+ memcpy (buf, cmd, length);
- memcpy (buf, cmd, STRLEN(cmd));
- length = STRLEN(cmd);
int code_len = strlen(code);
+ if (code_len == 0 || code_len > 80) { // UCS-2 encoding
+ chan_dongle_err = E_INVALID_USSD;
+ return -1;
+ }
- // use 7 bit encoding. 15 is 00001111 in binary and means 'Language using the GSM 7 bit default alphabet; Language unspecified' accodring to GSM 23.038
- uint16_t code16[code_len * 2];
- uint8_t code_packed[4069];
- res = utf8_to_ucs2(code, code_len, code16, sizeof(code16));
+ res = utf8_to_ucs2(code, code_len, buf+length, sizeof(buf)-sizeof(cmd)-sizeof(cmd_end));
if (res < 0) {
chan_dongle_err = E_PARSE_UTF8;
return -1;
}
- res = gsm7_encode(code16, res, code16);
- if (res < 0) {
- chan_dongle_err = E_ENCODE_GSM7;
- return -1;
- }
- res = gsm7_pack(code16, res, code_packed, sizeof(code_packed), 0);
- if (res < 0) {
- chan_dongle_err = E_PACK_GSM7;
- return -1;
- }
- res = (res + 1) / 2;
- hexify(code_packed, res, buf + STRLEN(cmd));
- length += res * 2;
- memcpy(buf + length, cmd_end, STRLEN(cmd_end)+1);
+ hexify(buf+length, res*2, buf+length);
+ length += res * 4;
+ memcpy(buf+length, cmd_end, STRLEN(cmd_end)+1);
length += STRLEN(cmd_end);
at_cmd.length = length;
@@ -378,6 +368,7 @@ EXPORT_DEF int at_enqueue_ussd(struct cpvt *cpvt, const char *code)
chan_dongle_err = E_QUEUE;
return -1;
}
+
return 0;
}
diff --git a/at_response.c b/at_response.c
index 125a688..41a8990 100644
--- a/at_response.c
+++ b/at_response.c
@@ -1456,12 +1456,12 @@
typebuf[0] = type + '0';
typebuf[1] = 0;
- // sanitize DCS
- if (dcs & 0x40) {
+ // FIXME: strictly check USSD encoding and detect encoding
+ if (dcs >=0 && dcs & 0x40) {
dcs = (dcs & 0xc) >> 2;
if (dcs == 3) dcs = 0;
} else {
- dcs = 0;
+ dcs = 2;
}
ast_verb (1, "[%s] USSD DCS=%d (0: gsm7, 1: ascii, 2: ucs2)\n", PVT_ID(pvt), dcs); |
@bsdice I assume that Docs from 27007-g50.zip ( https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1515 ):
See also: /* bits 3..2 */
#define PDU_DCS_ALPHABET_SHIFT 2
#define PDU_DCS_ALPHABET_7BIT (0x00 << PDU_DCS_ALPHABET_SHIFT)
#define PDU_DCS_ALPHABET_8BIT (0x01 << PDU_DCS_ALPHABET_SHIFT)
#define PDU_DCS_ALPHABET_UCS2 (0x02 << PDU_DCS_ALPHABET_SHIFT)
#define PDU_DCS_ALPHABET_MASK (0x03 << PDU_DCS_ALPHABET_SHIFT)
#define PDU_DCS_ALPHABET(dcs) ((dcs) & PDU_DCS_ALPHABET_MASK) and /* Apparently bits 0..3 are not reserved anymore:
* bits 3..2: {7bit, 8bit, ucs2, undef} */
alphabet = PDU_DCS_ALPHABET(dcs);
/* Bits 3..2 set to 11 is reserved, but
* according to 3GPP TS 23.038 v14.0.0 (2017-03)
* for HIGH 1111 bit 3 (regardless of bit 2) is
* reserved. */
if (alphabet == PDU_DCS_ALPHABET_MASK) {
reserved = 1;
}
/* if 0x1 || 0xF then (dsc_lo & 3): {
* class0, class1-ME-specific,
* class2-SIM-specific,
* class3-TE-specific (3GPP TS 27.005)} */ |
But that changeset contained a bunch of good stuff too. It's always hard to make people adhere to best practices when no one is getting paid. I hereby welcome others to review changes too 😁 |
I totally get what you are saying. But did you ask? Younger programmers imho just don't know that splitting changes into smallish chunks aids in debugging immensely. Would have saved me hours yesterday. 😅 If you don't mind me asking, why are you keeping this fork current, if you don't even have hardware and are not using it? |
I tried, but I can't tell, because my German provider has likely locked me out. For, I guess, sending too many USSD queries to prevent brute-forcing prepaid cash token numbers? Hope they reset this at some point because I have zero hope of reaching any competent technician at that company. Yesterday USSD started working again for me after switching to UCS-2 format for send, and pretty much forcing UCS-2 for receive. So I am keeping my patch from above active on Asterisk 13.37 (what a nice number). Worthless dialog below. I also tried 0..3. Hardware is a Huawei K3765 11.126.03.09.00 USB 2G/3G dongle.
|
I don't recall. And I'm not making this a blame game. If you don't have infinite time and don't have infinite goodwill, you sometimes have to accept what's there.
That is indeed a good question 🤔 |
Uhh can't. Many reasons. But thanks. :) If you are serious though, one of the past committers will surely take it. Possibly write a note of this in README.md. Or just wait until somebody else forks it and starts to pull in patches from others. For reference to future readers I rolled back to 1d00a5d again and USSD works again. So my fix is worthless or not 100%. Or my USB stick is special aka firmware oddity. I vote to keep this open, maybe somebody will stumble onto this with time and energy to track the difference on the wire down. |
Some progress... maybe even insights:
With these changes USSD works again here. 🍰 diff --git a/at_command.c b/at_command.c
index 4882d82..b704ae0 100644
--- a/at_command.c
+++ b/at_command.c
@@ -87,7 +87,7 @@ static int __attribute__ ((format(printf, 2, 3))) at_fill_generic_cmd (at_queue_
* \return 0 on success
*/
-static int __attribute__ ((format(printf, 4, 5))) at_enqueue_generic(struct cpvt *cpvt, at_cmd_t cmd, int prio, const char *format, ...)
+EXPORT_DEF int __attribute__ ((format(printf, 4, 5))) at_enqueue_generic(struct cpvt *cpvt, at_cmd_t cmd, int prio, const char *format, ...)
{
va_list ap;
int rv;
@@ -132,7 +132,7 @@ EXPORT_DEF int at_enqueue_initialization(struct cpvt *cpvt, at_cmd_t from_comman
// static const char cmd18[] = "AT+CLIP=0\r";
static const char cmd19[] = "AT+CSSN=1,1\r";
static const char cmd20[] = "AT+CMGF=0\r";
- static const char cmd21[] = "AT+CSCS=\"UCS2\"\r";
+ static const char cmd21[] = "AT+CSCS=\"GSM\"\r";
static const char cmd22[] = "AT+CPMS=\"SM\",\"SM\",\"SM\"\r";
static const char cmd23[] = "AT+CNMI=2,1,0,2,0\r";
@@ -164,7 +164,7 @@ EXPORT_DEF int at_enqueue_initialization(struct cpvt *cpvt, at_cmd_t from_comman
ATQ_CMD_DECLARE_ST(CMD_AT_CSSN, cmd19), /* activate Supplementary Service Notification with CSSI and CSSU */
ATQ_CMD_DECLARE_ST(CMD_AT_CMGF, cmd20), /* Set Message Format */
-// ATQ_CMD_DECLARE_STI(CMD_AT_CSCS, cmd21), /* UCS-2 text encoding */
+ ATQ_CMD_DECLARE_STI(CMD_AT_CSCS, cmd21), /* GSM text encoding */
ATQ_CMD_DECLARE_ST(CMD_AT_CPMS, cmd22), /* SMS Storage Selection */
/* pvt->initialized = 1 after successful of CMD_AT_CNMI */
@@ -335,36 +335,26 @@ EXPORT_DEF int at_enqueue_ussd(struct cpvt *cpvt, const char *code)
static const char cmd_end[] = "\",15\r";
at_queue_cmd_t at_cmd = ATQ_CMD_DECLARE_DYN(CMD_AT_CUSD);
ssize_t res;
- int length;
- char buf[4096];
+ char buf[160*4+sizeof(cmd)+sizeof(cmd_end)+1];
+
+ int length = STRLEN(cmd);
+ memcpy (buf, cmd, length);
- memcpy (buf, cmd, STRLEN(cmd));
- length = STRLEN(cmd);
int code_len = strlen(code);
+ if (code_len == 0 || code_len > 80) { // UCS-2 encoding
+ chan_dongle_err = E_INVALID_USSD;
+ return -1;
+ }
- // use 7 bit encoding. 15 is 00001111 in binary and means 'Language using the GSM 7 bit default alphabet; Language unspecified' accodring to GSM 23.038
- uint16_t code16[code_len * 2];
- uint8_t code_packed[4069];
- res = utf8_to_ucs2(code, code_len, code16, sizeof(code16));
+ res = utf8_to_ucs2(code, code_len, buf+length, sizeof(buf)-sizeof(cmd)-sizeof(cmd_end));
if (res < 0) {
chan_dongle_err = E_PARSE_UTF8;
return -1;
}
- res = gsm7_encode(code16, res, code16);
- if (res < 0) {
- chan_dongle_err = E_ENCODE_GSM7;
- return -1;
- }
- res = gsm7_pack(code16, res, code_packed, sizeof(code_packed), 0);
- if (res < 0) {
- chan_dongle_err = E_PACK_GSM7;
- return -1;
- }
- res = (res + 1) / 2;
- hexify(code_packed, res, buf + STRLEN(cmd));
- length += res * 2;
- memcpy(buf + length, cmd_end, STRLEN(cmd_end)+1);
+ hexify(buf+length, res*2, buf+length);
+ length += res * 4;
+ memcpy(buf+length, cmd_end, STRLEN(cmd_end)+1);
length += STRLEN(cmd_end);
at_cmd.length = length;
@@ -374,10 +364,15 @@ EXPORT_DEF int at_enqueue_ussd(struct cpvt *cpvt, const char *code)
return -1;
}
+ if (at_enqueue_generic(cpvt, CMD_AT_CSCS, 0, "AT+CSCS=\"UCS2\"\r") != 0) {
+ chan_dongle_err = E_QUEUE;
+ return -1;
+ }
if (at_queue_insert(cpvt, &at_cmd, 1, 0) != 0) {
chan_dongle_err = E_QUEUE;
return -1;
}
+
return 0;
}
diff --git a/at_command.h b/at_command.h
index 32535d6..0b5b81d 100644
--- a/at_command.h
+++ b/at_command.h
@@ -123,5 +123,6 @@ EXPORT_DECL int at_enqueue_activate(struct cpvt *cpvt);
EXPORT_DECL int at_enqueue_flip_hold(struct cpvt *cpvt);
EXPORT_DECL int at_enqueue_conference(struct cpvt *cpvt);
EXPORT_DECL void at_hangup_immediality(struct cpvt *cpvt);
+EXPORT_DECL int __attribute__ ((format(printf, 4, 5))) at_enqueue_generic(struct cpvt *cpvt, at_cmd_t cmd, int prio, const char *format, ...);
#endif /* CHAN_DONGLE_AT_SEND_H_INCLUDED */
diff --git a/at_response.c b/at_response.c
index 125a688..541459c 100644
--- a/at_response.c
+++ b/at_response.c
@@ -140,9 +140,8 @@ static int at_response_ok (struct pvt* pvt, at_res_t res)
break;
case CMD_AT_CSCS:
- ast_debug (1, "[%s] UCS-2 text encoding enabled\n", PVT_ID(pvt));
-
- pvt->use_ucs2_encoding = 1;
+ ast_debug (1, "[%s] Text encoding set\n", PVT_ID(pvt));
+ //pvt->use_ucs2_encoding = 1;
break;
case CMD_AT_CPMS:
@@ -1438,6 +1437,9 @@ static int at_response_cusd (struct pvt * pvt, char * str, size_t len)
char typebuf[2];
const char* typestr;
+
+ at_enqueue_generic(&pvt->sys_chan, CMD_AT_CSCS, 1, "AT+CSCS=\"GSM\"\r");
+
manager_event_message("DongleNewCUSD", PVT_ID(pvt), str);
if (at_parse_cusd (str, &type, &cusd, &dcs))
@@ -1456,12 +1458,12 @@ static int at_response_cusd (struct pvt * pvt, char * str, size_t len)
typebuf[0] = type + '0';
typebuf[1] = 0;
- // sanitize DCS
- if (dcs & 0x40) {
+ // FIXME: strictly check USSD encoding and detect encoding
+ if (dcs >=0 && dcs & 0x40) {
dcs = (dcs & 0xc) >> 2;
if (dcs == 3) dcs = 0;
} else {
- dcs = 0;
+ dcs = 2;
}
ast_verb (1, "[%s] USSD DCS=%d (0: gsm7, 1: ascii, 2: ucs2)\n", PVT_ID(pvt), dcs); |
Thanks for the updates. Okay. Calling
first in your case sounds good and portable. Switching to back and from UCS2 feels icky if it can be avoided. If it must be switched, then it should be called before every other command that uses any encoding (set ucs2 before cusd, set gsm before sms). And after setting GSM, I wonder if the data should be hexlify'd at all.. And have you tried P.S.
There is no >0x7F in ASCII. All 8bit-on characters uses some charset (latin1, cp437, cp850...). |
I tried ,32 but all the stick would accept is ,15, no matter what CSCS is set to (IRA, GSM, UCS2). Then I experimented with sending plain ASCII *102# while CSCS=GSM, but parsing here is totally broken. The string that comes back from my stick uses the GSM charset alright, together with some escapes for Euro-sign etc. But it is not GSM-7 encoded i.e. 7-bit characters shifted into 8-bit. Also my string is not "hexified", so whatever @magcks's stick is producing, this will never work with my stick. Only the UCS2 code path works. While there I also discovered a serious parsing flaw in at_parse.c, function at_parse_cusd. If non-UCS2-text comes back from the network and it contains commas, the code will fall over and produce pruned strings, because it assumes commas are unique delimiters of fields, which they aren't if between double quotes. There was an earlier code from back in 2010 (the bug is this old) which works that I adapted: EXPORT_DEF int at_parse_cusd (char* str, int * type, char** cusd, int * dcs)
{
/*
* parse cusd message in the following format:
* +CUSD: <m>,[<str>,<dcs>]
*
* examples
* +CUSD: 5
* +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#.",15
*/
int state;
int len = strlen (str);
char* p = NULL;
size_t i;
*cusd = NULL;
*dcs = 0;
if (!sscanf(str, "+CUSD: %u,", type)) {
return -1;
}
for (i = 0, state = 0; i < len && state < 5; i++)
{
switch (state)
{
case 0:
if (str[i] == '"')
{
state++;
}
break;
case 1:
if (cusd)
{
*cusd = &str[i];
state++;
}
break;
case 2:
if (str[i] == '"')
{
str[i] = '\0';
state++;
}
break;
case 3:
if (str[i] == ',')
{
state++;
}
break;
case 4:
p = &str[i];
state++;
break;
}
}
if (state != 5)
{
return -1;
}
errno = 0;
*dcs = (unsigned char) strtol (p, (char**) NULL, 10);
if (errno == EINVAL)
{
return -1;
}
return 0;
} |
As far as I see, the problem is: Different devices reqire different code implementation and we can't automaticaly find the correct way. Is it posible to leave previous implementation with posibility to turn it on at dongle.config? P.S. Do you have any workaround ideas? e.g. custom dongle init string or switching dongle encoding mode by extra command at extention.conf ussd section? |
Hello!
Previous version worked fine at the same equipment, but now USSD answers are empty:
[dongle-incoming-ussd]
exten => ussd,1,Noop(Incoming USSD: ${USSD} ${USSD_BASE64})
exten => ussd,n,Hangup()
[Sep 18 11:51:20] NOTICE[26464]: at_response.c:268 at_response_ok: [gsm1] Successfully sent USSD 0x76602ad8
[gsm1] USSD DCS=2 (0: gsm7, 1: ascii, 2: ucs2)
[gsm1] Got USSD type 0 'USSD Notify': ''
-- Executing [ussd@dongle-incoming:1] NoOp("Local/ussd@dongle-incoming-00000000;1", "Incoming USSD: AAAAAAAAAAAAAAAAAAA=") in new stack
...
The text was updated successfully, but these errors were encountered: