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