summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Meyerriecks <rmeyerreicks@digium.com>2012-07-11 16:13:22 +0000
committerRuss Meyerriecks <rmeyerreicks@digium.com>2012-07-11 16:13:22 +0000
commit56661e97ee2f47f7c8ec1fe39e943103bc3ce476 (patch)
treeceb5b010ef78677fdda7d9aba30d2133b23bfa4e
parentcff227deb179d34e44b26669869a057f8924c61a (diff)
wcte12xp: Fix stack corruption when checking T1 RBS states.
This fixes an (embarrassing) error in t1_check_sigbits in the previous commit where I was writing pass the end of an array on the stack. Now instead of using an array on the stack, of which all elements were not used, the pending commands are now stored on a list. I also removed the automatic free of commands from __t1_getresults and now the function that allocated the command now frees them. I believe this will be less error-prone going forward. Signed-off-by: Shaun Ruffell <sruffell@digium.com> Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10700 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/wcte12xp/base.c112
1 files changed, 85 insertions, 27 deletions
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
index 8eec46c..18f1129 100644
--- a/drivers/dahdi/wcte12xp/base.c
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -688,18 +688,20 @@ static int __t1_getresult(struct t1 *wc, struct command *cmd)
}
}
ret = cmd->data;
- free_cmd(wc, cmd);
return ret;
}
static int t1_getreg(struct t1 *wc, int addr)
{
+ int res;
struct command *cmd = NULL;
cmd = get_free_cmd(wc);
if (!cmd)
return -ENOMEM;
__t1_getreg(wc, addr, cmd);
- return __t1_getresult(wc, cmd);
+ res = __t1_getresult(wc, cmd);
+ free_cmd(wc, cmd);
+ return res;
}
static void t1_setleds(struct t1 *wc, int leds)
@@ -1195,27 +1197,45 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits)
static void t1_check_sigbits(struct t1 *wc)
{
- struct command *cmds[15] = {NULL,};
+ struct command_container {
+ struct command *cmd;
+ struct list_head node;
+ unsigned int index;
+ };
+ struct command_container *cont;
+ LIST_HEAD(commands);
int a,i,rxs;
if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags)))
return;
+
if (dahdi_is_e1_span(&wc->span)) {
/* Send out all the commands first. */
for (i = 0; i < 15; i++) {
if (!(wc->span.chans[i+16]->sig & DAHDI_SIG_CLEAR) ||
!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) {
- cmds[i] = get_free_cmd(wc);
- __t1_getreg(wc, 0x71 + i, cmds[i]);
+ cont = kzalloc(sizeof(*cont), GFP_KERNEL);
+ if (!cont) {
+ WARN_ON_ONCE(1);
+ goto done;
+ }
+ cont->cmd = get_free_cmd(wc);
+ if (!cont->cmd) {
+ WARN_ON_ONCE(1);
+ goto done;
+ }
+ cont->index = i;
+ list_add_tail(&cont->node, &commands);
+ __t1_getreg(wc, 0x71 + i, cont->cmd);
}
}
/* Now check the results */
- for (i = 14; i >= 0; --i) {
- struct command *cmd = cmds[i];
- if (!cmd)
- continue;
- a = __t1_getresult(wc, cmd);
+ list_for_each_entry_reverse(cont, &commands, node) {
+ i = cont->index;
+ a = __t1_getresult(wc, cont->cmd);
+ free_cmd(wc, cont->cmd);
+ cont->cmd = NULL;
if (a > -1) {
/* Get high channel in low bits */
rxs = (a & 0xf);
@@ -1234,18 +1254,28 @@ static void t1_check_sigbits(struct t1 *wc)
}
} else if (wc->span.lineconfig & DAHDI_CONFIG_D4) {
/* First we'll send out the commands */
- for (i = 0; i < 24; i+=4) {
- cmds[i] = get_free_cmd(wc);
- if (!cmds[i]) {
- WARN_ON(1);
- return;
+ for (i = 0; i < 24; i += 4) {
+ cont = kzalloc(sizeof(*cont), GFP_KERNEL);
+ if (!cont) {
+ WARN_ON_ONCE(1);
+ goto done;
+ }
+ cont->cmd = get_free_cmd(wc);
+ if (!cont->cmd) {
+ WARN_ON_ONCE(1);
+ goto done;
}
- __t1_getreg(wc, 0x70 + (i>>2), cmds[i]);
+ cont->index = i;
+ list_add_tail(&cont->node, &commands);
+ __t1_getreg(wc, 0x70 + (i>>2), cont->cmd);
}
/* Now we'll check the results */
- for (i = 20; i >= 0; i -= 4) {
- a = __t1_getresult(wc, cmds[i]);
+ list_for_each_entry_reverse(cont, &commands, node) {
+ i = cont->index;
+ a = __t1_getresult(wc, cont->cmd);
+ free_cmd(wc, cont->cmd);
+ cont->cmd = NULL;
if (a > -1) {
/* Get high channel in low bits */
rxs = (a & 0x3) << 2;
@@ -1276,17 +1306,27 @@ static void t1_check_sigbits(struct t1 *wc)
}
} else {
/* First send out the commands. */
- for (i = 0; i < 24; i+=2) {
- cmds[i] = get_free_cmd(wc);
- if (!cmds[i]) {
- WARN_ON(1);
- return;
+ for (i = 0; i < 24; i += 2) {
+ cont = kzalloc(sizeof(*cont), GFP_KERNEL);
+ if (!cont) {
+ WARN_ON_ONCE(1);
+ goto done;
}
- __t1_getreg(wc, 0x70 + (i>>1), cmds[i]);
+ cont->cmd = get_free_cmd(wc);
+ if (!cont->cmd) {
+ WARN_ON_ONCE(1);
+ goto done;
+ }
+ cont->index = i;
+ list_add_tail(&cont->node, &commands);
+ __t1_getreg(wc, 0x70 + (i>>1), cont->cmd);
}
- /* Now check the results. */
- for (i = 22; i >= 0; i -= 2) {
- a = __t1_getresult(wc, cmds[i]);
+
+ list_for_each_entry_reverse(cont, &commands, node) {
+ i = cont->index;
+ a = __t1_getresult(wc, cont->cmd);
+ free_cmd(wc, cont->cmd);
+ cont->cmd = NULL;
if (a > -1) {
/* Get high channel in low bits */
rxs = (a & 0xf);
@@ -1304,6 +1344,21 @@ static void t1_check_sigbits(struct t1 *wc)
}
}
}
+done:
+ while (!list_empty(&commands)) {
+ cont = container_of(commands.next,
+ struct command_container, node);
+ if (unlikely(cont->cmd)) {
+ /* We do not care about the result, let's just wait for
+ * the rest of the system to finish with it. */
+ __t1_getresult(wc, cont->cmd);
+ free_cmd(wc, cont->cmd);
+ cont->cmd = NULL;
+ }
+ list_del(&cont->node);
+ kfree(cont);
+ }
+ return;
}
struct maint_work_struct {
@@ -2118,6 +2173,9 @@ static void t1_check_alarms(struct t1 *wc)
fmr4 = __t1_getresult(wc, cmds[1]);
c = __t1_getresult(wc, cmds[0]);
+ for (x=0; x < ARRAY_SIZE(cmds); ++x)
+ free_cmd(wc, cmds[x]);
+
/* Assume no alarms */
alarms = 0;