xref: /openbmc/ipmitool/src/plugins/lan/lan.c (revision deb9a4ed5d852c4e01c3811f30a521f52bbb2817)
1c18ec02fSPetter Reinholdtsen /*
2c18ec02fSPetter Reinholdtsen  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3c18ec02fSPetter Reinholdtsen  *
4c18ec02fSPetter Reinholdtsen  * Redistribution and use in source and binary forms, with or without
5c18ec02fSPetter Reinholdtsen  * modification, are permitted provided that the following conditions
6c18ec02fSPetter Reinholdtsen  * are met:
7c18ec02fSPetter Reinholdtsen  *
8c18ec02fSPetter Reinholdtsen  * Redistribution of source code must retain the above copyright
9c18ec02fSPetter Reinholdtsen  * notice, this list of conditions and the following disclaimer.
10c18ec02fSPetter Reinholdtsen  *
11c18ec02fSPetter Reinholdtsen  * Redistribution in binary form must reproduce the above copyright
12c18ec02fSPetter Reinholdtsen  * notice, this list of conditions and the following disclaimer in the
13c18ec02fSPetter Reinholdtsen  * documentation and/or other materials provided with the distribution.
14c18ec02fSPetter Reinholdtsen  *
15c18ec02fSPetter Reinholdtsen  * Neither the name of Sun Microsystems, Inc. or the names of
16c18ec02fSPetter Reinholdtsen  * contributors may be used to endorse or promote products derived
17c18ec02fSPetter Reinholdtsen  * from this software without specific prior written permission.
18c18ec02fSPetter Reinholdtsen  *
19c18ec02fSPetter Reinholdtsen  * This software is provided "AS IS," without a warranty of any kind.
20c18ec02fSPetter Reinholdtsen  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21c18ec02fSPetter Reinholdtsen  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22c18ec02fSPetter Reinholdtsen  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23c18ec02fSPetter Reinholdtsen  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24c18ec02fSPetter Reinholdtsen  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25c18ec02fSPetter Reinholdtsen  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26c18ec02fSPetter Reinholdtsen  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27c18ec02fSPetter Reinholdtsen  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28c18ec02fSPetter Reinholdtsen  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29c18ec02fSPetter Reinholdtsen  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30c18ec02fSPetter Reinholdtsen  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31c18ec02fSPetter Reinholdtsen  */
32c18ec02fSPetter Reinholdtsen 
33c18ec02fSPetter Reinholdtsen #include <stdlib.h>
34c18ec02fSPetter Reinholdtsen #include <stdio.h>
35c18ec02fSPetter Reinholdtsen #include <inttypes.h>
36c18ec02fSPetter Reinholdtsen #include <string.h>
37c18ec02fSPetter Reinholdtsen #include <sys/types.h>
38c18ec02fSPetter Reinholdtsen #include <sys/socket.h>
39c18ec02fSPetter Reinholdtsen #include <netinet/in.h>
40c18ec02fSPetter Reinholdtsen #include <arpa/inet.h>
41c18ec02fSPetter Reinholdtsen #include <errno.h>
42c18ec02fSPetter Reinholdtsen #include <unistd.h>
43c18ec02fSPetter Reinholdtsen #include <netdb.h>
44c18ec02fSPetter Reinholdtsen #include <fcntl.h>
45c18ec02fSPetter Reinholdtsen 
46c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h>
47c18ec02fSPetter Reinholdtsen #include <ipmitool/log.h>
48c18ec02fSPetter Reinholdtsen #include <ipmitool/bswap.h>
49c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h>
50c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_sel.h>
51c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h>
52c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_oem.h>
53c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_strings.h>
54c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_constants.h>
5523e9340bSZdenek Styblik #include <ipmitool/hpm2.h>
56c18ec02fSPetter Reinholdtsen 
57c18ec02fSPetter Reinholdtsen #if HAVE_CONFIG_H
58c18ec02fSPetter Reinholdtsen # include <config.h>
59c18ec02fSPetter Reinholdtsen #endif
60c18ec02fSPetter Reinholdtsen 
61c18ec02fSPetter Reinholdtsen #include "lan.h"
62c18ec02fSPetter Reinholdtsen #include "rmcp.h"
63c18ec02fSPetter Reinholdtsen #include "asf.h"
64c18ec02fSPetter Reinholdtsen #include "auth.h"
65c18ec02fSPetter Reinholdtsen 
66c18ec02fSPetter Reinholdtsen #define IPMI_LAN_TIMEOUT	2
67c18ec02fSPetter Reinholdtsen #define IPMI_LAN_RETRY		4
68c18ec02fSPetter Reinholdtsen #define IPMI_LAN_PORT		0x26f
69c18ec02fSPetter Reinholdtsen #define IPMI_LAN_CHANNEL_E	0x0e
70c18ec02fSPetter Reinholdtsen 
7123e9340bSZdenek Styblik /*
7223e9340bSZdenek Styblik  * LAN interface is required to support 45 byte request transactions and
7323e9340bSZdenek Styblik  * 42 byte response transactions.
7423e9340bSZdenek Styblik  */
7523e9340bSZdenek Styblik #define IPMI_LAN_MAX_REQUEST_SIZE	38	/* 45 - 7 */
7623e9340bSZdenek Styblik #define IPMI_LAN_MAX_RESPONSE_SIZE	34	/* 42 - 8 */
7723e9340bSZdenek Styblik 
78c18ec02fSPetter Reinholdtsen extern const struct valstr ipmi_privlvl_vals[];
79c18ec02fSPetter Reinholdtsen extern const struct valstr ipmi_authtype_session_vals[];
80c18ec02fSPetter Reinholdtsen extern int verbose;
81c18ec02fSPetter Reinholdtsen 
82c18ec02fSPetter Reinholdtsen struct ipmi_rq_entry * ipmi_req_entries;
83c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry * ipmi_req_entries_tail;
84c18ec02fSPetter Reinholdtsen static uint8_t bridge_possible = 0;
85c18ec02fSPetter Reinholdtsen 
86c18ec02fSPetter Reinholdtsen static int ipmi_lan_send_packet(struct ipmi_intf * intf, uint8_t * data, int data_len);
87c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lan_recv_packet(struct ipmi_intf * intf);
88c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lan_poll_recv(struct ipmi_intf * intf);
89c18ec02fSPetter Reinholdtsen static int ipmi_lan_setup(struct ipmi_intf * intf);
90c18ec02fSPetter Reinholdtsen static int ipmi_lan_keepalive(struct ipmi_intf * intf);
91c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lan_recv_sol(struct ipmi_intf * intf);
92c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lan_send_sol(struct ipmi_intf * intf,
93c18ec02fSPetter Reinholdtsen 					  struct ipmi_v2_payload * payload);
94c18ec02fSPetter Reinholdtsen static struct ipmi_rs * ipmi_lan_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req);
95c18ec02fSPetter Reinholdtsen static int ipmi_lan_send_rsp(struct ipmi_intf * intf, struct ipmi_rs * rsp);
96c18ec02fSPetter Reinholdtsen static int ipmi_lan_open(struct ipmi_intf * intf);
97c18ec02fSPetter Reinholdtsen static void ipmi_lan_close(struct ipmi_intf * intf);
98c18ec02fSPetter Reinholdtsen static int ipmi_lan_ping(struct ipmi_intf * intf);
9923e9340bSZdenek Styblik static void ipmi_lan_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size);
10023e9340bSZdenek Styblik static void ipmi_lan_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size);
101c18ec02fSPetter Reinholdtsen 
102c18ec02fSPetter Reinholdtsen struct ipmi_intf ipmi_lan_intf = {
103c18ec02fSPetter Reinholdtsen 	name:		"lan",
104c18ec02fSPetter Reinholdtsen 	desc:		"IPMI v1.5 LAN Interface",
105c18ec02fSPetter Reinholdtsen 	setup:		ipmi_lan_setup,
106c18ec02fSPetter Reinholdtsen 	open:		ipmi_lan_open,
107c18ec02fSPetter Reinholdtsen 	close:		ipmi_lan_close,
108c18ec02fSPetter Reinholdtsen 	sendrecv:	ipmi_lan_send_cmd,
109c18ec02fSPetter Reinholdtsen 	sendrsp:	ipmi_lan_send_rsp,
110c18ec02fSPetter Reinholdtsen 	recv_sol:	ipmi_lan_recv_sol,
111c18ec02fSPetter Reinholdtsen 	send_sol:	ipmi_lan_send_sol,
112c18ec02fSPetter Reinholdtsen 	keepalive:	ipmi_lan_keepalive,
11323e9340bSZdenek Styblik 	set_max_request_data_size: ipmi_lan_set_max_rq_data_size,
11423e9340bSZdenek Styblik 	set_max_response_data_size: ipmi_lan_set_max_rp_data_size,
115c18ec02fSPetter Reinholdtsen 	target_addr:	IPMI_BMC_SLAVE_ADDR,
116c18ec02fSPetter Reinholdtsen };
117c18ec02fSPetter Reinholdtsen 
118c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry *
119c18ec02fSPetter Reinholdtsen ipmi_req_add_entry(struct ipmi_intf * intf, struct ipmi_rq * req, uint8_t req_seq)
120c18ec02fSPetter Reinholdtsen {
121c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * e;
122c18ec02fSPetter Reinholdtsen 
123c18ec02fSPetter Reinholdtsen 	e = malloc(sizeof(struct ipmi_rq_entry));
124c18ec02fSPetter Reinholdtsen 	if (e == NULL) {
125c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
126c18ec02fSPetter Reinholdtsen 		return NULL;
127c18ec02fSPetter Reinholdtsen 	}
128c18ec02fSPetter Reinholdtsen 
129c18ec02fSPetter Reinholdtsen 	memset(e, 0, sizeof(struct ipmi_rq_entry));
130c18ec02fSPetter Reinholdtsen 	memcpy(&e->req, req, sizeof(struct ipmi_rq));
131c18ec02fSPetter Reinholdtsen 
132c18ec02fSPetter Reinholdtsen 	e->intf = intf;
133c18ec02fSPetter Reinholdtsen 	e->rq_seq = req_seq;
134c18ec02fSPetter Reinholdtsen 
135c18ec02fSPetter Reinholdtsen 	if (ipmi_req_entries == NULL)
136c18ec02fSPetter Reinholdtsen 		ipmi_req_entries = e;
137c18ec02fSPetter Reinholdtsen 	else
138c18ec02fSPetter Reinholdtsen 		ipmi_req_entries_tail->next = e;
139c18ec02fSPetter Reinholdtsen 
140c18ec02fSPetter Reinholdtsen 	ipmi_req_entries_tail = e;
141c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+3, "added list entry seq=0x%02x cmd=0x%02x",
142c18ec02fSPetter Reinholdtsen 		e->rq_seq, e->req.msg.cmd);
143c18ec02fSPetter Reinholdtsen 	return e;
144c18ec02fSPetter Reinholdtsen }
145c18ec02fSPetter Reinholdtsen 
146c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry *
147c18ec02fSPetter Reinholdtsen ipmi_req_lookup_entry(uint8_t seq, uint8_t cmd)
148c18ec02fSPetter Reinholdtsen {
149c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * e = ipmi_req_entries;
150c18ec02fSPetter Reinholdtsen 	while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) {
151c18ec02fSPetter Reinholdtsen 		if (e->next == NULL || e == e->next)
152c18ec02fSPetter Reinholdtsen 			return NULL;
153c18ec02fSPetter Reinholdtsen 		e = e->next;
154c18ec02fSPetter Reinholdtsen 	}
155c18ec02fSPetter Reinholdtsen 	return e;
156c18ec02fSPetter Reinholdtsen }
157c18ec02fSPetter Reinholdtsen 
158c18ec02fSPetter Reinholdtsen static void
159c18ec02fSPetter Reinholdtsen ipmi_req_remove_entry(uint8_t seq, uint8_t cmd)
160c18ec02fSPetter Reinholdtsen {
161c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * p, * e, * saved_next_entry;
162c18ec02fSPetter Reinholdtsen 
163c18ec02fSPetter Reinholdtsen 	e = p = ipmi_req_entries;
164c18ec02fSPetter Reinholdtsen 
165c18ec02fSPetter Reinholdtsen 	while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) {
166c18ec02fSPetter Reinholdtsen 		p = e;
167c18ec02fSPetter Reinholdtsen 		e = e->next;
168c18ec02fSPetter Reinholdtsen 	}
169c18ec02fSPetter Reinholdtsen 	if (e) {
170c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG+3, "removed list entry seq=0x%02x cmd=0x%02x",
171c18ec02fSPetter Reinholdtsen 			seq, cmd);
172c18ec02fSPetter Reinholdtsen 		saved_next_entry = e->next;
173c18ec02fSPetter Reinholdtsen 		p->next = (p->next == e->next) ? NULL : e->next;
174c18ec02fSPetter Reinholdtsen 		/* If entry being removed is first in list, fix up list head */
175c18ec02fSPetter Reinholdtsen 		if (ipmi_req_entries == e) {
176c18ec02fSPetter Reinholdtsen 			if (ipmi_req_entries != p)
177c18ec02fSPetter Reinholdtsen 				ipmi_req_entries = p;
178c18ec02fSPetter Reinholdtsen 			else
179c18ec02fSPetter Reinholdtsen 				ipmi_req_entries = saved_next_entry;
180c18ec02fSPetter Reinholdtsen 		}
181c18ec02fSPetter Reinholdtsen 		/* If entry being removed is last in list, fix up list tail */
182c18ec02fSPetter Reinholdtsen 		if (ipmi_req_entries_tail == e) {
183c18ec02fSPetter Reinholdtsen 			if (ipmi_req_entries_tail != p)
184c18ec02fSPetter Reinholdtsen 				ipmi_req_entries_tail = p;
185c18ec02fSPetter Reinholdtsen 			else
186c18ec02fSPetter Reinholdtsen 				ipmi_req_entries_tail = NULL;
187c18ec02fSPetter Reinholdtsen 		}
188c18ec02fSPetter Reinholdtsen 		if (e->msg_data) {
189c18ec02fSPetter Reinholdtsen 			free(e->msg_data);
190c18ec02fSPetter Reinholdtsen 			e->msg_data = NULL;
191c18ec02fSPetter Reinholdtsen 		}
192c18ec02fSPetter Reinholdtsen 		free(e);
193c18ec02fSPetter Reinholdtsen 		e = NULL;
194c18ec02fSPetter Reinholdtsen 	}
195c18ec02fSPetter Reinholdtsen }
196c18ec02fSPetter Reinholdtsen 
197c18ec02fSPetter Reinholdtsen static void
198c18ec02fSPetter Reinholdtsen ipmi_req_clear_entries(void)
199c18ec02fSPetter Reinholdtsen {
200c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * p, * e;
201c18ec02fSPetter Reinholdtsen 
202c18ec02fSPetter Reinholdtsen 	e = ipmi_req_entries;
203c18ec02fSPetter Reinholdtsen 	while (e) {
204c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG+3, "cleared list entry seq=0x%02x cmd=0x%02x",
205c18ec02fSPetter Reinholdtsen 			e->rq_seq, e->req.msg.cmd);
206c18ec02fSPetter Reinholdtsen 		if (e->next != NULL) {
207c18ec02fSPetter Reinholdtsen 			p = e->next;
208c18ec02fSPetter Reinholdtsen 			free(e);
209c18ec02fSPetter Reinholdtsen 			e = p;
210c18ec02fSPetter Reinholdtsen 		} else {
211c18ec02fSPetter Reinholdtsen 			free(e);
212c18ec02fSPetter Reinholdtsen 			e = NULL;
213c18ec02fSPetter Reinholdtsen 			break;
214c18ec02fSPetter Reinholdtsen 		}
215c18ec02fSPetter Reinholdtsen 	}
216c18ec02fSPetter Reinholdtsen 	ipmi_req_entries = NULL;
217c18ec02fSPetter Reinholdtsen }
218c18ec02fSPetter Reinholdtsen 
219c18ec02fSPetter Reinholdtsen static int
220c18ec02fSPetter Reinholdtsen get_random(void *data, int len)
221c18ec02fSPetter Reinholdtsen {
222c18ec02fSPetter Reinholdtsen 	int fd = open("/dev/urandom", O_RDONLY);
223c18ec02fSPetter Reinholdtsen 	int rv;
224c18ec02fSPetter Reinholdtsen 
225c18ec02fSPetter Reinholdtsen 	if (fd < 0)
226c18ec02fSPetter Reinholdtsen 		return errno;
227c18ec02fSPetter Reinholdtsen 	if (len < 0) {
228c18ec02fSPetter Reinholdtsen 		close(fd);
229c18ec02fSPetter Reinholdtsen 		return errno; /* XXX: ORLY? */
230c18ec02fSPetter Reinholdtsen 	}
231c18ec02fSPetter Reinholdtsen 
232c18ec02fSPetter Reinholdtsen 	rv = read(fd, data, len);
233c18ec02fSPetter Reinholdtsen 
234c18ec02fSPetter Reinholdtsen 	close(fd);
235c18ec02fSPetter Reinholdtsen 	return rv;
236c18ec02fSPetter Reinholdtsen }
237c18ec02fSPetter Reinholdtsen 
238c18ec02fSPetter Reinholdtsen static int
239c18ec02fSPetter Reinholdtsen ipmi_lan_send_packet(struct ipmi_intf * intf, uint8_t * data, int data_len)
240c18ec02fSPetter Reinholdtsen {
241c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
242c18ec02fSPetter Reinholdtsen 		printbuf(data, data_len, "send_packet");
243c18ec02fSPetter Reinholdtsen 
244c18ec02fSPetter Reinholdtsen 	return send(intf->fd, data, data_len, 0);
245c18ec02fSPetter Reinholdtsen }
246c18ec02fSPetter Reinholdtsen 
247c18ec02fSPetter Reinholdtsen static struct ipmi_rs *
248c18ec02fSPetter Reinholdtsen ipmi_lan_recv_packet(struct ipmi_intf * intf)
249c18ec02fSPetter Reinholdtsen {
250c18ec02fSPetter Reinholdtsen 	static struct ipmi_rs rsp;
251c18ec02fSPetter Reinholdtsen 	fd_set read_set, err_set;
252c18ec02fSPetter Reinholdtsen 	struct timeval tmout;
253c18ec02fSPetter Reinholdtsen 	int ret;
254c18ec02fSPetter Reinholdtsen 
255c18ec02fSPetter Reinholdtsen 	FD_ZERO(&read_set);
256c18ec02fSPetter Reinholdtsen 	FD_SET(intf->fd, &read_set);
257c18ec02fSPetter Reinholdtsen 
258c18ec02fSPetter Reinholdtsen 	FD_ZERO(&err_set);
259c18ec02fSPetter Reinholdtsen 	FD_SET(intf->fd, &err_set);
260c18ec02fSPetter Reinholdtsen 
261c18ec02fSPetter Reinholdtsen 	tmout.tv_sec = intf->session->timeout;
262c18ec02fSPetter Reinholdtsen 	tmout.tv_usec = 0;
263c18ec02fSPetter Reinholdtsen 
264c18ec02fSPetter Reinholdtsen 	ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout);
265c18ec02fSPetter Reinholdtsen 	if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set))
266c18ec02fSPetter Reinholdtsen 		return NULL;
267c18ec02fSPetter Reinholdtsen 
268c18ec02fSPetter Reinholdtsen 	/* the first read may return ECONNREFUSED because the rmcp ping
269c18ec02fSPetter Reinholdtsen 	 * packet--sent to UDP port 623--will be processed by both the
270c18ec02fSPetter Reinholdtsen 	 * BMC and the OS.
271c18ec02fSPetter Reinholdtsen 	 *
272c18ec02fSPetter Reinholdtsen 	 * The problem with this is that the ECONNREFUSED takes
273c18ec02fSPetter Reinholdtsen 	 * priority over any other received datagram; that means that
274c18ec02fSPetter Reinholdtsen 	 * the Connection Refused shows up _before_ the response packet,
275c18ec02fSPetter Reinholdtsen 	 * regardless of the order they were sent out.  (unless the
276c18ec02fSPetter Reinholdtsen 	 * response is read before the connection refused is returned)
277c18ec02fSPetter Reinholdtsen 	 */
278c18ec02fSPetter Reinholdtsen 	ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0);
279c18ec02fSPetter Reinholdtsen 
280c18ec02fSPetter Reinholdtsen 	if (ret < 0) {
281c18ec02fSPetter Reinholdtsen 		FD_ZERO(&read_set);
282c18ec02fSPetter Reinholdtsen 		FD_SET(intf->fd, &read_set);
283c18ec02fSPetter Reinholdtsen 
284c18ec02fSPetter Reinholdtsen 		FD_ZERO(&err_set);
285c18ec02fSPetter Reinholdtsen 		FD_SET(intf->fd, &err_set);
286c18ec02fSPetter Reinholdtsen 
287c18ec02fSPetter Reinholdtsen 		tmout.tv_sec = intf->session->timeout;
288c18ec02fSPetter Reinholdtsen 		tmout.tv_usec = 0;
289c18ec02fSPetter Reinholdtsen 
290c18ec02fSPetter Reinholdtsen 		ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout);
291c18ec02fSPetter Reinholdtsen 		if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set))
292c18ec02fSPetter Reinholdtsen 			return NULL;
293c18ec02fSPetter Reinholdtsen 
294c18ec02fSPetter Reinholdtsen 		ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0);
295c18ec02fSPetter Reinholdtsen 		if (ret < 0)
296c18ec02fSPetter Reinholdtsen 			return NULL;
297c18ec02fSPetter Reinholdtsen 	}
298c18ec02fSPetter Reinholdtsen 
299c18ec02fSPetter Reinholdtsen 	if (ret == 0)
300c18ec02fSPetter Reinholdtsen 		return NULL;
301c18ec02fSPetter Reinholdtsen 
302c18ec02fSPetter Reinholdtsen 	rsp.data[ret] = '\0';
303c18ec02fSPetter Reinholdtsen 	rsp.data_len = ret;
304c18ec02fSPetter Reinholdtsen 
305c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
306c18ec02fSPetter Reinholdtsen 		printbuf(rsp.data, rsp.data_len, "recv_packet");
307c18ec02fSPetter Reinholdtsen 
308c18ec02fSPetter Reinholdtsen 	return &rsp;
309c18ec02fSPetter Reinholdtsen }
310c18ec02fSPetter Reinholdtsen 
311c18ec02fSPetter Reinholdtsen /*
312c18ec02fSPetter Reinholdtsen  * parse response RMCP "pong" packet
313c18ec02fSPetter Reinholdtsen  *
314c18ec02fSPetter Reinholdtsen  * return -1 if ping response not received
315c18ec02fSPetter Reinholdtsen  * returns 0 if IPMI is NOT supported
316c18ec02fSPetter Reinholdtsen  * returns 1 if IPMI is supported
317c18ec02fSPetter Reinholdtsen  *
318c18ec02fSPetter Reinholdtsen  * udp.source	= 0x026f	// RMCP_UDP_PORT
319c18ec02fSPetter Reinholdtsen  * udp.dest	= ?		// udp.source from rmcp-ping
320c18ec02fSPetter Reinholdtsen  * udp.len	= ?
321c18ec02fSPetter Reinholdtsen  * udp.check	= ?
322c18ec02fSPetter Reinholdtsen  * rmcp.ver	= 0x06		// RMCP Version 1.0
323c18ec02fSPetter Reinholdtsen  * rmcp.__res	= 0x00		// RESERVED
324c18ec02fSPetter Reinholdtsen  * rmcp.seq	= 0xff		// no RMCP ACK
325c18ec02fSPetter Reinholdtsen  * rmcp.class	= 0x06		// RMCP_CLASS_ASF
326c18ec02fSPetter Reinholdtsen  * asf.iana	= 0x000011be	// ASF_RMCP_IANA
327c18ec02fSPetter Reinholdtsen  * asf.type	= 0x40		// ASF_TYPE_PONG
328c18ec02fSPetter Reinholdtsen  * asf.tag	= ?		// asf.tag from rmcp-ping
329c18ec02fSPetter Reinholdtsen  * asf.__res	= 0x00		// RESERVED
330c18ec02fSPetter Reinholdtsen  * asf.len	= 0x10		// 16 bytes
331c18ec02fSPetter Reinholdtsen  * asf.data[3:0]= 0x000011be	// IANA# = RMCP_ASF_IANA if no OEM
332c18ec02fSPetter Reinholdtsen  * asf.data[7:4]= 0x00000000	// OEM-defined (not for IPMI)
333c18ec02fSPetter Reinholdtsen  * asf.data[8]	= 0x81		// supported entities
334c18ec02fSPetter Reinholdtsen  * 				// [7]=IPMI [6:4]=RES [3:0]=ASF_1.0
335c18ec02fSPetter Reinholdtsen  * asf.data[9]	= 0x00		// supported interactions (reserved)
336c18ec02fSPetter Reinholdtsen  * asf.data[f:a]= 0x000000000000
337c18ec02fSPetter Reinholdtsen  */
338c18ec02fSPetter Reinholdtsen static int
339c18ec02fSPetter Reinholdtsen ipmi_handle_pong(struct ipmi_intf * intf, struct ipmi_rs * rsp)
340c18ec02fSPetter Reinholdtsen {
341c18ec02fSPetter Reinholdtsen 	struct rmcp_pong * pong;
342c18ec02fSPetter Reinholdtsen 
343c18ec02fSPetter Reinholdtsen 	if (rsp == NULL)
344c18ec02fSPetter Reinholdtsen 		return -1;
345c18ec02fSPetter Reinholdtsen 
346c18ec02fSPetter Reinholdtsen 	pong = (struct rmcp_pong *)rsp->data;
347c18ec02fSPetter Reinholdtsen 
348c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG,
349c18ec02fSPetter Reinholdtsen 		"Received IPMI/RMCP response packet: \n"
350c18ec02fSPetter Reinholdtsen 		"  IPMI%s Supported\n"
351c18ec02fSPetter Reinholdtsen 		"  ASF Version %s\n"
352c18ec02fSPetter Reinholdtsen 		"  RMCP Version %s\n"
353c18ec02fSPetter Reinholdtsen 		"  RMCP Sequence %d\n"
354c18ec02fSPetter Reinholdtsen 		"  IANA Enterprise %ld\n",
355c18ec02fSPetter Reinholdtsen 		(pong->sup_entities & 0x80) ? "" : " NOT",
356c18ec02fSPetter Reinholdtsen 		(pong->sup_entities & 0x01) ? "1.0" : "unknown",
357c18ec02fSPetter Reinholdtsen 		(pong->rmcp.ver == 6) ? "1.0" : "unknown",
358c18ec02fSPetter Reinholdtsen 		pong->rmcp.seq,
359c18ec02fSPetter Reinholdtsen 		ntohl(pong->iana));
360c18ec02fSPetter Reinholdtsen 
361c18ec02fSPetter Reinholdtsen 	return (pong->sup_entities & 0x80) ? 1 : 0;
362c18ec02fSPetter Reinholdtsen }
363c18ec02fSPetter Reinholdtsen 
364c18ec02fSPetter Reinholdtsen /* build and send RMCP presence ping packet
365c18ec02fSPetter Reinholdtsen  *
366c18ec02fSPetter Reinholdtsen  * RMCP ping
367c18ec02fSPetter Reinholdtsen  *
368c18ec02fSPetter Reinholdtsen  * udp.source	= ?
369c18ec02fSPetter Reinholdtsen  * udp.dest	= 0x026f	// RMCP_UDP_PORT
370c18ec02fSPetter Reinholdtsen  * udp.len	= ?
371c18ec02fSPetter Reinholdtsen  * udp.check	= ?
372c18ec02fSPetter Reinholdtsen  * rmcp.ver	= 0x06		// RMCP Version 1.0
373c18ec02fSPetter Reinholdtsen  * rmcp.__res	= 0x00		// RESERVED
374c18ec02fSPetter Reinholdtsen  * rmcp.seq	= 0xff		// no RMCP ACK
375c18ec02fSPetter Reinholdtsen  * rmcp.class	= 0x06		// RMCP_CLASS_ASF
376c18ec02fSPetter Reinholdtsen  * asf.iana	= 0x000011be	// ASF_RMCP_IANA
377c18ec02fSPetter Reinholdtsen  * asf.type	= 0x80		// ASF_TYPE_PING
378c18ec02fSPetter Reinholdtsen  * asf.tag	= ?		// ASF sequence number
379c18ec02fSPetter Reinholdtsen  * asf.__res	= 0x00		// RESERVED
380c18ec02fSPetter Reinholdtsen  * asf.len	= 0x00
381c18ec02fSPetter Reinholdtsen  *
382c18ec02fSPetter Reinholdtsen  */
383c18ec02fSPetter Reinholdtsen static int
384c18ec02fSPetter Reinholdtsen ipmi_lan_ping(struct ipmi_intf * intf)
385c18ec02fSPetter Reinholdtsen {
386c18ec02fSPetter Reinholdtsen 	struct asf_hdr asf_ping = {
387c18ec02fSPetter Reinholdtsen 		.iana	= htonl(ASF_RMCP_IANA),
388c18ec02fSPetter Reinholdtsen 		.type	= ASF_TYPE_PING,
389c18ec02fSPetter Reinholdtsen 	};
390c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp_ping = {
391c18ec02fSPetter Reinholdtsen 		.ver	= RMCP_VERSION_1,
392c18ec02fSPetter Reinholdtsen 		.class	= RMCP_CLASS_ASF,
393c18ec02fSPetter Reinholdtsen 		.seq	= 0xff,
394c18ec02fSPetter Reinholdtsen 	};
395c18ec02fSPetter Reinholdtsen 	uint8_t * data;
396c18ec02fSPetter Reinholdtsen 	int len = sizeof(rmcp_ping) + sizeof(asf_ping);
397c18ec02fSPetter Reinholdtsen 	int rv;
398c18ec02fSPetter Reinholdtsen 
399c18ec02fSPetter Reinholdtsen 	data = malloc(len);
400c18ec02fSPetter Reinholdtsen 	if (data == NULL) {
401c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
402c18ec02fSPetter Reinholdtsen 		return -1;
403c18ec02fSPetter Reinholdtsen 	}
404c18ec02fSPetter Reinholdtsen 	memset(data, 0, len);
405c18ec02fSPetter Reinholdtsen 	memcpy(data, &rmcp_ping, sizeof(rmcp_ping));
406c18ec02fSPetter Reinholdtsen 	memcpy(data+sizeof(rmcp_ping), &asf_ping, sizeof(asf_ping));
407c18ec02fSPetter Reinholdtsen 
408c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Sending IPMI/RMCP presence ping packet");
409c18ec02fSPetter Reinholdtsen 
410c18ec02fSPetter Reinholdtsen 	rv = ipmi_lan_send_packet(intf, data, len);
411c18ec02fSPetter Reinholdtsen 
412c18ec02fSPetter Reinholdtsen 	free(data);
413c18ec02fSPetter Reinholdtsen 	data = NULL;
414c18ec02fSPetter Reinholdtsen 
415c18ec02fSPetter Reinholdtsen 	if (rv < 0) {
416c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Unable to send IPMI presence ping packet");
417c18ec02fSPetter Reinholdtsen 		return -1;
418c18ec02fSPetter Reinholdtsen 	}
419c18ec02fSPetter Reinholdtsen 
420c18ec02fSPetter Reinholdtsen 	if (ipmi_lan_poll_recv(intf) == 0)
421c18ec02fSPetter Reinholdtsen 		return 0;
422c18ec02fSPetter Reinholdtsen 
423c18ec02fSPetter Reinholdtsen 	return 1;
424c18ec02fSPetter Reinholdtsen }
425c18ec02fSPetter Reinholdtsen 
426c18ec02fSPetter Reinholdtsen /*
427c18ec02fSPetter Reinholdtsen  * The "thump" functions are used to send an extra packet following each
428c18ec02fSPetter Reinholdtsen  * request message.  This may kick-start some BMCs that get confused with
429c18ec02fSPetter Reinholdtsen  * bad passwords or operate poorly under heavy network load.
430c18ec02fSPetter Reinholdtsen  */
431c18ec02fSPetter Reinholdtsen static void
432c18ec02fSPetter Reinholdtsen ipmi_lan_thump_first(struct ipmi_intf * intf)
433c18ec02fSPetter Reinholdtsen {
434c18ec02fSPetter Reinholdtsen 	/* is this random data? */
435c18ec02fSPetter Reinholdtsen 	uint8_t data[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
436c18ec02fSPetter Reinholdtsen 				   0x07, 0x20, 0x18, 0xc8, 0xc2, 0x01, 0x01, 0x3c };
437c18ec02fSPetter Reinholdtsen 	ipmi_lan_send_packet(intf, data, 16);
438c18ec02fSPetter Reinholdtsen }
439c18ec02fSPetter Reinholdtsen 
440c18ec02fSPetter Reinholdtsen static void
441c18ec02fSPetter Reinholdtsen ipmi_lan_thump(struct ipmi_intf * intf)
442c18ec02fSPetter Reinholdtsen {
443c18ec02fSPetter Reinholdtsen 	uint8_t data[10] = "thump";
444c18ec02fSPetter Reinholdtsen 	ipmi_lan_send_packet(intf, data, 10);
445c18ec02fSPetter Reinholdtsen }
446c18ec02fSPetter Reinholdtsen 
447c18ec02fSPetter Reinholdtsen static struct ipmi_rs *
448c18ec02fSPetter Reinholdtsen ipmi_lan_poll_recv(struct ipmi_intf * intf)
449c18ec02fSPetter Reinholdtsen {
450c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp_rsp;
451c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
452c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * entry;
453c18ec02fSPetter Reinholdtsen 	int x=0, rv;
454c18ec02fSPetter Reinholdtsen 	uint8_t our_address = intf->my_addr;
455c18ec02fSPetter Reinholdtsen 
456c18ec02fSPetter Reinholdtsen 	if (our_address == 0)
457c18ec02fSPetter Reinholdtsen 		our_address = IPMI_BMC_SLAVE_ADDR;
458c18ec02fSPetter Reinholdtsen 
459c18ec02fSPetter Reinholdtsen 	rsp = ipmi_lan_recv_packet(intf);
460c18ec02fSPetter Reinholdtsen 
461c18ec02fSPetter Reinholdtsen 	while (rsp != NULL) {
462c18ec02fSPetter Reinholdtsen 
463c18ec02fSPetter Reinholdtsen 		/* parse response headers */
464c18ec02fSPetter Reinholdtsen 		memcpy(&rmcp_rsp, rsp->data, 4);
465c18ec02fSPetter Reinholdtsen 
466c18ec02fSPetter Reinholdtsen 		switch (rmcp_rsp.class) {
467c18ec02fSPetter Reinholdtsen 		case RMCP_CLASS_ASF:
468c18ec02fSPetter Reinholdtsen 			/* ping response packet */
469c18ec02fSPetter Reinholdtsen 			rv = ipmi_handle_pong(intf, rsp);
470c18ec02fSPetter Reinholdtsen 			return (rv <= 0) ? NULL : rsp;
471c18ec02fSPetter Reinholdtsen 		case RMCP_CLASS_IPMI:
472c18ec02fSPetter Reinholdtsen 			/* handled by rest of function */
473c18ec02fSPetter Reinholdtsen 			break;
474c18ec02fSPetter Reinholdtsen 		default:
475c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "Invalid RMCP class: %x",
476c18ec02fSPetter Reinholdtsen 				rmcp_rsp.class);
477c18ec02fSPetter Reinholdtsen 			rsp = ipmi_lan_recv_packet(intf);
478c18ec02fSPetter Reinholdtsen 			continue;
479c18ec02fSPetter Reinholdtsen 		}
480c18ec02fSPetter Reinholdtsen 
481c18ec02fSPetter Reinholdtsen 		x = 4;
482c18ec02fSPetter Reinholdtsen 		rsp->session.authtype = rsp->data[x++];
483c18ec02fSPetter Reinholdtsen 		memcpy(&rsp->session.seq, rsp->data+x, 4);
484c18ec02fSPetter Reinholdtsen 		x += 4;
485c18ec02fSPetter Reinholdtsen 		memcpy(&rsp->session.id, rsp->data+x, 4);
486c18ec02fSPetter Reinholdtsen 		x += 4;
487c18ec02fSPetter Reinholdtsen 
488c18ec02fSPetter Reinholdtsen 		if (rsp->session.id == (intf->session->session_id + 0x10000000)) {
489c18ec02fSPetter Reinholdtsen 			/* With SOL, authtype is always NONE, so we have no authcode */
490c18ec02fSPetter Reinholdtsen 			rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_SOL;
491c18ec02fSPetter Reinholdtsen 
492c18ec02fSPetter Reinholdtsen 			rsp->session.msglen = rsp->data[x++];
493c18ec02fSPetter Reinholdtsen 
494c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.packet_sequence_number =
495c18ec02fSPetter Reinholdtsen 				rsp->data[x++] & 0x0F;
496c18ec02fSPetter Reinholdtsen 
497c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.acked_packet_number =
498c18ec02fSPetter Reinholdtsen 				rsp->data[x++] & 0x0F;
499c18ec02fSPetter Reinholdtsen 
500c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.accepted_character_count =
501c18ec02fSPetter Reinholdtsen 				rsp->data[x++];
502c18ec02fSPetter Reinholdtsen 
503c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.is_nack =
504c18ec02fSPetter Reinholdtsen 				rsp->data[x] & 0x40;
505c18ec02fSPetter Reinholdtsen 
506c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.transfer_unavailable =
507c18ec02fSPetter Reinholdtsen 				rsp->data[x] & 0x20;
508c18ec02fSPetter Reinholdtsen 
509c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.sol_inactive =
510c18ec02fSPetter Reinholdtsen 				rsp->data[x] & 0x10;
511c18ec02fSPetter Reinholdtsen 
512c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.transmit_overrun =
513c18ec02fSPetter Reinholdtsen 				rsp->data[x] & 0x08;
514c18ec02fSPetter Reinholdtsen 
515c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.break_detected =
516c18ec02fSPetter Reinholdtsen 				rsp->data[x++] & 0x04;
517c18ec02fSPetter Reinholdtsen 
518c18ec02fSPetter Reinholdtsen 			x++; /* On ISOL there's and additional fifth byte before the data starts */
519c18ec02fSPetter Reinholdtsen 
520c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "SOL sequence number     : 0x%02x",
521c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.packet_sequence_number);
522c18ec02fSPetter Reinholdtsen 
523c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "SOL acked packet        : 0x%02x",
524c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.acked_packet_number);
525c18ec02fSPetter Reinholdtsen 
526c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "SOL accepted char count : 0x%02x",
527c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.accepted_character_count);
528c18ec02fSPetter Reinholdtsen 
529c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "SOL is nack             : %s",
530c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.is_nack? "true" : "false");
531c18ec02fSPetter Reinholdtsen 
532c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "SOL xfer unavailable    : %s",
533c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.transfer_unavailable? "true" : "false");
534c18ec02fSPetter Reinholdtsen 
535c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "SOL inactive            : %s",
536c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.sol_inactive? "true" : "false");
537c18ec02fSPetter Reinholdtsen 
538c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "SOL transmit overrun    : %s",
539c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.transmit_overrun? "true" : "false");
540c18ec02fSPetter Reinholdtsen 
541c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "SOL break detected      : %s",
542c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.break_detected? "true" : "false");
543c18ec02fSPetter Reinholdtsen 		}
544c18ec02fSPetter Reinholdtsen 		else
545c18ec02fSPetter Reinholdtsen 		{
546c18ec02fSPetter Reinholdtsen 			/* Standard IPMI 1.5 packet */
547c18ec02fSPetter Reinholdtsen 			rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_IPMI;
548c18ec02fSPetter Reinholdtsen 			if (intf->session->active && (rsp->session.authtype || intf->session->authtype))
549c18ec02fSPetter Reinholdtsen 				x += 16;
550c18ec02fSPetter Reinholdtsen 
551c18ec02fSPetter Reinholdtsen 			rsp->session.msglen = rsp->data[x++];
552c18ec02fSPetter Reinholdtsen 			rsp->payload.ipmi_response.rq_addr = rsp->data[x++];
553c18ec02fSPetter Reinholdtsen 			rsp->payload.ipmi_response.netfn   = rsp->data[x] >> 2;
554c18ec02fSPetter Reinholdtsen 			rsp->payload.ipmi_response.rq_lun  = rsp->data[x++] & 0x3;
555c18ec02fSPetter Reinholdtsen 			x++;		/* checksum */
556c18ec02fSPetter Reinholdtsen 			rsp->payload.ipmi_response.rs_addr = rsp->data[x++];
557c18ec02fSPetter Reinholdtsen 			rsp->payload.ipmi_response.rq_seq  = rsp->data[x] >> 2;
558c18ec02fSPetter Reinholdtsen 			rsp->payload.ipmi_response.rs_lun  = rsp->data[x++] & 0x3;
559c18ec02fSPetter Reinholdtsen 			rsp->payload.ipmi_response.cmd     = rsp->data[x++];
560c18ec02fSPetter Reinholdtsen 			rsp->ccode          = rsp->data[x++];
561c18ec02fSPetter Reinholdtsen 
562c18ec02fSPetter Reinholdtsen 			if (verbose > 2)
563c18ec02fSPetter Reinholdtsen 				printbuf(rsp->data, rsp->data_len, "ipmi message header");
564c18ec02fSPetter Reinholdtsen 
565c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<< IPMI Response Session Header");
566c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Authtype   : %s",
567c18ec02fSPetter Reinholdtsen 				val2str(rsp->session.authtype, ipmi_authtype_session_vals));
568c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Sequence   : 0x%08lx",
569c18ec02fSPetter Reinholdtsen 				(long)rsp->session.seq);
570c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Session ID : 0x%08lx",
571c18ec02fSPetter Reinholdtsen 				(long)rsp->session.id);
572c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<< IPMI Response Message Header");
573c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rq Addr    : %02x",
574c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rq_addr);
575c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   NetFn      : %02x",
576c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.netfn);
577c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rq LUN     : %01x",
578c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rq_lun);
579c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rs Addr    : %02x",
580c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rs_addr);
581c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rq Seq     : %02x",
582c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rq_seq);
583c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Rs Lun     : %01x",
584c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.rs_lun);
585c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Command    : %02x",
586c18ec02fSPetter Reinholdtsen 				rsp->payload.ipmi_response.cmd);
587c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG+1, "<<   Compl Code : 0x%02x",
588c18ec02fSPetter Reinholdtsen 				rsp->ccode);
589c18ec02fSPetter Reinholdtsen 
590c18ec02fSPetter Reinholdtsen 			/* now see if we have outstanding entry in request list */
591c18ec02fSPetter Reinholdtsen 			entry = ipmi_req_lookup_entry(rsp->payload.ipmi_response.rq_seq,
592c18ec02fSPetter Reinholdtsen 						      rsp->payload.ipmi_response.cmd);
593c18ec02fSPetter Reinholdtsen 			if (entry) {
594c18ec02fSPetter Reinholdtsen 				lprintf(LOG_DEBUG+2, "IPMI Request Match found");
595c18ec02fSPetter Reinholdtsen 				if ((intf->target_addr != our_address) && bridge_possible) {
596c18ec02fSPetter Reinholdtsen 					if ((rsp->data_len) && (rsp->payload.ipmi_response.netfn == 7) &&
597c18ec02fSPetter Reinholdtsen 					    (rsp->payload.ipmi_response.cmd != 0x34)) {
598c18ec02fSPetter Reinholdtsen 						if (verbose > 2)
599c18ec02fSPetter Reinholdtsen 							printbuf(&rsp->data[x], rsp->data_len-x,
600c18ec02fSPetter Reinholdtsen 								 "bridge command response");
601c18ec02fSPetter Reinholdtsen 					}
602c18ec02fSPetter Reinholdtsen 					/* bridged command: lose extra header */
603c18ec02fSPetter Reinholdtsen 					if (entry->bridging_level &&
604c18ec02fSPetter Reinholdtsen 					    rsp->payload.ipmi_response.netfn == 7 &&
605c18ec02fSPetter Reinholdtsen 					    rsp->payload.ipmi_response.cmd == 0x34) {
606c18ec02fSPetter Reinholdtsen 						entry->bridging_level--;
607c18ec02fSPetter Reinholdtsen 						if (rsp->data_len - x - 1 == 0) {
608c18ec02fSPetter Reinholdtsen 							rsp = !rsp->ccode ? ipmi_lan_recv_packet(intf) : NULL;
609c18ec02fSPetter Reinholdtsen 							if (!entry->bridging_level)
610c18ec02fSPetter Reinholdtsen 								entry->req.msg.cmd = entry->req.msg.target_cmd;
611c18ec02fSPetter Reinholdtsen 							if (rsp == NULL) {
612c18ec02fSPetter Reinholdtsen 								ipmi_req_remove_entry(entry->rq_seq, entry->req.msg.cmd);
613c18ec02fSPetter Reinholdtsen 							}
614c18ec02fSPetter Reinholdtsen 							continue;
615c18ec02fSPetter Reinholdtsen 						} else {
616c18ec02fSPetter Reinholdtsen 							/* The bridged answer data are inside the incoming packet */
617c18ec02fSPetter Reinholdtsen 							memmove(rsp->data + x - 7,
618c18ec02fSPetter Reinholdtsen 								rsp->data + x,
619c18ec02fSPetter Reinholdtsen 								rsp->data_len - x - 1);
620c18ec02fSPetter Reinholdtsen 							rsp->data[x - 8] -= 8;
621c18ec02fSPetter Reinholdtsen 							rsp->data_len -= 8;
622c18ec02fSPetter Reinholdtsen 							entry->rq_seq = rsp->data[x - 3] >> 2;
623c18ec02fSPetter Reinholdtsen 							if (!entry->bridging_level)
624c18ec02fSPetter Reinholdtsen 								entry->req.msg.cmd = entry->req.msg.target_cmd;
625c18ec02fSPetter Reinholdtsen 							continue;
626c18ec02fSPetter Reinholdtsen 						}
627c18ec02fSPetter Reinholdtsen 					} else {
628c18ec02fSPetter Reinholdtsen 						//x += sizeof(rsp->payload.ipmi_response);
629c18ec02fSPetter Reinholdtsen 						if (rsp->data[x-1] != 0)
630c18ec02fSPetter Reinholdtsen 							lprintf(LOG_DEBUG, "WARNING: Bridged "
631c18ec02fSPetter Reinholdtsen 								"cmd ccode = 0x%02x",
632c18ec02fSPetter Reinholdtsen 								rsp->data[x-1]);
633c18ec02fSPetter Reinholdtsen 					}
634c18ec02fSPetter Reinholdtsen 				}
635c18ec02fSPetter Reinholdtsen 				ipmi_req_remove_entry(rsp->payload.ipmi_response.rq_seq,
636c18ec02fSPetter Reinholdtsen 						      rsp->payload.ipmi_response.cmd);
637c18ec02fSPetter Reinholdtsen 			} else {
638c18ec02fSPetter Reinholdtsen 				lprintf(LOG_INFO, "IPMI Request Match NOT FOUND");
639c18ec02fSPetter Reinholdtsen 				rsp = ipmi_lan_recv_packet(intf);
640c18ec02fSPetter Reinholdtsen 				continue;
641c18ec02fSPetter Reinholdtsen 			}
642c18ec02fSPetter Reinholdtsen 		}
643c18ec02fSPetter Reinholdtsen 
644c18ec02fSPetter Reinholdtsen 		break;
645c18ec02fSPetter Reinholdtsen 	}
646c18ec02fSPetter Reinholdtsen 
647c18ec02fSPetter Reinholdtsen 	/* shift response data to start of array */
648c18ec02fSPetter Reinholdtsen 	if (rsp && rsp->data_len > x) {
649c18ec02fSPetter Reinholdtsen 		rsp->data_len -= x;
650c18ec02fSPetter Reinholdtsen 		if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_IPMI)
651c18ec02fSPetter Reinholdtsen 			rsp->data_len -= 1; /* We don't want the checksum */
652c18ec02fSPetter Reinholdtsen 		memmove(rsp->data, rsp->data + x, rsp->data_len);
653c18ec02fSPetter Reinholdtsen 		memset(rsp->data + rsp->data_len, 0, IPMI_BUF_SIZE - rsp->data_len);
654c18ec02fSPetter Reinholdtsen 	}
655c18ec02fSPetter Reinholdtsen 
656c18ec02fSPetter Reinholdtsen 	return rsp;
657c18ec02fSPetter Reinholdtsen }
658c18ec02fSPetter Reinholdtsen 
659c18ec02fSPetter Reinholdtsen /*
660c18ec02fSPetter Reinholdtsen  * IPMI LAN Request Message Format
661c18ec02fSPetter Reinholdtsen  * +--------------------+
662c18ec02fSPetter Reinholdtsen  * |  rmcp.ver          | 4 bytes
663c18ec02fSPetter Reinholdtsen  * |  rmcp.__reserved   |
664c18ec02fSPetter Reinholdtsen  * |  rmcp.seq          |
665c18ec02fSPetter Reinholdtsen  * |  rmcp.class        |
666c18ec02fSPetter Reinholdtsen  * +--------------------+
667c18ec02fSPetter Reinholdtsen  * |  session.authtype  | 9 bytes
668c18ec02fSPetter Reinholdtsen  * |  session.seq       |
669c18ec02fSPetter Reinholdtsen  * |  session.id        |
670c18ec02fSPetter Reinholdtsen  * +--------------------+
671c18ec02fSPetter Reinholdtsen  * | [session.authcode] | 16 bytes (AUTHTYPE != none)
672c18ec02fSPetter Reinholdtsen  * +--------------------+
673c18ec02fSPetter Reinholdtsen  * |  message length    | 1 byte
674c18ec02fSPetter Reinholdtsen  * +--------------------+
675c18ec02fSPetter Reinholdtsen  * |  message.rs_addr   | 6 bytes
676c18ec02fSPetter Reinholdtsen  * |  message.netfn_lun |
677c18ec02fSPetter Reinholdtsen  * |  message.checksum  |
678c18ec02fSPetter Reinholdtsen  * |  message.rq_addr   |
679c18ec02fSPetter Reinholdtsen  * |  message.rq_seq    |
680c18ec02fSPetter Reinholdtsen  * |  message.cmd       |
681c18ec02fSPetter Reinholdtsen  * +--------------------+
682c18ec02fSPetter Reinholdtsen  * | [request data]     | data_len bytes
683c18ec02fSPetter Reinholdtsen  * +--------------------+
684c18ec02fSPetter Reinholdtsen  * |  checksum          | 1 byte
685c18ec02fSPetter Reinholdtsen  * +--------------------+
686c18ec02fSPetter Reinholdtsen  */
687c18ec02fSPetter Reinholdtsen static struct ipmi_rq_entry *
688c18ec02fSPetter Reinholdtsen ipmi_lan_build_cmd(struct ipmi_intf * intf, struct ipmi_rq * req, int isRetry)
689c18ec02fSPetter Reinholdtsen {
690c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp = {
691c18ec02fSPetter Reinholdtsen 		.ver		= RMCP_VERSION_1,
692c18ec02fSPetter Reinholdtsen 		.class		= RMCP_CLASS_IPMI,
693c18ec02fSPetter Reinholdtsen 		.seq		= 0xff,
694c18ec02fSPetter Reinholdtsen 	};
695c18ec02fSPetter Reinholdtsen 	uint8_t * msg, * temp;
696c18ec02fSPetter Reinholdtsen 	int cs, mp, tmp;
697c18ec02fSPetter Reinholdtsen 	int ap = 0;
698c18ec02fSPetter Reinholdtsen 	int len = 0;
699c18ec02fSPetter Reinholdtsen 	int cs2 = 0, cs3 = 0;
700c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * entry;
701c18ec02fSPetter Reinholdtsen 	struct ipmi_session * s = intf->session;
702c18ec02fSPetter Reinholdtsen 	static int curr_seq = 0;
703c18ec02fSPetter Reinholdtsen 	uint8_t our_address = intf->my_addr;
704c18ec02fSPetter Reinholdtsen 
705c18ec02fSPetter Reinholdtsen 	if (our_address == 0)
706c18ec02fSPetter Reinholdtsen 		our_address = IPMI_BMC_SLAVE_ADDR;
707c18ec02fSPetter Reinholdtsen 
708c18ec02fSPetter Reinholdtsen 	if (isRetry == 0)
709c18ec02fSPetter Reinholdtsen 		curr_seq++;
710c18ec02fSPetter Reinholdtsen 
711c18ec02fSPetter Reinholdtsen 	if (curr_seq >= 64)
712c18ec02fSPetter Reinholdtsen 		curr_seq = 0;
713c18ec02fSPetter Reinholdtsen 
714c18ec02fSPetter Reinholdtsen 	// Bug in the existing code where it keeps on adding same command/seq pair
715c18ec02fSPetter Reinholdtsen 	// in the lookup entry list.
716c18ec02fSPetter Reinholdtsen 	// Check if we have cmd,seq pair already in our list. As we are not changing
717c18ec02fSPetter Reinholdtsen 	// the seq number we have to re-use the node which has existing
718c18ec02fSPetter Reinholdtsen 	// command and sequence number. If we add then we will have redundant node with
719c18ec02fSPetter Reinholdtsen 	// same cmd,seq pair
720c18ec02fSPetter Reinholdtsen 	entry = ipmi_req_lookup_entry(curr_seq, req->msg.cmd);
721c18ec02fSPetter Reinholdtsen 	if (entry)
722c18ec02fSPetter Reinholdtsen 	{
723c18ec02fSPetter Reinholdtsen 		// This indicates that we have already same command and seq in list
724c18ec02fSPetter Reinholdtsen 		// No need to add once again and we will re-use the existing node.
725c18ec02fSPetter Reinholdtsen 		// Only thing we have to do is clear the msg_data as we create
726c18ec02fSPetter Reinholdtsen 		// a new one below in the code for it.
727c18ec02fSPetter Reinholdtsen 		if (entry->msg_data) {
728c18ec02fSPetter Reinholdtsen 			free(entry->msg_data);
729c18ec02fSPetter Reinholdtsen 			entry->msg_data = NULL;
730c18ec02fSPetter Reinholdtsen 		}
731c18ec02fSPetter Reinholdtsen 	}
732c18ec02fSPetter Reinholdtsen 	else
733c18ec02fSPetter Reinholdtsen 	{
734c18ec02fSPetter Reinholdtsen 		// We dont have this request in the list so we can add it
735c18ec02fSPetter Reinholdtsen 		// to the list
736c18ec02fSPetter Reinholdtsen 		entry = ipmi_req_add_entry(intf, req, curr_seq);
737c18ec02fSPetter Reinholdtsen 		if (entry == NULL)
738c18ec02fSPetter Reinholdtsen 			return NULL;
739c18ec02fSPetter Reinholdtsen 	}
740c18ec02fSPetter Reinholdtsen 
741c18ec02fSPetter Reinholdtsen 	len = req->msg.data_len + 29;
742c18ec02fSPetter Reinholdtsen 	if (s->active && s->authtype)
743c18ec02fSPetter Reinholdtsen 		len += 16;
744c18ec02fSPetter Reinholdtsen 	if (intf->transit_addr != intf->my_addr && intf->transit_addr != 0)
745c18ec02fSPetter Reinholdtsen 		len += 8;
746c18ec02fSPetter Reinholdtsen 	msg = malloc(len);
747c18ec02fSPetter Reinholdtsen 	if (msg == NULL) {
748c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
749c18ec02fSPetter Reinholdtsen 		return NULL;
750c18ec02fSPetter Reinholdtsen 	}
751c18ec02fSPetter Reinholdtsen 	memset(msg, 0, len);
752c18ec02fSPetter Reinholdtsen 
753c18ec02fSPetter Reinholdtsen 	/* rmcp header */
754c18ec02fSPetter Reinholdtsen 	memcpy(msg, &rmcp, sizeof(rmcp));
755c18ec02fSPetter Reinholdtsen 	len = sizeof(rmcp);
756c18ec02fSPetter Reinholdtsen 
757c18ec02fSPetter Reinholdtsen 	/* ipmi session header */
758c18ec02fSPetter Reinholdtsen 	msg[len++] = s->active ? s->authtype : 0;
759c18ec02fSPetter Reinholdtsen 
760c18ec02fSPetter Reinholdtsen 	msg[len++] = s->in_seq & 0xff;
761c18ec02fSPetter Reinholdtsen 	msg[len++] = (s->in_seq >> 8) & 0xff;
762c18ec02fSPetter Reinholdtsen 	msg[len++] = (s->in_seq >> 16) & 0xff;
763c18ec02fSPetter Reinholdtsen 	msg[len++] = (s->in_seq >> 24) & 0xff;
764c18ec02fSPetter Reinholdtsen 	memcpy(msg+len, &s->session_id, 4);
765c18ec02fSPetter Reinholdtsen 	len += 4;
766c18ec02fSPetter Reinholdtsen 
767c18ec02fSPetter Reinholdtsen 	/* ipmi session authcode */
768c18ec02fSPetter Reinholdtsen 	if (s->active && s->authtype) {
769c18ec02fSPetter Reinholdtsen 		ap = len;
770c18ec02fSPetter Reinholdtsen 		memcpy(msg+len, s->authcode, 16);
771c18ec02fSPetter Reinholdtsen 		len += 16;
772c18ec02fSPetter Reinholdtsen 	}
773c18ec02fSPetter Reinholdtsen 
774c18ec02fSPetter Reinholdtsen 	/* message length */
775c18ec02fSPetter Reinholdtsen 	if ((intf->target_addr == our_address) || !bridge_possible) {
776c18ec02fSPetter Reinholdtsen 		entry->bridging_level = 0;
777c18ec02fSPetter Reinholdtsen 		msg[len++] = req->msg.data_len + 7;
778c18ec02fSPetter Reinholdtsen 		cs = mp = len;
779c18ec02fSPetter Reinholdtsen 	} else {
780c18ec02fSPetter Reinholdtsen 		/* bridged request: encapsulate w/in Send Message */
781c18ec02fSPetter Reinholdtsen 		entry->bridging_level = 1;
782c18ec02fSPetter Reinholdtsen 		msg[len++] = req->msg.data_len + 15 +
783c18ec02fSPetter Reinholdtsen 		  (intf->transit_addr != intf->my_addr && intf->transit_addr != 0 ? 8 : 0);
784c18ec02fSPetter Reinholdtsen 		cs = mp = len;
785c18ec02fSPetter Reinholdtsen 		msg[len++] = IPMI_BMC_SLAVE_ADDR;
786c18ec02fSPetter Reinholdtsen 		msg[len++] = IPMI_NETFN_APP << 2;
787c18ec02fSPetter Reinholdtsen 		tmp = len - cs;
788c18ec02fSPetter Reinholdtsen 		msg[len++] = ipmi_csum(msg+cs, tmp);
789c18ec02fSPetter Reinholdtsen 		cs2 = len;
790c18ec02fSPetter Reinholdtsen 		msg[len++] = IPMI_REMOTE_SWID;
791c18ec02fSPetter Reinholdtsen 		msg[len++] = curr_seq << 2;
792c18ec02fSPetter Reinholdtsen 		msg[len++] = 0x34;			/* Send Message rqst */
793c18ec02fSPetter Reinholdtsen 		entry->req.msg.target_cmd = entry->req.msg.cmd;	/* Save target command */
794c18ec02fSPetter Reinholdtsen 		entry->req.msg.cmd = 0x34;		/* (fixup request entry) */
795c18ec02fSPetter Reinholdtsen 
796c18ec02fSPetter Reinholdtsen 		if (intf->transit_addr == intf->my_addr || intf->transit_addr == 0) {
797c18ec02fSPetter Reinholdtsen 		        msg[len++] = (0x40|intf->target_channel); /* Track request*/
798c18ec02fSPetter Reinholdtsen 		} else {
799c18ec02fSPetter Reinholdtsen 		        entry->bridging_level++;
800c18ec02fSPetter Reinholdtsen                		msg[len++] = (0x40|intf->transit_channel); /* Track request*/
801c18ec02fSPetter Reinholdtsen 			cs = len;
802c18ec02fSPetter Reinholdtsen 			msg[len++] = intf->transit_addr;
803c18ec02fSPetter Reinholdtsen 			msg[len++] = IPMI_NETFN_APP << 2;
804c18ec02fSPetter Reinholdtsen 			tmp = len - cs;
805c18ec02fSPetter Reinholdtsen 			msg[len++] = ipmi_csum(msg+cs, tmp);
806c18ec02fSPetter Reinholdtsen 			cs3 = len;
807c18ec02fSPetter Reinholdtsen 			msg[len++] = intf->my_addr;
808c18ec02fSPetter Reinholdtsen 			msg[len++] = curr_seq << 2;
809c18ec02fSPetter Reinholdtsen 			msg[len++] = 0x34;			/* Send Message rqst */
810c18ec02fSPetter Reinholdtsen 			msg[len++] = (0x40|intf->target_channel); /* Track request */
811c18ec02fSPetter Reinholdtsen 		}
812c18ec02fSPetter Reinholdtsen 		cs = len;
813c18ec02fSPetter Reinholdtsen 	}
814c18ec02fSPetter Reinholdtsen 
815c18ec02fSPetter Reinholdtsen 	/* ipmi message header */
816c18ec02fSPetter Reinholdtsen 	msg[len++] = intf->target_addr;
817c18ec02fSPetter Reinholdtsen 	msg[len++] = req->msg.netfn << 2 | (req->msg.lun & 3);
818c18ec02fSPetter Reinholdtsen 	tmp = len - cs;
819c18ec02fSPetter Reinholdtsen 	msg[len++] = ipmi_csum(msg+cs, tmp);
820c18ec02fSPetter Reinholdtsen 	cs = len;
821c18ec02fSPetter Reinholdtsen 
822c18ec02fSPetter Reinholdtsen 	if (!entry->bridging_level)
823c18ec02fSPetter Reinholdtsen 		msg[len++] = IPMI_REMOTE_SWID;
824c18ec02fSPetter Reinholdtsen    /* Bridged message */
825c18ec02fSPetter Reinholdtsen 	else if (entry->bridging_level)
826c18ec02fSPetter Reinholdtsen 		msg[len++] = intf->my_addr;
827c18ec02fSPetter Reinholdtsen 
828c18ec02fSPetter Reinholdtsen 	entry->rq_seq = curr_seq;
829c18ec02fSPetter Reinholdtsen 	msg[len++] = entry->rq_seq << 2;
830c18ec02fSPetter Reinholdtsen 	msg[len++] = req->msg.cmd;
831c18ec02fSPetter Reinholdtsen 
832c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">> IPMI Request Session Header (level %d)", entry->bridging_level);
833c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Authtype   : %s",
834c18ec02fSPetter Reinholdtsen 	       val2str(s->authtype, ipmi_authtype_session_vals));
835c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Sequence   : 0x%08lx", (long)s->in_seq);
836c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Session ID : 0x%08lx", (long)s->session_id);
837c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">> IPMI Request Message Header");
838c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rs Addr    : %02x", intf->target_addr);
839c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   NetFn      : %02x", req->msg.netfn);
840c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rs LUN     : %01x", 0);
841c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rq Addr    : %02x", IPMI_REMOTE_SWID);
842c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rq Seq     : %02x", entry->rq_seq);
843c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Rq Lun     : %01x", 0);
844c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG+1, ">>   Command    : %02x", req->msg.cmd);
845c18ec02fSPetter Reinholdtsen 
846c18ec02fSPetter Reinholdtsen 	/* message data */
847c18ec02fSPetter Reinholdtsen 	if (req->msg.data_len) {
848c18ec02fSPetter Reinholdtsen  		memcpy(msg+len, req->msg.data, req->msg.data_len);
849c18ec02fSPetter Reinholdtsen 		len += req->msg.data_len;
850c18ec02fSPetter Reinholdtsen 	}
851c18ec02fSPetter Reinholdtsen 
852c18ec02fSPetter Reinholdtsen 	/* second checksum */
853c18ec02fSPetter Reinholdtsen 	tmp = len - cs;
854c18ec02fSPetter Reinholdtsen 	msg[len++] = ipmi_csum(msg+cs, tmp);
855c18ec02fSPetter Reinholdtsen 
856c18ec02fSPetter Reinholdtsen 	/* bridged request: 2nd checksum */
857c18ec02fSPetter Reinholdtsen 	if (entry->bridging_level) {
858c18ec02fSPetter Reinholdtsen 		if (intf->transit_addr != intf->my_addr && intf->transit_addr != 0) {
859c18ec02fSPetter Reinholdtsen 			tmp = len - cs3;
860c18ec02fSPetter Reinholdtsen 			msg[len++] = ipmi_csum(msg+cs3, tmp);
861c18ec02fSPetter Reinholdtsen 		}
862c18ec02fSPetter Reinholdtsen 		tmp = len - cs2;
863c18ec02fSPetter Reinholdtsen 		msg[len++] = ipmi_csum(msg+cs2, tmp);
864c18ec02fSPetter Reinholdtsen 	}
865c18ec02fSPetter Reinholdtsen 
866c18ec02fSPetter Reinholdtsen 	if (s->active) {
867c18ec02fSPetter Reinholdtsen 		/*
868c18ec02fSPetter Reinholdtsen 		 * s->authcode is already copied to msg+ap but some
869c18ec02fSPetter Reinholdtsen 		 * authtypes require portions of the ipmi message to
870c18ec02fSPetter Reinholdtsen 		 * create the authcode so they must be done last.
871c18ec02fSPetter Reinholdtsen 		 */
872c18ec02fSPetter Reinholdtsen 		switch (s->authtype) {
873c18ec02fSPetter Reinholdtsen 		case IPMI_SESSION_AUTHTYPE_MD5:
874c18ec02fSPetter Reinholdtsen 			temp = ipmi_auth_md5(s, msg+mp, msg[mp-1]);
875c18ec02fSPetter Reinholdtsen 			memcpy(msg+ap, temp, 16);
876c18ec02fSPetter Reinholdtsen 			break;
877c18ec02fSPetter Reinholdtsen 		case IPMI_SESSION_AUTHTYPE_MD2:
878c18ec02fSPetter Reinholdtsen 			temp = ipmi_auth_md2(s, msg+mp, msg[mp-1]);
879c18ec02fSPetter Reinholdtsen 			memcpy(msg+ap, temp, 16);
880c18ec02fSPetter Reinholdtsen 			break;
881c18ec02fSPetter Reinholdtsen 		}
882c18ec02fSPetter Reinholdtsen 	}
883c18ec02fSPetter Reinholdtsen 
884c18ec02fSPetter Reinholdtsen 	if (s->in_seq) {
885c18ec02fSPetter Reinholdtsen 		s->in_seq++;
886c18ec02fSPetter Reinholdtsen 		if (s->in_seq == 0)
887c18ec02fSPetter Reinholdtsen 			s->in_seq++;
888c18ec02fSPetter Reinholdtsen 	}
889c18ec02fSPetter Reinholdtsen 
890c18ec02fSPetter Reinholdtsen 	entry->msg_len = len;
891c18ec02fSPetter Reinholdtsen 	entry->msg_data = msg;
892c18ec02fSPetter Reinholdtsen 
893c18ec02fSPetter Reinholdtsen 	return entry;
894c18ec02fSPetter Reinholdtsen }
895c18ec02fSPetter Reinholdtsen 
896c18ec02fSPetter Reinholdtsen static struct ipmi_rs *
897c18ec02fSPetter Reinholdtsen ipmi_lan_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
898c18ec02fSPetter Reinholdtsen {
899c18ec02fSPetter Reinholdtsen 	struct ipmi_rq_entry * entry;
900c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp = NULL;
901c18ec02fSPetter Reinholdtsen 	int try = 0;
902c18ec02fSPetter Reinholdtsen 	int isRetry = 0;
903c18ec02fSPetter Reinholdtsen 
904c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "ipmi_lan_send_cmd:opened=[%d], open=[%d]",
905c18ec02fSPetter Reinholdtsen 		intf->opened, intf->open);
906c18ec02fSPetter Reinholdtsen 
907c18ec02fSPetter Reinholdtsen 	if (intf->opened == 0 && intf->open != NULL) {
908c18ec02fSPetter Reinholdtsen 		if (intf->open(intf) < 0) {
909c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "Failed to open LAN interface");
910c18ec02fSPetter Reinholdtsen 			return NULL;
911c18ec02fSPetter Reinholdtsen 		}
912c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "\topened=[%d], open=[%d]",
913c18ec02fSPetter Reinholdtsen 			intf->opened, intf->open);
914c18ec02fSPetter Reinholdtsen 	}
915c18ec02fSPetter Reinholdtsen 
916c18ec02fSPetter Reinholdtsen 	for (;;) {
917c18ec02fSPetter Reinholdtsen 		isRetry = ( try > 0 ) ? 1 : 0;
918c18ec02fSPetter Reinholdtsen 
919c18ec02fSPetter Reinholdtsen 		entry = ipmi_lan_build_cmd(intf, req, isRetry);
920c18ec02fSPetter Reinholdtsen 		if (entry == NULL) {
921c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Aborting send command, unable to build");
922c18ec02fSPetter Reinholdtsen 			return NULL;
923c18ec02fSPetter Reinholdtsen 		}
924c18ec02fSPetter Reinholdtsen 
925c18ec02fSPetter Reinholdtsen 		if (ipmi_lan_send_packet(intf, entry->msg_data, entry->msg_len) < 0) {
926c18ec02fSPetter Reinholdtsen 			try++;
927c18ec02fSPetter Reinholdtsen 			usleep(5000);
928c18ec02fSPetter Reinholdtsen 			ipmi_req_remove_entry(entry->rq_seq, entry->req.msg.target_cmd);
929c18ec02fSPetter Reinholdtsen 			continue;
930c18ec02fSPetter Reinholdtsen 		}
931c18ec02fSPetter Reinholdtsen 
932c18ec02fSPetter Reinholdtsen 		/* if we are set to noanswer we do not expect response */
933c18ec02fSPetter Reinholdtsen 		if (intf->noanswer)
934c18ec02fSPetter Reinholdtsen 			break;
935c18ec02fSPetter Reinholdtsen 
936c18ec02fSPetter Reinholdtsen 		if (ipmi_oem_active(intf, "intelwv2"))
937c18ec02fSPetter Reinholdtsen 			ipmi_lan_thump(intf);
938c18ec02fSPetter Reinholdtsen 
939c18ec02fSPetter Reinholdtsen 		usleep(100);
940c18ec02fSPetter Reinholdtsen 
941c18ec02fSPetter Reinholdtsen 		rsp = ipmi_lan_poll_recv(intf);
942c18ec02fSPetter Reinholdtsen 
943c18ec02fSPetter Reinholdtsen 		/* Duplicate Request ccode most likely indicates a response to
944c18ec02fSPetter Reinholdtsen 		   a previous retry. Ignore and keep polling. */
945c18ec02fSPetter Reinholdtsen 		if((rsp != NULL) && (rsp->ccode == 0xcf)) {
946c18ec02fSPetter Reinholdtsen 			rsp = NULL;
947c18ec02fSPetter Reinholdtsen 			rsp = ipmi_lan_poll_recv(intf);
948c18ec02fSPetter Reinholdtsen 		}
949c18ec02fSPetter Reinholdtsen 
950c18ec02fSPetter Reinholdtsen 		if (rsp)
951c18ec02fSPetter Reinholdtsen 			break;
952c18ec02fSPetter Reinholdtsen 
953c18ec02fSPetter Reinholdtsen 		usleep(5000);
954c18ec02fSPetter Reinholdtsen 		if (++try >= intf->session->retry) {
955c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "  No response from remote controller");
956c18ec02fSPetter Reinholdtsen 			break;
957c18ec02fSPetter Reinholdtsen 		}
958c18ec02fSPetter Reinholdtsen 	}
959c18ec02fSPetter Reinholdtsen 
960c18ec02fSPetter Reinholdtsen 	// We need to cleanup the existing entries from the list. Because if we
961c18ec02fSPetter Reinholdtsen 	// keep it and then when we send the new command and if the response is for
962c18ec02fSPetter Reinholdtsen 	// old command it still matches it and then returns success.
963c18ec02fSPetter Reinholdtsen 	// This is the corner case where the remote controller responds very slowly.
964c18ec02fSPetter Reinholdtsen 	//
965c18ec02fSPetter Reinholdtsen 	// Example: We have to send command 23 and 2d.
966c18ec02fSPetter Reinholdtsen 	// If we send command,seq as 23,10 and if we dont get any response it will
967c18ec02fSPetter Reinholdtsen 	// retry 4 times with 23,10 and then come out here and indicate that there is no
968c18ec02fSPetter Reinholdtsen 	// reponse from the remote controller and will send the next command for
969c18ec02fSPetter Reinholdtsen 	// ie 2d,11. And if the BMC is slow to respond and returns 23,10 then it
970c18ec02fSPetter Reinholdtsen 	// will match it in the list and will take response of command 23 as response
971c18ec02fSPetter Reinholdtsen 	// for command 2d and return success. So ideally when retries are done and
972c18ec02fSPetter Reinholdtsen 	// are out of this function we should be clearing the list to be safe so that
973c18ec02fSPetter Reinholdtsen 	// we dont match the old response with new request.
974c18ec02fSPetter Reinholdtsen 	//          [23, 10] --> BMC
975c18ec02fSPetter Reinholdtsen 	//          [23, 10] --> BMC
976c18ec02fSPetter Reinholdtsen 	//          [23, 10] --> BMC
977c18ec02fSPetter Reinholdtsen 	//          [23, 10] --> BMC
978c18ec02fSPetter Reinholdtsen 	//          [2D, 11] --> BMC
979c18ec02fSPetter Reinholdtsen 	//                   <-- [23, 10]
980c18ec02fSPetter Reinholdtsen 	//  here if we maintain 23,10 in the list then it will get matched and consider
981c18ec02fSPetter Reinholdtsen 	//  23 response as response for 2D.
982c18ec02fSPetter Reinholdtsen 	ipmi_req_clear_entries();
983c18ec02fSPetter Reinholdtsen 
984c18ec02fSPetter Reinholdtsen 	return rsp;
985c18ec02fSPetter Reinholdtsen }
986c18ec02fSPetter Reinholdtsen 
987c18ec02fSPetter Reinholdtsen static uint8_t *
988c18ec02fSPetter Reinholdtsen ipmi_lan_build_rsp(struct ipmi_intf * intf, struct ipmi_rs * rsp, int * llen)
989c18ec02fSPetter Reinholdtsen {
990c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp = {
991c18ec02fSPetter Reinholdtsen 		.ver	= RMCP_VERSION_1,
992c18ec02fSPetter Reinholdtsen 		.class	= RMCP_CLASS_IPMI,
993c18ec02fSPetter Reinholdtsen 		.seq	= 0xff,
994c18ec02fSPetter Reinholdtsen 	};
995c18ec02fSPetter Reinholdtsen 	struct ipmi_session * s = intf->session;
996c18ec02fSPetter Reinholdtsen 	int cs, mp, ap = 0, tmp;
997c18ec02fSPetter Reinholdtsen 	int len;
998c18ec02fSPetter Reinholdtsen 	uint8_t * msg;
999c18ec02fSPetter Reinholdtsen 
1000c18ec02fSPetter Reinholdtsen 	len = rsp->data_len + 22;
1001c18ec02fSPetter Reinholdtsen 	if (s->active)
1002c18ec02fSPetter Reinholdtsen 		len += 16;
1003c18ec02fSPetter Reinholdtsen 
1004c18ec02fSPetter Reinholdtsen 	msg = malloc(len);
1005c18ec02fSPetter Reinholdtsen 	if (msg == NULL) {
1006c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
1007c18ec02fSPetter Reinholdtsen 		return NULL;
1008c18ec02fSPetter Reinholdtsen 	}
1009c18ec02fSPetter Reinholdtsen 	memset(msg, 0, len);
1010c18ec02fSPetter Reinholdtsen 
1011c18ec02fSPetter Reinholdtsen 	/* rmcp header */
1012c18ec02fSPetter Reinholdtsen 	memcpy(msg, &rmcp, 4);
1013c18ec02fSPetter Reinholdtsen 	len = sizeof(rmcp);
1014c18ec02fSPetter Reinholdtsen 
1015c18ec02fSPetter Reinholdtsen 	/* ipmi session header */
1016c18ec02fSPetter Reinholdtsen 	msg[len++] = s->active ? s->authtype : 0;
1017c18ec02fSPetter Reinholdtsen 
1018c18ec02fSPetter Reinholdtsen 	if (s->in_seq) {
1019c18ec02fSPetter Reinholdtsen 		s->in_seq++;
1020c18ec02fSPetter Reinholdtsen 		if (s->in_seq == 0)
1021c18ec02fSPetter Reinholdtsen 			s->in_seq++;
1022c18ec02fSPetter Reinholdtsen 	}
1023c18ec02fSPetter Reinholdtsen 	memcpy(msg+len, &s->in_seq, 4);
1024c18ec02fSPetter Reinholdtsen 	len += 4;
1025c18ec02fSPetter Reinholdtsen 	memcpy(msg+len, &s->session_id, 4);
1026c18ec02fSPetter Reinholdtsen 	len += 4;
1027c18ec02fSPetter Reinholdtsen 
1028c18ec02fSPetter Reinholdtsen 	/* session authcode, if session active and authtype is not none */
1029c18ec02fSPetter Reinholdtsen 	if (s->active && s->authtype) {
1030c18ec02fSPetter Reinholdtsen 		ap = len;
1031c18ec02fSPetter Reinholdtsen 		memcpy(msg+len, s->authcode, 16);
1032c18ec02fSPetter Reinholdtsen 		len += 16;
1033c18ec02fSPetter Reinholdtsen 	}
1034c18ec02fSPetter Reinholdtsen 
1035c18ec02fSPetter Reinholdtsen 	/* message length */
1036c18ec02fSPetter Reinholdtsen 	msg[len++] = rsp->data_len + 8;
1037c18ec02fSPetter Reinholdtsen 
1038c18ec02fSPetter Reinholdtsen 	/* message header */
1039c18ec02fSPetter Reinholdtsen 	cs = mp = len;
1040c18ec02fSPetter Reinholdtsen 	msg[len++] = IPMI_REMOTE_SWID;
1041c18ec02fSPetter Reinholdtsen 	msg[len++] = rsp->msg.netfn << 2;
1042c18ec02fSPetter Reinholdtsen 	tmp = len - cs;
1043c18ec02fSPetter Reinholdtsen 	msg[len++] = ipmi_csum(msg+cs, tmp);
1044c18ec02fSPetter Reinholdtsen 	cs = len;
1045c18ec02fSPetter Reinholdtsen 	msg[len++] = IPMI_BMC_SLAVE_ADDR;
1046c18ec02fSPetter Reinholdtsen 	msg[len++] = (rsp->msg.seq << 2) | (rsp->msg.lun & 3);
1047c18ec02fSPetter Reinholdtsen 	msg[len++] = rsp->msg.cmd;
1048c18ec02fSPetter Reinholdtsen 
1049c18ec02fSPetter Reinholdtsen 	/* completion code */
1050c18ec02fSPetter Reinholdtsen 	msg[len++] = rsp->ccode;
1051c18ec02fSPetter Reinholdtsen 
1052c18ec02fSPetter Reinholdtsen 	/* message data */
1053c18ec02fSPetter Reinholdtsen 	if (rsp->data_len) {
1054c18ec02fSPetter Reinholdtsen 		memcpy(msg+len, rsp->data, rsp->data_len);
1055c18ec02fSPetter Reinholdtsen 		len += rsp->data_len;
1056c18ec02fSPetter Reinholdtsen 	}
1057c18ec02fSPetter Reinholdtsen 
1058c18ec02fSPetter Reinholdtsen 	/* second checksum */
1059c18ec02fSPetter Reinholdtsen 	tmp = len - cs;
1060c18ec02fSPetter Reinholdtsen 	msg[len++] = ipmi_csum(msg+cs, tmp);
1061c18ec02fSPetter Reinholdtsen 
1062c18ec02fSPetter Reinholdtsen 	if (s->active) {
1063c18ec02fSPetter Reinholdtsen 		uint8_t * d;
1064c18ec02fSPetter Reinholdtsen 		switch (s->authtype) {
1065c18ec02fSPetter Reinholdtsen 		case IPMI_SESSION_AUTHTYPE_MD5:
1066c18ec02fSPetter Reinholdtsen 			d = ipmi_auth_md5(s, msg+mp, msg[mp-1]);
1067c18ec02fSPetter Reinholdtsen 			memcpy(msg+ap, d, 16);
1068c18ec02fSPetter Reinholdtsen 			break;
1069c18ec02fSPetter Reinholdtsen 		case IPMI_SESSION_AUTHTYPE_MD2:
1070c18ec02fSPetter Reinholdtsen 			d = ipmi_auth_md2(s, msg+mp, msg[mp-1]);
1071c18ec02fSPetter Reinholdtsen 			memcpy(msg+ap, d, 16);
1072c18ec02fSPetter Reinholdtsen 			break;
1073c18ec02fSPetter Reinholdtsen 		}
1074c18ec02fSPetter Reinholdtsen 	}
1075c18ec02fSPetter Reinholdtsen 
1076c18ec02fSPetter Reinholdtsen 	*llen = len;
1077c18ec02fSPetter Reinholdtsen 	return msg;
1078c18ec02fSPetter Reinholdtsen }
1079c18ec02fSPetter Reinholdtsen 
1080c18ec02fSPetter Reinholdtsen static int
1081c18ec02fSPetter Reinholdtsen ipmi_lan_send_rsp(struct ipmi_intf * intf, struct ipmi_rs * rsp)
1082c18ec02fSPetter Reinholdtsen {
1083c18ec02fSPetter Reinholdtsen 	uint8_t * msg;
1084c18ec02fSPetter Reinholdtsen 	int len = 0;
1085c18ec02fSPetter Reinholdtsen 	int rv;
1086c18ec02fSPetter Reinholdtsen 
1087c18ec02fSPetter Reinholdtsen 	msg = ipmi_lan_build_rsp(intf, rsp, &len);
1088c18ec02fSPetter Reinholdtsen 	if (len <= 0 || msg == NULL) {
1089c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Invalid response packet");
1090c18ec02fSPetter Reinholdtsen 		if (msg != NULL) {
1091c18ec02fSPetter Reinholdtsen 			free(msg);
1092c18ec02fSPetter Reinholdtsen 			msg = NULL;
1093c18ec02fSPetter Reinholdtsen 		}
1094c18ec02fSPetter Reinholdtsen 		return -1;
1095c18ec02fSPetter Reinholdtsen 	}
1096c18ec02fSPetter Reinholdtsen 
1097c18ec02fSPetter Reinholdtsen 	rv = sendto(intf->fd, msg, len, 0,
1098c18ec02fSPetter Reinholdtsen 		    (struct sockaddr *)&intf->session->addr,
1099c18ec02fSPetter Reinholdtsen 		    intf->session->addrlen);
1100c18ec02fSPetter Reinholdtsen 	if (rv < 0) {
1101c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Packet send failed");
1102c18ec02fSPetter Reinholdtsen 		if (msg != NULL) {
1103c18ec02fSPetter Reinholdtsen 			free(msg);
1104c18ec02fSPetter Reinholdtsen 			msg = NULL;
1105c18ec02fSPetter Reinholdtsen 		}
1106c18ec02fSPetter Reinholdtsen 		return -1;
1107c18ec02fSPetter Reinholdtsen 	}
1108c18ec02fSPetter Reinholdtsen 
1109c18ec02fSPetter Reinholdtsen 	if (msg != NULL) {
1110c18ec02fSPetter Reinholdtsen 		free(msg);
1111c18ec02fSPetter Reinholdtsen 		msg = NULL;
1112c18ec02fSPetter Reinholdtsen 	}
1113c18ec02fSPetter Reinholdtsen 	return 0;
1114c18ec02fSPetter Reinholdtsen }
1115c18ec02fSPetter Reinholdtsen 
1116c18ec02fSPetter Reinholdtsen /*
1117c18ec02fSPetter Reinholdtsen  * IPMI SOL Payload Format
1118c18ec02fSPetter Reinholdtsen  * +--------------------+
1119c18ec02fSPetter Reinholdtsen  * |  rmcp.ver          | 4 bytes
1120c18ec02fSPetter Reinholdtsen  * |  rmcp.__reserved   |
1121c18ec02fSPetter Reinholdtsen  * |  rmcp.seq          |
1122c18ec02fSPetter Reinholdtsen  * |  rmcp.class        |
1123c18ec02fSPetter Reinholdtsen  * +--------------------+
1124c18ec02fSPetter Reinholdtsen  * |  session.authtype  | 9 bytes
1125c18ec02fSPetter Reinholdtsen  * |  session.seq       |
1126c18ec02fSPetter Reinholdtsen  * |  session.id        |
1127c18ec02fSPetter Reinholdtsen  * +--------------------+
1128c18ec02fSPetter Reinholdtsen  * |  message length    | 1 byte
1129c18ec02fSPetter Reinholdtsen  * +--------------------+
1130c18ec02fSPetter Reinholdtsen  * |  sol.seq           | 5 bytes
1131c18ec02fSPetter Reinholdtsen  * |  sol.ack_seq       |
1132c18ec02fSPetter Reinholdtsen  * |  sol.acc_count     |
1133c18ec02fSPetter Reinholdtsen  * |  sol.control       |
1134c18ec02fSPetter Reinholdtsen  * |  sol.__reserved    |
1135c18ec02fSPetter Reinholdtsen  * +--------------------+
1136c18ec02fSPetter Reinholdtsen  * | [request data]     | data_len bytes
1137c18ec02fSPetter Reinholdtsen  * +--------------------+
1138c18ec02fSPetter Reinholdtsen  */
1139c18ec02fSPetter Reinholdtsen uint8_t * ipmi_lan_build_sol_msg(struct ipmi_intf * intf,
1140c18ec02fSPetter Reinholdtsen 				 struct ipmi_v2_payload * payload,
1141c18ec02fSPetter Reinholdtsen 				 int * llen)
1142c18ec02fSPetter Reinholdtsen {
1143c18ec02fSPetter Reinholdtsen 	struct rmcp_hdr rmcp = {
1144c18ec02fSPetter Reinholdtsen 		.ver		= RMCP_VERSION_1,
1145c18ec02fSPetter Reinholdtsen 		.class		= RMCP_CLASS_IPMI,
1146c18ec02fSPetter Reinholdtsen 		.seq		= 0xff,
1147c18ec02fSPetter Reinholdtsen 	};
1148c18ec02fSPetter Reinholdtsen 	struct ipmi_session * session = intf->session;
1149c18ec02fSPetter Reinholdtsen 
1150c18ec02fSPetter Reinholdtsen 	/* msg will hold the entire message to be sent */
1151c18ec02fSPetter Reinholdtsen 	uint8_t * msg;
1152c18ec02fSPetter Reinholdtsen 
1153c18ec02fSPetter Reinholdtsen 	int len = 0;
1154c18ec02fSPetter Reinholdtsen 
1155c18ec02fSPetter Reinholdtsen 	len =	sizeof(rmcp)                                 +  // RMCP Header (4)
1156c18ec02fSPetter Reinholdtsen 		10                                           +  // IPMI Session Header
1157c18ec02fSPetter Reinholdtsen 		5                                            +  // SOL header
1158c18ec02fSPetter Reinholdtsen 		payload->payload.sol_packet.character_count;    // The actual payload
1159c18ec02fSPetter Reinholdtsen 
1160c18ec02fSPetter Reinholdtsen 	msg = malloc(len);
1161c18ec02fSPetter Reinholdtsen 	if (msg == NULL) {
1162c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
1163c18ec02fSPetter Reinholdtsen 		return NULL;
1164c18ec02fSPetter Reinholdtsen 	}
1165c18ec02fSPetter Reinholdtsen 	memset(msg, 0, len);
1166c18ec02fSPetter Reinholdtsen 
1167c18ec02fSPetter Reinholdtsen 	/* rmcp header */
1168c18ec02fSPetter Reinholdtsen 	memcpy(msg, &rmcp, sizeof(rmcp));
1169c18ec02fSPetter Reinholdtsen 	len = sizeof(rmcp);
1170c18ec02fSPetter Reinholdtsen 
1171c18ec02fSPetter Reinholdtsen 	/* ipmi session header */
1172c18ec02fSPetter Reinholdtsen 	msg[len++] = 0; /* SOL is always authtype = NONE */
1173c18ec02fSPetter Reinholdtsen 	msg[len++] = session->in_seq & 0xff;
1174c18ec02fSPetter Reinholdtsen 	msg[len++] = (session->in_seq >> 8) & 0xff;
1175c18ec02fSPetter Reinholdtsen 	msg[len++] = (session->in_seq >> 16) & 0xff;
1176c18ec02fSPetter Reinholdtsen 	msg[len++] = (session->in_seq >> 24) & 0xff;
1177c18ec02fSPetter Reinholdtsen 
1178c18ec02fSPetter Reinholdtsen 	msg[len++] = session->session_id & 0xff;
1179c18ec02fSPetter Reinholdtsen 	msg[len++] = (session->session_id >> 8) & 0xff;
1180c18ec02fSPetter Reinholdtsen 	msg[len++] = (session->session_id >> 16) & 0xff;
1181c18ec02fSPetter Reinholdtsen 	msg[len++] = ((session->session_id >> 24) + 0x10) & 0xff; /* Add 0x10 to MSB for SOL */
1182c18ec02fSPetter Reinholdtsen 
1183c18ec02fSPetter Reinholdtsen 	msg[len++] = payload->payload.sol_packet.character_count + 5;
1184c18ec02fSPetter Reinholdtsen 
1185c18ec02fSPetter Reinholdtsen 	/* sol header */
1186c18ec02fSPetter Reinholdtsen 	msg[len++] = payload->payload.sol_packet.packet_sequence_number;
1187c18ec02fSPetter Reinholdtsen 	msg[len++] = payload->payload.sol_packet.acked_packet_number;
1188c18ec02fSPetter Reinholdtsen 	msg[len++] = payload->payload.sol_packet.accepted_character_count;
1189c18ec02fSPetter Reinholdtsen 	msg[len]    = payload->payload.sol_packet.is_nack           ? 0x40 : 0;
1190c18ec02fSPetter Reinholdtsen 	msg[len]   |= payload->payload.sol_packet.assert_ring_wor   ? 0x20 : 0;
1191c18ec02fSPetter Reinholdtsen 	msg[len]   |= payload->payload.sol_packet.generate_break    ? 0x10 : 0;
1192c18ec02fSPetter Reinholdtsen 	msg[len]   |= payload->payload.sol_packet.deassert_cts      ? 0x08 : 0;
1193c18ec02fSPetter Reinholdtsen 	msg[len]   |= payload->payload.sol_packet.deassert_dcd_dsr  ? 0x04 : 0;
1194c18ec02fSPetter Reinholdtsen 	msg[len]   |= payload->payload.sol_packet.flush_inbound     ? 0x02 : 0;
1195c18ec02fSPetter Reinholdtsen 	msg[len++] |= payload->payload.sol_packet.flush_outbound    ? 0x01 : 0;
1196c18ec02fSPetter Reinholdtsen 
1197c18ec02fSPetter Reinholdtsen 	len++; /* On SOL there's and additional fifth byte before the data starts */
1198c18ec02fSPetter Reinholdtsen 
1199c18ec02fSPetter Reinholdtsen 	if (payload->payload.sol_packet.character_count) {
1200c18ec02fSPetter Reinholdtsen 		/* We may have data to add */
1201c18ec02fSPetter Reinholdtsen 		memcpy(msg + len,
1202c18ec02fSPetter Reinholdtsen 		       payload->payload.sol_packet.data,
1203c18ec02fSPetter Reinholdtsen 		       payload->payload.sol_packet.character_count);
1204c18ec02fSPetter Reinholdtsen 		len += payload->payload.sol_packet.character_count;
1205c18ec02fSPetter Reinholdtsen 	}
1206c18ec02fSPetter Reinholdtsen 
1207c18ec02fSPetter Reinholdtsen 	session->in_seq++;
1208c18ec02fSPetter Reinholdtsen 	if (session->in_seq == 0)
1209c18ec02fSPetter Reinholdtsen 		session->in_seq++;
1210c18ec02fSPetter Reinholdtsen 
1211c18ec02fSPetter Reinholdtsen 	*llen = len;
1212c18ec02fSPetter Reinholdtsen 	return msg;
1213c18ec02fSPetter Reinholdtsen }
1214c18ec02fSPetter Reinholdtsen 
1215c18ec02fSPetter Reinholdtsen /*
1216c18ec02fSPetter Reinholdtsen  * is_sol_packet
1217c18ec02fSPetter Reinholdtsen  */
1218c18ec02fSPetter Reinholdtsen static int
1219c18ec02fSPetter Reinholdtsen is_sol_packet(struct ipmi_rs * rsp)
1220c18ec02fSPetter Reinholdtsen {
1221c18ec02fSPetter Reinholdtsen 	return (rsp                                                           &&
1222c18ec02fSPetter Reinholdtsen 		(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL));
1223c18ec02fSPetter Reinholdtsen }
1224c18ec02fSPetter Reinholdtsen 
1225c18ec02fSPetter Reinholdtsen 
1226c18ec02fSPetter Reinholdtsen 
1227c18ec02fSPetter Reinholdtsen /*
1228c18ec02fSPetter Reinholdtsen  * sol_response_acks_packet
1229c18ec02fSPetter Reinholdtsen  */
1230c18ec02fSPetter Reinholdtsen static int
1231c18ec02fSPetter Reinholdtsen sol_response_acks_packet(struct ipmi_rs         * rsp,
1232c18ec02fSPetter Reinholdtsen 			 struct ipmi_v2_payload * payload)
1233c18ec02fSPetter Reinholdtsen {
1234c18ec02fSPetter Reinholdtsen 	return (is_sol_packet(rsp)                                            &&
1235c18ec02fSPetter Reinholdtsen 		payload                                                       &&
1236c18ec02fSPetter Reinholdtsen 		(payload->payload_type    == IPMI_PAYLOAD_TYPE_SOL)           &&
1237c18ec02fSPetter Reinholdtsen 		(rsp->payload.sol_packet.acked_packet_number ==
1238c18ec02fSPetter Reinholdtsen 		 payload->payload.sol_packet.packet_sequence_number));
1239c18ec02fSPetter Reinholdtsen }
1240c18ec02fSPetter Reinholdtsen 
1241c18ec02fSPetter Reinholdtsen /*
1242c18ec02fSPetter Reinholdtsen  * ipmi_lan_send_sol_payload
1243c18ec02fSPetter Reinholdtsen  *
1244c18ec02fSPetter Reinholdtsen  */
1245c18ec02fSPetter Reinholdtsen static struct ipmi_rs *
1246c18ec02fSPetter Reinholdtsen ipmi_lan_send_sol_payload(struct ipmi_intf * intf,
1247c18ec02fSPetter Reinholdtsen 			  struct ipmi_v2_payload * payload)
1248c18ec02fSPetter Reinholdtsen {
1249c18ec02fSPetter Reinholdtsen 	struct ipmi_rs      * rsp = NULL;
1250c18ec02fSPetter Reinholdtsen 	uint8_t             * msg;
1251c18ec02fSPetter Reinholdtsen 	int                   len;
1252c18ec02fSPetter Reinholdtsen 	int                   try = 0;
1253c18ec02fSPetter Reinholdtsen 
1254c18ec02fSPetter Reinholdtsen 	if (intf->opened == 0 && intf->open != NULL) {
1255c18ec02fSPetter Reinholdtsen 		if (intf->open(intf) < 0)
1256c18ec02fSPetter Reinholdtsen 			return NULL;
1257c18ec02fSPetter Reinholdtsen 	}
1258c18ec02fSPetter Reinholdtsen 
1259c18ec02fSPetter Reinholdtsen 	msg = ipmi_lan_build_sol_msg(intf, payload, &len);
1260c18ec02fSPetter Reinholdtsen 	if (len <= 0 || msg == NULL) {
1261c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Invalid SOL payload packet");
1262c18ec02fSPetter Reinholdtsen 		if (msg != NULL) {
1263c18ec02fSPetter Reinholdtsen 			free(msg);
1264c18ec02fSPetter Reinholdtsen 			msg = NULL;
1265c18ec02fSPetter Reinholdtsen 		}
1266c18ec02fSPetter Reinholdtsen 		return NULL;
1267c18ec02fSPetter Reinholdtsen 	}
1268c18ec02fSPetter Reinholdtsen 
1269c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, ">> SENDING A SOL MESSAGE\n");
1270c18ec02fSPetter Reinholdtsen 
1271c18ec02fSPetter Reinholdtsen 	for (;;) {
1272c18ec02fSPetter Reinholdtsen 		if (ipmi_lan_send_packet(intf, msg, len) < 0) {
1273c18ec02fSPetter Reinholdtsen 			try++;
1274c18ec02fSPetter Reinholdtsen 			usleep(5000);
1275c18ec02fSPetter Reinholdtsen 			continue;
1276c18ec02fSPetter Reinholdtsen 		}
1277c18ec02fSPetter Reinholdtsen 
1278c18ec02fSPetter Reinholdtsen 		/* if we are set to noanswer we do not expect response */
1279c18ec02fSPetter Reinholdtsen 		if (intf->noanswer)
1280c18ec02fSPetter Reinholdtsen 			break;
1281c18ec02fSPetter Reinholdtsen 
1282c18ec02fSPetter Reinholdtsen 		if (payload->payload.sol_packet.packet_sequence_number == 0) {
1283c18ec02fSPetter Reinholdtsen 			/* We're just sending an ACK.  No need to retry. */
1284c18ec02fSPetter Reinholdtsen 			break;
1285c18ec02fSPetter Reinholdtsen 		}
1286c18ec02fSPetter Reinholdtsen 
1287c18ec02fSPetter Reinholdtsen 		usleep(100);
1288c18ec02fSPetter Reinholdtsen 
1289c18ec02fSPetter Reinholdtsen 		rsp = ipmi_lan_recv_sol(intf); /* Grab the next packet */
1290c18ec02fSPetter Reinholdtsen 
1291c18ec02fSPetter Reinholdtsen 		if (sol_response_acks_packet(rsp, payload))
1292c18ec02fSPetter Reinholdtsen 			break;
1293c18ec02fSPetter Reinholdtsen 
1294c18ec02fSPetter Reinholdtsen 		else if (is_sol_packet(rsp) && rsp->data_len)
1295c18ec02fSPetter Reinholdtsen 		{
1296c18ec02fSPetter Reinholdtsen 			/*
1297c18ec02fSPetter Reinholdtsen 			 * We're still waiting for our ACK, but we more data from
1298c18ec02fSPetter Reinholdtsen 			 * the BMC
1299c18ec02fSPetter Reinholdtsen 			 */
1300c18ec02fSPetter Reinholdtsen 			intf->session->sol_data.sol_input_handler(rsp);
1301c18ec02fSPetter Reinholdtsen 		}
1302c18ec02fSPetter Reinholdtsen 
1303c18ec02fSPetter Reinholdtsen 		usleep(5000);
1304c18ec02fSPetter Reinholdtsen 		if (++try >= intf->session->retry) {
1305c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "  No response from remote controller");
1306c18ec02fSPetter Reinholdtsen 			break;
1307c18ec02fSPetter Reinholdtsen 		}
1308c18ec02fSPetter Reinholdtsen 	}
1309c18ec02fSPetter Reinholdtsen 
1310c18ec02fSPetter Reinholdtsen 	if (msg != NULL) {
1311c18ec02fSPetter Reinholdtsen 		free(msg);
1312c18ec02fSPetter Reinholdtsen 		msg = NULL;
1313c18ec02fSPetter Reinholdtsen 	}
1314c18ec02fSPetter Reinholdtsen 	return rsp;
1315c18ec02fSPetter Reinholdtsen }
1316c18ec02fSPetter Reinholdtsen 
1317c18ec02fSPetter Reinholdtsen /*
1318c18ec02fSPetter Reinholdtsen  * is_sol_partial_ack
1319c18ec02fSPetter Reinholdtsen  *
1320c18ec02fSPetter Reinholdtsen  * Determine if the response is a partial ACK/NACK that indicates
1321c18ec02fSPetter Reinholdtsen  * we need to resend part of our packet.
1322c18ec02fSPetter Reinholdtsen  *
1323c18ec02fSPetter Reinholdtsen  * returns the number of characters we need to resend, or
1324c18ec02fSPetter Reinholdtsen  *         0 if this isn't an ACK or we don't need to resend anything
1325c18ec02fSPetter Reinholdtsen  */
1326c18ec02fSPetter Reinholdtsen static int is_sol_partial_ack(struct ipmi_v2_payload * v2_payload,
1327c18ec02fSPetter Reinholdtsen 			      struct ipmi_rs         * rsp)
1328c18ec02fSPetter Reinholdtsen {
1329c18ec02fSPetter Reinholdtsen 	int chars_to_resend = 0;
1330c18ec02fSPetter Reinholdtsen 
1331c18ec02fSPetter Reinholdtsen 	if (v2_payload                                &&
1332c18ec02fSPetter Reinholdtsen 	    rsp                                       &&
1333c18ec02fSPetter Reinholdtsen 	    is_sol_packet(rsp)                        &&
1334c18ec02fSPetter Reinholdtsen 	    sol_response_acks_packet(rsp, v2_payload) &&
1335c18ec02fSPetter Reinholdtsen 	    (rsp->payload.sol_packet.accepted_character_count <
1336c18ec02fSPetter Reinholdtsen 	     v2_payload->payload.sol_packet.character_count))
1337c18ec02fSPetter Reinholdtsen 	{
1338c18ec02fSPetter Reinholdtsen 		if (rsp->payload.sol_packet.accepted_character_count == 0) {
1339c18ec02fSPetter Reinholdtsen 			/* We should not resend data */
1340c18ec02fSPetter Reinholdtsen 			chars_to_resend = 0;
1341c18ec02fSPetter Reinholdtsen 		}
1342c18ec02fSPetter Reinholdtsen 		else
1343c18ec02fSPetter Reinholdtsen 		{
1344c18ec02fSPetter Reinholdtsen 			chars_to_resend =
1345c18ec02fSPetter Reinholdtsen 				v2_payload->payload.sol_packet.character_count -
1346c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.accepted_character_count;
1347c18ec02fSPetter Reinholdtsen 		}
1348c18ec02fSPetter Reinholdtsen 	}
1349c18ec02fSPetter Reinholdtsen 
1350c18ec02fSPetter Reinholdtsen 	return chars_to_resend;
1351c18ec02fSPetter Reinholdtsen }
1352c18ec02fSPetter Reinholdtsen 
1353c18ec02fSPetter Reinholdtsen /*
1354c18ec02fSPetter Reinholdtsen  * set_sol_packet_sequence_number
1355c18ec02fSPetter Reinholdtsen  */
1356c18ec02fSPetter Reinholdtsen static void set_sol_packet_sequence_number(struct ipmi_intf * intf,
1357c18ec02fSPetter Reinholdtsen 					   struct ipmi_v2_payload * v2_payload)
1358c18ec02fSPetter Reinholdtsen {
1359c18ec02fSPetter Reinholdtsen 	/* Keep our sequence number sane */
1360c18ec02fSPetter Reinholdtsen 	if (intf->session->sol_data.sequence_number > 0x0F)
1361c18ec02fSPetter Reinholdtsen 		intf->session->sol_data.sequence_number = 1;
1362c18ec02fSPetter Reinholdtsen 
1363c18ec02fSPetter Reinholdtsen 	v2_payload->payload.sol_packet.packet_sequence_number =
1364c18ec02fSPetter Reinholdtsen 		intf->session->sol_data.sequence_number++;
1365c18ec02fSPetter Reinholdtsen }
1366c18ec02fSPetter Reinholdtsen 
1367c18ec02fSPetter Reinholdtsen /*
1368c18ec02fSPetter Reinholdtsen  * ipmi_lan_send_sol
1369c18ec02fSPetter Reinholdtsen  *
1370c18ec02fSPetter Reinholdtsen  * Sends a SOL packet..  We handle partial ACK/NACKs from the BMC here.
1371c18ec02fSPetter Reinholdtsen  *
1372c18ec02fSPetter Reinholdtsen  * Returns a pointer to the SOL ACK we received, or
1373c18ec02fSPetter Reinholdtsen  *         0 on failure
1374c18ec02fSPetter Reinholdtsen  *
1375c18ec02fSPetter Reinholdtsen  */
1376c18ec02fSPetter Reinholdtsen struct ipmi_rs *
1377c18ec02fSPetter Reinholdtsen ipmi_lan_send_sol(struct ipmi_intf * intf,
1378c18ec02fSPetter Reinholdtsen 		  struct ipmi_v2_payload * v2_payload)
1379c18ec02fSPetter Reinholdtsen {
1380c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
1381c18ec02fSPetter Reinholdtsen 	int chars_to_resend = 0;
1382c18ec02fSPetter Reinholdtsen 
1383c18ec02fSPetter Reinholdtsen 	v2_payload->payload_type   = IPMI_PAYLOAD_TYPE_SOL;
1384c18ec02fSPetter Reinholdtsen 
1385c18ec02fSPetter Reinholdtsen 	/*
1386c18ec02fSPetter Reinholdtsen 	 * Payload length is just the length of the character
1387c18ec02fSPetter Reinholdtsen 	 * data here.
1388c18ec02fSPetter Reinholdtsen 	 */
1389c18ec02fSPetter Reinholdtsen 	v2_payload->payload.sol_packet.acked_packet_number = 0; /* NA */
1390c18ec02fSPetter Reinholdtsen 
1391c18ec02fSPetter Reinholdtsen 	set_sol_packet_sequence_number(intf, v2_payload);
1392c18ec02fSPetter Reinholdtsen 
1393c18ec02fSPetter Reinholdtsen 	v2_payload->payload.sol_packet.accepted_character_count = 0; /* NA */
1394c18ec02fSPetter Reinholdtsen 
1395c18ec02fSPetter Reinholdtsen 	rsp = ipmi_lan_send_sol_payload(intf, v2_payload);
1396c18ec02fSPetter Reinholdtsen 
1397c18ec02fSPetter Reinholdtsen 	/* Determine if we need to resend some of our data */
1398c18ec02fSPetter Reinholdtsen 	chars_to_resend = is_sol_partial_ack(v2_payload, rsp);
1399c18ec02fSPetter Reinholdtsen 
1400c18ec02fSPetter Reinholdtsen 	while (chars_to_resend)
1401c18ec02fSPetter Reinholdtsen 	{
1402c18ec02fSPetter Reinholdtsen 		/*
1403c18ec02fSPetter Reinholdtsen 		 * We first need to handle any new data we might have
1404c18ec02fSPetter Reinholdtsen 		 * received in our NACK
1405c18ec02fSPetter Reinholdtsen 		 */
1406c18ec02fSPetter Reinholdtsen 		if (rsp->data_len)
1407c18ec02fSPetter Reinholdtsen 			intf->session->sol_data.sol_input_handler(rsp);
1408c18ec02fSPetter Reinholdtsen 
1409c18ec02fSPetter Reinholdtsen 		set_sol_packet_sequence_number(intf, v2_payload);
1410c18ec02fSPetter Reinholdtsen 
1411c18ec02fSPetter Reinholdtsen 		/* Just send the required data */
1412c18ec02fSPetter Reinholdtsen 		memmove(v2_payload->payload.sol_packet.data,
1413c18ec02fSPetter Reinholdtsen 			v2_payload->payload.sol_packet.data +
1414c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.accepted_character_count,
1415c18ec02fSPetter Reinholdtsen 			chars_to_resend);
1416c18ec02fSPetter Reinholdtsen 
1417c18ec02fSPetter Reinholdtsen 		v2_payload->payload.sol_packet.character_count = chars_to_resend;
1418c18ec02fSPetter Reinholdtsen 
1419c18ec02fSPetter Reinholdtsen 		rsp = ipmi_lan_send_sol_payload(intf, v2_payload);
1420c18ec02fSPetter Reinholdtsen 
1421c18ec02fSPetter Reinholdtsen 		chars_to_resend = is_sol_partial_ack(v2_payload, rsp);
1422c18ec02fSPetter Reinholdtsen 	}
1423c18ec02fSPetter Reinholdtsen 
1424c18ec02fSPetter Reinholdtsen 	return rsp;
1425c18ec02fSPetter Reinholdtsen }
1426c18ec02fSPetter Reinholdtsen 
1427c18ec02fSPetter Reinholdtsen /*
1428c18ec02fSPetter Reinholdtsen  * check_sol_packet_for_new_data
1429c18ec02fSPetter Reinholdtsen  *
1430c18ec02fSPetter Reinholdtsen  * Determine whether the SOL packet has already been seen
1431c18ec02fSPetter Reinholdtsen  * and whether the packet has new data for us.
1432c18ec02fSPetter Reinholdtsen  *
1433c18ec02fSPetter Reinholdtsen  * This function has the side effect of removing an previously
1434c18ec02fSPetter Reinholdtsen  * seen data, and moving new data to the front.
1435c18ec02fSPetter Reinholdtsen  *
1436c18ec02fSPetter Reinholdtsen  * It also "Remembers" the data so we don't get repeats.
1437c18ec02fSPetter Reinholdtsen  *
1438c18ec02fSPetter Reinholdtsen  */
1439c18ec02fSPetter Reinholdtsen static int
1440c18ec02fSPetter Reinholdtsen check_sol_packet_for_new_data(struct ipmi_intf * intf,
1441c18ec02fSPetter Reinholdtsen 			      struct ipmi_rs *rsp)
1442c18ec02fSPetter Reinholdtsen {
1443c18ec02fSPetter Reinholdtsen 	static uint8_t last_received_sequence_number = 0;
1444c18ec02fSPetter Reinholdtsen 	static uint8_t last_received_byte_count      = 0;
1445c18ec02fSPetter Reinholdtsen 	int new_data_size                            = 0;
1446c18ec02fSPetter Reinholdtsen 
1447c18ec02fSPetter Reinholdtsen 	if (rsp &&
1448c18ec02fSPetter Reinholdtsen 	    (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
1449c18ec02fSPetter Reinholdtsen 
1450c18ec02fSPetter Reinholdtsen 	{
1451c18ec02fSPetter Reinholdtsen 		uint8_t unaltered_data_len = rsp->data_len;
1452c18ec02fSPetter Reinholdtsen 		if (rsp->payload.sol_packet.packet_sequence_number ==
1453c18ec02fSPetter Reinholdtsen 		    last_received_sequence_number)
1454c18ec02fSPetter Reinholdtsen 		{
1455c18ec02fSPetter Reinholdtsen 			/*
1456c18ec02fSPetter Reinholdtsen 			 * This is the same as the last packet, but may include
1457c18ec02fSPetter Reinholdtsen 			 * extra data
1458c18ec02fSPetter Reinholdtsen 			 */
1459c18ec02fSPetter Reinholdtsen 			new_data_size = rsp->data_len - last_received_byte_count;
1460c18ec02fSPetter Reinholdtsen 
1461c18ec02fSPetter Reinholdtsen 			if (new_data_size > 0)
1462c18ec02fSPetter Reinholdtsen 			{
1463c18ec02fSPetter Reinholdtsen 				/* We have more data to process */
1464c18ec02fSPetter Reinholdtsen 				memmove(rsp->data,
1465c18ec02fSPetter Reinholdtsen 					rsp->data +
1466c18ec02fSPetter Reinholdtsen 					rsp->data_len - new_data_size,
1467c18ec02fSPetter Reinholdtsen 					new_data_size);
1468c18ec02fSPetter Reinholdtsen 			}
1469c18ec02fSPetter Reinholdtsen 
1470c18ec02fSPetter Reinholdtsen 			rsp->data_len = new_data_size;
1471c18ec02fSPetter Reinholdtsen 		}
1472c18ec02fSPetter Reinholdtsen 
1473c18ec02fSPetter Reinholdtsen 		/*
1474c18ec02fSPetter Reinholdtsen 		 *Rember the data for next round
1475c18ec02fSPetter Reinholdtsen 		 */
1476c18ec02fSPetter Reinholdtsen 		if (rsp && rsp->payload.sol_packet.packet_sequence_number)
1477c18ec02fSPetter Reinholdtsen 		{
1478c18ec02fSPetter Reinholdtsen 			last_received_sequence_number =
1479c18ec02fSPetter Reinholdtsen 				rsp->payload.sol_packet.packet_sequence_number;
1480c18ec02fSPetter Reinholdtsen 			last_received_byte_count = unaltered_data_len;
1481c18ec02fSPetter Reinholdtsen 		}
1482c18ec02fSPetter Reinholdtsen 	}
1483c18ec02fSPetter Reinholdtsen 
1484c18ec02fSPetter Reinholdtsen 	return new_data_size;
1485c18ec02fSPetter Reinholdtsen }
1486c18ec02fSPetter Reinholdtsen 
1487c18ec02fSPetter Reinholdtsen /*
1488c18ec02fSPetter Reinholdtsen  * ack_sol_packet
1489c18ec02fSPetter Reinholdtsen  *
1490c18ec02fSPetter Reinholdtsen  * Provided the specified packet looks reasonable, ACK it.
1491c18ec02fSPetter Reinholdtsen  */
1492c18ec02fSPetter Reinholdtsen static void
1493c18ec02fSPetter Reinholdtsen ack_sol_packet(struct ipmi_intf * intf,
1494c18ec02fSPetter Reinholdtsen 	       struct ipmi_rs * rsp)
1495c18ec02fSPetter Reinholdtsen {
1496c18ec02fSPetter Reinholdtsen 	if (rsp &&
1497c18ec02fSPetter Reinholdtsen 	    (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) &&
1498c18ec02fSPetter Reinholdtsen 	    (rsp->payload.sol_packet.packet_sequence_number))
1499c18ec02fSPetter Reinholdtsen 	{
1500c18ec02fSPetter Reinholdtsen 		struct ipmi_v2_payload ack;
1501c18ec02fSPetter Reinholdtsen 
1502c18ec02fSPetter Reinholdtsen 		memset(&ack, 0, sizeof(struct ipmi_v2_payload));
1503c18ec02fSPetter Reinholdtsen 
1504c18ec02fSPetter Reinholdtsen 		ack.payload_type = IPMI_PAYLOAD_TYPE_SOL;
1505c18ec02fSPetter Reinholdtsen 
1506c18ec02fSPetter Reinholdtsen 		/*
1507c18ec02fSPetter Reinholdtsen 		 * Payload length is just the length of the character
1508c18ec02fSPetter Reinholdtsen 		 * data here.
1509c18ec02fSPetter Reinholdtsen 		 */
1510c18ec02fSPetter Reinholdtsen 		ack.payload_length = 0;
1511c18ec02fSPetter Reinholdtsen 
1512c18ec02fSPetter Reinholdtsen 		/* ACK packets have sequence numbers of 0 */
1513c18ec02fSPetter Reinholdtsen 		ack.payload.sol_packet.packet_sequence_number = 0;
1514c18ec02fSPetter Reinholdtsen 
1515c18ec02fSPetter Reinholdtsen 		ack.payload.sol_packet.acked_packet_number =
1516c18ec02fSPetter Reinholdtsen 			rsp->payload.sol_packet.packet_sequence_number;
1517c18ec02fSPetter Reinholdtsen 
1518c18ec02fSPetter Reinholdtsen 		ack.payload.sol_packet.accepted_character_count = rsp->data_len;
1519c18ec02fSPetter Reinholdtsen 
1520c18ec02fSPetter Reinholdtsen 		ipmi_lan_send_sol_payload(intf, &ack);
1521c18ec02fSPetter Reinholdtsen 	}
1522c18ec02fSPetter Reinholdtsen }
1523c18ec02fSPetter Reinholdtsen 
1524c18ec02fSPetter Reinholdtsen /*
1525c18ec02fSPetter Reinholdtsen  * ipmi_recv_sol
1526c18ec02fSPetter Reinholdtsen  *
1527c18ec02fSPetter Reinholdtsen  * Receive a SOL packet and send an ACK in response.
1528c18ec02fSPetter Reinholdtsen  *
1529c18ec02fSPetter Reinholdtsen  */
1530c18ec02fSPetter Reinholdtsen static struct ipmi_rs *
1531c18ec02fSPetter Reinholdtsen ipmi_lan_recv_sol(struct ipmi_intf * intf)
1532c18ec02fSPetter Reinholdtsen {
1533c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp = ipmi_lan_poll_recv(intf);
1534c18ec02fSPetter Reinholdtsen 
1535c18ec02fSPetter Reinholdtsen 	ack_sol_packet(intf, rsp);
1536c18ec02fSPetter Reinholdtsen 
1537c18ec02fSPetter Reinholdtsen 	/*
1538c18ec02fSPetter Reinholdtsen 	 * Remembers the data sent, and alters the data to just
1539c18ec02fSPetter Reinholdtsen 	 * include the new stuff.
1540c18ec02fSPetter Reinholdtsen 	 */
1541c18ec02fSPetter Reinholdtsen 	check_sol_packet_for_new_data(intf, rsp);
1542c18ec02fSPetter Reinholdtsen 
1543c18ec02fSPetter Reinholdtsen 	return rsp;
1544c18ec02fSPetter Reinholdtsen }
1545c18ec02fSPetter Reinholdtsen 
1546c18ec02fSPetter Reinholdtsen /* send a get device id command to keep session active */
1547c18ec02fSPetter Reinholdtsen static int
1548c18ec02fSPetter Reinholdtsen ipmi_lan_keepalive(struct ipmi_intf * intf)
1549c18ec02fSPetter Reinholdtsen {
1550c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
1551c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req = { msg: {
1552c18ec02fSPetter Reinholdtsen 		netfn: IPMI_NETFN_APP,
1553c18ec02fSPetter Reinholdtsen 		cmd: 1,
1554c18ec02fSPetter Reinholdtsen 	}};
1555c18ec02fSPetter Reinholdtsen 
1556c18ec02fSPetter Reinholdtsen 	if (!intf->opened)
1557c18ec02fSPetter Reinholdtsen 		return 0;
1558c18ec02fSPetter Reinholdtsen 
1559c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
1560c18ec02fSPetter Reinholdtsen 	if (rsp == NULL)
1561c18ec02fSPetter Reinholdtsen 		return -1;
1562c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0)
1563c18ec02fSPetter Reinholdtsen 		return -1;
1564c18ec02fSPetter Reinholdtsen 
1565c18ec02fSPetter Reinholdtsen 	return 0;
1566c18ec02fSPetter Reinholdtsen }
1567c18ec02fSPetter Reinholdtsen 
1568c18ec02fSPetter Reinholdtsen /*
1569c18ec02fSPetter Reinholdtsen  * IPMI Get Channel Authentication Capabilities Command
1570c18ec02fSPetter Reinholdtsen  */
1571c18ec02fSPetter Reinholdtsen static int
1572c18ec02fSPetter Reinholdtsen ipmi_get_auth_capabilities_cmd(struct ipmi_intf * intf)
1573c18ec02fSPetter Reinholdtsen {
1574c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
1575c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
1576c18ec02fSPetter Reinholdtsen 	struct ipmi_session * s = intf->session;
1577c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[2];
1578c18ec02fSPetter Reinholdtsen 
1579c18ec02fSPetter Reinholdtsen 	msg_data[0] = IPMI_LAN_CHANNEL_E;
1580c18ec02fSPetter Reinholdtsen 	msg_data[1] = s->privlvl;
1581c18ec02fSPetter Reinholdtsen 
1582c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
1583c18ec02fSPetter Reinholdtsen 	req.msg.netfn    = IPMI_NETFN_APP;
1584c18ec02fSPetter Reinholdtsen 	req.msg.cmd      = 0x38;
1585c18ec02fSPetter Reinholdtsen 	req.msg.data     = msg_data;
1586c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 2;
1587c18ec02fSPetter Reinholdtsen 
1588c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
1589c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
1590c18ec02fSPetter Reinholdtsen 		lprintf(LOG_INFO, "Get Auth Capabilities command failed");
1591c18ec02fSPetter Reinholdtsen 		return -1;
1592c18ec02fSPetter Reinholdtsen 	}
1593c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
1594c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "get_auth_capabilities");
1595c18ec02fSPetter Reinholdtsen 
1596c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
1597c18ec02fSPetter Reinholdtsen 		lprintf(LOG_INFO, "Get Auth Capabilities command failed: %s",
1598c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
1599c18ec02fSPetter Reinholdtsen 		return -1;
1600c18ec02fSPetter Reinholdtsen 	}
1601c18ec02fSPetter Reinholdtsen 
1602c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Channel %02x Authentication Capabilities:",
1603c18ec02fSPetter Reinholdtsen 		rsp->data[0]);
1604c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Privilege Level : %s",
1605c18ec02fSPetter Reinholdtsen 		val2str(req.msg.data[1], ipmi_privlvl_vals));
1606c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Auth Types      : %s%s%s%s%s",
1607c18ec02fSPetter Reinholdtsen 		(rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "",
1608c18ec02fSPetter Reinholdtsen 		(rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "",
1609c18ec02fSPetter Reinholdtsen 		(rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "",
1610c18ec02fSPetter Reinholdtsen 		(rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "",
1611c18ec02fSPetter Reinholdtsen 		(rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : "");
1612c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Per-msg auth    : %sabled",
1613c18ec02fSPetter Reinholdtsen 		(rsp->data[2] & IPMI_AUTHSTATUS_PER_MSG_DISABLED) ?
1614c18ec02fSPetter Reinholdtsen 		"dis" : "en");
1615c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  User level auth : %sabled",
1616c18ec02fSPetter Reinholdtsen 		(rsp->data[2] & IPMI_AUTHSTATUS_PER_USER_DISABLED) ?
1617c18ec02fSPetter Reinholdtsen 		"dis" : "en");
1618c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Non-null users  : %sabled",
1619c18ec02fSPetter Reinholdtsen 		(rsp->data[2] & IPMI_AUTHSTATUS_NONNULL_USERS_ENABLED) ?
1620c18ec02fSPetter Reinholdtsen 		"en" : "dis");
1621c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Null users      : %sabled",
1622c18ec02fSPetter Reinholdtsen 		(rsp->data[2] & IPMI_AUTHSTATUS_NULL_USERS_ENABLED) ?
1623c18ec02fSPetter Reinholdtsen 		"en" : "dis");
1624c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Anonymous login : %sabled",
1625c18ec02fSPetter Reinholdtsen 		(rsp->data[2] & IPMI_AUTHSTATUS_ANONYMOUS_USERS_ENABLED) ?
1626c18ec02fSPetter Reinholdtsen 		"en" : "dis");
1627c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "");
1628c18ec02fSPetter Reinholdtsen 
1629c18ec02fSPetter Reinholdtsen 	s->authstatus = rsp->data[2];
1630c18ec02fSPetter Reinholdtsen 
1631c18ec02fSPetter Reinholdtsen 	if (s->password &&
1632c18ec02fSPetter Reinholdtsen 	    (s->authtype_set == 0 ||
1633c18ec02fSPetter Reinholdtsen 	     s->authtype_set == IPMI_SESSION_AUTHTYPE_MD5) &&
1634c18ec02fSPetter Reinholdtsen 	    (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD5))
1635c18ec02fSPetter Reinholdtsen 	{
1636c18ec02fSPetter Reinholdtsen 		s->authtype = IPMI_SESSION_AUTHTYPE_MD5;
1637c18ec02fSPetter Reinholdtsen 	}
1638c18ec02fSPetter Reinholdtsen 	else if (s->password &&
1639c18ec02fSPetter Reinholdtsen 		 (s->authtype_set == 0 ||
1640c18ec02fSPetter Reinholdtsen 		  s->authtype_set == IPMI_SESSION_AUTHTYPE_MD2) &&
1641c18ec02fSPetter Reinholdtsen 		 (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD2))
1642c18ec02fSPetter Reinholdtsen 	{
1643c18ec02fSPetter Reinholdtsen 		s->authtype = IPMI_SESSION_AUTHTYPE_MD2;
1644c18ec02fSPetter Reinholdtsen 	}
1645c18ec02fSPetter Reinholdtsen 	else if (s->password &&
1646c18ec02fSPetter Reinholdtsen 		 (s->authtype_set == 0 ||
1647c18ec02fSPetter Reinholdtsen 		  s->authtype_set == IPMI_SESSION_AUTHTYPE_PASSWORD) &&
1648c18ec02fSPetter Reinholdtsen 		 (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD))
1649c18ec02fSPetter Reinholdtsen 	{
1650c18ec02fSPetter Reinholdtsen 		s->authtype = IPMI_SESSION_AUTHTYPE_PASSWORD;
1651c18ec02fSPetter Reinholdtsen 	}
1652c18ec02fSPetter Reinholdtsen 	else if (s->password &&
1653c18ec02fSPetter Reinholdtsen 		 (s->authtype_set == 0 ||
1654c18ec02fSPetter Reinholdtsen 		  s->authtype_set == IPMI_SESSION_AUTHTYPE_OEM) &&
1655c18ec02fSPetter Reinholdtsen 		 (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_OEM))
1656c18ec02fSPetter Reinholdtsen 	{
1657c18ec02fSPetter Reinholdtsen 		s->authtype = IPMI_SESSION_AUTHTYPE_OEM;
1658c18ec02fSPetter Reinholdtsen 	}
1659c18ec02fSPetter Reinholdtsen 	else if ((s->authtype_set == 0 ||
1660c18ec02fSPetter Reinholdtsen 		  s->authtype_set == IPMI_SESSION_AUTHTYPE_NONE) &&
1661c18ec02fSPetter Reinholdtsen 		 (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_NONE))
1662c18ec02fSPetter Reinholdtsen 	{
1663c18ec02fSPetter Reinholdtsen 		s->authtype = IPMI_SESSION_AUTHTYPE_NONE;
1664c18ec02fSPetter Reinholdtsen 	}
1665c18ec02fSPetter Reinholdtsen 	else {
1666c18ec02fSPetter Reinholdtsen 		if (!(rsp->data[1] & 1<<s->authtype_set))
1667c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Authentication type %s not supported",
1668c18ec02fSPetter Reinholdtsen 			       val2str(s->authtype_set, ipmi_authtype_session_vals));
1669c18ec02fSPetter Reinholdtsen 		else
1670c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "No supported authtypes found");
1671c18ec02fSPetter Reinholdtsen 
1672c18ec02fSPetter Reinholdtsen 		return -1;
1673c18ec02fSPetter Reinholdtsen 	}
1674c18ec02fSPetter Reinholdtsen 
1675c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Proceeding with AuthType %s",
1676c18ec02fSPetter Reinholdtsen 		val2str(s->authtype, ipmi_authtype_session_vals));
1677c18ec02fSPetter Reinholdtsen 
1678c18ec02fSPetter Reinholdtsen 	return 0;
1679c18ec02fSPetter Reinholdtsen }
1680c18ec02fSPetter Reinholdtsen 
1681c18ec02fSPetter Reinholdtsen /*
1682c18ec02fSPetter Reinholdtsen  * IPMI Get Session Challenge Command
1683c18ec02fSPetter Reinholdtsen  * returns a temporary session ID and 16 byte challenge string
1684c18ec02fSPetter Reinholdtsen  */
1685c18ec02fSPetter Reinholdtsen static int
1686c18ec02fSPetter Reinholdtsen ipmi_get_session_challenge_cmd(struct ipmi_intf * intf)
1687c18ec02fSPetter Reinholdtsen {
1688c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
1689c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
1690c18ec02fSPetter Reinholdtsen 	struct ipmi_session * s = intf->session;
1691c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[17];
1692c18ec02fSPetter Reinholdtsen 
1693c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 17);
1694c18ec02fSPetter Reinholdtsen 	msg_data[0] = s->authtype;
1695c18ec02fSPetter Reinholdtsen 	memcpy(msg_data+1, s->username, 16);
1696c18ec02fSPetter Reinholdtsen 
1697c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
1698c18ec02fSPetter Reinholdtsen 	req.msg.netfn		= IPMI_NETFN_APP;
1699c18ec02fSPetter Reinholdtsen 	req.msg.cmd		= 0x39;
1700c18ec02fSPetter Reinholdtsen 	req.msg.data		= msg_data;
1701c18ec02fSPetter Reinholdtsen 	req.msg.data_len	= 17; /* 1 byte for authtype, 16 for user */
1702c18ec02fSPetter Reinholdtsen 
1703c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
1704c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
1705c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Get Session Challenge command failed");
1706c18ec02fSPetter Reinholdtsen 		return -1;
1707c18ec02fSPetter Reinholdtsen 	}
1708c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
1709c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "get_session_challenge");
1710c18ec02fSPetter Reinholdtsen 
1711c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
1712c18ec02fSPetter Reinholdtsen 		switch (rsp->ccode) {
1713c18ec02fSPetter Reinholdtsen 		case 0x81:
1714c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Invalid user name");
1715c18ec02fSPetter Reinholdtsen 			break;
1716c18ec02fSPetter Reinholdtsen 		case 0x82:
1717c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "NULL user name not enabled");
1718c18ec02fSPetter Reinholdtsen 			break;
1719c18ec02fSPetter Reinholdtsen 		default:
1720c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Get Session Challenge command failed: %s",
1721c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
1722c18ec02fSPetter Reinholdtsen 		}
1723c18ec02fSPetter Reinholdtsen 		return -1;
1724c18ec02fSPetter Reinholdtsen 	}
1725c18ec02fSPetter Reinholdtsen 
1726c18ec02fSPetter Reinholdtsen 	memcpy(&s->session_id, rsp->data, 4);
1727c18ec02fSPetter Reinholdtsen 	memcpy(s->challenge, rsp->data + 4, 16);
1728c18ec02fSPetter Reinholdtsen 
1729c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Opening Session");
1730c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Session ID      : %08lx", (long)s->session_id);
1731c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Challenge       : %s", buf2str(s->challenge, 16));
1732c18ec02fSPetter Reinholdtsen 
1733c18ec02fSPetter Reinholdtsen 	return 0;
1734c18ec02fSPetter Reinholdtsen }
1735c18ec02fSPetter Reinholdtsen 
1736c18ec02fSPetter Reinholdtsen /*
1737c18ec02fSPetter Reinholdtsen  * IPMI Activate Session Command
1738c18ec02fSPetter Reinholdtsen  */
1739c18ec02fSPetter Reinholdtsen static int
1740c18ec02fSPetter Reinholdtsen ipmi_activate_session_cmd(struct ipmi_intf * intf)
1741c18ec02fSPetter Reinholdtsen {
1742c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
1743c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
1744c18ec02fSPetter Reinholdtsen 	struct ipmi_session * s = intf->session;
1745c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[22];
1746c18ec02fSPetter Reinholdtsen 
1747c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
1748c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_APP;
1749c18ec02fSPetter Reinholdtsen 	req.msg.cmd = 0x3a;
1750c18ec02fSPetter Reinholdtsen 
1751c18ec02fSPetter Reinholdtsen 	msg_data[0] = s->authtype;
1752c18ec02fSPetter Reinholdtsen 	msg_data[1] = s->privlvl;
1753c18ec02fSPetter Reinholdtsen 
1754c18ec02fSPetter Reinholdtsen 	/* supermicro oem authentication hack */
1755c18ec02fSPetter Reinholdtsen 	if (ipmi_oem_active(intf, "supermicro")) {
1756c18ec02fSPetter Reinholdtsen 		uint8_t * special = ipmi_auth_special(s);
1757c18ec02fSPetter Reinholdtsen 		memcpy(s->authcode, special, 16);
1758c18ec02fSPetter Reinholdtsen 		memset(msg_data + 2, 0, 16);
1759c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "  OEM Auth        : %s",
1760c18ec02fSPetter Reinholdtsen 			buf2str(special, 16));
1761c18ec02fSPetter Reinholdtsen 	} else {
1762c18ec02fSPetter Reinholdtsen 		memcpy(msg_data + 2, s->challenge, 16);
1763c18ec02fSPetter Reinholdtsen 	}
1764c18ec02fSPetter Reinholdtsen 
1765c18ec02fSPetter Reinholdtsen 	/* setup initial outbound sequence number */
1766c18ec02fSPetter Reinholdtsen 	get_random(msg_data+18, 4);
1767c18ec02fSPetter Reinholdtsen 
1768c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
1769c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 22;
1770c18ec02fSPetter Reinholdtsen 
1771c18ec02fSPetter Reinholdtsen 	s->active = 1;
1772c18ec02fSPetter Reinholdtsen 
1773c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Privilege Level : %s",
1774c18ec02fSPetter Reinholdtsen 		val2str(msg_data[1], ipmi_privlvl_vals));
1775c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Auth Type       : %s",
1776c18ec02fSPetter Reinholdtsen 		val2str(s->authtype, ipmi_authtype_session_vals));
1777c18ec02fSPetter Reinholdtsen 
1778c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
1779c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
1780c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Activate Session command failed");
1781c18ec02fSPetter Reinholdtsen 		s->active = 0;
1782c18ec02fSPetter Reinholdtsen 		return -1;
1783c18ec02fSPetter Reinholdtsen 	}
1784c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
1785c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "activate_session");
1786c18ec02fSPetter Reinholdtsen 
1787c18ec02fSPetter Reinholdtsen 	if (rsp->ccode) {
1788c18ec02fSPetter Reinholdtsen 		fprintf(stderr, "Activate Session error:");
1789c18ec02fSPetter Reinholdtsen 		switch (rsp->ccode) {
1790c18ec02fSPetter Reinholdtsen 		case 0x81:
1791c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "\tNo session slot available");
1792c18ec02fSPetter Reinholdtsen 			break;
1793c18ec02fSPetter Reinholdtsen 		case 0x82:
1794c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "\tNo slot available for given user - "
1795c18ec02fSPetter Reinholdtsen 				"limit reached");
1796c18ec02fSPetter Reinholdtsen 			break;
1797c18ec02fSPetter Reinholdtsen 		case 0x83:
1798c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "\tNo slot available to support user "
1799c18ec02fSPetter Reinholdtsen 				"due to maximum privilege capacity");
1800c18ec02fSPetter Reinholdtsen 			break;
1801c18ec02fSPetter Reinholdtsen 		case 0x84:
1802c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "\tSession sequence out of range");
1803c18ec02fSPetter Reinholdtsen 			break;
1804c18ec02fSPetter Reinholdtsen 		case 0x85:
1805c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "\tInvalid session ID in request");
1806c18ec02fSPetter Reinholdtsen 			break;
1807c18ec02fSPetter Reinholdtsen 		case 0x86:
1808c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "\tRequested privilege level "
1809c18ec02fSPetter Reinholdtsen 				"exceeds limit");
1810c18ec02fSPetter Reinholdtsen 			break;
1811c18ec02fSPetter Reinholdtsen 		case 0xd4:
1812c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "\tInsufficient privilege level");
1813c18ec02fSPetter Reinholdtsen 			break;
1814c18ec02fSPetter Reinholdtsen 		default:
1815c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "\t%s",
1816c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
1817c18ec02fSPetter Reinholdtsen 		}
1818c18ec02fSPetter Reinholdtsen 		return -1;
1819c18ec02fSPetter Reinholdtsen 	}
1820c18ec02fSPetter Reinholdtsen 
1821c18ec02fSPetter Reinholdtsen 	memcpy(&s->session_id, rsp->data + 1, 4);
1822c18ec02fSPetter Reinholdtsen 	s->in_seq = rsp->data[8] << 24 | rsp->data[7] << 16 | rsp->data[6] << 8 | rsp->data[5];
1823c18ec02fSPetter Reinholdtsen 	if (s->in_seq == 0)
1824c18ec02fSPetter Reinholdtsen 		++s->in_seq;
1825c18ec02fSPetter Reinholdtsen 
1826c18ec02fSPetter Reinholdtsen 	if (s->authstatus & IPMI_AUTHSTATUS_PER_MSG_DISABLED)
1827c18ec02fSPetter Reinholdtsen 		s->authtype = IPMI_SESSION_AUTHTYPE_NONE;
1828c18ec02fSPetter Reinholdtsen 	else if (s->authtype != (rsp->data[0] & 0xf)) {
1829c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Invalid Session AuthType %s in response",
1830c18ec02fSPetter Reinholdtsen 			val2str(s->authtype, ipmi_authtype_session_vals));
1831c18ec02fSPetter Reinholdtsen 		return -1;
1832c18ec02fSPetter Reinholdtsen 	}
1833c18ec02fSPetter Reinholdtsen 
1834c18ec02fSPetter Reinholdtsen 	bridge_possible = 1;
1835c18ec02fSPetter Reinholdtsen 
1836c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "\nSession Activated");
1837c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Auth Type       : %s",
1838c18ec02fSPetter Reinholdtsen 		val2str(rsp->data[0], ipmi_authtype_session_vals));
1839c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Max Priv Level  : %s",
1840c18ec02fSPetter Reinholdtsen 		val2str(rsp->data[9], ipmi_privlvl_vals));
1841c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Session ID      : %08lx", (long)s->session_id);
1842c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "  Inbound Seq     : %08lx\n", (long)s->in_seq);
1843c18ec02fSPetter Reinholdtsen 
1844c18ec02fSPetter Reinholdtsen 	return 0;
1845c18ec02fSPetter Reinholdtsen }
1846c18ec02fSPetter Reinholdtsen 
1847c18ec02fSPetter Reinholdtsen 
1848c18ec02fSPetter Reinholdtsen /*
1849c18ec02fSPetter Reinholdtsen  * IPMI Set Session Privilege Level Command
1850c18ec02fSPetter Reinholdtsen  */
1851c18ec02fSPetter Reinholdtsen static int
1852c18ec02fSPetter Reinholdtsen ipmi_set_session_privlvl_cmd(struct ipmi_intf * intf)
1853c18ec02fSPetter Reinholdtsen {
1854c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
1855c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
1856c18ec02fSPetter Reinholdtsen 	uint8_t privlvl = intf->session->privlvl;
1857c18ec02fSPetter Reinholdtsen 	uint8_t backup_bridge_possible = bridge_possible;
1858c18ec02fSPetter Reinholdtsen 
1859c18ec02fSPetter Reinholdtsen 	if (privlvl <= IPMI_SESSION_PRIV_USER)
1860c18ec02fSPetter Reinholdtsen 		return 0;	/* no need to set higher */
1861c18ec02fSPetter Reinholdtsen 
1862c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
1863c18ec02fSPetter Reinholdtsen 	req.msg.netfn		= IPMI_NETFN_APP;
1864c18ec02fSPetter Reinholdtsen 	req.msg.cmd		= 0x3b;
1865c18ec02fSPetter Reinholdtsen 	req.msg.data		= &privlvl;
1866c18ec02fSPetter Reinholdtsen 	req.msg.data_len	= 1;
1867c18ec02fSPetter Reinholdtsen 
1868c18ec02fSPetter Reinholdtsen 	bridge_possible = 0;
1869c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
1870c18ec02fSPetter Reinholdtsen 	bridge_possible = backup_bridge_possible;
1871c18ec02fSPetter Reinholdtsen 
1872c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
1873c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Set Session Privilege Level to %s failed",
1874c18ec02fSPetter Reinholdtsen 			val2str(privlvl, ipmi_privlvl_vals));
1875c18ec02fSPetter Reinholdtsen 		return -1;
1876c18ec02fSPetter Reinholdtsen 	}
1877c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
1878c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "set_session_privlvl");
1879c18ec02fSPetter Reinholdtsen 
1880c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
1881c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Set Session Privilege Level to %s failed: %s",
1882c18ec02fSPetter Reinholdtsen 			val2str(privlvl, ipmi_privlvl_vals),
1883c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
1884c18ec02fSPetter Reinholdtsen 		return -1;
1885c18ec02fSPetter Reinholdtsen 	}
1886c18ec02fSPetter Reinholdtsen 
1887c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Set Session Privilege Level to %s\n",
1888c18ec02fSPetter Reinholdtsen 		val2str(rsp->data[0], ipmi_privlvl_vals));
1889c18ec02fSPetter Reinholdtsen 
1890c18ec02fSPetter Reinholdtsen 	return 0;
1891c18ec02fSPetter Reinholdtsen }
1892c18ec02fSPetter Reinholdtsen 
1893c18ec02fSPetter Reinholdtsen static int
1894c18ec02fSPetter Reinholdtsen ipmi_close_session_cmd(struct ipmi_intf * intf)
1895c18ec02fSPetter Reinholdtsen {
1896c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
1897c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
1898c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
1899c18ec02fSPetter Reinholdtsen 	uint32_t session_id = intf->session->session_id;
1900c18ec02fSPetter Reinholdtsen 
1901c18ec02fSPetter Reinholdtsen 	if (intf->session->active == 0)
1902c18ec02fSPetter Reinholdtsen 		return -1;
1903c18ec02fSPetter Reinholdtsen 
1904c18ec02fSPetter Reinholdtsen 	intf->target_addr = IPMI_BMC_SLAVE_ADDR;
1905c18ec02fSPetter Reinholdtsen 	bridge_possible = 0;  /* Not a bridge message */
1906c18ec02fSPetter Reinholdtsen 
1907c18ec02fSPetter Reinholdtsen 	memcpy(&msg_data, &session_id, 4);
1908c18ec02fSPetter Reinholdtsen 
1909c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
1910c18ec02fSPetter Reinholdtsen 	req.msg.netfn		= IPMI_NETFN_APP;
1911c18ec02fSPetter Reinholdtsen 	req.msg.cmd		= 0x3c;
1912c18ec02fSPetter Reinholdtsen 	req.msg.data		= msg_data;
1913c18ec02fSPetter Reinholdtsen 	req.msg.data_len	= 4;
1914c18ec02fSPetter Reinholdtsen 
1915c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
1916c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
1917c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Close Session command failed");
1918c18ec02fSPetter Reinholdtsen 		return -1;
1919c18ec02fSPetter Reinholdtsen 	}
1920c18ec02fSPetter Reinholdtsen 	if (verbose > 2)
1921c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "close_session");
1922c18ec02fSPetter Reinholdtsen 
1923c18ec02fSPetter Reinholdtsen 	if (rsp->ccode == 0x87) {
1924c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Failed to Close Session: invalid "
1925c18ec02fSPetter Reinholdtsen 			"session ID %08lx", (long)session_id);
1926c18ec02fSPetter Reinholdtsen 		return -1;
1927c18ec02fSPetter Reinholdtsen 	}
1928c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
1929c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Close Session command failed: %s",
1930c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
1931c18ec02fSPetter Reinholdtsen 		return -1;
1932c18ec02fSPetter Reinholdtsen 	}
1933c18ec02fSPetter Reinholdtsen 
1934c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Closed Session %08lx\n", (long)session_id);
1935c18ec02fSPetter Reinholdtsen 
1936c18ec02fSPetter Reinholdtsen 	return 0;
1937c18ec02fSPetter Reinholdtsen }
1938c18ec02fSPetter Reinholdtsen 
1939c18ec02fSPetter Reinholdtsen /*
1940c18ec02fSPetter Reinholdtsen  * IPMI LAN Session Activation (IPMI spec v1.5 section 12.9)
1941c18ec02fSPetter Reinholdtsen  *
1942c18ec02fSPetter Reinholdtsen  * 1. send "RMCP Presence Ping" message, response message will
1943c18ec02fSPetter Reinholdtsen  *    indicate whether the platform supports IPMI
1944c18ec02fSPetter Reinholdtsen  * 2. send "Get Channel Authentication Capabilities" command
1945c18ec02fSPetter Reinholdtsen  *    with AUTHTYPE = none, response packet will contain information
1946c18ec02fSPetter Reinholdtsen  *    about supported challenge/response authentication types
1947c18ec02fSPetter Reinholdtsen  * 3. send "Get Session Challenge" command with AUTHTYPE = none
1948c18ec02fSPetter Reinholdtsen  *    and indicate the authentication type in the message, response
1949c18ec02fSPetter Reinholdtsen  *    packet will contain challenge string and temporary session ID.
1950c18ec02fSPetter Reinholdtsen  * 4. send "Activate Session" command, authenticated with AUTHTYPE
1951c18ec02fSPetter Reinholdtsen  *    sent in previous message.  Also sends the initial value for
1952c18ec02fSPetter Reinholdtsen  *    the outbound sequence number for BMC.
1953c18ec02fSPetter Reinholdtsen  * 5. BMC returns response confirming session activation and
1954c18ec02fSPetter Reinholdtsen  *    session ID for this session and initial inbound sequence.
1955c18ec02fSPetter Reinholdtsen  */
1956c18ec02fSPetter Reinholdtsen static int
1957c18ec02fSPetter Reinholdtsen ipmi_lan_activate_session(struct ipmi_intf * intf)
1958c18ec02fSPetter Reinholdtsen {
1959c18ec02fSPetter Reinholdtsen 	int rc;
1960c18ec02fSPetter Reinholdtsen 
1961c18ec02fSPetter Reinholdtsen 	/* don't fail on ping because its not always supported.
1962c18ec02fSPetter Reinholdtsen 	 * Supermicro's IPMI LAN 1.5 cards don't tolerate pings.
1963c18ec02fSPetter Reinholdtsen 	 */
1964c18ec02fSPetter Reinholdtsen 	if (!ipmi_oem_active(intf, "supermicro"))
1965c18ec02fSPetter Reinholdtsen 		ipmi_lan_ping(intf);
1966c18ec02fSPetter Reinholdtsen 
1967c18ec02fSPetter Reinholdtsen 	/* Some particular Intel boards need special help
1968c18ec02fSPetter Reinholdtsen 	 */
1969c18ec02fSPetter Reinholdtsen 	if (ipmi_oem_active(intf, "intelwv2"))
1970c18ec02fSPetter Reinholdtsen 		ipmi_lan_thump_first(intf);
1971c18ec02fSPetter Reinholdtsen 
1972c18ec02fSPetter Reinholdtsen 	rc = ipmi_get_auth_capabilities_cmd(intf);
1973c18ec02fSPetter Reinholdtsen 	if (rc < 0) {
1974c18ec02fSPetter Reinholdtsen 		goto fail;
1975c18ec02fSPetter Reinholdtsen 	}
1976c18ec02fSPetter Reinholdtsen 
1977c18ec02fSPetter Reinholdtsen 	rc = ipmi_get_session_challenge_cmd(intf);
1978c18ec02fSPetter Reinholdtsen 	if (rc < 0)
1979c18ec02fSPetter Reinholdtsen 		goto fail;
1980c18ec02fSPetter Reinholdtsen 
1981c18ec02fSPetter Reinholdtsen 	rc = ipmi_activate_session_cmd(intf);
1982c18ec02fSPetter Reinholdtsen 	if (rc < 0)
1983c18ec02fSPetter Reinholdtsen 		goto fail;
1984c18ec02fSPetter Reinholdtsen 
1985c18ec02fSPetter Reinholdtsen 	intf->abort = 0;
1986c18ec02fSPetter Reinholdtsen 
1987c18ec02fSPetter Reinholdtsen 	rc = ipmi_set_session_privlvl_cmd(intf);
1988c18ec02fSPetter Reinholdtsen 	if (rc < 0)
1989c18ec02fSPetter Reinholdtsen 		goto fail;
1990c18ec02fSPetter Reinholdtsen 
1991c18ec02fSPetter Reinholdtsen 	return 0;
1992c18ec02fSPetter Reinholdtsen 
1993c18ec02fSPetter Reinholdtsen  fail:
1994c18ec02fSPetter Reinholdtsen 	lprintf(LOG_ERR, "Error: Unable to establish LAN session");
1995c18ec02fSPetter Reinholdtsen 	return -1;
1996c18ec02fSPetter Reinholdtsen }
1997c18ec02fSPetter Reinholdtsen 
1998c18ec02fSPetter Reinholdtsen static void
1999c18ec02fSPetter Reinholdtsen ipmi_lan_close(struct ipmi_intf * intf)
2000c18ec02fSPetter Reinholdtsen {
2001c18ec02fSPetter Reinholdtsen 	if (intf->abort == 0)
2002c18ec02fSPetter Reinholdtsen 		ipmi_close_session_cmd(intf);
2003c18ec02fSPetter Reinholdtsen 
2004c18ec02fSPetter Reinholdtsen 	if (intf->fd >= 0)
2005c18ec02fSPetter Reinholdtsen 		close(intf->fd);
2006c18ec02fSPetter Reinholdtsen 
2007c18ec02fSPetter Reinholdtsen 	ipmi_req_clear_entries();
2008*deb9a4edSZdenek Styblik 	ipmi_intf_session_cleanup(intf);
2009c18ec02fSPetter Reinholdtsen 	intf->opened = 0;
2010c18ec02fSPetter Reinholdtsen 	intf->manufacturer_id = IPMI_OEM_UNKNOWN;
2011c18ec02fSPetter Reinholdtsen 	intf = NULL;
2012c18ec02fSPetter Reinholdtsen }
2013c18ec02fSPetter Reinholdtsen 
2014c18ec02fSPetter Reinholdtsen static int
2015c18ec02fSPetter Reinholdtsen ipmi_lan_open(struct ipmi_intf * intf)
2016c18ec02fSPetter Reinholdtsen {
2017c18ec02fSPetter Reinholdtsen 	int rc;
2018c18ec02fSPetter Reinholdtsen 	struct ipmi_session *s;
2019c18ec02fSPetter Reinholdtsen 
2020c18ec02fSPetter Reinholdtsen 	if (intf == NULL || intf->session == NULL)
2021c18ec02fSPetter Reinholdtsen 		return -1;
2022c18ec02fSPetter Reinholdtsen 	s = intf->session;
2023c18ec02fSPetter Reinholdtsen 
2024c18ec02fSPetter Reinholdtsen 	if (s->port == 0)
2025c18ec02fSPetter Reinholdtsen 		s->port = IPMI_LAN_PORT;
2026c18ec02fSPetter Reinholdtsen 	if (s->privlvl == 0)
2027c18ec02fSPetter Reinholdtsen 		s->privlvl = IPMI_SESSION_PRIV_ADMIN;
2028c18ec02fSPetter Reinholdtsen 	if (s->timeout == 0)
2029c18ec02fSPetter Reinholdtsen 		s->timeout = IPMI_LAN_TIMEOUT;
2030c18ec02fSPetter Reinholdtsen 	if (s->retry == 0)
2031c18ec02fSPetter Reinholdtsen 		s->retry = IPMI_LAN_RETRY;
2032c18ec02fSPetter Reinholdtsen 
2033c18ec02fSPetter Reinholdtsen 	if (s->hostname == NULL || strlen((const char *)s->hostname) == 0) {
2034c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "No hostname specified!");
2035c18ec02fSPetter Reinholdtsen 		return -1;
2036c18ec02fSPetter Reinholdtsen 	}
2037c18ec02fSPetter Reinholdtsen 
2038c18ec02fSPetter Reinholdtsen 	intf->abort = 1;
2039c18ec02fSPetter Reinholdtsen 
2040c18ec02fSPetter Reinholdtsen 	intf->session->sol_data.sequence_number = 1;
2041c18ec02fSPetter Reinholdtsen 
2042c18ec02fSPetter Reinholdtsen 	if (ipmi_intf_socket_connect (intf) == -1) {
2043c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Could not open socket!");
2044c18ec02fSPetter Reinholdtsen 		return -1;
2045c18ec02fSPetter Reinholdtsen 	}
2046c18ec02fSPetter Reinholdtsen 
2047c18ec02fSPetter Reinholdtsen 	if (intf->fd < 0) {
2048c18ec02fSPetter Reinholdtsen 		lperror(LOG_ERR, "Connect to %s failed",
2049c18ec02fSPetter Reinholdtsen 			s->hostname);
2050c18ec02fSPetter Reinholdtsen 		intf->close(intf);
2051c18ec02fSPetter Reinholdtsen 		return -1;
2052c18ec02fSPetter Reinholdtsen 	}
2053c18ec02fSPetter Reinholdtsen 
2054c18ec02fSPetter Reinholdtsen 	intf->opened = 1;
2055c18ec02fSPetter Reinholdtsen 
2056c18ec02fSPetter Reinholdtsen 	/* try to open session */
2057c18ec02fSPetter Reinholdtsen 	rc = ipmi_lan_activate_session(intf);
2058c18ec02fSPetter Reinholdtsen 	if (rc < 0) {
2059c18ec02fSPetter Reinholdtsen 		intf->close(intf);
2060c18ec02fSPetter Reinholdtsen 		intf->opened = 0;
2061c18ec02fSPetter Reinholdtsen 		return -1;
2062c18ec02fSPetter Reinholdtsen 	}
2063c18ec02fSPetter Reinholdtsen 
2064c18ec02fSPetter Reinholdtsen 	intf->manufacturer_id = ipmi_get_oem(intf);
206523e9340bSZdenek Styblik 
206623e9340bSZdenek Styblik 	/* automatically detect interface request and response sizes */
206723e9340bSZdenek Styblik 	hpm2_detect_max_payload_size(intf);
206823e9340bSZdenek Styblik 
2069c18ec02fSPetter Reinholdtsen 	return intf->fd;
2070c18ec02fSPetter Reinholdtsen }
2071c18ec02fSPetter Reinholdtsen 
2072c18ec02fSPetter Reinholdtsen static int
2073c18ec02fSPetter Reinholdtsen ipmi_lan_setup(struct ipmi_intf * intf)
2074c18ec02fSPetter Reinholdtsen {
2075c18ec02fSPetter Reinholdtsen 	intf->session = malloc(sizeof(struct ipmi_session));
2076c18ec02fSPetter Reinholdtsen 	if (intf->session == NULL) {
2077c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
2078c18ec02fSPetter Reinholdtsen 		return -1;
2079c18ec02fSPetter Reinholdtsen 	}
2080c18ec02fSPetter Reinholdtsen 	memset(intf->session, 0, sizeof(struct ipmi_session));
208123e9340bSZdenek Styblik 
208223e9340bSZdenek Styblik 	/* setup default LAN maximum request and response sizes */
208323e9340bSZdenek Styblik 	intf->max_request_data_size = IPMI_LAN_MAX_REQUEST_SIZE;
208423e9340bSZdenek Styblik 	intf->max_response_data_size = IPMI_LAN_MAX_RESPONSE_SIZE;
208523e9340bSZdenek Styblik 
2086c18ec02fSPetter Reinholdtsen 	return 0;
2087c18ec02fSPetter Reinholdtsen }
208823e9340bSZdenek Styblik 
208923e9340bSZdenek Styblik static void
209023e9340bSZdenek Styblik ipmi_lan_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size)
209123e9340bSZdenek Styblik {
209223e9340bSZdenek Styblik 	if (size + 7 > 0xFF) {
209323e9340bSZdenek Styblik 		size = 0xFF - 7;
209423e9340bSZdenek Styblik 	}
209523e9340bSZdenek Styblik 
209623e9340bSZdenek Styblik 	intf->max_request_data_size = size;
209723e9340bSZdenek Styblik }
209823e9340bSZdenek Styblik 
209923e9340bSZdenek Styblik static void
210023e9340bSZdenek Styblik ipmi_lan_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size)
210123e9340bSZdenek Styblik {
210223e9340bSZdenek Styblik 	if (size + 8 > 0xFF) {
210323e9340bSZdenek Styblik 		size = 0xFF - 8;
210423e9340bSZdenek Styblik 	}
210523e9340bSZdenek Styblik 
210623e9340bSZdenek Styblik 	intf->max_response_data_size = size;
210723e9340bSZdenek Styblik }
2108