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  */
  25 
  26 #include <stdlib.h>
  27 #include <stdio.h>
  28 #include <assert.h>
  29 #include <inttypes.h>
  30 #include <string.h>
  31 #include <sys/types.h>
  32 #include <sys/socket.h>
  33 #include <netinet/in.h>
  34 #include <arpa/inet.h>
  35 #include <errno.h>
  36 #include <unistd.h>
  37 #include <netdb.h>
  38 #include <fcntl.h>
  39 
  40 #include "libipmi.h"
  41 #include "ipmi_lan.h"
  42 #include "ipmi_impl.h"
  43 
  44 #define DEF_IPMI_LAN_TIMEOUT            3 /* seconds */
  45 #define DEF_IPMI_LAN_NUM_RETRIES        5
  46 #define IPMI_LAN_CHANNEL_E              0x0e
  47 
  48 typedef struct ipmi_rs {
  49         uint8_t         ir_data[IPMI_BUF_SIZE];
  50         int             ir_dlen;
  51         ipmi_msg_hdr_t  ir_ihdr;
  52         uint8_t         ir_ccode;
  53 } ipmi_rs_t;
  54 
  55 static ipmi_rs_t *ipmi_lan_poll_recv(ipmi_handle_t *);
  56 
  57 typedef struct ipmi_rq_entry {
  58         ipmi_list_t     ire_list;
  59         ipmi_cmd_t      ire_req;
  60         uint8_t         ire_target_cmd;
  61         uint8_t         ire_rq_seq;
  62         uint8_t         *ire_msg_data;
  63         int             ire_msg_len;
  64 } ipmi_rq_entry_t;
  65 
  66 ipmi_rq_entry_t *ipmi_req_entries = NULL;
  67 
  68 /*
  69  * LAN transport-specific data
  70  */
  71 typedef struct ipmi_lan {
  72         ipmi_handle_t   *il_ihp;
  73         char            il_host[MAXHOSTNAMELEN + 1];
  74         uint16_t        il_port;
  75         char            il_user[17];
  76         char            il_authcode[IPMI_AUTHCODE_BUF_SIZE + 1];
  77         uint8_t         il_challenge[16];
  78         uint32_t        il_session_id;
  79         int             il_sd;
  80         boolean_t       il_send_authcode;
  81         boolean_t       il_session_active;
  82         uint8_t         il_authtype;
  83         uint8_t         il_privlvl;
  84         uint8_t         il_num_retries;
  85         uint32_t        il_in_seq;
  86         uint32_t        il_timeout;
  87         struct sockaddr_in il_addr;
  88         socklen_t       il_addrlen;
  89 } ipmi_lan_t;
  90 
  91 /*
  92  * Calculate and returns IPMI checksum
  93  *
  94  * Checksum algorithm is described in Section 13.8
  95  *
  96  * d:           buffer to check
  97  * s:           position in buffer to start checksum from
  98  */
  99 static uint8_t
 100 ipmi_csum(uint8_t *d, int s)
 101 {
 102         uint8_t c = 0;
 103         for (; s > 0; s--, d++)
 104                 c += *d;
 105         return (-c);
 106 }
 107 
 108 static ipmi_rq_entry_t *
 109 ipmi_req_add_entry(ipmi_handle_t *ihp, ipmi_cmd_t *req)
 110 {
 111         ipmi_rq_entry_t *e;
 112 
 113         if ((e = ipmi_zalloc(ihp, sizeof (ipmi_rq_entry_t))) == NULL)
 114                 return (NULL);
 115 
 116         (void) memcpy(&e->ire_req, req, sizeof (ipmi_cmd_t));
 117         ipmi_list_append(&ipmi_req_entries->ire_list, e);
 118 
 119         return (e);
 120 }
 121 
 122 /*ARGSUSED*/
 123 static ipmi_rq_entry_t *
 124 ipmi_req_lookup_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd)
 125 {
 126         ipmi_rq_entry_t *e;
 127 
 128         for (e = ipmi_list_next(&ipmi_req_entries->ire_list); e != NULL;
 129             e = ipmi_list_next(e))
 130                 if (e->ire_rq_seq == seq && e->ire_req.ic_cmd == cmd)
 131                         return (e);
 132 
 133         return (NULL);
 134 }
 135 
 136 static void
 137 ipmi_req_remove_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd)
 138 {
 139         ipmi_rq_entry_t *e;
 140 
 141         e = ipmi_req_lookup_entry(ihp, seq, cmd);
 142 
 143         if (e) {
 144                 ipmi_list_delete(&ipmi_req_entries->ire_list, e);
 145                 ipmi_free(ihp, e->ire_msg_data);
 146                 ipmi_free(ihp, e);
 147         }
 148 }
 149 
 150 static void
 151 ipmi_req_clear_entries(ipmi_handle_t *ihp)
 152 {
 153         ipmi_rq_entry_t *e;
 154 
 155         while ((e = ipmi_list_next(&ipmi_req_entries->ire_list)) != NULL) {
 156                 ipmi_list_delete(&ipmi_req_entries->ire_list, e);
 157                 ipmi_free(ihp, e);
 158         }
 159 }
 160 
 161 static int
 162 get_random(void *buf, uint_t len)
 163 {
 164         int fd;
 165 
 166         assert(buf != NULL && len > 0);
 167         if ((fd = open("/dev/urandom", O_RDONLY)) < 0)
 168                 return (-1);
 169 
 170         if (read(fd, buf, len) < 0) {
 171                 (void) close(fd);
 172                 return (-1);
 173         }
 174         (void) close(fd);
 175         return (0);
 176 }
 177 
 178 static int
 179 ipmi_lan_send_packet(ipmi_handle_t *ihp, uint8_t *data, int dlen)
 180 {
 181         ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
 182 
 183         return (send(ilp->il_sd, data, dlen, 0));
 184 }
 185 
 186 static ipmi_rs_t *
 187 ipmi_lan_recv_packet(ipmi_handle_t *ihp)
 188 {
 189         static ipmi_rs_t rsp;
 190         fd_set read_set, err_set;
 191         struct timeval tmout;
 192         ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
 193         int ret;
 194 
 195         FD_ZERO(&read_set);
 196         FD_SET(ilp->il_sd, &read_set);
 197 
 198         FD_ZERO(&err_set);
 199         FD_SET(ilp->il_sd, &err_set);
 200 
 201         tmout.tv_sec =  ilp->il_timeout;
 202         tmout.tv_usec = 0;
 203 
 204         ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout);
 205         if (ret < 0 || FD_ISSET(ilp->il_sd, &err_set) ||
 206             !FD_ISSET(ilp->il_sd, &read_set))
 207                 return (NULL);
 208 
 209         /*
 210          * The first read may return ECONNREFUSED because the rmcp ping
 211          * packet--sent to UDP port 623--will be processed by both the
 212          * BMC and the OS.
 213          *
 214          * The problem with this is that the ECONNREFUSED takes
 215          * priority over any other received datagram; that means that
 216          * the Connection Refused shows up _before_ the response packet,
 217          * regardless of the order they were sent out.  (unless the
 218          * response is read before the connection refused is returned)
 219          */
 220         ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0);
 221 
 222         if (ret < 0) {
 223                 FD_ZERO(&read_set);
 224                 FD_SET(ilp->il_sd, &read_set);
 225 
 226                 FD_ZERO(&err_set);
 227                 FD_SET(ilp->il_sd, &err_set);
 228 
 229                 tmout.tv_sec = ilp->il_timeout;
 230                 tmout.tv_usec = 0;
 231 
 232                 ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout);
 233                 if (ret < 0) {
 234                         if (FD_ISSET(ilp->il_sd, &err_set) ||
 235                             !FD_ISSET(ilp->il_sd, &read_set))
 236                                 return (NULL);
 237 
 238                         ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0);
 239                         if (ret < 0)
 240                                 return (NULL);
 241                 }
 242         }
 243 
 244         if (ret == 0)
 245                 return (NULL);
 246 
 247         rsp.ir_data[ret] = '\0';
 248         rsp.ir_dlen = ret;
 249 
 250         return (&rsp);
 251 }
 252 
 253 
 254 /*
 255  * ASF/RMCP Pong Message
 256  *
 257  * See section 13.2.4
 258  */
 259 struct rmcp_pong {
 260         rmcp_hdr_t rp_rmcp;
 261         asf_hdr_t rp_asf;
 262         uint32_t rp_iana;
 263         uint32_t rp_oem;
 264         uint8_t rp_sup_entities;
 265         uint8_t rp_sup_interact;
 266         uint8_t rp_reserved[6];
 267 };
 268 
 269 /*
 270  * parse response RMCP "pong" packet
 271  *
 272  * return -1 if ping response not received
 273  * returns 0 if IPMI is NOT supported
 274  * returns 1 if IPMI is supported
 275  */
 276 /*ARGSUSED*/
 277 static int
 278 ipmi_handle_pong(ipmi_handle_t *ihp, ipmi_rs_t *rsp)
 279 {
 280         struct rmcp_pong *pong;
 281 
 282         if (rsp == NULL)
 283                 return (-1);
 284 
 285         /*LINTED: E_BAD_PTR_CAST_ALIGN*/
 286         pong = (struct rmcp_pong *)rsp->ir_data;
 287 
 288         return ((pong->rp_sup_entities & 0x80) ? 1 : 0);
 289 }
 290 
 291 /*
 292  * Build and send RMCP presence ping message
 293  */
 294 static int
 295 ipmi_lan_ping(ipmi_handle_t *ihp)
 296 {
 297         rmcp_hdr_t rmcp_ping;
 298         asf_hdr_t asf_ping;
 299         uint8_t *data;
 300         int rv, dlen = sizeof (rmcp_ping) + sizeof (asf_ping);
 301 
 302         (void) memset(&rmcp_ping, 0, sizeof (rmcp_ping));
 303         rmcp_ping.rh_version = RMCP_VERSION_1;
 304         rmcp_ping.rh_msg_class = RMCP_CLASS_ASF;
 305         rmcp_ping.rh_seq = 0xff;
 306 
 307         (void) memset(&asf_ping, 0, sizeof (asf_ping));
 308         asf_ping.ah_iana = htonl(ASF_RMCP_IANA);
 309         asf_ping.ah_msg_type = ASF_TYPE_PING;
 310 
 311         if ((data = ipmi_zalloc(ihp, dlen)) == NULL)
 312                 return (-1);
 313 
 314         (void) memcpy(data, &rmcp_ping, sizeof (rmcp_ping));
 315         (void) memcpy(data + sizeof (rmcp_ping), &asf_ping, sizeof (asf_ping));
 316 
 317         rv = ipmi_lan_send_packet(ihp, data, dlen);
 318 
 319         ipmi_free(ihp, data);
 320 
 321         if (rv < 0)
 322                 return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL));
 323 
 324         if (ipmi_lan_poll_recv(ihp) == NULL)
 325                 return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL));
 326 
 327         return (0);
 328 }
 329 
 330 static ipmi_rs_t *
 331 ipmi_lan_poll_recv(ipmi_handle_t *ihp)
 332 {
 333         rmcp_hdr_t rmcp_rsp;
 334         ipmi_rs_t *rsp;
 335         ipmi_rq_entry_t *entry;
 336         int off = 0, rv;
 337         ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
 338         uint8_t rsp_authtype;
 339 
 340         rsp = ipmi_lan_recv_packet(ihp);
 341 
 342         while (rsp != NULL) {
 343 
 344                 /* parse response headers */
 345                 (void) memcpy(&rmcp_rsp, rsp->ir_data, 4);
 346 
 347                 switch (rmcp_rsp.rh_msg_class) {
 348                 case RMCP_CLASS_ASF:
 349                         /* ping response packet */
 350                         rv = ipmi_handle_pong(ihp, rsp);
 351                         return ((rv <= 0) ? NULL : rsp);
 352                 case RMCP_CLASS_IPMI:
 353                         /* handled by rest of function */
 354                         break;
 355                 default:
 356                         /* Invalid RMCP class */
 357                         rsp = ipmi_lan_recv_packet(ihp);
 358                         continue;
 359                 }
 360 
 361                 off = sizeof (rmcp_hdr_t);
 362                 rsp_authtype = rsp->ir_data[off];
 363                 if (ilp->il_send_authcode && (rsp_authtype || ilp->il_authtype))
 364                         off += 26;
 365                 else
 366                         off += 10;
 367 
 368                 (void) memcpy(&rsp->ir_ihdr, (void *)(rsp->ir_data + off),
 369                     sizeof (rsp->ir_ihdr));
 370                 rsp->ir_ihdr.imh_seq = rsp->ir_ihdr.imh_seq >> 2;
 371                 off += sizeof (rsp->ir_ihdr);
 372                 rsp->ir_ccode = rsp->ir_data[off++];
 373 
 374                 entry = ipmi_req_lookup_entry(ihp, rsp->ir_ihdr.imh_seq,
 375                     rsp->ir_ihdr.imh_cmd);
 376                 if (entry) {
 377                         ipmi_req_remove_entry(ihp, rsp->ir_ihdr.imh_seq,
 378                             rsp->ir_ihdr.imh_cmd);
 379                 } else {
 380                         rsp = ipmi_lan_recv_packet(ihp);
 381                         continue;
 382                 }
 383                 break;
 384         }
 385 
 386         /* shift response data to start of array */
 387         if (rsp && rsp->ir_dlen > off) {
 388                 rsp->ir_dlen -= off + 1;
 389                 (void) memmove(rsp->ir_data, rsp->ir_data + off, rsp->ir_dlen);
 390                 (void) memset(rsp->ir_data + rsp->ir_dlen, 0,
 391                     IPMI_BUF_SIZE - rsp->ir_dlen);
 392         }
 393         return (rsp);
 394 }
 395 
 396 /*
 397  * IPMI LAN Request Message Format
 398  *
 399  * See section 13.8
 400  *
 401  * +---------------------+
 402  * |  rmcp_hdr_t         | 4 bytes
 403  * +---------------------+
 404  * |  v15_session_hdr_t  | 9 bytes
 405  * +---------------------+
 406  * | [authcode]          | 16 bytes (if AUTHTYPE != none)
 407  * +---------------------+
 408  * |  msg length         | 1 byte
 409  * +---------------------+
 410  * |  ipmi_msg_hdr_t     | 6 bytes
 411  * +---------------------+
 412  * | [msg data]          | variable
 413  * +---------------------+
 414  * |  msg data checksum  | 1 byte
 415  * +---------------------+
 416  */
 417 static ipmi_rq_entry_t *
 418 ipmi_lan_build_cmd(ipmi_handle_t *ihp, ipmi_cmd_t *req)
 419 {
 420         ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata;
 421         rmcp_hdr_t rmcp_hdr;
 422         v15_session_hdr_t session_hdr;
 423         ipmi_msg_hdr_t msg_hdr;
 424         uint8_t *msg;
 425         int cs, tmp, off = 0, len;
 426         ipmi_rq_entry_t *entry;
 427         static int curr_seq = 0;
 428 
 429         if (curr_seq >= 64)
 430                 curr_seq = 0;
 431 
 432         if ((entry = ipmi_req_add_entry(ihp, req)) == NULL)
 433                 return (NULL);
 434 
 435         len = req->ic_dlen + 29;
 436         if (ilp->il_send_authcode && ilp->il_authtype)
 437                 len += 16;
 438 
 439         if ((msg = ipmi_zalloc(ihp, len)) == NULL)
 440                 /* ipmi_errno set */
 441                 return (NULL);
 442 
 443         /* RMCP header */
 444         (void) memset(&rmcp_hdr, 0, sizeof (rmcp_hdr));
 445         rmcp_hdr.rh_version = RMCP_VERSION_1;
 446         rmcp_hdr.rh_msg_class = RMCP_CLASS_IPMI;
 447         rmcp_hdr.rh_seq = 0xff;
 448         (void) memcpy(msg, &rmcp_hdr, sizeof (rmcp_hdr));
 449         off = sizeof (rmcp_hdr);
 450 
 451         /* IPMI session header */
 452         (void) memset(&session_hdr, 0, sizeof (session_hdr));
 453         if (! ilp->il_send_authcode)
 454                 session_hdr.sh_authtype = 0x00;
 455         else
 456                 /* hardcode passwd authentication */
 457                 session_hdr.sh_authtype = 0x04;
 458 
 459         (void) memcpy(&session_hdr.sh_seq, &ilp->il_in_seq, sizeof (uint32_t));
 460         (void) memcpy(&session_hdr.sh_id, &ilp->il_session_id,
 461             sizeof (uint32_t));
 462 
 463         (void) memcpy(msg + off, &session_hdr, sizeof (session_hdr));
 464         off += sizeof (session_hdr);
 465 
 466         /* IPMI session authcode */
 467         if (ilp->il_send_authcode && ilp->il_authtype) {
 468                 (void) memcpy(msg + off, ilp->il_authcode, 16);
 469                 off += 16;
 470         }
 471 
 472         /* message length */
 473         msg[off++] = req->ic_dlen + 7;
 474         cs = off;
 475 
 476         /* IPMI message header */
 477         (void) memset(&msg_hdr, 0, sizeof (msg_hdr));
 478         msg_hdr.imh_addr1 = IPMI_BMC_SLAVE_ADDR;
 479         msg_hdr.imh_lun = req->ic_lun;
 480         msg_hdr.imh_netfn = req->ic_netfn;
 481         tmp = off - cs;
 482         msg_hdr.imh_csum = ipmi_csum(msg + cs, tmp);
 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 };