1 /*
2 * basic_ui.c
3 *
4 * MontaVista IPMI basic UI to use the main UI code.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2002,2003 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this program; if not, write to the Free
31 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
34
35 #include <config.h>
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <OpenIPMI/selector.h>
42 #include <OpenIPMI/ipmi_ui.h>
43 #include <OpenIPMI/ipmi_auth.h>
44 #include <OpenIPMI/ipmi_conn.h>
45 #include <OpenIPMI/ipmi_debug.h>
46 #include <OpenIPMI/ipmiif.h>
47
48 #include <OpenIPMI/internal/ipmi_malloc.h>
49
50 #ifdef HAVE_UCDSNMP
51 # ifdef HAVE_NETSNMP
52 # include <net-snmp/net-snmp-config.h>
53 # include <net-snmp/net-snmp-includes.h>
54 # elif defined(HAVE_ALT_UCDSNMP_DIR)
55 # include <ucd-snmp/asn1.h>
56 # include <ucd-snmp/snmp_api.h>
57 # include <ucd-snmp/snmp.h>
58 # else
59 # include <asn1.h>
60 # include <snmp_api.h>
61 # include <snmp.h>
62 # endif
63 #endif
64
65 extern struct selector_s *ui_sel;
66
67 /* This is here because the POSIX library requires it, but we only
68 pull the posix library to get the selector code, so this is not
69 used. */
70 void
posix_vlog(char * format,enum ipmi_log_type_e log_type,va_list ap)71 posix_vlog(char *format,
72 enum ipmi_log_type_e log_type,
73 va_list ap)
74 {
75 }
76
77 #ifdef HAVE_UCDSNMP
78 #define IPMI_OID_SIZE 9
79 static oid ipmi_oid[IPMI_OID_SIZE] = {1,3,6,1,4,1,3183,1,1};
snmp_input(int op,struct snmp_session * session,int reqid,struct snmp_pdu * pdu,void * magic)80 int snmp_input(int op,
81 struct snmp_session *session,
82 int reqid,
83 struct snmp_pdu *pdu,
84 void *magic)
85 {
86 struct sockaddr_in *src_ip;
87 uint32_t specific;
88 struct variable_list *var;
89
90 #ifdef HAVE_NETSNMP
91 if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE)
92 goto out;
93 #else
94 if (op != RECEIVED_MESSAGE)
95 goto out;
96 #endif
97 if (pdu->command != SNMP_MSG_TRAP)
98 goto out;
99 if (snmp_oid_compare(ipmi_oid, IPMI_OID_SIZE,
100 pdu->enterprise, pdu->enterprise_length)
101 != 0)
102 {
103 goto out;
104 }
105 if (pdu->trap_type != SNMP_TRAP_ENTERPRISESPECIFIC)
106 goto out;
107
108 src_ip = (struct sockaddr_in *) &pdu->agent_addr;
109 specific = pdu->specific_type;
110
111 var = pdu->variables;
112 if (var == NULL)
113 goto out;
114 if (var->type != ASN_OCTET_STR)
115 goto out;
116 if (snmp_oid_compare(ipmi_oid, IPMI_OID_SIZE, var->name, var->name_length)
117 != 0)
118 {
119 goto out;
120 }
121 if (var->val_len < 46)
122 goto out;
123
124 ipmi_handle_snmp_trap_data(src_ip,
125 sizeof(*src_ip),
126 IPMI_EXTERN_ADDR_IP,
127 specific,
128 var->val.string,
129 var->val_len);
130
131 out:
132 return 1;
133 }
134
135 #ifdef HAVE_NETSNMP
136 static int
snmp_pre_parse(netsnmp_session * session,netsnmp_transport * transport,void * transport_data,int transport_data_length)137 snmp_pre_parse(netsnmp_session * session, netsnmp_transport *transport,
138 void *transport_data, int transport_data_length)
139 {
140 return 1;
141 }
142 #else
143 static int
snmp_pre_parse(struct snmp_session * session,snmp_ipaddr from)144 snmp_pre_parse(struct snmp_session *session, snmp_ipaddr from)
145 {
146 return 1;
147 }
148 #endif
149
150 struct snmp_session *snmp_session;
151
152 struct snmp_fd_data {
153 int fd;
154 os_hnd_fd_id_t *id;
155 struct snmp_fd_data *next;
156 };
157
158 static struct snmp_fd_data *snmpfd = NULL;
159 os_hnd_timer_id_t *snmp_timer = NULL;
160
161 static void
snmp_check_read_fds(int fd,void * cb_data,os_hnd_fd_id_t * id)162 snmp_check_read_fds(int fd, void *cb_data, os_hnd_fd_id_t *id)
163 {
164 fd_set fdset;
165
166 FD_ZERO(&fdset);
167 FD_SET(fd, &fdset);
168 snmp_read(&fdset);
169 }
170
171 static void
snmp_check_timeout(void * cb_data,os_hnd_timer_id_t * id)172 snmp_check_timeout(void *cb_data, os_hnd_timer_id_t *id)
173 {
174 snmp_timeout();
175 }
176
177 static void
snmp_setup_fds(os_handler_t * os_hnd)178 snmp_setup_fds(os_handler_t *os_hnd)
179 {
180 int nfds = 0, block = 0, i, rv;
181 fd_set fdset;
182 struct timeval tv;
183 struct snmp_fd_data *fdd, *nfdd, *prev = NULL;
184
185 FD_ZERO(&fdset);
186 tv.tv_sec = 0;
187 tv.tv_usec = 0;
188 snmp_select_info(&nfds, &fdset, &tv, &block);
189
190 /* Run through the list. Since the list is kept sorted, we only
191 need one pass. */
192 fdd = snmpfd;
193 for (i = 0; i < nfds; i++) {
194 if (!FD_ISSET(i, &fdset))
195 continue;
196
197 if (fdd) {
198 if (fdd->fd == i) {
199 /* Didn't change. */
200 prev = fdd;
201 fdd = fdd->next;
202 continue;
203 }
204 if (fdd->fd < i) {
205 /* Current one was deleted. */
206 os_hnd->remove_fd_to_wait_for(os_hnd, fdd->id);
207 if (prev)
208 prev->next = fdd->next;
209 else
210 snmpfd = fdd->next;
211 os_hnd->mem_free(fdd);
212 continue;
213 }
214 }
215
216 /* New one to add. */
217 nfdd = os_hnd->mem_alloc(sizeof(*fdd));
218 if (!nfdd) {
219 rv = ENOMEM;
220 goto err;
221 }
222 nfdd->fd = i;
223 rv = os_hnd->add_fd_to_wait_for(os_hnd, i, snmp_check_read_fds,
224 NULL, NULL, &nfdd->id);
225 if (rv)
226 goto err;
227
228 /* Insert after */
229 if (fdd) {
230 nfdd->next = fdd->next;
231 fdd->next = nfdd;
232 } else {
233 nfdd->next = NULL;
234 snmpfd = fdd;
235 }
236 }
237
238 if (!block) {
239 os_hnd->stop_timer(os_hnd, snmp_timer);
240 } else {
241 os_hnd->stop_timer(os_hnd, snmp_timer);
242 os_hnd->start_timer(os_hnd, snmp_timer, &tv, snmp_check_timeout, NULL);
243 }
244 return;
245
246 err:
247 fprintf(stderr, "Error handling SNMP fd data: %s\n", strerror(rv));
248 exit(1);
249 }
250
251 int
snmp_init(os_handler_t * os_hnd)252 snmp_init(os_handler_t *os_hnd)
253 {
254 struct snmp_session session;
255 #ifdef HAVE_NETSNMP
256 netsnmp_transport *transport = NULL;
257 static char *snmp_default_port = "udp:162";
258 int rv;
259
260 rv = os_hnd->alloc_timer(os_hnd, &snmp_timer);
261 if (rv) {
262 fprintf(stderr, "Could not allocate SNMP timer\n");
263 return -1;
264 }
265
266 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
267 NETSNMP_DS_LIB_MIB_ERRORS,
268 0);
269
270 init_snmp("ipmi_ui");
271
272 transport = netsnmp_tdomain_transport(snmp_default_port, 1, "udp");
273 if (!transport) {
274 snmp_sess_perror("ipmi_ui", &session);
275 return -1;
276 }
277 #else
278 void *transport = NULL;
279 #endif
280 snmp_sess_init(&session);
281 session.peername = SNMP_DEFAULT_PEERNAME;
282 session.version = SNMP_DEFAULT_VERSION;
283 session.community_len = SNMP_DEFAULT_COMMUNITY_LEN;
284 session.retries = SNMP_DEFAULT_RETRIES;
285 session.timeout = SNMP_DEFAULT_TIMEOUT;
286 session.local_port = SNMP_TRAP_PORT;
287 session.callback = snmp_input;
288 session.callback_magic = transport;
289 session.authenticator = NULL;
290 session.isAuthoritative = SNMP_SESS_UNKNOWNAUTH;
291
292 #ifdef HAVE_NETSNMP
293 snmp_session = snmp_add(&session, transport, snmp_pre_parse, NULL);
294 #else
295 snmp_session = snmp_open_ex(&session, snmp_pre_parse,
296 NULL, NULL, NULL, NULL);
297 #endif
298 if (snmp_session == NULL) {
299 snmp_sess_perror("ipmi_ui", &session);
300 return -1;
301 }
302
303 return 0;
304 }
305 #else
snmp_setup_fds(os_handler_t * os_hnd)306 static void snmp_setup_fds(os_handler_t *os_hnd) { }
307 #endif /* HAVE_UCDSNMP */
308
309 int
main(int argc,char * argv[])310 main(int argc, char *argv[])
311 {
312 int rv;
313 int curr_arg = 1;
314 const char *arg;
315 int full_screen = 1;
316 ipmi_domain_id_t domain_id;
317 int i;
318 #ifdef HAVE_UCDSNMP
319 int init_snmp = 0;
320 #endif
321 ipmi_args_t *con_parms[2];
322 ipmi_con_t *con[2];
323 int last_con = 0;
324
325 while ((curr_arg < argc) && (argv[curr_arg][0] == '-')) {
326 arg = argv[curr_arg];
327 curr_arg++;
328 if (strcmp(arg, "--") == 0) {
329 break;
330 } else if (strcmp(arg, "-c") == 0) {
331 full_screen = 0;
332 } else if (strcmp(arg, "-dlock") == 0) {
333 DEBUG_LOCKS_ENABLE();
334 } else if (strcmp(arg, "-dmem") == 0) {
335 DEBUG_MALLOC_ENABLE();
336 } else if (strcmp(arg, "-drawmsg") == 0) {
337 DEBUG_RAWMSG_ENABLE();
338 } else if (strcmp(arg, "-dmsg") == 0) {
339 DEBUG_MSG_ENABLE();
340 #ifdef HAVE_UCDSNMP
341 } else if (strcmp(arg, "-snmp") == 0) {
342 init_snmp = 1;
343 #endif
344 } else {
345 fprintf(stderr, "Unknown option: %s\n", arg);
346 return 1;
347 }
348 }
349
350 rv = sel_alloc_selector_nothread(&ui_sel);
351 if (rv) {
352 fprintf(stderr, "Could not allocate selector\n");
353 exit(1);
354 }
355
356 rv = ipmi_ui_init(&ipmi_ui_cb_handlers, full_screen);
357
358 #ifdef HAVE_UCDSNMP
359 if (init_snmp) {
360 if (snmp_init(&ipmi_ui_cb_handlers) < 0)
361 goto out;
362 }
363 #endif
364
365 next_con:
366 rv = ipmi_parse_args2(&curr_arg, argc, argv, &con_parms[last_con]);
367 if (rv) {
368 fprintf(stderr, "Error parsing command arguments, argument %d: %s\n",
369 curr_arg, strerror(rv));
370 exit(1);
371 }
372 last_con++;
373
374 if (curr_arg < argc) {
375 if (last_con == 2) {
376 fprintf(stderr, "Too many connections\n");
377 rv = EINVAL;
378 goto out;
379 }
380 goto next_con;
381 }
382
383 for (i=0; i<last_con; i++) {
384 rv = ipmi_args_setup_con(con_parms[i],
385 &ipmi_ui_cb_handlers,
386 NULL,
387 &con[i]);
388 if (rv) {
389 fprintf(stderr, "ipmi_ip_setup_con: %s", strerror(rv));
390 exit(1);
391 }
392 }
393
394 for (i=0; i<last_con; i++)
395 ipmi_free_args(con_parms[i]);
396
397 rv = ipmi_open_domain("first", con, last_con, ipmi_ui_setup_done,
398 NULL, NULL, NULL, NULL, 0, &domain_id);
399 if (rv) {
400 fprintf(stderr, "ipmi_open_domain: %s\n", strerror(rv));
401 goto out;
402 }
403
404 for (;;) {
405 #ifdef HAVE_UCDSNMP
406 if (init_snmp)
407 snmp_setup_fds(&ipmi_ui_cb_handlers);
408 #endif
409 ipmi_ui_cb_handlers.perform_one_op(&ipmi_ui_cb_handlers, NULL);
410 }
411
412 out:
413 ipmi_ui_shutdown();
414
415 if (rv)
416 return 1;
417 return 0;
418 }
419