/*
 *===========================================================================
 *                         ipsecctrl_set
 *===========================================================================
 */
static int
ipsecctrl_set(Argvars *vars)
{
    int     i;
    Ip_tag  tags[3];

    if (vars->argc != 4)
    {
        ipcom_printf("usage: > ipsecctrl set <name> <integer value>"IP_LF);
        return -1;
    }

    for (i = 0; params[i].name != IP_NULL; i++)
        if (ipcom_strcmp(vars->argv[2], params[i].name) == 0)
        {
            tags[0] = params[i].set;
            tags[1] = ipcom_atoi(vars->argv[3]);
            tags[2] = IP_TAG_END;
            ipipsec_conf(tags);
            ipcom_printf("ipsecctrl: %s set to %d"IP_LF, params[i].name, tags[1]);
            return 0;
        }

    ipcom_printf("ipsecctrl set: '%s' not found"IP_LF, vars->argv[2]);
    return -1;
}
/*
 *===========================================================================
 *                    ipnet_cmd_qc_parse_bit_string
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC Ip_bool
ipnet_cmd_qc_parse_bit_string(const char *bit_str, Ip_u32 *pattern, Ip_u8 *pattern_len)
{
    char *ctx;
    char *bit;
    char *dup_bit_str = ipcom_strdup(bit_str);

    if (dup_bit_str == IP_NULL)
    {
        ipcom_printf("Failed to duplicate string '%s'"IP_LF, bit_str);
        return IP_FALSE;
    }

    *pattern = 0;
    *pattern_len = 0;
    bit = ipcom_strtok_r(dup_bit_str, ",", &ctx);
    if (bit == IP_NULL)
    {
        ipcom_free(dup_bit_str);
        ipcom_printf("Invalid format of the pattern, must be a comma separated list of 0 and 1"IP_LF);
        return IP_FALSE;
    }

    while (bit != IP_NULL)
    {
        if (ipcom_atoi(bit))
            IP_BIT_SET(*pattern, 1 << *pattern_len);
        ++*pattern_len;
        bit = ipcom_strtok_r(IP_NULL, ",", &ctx);
    }

    ipcom_free(dup_bit_str);
    return IP_TRUE;
}
/*
 *===========================================================================
 *                    ipnet_cmd_qc_parse_netemu
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_help_netemu(void)
{
    ipcom_printf("Usage: ... netemu limit <number> [min_latency <msec>] [max_latency <msec>] ");
    ipcom_printf("[drop <number> [random] [pattern X,X,..,X]] [corrupt <number> [random]]"IP_LF);
    return -IP_ERRNO_EINVAL;
}
/*
 *===========================================================================
 *                    ipcom_shellalias_find
 *===========================================================================
 * Description: Find a given alias based on name.
 * Parameters:  name        - The alias name.
 * Returns:     The alias if found.
 *
 */
IP_STATIC struct Ipcom_shellalias_alias *
ipcom_shellalias_find(const char *name)
{
    struct Ipcom_shellalias_alias   *alias;

    /* Go through the aliases */
    for (alias = IPCOM_LIST_FIRST(&ipcom_shellalias_head);
         alias != IP_NULL;
         alias = IPCOM_LIST_NEXT(&alias->next))
    {
        if (name == IP_NULL)
        {
            int i;
            ipcom_printf("%-15s\t'", alias->name);
            for (i = 0; i < alias->argc; i++)
            {
                ipcom_printf("%s%s",
                             alias->argv[i],
                             (i == alias->argc - 1)? "" : " ");
            }
            ipcom_printf("'"IP_LF);
        }
        /* Did it match? */
        else if (ipcom_strcmp(alias->name, name) == 0)
        {
            /* Return it */
            return alias;
        }
    }

    /* No go */
    return IP_NULL;
}
/*
 *===========================================================================
 *                    ipl2tp_l2tp_read
 *===========================================================================
 * Description: Read a L2TP control message via UDP.
 * Parameters:  
 * Returns:     
 *
 */
IP_STATIC int
ipl2tp_l2tp_read(Ip_fd                      fd,
                 Ip_u8                      **buf, 
                 union Ip_sockaddr_union    *ipp)
{
    Ip_socklen_t            faddrsize = sizeof(*ipp);
    int                     length;
    Ip_u8                   *buffer;

