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