1283bfb4dSEric Schrock /* 2283bfb4dSEric Schrock * CDDL HEADER START 3283bfb4dSEric Schrock * 4283bfb4dSEric Schrock * The contents of this file are subject to the terms of the 5283bfb4dSEric Schrock * Common Development and Distribution License (the "License"). 6283bfb4dSEric Schrock * You may not use this file except in compliance with the License. 7283bfb4dSEric Schrock * 8283bfb4dSEric Schrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9283bfb4dSEric Schrock * or http://www.opensolaris.org/os/licensing. 10283bfb4dSEric Schrock * See the License for the specific language governing permissions 11283bfb4dSEric Schrock * and limitations under the License. 12283bfb4dSEric Schrock * 13283bfb4dSEric Schrock * When distributing Covered Code, include this CDDL HEADER in each 14283bfb4dSEric Schrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15283bfb4dSEric Schrock * If applicable, add the following below this CDDL HEADER, with the 16283bfb4dSEric Schrock * fields enclosed by brackets "[]" replaced with your own identifying 17283bfb4dSEric Schrock * information: Portions Copyright [yyyy] [name of copyright owner] 18283bfb4dSEric Schrock * 19283bfb4dSEric Schrock * CDDL HEADER END 20283bfb4dSEric Schrock */ 21283bfb4dSEric Schrock /* 22*81d9f076SRobert Johnston * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23283bfb4dSEric Schrock * Use is subject to license terms. 24283bfb4dSEric Schrock */ 25283bfb4dSEric Schrock 26*81d9f076SRobert Johnston #include <stdlib.h> 27*81d9f076SRobert Johnston #include <stdio.h> 28*81d9f076SRobert Johnston #include <assert.h> 29*81d9f076SRobert Johnston #include <inttypes.h> 30*81d9f076SRobert Johnston #include <string.h> 31*81d9f076SRobert Johnston #include <sys/types.h> 32*81d9f076SRobert Johnston #include <sys/socket.h> 33*81d9f076SRobert Johnston #include <netinet/in.h> 34*81d9f076SRobert Johnston #include <arpa/inet.h> 35*81d9f076SRobert Johnston #include <errno.h> 36*81d9f076SRobert Johnston #include <unistd.h> 37*81d9f076SRobert Johnston #include <netdb.h> 38*81d9f076SRobert Johnston #include <fcntl.h> 39283bfb4dSEric Schrock 40*81d9f076SRobert Johnston #include "libipmi.h" 41*81d9f076SRobert Johnston #include "ipmi_lan.h" 42283bfb4dSEric Schrock #include "ipmi_impl.h" 43283bfb4dSEric Schrock 44*81d9f076SRobert Johnston #define DEF_IPMI_LAN_TIMEOUT 3 /* seconds */ 45*81d9f076SRobert Johnston #define DEF_IPMI_LAN_NUM_RETRIES 5 46*81d9f076SRobert Johnston #define IPMI_LAN_CHANNEL_E 0x0e 47283bfb4dSEric Schrock 48*81d9f076SRobert Johnston typedef struct ipmi_rs { 49*81d9f076SRobert Johnston uint8_t ir_data[IPMI_BUF_SIZE]; 50*81d9f076SRobert Johnston int ir_dlen; 51*81d9f076SRobert Johnston ipmi_msg_hdr_t ir_ihdr; 52*81d9f076SRobert Johnston uint8_t ir_ccode; 53*81d9f076SRobert Johnston } ipmi_rs_t; 54283bfb4dSEric Schrock 55*81d9f076SRobert Johnston static ipmi_rs_t *ipmi_lan_poll_recv(ipmi_handle_t *); 56283bfb4dSEric Schrock 57*81d9f076SRobert Johnston typedef struct ipmi_rq_entry { 58*81d9f076SRobert Johnston ipmi_list_t ire_list; 59*81d9f076SRobert Johnston ipmi_cmd_t ire_req; 60*81d9f076SRobert Johnston uint8_t ire_target_cmd; 61*81d9f076SRobert Johnston uint8_t ire_rq_seq; 62*81d9f076SRobert Johnston uint8_t *ire_msg_data; 63*81d9f076SRobert Johnston int ire_msg_len; 64*81d9f076SRobert Johnston } ipmi_rq_entry_t; 65283bfb4dSEric Schrock 66*81d9f076SRobert Johnston ipmi_rq_entry_t *ipmi_req_entries = NULL; 67283bfb4dSEric Schrock 68*81d9f076SRobert Johnston /* 69*81d9f076SRobert Johnston * LAN transport-specific data 70*81d9f076SRobert Johnston */ 71*81d9f076SRobert Johnston typedef struct ipmi_lan { 72*81d9f076SRobert Johnston ipmi_handle_t *il_ihp; 73*81d9f076SRobert Johnston char il_host[MAXHOSTNAMELEN + 1]; 74*81d9f076SRobert Johnston uint16_t il_port; 75*81d9f076SRobert Johnston char il_user[17]; 76*81d9f076SRobert Johnston char il_authcode[IPMI_AUTHCODE_BUF_SIZE + 1]; 77*81d9f076SRobert Johnston uint8_t il_challenge[16]; 78*81d9f076SRobert Johnston uint32_t il_session_id; 79*81d9f076SRobert Johnston int il_sd; 80*81d9f076SRobert Johnston boolean_t il_send_authcode; 81*81d9f076SRobert Johnston boolean_t il_session_active; 82*81d9f076SRobert Johnston uint8_t il_authtype; 83*81d9f076SRobert Johnston uint8_t il_privlvl; 84*81d9f076SRobert Johnston uint8_t il_num_retries; 85*81d9f076SRobert Johnston uint32_t il_in_seq; 86*81d9f076SRobert Johnston uint32_t il_timeout; 87*81d9f076SRobert Johnston struct sockaddr_in il_addr; 88*81d9f076SRobert Johnston socklen_t il_addrlen; 89*81d9f076SRobert Johnston } ipmi_lan_t; 90283bfb4dSEric Schrock 91*81d9f076SRobert Johnston /* 92*81d9f076SRobert Johnston * Calculate and returns IPMI checksum 93*81d9f076SRobert Johnston * 94*81d9f076SRobert Johnston * Checksum algorithm is described in Section 13.8 95*81d9f076SRobert Johnston * 96*81d9f076SRobert Johnston * d: buffer to check 97*81d9f076SRobert Johnston * s: position in buffer to start checksum from 98*81d9f076SRobert Johnston */ 99*81d9f076SRobert Johnston static uint8_t 100*81d9f076SRobert Johnston ipmi_csum(uint8_t *d, int s) 101*81d9f076SRobert Johnston { 102*81d9f076SRobert Johnston uint8_t c = 0; 103*81d9f076SRobert Johnston for (; s > 0; s--, d++) 104*81d9f076SRobert Johnston c += *d; 105*81d9f076SRobert Johnston return (-c); 106*81d9f076SRobert Johnston } 107*81d9f076SRobert Johnston 108*81d9f076SRobert Johnston static ipmi_rq_entry_t * 109*81d9f076SRobert Johnston ipmi_req_add_entry(ipmi_handle_t *ihp, ipmi_cmd_t *req) 110*81d9f076SRobert Johnston { 111*81d9f076SRobert Johnston ipmi_rq_entry_t *e; 112*81d9f076SRobert Johnston 113*81d9f076SRobert Johnston if ((e = ipmi_zalloc(ihp, sizeof (ipmi_rq_entry_t))) == NULL) 114*81d9f076SRobert Johnston return (NULL); 115*81d9f076SRobert Johnston 116*81d9f076SRobert Johnston (void) memcpy(&e->ire_req, req, sizeof (ipmi_cmd_t)); 117*81d9f076SRobert Johnston ipmi_list_append(&ipmi_req_entries->ire_list, e); 118*81d9f076SRobert Johnston 119*81d9f076SRobert Johnston return (e); 120*81d9f076SRobert Johnston } 121*81d9f076SRobert Johnston 122*81d9f076SRobert Johnston /*ARGSUSED*/ 123*81d9f076SRobert Johnston static ipmi_rq_entry_t * 124*81d9f076SRobert Johnston ipmi_req_lookup_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd) 125*81d9f076SRobert Johnston { 126*81d9f076SRobert Johnston ipmi_rq_entry_t *e; 127*81d9f076SRobert Johnston 128*81d9f076SRobert Johnston for (e = ipmi_list_next(&ipmi_req_entries->ire_list); e != NULL; 129*81d9f076SRobert Johnston e = ipmi_list_next(e)) 130*81d9f076SRobert Johnston if (e->ire_rq_seq == seq && e->ire_req.ic_cmd == cmd) 131*81d9f076SRobert Johnston return (e); 132*81d9f076SRobert Johnston 133*81d9f076SRobert Johnston return (NULL); 134*81d9f076SRobert Johnston } 135*81d9f076SRobert Johnston 136*81d9f076SRobert Johnston static void 137*81d9f076SRobert Johnston ipmi_req_remove_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd) 138*81d9f076SRobert Johnston { 139*81d9f076SRobert Johnston ipmi_rq_entry_t *e; 140*81d9f076SRobert Johnston 141*81d9f076SRobert Johnston e = ipmi_req_lookup_entry(ihp, seq, cmd); 142*81d9f076SRobert Johnston 143*81d9f076SRobert Johnston if (e) { 144*81d9f076SRobert Johnston ipmi_list_delete(&ipmi_req_entries->ire_list, e); 145*81d9f076SRobert Johnston ipmi_free(ihp, e->ire_msg_data); 146*81d9f076SRobert Johnston ipmi_free(ihp, e); 147*81d9f076SRobert Johnston } 148*81d9f076SRobert Johnston } 149*81d9f076SRobert Johnston 150*81d9f076SRobert Johnston static void 151*81d9f076SRobert Johnston ipmi_req_clear_entries(ipmi_handle_t *ihp) 152*81d9f076SRobert Johnston { 153*81d9f076SRobert Johnston ipmi_rq_entry_t *e; 154*81d9f076SRobert Johnston 155*81d9f076SRobert Johnston while ((e = ipmi_list_next(&ipmi_req_entries->ire_list)) != NULL) { 156*81d9f076SRobert Johnston ipmi_list_delete(&ipmi_req_entries->ire_list, e); 157*81d9f076SRobert Johnston ipmi_free(ihp, e); 158*81d9f076SRobert Johnston } 159*81d9f076SRobert Johnston } 160*81d9f076SRobert Johnston 161*81d9f076SRobert Johnston static int 162*81d9f076SRobert Johnston get_random(void *buf, uint_t len) 163*81d9f076SRobert Johnston { 164*81d9f076SRobert Johnston int fd; 165*81d9f076SRobert Johnston 166*81d9f076SRobert Johnston assert(buf != NULL && len > 0); 167*81d9f076SRobert Johnston if ((fd = open("/dev/urandom", O_RDONLY)) < 0) 168*81d9f076SRobert Johnston return (-1); 169*81d9f076SRobert Johnston 170*81d9f076SRobert Johnston if (read(fd, buf, len) < 0) { 171*81d9f076SRobert Johnston (void) close(fd); 172*81d9f076SRobert Johnston return (-1); 173*81d9f076SRobert Johnston } 174*81d9f076SRobert Johnston (void) close(fd); 175*81d9f076SRobert Johnston return (0); 176*81d9f076SRobert Johnston } 177*81d9f076SRobert Johnston 178*81d9f076SRobert Johnston static int 179*81d9f076SRobert Johnston ipmi_lan_send_packet(ipmi_handle_t *ihp, uint8_t *data, int dlen) 180*81d9f076SRobert Johnston { 181*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; 182*81d9f076SRobert Johnston 183*81d9f076SRobert Johnston return (send(ilp->il_sd, data, dlen, 0)); 184*81d9f076SRobert Johnston } 185*81d9f076SRobert Johnston 186*81d9f076SRobert Johnston static ipmi_rs_t * 187*81d9f076SRobert Johnston ipmi_lan_recv_packet(ipmi_handle_t *ihp) 188*81d9f076SRobert Johnston { 189*81d9f076SRobert Johnston static ipmi_rs_t rsp; 190*81d9f076SRobert Johnston fd_set read_set, err_set; 191*81d9f076SRobert Johnston struct timeval tmout; 192*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; 193*81d9f076SRobert Johnston int ret; 194*81d9f076SRobert Johnston 195*81d9f076SRobert Johnston FD_ZERO(&read_set); 196*81d9f076SRobert Johnston FD_SET(ilp->il_sd, &read_set); 197*81d9f076SRobert Johnston 198*81d9f076SRobert Johnston FD_ZERO(&err_set); 199*81d9f076SRobert Johnston FD_SET(ilp->il_sd, &err_set); 200*81d9f076SRobert Johnston 201*81d9f076SRobert Johnston tmout.tv_sec = ilp->il_timeout; 202*81d9f076SRobert Johnston tmout.tv_usec = 0; 203*81d9f076SRobert Johnston 204*81d9f076SRobert Johnston ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout); 205*81d9f076SRobert Johnston if (ret < 0 || FD_ISSET(ilp->il_sd, &err_set) || 206*81d9f076SRobert Johnston !FD_ISSET(ilp->il_sd, &read_set)) 207*81d9f076SRobert Johnston return (NULL); 208*81d9f076SRobert Johnston 209*81d9f076SRobert Johnston /* 210*81d9f076SRobert Johnston * The first read may return ECONNREFUSED because the rmcp ping 211*81d9f076SRobert Johnston * packet--sent to UDP port 623--will be processed by both the 212*81d9f076SRobert Johnston * BMC and the OS. 213*81d9f076SRobert Johnston * 214*81d9f076SRobert Johnston * The problem with this is that the ECONNREFUSED takes 215*81d9f076SRobert Johnston * priority over any other received datagram; that means that 216*81d9f076SRobert Johnston * the Connection Refused shows up _before_ the response packet, 217*81d9f076SRobert Johnston * regardless of the order they were sent out. (unless the 218*81d9f076SRobert Johnston * response is read before the connection refused is returned) 219*81d9f076SRobert Johnston */ 220*81d9f076SRobert Johnston ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0); 221*81d9f076SRobert Johnston 222*81d9f076SRobert Johnston if (ret < 0) { 223*81d9f076SRobert Johnston FD_ZERO(&read_set); 224*81d9f076SRobert Johnston FD_SET(ilp->il_sd, &read_set); 225*81d9f076SRobert Johnston 226*81d9f076SRobert Johnston FD_ZERO(&err_set); 227*81d9f076SRobert Johnston FD_SET(ilp->il_sd, &err_set); 228*81d9f076SRobert Johnston 229*81d9f076SRobert Johnston tmout.tv_sec = ilp->il_timeout; 230*81d9f076SRobert Johnston tmout.tv_usec = 0; 231*81d9f076SRobert Johnston 232*81d9f076SRobert Johnston ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout); 233*81d9f076SRobert Johnston if (ret < 0) { 234*81d9f076SRobert Johnston if (FD_ISSET(ilp->il_sd, &err_set) || 235*81d9f076SRobert Johnston !FD_ISSET(ilp->il_sd, &read_set)) 236*81d9f076SRobert Johnston return (NULL); 237*81d9f076SRobert Johnston 238*81d9f076SRobert Johnston ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0); 239*81d9f076SRobert Johnston if (ret < 0) 240*81d9f076SRobert Johnston return (NULL); 241*81d9f076SRobert Johnston } 242*81d9f076SRobert Johnston } 243*81d9f076SRobert Johnston 244*81d9f076SRobert Johnston if (ret == 0) 245*81d9f076SRobert Johnston return (NULL); 246*81d9f076SRobert Johnston 247*81d9f076SRobert Johnston rsp.ir_data[ret] = '\0'; 248*81d9f076SRobert Johnston rsp.ir_dlen = ret; 249*81d9f076SRobert Johnston 250*81d9f076SRobert Johnston return (&rsp); 251*81d9f076SRobert Johnston } 252*81d9f076SRobert Johnston 253*81d9f076SRobert Johnston 254*81d9f076SRobert Johnston /* 255*81d9f076SRobert Johnston * ASF/RMCP Pong Message 256*81d9f076SRobert Johnston * 257*81d9f076SRobert Johnston * See section 13.2.4 258*81d9f076SRobert Johnston */ 259*81d9f076SRobert Johnston struct rmcp_pong { 260*81d9f076SRobert Johnston rmcp_hdr_t rp_rmcp; 261*81d9f076SRobert Johnston asf_hdr_t rp_asf; 262*81d9f076SRobert Johnston uint32_t rp_iana; 263*81d9f076SRobert Johnston uint32_t rp_oem; 264*81d9f076SRobert Johnston uint8_t rp_sup_entities; 265*81d9f076SRobert Johnston uint8_t rp_sup_interact; 266*81d9f076SRobert Johnston uint8_t rp_reserved[6]; 267283bfb4dSEric Schrock }; 268283bfb4dSEric Schrock 269*81d9f076SRobert Johnston /* 270*81d9f076SRobert Johnston * parse response RMCP "pong" packet 271*81d9f076SRobert Johnston * 272*81d9f076SRobert Johnston * return -1 if ping response not received 273*81d9f076SRobert Johnston * returns 0 if IPMI is NOT supported 274*81d9f076SRobert Johnston * returns 1 if IPMI is supported 275*81d9f076SRobert Johnston */ 276*81d9f076SRobert Johnston /*ARGSUSED*/ 277283bfb4dSEric Schrock static int 278*81d9f076SRobert Johnston ipmi_handle_pong(ipmi_handle_t *ihp, ipmi_rs_t *rsp) 279283bfb4dSEric Schrock { 280*81d9f076SRobert Johnston struct rmcp_pong *pong; 281283bfb4dSEric Schrock 282*81d9f076SRobert Johnston if (rsp == NULL) 283283bfb4dSEric Schrock return (-1); 284283bfb4dSEric Schrock 285*81d9f076SRobert Johnston /*LINTED: E_BAD_PTR_CAST_ALIGN*/ 286*81d9f076SRobert Johnston pong = (struct rmcp_pong *)rsp->ir_data; 287283bfb4dSEric Schrock 288*81d9f076SRobert Johnston return ((pong->rp_sup_entities & 0x80) ? 1 : 0); 289283bfb4dSEric Schrock } 290283bfb4dSEric Schrock 291283bfb4dSEric Schrock /* 292*81d9f076SRobert Johnston * Build and send RMCP presence ping message 293283bfb4dSEric Schrock */ 294*81d9f076SRobert Johnston static int 295*81d9f076SRobert Johnston ipmi_lan_ping(ipmi_handle_t *ihp) 296*81d9f076SRobert Johnston { 297*81d9f076SRobert Johnston rmcp_hdr_t rmcp_ping; 298*81d9f076SRobert Johnston asf_hdr_t asf_ping; 299*81d9f076SRobert Johnston uint8_t *data; 300*81d9f076SRobert Johnston int rv, dlen = sizeof (rmcp_ping) + sizeof (asf_ping); 301*81d9f076SRobert Johnston 302*81d9f076SRobert Johnston (void) memset(&rmcp_ping, 0, sizeof (rmcp_ping)); 303*81d9f076SRobert Johnston rmcp_ping.rh_version = RMCP_VERSION_1; 304*81d9f076SRobert Johnston rmcp_ping.rh_msg_class = RMCP_CLASS_ASF; 305*81d9f076SRobert Johnston rmcp_ping.rh_seq = 0xff; 306*81d9f076SRobert Johnston 307*81d9f076SRobert Johnston (void) memset(&asf_ping, 0, sizeof (asf_ping)); 308*81d9f076SRobert Johnston asf_ping.ah_iana = htonl(ASF_RMCP_IANA); 309*81d9f076SRobert Johnston asf_ping.ah_msg_type = ASF_TYPE_PING; 310*81d9f076SRobert Johnston 311*81d9f076SRobert Johnston if ((data = ipmi_zalloc(ihp, dlen)) == NULL) 312283bfb4dSEric Schrock return (-1); 313283bfb4dSEric Schrock 314*81d9f076SRobert Johnston (void) memcpy(data, &rmcp_ping, sizeof (rmcp_ping)); 315*81d9f076SRobert Johnston (void) memcpy(data + sizeof (rmcp_ping), &asf_ping, sizeof (asf_ping)); 316*81d9f076SRobert Johnston 317*81d9f076SRobert Johnston rv = ipmi_lan_send_packet(ihp, data, dlen); 318*81d9f076SRobert Johnston 319*81d9f076SRobert Johnston ipmi_free(ihp, data); 320*81d9f076SRobert Johnston 321*81d9f076SRobert Johnston if (rv < 0) 322*81d9f076SRobert Johnston return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL)); 323*81d9f076SRobert Johnston 324*81d9f076SRobert Johnston if (ipmi_lan_poll_recv(ihp) == NULL) 325*81d9f076SRobert Johnston return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL)); 326*81d9f076SRobert Johnston 327*81d9f076SRobert Johnston return (0); 328*81d9f076SRobert Johnston } 329*81d9f076SRobert Johnston 330*81d9f076SRobert Johnston static ipmi_rs_t * 331*81d9f076SRobert Johnston ipmi_lan_poll_recv(ipmi_handle_t *ihp) 332*81d9f076SRobert Johnston { 333*81d9f076SRobert Johnston rmcp_hdr_t rmcp_rsp; 334*81d9f076SRobert Johnston ipmi_rs_t *rsp; 335*81d9f076SRobert Johnston ipmi_rq_entry_t *entry; 336*81d9f076SRobert Johnston int off = 0, rv; 337*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; 338*81d9f076SRobert Johnston uint8_t rsp_authtype; 339*81d9f076SRobert Johnston 340*81d9f076SRobert Johnston rsp = ipmi_lan_recv_packet(ihp); 341*81d9f076SRobert Johnston 342*81d9f076SRobert Johnston while (rsp != NULL) { 343*81d9f076SRobert Johnston 344*81d9f076SRobert Johnston /* parse response headers */ 345*81d9f076SRobert Johnston (void) memcpy(&rmcp_rsp, rsp->ir_data, 4); 346*81d9f076SRobert Johnston 347*81d9f076SRobert Johnston switch (rmcp_rsp.rh_msg_class) { 348*81d9f076SRobert Johnston case RMCP_CLASS_ASF: 349*81d9f076SRobert Johnston /* ping response packet */ 350*81d9f076SRobert Johnston rv = ipmi_handle_pong(ihp, rsp); 351*81d9f076SRobert Johnston return ((rv <= 0) ? NULL : rsp); 352*81d9f076SRobert Johnston case RMCP_CLASS_IPMI: 353*81d9f076SRobert Johnston /* handled by rest of function */ 354*81d9f076SRobert Johnston break; 355*81d9f076SRobert Johnston default: 356*81d9f076SRobert Johnston /* Invalid RMCP class */ 357*81d9f076SRobert Johnston rsp = ipmi_lan_recv_packet(ihp); 358283bfb4dSEric Schrock continue; 359*81d9f076SRobert Johnston } 360283bfb4dSEric Schrock 361*81d9f076SRobert Johnston off = sizeof (rmcp_hdr_t); 362*81d9f076SRobert Johnston rsp_authtype = rsp->ir_data[off]; 363*81d9f076SRobert Johnston if (ilp->il_send_authcode && (rsp_authtype || ilp->il_authtype)) 364*81d9f076SRobert Johnston off += 26; 365*81d9f076SRobert Johnston else 366*81d9f076SRobert Johnston off += 10; 367*81d9f076SRobert Johnston 368*81d9f076SRobert Johnston (void) memcpy(&rsp->ir_ihdr, (void *)(rsp->ir_data + off), 369*81d9f076SRobert Johnston sizeof (rsp->ir_ihdr)); 370*81d9f076SRobert Johnston rsp->ir_ihdr.imh_seq = rsp->ir_ihdr.imh_seq >> 2; 371*81d9f076SRobert Johnston off += sizeof (rsp->ir_ihdr); 372*81d9f076SRobert Johnston rsp->ir_ccode = rsp->ir_data[off++]; 373*81d9f076SRobert Johnston 374*81d9f076SRobert Johnston entry = ipmi_req_lookup_entry(ihp, rsp->ir_ihdr.imh_seq, 375*81d9f076SRobert Johnston rsp->ir_ihdr.imh_cmd); 376*81d9f076SRobert Johnston if (entry) { 377*81d9f076SRobert Johnston ipmi_req_remove_entry(ihp, rsp->ir_ihdr.imh_seq, 378*81d9f076SRobert Johnston rsp->ir_ihdr.imh_cmd); 379*81d9f076SRobert Johnston } else { 380*81d9f076SRobert Johnston rsp = ipmi_lan_recv_packet(ihp); 381*81d9f076SRobert Johnston continue; 382*81d9f076SRobert Johnston } 383*81d9f076SRobert Johnston break; 384*81d9f076SRobert Johnston } 385*81d9f076SRobert Johnston 386*81d9f076SRobert Johnston /* shift response data to start of array */ 387*81d9f076SRobert Johnston if (rsp && rsp->ir_dlen > off) { 388*81d9f076SRobert Johnston rsp->ir_dlen -= off + 1; 389*81d9f076SRobert Johnston (void) memmove(rsp->ir_data, rsp->ir_data + off, rsp->ir_dlen); 390*81d9f076SRobert Johnston (void) memset(rsp->ir_data + rsp->ir_dlen, 0, 391*81d9f076SRobert Johnston IPMI_BUF_SIZE - rsp->ir_dlen); 392*81d9f076SRobert Johnston } 393*81d9f076SRobert Johnston return (rsp); 394*81d9f076SRobert Johnston } 395*81d9f076SRobert Johnston 396283bfb4dSEric Schrock /* 397*81d9f076SRobert Johnston * IPMI LAN Request Message Format 398*81d9f076SRobert Johnston * 399*81d9f076SRobert Johnston * See section 13.8 400*81d9f076SRobert Johnston * 401*81d9f076SRobert Johnston * +---------------------+ 402*81d9f076SRobert Johnston * | rmcp_hdr_t | 4 bytes 403*81d9f076SRobert Johnston * +---------------------+ 404*81d9f076SRobert Johnston * | v15_session_hdr_t | 9 bytes 405*81d9f076SRobert Johnston * +---------------------+ 406*81d9f076SRobert Johnston * | [authcode] | 16 bytes (if AUTHTYPE != none) 407*81d9f076SRobert Johnston * +---------------------+ 408*81d9f076SRobert Johnston * | msg length | 1 byte 409*81d9f076SRobert Johnston * +---------------------+ 410*81d9f076SRobert Johnston * | ipmi_msg_hdr_t | 6 bytes 411*81d9f076SRobert Johnston * +---------------------+ 412*81d9f076SRobert Johnston * | [msg data] | variable 413*81d9f076SRobert Johnston * +---------------------+ 414*81d9f076SRobert Johnston * | msg data checksum | 1 byte 415*81d9f076SRobert Johnston * +---------------------+ 416283bfb4dSEric Schrock */ 417*81d9f076SRobert Johnston static ipmi_rq_entry_t * 418*81d9f076SRobert Johnston ipmi_lan_build_cmd(ipmi_handle_t *ihp, ipmi_cmd_t *req) 419*81d9f076SRobert Johnston { 420*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; 421*81d9f076SRobert Johnston rmcp_hdr_t rmcp_hdr; 422*81d9f076SRobert Johnston v15_session_hdr_t session_hdr; 423*81d9f076SRobert Johnston ipmi_msg_hdr_t msg_hdr; 424*81d9f076SRobert Johnston uint8_t *msg; 425*81d9f076SRobert Johnston int cs, tmp, off = 0, len; 426*81d9f076SRobert Johnston ipmi_rq_entry_t *entry; 427*81d9f076SRobert Johnston static int curr_seq = 0; 428*81d9f076SRobert Johnston 429*81d9f076SRobert Johnston if (curr_seq >= 64) 430*81d9f076SRobert Johnston curr_seq = 0; 431*81d9f076SRobert Johnston 432*81d9f076SRobert Johnston if ((entry = ipmi_req_add_entry(ihp, req)) == NULL) 433*81d9f076SRobert Johnston return (NULL); 434*81d9f076SRobert Johnston 435*81d9f076SRobert Johnston len = req->ic_dlen + 29; 436*81d9f076SRobert Johnston if (ilp->il_send_authcode && ilp->il_authtype) 437*81d9f076SRobert Johnston len += 16; 438*81d9f076SRobert Johnston 439*81d9f076SRobert Johnston if ((msg = ipmi_zalloc(ihp, len)) == NULL) 440*81d9f076SRobert Johnston /* ipmi_errno set */ 441*81d9f076SRobert Johnston return (NULL); 442*81d9f076SRobert Johnston 443*81d9f076SRobert Johnston /* RMCP header */ 444*81d9f076SRobert Johnston (void) memset(&rmcp_hdr, 0, sizeof (rmcp_hdr)); 445*81d9f076SRobert Johnston rmcp_hdr.rh_version = RMCP_VERSION_1; 446*81d9f076SRobert Johnston rmcp_hdr.rh_msg_class = RMCP_CLASS_IPMI; 447*81d9f076SRobert Johnston rmcp_hdr.rh_seq = 0xff; 448*81d9f076SRobert Johnston (void) memcpy(msg, &rmcp_hdr, sizeof (rmcp_hdr)); 449*81d9f076SRobert Johnston off = sizeof (rmcp_hdr); 450*81d9f076SRobert Johnston 451*81d9f076SRobert Johnston /* IPMI session header */ 452*81d9f076SRobert Johnston (void) memset(&session_hdr, 0, sizeof (session_hdr)); 453*81d9f076SRobert Johnston if (! ilp->il_send_authcode) 454*81d9f076SRobert Johnston session_hdr.sh_authtype = 0x00; 455*81d9f076SRobert Johnston else 456*81d9f076SRobert Johnston /* hardcode passwd authentication */ 457*81d9f076SRobert Johnston session_hdr.sh_authtype = 0x04; 458*81d9f076SRobert Johnston 459*81d9f076SRobert Johnston (void) memcpy(&session_hdr.sh_seq, &ilp->il_in_seq, sizeof (uint32_t)); 460*81d9f076SRobert Johnston (void) memcpy(&session_hdr.sh_id, &ilp->il_session_id, 461*81d9f076SRobert Johnston sizeof (uint32_t)); 462*81d9f076SRobert Johnston 463*81d9f076SRobert Johnston (void) memcpy(msg + off, &session_hdr, sizeof (session_hdr)); 464*81d9f076SRobert Johnston off += sizeof (session_hdr); 465*81d9f076SRobert Johnston 466*81d9f076SRobert Johnston /* IPMI session authcode */ 467*81d9f076SRobert Johnston if (ilp->il_send_authcode && ilp->il_authtype) { 468*81d9f076SRobert Johnston (void) memcpy(msg + off, ilp->il_authcode, 16); 469*81d9f076SRobert Johnston off += 16; 470*81d9f076SRobert Johnston } 471*81d9f076SRobert Johnston 472*81d9f076SRobert Johnston /* message length */ 473*81d9f076SRobert Johnston msg[off++] = req->ic_dlen + 7; 474*81d9f076SRobert Johnston cs = off; 475*81d9f076SRobert Johnston 476*81d9f076SRobert Johnston /* IPMI message header */ 477*81d9f076SRobert Johnston (void) memset(&msg_hdr, 0, sizeof (msg_hdr)); 478*81d9f076SRobert Johnston msg_hdr.imh_addr1 = IPMI_BMC_SLAVE_ADDR; 479*81d9f076SRobert Johnston msg_hdr.imh_lun = req->ic_lun; 480*81d9f076SRobert Johnston msg_hdr.imh_netfn = req->ic_netfn; 481*81d9f076SRobert Johnston tmp = off - cs; 482*81d9f076SRobert Johnston msg_hdr.imh_csum = ipmi_csum(msg + cs, tmp); 483*81d9f076SRobert Johnston cs = off; 484*81d9f076SRobert Johnston msg_hdr.imh_addr2 = IPMI_BMC_SLAVE_ADDR; 485*81d9f076SRobert Johnston entry->ire_rq_seq = curr_seq++; 486*81d9f076SRobert Johnston msg_hdr.imh_seq = entry->ire_rq_seq << 2; 487*81d9f076SRobert Johnston msg_hdr.imh_cmd = req->ic_cmd; 488*81d9f076SRobert Johnston (void) memcpy(msg + off, &msg_hdr, sizeof (msg_hdr)); 489*81d9f076SRobert Johnston off += sizeof (msg_hdr); 490*81d9f076SRobert Johnston 491*81d9f076SRobert Johnston /* message data */ 492*81d9f076SRobert Johnston if (req->ic_dlen != 0) { 493*81d9f076SRobert Johnston (void) memcpy(msg + off, req->ic_data, req->ic_dlen); 494*81d9f076SRobert Johnston off += req->ic_dlen; 495*81d9f076SRobert Johnston } 496*81d9f076SRobert Johnston 497*81d9f076SRobert Johnston /* message data checksum */ 498*81d9f076SRobert Johnston tmp = off - cs; 499*81d9f076SRobert Johnston msg[off++] = ipmi_csum(msg + cs, tmp); 500*81d9f076SRobert Johnston 501*81d9f076SRobert Johnston if (ilp->il_in_seq) { 502*81d9f076SRobert Johnston ilp->il_in_seq++; 503*81d9f076SRobert Johnston if (ilp->il_in_seq == 0) 504*81d9f076SRobert Johnston ilp->il_in_seq++; 505*81d9f076SRobert Johnston } 506*81d9f076SRobert Johnston 507*81d9f076SRobert Johnston entry->ire_msg_len = off; 508*81d9f076SRobert Johnston entry->ire_msg_data = msg; 509*81d9f076SRobert Johnston 510*81d9f076SRobert Johnston return (entry); 511*81d9f076SRobert Johnston } 512*81d9f076SRobert Johnston 513*81d9f076SRobert Johnston static int 514*81d9f076SRobert Johnston ipmi_lan_send(void *data, ipmi_cmd_t *cmd, ipmi_cmd_t *response, 515*81d9f076SRobert Johnston int *completion) 516*81d9f076SRobert Johnston { 517*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)data; 518*81d9f076SRobert Johnston ipmi_rq_entry_t *entry = NULL; 519*81d9f076SRobert Johnston ipmi_rs_t *rsp = NULL; 520*81d9f076SRobert Johnston uint_t try = 0; 521*81d9f076SRobert Johnston 522*81d9f076SRobert Johnston for (;;) { 523*81d9f076SRobert Johnston if ((entry = ipmi_lan_build_cmd(ilp->il_ihp, cmd)) == NULL) 524*81d9f076SRobert Johnston return (-1); 525*81d9f076SRobert Johnston 526*81d9f076SRobert Johnston if (ipmi_lan_send_packet(ilp->il_ihp, entry->ire_msg_data, 527*81d9f076SRobert Johnston entry->ire_msg_len) < 0) { 528*81d9f076SRobert Johnston if (++try >= ilp->il_num_retries) 529*81d9f076SRobert Johnston return (-1); 530*81d9f076SRobert Johnston (void) usleep(5000); 531*81d9f076SRobert Johnston continue; 532*81d9f076SRobert Johnston } 533*81d9f076SRobert Johnston 534*81d9f076SRobert Johnston (void) usleep(100); 535*81d9f076SRobert Johnston 536*81d9f076SRobert Johnston if ((rsp = ipmi_lan_poll_recv(ilp->il_ihp)) != NULL) 537*81d9f076SRobert Johnston break; 538*81d9f076SRobert Johnston 539*81d9f076SRobert Johnston (void) usleep(5000); 540*81d9f076SRobert Johnston ipmi_req_remove_entry(ilp->il_ihp, entry->ire_rq_seq, 541*81d9f076SRobert Johnston entry->ire_req.ic_cmd); 542*81d9f076SRobert Johnston 543*81d9f076SRobert Johnston if (++try >= ilp->il_num_retries) 544283bfb4dSEric Schrock return (-1); 545283bfb4dSEric Schrock } 546*81d9f076SRobert Johnston response->ic_netfn = rsp->ir_ihdr.imh_netfn; 547*81d9f076SRobert Johnston response->ic_lun = rsp->ir_ihdr.imh_lun; 548*81d9f076SRobert Johnston response->ic_cmd = rsp->ir_ihdr.imh_cmd; 549*81d9f076SRobert Johnston if (rsp->ir_ccode != 0) { 550*81d9f076SRobert Johnston *completion = rsp->ir_ccode; 551*81d9f076SRobert Johnston response->ic_dlen = 0; 552*81d9f076SRobert Johnston response->ic_data = NULL; 553*81d9f076SRobert Johnston } else { 554*81d9f076SRobert Johnston *completion = 0; 555*81d9f076SRobert Johnston response->ic_dlen = rsp->ir_dlen; 556*81d9f076SRobert Johnston response->ic_data = rsp->ir_data; 557*81d9f076SRobert Johnston } 558*81d9f076SRobert Johnston return (0); 559283bfb4dSEric Schrock } 560283bfb4dSEric Schrock 561283bfb4dSEric Schrock /* 562*81d9f076SRobert Johnston * IPMI Get Session Challenge Command 563*81d9f076SRobert Johnston * 564*81d9f076SRobert Johnston * Copies the returned session ID and 16-byte challenge string to the supplied 565*81d9f076SRobert Johnston * buffers 566*81d9f076SRobert Johnston * 567*81d9f076SRobert Johnston * See section 22.16 568283bfb4dSEric Schrock */ 569*81d9f076SRobert Johnston static int 570*81d9f076SRobert Johnston ipmi_get_session_challenge_cmd(ipmi_handle_t *ihp, uint32_t *session_id, 571*81d9f076SRobert Johnston uint8_t *challenge) 572*81d9f076SRobert Johnston { 573*81d9f076SRobert Johnston ipmi_cmd_t cmd, resp; 574*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; 575*81d9f076SRobert Johnston char msg_data[17]; 576*81d9f076SRobert Johnston int ccode; 577*81d9f076SRobert Johnston 578*81d9f076SRobert Johnston (void) memset(msg_data, 0, 17); 579*81d9f076SRobert Johnston 580*81d9f076SRobert Johnston switch (ilp->il_authtype) { 581*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_NONE: 582*81d9f076SRobert Johnston msg_data[0] = 0x00; 583*81d9f076SRobert Johnston break; 584*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_MD2: 585*81d9f076SRobert Johnston msg_data[0] = 0x01; 586*81d9f076SRobert Johnston break; 587*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_MD5: 588*81d9f076SRobert Johnston msg_data[0] = 0x02; 589*81d9f076SRobert Johnston break; 590*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_PASSWORD: 591*81d9f076SRobert Johnston msg_data[0] = 0x04; 592*81d9f076SRobert Johnston break; 593*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_OEM: 594*81d9f076SRobert Johnston msg_data[0] = 0x05; 595*81d9f076SRobert Johnston break; 596*81d9f076SRobert Johnston } 597*81d9f076SRobert Johnston (void) memcpy(msg_data + 1, ilp->il_user, 16); 598*81d9f076SRobert Johnston 599*81d9f076SRobert Johnston cmd.ic_netfn = IPMI_NETFN_APP; 600*81d9f076SRobert Johnston cmd.ic_lun = 0; 601*81d9f076SRobert Johnston cmd.ic_cmd = IPMI_CMD_GET_SESSION_CHALLENGE; 602*81d9f076SRobert Johnston cmd.ic_data = msg_data; 603*81d9f076SRobert Johnston cmd.ic_dlen = 17; 604*81d9f076SRobert Johnston 605*81d9f076SRobert Johnston if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0 || ccode) 606*81d9f076SRobert Johnston return (ipmi_set_error(ihp, EIPMI_LAN_CHALLENGE, NULL)); 607*81d9f076SRobert Johnston 608*81d9f076SRobert Johnston (void) memcpy(session_id, resp.ic_data, 4); 609*81d9f076SRobert Johnston (void) memcpy(challenge, (uint8_t *)resp.ic_data + 4, 16); 610*81d9f076SRobert Johnston 611*81d9f076SRobert Johnston return (0); 612*81d9f076SRobert Johnston } 613*81d9f076SRobert Johnston 614*81d9f076SRobert Johnston /* 615*81d9f076SRobert Johnston * IPMI Activate Session Command 616*81d9f076SRobert Johnston * 617*81d9f076SRobert Johnston * See section 22.17 618*81d9f076SRobert Johnston */ 619*81d9f076SRobert Johnston static int 620*81d9f076SRobert Johnston ipmi_activate_session_cmd(ipmi_handle_t *ihp) 621*81d9f076SRobert Johnston { 622*81d9f076SRobert Johnston ipmi_cmd_t cmd, resp; 623*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; 624*81d9f076SRobert Johnston uint8_t msg_data[22], *resp_data; 625*81d9f076SRobert Johnston int ccode; 626*81d9f076SRobert Johnston 627*81d9f076SRobert Johnston cmd.ic_netfn = IPMI_NETFN_APP; 628*81d9f076SRobert Johnston cmd.ic_lun = 0; 629*81d9f076SRobert Johnston cmd.ic_cmd = IPMI_CMD_ACTIVATE_SESSION; 630*81d9f076SRobert Johnston 631*81d9f076SRobert Johnston switch (ilp->il_authtype) { 632*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_NONE: 633*81d9f076SRobert Johnston msg_data[0] = 0x00; 634*81d9f076SRobert Johnston break; 635*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_MD2: 636*81d9f076SRobert Johnston msg_data[0] = 0x01; 637*81d9f076SRobert Johnston break; 638*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_MD5: 639*81d9f076SRobert Johnston msg_data[0] = 0x02; 640*81d9f076SRobert Johnston break; 641*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_PASSWORD: 642*81d9f076SRobert Johnston msg_data[0] = 0x04; 643*81d9f076SRobert Johnston break; 644*81d9f076SRobert Johnston case IPMI_SESSION_AUTHTYPE_OEM: 645*81d9f076SRobert Johnston msg_data[0] = 0x05; 646*81d9f076SRobert Johnston break; 647*81d9f076SRobert Johnston } 648*81d9f076SRobert Johnston msg_data[1] = ilp->il_privlvl; 649*81d9f076SRobert Johnston 650*81d9f076SRobert Johnston (void) memcpy(msg_data + 2, ilp->il_challenge, 16); 651*81d9f076SRobert Johnston 652*81d9f076SRobert Johnston /* setup initial outbound sequence number */ 653*81d9f076SRobert Johnston (void) get_random(msg_data + 18, 4); 654*81d9f076SRobert Johnston 655*81d9f076SRobert Johnston cmd.ic_data = msg_data; 656*81d9f076SRobert Johnston cmd.ic_dlen = 22; 657*81d9f076SRobert Johnston 658*81d9f076SRobert Johnston ilp->il_send_authcode = B_TRUE; 659*81d9f076SRobert Johnston 660*81d9f076SRobert Johnston if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0 || ccode) { 661*81d9f076SRobert Johnston ilp->il_send_authcode = B_FALSE; 662*81d9f076SRobert Johnston return (ipmi_set_error(ihp, EIPMI_LAN_SESSION, NULL)); 663*81d9f076SRobert Johnston } 664*81d9f076SRobert Johnston 665*81d9f076SRobert Johnston resp_data = (uint8_t *)resp.ic_data; 666*81d9f076SRobert Johnston (void) memcpy(&ilp->il_session_id, resp_data + 1, 4); 667*81d9f076SRobert Johnston ilp->il_in_seq = resp_data[8] << 24 | resp_data[7] << 16 | 668*81d9f076SRobert Johnston resp_data[6] << 8 | resp_data[5]; 669*81d9f076SRobert Johnston if (ilp->il_in_seq == 0) 670*81d9f076SRobert Johnston ++ilp->il_in_seq; 671*81d9f076SRobert Johnston 672*81d9f076SRobert Johnston return (0); 673*81d9f076SRobert Johnston } 674*81d9f076SRobert Johnston 675*81d9f076SRobert Johnston 676*81d9f076SRobert Johnston /* 677*81d9f076SRobert Johnston * See section 22.18 678*81d9f076SRobert Johnston * 679*81d9f076SRobert Johnston * returns privilege level or -1 on error 680*81d9f076SRobert Johnston */ 681*81d9f076SRobert Johnston static int 682*81d9f076SRobert Johnston ipmi_set_session_privlvl_cmd(ipmi_handle_t *ihp, uint8_t privlvl) 683*81d9f076SRobert Johnston { 684*81d9f076SRobert Johnston ipmi_cmd_t cmd, resp; 685*81d9f076SRobert Johnston int ret = 0, ccode; 686*81d9f076SRobert Johnston 687*81d9f076SRobert Johnston if (privlvl > IPMI_SESSION_PRIV_OEM) 688*81d9f076SRobert Johnston return (ipmi_set_error(ihp, EIPMI_BADPARAM, NULL)); 689*81d9f076SRobert Johnston 690*81d9f076SRobert Johnston cmd.ic_netfn = IPMI_NETFN_APP; 691*81d9f076SRobert Johnston cmd.ic_lun = 0; 692*81d9f076SRobert Johnston cmd.ic_cmd = IPMI_CMD_SET_SESSION_PRIVLVL; 693*81d9f076SRobert Johnston cmd.ic_data = &privlvl; 694*81d9f076SRobert Johnston cmd.ic_dlen = 1; 695*81d9f076SRobert Johnston 696*81d9f076SRobert Johnston if (ipmi_lan_send(ihp->ih_tdata, &cmd, &resp, &ccode) != 0) 697*81d9f076SRobert Johnston ret = ipmi_set_error(ihp, EIPMI_LAN_SETPRIV, NULL); 698*81d9f076SRobert Johnston 699*81d9f076SRobert Johnston return (ret); 700*81d9f076SRobert Johnston } 701*81d9f076SRobert Johnston 702*81d9f076SRobert Johnston /* 703*81d9f076SRobert Johnston * See section 22.19 704*81d9f076SRobert Johnston */ 705*81d9f076SRobert Johnston static int 706*81d9f076SRobert Johnston ipmi_close_session_cmd(ipmi_handle_t *ihp) 707*81d9f076SRobert Johnston { 708*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; 709*81d9f076SRobert Johnston ipmi_cmd_t cmd, resp; 710*81d9f076SRobert Johnston uint8_t msg_data[4]; 711*81d9f076SRobert Johnston int ret = 0, ccode; 712*81d9f076SRobert Johnston 713*81d9f076SRobert Johnston if (! ilp->il_session_active) 714*81d9f076SRobert Johnston return (-1); 715*81d9f076SRobert Johnston 716*81d9f076SRobert Johnston (void) memcpy(&msg_data, &ilp->il_session_id, 4); 717*81d9f076SRobert Johnston 718*81d9f076SRobert Johnston cmd.ic_netfn = IPMI_NETFN_APP; 719*81d9f076SRobert Johnston cmd.ic_lun = 0; 720*81d9f076SRobert Johnston cmd.ic_cmd = IPMI_CMD_CLOSE_SESSION; 721*81d9f076SRobert Johnston cmd.ic_data = msg_data; 722*81d9f076SRobert Johnston cmd.ic_dlen = 4; 723*81d9f076SRobert Johnston 724*81d9f076SRobert Johnston if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0) 725*81d9f076SRobert Johnston ret = -1; 726*81d9f076SRobert Johnston 727*81d9f076SRobert Johnston return (ret); 728*81d9f076SRobert Johnston } 729*81d9f076SRobert Johnston 730*81d9f076SRobert Johnston /* 731*81d9f076SRobert Johnston * IPMI LAN Session Activation 732*81d9f076SRobert Johnston * 733*81d9f076SRobert Johnston * See section 13.14 734*81d9f076SRobert Johnston * 735*81d9f076SRobert Johnston * 1. send "RMCP Presence Ping" message, response message will 736*81d9f076SRobert Johnston * indicate whether the platform supports IPMI 737*81d9f076SRobert Johnston * 2. send "Get Channel Authentication Capabilities" command 738*81d9f076SRobert Johnston * with AUTHTYPE = none, response packet will contain information 739*81d9f076SRobert Johnston * about supported challenge/response authentication types 740*81d9f076SRobert Johnston * 3. send "Get Session Challenge" command with AUTHTYPE = none 741*81d9f076SRobert Johnston * and indicate the authentication type in the message, response 742*81d9f076SRobert Johnston * packet will contain challenge string and temporary session ID. 743*81d9f076SRobert Johnston * 4. send "Activate Session" command, authenticated with AUTHTYPE 744*81d9f076SRobert Johnston * sent in previous message. Also sends the initial value for 745*81d9f076SRobert Johnston * the outbound sequence number for BMC. 746*81d9f076SRobert Johnston * 5. BMC returns response confirming session activation and 747*81d9f076SRobert Johnston * session ID for this session and initial inbound sequence. 748*81d9f076SRobert Johnston */ 749*81d9f076SRobert Johnston static int 750*81d9f076SRobert Johnston ipmi_lan_activate_session(ipmi_handle_t *ihp) 751*81d9f076SRobert Johnston { 752*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; 753*81d9f076SRobert Johnston ipmi_channel_auth_caps_t *ac; 754*81d9f076SRobert Johnston 755*81d9f076SRobert Johnston if (ipmi_lan_ping(ihp) != 0) 756*81d9f076SRobert Johnston return (-1); 757*81d9f076SRobert Johnston 758*81d9f076SRobert Johnston if ((ac = ipmi_get_channel_auth_caps(ihp, IPMI_LAN_CHANNEL_E, 759*81d9f076SRobert Johnston ilp->il_privlvl)) == NULL) 760*81d9f076SRobert Johnston return (-1); 761*81d9f076SRobert Johnston 762*81d9f076SRobert Johnston /* 763*81d9f076SRobert Johnston * For the sake of simplicity, we're just supporting basic password 764*81d9f076SRobert Johnston * authentication. If this authentication type is not supported then 765*81d9f076SRobert Johnston * we'll bail here. 766*81d9f076SRobert Johnston */ 767*81d9f076SRobert Johnston if (!(ac->cap_authtype & IPMI_SESSION_AUTHTYPE_PASSWORD)) { 768*81d9f076SRobert Johnston free(ac); 769*81d9f076SRobert Johnston return (ipmi_set_error(ihp, EIPMI_LAN_PASSWD_NOTSUP, NULL)); 770*81d9f076SRobert Johnston } 771*81d9f076SRobert Johnston free(ac); 772*81d9f076SRobert Johnston 773*81d9f076SRobert Johnston if (ipmi_get_session_challenge_cmd(ihp, &ilp->il_session_id, 774*81d9f076SRobert Johnston ilp->il_challenge) != 0) 775*81d9f076SRobert Johnston return (-1); 776*81d9f076SRobert Johnston 777*81d9f076SRobert Johnston if (ipmi_activate_session_cmd(ihp) != 0) 778*81d9f076SRobert Johnston return (-1); 779*81d9f076SRobert Johnston 780*81d9f076SRobert Johnston ilp->il_session_active = B_TRUE; 781*81d9f076SRobert Johnston 782*81d9f076SRobert Johnston if (ipmi_set_session_privlvl_cmd(ihp, ilp->il_privlvl) != 0) 783283bfb4dSEric Schrock return (-1); 784283bfb4dSEric Schrock 785283bfb4dSEric Schrock return (0); 786283bfb4dSEric Schrock } 787*81d9f076SRobert Johnston 788*81d9f076SRobert Johnston static void 789*81d9f076SRobert Johnston ipmi_lan_close(void *data) 790*81d9f076SRobert Johnston { 791*81d9f076SRobert Johnston ipmi_lan_t *ilp = (ipmi_lan_t *)data; 792*81d9f076SRobert Johnston 793*81d9f076SRobert Johnston if (ilp->il_session_active) 794*81d9f076SRobert Johnston (void) ipmi_close_session_cmd(ilp->il_ihp); 795*81d9f076SRobert Johnston 796*81d9f076SRobert Johnston if (ilp->il_sd >= 0) 797*81d9f076SRobert Johnston (void) close(ilp->il_sd); 798*81d9f076SRobert Johnston 799*81d9f076SRobert Johnston ipmi_req_clear_entries(ilp->il_ihp); 800*81d9f076SRobert Johnston ipmi_free(ilp->il_ihp, ipmi_req_entries); 801*81d9f076SRobert Johnston ipmi_free(ilp->il_ihp, ilp); 802*81d9f076SRobert Johnston } 803*81d9f076SRobert Johnston 804*81d9f076SRobert Johnston static void * 805*81d9f076SRobert Johnston ipmi_lan_open(ipmi_handle_t *ihp, nvlist_t *params) 806*81d9f076SRobert Johnston { 807*81d9f076SRobert Johnston int rc; 808*81d9f076SRobert Johnston struct hostent *host; 809*81d9f076SRobert Johnston ipmi_lan_t *ilp; 810*81d9f076SRobert Johnston char *hostname, *user, *authcode; 811*81d9f076SRobert Johnston 812*81d9f076SRobert Johnston if ((ilp = ipmi_zalloc(ihp, sizeof (ipmi_lan_t))) == NULL) { 813*81d9f076SRobert Johnston /* ipmi errno set */ 814*81d9f076SRobert Johnston return (NULL); 815*81d9f076SRobert Johnston } 816*81d9f076SRobert Johnston ilp->il_ihp = ihp; 817*81d9f076SRobert Johnston ihp->ih_tdata = ilp; 818*81d9f076SRobert Johnston 819*81d9f076SRobert Johnston /* 820*81d9f076SRobert Johnston * Parse the parameters passed in the params nvlist. The following 821*81d9f076SRobert Johnston * parameters are required 822*81d9f076SRobert Johnston * IPMI_LAN_HOST, IPMI_LAN_USER and IPMI_LAN_PASSWD 823*81d9f076SRobert Johnston * 824*81d9f076SRobert Johnston * If any of these were not specified then we abort 825*81d9f076SRobert Johnston */ 826*81d9f076SRobert Johnston if (nvlist_lookup_string(params, IPMI_LAN_HOST, &hostname) || 827*81d9f076SRobert Johnston nvlist_lookup_string(params, IPMI_LAN_USER, &user) || 828*81d9f076SRobert Johnston nvlist_lookup_string(params, IPMI_LAN_PASSWD, &authcode)) { 829*81d9f076SRobert Johnston ipmi_free(ihp, ilp); 830*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_BADPARAM, NULL); 831*81d9f076SRobert Johnston return (NULL); 832*81d9f076SRobert Johnston } 833*81d9f076SRobert Johnston (void) strncpy(ilp->il_host, hostname, MAXHOSTNAMELEN); 834*81d9f076SRobert Johnston (void) strncpy(ilp->il_user, user, 16); 835*81d9f076SRobert Johnston (void) strncpy(ilp->il_authcode, authcode, 16); 836*81d9f076SRobert Johnston 837*81d9f076SRobert Johnston /* 838*81d9f076SRobert Johnston * IPMI_LAN_PORT is an optional parameter and defaults to port 623 839*81d9f076SRobert Johnston * IPMI_LAN_PRIVLVL is also optional and defaults to admin 840*81d9f076SRobert Johnston * IPMI_LAN_TIMEOUT is optional and will default to 3 seconds 841*81d9f076SRobert Johnston * IPMI_LAN_NUM_RETIES is optional and will default to 5 842*81d9f076SRobert Johnston */ 843*81d9f076SRobert Johnston if (nvlist_lookup_uint16(params, IPMI_LAN_PORT, &ilp->il_port)) 844*81d9f076SRobert Johnston ilp->il_port = RMCP_UDP_PORT; 845*81d9f076SRobert Johnston 846*81d9f076SRobert Johnston if (nvlist_lookup_uint8(params, IPMI_LAN_PRIVLVL, &ilp->il_privlvl)) 847*81d9f076SRobert Johnston ilp->il_privlvl = IPMI_SESSION_PRIV_ADMIN; 848*81d9f076SRobert Johnston 849*81d9f076SRobert Johnston if (nvlist_lookup_uint32(params, IPMI_LAN_TIMEOUT, &ilp->il_timeout)) 850*81d9f076SRobert Johnston ilp->il_timeout = DEF_IPMI_LAN_TIMEOUT; 851*81d9f076SRobert Johnston 852*81d9f076SRobert Johnston if (nvlist_lookup_uint8(params, IPMI_LAN_NUM_RETRIES, 853*81d9f076SRobert Johnston &ilp->il_num_retries)) 854*81d9f076SRobert Johnston ilp->il_num_retries = DEF_IPMI_LAN_NUM_RETRIES; 855*81d9f076SRobert Johnston 856*81d9f076SRobert Johnston ilp->il_authtype = IPMI_SESSION_AUTHTYPE_PASSWORD; 857*81d9f076SRobert Johnston 858*81d9f076SRobert Johnston /* 859*81d9f076SRobert Johnston * Open up and connect a UDP socket between us and the service 860*81d9f076SRobert Johnston * processor 861*81d9f076SRobert Johnston */ 862*81d9f076SRobert Johnston ilp->il_addr.sin_family = AF_INET; 863*81d9f076SRobert Johnston ilp->il_addr.sin_port = htons(ilp->il_port); 864*81d9f076SRobert Johnston 865*81d9f076SRobert Johnston rc = inet_pton(AF_INET, (const char *)ilp->il_host, 866*81d9f076SRobert Johnston &ilp->il_addr.sin_addr); 867*81d9f076SRobert Johnston if (rc <= 0) { 868*81d9f076SRobert Johnston if ((host = gethostbyname((const char *)ilp->il_host)) 869*81d9f076SRobert Johnston == NULL) { 870*81d9f076SRobert Johnston ipmi_free(ihp, ilp); 871*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL); 872*81d9f076SRobert Johnston return (NULL); 873*81d9f076SRobert Johnston } 874*81d9f076SRobert Johnston ilp->il_addr.sin_family = host->h_addrtype; 875*81d9f076SRobert Johnston (void) memcpy(&ilp->il_addr.sin_addr, host->h_addr, 876*81d9f076SRobert Johnston host->h_length); 877*81d9f076SRobert Johnston } 878*81d9f076SRobert Johnston 879*81d9f076SRobert Johnston if ((ilp->il_sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 880*81d9f076SRobert Johnston ipmi_free(ihp, ilp); 881*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL); 882*81d9f076SRobert Johnston return (NULL); 883*81d9f076SRobert Johnston } 884*81d9f076SRobert Johnston if (connect(ilp->il_sd, (struct sockaddr *)&ilp->il_addr, 885*81d9f076SRobert Johnston sizeof (struct sockaddr_in)) < 0) { 886*81d9f076SRobert Johnston ipmi_lan_close(ilp); 887*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL); 888*81d9f076SRobert Johnston return (NULL); 889*81d9f076SRobert Johnston } 890*81d9f076SRobert Johnston 891*81d9f076SRobert Johnston if ((ipmi_req_entries = ipmi_zalloc(ihp, sizeof (ipmi_rq_entry_t))) 892*81d9f076SRobert Johnston == NULL) 893*81d9f076SRobert Johnston return (NULL); 894*81d9f076SRobert Johnston 895*81d9f076SRobert Johnston /* 896*81d9f076SRobert Johnston * Finally we start up the IPMI LAN session 897*81d9f076SRobert Johnston */ 898*81d9f076SRobert Johnston if ((rc = ipmi_lan_activate_session(ihp)) < 0) { 899*81d9f076SRobert Johnston ipmi_lan_close(ilp); 900*81d9f076SRobert Johnston return (NULL); 901*81d9f076SRobert Johnston } 902*81d9f076SRobert Johnston 903*81d9f076SRobert Johnston return (ilp); 904*81d9f076SRobert Johnston } 905*81d9f076SRobert Johnston 906*81d9f076SRobert Johnston ipmi_transport_t ipmi_transport_lan = { 907*81d9f076SRobert Johnston ipmi_lan_open, 908*81d9f076SRobert Johnston ipmi_lan_close, 909*81d9f076SRobert Johnston ipmi_lan_send 910*81d9f076SRobert Johnston }; 911