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