/* * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* Standard include files */ #define _GNU_SOURCE #include #include #include #include /* module specific include files */ #include #include "cmd_shell_loc.h" /* For debugging */ #define DEBUG #define DEBUG1 #define OPTION_ID_IF_NAME 1 #define OPTION_ID_SP_ID 2 #define OPTION_ID_CMD_NAME 3 #define OPTION_ID_ESN 4 #define OPTION_ID_GTPU_TEID 5 #define OPTION_ID_NUM_TEIDS 6 #define OPTION_ID_SHARED_SA 7 #define OPTION_ID_MAX 8 enum cmd_id { CMD_ID_OFFLOAD_SP = 1, CMD_ID_STOP_OFFLOAD, CMD_ID_HELP, CMD_ID_EXIT, CMD_ID_LAST }; /* Maximum strlen() of string variables */ #define MAX_STR_VAR_SIZE 32 /* Maximum number of commands */ #define MAX_CMDS CMD_ID_LAST typedef union { unsigned long intval; char strval[MAX_STR_VAR_SIZE]; } opt_val_gen_t; typedef struct { opt_val_gen_t value; uint8_t is_valid; } opt_attr_gen_t; static opt_attr_gen_t opt_input_gen[OPTION_ID_MAX]; /* Module context */ static cmd_shell_ctx_t shell_ctx; static int parse_intval(char* int_str, opt_attr_gen_t *opt_attr) { int i; for (i=0; int_str[i]!= '\0'; i++) int_str[i] = (char) tolower(int_str[i]); if (strncmp("0x", int_str, 2)) { opt_attr->value.intval = strtoul(int_str, (char **)NULL, 10); } else { opt_attr->value.intval = strtoul(int_str, (char **)NULL, 16); } opt_attr->is_valid = 1; return 0; } static int parse_strval(char* str, opt_attr_gen_t *opt_attr) { strncpy(opt_attr->value.strval, str, MAX_STR_VAR_SIZE-1); opt_attr->is_valid = 1; return 0; } static char short_opts[200]; #define CMD_NAME_OFFLOAD_SP "offload_sp" #define CMD_DESC_OFFLOAD_SP "Offload an IPSec Policy to Fast Path" #define CMD_MIN_ARGS_OFFLOAD_SP 3 #define CMD_SHORT_OPTS_OFFLOAD_SP sprintf(short_opts, "%d:%d:%d%d:%d:",\ OPTION_ID_SP_ID, OPTION_ID_IF_NAME, OPTION_ID_ESN,\ OPTION_ID_GTPU_TEID, OPTION_ID_NUM_TEIDS,\ OPTION_ID_SHARED_SA); static struct option offload_sp_options[] = { {"sp_id", required_argument, 0, OPTION_ID_SP_ID}, {"if_name", required_argument, 0, OPTION_ID_IF_NAME}, {"esn", no_argument, 0, OPTION_ID_ESN}, {"gtpu_teid", required_argument, 0, OPTION_ID_GTPU_TEID}, {"num_teids", required_argument, 0, OPTION_ID_NUM_TEIDS}, {"shared", no_argument, 0, OPTION_ID_SHARED_SA}, {0, 0, 0, 0} }; #define CMD_NAME_STOP_OFFLOAD "stop_offload" #define CMD_DESC_STOP_OFFLOAD "Stop Offload of an IPSec Policy" #define CMD_MIN_ARGS_STOP_OFFLOAD 3 #define CMD_SHORT_OPTS_STOP_OFFLOAD sprintf(short_opts, "%d:", OPTION_ID_SP_ID); static struct option stop_offload_options[] = { {"sp_id", required_argument, 0, OPTION_ID_SP_ID}, {0, 0, 0, 0} }; #define CMD_NAME_EXIT "exit" #define CMD_DESC_EXIT "Exit the netcpcfg command shell" #define CMD_MIN_ARGS_EXIT 1 #define CMD_SHORT_OPTS_EXIT sprintf(short_opts, ""); static struct option exit_options[] = { {0, 0, 0, 0} }; #define CMD_NAME_HELP "help" #define CMD_DESC_HELP "Help on available commands" #define CMD_MIN_ARGS_HELP 1 #define CMD_SHORT_OPTS_HELP sprintf(short_opts, "%d:", OPTION_ID_CMD_NAME); static struct option help_options[] = { {"cmd", required_argument, 0, OPTION_ID_CMD_NAME}, {0, 0, 0, 0} }; struct cmd_tbl_s { char *cmd_name; struct option *opt_tbl; char *desc; }; struct cmd_tbl_s cmd_table[MAX_CMDS] = { {CMD_NAME_OFFLOAD_SP, offload_sp_options, CMD_DESC_OFFLOAD_SP}, {CMD_NAME_STOP_OFFLOAD, stop_offload_options, CMD_DESC_STOP_OFFLOAD}, {CMD_NAME_EXIT, exit_options, CMD_DESC_EXIT}, {CMD_NAME_HELP, help_options, CMD_DESC_HELP}, {0, 0} }; static void print_help (char *cmd_name) { int i,j; if (!cmd_name) { printf ("For help on command options type \"%s --cmd \"\n", CMD_NAME_HELP); printf ("Available commands:\n"); for (i=0; ((i < MAX_CMDS) && cmd_table[i].cmd_name); i++) { printf (" %s\t%s\n", cmd_table[i].cmd_name, cmd_table[i].desc); } return; } for (i=0; ((i < MAX_CMDS) && (cmd_table[i].cmd_name)); i++) { struct option *opt = cmd_table[i].opt_tbl; if (strcmp(cmd_name, cmd_table[i].cmd_name)) { continue; } printf ("options for \"%s\"\n", cmd_name); for (j=0; opt->name; j++, opt++) { printf (" --%s\n", opt->name); } return; } printf ("No help available for %s\n", cmd_name); return; } static int setargs (char *args, char **argv) { int count = 0; while (isspace(*args)) ++args; while (*args) { if (argv) argv[count] = args; while (*args && !isspace(*args)) ++args; if (argv && *args) *args++ = '\0'; while (isspace(*args)) ++args; count++; } return count; } static char **parsedargs(char *args, int *argc) { char **argv = NULL; int argn = 0; if (args && *args && (args = strdup(args)) && (argn = setargs(args,NULL)) && (argv = malloc((argn+1) * sizeof(char *)))) { *argv++ = args; argn = setargs(args,argv); } if (args && !argv) free(args); *argc = argn; return argv; } static void freeparsedargs(char **argv) { if (argv) { free(argv[-1]); free(argv-1); } } #define COMMAND_LINE_SIZE 400 void* cmd_shell (void* args) { char *line = NULL; size_t len = 0; ssize_t read = 0; char cmd[20]; int nargs, c, rargs; struct option *long_options; char **av; enum cmd_id cmd_id; memset(&shell_ctx, 0, sizeof(shell_ctx)); if (ipsecmgr_ipc_get_user_send_iface(&shell_ctx.ipc_send_if)) { printf ("\ncmd_shell: Failed to get IPC send interface\n"); return; } while (1) { memset(opt_input_gen, 0, sizeof(opt_input_gen)); cmd_id = 0; printf ("\nIPSECMGR-CFG> "); if (line) free(line); line = malloc(COMMAND_LINE_SIZE); if (line == NULL) { printf("\nError allocating memory"); return; } read = getline(&line, &len, stdin); if (read == -1) { printf("\nERROR: reading line"); continue; } if (!read) continue; memset(cmd, 0, sizeof(cmd)); sscanf(line, "%s", cmd); if ( !strcmp(cmd, "exit")) exit(0); if (!strcmp(cmd, CMD_NAME_OFFLOAD_SP)) { cmd_id = CMD_ID_OFFLOAD_SP; long_options = offload_sp_options; CMD_SHORT_OPTS_OFFLOAD_SP; rargs = CMD_MIN_ARGS_OFFLOAD_SP; } else if (!strcmp(cmd, CMD_NAME_STOP_OFFLOAD)) { cmd_id = CMD_ID_STOP_OFFLOAD; long_options = stop_offload_options; CMD_SHORT_OPTS_STOP_OFFLOAD; rargs = CMD_MIN_ARGS_STOP_OFFLOAD; } else if (!strcmp(cmd, CMD_NAME_HELP)) { cmd_id = CMD_ID_HELP; long_options = help_options; CMD_SHORT_OPTS_HELP; rargs = CMD_MIN_ARGS_HELP; } else { if (strlen(cmd)) printf ("Unknown command: %s\n", cmd); continue; } if ((av = parsedargs(line, &nargs)) == NULL) { printf ("error parsing arguments"); continue; } if (nargs < rargs) { printf ("Insufficient paramaters for command \"%s\"\n", cmd); print_help (cmd); goto loop_over; } #ifdef DEBUG1 { int i; for (i = 0; i < nargs; i++) printf("[%s]\n",av[i]); } #endif optind = 0; while (1) { /* getopt_long stores the option index here. */ int option_index = 0; c = getopt_long (nargs, av, short_opts, long_options, &option_index); /* Detect the end of the options. */ #ifdef DEBUG1 printf("c=%d",c); #endif if (c == -1) break; switch (c) { case OPTION_ID_SP_ID: #ifdef DEBUG printf ("option sp_id with value `%s'\n", optarg); #endif if (parse_intval(optarg, &opt_input_gen[c])) { printf ("Invalid argument for sp_id\n"); } break; case OPTION_ID_IF_NAME: #ifdef DEBUG printf ("option if_name with value `%s'\n", optarg); #endif if (parse_strval(optarg, &opt_input_gen[c])) { printf ("Invalid argument for if_name\n"); } break; case OPTION_ID_CMD_NAME: #ifdef DEBUG printf ("option cmd with value `%s'\n", optarg); #endif if (parse_strval(optarg, &opt_input_gen[c])) { printf ("Invalid argument for cmd\n"); } break; case OPTION_ID_ESN: #ifdef DEBUG printf ("option esn enabled\n"); #endif opt_input_gen[c].is_valid = 1; break; case OPTION_ID_GTPU_TEID: #ifdef DEBUG printf ("option gtpu_teid with value `%s'\n", optarg); #endif if (parse_intval(optarg, &opt_input_gen[c])) { printf ("Invalid argument for gtpu_teid\n"); } break; case OPTION_ID_NUM_TEIDS: #ifdef DEBUG printf ("option num_teids with value `%s'\n", optarg); #endif if (parse_intval(optarg, &opt_input_gen[c])) { printf ("Invalid argument for num_teids\n"); } break; case OPTION_ID_SHARED_SA: #ifdef DEBUG printf ("option shared SA enabled\n"); #endif opt_input_gen[c].is_valid = 1; break; default: printf ("unknown option c=%d\n", c); break; } } #ifdef DEBUG1 /* Print any remaining command line arguments (not options). */ if (optind < nargs) { printf ("non-option elements: "); while (optind < nargs) printf ("%s ", av[optind++]); putchar ('\n'); } #endif switch (cmd_id) { case CMD_ID_HELP: { if (!opt_input_gen[OPTION_ID_CMD_NAME].is_valid) { print_help(NULL); } else { print_help(opt_input_gen[OPTION_ID_CMD_NAME].value.strval); } break; } case CMD_ID_OFFLOAD_SP: { ipsecmgr_ipc_offload_sp_req_param_t req; ipsecmgr_ifname_t if_name; ipsecmgr_l5_selector_t l5_selector; if (!opt_input_gen[OPTION_ID_SP_ID].is_valid) { printf ("Mandatory paramater missing: sp_id\n"); goto loop_over; } memset(&req, 0, sizeof(req)); memset(&if_name, 0, sizeof(if_name)); memset(&l5_selector, 0, sizeof(l5_selector)); req.trans_id = ++shell_ctx.trans_id; /* sp_id */ req.policy_id = (uint32_t)opt_input_gen[OPTION_ID_SP_ID].value.intval; /* if_name */ if (opt_input_gen[OPTION_ID_IF_NAME].is_valid) { strcpy(if_name.name, opt_input_gen[OPTION_ID_IF_NAME].value.strval); req.if_name = &if_name; } /* esn */ if (opt_input_gen[OPTION_ID_ESN].is_valid) { req.sa_flags |= IPSECMGR_SA_FLAGS_ESN; } /* gtpu_teid */ if (opt_input_gen[OPTION_ID_GTPU_TEID].is_valid) { l5_selector.proto = IPSECMGR_L5_PROTO_GTPU; l5_selector.value.gtpu.teid_start = (uint32_t)opt_input_gen[OPTION_ID_GTPU_TEID].value.intval; req.l5_selector = &l5_selector; } /* num_teids */ if (opt_input_gen[OPTION_ID_NUM_TEIDS].is_valid) { l5_selector.value.gtpu.teid_end = l5_selector.value.gtpu.teid_start - 1 + (uint32_t)opt_input_gen[OPTION_ID_NUM_TEIDS].value.intval; } else { /* default is 1 TEID */ l5_selector.value.gtpu.teid_end = l5_selector.value.gtpu.teid_start; } /* shared tunnel */ if (opt_input_gen[OPTION_ID_SHARED_SA].is_valid) { req.sa_flags |= IPSECMGR_SA_FLAGS_SHARED; } if (shell_ctx.ipc_send_if->offload_sp_req(&req)) { printf("%s failed\n", CMD_NAME_OFFLOAD_SP); } else { printf("%s trans_id: 0x%x\n", CMD_NAME_OFFLOAD_SP, shell_ctx.trans_id); } break; } case CMD_ID_STOP_OFFLOAD: { ipsecmgr_ipc_stop_offload_req_param_t req; if (!opt_input_gen[OPTION_ID_SP_ID].is_valid) { printf ("Mandatory paramater missing: sp_id\n"); goto loop_over; } memset(&req, 0, sizeof(req)); req.trans_id = ++shell_ctx.trans_id; /* sp_id */ req.policy_id = (uint32_t)opt_input_gen[OPTION_ID_SP_ID].value.intval; if (shell_ctx.ipc_send_if->stop_offload_req(&req)) { printf("%s failed\n", CMD_NAME_STOP_OFFLOAD); } else { printf("%s trans_id: 0x%x\n", CMD_NAME_STOP_OFFLOAD, shell_ctx.trans_id); } break; } } /* switch cmd_id */ loop_over: freeparsedargs(av); } return (void*)(0); } void cmd_shell_offload_sp_rsp ( ipsecmgr_ipc_offload_sp_rsp_param_t *rsp ) { char resp_str[10] = {0,}; printf ("\nRecvd OFFLOAD_SP response:\n"); printf (" trans_id:\t0x%x\n", rsp->trans_id); if (rsp->type & RSP_TYPE_ACK) { strcpy(resp_str, "ACK"); } else if (rsp->type & RSP_TYPE_DONE) { int slen = strlen(resp_str); if (slen) strcpy(&resp_str[slen], "|DONE"); else strcpy(&resp_str[slen], "DONE"); } printf (" resp_type:\t(%d) %s\n", rsp->type, resp_str); printf (" result:\t(%d) %s\n", rsp->result, ((rsp->result == RESULT_SUCCESS) ? "SUCCESS":"FAIL")); if (rsp->err_code) { printf (" FP lib retval:\t%d\n", rsp->err_code); } if (rsp->sa_handle) printf (" sa_handle:\t0x%x\n", rsp->sa_handle); if (rsp->sp_handle) printf (" sp_handle:\t0x%x\n", rsp->sp_handle); return; } void cmd_shell_stop_offload_rsp ( ipsecmgr_ipc_stop_offload_rsp_param_t *rsp ) { char resp_str[10] = {0,}; printf ("\nRecvd STOP_OFFLOAD response:\n"); printf (" trans_id:\t0x%x\n", rsp->trans_id); if (rsp->type & RSP_TYPE_ACK) { strcpy(resp_str, "ACK"); } else if (rsp->type & RSP_TYPE_DONE) { int slen = strlen(resp_str); if (slen) strcpy(&resp_str[slen], "|DONE"); else strcpy(&resp_str[slen], "DONE"); } printf (" resp_type:\t(%d) %s\n", rsp->type, resp_str); printf (" result:\t(%d) %s\n", rsp->result, ((rsp->result == RESULT_SUCCESS) ? "SUCCESS":"FAIL")); return; }