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