K2.6 patches and update.
[tomato.git] / release / src-rt / wl / exe / shellproc_linux.c
blobd0fca41acadaf9f4d1f757422c31de03a29298ec
1 /*
2 * Remote shell command execution (common for all transports) for linux
4 * Copyright (C) 2010, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
12 * $Id: shellproc_linux.c,v 1.12 2009-08-11 08:51:01 Exp $
15 /* Linux remote shell command execution
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <sys/socket.h>
27 #include <sys/select.h>
28 #include <sys/types.h>
29 #include <netinet/in.h>
30 #include <sys/wait.h>
31 #include <signal.h>
32 #include <fcntl.h>
33 #include <typedefs.h>
34 #include <bcmutils.h>
35 #include <bcmcdc.h>
36 #include "wlu_remote.h"
37 #include <sys/poll.h>
38 #ifndef MACOSX
39 #include <malloc.h>
40 #endif
41 #include <miniopt.h>
42 #include <sys/utsname.h>
43 #define ASYNC_RESP 0
44 #define MAX_SHELL_ASYNC_RESP 128 /* Support for maximum 5 async process */
45 #define MAX_ASYNC_FILE_LENGTH 50
46 #define MAX_PID_CMD_LENGTH 20
47 #define MAX_PID_RESP_LENTH 50
48 #define MAX_SHELL_CMD_LENTH 256
49 #define PID_TOKEN_SIZE 50
50 #define PID_SEARCH_CMD_SIZE 100
51 #define ASYNC_SHELL_CHAR "%" /* Async process identifier from the client */
52 #define FILE_PERMISSION 777
54 #define DEFAULT_SHELL_TIMEOUT 0 /* Default TimeOut Value for synchronous shell commands */
55 #define SHELL_RETURNVALUE_SIZE 2 /* Size of Return Value of the shell command */
56 #define SHELL_ASYNCCMD_ID 1 /* To identify if it is an async command */
57 #define REBOOT_MSG "Rebooting AP ...\n"
59 /* Function prototypes */
61 static int rwl_get_file_size(char *file_name);
62 static int remote_shell_async_exec(char *buf_ptr);
63 static int remote_shell_sync_exec(char *cmd_buf_ptr, void *wl);
66 /* Data structure to hold async shell information */
67 typedef struct remote_shell_async {
68 pid_t PID;
69 char file_name[MAX_ASYNC_FILE_LENGTH];
70 } remote_shell_async_t;
72 remote_shell_async_t g_async_resp[MAX_SHELL_ASYNC_RESP];
74 extern int g_shellsync_pid;
76 extern unsigned char g_return_stat;
77 extern void rwl_chld_handler(int num);
78 extern int set_ctrlc;
79 extern void handle_ctrlc(int unused);
81 /* Global variable to store the timeout value for the shell commands */
82 static int g_shellsync_timeout = DEFAULT_SHELL_TIMEOUT;
83 char globalbuffer[MAX_SHELL_CMD_LENTH];
85 /* Wait for process termination.
86 * This function returns immediately if the child has
87 * already exited (zombie process)
89 static void
90 sigchld_handler(int s)
92 UNUSED_PARAMETER(s);
94 while (waitpid(-1, NULL, WNOHANG) > 0);
97 /* Create a main directory \tmp\RWL\ for the shell response files */
98 int
99 rwl_create_dir(void)
101 #ifndef MACOSX
102 if (mkdir(SHELL_RESP_PATH, FILE_PERMISSION) < 0) {
103 if (errno != EEXIST)
104 return BCME_ERROR;
106 #else
107 system("mkdir -p /tmp/RWL");
108 #endif /* mkdir linux command doesnot work in MAC, hence using shell */
110 return SUCCESS;
113 /* Main function for shell command execution */
115 remote_shell_execute(char* buf_ptr, void *wl)
117 char *async_cmd_flag;
118 int msg_len;
120 /* Check for the "%" token in the buffer from client
121 * If "%" token is present, execute asynchronous process
122 * else, execute synchronous shell process
124 async_cmd_flag = strstr((char*)buf_ptr, ASYNC_SHELL_CHAR);
126 if ((async_cmd_flag != NULL) && (!strcmp(async_cmd_flag, ASYNC_SHELL_CHAR))) {
127 g_shellsync_pid = SHELL_ASYNCCMD_ID;
128 msg_len = remote_shell_async_exec(buf_ptr);
130 else {
131 msg_len = remote_shell_sync_exec(buf_ptr, wl);
132 strcpy(buf_ptr, globalbuffer);
134 return msg_len;
137 /* Function to get the shell response from the file */
139 remote_shell_async_get_resp(char* shell_fname, char* buf_ptr, int msg_len)
141 int sts = 0;
142 FILE *shell_fpt;
144 shell_fpt = fopen(shell_fname, "rb");
146 if (shell_fpt == NULL) {
147 DPRINT_ERR(ERR, "\nShell Cmd:File open error\n");
148 return sts;
151 /* If there is any response from the shell, Read the file and
152 * update the buffer for the shell response
153 * else Just send the return value of the command executed
155 if (g_shellsync_pid != SHELL_ASYNCCMD_ID) {
156 if (msg_len)
157 sts = fread(buf_ptr, sizeof(char), msg_len, shell_fpt);
158 fscanf(shell_fpt, "%2x", &sts);
160 else
161 sts = fread(buf_ptr, sizeof(char), MAX_SHELL_CMD_LENTH, shell_fpt);
163 fclose(shell_fpt);
165 remove(shell_fname);
167 DPRINT_DBG(OUTPUT, "\n Resp buff from shell cmdis %s\n", buf_ptr);
169 return sts;
173 * Function to get the shell response length
174 * by opening the file containing the shell response
175 * and get the total file size.
176 * For a given input file name it returns File size.
178 static int
179 rwl_get_file_size(char *file_name)
181 FILE *shell_fpt;
182 int filesize = 0;
184 shell_fpt = fopen(file_name, "rb");
186 if (shell_fpt == NULL) {
187 DPRINT_DBG(OUTPUT, "\nShell Cmd:File open error\n");
188 return filesize;
191 /* obtain file size */
192 if (fseek(shell_fpt, 0, SEEK_END) < 0)
193 return filesize;
195 filesize = ftell(shell_fpt);
196 fclose(shell_fpt);
198 return filesize;
202 * Function for executing asynchronous shell comamnd
203 * Stores the results in async temp file and returns the PID
205 static int
206 remote_shell_async_exec(char *buf_ptr)
208 int PID_val, val, msg_len, sts;
209 FILE *fpt;
210 int async_count = 0; /* counter needs to be initialized */
211 struct sigaction sa;
212 char pid_search_cmd[MAX_PID_CMD_LENGTH];
213 char pid_resp_buf[MAX_PID_RESP_LENTH];
214 char temp_async_file_name[MAX_ASYNC_FILE_LENGTH];
215 pid_t pid;
216 char *pid_token, next_pid[PID_TOKEN_SIZE][PID_TOKEN_SIZE];
217 struct utsname name;
219 /* Call the signal handler for reaping defunct or zombie process */
220 sa.sa_handler = sigchld_handler;
221 sigemptyset(&sa.sa_mask);
222 sa.sa_flags = SA_RESTART;
223 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
224 perror("sigaction:");
227 /* Store the async file name if that async process is not killed.
228 * Async file name: async_temp_0...5
230 for (val = 0; val < MAX_SHELL_ASYNC_RESP; val++) {
231 if (g_async_resp[val].PID > 0) {
232 async_count++;
233 } else {
234 sprintf(g_async_resp[val].file_name, "%s%d", "async_temp_", val);
235 break;
238 sprintf(temp_async_file_name, "%s%s", SHELL_RESP_PATH,
239 g_async_resp[val].file_name);
241 DPRINT_DBG(OUTPUT, "\nasync_count:%d\n", async_count);
242 if (async_count >= MAX_SHELL_ASYNC_RESP) {
243 sprintf(buf_ptr, "\n%s\n", "Exceeded max async process forking");
244 return BCME_ERROR;
247 /* Open a child process. The fork will return the PID of the child process
248 * (i.e) defunct process PID in parent's thread of execution. Zero is returned
249 * for child's thread of execution.
251 if ((pid = fork()) == 0) {
252 /* Redirect the async process output to the async file
253 * Then after the client executes the kill command for that
254 * async process, the file will give the status of async process
256 strtok(buf_ptr, ASYNC_SHELL_CHAR); /* Remove % character from the command buf */
257 uname(&name);
259 * Checking for mips architecture
260 * different command for mips and x86
262 if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) {
263 strcat(buf_ptr, "&> "); /* buf_ptr is now "ping 127.0.0.1&> " */
264 strcat(buf_ptr, temp_async_file_name); /* Add path \tmp\RWL\async_temp_* */
266 else {
267 strcat(buf_ptr, " > "); /* buf_ptr is now "ping 127.0.0.1> " */
268 strcat(buf_ptr, temp_async_file_name); /* Add path \tmp\RWL\async_temp_* */
269 strcat(buf_ptr, " 2>&1 &");
271 if ((sts = execl(SH_PATH, "sh", "-c", buf_ptr, NULL)) == -1) {
272 sprintf(buf_ptr, "%s\n", "Not able to execute shell cmd");
273 return BCME_ERROR;
275 exit(0);
276 } /* end of fork */
278 if (pid < 0) {
279 perror("\nFork error:");
280 sprintf(buf_ptr, "%s\n", "Forking async process failed");
281 return BCME_ERROR;
284 /* Find the PID of the running process (for ex: ping)
285 * pidof -s options returns latest PID of the command.
287 strtok(buf_ptr, " ");
289 uname(&name);
290 /* Checking for mips architecture */
291 if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0)
292 sprintf(pid_search_cmd, "pidof -s %s", buf_ptr);
293 else
294 sprintf(pid_search_cmd, "pidof %s", buf_ptr);
296 sleep(1);
298 /* Execute the command e.g "pidof ping" */
299 if ((fpt = popen(pid_search_cmd, "r")) == NULL) {
300 sprintf(buf_ptr, "%s\n", "Can't return PID");
301 return BCME_ERROR;
304 /* Get the PID and copy the PID in buf_ptr to send to the client */
305 fgets(pid_resp_buf, sizeof(pid_resp_buf), fpt);
307 /* Checking for mips architecture */
308 if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) {
309 PID_val = atoi(pid_resp_buf);
311 else {
312 /* code to extract the correct PID */
313 pid_token = strtok_r(pid_resp_buf, " ", (char **)next_pid);
314 if (pid_token != NULL) {
315 while (pid_token != NULL) {
316 /* the pid buffer will terminate with a '\n'
317 * It will affect the string tokenizing logic
318 * To avoid this we're using the if case
320 if (strncmp(pid_token, "\n", sizeof(pid_token)) == 0)
321 break;
322 PID_val = atoi(pid_token);
323 pid_token = strtok_r(NULL, " ", (char **)next_pid);
326 else
327 PID_val = atoi(pid_token);
329 if (PID_val == 0) {
330 msg_len = rwl_get_file_size(temp_async_file_name);
331 remote_shell_async_get_resp(temp_async_file_name, buf_ptr, msg_len);
333 } else {
334 g_async_resp[val].PID = PID_val;
335 /* Update PID value in buffer to send it to client */
336 sprintf(buf_ptr, "%d", PID_val);
337 msg_len = strlen(buf_ptr);
340 pclose(fpt);
341 /* In async case, the PID value will be copied to the input buffer only
342 * and there is no need of getting the response from the file. So return
343 * value can be -1.
345 return msg_len;
348 /* Process for 'kill' command.
349 * Kill command can also be used from the client to get the
350 * result of asynchronous command and actually kill the mentioned process
352 static int
353 remote_kill_cmd_exec(char *cmd_buf_ptr)
355 char file_name[MAX_ASYNC_FILE_LENGTH];
356 int PID_val, val, msg_len;
357 FILE *fpt;
358 char *pid_token, next_pid[PID_TOKEN_SIZE][PID_TOKEN_SIZE];
360 system(cmd_buf_ptr);
362 /* Parse the PID val from the kill command.
364 pid_token = strtok_r(cmd_buf_ptr, " ", (char **)next_pid);
365 while (pid_token != NULL) {
366 /* to extract the PID from the kill command */
367 if (strncmp(pid_token, "\n", sizeof(pid_token)) == 0)
368 break;
369 PID_val = atoi(pid_token);
370 pid_token = strtok_r(NULL, " ", (char **)next_pid);
373 /* Check for the matching PID from the async structure and
374 * give the last 256 bytes statistics of the async process
375 * that was running
377 for (val = 0; val < MAX_SHELL_ASYNC_RESP; ++val) {
378 if (g_async_resp[val].PID == PID_val) {
379 /* We found a match here. Hence get the response now from the
380 * corresponding async response file
382 sprintf(file_name, "%s%s", SHELL_RESP_PATH, g_async_resp[val].file_name);
383 msg_len = rwl_get_file_size(file_name);
384 if (msg_len > 0) {
385 if ((fpt = fopen(file_name, "rb")) == NULL) {
386 DPRINT_DBG(OUTPUT, "\nShell Cmd:File open error\n");
387 return BCME_ERROR;
390 if (fseek(fpt, 0, SEEK_SET) < 0) {
391 fclose(fpt);
392 return BCME_ERROR;
395 if (fread(cmd_buf_ptr, sizeof(char), MAX_SHELL_CMD_LENTH,
396 fpt) <= 0) {
397 sprintf(cmd_buf_ptr, "%s\n", "Shell Resp:Reading error");
398 fclose(fpt);
399 return BCME_ERROR;
402 fclose(fpt);
404 else
405 sprintf(cmd_buf_ptr, "ed %d: No Response\n", PID_val);
406 remove(g_async_resp[val].file_name);
408 g_async_resp[val].PID = 0;
409 break;
412 return MAX_SHELL_CMD_LENTH;
415 /* Handle --timeout command line option for linux servers */
417 shell_timeout_cmd(char *cmd_buf_ptr, char *sync_file_name)
419 char *token1, *token2, *nexttoken;
420 FILE* fp;
421 int msg_len;
423 token1 = strtok_r(cmd_buf_ptr, "--timeout ", &nexttoken);
424 if (token1)
425 token2 = strtok_r(NULL, token1, &nexttoken);
426 if (token1 == NULL || atoi(token1) <= 0 || token2 == NULL) {
427 fp = fopen(sync_file_name, "w+");
428 fprintf(fp, "Usage: ./wl --<transport> <ip/mac> sh"
429 "--timeout <timeout value> <shell command>\n");
430 fprintf(fp, "Eg: ./wl --socket 172.22.65.226 sh --timeout 15 ls\n");
431 fflush(fp);
432 msg_len = rwl_get_file_size(sync_file_name);
433 strcpy(cmd_buf_ptr, sync_file_name);
434 fclose(fp);
435 strcpy(globalbuffer, sync_file_name);
436 printf("Fix timeout problem in socket!!!!!\n");
437 return msg_len;
439 else
440 g_shellsync_timeout = atoi(token1);
441 return BCME_OK;
444 /* Handle synchronous shell commands here */
445 static int
446 remote_shell_sync_exec(char *cmd_buf_ptr, void *wl)
448 char *kill_cmd_token;
449 char sync_file_name[] = TEMPLATE;
450 int fd, msg_len;
451 char cmd[(strlen(cmd_buf_ptr) + 1)];
452 int pid, status, pid_final;
453 char buf[SHELL_RESP_SIZE], cmd_find_lastpid[PID_SEARCH_CMD_SIZE];
454 int nbytes = 0;
455 int child_status;
456 static int sent_once = 0;
457 struct utsname name;
458 FILE *fpt;
460 /* Default Size of Return Value of the shell command is 2bytes */
462 kill_cmd_token = strstr(cmd_buf_ptr, "kill");
464 /* Synchronous Kill command processing is handled separately */
465 if (kill_cmd_token != NULL) {
466 msg_len = remote_kill_cmd_exec(cmd_buf_ptr);
467 remote_tx_response(wl, cmd_buf_ptr, msg_len);
468 return 0;
472 /* Process synchronous command other than kill command */
473 if ((fd = mkstemp(sync_file_name)) < 0) {
474 perror("mkstemp failed");
475 DPRINT_ERR(ERR, "\n errno:%d\n", errno);
476 sprintf(cmd_buf_ptr, "%s\n", "mkstemp failed");
477 return BCME_ERROR;
480 close(fd);
482 strcpy(cmd, cmd_buf_ptr);
483 /* Synchronous timeout command processing is handled separately */
484 if (strstr(cmd_buf_ptr, "--timeout") != NULL) {
485 if ((msg_len = shell_timeout_cmd (cmd, sync_file_name) > 0)) {
486 /* Signal end of command output */
487 g_rem_ptr->msg.len = 0;
488 g_rem_ptr->msg.cmd = g_return_stat;
489 remote_tx_response(wl, NULL, 0);
490 return msg_len;
491 } else {
492 /* Parse out --timeout <val> since command is successful
493 * point buffer to the shell command
495 strcpy(cmd, cmd_buf_ptr);
496 strtok_r(cmd, " ", &cmd_buf_ptr);
497 strcpy(cmd, cmd_buf_ptr);
498 strtok_r(cmd, " ", &cmd_buf_ptr);
502 /* Schedule an ALARM in case of timeout value of SHELL_TIMEOUT seconds */
503 /* Defalut time out only in case of Non socket transport */
504 alarm(g_shellsync_timeout);
505 /* registering the relevant signals to handle end of child process,
506 * the ctrl+c event on the server side and the kill command on the
507 * server process
509 signal(SIGCHLD, rwl_chld_handler);
510 signal(SIGINT, handle_ctrlc);
511 signal(SIGTERM, handle_ctrlc);
513 /* Set g_sig_chld before forking */
514 g_sig_chld = 1;
516 if (strcmp("reboot", cmd_buf_ptr) == 0) { /* reboot command */
517 memset(buf, 0, sizeof(buf));
518 strncpy(buf, REBOOT_MSG, sizeof(REBOOT_MSG));
519 remote_tx_response(wl, buf, 0);
521 /* Signal end of command output */
522 g_rem_ptr->msg.len = 0;
523 g_rem_ptr->msg.cmd = 0;
524 remote_tx_response(wl, NULL, 0);
525 sleep(1);
527 /* Clean up the temp file */
528 remove(sync_file_name);
531 if ((pid = fork()) == 0) {
532 close(STDOUT_FILENO);
533 fd = open(sync_file_name, O_WRONLY|O_SYNC);
534 /* Redirect stdin to dev/null. This handles un usual commands like
535 * sh cat from the client side
537 close(STDIN_FILENO);
538 open("/dev/null", O_RDONLY);
539 close(STDERR_FILENO);
540 fcntl(fd, F_DUPFD, STDERR_FILENO);
541 if ((status = execl(SH_PATH, "sh", "-c", cmd_buf_ptr, NULL)) == -1) {
542 perror("Exec error");
545 } /* end of fork */
547 g_shellsync_pid = pid;
548 /* The g_return_stat is being set for short commands */
549 waitpid(g_shellsync_pid, &child_status, WNOHANG);
550 if (WIFEXITED(child_status))
551 g_return_stat = WEXITSTATUS(child_status);
552 else
553 g_return_stat = 1;
555 /* Read file in the interim from a temp file and send back the results */
556 fd = open(sync_file_name, O_RDONLY|O_SYNC);
558 while (1) {
559 /* read file in the interim and send back the results */
560 nbytes = read(fd, buf, SHELL_RESP_SIZE);
561 g_rem_ptr->msg.len = nbytes;
562 if (nbytes > 0) {
563 remote_tx_response(wl, buf, 0);
564 #ifdef RWL_SERIAL
565 /* usleep introduced for flooding of data over serial port */
566 usleep(1);
567 #endif
569 if (get_ctrlc_header(wl) >= 0) {
570 if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) {
571 uname(&name);
572 /* Checking for mips architecture
573 * The mips machine responds differently to
574 * execl command. so the pid is incremented
575 * to kill the right command.
577 if (strncmp(name.machine, "mips", sizeof(name.machine)) == 0)
578 pid++;
579 if (strncmp(name.machine, "armv5tel", sizeof(name.machine)) == 0) {
580 snprintf(cmd_find_lastpid, sizeof(cmd_find_lastpid),
581 "ps | awk \'PRINT $1\' | tail -n 1");
582 if ((fpt = popen(cmd_find_lastpid, "r")) == NULL) {
583 sprintf(buf, "%s\n", "Can't return PID");
584 return BCME_ERROR;
586 fgets(cmd_find_lastpid, sizeof(cmd_find_lastpid), fpt);
587 pid_final = atoi(cmd_find_lastpid);
588 while (pid <= pid_final) {
589 kill(pid, SIGKILL);
590 pid++;
592 pclose(fpt);
594 else {
595 kill(pid, SIGKILL);
597 break;
600 if (get_ctrlc_header(wl) >= 0) {
601 if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) {
602 uname(&name);
603 /* Checking for mips architecture
604 * The mips machine responds differently to
605 * execl command. so the pid is incremented
606 * to kill the right command.
608 if (strncmp(name.machine, "mips", sizeof(name.machine)) == 0) {
609 pid++;
610 kill(pid, SIGKILL);
612 /* Checking for arm architecture
613 * The multiple commands would not work
614 * for ctrl+C. So we kill the processes
615 * spawned after the parent. This method has
616 * its own limitations but the busybox in pxa
617 * doesnot have many options to implement it better
619 else {
620 if (strncmp(name.machine, "armv5tel",
621 sizeof(name.machine)) == 0) {
622 /* The command below is used to get the
623 * PIDs and they are killed
625 snprintf(cmd_find_lastpid,
626 sizeof(cmd_find_lastpid),
627 "ps | awk \'PRINT $1\' | tail -n 1");
628 if ((fpt = popen(cmd_find_lastpid, "r")) == NULL) {
629 sprintf(buf, "%s\n", "Can't return PID");
630 return BCME_ERROR;
632 fgets(cmd_find_lastpid, sizeof(cmd_find_lastpid),
633 fpt);
634 pid_final = atoi(cmd_find_lastpid);
635 while (pid <= pid_final) {
636 kill(pid, SIGKILL);
637 pid++;
639 pclose(fpt);
641 /* In the case of x86, on receiving ctrl+C
642 * the child PIDs are obtained by searching
643 * the parent PID to obtain the PIDs of the
644 * and kill them
646 else {
647 while (pid != 0) {
648 /* The commad below is used to get the
649 * child PIDs by using their parent PID
651 snprintf(cmd_find_lastpid,
652 sizeof(cmd_find_lastpid),
653 "ps al | awk \"{ if (\\$4 == %d)"
654 " {print \\$3}}\"| head -n 1",
655 g_shellsync_pid);
656 if ((fpt = popen(cmd_find_lastpid, "r"))
657 == NULL) {
658 sprintf(buf, "%s\n",
659 "Can't return PID");
660 return BCME_ERROR;
662 fgets(cmd_find_lastpid,
663 sizeof(cmd_find_lastpid),
664 fpt);
665 pid = atoi(cmd_find_lastpid);
666 if (pid == 0)
667 kill(g_shellsync_pid, SIGKILL);
668 else
669 kill(pid, SIGKILL);
670 pclose(fpt);
674 break;
677 if (set_ctrlc == 1) {
678 g_rem_ptr->msg.len = 0;
679 g_rem_ptr->msg.cmd = g_return_stat;
680 remote_tx_response(wl, NULL, g_return_stat);
681 unlink(sync_file_name);
682 kill(0, SIGKILL);
684 /* It is possible that the child would have exited
685 * However we did not get a chance to read the file
686 * In this case go once again and check the file
688 if (!sent_once && !g_sig_chld) {
689 sent_once = 1;
690 continue;
693 if (!(g_sig_chld || nbytes))
694 break;
696 wait(NULL);
697 close(fd);
699 /* Signal end of command output */
700 g_rem_ptr->msg.len = 0;
701 g_rem_ptr->msg.cmd = g_return_stat;
703 remote_tx_response(wl, NULL, g_return_stat);
704 /* Cancel the time out alarm if any */
705 alarm(0);
706 sent_once = 0;
707 /* Clean up the temp file */
708 unlink(sync_file_name);
709 g_shellsync_timeout = DEFAULT_SHELL_TIMEOUT;
710 signal(SIGINT, SIG_DFL);
711 signal(SIGTERM, SIG_DFL);
713 return BCME_OK;