    /* Get buffer */
    if ((buffer = ipl2tp_cache_malloc(HEADER_SPACE +
                                      IPL2TP_MAX_MESSAGE_SIZE)) == IP_NULL)
    {
        ipcom_printf("Out of memory when reading L2TP socket"IP_LF);
        return 0;
    }

    /* Receive an UDP packet */
    if ((length = ipcom_recvfrom(fd, buffer, IPL2TP_MAX_MESSAGE_SIZE, 0,
                                 &ipp->sa,
                                 &faddrsize)) < 0)
    {
        ipcom_printf("ipl2tp_l2tp_read() failed with errno: %d"IP_LF,
                     ipcom_errno);
        ipl2tp_cache_free(buffer);
        return 0;
    }

    *buf = buffer;
    return length;
}
/*
 *===========================================================================
 *                      ipnet_cmd_qc_show_queue
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_show_queue(Ipnet_cmd_qc *p)
{
    Ipnet_cmd_qc_type_handler *h;

    if (ipcom_socketioctl(p->fd, IPNET_SIOCGIFQUEUE, &p->p.ifq) < 0)
    {
        ipcom_printf("Failed to get the queue: %s"IP_LF, ipcom_strerror(ipcom_errno));
        return -1;
    }

    h = ipnet_cmd_qc_get_type_handler(p->p.ifq.ifq_type);
    if (h == IP_NULL)
    {
        ipcom_printf("No 'show' handler implemented for queue type '%s'"IP_LF,
                     p->p.ifq.ifq_type);
        return -1;
    }

    ipnet_cmd_qc_output_indent(p);
    ipcom_printf("%s/%d[%d] queue at %s"IP_LF,
                 p->p.ifq.ifq_type,
                 p->p.ifq.ifq_id,
                 p->p.ifq.ifq_parent_id,
                 p->p.ifq.ifq_name);
    ipnet_cmd_qc_output_indent(p);

    return h->show(p);
}
static void
ipsecctrl_trap_print(void)
{
    Ip_tag  tags[17];
    Ip_err retval;

    ipcom_printf(IP_LF"***** IPsec trap control ::"IP_LF);

    tags[ 0] = IPIPSEC_CTRLT_GET_espAuthFailureTrapEnable;
    tags[ 2] = IPIPSEC_CTRLT_GET_ahAuthFailureTrapEnable;
    tags[ 4] = IPIPSEC_CTRLT_GET_espReplayFailureTrapEnable;
    tags[ 6] = IPIPSEC_CTRLT_GET_ahReplayFailureTrapEnable;
    tags[ 8] = IPIPSEC_CTRLT_GET_espPolicyFailureTrapEnable;
    tags[10] = IPIPSEC_CTRLT_GET_ahPolicyFailureTrapEnable;
    tags[12] = IPIPSEC_CTRLT_GET_invalidSpiTrapEnable;
    tags[14] = IPIPSEC_CTRLT_GET_otherPolicyFailureTrapEnable;
    tags[16] = IP_TAG_END;

    retval = ipipsec_ctrl(tags);
    if (retval != IPCOM_SUCCESS)
        ipcom_printf("error: trap print aborted: error = %d"IP_LF, retval);
    else
    {
        ipcom_printf("espAuthFailureTrapEnable = %ld"IP_LF, tags[ 1]);
        ipcom_printf("ahAuthFailureTrapEnable = %ld"IP_LF, tags[ 3]);
        ipcom_printf("espReplayFailureTrapEnable = %ld"IP_LF, tags[ 5]);
        ipcom_printf("ahReplayFailureTrapEnable = %ld"IP_LF, tags[ 7]);
        ipcom_printf("espPolicyFailureTrapEnable = %ld"IP_LF, tags[ 9]);
        ipcom_printf("ahPolicyFailureTrapEnable = %ld"IP_LF, tags[11]);
        ipcom_printf("invalidSpiTrapEnable = %ld"IP_LF, tags[13]);
        ipcom_printf("otherPolicyFailureTrapEnable = %ld"IP_LF, tags[15]);
    }
}
/*
 *===========================================================================
 *                    ipcom_cmd_sockperf_connect
 *===========================================================================
 * Description: Active open of socket(s)
 * Parameters:
 * Returns:
 */
