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