/*
* basic_ui.c
*
* MontaVista IPMI basic UI to use the main UI code.
*
* Author: MontaVista Software, Inc.
* Corey Minyard <minyard@mvista.com>
* source@mvista.com
*
* Copyright 2002,2003 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
*
* THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <OpenIPMI/selector.h>
#include <OpenIPMI/ipmi_ui.h>
#include <OpenIPMI/ipmi_auth.h>
#include <OpenIPMI/ipmi_conn.h>
#include <OpenIPMI/ipmi_debug.h>
#include <OpenIPMI/ipmiif.h>
#include <OpenIPMI/internal/ipmi_malloc.h>
#ifdef HAVE_UCDSNMP
# ifdef HAVE_NETSNMP
# include <net-snmp/net-snmp-config.h>
# include <net-snmp/net-snmp-includes.h>
# elif defined(HAVE_ALT_UCDSNMP_DIR)
# include <ucd-snmp/asn1.h>
# include <ucd-snmp/snmp_api.h>
# include <ucd-snmp/snmp.h>
# else
# include <asn1.h>
# include <snmp_api.h>
# include <snmp.h>
# endif
#endif
extern struct selector_s *ui_sel;
/* This is here because the POSIX library requires it, but we only
pull the posix library to get the selector code, so this is not
used. */
void
posix_vlog(char *format,
enum ipmi_log_type_e log_type,
va_list ap)
{
}
#ifdef HAVE_UCDSNMP
#define IPMI_OID_SIZE 9
static oid ipmi_oid[IPMI_OID_SIZE] = {1,3,6,1,4,1,3183,1,1};
int snmp_input(int op,
struct snmp_session *session,
int reqid,
struct snmp_pdu *pdu,
void *magic)
{
struct sockaddr_in *src_ip;
uint32_t specific;
struct variable_list *var;
#ifdef HAVE_NETSNMP
if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE)
goto out;
#else
if (op != RECEIVED_MESSAGE)
goto out;
#endif
if (pdu->command != SNMP_MSG_TRAP)
goto out;
if (snmp_oid_compare(ipmi_oid, IPMI_OID_SIZE,
pdu->enterprise, pdu->enterprise_length)
!= 0)
{
goto out;
}
if (pdu->trap_type != SNMP_TRAP_ENTERPRISESPECIFIC)
goto out;
src_ip = (struct sockaddr_in *) &pdu->agent_addr;
specific = pdu->specific_type;
var = pdu->variables;
if (var == NULL)
goto out;
if (var->type != ASN_OCTET_STR)
goto out;
if (snmp_oid_compare(ipmi_oid, IPMI_OID_SIZE, var->name, var->name_length)
!= 0)
{
goto out;
}
if (var->val_len < 46)
goto out;
ipmi_handle_snmp_trap_data(src_ip,
sizeof(*src_ip),
IPMI_EXTERN_ADDR_IP,
specific,
var->val.string,
var->val_len);
out:
return 1;
}
#ifdef HAVE_NETSNMP
static int
snmp_pre_parse(netsnmp_session * session, netsnmp_transport *transport,
void *transport_data, int transport_data_length)
{
return 1;
}
#else
static int
snmp_pre_parse(struct snmp_session *session, snmp_ipaddr from)
{
return 1;
}
#endif
struct snmp_session *snmp_session;
struct snmp_fd_data {
int fd;
os_hnd_fd_id_t *id;
struct snmp_fd_data *next;
};
static struct snmp_fd_data *snmpfd = NULL;
os_hnd_timer_id_t *snmp_timer = NULL;
static void
snmp_check_read_fds(int fd, void *cb_data, os_hnd_fd_id_t *id)
{
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
snmp_read(&fdset);
}
static void
snmp_check_timeout(void *cb_data, os_hnd_timer_id_t *id)
{
snmp_timeout();
}
static void
snmp_setup_fds(os_handler_t *os_hnd)
{
int nfds = 0, block = 0, i, rv;
fd_set fdset;
struct timeval tv;
struct snmp_fd_data *fdd, *nfdd, *prev = NULL;
FD_ZERO(&fdset);
tv.tv_sec = 0;
tv.tv_usec = 0;
snmp_select_info(&nfds, &fdset, &tv, &block);
/* Run through the list. Since the list is kept sorted, we only
need one pass. */
fdd = snmpfd;
for (i = 0; i < nfds; i++) {
if (!FD_ISSET(i, &fdset))
continue;
if (fdd) {
if (fdd->fd == i) {
/* Didn't change. */
prev = fdd;
fdd = fdd->next;
continue;
}
if (fdd->fd < i) {
/* Current one was deleted. */
os_hnd->remove_fd_to_wait_for(os_hnd, fdd->id);
if (prev)
prev->next = fdd->next;
else
snmpfd = fdd->next;
os_hnd->mem_free(fdd);
continue;
}
}
/* New one to add. */
nfdd = os_hnd->mem_alloc(sizeof(*fdd));
if (!nfdd) {
rv = ENOMEM;
goto err;
}
nfdd->fd = i;
rv = os_hnd->add_fd_to_wait_for(os_hnd, i, snmp_check_read_fds,
NULL, NULL, &nfdd->id);
if (rv)
goto err;
/* Insert after */
if (fdd) {
nfdd->next = fdd->next;
fdd->next = nfdd;
} else {
nfdd->next = NULL;
snmpfd = fdd;
}
}
if (!block) {
os_hnd->stop_timer(os_hnd, snmp_timer);
} else {
os_hnd->stop_timer(os_hnd, snmp_timer);
os_hnd->start_timer(os_hnd, snmp_timer, &tv, snmp_check_timeout, NULL);
}
return;
err:
fprintf(stderr, "Error handling SNMP fd data: %s\n", strerror(rv));
exit(1);
}
int
snmp_init(os_handler_t *os_hnd)
{
struct snmp_session session;
#ifdef HAVE_NETSNMP
netsnmp_transport *transport = NULL;
static char *snmp_default_port = "udp:162";
int rv;
rv = os_hnd->alloc_timer(os_hnd, &snmp_timer);
if (rv) {
fprintf(stderr, "Could not allocate SNMP timer\n");
return -1;
}
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
NETSNMP_DS_LIB_MIB_ERRORS,
0);
init_snmp("ipmi_ui");
transport = netsnmp_tdomain_transport(snmp_default_port, 1, "udp");
if (!transport) {
snmp_sess_perror("ipmi_ui", &session);
return -1;
}
#else
void *transport = NULL;
#endif
snmp_sess_init(&session);
session.peername = SNMP_DEFAULT_PEERNAME;
session.version = SNMP_DEFAULT_VERSION;
session.community_len = SNMP_DEFAULT_COMMUNITY_LEN;
session.retries = SNMP_DEFAULT_RETRIES;
session.timeout = SNMP_DEFAULT_TIMEOUT;
session.local_port = SNMP_TRAP_PORT;
session.callback = snmp_input;
session.callback_magic = transport;
session.authenticator = NULL;
session.isAuthoritative = SNMP_SESS_UNKNOWNAUTH;
#ifdef HAVE_NETSNMP
snmp_session = snmp_add(&session, transport, snmp_pre_parse, NULL);
#else
snmp_session = snmp_open_ex(&session, snmp_pre_parse,
NULL, NULL, NULL, NULL);
#endif
if (snmp_session == NULL) {
snmp_sess_perror("ipmi_ui", &session);
return -1;
}
return 0;
}
#else
static void snmp_setup_fds(os_handler_t *os_hnd) { }
#endif /* HAVE_UCDSNMP */
void help(void)
{
fprintf(stdout, "ipmi_ui [ options ] smi smi-num\n");
fprintf(stdout, "ipmi_ui [ oprions ] lan IP port [IP2 port2] auth priv user pass\n");
fprintf(stdout, "\n");
fprintf(stdout, "Options:\n");
fprintf(stdout, " -c Command line mode\n");
fprintf(stdout, " -dlock Lock debugging ON\n");
fprintf(stdout, " -dmem Memory debugging ON\n");
fprintf(stdout, " -drawmsg Raw message ON\n");
fprintf(stdout, " -dmsg Dump all messages.\n");
#ifdef HAVE_UCDSNMP
fprintf(stdout, " -snmp SNMP trap handler ON\n");
#endif
fprintf(stdout, "Auth:\n");
fprintf(stdout, " none | straight | md5 | md2\n");
fprintf(stdout, "Priv:\n");
fprintf(stdout, " callback | user | operator | admin\n");
}
int
main(int argc, char *argv[])
{
int rv;
int curr_arg = 1;
const char *arg;
int full_screen = 1;
ipmi_domain_id_t domain_id;
int i;
#ifdef HAVE_UCDSNMP
int init_snmp = 0;
#endif
ipmi_args_t *con_parms[2];
ipmi_con_t *con[2];
int last_con = 0;
while ((curr_arg < argc) && (argv[curr_arg][0] == '-')) {
arg = argv[curr_arg];
curr_arg++;
if (strcmp(arg, "--") == 0) {
break;
} else if (strcmp(arg, "-?") == 0 ||
strcmp(arg, "-h") == 0 ||
strcmp(arg, "--help") == 0) {
help();
return(1);
} else if (strcmp(arg, "-c") == 0) {
full_screen = 0;
} else if (strcmp(arg, "-dlock") == 0) {
DEBUG_LOCKS_ENABLE();
} else if (strcmp(arg, "-dmem") == 0) {
DEBUG_MALLOC_ENABLE();
} else if (strcmp(arg, "-drawmsg") == 0) {
DEBUG_RAWMSG_ENABLE();
} else if (strcmp(arg, "-dmsg") == 0) {
DEBUG_MSG_ENABLE();
#ifdef HAVE_UCDSNMP
} else if (strcmp(arg, "-snmp") == 0) {
init_snmp = 1;
#endif
} else {
fprintf(stderr, "Unknown option: %s\n", arg);
return 1;
}
}
rv = sel_alloc_selector_nothread(&ui_sel);
if (rv) {
fprintf(stderr, "Could not allocate selector\n");
exit(1);
}
rv = ipmi_ui_init(&ipmi_ui_cb_handlers, full_screen);
#ifdef HAVE_UCDSNMP
if (init_snmp) {
if (snmp_init(&ipmi_ui_cb_handlers) < 0)
goto out;
}
#endif
next_con:
rv = ipmi_parse_args2(&curr_arg, argc, argv, &con_parms[last_con]);
if (rv) {
fprintf(stderr, "Error parsing command arguments, argument %d: %s\n",
curr_arg, strerror(rv));
exit(1);
}
last_con++;
if (curr_arg < argc) {
if (last_con == 2) {
fprintf(stderr, "Too many connections\n");
rv = EINVAL;
goto out;
}
goto next_con;
}
for (i=0; i<last_con; i++) {
rv = ipmi_args_setup_con(con_parms[i],
&ipmi_ui_cb_handlers,
NULL,
&con[i]);
if (rv) {
fprintf(stderr, "ipmi_ip_setup_con: %s", strerror(rv));
exit(1);
}
}
for (i=0; i<last_con; i++)
ipmi_free_args(con_parms[i]);
rv = ipmi_open_domain("first", con, last_con, ipmi_ui_setup_done,
NULL, NULL, NULL, NULL, 0, &domain_id);
if (rv) {
fprintf(stderr, "ipmi_open_domain: %s\n", strerror(rv));
goto out;
}
for (;;) {
#ifdef HAVE_UCDSNMP
if (init_snmp)
snmp_setup_fds(&ipmi_ui_cb_handlers);
#endif
ipmi_ui_cb_handlers.perform_one_op(&ipmi_ui_cb_handlers, NULL);
}
out:
ipmi_ui_shutdown();
if (rv)
return 1;
return 0;
}