IP_STATIC void
ipcom_cmd_sockperf_connect(Ipcom_cmd_sockperf_t *cmd)
{
    Ip_fd            *s = cmd->sock_array;
    Ip_u32            created_sockets;
    struct Ip_timeval start;
    struct Ip_timeval stop;

    ipcom_printf("sockperf-c: connecting to %s[%d]"IP_LF,
                 cmd->res->ai_canonname,
                 ip_ntohs(((struct Ip_sockaddr_in *)cmd->res->ai_addr)->sin_port));
    ipcom_microtime(&start);
    for (created_sockets = 0; created_sockets < cmd->num_sock; created_sockets++)
    {
        s[created_sockets] = ipcom_socket(cmd->res->ai_family,
                                          cmd->res->ai_socktype,
                                          cmd->res->ai_protocol);
        if (s[created_sockets] == IP_SOCKERR)
        {
            ipcom_printf("sockperf-c: Failed to create socket: %s"IP_LF,
                         ipcom_strerror(ipcom_errno));
            created_sockets--;
            goto cleanup;
        }

        if (ipcom_setsockopt(s[created_sockets],
                             IP_SOL_SOCKET,
                             IP_SO_LINGER,
                             &cmd->linger,
                             sizeof(cmd->linger)) < 0)
        {
            ipcom_printf("sockperf-c: setsockopt SO_LINGER failed : %s"IP_LF,
                         ipcom_strerror(ipcom_errno));
            goto cleanup;
        }

        if (ipcom_connect(s[created_sockets], cmd->res->ai_addr, cmd->res->ai_addrlen) < 0)
        {
            ipcom_printf("sockperf-c: Failed to connect: %s"IP_LF,
                         ipcom_strerror(ipcom_errno));
            goto cleanup;
        }
    }
    ipcom_microtime(&stop);
    ipcom_printf("sockperf-t: %ld sockets connected in %ld ms"IP_LF,
                 created_sockets,
                 ipcom_cmd_sockperf_tv_to_msec(&start, &stop));

    ipcom_cmd_sockperf_run(cmd);

 cleanup:
    while (created_sockets > 0)
        (void)ipcom_socketclose(s[created_sockets--]);
}
/*
 *===========================================================================
 *                      ipnet_cmd_qc_show_htbc
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_show_htbc(Ipnet_cmd_qc *p)
{
    struct Ipnet_ifqueue_htbc *h = &p->p.ifq.ifq_data.htbc;

    ipcom_printf("  rate: %s, ",
                 ipnet_cmd_qc_format_rate(p->s, sizeof(p->s), h->htbc_byterate));
    ipcom_printf("burst: %s, default id: %d"IP_LF,
                 ipnet_cmd_qc_format_number(p->s, sizeof(p->s), h->htbc_token_limit),
                 h->htbc_default_id);
    return ipnet_cmd_qc_show_children(p, &h->htbc_container);
}
/*
 *===========================================================================
 *                    ipl2tp_ppp_data_cb
 *===========================================================================
 * Description: Data callback.
 * Parameters:  user_data   - User callback data.
 *              buffer      - Original data buffer.
 *              payload     - Payload pointer in data buffer.
 *              length      - Length of payload.
 * Returns:     
 *
 */
