1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <assert.h>
30 #include <inttypes.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <netdb.h>
39 #include <fcntl.h>
40
41 #include "libipmi.h"
42 #include "ipmi_lan.h"
43 #include "ipmi_impl.h"
44
45 #define DEF_IPMI_LAN_TIMEOUT 3 /* seconds */
46 #define DEF_IPMI_LAN_NUM_RETRIES 5
47 #define IPMI_LAN_CHANNEL_E 0x0e
48
49 typedef struct ipmi_rs {
50 uint8_t ir_data[IPMI_BUF_SIZE];
51 int ir_dlen;
52 ipmi_msg_hdr_t ir_ihdr;
53 uint8_t ir_ccode;
54 } ipmi_rs_t;
55
56 static ipmi_rs_t *ipmi_lan_poll_recv(ipmi_handle_t *);
57
58 typedef struct ipmi_rq_entry {
59 ipmi_list_t ire_list;
60 ipmi_cmd_t ire_req;
61 uint8_t ire_target_cmd;
62 uint8_t ire_rq_seq;
63 uint8_t *ire_msg_data;
64 int ire_msg_len;
65 } ipmi_rq_entry_t;
66
67 ipmi_rq_entry_t *ipmi_req_entries = NULL;
68
69 /*
70 * LAN transport-specific data
71 */
72 typedef struct ipmi_lan {
73 ipmi_handle_t *il_ihp;
74 char il_host[MAXHOSTNAMELEN + 1];
75 uint16_t il_port;
76 char il_user[17];
77 char il_authcode[IPMI_AUTHCODE_BUF_SIZE + 1];
78 uint8_t il_challenge[16];
79 uint32_t il_session_id;
80 int il_sd;
81 boolean_t il_send_authcode;
82 boolean_t il_session_active;
83 uint8_t il_authtype;
84 uint8_t il_privlvl;
85 uint8_t il_num_retries;
86 uint32_t il_in_seq;
87 uint32_t il_timeout;
88 struct sockaddr_in il_addr;
89 socklen_t il_addrlen;
90 } ipmi_lan_t;
91
92 /*
93 * Calculate and returns IPMI checksum
94 *
95 * Checksum algorithm is described in Section 13.8
96 *
97 * d: buffer to check
98 * s: position in buffer to start checksum from
99 */
100 static uint8_t
101 ipmi_csum(uint8_t *d, int s)
102 {
103 uint8_t c = 0;
104 for (; s > 0; s--, d++)
105 c += *d;
106 return (-c);
107 }
108
109 static ipmi_rq_entry_t *
110 ipmi_req_add_entry(ipmi_handle_t *ihp, ipmi_cmd_t *req)
111 {
112 ipmi_rq_entry_t *e;
113
114 if ((e = ipmi_zalloc(ihp, sizeof (ipmi_rq_entry_t))) == NULL)
115 return (NULL);
116
117 (void) memcpy(&e->ire_req, req, sizeof (ipmi_cmd_t));
118 ipmi_list_append(&ipmi_req_entries->ire_list, e);
119
120 return (e);
121 }
122
123 /*ARGSUSED*/
124 static ipmi_rq_entry_t *
125 ipmi_req_lookup_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd)
126 {
127 ipmi_rq_entry_t *e;
128
129 for (e = ipmi_list_next(&ipmi_req_entries->ire_list); e != NULL;
130 e = ipmi_list_next(e))
131 if (e->ire_rq_seq == seq && e->ire_req.ic_cmd == cmd)
132 return (e);
133
134 return (NULL);
135 }
136
137 static void
138 ipmi_req_remove_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd)
139 {
140 ipmi_rq_entry_t *e;
141
142 e = ipmi_req_lookup_entry(ihp, seq, cmd);
143
144 if (e) {
145 ipmi_list_delete(&ipmi_req_entries->ire_list, e);
146 ipmi_free(ihp, e->ire_msg_data);
147 ipmi_free(ihp, e);
148 }
149 }
150
151 static void
152 ipmi_req_clear_entries(ipmi_handle_t *ihp)
153 {
154 ipmi_rq_entry_t *e;
155
156 while ((e = ipmi_list_next(&ipmi_req_entries->ire_list)) != NULL) {
157 ipmi_list_delete(&ipmi_req_entries->ire_list, e);
158 ipmi_free(ihp, e);
159 }
160 }
161
162 static int
163 get_random(void *buf, uint_t len)
164 {
165 int fd;
166
167 assert(buf != NULL && len > 0);
168 if ((fd = open("/dev/urandom", O_RDONLY)) < 0)
169 return (-1);
170
171 if (read(fd, buf, len) < 0) {
172 (void) close(fd);
173 return (-1);
174 }
175 (void) close(fd);
176 return (0);
177 }
178
179 static int
180 ipmi_lan_send_packet(ipmi_handle_t *ihp, uint8_t *data, int dlen)
181 {
182 ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
183
184 return (send(ilp->il_sd, data, dlen, 0));
185 }
186
187 static ipmi_rs_t *
188 ipmi_lan_recv_packet(ipmi_handle_t *ihp)
189 {
190 static ipmi_rs_t rsp;
191 fd_set read_set, err_set;
192 struct timeval tmout;
193 ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
194 int ret;
195
196 FD_ZERO(&read_set);
197 FD_SET(ilp->il_sd, &read_set);
198
199 FD_ZERO(&err_set);
200 FD_SET(ilp->il_sd, &err_set);
201
202 tmout.tv_sec = ilp->il_timeout;
203 tmout.tv_usec = 0;
204
205 ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout);
206 if (ret < 0 || FD_ISSET(ilp->il_sd, &err_set) ||
207 !FD_ISSET(ilp->il_sd, &read_set))
208 return (NULL);
209
210 /*
211 * The first read may return ECONNREFUSED because the rmcp ping
212 * packet--sent to UDP port 623--will be processed by both the
213 * BMC and the OS.
214 *
215 * The problem with this is that the ECONNREFUSED takes
216 * priority over any other received datagram; that means that
217 * the Connection Refused shows up _before_ the response packet,
218 * regardless of the order they were sent out. (unless the
219 * response is read before the connection refused is returned)
220 */
221 ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0);
222
223 if (ret < 0) {
224 FD_ZERO(&read_set);
225 FD_SET(ilp->il_sd, &read_set);
226
227 FD_ZERO(&err_set);
228 FD_SET(ilp->il_sd, &err_set);
229
230 tmout.tv_sec = ilp->il_timeout;
231 tmout.tv_usec = 0;
232
233 ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout);
234 if (ret < 0) {
235 if (FD_ISSET(ilp->il_sd, &err_set) ||
236 !FD_ISSET(ilp->il_sd, &read_set))
237 return (NULL);
238
239 ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0);
240 if (ret < 0)
241 return (NULL);
242 }
243 }
244
245 if (ret == 0)
246 return (NULL);
247
248 rsp.ir_data[ret] = '\0';
249 rsp.ir_dlen = ret;
250
251 return (&rsp);
252 }
253
254
255 /*
256 * ASF/RMCP Pong Message
257 *
258 * See section 13.2.4
259 */
260 struct rmcp_pong {
261 rmcp_hdr_t rp_rmcp;
262 asf_hdr_t rp_asf;
263 uint32_t rp_iana;
264 uint32_t rp_oem;
265 uint8_t rp_sup_entities;
266 uint8_t rp_sup_interact;
267 uint8_t rp_reserved[6];
268 };
269
270 /*
271 * parse response RMCP "pong" packet
272 *
273 * return -1 if ping response not received
274 * returns 0 if IPMI is NOT supported
275 * returns 1 if IPMI is supported
276 */
277 /*ARGSUSED*/
278 static int
279 ipmi_handle_pong(ipmi_handle_t *ihp, ipmi_rs_t *rsp)
280 {
281 struct rmcp_pong *pong;
282
283 if (rsp == NULL)
284 return (-1);
285
286 /*LINTED: E_BAD_PTR_CAST_ALIGN*/
287 pong = (struct rmcp_pong *)rsp->ir_data;
288
289 return ((pong->rp_sup_entities & 0x80) ? 1 : 0);
290 }
291
292 /*
293 * Build and send RMCP presence ping message
294 */
295 static int
296 ipmi_lan_ping(ipmi_handle_t *ihp)
297 {
298 rmcp_hdr_t rmcp_ping;
299 asf_hdr_t asf_ping;
300 uint8_t *data;
301 int rv, dlen = sizeof (rmcp_ping) + sizeof (asf_ping);
302
303 (void) memset(&rmcp_ping, 0, sizeof (rmcp_ping));
304 rmcp_ping.rh_version = RMCP_VERSION_1;
305 rmcp_ping.rh_msg_class = RMCP_CLASS_ASF;
306 rmcp_ping.rh_seq = 0xff;
307
308 (void) memset(&asf_ping, 0, sizeof (asf_ping));
309 asf_ping.ah_iana = htonl(ASF_RMCP_IANA);
310 asf_ping.ah_msg_type = ASF_TYPE_PING;
311
312 if ((data = ipmi_zalloc(ihp, dlen)) == NULL)
313 return (-1);
314
315 (void) memcpy(data, &rmcp_ping, sizeof (rmcp_ping));
316 (void) memcpy(data + sizeof (rmcp_ping), &asf_ping, sizeof (asf_ping));
317
318 rv = ipmi_lan_send_packet(ihp, data, dlen);
319
320 ipmi_free(ihp, data);
321
322 if (rv < 0)
323 return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL));
324
325 if (ipmi_lan_poll_recv(ihp) == NULL)
326 return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL));
327
328 return (0);
329 }
330
331 static ipmi_rs_t *
332 ipmi_lan_poll_recv(ipmi_handle_t *ihp)
333 {
334 rmcp_hdr_t rmcp_rsp;
335 ipmi_rs_t *rsp;
336 ipmi_rq_entry_t *entry;
337 int off = 0, rv;
338 ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
339 uint8_t rsp_authtype;
340
341 rsp = ipmi_lan_recv_packet(ihp);
342
343 while (rsp != NULL) {
344
345 /* parse response headers */
346 (void) memcpy(&rmcp_rsp, rsp->ir_data, 4);
347
348 switch (rmcp_rsp.rh_msg_class) {
349 case RMCP_CLASS_ASF:
350 /* ping response packet */
351 rv = ipmi_handle_pong(ihp, rsp);
352 return ((rv <= 0) ? NULL : rsp);
353 case RMCP_CLASS_IPMI:
354 /* handled by rest of function */
355 break;
356 default:
357 /* Invalid RMCP class */
358 rsp = ipmi_lan_recv_packet(ihp);
359 continue;
360 }
361
362 off = sizeof (rmcp_hdr_t);
363 rsp_authtype = rsp->ir_data[off];
364 if (ilp->il_send_authcode && (rsp_authtype || ilp->il_authtype))
365 off += 26;
366 else
367 off += 10;
368
369 (void) memcpy(&rsp->ir_ihdr, (void *)(rsp->ir_data + off),
370 sizeof (rsp->ir_ihdr));
371 rsp->ir_ihdr.imh_seq = rsp->ir_ihdr.imh_seq >> 2;
372 off += sizeof (rsp->ir_ihdr);
373 rsp->ir_ccode = rsp->ir_data[off++];
374
375 entry = ipmi_req_lookup_entry(ihp, rsp->ir_ihdr.imh_seq,
376 rsp->ir_ihdr.imh_cmd);
377 if (entry) {
378 ipmi_req_remove_entry(ihp, rsp->ir_ihdr.imh_seq,
379 rsp->ir_ihdr.imh_cmd);
380 } else {
381 rsp = ipmi_lan_recv_packet(ihp);
382 continue;
383 }
384 break;
385 }
386
387 /* shift response data to start of array */
388 if (rsp && rsp->ir_dlen > off) {
389 rsp->ir_dlen -= off + 1;
390 (void) memmove(rsp->ir_data, rsp->ir_data + off, rsp->ir_dlen);
391 (void) memset(rsp->ir_data + rsp->ir_dlen, 0,
392 IPMI_BUF_SIZE - rsp->ir_dlen);
393 }
394 return (rsp);
395 }
396
397 /*
398 * IPMI LAN Request Message Format
399 *
400 * See section 13.8
401 *
402 * +---------------------+
403 * | rmcp_hdr_t | 4 bytes
404 * +---------------------+
405 * | v15_session_hdr_t | 9 bytes
406 * +---------------------+
407 * | [authcode] | 16 bytes (if AUTHTYPE != none)
408 * +---------------------+
409 * | msg length | 1 byte
410 * +---------------------+
411 * | ipmi_msg_hdr_t | 6 bytes
412 * +---------------------+
413 * | [msg data] | variable
414 * +---------------------+
415 * | msg data checksum | 1 byte
416 * +---------------------+
417 */
418 static ipmi_rq_entry_t *
419 ipmi_lan_build_cmd(ipmi_handle_t *ihp, ipmi_cmd_t *req)
420 {
421 ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
422 rmcp_hdr_t rmcp_hdr;
423 v15_session_hdr_t session_hdr;
424 ipmi_msg_hdr_t msg_hdr;
425 uint8_t *msg;
426 int cs, tmp, off = 0, len;
427 ipmi_rq_entry_t *entry;
428 static int curr_seq = 0;
429
430 if (curr_seq >= 64)
431 curr_seq = 0;
432
433 if ((entry = ipmi_req_add_entry(ihp, req)) == NULL)
434 return (NULL);
435
436 len = req->ic_dlen + 29;
437 if (ilp->il_send_authcode && ilp->il_authtype)
438 len += 16;
439
440 if ((msg = ipmi_zalloc(ihp, len)) == NULL)
441 /* ipmi_errno set */
442 return (NULL);
443
444 /* RMCP header */
445 (void) memset(&rmcp_hdr, 0, sizeof (rmcp_hdr));
446 rmcp_hdr.rh_version = RMCP_VERSION_1;
447 rmcp_hdr.rh_msg_class = RMCP_CLASS_IPMI;
448 rmcp_hdr.rh_seq = 0xff;
449 (void) memcpy(msg, &rmcp_hdr, sizeof (rmcp_hdr));
450 off = sizeof (rmcp_hdr);
451
452 /* IPMI session header */
453 (void) memset(&session_hdr, 0, sizeof (session_hdr));
454 if (! ilp->il_send_authcode)
455 session_hdr.sh_authtype = 0x00;
456 else
457 /* hardcode passwd authentication */
458 session_hdr.sh_authtype = 0x04;
459
460 (void) memcpy(&session_hdr.sh_seq, &ilp->il_in_seq, sizeof (uint32_t));
461 (void) memcpy(&session_hdr.sh_id, &ilp->il_session_id,
462 sizeof (uint32_t));
463
464 (void) memcpy(msg + off, &session_hdr, sizeof (session_hdr));
465 off += sizeof (session_hdr);
466
467 /* IPMI session authcode */
468 if (ilp->il_send_authcode && ilp->il_authtype) {
469 (void) memcpy(msg + off, ilp->il_authcode, 16);
470 off += 16;
471 }
472
473 /* message length */
474 msg[off++] = req->ic_dlen + 7;
475 cs = off;
476
477 /* IPMI message header */
478 (void) memset(&msg_hdr, 0, sizeof (msg_hdr));
479 msg_hdr.imh_addr1 = IPMI_BMC_SLAVE_ADDR;
480 msg_hdr.imh_lun = req->ic_lun;
481 msg_hdr.imh_netfn = req->ic_netfn;
482 msg_hdr.imh_csum = ipmi_csum((uint8_t *)&msg_hdr, sizeof (msg_hdr));
483 cs = off;
484 msg_hdr.imh_addr2 = IPMI_BMC_SLAVE_ADDR;
485 entry->ire_rq_seq = curr_seq++;
486 msg_hdr.imh_seq = entry->ire_rq_seq << 2;
487 msg_hdr.imh_cmd = req->ic_cmd;
488 (void) memcpy(msg + off, &msg_hdr, sizeof (msg_hdr));
489 off += sizeof (msg_hdr);
490
491 /* message data */
492 if (req->ic_dlen != 0) {
493 (void) memcpy(msg + off, req->ic_data, req->ic_dlen);
494 off += req->ic_dlen;
495 }
496
497 /* message data checksum */
498 tmp = off - cs;
499 msg[off++] = ipmi_csum(msg + cs, tmp);
500
501 if (ilp->il_in_seq) {
502 ilp->il_in_seq++;
503 if (ilp->il_in_seq == 0)
504 ilp->il_in_seq++;
505 }
506
507 entry->ire_msg_len = off;
508 entry->ire_msg_data = msg;
509
510 return (entry);
511 }
512
513 static int
514 ipmi_lan_send(void *data, ipmi_cmd_t *cmd, ipmi_cmd_t *response,
515 int *completion)
516 {
517 ipmi_lan_t *ilp = (ipmi_lan_t *)data;
518 ipmi_rq_entry_t *entry = NULL;
519 ipmi_rs_t *rsp = NULL;
520 uint_t try = 0;
521
522 for (;;) {
523 if ((entry = ipmi_lan_build_cmd(ilp->il_ihp, cmd)) == NULL)
524 return (-1);
525
526 if (ipmi_lan_send_packet(ilp->il_ihp, entry->ire_msg_data,
527 entry->ire_msg_len) < 0) {
528 if (++try >= ilp->il_num_retries)
529 return (-1);
530 (void) usleep(5000);
531 continue;
532 }
533
534 (void) usleep(100);
535
536 if ((rsp = ipmi_lan_poll_recv(ilp->il_ihp)) != NULL)
537 break;
538
539 (void) usleep(5000);
540 ipmi_req_remove_entry(ilp->il_ihp, entry->ire_rq_seq,
541 entry->ire_req.ic_cmd);
542
543 if (++try >= ilp->il_num_retries)
544 return (-1);
545 }
546 response->ic_netfn = rsp->ir_ihdr.imh_netfn;
547 response->ic_lun = rsp->ir_ihdr.imh_lun;
548 response->ic_cmd = rsp->ir_ihdr.imh_cmd;
549 if (rsp->ir_ccode != 0) {
550 *completion = rsp->ir_ccode;
551 response->ic_dlen = 0;
552 response->ic_data = NULL;
553 } else {
554 *completion = 0;
555 response->ic_dlen = rsp->ir_dlen;
556 response->ic_data = rsp->ir_data;
557 }
558 return (0);
559 }
560
561 /*
562 * IPMI Get Session Challenge Command
563 *
564 * Copies the returned session ID and 16-byte challenge string to the supplied
565 * buffers
566 *
567 * See section 22.16
568 */
569 static int
570 ipmi_get_session_challenge_cmd(ipmi_handle_t *ihp, uint32_t *session_id,
571 uint8_t *challenge)
572 {
573 ipmi_cmd_t cmd, resp;
574 ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
575 char msg_data[17];
576 int ccode;
577
578 (void) memset(msg_data, 0, 17);
579
580 switch (ilp->il_authtype) {
581 case IPMI_SESSION_AUTHTYPE_NONE:
582 msg_data[0] = 0x00;
583 break;
584 case IPMI_SESSION_AUTHTYPE_MD2:
585 msg_data[0] = 0x01;
586 break;
587 case IPMI_SESSION_AUTHTYPE_MD5:
588 msg_data[0] = 0x02;
589 break;
590 case IPMI_SESSION_AUTHTYPE_PASSWORD:
591 msg_data[0] = 0x04;
592 break;
593 case IPMI_SESSION_AUTHTYPE_OEM:
594 msg_data[0] = 0x05;
595 break;
596 }
597 (void) memcpy(msg_data + 1, ilp->il_user, 16);
598
599 cmd.ic_netfn = IPMI_NETFN_APP;
600 cmd.ic_lun = 0;
601 cmd.ic_cmd = IPMI_CMD_GET_SESSION_CHALLENGE;
602 cmd.ic_data = msg_data;
603 cmd.ic_dlen = 17;
604
605 if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0 || ccode)
606 return (ipmi_set_error(ihp, EIPMI_LAN_CHALLENGE, NULL));
607
608 (void) memcpy(session_id, resp.ic_data, 4);
609 (void) memcpy(challenge, (uint8_t *)resp.ic_data + 4, 16);
610
611 return (0);
612 }
613
614 /*
615 * IPMI Activate Session Command
616 *
617 * See section 22.17
618 */
619 static int
620 ipmi_activate_session_cmd(ipmi_handle_t *ihp)
621 {
622 ipmi_cmd_t cmd, resp;
623 ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
624 uint8_t msg_data[22], *resp_data;
625 int ccode;
626
627 cmd.ic_netfn = IPMI_NETFN_APP;
628 cmd.ic_lun = 0;
629 cmd.ic_cmd = IPMI_CMD_ACTIVATE_SESSION;
630
631 switch (ilp->il_authtype) {
632 case IPMI_SESSION_AUTHTYPE_NONE:
633 msg_data[0] = 0x00;
634 break;
635 case IPMI_SESSION_AUTHTYPE_MD2:
636 msg_data[0] = 0x01;
637 break;
638 case IPMI_SESSION_AUTHTYPE_MD5:
639 msg_data[0] = 0x02;
640 break;
641 case IPMI_SESSION_AUTHTYPE_PASSWORD:
642 msg_data[0] = 0x04;
643 break;
644 case IPMI_SESSION_AUTHTYPE_OEM:
645 msg_data[0] = 0x05;
646 break;
647 }
648 msg_data[1] = ilp->il_privlvl;
649
650 (void) memcpy(msg_data + 2, ilp->il_challenge, 16);
651
652 /* setup initial outbound sequence number */
653 (void) get_random(msg_data + 18, 4);
654
655 cmd.ic_data = msg_data;
656 cmd.ic_dlen = 22;
657
658 ilp->il_send_authcode = B_TRUE;
659
660 if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0 || ccode) {
661 ilp->il_send_authcode = B_FALSE;
662 return (ipmi_set_error(ihp, EIPMI_LAN_SESSION, NULL));
663 }
664
665 resp_data = (uint8_t *)resp.ic_data;
666 (void) memcpy(&ilp->il_session_id, resp_data + 1, 4);
667 ilp->il_in_seq = resp_data[8] << 24 | resp_data[7] << 16 |
668 resp_data[6] << 8 | resp_data[5];
669 if (ilp->il_in_seq == 0)
670 ++ilp->il_in_seq;
671
672 return (0);
673 }
674
675
676 /*
677 * See section 22.18
678 *
679 * returns privilege level or -1 on error
680 */
681 static int
682 ipmi_set_session_privlvl_cmd(ipmi_handle_t *ihp, uint8_t privlvl)
683 {
684 ipmi_cmd_t cmd, resp;
685 int ret = 0, ccode;
686
687 if (privlvl > IPMI_SESSION_PRIV_OEM)
688 return (ipmi_set_error(ihp, EIPMI_BADPARAM, NULL));
689
690 cmd.ic_netfn = IPMI_NETFN_APP;
691 cmd.ic_lun = 0;
692 cmd.ic_cmd = IPMI_CMD_SET_SESSION_PRIVLVL;
693 cmd.ic_data = &privlvl;
694 cmd.ic_dlen = 1;
695
696 if (ipmi_lan_send(ihp->ih_tdata, &cmd, &resp, &ccode) != 0)
697 ret = ipmi_set_error(ihp, EIPMI_LAN_SETPRIV, NULL);
698
699 return (ret);
700 }
701
702 /*
703 * See section 22.19
704 */
705 static int
706 ipmi_close_session_cmd(ipmi_handle_t *ihp)
707 {
708 ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
709 ipmi_cmd_t cmd, resp;
710 uint8_t msg_data[4];
711 int ret = 0, ccode;
712
713 if (! ilp->il_session_active)
714 return (-1);
715
716 (void) memcpy(&msg_data, &ilp->il_session_id, 4);
717
718 cmd.ic_netfn = IPMI_NETFN_APP;
719 cmd.ic_lun = 0;
720 cmd.ic_cmd = IPMI_CMD_CLOSE_SESSION;
721 cmd.ic_data = msg_data;
722 cmd.ic_dlen = 4;
723
724 if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0)
725 ret = -1;
726
727 return (ret);
728 }
729
730 /*
731 * IPMI LAN Session Activation
732 *
733 * See section 13.14
734 *
735 * 1. send "RMCP Presence Ping" message, response message will
736 * indicate whether the platform supports IPMI
737 * 2. send "Get Channel Authentication Capabilities" command
738 * with AUTHTYPE = none, response packet will contain information
739 * about supported challenge/response authentication types
740 * 3. send "Get Session Challenge" command with AUTHTYPE = none
741 * and indicate the authentication type in the message, response
742 * packet will contain challenge string and temporary session ID.
743 * 4. send "Activate Session" command, authenticated with AUTHTYPE
744 * sent in previous message. Also sends the initial value for
745 * the outbound sequence number for BMC.
746 * 5. BMC returns response confirming session activation and
747 * session ID for this session and initial inbound sequence.
748 */
749 static int
750 ipmi_lan_activate_session(ipmi_handle_t *ihp)
751 {
752 ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
753 ipmi_channel_auth_caps_t *ac;
754
755 if (ipmi_lan_ping(ihp) != 0)
756 return (-1);
757
758 if ((ac = ipmi_get_channel_auth_caps(ihp, IPMI_LAN_CHANNEL_E,
759 ilp->il_privlvl)) == NULL)
760 return (-1);
761
762 /*
763 * For the sake of simplicity, we're just supporting basic password
764 * authentication. If this authentication type is not supported then
765 * we'll bail here.
766 */
767 if (!(ac->cap_authtype & IPMI_SESSION_AUTHTYPE_PASSWORD)) {
768 free(ac);
769 return (ipmi_set_error(ihp, EIPMI_LAN_PASSWD_NOTSUP, NULL));
770 }
771 free(ac);
772
773 if (ipmi_get_session_challenge_cmd(ihp, &ilp->il_session_id,
774 ilp->il_challenge) != 0)
775 return (-1);
776
777 if (ipmi_activate_session_cmd(ihp) != 0)
778 return (-1);
779
780 ilp->il_session_active = B_TRUE;
781
782 if (ipmi_set_session_privlvl_cmd(ihp, ilp->il_privlvl) != 0)
783 return (-1);
784
785 return (0);
786 }
787
788 static void
789 ipmi_lan_close(void *data)
790 {
791 ipmi_lan_t *ilp = (ipmi_lan_t *)data;
792
793 if (ilp->il_session_active)
794 (void) ipmi_close_session_cmd(ilp->il_ihp);
795
796 if (ilp->il_sd >= 0)
797 (void) close(ilp->il_sd);
798
799 ipmi_req_clear_entries(ilp->il_ihp);
800 ipmi_free(ilp->il_ihp, ipmi_req_entries);
801 ipmi_free(ilp->il_ihp, ilp);
802 }
803
804 static void *
805 ipmi_lan_open(ipmi_handle_t *ihp, nvlist_t *params)
806 {
807 int rc;
808 struct hostent *host;
809 ipmi_lan_t *ilp;
810 char *hostname, *user, *authcode;
811
812 if ((ilp = ipmi_zalloc(ihp, sizeof (ipmi_lan_t))) == NULL) {
813 /* ipmi errno set */
814 return (NULL);
815 }
816 ilp->il_ihp = ihp;
817 ihp->ih_tdata = ilp;
818
819 /*
820 * Parse the parameters passed in the params nvlist. The following
821 * parameters are required
822 * IPMI_LAN_HOST, IPMI_LAN_USER and IPMI_LAN_PASSWD
823 *
824 * If any of these were not specified then we abort
825 */
826 if (nvlist_lookup_string(params, IPMI_LAN_HOST, &hostname) ||
827 nvlist_lookup_string(params, IPMI_LAN_USER, &user) ||
828 nvlist_lookup_string(params, IPMI_LAN_PASSWD, &authcode)) {
829 ipmi_free(ihp, ilp);
830 (void) ipmi_set_error(ihp, EIPMI_BADPARAM, NULL);
831 return (NULL);
832 }
833 (void) strncpy(ilp->il_host, hostname, MAXHOSTNAMELEN);
834 (void) strncpy(ilp->il_user, user, 16);
835 (void) strncpy(ilp->il_authcode, authcode, 16);
836
837 /*
838 * IPMI_LAN_PORT is an optional parameter and defaults to port 623
839 * IPMI_LAN_PRIVLVL is also optional and defaults to admin
840 * IPMI_LAN_TIMEOUT is optional and will default to 3 seconds
841 * IPMI_LAN_NUM_RETIES is optional and will default to 5
842 */
843 if (nvlist_lookup_uint16(params, IPMI_LAN_PORT, &ilp->il_port))
844 ilp->il_port = RMCP_UDP_PORT;
845
846 if (nvlist_lookup_uint8(params, IPMI_LAN_PRIVLVL, &ilp->il_privlvl))
847 ilp->il_privlvl = IPMI_SESSION_PRIV_ADMIN;
848
849 if (nvlist_lookup_uint32(params, IPMI_LAN_TIMEOUT, &ilp->il_timeout))
850 ilp->il_timeout = DEF_IPMI_LAN_TIMEOUT;
851
852 if (nvlist_lookup_uint8(params, IPMI_LAN_NUM_RETRIES,
853 &ilp->il_num_retries))
854 ilp->il_num_retries = DEF_IPMI_LAN_NUM_RETRIES;
855
856 ilp->il_authtype = IPMI_SESSION_AUTHTYPE_PASSWORD;
857
858 /*
859 * Open up and connect a UDP socket between us and the service
860 * processor
861 */
862 ilp->il_addr.sin_family = AF_INET;
863 ilp->il_addr.sin_port = htons(ilp->il_port);
864
865 rc = inet_pton(AF_INET, (const char *)ilp->il_host,
866 &ilp->il_addr.sin_addr);
867 if (rc <= 0) {
868 if ((host = gethostbyname((const char *)ilp->il_host))
869 == NULL) {
870 ipmi_free(ihp, ilp);
871 (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL);
872 return (NULL);
873 }
874 ilp->il_addr.sin_family = host->h_addrtype;
875 (void) memcpy(&ilp->il_addr.sin_addr, host->h_addr,
876 host->h_length);
877 }
878
879 if ((ilp->il_sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
880 ipmi_free(ihp, ilp);
881 (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL);
882 return (NULL);
883 }
884 if (connect(ilp->il_sd, (struct sockaddr *)&ilp->il_addr,
885 sizeof (struct sockaddr_in)) < 0) {
886 ipmi_lan_close(ilp);
887 (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL);
888 return (NULL);
889 }
890
891 if ((ipmi_req_entries = ipmi_zalloc(ihp, sizeof (ipmi_rq_entry_t)))
892 == NULL)
893 return (NULL);
894
895 /*
896 * Finally we start up the IPMI LAN session
897 */
898 if ((rc = ipmi_lan_activate_session(ihp)) < 0) {
899 ipmi_lan_close(ilp);
900 return (NULL);
901 }
902
903 return (ilp);
904 }
905
906 ipmi_transport_t ipmi_transport_lan = {
907 ipmi_lan_open,
908 ipmi_lan_close,
909 ipmi_lan_send
910 };