1 /*
2  * lanserv_force_oem.c
3  *
4  * MontaVista IPMI IPMI LAN code for OEM Force Computers board handling
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2003 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 <stdlib.h>
51 
52 #include <OpenIPMI/ipmi_auth.h>
53 #include <OpenIPMI/serv.h>
54 
55 typedef struct force_oem_data_s
56 {
57     unsigned char slave_addr;
58     unsigned char curr_addr;
59 } force_oem_data_t;
60 
61 static int
force_rsp_handler(channel_t * chan,msg_t * msg,rsp_msg_t * rsp)62 force_rsp_handler(channel_t *chan, msg_t *msg, rsp_msg_t *rsp)
63 {
64     unsigned char new_addr;
65 
66     if (rsp->netfn == 0x31) {
67 	/* A force OEM response. */
68 	force_oem_data_t *fdata = chan->oem.oem_data;
69 
70 	switch (rsp->cmd)
71 	{
72 	    case 3:
73 		/* A response to a change mode. */
74 
75 		/* Ignore errors. */
76 		if (rsp->data_len < 1)
77 		    return 0;
78 		if (rsp->data[0] != 0)
79 		    return 0;
80 
81 		/* See what it was changed to. */
82 		if (msg->data[0] == 0)
83 		    /* Changed to master, address is 0x20 */
84 		    new_addr = 0x20;
85 		else
86 		    new_addr = fdata->slave_addr;
87 
88 		if (new_addr != fdata->curr_addr) {
89 		    fdata->curr_addr = fdata->slave_addr;
90 		    chan->log(chan, INFO, NULL,
91 			      "Change Force MC address to 0x%x", new_addr);
92 		    if (chan->oem.ipmb_addr_change)
93 			chan->oem.ipmb_addr_change(chan, fdata->curr_addr);
94 		}
95 		break;
96 
97 	    case 4:
98 		/* A request for the IPMB address. */
99 
100 		/* Ignore errors. */
101 		if (rsp->data_len < 4)
102 		    return 0;
103 		if (rsp->data[0] != 0)
104 		    return 0;
105 
106 		fdata->slave_addr = rsp->data[3];
107 		if (fdata->curr_addr != rsp->data[2]) {
108 		    fdata->curr_addr = rsp->data[2];
109 		    if (chan->oem.ipmb_addr_change)
110 			chan->oem.ipmb_addr_change(chan, fdata->curr_addr);
111 		}
112 
113 		return msg->oem_data;
114 	}
115     }
116 
117     return 0;
118 }
119 
120 static int
force_check_permitted(unsigned char priv,unsigned char netfn,unsigned char cmd)121 force_check_permitted(unsigned char priv,
122 		      unsigned char netfn,
123 		      unsigned char cmd)
124 {
125     int req_priv = IPMI_PRIVILEGE_ADMIN;
126 
127     if (netfn != 0x30)
128 	return IPMI_PRIV_INVALID;
129 
130     switch (cmd)
131     {
132 	case 3:
133 	    req_priv = IPMI_PRIVILEGE_OPERATOR;
134 	    break;
135 
136 	case 4:
137 	    req_priv = IPMI_PRIVILEGE_USER;
138 	    break;
139 
140 	case 5:
141 	    req_priv = IPMI_PRIVILEGE_USER;
142 	    break;
143 
144 	case 6:
145 	    req_priv = IPMI_PRIVILEGE_OPERATOR;
146 	    break;
147     }
148 
149     if (priv >= req_priv)
150 	return IPMI_PRIV_PERMITTED;
151     else
152 	return IPMI_PRIV_DENIED;
153 }
154 
155 static force_oem_data_t force_data =
156 {
157     .slave_addr = 0,
158     .curr_addr  = 0,
159 };
160 
161 static void
force_oem_installer(channel_t * chan,void * cb_data)162 force_oem_installer(channel_t *chan, void *cb_data)
163 {
164     chan->oem.oem_handle_rsp = force_rsp_handler;
165     chan->oem.oem_check_permitted = force_check_permitted;
166     chan->oem.oem_data = &force_data;
167 
168     /* Set a command to get the current address. */
169     ipmi_oem_send_msg(chan, 0x30, 4, NULL, 0, 1);
170 }
171 
172 static oem_handler_t force_735_oem =
173 {
174     .manufacturer_id = 0x000e48,
175     .product_id      = 0x0804,
176     .handler         = force_oem_installer,
177     .cb_data         = NULL,
178 };
179 
180 static oem_handler_t force_740_oem =
181 {
182     .manufacturer_id = 0x000e48,
183     .product_id      = 0x0808,
184     .handler         = force_oem_installer,
185     .cb_data         = NULL,
186 };
187 
188 static oem_handler_t force_786_oem =
189 {
190     .manufacturer_id = 0x000e48,
191     .product_id      = 0x0810,
192     .handler         = force_oem_installer,
193     .cb_data         = NULL,
194 };
195 
196 static oem_handler_t force_550_oem =
197 {
198     .manufacturer_id = 0x000e48,
199     .product_id      = 0x0880,
200     .handler         = force_oem_installer,
201     .cb_data         = NULL,
202 };
203 
204 static oem_handler_t force_560_oem =
205 {
206     .manufacturer_id = 0x000e48,
207     .product_id      = 0x0888,
208     .handler         = force_oem_installer,
209     .cb_data         = NULL,
210 };
211 
212 static oem_handler_t force_690_oem =
213 {
214     .manufacturer_id = 0x000e48,
215     .product_id      = 0x0900,
216     .handler         = force_oem_installer,
217     .cb_data         = NULL,
218 };
219 
220 static oem_handler_t force_695_oem =
221 {
222     .manufacturer_id = 0x000e48,
223     .product_id      = 0x0904,
224     .handler         = force_oem_installer,
225     .cb_data         = NULL,
226 };
227 
228 
229 void
init_oem_force(void)230 init_oem_force(void)
231 {
232     ipmi_register_oem(&force_735_oem);
233     ipmi_register_oem(&force_740_oem);
234     ipmi_register_oem(&force_786_oem);
235     ipmi_register_oem(&force_550_oem);
236     ipmi_register_oem(&force_560_oem);
237     ipmi_register_oem(&force_690_oem);
238     ipmi_register_oem(&force_695_oem);
239 }
240 
241 #if 0
242 /* If you include this as a module under Linux, you can use the
243    following code to initialize it.  Otherwise, something has to call
244    init_oem_force(). */
245 static void (*const __init_patch_debug[1])                                    \
246    (void) __attribute__ ((section(".ctors"))) = { init_oem_force };
247 #endif
248