Home | History | Annotate | Download | only in common
      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 2008 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