1 /*
2  * bmc_transport.c
3  *
4  * MontaVista IPMI code for emulating a MC.
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2003,2012 MontaVista Software Inc.
11  *
12  *  This program is free software; you can redistribute it and/or
13  *  modify it under the terms of the GNU Lesser General Public License
14  *  as published by the Free Software Foundation; either version 2 of
15  *  the License, or (at your option) any later version.
16  *
17  *
18  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  You should have received a copy of the GNU Lesser General Public
30  *  License along with this program; if not, write to the Free
31  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32  *
33  * Modified BSD Licence
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  *
39  *   1. Redistributions of source code must retain the above copyright
40  *      notice, this list of conditions and the following disclaimer.
41  *   2. Redistributions in binary form must reproduce the above
42  *      copyright notice, this list of conditions and the following
43  *      disclaimer in the documentation and/or other materials provided
44  *      with the distribution.
45  *   3. The name of the author may not be used to endorse or promote
46  *      products derived from this software without specific prior
47  *      written permission.
48  */
49 
50 #include "bmc.h"
51 
52 #include <errno.h>
53 #include <string.h>
54 
55 #include <OpenIPMI/ipmi_err.h>
56 #include <OpenIPMI/ipmi_msgbits.h>
57 
58 static void
handle_ipmi_set_lan_config_parms(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)59 handle_ipmi_set_lan_config_parms(lmc_data_t    *mc,
60 				 msg_t         *msg,
61 				 unsigned char *rdata,
62 				 unsigned int  *rdata_len,
63 				 void          *cb_data)
64 {
65     unsigned char lchan;
66     channel_t *chan;
67 
68     if (msg->len < 3) {
69 	rdata[0] = IPMI_REQUEST_DATA_LENGTH_INVALID_CC;
70 	*rdata_len = 1;
71 	return;
72     }
73 
74     lchan = msg->data[0];
75     if (lchan == 0xe)
76 	lchan = msg->channel;
77     else if (lchan >= IPMI_MAX_CHANNELS) {
78 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
79 	*rdata_len = 1;
80 	return;
81     }
82 
83     if (!mc->channels[lchan]) {
84 	rdata[0] = IPMI_NOT_PRESENT_CC;
85 	*rdata_len = 1;
86 	return;
87     }
88     chan = mc->channels[lchan];
89 
90     if (!chan->set_lan_parms) {
91 	rdata[0] = IPMI_INVALID_CMD_CC;
92 	*rdata_len = 1;
93 	return;
94     }
95 
96     chan->set_lan_parms(chan, msg, rdata, rdata_len);
97 }
98 
99 static void
handle_ipmi_get_lan_config_parms(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)100 handle_ipmi_get_lan_config_parms(lmc_data_t    *mc,
101 				 msg_t         *msg,
102 				 unsigned char *rdata,
103 				 unsigned int  *rdata_len,
104 				 void          *cb_data)
105 {
106     unsigned char lchan;
107     channel_t *chan;
108 
109     if (msg->len < 4) {
110 	rdata[0] = IPMI_REQUEST_DATA_LENGTH_INVALID_CC;
111 	*rdata_len = 1;
112 	return;
113     }
114 
115     lchan = msg->data[0];
116     if (lchan == 0xe)
117 	lchan = msg->channel;
118     else if (lchan >= IPMI_MAX_CHANNELS) {
119 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
120 	*rdata_len = 1;
121 	return;
122     }
123 
124     if (!mc->channels[lchan]) {
125 	rdata[0] = IPMI_NOT_PRESENT_CC;
126 	*rdata_len = 1;
127 	return;
128     }
129 
130     chan = mc->channels[lchan];
131 
132     if (!chan->get_lan_parms) {
133 	rdata[0] = IPMI_INVALID_CMD_CC;
134 	*rdata_len = 1;
135 	return;
136     }
137 
138     chan->get_lan_parms(chan, msg, rdata, rdata_len);
139 }
140 
141 static void
handle_set_sol_config_parms(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)142 handle_set_sol_config_parms(lmc_data_t    *mc,
143 			    msg_t         *msg,
144 			    unsigned char *rdata,
145 			    unsigned int  *rdata_len,
146 			    void          *cb_data)
147 {
148     unsigned char err = 0;
149     unsigned char val;
150     int write_config = 0;
151     ipmi_sol_t *sol = &mc->sol;
152 
153     if (!mc->sol.configured) {
154 	handle_invalid_cmd(mc, rdata, rdata_len);
155 	return;
156     }
157 
158     if (msg->len < 3) {
159 	rdata[0] = IPMI_REQUEST_DATA_LENGTH_INVALID_CC;
160 	*rdata_len = 1;
161 	return;
162     }
163 
164     /*
165      * There is a channel in this message, but as far as I can tell,
166      * it is completely without point.  The data is generic to the
167      * management controller.  So just ignore it.
168      */
169 
170     switch (msg->data[1]) {
171     case 0:
172 	switch (msg->data[2] & 0x3) {
173 	case 0:
174 	    if (sol->set_in_progress) {
175 		/* Rollback */
176 		memcpy(&mc->sol.solparm, &mc->sol.solparm_rollback,
177 		       sizeof(solparm_t));
178 		write_config = 1;
179 	    }
180 	    break;
181 
182 	case 1:
183 	    if (sol->set_in_progress)
184 		err = 0x81; /* Another user is writing. */
185 	    else {
186 		/* Save rollback data */
187 		memcpy(&mc->sol.solparm_rollback, &mc->sol.solparm,
188 		       sizeof(solparm_t));
189 		sol->set_in_progress = 1;
190 	    }
191 	    break;
192 
193 	case 2:
194 	    sol->set_in_progress = 0;
195 	    break;
196 
197 	case 3:
198 	    err = IPMI_INVALID_DATA_FIELD_CC;
199 	}
200 	break;
201 
202     case 1:
203 	sol->solparm.enabled = msg->data[2] & 1;
204 	write_config = 1;
205 	break;
206 
207     case 5:
208 	val = msg->data[2] & 0xf;
209 	if ((val < 6) || (val > 0xa)) {
210 	    err = IPMI_INVALID_DATA_FIELD_CC;
211 	} else {
212 	    sol->solparm.bitrate_nonv = val;
213 	    write_config = 1;
214 	}
215 	break;
216 
217     case 6:
218 	val = msg->data[2] & 0xf;
219 	if ((val < 6) || (val > 0xa)) {
220 	    err = IPMI_INVALID_DATA_FIELD_CC;
221 	} else {
222 	    sol->solparm.bitrate = val;
223 	    if (sol->update_bitrate)
224 		sol->update_bitrate(mc);
225 	}
226 	break;
227 
228     default:
229 	err = 0x80; /* Parm not supported */
230     }
231 
232     if (write_config)
233 	write_sol_config(mc);
234 
235     rdata[0] = err;
236     *rdata_len = 1;
237 }
238 
239 static void
handle_get_sol_config_parms(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)240 handle_get_sol_config_parms(lmc_data_t    *mc,
241 			    msg_t         *msg,
242 			    unsigned char *rdata,
243 			    unsigned int  *rdata_len,
244 			    void          *cb_data)
245 {
246     ipmi_sol_t *sol = &mc->sol;
247     unsigned char databyte = 0;
248 
249     if (!mc->sol.configured) {
250 	handle_invalid_cmd(mc, rdata, rdata_len);
251 	return;
252     }
253 
254     if (msg->len < 4) {
255 	rdata[0] = IPMI_REQUEST_DATA_LENGTH_INVALID_CC;
256 	*rdata_len = 1;
257 	return;
258     }
259 
260     /*
261      * There is a channel in this message, but as far as I can tell,
262      * it is completely without point.  The data is generic to the
263      * management controller.  So just ignore it.
264      */
265 
266     switch (msg->data[1]) {
267     case 0:
268 	databyte = sol->set_in_progress;
269 	break;
270 
271     case 1:
272 	databyte = sol->solparm.enabled;
273 	break;
274 
275     case 5:
276 	databyte = sol->solparm.bitrate_nonv;
277 	break;
278 
279     case 6:
280 	databyte = sol->solparm.bitrate;
281 	break;
282 
283     default:
284 	rdata[0] = 0x80; /* Parm not supported */
285 	*rdata_len = 1;
286 	return;
287     }
288 
289     rdata[0] = 0;
290     rdata[1] = 0x11;
291     rdata[2] = databyte;
292     *rdata_len = 3;
293 }
294 
295 cmd_handler_f transport_netfn_handlers[256] = {
296     [IPMI_SET_LAN_CONFIG_PARMS_CMD] = handle_ipmi_set_lan_config_parms,
297     [IPMI_GET_LAN_CONFIG_PARMS_CMD] = handle_ipmi_get_lan_config_parms,
298     [IPMI_SET_SOL_CONFIGURATION_PARAMETERS] = handle_set_sol_config_parms,
299     [IPMI_GET_SOL_CONFIGURATION_PARAMETERS] = handle_get_sol_config_parms
300 };
301