IP_STATIC void
ipl2tp_ppp_data_cb(void *user_data, Ipl2tp_key *id,
                   void *buffer, void *payload, Ip_u16 length)
{
    int ifindex = (int)user_data;

    (void)id;
    (void)buffer;
    (void)payload;
    (void)length;

    /* Do the write */
    if (ifindex != -1)
    {
        /*
         * Buffer will be used by PPP for a while,
         * and then released in ppp_writedone_hook().
         */
/*
        ipl2tp_buffer_free = 0;
*/

        l2tp_output = 1;

        /*
        ** Insert PPP write routine here, e.g.:
        ** ppplink_write(ifindex, payload, length, HEADER_SPACE, buffer);
        */
#ifdef IPPPP_USE_PPPL2TP

        if (user_data == (void *)0x0)
        {
#ifdef IPPPP_USE_PPPL2TP_LNS
            if ((ipcom_sysvar_get_conf_as_int("ipppp.l2tp.server", IP_NULL, IP_NULL) != 1) || 
                ((ifindex = ipppp_pppl2tp_if_create_server(id)) < 0))
            {
                ipcom_printf ("Failed to create new server interface."IP_LF);
                return;
            }
#else
            ipcom_printf ("Data callback: no ifindex."IP_LF);
            return;
#endif
        }

        ipppp_pppl2tp_input (ifindex, payload, length);
#endif

        l2tp_output = 0;
    }
}
/*
 *===========================================================================
 *                      ipnet_cmd_qc_show_dpaf
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_show_dpaf(Ipnet_cmd_qc *p)
{
    ipcom_printf("  limit: %s"IP_LF,
                 ipnet_cmd_qc_format_number(p->s, sizeof(p->s), p->p.ifq.ifq_data.dpaf.dpaf_limit));
    return 0;
}
/*
 *===========================================================================
 *                    ipnet_cmd_qc_parse_number
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC Ip_bool
ipnet_cmd_qc_parse_number(const char *str_num, Ip_u32 *num)
{
    char *end;
    long  lnum;

    lnum = ipcom_strtol(str_num, &end, 10);
    if (lnum < 0)
        *num = 0;
    else
        *num = (Ip_u32) lnum;

    if (end && ipcom_strlen(end) > 0)
    {
        if (ipcom_strcmp(end, "k") == 0 || ipcom_strcmp(end, "kb") == 0)
            *num *= 1000;
        else if (ipcom_strcmp(end, "M") == 0 || ipcom_strcmp(end, "Mb") == 0)
            *num *= 1000000;
        else
        {
            ipcom_printf("'%s' is an unsupported number suffix"IP_LF, str_num);
            return IP_FALSE;
        }
    }
    return IP_TRUE;
}
/*
 *===========================================================================
 *                      ipnet_cmd_qc_add_filter
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_show_filter(Ipnet_cmd_qc *p)
{
    ipnet_cmd_qc_set_filter_id(p);
    ipcom_printf("Not implemented"IP_LF);
    return 0;
}
/*
 *===========================================================================
 *                      ipnet_cmd_qc_parse_parent
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_parse_parent(Ipnet_cmd_qc *p)
{
    p->p.ifq.ifq_parent_id = IP_IFQ_ID_NONE;

    if (p->argc < 1)
        return 0;

    if (ipcom_strcmp(*p->argv, "root") == 0)
    {
        ipnet_cmd_qc_next_arg(p);
        return 0;
    }

    if (ipcom_strcmp(*p->argv, "parent") == 0)
    {
        ipnet_cmd_qc_next_arg(p);
        if (p->argc < 1)
        {
            ipcom_printf("Expected [ root | parent <q-id> ]"IP_LF);
            return -1;
        }
        p->p.ifq.ifq_parent_id = ipcom_atoi(*p->argv);
        ipnet_cmd_qc_next_arg(p);
    }
    return 0;
}
/*
 *===========================================================================
 *                    ipnet_cmd_qc_parse_rate
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC Ip_bool
ipnet_cmd_qc_parse_rate(const char *str_rate, Ip_u32 *rate)
{
    char   *end;

    *rate = (Ip_u32) ipcom_strtol(str_rate, &end, 10);
    if (end && ipcom_strlen(end) > 0)
    {
        if (ipcom_strcmp(end, "kbps") == 0)
            *rate *= 1000;
        else if (ipcom_strcmp(end, "Mbps") == 0)
            *rate *= 1000000;
        else if (ipcom_strcmp(end, "kbit") == 0)
            *rate *= 1000 / 8;
        else if (ipcom_strcmp(end, "Mbit") == 0)
            *rate *= 1000000 / 8;
        else if (ipcom_strcmp(end, "bit") == 0)
            *rate /= 8;
        else if (ipcom_strcmp(end, "bps") == 0)
            ;
        else
        {
            ipcom_printf("'%s' is an unsupported rate suffix"IP_LF, end);
            return IP_FALSE;
        }
    }
    return IP_TRUE;
}
/*
 *===========================================================================
 *                    ipcom_cmd_sockperf_print_usage
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 */
IP_STATIC void
ipcom_cmd_sockperf_print_usage(void)
{
    ipcom_printf("Network performance tool"IP_LF
                 "usage:  "IP_LF
                 "   sockperf [options] [address]"IP_LF
                 "      -6         use IPv6 (default is IPv4)"IP_LF
                 "      -a         use passive open (default is active open)"IP_LF
                 "      -e         echo test pattern on shell"IP_LF
                 "      -L <sec>   linger time for all sockets (default is 3s)"IP_LF
                 "      -l <bytes> number of bytes to write/read in each call (default 8192)"IP_LF
                 "      -n <num>   number of buffers to write (default 2048)"IP_LF
                 "      -P         create(transmit) or verify(receive) test pattern"IP_LF
                 "      -p <port>  socket port (default 7373)"IP_LF
                 "      -R         socket receive buffer size (default 16384)"IP_LF
                 "      -r         receive data (not mutually exclusive with -t)"IP_LF
                 "      -s <num>   number of sockets to use, must be same on both ends (default 1)"IP_LF
                 "      -T         socket send buffer size (default 32767)"IP_LF
                 "      -t         transmit data (not mutually exclusive with -r)"IP_LF
                 "example:"IP_LF
                 "   \"sockperf -r -a\" and \"sockperf -t <addr>\" should give about the same"IP_LF
                 "   performance value as \"ttcp -r\" and \"ttcp <addr>\""IP_LF
                 IP_LF
                 );
}
/*
 *===========================================================================
 *                         ipsecctrl_mib
 *===========================================================================
 * List the IPSec Monitoring MIB (draft-ietf-ipsec-monitor-mib-03.txt).
 *
 * ESP Input table.
 * AH Input table.
 * ESP output table.
 * AH output table.
 */
