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