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