diff options
author | erin_yueh <erin_yueh@99fdad57-331a-0410-800a-d7fa5415bdb3> | 2008-01-08 07:03:12 +0000 |
---|---|---|
committer | erin_yueh <erin_yueh@99fdad57-331a-0410-800a-d7fa5415bdb3> | 2008-01-08 07:03:12 +0000 |
commit | 3e57d49d7cf1fe0824720d720896ec181e35bd64 (patch) | |
tree | 677d620918cce5bb56a5f8f1ed0e98dc0914211f /src/gsmd | |
parent | 315e8b45506745f4b28f658772cc65cdef9a2d9e (diff) |
gsmd: fix segfault for list operator names (Sean Chiang)
git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@3784 99fdad57-331a-0410-800a-d7fa5415bdb3
Diffstat (limited to 'src/gsmd')
-rw-r--r-- | src/gsmd/usock.c | 125 |
1 files changed, 75 insertions, 50 deletions
diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c index 5caedac..a45a6b0 100644 --- a/src/gsmd/usock.c +++ b/src/gsmd/usock.c @@ -767,69 +767,94 @@ static int network_oper_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) return ret; } -static int network_opers_parse(const char *str, struct gsmd_msg_oper out[]) +static int network_opers_parse(const char *str, struct gsmd_msg_oper **out) { int len = 0; - int stat, n; - char opname_longalpha[16 + 1]; - char opname_shortalpha[8 + 1]; - char opname_num[6 + 1]; + struct gsm_extrsp *er; + char buf[64]; + char *head, *tail, *ptr; + struct gsmd_msg_oper *out2; if (strncmp(str, "+COPS: ", 7)) - goto final; - str += 7; - - while (*str == '(') { - if (out) { - out->is_last = 0; - if (sscanf(str, - "(%i,\"%16[^\"]\"," - "\"%8[^\"]\",\"%6[0-9]\")%n", - &stat, - opname_longalpha, - opname_shortalpha, - opname_num, - &n) < 4) - goto final; - out->stat = stat; - memcpy(out->opname_longalpha, opname_longalpha, - sizeof(out->opname_longalpha)); - memcpy(out->opname_shortalpha, opname_shortalpha, - sizeof(out->opname_shortalpha)); - memcpy(out->opname_num, opname_num, - sizeof(out->opname_num)); - } else - if (sscanf(str, - "(%*i,\"%*[^\"]\"," - "\"%*[^\"]\",\"%*[0-9]\")%n", - &n) < 0) - goto final; - if (n < 10 || str[n - 1] != ')') - goto final; - if (str[n] == ',') - n ++; - str += n; - len ++; - if (out) - out ++; + return -EINVAL; + + ptr = str; + while (*str) { + if ( *str == '(' && isdigit(*(str+1)) ) { + len++; + str+=2; + } + else + str++; } -final: - if (out) - out->is_last = 1; + + *out = talloc_size(__gu_ctx, sizeof(struct gsmd_msg_oper) * (len + 1)); + + if (!out) + return -ENOMEM; + + out2 = *out; + str = ptr; + + while (*str) { + if ( *str == '(' ) + head = str; + else if ( *str == ')' ) { + tail = str; + + memset(buf, '\0', sizeof(buf)); + strncpy(buf, head+1, (tail-head-1)); + + DEBUGP("buf: %s\n", buf); + + er = extrsp_parse(gsmd_tallocs, buf); + + if ( !er ) + return -ENOMEM; + + //extrsp_dump(er); + + if ( er->num_tokens == 4 && + er->tokens[0].type == GSMD_ECMD_RTT_NUMERIC && + er->tokens[1].type == GSMD_ECMD_RTT_STRING && + er->tokens[2].type == GSMD_ECMD_RTT_STRING && + er->tokens[3].type == GSMD_ECMD_RTT_STRING ) { + + /* + * +COPS=? +COPS: [list of supported (<stat>,long alphanumeric <oper> + * ,short alphanumeric <oper>,numeric <oper>)s] + */ + + out2->stat = er->tokens[0].u.numeric; + strcpy(out2->opname_longalpha, er->tokens[1].u.string); + strcpy(out2->opname_shortalpha, er->tokens[2].u.string); + strcpy(out2->opname_num, er->tokens[3].u.string); + } + else { + DEBUGP("Invalid Input : Parse error\n"); + talloc_free(*out); + return -EINVAL; + } + + talloc_free(er); + out2->is_last = 0; + out2 ++; + } + + str ++; + } + + out2->is_last = 1; return len; } static int network_opers_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { struct gsmd_user *gu = ctx; - struct gsmd_msg_oper *buf; + struct gsmd_msg_oper *buf = NULL; int len, ret; - len = network_opers_parse(resp, 0); - buf = talloc_size(__gu_ctx, sizeof(struct gsmd_msg_oper) * (len + 1)); - if (!buf) - return -ENOMEM; - network_opers_parse(resp, buf); + len = network_opers_parse(resp, &buf); ret = gsmd_ucmd_submit(gu, GSMD_MSG_NETWORK, GSMD_NETWORK_OPER_LIST, cmd->id, sizeof(*buf) * (len + 1), buf); |