static int
ipsecctrl_mib(Argvars *vars)
{
    (void)vars;

    ipcom_printf("draft-ietf-ipsec-monitor-mib-03.txt - IPSec Monitoring MIB:"IP_LF);

    ipsecctrl_selectorTable_print(vars);

#ifdef IPCOM_USE_INET
    ipsecctrl_saTables_print(vars, IPIPSEC_SADIR_INPUT, IP_IPPROTO_ESP, IP_AF_INET);
    ipsecctrl_saTables_print(vars, IPIPSEC_SADIR_INPUT, IP_IPPROTO_AH, IP_AF_INET);
    ipsecctrl_saTables_print(vars, IPIPSEC_SADIR_OUTPUT, IP_IPPROTO_ESP, IP_AF_INET);
    ipsecctrl_saTables_print(vars, IPIPSEC_SADIR_OUTPUT, IP_IPPROTO_AH, IP_AF_INET);
#endif

#ifdef IPCOM_USE_INET6
    ipsecctrl_saTables_print(vars, IPIPSEC_SADIR_INPUT, IP_IPPROTO_ESP, IP_AF_INET6);
    ipsecctrl_saTables_print(vars, IPIPSEC_SADIR_INPUT, IP_IPPROTO_AH, IP_AF_INET6);
    ipsecctrl_saTables_print(vars, IPIPSEC_SADIR_OUTPUT, IP_IPPROTO_ESP, IP_AF_INET6);
    ipsecctrl_saTables_print(vars, IPIPSEC_SADIR_OUTPUT, IP_IPPROTO_AH, IP_AF_INET6);
#endif

    ipsecctrl_stats_print();

#ifdef IPIPSEC_USE_TRAPS
    ipsecctrl_trap_print();
#endif

    return 0;
}
/*
 *===========================================================================
 *                    ipl2tp_l2tp_write
 *===========================================================================
 * Description: Send a L2TP control message via UDP.
 * Parameters:  message - Message to send.
 *              addr    - Destination IP address.
 * Returns:     
 *
 */
IP_STATIC int
ipl2tp_l2tp_write(void                      *user_data, 
                  Ipl2tp_key                *key,
                  struct Ip_iovec           *iov,
                  int                       iovlen,
                  union Ip_sockaddr_union   *addr,
                  int                       transport)
{
    int                 sz;
    int                 fd;
    struct Ip_msghdr    msg;

    (void)user_data;
    (void)key;

    if (transport == IPL2TP_ATTR_TRANSPORT_UDP)
    {
        fd = udp_fd;
    }
    else if (transport == IPL2TP_ATTR_TRANSPORT_IP)
    {
        fd = ip_fd;
    }
    else
    {
        ipcom_printf("Bad transport %u!!"IP_LF, transport);
        return -1;
    }

    ipcom_memset(&msg, 0, sizeof(msg));

    /* Set it up */
    msg.msg_iov     = iov;
    msg.msg_iovlen  = iovlen;
    msg.msg_name    = &addr->sa;
    msg.msg_namelen = addr->sa.sa_len;

    /* Transmit the UDP packet */
    if ((sz = ipcom_sendmsg(fd, &msg, 0)) < 0)
    {
        ipcom_printf("ipl2tp_l2tp_write() failed with errno: %d"IP_LF,
                     ipcom_errno);
        return 0;
    }

    return sz;
}
/*
 * TODO: Might not use an Ipcom_pipe in the AMP version...
 */
