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
ipmi_lan_get_param(ipmi_handle_t * ihp,int channel,int param,int set,int block,void * data,size_t len)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
ipmi_lan_get_config(ipmi_handle_t * ihp,int channel,ipmi_lan_config_t * cfgp)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
ipmi_lan_set_param(ipmi_handle_t * ihp,int channel,int param,void * data,size_t len)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
ipmi_lan_set_config(ipmi_handle_t * ihp,int channel,ipmi_lan_config_t * cfgp,int mask)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