1*81d9f076SRobert Johnston /* 2*81d9f076SRobert Johnston * CDDL HEADER START 3*81d9f076SRobert Johnston * 4*81d9f076SRobert Johnston * The contents of this file are subject to the terms of the 5*81d9f076SRobert Johnston * Common Development and Distribution License (the "License"). 6*81d9f076SRobert Johnston * You may not use this file except in compliance with the License. 7*81d9f076SRobert Johnston * 8*81d9f076SRobert Johnston * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*81d9f076SRobert Johnston * or http://www.opensolaris.org/os/licensing. 10*81d9f076SRobert Johnston * See the License for the specific language governing permissions 11*81d9f076SRobert Johnston * and limitations under the License. 12*81d9f076SRobert Johnston * 13*81d9f076SRobert Johnston * When distributing Covered Code, include this CDDL HEADER in each 14*81d9f076SRobert Johnston * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*81d9f076SRobert Johnston * If applicable, add the following below this CDDL HEADER, with the 16*81d9f076SRobert Johnston * fields enclosed by brackets "[]" replaced with your own identifying 17*81d9f076SRobert Johnston * information: Portions Copyright [yyyy] [name of copyright owner] 18*81d9f076SRobert Johnston * 19*81d9f076SRobert Johnston * CDDL HEADER END 20*81d9f076SRobert Johnston */ 21*81d9f076SRobert Johnston /* 22*81d9f076SRobert Johnston * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23*81d9f076SRobert Johnston * Use is subject to license terms. 24*81d9f076SRobert Johnston */ 25*81d9f076SRobert Johnston 26*81d9f076SRobert Johnston /* 27*81d9f076SRobert Johnston * Query and configure LAN interfaces over IPMI. This is done through the 28*81d9f076SRobert Johnston * complicated get/set LAN Configuration Parameters command. This queries or 29*81d9f076SRobert Johnston * sets the parameters one per command in series. We hide this implementation 30*81d9f076SRobert Johnston * detail and instead export a single structure to consumers. 31*81d9f076SRobert Johnston */ 32*81d9f076SRobert Johnston 33*81d9f076SRobert Johnston #include <stddef.h> 34*81d9f076SRobert Johnston #include <strings.h> 35*81d9f076SRobert Johnston 36*81d9f076SRobert Johnston #include <libipmi.h> 37*81d9f076SRobert Johnston 38*81d9f076SRobert Johnston #include "ipmi_impl.h" 39*81d9f076SRobert Johnston 40*81d9f076SRobert Johnston typedef struct ipmi_cmd_lan_get_config { 41*81d9f076SRobert Johnston DECL_BITFIELD3( 42*81d9f076SRobert Johnston ilgc_number :4, 43*81d9f076SRobert Johnston __reserved :3, 44*81d9f076SRobert Johnston ilgc_revonly :1); 45*81d9f076SRobert Johnston uint8_t ilgc_param; 46*81d9f076SRobert Johnston uint8_t ilgc_set; 47*81d9f076SRobert Johnston uint8_t ilgc_block; 48*81d9f076SRobert Johnston } ipmi_cmd_lan_get_config_t; 49*81d9f076SRobert Johnston 50*81d9f076SRobert Johnston typedef struct ipmi_cmd_lan_set_config { 51*81d9f076SRobert Johnston DECL_BITFIELD2( 52*81d9f076SRobert Johnston ilsc_number :4, 53*81d9f076SRobert Johnston __reserved :4); 54*81d9f076SRobert Johnston uint8_t ilsc_param; 55*81d9f076SRobert Johnston uint8_t ilsc_data[18]; 56*81d9f076SRobert Johnston } ipmi_cmd_lan_set_config_t; 57*81d9f076SRobert Johnston 58*81d9f076SRobert Johnston #define IPMI_LAN_SET_LEN(dlen) \ 59*81d9f076SRobert Johnston (offsetof(ipmi_cmd_lan_set_config_t, ilsc_data) + (dlen)) 60*81d9f076SRobert Johnston 61*81d9f076SRobert Johnston #define IPMI_LAN_PARAM_SET_IN_PROGRESS 0 62*81d9f076SRobert Johnston #define IPMI_LAN_PARAM_IP_ADDR 3 63*81d9f076SRobert Johnston #define IPMI_LAN_PARAM_IP_SOURCE 4 64*81d9f076SRobert Johnston #define IPMI_LAN_PARAM_MAC_ADDR 5 65*81d9f076SRobert Johnston #define IPMI_LAN_PARAM_SUBNET_MASK 6 66*81d9f076SRobert Johnston #define IPMI_LAN_PARAM_GATEWAY_ADDR 12 67*81d9f076SRobert Johnston 68*81d9f076SRobert Johnston #define IPMI_LAN_SET_COMPLETE 0x0 69*81d9f076SRobert Johnston #define IPMI_LAN_SET_INPROGRESS 0x1 70*81d9f076SRobert Johnston #define IPMI_LAN_SET_COMMIT 0x2 71*81d9f076SRobert Johnston 72*81d9f076SRobert Johnston typedef struct ipmi_lan_entry { 73*81d9f076SRobert Johnston int ile_param; 74*81d9f076SRobert Johnston int ile_mask; 75*81d9f076SRobert Johnston int ile_set; 76*81d9f076SRobert Johnston int ile_block; 77*81d9f076SRobert Johnston size_t ile_offset; 78*81d9f076SRobert Johnston size_t ile_len; 79*81d9f076SRobert Johnston } ipmi_lan_entry_t; 80*81d9f076SRobert Johnston 81*81d9f076SRobert Johnston static ipmi_lan_entry_t ipmi_lan_table[] = { 82*81d9f076SRobert Johnston { IPMI_LAN_PARAM_IP_ADDR, IPMI_LAN_SET_IPADDR, 0, 0, 83*81d9f076SRobert Johnston offsetof(ipmi_lan_config_t, ilc_ipaddr), sizeof (uint32_t) }, 84*81d9f076SRobert Johnston { IPMI_LAN_PARAM_IP_SOURCE, IPMI_LAN_SET_IPADDR_SOURCE, 0, 0, 85*81d9f076SRobert Johnston offsetof(ipmi_lan_config_t, ilc_ipaddr_source), sizeof (uint8_t) }, 86*81d9f076SRobert Johnston { IPMI_LAN_PARAM_MAC_ADDR, IPMI_LAN_SET_MACADDR, 0, 0, 87*81d9f076SRobert Johnston offsetof(ipmi_lan_config_t, ilc_macaddr), 6 * sizeof (uint8_t) }, 88*81d9f076SRobert Johnston { IPMI_LAN_PARAM_SUBNET_MASK, IPMI_LAN_SET_SUBNET, 0, 0, 89*81d9f076SRobert Johnston offsetof(ipmi_lan_config_t, ilc_subnet), sizeof (uint32_t) }, 90*81d9f076SRobert Johnston { IPMI_LAN_PARAM_GATEWAY_ADDR, IPMI_LAN_SET_GATEWAY_ADDR, 0, 0, 91*81d9f076SRobert Johnston offsetof(ipmi_lan_config_t, ilc_gateway_addr), sizeof (uint32_t) } 92*81d9f076SRobert Johnston }; 93*81d9f076SRobert Johnston 94*81d9f076SRobert Johnston #define IPMI_LAN_NENTRIES \ 95*81d9f076SRobert Johnston (sizeof (ipmi_lan_table) / sizeof (ipmi_lan_table[0])) 96*81d9f076SRobert Johnston 97*81d9f076SRobert Johnston static int 98*81d9f076SRobert Johnston ipmi_lan_get_param(ipmi_handle_t *ihp, int channel, int param, int set, 99*81d9f076SRobert Johnston int block, void *data, size_t len) 100*81d9f076SRobert Johnston { 101*81d9f076SRobert Johnston ipmi_cmd_t cmd, *rsp; 102*81d9f076SRobert Johnston ipmi_cmd_lan_get_config_t lcmd = { 0 }; 103*81d9f076SRobert Johnston 104*81d9f076SRobert Johnston lcmd.ilgc_number = channel; 105*81d9f076SRobert Johnston lcmd.ilgc_param = param; 106*81d9f076SRobert Johnston lcmd.ilgc_set = set; 107*81d9f076SRobert Johnston lcmd.ilgc_block = block; 108*81d9f076SRobert Johnston 109*81d9f076SRobert Johnston cmd.ic_netfn = IPMI_NETFN_TRANSPORT; 110*81d9f076SRobert Johnston cmd.ic_lun = 0; 111*81d9f076SRobert Johnston cmd.ic_cmd = IPMI_CMD_GET_LAN_CONFIG; 112*81d9f076SRobert Johnston cmd.ic_data = &lcmd; 113*81d9f076SRobert Johnston cmd.ic_dlen = sizeof (lcmd); 114*81d9f076SRobert Johnston 115*81d9f076SRobert Johnston if ((rsp = ipmi_send(ihp, &cmd)) == NULL) { 116*81d9f076SRobert Johnston switch (ihp->ih_completion) { 117*81d9f076SRobert Johnston case 0x80: 118*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_BADPARAM, NULL); 119*81d9f076SRobert Johnston break; 120*81d9f076SRobert Johnston } 121*81d9f076SRobert Johnston return (-1); 122*81d9f076SRobert Johnston } 123*81d9f076SRobert Johnston 124*81d9f076SRobert Johnston if (rsp->ic_dlen < len + 1) 125*81d9f076SRobert Johnston return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); 126*81d9f076SRobert Johnston 127*81d9f076SRobert Johnston bcopy((uint8_t *)rsp->ic_data + 1, data, len); 128*81d9f076SRobert Johnston 129*81d9f076SRobert Johnston return (0); 130*81d9f076SRobert Johnston } 131*81d9f076SRobert Johnston 132*81d9f076SRobert Johnston int 133*81d9f076SRobert Johnston ipmi_lan_get_config(ipmi_handle_t *ihp, int channel, ipmi_lan_config_t *cfgp) 134*81d9f076SRobert Johnston { 135*81d9f076SRobert Johnston uint8_t set; 136*81d9f076SRobert Johnston int i; 137*81d9f076SRobert Johnston ipmi_lan_entry_t *lep; 138*81d9f076SRobert Johnston 139*81d9f076SRobert Johnston if (ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, 0, 140*81d9f076SRobert Johnston 0, &set, sizeof (set)) != 0) 141*81d9f076SRobert Johnston return (-1); 142*81d9f076SRobert Johnston 143*81d9f076SRobert Johnston if (set & IPMI_LAN_SET_INPROGRESS) 144*81d9f076SRobert Johnston cfgp->ilc_set_in_progress = B_TRUE; 145*81d9f076SRobert Johnston else 146*81d9f076SRobert Johnston cfgp->ilc_set_in_progress = B_FALSE; 147*81d9f076SRobert Johnston 148*81d9f076SRobert Johnston for (i = 0; i < IPMI_LAN_NENTRIES; i++) { 149*81d9f076SRobert Johnston lep = &ipmi_lan_table[i]; 150*81d9f076SRobert Johnston if (ipmi_lan_get_param(ihp, channel, lep->ile_param, 151*81d9f076SRobert Johnston lep->ile_set, lep->ile_block, 152*81d9f076SRobert Johnston (char *)cfgp + lep->ile_offset, lep->ile_len) != 0) 153*81d9f076SRobert Johnston return (-1); 154*81d9f076SRobert Johnston } 155*81d9f076SRobert Johnston 156*81d9f076SRobert Johnston return (0); 157*81d9f076SRobert Johnston } 158*81d9f076SRobert Johnston 159*81d9f076SRobert Johnston static int 160*81d9f076SRobert Johnston ipmi_lan_set_param(ipmi_handle_t *ihp, int channel, int param, void *data, 161*81d9f076SRobert Johnston size_t len) 162*81d9f076SRobert Johnston { 163*81d9f076SRobert Johnston ipmi_cmd_t cmd; 164*81d9f076SRobert Johnston ipmi_cmd_lan_set_config_t lcmd = { 0 }; 165*81d9f076SRobert Johnston 166*81d9f076SRobert Johnston lcmd.ilsc_number = channel; 167*81d9f076SRobert Johnston lcmd.ilsc_param = param; 168*81d9f076SRobert Johnston bcopy(data, lcmd.ilsc_data, len); 169*81d9f076SRobert Johnston 170*81d9f076SRobert Johnston cmd.ic_netfn = IPMI_NETFN_TRANSPORT; 171*81d9f076SRobert Johnston cmd.ic_lun = 0; 172*81d9f076SRobert Johnston cmd.ic_cmd = IPMI_CMD_SET_LAN_CONFIG; 173*81d9f076SRobert Johnston cmd.ic_data = &lcmd; 174*81d9f076SRobert Johnston cmd.ic_dlen = IPMI_LAN_SET_LEN(len); 175*81d9f076SRobert Johnston 176*81d9f076SRobert Johnston if (ipmi_send(ihp, &cmd) == NULL) { 177*81d9f076SRobert Johnston switch (ihp->ih_completion) { 178*81d9f076SRobert Johnston case 0x80: 179*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_BADPARAM, NULL); 180*81d9f076SRobert Johnston break; 181*81d9f076SRobert Johnston 182*81d9f076SRobert Johnston case 0x81: 183*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_BUSY, NULL); 184*81d9f076SRobert Johnston break; 185*81d9f076SRobert Johnston 186*81d9f076SRobert Johnston case 0x82: 187*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_READONLY, NULL); 188*81d9f076SRobert Johnston break; 189*81d9f076SRobert Johnston 190*81d9f076SRobert Johnston case 0x83: 191*81d9f076SRobert Johnston (void) ipmi_set_error(ihp, EIPMI_WRITEONLY, NULL); 192*81d9f076SRobert Johnston break; 193*81d9f076SRobert Johnston } 194*81d9f076SRobert Johnston return (-1); 195*81d9f076SRobert Johnston } 196*81d9f076SRobert Johnston 197*81d9f076SRobert Johnston return (0); 198*81d9f076SRobert Johnston } 199*81d9f076SRobert Johnston 200*81d9f076SRobert Johnston int 201*81d9f076SRobert Johnston ipmi_lan_set_config(ipmi_handle_t *ihp, int channel, ipmi_lan_config_t *cfgp, 202*81d9f076SRobert Johnston int mask) 203*81d9f076SRobert Johnston { 204*81d9f076SRobert Johnston uint8_t set; 205*81d9f076SRobert Johnston int i; 206*81d9f076SRobert Johnston ipmi_lan_entry_t *lep; 207*81d9f076SRobert Johnston 208*81d9f076SRobert Johnston /* 209*81d9f076SRobert Johnston * Cancel any pending transaction, then open a new transaction. 210*81d9f076SRobert Johnston */ 211*81d9f076SRobert Johnston set = IPMI_LAN_SET_COMPLETE; 212*81d9f076SRobert Johnston if (ipmi_lan_set_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, 213*81d9f076SRobert Johnston &set, sizeof (set)) != 0) 214*81d9f076SRobert Johnston return (-1); 215*81d9f076SRobert Johnston set = IPMI_LAN_SET_INPROGRESS; 216*81d9f076SRobert Johnston if (ipmi_lan_set_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, 217*81d9f076SRobert Johnston &set, sizeof (set)) != 0) 218*81d9f076SRobert Johnston return (-1); 219*81d9f076SRobert Johnston 220*81d9f076SRobert Johnston /* 221*81d9f076SRobert Johnston * Iterate over all parameters and set them. 222*81d9f076SRobert Johnston */ 223*81d9f076SRobert Johnston for (i = 0; i < IPMI_LAN_NENTRIES; i++) { 224*81d9f076SRobert Johnston lep = &ipmi_lan_table[i]; 225*81d9f076SRobert Johnston if (!(lep->ile_mask & mask)) 226*81d9f076SRobert Johnston continue; 227*81d9f076SRobert Johnston 228*81d9f076SRobert Johnston if (ipmi_lan_set_param(ihp, channel, lep->ile_param, 229*81d9f076SRobert Johnston (char *)cfgp + lep->ile_offset, lep->ile_len) != 0) { 230*81d9f076SRobert Johnston /* 231*81d9f076SRobert Johnston * On some systems, setting the mode to DHCP may cause 232*81d9f076SRobert Johnston * the command to timeout, presumably because it is 233*81d9f076SRobert Johnston * waiting for the setting to take effect. If we see 234*81d9f076SRobert Johnston * completion code 0xc3 (command timeout) while setting 235*81d9f076SRobert Johnston * the DHCP value, just ignore it. 236*81d9f076SRobert Johnston */ 237*81d9f076SRobert Johnston if (mask != IPMI_LAN_SET_IPADDR_SOURCE || 238*81d9f076SRobert Johnston cfgp->ilc_ipaddr_source != IPMI_LAN_SRC_DHCP || 239*81d9f076SRobert Johnston ihp->ih_completion != 0xC3) 240*81d9f076SRobert Johnston return (-1); 241*81d9f076SRobert Johnston } 242*81d9f076SRobert Johnston } 243*81d9f076SRobert Johnston 244*81d9f076SRobert Johnston /* 245*81d9f076SRobert Johnston * Commit the transaction. 246*81d9f076SRobert Johnston */ 247*81d9f076SRobert Johnston set = IPMI_LAN_SET_COMPLETE; 248*81d9f076SRobert Johnston if (ipmi_lan_set_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, 249*81d9f076SRobert Johnston &set, sizeof (set)) != 0) 250*81d9f076SRobert Johnston return (-1); 251*81d9f076SRobert Johnston 252*81d9f076SRobert Johnston return (0); 253*81d9f076SRobert Johnston } 254