IP_EXTERN void
ipcom_forwarder_loop(void * fw_cookie, void * pipe)
{
    int ix;
    fw_msg_t *fw_msg;

#ifdef IPCOM_FORWARDER_AMP
    (void)pipe; /* TODO */
#else
    int *sw_msg;
    Ipcom_pipe **control_pipe = pipe;
#endif

    for (;;)
    {
        fw_msg = ipcom_forwarder_rx(fw_cookie);
        /* IPCOM_FWD_WAIT check for potential cache update moved to ipcom_forwarder_rx() */
        if (IP_LIKELY(fw_msg))
        {
            ix = ipcom_forwarder_get_fw_if(fw_msg);
            if (IP_LIKELY(ix >= 0))
            {
                /* Cache entry found => forward packet */
                (void)ipcom_forwarder_tx(ix, fw_msg, fw_cookie);
            }
            else if (IS_DROP_MSG_FW(fw_msg) == IP_TRUE)
            {
#ifdef FW_IPSEC_DEBUG
                ipcom_printf("FW_IPSEC :: dropped!\n");
#endif
                ipcom_forwarder_drop_fw_msg(fw_msg, fw_cookie);
            }
            else if (IS_CONTROL_MSG_FW(fw_msg) == IP_FALSE)
            {
                ipcom_forwarder_slow_path(fw_msg, fw_cookie);
            }
            /* The rest are control messages */
#ifndef IPCOM_FORWARDER_AMP
            else if (FW_MSG(fw_msg) == FW_MSG_TRIGGER_PIPE_READ)
            {
                if (ipcom_pipe_try_recv(*control_pipe, (void **)&sw_msg) == IPCOM_SUCCESS)
                {
                    if (*sw_msg == IPCOM_SIG_STOP_FW)
                    {
                        do
                        {
                            ipcom_pipe_recv(*control_pipe,(void **)&sw_msg);

                        } while(*sw_msg != IPCOM_SIG_START_FW);
                    }
                }
                ipcom_forwarder_free_trigger_msg(fw_msg, fw_cookie);
            }
#else /* IPCOM_FORWARDER_AMP */
            /* TODO */
#endif /* IPCOM_FORWARDER_AMP */
        }
    }
}
/*
 *===========================================================================
 *                     ipnet_cmd_qc_output_indent
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC void
ipnet_cmd_qc_output_indent(Ipnet_cmd_qc *p)
{
    int i;

    for (i = 0; i < p->recurse_level; i++)
        ipcom_printf("\t");
}
/*
 *===========================================================================
 *                     ipnet_cmd_qc_get_type_handler
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC Ipnet_cmd_qc_type_handler *
ipnet_cmd_qc_get_type_handler(const char *type)
{
    int i;
    int count = sizeof(ipnet_qc_type_handlers) / sizeof(ipnet_qc_type_handlers[0]);

    for (i = 0; i < count; i++)
        if (ipcom_strcmp(ipnet_qc_type_handlers[i].type, type) == 0)
            return &ipnet_qc_type_handlers[i];

    ipcom_printf("'%s' is an unknown queue type, known types are: ", type);
    for (i = 0; i < count; i++)
        ipcom_printf("%s, ", ipnet_qc_type_handlers[i].type);
    ipcom_printf(IP_LF);

    return IP_NULL;
}
/*
 *===========================================================================
 *                    ipcom_cmd_smptest_server
 *===========================================================================
 * Description: This is the server part of the smptest command
 * Parameters:  The address we should listen to, and info about how many sockets
 *              we should use.
 * Returns:     0 on success. -1 on failure.
 */
