1 /*
2  * bmc_storage.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 <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #include <time.h>
60 
61 #include <OpenIPMI/ipmi_err.h>
62 #include <OpenIPMI/ipmi_msgbits.h>
63 #include <OpenIPMI/persist.h>
64 
65 /*
66  * SEL handling commands.
67  */
68 
69 #define IPMI_SEL_SUPPORTS_DELETE         (1 << 3)
70 #define IPMI_SEL_SUPPORTS_RESERVE        (1 << 1)
71 #define IPMI_SEL_SUPPORTS_GET_ALLOC_INFO (1 << 0)
72 
73 static sel_entry_t *
find_sel_event_by_recid(lmc_data_t * mc,uint16_t record_id,sel_entry_t ** prev)74 find_sel_event_by_recid(lmc_data_t  *mc,
75 			uint16_t    record_id,
76 			sel_entry_t **prev)
77 {
78     sel_entry_t *entry;
79     sel_entry_t *p_entry = NULL;
80 
81     entry = mc->sel.entries;
82     while (entry) {
83 	if (record_id == entry->record_id)
84 	    break;
85 	p_entry = entry;
86 	entry = entry->next;
87     }
88     if (prev)
89 	*prev = p_entry;
90     return entry;
91 }
92 
93 static int
handle_sel(const char * name,void * data,unsigned int len,void * cb_data)94 handle_sel(const char *name, void *data, unsigned int len, void *cb_data)
95 {
96     sel_entry_t *e, *n;
97     lmc_data_t *mc = cb_data;
98 
99     if (len != 16) {
100 	mc->sysinfo->log(mc->sysinfo, INFO, NULL,
101 			 "Got invalid SEL entry for %2.2x, name is %s",
102 			 ipmi_mc_get_ipmb(mc), name);
103 	goto out;
104     }
105 
106     n = malloc(sizeof(*n));
107     if (!n)
108 	return ENOMEM;
109 
110     memcpy(n->data, data, 16);
111     n->record_id = n->data[0] | (n->data[1] << 8);
112     n->next = NULL;
113 
114     e = mc->sel.entries;
115     if (!e)
116 	mc->sel.entries = n;
117     else {
118 	while (e->next)
119 	    e = e->next;
120 	e->next = n;
121     }
122     mc->sel.count++;
123 
124   out:
125     return ITER_PERSIST_CONTINUE;
126 }
127 
128 static int
handle_sel_time(const char * name,long val,void * cb_data)129 handle_sel_time(const char *name, long val, void *cb_data)
130 {
131     lmc_data_t *mc = cb_data;
132 
133     if (strcmp(name, "last_add_time") == 0)
134 	mc->sel.last_add_time = val;
135     else if (strcmp(name, "last_erase_time") == 0)
136 	mc->sel.last_erase_time = val;
137     return ITER_PERSIST_CONTINUE;
138 }
139 
140 int
ipmi_mc_enable_sel(lmc_data_t * mc,int max_entries,unsigned char flags)141 ipmi_mc_enable_sel(lmc_data_t    *mc,
142 		   int           max_entries,
143 		   unsigned char flags)
144 {
145     persist_t *p;
146 
147     mc->sel.entries = NULL;
148     mc->sel.count = 0;
149     mc->sel.max_count = max_entries;
150     mc->sel.last_add_time = 0;
151     mc->sel.last_erase_time = 0;
152     mc->sel.flags = flags & 0xb;
153     mc->sel.reservation = 0;
154     mc->sel.next_entry = 1;
155 
156     p = read_persist("sel.%2.2x", ipmi_mc_get_ipmb(mc));
157     if (!p)
158 	return 0;
159 
160     iterate_persist(p, mc, handle_sel, handle_sel_time);
161     free_persist(p);
162     return 0;
163 }
164 
165 static void
rewrite_sels(lmc_data_t * mc)166 rewrite_sels(lmc_data_t *mc)
167 {
168     persist_t *p = NULL;
169     sel_entry_t *e;
170     int err;
171 
172     p = alloc_persist("sel.%2.2x", ipmi_mc_get_ipmb(mc));
173     if (!p) {
174 	err = ENOMEM;
175 	goto out_err;
176     }
177 
178     err = add_persist_int(p, mc->sel.last_add_time, "last_add_time");
179     if (err)
180 	goto out_err;
181 
182     err = add_persist_int(p, mc->sel.last_erase_time, "last_erase_time");
183     if (err)
184 	goto out_err;
185 
186     for (e = mc->sel.entries; e; e = e->next) {
187 	err = add_persist_data(p, e->data, 16, "%d", e->record_id);
188 	if (err)
189 	    goto out_err;
190     }
191 
192     err = write_persist(p);
193     if (err)
194 	goto out_err;
195     free_persist(p);
196     return;
197 
198   out_err:
199     mc->sysinfo->log(mc->sysinfo, OS_ERROR, NULL,
200 		     "Unable to write persistent SELs for MC %d: %d",
201 		     ipmi_mc_get_ipmb(mc), err);
202     if (p)
203 	free_persist(p);
204 }
205 
206 int
ipmi_mc_add_to_sel(lmc_data_t * mc,unsigned char record_type,unsigned char event[13],unsigned int * recid)207 ipmi_mc_add_to_sel(lmc_data_t    *mc,
208 		   unsigned char record_type,
209 		   unsigned char event[13],
210 		   unsigned int  *recid)
211 {
212     sel_entry_t    *e;
213     struct timeval t;
214     uint16_t       start_record_id;
215 
216     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE))
217 	return ENOTSUP;
218 
219     if (mc->sel.count >= mc->sel.max_count) {
220 	mc->sel.flags |= 0x80;
221 	return EAGAIN;
222     }
223 
224     e = malloc(sizeof(*e));
225     if (!e)
226 	return ENOMEM;
227 
228     /* FIXME - this is inefficient, but simple */
229     e->record_id = mc->sel.next_entry;
230     mc->sel.next_entry++;
231     start_record_id = e->record_id;
232     while ((mc->sel.next_entry == 0)
233 	   || find_sel_event_by_recid(mc, e->record_id, NULL))
234     {
235 	e->record_id++;
236 	if (e->record_id == start_record_id) {
237 	    free(e);
238 	    return EAGAIN;
239 	}
240 	mc->sel.next_entry++;
241     }
242 
243     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
244 
245     ipmi_set_uint16(e->data, e->record_id);
246     e->data[2] = record_type;
247     if (record_type < 0xe0) {
248 	ipmi_set_uint32(e->data+3, t.tv_sec + mc->sel.time_offset);
249 	memcpy(e->data+7, event+4, 9);
250     } else {
251 	memcpy(e->data+3, event, 13);
252     }
253 
254     e->next = NULL;
255     if (!mc->sel.entries) {
256 	mc->sel.entries = e;
257     } else {
258 	sel_entry_t *f = mc->sel.entries;
259 	while (f->next)
260 	    f = f->next;
261 	f->next = e;
262     }
263 
264     mc->sel.count++;
265 
266     mc->sel.last_add_time = t.tv_sec + mc->sel.time_offset;
267 
268     if (recid)
269 	*recid = e->record_id;
270 
271     rewrite_sels(mc);
272 
273     return 0;
274 }
275 
276 void
mc_new_event(lmc_data_t * mc,unsigned char record_type,unsigned char event[13])277 mc_new_event(lmc_data_t *mc,
278 	     unsigned char record_type,
279 	     unsigned char event[13])
280 {
281     unsigned int recid;
282     int rv;
283 
284     if (IPMI_MC_EVENT_LOG_ENABLED(mc)) {
285 	rv = ipmi_mc_add_to_sel(mc, record_type, event, &recid);
286 	if (rv)
287 	    recid = 0xffff;
288     } else
289 	recid = 0xffff;
290     if (!mc->ev_in_q && IPMI_MC_EVENT_MSG_BUF_ENABLED(mc)) {
291 	channel_t *chan = mc->channels[15];
292 	mc->ev_in_q = 1;
293 	ipmi_set_uint16(mc->evq, recid);
294 	mc->evq[2] = record_type;
295 	memcpy(mc->evq + 3, event, 13);
296 	mc->msg_flags |= IPMI_MC_MSG_FLAG_EVT_BUF_FULL;
297 	if (chan->set_atn)
298 	    chan->set_atn(chan, 1, IPMI_MC_EVBUF_FULL_INT_ENABLED(mc));
299     }
300 }
301 
302 static void
handle_get_sel_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)303 handle_get_sel_info(lmc_data_t    *mc,
304 		    msg_t         *msg,
305 		    unsigned char *rdata,
306 		    unsigned int  *rdata_len,
307 		    void          *cb_data)
308 {
309     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
310 	handle_invalid_cmd(mc, rdata, rdata_len);
311 	return;
312     }
313 
314     memset(rdata, 0, 15);
315     rdata[1] = 0x51;
316     ipmi_set_uint16(rdata+2, mc->sel.count);
317     ipmi_set_uint16(rdata+4, (mc->sel.max_count - mc->sel.count) * 16);
318     ipmi_set_uint32(rdata+6, mc->sel.last_add_time);
319     ipmi_set_uint32(rdata+10, mc->sel.last_erase_time);
320     rdata[14] = mc->sel.flags;
321 
322     *rdata_len = 15;
323 }
324 
325 static void
handle_get_sel_allocation_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)326 handle_get_sel_allocation_info(lmc_data_t    *mc,
327 			       msg_t         *msg,
328 			       unsigned char *rdata,
329 			       unsigned int  *rdata_len,
330 			       void          *cb_data)
331 {
332     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
333 	handle_invalid_cmd(mc, rdata, rdata_len);
334 	return;
335     }
336 
337     if (!(mc->sel.flags & IPMI_SEL_SUPPORTS_GET_ALLOC_INFO)) {
338 	handle_invalid_cmd(mc, rdata, rdata_len);
339 	return;
340     }
341 
342     memset(rdata, 0, 10);
343     ipmi_set_uint16(rdata+1, mc->sel.max_count * 16);
344     ipmi_set_uint16(rdata+3, 16);
345     ipmi_set_uint32(rdata+5, (mc->sel.max_count - mc->sel.count) * 16);
346     ipmi_set_uint32(rdata+7, (mc->sel.max_count - mc->sel.count) * 16);
347     rdata[9] = 1;
348 
349     *rdata_len = 10;
350 }
351 
352 static void
handle_reserve_sel(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)353 handle_reserve_sel(lmc_data_t    *mc,
354 		   msg_t         *msg,
355 		   unsigned char *rdata,
356 		   unsigned int  *rdata_len,
357 		   void          *cb_data)
358 {
359     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
360 	handle_invalid_cmd(mc, rdata, rdata_len);
361 	return;
362     }
363 
364     if (!(mc->sel.flags & IPMI_SEL_SUPPORTS_RESERVE)) {
365 	handle_invalid_cmd(mc, rdata, rdata_len);
366 	return;
367     }
368 
369     mc->sel.reservation++;
370     if (mc->sel.reservation == 0)
371 	mc->sel.reservation++;
372     rdata[0] = 0;
373     ipmi_set_uint16(rdata+1, mc->sel.reservation);
374     *rdata_len = 3;
375 }
376 
377 static void
handle_get_sel_entry(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)378 handle_get_sel_entry(lmc_data_t    *mc,
379 		     msg_t         *msg,
380 		     unsigned char *rdata,
381 		     unsigned int  *rdata_len,
382 		     void          *cb_data)
383 {
384     uint16_t    record_id;
385     int         offset;
386     int         count;
387     sel_entry_t *entry;
388 
389     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
390 	handle_invalid_cmd(mc, rdata, rdata_len);
391 	return;
392     }
393 
394     if (check_msg_length(msg, 6, rdata, rdata_len))
395 	return;
396 
397     if (mc->sel.flags & IPMI_SEL_SUPPORTS_RESERVE) {
398 	uint16_t reservation = ipmi_get_uint16(msg->data+0);
399 
400 	if ((reservation != 0) && (reservation != mc->sel.reservation)) {
401 	    rdata[0] = IPMI_INVALID_RESERVATION_CC;
402 	    *rdata_len = 1;
403 	    return;
404 	}
405     }
406 
407     record_id = ipmi_get_uint16(msg->data+2);
408     offset = msg->data[4];
409     count = msg->data[5];
410 
411     if (offset >= 16) {
412 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
413 	*rdata_len = 1;
414 	return;
415     }
416 
417     if (record_id == 0) {
418 	entry = mc->sel.entries;
419     } else if (record_id == 0xffff) {
420 	entry = mc->sel.entries;
421 	if (entry) {
422 	    while (entry->next) {
423 		entry = entry->next;
424 	    }
425 	}
426     } else {
427 	entry = find_sel_event_by_recid(mc, record_id, NULL);
428     }
429 
430     if (entry == NULL) {
431 	rdata[0] = IPMI_NOT_PRESENT_CC;
432 	*rdata_len = 1;
433 	return;
434     }
435 
436     rdata[0] = 0;
437     if (entry->next)
438 	ipmi_set_uint16(rdata+1, entry->next->record_id);
439     else {
440 	rdata[1] = 0xff;
441 	rdata[2] = 0xff;
442     }
443 
444     if ((offset+count) > 16)
445 	count = 16 - offset;
446     memcpy(rdata+3, entry->data+offset, count);
447     *rdata_len = count + 3;
448 }
449 
450 static void
handle_add_sel_entry(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)451 handle_add_sel_entry(lmc_data_t    *mc,
452 		     msg_t         *msg,
453 		     unsigned char *rdata,
454 		     unsigned int  *rdata_len,
455 		     void          *cb_data)
456 {
457     int          rv;
458     unsigned int r;
459 
460     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
461 	handle_invalid_cmd(mc, rdata, rdata_len);
462 	return;
463     }
464 
465     if (check_msg_length(msg, 16, rdata, rdata_len))
466 	return;
467 
468     rv = ipmi_mc_add_to_sel(mc, msg->data[2], msg->data+3, &r);
469     if (rv == EAGAIN) {
470 	rdata[0] = IPMI_OUT_OF_SPACE_CC;
471     } else if (rv) {
472 	rdata[0] = IPMI_UNKNOWN_ERR_CC;
473     } else {
474 	rdata[0] = 0;
475 	ipmi_set_uint16(rdata+1, r);
476     }
477     *rdata_len = 3;
478 }
479 
480 static void
handle_delete_sel_entry(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)481 handle_delete_sel_entry(lmc_data_t    *mc,
482 			msg_t         *msg,
483 			unsigned char *rdata,
484 			unsigned int  *rdata_len,
485 			void          *cb_data)
486 {
487     uint16_t    record_id;
488     sel_entry_t *entry, *p_entry;
489 
490     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
491 	handle_invalid_cmd(mc, rdata, rdata_len);
492 	return;
493     }
494 
495     if (!(mc->sel.flags & IPMI_SEL_SUPPORTS_DELETE)) {
496 	handle_invalid_cmd(mc, rdata, rdata_len);
497 	return;
498     }
499 
500     if (check_msg_length(msg, 4, rdata, rdata_len))
501 	return;
502 
503     if (mc->sel.flags & IPMI_SEL_SUPPORTS_RESERVE) {
504 	uint16_t reservation = ipmi_get_uint16(msg->data+0);
505 
506 	if ((reservation != 0) && (reservation != mc->sel.reservation)) {
507 	    rdata[0] = IPMI_INVALID_RESERVATION_CC;
508 	    *rdata_len = 1;
509 	    return;
510 	}
511     }
512 
513     record_id = ipmi_get_uint16(msg->data+2);
514 
515     if (record_id == 0) {
516 	entry = mc->sel.entries;
517 	p_entry = NULL;
518     } else if (record_id == 0xffff) {
519 	entry = mc->sel.entries;
520 	p_entry = NULL;
521 	if (entry) {
522 	    while (entry->next) {
523 		p_entry = entry;
524 		entry = entry->next;
525 	    }
526 	}
527     } else {
528 	entry = find_sel_event_by_recid(mc, record_id, &p_entry);
529     }
530     if (!entry) {
531 	rdata[0] = IPMI_NOT_PRESENT_CC;
532 	*rdata_len = 1;
533 	return;
534     }
535 
536     if (p_entry)
537 	p_entry->next = entry->next;
538     else
539 	mc->sel.entries = entry->next;
540 
541     /* Clear the overflow flag. */
542     mc->sel.flags &= ~0x80;
543 
544     rdata[0] = 0;
545     ipmi_set_uint16(rdata+1, entry->record_id);
546     *rdata_len = 3;
547 
548     mc->sel.count--;
549     free(entry);
550 
551     rewrite_sels(mc);
552 }
553 
554 static void
handle_clear_sel(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)555 handle_clear_sel(lmc_data_t    *mc,
556 		 msg_t         *msg,
557 		 unsigned char *rdata,
558 		 unsigned int  *rdata_len,
559 		 void          *cb_data)
560 {
561     sel_entry_t    *entry, *n_entry;
562     unsigned char  op;
563     struct timeval t;
564 
565     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
566 	handle_invalid_cmd(mc, rdata, rdata_len);
567 	return;
568     }
569 
570     if (check_msg_length(msg, 6, rdata, rdata_len))
571 	return;
572 
573     if (mc->sel.flags & IPMI_SEL_SUPPORTS_RESERVE) {
574 	uint16_t reservation = ipmi_get_uint16(msg->data+0);
575 
576 	if ((reservation != 0) && (reservation != mc->sel.reservation)) {
577 	    rdata[0] = IPMI_INVALID_RESERVATION_CC;
578 	    *rdata_len = 1;
579 	    return;
580 	}
581     }
582 
583     if ((msg->data[2] != 'C')
584 	|| (msg->data[3] != 'L')
585 	|| (msg->data[4] != 'R'))
586     {
587 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
588 	*rdata_len = 1;
589 	return;
590     }
591 
592     op = msg->data[5];
593     if ((op != 0) && (op != 0xaa))
594     {
595 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
596 	*rdata_len = 1;
597 	return;
598     }
599 
600     rdata[1] = 1;
601     if (op == 0xaa) {
602 	entry = mc->sel.entries;
603 	mc->sel.entries = NULL;
604 	mc->sel.count = 0;
605 	while (entry) {
606 	    n_entry = entry->next;
607 	    free(entry);
608 	    entry = n_entry;
609 	}
610     }
611 
612     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
613     mc->sel.last_erase_time = t.tv_sec + mc->sel.time_offset;
614 
615     rdata[0] = 0;
616     *rdata_len = 2;
617 
618     /* Clear the overflow flag. */
619     mc->sel.flags &= ~0x80;
620 
621     rewrite_sels(mc);
622 }
623 
624 static void
handle_get_sel_time(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)625 handle_get_sel_time(lmc_data_t    *mc,
626 		    msg_t         *msg,
627 		    unsigned char *rdata,
628 		    unsigned int  *rdata_len,
629 		    void          *cb_data)
630 {
631     struct timeval t;
632 
633     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
634 	handle_invalid_cmd(mc, rdata, rdata_len);
635 	return;
636     }
637 
638     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
639     rdata[0] = 0;
640     ipmi_set_uint32(rdata+1, t.tv_sec + mc->sel.time_offset);
641     *rdata_len = 5;
642 }
643 
644 static void
handle_set_sel_time(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)645 handle_set_sel_time(lmc_data_t    *mc,
646 		    msg_t         *msg,
647 		    unsigned char *rdata,
648 		    unsigned int  *rdata_len,
649 		    void          *cb_data)
650 {
651     struct timeval t;
652 
653     if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
654 	handle_invalid_cmd(mc, rdata, rdata_len);
655 	return;
656     }
657 
658     if (check_msg_length(msg, 4, rdata, rdata_len))
659 	return;
660 
661     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
662     mc->sel.time_offset = ipmi_get_uint32(msg->data) - t.tv_sec;
663 
664     rdata[0] = 0;
665     *rdata_len = 1;
666 }
667 
668 /*
669  * SDR handling commands
670  */
671 
672 #define IPMI_SDR_OVERFLOW_FLAG				(1 << 7)
673 #define IPMI_SDR_GET_MODAL(v)   (((v) >> 5) & 0x3)
674 #define IPMI_SDR_MODAL_UNSPECIFIED	0
675 #define IPMI_SDR_NON_MODAL_ONLY		1
676 #define IPMI_SDR_MODAL_ONLY		2
677 #define IPMI_SDR_MODAL_BOTH		3
678 
679 sdr_t *
find_sdr_by_recid(sdrs_t * sdrs,uint16_t record_id,sdr_t ** prev)680 find_sdr_by_recid(sdrs_t     *sdrs,
681 		  uint16_t   record_id,
682 		  sdr_t      **prev)
683 {
684     sdr_t *entry;
685     sdr_t *p_entry = NULL;
686 
687     entry = sdrs->sdrs;
688     while (entry) {
689 	if (record_id == entry->record_id)
690 	    break;
691 	p_entry = entry;
692 	entry = entry->next;
693     }
694     if (prev)
695 	*prev = p_entry;
696     return entry;
697 }
698 
699 sdr_t *
new_sdr_entry(sdrs_t * sdrs,unsigned char length)700 new_sdr_entry(sdrs_t *sdrs, unsigned char length)
701 {
702     sdr_t    *entry;
703     uint16_t start_recid;
704 
705     start_recid = sdrs->next_entry;
706     while (find_sdr_by_recid(sdrs, sdrs->next_entry, NULL)) {
707 	sdrs->next_entry++;
708 	if (sdrs->next_entry == 0xffff)
709 	    sdrs->next_entry = 1;
710 	if (sdrs->next_entry == start_recid)
711 	    return NULL;
712     }
713 
714     entry = malloc(sizeof(*entry));
715     if (!entry)
716 	return NULL;
717 
718     entry->data = malloc(length + 6);
719     if (!entry->data) {
720 	free(entry);
721 	return NULL;
722     }
723 
724     entry->record_id = sdrs->next_entry;
725 
726     sdrs->next_entry++;
727 
728     ipmi_set_uint16(entry->data, entry->record_id);
729 
730     entry->length = length + 6;
731     entry->next = NULL;
732     return entry;
733 }
734 
735 static void
rewrite_sdrs(lmc_data_t * mc,sdrs_t * sdrs)736 rewrite_sdrs(lmc_data_t *mc, sdrs_t *sdrs)
737 {
738     persist_t *p = NULL;
739     sdr_t *sdr;
740     int err;
741 
742     p = alloc_persist("sdr.%2.2x.main", ipmi_mc_get_ipmb(mc));
743     if (!p) {
744 	err = ENOMEM;
745 	goto out_err;
746     }
747 
748     err = add_persist_int(p, sdrs->last_add_time, "last_add_time");
749     if (err)
750 	goto out_err;
751 
752     err = add_persist_int(p, sdrs->last_erase_time, "last_erase_time");
753     if (err)
754 	goto out_err;
755 
756     for (sdr = sdrs->sdrs; sdr; sdr = sdr->next) {
757 	unsigned int recid = ipmi_get_uint16(sdr->data);
758 	err = add_persist_data(p, sdr->data, sdr->length, "%d", recid);
759 	if (err)
760 	    goto out_err;
761     }
762 
763     err = write_persist(p);
764     if (err)
765 	goto out_err;
766     free_persist(p);
767     return;
768 
769   out_err:
770     mc->sysinfo->log(mc->sysinfo, OS_ERROR, NULL,
771 		     "Unable to write persistent SDRs for MC %d: %d",
772 		     ipmi_mc_get_ipmb(mc), err);
773     if (p)
774 	free_persist(p);
775 }
776 
777 void
add_sdr_entry(lmc_data_t * mc,sdrs_t * sdrs,sdr_t * entry)778 add_sdr_entry(lmc_data_t *mc, sdrs_t *sdrs, sdr_t *entry)
779 {
780     sdr_t          *p;
781     struct timeval t;
782 
783     entry->next = NULL;
784     p = sdrs->sdrs;
785     if (!p)
786 	sdrs->sdrs = entry;
787     else {
788 	while (p->next)
789 	    p = p->next;
790 	p->next = entry;
791     }
792 
793     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
794     sdrs->last_add_time = t.tv_sec + mc->main_sdrs.time_offset;
795     sdrs->sdr_count++;
796 
797     rewrite_sdrs(mc, sdrs);
798 }
799 
800 static void
free_sdr(sdr_t * sdr)801 free_sdr(sdr_t *sdr)
802 {
803     free(sdr->data);
804     free(sdr);
805 }
806 
807 static int
handle_sdr(const char * name,void * data,unsigned int len,void * cb_data)808 handle_sdr(const char *name, void *data, unsigned int len, void *cb_data)
809 {
810     sdr_t *sdr, *p;
811     sdrs_t *sdrs = cb_data;
812 
813     sdr = new_sdr_entry(sdrs, len);
814     if (!sdr)
815 	return ENOMEM;
816     memcpy(sdr->data, data, len);
817 
818     sdr->next = NULL;
819     p = sdrs->sdrs;
820     if (!p)
821 	sdrs->sdrs = sdr;
822     else {
823 	while (p->next)
824 	    p = p->next;
825 	p->next = sdr;
826     }
827     sdrs->sdr_count++;
828 
829     return ITER_PERSIST_CONTINUE;
830 }
831 
832 static int
handle_sdr_time(const char * name,long val,void * cb_data)833 handle_sdr_time(const char *name, long val, void *cb_data)
834 {
835     sdrs_t *sdrs = cb_data;
836 
837     if (strcmp(name, "last_add_time") == 0)
838 	sdrs->last_add_time = val;
839     else if (strcmp(name, "last_erase_time") == 0)
840 	sdrs->last_erase_time = val;
841     return ITER_PERSIST_CONTINUE;
842 }
843 
844 void
read_mc_sdrs(lmc_data_t * mc,sdrs_t * sdrs,const char * sdrtype)845 read_mc_sdrs(lmc_data_t *mc, sdrs_t *sdrs, const char *sdrtype)
846 {
847     persist_t *p;
848 
849     p = read_persist("sdr.%2.2x.%s", ipmi_mc_get_ipmb(mc), sdrtype);
850     if (!p)
851 	return;
852 
853     iterate_persist(p, sdrs, handle_sdr, handle_sdr_time);
854     free_persist(p);
855 }
856 
857 int
ipmi_mc_add_main_sdr(lmc_data_t * mc,unsigned char * data,unsigned int data_len)858 ipmi_mc_add_main_sdr(lmc_data_t    *mc,
859 		     unsigned char *data,
860 		     unsigned int  data_len)
861 {
862     sdr_t *entry;
863 
864     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV))
865 	return ENOSYS;
866 
867     if ((data_len < 5) || (data_len != (((unsigned int) data[4]) + 5)))
868 	return EINVAL;
869 
870     entry = new_sdr_entry(&mc->main_sdrs, data_len);
871     if (!entry)
872 	return ENOMEM;
873 
874     memcpy(entry->data+2, data+2, data_len-2);
875 
876     add_sdr_entry(mc, &mc->main_sdrs, entry);
877 
878     return 0;
879 }
880 
881 int
ipmi_mc_add_device_sdr(lmc_data_t * mc,unsigned char lun,unsigned char * data,unsigned int data_len)882 ipmi_mc_add_device_sdr(lmc_data_t    *mc,
883 		       unsigned char lun,
884 		       unsigned char *data,
885 		       unsigned int  data_len)
886 {
887     struct timeval t;
888     sdr_t          *entry;
889 
890     if (lun >= 4)
891 	return EINVAL;
892 
893     if (!(mc->has_device_sdrs)) {
894 	return ENOSYS;
895     }
896 
897     entry = new_sdr_entry(&mc->device_sdrs[lun], data_len);
898     if (!entry)
899 	return ENOMEM;
900 
901     add_sdr_entry(mc, &mc->device_sdrs[lun], entry);
902 
903     memcpy(entry->data+2, data+2, data_len-2);
904 
905     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
906     mc->sensor_population_change_time = t.tv_sec + mc->main_sdrs.time_offset;
907     mc->lun_has_sensors[lun] = 1;
908     mc->num_sensors_per_lun[lun]++;
909     return 0;
910 }
911 
912 static void
handle_get_sdr_repository_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)913 handle_get_sdr_repository_info(lmc_data_t    *mc,
914 			       msg_t         *msg,
915 			       unsigned char *rdata,
916 			       unsigned int  *rdata_len,
917 			       void          *cb_data)
918 {
919     unsigned int space;
920 
921     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
922 	handle_invalid_cmd(mc, rdata, rdata_len);
923 	return;
924     }
925 
926     rdata[0] = 0;
927     rdata[1] = 0x51;
928     ipmi_set_uint16(rdata+2, mc->main_sdrs.sdr_count);
929     space = MAX_SDR_LENGTH * (MAX_NUM_SDRS - mc->main_sdrs.sdr_count);
930     if (space > 0xfffe)
931 	space = 0xfffe;
932     ipmi_set_uint16(rdata+4, space);
933     ipmi_set_uint32(rdata+6, mc->main_sdrs.last_add_time);
934     ipmi_set_uint32(rdata+10, mc->main_sdrs.last_erase_time);
935     rdata[14] = mc->main_sdrs.flags;
936     *rdata_len = 15;
937 }
938 
939 static void
handle_get_sdr_repository_alloc_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)940 handle_get_sdr_repository_alloc_info(lmc_data_t    *mc,
941 				     msg_t         *msg,
942 				     unsigned char *rdata,
943 				     unsigned int  *rdata_len,
944 				     void          *cb_data)
945 {
946     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
947 	handle_invalid_cmd(mc, rdata, rdata_len);
948 	return;
949     }
950 
951     if (!(mc->main_sdrs.flags & IPMI_SDR_GET_SDR_ALLOC_INFO_SDR_SUPPORTED)) {
952 	handle_invalid_cmd(mc, rdata, rdata_len);
953 	return;
954     }
955 
956     rdata[0] = 0;
957     ipmi_set_uint16(rdata+1, MAX_NUM_SDRS);
958     ipmi_set_uint16(rdata+3, MAX_SDR_LENGTH);
959     ipmi_set_uint16(rdata+5, MAX_NUM_SDRS - mc->main_sdrs.sdr_count);
960     ipmi_set_uint16(rdata+7, MAX_NUM_SDRS - mc->main_sdrs.sdr_count);
961     rdata[9] = 1;
962     *rdata_len = 10;
963 }
964 
965 static void
handle_reserve_sdr_repository(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)966 handle_reserve_sdr_repository(lmc_data_t    *mc,
967 			      msg_t         *msg,
968 			      unsigned char *rdata,
969 			      unsigned int  *rdata_len,
970 			      void          *cb_data)
971 {
972     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
973 	handle_invalid_cmd(mc, rdata, rdata_len);
974 	return;
975     }
976 
977     if (!(mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED)) {
978 	handle_invalid_cmd(mc, rdata, rdata_len);
979 	return;
980     }
981 
982     mc->main_sdrs.reservation++;
983     if (mc->main_sdrs.reservation == 0)
984 	mc->main_sdrs.reservation++;
985 
986     rdata[0] = 0;
987     ipmi_set_uint16(rdata+1, mc->main_sdrs.reservation);
988     *rdata_len = 3;
989 
990     /* If adding an SDR and the reservation changes, we have to
991        destroy the working SDR addition. */
992     if (mc->part_add_sdr) {
993 	free_sdr(mc->part_add_sdr);
994 	mc->part_add_sdr = NULL;
995     }
996 }
997 
998 static void
handle_get_sdr(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)999 handle_get_sdr(lmc_data_t    *mc,
1000 	       msg_t         *msg,
1001 	       unsigned char *rdata,
1002 	       unsigned int  *rdata_len,
1003 	       void          *cb_data)
1004 {
1005     uint16_t     record_id;
1006     unsigned int offset;
1007     unsigned int count;
1008     sdr_t        *entry;
1009 
1010     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1011 	handle_invalid_cmd(mc, rdata, rdata_len);
1012 	return;
1013     }
1014 
1015     if (check_msg_length(msg, 6, rdata, rdata_len))
1016 	return;
1017 
1018     if (mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED) {
1019 	uint16_t reservation = ipmi_get_uint16(msg->data+0);
1020 
1021 	if ((reservation != 0) && (reservation != mc->main_sdrs.reservation)) {
1022 	    rdata[0] = IPMI_INVALID_RESERVATION_CC;
1023 	    *rdata_len = 1;
1024 	    return;
1025 	}
1026     }
1027 
1028     record_id = ipmi_get_uint16(msg->data+2);
1029     offset = msg->data[4];
1030     count = msg->data[5];
1031 
1032     if (record_id == 0) {
1033 	entry = mc->main_sdrs.sdrs;
1034     } else if (record_id == 0xffff) {
1035 	entry = mc->main_sdrs.sdrs;
1036 	if (entry) {
1037 	    while (entry->next) {
1038 		entry = entry->next;
1039 	    }
1040 	}
1041     } else {
1042 	entry = find_sdr_by_recid(&mc->main_sdrs, record_id, NULL);
1043     }
1044 
1045     if (entry == NULL) {
1046 	rdata[0] = IPMI_NOT_PRESENT_CC;
1047 	*rdata_len = 1;
1048 	return;
1049     }
1050 
1051     if (offset >= entry->length) {
1052 	rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC;
1053 	*rdata_len = 1;
1054 	return;
1055     }
1056 
1057     if ((offset+count) > entry->length)
1058 	count = entry->length - offset;
1059     if (count+3 > *rdata_len) {
1060 	/* Too much data to put into response. */
1061 	rdata[0] = IPMI_CANNOT_RETURN_REQ_LENGTH_CC;
1062 	*rdata_len = 1;
1063 	return;
1064     }
1065 
1066     rdata[0] = 0;
1067     if (entry->next)
1068 	ipmi_set_uint16(rdata+1, entry->next->record_id);
1069     else {
1070 	rdata[1] = 0xff;
1071 	rdata[2] = 0xff;
1072     }
1073 
1074     memcpy(rdata+3, entry->data+offset, count);
1075     *rdata_len = count + 3;
1076 }
1077 
1078 static void
handle_add_sdr(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1079 handle_add_sdr(lmc_data_t    *mc,
1080 	       msg_t         *msg,
1081 	       unsigned char *rdata,
1082 	       unsigned int  *rdata_len,
1083 	       void          *cb_data)
1084 {
1085     int            modal;
1086     sdr_t          *entry;
1087 
1088     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1089 	handle_invalid_cmd(mc, rdata, rdata_len);
1090 	return;
1091     }
1092 
1093     modal = IPMI_SDR_GET_MODAL(mc->main_sdrs.flags);
1094     if ((modal == IPMI_SDR_NON_MODAL_ONLY)
1095 	&& !mc->in_update_mode)
1096     {
1097 	rdata[0] = IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC;
1098 	*rdata_len = 1;
1099 	return;
1100     }
1101 
1102     if (check_msg_length(msg, 6, rdata, rdata_len))
1103 	return;
1104 
1105     if (msg->len != (unsigned int) msg->data[5] + 6) {
1106 	rdata[0] = 0x80; /* Length is invalid. */
1107 	*rdata_len = 1;
1108 	return;
1109     }
1110 
1111     entry = new_sdr_entry(&mc->main_sdrs, msg->data[5]);
1112     if (!entry) {
1113 	rdata[0] = IPMI_OUT_OF_SPACE_CC;
1114 	*rdata_len = 1;
1115 	return;
1116     }
1117     add_sdr_entry(mc, &mc->main_sdrs, entry);
1118 
1119     memcpy(entry->data+2, msg->data+2, entry->length-2);
1120 
1121     rdata[0] = 0;
1122     ipmi_set_uint16(rdata+1, entry->record_id);
1123     *rdata_len = 3;
1124 }
1125 
1126 static void
handle_partial_add_sdr(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1127 handle_partial_add_sdr(lmc_data_t    *mc,
1128 		       msg_t         *msg,
1129 		       unsigned char *rdata,
1130 		       unsigned int  *rdata_len,
1131 		       void          *cb_data)
1132 {
1133     uint16_t     record_id;
1134     unsigned int offset;
1135     int          modal;
1136 
1137     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1138 	handle_invalid_cmd(mc, rdata, rdata_len);
1139 	return;
1140     }
1141 
1142     if (!(mc->main_sdrs.flags & IPMI_SDR_PARTIAL_ADD_SDR_SUPPORTED)) {
1143 	handle_invalid_cmd(mc, rdata, rdata_len);
1144 	return;
1145     }
1146 
1147     if (mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED) {
1148 	uint16_t reservation = ipmi_get_uint16(msg->data+0);
1149 
1150 	if ((reservation != 0) && (reservation != mc->main_sdrs.reservation)) {
1151 	    rdata[0] = IPMI_INVALID_RESERVATION_CC;
1152 	    *rdata_len = 1;
1153 	    return;
1154 	}
1155     }
1156 
1157     modal = IPMI_SDR_GET_MODAL(mc->main_sdrs.flags);
1158     if ((modal == IPMI_SDR_NON_MODAL_ONLY)
1159 	&& !mc->in_update_mode)
1160     {
1161 	rdata[0] = IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC;
1162 	*rdata_len = 1;
1163 	return;
1164     }
1165 
1166     offset = msg->data[4];
1167     record_id = ipmi_get_uint16(rdata+2);
1168     if (record_id == 0) {
1169 	/* New add. */
1170 	if (check_msg_length(msg, 12, rdata, rdata_len))
1171 	    return;
1172 	if (offset != 0) {
1173 	    rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1174 	    *rdata_len = 1;
1175 	    return;
1176 	}
1177 	if (msg->len > (unsigned int) msg->data[11] + 12) {
1178 	    rdata[0] = 0x80; /* Invalid data length */
1179 	    *rdata_len = 1;
1180 	    return;
1181 	}
1182 	if (mc->part_add_sdr) {
1183 	    /* Still working on a previous one, return an error and
1184 	       abort. */
1185 	    free_sdr(mc->part_add_sdr);
1186 	    mc->part_add_sdr = NULL;
1187 	    rdata[0] = IPMI_UNKNOWN_ERR_CC;
1188 	    *rdata_len = 1;
1189 	    return;
1190 	}
1191 	mc->part_add_sdr = new_sdr_entry(&mc->main_sdrs, msg->data[11]);
1192 	memcpy(mc->part_add_sdr->data+2, msg->data+8, msg->len - 8);
1193 	mc->part_add_next = msg->len - 8;
1194     } else {
1195 	if (!mc->part_add_next) {
1196 	    rdata[0] = IPMI_UNKNOWN_ERR_CC;
1197 	    *rdata_len = 1;
1198 	    return;
1199 	}
1200 	if (offset != mc->part_add_next) {
1201 	    free_sdr(mc->part_add_sdr);
1202 	    mc->part_add_sdr = NULL;
1203 	    rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1204 	    *rdata_len = 1;
1205 	    return;
1206 	}
1207 	if ((offset + msg->len - 6) > mc->part_add_sdr->length) {
1208 	    free_sdr(mc->part_add_sdr);
1209 	    mc->part_add_sdr = NULL;
1210 	    rdata[0] = 0x80; /* Invalid data length */
1211 	    *rdata_len = 1;
1212 	    return;
1213 	}
1214 	memcpy(mc->part_add_sdr->data+offset, msg->data+6, msg->len-6);
1215 	mc->part_add_next += msg->len - 6;
1216     }
1217 
1218     if ((msg->data[5] & 0xf) == 1) {
1219 	/* End of the operation. */
1220 	if (mc->part_add_next != mc->part_add_sdr->length) {
1221 	    free_sdr(mc->part_add_sdr);
1222 	    mc->part_add_sdr = NULL;
1223 	    rdata[0] = 0x80; /* Invalid data length */
1224 	    *rdata_len = 1;
1225 	    return;
1226 	}
1227 	add_sdr_entry(mc, &mc->main_sdrs, mc->part_add_sdr);
1228 	mc->part_add_sdr = NULL;
1229     }
1230 
1231     rdata[0] = 0;
1232     *rdata_len = 1;
1233 }
1234 
1235 void
iterate_sdrs(lmc_data_t * mc,sdrs_t * sdrs,int (* func)(lmc_data_t * mc,unsigned char * sdr,unsigned int len,void * cb_data),void * cb_data)1236 iterate_sdrs(lmc_data_t *mc,
1237 	     sdrs_t     *sdrs,
1238 	     int (*func)(lmc_data_t *mc, unsigned char *sdr,
1239 			 unsigned int len, void *cb_data),
1240 	     void *cb_data)
1241 {
1242     sdr_t *entry;
1243 
1244     for (entry = sdrs->sdrs; entry; entry = entry->next)
1245 	func(mc, entry->data, entry->length, cb_data);
1246 }
1247 
1248 static void
handle_delete_sdr(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1249 handle_delete_sdr(lmc_data_t    *mc,
1250 		  msg_t         *msg,
1251 		  unsigned char *rdata,
1252 		  unsigned int  *rdata_len,
1253 		  void          *cb_data)
1254 {
1255     uint16_t       record_id;
1256     sdr_t          *entry, *p_entry;
1257     struct timeval t;
1258 
1259     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1260 	handle_invalid_cmd(mc, rdata, rdata_len);
1261 	return;
1262     }
1263 
1264     if (check_msg_length(msg, 4, rdata, rdata_len))
1265 	return;
1266 
1267     if (mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED) {
1268 	uint16_t reservation = ipmi_get_uint16(msg->data+0);
1269 
1270 	if ((reservation != 0) && (reservation != mc->main_sdrs.reservation)) {
1271 	    rdata[0] = IPMI_INVALID_RESERVATION_CC;
1272 	    *rdata_len = 1;
1273 	    return;
1274 	}
1275     }
1276 
1277     record_id = ipmi_get_uint16(rdata+2);
1278 
1279     if (record_id == 0) {
1280 	entry = mc->main_sdrs.sdrs;
1281 	p_entry = NULL;
1282     } else if (record_id == 0xffff) {
1283 	entry = mc->main_sdrs.sdrs;
1284 	p_entry = NULL;
1285 	if (entry) {
1286 	    while (entry->next) {
1287 		p_entry = entry;
1288 		entry = entry->next;
1289 	    }
1290 	}
1291     } else {
1292 	entry = find_sdr_by_recid(&mc->main_sdrs, record_id, &p_entry);
1293     }
1294     if (!entry) {
1295 	rdata[0] = IPMI_NOT_PRESENT_CC;
1296 	*rdata_len = 1;
1297 	return;
1298     }
1299 
1300     if (p_entry)
1301 	p_entry->next = entry->next;
1302     else
1303 	mc->main_sdrs.sdrs = entry->next;
1304 
1305     rdata[0] = 0;
1306     ipmi_set_uint16(rdata+1, entry->record_id);
1307     *rdata_len = 3;
1308 
1309     free_sdr(entry);
1310 
1311     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
1312     mc->main_sdrs.last_erase_time = t.tv_sec + mc->main_sdrs.time_offset;
1313     mc->main_sdrs.sdr_count--;
1314     rewrite_sdrs(mc, &mc->main_sdrs);
1315 }
1316 
1317 static void
handle_clear_sdr_repository(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1318 handle_clear_sdr_repository(lmc_data_t    *mc,
1319 			    msg_t         *msg,
1320 			    unsigned char *rdata,
1321 			    unsigned int  *rdata_len,
1322 			    void          *cb_data)
1323 {
1324     sdr_t          *entry, *n_entry;
1325     struct timeval t;
1326     unsigned char  op;
1327 
1328     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1329 	handle_invalid_cmd(mc, rdata, rdata_len);
1330 	return;
1331     }
1332 
1333     if (check_msg_length(msg, 6, rdata, rdata_len))
1334 	return;
1335 
1336     if (mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED) {
1337 	uint16_t reservation = ipmi_get_uint16(msg->data+0);
1338 
1339 	if ((reservation != 0) && (reservation != mc->main_sdrs.reservation)) {
1340 	    rdata[0] = IPMI_INVALID_RESERVATION_CC;
1341 	    *rdata_len = 1;
1342 	    return;
1343 	}
1344     }
1345 
1346     if ((msg->data[2] != 'C')
1347 	|| (msg->data[3] != 'L')
1348 	|| (msg->data[4] != 'R'))
1349     {
1350 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1351 	*rdata_len = 1;
1352 	return;
1353     }
1354 
1355     op = msg->data[5];
1356     if ((op != 0) && (op != 0xaa))
1357     {
1358 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1359 	*rdata_len = 1;
1360 	return;
1361     }
1362 
1363     rdata[1] = 1;
1364     if (op == 0) {
1365 	entry = mc->main_sdrs.sdrs;
1366 	while (entry) {
1367 	    n_entry = entry->next;
1368 	    free_sdr(entry);
1369 	    entry = n_entry;
1370 	}
1371     }
1372 
1373     rdata[0] = 0;
1374     *rdata_len = 2;
1375 
1376     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
1377     mc->main_sdrs.last_erase_time = t.tv_sec + mc->main_sdrs.time_offset;
1378     rewrite_sdrs(mc, &mc->main_sdrs);
1379 }
1380 
1381 static void
handle_get_sdr_repository_time(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1382 handle_get_sdr_repository_time(lmc_data_t    *mc,
1383 			       msg_t         *msg,
1384 			       unsigned char *rdata,
1385 			       unsigned int  *rdata_len,
1386 			       void          *cb_data)
1387 {
1388     struct timeval t;
1389 
1390     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1391 	handle_invalid_cmd(mc, rdata, rdata_len);
1392 	return;
1393     }
1394 
1395     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
1396     rdata[0] = 0;
1397     ipmi_set_uint32(rdata+1, t.tv_sec + mc->main_sdrs.time_offset);
1398     *rdata_len = 5;
1399 }
1400 
1401 static void
handle_set_sdr_repository_time(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1402 handle_set_sdr_repository_time(lmc_data_t    *mc,
1403 			       msg_t         *msg,
1404 			       unsigned char *rdata,
1405 			       unsigned int  *rdata_len,
1406 			       void          *cb_data)
1407 {
1408     struct timeval t;
1409 
1410     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1411 	handle_invalid_cmd(mc, rdata, rdata_len);
1412 	return;
1413     }
1414 
1415     if (check_msg_length(msg, 4, rdata, rdata_len))
1416 	return;
1417 
1418     mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
1419     mc->main_sdrs.time_offset = ipmi_get_uint32(msg->data) - t.tv_sec;
1420 
1421     rdata[0] = 0;
1422     *rdata_len = 1;
1423 }
1424 
1425 static void
handle_enter_sdr_repository_update(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1426 handle_enter_sdr_repository_update(lmc_data_t    *mc,
1427 				   msg_t         *msg,
1428 				   unsigned char *rdata,
1429 				   unsigned int  *rdata_len,
1430 				   void          *cb_data)
1431 {
1432     int modal;
1433 
1434     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1435 	handle_invalid_cmd(mc, rdata, rdata_len);
1436 	return;
1437     }
1438 
1439     modal = IPMI_SDR_GET_MODAL(mc->main_sdrs.flags);
1440     if ((modal == IPMI_SDR_MODAL_UNSPECIFIED)
1441 	|| (modal == IPMI_SDR_NON_MODAL_ONLY))
1442     {
1443 	handle_invalid_cmd(mc, rdata, rdata_len);
1444 	return;
1445     }
1446 
1447     mc->in_update_mode = 1;
1448 
1449     rdata[0] = 0;
1450     *rdata_len = 1;
1451 }
1452 
1453 static void
handle_exit_sdr_repository_update(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1454 handle_exit_sdr_repository_update(lmc_data_t    *mc,
1455 				  msg_t         *msg,
1456 				  unsigned char *rdata,
1457 				  unsigned int  *rdata_len,
1458 				  void          *cb_data)
1459 {
1460     int modal;
1461 
1462     if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1463 	handle_invalid_cmd(mc, rdata, rdata_len);
1464 	return;
1465     }
1466 
1467     modal = IPMI_SDR_GET_MODAL(mc->main_sdrs.flags);
1468     if ((modal == IPMI_SDR_MODAL_UNSPECIFIED)
1469 	|| (modal == IPMI_SDR_NON_MODAL_ONLY))
1470     {
1471 	handle_invalid_cmd(mc, rdata, rdata_len);
1472 	return;
1473     }
1474 
1475     mc->in_update_mode = 0;
1476 
1477     rdata[0] = 0;
1478     *rdata_len = 1;
1479 }
1480 
1481 /*
1482  * FRU Inventory handling
1483  */
1484 
1485 fru_data_t *
find_fru(lmc_data_t * mc,unsigned int devid)1486 find_fru(lmc_data_t *mc, unsigned int devid)
1487 {
1488     fru_data_t *fru = mc->frulist;
1489 
1490     while (fru && fru->devid != devid)
1491 	fru = fru->next;
1492 
1493     return fru;
1494 }
1495 
1496 int
ipmi_mc_set_frudata_handler(lmc_data_t * mc,unsigned int devid,get_frudata_f handler,free_frudata_f freefunc)1497 ipmi_mc_set_frudata_handler(lmc_data_t *mc, unsigned int devid,
1498 			    get_frudata_f handler, free_frudata_f freefunc)
1499 {
1500     fru_data_t *fru = find_fru(mc, devid);
1501 
1502     if (!fru)
1503 	return EINVAL;
1504     fru->get = handler;
1505     fru->free = freefunc;
1506     return 0;
1507 }
1508 
1509 static void
fru_session_closed(lmc_data_t * mc,uint32_t session_id,void * cb_data)1510 fru_session_closed(lmc_data_t *mc, uint32_t session_id, void *cb_data)
1511 {
1512     fru_session_t *ses = cb_data;
1513     fru_data_t *fru = ses->fru;
1514 
1515     if (fru->sessions == ses) {
1516 	fru->sessions = ses->next;
1517     } else {
1518 	fru_session_t *p = fru->sessions;
1519 	while (p && p->next != ses)
1520 	    p = p->next;
1521 	if (p && p->next != ses)
1522 	    p->next = ses->next;
1523     }
1524     fru->free(mc, ses->data_to_free);
1525     free(ses);
1526 }
1527 
1528 static void
handle_get_fru_inventory_area_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1529 handle_get_fru_inventory_area_info(lmc_data_t    *mc,
1530 				   msg_t         *msg,
1531 				   unsigned char *rdata,
1532 				   unsigned int  *rdata_len,
1533 				   void          *cb_data)
1534 {
1535     unsigned char devid;
1536     fru_data_t *fru;
1537     unsigned int size;
1538     unsigned char *data;
1539     int rv;
1540 
1541     if (check_msg_length(msg, 1, rdata, rdata_len))
1542 	return;
1543 
1544     devid = msg->data[0];
1545 
1546     fru = find_fru(mc, devid);
1547     if (!fru) {
1548 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1549 	*rdata_len = 1;
1550 	return;
1551     }
1552 
1553     if (fru->get) {
1554 	channel_t *channel;
1555 	fru_session_t *ses;
1556 	int link_in = 0;
1557 
1558 	ses = fru->sessions;
1559 	while (ses) {
1560 	    if (ses->sid == msg->sid)
1561 		break;
1562 	    ses = ses->next;
1563 	}
1564 	if (!ses) {
1565 	    ses = malloc(sizeof(*ses));
1566 	    if (!ses) {
1567 		rdata[0] = IPMI_OUT_OF_SPACE_CC;
1568 		*rdata_len = 1;
1569 		return;
1570 	    }
1571 	    memset(ses, 0, sizeof(*ses));
1572 	    ses->sid = msg->sid;
1573 	    ses->fru = fru;
1574 	    link_in = 1;
1575 	}
1576 
1577 	/* Set up to free the FRU data when the session closes. */
1578 	channel = msg->orig_channel;
1579 	rv = channel->set_associated_mc(channel, msg->sid, 0, mc,
1580 					NULL, fru_session_closed, ses);
1581 	if (rv == EBUSY) {
1582 	    rdata[0] = IPMI_NODE_BUSY_CC;
1583 	    *rdata_len = 1;
1584 	    return;
1585 	} else if (rv) {
1586 	    rdata[0] = IPMI_UNKNOWN_ERR_CC;
1587 	    *rdata_len = 1;
1588 	    return;
1589 	}
1590 
1591 	data = fru->get(mc, &size);
1592 	if (!data) {
1593 	    channel->set_associated_mc(channel, msg->sid, 0, NULL,
1594 				       NULL, NULL, NULL);
1595 	    rdata[0] = IPMI_OUT_OF_SPACE_CC;
1596 	    *rdata_len = 1;
1597 	    return;
1598 	}
1599 
1600 	if (ses->data_to_free)
1601 	    fru->free(mc, ses->data_to_free);
1602 
1603 	ses->data_to_free = data;
1604 	if (size > 65535) {
1605 	    ses->data = data + (size - 65535);
1606 	    size = 65535;
1607 	} else {
1608 	    ses->data = data;
1609 	}
1610 	ses->length = size;
1611 
1612 	if (link_in) {
1613 	    ses->next = fru->sessions;
1614 	    fru->sessions = ses;
1615 	}
1616     } else {
1617 	size = fru->length;
1618 	data = fru->data;
1619     }
1620 
1621     if (!data) {
1622 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1623 	*rdata_len = 1;
1624 	return;
1625     }
1626 
1627     rdata[0] = 0;
1628     ipmi_set_uint16(rdata+1, size);
1629     rdata[3] = 0; /* We only support byte access for now. */
1630     *rdata_len = 4;
1631 }
1632 
1633 static int
fru_sem_trywait(fru_data_t * fru)1634 fru_sem_trywait(fru_data_t *fru)
1635 {
1636     struct timespec ts;
1637     int rv;
1638 
1639     /* Wait 250ms for the semaphore. */
1640   restart:
1641     rv = clock_gettime(CLOCK_REALTIME, &ts);
1642     if (rv == -1)
1643 	return errno;
1644 
1645     ts.tv_nsec += 250000000;
1646     if (ts.tv_nsec >= 1000000000) {
1647 	ts.tv_nsec -= 1000000000;
1648 	ts.tv_sec += 1;
1649     }
1650     rv = sem_timedwait(&fru->sem, &ts);
1651     if (rv) {
1652 	if (rv == EINTR)
1653 	    goto restart;
1654 	if (rv == ETIMEDOUT)
1655 	    rv = EAGAIN;
1656 	else
1657 	    rv = errno;
1658 	return rv;
1659     }
1660     return 0;
1661 }
1662 
1663 static void
handle_read_fru_data(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1664 handle_read_fru_data(lmc_data_t    *mc,
1665 		     msg_t         *msg,
1666 		     unsigned char *rdata,
1667 		     unsigned int  *rdata_len,
1668 		     void          *cb_data)
1669 {
1670     unsigned char devid;
1671     unsigned int  offset;
1672     unsigned int  count;
1673     unsigned char *data = NULL;
1674     unsigned int  size;
1675     fru_session_t *ses;
1676     fru_data_t *fru;
1677     int           rv;
1678 
1679     if (check_msg_length(msg, 4, rdata, rdata_len))
1680 	return;
1681 
1682     devid = msg->data[0];
1683     fru = find_fru(mc, devid);
1684     if (!fru) {
1685 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1686 	*rdata_len = 1;
1687 	return;
1688     }
1689 
1690     rv = fru_sem_trywait(fru);
1691     if (rv) {
1692 	if (rv == EAGAIN)
1693 	    rdata[0] = IPMI_NODE_BUSY_CC;
1694 	else
1695 	    rdata[0] = IPMI_UNKNOWN_ERR_CC;
1696 	*rdata_len = 1;
1697 	return;
1698     }
1699 
1700     offset = ipmi_get_uint16(msg->data+1);
1701     count = msg->data[3];
1702 
1703     size = fru->length;
1704 
1705     if (!fru->fru_io_cb) {
1706 	data = fru->data;
1707 	ses = fru->sessions;
1708 	while (ses && (ses->sid != msg->sid))
1709 	    ses = ses->next;
1710 	if (ses) {
1711 	    data = ses->data;
1712 	    size = ses->length;
1713 	}
1714 
1715 	if (!data) {
1716 	    rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1717 	    *rdata_len = 1;
1718 	    goto out_unlock;
1719 	}
1720 
1721 	if (offset >= size) {
1722 	    rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC;
1723 	    *rdata_len = 1;
1724 	    goto out_unlock;
1725 	}
1726     }
1727 
1728     if ((offset+count) > size)
1729 	count = size - offset;
1730     if (count+2 > *rdata_len) {
1731 	/* Too much data to put into response. */
1732 	rdata[0] = IPMI_REQUESTED_DATA_LENGTH_EXCEEDED_CC;
1733 	*rdata_len = 1;
1734 	goto out_unlock;
1735     }
1736 
1737     if (fru->fru_io_cb) {
1738 	int rv;
1739 
1740 	rv = fru->fru_io_cb(fru->data, FRU_IO_READ, rdata + 2, offset, count);
1741 	if (rv) {
1742 	    rdata[0] = IPMI_UNKNOWN_ERR_CC;
1743 	    *rdata_len = 1;
1744 	    goto out_unlock;
1745 	}
1746     } else {
1747 	memcpy(rdata + 2, data + offset, count);
1748     }
1749 
1750     rdata[0] = 0;
1751     rdata[1] = count;
1752     *rdata_len = 2 + count;
1753 
1754   out_unlock:
1755     sem_post(&fru->sem);
1756 }
1757 
1758 static void
handle_write_fru_data(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1759 handle_write_fru_data(lmc_data_t    *mc,
1760 		      msg_t         *msg,
1761 		      unsigned char *rdata,
1762 		      unsigned int  *rdata_len,
1763 		      void          *cb_data)
1764 {
1765     unsigned char device_id;
1766     unsigned int  offset;
1767     unsigned int  count;
1768     fru_data_t    *fru;
1769     int           rv;
1770 
1771     if (check_msg_length(msg, 3, rdata, rdata_len))
1772 	return;
1773 
1774     device_id = msg->data[0];
1775     fru = find_fru(mc, device_id);
1776     if (!fru) {
1777 	rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1778 	*rdata_len = 1;
1779 	return;
1780     }
1781 
1782     rv = fru_sem_trywait(fru);
1783     if (rv) {
1784 	if (rv == EAGAIN)
1785 	    rdata[0] = IPMI_NODE_BUSY_CC;
1786 	else
1787 	    rdata[0] = IPMI_UNKNOWN_ERR_CC;
1788 	*rdata_len = 1;
1789 	return;
1790     }
1791 
1792     offset = ipmi_get_uint16(msg->data+1);
1793     count = msg->len - 3;
1794 
1795     if (offset >= fru->length) {
1796 	rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC;
1797 	*rdata_len = 1;
1798 	goto out_unlock;
1799     }
1800 
1801     if ((offset+count) > fru->length) {
1802 	/* Too much data to put into FRU. */
1803 	rdata[0] = IPMI_REQUESTED_DATA_LENGTH_EXCEEDED_CC;
1804 	*rdata_len = 1;
1805 	goto out_unlock;
1806     }
1807 
1808     if (fru->fru_io_cb) {
1809 	int rv;
1810 
1811 	rv = fru->fru_io_cb(fru->data, FRU_IO_WRITE, msg->data + 3, offset,
1812 			    count);
1813 	if (rv) {
1814 	    rdata[0] = IPMI_UNKNOWN_ERR_CC;
1815 	    *rdata_len = 1;
1816 	    goto out_unlock;
1817 	}
1818     } else {
1819 	memcpy(fru->data+offset, msg->data+3, count);
1820     }
1821     rdata[0] = 0;
1822     rdata[1] = count;
1823     *rdata_len = 2;
1824 
1825   out_unlock:
1826     sem_post(&fru->sem);
1827 }
1828 
1829 int
ipmi_mc_get_fru_data_len(lmc_data_t * mc,unsigned char device_id,unsigned int * length)1830 ipmi_mc_get_fru_data_len(lmc_data_t    *mc,
1831 			 unsigned char device_id,
1832 			 unsigned int  *length)
1833 {
1834     fru_data_t *fru;
1835 
1836     if (!(mc->device_support & IPMI_DEVID_FRU_INVENTORY_DEV))
1837 	return ENOSYS;
1838 
1839     if (device_id >= 255)
1840 	return EINVAL;
1841 
1842     fru = find_fru(mc, device_id);
1843     if (!fru || !fru->data)
1844 	return EINVAL;
1845 
1846     *length = fru->length;
1847 
1848     return 0;
1849 }
1850 
1851 int
ipmi_mc_get_fru_data(lmc_data_t * mc,unsigned char device_id,unsigned int length,unsigned char * data)1852 ipmi_mc_get_fru_data(lmc_data_t    *mc,
1853 		     unsigned char device_id,
1854 		     unsigned int  length,
1855 		     unsigned char *data)
1856 {
1857     fru_data_t *fru;
1858     int        rv;
1859 
1860     if (!(mc->device_support & IPMI_DEVID_FRU_INVENTORY_DEV))
1861 	return ENOSYS;
1862 
1863     fru = find_fru(mc, device_id);
1864     if (!fru)
1865 	return EINVAL;
1866 
1867     if (length > fru->length)
1868 	return EINVAL;
1869 
1870     rv = fru_sem_trywait(fru);
1871     if (rv)
1872 	return errno;
1873 
1874     if (fru->fru_io_cb) {
1875 	rv = fru->fru_io_cb(fru->data, FRU_IO_READ, data, 0, length);
1876     } else {
1877 	memcpy(data, fru->data, length);
1878     }
1879 
1880     sem_post(&fru->sem);
1881     return rv;
1882 }
1883 
1884 int
ipmi_mc_add_fru_data(lmc_data_t * mc,unsigned char device_id,unsigned int length,fru_io_cb fru_io_cb,void * data)1885 ipmi_mc_add_fru_data(lmc_data_t    *mc,
1886 		     unsigned char device_id,
1887 		     unsigned int  length,
1888 		     fru_io_cb     fru_io_cb,
1889 		     void          *data)
1890 {
1891     fru_data_t *fru;
1892 
1893     if (device_id > 255)
1894 	return EINVAL;
1895 
1896     fru = find_fru(mc, device_id);
1897     if (!fru) {
1898 	int rv;
1899 	fru = malloc(sizeof(*fru));
1900 	memset(fru, 0, sizeof(*fru));
1901 	rv = sem_init(&fru->sem, 0, 1);
1902 	if (rv) {
1903 	    rv = errno;
1904 	    free(fru);
1905 	    return rv;
1906 	}
1907 	fru->devid = device_id;
1908 	fru->next = mc->frulist;
1909 	mc->frulist = fru;
1910     }
1911 
1912     if (fru->data) {
1913 	free(fru->data);
1914 	fru->length = 0;
1915     }
1916 
1917     if (fru_io_cb) {
1918 	fru->fru_io_cb = fru_io_cb;
1919 	fru->data = data;
1920     } else if (length) {
1921 	fru->data = malloc(length);
1922 	if (!fru->data)
1923 	    return ENOMEM;
1924 	memcpy(fru->data, data, length);
1925     } else
1926 	fru->data = NULL;
1927 
1928     fru->length = length;
1929 
1930     return 0;
1931 }
1932 
1933 int
ipmi_mc_fru_sem_wait(lmc_data_t * mc,unsigned char device_id)1934 ipmi_mc_fru_sem_wait(lmc_data_t *mc, unsigned char device_id)
1935 {
1936     int rv;
1937     fru_data_t *fru = find_fru(mc, device_id);
1938     if (!fru)
1939 	return EINVAL;
1940     rv = sem_wait(&fru->sem);
1941     if (rv)
1942 	return errno;
1943     return 0;
1944 }
1945 
1946 int
ipmi_mc_fru_sem_trywait(lmc_data_t * mc,unsigned char device_id)1947 ipmi_mc_fru_sem_trywait(lmc_data_t *mc, unsigned char device_id)
1948 {
1949     int rv;
1950     fru_data_t *fru = find_fru(mc, device_id);
1951     if (!fru)
1952 	return EINVAL;
1953     rv = fru_sem_trywait(fru);
1954     if (rv)
1955 	return errno;
1956     return 0;
1957 }
1958 
1959 int
ipmi_mc_fru_sem_post(lmc_data_t * mc,unsigned char device_id)1960 ipmi_mc_fru_sem_post(lmc_data_t *mc, unsigned char device_id)
1961 {
1962     int rv;
1963     fru_data_t *fru = find_fru(mc, device_id);
1964     if (!fru)
1965 	return EINVAL;
1966     rv = sem_post(&fru->sem);
1967     if (rv)
1968 	return errno;
1969     return 0;
1970 }
1971 
1972 struct fru_file_io_info {
1973     lmc_data_t   *mc;
1974     char         *filename;
1975     unsigned int file_offset;
1976     unsigned int length;
1977 };
1978 
fru_file_io_cb(void * cb_data,enum fru_io_cb_op op,unsigned char * data,unsigned int offset,unsigned int length)1979 static int fru_file_io_cb(void *cb_data,
1980 			  enum fru_io_cb_op op,
1981 			  unsigned char *data,
1982 			  unsigned int offset,
1983 			  unsigned int length)
1984 {
1985     struct fru_file_io_info *info = cb_data;
1986     int fd;
1987     int rv = 0;
1988     int l;
1989 
1990     if (offset + length > info->length)
1991 	return EINVAL;
1992 
1993     switch (op) {
1994     case FRU_IO_READ:
1995 	fd = open(info->filename, O_RDONLY);
1996 	if (fd == -1) {
1997 	    rv = errno;
1998 	    info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
1999 				   "fru_io: (read) error on open of %s: %s",
2000 				   info->filename, strerror(rv));
2001 	    return rv;
2002 	}
2003 	if (lseek(fd, info->file_offset + offset, SEEK_SET) == -1) {
2004 	    rv = errno;
2005 	    close(fd);
2006 	    info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2007 				   "fru_io: (read) error on lseek"
2008 				   " of %s to %u: %s",
2009 				   info->filename, info->file_offset + offset,
2010 				   strerror(rv));
2011 	    return rv;
2012 	}
2013     restart_read:
2014 	l = read(fd, data, length);
2015 	if (l == -1) {
2016 	    if (errno == EINTR)
2017 		goto restart_read;
2018 	    rv = errno;
2019 	    info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2020 				   "fru_io: error on read of %u bytes of %s"
2021 				   " at %u: %s",
2022 				   length, info->filename,
2023 				   info->file_offset + offset,
2024 				   strerror(rv));
2025 	} else if (l == 0) {
2026 	    rv = EIO;
2027 	    info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2028 				   "fru_io: end of file read of %u bytes of %s"
2029 				   " at %u: %s",
2030 				   length, info->filename,
2031 				   info->file_offset + offset,
2032 				   strerror(rv));
2033 	} else if (((unsigned int) l) != length) {
2034 	    length -= l;
2035 	    data += l;
2036 	    goto restart_read;
2037 	}
2038 	close(fd);
2039 	break;
2040 
2041     case FRU_IO_WRITE:
2042 	fd = open(info->filename, O_WRONLY);
2043 	if (fd == -1) {
2044 	    rv = errno;
2045 	    info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2046 				   "fru_io: (write) error on open of %s: %s",
2047 				   info->filename, strerror(rv));
2048 	    return rv;
2049 	}
2050 	if (lseek(fd, info->file_offset + offset, SEEK_SET) == -1) {
2051 	    rv = errno;
2052 	    close(fd);
2053 	    info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2054 				   "fru_io: (write) error on lseek"
2055 				   " of %s to %u: %s",
2056 				   info->filename, info->file_offset + offset,
2057 				   strerror(rv));
2058 	    return rv;
2059 	}
2060     restart_write:
2061 	l = write(fd, data, length);
2062 	if (l == -1) {
2063 	    if (errno == EINTR)
2064 		goto restart_write;
2065 	    rv = errno;
2066 	    info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2067 				   "fru_io: error on write of %u bytes of %s"
2068 				   " at %u: %s",
2069 				   length, info->filename,
2070 				   info->file_offset + offset,
2071 				   strerror(rv));
2072 	} else if (l == 0) {
2073 	    rv = EIO;
2074 	    info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2075 				   "fru_io: end of file write of %u bytes of %s"
2076 				   " at %u: %s",
2077 				   length, info->filename,
2078 				   info->file_offset + offset,
2079 				   strerror(rv));
2080 	} else if (((unsigned int) l) != length) {
2081 	    length -= l;
2082 	    data += l;
2083 	    goto restart_write;
2084 	}
2085 	close(fd);
2086 	break;
2087 
2088     default:
2089 	return EINVAL;
2090     }
2091 
2092     return rv;
2093 }
2094 
ipmi_mc_add_fru_file(lmc_data_t * mc,unsigned char device_id,unsigned int length,unsigned int file_offset,const char * filename)2095 int ipmi_mc_add_fru_file(lmc_data_t    *mc,
2096 			 unsigned char device_id,
2097 			 unsigned int  length,
2098 			 unsigned int  file_offset,
2099 			 const char    *filename)
2100 {
2101     struct fru_file_io_info *info;
2102     int rv;
2103 
2104     info = malloc(sizeof(*info));
2105     if (!info)
2106 	return ENOMEM;
2107     info->filename = strdup(filename);
2108     if (!info->filename) {
2109 	free(info);
2110 	return ENOMEM;
2111     }
2112     info->mc = mc;
2113     info->length = length;
2114     info->file_offset = file_offset;
2115 
2116     rv = ipmi_mc_add_fru_data(mc, device_id, length, fru_file_io_cb, info);
2117     if (rv) {
2118 	free(info->filename);
2119 	free(info);
2120     }
2121 
2122     return rv;
2123 }
2124 
2125 /* We don't currently care about partial sel adds, since they are
2126    pretty stupid. */
2127 cmd_handler_f storage_netfn_handlers[256] = {
2128     [IPMI_GET_SEL_INFO_CMD] = handle_get_sel_info,
2129     [IPMI_GET_SEL_ALLOCATION_INFO_CMD] = handle_get_sel_allocation_info,
2130     [IPMI_RESERVE_SEL_CMD] = handle_reserve_sel,
2131     [IPMI_GET_SEL_ENTRY_CMD] = handle_get_sel_entry,
2132     [IPMI_ADD_SEL_ENTRY_CMD] = handle_add_sel_entry,
2133     [IPMI_DELETE_SEL_ENTRY_CMD] = handle_delete_sel_entry,
2134     [IPMI_CLEAR_SEL_CMD] = handle_clear_sel,
2135     [IPMI_GET_SEL_TIME_CMD] = handle_get_sel_time,
2136     [IPMI_SET_SEL_TIME_CMD] = handle_set_sel_time,
2137     [IPMI_GET_SDR_REPOSITORY_INFO_CMD] = handle_get_sdr_repository_info,
2138     [IPMI_GET_SDR_REPOSITORY_ALLOC_INFO_CMD] = handle_get_sdr_repository_alloc_info,
2139     [IPMI_RESERVE_SDR_REPOSITORY_CMD] = handle_reserve_sdr_repository,
2140     [IPMI_GET_SDR_CMD] = handle_get_sdr,
2141     [IPMI_ADD_SDR_CMD] = handle_add_sdr,
2142     [IPMI_PARTIAL_ADD_SDR_CMD] = handle_partial_add_sdr,
2143     [IPMI_DELETE_SDR_CMD] = handle_delete_sdr,
2144     [IPMI_CLEAR_SDR_REPOSITORY_CMD] = handle_clear_sdr_repository,
2145     [IPMI_GET_SDR_REPOSITORY_TIME_CMD] = handle_get_sdr_repository_time,
2146     [IPMI_SET_SDR_REPOSITORY_TIME_CMD] = handle_set_sdr_repository_time,
2147     [IPMI_ENTER_SDR_REPOSITORY_UPDATE_CMD] = handle_enter_sdr_repository_update,
2148     [IPMI_EXIT_SDR_REPOSITORY_UPDATE_CMD] = handle_exit_sdr_repository_update,
2149     [IPMI_GET_FRU_INVENTORY_AREA_INFO_CMD] = handle_get_fru_inventory_area_info,
2150     [IPMI_READ_FRU_DATA_CMD] = handle_read_fru_data,
2151     [IPMI_WRITE_FRU_DATA_CMD] = handle_write_fru_data
2152 };
2153