4
* MontaVista IPMI code for handling IPMI-specific data formatting
6
* Author: MontaVista Software, Inc.
7
* Corey Minyard <minyard@mvista.com>
10
* Copyright 2002,2003,2004 MontaVista Software Inc.
12
* This program is free software; you can redistribute it and/or
13
* modify it under the terms of the GNU Lesser General Public License
14
* as published by the Free Software Foundation; either version 2 of
15
* the License, or (at your option) any later version.
18
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
* You should have received a copy of the GNU Lesser General Public
30
* License along with this program; if not, write to the Free
31
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36
#include <OpenIPMI/ipmi_lan.h>
37
#include <OpenIPMI/ipmi_err.h>
38
#include <OpenIPMI/ipmi_addr.h>
39
#include <OpenIPMI/ipmi_conn.h>
40
#include <OpenIPMI/ipmi_msgbits.h>
41
#include <OpenIPMI/ipmi_debug.h>
42
#include <OpenIPMI/internal/ipmi_int.h>
44
#if defined(DEBUG_MSG) || defined(DEBUG_RAWMSG)
46
dump_hex(void *vdata, int len)
48
unsigned char *data = vdata;
50
for (i=0; i<len; i++) {
51
if ((i != 0) && ((i % 16) == 0)) {
52
ipmi_log(IPMI_LOG_DEBUG_CONT, "\n ");
54
ipmi_log(IPMI_LOG_DEBUG_CONT, " %2.2x", data[i]);
60
ipmb_checksum(unsigned char *data, int size)
62
unsigned char csum = 0;
64
for (; size > 0; size--, data++)
71
ipmi_format_msg(ipmi_con_t *ipmi,
73
unsigned int addr_len,
75
unsigned char *out_data,
76
unsigned int *out_data_len,
80
unsigned char *tmsg = out_data;
84
if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
85
/* It's a message straight to the BMC. */
86
ipmi_system_interface_addr_t *si_addr
87
= (ipmi_system_interface_addr_t *) addr;
89
if ((msg->data_len + 7) > *out_data_len)
91
if (ipmi->hacks & IPMI_CONN_HACK_20_AS_MAIN_ADDR)
94
tmsg[0] = ipmi->ipmb_addr; /* To the BMC. */
95
tmsg[1] = (msg->netfn << 2) | si_addr->lun;
96
tmsg[2] = ipmb_checksum(tmsg, 2);
97
tmsg[3] = 0x81; /* Remote console IPMI Software ID */
100
memcpy(tmsg+6, msg->data, msg->data_len);
101
pos = msg->data_len + 6;
102
tmsg[pos] = ipmb_checksum(tmsg+3, pos-3);
105
/* It's an IPMB address, route it using a send message
107
ipmi_ipmb_addr_t *ipmb_addr = (ipmi_ipmb_addr_t *) addr;
108
int do_broadcast = 0;
110
if ((addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
111
&& (!ipmi->broadcast_broken))
116
if ((msg->data_len + 15 + do_broadcast) > *out_data_len)
120
if (ipmi->hacks & IPMI_CONN_HACK_20_AS_MAIN_ADDR)
123
tmsg[pos++] = ipmi->ipmb_addr; /* BMC is the bridge. */
124
tmsg[pos++] = (IPMI_APP_NETFN << 2) | 0;
125
tmsg[pos++] = ipmb_checksum(tmsg, 2);
126
tmsg[pos++] = 0x81; /* Remote console IPMI Software ID */
127
tmsg[pos++] = (seq << 2) | 0; /* LUN is zero */
128
tmsg[pos++] = IPMI_SEND_MSG_CMD;
129
tmsg[pos++] = ((ipmb_addr->channel & 0xf)
130
| (1 << 6)); /* Turn on tracking. */
132
tmsg[pos++] = 0; /* Do a broadcast. */
134
tmsg[pos++] = ipmb_addr->slave_addr;
135
tmsg[pos++] = (msg->netfn << 2) | ipmb_addr->lun;
136
tmsg[pos++] = ipmb_checksum(tmsg+msgstart, 2);
138
tmsg[pos++] = ipmi->ipmb_addr;
139
tmsg[pos++] = (seq << 2) | 2; /* add 2 as the SMS LUN */
140
tmsg[pos++] = msg->cmd;
141
memcpy(tmsg+pos, msg->data, msg->data_len);
142
pos += msg->data_len;
143
tmsg[pos] = ipmb_checksum(tmsg+msgstart, pos-msgstart);
145
tmsg[pos] = ipmb_checksum(tmsg+3, pos-3);
154
ipmi_get_recv_seq(ipmi_con_t *ipmi,
156
unsigned int data_len,
159
if (data_len < 8) { /* Minimum size of an IPMI msg. */
160
if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
161
ipmi_log(IPMI_LOG_DEBUG,
162
"Dropped message because too small(6)");
166
if ((data[5] == IPMI_READ_EVENT_MSG_BUFFER_CMD)
167
&& ((data[1] >> 2) == (IPMI_APP_NETFN | 1)))
169
/* An async event has no seq #, handle async. */
178
ipmi_handle_recv(ipmi_con_t *ipmi,
180
ipmi_addr_t *orig_addr,
181
unsigned int orig_addr_len,
182
ipmi_msg_t *orig_msg,
184
unsigned int data_len)
186
ipmi_msg_t *msg = &(rspi->msg);
187
ipmi_addr_t *addr = &(rspi->addr);
189
unsigned int addr_len;
191
unsigned char *tmsg = data;
193
if (data_len < 8) { /* Minimum size of an IPMI msg. */
194
if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
195
ipmi_log(IPMI_LOG_DEBUG,
196
"Dropped message because too small(6)");
200
/* We don't check the checksums, because the network layer should
201
validate all this for us. */
205
if ((tmsg[5] == IPMI_SEND_MSG_CMD)
206
&& ((tmsg[1] >> 2) == (IPMI_APP_NETFN | 1)))
208
/* It's a response to a sent message. */
209
ipmi_ipmb_addr_t *ipmb_addr = (ipmi_ipmb_addr_t *) addr;
210
ipmi_ipmb_addr_t *ipmb2 = (ipmi_ipmb_addr_t *) orig_addr;
212
/* FIXME - this entire thing is a cheap hack. */
214
/* Got an error from the send message. We don't have any
215
IPMB information to work with, so just extract it from
216
the original message. */
217
memcpy(ipmb_addr, ipmb2, sizeof(*ipmb_addr));
218
/* Just in case it's a broadcast. */
219
ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
220
addr_len = sizeof(ipmi_ipmb_addr_t);
221
msg->netfn = orig_msg->netfn | 1;
222
msg->cmd = orig_msg->cmd;
223
msg->data = tmsg + 6;
225
if (ipmi->handle_send_rsp_err) {
226
ipmi->handle_send_rsp_err(ipmi, msg);
230
/* The response to a send message was not carrying the
234
if (tmsg[10] == ipmi->ipmb_addr) {
235
ipmi_system_interface_addr_t *si_addr
236
= (ipmi_system_interface_addr_t *) addr;
238
/* It's directly from the BMC, so it's a system interface
240
si_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
241
si_addr->channel = 0xf;
242
si_addr->lun = tmsg[11] & 3;
244
/* This is a hack, but the channel does not come back in the
245
message. So we use the channel from the original
247
ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
248
ipmb_addr->channel = ipmb2->channel;
249
ipmb_addr->slave_addr = tmsg[10];
250
ipmb_addr->lun = tmsg[11] & 0x3;
252
msg->netfn = tmsg[8] >> 2;
254
addr_len = sizeof(ipmi_ipmb_addr_t);
256
msg->data_len = data_len - 15;
258
} else if ((orig_addr->addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
259
&& (((ipmi->hacks & IPMI_CONN_HACK_20_AS_MAIN_ADDR)
260
&& (tmsg[3] == 0x20))
261
|| ((! (ipmi->hacks & IPMI_CONN_HACK_20_AS_MAIN_ADDR))
262
&& (tmsg[3] == ipmi->ipmb_addr))))
264
/* In some cases, a message from the IPMB looks like it came
265
from the BMC itself, IMHO a misinterpretation of the
266
errata. IPMIv1_5_rev1_1_0926 markup, section 6.12.4,
267
didn't clear things up at all. Some manufacturers have
268
interpreted it this way, but IMHO it is incorrect. */
269
memcpy(addr, orig_addr, orig_addr_len);
270
addr_len = orig_addr_len;
271
if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
272
addr->addr_type = IPMI_IPMB_ADDR_TYPE;
273
msg->netfn = tmsg[1] >> 2;
276
msg->data_len = data_len - 7;
278
/* It's not encapsulated in a send message response. */
280
if (((ipmi->hacks & IPMI_CONN_HACK_20_AS_MAIN_ADDR)
281
&& (tmsg[3] == 0x20))
282
|| ((!(ipmi->hacks & IPMI_CONN_HACK_20_AS_MAIN_ADDR))
283
&& (tmsg[3] == ipmi->ipmb_addr)))
285
ipmi_system_interface_addr_t *si_addr
286
= (ipmi_system_interface_addr_t *) addr;
288
/* It's directly from the BMC, so it's a system interface
290
si_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
291
si_addr->channel = 0xf;
292
si_addr->lun = tmsg[4] & 3;
294
ipmi_ipmb_addr_t *ipmb_addr = (ipmi_ipmb_addr_t *) addr;
295
ipmi_ipmb_addr_t *ipmb2 = (ipmi_ipmb_addr_t *) orig_addr;
297
/* A message from the IPMB. */
298
ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
299
/* This is a hack, but the channel does not come back in the
300
message. So we use the channel from the original
302
ipmb_addr->channel = ipmb2->channel;
303
ipmb_addr->slave_addr = tmsg[3];
304
ipmb_addr->lun = tmsg[4] & 0x3;
307
msg->netfn = tmsg[1] >> 2;
309
addr_len = sizeof(ipmi_system_interface_addr_t);
311
msg->data_len = data_len - 6;
312
msg->data_len--; /* Remove the checksum */
315
/* Convert broadcast addresses to regular IPMB addresses, since
316
they come back that way. */
317
memcpy(&addr2, orig_addr, orig_addr_len);
318
if (addr2.addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
319
addr2.addr_type = IPMI_IPMB_ADDR_TYPE;
321
/* Validate that this response if for this command. */
322
if (((orig_msg->netfn | 1) != msg->netfn)
323
|| (orig_msg->cmd != msg->cmd)
324
|| (! ipmi_addr_equal(&addr2, orig_addr_len, addr, addr_len)))
326
if (DEBUG_RAWMSG || DEBUG_MSG_ERR) {
327
ipmi_log(IPMI_LOG_DEBUG_START,
328
"Dropped message seq %d - netfn/cmd/addr mismatch\n"
329
" netfn = %2.2x, exp netfn = %2.2x\n"
330
" cmd = %2.2x, exp cmd = %2.2x\n"
333
msg->netfn, orig_msg->netfn | 1,
334
msg->cmd, orig_msg->cmd);
335
dump_hex(addr, addr_len);
336
ipmi_log(IPMI_LOG_DEBUG_CONT,
338
dump_hex(&addr2, orig_addr_len);
340
ipmi_log(IPMI_LOG_DEBUG_CONT, "\n data =\n ");
341
dump_hex(tmsg, data_len);
343
dump_hex(addr, addr_len);
344
ipmi_log(IPMI_LOG_DEBUG_END, " ");
349
rspi->addr_len = addr_len;
350
memcpy(rspi->data, msg->data, msg->data_len);
351
msg->data = rspi->data;
354
char buf1[32], buf2[32], buf3[32];
355
ipmi_log(IPMI_LOG_DEBUG_START, "incoming msg from IPMB addr =");
356
dump_hex((unsigned char *) addr, addr_len);
357
ipmi_log(IPMI_LOG_DEBUG_CONT,
358
"\n msg = netfn=%s cmd=%s data_len=%d. cc=%s",
359
ipmi_get_netfn_string(msg->netfn, buf1, 32),
360
ipmi_get_command_string(msg->netfn, msg->cmd, buf2, 32),
362
ipmi_get_cc_string(msg->data[0], buf3, 32));
364
ipmi_log(IPMI_LOG_DEBUG_CONT, "\n data =\n ");
365
dump_hex(msg->data, msg->data_len);
367
ipmi_log(IPMI_LOG_DEBUG_END, " ");
374
ipmi_handle_recv_async(ipmi_con_t *ipmi,
376
unsigned int data_len)
379
unsigned int addr_len;
382
if ((tmsg[5] == IPMI_READ_EVENT_MSG_BUFFER_CMD)
383
&& ((tmsg[1] >> 2) == (IPMI_APP_NETFN | 1)))
385
/* It is an event from the event buffer. */
386
ipmi_system_interface_addr_t *si_addr
387
= (ipmi_system_interface_addr_t *) &addr;
390
/* An error getting the events, just ignore it. */
391
if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
392
ipmi_log(IPMI_LOG_DEBUG, "Dropped message err getting event");
396
si_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
397
si_addr->channel = 0xf;
398
si_addr->lun = tmsg[4] & 3;
400
msg.netfn = tmsg[1] >> 2;
402
addr_len = sizeof(ipmi_system_interface_addr_t);
404
msg.data_len = data_len - 6;
406
char buf1[32], buf2[32], buf3[32];
407
ipmi_log(IPMI_LOG_DEBUG_START, "incoming async event\n addr =");
408
dump_hex((unsigned char *) &addr, addr_len);
409
ipmi_log(IPMI_LOG_DEBUG_CONT,
410
"\n msg = netfn=%s cmd=%s data_len=%d. cc=%s",
411
ipmi_get_netfn_string(msg.netfn, buf1, 32),
412
ipmi_get_command_string(msg.netfn, msg.cmd, buf2, 32),
414
ipmi_get_cc_string(msg.data[0], buf3, 32));
416
ipmi_log(IPMI_LOG_DEBUG_CONT, "\n data(len=%d.) =\n ",
418
dump_hex(msg.data, msg.data_len);
420
ipmi_log(IPMI_LOG_DEBUG_END, " ");
422
if (ipmi->handle_async_event)
423
ipmi->handle_async_event(ipmi, &addr, addr_len, &msg);
425
ipmi_log(IPMI_LOG_SEVERE, "ipmi_lan.c(ipmi_handle_recv_async): "
426
"Got an invalid async event, shouldn't happen");
430
ipmi_payload_t _ipmi_payload =
431
{ ipmi_format_msg, ipmi_get_recv_seq, ipmi_handle_recv,
432
ipmi_handle_recv_async };