IP_STATIC int
ipcom_cmd_smptest_server()
{
    Ipcom_proc_attr    attr;
    unsigned int i;
    Ipcom_proc *proc;
    int retval;

    spawn_number_server     = 0;

    if ( 0 != ipcom_sem_create( &sem_wait_server, 0 ) )
    {
        ipcom_printf("ipcom_sem_create failed: %s"IP_LF, ipcom_strerror(ipcom_errno));
        return -1;
    }
    ipcom_atomic_set( &num_wait_server, smp_opt_server.num_sock );
    ipcom_atomic_set( &listen_wait, smp_opt_server.num_sock );

    ipcom_proc_attr_init(&attr);
    attr.priority   = IPCOM_PRIORITY_DEFAULT;


    /* Hacky hacky way to write from a task.. copied from ipcom_mshell.c */
    proc = ipcom_proc_self();
    ip_assert( proc != 0 );
    server_out = proc->shell_fd;

    for ( i = 0;i < smp_opt_server.num_sock;++i )
    {
        retval = ipcom_proc_acreate("ipcom_cmd_smptest_server_spawn",
                                        (Ipcom_proc_func)ipcom_cmd_smptest_server_spawn, &attr, 0 );
        if (retval != 0)
        {
            ipcom_printf( "Error spawning smptest server"IP_LF );
            return retval;
        }
    }

    ipcom_sem_wait( sem_wait_server );

    ipcom_sem_delete( &sem_wait_server );

    return 0;
}
/*
 *===========================================================================
 *                    ipsecctrl_selectorTable_print
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
static void
ipsecctrl_selectorTable_print(Argvars *vars)
{
    Ipipsec_ctrl_selector   sel;
#ifdef IPCOM_USE_INET6
    char str[IP_INET6_ADDRSTRLEN];
#else
    char str[16];
#endif

    ipcom_printf(IP_LF"***** selectorTable ::"IP_LF);

    sel.Index = 0;  /* get first selector. */

    /* Get and print the Selectors in MIB format. */
    for (;;)
    {
        /* Get first/next Selector */
        if (ipcom_socketioctl(vars->fd, IP_SIOCXIPSEC_SELECTOR, &sel) < 0)
        {
            ipcom_printf("ipsecctrl: ipcom_socketioctl(SELECTOR) failed (%s)"IP_LF,
                         ipcom_strerror(ipcom_errno));
            return;
        }

        if (sel.Index == 0)
            break;

        /* Print selector index */
        ipcom_printf(IP_LF"Selector Entry #%ld:"IP_LF
                     "selectorIndex = %ld"IP_LF,
                     sel.Index,
                     sel.Index);

        ipcom_printf("selectorLocalId = %s"IP_LF
                     "selectorLocalIdType = %s"IP_LF,
                     ipcom_inet_ntop(sel.domain, &sel.LocalId, str, sizeof(str)),
                     sel.domain == IP_AF_INET ? "idIpv4Addr" : "idIpv6Addr");


        ipcom_printf("selectorRemoteId = %s"IP_LF
                     "selectorRemoteIdType = %s"IP_LF,
                     ipcom_inet_ntop(sel.domain, &sel.RemoteId, str, sizeof(str)),
                     sel.domain == IP_AF_INET ? "idIpv4Addr" : "idIpv6Addr");

        ipcom_printf("selectorProtocol = %s"IP_LF,
                     ipcom_ipproto_name(sel.Protocol));

        ipcom_printf("selectorLocalPort = %d"IP_LF,
                     ip_ntohs(sel.LocalPort));
        ipcom_printf("selectorRemotePort = %d"IP_LF,
                     ip_ntohs(sel.RemotePort));
    }
}
/*
 *===========================================================================
 *                    ipnet_cmd_sysctl_print_key
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC void
ipnet_cmd_sysctl_print_key(char **names,
                           int  nameslen)
{
    int i;
    for (i = 0; i < nameslen; i++)
    {
        ipcom_printf("%s%s", i != 0? "." : "", names[i]);
    }
}
/*
 *===========================================================================
 *                     ipnet_cmd_qc_get_op_func
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC Ipnet_cmd_qc_op
ipnet_cmd_qc_get_op_func(const char *type, const char *op)
{
    int i;
    int count = sizeof(ipnet_cmd_qc_op_handlers) / sizeof(ipnet_cmd_qc_op_handlers[0]);

    for (i = 0; i < count; i++)
        if (ipcom_strcmp(ipnet_cmd_qc_op_handlers[i].type, type) == 0
            && ipcom_strcmp(ipnet_cmd_qc_op_handlers[i].op, op) == 0)
            return ipnet_cmd_qc_op_handlers[i].f_op;

    ipcom_printf("'%s %s' is an unknown operation, knowed operations are:"IP_LF, type, op);
    for (i = 0; i < count; i++)
        ipcom_printf("  '%s %s', " IP_LF,
                     ipnet_cmd_qc_op_handlers[i].type,
                     ipnet_cmd_qc_op_handlers[i].op);

    return IP_NULL;
}
/*
 *===========================================================================
 *                      ipnet_cmd_qc_show_mbc
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_show_mbc(Ipnet_cmd_qc *p)
{
    struct Ipnet_ifqueue_mbc *m = &p->p.ifq.ifq_data.mbc;

    ipcom_printf("  bands: %ld, default_band: %ld"IP_LF,
                 m->mbc_bands,
                 m->mbc_default_band);
    return ipnet_cmd_qc_show_children(p, &m->mbc_container);
}
/*
 *===========================================================================
 *                    ipcom_cmd_version
 *===========================================================================
 * Description:     Shell command: Print Interpeak product versions.
 * Parameters:      argc - number of arguments
 *                  argv - pointer to pointer to the arguments
 * Returns:         0
 *
 */
