xref: /titanic_50/usr/src/lib/libipmi/common/ipmi_lan.c (revision 7c1d35456b77b833f089b886b99aa431a24e1377)
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  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include <inttypes.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <fcntl.h>
39 
40 #include "libipmi.h"
41 #include "ipmi_lan.h"
42 #include "ipmi_impl.h"
43 
44 #define	DEF_IPMI_LAN_TIMEOUT		3 /* seconds */
45 #define	DEF_IPMI_LAN_NUM_RETRIES	5
46 #define	IPMI_LAN_CHANNEL_E		0x0e
47 
48 typedef struct ipmi_rs {
49 	uint8_t		ir_data[IPMI_BUF_SIZE];
50 	int		ir_dlen;
51 	ipmi_msg_hdr_t	ir_ihdr;
52 	uint8_t		ir_ccode;
53 } ipmi_rs_t;
54 
55 static ipmi_rs_t *ipmi_lan_poll_recv(ipmi_handle_t *);
56 
57 typedef struct ipmi_rq_entry {
58 	ipmi_list_t	ire_list;
59 	ipmi_cmd_t	ire_req;
60 	uint8_t		ire_target_cmd;
61 	uint8_t		ire_rq_seq;
62 	uint8_t		*ire_msg_data;
63 	int		ire_msg_len;
64 } ipmi_rq_entry_t;
65 
66 ipmi_rq_entry_t *ipmi_req_entries = NULL;
67 
68 /*
69  * LAN transport-specific data
70  */
71 typedef struct ipmi_lan {
72 	ipmi_handle_t	*il_ihp;
73 	char		il_host[MAXHOSTNAMELEN + 1];
74 	uint16_t	il_port;
75 	char		il_user[17];
76 	char		il_authcode[IPMI_AUTHCODE_BUF_SIZE + 1];
77 	uint8_t		il_challenge[16];
78 	uint32_t	il_session_id;
79 	int 		il_sd;
80 	boolean_t	il_send_authcode;
81 	boolean_t	il_session_active;
82 	uint8_t		il_authtype;
83 	uint8_t		il_privlvl;
84 	uint8_t		il_num_retries;
85 	uint32_t	il_in_seq;
86 	uint32_t	il_timeout;
87 	struct sockaddr_in il_addr;
88 	socklen_t	il_addrlen;
89 } ipmi_lan_t;
90 
91 /*
92  * Calculate and returns IPMI checksum
93  *
94  * Checksum algorithm is described in Section 13.8
95  *
96  * d:		buffer to check
97  * s:		position in buffer to start checksum from
98  */
99 static uint8_t
100 ipmi_csum(uint8_t *d, int s)
101 {
102 	uint8_t c = 0;
103 	for (; s > 0; s--, d++)
104 		c += *d;
105 	return (-c);
106 }
107 
108 static ipmi_rq_entry_t *
109 ipmi_req_add_entry(ipmi_handle_t *ihp, ipmi_cmd_t *req)
110 {
111 	ipmi_rq_entry_t *e;
112 
113 	if ((e = ipmi_zalloc(ihp, sizeof (ipmi_rq_entry_t))) == NULL)
114 		return (NULL);
115 
116 	(void) memcpy(&e->ire_req, req, sizeof (ipmi_cmd_t));
117 	ipmi_list_append(&ipmi_req_entries->ire_list, e);
118 
119 	return (e);
120 }
121 
122 /*ARGSUSED*/
123 static ipmi_rq_entry_t *
124 ipmi_req_lookup_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd)
125 {
126 	ipmi_rq_entry_t *e;
127 
128 	for (e = ipmi_list_next(&ipmi_req_entries->ire_list); e != NULL;
129 	    e = ipmi_list_next(e))
130 		if (e->ire_rq_seq == seq && e->ire_req.ic_cmd == cmd)
131 			return (e);
132 
133 	return (NULL);
134 }
135 
136 static void
137 ipmi_req_remove_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd)
138 {
139 	ipmi_rq_entry_t *e;
140 
141 	e = ipmi_req_lookup_entry(ihp, seq, cmd);
142 
143 	if (e) {
144 		ipmi_list_delete(&ipmi_req_entries->ire_list, e);
145 		ipmi_free(ihp, e->ire_msg_data);
146 		ipmi_free(ihp, e);
147 	}
148 }
149 
150 static void
151 ipmi_req_clear_entries(ipmi_handle_t *ihp)
152 {
153 	ipmi_rq_entry_t *e;
154 
155 	while ((e = ipmi_list_next(&ipmi_req_entries->ire_list)) != NULL) {
156 		ipmi_list_delete(&ipmi_req_entries->ire_list, e);
157 		ipmi_free(ihp, e);
158 	}
159 }
160 
161 static int
162 get_random(void *buf, uint_t len)
163 {
164 	int fd;
165 
166 	assert(buf != NULL && len > 0);
167 	if ((fd = open("/dev/urandom", O_RDONLY)) < 0)
168 		return (-1);
169 
170 	if (read(fd, buf, len) < 0) {
171 		(void) close(fd);
172 		return (-1);
173 	}
174 	(void) close(fd);
175 	return (0);
176 }
177 
178 static int
179 ipmi_lan_send_packet(ipmi_handle_t *ihp, uint8_t *data, int dlen)
180 {
181 	ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
182 
183 	return (send(ilp->il_sd, data, dlen, 0));
184 }
185 
186 static ipmi_rs_t *
187 ipmi_lan_recv_packet(ipmi_handle_t *ihp)
188 {
189 	static ipmi_rs_t rsp;
190 	fd_set read_set, err_set;
191 	struct timeval tmout;
192 	ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
193 	int ret;
194 
195 	FD_ZERO(&read_set);
196 	FD_SET(ilp->il_sd, &read_set);
197 
198 	FD_ZERO(&err_set);
199 	FD_SET(ilp->il_sd, &err_set);
200 
201 	tmout.tv_sec = 	ilp->il_timeout;
202 	tmout.tv_usec = 0;
203 
204 	ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout);
205 	if (ret < 0 || FD_ISSET(ilp->il_sd, &err_set) ||
206 	    !FD_ISSET(ilp->il_sd, &read_set))
207 		return (NULL);
208 
209 	/*
210 	 * The first read may return ECONNREFUSED because the rmcp ping
211 	 * packet--sent to UDP port 623--will be processed by both the
212 	 * BMC and the OS.
213 	 *
214 	 * The problem with this is that the ECONNREFUSED takes
215 	 * priority over any other received datagram; that means that
216 	 * the Connection Refused shows up _before_ the response packet,
217 	 * regardless of the order they were sent out.  (unless the
218 	 * response is read before the connection refused is returned)
219 	 */
220 	ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0);
221 
222 	if (ret < 0) {
223 		FD_ZERO(&read_set);
224 		FD_SET(ilp->il_sd, &read_set);
225 
226 		FD_ZERO(&err_set);
227 		FD_SET(ilp->il_sd, &err_set);
228 
229 		tmout.tv_sec = ilp->il_timeout;
230 		tmout.tv_usec = 0;
231 
232 		ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout);
233 		if (ret < 0) {
234 			if (FD_ISSET(ilp->il_sd, &err_set) ||
235 			    !FD_ISSET(ilp->il_sd, &read_set))
236 				return (NULL);
237 
238 			ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0);
239 			if (ret < 0)
240 				return (NULL);
241 		}
242 	}
243 
244 	if (ret == 0)
245 		return (NULL);
246 
247 	rsp.ir_data[ret] = '\0';
248 	rsp.ir_dlen = ret;
249 
250 	return (&rsp);
251 }
252 
253 
254 /*
255  * ASF/RMCP Pong Message
256  *
257  * See section 13.2.4
258  */
259 struct rmcp_pong {
260 	rmcp_hdr_t rp_rmcp;
261 	asf_hdr_t rp_asf;
262 	uint32_t rp_iana;
263 	uint32_t rp_oem;
264 	uint8_t rp_sup_entities;
265 	uint8_t rp_sup_interact;
266 	uint8_t rp_reserved[6];
267 };
268 
269 /*
270  * parse response RMCP "pong" packet
271  *
272  * return -1 if ping response not received
273  * returns 0 if IPMI is NOT supported
274  * returns 1 if IPMI is supported
275  */
276 /*ARGSUSED*/
277 static int
278 ipmi_handle_pong(ipmi_handle_t *ihp, ipmi_rs_t *rsp)
279 {
280 	struct rmcp_pong *pong;
281 
282 	if (rsp == NULL)
283 		return (-1);
284 
285 	/*LINTED: E_BAD_PTR_CAST_ALIGN*/
286 	pong = (struct rmcp_pong *)rsp->ir_data;
287 
288 	return ((pong->rp_sup_entities & 0x80) ? 1 : 0);
289 }
290 
291 /*
292  * Build and send RMCP presence ping message
293  */
294 static int
295 ipmi_lan_ping(ipmi_handle_t *ihp)
296 {
297 	rmcp_hdr_t rmcp_ping;
298 	asf_hdr_t asf_ping;
299 	uint8_t *data;
300 	int rv, dlen = sizeof (rmcp_ping) + sizeof (asf_ping);
301 
302 	(void) memset(&rmcp_ping, 0, sizeof (rmcp_ping));
303 	rmcp_ping.rh_version = RMCP_VERSION_1;
304 	rmcp_ping.rh_msg_class = RMCP_CLASS_ASF;
305 	rmcp_ping.rh_seq = 0xff;
306 
307 	(void) memset(&asf_ping, 0, sizeof (asf_ping));
308 	asf_ping.ah_iana = htonl(ASF_RMCP_IANA);
309 	asf_ping.ah_msg_type = ASF_TYPE_PING;
310 
311 	if ((data = ipmi_zalloc(ihp, dlen)) == NULL)
312 		return (-1);
313 
314 	(void) memcpy(data, &rmcp_ping, sizeof (rmcp_ping));
315 	(void) memcpy(data + sizeof (rmcp_ping), &asf_ping, sizeof (asf_ping));
316 
317 	rv = ipmi_lan_send_packet(ihp, data, dlen);
318 
319 	ipmi_free(ihp, data);
320 
321 	if (rv < 0)
322 		return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL));
323 
324 	if (ipmi_lan_poll_recv(ihp) == NULL)
325 		return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL));
326 
327 	return (0);
328 }
329 
330 static ipmi_rs_t *
331 ipmi_lan_poll_recv(ipmi_handle_t *ihp)
332 {
333 	rmcp_hdr_t rmcp_rsp;
334 	ipmi_rs_t *rsp;
335 	ipmi_rq_entry_t *entry;
336 	int off = 0, rv;
337 	ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
338 	uint8_t rsp_authtype;
339 
340 	rsp = ipmi_lan_recv_packet(ihp);
341 
342 	while (rsp != NULL) {
343 
344 		/* parse response headers */
345 		(void) memcpy(&rmcp_rsp, rsp->ir_data, 4);
346 
347 		switch (rmcp_rsp.rh_msg_class) {
348 		case RMCP_CLASS_ASF:
349 			/* ping response packet */
350 			rv = ipmi_handle_pong(ihp, rsp);
351 			return ((rv <= 0) ? NULL : rsp);
352 		case RMCP_CLASS_IPMI:
353 			/* handled by rest of function */
354 			break;
355 		default:
356 			/* Invalid RMCP class */
357 			rsp = ipmi_lan_recv_packet(ihp);
358 			continue;
359 		}
360 
361 		off = sizeof (rmcp_hdr_t);
362 		rsp_authtype = rsp->ir_data[off];
363 		if (ilp->il_send_authcode && (rsp_authtype || ilp->il_authtype))
364 			off += 26;
365 		else
366 			off += 10;
367 
368 		(void) memcpy(&rsp->ir_ihdr, (void *)(rsp->ir_data + off),
369 		    sizeof (rsp->ir_ihdr));
370 		rsp->ir_ihdr.imh_seq = rsp->ir_ihdr.imh_seq >> 2;
371 		off += sizeof (rsp->ir_ihdr);
372 		rsp->ir_ccode = rsp->ir_data[off++];
373 
374 		entry = ipmi_req_lookup_entry(ihp, rsp->ir_ihdr.imh_seq,
375 		    rsp->ir_ihdr.imh_cmd);
376 		if (entry) {
377 			ipmi_req_remove_entry(ihp, rsp->ir_ihdr.imh_seq,
378 			    rsp->ir_ihdr.imh_cmd);
379 		} else {
380 			rsp = ipmi_lan_recv_packet(ihp);
381 			continue;
382 		}
383 		break;
384 	}
385 
386 	/* shift response data to start of array */
387 	if (rsp && rsp->ir_dlen > off) {
388 		rsp->ir_dlen -= off + 1;
389 		(void) memmove(rsp->ir_data, rsp->ir_data + off, rsp->ir_dlen);
390 		(void) memset(rsp->ir_data + rsp->ir_dlen, 0,
391 		    IPMI_BUF_SIZE - rsp->ir_dlen);
392 	}
393 	return (rsp);
394 }
395 
396 /*
397  * IPMI LAN Request Message Format
398  *
399  * See section 13.8
400  *
401  * +---------------------+
402  * |  rmcp_hdr_t         | 4 bytes
403  * +---------------------+
404  * |  v15_session_hdr_t  | 9 bytes
405  * +---------------------+
406  * | [authcode]          | 16 bytes (if AUTHTYPE != none)
407  * +---------------------+
408  * |  msg length         | 1 byte
409  * +---------------------+
410  * |  ipmi_msg_hdr_t     | 6 bytes
411  * +---------------------+
412  * | [msg data]          | variable
413  * +---------------------+
414  * |  msg data checksum  | 1 byte
415  * +---------------------+
416  */
417 static ipmi_rq_entry_t *
418 ipmi_lan_build_cmd(ipmi_handle_t *ihp, ipmi_cmd_t *req)
419 {
420 	ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
421 	rmcp_hdr_t rmcp_hdr;
422 	v15_session_hdr_t session_hdr;
423 	ipmi_msg_hdr_t msg_hdr;
424 	uint8_t *msg;
425 	int cs, tmp, off = 0, len;
426 	ipmi_rq_entry_t *entry;
427 	static int curr_seq = 0;
428 
429 	if (curr_seq >= 64)
430 		curr_seq = 0;
431 
432 	if ((entry = ipmi_req_add_entry(ihp, req)) == NULL)
433 		return (NULL);
434 
435 	len = req->ic_dlen + 29;
436 	if (ilp->il_send_authcode && ilp->il_authtype)
437 		len += 16;
438 
439 	if ((msg = ipmi_zalloc(ihp, len)) == NULL)
440 		/* ipmi_errno set */
441 		return (NULL);
442 
443 	/* RMCP header */
444 	(void) memset(&rmcp_hdr, 0, sizeof (rmcp_hdr));
445 	rmcp_hdr.rh_version = RMCP_VERSION_1;
446 	rmcp_hdr.rh_msg_class = RMCP_CLASS_IPMI;
447 	rmcp_hdr.rh_seq = 0xff;
448 	(void) memcpy(msg, &rmcp_hdr, sizeof (rmcp_hdr));
449 	off = sizeof (rmcp_hdr);
450 
451 	/* IPMI session header */
452 	(void) memset(&session_hdr, 0, sizeof (session_hdr));
453 	if (! ilp->il_send_authcode)
454 		session_hdr.sh_authtype = 0x00;
455 	else
456 		/* hardcode passwd authentication */
457 		session_hdr.sh_authtype = 0x04;
458 
459 	(void) memcpy(&session_hdr.sh_seq, &ilp->il_in_seq, sizeof (uint32_t));
460 	(void) memcpy(&session_hdr.sh_id, &ilp->il_session_id,
461 	    sizeof (uint32_t));
462 
463 	(void) memcpy(msg + off, &session_hdr, sizeof (session_hdr));
464 	off += sizeof (session_hdr);
465 
466 	/* IPMI session authcode */
467 	if (ilp->il_send_authcode && ilp->il_authtype) {
468 		(void) memcpy(msg + off, ilp->il_authcode, 16);
469 		off += 16;
470 	}
471 
472 	/* message length */
473 	msg[off++] = req->ic_dlen + 7;
474 	cs = off;
475 
476 	/* IPMI message header */
477 	(void) memset(&msg_hdr, 0, sizeof (msg_hdr));
478 	msg_hdr.imh_addr1 = IPMI_BMC_SLAVE_ADDR;
479 	msg_hdr.imh_lun = req->ic_lun;
480 	msg_hdr.imh_netfn = req->ic_netfn;
481 	tmp = off - cs;
482 	msg_hdr.imh_csum = ipmi_csum(msg + cs, tmp);
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 };
911