IP_PUBLIC int
ipcom_cmd_version(int argc, char **argv)
{
    int i;

    (void)argc;
    (void)argv;

    /* Print IPCOM version */
    ipcom_printf(ipcom_version);
    ipcom_printf(IP_LF);

    /* Printf the other product versions. */
    for(i = 0; ipcom_ipd_products[i].name != IP_NULL; i++)
        if (ipcom_ipd_products[i].version != IP_NULL)
            ipcom_printf("%s"IP_LF, ipcom_ipd_products[i].version());

    return 0;
}
/*
 *===========================================================================
 *                      ipnet_cmd_qc_parse_dev
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_parse_dev(Ipnet_cmd_qc *p)
{
    if (p->argc < 2 || ipcom_strcmp(*p->argv, "dev") != 0)
    {
        ipcom_printf("expected 'dev <if>'" IP_LF);
        return -IP_ERRNO_EINVAL;
    }
    ipnet_cmd_qc_next_arg(p);
    if (ipcom_if_nametoindex(*p->argv) == 0)
    {
        ipcom_printf("'%s' is not a valid interface name" IP_LF, *p->argv);
        return -IP_ERRNO_EINVAL;

    }
    ipcom_strcpy(p->p.ifq.ifq_name, *p->argv);
    ipnet_cmd_qc_next_arg(p);
    return 0;
}
/*
 *===========================================================================
 *                    ipnet_cmd_qc_parse_mbc
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_parse_mbc(Ipnet_cmd_qc *p)
{
    struct Ipnet_ifqueue_mbc *m = &p->p.ifq.ifq_data.mbc;

    if (p->argc == 0)
        return ipnet_cmd_qc_help_mbc();

    m->mbc_bands        = 0;
    m->mbc_default_band = 1;

    while (p->argc)
    {
        if (ipcom_strcmp(*p->argv, "bands") == 0)
        {
            ipnet_cmd_qc_next_arg(p);
            if (!ipnet_cmd_qc_parse_number(*p->argv, &m->mbc_bands))
                return -1;
        }
        else if (ipcom_strcmp(*p->argv, "default_band") == 0)
        {
            ipnet_cmd_qc_next_arg(p);
            if (!ipnet_cmd_qc_parse_number(*p->argv, &m->mbc_default_band))
                return -1;
        }
        else
        {
            ipcom_printf("'%s' is not a MBC parameter"IP_LF, *p->argv);
            return ipnet_cmd_qc_help_mbc();
        }
        ipnet_cmd_qc_next_arg(p);
    }

    if (m->mbc_bands < 2 || m->mbc_bands > IPNET_IFQ_CONTAINER_MAX_COUNT)
    {
        ipcom_printf("The number of bands for MBC must be between 2 and %d"IP_LF,
                     IPNET_IFQ_CONTAINER_MAX_COUNT);
        return ipnet_cmd_qc_help_mbc();
    }

    return 0;
}
/*
 *===========================================================================
 *                      ipnet_cmd_qc_del_queue
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_cmd_qc_del_queue(Ipnet_cmd_qc *p)
{
    ipcom_strcpy(p->p.ifq.ifq_type, "none");
    if (ipcom_socketioctl(p->fd, IPNET_SIOCSIFQUEUE, &p->p.ifq) < 0)
    {
        ipcom_printf("Failed to delete the queue: %s"IP_LF, ipcom_strerror(ipcom_errno));
        return -1;
    }
    return 0;
}